feat(lanes): add ccam skills install (E, F3b)

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.
This commit is contained in:
2026-08-05 17:16:38 +07:00
parent c781fcdb45
commit 6d24f9d7ad
+32
View File
@@ -1520,6 +1520,27 @@ async function cmdLanesAdd(args) {
console.log(`${c.green("✔")} Created lane #${lane.id}: ${lane.title}`); 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 <repo>` — detect a Node.js project and scaffold * `ccam lanes profile init <repo>` — detect a Node.js project and scaffold
* `.ccam/profile/`. Pure filesystem action against the SOURCE repo; does not * `.ccam/profile/`. Pure filesystem action against the SOURCE repo; does not
@@ -2412,6 +2433,11 @@ const COMMAND_GROUPS = [
"<name> [<id>]", "<name> [<id>]",
"Check whether a named integration (tracker, dev_qc, ci_wait) is on for this lane — exit 0/1", "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", "lock status|acquire|release",
"[<name>] [--holder X] [--timeout N]", "[<name>] [--holder X] [--timeout N]",
@@ -3240,6 +3266,12 @@ async function runCommand(argv) {
return cmdLanesIntegration(rest.slice(1)); return cmdLanesIntegration(rest.slice(1));
} }
return cmdLanes(); return cmdLanes();
case "skills": {
if (rest[0] === "install") return cmdSkillsInstall();
console.error("usage: ccam skills install");
process.exitCode = 1;
return;
}
case "lock": { case "lock": {
const sub = rest[0]; const sub = rest[0];
if (sub === "status") return cmdLockStatus(rest.slice(1)); if (sub === "status") return cmdLockStatus(rest.slice(1));