@dadado/agent-kit-cli 5.17.0 → 6.0.0

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 (62) hide show
  1. package/LICENSE +201 -74
  2. package/NOTICE +2 -0
  3. package/README.md +3 -3
  4. package/dashboard/README.md +10 -1
  5. package/dashboard/dashboard-data.mjs +23 -13
  6. package/dashboard/dashboard.html +58 -0
  7. package/dashboard/lib/processes.mjs +1 -1
  8. package/dashboard/lib/run-logs.d.mts +34 -0
  9. package/dashboard/lib/run-logs.mjs +218 -0
  10. package/dashboard/lib/semantic-model.mjs +4 -3
  11. package/dashboard/serve.mjs +4 -4
  12. package/dashboard/start-broadcast.mjs +1 -1
  13. package/dashboard/start.mjs +1 -1
  14. package/dist/{add-HTYIFKMN.js → add-YTCDLPUS.js} +4 -4
  15. package/dist/{chunk-SMGFN3Z4.js → chunk-2FQX2O4I.js} +4 -4
  16. package/dist/{chunk-PNG7LO2F.js → chunk-3DGTPONS.js} +1 -1
  17. package/dist/{chunk-VY7MTPJ2.js → chunk-426GITN7.js} +1 -1
  18. package/dist/{chunk-2IPXQFJE.js → chunk-4CRBUEJ6.js} +2 -2
  19. package/dist/{chunk-STGFBAYT.js → chunk-4U7DLAQH.js} +11 -19
  20. package/dist/{chunk-77V75A7O.js → chunk-5B4DVO6C.js} +1 -1
  21. package/dist/{chunk-4IWG5CVE.js → chunk-B3VR5YBQ.js} +10 -5
  22. package/dist/{chunk-OUQZC744.js → chunk-B5CH47OS.js} +852 -74
  23. package/dist/{chunk-2RDRMGD3.js → chunk-BBVBYQJO.js} +2 -2
  24. package/dist/chunk-C26I6HTO.js +39 -0
  25. package/dist/{chunk-AW74INUW.js → chunk-DBPNGZNH.js} +6 -5
  26. package/dist/{chunk-DQA434Y4.js → chunk-DBXDV5O7.js} +3 -3
  27. package/dist/{chunk-S6GMFDKV.js → chunk-DRND2KYV.js} +2 -2
  28. package/dist/{chunk-F4VMYR7U.js → chunk-GN4SAZF2.js} +4 -4
  29. package/dist/{chunk-ZXKZBTXE.js → chunk-HAFRAXGV.js} +1 -1
  30. package/dist/{chunk-CBCW5R5J.js → chunk-MCH3E46V.js} +2 -2
  31. package/dist/{chunk-WW3YZKHW.js → chunk-NDIGZXFF.js} +26 -5
  32. package/dist/{chunk-TFZ2JUXH.js → chunk-PAB35H27.js} +523 -73
  33. package/dist/{chunk-NQ7IQ5XT.js → chunk-PFEUZXVT.js} +1 -1
  34. package/dist/{chunk-W24CMQ32.js → chunk-PPKX55GI.js} +3 -3
  35. package/dist/{chunk-ZCTSUQRR.js → chunk-T6P5ZMG2.js} +3 -3
  36. package/dist/{chunk-N3HTJVBR.js → chunk-VTOUQAVR.js} +1 -1
  37. package/dist/{chunk-B73KQ5KX.js → chunk-WFXHMP47.js} +11 -11
  38. package/dist/chunk-WGLPZXNU.js +45 -0
  39. package/dist/{chunk-KD2MYBB6.js → chunk-WUWRGOUV.js} +2 -2
  40. package/dist/{contribute-C6AW2P6J.js → contribute-A7NCWTUM.js} +5 -5
  41. package/dist/{cursor-awareness-KTL2RGKD.js → cursor-awareness-TN5JXD2C.js} +3 -3
  42. package/dist/{diff-VHNR62SI.js → diff-4MDU5SLE.js} +6 -6
  43. package/dist/{doctor-PET2HRRJ.js → doctor-MQAXOFKM.js} +16 -14
  44. package/dist/{dogfood-KKFVRWT6.js → dogfood-2JAHSYQA.js} +4 -4
  45. package/dist/{handoff-3UI6VKVG.js → handoff-MK5JG3J5.js} +4 -4
  46. package/dist/{hook-DYIMKJYL.js → hook-D2WHBKRN.js} +12 -12
  47. package/dist/index.js +26 -24
  48. package/dist/{init-Q4LBM6KT.js → init-7T6KNDFE.js} +17 -16
  49. package/dist/install-6G3D7J4U.js +35 -0
  50. package/dist/{monitors-QV2IS3MP.js → monitors-PDXBLB3U.js} +1 -1
  51. package/dist/{plan-index-JMC7Z4DW.js → plan-index-V7T5MKL6.js} +3 -3
  52. package/dist/{public-inbound-radar-WP3XF7GS.js → public-inbound-radar-5U4JMBRU.js} +3 -3
  53. package/dist/{remote-issues-SZ4HDQL5.js → remote-issues-APYOMIJC.js} +4 -4
  54. package/dist/{run-I3BFGULT.js → run-MWOI7UW5.js} +7 -6
  55. package/dist/{run-plan-FO7CL4M3.js → run-plan-UWQD3BIJ.js} +37 -6
  56. package/dist/{scan-NI2SWJ2E.js → scan-3MIUE7OR.js} +2 -2
  57. package/dist/{setup-global-M42GEODI.js → setup-global-AT4DD3MG.js} +9 -9
  58. package/dist/{status-XPVQVQMX.js → status-MXNTBKPL.js} +11 -11
  59. package/dist/{update-FJ2EBZVO.js → update-P62637ZI.js} +12 -12
  60. package/package.json +10 -6
  61. package/dist/chunk-5VCOWTTP.js +0 -6
  62. package/dist/install-RHOS3OYZ.js +0 -34
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Headless run feed for Mission Control: the kit's own `.cursor/loop-logs/`
3
+ * (`tick-*.log` from `agent-kit run-plan`, `run-*.log` from `agent-kit run`),
4
+ * so the panel and an embedding host can show agent output, gates and tick
5
+ * results without reading `~/.cursor/projects` (ADR 2026-10-08
6
+ * mission-control-embeddable-contract).
7
+ *
8
+ * The logs are already redacted when the CLI writes them; a caller-supplied
9
+ * `redact` runs again over every string this module returns. Read-only and
10
+ * bounded: newest MAX_RUN_LOGS files, the last MAX_RUN_LOG_BYTES of each.
11
+ * Understands the three shapes the backends write: claude / cursor-agent
12
+ * stream-json, codex `exec --json`, and the cursor-acp JSON-RPC transcript.
13
+ */
14
+ import { readdirSync, readFileSync, statSync } from "node:fs";
15
+ import { join } from "node:path";
16
+
17
+ export const MAX_RUN_LOGS = 10;
18
+ export const MAX_RUN_LOG_BYTES = 256 * 1024;
19
+ export const MAX_RUN_LOG_TEXT = 600;
20
+ const MAX_LIST = 10;
21
+
22
+ const LOG_NAME_RE = /^(tick|run)-[0-9-]+\.log$/;
23
+ const GATE_RE = /^HITL_GATE:\s*([a-z0-9-]+)\s*\|/m;
24
+ const SENTINEL_RE = /LOOP_TICK_RESULT:\s*(continue|stop(?:\s*[—-].*)?)/i;
25
+ const REPLY_RE = /HITL_REPLY:\s*[a-z0-9-]+\s*\|[^\n]*/;
26
+
27
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
28
+
29
+ function cap(text, max = MAX_RUN_LOG_TEXT) {
30
+ const s = String(text ?? "").trim();
31
+ return s.length > max ? `${s.slice(0, max - 1)}…` : s;
32
+ }
33
+
34
+ function textOf(content) {
35
+ if (typeof content === "string") return content;
36
+ if (!Array.isArray(content)) return "";
37
+ return content
38
+ .map((part) => (isRecord(part) && typeof part.text === "string" ? part.text : ""))
39
+ .join("");
40
+ }
41
+
42
+ /**
43
+ * Summary of one log's text: backend shape, session id, last agent text,
44
+ * the final result, the `LOOP_TICK_RESULT` line, gate ids and reply stamps.
45
+ * Never throws; unknown lines are skipped.
46
+ */
47
+ export function summarizeRunLog(text, redact = (s) => s) {
48
+ const out = {
49
+ format: null,
50
+ sessionId: null,
51
+ events: 0,
52
+ lastText: "",
53
+ result: null,
54
+ sentinel: null,
55
+ gates: [],
56
+ replies: [],
57
+ };
58
+ let acpTurn = "";
59
+ const noteText = (t) => {
60
+ if (!t) return;
61
+ out.lastText = t;
62
+ const gate = GATE_RE.exec(t);
63
+ if (gate?.[1] && out.gates.length < MAX_LIST) out.gates.push(gate[1]);
64
+ };
65
+ const noteReply = (t) => {
66
+ const m = REPLY_RE.exec(t);
67
+ if (m && out.replies.length < MAX_LIST) out.replies.push(m[0].trim());
68
+ };
69
+ for (const raw of String(text ?? "").split("\n")) {
70
+ const line = raw.trim();
71
+ if (!line.startsWith("{")) continue;
72
+ let ev;
73
+ try {
74
+ ev = JSON.parse(line);
75
+ } catch {
76
+ continue;
77
+ }
78
+ if (!isRecord(ev)) continue;
79
+ out.events += 1;
80
+ // cursor-acp: JSON-RPC 2.0 transcript (both directions).
81
+ if (ev.jsonrpc === "2.0") {
82
+ out.format ??= "acp";
83
+ const params = isRecord(ev.params) ? ev.params : null;
84
+ if (ev.method === "session/update" && isRecord(params?.update)) {
85
+ const u = params.update;
86
+ if (u.sessionUpdate === "agent_message_chunk" && isRecord(u.content)) {
87
+ acpTurn += typeof u.content.text === "string" ? u.content.text : "";
88
+ }
89
+ } else if (ev.method === "session/prompt" && params) {
90
+ noteReply(textOf(params.prompt));
91
+ } else if (isRecord(ev.result) && typeof ev.result.sessionId === "string") {
92
+ out.sessionId = ev.result.sessionId;
93
+ } else if (isRecord(ev.result) && typeof ev.result.stopReason === "string") {
94
+ noteText(acpTurn);
95
+ out.result = { isError: false, subtype: ev.result.stopReason, text: cap(acpTurn) };
96
+ acpTurn = "";
97
+ } else if (isRecord(ev.error) && ev.id !== undefined && !ev.method) {
98
+ const message = typeof ev.error.message === "string" ? ev.error.message : "error";
99
+ out.result = { isError: true, subtype: "error", text: cap(message) };
100
+ }
101
+ continue;
102
+ }
103
+ const type = ev.type;
104
+ // codex exec --json
105
+ if (type === "thread.started" || type === "turn.completed" || type === "turn.failed") {
106
+ out.format ??= "codex";
107
+ }
108
+ if (type === "thread.started" && typeof ev.thread_id === "string") out.sessionId = ev.thread_id;
109
+ else if (type === "item.completed" && isRecord(ev.item)) {
110
+ const kind = ev.item.type ?? ev.item.item_type;
111
+ if (
112
+ (kind === "agent_message" || kind === "assistant_message") &&
113
+ typeof ev.item.text === "string"
114
+ ) {
115
+ noteText(ev.item.text);
116
+ }
117
+ } else if (type === "turn.completed") {
118
+ out.result = { isError: false, subtype: "success", text: cap(out.lastText) };
119
+ } else if (type === "turn.failed") {
120
+ const message =
121
+ isRecord(ev.error) && typeof ev.error.message === "string" ? ev.error.message : "failed";
122
+ out.result = { isError: true, subtype: "error", text: cap(message) };
123
+ }
124
+ // claude / cursor-agent stream-json
125
+ else if (type === "system" && ev.subtype === "init") {
126
+ out.format ??= "stream-json";
127
+ if (typeof ev.session_id === "string") out.sessionId = ev.session_id;
128
+ } else if (type === "assistant" && isRecord(ev.message)) {
129
+ noteText(textOf(ev.message.content));
130
+ } else if (type === "user" && ev.isReplay === true && isRecord(ev.message)) {
131
+ noteReply(textOf(ev.message.content));
132
+ } else if (type === "result") {
133
+ out.format ??= "stream-json";
134
+ const resultText = typeof ev.result === "string" ? ev.result : "";
135
+ if (resultText) noteText(resultText);
136
+ out.result = {
137
+ isError: ev.is_error === true,
138
+ subtype: typeof ev.subtype === "string" ? ev.subtype : null,
139
+ text: cap(resultText),
140
+ };
141
+ }
142
+ }
143
+ const sentinel = SENTINEL_RE.exec(out.result?.text || out.lastText);
144
+ out.sentinel = sentinel ? `LOOP_TICK_RESULT: ${sentinel[1].trim()}` : null;
145
+ out.lastText = cap(out.lastText);
146
+ out.gates = [...new Set(out.gates)];
147
+ out.lastText = redact(out.lastText);
148
+ if (out.result) out.result.text = redact(out.result.text);
149
+ out.replies = out.replies.map((r) => redact(r));
150
+ return out;
151
+ }
152
+
153
+ /**
154
+ * Runner state dir for the loop logs: mirrors `resolveStateDir` in
155
+ * packages/cli/src/utils/kit-paths.ts (`AGENT_KIT_STATE_ROOT`, `.cursor` or
156
+ * `.agent-kit`, anything else falls back to `.cursor`). HTML/ESM cannot import
157
+ * the TS module; a parity test keeps the two in step.
158
+ */
159
+ export function resolveRunnerStateDir(env = process.env) {
160
+ const raw = String(env?.AGENT_KIT_STATE_ROOT ?? "")
161
+ .trim()
162
+ .replace(/\/+$/, "");
163
+ return raw === ".agent-kit" ? ".agent-kit" : ".cursor";
164
+ }
165
+
166
+ /** Read the tail of a file (the newest events matter; the head may be a long prompt echo). */
167
+ function readTail(file, size) {
168
+ const text = readFileSync(file, "utf8");
169
+ if (size <= MAX_RUN_LOG_BYTES) return text;
170
+ const tail = text.slice(-MAX_RUN_LOG_BYTES);
171
+ const cut = tail.indexOf("\n");
172
+ return cut === -1 ? tail : tail.slice(cut + 1);
173
+ }
174
+
175
+ /**
176
+ * Rows for the newest headless logs under `<root>/<stateDir>/loop-logs/`.
177
+ * A missing directory or unreadable file yields fewer rows, never an error.
178
+ */
179
+ export function collectRunLogs(root, opts = {}) {
180
+ const stateDir = opts.stateDir ?? resolveRunnerStateDir();
181
+ const redact = typeof opts.redact === "function" ? opts.redact : (s) => s;
182
+ const max = opts.max ?? MAX_RUN_LOGS;
183
+ const dir = join(root, stateDir, "loop-logs");
184
+ let names;
185
+ try {
186
+ names = readdirSync(dir).filter((f) => LOG_NAME_RE.test(f));
187
+ } catch {
188
+ return [];
189
+ }
190
+ const files = [];
191
+ for (const name of names) {
192
+ try {
193
+ const st = statSync(join(dir, name));
194
+ if (st.isFile()) files.push({ name, mtimeMs: st.mtimeMs, size: st.size });
195
+ } catch {
196
+ // vanished between readdir and stat
197
+ }
198
+ }
199
+ files.sort((a, b) => b.mtimeMs - a.mtimeMs || (a.name < b.name ? 1 : -1));
200
+ const rows = [];
201
+ for (const f of files.slice(0, max)) {
202
+ try {
203
+ const summary = summarizeRunLog(readTail(join(dir, f.name), f.size), redact);
204
+ rows.push({
205
+ id: f.name,
206
+ kind: f.name.startsWith("tick-") ? "tick" : "run",
207
+ path: `${stateDir}/loop-logs/${f.name}`,
208
+ updatedAt: new Date(f.mtimeMs).toISOString(),
209
+ bytes: f.size,
210
+ source: "loop-logs",
211
+ ...summary,
212
+ });
213
+ } catch {
214
+ // unreadable log: skipped
215
+ }
216
+ }
217
+ return rows;
218
+ }
@@ -2,10 +2,10 @@
2
2
  // Pure Mission Control view-model helpers (testable; no fs/git I/O).
