infra-kit 0.1.114 → 0.1.115

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 (202) hide show
  1. package/.eslintcache +1 -1
  2. package/.omc/state/agent-replay-1fcfe0ec-7567-41c3-9bfd-501e99e86819.jsonl +19 -0
  3. package/.omc/state/agent-replay-38382db5-3088-4b5a-aff7-2561a60827c7.jsonl +17 -0
  4. package/.omc/state/agent-replay-50c36be9-a3a2-42b9-9c85-5a06d3e22f6a.jsonl +5 -0
  5. package/.omc/state/agent-replay-8198b3e5-fad6-4ee0-9c59-ef773ad89af4.jsonl +1 -0
  6. package/.omc/state/agent-replay-8cd7652a-b8b5-49cf-9b1f-bee8e5972458.jsonl +3 -0
  7. package/.omc/state/agent-replay-9bea518f-a9ee-4d14-bb53-a936ebaf647c.jsonl +7 -0
  8. package/.omc/state/agent-replay-b52d89fb-0e24-4901-bc66-27e3c1697126.jsonl +2 -0
  9. package/.omc/state/agent-replay-f581a1ae-0ee4-48a3-96f3-ce31a0633bb0.jsonl +1 -0
  10. package/.omc/state/agent-replay-fe1057b4-9a25-4e8e-8c3f-3e11652ee697.jsonl +5 -0
  11. package/.omc/state/idle-notif-cooldown.json +1 -1
  12. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/last-tool-error-state.json +7 -0
  13. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/mission-state.json +109 -0
  14. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/pre-tool-advisory-throttle.json +42 -0
  15. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/ralph-state.json +13 -0
  16. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/skill-active-state.json +15 -0
  17. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/subagent-tracking-state.json +62 -0
  18. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/ultrawork-state.json +11 -0
  19. package/.omc/state/sessions/23d0ff82-17e5-428b-8743-38f7979bb6f3/last-tool-error-state.json +7 -0
  20. package/.omc/state/sessions/23d0ff82-17e5-428b-8743-38f7979bb6f3/pre-tool-advisory-throttle.json +18 -0
  21. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/last-tool-error-state.json +7 -0
  22. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/mission-state.json +145 -0
  23. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/pre-tool-advisory-throttle.json +38 -0
  24. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/ralplan-state.json +11 -0
  25. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/subagent-tracking-state.json +98 -0
  26. package/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/last-tool-error-state.json +7 -0
  27. package/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/pre-tool-advisory-throttle.json +18 -0
  28. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/mission-state.json +61 -0
  29. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/pre-tool-advisory-throttle.json +22 -0
  30. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/skill-active-state.json +15 -0
  31. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/subagent-tracking-state.json +26 -0
  32. package/.omc/state/sessions/8198b3e5-fad6-4ee0-9c59-ef773ad89af4/pre-tool-advisory-throttle.json +14 -0
  33. package/.omc/state/sessions/8198b3e5-fad6-4ee0-9c59-ef773ad89af4/subagent-tracking-state.json +17 -0
  34. package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/pre-tool-advisory-throttle.json +18 -0
  35. package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/ralplan-state.json +11 -0
  36. package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/subagent-tracking-state.json +35 -0
  37. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/last-tool-error-state.json +7 -0
  38. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/mission-state.json +79 -0
  39. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/pre-tool-advisory-throttle.json +22 -0
  40. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/progress.txt +7 -0
  41. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/skill-active-state.json +15 -0
  42. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/subagent-tracking-state.json +26 -0
  43. package/.omc/state/sessions/b52d89fb-0e24-4901-bc66-27e3c1697126/pre-tool-advisory-throttle.json +14 -0
  44. package/.omc/state/sessions/b52d89fb-0e24-4901-bc66-27e3c1697126/subagent-tracking-state.json +17 -0
  45. package/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/pre-tool-advisory-throttle.json +18 -0
  46. package/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/pre-tool-advisory-throttle.json +18 -0
  47. package/.omc/state/sessions/f581a1ae-0ee4-48a3-96f3-ce31a0633bb0/pre-tool-advisory-throttle.json +18 -0
  48. package/.omc/state/sessions/f581a1ae-0ee4-48a3-96f3-ce31a0633bb0/subagent-tracking-state.json +17 -0
  49. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/last-tool-error-state.json +7 -0
  50. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/mission-state.json +61 -0
  51. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/prd.json +22 -0
  52. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/pre-tool-advisory-throttle.json +22 -0
  53. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/progress.txt +22 -0
  54. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/skill-active-state.json +15 -0
  55. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/subagent-tracking-state.json +26 -0
  56. package/.turbo/turbo-build.log +3 -3
  57. package/.turbo/turbo-test.log +92 -44
  58. package/dist/boot-K4QUAFSP.js +2 -0
  59. package/dist/boot-K4QUAFSP.js.map +7 -0
  60. package/dist/chunk-RTSP2FCA.js +2 -0
  61. package/dist/chunk-RTSP2FCA.js.map +7 -0
  62. package/dist/chunk-VPBZR2PY.js +166 -0
  63. package/dist/chunk-VPBZR2PY.js.map +7 -0
  64. package/dist/cli.js +11 -107
  65. package/dist/cli.js.map +4 -4
  66. package/dist/entry/index.d.ts +2 -0
  67. package/dist/index.js +1 -1
  68. package/dist/index.js.map +4 -4
  69. package/dist/lib/vendor/config-schema.d.ts +58 -0
  70. package/dist/mcp.js +1 -54
  71. package/dist/mcp.js.map +4 -4
  72. package/eslint.config.js +33 -1
  73. package/package.json +5 -1
  74. package/scripts/build.js +11 -1
  75. package/src/.omc/state/agent-replay-c513ef38-cc3e-4a29-9c4c-1e0137245dd5.jsonl +4 -0
  76. package/src/.omc/state/agent-replay-ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a.jsonl +2 -0
  77. package/src/.omc/state/idle-notif-cooldown.json +1 -1
  78. package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/mission-state.json +79 -0
  79. package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/pre-tool-advisory-throttle.json +22 -0
  80. package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/subagent-tracking-state.json +26 -0
  81. package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/pre-tool-advisory-throttle.json +18 -0
  82. package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/ralph-state.json +13 -0
  83. package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/ultrawork-state.json +11 -0
  84. package/src/commands/config/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/last-tool-error-state.json +7 -0
  85. package/src/commands/config/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/pre-tool-advisory-throttle.json +18 -0
  86. package/src/commands/config/config.ts +7 -37
  87. package/src/commands/doctor/__tests__/agent-files.test.ts +8 -30
  88. package/src/commands/doctor/__tests__/check-legacy-user-global-config.test.ts +110 -0
  89. package/src/commands/doctor/doctor.ts +104 -44
  90. package/src/commands/env-autoload/env-autoload.ts +12 -0
  91. package/src/commands/env-autoload/index.ts +1 -0
  92. package/src/commands/env-clear/__tests__/env-clear.test.ts +27 -0
  93. package/src/commands/env-clear/env-clear.ts +22 -8
  94. package/src/commands/env-load/__tests__/env-load.test.ts +36 -1
  95. package/src/commands/env-load/env-load.ts +152 -35
  96. package/src/commands/env-load/index.ts +2 -1
  97. package/src/commands/env-status/__tests__/env-status.test.ts +78 -0
  98. package/src/commands/env-status/env-status.ts +19 -7
  99. package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +45 -1
  100. package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +46 -1
  101. package/src/commands/init/__tests__/agent-files.test.ts +145 -27
  102. package/src/commands/init/__tests__/migrate-config.test.ts +136 -5
  103. package/src/commands/init/__tests__/migrate-factory-config.test.ts +93 -0
  104. package/src/commands/init/__tests__/seed-user-global-config.test.ts +64 -0
  105. package/src/commands/init/__tests__/shell-body.test.ts +30 -0
  106. package/src/commands/init/agent-files.ts +65 -45
  107. package/src/commands/init/init.ts +140 -31
  108. package/src/commands/init/migrate-config.ts +160 -32
  109. package/src/commands/vendor-check/__tests__/runtime-isolation.test.ts +71 -0
  110. package/src/commands/vendor-check/__tests__/vendor-check.test.ts +87 -0
  111. package/src/commands/vendor-check/index.ts +1 -0
  112. package/src/commands/vendor-check/vendor-check.ts +127 -0
  113. package/src/commands/vendor-config/__tests__/vendor-config.test.ts +103 -0
  114. package/src/commands/vendor-config/index.ts +1 -0
  115. package/src/commands/vendor-config/vendor-config.ts +162 -0
  116. package/src/commands/vendor-diff/__tests__/vendor-diff.test.ts +74 -0
  117. package/src/commands/vendor-diff/index.ts +1 -0
  118. package/src/commands/vendor-diff/vendor-diff.ts +77 -0
  119. package/src/commands/vendor-manifest/index.ts +1 -0
  120. package/src/commands/vendor-manifest/vendor-manifest.ts +60 -0
  121. package/src/commands/vendor-sync/__tests__/vendor-write.test.ts +86 -0
  122. package/src/commands/vendor-sync/index.ts +1 -0
  123. package/src/commands/vendor-sync/vendor-sync.ts +90 -0
  124. package/src/commands/worktrees-add/worktrees-add.ts +1 -1
  125. package/src/commands/worktrees-reload/worktrees-reload.ts +6 -5
  126. package/src/commands/worktrees-remove/worktrees-remove.ts +10 -1
  127. package/src/commands/worktrees-sync/worktrees-sync.ts +9 -1
  128. package/src/entry/cli.ts +417 -210
  129. package/src/entry/index.ts +7 -1
  130. package/src/integrations/cmux/__tests__/open-workspace-with-layout.test.ts +127 -0
  131. package/src/integrations/cmux/close-workspace-by-title.ts +2 -2
  132. package/src/integrations/cmux/list-workspace-titles.ts +1 -1
  133. package/src/integrations/cmux/open-workspace-with-layout.ts +15 -4
  134. package/src/integrations/cursor/open-cursor-workspace.ts +6 -11
  135. package/src/integrations/doppler/__tests__/doppler-errors.test.ts +76 -0
  136. package/src/integrations/doppler/doppler-cli-auth.ts +12 -4
  137. package/src/integrations/doppler/doppler-errors.ts +88 -0
  138. package/src/integrations/doppler/doppler-project.ts +80 -0
  139. package/src/integrations/doppler/index.ts +3 -1
  140. package/src/integrations/gh/gh-cli-auth/gh-cli-auth.ts +9 -5
  141. package/src/integrations/gh/gh-release-prs/gh-release-prs.ts +16 -8
  142. package/src/integrations/ide/__tests__/ide-facade.test.ts +49 -10
  143. package/src/integrations/ide/open-ide-workspace.ts +6 -6
  144. package/src/integrations/ide/remove-ide-worktree-folders.ts +95 -30
  145. package/src/integrations/ide/types.ts +10 -1
  146. package/src/integrations/zed/__tests__/open-zed-workspace.test.ts +1 -17
  147. package/src/integrations/zed/__tests__/reuse-zed-workspace.test.ts +86 -0
  148. package/src/integrations/zed/index.ts +1 -0
  149. package/src/integrations/zed/open-zed-workspace.ts +4 -10
  150. package/src/integrations/zed/reuse-zed-workspace.ts +57 -0
  151. package/src/lib/command-catalog/__tests__/__snapshots__/command-catalog.test.ts.snap +212 -0
  152. package/src/lib/command-catalog/__tests__/command-catalog.test.ts +193 -0
  153. package/src/lib/command-catalog/command-catalog.ts +141 -0
  154. package/src/lib/command-catalog/index.ts +2 -0
  155. package/src/lib/command-echo/__tests__/command-echo.test.ts +127 -0
  156. package/src/lib/constants/constants.ts +13 -0
  157. package/src/lib/constants/index.ts +2 -0
  158. package/src/lib/env-autoload/__tests__/env-autoload.test.ts +288 -0
  159. package/src/lib/env-autoload/env-autoload.ts +294 -0
  160. package/src/lib/env-autoload/index.ts +9 -0
  161. package/src/lib/errors/operation-error.ts +1 -1
  162. package/src/lib/infra-kit-config/__tests__/env-autoload-schema.test.ts +71 -0
  163. package/src/lib/infra-kit-config/__tests__/infra-kit-config.test.ts +77 -6
  164. package/src/lib/infra-kit-config/index.ts +9 -1
  165. package/src/lib/infra-kit-config/infra-kit-config.ts +71 -11
  166. package/src/lib/json-output/__tests__/json-output.test.ts +139 -0
  167. package/src/lib/json-output/index.ts +1 -0
  168. package/src/lib/json-output/json-output.ts +47 -0
  169. package/src/lib/managed-block/managed-block.ts +4 -4
  170. package/src/lib/path-display/index.ts +1 -0
  171. package/src/lib/path-display/path-display.ts +42 -0
  172. package/src/lib/render/__tests__/render.test.ts +48 -0
  173. package/src/lib/render/index.ts +1 -0
  174. package/src/lib/render/render.ts +24 -0
  175. package/src/lib/vendor/__tests__/config-schema.test.ts +31 -0
  176. package/src/lib/vendor/__tests__/config.test.ts +63 -0
  177. package/src/lib/vendor/__tests__/factory-config.test.ts +92 -0
  178. package/src/lib/vendor/__tests__/vendor-lib.test.ts +158 -0
  179. package/src/lib/vendor/__tests__/zx-mock.ts +32 -0
  180. package/src/lib/vendor/config-schema.ts +78 -0
  181. package/src/lib/vendor/config.ts +58 -0
  182. package/src/lib/vendor/factory-config-schema.ts +35 -0
  183. package/src/lib/vendor/factory-config.ts +91 -0
  184. package/src/lib/vendor/hash.ts +16 -0
  185. package/src/lib/vendor/index.ts +23 -0
  186. package/src/lib/vendor/manifest.ts +151 -0
  187. package/src/lib/vendor/skip-sets.ts +48 -0
  188. package/src/lib/vendor/sync-ops.ts +290 -0
  189. package/src/lib/vendor/walk.ts +56 -0
  190. package/src/mcp/tools/index.ts +5 -42
  191. package/src/sanity.test.tsx +1 -0
  192. package/src/tui/__tests__/no-react-boundary.test.ts +51 -0
  193. package/src/tui/boot.tsx +45 -0
  194. package/src/tui/screens/__tests__/command-palette.test.tsx +136 -0
  195. package/src/tui/screens/command-palette.tsx +159 -0
  196. package/src/tui/types.ts +8 -0
  197. package/tsconfig.json +1 -0
  198. package/tsconfig.tsbuildinfo +1 -1
  199. package/vitest.config.ts +8 -0
  200. package/src/commands/worktrees-open/__tests__/open-cmux.test.ts +0 -96
  201. package/src/commands/worktrees-open/index.ts +0 -1
  202. package/src/commands/worktrees-open/worktrees-open.ts +0 -195
