@sechroom/cli 2026.7.24 → 2026.7.26

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 +66 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1031,7 +1031,7 @@ async function resolveInstruction(cfg, section, personalWorkspaceId) {
1031
1031
  const { data } = await client.POST("/memories/search", {
1032
1032
  body: { query: null, textQuery: null, semanticQuery: null, hybrid: false, limit: 1, includeArchived: false, includeSystem: false, tags }
1033
1033
  });
1034
- const hits = data ?? [];
1034
+ const hits = data?.items ?? [];
1035
1035
  if (hits.length === 0) continue;
1036
1036
  const templateId = hits[0].id;
1037
1037
  const template = await fetchMemoryFields(cfg, templateId);
@@ -1041,7 +1041,7 @@ async function resolveInstruction(cfg, section, personalWorkspaceId) {
1041
1041
  const { data: ovr } = await client.POST("/memories/search", {
1042
1042
  body: { query: null, textQuery: null, semanticQuery: null, hybrid: false, limit: 1, includeArchived: false, includeSystem: false, tags: ["sechroom:role:override", `sechroom:template-ref:${templateId}`], owner: { type: "Workspace", id: personalWorkspaceId } }
1043
1043
  });
1044
- const ovrHits = ovr ?? [];
1044
+ const ovrHits = ovr?.items ?? [];
1045
1045
  if (ovrHits.length > 0) {
1046
1046
  const override = await fetchMemoryFields(cfg, ovrHits[0].id);
1047
1047
  if (typeof override?.text === "string" && override.text.length > 0) {
@@ -3557,6 +3557,7 @@ Examples:
3557
3557
  }
3558
3558
 
3559
3559
  // src/commands/decomposition.ts
3560
+ import { readFile } from "fs/promises";
3560
3561
  function registerDecomposition(program2) {
3561
3562
  const decomposition = program2.command("decomposition").description(
3562
3563
  "Drive a WLP decomposition: decompose a brief, then execute / accept / reject"
@@ -3566,6 +3567,8 @@ function registerDecomposition(program2) {
3566
3567
  `
3567
3568
  Examples:
3568
3569
  $ sechroom decomposition decompose mem_XXXX
3570
+ $ sechroom decomposition from-plan mem_XXXX --file plan.json
3571
+ $ sechroom decomposition plan wlp_XXXX
3569
3572
  $ sechroom decomposition execute sug_XXXX
3570
3573
  $ sechroom decomposition publish-run sug_XXXX
3571
3574
  $ sechroom decomposition accept sug_XXXX
@@ -3588,6 +3591,47 @@ Examples:
3588
3591
  cmd.optsWithGlobals().json
3589
3592
  );
3590
3593
  });
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
+ });
3591
3635
  decomposition.command("execute <decompositionId>").description(
3592
3636
  "Execute a decomposition's Task graph (POST /decompositions/{id}/execute)"
3593
3637
  ).action(async (decompositionId, _opts, cmd) => {
@@ -3657,6 +3701,24 @@ Examples:
3657
3701
  );
3658
3702
  });
3659
3703
  }
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
+ }
3660
3722
 
3661
3723
  // src/commands/filing.ts
3662
3724
  function registerFiling(program2) {
@@ -6491,7 +6553,7 @@ function registerTelemetry(program2) {
6491
6553
  "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."
6492
6554
  ).action(async (_opts, cmd) => {
6493
6555
  try {
6494
- const raw = await readStdin2();
6556
+ const raw = await readStdin3();
6495
6557
  const input = parseHookInput2(raw);
6496
6558
  const cwd = input.cwd ?? process.cwd();
6497
6559
  const binding = findBinding(cwd);
@@ -6683,7 +6745,7 @@ function isPermissionNotification(input) {
6683
6745
  if (t) return t.includes("permission");
6684
6746
  return (input.message ?? "").toLowerCase().includes("permission");
6685
6747
  }
6686
- async function readStdin2() {
6748
+ async function readStdin3() {
6687
6749
  if (process.stdin.isTTY) return "";
6688
6750
  const chunks = [];
6689
6751
  for await (const chunk of process.stdin) chunks.push(chunk);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.7.24",
3
+ "version": "2026.7.26",
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",