3
3
 
4
4
  import { truncateStr } from "./guards.mjs";
5
- import { TRIAGE_HEADING_RE, hasTriageHeading } from "./triage-heading.mjs";
5
+ import { hasTriageHeading, TRIAGE_HEADING_RE } from "./triage-heading.mjs";
6
6
 
7
7
  /** Durable triage heading SoT (shared with CLI `monitors --untriaged`). */
8
- export { TRIAGE_HEADING_RE, hasTriageHeading };
8
+ export { hasTriageHeading, TRIAGE_HEADING_RE };
9
9
 
10
10
  export const MAX_ACTIVITY = 28;
11
11
  export const MAX_ATTENTION = 15;
@@ -1399,7 +1399,7 @@ export function normalizeHandoffGaps(raw) {
1399
1399
  if (!text) return null;
1400
1400
  if (/^(none|n\/a)$/i.test(text)) return null;
1401
1401
  // OK + pointer anti-pattern: "none. Residuals…", "None: …", "N/A - …", "none (…)"
1402
- if (/^(none|n\/a)\s*[.:,;\/(\-–—…]/i.test(text)) return null;
1402
+ if (/^(none|n\/a)\s*[.:,;/(\-–—…]/i.test(text)) return null;
1403
1403
  // Empty residual placeholders
1404
1404
  if (/^([-–—.…]|empty|no gaps?|cleared|all clear|ok)$/i.test(text)) return null;
1405
1405
  return truncateStr(text, MAX_SEMANTIC_LABEL);
@@ -1426,6 +1426,7 @@ export function classifyFlightLogMessageKind(text, opts = {}) {
1426
1426
  const collapsed = text.replace(/\s+/g, " ").trim();
1427
1427
  if (!collapsed) return "ok";
1428
1428
  if (/^(none|n\/a)$/i.test(collapsed)) return "ok";
1429
+ // biome-ignore lint/complexity/noUselessEscapeInRegex: byte parity with dashboard.html flightLogMessageKind (pinned by plugin-ux-validation.test.ts)
1429
1430
  if (/^(none|n\/a)\s*[.:,;\/(\-–—…]/i.test(collapsed)) return "ok";
1430
1431
  if (/^([-–—.…]|empty|no gaps?|cleared|all clear|ok)$/i.test(collapsed)) return "ok";
1431
1432
  if (
@@ -12,17 +12,17 @@ import { dirname, extname, join } from "node:path";
12
12
  import { fileURLToPath } from "node:url";
13
13
  import { shareShellTokenRequired } from "./lib/broadcast-share.mjs";
14
14
  import {
15
- DEFAULT_HOST,
16
- REPO_ROOT_ENV,
17
15
  allowlistConfig,
18
16
  applyCorsHeaders,
19
17
  authorizeMissionControlRequest,
20
18
  broadcastAuthCookieHeader,
19
+ DEFAULT_HOST,
21
20
  isAllowedHostHeader,
22
21
  isAllowedOrigin,
23
22
  isLoopbackAddress,
24
23
  listLanIPv4Addresses,
25
24
  mergeConfigAllowlist,
25
+ REPO_ROOT_ENV,
26
26
  resolveBroadcastAuth,
27
27
  resolveContextConfigPath,
28
28
  resolveDashboardStatic,
@@ -30,11 +30,11 @@ import {
30
30
  validateConfigWriteBody,
31
31
  } from "./lib/guards.mjs";
32
32
  import {
33
- PERIODIC_REFRESH_MS,
34
- WATCH_DEBOUNCE_MS,
35
33
  createTrailingDebounce,
34
+ PERIODIC_REFRESH_MS,
36
35
  resolveAgentTranscriptsWatchPath,
37
36
  resolveWatchPaths,
37
+ WATCH_DEBOUNCE_MS,
38
38
  } from "./lib/live-refresh.mjs";
39
39
  import { PIPELINE_CACHE_ENV, pipelineCacheJsonFromSnapshot } from "./lib/pipeline-cache.mjs";
40
40
  import { buildInventoryBaseline } from "./lib/semantic-model.mjs";
@@ -25,7 +25,6 @@ import {
25
25
  } from "./lib/broadcast-share.mjs";
26
26
  import {
27
27
  BROADCAST_TOKEN_ENV,
28
- REPO_ROOT_ENV,
29
28
  describeBroadcastListener,
30
29
  escapePerlDoubleQuoted,
31
30
  generateBroadcastToken,
@@ -33,6 +32,7 @@ import {
33
32
  isValidBroadcastToken,
34
33
  listLanIPv4Addresses,
35
34
  normalizeAuthToken,
35
+ REPO_ROOT_ENV,
36
36
  repoRootLogId,
37
37
  resolveBindHost,
38
38
  resolveBroadcastPort,
@@ -21,8 +21,8 @@ import { existsSync, openSync, realpathSync } from "node:fs";
21
21
  import { basename, dirname, join, resolve } from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import {
24
- REPO_ROOT_ENV,
25
24
  escapePerlDoubleQuoted,
25
+ REPO_ROOT_ENV,
26
26
  repoRootLogId,
27
27
  resolveContextConfigPath,
28
28
  resolveMissionControlPort,
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  REGISTRY_CLI_ARGS,
7
7
  resolveRegistryFromCli
8
- } from "./chunk-PNG7LO2F.js";
8
+ } from "./chunk-3DGTPONS.js";
9
9
  import {
10
10
  logger
11
11
  } from "./chunk-ZB43YMHW.js";
@@ -22,12 +22,12 @@ import {
22
22
  resolveProtectedGlobs,
23
23
  saveManifest,
24
24
  upsertIdList
25
- } from "./chunk-AW74INUW.js";
26
- import "./chunk-5VCOWTTP.js";
25
+ } from "./chunk-DBPNGZNH.js";
27
26
  import {
28
27
  KIT_VERSION
29
28
  } from "./chunk-7HDQEK6T.js";
30
- import "./chunk-77V75A7O.js";
29
+ import "./chunk-C26I6HTO.js";
30
+ import "./chunk-5B4DVO6C.js";
31
31
 
32
32
  // src/commands/add.ts
33
33
  import { defineCommand } from "citty";
@@ -2,17 +2,17 @@ import {
2
2
  contextConfigPath,
3
3
  intervalElapsed,
4
4
  loadContextConfig
5
- } from "./chunk-NQ7IQ5XT.js";
5
+ } from "./chunk-PFEUZXVT.js";
6
6
  import {
7
7
  diffAgainstRegistry,
8
8
  summarizeDiff
9
- } from "./chunk-2RDRMGD3.js";
9
+ } from "./chunk-BBVBYQJO.js";
10
10
  import {
11
11
  DEFAULT_REGISTRY_URL,
12
12
  assertSafeRegistrySource,
13
13
  loadAgentKitManifest,
14
14
  resolveRegistryRoot
15
- } from "./chunk-AW74INUW.js";
15
+ } from "./chunk-DBPNGZNH.js";
16
16
  import {
17
17
  KIT_PACKAGE_SPEC,
18
18
  KIT_VERSION
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  readJson,
22
22
  writeJson
23
- } from "./chunk-77V75A7O.js";
23
+ } from "./chunk-5B4DVO6C.js";
24
24
 
25
25
  // src/lifecycle/check-updates.ts
26
26
  import { execFile } from "child_process";
@@ -5,7 +5,7 @@ import {
5
5
  DEFAULT_REGISTRY_REF,
6
6
  DEFAULT_REGISTRY_URL,
7
7
  resolveRegistryRoot
8
- } from "./chunk-AW74INUW.js";
8
+ } from "./chunk-DBPNGZNH.js";
9
9
 
10
10
  // src/lifecycle/resolve-cli.ts
11
11
  async function resolveRegistryFromCli(options) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  PUBLIC_INBOUND_REPO,
3
3
  detectFactoryCheckout
4
- } from "./chunk-2IPXQFJE.js";
4
+ } from "./chunk-4CRBUEJ6.js";
5
5
 
