@sechroom/cli 2026.7.12 → 2026.7.13

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 +86 -20
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1403,10 +1403,15 @@ var CLAUDE_HOOK_COMMANDS = {
1403
1403
  SessionStart: "sechroom hook session-start",
1404
1404
  PreCompact: "sechroom hook pre-compact",
1405
1405
  SessionEnd: "sechroom hook session-end",
1406
- // WLP telemetry tap (D-WLP-10) — per-turn executor self-report. No-op (exit 0) unless this
1407
- // checkout is bound to a decomposition+task via `sechroom telemetry bind`, so it's safe to wire
1408
- // for every Claude install. Claude-only (it parses a Claude Code transcript).
1409
- Stop: "sechroom telemetry hook"
1406
+ // WLP telemetry tap (D-WLP-10 + FR-352 Tier 1) — per-turn executor self-report. The one
1407
+ // `telemetry hook` verb dispatches on hook_event_name: Stop/SubagentStop parsed (token/context) +
1408
+ // terminal (turn end), Notification/PermissionDenied → approval. No-op (exit 0) unless this checkout
1409
+ // is bound via `sechroom telemetry bind`, so it's safe to wire for every Claude install; an event a
1410
+ // given Claude Code version doesn't know is inert (never fires). Claude-only.
1411
+ Stop: "sechroom telemetry hook",
1412
+ SubagentStop: "sechroom telemetry hook",
1413
+ Notification: "sechroom telemetry hook",
1414
+ PermissionDenied: "sechroom telemetry hook"
1410
1415
  };
