@dadado/agent-kit-cli 5.16.0 → 5.18.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 (40) hide show
  1. package/dashboard/README.md +10 -1
  2. package/dashboard/dashboard-data.mjs +12 -2
  3. package/dashboard/dashboard.html +58 -0
  4. package/dashboard/lib/run-logs.d.mts +34 -0
  5. package/dashboard/lib/run-logs.mjs +218 -0
  6. package/dist/{add-7UMSGVWC.js → add-KQJE3ZTG.js} +3 -3
  7. package/dist/{chunk-KD2MYBB6.js → chunk-3J3I2W22.js} +1 -1
  8. package/dist/{chunk-YGBBHKBE.js → chunk-6FXQINND.js} +2 -2
  9. package/dist/{chunk-OUQZC744.js → chunk-B5CH47OS.js} +852 -74
  10. package/dist/chunk-C26I6HTO.js +39 -0
  11. package/dist/{chunk-6QV2BFGA.js → chunk-GSCXFJB7.js} +1 -1
  12. package/dist/{chunk-KI6ZHBPV.js → chunk-HRILMD5N.js} +312 -11
  13. package/dist/{chunk-OZ4QV6LM.js → chunk-KIXK7KOW.js} +42 -148
  14. package/dist/chunk-P6PMKYWU.js +50 -0
  15. package/dist/{chunk-WW3YZKHW.js → chunk-RZ5TNBHU.js} +25 -4
  16. package/dist/{chunk-TFZ2JUXH.js → chunk-TOWH3XCJ.js} +520 -70
  17. package/dist/{chunk-CGTE7DHN.js → chunk-TZYKLR5J.js} +135 -20
  18. package/dist/{chunk-5OXPNVCF.js → chunk-UEKWZ7BN.js} +2 -2
  19. package/dist/chunk-WGLPZXNU.js +45 -0
  20. package/dist/{chunk-VS2JD2XC.js → chunk-WSJ77EHO.js} +5 -2
  21. package/dist/{chunk-VGZBARQC.js → chunk-YJMZ6UM2.js} +2 -2
  22. package/dist/{chunk-XZZAVHH4.js → chunk-YMYLO5LG.js} +2 -2
  23. package/dist/{chunk-XWPO3VYQ.js → chunk-ZDCEAGD4.js} +1 -1
  24. package/dist/{contribute-YKK6YCSI.js → contribute-LFT762Y4.js} +4 -4
  25. package/dist/{diff-YTR7VOAN.js → diff-56KMRCER.js} +5 -5
  26. package/dist/doctor-AA64XVEY.js +237 -0
  27. package/dist/{handoff-3UI6VKVG.js → handoff-34SDU4FF.js} +2 -2
  28. package/dist/{hook-MUV6Y7UW.js → hook-KRIXBLNW.js} +7 -7
  29. package/dist/index.js +19 -17
  30. package/dist/{init-TTTKGC4C.js → init-XP5EAUSJ.js} +12 -11
  31. package/dist/{install-ZMFJBPOI.js → install-SHDEX54F.js} +12 -11
  32. package/dist/{plan-index-JMC7Z4DW.js → plan-index-O3545OA7.js} +2 -2
  33. package/dist/{run-I3BFGULT.js → run-FADX6QCP.js} +6 -5
  34. package/dist/{run-plan-FO7CL4M3.js → run-plan-MO4IFAKV.js} +36 -5
  35. package/dist/{setup-global-JUVMJXJ5.js → setup-global-CBWLXOQG.js} +6 -6
  36. package/dist/{status-MVCUNCWX.js → status-BSIXWZMY.js} +19 -7
  37. package/dist/{update-Q4EBIRUB.js → update-FJX3DA6X.js} +33 -10
  38. package/package.json +3 -3
  39. package/dist/chunk-5VCOWTTP.js +0 -6
  40. package/dist/doctor-TA2FWREU.js +0 -497
@@ -4,35 +4,146 @@ import {
4
4
  import {
5
5
  assertRealContained,
6
6
  assertRealParentContained,
7
+ contentHash,
7
8
  isRealWriteTargetContained,
8
- resolveContained
9
- } from "./chunk-VS2JD2XC.js";
9
+ loadManagedHashLedger,
10
+ resolveContained,
11
+ saveManagedHashLedger,
12
+ shouldPreserveCustomizedOverlay
13
+ } from "./chunk-WSJ77EHO.js";
10
14
  import {
11
- ensureDir
15
+ ensureDir,
16
+ fileExists
12
17
  } from "./chunk-77V75A7O.js";