package/eslint.config.js CHANGED
@@ -1,3 +1,35 @@
1
1
  import config from '@wl/eslint-config'
2
2
 
3
- export default config()
3
+ /**
4
+ * No-React boundary: the entry/MCP/command code must never STATICALLY import the
5
+ * Ink TUI (or ink/react). The TUI is reached only via dynamic `await import()`
6
+ * from the TTY branch, so React stays off the MCP / `--json` / non-TTY paths.
7
+ * `no-restricted-imports` only flags static imports — dynamic import() is allowed.
8
+ */
9
+ const noTuiOnMachinePaths = {
10
+ files: ['src/entry/cli.ts', 'src/entry/mcp.ts', 'src/commands/**/*.ts', 'src/commands/**/*.tsx'],
11
+ rules: {
12
+ 'no-restricted-imports': [
13
+ 'error',
14
+ {
15
+ paths: [
16
+ { name: 'ink', message: 'Do not import ink outside src/tui/* — load the TUI via dynamic import().' },
17
+ { name: 'react', message: 'Do not import react outside src/tui/* — load the TUI via dynamic import().' },
18
+ ],
19
+ patterns: [
20
+ {
21
+ group: ['src/tui', 'src/tui/*', '**/tui', '**/tui/*'],
22
+ message:
23
+ 'Do not statically import the Ink TUI from CLI/MCP/command code; use a dynamic import() in the TTY branch.',
24
+ },
25
+ ],
26
+ },
27
+ ],
28
+ },
29
+ }
30
+
31
+ // `config()` returns a Promise resolving to the flat-config array; ESLint awaits
32
+ // the default export, so resolve it and append our local boundary rule.
33
+ export default config().then((base) => {
34
+ return [...base, noTuiOnMachinePaths]
35
+ })
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.1.114",
4
+ "version": "0.1.115",
5
5
  "description": "infra-kit",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -42,16 +42,20 @@
