@sechroom/cli 2026.7.21-rc.59d9df67 → 2026.7.21
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 +12 -145
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2213,7 +2213,7 @@ function registerExecutor(program2) {
|
|
|
2213
2213
|
);
|
|
2214
2214
|
});
|
|
2215
2215
|
executor.command("refresh <id>").description("Refresh one advertisement lease once").option("--ttl <seconds>", "Advertisement TTL (30-600)", parseInteger, 120).action(async (id, opts, cmd) => {
|
|
2216
|
-
const data = await
|
|
2216
|
+
const data = await refresh(
|
|
2217
2217
|
resolveConfig(cmd.optsWithGlobals()),
|
|
2218
2218
|
id,
|
|
2219
2219
|
opts.ttl
|
|
@@ -2224,13 +2224,13 @@ function registerExecutor(program2) {
|
|
|
2224
2224
|
if (opts.interval >= opts.ttl)
|
|
2225
2225
|
fail("heartbeat interval must be shorter than the TTL");
|
|
2226
2226
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
2227
|
-
await
|
|
2227
|
+
await refresh(cfg, id, opts.ttl);
|
|
2228
2228
|
process.stderr.write(
|
|
2229
2229
|
style.green("executor heartbeat active") + style.dim(` \u2014 ${id}
|
|
2230
2230
|
`)
|
|
2231
2231
|
);
|
|
2232
2232
|
await holdHeartbeat(async () => {
|
|
2233
|
-
await
|
|
2233
|
+
await refresh(cfg, id, opts.ttl);
|
|
2234
2234
|
}, opts.interval * 1e3);
|
|
2235
2235
|
});
|
|
2236
2236
|
executor.command("offers <id>").description("List live dispatch offers addressed to this exact instance").action(async (id, _opts, cmd) => {
|
|
@@ -2275,7 +2275,7 @@ function parseTransport(value) {
|
|
|
2275
2275
|
return fail("transport must be push or pull");
|
|
2276
2276
|
}
|
|
2277
2277
|
}
|
|
2278
|
-
async function
|
|
2278
|
+
async function refresh(cfg, id, ttlSeconds) {
|
|
2279
2279
|
return api(
|
|
2280
2280
|
cfg,
|
|
2281
2281
|
`/me/executor-instances/${encodeURIComponent(id)}/refresh`,
|
|
@@ -2404,10 +2404,6 @@ function registerChannel(program2) {
|
|
|
2404
2404
|
);
|
|
2405
2405
|
await drain();
|
|
2406
2406
|
const stopReconciliation = startOfferReconciliation(drain);
|
|
2407
|
-
const stopHeartbeat = startExecutorHeartbeat(
|
|
2408
|
-
() => refreshExecutorInstance(cfg, instance.id, located.state.ttlSeconds),
|
|
2409
|
-
located.state.refreshAfterSeconds * 1e3
|
|
2410
|
-
);
|
|
2411
2407
|
if (json) {
|
|
2412
2408
|
emit(
|
|
2413
2409
|
{
|
|
@@ -2431,7 +2427,6 @@ function registerChannel(program2) {
|
|
|
2431
2427
|
await holdOpen(conn);
|
|
2432
2428
|
} finally {
|
|
2433
2429
|
stopReconciliation();
|
|
2434
|
-
stopHeartbeat();
|
|
2435
2430
|
}
|
|
2436
2431
|
});
|
|
2437
2432
|
withFilterOpts(
|
|
@@ -2474,10 +2469,6 @@ function registerChannel(program2) {
|
|
|
2474
2469
|
);
|
|
2475
2470
|
await drain();
|
|
2476
2471
|
const stopReconciliation = startOfferReconciliation(drain);
|
|
2477
|
-
const stopHeartbeat = startExecutorHeartbeat(
|
|
2478
|
-
() => refreshExecutorInstance(cfg, instance.id, located.state.ttlSeconds),
|
|
2479
|
-
located.state.refreshAfterSeconds * 1e3
|
|
2480
|
-
);
|
|
2481
2472
|
process.stderr.write(
|
|
2482
2473
|
style.dim(
|
|
2483
2474
|
`sechroom channel (mcp) \u2014 tenant ${cfg.tenant}, executor ${located.state.instanceKey}
|
|
@@ -2488,7 +2479,6 @@ function registerChannel(program2) {
|
|
|
2488
2479
|
await holdOpen(conn);
|
|
2489
2480
|
} finally {
|
|
2490
2481
|
stopReconciliation();
|
|
2491
|
-
stopHeartbeat();
|
|
2492
2482
|
}
|
|
2493
2483
|
});
|
|
2494
2484
|
channel.command("install").description(
|
|
@@ -2594,16 +2584,6 @@ function startOfferReconciliation(drain, intervalMilliseconds = 5e3, dependencie
|
|
|
2594
2584
|
}, intervalMilliseconds);
|
|
2595
2585
|
return () => cancel(timer);
|
|
2596
2586
|
}
|
|
2597
|
-
function startExecutorHeartbeat(refresh, intervalMilliseconds, dependencies = {}) {
|
|
2598
|
-
const schedule = dependencies.setInterval ?? setInterval;
|
|
2599
|
-
const cancel = dependencies.clearInterval ?? clearInterval;
|
|
2600
|
-
const onError = dependencies.onError ?? ((error) => process.stderr.write(err(`channel heartbeat failed: ${String(error)}
|
|
2601
|
-
`)));
|
|
2602
|
-
const timer = schedule(() => {
|
|
2603
|
-
void refresh().catch(onError);
|
|
2604
|
-
}, intervalMilliseconds);
|
|
2605
|
-
return () => cancel(timer);
|
|
2606
|
-
}
|
|
2607
2587
|
async function drainClaims(cfg, executorInstanceId, deliver, dependencies = {}) {
|
|
2608
2588
|
const request = dependencies.request ?? api;
|
|
2609
2589
|
const sleep = dependencies.sleep ?? ((milliseconds) => new Promise((resolve3) => setTimeout(resolve3, milliseconds)));
|
|
@@ -3557,7 +3537,6 @@ Examples:
|
|
|
3557
3537
|
}
|
|
3558
3538
|
|
|
3559
3539
|
// src/commands/decomposition.ts
|
|
3560
|
-
import { readFile } from "fs/promises";
|
|
3561
3540
|
function registerDecomposition(program2) {
|
|
3562
3541
|
const decomposition = program2.command("decomposition").description(
|
|
3563
3542
|
"Drive a WLP decomposition: decompose a brief, then execute / accept / reject"
|
|
@@ -3567,8 +3546,6 @@ function registerDecomposition(program2) {
|
|
|
3567
3546
|
`
|
|
3568
3547
|
Examples:
|
|
3569
3548
|
$ sechroom decomposition decompose mem_XXXX
|
|
3570
|
-
$ sechroom decomposition from-plan mem_XXXX --file plan.json
|
|
3571
|
-
$ sechroom decomposition plan wlp_XXXX
|
|
3572
3549
|
$ sechroom decomposition execute sug_XXXX
|
|
3573
3550
|
$ sechroom decomposition publish-run sug_XXXX
|
|
3574
3551
|
$ sechroom decomposition accept sug_XXXX
|
|
@@ -3591,47 +3568,6 @@ Examples:
|
|
|
3591
3568
|
cmd.optsWithGlobals().json
|
|
3592
3569
|
);
|
|
3593
3570
|
});
|
|
3594
|
-
decomposition.command("from-plan <briefId>").description(
|
|
3595
|
-
"Create a decomposition from a hand-authored JSON plan; tasks may carry Unix-millisecond wakeAtMs"
|
|
3596
|
-
).requiredOption(
|
|
3597
|
-
"--file <path>",
|
|
3598
|
-
"JSON file containing { project, tasks, source? }; use - for stdin"
|
|
3599
|
-
).action(async (briefId, opts, cmd) => {
|
|
3600
|
-
const raw = opts.file === "-" ? await readStdin2() : await readFile(opts.file, "utf8");
|
|
3601
|
-
const body = parsePlanInput(raw, opts.file);
|
|
3602
|
-
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3603
|
-
const data = await runApi(
|
|
3604
|
-
"Creating decomposition from plan",
|
|
3605
|
-
async () => {
|
|
3606
|
-
const client = await makeClient(cfg);
|
|
3607
|
-
return client.POST("/work-briefs/{id}/decompose-from-plan", {
|
|
3608
|
-
params: { path: { id: briefId } },
|
|
3609
|
-
body
|
|
3610
|
-
});
|
|
3611
|
-
}
|
|
3612
|
-
);
|
|
3613
|
-
emitAction(
|
|
3614
|
-
`created ${style.bold(data.suggestionId)} from ${data.taskCount} hand-authored task(s)`,
|
|
3615
|
-
data,
|
|
3616
|
-
cmd.optsWithGlobals().json
|
|
3617
|
-
);
|
|
3618
|
-
});
|
|
3619
|
-
decomposition.command("plan <decompositionId>").description(
|
|
3620
|
-
"Inspect the compiled plan, including each scheduled step's Unix-millisecond wakeAtMs"
|
|
3621
|
-
).action(async (decompositionId, _opts, cmd) => {
|
|
3622
|
-
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3623
|
-
const data = await runApi("Reading decomposition plan", async () => {
|
|
3624
|
-
const client = await makeClient(cfg);
|
|
3625
|
-
return client.GET("/decompositions/{id}/plan", {
|
|
3626
|
-
params: { path: { id: decompositionId } }
|
|
3627
|
-
});
|
|
3628
|
-
});
|
|
3629
|
-
emitAction(
|
|
3630
|
-
`read ${style.bold(decompositionId)} plan (${data.steps.length} step(s))`,
|
|
3631
|
-
data,
|
|
3632
|
-
cmd.optsWithGlobals().json
|
|
3633
|
-
);
|
|
3634
|
-
});
|
|
3635
3571
|
decomposition.command("execute <decompositionId>").description(
|
|
3636
3572
|
"Execute a decomposition's Task graph (POST /decompositions/{id}/execute)"
|
|
3637
3573
|
).action(async (decompositionId, _opts, cmd) => {
|
|
@@ -3701,24 +3637,6 @@ Examples:
|
|
|
3701
3637
|
);
|
|
3702
3638
|
});
|
|
3703
3639
|
}
|
|
3704
|
-
function parsePlanInput(raw, sourceName = "plan input") {
|
|
3705
|
-
let value;
|
|
3706
|
-
try {
|
|
3707
|
-
value = JSON.parse(raw);
|
|
3708
|
-
} catch (error) {
|
|
3709
|
-
throw new Error(
|
|
3710
|
-
`${sourceName} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
3711
|
-
);
|
|
3712
|
-
}
|
|
3713
|
-
if (!value || typeof value !== "object" || !Array.isArray(value.tasks))
|
|
3714
|
-
throw new Error(`${sourceName} must contain an object with a tasks array`);
|
|
3715
|
-
return value;
|
|
3716
|
-
}
|
|
3717
|
-
async function readStdin2() {
|
|
3718
|
-
const chunks = [];
|
|
3719
|
-
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
3720
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
3721
|
-
}
|
|
3722
3640
|
|
|
3723
3641
|
// src/commands/filing.ts
|
|
3724
3642
|
function registerFiling(program2) {
|
|
@@ -5984,23 +5902,23 @@ Examples:
|
|
|
5984
5902
|
});
|
|
5985
5903
|
emit(data, cmd.optsWithGlobals().json);
|
|
5986
5904
|
});
|
|
5987
|
-
suggestion.command("accept <id>").description("Accept a suggestion (POST /relationship-suggestions/{
|
|
5905
|
+
suggestion.command("accept <id>").description("Accept a suggestion (POST /relationship-suggestions/{id}/accept)").action(async (id, _opts, cmd) => {
|
|
5988
5906
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
5989
5907
|
const data = await runApi("Accepting suggestion", async () => {
|
|
5990
5908
|
const client = await makeClient(cfg);
|
|
5991
|
-
return client.POST("/relationship-suggestions/{
|
|
5992
|
-
params: { path: {
|
|
5909
|
+
return client.POST("/relationship-suggestions/{id}/accept", {
|
|
5910
|
+
params: { path: { id } },
|
|
5993
5911
|
body: {}
|
|
5994
5912
|
});
|
|
5995
5913
|
});
|
|
5996
5914
|
emitAction(`accepted suggestion ${style.bold(id)}`, data, cmd.optsWithGlobals().json);
|
|
5997
5915
|
});
|
|
5998
|
-
suggestion.command("reject <id>").description("Reject a suggestion (POST /relationship-suggestions/{
|
|
5916
|
+
suggestion.command("reject <id>").description("Reject a suggestion (POST /relationship-suggestions/{id}/reject)").option("--reason <reason>", "Why it's being rejected").option("--reason-code <code>", "Structured reason code").action(async (id, opts, cmd) => {
|
|
5999
5917
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
6000
5918
|
const data = await runApi("Rejecting suggestion", async () => {
|
|
6001
5919
|
const client = await makeClient(cfg);
|
|
6002
|
-
return client.POST("/relationship-suggestions/{
|
|
6003
|
-
params: { path: {
|
|
5920
|
+
return client.POST("/relationship-suggestions/{id}/reject", {
|
|
5921
|
+
params: { path: { id } },
|
|
6004
5922
|
body: {
|
|
6005
5923
|
reason: opts.reason ?? null,
|
|
6006
5924
|
...opts.reasonCode ? { reasonCode: opts.reasonCode } : {}
|
|
@@ -6553,7 +6471,7 @@ function registerTelemetry(program2) {
|
|
|
6553
6471
|
"Per-turn telemetry self-report for Claude Code hooks \u2014 Stop/SubagentStop \u2192 parsed + terminal, Notification/PermissionDenied \u2192 approval (reads stdin; no-op unless bound). Fail-soft."
|
|
6554
6472
|
).action(async (_opts, cmd) => {
|
|
6555
6473
|
try {
|
|
6556
|
-
const raw = await
|
|
6474
|
+
const raw = await readStdin2();
|
|
6557
6475
|
const input = parseHookInput2(raw);
|
|
6558
6476
|
const cwd = input.cwd ?? process.cwd();
|
|
6559
6477
|
const binding = findBinding(cwd);
|
|
@@ -6745,7 +6663,7 @@ function isPermissionNotification(input) {
|
|
|
6745
6663
|
if (t) return t.includes("permission");
|
|
6746
6664
|
return (input.message ?? "").toLowerCase().includes("permission");
|
|
6747
6665
|
}
|
|
6748
|
-
async function
|
|
6666
|
+
async function readStdin2() {
|
|
6749
6667
|
if (process.stdin.isTTY) return "";
|
|
6750
6668
|
const chunks = [];
|
|
6751
6669
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
@@ -6975,56 +6893,6 @@ Examples:
|
|
|
6975
6893
|
});
|
|
6976
6894
|
}
|
|
6977
6895
|
|
|
6978
|
-
// src/commands/work-brief.ts
|
|
6979
|
-
function registerWorkBrief(program2) {
|
|
6980
|
-
const workBrief = program2.command("work-brief").description("Control an active work brief run");
|
|
6981
|
-
workBrief.addHelpText(
|
|
6982
|
-
"after",
|
|
6983
|
-
`
|
|
6984
|
-
Examples:
|
|
6985
|
-
$ sechroom work-brief pause mem_XXXX --reason-code operator-hold --source claude-code-chris
|
|
6986
|
-
$ sechroom work-brief resume mem_XXXX --reason-code operator-resume --source claude-code-chris --reason "Ready to continue"
|
|
6987
|
-
$ sechroom work-brief cancel mem_XXXX --reason-code operator-stopped --source claude-code-chris --reason "Work no longer required"`
|
|
6988
|
-
);
|
|
6989
|
-
registerLifecycleAction(workBrief, "pause");
|
|
6990
|
-
registerLifecycleAction(workBrief, "resume");
|
|
6991
|
-
registerLifecycleAction(workBrief, "cancel");
|
|
6992
|
-
}
|
|
6993
|
-
function registerLifecycleAction(workBrief, action) {
|
|
6994
|
-
const presentParticiple = action === "pause" ? "Pausing" : action === "resume" ? "Resuming" : "Cancelling";
|
|
6995
|
-
const pastTense = action === "pause" ? "paused" : action === "resume" ? "resumed" : "cancelled";
|
|
6996
|
-
workBrief.command(`${action} <briefId>`).description(`${capitalize(action)} an active work brief run`).requiredOption(
|
|
6997
|
-
"--reason-code <code>",
|
|
6998
|
-
"Stable machine-readable reason code"
|
|
6999
|
-
).requiredOption(
|
|
7000
|
-
"--source <source>",
|
|
7001
|
-
"Calling surface or lane recorded in the audit"
|
|
7002
|
-
).option("--reason <text>", "Optional human-readable reason").action(async (briefId, opts, cmd) => {
|
|
7003
|
-
const globals = cmd.optsWithGlobals();
|
|
7004
|
-
const cfg = resolveConfig(globals);
|
|
7005
|
-
const data = await runApi(`${presentParticiple} work brief`, async () => {
|
|
7006
|
-
const client = await makeClient(cfg);
|
|
7007
|
-
return client.POST("/work-briefs/{id}/lifecycle", {
|
|
7008
|
-
params: { path: { id: briefId } },
|
|
7009
|
-
body: {
|
|
7010
|
-
action,
|
|
7011
|
-
reasonCode: opts.reasonCode,
|
|
7012
|
-
source: opts.source,
|
|
7013
|
-
reasonText: opts.reason ?? null
|
|
7014
|
-
}
|
|
7015
|
-
});
|
|
7016
|
-
});
|
|
7017
|
-
emitAction(
|
|
7018
|
-
`${pastTense} work brief ${style.bold(briefId)} \u2192 ${data.outcome}`,
|
|
7019
|
-
data,
|
|
7020
|
-
globals.json
|
|
7021
|
-
);
|
|
7022
|
-
});
|
|
7023
|
-
}
|
|
7024
|
-
function capitalize(value) {
|
|
7025
|
-
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
7026
|
-
}
|
|
7027
|
-
|
|
7028
6896
|
// src/index.ts
|
|
7029
6897
|
function resolveVersion() {
|
|
7030
6898
|
try {
|
|
@@ -7187,7 +7055,6 @@ registerLookup(program);
|
|
|
7187
7055
|
registerRelationships(program);
|
|
7188
7056
|
registerWorkspace(program);
|
|
7189
7057
|
registerProject(program);
|
|
7190
|
-
registerWorkBrief(program);
|
|
7191
7058
|
registerDecomposition(program);
|
|
7192
7059
|
registerExecutor(program);
|
|
7193
7060
|
registerClose(program);
|
package/package.json
CHANGED