1411
1416
  var CODEX_HOOK_COMMANDS = {
1412
1417
  SessionStart: "sechroom hook session-start",
@@ -2891,6 +2896,7 @@ function registerDecomposition(program2) {
2891
2896
  Examples:
2892
2897
  $ sechroom decomposition decompose mem_XXXX
2893
2898
  $ sechroom decomposition execute sug_XXXX
2899
+ $ sechroom decomposition publish-run sug_XXXX
2894
2900
  $ sechroom decomposition accept sug_XXXX
2895
2901
  $ sechroom decomposition reject sug_XXXX --reason "wrong shape"`
2896
2902
  );
@@ -2928,6 +2934,23 @@ Examples:
2928
2934
  cmd.optsWithGlobals().json
2929
2935
  );
2930
2936
  });
2937
+ decomposition.command("publish-run <decompositionId>").description(
2938
+ "Publish an accepted decomposition's context pack on demand (POST /decompositions/{id}/publish-run)"
2939
+ ).action(async (decompositionId, _opts, cmd) => {
2940
+ const cfg = resolveConfig(cmd.optsWithGlobals());
2941
+ const data = await runApi("Publishing context pack", async () => {
2942
+ const client = await makeClient(cfg);
2943
+ return client.POST("/decompositions/{id}/publish-run", {
2944
+ params: { path: { id: decompositionId } },
2945
+ body: {}
2946
+ });
2947
+ });
2948
+ emitAction(
2949
+ `published ${style.bold(decompositionId)} \u2192 run ${style.bold(data.runRecordId)} (${data.outcome})`,
2950
+ data,
2951
+ cmd.optsWithGlobals().json
2952
+ );
2953
+ });
2931
2954
  decomposition.command("accept <decompositionId>").description(
2932
2955
  "Accept a Pending decomposition \u2014 promote + ratify its Tasks (POST /decompositions/{id}/accept)"
2933
2956
  ).action(async (decompositionId, _opts, cmd) => {
@@ -5788,7 +5811,7 @@ function registerTelemetry(program2) {
5788
5811
  );
5789
5812
  });
5790
5813
  telemetry.command("hook").description(
5791
- "Per-turn telemetry self-report for a Claude Code Stop hook (reads stdin; no-op unless bound). Fail-soft."
5814
+ "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."
5792
5815
  ).action(async (_opts, cmd) => {
5793
5816
  try {
5794
5817
  const raw = await readStdin2();
@@ -5797,21 +5820,10 @@ function registerTelemetry(program2) {
5797
5820
  const binding = findBinding(cwd);
5798
5821
  if (!binding) return process.exit(0);
5799
5822
  const usage = input.transcript_path ? parseTranscript(input.transcript_path) : null;
5800
- if (!usage) return process.exit(0);
5823
+ const events = buildHookEvents(input, usage, binding.taskId);
5824
+ if (events.length === 0) return process.exit(0);
5801
5825
  const cfg = resolveConfig(cmd.optsWithGlobals());
5802
- await postTelemetry(cfg, binding.decompositionId, [
5803
- {
5804
- taskId: binding.taskId,
5805
- kind: "Parsed",
5806
- tokensIn: usage.tokensIn,
5807
- tokensOut: usage.tokensOut,
5808
- contextUsed: usage.contextUsed,
5809
- contextWindow: usage.contextWindow,
5810
- text: null,
5811
- approvalState: null,
5812
- verdict: null
5813
- }
5814
- ]);
5826
+ await postTelemetry(cfg, binding.decompositionId, events);
5815
5827
  return process.exit(0);
5816
5828
  } catch {
5817
5829
  return process.exit(0);
@@ -5839,7 +5851,12 @@ function registerTelemetry(program2) {
5839
5851
  scope,
5840
5852
  cwd
5841
5853
  });
5842
- const commands = { Stop: "sechroom telemetry hook" };
5854
+ const commands = {
5855
+ Stop: "sechroom telemetry hook",
5856
+ SubagentStop: "sechroom telemetry hook",
5857
+ Notification: "sechroom telemetry hook",
5858
+ PermissionDenied: "sechroom telemetry hook"
5859
+ };
5843
5860
  try {
5844
5861
  const multi = targets.length > 1;
5845
5862
  const results = targets.map((t) => {
@@ -5940,6 +5957,55 @@ function windowFor(model, contextUsed = 0) {
5940
5957
  if (m.includes("[1m]") || m.includes("-1m")) return 1e6;
5941
5958
  return contextUsed > 2e5 ? 1e6 : 2e5;
5942
5959
  }
5960
+ function buildHookEvents(input, usage, taskId) {
5961
+ const events = [];
5962
+ const base = (kind, over) => ({
5963
+ taskId,
5964
+ kind,
5965
+ tokensIn: null,
5966
+ tokensOut: null,
5967
+ contextUsed: null,
5968
+ contextWindow: null,
5969
+ text: null,
5970
+ approvalState: null,
5971
+ verdict: null,
5972
+ ...over
5973
+ });
5974
+ if (usage) {
5975
+ events.push(
5976
+ base("Parsed", {
5977
+ tokensIn: usage.tokensIn,
5978
+ tokensOut: usage.tokensOut,
5979
+ contextUsed: usage.contextUsed,
5980
+ contextWindow: usage.contextWindow
5981
+ })
5982
+ );
5983
+ }
5984
+ switch (input.hook_event_name) {
5985
+ case "PermissionDenied":
5986
+ events.push(
5987
+ base("Approval", {
5988
+ approvalState: "denied",
5989
+ text: input.tool_name ?? input.message ?? null
5990
+ })
5991
+ );
5992
+ break;
5993
+ case "Notification":
5994
+ if (isPermissionNotification(input))
5995
+ events.push(base("Approval", { text: input.message ?? null }));
5996
+ break;
5997
+ case "Stop":
5998
+ case "SubagentStop":
5999
+ events.push(base("Terminal", { text: input.last_assistant_message ?? null }));
6000
+ break;
6001
+ }
6002
+ return events;
6003
+ }
6004
+ function isPermissionNotification(input) {
6005
+ const t = (input.notification_type ?? input.type ?? "").toLowerCase();
6006
+ if (t) return t.includes("permission");
6007
+ return (input.message ?? "").toLowerCase().includes("permission");
6008
+ }
5943
6009
  async function readStdin2() {
5944
6010
  if (process.stdin.isTTY) return "";
5945
6011
  const chunks = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.7.12",
3
+ "version": "2026.7.13",
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",
@@ -36,7 +36,8 @@
36
36
  "openapi-typescript": "^7.4.0",
37
37
  "tsup": "^8.3.0",
38
38
  "tsx": "^4.19.0",
39
- "typescript": "^5.6.0"
39
+ "typescript": "^5.6.0",
40
+ "typescript-7": "npm:typescript@^7.0.2"
40
41
  },
41
42
  "scripts": {
42
43
  "gen": "openapi-typescript \"${SECHROOM_OPENAPI_URL:-https://app.sechroom.ai/api/openapi/v1.json}\" -o src/generated/api.d.ts",