13
18
 
19
+ // src/generator/claude-command-adapters.ts
20
+ import { readFile, readdir, writeFile } from "fs/promises";
21
+ import path from "path";
22
+ var CURSOR_COMMANDS_DIR_REL = ".cursor/commands";
23
+ var CLAUDE_COMMANDS_DIR_REL = ".claude/commands";
24
+ var RESERVED_ADAPTER_NAMES = /* @__PURE__ */ new Set(["agent-kit"]);
25
+ function parseCommandFrontmatter(name, raw) {
26
+ const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
27
+ if (!match) return null;
28
+ const body = match[1] ?? "";
29
+ const descMatch = /^description:\s*(.+)$/m.exec(body);
30
+ if (!descMatch) return null;
31
+ const description = (descMatch[1] ?? "").trim();
32
+ if (!description) return null;
33
+ return { name, description };
34
+ }
35
+ var CLAUDE_HITL_FALLBACK = `Cursor "Ask questions" is unavailable here: use AskUserQuestion when possible, else print one line \`HITL_GATE: <ask-id> | <label 1> | <label 2> | ...\` immediately followed by the same labels as one numbered list, one list per message, and WAIT for the answer (ask-id and labels: \`.cursor/skills/core/hitl-gates/SKILL.md\`). A headless reply arrives as \`HITL_REPLY: <ask-id> | operator reply <n> | <label>\`; cite that line as the Ask provenance.`;
36
+ var MODEL_INVOCATION_DISABLED = /* @__PURE__ */ new Set([
37
+ "git-prod",
38
+ "kit-prod",
39
+ "backlog-delete",
40
+ "backlog-cancel",
41
+ "archive-plan",
42
+ "hotfix",
43
+ "run-plan-all"
44
+ ]);
45
+ function renderClaudeCommandAdapter(command) {
46
+ const invocation = MODEL_INVOCATION_DISABLED.has(command.name) ? "disable-model-invocation: true\n" : "";
47
+ return `---
48
+ description: ${command.description}
49
+ ${invocation}---
50
+
51
+ Read \`.cursor/commands/${command.name}.md\` now and follow that contract exactly \u2014 it is the source of truth for /${command.name}; this file is only a thin adapter for Claude Code.
52
+
53
+ Adapter rules (Claude Code CLI):
54
+ - ${CLAUDE_HITL_FALLBACK}
55
+ - Skip or cancel means stop.
56
+ - Never \`/git-prod\` without an explicit operator yes.
57
+ - Do not clone Cursor hooks or invent behavior beyond the SoT file.
58
+ `;
59
+ }
60
+ async function discoverInstalledCommands(rootDir) {
61
+ const dir = path.join(rootDir, CURSOR_COMMANDS_DIR_REL);
62
+ let entries;
63
+ try {
64
+ entries = (await readdir(dir)).filter((f) => f.endsWith(".md"));
65
+ } catch {
66
+ return [];
67
+ }
68
+ const commands = [];
69
+ for (const file of entries.sort()) {
70
+ const name = file.slice(0, -3);
71
+ if (RESERVED_ADAPTER_NAMES.has(name)) continue;
72
+ try {
73
+ const raw = await readFile(path.join(dir, file), "utf8");
74
+ const parsed = parseCommandFrontmatter(name, raw);
75
+ if (parsed) commands.push(parsed);
76
+ } catch {
77
+ }
78
+ }
79
+ return commands;
80
+ }
81
+ async function generateClaudeCommandAdapters(rootDir) {
82
+ const commands = await discoverInstalledCommands(rootDir);
83
+ if (commands.length === 0) return [];
84
+ const ledger = await loadManagedHashLedger(rootDir);
85
+ const results = [];
86
+ let ledgerDirty = false;
87
+ for (const command of commands) {
88
+ const relPath = path.posix.join(CLAUDE_COMMANDS_DIR_REL, `${command.name}.md`);
89
+ const rendered = renderClaudeCommandAdapter(command);
90
+ const abs = resolveContained(rootDir, relPath);
91
+ if (!await isRealWriteTargetContained(rootDir, abs)) {
92
+ results.push({ relativePath: relPath, status: "skipped-symlink" });
93
+ continue;
94
+ }
95
+ if (!await fileExists(abs)) {
96
+ await ensureDir(path.dirname(abs));
97
+ await writeFile(abs, rendered, "utf8");
98
+ ledger.hashes[relPath] = contentHash(rendered);
99
+ ledgerDirty = true;
100
+ results.push({ relativePath: relPath, status: "applied" });
101
+ continue;
102
+ }
103
+ const localContent = await readFile(abs, "utf8");
104
+ if (localContent === rendered) {
105
+ if (ledger.hashes[relPath] !== contentHash(rendered)) {
106
+ ledger.hashes[relPath] = contentHash(rendered);
107
+ ledgerDirty = true;
108
+ }
109
+ results.push({ relativePath: relPath, status: "unchanged" });
110
+ continue;
111
+ }
112
+ if (shouldPreserveCustomizedOverlay(localContent, ledger.hashes[relPath])) {
113
+ results.push({ relativePath: relPath, status: "preserved-customized" });
114
+ continue;
115
+ }
116
+ await writeFile(abs, rendered, "utf8");
117
+ ledger.hashes[relPath] = contentHash(rendered);
118
+ ledgerDirty = true;
119
+ results.push({ relativePath: relPath, status: "refreshed" });
120
+ }
121
+ if (ledgerDirty) await saveManagedHashLedger(rootDir, ledger);
122
+ return results;
123
+ }
124
+
14
125
  // src/generator/claude-session-start-hook.ts