6
6
  // src/lifecycle/remote-issues.ts
7
7
  import { execFile } from "child_process";
@@ -2,11 +2,11 @@ import {
2
2
  contextConfigPath,
3
3
  intervalElapsed,
4
4
  loadContextConfig
5
- } from "./chunk-NQ7IQ5XT.js";
5
+ } from "./chunk-PFEUZXVT.js";
6
6
  import {
7
7
  fileExists,
8
8
  writeJson
9
- } from "./chunk-77V75A7O.js";
9
+ } from "./chunk-5B4DVO6C.js";
10
10
 
11
11
  // src/lifecycle/public-inbound-radar.ts
12
12
  import { execFile } from "child_process";
@@ -5,7 +5,10 @@ import {
5
5
  RESOLVE_AGENT_KIT_REL,
6
6
  SESSION_START_HOOK_MARKER,
7
7
  discoverInstalledCommands
8
- } from "./chunk-W24CMQ32.js";
8
+ } from "./chunk-PPKX55GI.js";
9
+ import {
10
+ findOnPath
11
+ } from "./chunk-WGLPZXNU.js";
9
12
  import {
10
13
  createReadinessReport
11
14
  } from "./chunk-PNFF6OU3.js";
@@ -15,21 +18,21 @@ import {
15
18
  REQUIRED_SECRET_PATTERNS,
16
19
  detectGitDirty,
17
20
  runScanner
18
- } from "./chunk-ZCTSUQRR.js";
21
+ } from "./chunk-T6P5ZMG2.js";
19
22
  import {
20
23
  CONTEXT_CONFIG_REL,
21
24
  contextConfigPath
22
- } from "./chunk-NQ7IQ5XT.js";
25
+ } from "./chunk-PFEUZXVT.js";
23
26
  import {
24
27
  ensureDir,
25
28
  fileExists,
26
29
  readJson,
27
30
  writeJson
28
- } from "./chunk-77V75A7O.js";
31
+ } from "./chunk-5B4DVO6C.js";
29
32
 