42
42
  "@inquirer/select": "^5.2.1",
43
43
  "@modelcontextprotocol/sdk": "^1.29.0",
44
44
  "commander": "^15.0.0",
45
+ "ink": "^7.1.0",
45
46
  "pino": "^10.3.1",
46
47
  "pino-pretty": "^13.1.3",
48
+ "react": "catalog:",
47
49
  "yaml": "^2.9.0",
48
50
  "zod": "^4.4.3",
49
51
  "zx": "^8.8.5"
50
52
  },
51
53
  "devDependencies": {
54
+ "@types/react": "catalog:",
52
55
  "@wl/eslint-config": "workspace:*",
53
56
  "@wl/vitest-config": "workspace:*",
54
57
  "esbuild": "^0.28.1",
58
+ "ink-testing-library": "^4.0.0",
55
59
  "typescript": "^6.0.3"
56
60
  }
57
61
  }
package/scripts/build.js CHANGED
@@ -28,7 +28,17 @@ await esbuild.build({
28
28
  outdir: OUT_DIR,
29
29
  sourcemap: true,
30
30
  minify: true,
31
- external: Object.keys(packageJson.dependencies),
31
+ // `splitting` is required so the dynamically-imported Ink TUI (src/tui/*) lands
32
+ // in a separate lazy chunk. Without it, the auto-injected `react/jsx-runtime`
33
+ // import would be hoisted into the eager cli.js/mcp.js bundle and load React on
34
+ // every invocation — breaking the "no React on machine paths" guarantee.
35
+ splitting: true,
36
+ // Automatic JSX runtime so .tsx needs no `import React`. Pairs with
37
+ // tsconfig `"jsx": "react-jsx"`.
38
+ jsx: 'automatic',
39
+ // Externalize deps + the React JSX runtime subpaths (the `react` key alone
40
+ // does not cover subpaths in esbuild's external matching).
41
+ external: [...Object.keys(packageJson.dependencies), 'react/jsx-runtime', 'react/jsx-dev-runtime'],
32
42
  })