15
- import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
16
- import path2 from "path";
126
+ import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
127
+ import path3 from "path";
17
128
 
18
129
  // src/generator/claude-settings-ledger.ts
19
- import { lstat, mkdir, readFile, writeFile } from "fs/promises";
20
- import path from "path";
130
+ import { lstat, mkdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
131
+ import path2 from "path";
21
132
  var CLAUDE_SETTINGS_LEDGER_REL = ".cursor/agent-kit.claude-settings.json";
22
133
  var ClaudeSettingsLedgerSymlinkError = class extends Error {
23
- constructor(path3, detail) {
24
- super(`Refusing to use Claude settings ledger ${path3}: ${detail}`);
25
- this.path = path3;
134
+ constructor(path4, detail) {
135
+ super(`Refusing to use Claude settings ledger ${path4}: ${detail}`);
136
+ this.path = path4;
26
137
  this.name = "ClaudeSettingsLedgerSymlinkError";
27
138
  }
28
139
  path;
29
140
  };
30
141
  var ClaudeSettingsLedgerInvalidError = class extends Error {
31
- constructor(path3) {
142
+ constructor(path4) {
32
143
  super(
33
- `Claude settings ledger ${path3} is malformed or has an unknown schemaVersion; not overwriting without authorization.`
144
+ `Claude settings ledger ${path4} is malformed or has an unknown schemaVersion; not overwriting without authorization.`
34
145
  );
35
- this.path = path3;
146
+ this.path = path4;
36
147
  this.name = "ClaudeSettingsLedgerInvalidError";
37
148
  }
38
149
  path;
@@ -98,7 +209,7 @@ async function readState(root) {
98
209
  );
99
210
  }
100
211
  if (!exists) return { abs, state: { kind: "missing" } };
101
- const ledger = parseLedger(await readFile(abs, "utf8"));
212
+ const ledger = parseLedger(await readFile2(abs, "utf8"));
102
213
  return { abs, state: ledger ? { kind: "ok", ledger } : { kind: "invalid" } };
103
214
  }
104
215
  async function loadClaudeSettingsLedger(root) {
@@ -115,8 +226,8 @@ async function saveClaudeSettingsLedger(root, additions, opts = {}) {
115
226
  [...base.denyRowsWritten, ...additions.denyRowsWritten ?? []],
116
227
  [...base.hookEntriesWritten, ...additions.hookEntriesWritten ?? []]
117
228
  );
118
- await mkdir(path.dirname(abs), { recursive: true });
119
- await writeFile(abs, `${JSON.stringify(merged, null, 2)}
229
+ await mkdir(path2.dirname(abs), { recursive: true });
230
+ await writeFile2(abs, `${JSON.stringify(merged, null, 2)}
120
231
  `, "utf8");
121
232
  return merged;
122
233
  }
@@ -294,7 +405,7 @@ async function writeClaudeSessionStartHook(rootDir, opts = {}) {
294
405
  }
295
406
  let existing = null;
296
407
  try {
297
- existing = await readFile2(abs, "utf8");
408
+ existing = await readFile3(abs, "utf8");
298
409
  } catch {
299
410
  existing = null;
300
411
  }
@@ -307,8 +418,8 @@ async function writeClaudeSessionStartHook(rootDir, opts = {}) {
307
418
  };
308
419
  }
309
420
  if (merged.status !== "unchanged") {
310
- await ensureDir(path2.dirname(abs));
311
- await writeFile2(abs, merged.content, "utf8");
421
+ await ensureDir(path3.dirname(abs));
422
+ await writeFile3(abs, merged.content, "utf8");
312
423
  }
313
424
  const result = {
314
425
  relativePath: CLAUDE_SETTINGS_REL,
@@ -334,7 +445,7 @@ async function planClaudeSettingsDrift(rootDir) {
334
445
  if (!await isRealWriteTargetContained(rootDir, abs)) return null;
335
446
  let raw;
336
447
  try {
337
- raw = await readFile2(abs, "utf8");
448
+ raw = await readFile3(abs, "utf8");
338
449
  } catch {
339
450
  return null;
340
451
  }
@@ -400,6 +511,10 @@ function formatClaudeSettingsDrift(report, opts) {
400
511
  }
401
512
 
402
513
  export {
514
+ CLAUDE_COMMANDS_DIR_REL,
515
+ CLAUDE_HITL_FALLBACK,
516
+ discoverInstalledCommands,
517
+ generateClaudeCommandAdapters,
403
518
  CLAUDE_SETTINGS_REL,
404
519
  RESOLVE_AGENT_KIT_REL,
405
520
  SESSION_START_HOOK_MARKER,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  L0_ARTIFACTS
3
- } from "./chunk-6QV2BFGA.js";
3
+ } from "./chunk-GSCXFJB7.js";
4
4
  import {
5
5
  copyRegistryFile,
6
6
  emptyStats,
@@ -12,7 +12,7 @@ import {
12
12
  recordOutcome,
13
13
  resolveProtectedGlobs,
14
14
  saveManagedHashLedger
15
- } from "./chunk-VS2JD2XC.js";
15
+ } from "./chunk-WSJ77EHO.js";
16
16
  import {
17
17
  fileExists
18
18
  } from "./chunk-77V75A7O.js";
@@ -0,0 +1,45 @@
1
+ // src/utils/find-on-path.ts
2
+ import { constants } from "fs";
3
+ import { access, stat } from "fs/promises";
4
+ import path from "path";
5
+ var DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD";
6
+ async function findOnPath(bin, opts = {}) {
7
+ const env = opts.env ?? process.env;
8
+ const platform = opts.platform ?? process.platform;
9
+ const win = platform === "win32";
10
+ const pathApi = win ? path.win32 : path.posix;
11
+ const check = opts.accessFn ?? (async (file, mode2) => {
12
+ await access(file, mode2);
13
+ if (!(await stat(file)).isFile()) throw new Error("not a file");
14
+ });
15
+ const mode = win ? constants.F_OK : constants.X_OK;
16
+ if (!bin.trim()) return null;
17
+ const pathValue = (win ? env.Path ?? env.PATH ?? env.path : env.PATH) ?? "";
18
+ const exts = win ? (env.PATHEXT ?? DEFAULT_PATHEXT).split(";").filter(Boolean) : [""];
19
+ const hasExt = win && exts.some((ext) => bin.toLowerCase().endsWith(ext.toLowerCase()));
20
+ const suffixes = hasExt ? [""] : exts;
21
+ const tryFile = async (file) => {
22
+ for (const ext of suffixes) {
23
+ const candidate = `${file}${ext}`;
24
+ try {
25
+ await check(candidate, mode);
26
+ return candidate;
27
+ } catch {
28
+ }
29
+ }
30
+ return null;
31
+ };
32
+ if (bin.includes("/") || win && bin.includes("\\")) return tryFile(bin);
33
+ const delimiter = win ? ";" : ":";
34
+ for (const raw of pathValue.split(delimiter)) {
35
+ const dir = raw.trim().replace(/^"(.*)"$/, "$1");
36
+ if (!dir) continue;
37
+ const hit = await tryFile(pathApi.join(dir, bin));
38
+ if (hit) return hit;
39
+ }
40
+ return null;
41
+ }
42
+
43
+ export {
44
+ findOnPath
45
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HANDOFF_REL
3
- } from "./chunk-5VCOWTTP.js";
3
+ } from "./chunk-C26I6HTO.js";
4
4
  import {
5
5
  fileExists,
6
6
  readJson,
@@ -678,7 +678,10 @@ var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
678
678
  "41d3eac7f116ec22535d830149979fe0a8dbf44625dd841bc9785cbd7c5ddc95",
679
679
  "80e11549ad3700d1e7345447aff1b3858e532e9347594ee4f028566c8c7b8a6a",
680
680
  "1ffbfa48a76d39f78db66f4ea250c451ae335c31d7e45d0fdc4d99bc714bae33",
681
- "19a5aa359e740fa18d7cc19f0b11243bc53d8d016545bce35837deac7fe2ef7e"
681
+ "19a5aa359e740fa18d7cc19f0b11243bc53d8d016545bce35837deac7fe2ef7e",
682
+ "f1c7beac6a619520d744fd984bc16b322f3d545b9d8490801aee628dabd94aff",
683
+ "14d919d01637aa6b5acc92804dbb4ab56cecc88281aedd5cb7b5dcf8f7da958e",
684
+ "a8decf7b78e2b2c833b0808c3e108322cfb895fadaec159467973a681028d92a"
682
685
  ]);
683
686
 
684
687
  // src/lifecycle/paths.ts
@@ -4,10 +4,10 @@ import {
4
4
  import {
5
5
  compareSemver,
6
6
  normalizeSemver
7
- } from "./chunk-XZZAVHH4.js";
7
+ } from "./chunk-YMYLO5LG.js";
8
8
  import {
9
9
  MANIFEST_RELATIVE_PATH
10
- } from "./chunk-VS2JD2XC.js";
10
+ } from "./chunk-WSJ77EHO.js";
11
11
  import {
12
12
  KIT_VERSION,
13
13
  pinnedCliSpec
@@ -6,13 +6,13 @@ import {
6
6
  import {
7
7
  diffAgainstRegistry,
8
8
  summarizeDiff
9
- } from "./chunk-YGBBHKBE.js";
9
+ } from "./chunk-6FXQINND.js";
10
10
  import {
11
11
  DEFAULT_REGISTRY_URL,
12
12
  assertSafeRegistrySource,
13
13
  loadAgentKitManifest,
14
14
  resolveRegistryRoot
15
- } from "./chunk-VS2JD2XC.js";
15
+ } from "./chunk-WSJ77EHO.js";
16
16
  import {
17
17
  KIT_PACKAGE_SPEC,
18
18
  KIT_VERSION
@@ -5,7 +5,7 @@ import {
5
5
  DEFAULT_REGISTRY_REF,
6
6
  DEFAULT_REGISTRY_URL,
7
7
  resolveRegistryRoot
8
- } from "./chunk-VS2JD2XC.js";
8
+ } from "./chunk-WSJ77EHO.js";
9
9
 
10
10
  // src/lifecycle/resolve-cli.ts
11
11
  async function resolveRegistryFromCli(options) {
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  REGISTRY_CLI_ARGS,
3
3
  resolveRegistryFromCli
4
- } from "./chunk-XWPO3VYQ.js";
4
+ } from "./chunk-ZDCEAGD4.js";
5
5
  import {
6
6
  logger
7
7
  } from "./chunk-ZB43YMHW.js";
8
8
  import {
9
9
  managedPairs
10
- } from "./chunk-6QV2BFGA.js";
10
+ } from "./chunk-GSCXFJB7.js";
11
11
  import {
12
12
  loadAgentKitManifest,
13
13
  normalizeRelPath,
14
14
  resolveContained
15
- } from "./chunk-VS2JD2XC.js";
16
- import "./chunk-5VCOWTTP.js";
15
+ } from "./chunk-WSJ77EHO.js";
16
+ import "./chunk-C26I6HTO.js";
17
17
  import "./chunk-77V75A7O.js";
18
18
 
19
19
  // src/commands/contribute.ts
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  REGISTRY_CLI_ARGS,
3
3
  resolveRegistryFromCli
4
- } from "./chunk-XWPO3VYQ.js";
4
+ } from "./chunk-ZDCEAGD4.js";
5
5
  import {
6
6
  logger
7
7
  } from "./chunk-ZB43YMHW.js";
8
8
  import {
9
9
  diffAgainstRegistry,
10
10
  summarizeDiff
11
- } from "./chunk-YGBBHKBE.js";
12
- import "./chunk-6QV2BFGA.js";
11
+ } from "./chunk-6FXQINND.js";
12
+ import "./chunk-GSCXFJB7.js";
13
13
  import {
14
14
  loadAgentKitManifest
15
- } from "./chunk-VS2JD2XC.js";
16
- import "./chunk-5VCOWTTP.js";
15
+ } from "./chunk-WSJ77EHO.js";
16
+ import "./chunk-C26I6HTO.js";
17
17
  import "./chunk-77V75A7O.js";
18
18
 
19
19
  // src/commands/diff.ts
@@ -0,0 +1,237 @@
1
+ import {
2
+ assessHooksHealth,
3
+ executeSafeReadinessFixes,
4
+ refreshRepositoryProfile
5
+ } from "./chunk-HRILMD5N.js";
6
+ import {
7
+ writeReadinessSnapshot
8
+ } from "./chunk-ZXKZBTXE.js";
9
+ import "./chunk-TZYKLR5J.js";
10
+ import "./chunk-WGLPZXNU.js";
11
+ import "./chunk-MAPOQEA2.js";
12
+ import {
13
+ withCliProgress
14
+ } from "./chunk-QTON2GQX.js";
15
+ import {
16
+ detectWorkspaceParent,
17
+ workspaceParentAdvisoryLines
18
+ } from "./chunk-P6PMKYWU.js";
19
+ import {
20
+ createReadinessReport
21
+ } from "./chunk-PNFF6OU3.js";
22
+ import {
23
+ runScanner
24
+ } from "./chunk-ZCTSUQRR.js";
25
+ import "./chunk-F6C3GFKV.js";
26
+ import {
27
+ logger
28
+ } from "./chunk-ZB43YMHW.js";
29
+ import {
30
+ assessEnvironment
31
+ } from "./chunk-4IWG5CVE.js";
32
+ import {
33
+ warnIfRunningCliBehindNpm
34
+ } from "./chunk-YMYLO5LG.js";
35
+ import "./chunk-NQ7IQ5XT.js";
36
+ import "./chunk-6FXQINND.js";
37
+ import "./chunk-GSCXFJB7.js";
38
+ import "./chunk-WSJ77EHO.js";
39
+ import {
40
+ KIT_VERSION
41
+ } from "./chunk-7HDQEK6T.js";
42
+ import "./chunk-C26I6HTO.js";
43
+ import {
44
+ readJson
45
+ } from "./chunk-77V75A7O.js";
46
+
47
+ // src/commands/doctor.ts
48
+ import path from "path";
49
+ import { defineCommand } from "citty";
50
+ async function readDeferredEssentials(rootDir, report) {
51
+ const config = await readJson(
52
+ path.join(rootDir, ".cursor", "context", "config.json")
53
+ );
54
+ const deferredItems = config?.onboarding?.deferredItems;
55
+ if (!Array.isArray(deferredItems)) return [];
56
+ const essentialIds = new Set(
57
+ report.pillars.flatMap((pillar) => pillar.checks).filter((check) => check.essential).map((check) => check.id)
58
+ );
59
+ return deferredItems.filter(
60
+ (item) => typeof item?.checkId === "string" && typeof item?.reason === "string" && essentialIds.has(item.checkId)
61
+ ).map((item) => ({ checkId: item.checkId, reason: item.reason }));
62
+ }
63
+ async function runDoctor(cwd, options = {}) {
64
+ const rootDir = path.resolve(cwd);
65
+ const hooks = await assessHooksHealth(rootDir);
66
+ const workspaceParent = await detectWorkspaceParent(rootDir);
67
+ if (workspaceParent) {
68
+ const scan2 = await runScanner(rootDir);
69
+ const report2 = createReadinessReport(scan2, {
70
+ generatorVersion: KIT_VERSION,
71
+ generatedAt: options.generatedAt
72
+ });
73
+ return {
74
+ report: report2,
75
+ safeChanges: [],
76
+ hooks,
77
+ env: await assessEnvironment(),
78
+ deferredEssentials: [],
79
+ workspaceParent
80
+ };
81
+ }
82
+ const env = await assessEnvironment();
83
+ if (options.fixSafe) {
84
+ const execution = await executeSafeReadinessFixes(rootDir, {
85
+ generatorVersion: KIT_VERSION,
86
+ generatedAt: options.generatedAt
87
+ });
88
+ await writeReadinessSnapshot(rootDir, execution.after);
89
+ return {
90
+ report: execution.after,
91
+ safeChanges: execution.changes,
92
+ hooks,
93
+ env,
94
+ deferredEssentials: await readDeferredEssentials(rootDir, execution.after)
95
+ };
96
+ }
97
+ if (options.refreshProfile) {
98
+ const refresh = await refreshRepositoryProfile(rootDir, {
99
+ generatorVersion: KIT_VERSION,
100
+ generatedAt: options.generatedAt
101
+ });
102
+ const scan2 = await runScanner(rootDir);
103
+ const report2 = createReadinessReport(scan2, {
104
+ generatorVersion: KIT_VERSION,
105
+ generatedAt: options.generatedAt
106
+ });
107
+ await writeReadinessSnapshot(rootDir, report2);
108
+ return {
109
+ report: report2,
110
+ safeChanges: [],
111
+ hooks,
112
+ env,
113
+ profileRefreshed: refresh.changed,
114
+ deferredEssentials: await readDeferredEssentials(rootDir, report2)
115
+ };
116
+ }
117
+ const scan = await runScanner(rootDir);
118
+ const report = createReadinessReport(scan, {
119
+ generatorVersion: KIT_VERSION,
120
+ generatedAt: options.generatedAt
121
+ });
122
+ await writeReadinessSnapshot(rootDir, report);
123
+ return {
124
+ report,
125
+ safeChanges: [],
126
+ hooks,
127
+ env,
128
+ deferredEssentials: await readDeferredEssentials(rootDir, report)
129
+ };
130
+ }
131
+ function printDoctorSummary(result, rootDir) {
132
+ if (result.workspaceParent) {
133
+ for (const line of workspaceParentAdvisoryLines(rootDir, result.workspaceParent, "doctor")) {
134
+ console.log(line);
135
+ }
136
+ return;
137
+ }
138
+ const { summary, pendingActions } = result.report;
139
+ const fixed = result.safeChanges.filter((change) => change.status === "applied").length;
140
+ const nextAction = pendingActions[0];
141
+ console.log("Repository readiness");
142
+ console.log(
143
+ ` ready: ${summary.ready}, choices: ${summary.needs_choice}, manual: ${summary.manual}, blocked: ${summary.blocked}`
144
+ );
145
+ console.log(` safe fixes applied: ${fixed}`);
146
+ console.log(` pending actions: ${pendingActions.length}`);
147
+ if (result.profileRefreshed !== void 0) {
148
+ console.log(
149
+ ` profile refreshed: ${result.profileRefreshed ? "yes (facts changed)" : "no (already current)"}`
150
+ );
151
+ }
152
+ for (const item of result.deferredEssentials) {
153
+ console.log(` Deferred essential: ${item.checkId} \u2014 ${item.reason}`);
154
+ }
155
+ console.log(`hooks: ${result.hooks.status}`);
156
+ if (result.hooks.reasons.length > 0) {
157
+ for (const reason of result.hooks.reasons.slice(0, 5)) {
158
+ console.log(` - ${reason}`);
159
+ }
160
+ }
161
+ if (result.hooks.advisories.length > 0) {
162
+ console.log("hooks advisories (soft; install via cp, see git-hooks/README.md):");
163
+ for (const tip of result.hooks.advisories.slice(0, 5)) {
164
+ console.log(` - ${tip}`);
165
+ }
166
+ }
167
+ console.log("environment:");
168
+ const pathLabel = result.env.binOnPath ? `ok (v${result.env.binVersion ?? "unknown"} at ${result.env.binPath})` : "MISSING";
169
+ console.log(` - bin on PATH (agent-kit): ${pathLabel}`);
170
+ console.log(
171
+ ` - npm prefix writable: ${result.env.npmPrefixWritable ? "ok" : "BLOCKED"}${result.env.npmPrefix.prefix ? ` (${result.env.npmPrefix.prefix})` : ""}`
172
+ );
173
+ if (!result.env.npmPrefixWritable && result.env.npmPrefix.reason) {
174
+ console.log(` - ${result.env.npmPrefix.reason}`);
175
+ }
176
+ console.log(
177
+ ` - node version >= 20: ${result.env.nodeVersionOk ? "ok" : "TOO OLD"} (${result.env.nodeVersion})`
178
+ );
179
+ console.log(
180
+ ` - shell profile: ${result.env.shellProfile ?? "not detected (zsh/bash only)"}${result.env.shell ? ` (shell: ${result.env.shell})` : ""}`
181
+ );
182
+ if (process.env.ALLOW_MAIN_PUSH === "1") {
183
+ console.log("\u26A0\uFE0F WARNING: ALLOW_MAIN_PUSH=1 is set in environment");
184
+ console.log(" This disables main-push protection for agent Shell commands.");
185
+ console.log(" Consider unsetting it: unset ALLOW_MAIN_PUSH");
186
+ }
187
+ console.log(
188
+ nextAction ? `Next: ${nextAction.recommendation}` : "Next: repository readiness checks are complete"
189
+ );
190
+ }
191
+ var doctorCommand = defineCommand({
192
+ meta: {
193
+ name: "doctor",
194
+ description: "Diagnose repository readiness; optional --fix-safe local repairs."
195
+ },
196
+ args: {
197
+ cwd: {
198
+ type: "string",
199
+ default: process.cwd()
200
+ },
201
+ json: {
202
+ type: "boolean",
203
+ description: "Print deterministic machine-readable JSON without status messages",
204
+ default: false
205
+ },
206
+ "fix-safe": {
207
+ type: "boolean",
208
+ description: "Apply only local, reversible, merge-safe readiness fixes",
209
+ default: false
210
+ },
211
+ "refresh-profile": {
212
+ type: "boolean",
213
+ description: "Reconcile .cursor/agent-kit.config.json with current scanner facts: fresh values win on shared keys, unrecognized existing keys are preserved",
214
+ default: false
215
+ }
216
+ },
217
+ async run({ args }) {
218
+ if (!args.json) {
219
+ await warnIfRunningCliBehindNpm(args.cwd, { warn: (message) => logger.warn(message) });
220
+ }
221
+ const run = () => runDoctor(args.cwd, {
222
+ fixSafe: args["fix-safe"],
223
+ refreshProfile: args["refresh-profile"]
224
+ });
225
+ const result = args.json ? await run() : await withCliProgress("doctor", run);
226
+ if (args.json) {
227
+ console.log(JSON.stringify(result, null, 2));
228
+ return;
229
+ }
230
+ printDoctorSummary(result, path.resolve(args.cwd));
231
+ }
232
+ });
233
+ export {
234
+ doctorCommand,
235
+ printDoctorSummary,
236
+ runDoctor
237
+ };
@@ -6,7 +6,7 @@ import {
6
6
  extractHandoffNamedPlans,
7
7
  namedPlanCandidatePaths,
8
8
  parsePlanFrontmatter
9
- } from "./chunk-KD2MYBB6.js";
9
+ } from "./chunk-3J3I2W22.js";
10
10
  import {
11
11
  PM_TOOL_LABELS
12
12
  } from "./chunk-F6C3GFKV.js";
@@ -15,7 +15,7 @@ import {
15
15
  } from "./chunk-ZB43YMHW.js";
16
16
  import {
17
17
  HANDOFF_REL
18
- } from "./chunk-5VCOWTTP.js";
18
+ } from "./chunk-C26I6HTO.js";
19
19
  import {
20
20
  ensureDir,
21
21
  fileExists,
@@ -16,25 +16,25 @@ import {
16
16
  import {
17
17
  formatPlanIndexSection,
18
18
  writePlanIndex
19
- } from "./chunk-KD2MYBB6.js";
19
+ } from "./chunk-3J3I2W22.js";
20
20
  import {
21
21
  READINESS_SNAPSHOT_RELATIVE_PATH
22
22
  } from "./chunk-ZXKZBTXE.js";
23
23
  import {
24
24
  stampLastCheckedAt
25
- } from "./chunk-XZZAVHH4.js";
25
+ } from "./chunk-YMYLO5LG.js";
26
26
  import {
27
27
  loadContextConfig
28
28
  } from "./chunk-NQ7IQ5XT.js";
29
- import "./chunk-YGBBHKBE.js";
30
- import "./chunk-6QV2BFGA.js";
29
+ import "./chunk-6FXQINND.js";
30
+ import "./chunk-GSCXFJB7.js";
31
31
  import {
32
32
  MANIFEST_RELATIVE_PATH
33
- } from "./chunk-VS2JD2XC.js";
33
+ } from "./chunk-WSJ77EHO.js";
34
+ import "./chunk-7HDQEK6T.js";
34
35
  import {
35
36
  HANDOFF_REL
36
- } from "./chunk-5VCOWTTP.js";
37
- import "./chunk-7HDQEK6T.js";
37
+ } from "./chunk-C26I6HTO.js";
38
38
  import {
39
39
  fileExists
40
40
  } from "./chunk-77V75A7O.js";