feat(cli): add 'ccam lanes shell' to attach a real terminal to a lane's tmux session
This commit is contained in:
+33
@@ -2300,6 +2300,31 @@ async function cmdLanesPipeline(args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a real terminal to the exact tmux session the dashboard uses for
|
||||||
|
* this lane's run. Creates it if it doesn't exist yet (`tmux new-session -A`
|
||||||
|
* is create-or-attach, the same idempotent semantics as clicking Start on
|
||||||
|
* the dashboard). The user types `claude` themselves inside — this command's
|
||||||
|
* only job is landing them in the right named session.
|
||||||
|
*/
|
||||||
|
async function cmdLanesShell(args) {
|
||||||
|
const resolved = await resolveLaneArg(args);
|
||||||
|
if (!resolved) return;
|
||||||
|
const { lane } = await get(`/api/lanes/${resolved.laneId}`);
|
||||||
|
const sessionName = `ccam-lane-${lane.id}`;
|
||||||
|
const child = spawn("tmux", ["new-session", "-A", "-s", sessionName, "-c", lane.cwd], {
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
child.on("close", resolve);
|
||||||
|
child.on("error", (err) => {
|
||||||
|
console.error(c.red(`✖ ${err?.message || err}`));
|
||||||
|
process.exitCode = 1;
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function cmdFeatureShow(args) {
|
async function cmdFeatureShow(args) {
|
||||||
const slug = args.find((arg) => !arg.startsWith("--"));
|
const slug = args.find((arg) => !arg.startsWith("--"));
|
||||||
if (!slug) {
|
if (!slug) {
|
||||||
@@ -2484,6 +2509,11 @@ const COMMAND_GROUPS = [
|
|||||||
"[<template-id>] [<id>]",
|
"[<template-id>] [<id>]",
|
||||||
"Show, or switch, which pipeline template a lane renders against",
|
"Show, or switch, which pipeline template a lane renders against",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"lanes shell",
|
||||||
|
"[<id>]",
|
||||||
|
"Attach a real terminal to the exact tmux session the dashboard uses for a lane's run",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"lanes reset|remove|purge",
|
"lanes reset|remove|purge",
|
||||||
"<id> [--force] [--keep-db] --yes",
|
"<id> [--force] [--keep-db] --yes",
|
||||||
@@ -3362,6 +3392,9 @@ async function runCommand(argv) {
|
|||||||
if (rest[0] === "pipeline") {
|
if (rest[0] === "pipeline") {
|
||||||
return cmdLanesPipeline(rest.slice(1));
|
return cmdLanesPipeline(rest.slice(1));
|
||||||
}
|
}
|
||||||
|
if (rest[0] === "shell") {
|
||||||
|
return cmdLanesShell(rest.slice(1));
|
||||||
|
}
|
||||||
if (rest[0] === "gc") {
|
if (rest[0] === "gc") {
|
||||||
return cmdLanesGc(rest.slice(1));
|
return cmdLanesGc(rest.slice(1));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user