33
43
 
34
44
  for (const entryPoint of entryPoints) {
@@ -0,0 +1,4 @@
1
+ {"t":0,"agent":"a6f037b","agent_type":"architect","event":"agent_start","parent_mode":"none"}
2
+ {"t":0,"agent":"a6f037b","agent_type":"architect","event":"agent_stop","success":true,"duration_ms":132042}
3
+ {"t":0,"agent":"ac9a1b4","agent_type":"critic","event":"agent_start","parent_mode":"none"}
4
+ {"t":0,"agent":"ac9a1b4","agent_type":"critic","event":"agent_stop","success":true,"duration_ms":236050}
@@ -0,0 +1,2 @@
1
+ {"t":0,"agent":"system","event":"keyword_detected","keyword":"ralph"}
2
+ {"t":0,"agent":"system","event":"mode_change","mode_from":"none","mode_to":"ralph"}
@@ -1,3 +1,3 @@
1
1
  {
2
- "lastSentAt": "2026-06-21T11:09:39.757Z"
2
+ "lastSentAt": "2026-06-22T13:44:36.933Z"
3
3
  }
@@ -0,0 +1,79 @@
1
+ {
2
+ "updatedAt": "2026-06-27T13:35:47.967Z",
3
+ "missions": [
4
+ {
5
+ "id": "session:c513ef38-cc3e-4a29-9c4c-1e0137245dd5:none",
6
+ "source": "session",
7
+ "name": "none",
8
+ "objective": "Session mission",
9
+ "createdAt": "2026-06-27T13:29:10.793Z",
10
+ "updatedAt": "2026-06-27T13:35:47.967Z",
11
+ "status": "done",
12
+ "workerCount": 2,
13
+ "taskCounts": {
14
+ "total": 2,
15
+ "pending": 0,
16
+ "blocked": 0,
17
+ "inProgress": 0,
18
+ "completed": 2,
19
+ "failed": 0
20
+ },
21
+ "agents": [
22
+ {
23
+ "name": "architect:a6f037b",
24
+ "role": "architect",
25
+ "ownership": "a6f037b2aebb4ef11",
26
+ "status": "done",
27
+ "currentStep": null,
28
+ "latestUpdate": "completed",
29
+ "completedSummary": null,
30
+ "updatedAt": "2026-06-27T13:31:22.835Z"
31
+ },
32
+ {
33
+ "name": "critic:ac9a1b4",
34
+ "role": "critic",
35
+ "ownership": "ac9a1b43d56c3ca70",
36
+ "status": "done",
37
+ "currentStep": null,
38
+ "latestUpdate": "completed",
39
+ "completedSummary": null,
40
+ "updatedAt": "2026-06-27T13:35:47.967Z"
41
+ }
42
+ ],
43
+ "timeline": [
44
+ {
45
+ "id": "session-start:a6f037b2aebb4ef11:2026-06-27T13:29:10.793Z",
46
+ "at": "2026-06-27T13:29:10.793Z",
47
+ "kind": "update",
48
+ "agent": "architect:a6f037b",
49
+ "detail": "started architect:a6f037b",
50
+ "sourceKey": "session-start:a6f037b2aebb4ef11"
51
+ },
52
+ {
53
+ "id": "session-stop:a6f037b2aebb4ef11:2026-06-27T13:31:22.835Z",
54
+ "at": "2026-06-27T13:31:22.835Z",
55
+ "kind": "completion",
56
+ "agent": "architect:a6f037b",
57
+ "detail": "completed",
58
+ "sourceKey": "session-stop:a6f037b2aebb4ef11"
59
+ },
60
+ {
61
+ "id": "session-start:ac9a1b43d56c3ca70:2026-06-27T13:31:51.917Z",
62
+ "at": "2026-06-27T13:31:51.917Z",
63
+ "kind": "update",
64
+ "agent": "critic:ac9a1b4",
65
+ "detail": "started critic:ac9a1b4",
66
+ "sourceKey": "session-start:ac9a1b43d56c3ca70"
67
+ },
68
+ {
69
+ "id": "session-stop:ac9a1b43d56c3ca70:2026-06-27T13:35:47.967Z",
70
+ "at": "2026-06-27T13:35:47.967Z",
71
+ "kind": "completion",
72
+ "agent": "critic:ac9a1b4",
73
+ "detail": "completed",
74
+ "sourceKey": "session-stop:ac9a1b43d56c3ca70"
75
+ }
76
+ ]
77
+ }
78
+ ]
79
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": 1,
3
+ "entries": {
4
+ "79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
5
+ "last_emitted_at_ms": 1782567157541,
6
+ "message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
7
+ },
8
+ "466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
9
+ "last_emitted_at_ms": 1782567145707,
10
+ "message": "Read multiple files in parallel when possible for faster analysis."
11
+ },
12
+ "f5aaba48c1f35bcc584c1486fcb615715c685334220b3f63e3c02d30e32e3273": {
13
+ "last_emitted_at_ms": 1782567111776,
14
+ "message": "Spawning agent: oh-my-claudecode:critic (opus) | Task: Critic evaluation of validation plan"
15
+ },
16
+ "2bbd4e7762c885bc584b86ba2061c9117aeda36cd34b8641a610e68d917fb1cc": {
17
+ "last_emitted_at_ms": 1782566950662,
18
+ "message": "Spawning agent: oh-my-claudecode:architect (opus) | Task: Architect review of validation plan"
19
+ }
20
+ },
21
+ "updated_at": "2026-06-27T13:32:37.541Z"
22
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "agents": [
3
+ {
4
+ "agent_id": "a6f037b2aebb4ef11",
5
+ "agent_type": "oh-my-claudecode:architect",
6
+ "started_at": "2026-06-27T13:29:10.793Z",
7
+ "parent_mode": "none",
8
+ "status": "completed",
9
+ "completed_at": "2026-06-27T13:31:22.835Z",
10
+ "duration_ms": 132042
11
+ },
12
+ {
13
+ "agent_id": "ac9a1b43d56c3ca70",
14
+ "agent_type": "oh-my-claudecode:critic",
15
+ "started_at": "2026-06-27T13:31:51.917Z",
16
+ "parent_mode": "none",
17
+ "status": "completed",
18
+ "completed_at": "2026-06-27T13:35:47.967Z",
19
+ "duration_ms": 236050
20
+ }
21
+ ],
22
+ "total_spawned": 2,
23
+ "total_completed": 2,
24
+ "total_failed": 0,
25
+ "last_updated": "2026-06-27T13:35:48.069Z"
26
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "version": 1,
3
+ "entries": {
4
+ "445ed27a3872b681d98190bae61ccb84954e1bc4e140df5370be958dee776b3a": {
5
+ "last_emitted_at_ms": 1782136131240,
6
+ "message": "Verify changes work after editing. Test functionality before marking complete."
7
+ },
8
+ "79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
9
+ "last_emitted_at_ms": 1782136112436,
10
+ "message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
11
+ },
12
+ "466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
13
+ "last_emitted_at_ms": 1782136101980,
14
+ "message": "Read multiple files in parallel when possible for faster analysis."
15
+ }
16
+ },
17
+ "updated_at": "2026-06-22T13:48:51.240Z"
18
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "active": true,
3
+ "iteration": 1,
4
+ "max_iterations": 100,
5
+ "started_at": "2026-06-22T13:48:06.524Z",
6
+ "prompt": "/ralph do it",
7
+ "session_id": "ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a",
8
+ "project_path": "/Users/arthur/projects/infra-kit/apps/infra-kit/cli/src",
9
+ "linked_ultrawork": true,
10
+ "awaiting_confirmation": true,
11
+ "awaiting_confirmation_set_at": "2026-06-22T13:48:06.524Z",
12
+ "last_checked_at": "2026-06-22T13:48:06.524Z"
13
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "active": true,
3
+ "started_at": "2026-06-22T13:48:06.540Z",
4
+ "original_prompt": "/ralph do it",
5
+ "session_id": "ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a",
6
+ "project_path": "/Users/arthur/projects/infra-kit/apps/infra-kit/cli/src",
7
+ "reinforcement_count": 0,
8
+ "awaiting_confirmation": true,
9
+ "awaiting_confirmation_set_at": "2026-06-22T13:48:06.540Z",
10
+ "last_checked_at": "2026-06-22T13:48:06.540Z"
11
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "tool_name": "Bash",
3
+ "tool_input_preview": "{\"command\":\"cd src/commands/init && echo \\\"=== os. usage (excl import/comment) ===\\\" && rtk grep -n \\\"os\\\\.\\\" migrate-config.ts | grep -v \\\"node:os\\\" | grep -v \\\"homedir()\\\"; echo \\\"--- all os. lines ...",
4
+ "error": "Exit code 2\n(eval):cd:1: no such file or directory: src/commands/init\n--- all os. lines ---\ngrep: migrate-config.ts: No such file or directory\n0 matches for 'os\\.'\n=== fs. usage count ===\ngrep: migrate-config.ts: No such file or directory",
5
+ "timestamp": "2026-06-25T14:31:26.386Z",
6
+ "retry_count": 1
7
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "version": 1,
3
+ "entries": {
4
+ "79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
5
+ "last_emitted_at_ms": 1782397886227,
6
+ "message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
7
+ },
8
+ "466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
9
+ "last_emitted_at_ms": 1782397881323,
10
+ "message": "Read multiple files in parallel when possible for faster analysis."
11
+ },
12
+ "445ed27a3872b681d98190bae61ccb84954e1bc4e140df5370be958dee776b3a": {
13
+ "last_emitted_at_ms": 1782397873064,
14
+ "message": "Verify changes work after editing. Test functionality before marking complete."
15
+ }
16
+ },
17
+ "updated_at": "2026-06-25T14:31:26.227Z"
18
+ }
@@ -1,45 +1,13 @@
1
1
  import fs from 'node:fs/promises'
