@sechroom/cli 2026.7.5-rc.ef6a4180 → 2026.7.6-rc.a2828c37
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 +93 -20
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -439,6 +439,9 @@ var quiet = false;
|
|
|
439
439
|
function setQuiet(q) {
|
|
440
440
|
quiet = q;
|
|
441
441
|
}
|
|
442
|
+
function isQuiet() {
|
|
443
|
+
return quiet;
|
|
444
|
+
}
|
|
442
445
|
function colorOn() {
|
|
443
446
|
return !quiet && !process.env.NO_COLOR && process.env.FORCE_COLOR !== "0" && Boolean(process.stdout.isTTY);
|
|
444
447
|
}
|
|
@@ -615,6 +618,22 @@ function emitAction(summary, data, json) {
|
|
|
615
618
|
process.stdout.write(`${ok("\u2713")} ${summary}
|
|
616
619
|
`);
|
|
617
620
|
}
|
|
621
|
+
var GOVERNANCE_QUEUED_PROBLEM_TYPE = "https://sechroom.dev/problems/governance-review-queued";
|
|
622
|
+
function isGovernanceQueued(body) {
|
|
623
|
+
return typeof body === "object" && body !== null && "type" in body && body.type === GOVERNANCE_QUEUED_PROBLEM_TYPE;
|
|
624
|
+
}
|
|
625
|
+
function formatQueuedForApproval(body, json) {
|
|
626
|
+
if (json) return JSON.stringify(body) + "\n";
|
|
627
|
+
const b = body ?? {};
|
|
628
|
+
const detail = typeof b.detail === "string" ? b.detail : void 0;
|
|
629
|
+
const requestId = typeof b.requestId === "string" ? b.requestId : void 0;
|
|
630
|
+
const message = detail ?? "This change requires operator approval before it takes effect.";
|
|
631
|
+
let out = `${warn("\u29D7")} Pending approval \u2014 ${message}
|
|
632
|
+
`;
|
|
633
|
+
if (requestId) out += ` ${style.dim(`request: ${requestId}`)}
|
|
634
|
+
`;
|
|
635
|
+
return out;
|
|
636
|
+
}
|
|
618
637
|
async function runApi(label, fn) {
|
|
619
638
|
const s = spinner(label);
|
|
620
639
|
let res;
|
|
@@ -624,6 +643,12 @@ async function runApi(label, fn) {
|
|
|
624
643
|
s.fail();
|
|
625
644
|
fail(err2);
|
|
626
645
|
}
|
|
646
|
+
const queuedBody = res.data ?? res.error;
|
|
647
|
+
if (res.response?.status === 202 && isGovernanceQueued(queuedBody)) {
|
|
648
|
+
s.stop();
|
|
649
|
+
process.stdout.write(formatQueuedForApproval(queuedBody, isQuiet()));
|
|
650
|
+
process.exit(0);
|
|
651
|
+
}
|
|
627
652
|
const httpFailed = res.response !== void 0 && !res.response.ok;
|
|
628
653
|
if (res.error !== void 0 && res.error !== null || httpFailed) {
|
|
629
654
|
s.fail();
|
|
@@ -1403,10 +1428,15 @@ var CLAUDE_HOOK_COMMANDS = {
|
|
|
1403
1428
|
SessionStart: "sechroom hook session-start",
|
|
1404
1429
|
PreCompact: "sechroom hook pre-compact",
|
|
1405
1430
|
SessionEnd: "sechroom hook session-end",
|
|
1406
|
-
// WLP telemetry tap (D-WLP-10) — per-turn executor self-report.
|
|
1407
|
-
//
|
|
1408
|
-
//
|
|
1409
|
-
|
|
1431
|
+
// WLP telemetry tap (D-WLP-10 + FR-352 Tier 1) — per-turn executor self-report. The one
|
|
1432
|
+
// `telemetry hook` verb dispatches on hook_event_name: Stop/SubagentStop → parsed (token/context) +
|
|
1433
|
+
// terminal (turn end), Notification/PermissionDenied → approval. No-op (exit 0) unless this checkout
|
|
1434
|
+
// is bound via `sechroom telemetry bind`, so it's safe to wire for every Claude install; an event a
|
|
1435
|
+
// given Claude Code version doesn't know is inert (never fires). Claude-only.
|
|
1436
|
+
Stop: "sechroom telemetry hook",
|
|
1437
|
+
SubagentStop: "sechroom telemetry hook",
|
|
1438
|
+
Notification: "sechroom telemetry hook",
|
|
1439
|
+
PermissionDenied: "sechroom telemetry hook"
|
|
1410
1440
|
};
|
|
1411
1441
|
var CODEX_HOOK_COMMANDS = {
|
|
1412
1442
|
SessionStart: "sechroom hook session-start",
|
|
@@ -5806,7 +5836,7 @@ function registerTelemetry(program2) {
|
|
|
5806
5836
|
);
|
|
5807
5837
|
});
|
|
5808
5838
|
telemetry.command("hook").description(
|
|
5809
|
-
"Per-turn telemetry self-report for
|
|
5839
|
+
"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."
|
|
5810
5840
|
).action(async (_opts, cmd) => {
|
|
5811
5841
|
try {
|
|
5812
5842
|
const raw = await readStdin2();
|
|
@@ -5815,21 +5845,10 @@ function registerTelemetry(program2) {
|
|
|
5815
5845
|
const binding = findBinding(cwd);
|
|
5816
5846
|
if (!binding) return process.exit(0);
|
|
5817
5847
|
const usage = input.transcript_path ? parseTranscript(input.transcript_path) : null;
|
|
5818
|
-
|
|
5848
|
+
const events = buildHookEvents(input, usage, binding.taskId);
|
|
5849
|
+
if (events.length === 0) return process.exit(0);
|
|
5819
5850
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
5820
|
-
await postTelemetry(cfg, binding.decompositionId,
|
|
5821
|
-
{
|
|
5822
|
-
taskId: binding.taskId,
|
|
5823
|
-
kind: "Parsed",
|
|
5824
|
-
tokensIn: usage.tokensIn,
|
|
5825
|
-
tokensOut: usage.tokensOut,
|
|
5826
|
-
contextUsed: usage.contextUsed,
|
|
5827
|
-
contextWindow: usage.contextWindow,
|
|
5828
|
-
text: null,
|
|
5829
|
-
approvalState: null,
|
|
5830
|
-
verdict: null
|
|
5831
|
-
}
|
|
5832
|
-
]);
|
|
5851
|
+
await postTelemetry(cfg, binding.decompositionId, events);
|
|
5833
5852
|
return process.exit(0);
|
|
5834
5853
|
} catch {
|
|
5835
5854
|
return process.exit(0);
|
|
@@ -5857,7 +5876,12 @@ function registerTelemetry(program2) {
|
|
|
5857
5876
|
scope,
|
|
5858
5877
|
cwd
|
|
5859
5878
|
});
|
|
5860
|
-
const commands = {
|
|
5879
|
+
const commands = {
|
|
5880
|
+
Stop: "sechroom telemetry hook",
|
|
5881
|
+
SubagentStop: "sechroom telemetry hook",
|
|
5882
|
+
Notification: "sechroom telemetry hook",
|
|
5883
|
+
PermissionDenied: "sechroom telemetry hook"
|
|
5884
|
+
};
|
|
5861
5885
|
try {
|
|
5862
5886
|
const multi = targets.length > 1;
|
|
5863
5887
|
const results = targets.map((t) => {
|
|
@@ -5958,6 +5982,55 @@ function windowFor(model, contextUsed = 0) {
|
|
|
5958
5982
|
if (m.includes("[1m]") || m.includes("-1m")) return 1e6;
|
|
5959
5983
|
return contextUsed > 2e5 ? 1e6 : 2e5;
|
|
5960
5984
|
}
|
|
5985
|
+
function buildHookEvents(input, usage, taskId) {
|
|
5986
|
+
const events = [];
|
|
5987
|
+
const base = (kind, over) => ({
|
|
5988
|
+
taskId,
|
|
5989
|
+
kind,
|
|
5990
|
+
tokensIn: null,
|
|
5991
|
+
tokensOut: null,
|
|
5992
|
+
contextUsed: null,
|
|
5993
|
+
contextWindow: null,
|
|
5994
|
+
text: null,
|
|
5995
|
+
approvalState: null,
|
|
5996
|
+
verdict: null,
|
|
5997
|
+
...over
|
|
5998
|
+
});
|
|
5999
|
+
if (usage) {
|
|
6000
|
+
events.push(
|
|
6001
|
+
base("Parsed", {
|
|
6002
|
+
tokensIn: usage.tokensIn,
|
|
6003
|
+
tokensOut: usage.tokensOut,
|
|
6004
|
+
contextUsed: usage.contextUsed,
|
|
6005
|
+
contextWindow: usage.contextWindow
|
|
6006
|
+
})
|
|
6007
|
+
);
|
|
6008
|
+
}
|
|
6009
|
+
switch (input.hook_event_name) {
|
|
6010
|
+
case "PermissionDenied":
|
|
6011
|
+
events.push(
|
|
6012
|
+
base("Approval", {
|
|
6013
|
+
approvalState: "denied",
|
|
6014
|
+
text: input.tool_name ?? input.message ?? null
|
|
6015
|
+
})
|
|
6016
|
+
);
|
|
6017
|
+
break;
|
|
6018
|
+
case "Notification":
|
|
6019
|
+
if (isPermissionNotification(input))
|
|
6020
|
+
events.push(base("Approval", { text: input.message ?? null }));
|
|
6021
|
+
break;
|
|
6022
|
+
case "Stop":
|
|
6023
|
+
case "SubagentStop":
|
|
6024
|
+
events.push(base("Terminal", { text: input.last_assistant_message ?? null }));
|
|
6025
|
+
break;
|
|
6026
|
+
}
|
|
6027
|
+
return events;
|
|
6028
|
+
}
|
|
6029
|
+
function isPermissionNotification(input) {
|
|
6030
|
+
const t = (input.notification_type ?? input.type ?? "").toLowerCase();
|
|
6031
|
+
if (t) return t.includes("permission");
|
|
6032
|
+
return (input.message ?? "").toLowerCase().includes("permission");
|
|
6033
|
+
}
|
|
5961
6034
|
async function readStdin2() {
|
|
5962
6035
|
if (process.stdin.isTTY) return "";
|
|
5963
6036
|
const chunks = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sechroom/cli",
|
|
3
|
-
"version": "2026.7.
|
|
3
|
+
"version": "2026.7.6-rc.a2828c37",
|
|
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,12 +36,14 @@
|
|
|
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",
|
|
43
44
|
"build": "tsup src/index.ts --format esm --target node20 --clean",
|
|
44
45
|
"dev": "tsx src/index.ts",
|
|
46
|
+
"test": "node --import tsx --test \"src/**/*.test.ts\"",
|
|
45
47
|
"check-types": "tsc --noEmit"
|
|
46
48
|
}
|
|
47
49
|
}
|