30
33
  // src/invariants/hooks-health.ts
31
34
  import { execFile } from "child_process";
32
- import { constants, access, readFile, readdir, stat } from "fs/promises";
35
+ import { access, constants, readdir, readFile, stat } from "fs/promises";
33
36
  import path from "path";
34
37
  import { promisify } from "util";
35
38
  var execFileAsync = promisify(execFile);
@@ -66,13 +69,7 @@ async function resolveAgentKitCli(rootDir) {
66
69
  for (const c of candidates) {
67
70
  if (await exists(c)) return c;
68
71
  }
69
- try {
70
- const { stdout } = await execFileAsync("which", ["agent-kit"], { encoding: "utf8" });
71
- const hit = stdout.trim().split("\n")[0]?.trim();
72
- if (hit) return hit;
73
- } catch {
74
- }
75
- return null;
72
+ return findOnPath("agent-kit");
76
73
  }
77
74
  function commandLooksLikeAdapter(command) {
78
75
  const trimmed = command.trim();
@@ -176,13 +173,8 @@ async function resolveGuardProbeArgv(root) {
176
173
  if (await isExecutable(local)) return [local];
177
174
  const dist = path.join(root, "packages", "cli", "dist", "index.js");
178
175
  if (await exists(dist)) return [process.execPath, dist];
179
- try {
180
- const { stdout } = await execFileAsync("which", ["agent-kit"], { encoding: "utf8" });
181
- const hit = stdout.trim().split("\n")[0]?.trim();
182
- if (hit) return [hit];
183
- } catch {
184
- }
185
- return null;
176
+ const hit = await findOnPath("agent-kit");
177
+ return hit ? [hit] : null;
186
178
  }
187
179
  async function assessClaudeGuardProbe(rootDir) {
188
180
  const root = path.resolve(rootDir);
@@ -1,7 +1,7 @@
1
1
  // src/utils/fs.ts
2
2
  import { randomUUID } from "crypto";
3
3
  import { constants } from "fs";
4
- import { access, mkdir, readFile, readdir, rename, writeFile } from "fs/promises";
4
+ import { access, mkdir, readdir, readFile, rename, writeFile } from "fs/promises";
5
5
  import path from "path";
6
6
  async function fileExists(target) {
7
7
  try {
@@ -1,8 +1,10 @@
1
1
  // src/readiness/env-checks.ts
2
- import { constants, access, readFile, realpath, stat } from "fs/promises";
2
+ import { access, constants, readFile, realpath, stat } from "fs/promises";
3
3
  import { homedir } from "os";
4
4
  import path from "path";
5
- var MIN_NODE_MAJOR = 20;
5
+ var MIN_NODE_MAJOR = 22;
6
+ var MIN_NODE_MINOR = 12;
7
+ var MIN_NODE_VERSION_LABEL = `${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}`;
6
8
  var CLI_PACKAGE_JSON_REL = path.join(
7
9
  "lib",
8
10
  "node_modules",
@@ -91,11 +93,13 @@ async function resolveBinOnPath(binName, env, platform) {
91
93
  }
92
94
  return null;
93
95
  }
94
- function isNodeVersionOk(nodeVersion, minMajor = MIN_NODE_MAJOR) {
95
- const match = /^v?(\d+)/.exec(nodeVersion);
96
+ function isNodeVersionOk(nodeVersion, minMajor = MIN_NODE_MAJOR, minMinor = minMajor === MIN_NODE_MAJOR ? MIN_NODE_MINOR : 0) {
97
+ const match = /^v?(\d+)(?:\.(\d+))?/.exec(nodeVersion);
96
98
  if (!match) return false;
97
99
  const major = Number(match[1]);
98
- return Number.isFinite(major) && major >= minMajor;
100
+ const minor = match[2] === void 0 ? 0 : Number(match[2]);
101
+ if (!Number.isFinite(major) || !Number.isFinite(minor)) return false;
102
+ return major > minMajor || major === minMajor && minor >= minMinor;
99
103
  }
100
104
  function detectShellName(env, platform) {
101
105
  if (platform === "win32") {
@@ -210,5 +214,6 @@ async function assessEnvironment(options = {}) {
210
214
  }
211
215
 
212
216
  export {
217
+ MIN_NODE_VERSION_LABEL,
213
218
  assessEnvironment
214
219
  };