2
- import os from 'node:os'
3
2
  import path from 'node:path'
4
3
  import process from 'node:process'
5
4
  import { $ } from 'zx'
6
5
 
7
6
  import { getInfraKitConfigPaths, resetInfraKitConfigCache } from 'src/lib/infra-kit-config'
8
7
  import { logger } from 'src/lib/logger'
8
+ import { fileExists, tildify } from 'src/lib/path-display'
9
9
  import type { ToolsExecutionResult } from 'src/types'
10
10
 
11
- /**
12
- * Resolve whether a file is reachable, suppressing ENOENT into a boolean.
13
- *
14
- * @example
15
- * await fileExists('/etc/hosts') // => true
16
- * await fileExists('/nope.txt') // => false
17
- */
18
- const fileExists = async (filePath: string): Promise<boolean> => {
19
- try {
20
- await fs.access(filePath)
21
-
22
- return true
23
- } catch {
24
- return false
25
- }
26
- }
27
-
28
- /**
29
- * Replace the user's home prefix with `~` so logged paths stay short and
30
- * portable across machines. Leaves non-home paths untouched.
31
- *
32
- * @example
33
- * // os.homedir() === '/Users/arthur'
34
- * tildify('/Users/arthur/.infra-kit/config.json') // => '~/.infra-kit/config.json'
35
- * tildify('/etc/hosts') // => '/etc/hosts'
36
- */
37
- const tildify = (filePath: string): string => {
38
- const home = os.homedir()
39
-
40
- return filePath.startsWith(home) ? `~${filePath.slice(home.length)}` : filePath
41
- }
42
-
43
11
  /**
44
12
  * Print the file paths that participate in the config merge chain along with
45
13
  * existence markers, so the user can see at a glance which override layers
@@ -50,7 +18,7 @@ const tildify = (filePath: string): string => {
50
18
  * // INFO: Project name: api
51
19
  * // INFO: Config merge chain (later overrides earlier):
52
20
  * // INFO: [✓] project (committed) ~/projects/api/infra-kit.json
53
- * // INFO: [ ] user global ~/.infra-kit/config.json
21
+ * // INFO: [ ] user global ~/.infra-kit/infra-kit.json
54
22
  * // INFO: [✓] user project ~/.infra-kit/projects/api/infra-kit.json
55
23
  */
