@sechroom/cli 2026.6.20 → 2026.6.22

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 +64 -40
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1574,7 +1574,7 @@ Examples:
1574
1574
  // src/commands/hook.ts
1575
1575
  import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1576
1576
  import { homedir as homedir3 } from "os";
1577
- import { dirname as dirname4, join as join4 } from "path";
1577
+ import { delimiter, dirname as dirname4, join as join4 } from "path";
1578
1578
 
1579
1579
  // src/sem.ts
1580
1580
  import { basename as basename2, dirname as dirname2, join as join2 } from "path";
@@ -2049,6 +2049,25 @@ function detectHookSurfaces(cwd) {
2049
2049
  if (detected.includes("codex")) surfaces.push("codex");
2050
2050
  return surfaces;
2051
2051
  }
2052
+ function isSechroomOnPath() {
2053
+ const pathEnv = process.env.PATH ?? "";
2054
+ if (!pathEnv) return false;
2055
+ const names = process.platform === "win32" ? ["sechroom.cmd", "sechroom.exe", "sechroom.bat", "sechroom"] : ["sechroom"];
2056
+ for (const dir of pathEnv.split(delimiter)) {
2057
+ if (!dir) continue;
2058
+ for (const name of names) {
2059
+ if (existsSync4(join4(dir, name))) return true;
2060
+ }
2061
+ }
2062
+ return false;
2063
+ }
2064
+ function warnIfSechroomNotOnPath(write = (s) => void process.stderr.write(s)) {
2065
+ if (isSechroomOnPath()) return false;
2066
+ write(
2067
+ "\n\u26A0 `sechroom` isn't on your PATH. The hooks run a bare `sechroom hook \u2026` command\n when your agent fires them, so a non-global install (npx / local) will fail at\n that point. Install globally so the command resolves:\n npm i -g @sechroom/cli\n"
2068
+ );
2069
+ return true;
2070
+ }
2052
2071
  function registerHook(program2) {
2053
2072
  const hook = program2.command("hook").description("Agent-lifecycle hook adapter (Claude Code / Codex) \u2014 bridges hooks to continuity");
2054
2073
  hook.addHelpText(
@@ -2160,6 +2179,7 @@ Fail-soft: no lane / no auth / no-or-partial intent file / API error -> exit 0,
2160
2179
  } else {
2161
2180
  process.stdout.write("\nRestart (or reload) your agent for the hooks to take effect.\n");
2162
2181
  }
2182
+ warnIfSechroomNotOnPath();
2163
2183
  return process.exit(0);
2164
2184
  });
2165
2185
  }
@@ -2588,9 +2608,47 @@ async function applyClient(cfg, setup, target, opts) {
2588
2608
  return actions;
2589
2609
  }
2590
2610
 
2611
+ // src/setup/hooks-offer.ts
2612
+ import { homedir as homedir4 } from "os";
2613
+ async function maybeOfferHooks(opts) {
2614
+ if (opts.dryRun) return;
2615
+ const cwd = opts.cwd ?? process.cwd();
2616
+ const surfaces = detectHookSurfaces(cwd);
2617
+ if (surfaces.length === 0) return;
2618
+ const names = surfaces.map((s) => HOOK_SURFACE_LABEL[s]).join(" + ");
2619
+ process.stderr.write(
2620
+ `
2621
+ Sechroom can wire continuity lifecycle hooks into ${style.bold(names)} so your agent
2622
+ auto-resumes where you left off and checkpoints working state before compacting.
2623
+ `
2624
+ );
2625
+ const install = opts.yes ? true : canPrompt() ? await promptYesNo(`Install the continuity hooks for ${names}?`) : false;
2626
+ if (!install) return;
2627
+ try {
2628
+ const installed = installHookSurfaces(surfaces, { dryRun: false, cwd, home: homedir4() });
2629
+ let changed = false;
2630
+ for (const { surface, results } of installed) {
2631
+ for (const r of results) {
2632
+ if (r.status !== "current") changed = true;
2633
+ const verb = r.status === "current" ? "already configured" : r.status === "created" ? "created" : "updated";
2634
+ process.stderr.write(`${style.green("\u2713")} ${HOOK_SURFACE_LABEL[surface]}: ${r.path} (${verb})
2635
+ `);
2636
+ }
2637
+ }
2638
+ if (changed) {
2639
+ process.stderr.write(`${style.dim("Restart (or reload) your agent for the hooks to take effect.")}
2640
+ `);
2641
+ }
2642
+ warnIfSechroomNotOnPath();
2643
+ } catch (err2) {
2644
+ process.stderr.write(`${style.dim(`(skipped hook install: ${err2.message})`)}
2645
+ `);
2646
+ }
2647
+ }
2648
+
2591
2649
  // src/setup/skills-offer.ts
