@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.
Files changed (2) hide show
  1. package/dist/index.js +12 -145
  2. 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 refreshExecutorInstance(
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 refreshExecutorInstance(cfg, id, opts.ttl);
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 refreshExecutorInstance(cfg, id, opts.ttl);
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 refreshExecutorInstance(cfg, id, ttlSeconds) {
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/{instanceId}/accept)").action(async (id, _opts, cmd) => {
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/{instanceId}/accept", {
5992
- params: { path: { instanceId: id } },
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/{instanceId}/reject)").option("--reason <reason>", "Why it's being rejected").option("--reason-code <code>", "Structured reason code").action(async (id, opts, cmd) => {
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/{instanceId}/reject", {
6003
- params: { path: { instanceId: id } },
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 readStdin3();
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 readStdin3() {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.7.21-rc.59d9df67",
3
+ "version": "2026.7.21",
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",