56
24
  export const configPath = async (): Promise<ToolsExecutionResult> => {
@@ -155,13 +123,15 @@ const buildUserProjectExample = (projectName: string): string => {
155
123
  return `// infra-kit user override for ${projectName} — ~/.infra-kit/projects/${projectName}/infra-kit.json
156
124
  //
157
125
  // Layer 3 (highest precedence) of the config merge chain. Shallow-merged on top
158
- // of <repo>/infra-kit.json and ~/.infra-kit/config.json — top-level keys
159
- // (environments, envManagement, ide, taskManager, worktrees) replace wholesale.
126
+ // of <repo>/infra-kit.json and ~/.infra-kit/infra-kit.json — top-level keys
127
+ // (environments, envManagement, ide, taskManager, worktrees, envAutoLoad) replace wholesale.
160
128
  //
161
129
  // This .example.jsonc is reference only — it is NOT loaded. Put real overrides
162
130
  // in the sibling infra-kit.json (strict JSON: no comments, double-quoted keys).
163
131
  {
164
- // "worktrees": { "openInGithubDesktop": false, "openInCmux": true }
132
+ // "worktrees": { "openInGithubDesktop": false, "openInCmux": true, "cmux": { "layout": "two-columns" } },
133
+ // // Auto-load Doppler env here. trigger (pick one): shell-startup | cli-invocation; config: an environment name.
134
+ // "envAutoLoad": { "trigger": "shell-startup", "config": "dev" }
165
135
  }
166
136
  `
167
137
  }
@@ -61,50 +61,28 @@ describe('checkAgentFiles', () => {
61
61
  )
62
62
  })
