@sechroom/cli 2026.6.192-rc.f5192d37 → 2026.6.194-rc.5f6d8f6f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +110 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1780,7 +1780,7 @@ import { delimiter, dirname as dirname4, join as join4 } from "path";
|
|
|
1780
1780
|
|
|
1781
1781
|
// src/sem.ts
|
|
1782
1782
|
import { basename as basename2, dirname as dirname2, join as join2 } from "path";
|
|
1783
|
-
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1783
|
+
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1784
1784
|
var SEM_FILE = join2(".sechroom", "lane.json");
|
|
1785
1785
|
var LEGACY_SEM_FILE = ".sem";
|
|
1786
1786
|
var STATE_DIR_NAME2 = ".sechroom";
|
|
@@ -1799,6 +1799,43 @@ function resolveSemPathForRead(start = process.cwd()) {
|
|
|
1799
1799
|
dir = parent;
|
|
1800
1800
|
}
|
|
1801
1801
|
}
|
|
1802
|
+
function applyWorktreeLaneSuffix(lane, start = process.cwd()) {
|
|
1803
|
+
try {
|
|
1804
|
+
let dir = start;
|
|
1805
|
+
let gitPath;
|
|
1806
|
+
for (; ; ) {
|
|
1807
|
+
const candidate = join2(dir, ".git");
|
|
1808
|
+
if (existsSync2(candidate)) {
|
|
1809
|
+
gitPath = candidate;
|
|
1810
|
+
break;
|
|
1811
|
+
}
|
|
1812
|
+
const parent = dirname2(dir);
|
|
1813
|
+
if (parent === dir) break;
|
|
1814
|
+
dir = parent;
|
|
1815
|
+
}
|
|
1816
|
+
if (!gitPath || statSync(gitPath).isDirectory()) return lane;
|
|
1817
|
+
const gitFile = readFileSync2(gitPath, "utf8");
|
|
1818
|
+
const common = gitFile.trim().match(/^gitdir:\s*(.+)\/worktrees\/[^/\s]+\s*$/);
|
|
1819
|
+
if (!common) return lane;
|
|
1820
|
+
const worktreesDir = join2(common[1], "worktrees");
|
|
1821
|
+
const siblings = readdirSync(worktreesDir).filter((n) => {
|
|
1822
|
+
try {
|
|
1823
|
+
return statSync(join2(worktreesDir, n)).isDirectory();
|
|
1824
|
+
} catch {
|
|
1825
|
+
return false;
|
|
1826
|
+
}
|
|
1827
|
+
});
|
|
1828
|
+
return laneWithWorktreeSuffix(lane, gitFile, siblings);
|
|
1829
|
+
} catch {
|
|
1830
|
+
return lane;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
function laneWithWorktreeSuffix(lane, gitFile, siblings) {
|
|
1834
|
+
const m = gitFile.trim().match(/\/worktrees\/([^/\s]+)\s*$/);
|
|
1835
|
+
if (!m) return lane;
|
|
1836
|
+
const idx = [...siblings].sort().indexOf(m[1]);
|
|
1837
|
+
return idx < 0 ? lane : `${lane}-${idx + 2}`;
|
|
1838
|
+
}
|
|
1802
1839
|
function parseSem(text) {
|
|
1803
1840
|
const out = {};
|
|
1804
1841
|
for (const raw of text.split("\n")) {
|
|
@@ -2090,8 +2127,9 @@ function resolveLane(flagLane, cwd) {
|
|
|
2090
2127
|
const env = process.env.SECHROOM_LANE;
|
|
2091
2128
|
if (env) return env;
|
|
2092
2129
|
const start = cwd ?? process.cwd();
|
|
2093
|
-
const
|
|
2094
|
-
return
|
|
2130
|
+
const base = readSem(resolveSemPathForRead(start))?.values["code-lane"];
|
|
2131
|
+
if (!base) return void 0;
|
|
2132
|
+
return applyWorktreeLaneSuffix(base, start);
|
|
2095
2133
|
}
|
|
2096
2134
|
var INTENT_FILE = join4(".sechroom", "continuity.json");
|
|
2097
2135
|
function resolveIntentPath(start) {
|
|
@@ -3248,7 +3286,7 @@ import { basename as basename3, join as join8 } from "path";
|
|
|
3248
3286
|
|
|
3249
3287
|
// src/commands/fanout.ts
|
|
3250
3288
|
import { spawnSync } from "child_process";
|
|
3251
|
-
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync, statSync } from "fs";
|
|
3289
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
3252
3290
|
import { isAbsolute, join as join7, resolve } from "path";
|
|
3253
3291
|
var ICON = {
|
|
3254
3292
|
refresh: "\u21BB",
|
|
@@ -3262,7 +3300,7 @@ function resolveChildDir(path, root) {
|
|
|
3262
3300
|
function discoverChildren(root) {
|
|
3263
3301
|
let names;
|
|
3264
3302
|
try {
|
|
3265
|
-
names =
|
|
3303
|
+
names = readdirSync2(root);
|
|
3266
3304
|
} catch {
|
|
3267
3305
|
return [];
|
|
3268
3306
|
}
|
|
@@ -3271,7 +3309,7 @@ function discoverChildren(root) {
|
|
|
3271
3309
|
if (name.startsWith(".") || name === "node_modules") continue;
|
|
3272
3310
|
const dir = join7(root, name);
|
|
3273
3311
|
try {
|
|
3274
|
-
if (!
|
|
3312
|
+
if (!statSync2(dir).isDirectory()) continue;
|
|
3275
3313
|
} catch {
|
|
3276
3314
|
continue;
|
|
3277
3315
|
}
|
|
@@ -4039,6 +4077,63 @@ Examples:
|
|
|
4039
4077
|
// src/commands/skills.ts
|
|
4040
4078
|
import { join as join10 } from "path";
|
|
4041
4079
|
import { existsSync as existsSync10, rmSync as rmSync2 } from "fs";
|
|
4080
|
+
|
|
4081
|
+
// src/commands/lane.ts
|
|
4082
|
+
var LANE_KEYS = ["code-lane", "design-lane"];
|
|
4083
|
+
function showLane(json) {
|
|
4084
|
+
const found = readSem();
|
|
4085
|
+
if (!found) {
|
|
4086
|
+
if (json) return emit({ path: null, values: {} }, true);
|
|
4087
|
+
return console.log(
|
|
4088
|
+
style.dim(`No ./.sechroom/lane.json pin in this checkout. Run 'sechroom lane set'.`)
|
|
4089
|
+
);
|
|
4090
|
+
}
|
|
4091
|
+
const resolved = { ...found.values };
|
|
4092
|
+
let suffixed = false;
|
|
4093
|
+
for (const k of LANE_KEYS) {
|
|
4094
|
+
const v = found.values[k];
|
|
4095
|
+
if (!v) continue;
|
|
4096
|
+
resolved[k] = applyWorktreeLaneSuffix(v);
|
|
4097
|
+
if (resolved[k] !== v) suffixed = true;
|
|
4098
|
+
}
|
|
4099
|
+
if (json) return emit({ path: found.path, values: resolved, worktreeSuffixApplied: suffixed }, true);
|
|
4100
|
+
console.log(style.dim(`from ${found.path}`));
|
|
4101
|
+
Object.entries(resolved).forEach(([k, v]) => console.log(" " + style.bold(k) + " = " + v));
|
|
4102
|
+
if (suffixed) console.log(style.dim(" (worktree -N suffix applied \u2014 non-primary git worktree)"));
|
|
4103
|
+
}
|
|
4104
|
+
function setLane(opts) {
|
|
4105
|
+
if (!opts.codeLane && !opts.designLane) fail("Provide --code-lane and/or --design-lane.");
|
|
4106
|
+
const target = localSemPath();
|
|
4107
|
+
const values = readLocalSemValues();
|
|
4108
|
+
if (opts.codeLane) values["code-lane"] = opts.codeLane;
|
|
4109
|
+
if (opts.designLane) values["design-lane"] = opts.designLane;
|
|
4110
|
+
writeSem(values, target);
|
|
4111
|
+
if (opts.json) return emit({ path: target, values }, true);
|
|
4112
|
+
console.log(style.green(`Wrote lane pin \u2192 ${target} ${style.dim("(git-ignored)")}`));
|
|
4113
|
+
Object.entries(values).forEach(([k, v]) => console.log(" " + style.dim(k) + " = " + v));
|
|
4114
|
+
}
|
|
4115
|
+
function registerLane(program2) {
|
|
4116
|
+
const lane = program2.command("lane").description("Show this checkout's continuity lane pin (worktree-aware -N suffix applied)").option("--json", "machine output").action((opts, cmd) => showLane(Boolean(opts.json) || Boolean(cmd.optsWithGlobals().json)));
|
|
4117
|
+
lane.command("set").description("Write this checkout's lane pin to ./.sechroom/lane.json").option("--code-lane <id>", "code-surface lane id (e.g. claude-code-chris)").option("--design-lane <id>", "design / substrate-authoring lane id (e.g. claude-design-chris)").option("--json", "machine output").action(
|
|
4118
|
+
(opts, cmd) => setLane({
|
|
4119
|
+
codeLane: opts.codeLane,
|
|
4120
|
+
designLane: opts.designLane,
|
|
4121
|
+
json: Boolean(opts.json) || Boolean(cmd.optsWithGlobals().json)
|
|
4122
|
+
})
|
|
4123
|
+
);
|
|
4124
|
+
lane.addHelpText(
|
|
4125
|
+
"after",
|
|
4126
|
+
`
|
|
4127
|
+
Examples:
|
|
4128
|
+
$ sechroom lane show the resolved lane(s)
|
|
4129
|
+
$ sechroom lane set --code-lane claude-code-chris --design-lane claude-design-chris
|
|
4130
|
+
|
|
4131
|
+
In a non-primary git worktree the ratified concurrent-session -N suffix is auto-applied (SBC-1094).
|
|
4132
|
+
(Aliases: 'sechroom skills lane' / 'skills set-lane' \u2014 kept for back-compat.)`
|
|
4133
|
+
);
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4136
|
+
// src/commands/skills.ts
|
|
4042
4137
|
function registerSkills(program2) {
|
|
4043
4138
|
const skills = program2.command("skills").description("Manage operator skills (materialised by `onboard`)");
|
|
4044
4139
|
skills.addHelpText(
|
|
@@ -4083,28 +4178,14 @@ To install/refresh skills, run 'sechroom onboard' (it offers to materialise them
|
|
|
4083
4178
|
if (opts.json) return emit({ slug, removed, dir }, true);
|
|
4084
4179
|
console.log(style.green(`Removed ${removed.length} skill(s) for ${slug} from ${dir}`));
|
|
4085
4180
|
});
|
|
4086
|
-
skills.command("set-lane").description("
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
console.log(style.green(`Wrote lane pin \u2192 ${target} ${style.dim("(git-ignored)")}`));
|
|
4095
|
-
Object.entries(values).forEach(([k, v]) => console.log(" " + style.dim(k) + " = " + v));
|
|
4096
|
-
});
|
|
4097
|
-
skills.command("lane").description("Show the lane pin resolved from ./.sechroom/lane.json (nearest in this checkout; legacy ./.sem honoured)").option("--json", "machine output").action((opts, cmd) => {
|
|
4098
|
-
const json = cmd.optsWithGlobals().json;
|
|
4099
|
-
const found = readSem();
|
|
4100
|
-
if (!found) {
|
|
4101
|
-
if (json) return emit({ path: null, values: {} }, true);
|
|
4102
|
-
return console.log(style.dim(`No ./.sechroom/lane.json pin in this checkout. Run 'sechroom skills set-lane'.`));
|
|
4103
|
-
}
|
|
4104
|
-
if (json) return emit(found, true);
|
|
4105
|
-
console.log(style.dim(`from ${found.path}`));
|
|
4106
|
-
Object.entries(found.values).forEach(([k, v]) => console.log(" " + style.bold(k) + " = " + v));
|
|
4107
|
-
});
|
|
4181
|
+
skills.command("set-lane").description("Alias of `sechroom lane set` (kept for back-compat) \u2014 write this checkout's lane pin").option("--code-lane <id>", "code-surface lane id (e.g. claude-code-chris)").option("--design-lane <id>", "design / substrate-authoring lane id (e.g. claude-design-chris)").option("--json", "machine output").action(
|
|
4182
|
+
(opts, cmd) => setLane({
|
|
4183
|
+
codeLane: opts.codeLane,
|
|
4184
|
+
designLane: opts.designLane,
|
|
4185
|
+
json: Boolean(opts.json) || Boolean(cmd.optsWithGlobals().json)
|
|
4186
|
+
})
|
|
4187
|
+
);
|
|
4188
|
+
skills.command("lane").description("Alias of `sechroom lane` (kept for back-compat) \u2014 show this checkout's lane pin").option("--json", "machine output").action((opts, cmd) => showLane(Boolean(opts.json) || Boolean(cmd.optsWithGlobals().json)));
|
|
4108
4189
|
skills.command("set-workflow").description("Set your per-operator workflow defaults (server-side; follows you across tenants)").option("--default-code-lane <id>", "personal default code lane (e.g. claude-code-chris)").option("--default-design-lane <id>", "personal default design lane (e.g. claude-design-chris)").option("--handover-recipient <id>", "your daily-handover counterparty (e.g. andy)").option("--json", "machine output").action(async (opts, cmd) => {
|
|
4109
4190
|
if (!opts.defaultCodeLane && !opts.defaultDesignLane && !opts.handoverRecipient)
|
|
4110
4191
|
fail("Provide at least one of --default-code-lane / --default-design-lane / --handover-recipient.");
|
|
@@ -4391,6 +4472,7 @@ registerSetup(program);
|
|
|
4391
4472
|
registerOnboard(program);
|
|
4392
4473
|
registerSweep(program);
|
|
4393
4474
|
registerSkills(program);
|
|
4475
|
+
registerLane(program);
|
|
4394
4476
|
registerReset(program);
|
|
4395
4477
|
program.parseAsync().catch((err2) => {
|
|
4396
4478
|
process.stderr.write(`error: ${err2 instanceof Error ? err2.message : String(err2)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sechroom/cli",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.194-rc.5f6d8f6f",
|
|
4
4
|
"description": "Sechroom CLI — a thin, generated client over the Sechroom HTTP API. An agent/human surface alongside MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|