From 6d24f9d7adb558fd23d310905ad48a3cc1b01ff9 Mon Sep 17 00:00:00 2001 From: nntrivi2001 Date: Wed, 5 Aug 2026 17:16:38 +0700 Subject: [PATCH] feat(lanes): add ccam skills install (E, F3b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copies .claude/skills/ship-feature-lane/ into ~/.claude/skills/, so /ship-feature-lane is discoverable from a session running inside any lane's own working directory — not just inside this repo, which is where it lived until now (Claude Code only auto-discovers .claude/ directories from the repo that owns them). Pure filesystem action, same self-location REPO_ROOT already gives lanes profile init. --- bin/ccam.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/bin/ccam.js b/bin/ccam.js index d3d93e6..47c4403 100755 --- a/bin/ccam.js +++ b/bin/ccam.js @@ -1520,6 +1520,27 @@ async function cmdLanesAdd(args) { console.log(`${c.green("✔")} Created lane #${lane.id}: ${lane.title}`); } +/** + * `ccam skills install` — copy this checkout's `.claude/skills/ship-feature-lane/` + * into `~/.claude/skills/ship-feature-lane/`, so `/ship-feature-lane` is + * discoverable from a session running inside any lane's own working + * directory, not just inside this repo. Pure filesystem action; does not + * talk to the dashboard server at all. Reinstall, not merge — overwrites an + * existing global copy with the current one. + */ +function cmdSkillsInstall() { + const src = path.join(REPO_ROOT, ".claude", "skills", "ship-feature-lane"); + if (!fs.existsSync(src)) { + console.error(`✖ not found: ${src}`); + process.exitCode = 1; + return; + } + const dest = path.join(require("node:os").homedir(), ".claude", "skills", "ship-feature-lane"); + fs.mkdirSync(path.dirname(dest), { recursive: true }); + fs.cpSync(src, dest, { recursive: true, force: true }); + console.log(`${c.green("✔")} installed ship-feature-lane skill -> ${dest}`); +} + /** * `ccam lanes profile init ` — detect a Node.js project and scaffold * `.ccam/profile/`. Pure filesystem action against the SOURCE repo; does not @@ -2412,6 +2433,11 @@ const COMMAND_GROUPS = [ " []", "Check whether a named integration (tracker, dev_qc, ci_wait) is on for this lane — exit 0/1", ], + [ + "skills install", + "", + "Install .claude/skills/ship-feature-lane/ into ~/.claude/skills/ so /ship-feature-lane works from any lane", + ], [ "lock status|acquire|release", "[] [--holder X] [--timeout N]", @@ -3240,6 +3266,12 @@ async function runCommand(argv) { return cmdLanesIntegration(rest.slice(1)); } return cmdLanes(); + case "skills": { + if (rest[0] === "install") return cmdSkillsInstall(); + console.error("usage: ccam skills install"); + process.exitCode = 1; + return; + } case "lock": { const sub = rest[0]; if (sub === "status") return cmdLockStatus(rest.slice(1));