63
63
 
64
- it('passes all three checks right after init runs the agent-files step', async () => {
64
+ it('checks only CLAUDE.md after init runs the agent-files step — no AGENTS.md or .cursor check', async () => {
65
65
  await withTmpRepo(async () => {
66
66
  await writeAgentFiles()
67
67
 
68
68
  const checks = await checkAgentFiles()
69
69
 
70
- expect(statusOf(checks, 'AGENTS.md block')).toBe('pass')
71
- expect(statusOf(checks, 'CLAUDE.md import')).toBe('pass')
72
- expect(statusOf(checks, '.cursor/rules block')).toBe('pass')
70
+ expect(checks).toHaveLength(1)
71
+ expect(statusOf(checks, 'CLAUDE.md block')).toBe('pass')
72
+ // The legacy AGENTS.md and .cursor/rules checks no longer exist.
73
+ expect(statusOf(checks, 'AGENTS.md block')).toBeUndefined()
74
+ expect(statusOf(checks, '.cursor/rules block')).toBeUndefined()
73
75
  })
74
76
  })
75
77
 
76
- it('flags AGENTS.md present but CLAUDE.md import removed', async () => {
78
+ it('flags a missing CLAUDE.md block', async () => {
77
79
  await withTmpRepo(async (tmp) => {
78
80
  await writeAgentFiles()
79
- // User deletes CLAUDE.md (drops the @AGENTS.md import) but keeps AGENTS.md.
80
81
  fs.rmSync(path.join(tmp, 'CLAUDE.md'))
81
82
 
82
83
  const checks = await checkAgentFiles()
83
84
 
84
- expect(statusOf(checks, 'AGENTS.md block')).toBe('pass')
85
- expect(statusOf(checks, 'CLAUDE.md import')).toBe('fail')
86
- })
87
- })
88
-
89
- it('flags a missing .cursor/rules block', async () => {
90
- await withTmpRepo(async (tmp) => {
91
- await writeAgentFiles()
92
- fs.rmSync(path.join(tmp, '.cursor', 'rules', 'infra-kit.mdc'))
93
-
94
- const checks = await checkAgentFiles()
95
-
96
- expect(statusOf(checks, '.cursor/rules block')).toBe('fail')
97
- })
98
- })
99
-
100
- it('flags a missing AGENTS.md block', async () => {
101
- await withTmpRepo(async (tmp) => {
102
- await writeAgentFiles()
103
- fs.rmSync(path.join(tmp, 'AGENTS.md'))
104
-
105
- const checks = await checkAgentFiles()
106
-
107
- expect(statusOf(checks, 'AGENTS.md block')).toBe('fail')
85
+ expect(statusOf(checks, 'CLAUDE.md block')).toBe('fail')
108
86
  })
109
87
  })
110
88
  })
@@ -0,0 +1,110 @@
1
+ import fs from 'node:fs'
2
+ import os from 'node:os'
3
+ import path from 'node:path'
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
5
+
6
+ import { checkLegacyUserGlobalConfig } from '../doctor'
7
+
8
+ const cfg = vi.hoisted(() => {
9
+ return { userGlobal: '', shouldThrow: false }
10
+ })
11
+
12
+ vi.mock('src/lib/infra-kit-config', () => {
13
+ return {
14
+ getInfraKitConfig: vi.fn(),
15
+ resetInfraKitConfigCache: vi.fn(),
16
+ resolveConfiguredIdes: vi.fn(() => {
17
+ return []
18
+ }),
19
+ getInfraKitConfigPaths: vi.fn(() => {
20
+ if (cfg.shouldThrow) {
21
+ return Promise.reject(new Error('no repo'))
22
+ }
23
+
24
+ return Promise.resolve({
25
+ main: '',
26
+ userGlobal: cfg.userGlobal,
27
+ userProject: '',
28
+ projectName: 'api',
29
+ })
30
+ }),
31
+ }
32
+ })
33
+
34
+ vi.mock('src/lib/logger', () => {
35
+ return { logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() } }
36
+ })
37
+
38
+ const withTmpHome = async (fn: (dir: string) => Promise<void>): Promise<void> => {
39
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'infra-kit-doctor-legacy-test-'))
40
+ const dir = path.join(tmp, '.infra-kit')
41
+
42
+ fs.mkdirSync(dir, { recursive: true })
43
+ cfg.userGlobal = path.join(dir, 'infra-kit.json')
44
+ const homedirSpy = vi.spyOn(os, 'homedir').mockReturnValue(tmp)
45
+
46
+ try {
47
+ await fn(dir)
48
+ } finally {
49
+ homedirSpy.mockRestore()
50
+ fs.rmSync(tmp, { recursive: true, force: true })
51
+ }
52
+ }
53
+
54
+ describe('checkLegacyUserGlobalConfig', () => {
55
+ beforeEach(() => {
56
+ cfg.shouldThrow = false
57
+ vi.clearAllMocks()
58
+ })
59
+
60
+ afterEach(() => {
61
+ vi.clearAllMocks()
62
+ })
63
+
64
+ it('fails with a migrate message when only config.json exists (overrides not applied)', async () => {
65
+ await withTmpHome(async (dir) => {
66
+ fs.writeFileSync(path.join(dir, 'config.json'), '{}\n')
67
+
68
+ const result = await checkLegacyUserGlobalConfig()
69
+
70
+ expect(result.status).toBe('fail')
71
+ expect(result.message).toMatch(/run `infra-kit init` to migrate/)
72
+ expect(result.message).toMatch(/not being applied/)
73
+ })
74
+ })
75
+
76
+ it('fails with a stale message when both config.json and infra-kit.json exist', async () => {
77
+ await withTmpHome(async (dir) => {
78
+ fs.writeFileSync(path.join(dir, 'config.json'), '{}\n')
79
+ fs.writeFileSync(path.join(dir, 'infra-kit.json'), '{}\n')
80
+
81
+ const result = await checkLegacyUserGlobalConfig()
82
+
83
+ expect(result.status).toBe('fail')
84
+ expect(result.message).toMatch(/Stale legacy config\.json/)
85
+ expect(result.message).toMatch(/remove the old file/)
86
+ // Must NOT falsely claim overrides aren't applied — infra-kit.json is active.
87
+ expect(result.message).not.toMatch(/not being applied/)
88
+ })
89
+ })
90
+
91
+ it('passes when there is no legacy config.json', async () => {
92
+ await withTmpHome(async (dir) => {
93
+ fs.writeFileSync(path.join(dir, 'infra-kit.json'), '{}\n')
94
+
95
+ const result = await checkLegacyUserGlobalConfig()
96
+
97
+ expect(result.status).toBe('pass')
98
+ expect(result.message).toMatch(/No legacy user-global config\.json/)
99
+ })
100
+ })
101
+
102
+ it('passes informationally when the config paths cannot be resolved', async () => {
103
+ cfg.shouldThrow = true
104
+
105
+ const result = await checkLegacyUserGlobalConfig()
106
+
107
+ expect(result.status).toBe('pass')
108
+ expect(result.message).toMatch(/Skipped/)
109
+ })
110
+ })