From 727823d75e03041ee796da8e3460e901e3a2ffed Mon Sep 17 00:00:00 2001 From: nntrivi2001 Date: Wed, 5 Aug 2026 12:46:56 +0700 Subject: [PATCH] feat(lanes): add ccam lanes agents install CLI (E3) --- bin/ccam.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/bin/ccam.js b/bin/ccam.js index 756476a..0d68c01 100755 --- a/bin/ccam.js +++ b/bin/ccam.js @@ -2155,6 +2155,25 @@ async function cmdLanesProofLink(args) { ); } +/** `ccam lanes agents install [] [--cwd path]` — write the ship-feature-lane + * agent templates (qc-local, senior-gate-reviewer) into /.claude/agents/, + * git-excluded. Never run automatically; a session calls it explicitly. */ +async function cmdLanesAgentsInstall(args) { + const resolved = await resolveLaneArg(args); + if (!resolved) return; + const result = await post( + `/api/lanes/${resolved.laneId}/agents/install`, + {}, + { allowError: true } + ); + if (result.status) { + console.error(`✖ agents install → ${result.data?.error?.message || result.status}`); + process.exitCode = 1; + return; + } + console.log(`${c.green("✔")} installed: ${result.installed.join(", ")}`); +} + async function cmdFeatureShow(args) { const slug = args.find((arg) => !arg.startsWith("--")); if (!slug) { @@ -2341,6 +2360,11 @@ const COMMAND_GROUPS = [ "[]", "Converge clone-root proof/ onto .playwright-mcp/proof (idempotent, never automatic)", ], + [ + "lanes agents install", + "[]", + "Write the ship-feature-lane agent templates (qc-local, senior-gate-reviewer) into /.claude/agents/, git-excluded", + ], [ "lock status|acquire|release", "[] [--holder X] [--timeout N]", @@ -3159,6 +3183,9 @@ async function runCommand(argv) { return cmdLanesRuntime(rest[0], rest.slice(1)); } if (rest[0] === "proof-link") return cmdLanesProofLink(rest.slice(1)); + if (rest[0] === "agents" && rest[1] === "install") { + return cmdLanesAgentsInstall(rest.slice(2)); + } return cmdLanes(); case "lock": { const sub = rest[0];