2592
2650
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
2593
- import { homedir as homedir4 } from "os";
2651
+ import { homedir as homedir5 } from "os";
2594
2652
  import { join as join5 } from "path";
2595
2653
 
2596
2654
  // src/setup/lane-pin.ts
@@ -2706,7 +2764,7 @@ async function maybeOfferSkills(cfg, personalWorkspaceId, opts) {
2706
2764
  Found ${style.bold(String(names.length))} operator skill(s) installed in your workspace: ${names.join(", ")}.
2707
2765
  `
2708
2766
  );
2709
- const dir = join5(homedir4(), ".claude", "skills");
2767
+ const dir = join5(homedir5(), ".claude", "skills");
2710
2768
  const materialise = opts.yes ? true : canPrompt() ? await promptYesNo(`Write them to ${dir}/ so ${surface} can use them?`) : false;
2711
2769
  if (!materialise) return;
2712
2770
  const written = [];
@@ -2810,6 +2868,9 @@ Examples:
2810
2868
  if (!json && !opts.dryRun && !opts.mcpOnly) {
2811
2869
  await maybeOfferSkills(cfg, personalWorkspaceId, { yes: false, dryRun: Boolean(opts.dryRun), surface: "claude-code" });
2812
2870
  }
2871
+ if (!json && !opts.dryRun && !opts.mcpOnly) {
2872
+ await maybeOfferHooks({ yes: false, dryRun: Boolean(opts.dryRun), cwd: process.cwd() });
2873
+ }
2813
2874
  if (json) {
2814
2875
  emit({ dryRun: Boolean(opts.dryRun), clients: result }, true);
2815
2876
  return;
@@ -2865,43 +2926,6 @@ async function runClients(clients, cmd, opts) {
2865
2926
  process.stdout.write(opts.dryRun ? "\n(dry run \u2014 nothing written)\n" : "\nDone.\n");
2866
2927
  }
2867
2928
 
2868
- // src/setup/hooks-offer.ts
2869
- import { homedir as homedir5 } from "os";
2870
- async function maybeOfferHooks(opts) {
2871
- if (opts.dryRun) return;
2872
- const cwd = opts.cwd ?? process.cwd();
2873
- const surfaces = detectHookSurfaces(cwd);
2874
- if (surfaces.length === 0) return;
2875
- const names = surfaces.map((s) => HOOK_SURFACE_LABEL[s]).join(" + ");
2876
- process.stderr.write(
2877
- `
2878
- Sechroom can wire continuity lifecycle hooks into ${style.bold(names)} so your agent
2879
- auto-resumes where you left off and checkpoints working state before compacting.
2880
- `
2881
- );
2882
- const install = opts.yes ? true : canPrompt() ? await promptYesNo(`Install the continuity hooks for ${names}?`) : false;
2883
- if (!install) return;
2884
- try {
2885
- const installed = installHookSurfaces(surfaces, { dryRun: false, cwd, home: homedir5() });
2886
- let changed = false;
2887
- for (const { surface, results } of installed) {
2888
- for (const r of results) {
2889
- if (r.status !== "current") changed = true;
2890
- const verb = r.status === "current" ? "already configured" : r.status === "created" ? "created" : "updated";
2891
- process.stderr.write(`${style.green("\u2713")} ${HOOK_SURFACE_LABEL[surface]}: ${r.path} (${verb})
2892
- `);
2893
- }
2894
- }
2895
- if (changed) {
2896
- process.stderr.write(`${style.dim("Restart (or reload) your agent for the hooks to take effect.")}
2897
- `);
2898
- }
2899
- } catch (err2) {
2900
- process.stderr.write(`${style.dim(`(skipped hook install: ${err2.message})`)}
2901
- `);
2902
- }
2903
- }
2904
-
2905
2929
  // src/commands/onboard.ts
2906
2930
  var DEFAULT_BASE_URL2 = "https://app.sechroom.ai/api";
2907
2931
  function systemTimezone() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.6.20",
3
+ "version": "2026.6.22",
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",