gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00

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 (545) hide show
  1. package/README.md +53 -17
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/github-sync/templates.js +103 -0
  15. package/dist/resources/extensions/google-search/index.js +3 -2
  16. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  17. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  18. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  19. package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
  20. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
  22. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  23. package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
  24. package/dist/resources/extensions/gsd/auto-start.js +107 -29
  25. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  26. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  27. package/dist/resources/extensions/gsd/auto.js +76 -21
  28. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  30. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  31. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  33. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  34. package/dist/resources/extensions/gsd/component-types.js +69 -0
  35. package/dist/resources/extensions/gsd/context-store.js +23 -7
  36. package/dist/resources/extensions/gsd/detection.js +49 -1
  37. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
  38. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  39. package/dist/resources/extensions/gsd/forensics.js +106 -0
  40. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  41. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  42. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  43. package/dist/resources/extensions/gsd/git-service.js +126 -2
  44. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  45. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  46. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  47. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  48. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  49. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  50. package/dist/resources/extensions/gsd/model-router.js +6 -0
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  53. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  58. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  59. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  60. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  61. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  62. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  64. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  65. package/dist/resources/extensions/gsd/state.js +69 -58
  66. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  68. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  69. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  70. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  73. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  75. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  77. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  79. package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  82. package/dist/resources/extensions/mcp-client/index.js +3 -1
  83. package/dist/resources/extensions/ollama/index.js +5 -1
  84. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  88. package/dist/web/standalone/.next/build-manifest.json +2 -2
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  115. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  116. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/package.json +2 -3
  123. package/packages/daemon/package.json +2 -2
  124. package/packages/daemon/src/logger.ts +4 -3
  125. package/packages/mcp-server/dist/server.d.ts +24 -0
  126. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/server.js +88 -87
  128. package/packages/mcp-server/dist/server.js.map +1 -1
  129. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  130. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  131. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  132. package/packages/mcp-server/package.json +2 -2
  133. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  134. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  135. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  136. package/packages/mcp-server/src/server.ts +131 -105
  137. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  138. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  139. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  140. package/packages/native/package.json +2 -2
  141. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  142. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  143. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  144. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  145. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  146. package/packages/pi-agent-core/package.json +1 -1
  147. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  148. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  149. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  150. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  152. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  153. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  154. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  155. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  156. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  158. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  159. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  160. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  161. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  162. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  163. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  164. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  165. package/packages/pi-ai/dist/models.test.js +36 -11
  166. package/packages/pi-ai/dist/models.test.js.map +1 -1
  167. package/packages/pi-ai/package.json +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  169. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  170. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  171. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  172. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  173. package/packages/pi-ai/src/models.test.ts +48 -11
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  176. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  178. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  182. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  186. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  190. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  197. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  199. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  201. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  203. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/index.js +1 -0
  207. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  230. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  231. package/packages/pi-coding-agent/package.json +1 -1
  232. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  233. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  234. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  235. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  236. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  237. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  238. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  239. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  240. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  241. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  242. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  243. package/packages/pi-coding-agent/src/index.ts +1 -0
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  245. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  246. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  247. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  248. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  249. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  251. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  254. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  255. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  256. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  257. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
  258. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  259. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  260. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  261. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  262. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  263. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  264. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  265. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  266. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  267. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  268. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/editor.js +19 -0
  270. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  271. package/packages/pi-tui/dist/components/image.test.js +6 -5
  272. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  273. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  274. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  275. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  276. package/packages/pi-tui/package.json +1 -1
  277. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  278. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  279. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
  280. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  281. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  282. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  283. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  284. package/packages/pi-tui/src/components/editor.ts +22 -0
  285. package/packages/pi-tui/src/components/image.test.ts +10 -5
  286. package/packages/pi-tui/src/editor-component.ts +3 -0
  287. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  288. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  289. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  290. package/packages/rpc-client/package.json +1 -1
  291. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  292. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  293. package/pkg/package.json +1 -1
  294. package/scripts/install.js +15 -1
  295. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  296. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  297. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  298. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  299. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  300. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  301. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  302. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  303. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  304. package/src/resources/extensions/github-sync/templates.ts +151 -0
  305. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  306. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  307. package/src/resources/extensions/google-search/index.ts +3 -2
  308. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  309. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  310. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  311. package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
  312. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  313. package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
  314. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  315. package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
  316. package/src/resources/extensions/gsd/auto-start.ts +127 -9
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  318. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  319. package/src/resources/extensions/gsd/auto.ts +90 -23
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  322. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  323. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  324. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  325. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  326. package/src/resources/extensions/gsd/component-types.ts +362 -0
  327. package/src/resources/extensions/gsd/context-store.ts +25 -8
  328. package/src/resources/extensions/gsd/detection.ts +58 -1
  329. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  331. package/src/resources/extensions/gsd/forensics.ts +118 -1
  332. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  333. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  334. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  335. package/src/resources/extensions/gsd/git-service.ts +149 -2
  336. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  338. package/src/resources/extensions/gsd/journal.ts +11 -1
  339. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  340. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  341. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  342. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  343. package/src/resources/extensions/gsd/model-router.ts +6 -0
  344. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  345. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  346. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  347. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  348. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  349. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  350. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  351. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  352. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  353. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  354. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  355. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  356. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  357. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  358. package/src/resources/extensions/gsd/state.ts +76 -66
  359. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  360. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  361. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  362. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  363. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  364. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
  365. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  366. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  367. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  368. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  369. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  370. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  371. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  372. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  373. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  374. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  375. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  376. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  377. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  378. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  379. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  380. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  381. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  382. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  383. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  384. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  385. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  386. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  389. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  390. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  391. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  392. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  394. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  395. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  396. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  397. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  398. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
  399. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  400. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  401. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  402. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  403. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  404. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  405. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  406. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  407. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  408. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
  410. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  411. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  412. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  413. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  415. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  416. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  417. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  419. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  420. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  421. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  422. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  423. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  424. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  425. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  426. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  427. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  428. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  429. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  430. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  431. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  432. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  434. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  437. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  439. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  440. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  442. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  443. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  444. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  445. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  446. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  447. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  448. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  449. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  451. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  452. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  453. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  454. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  455. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  456. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  457. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  458. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  459. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  460. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  461. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  462. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  463. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  464. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  465. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  466. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  467. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  468. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  469. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  470. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  471. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  472. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  473. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  474. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  475. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  476. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  477. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  478. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  479. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  481. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  482. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  483. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  484. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  485. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
  486. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  487. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  488. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  489. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  490. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  491. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  492. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  493. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  494. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  495. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  496. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  497. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  498. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  499. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  500. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  501. package/src/resources/extensions/gsd/types.ts +3 -3
  502. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  503. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  504. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  505. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  506. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  507. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  508. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  509. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  510. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  511. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  512. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  514. package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
  515. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  516. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  517. package/src/resources/extensions/mcp-client/index.ts +3 -1
  518. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  519. package/src/resources/extensions/ollama/index.ts +5 -1
  520. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  522. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  523. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  524. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  525. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  526. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  527. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  528. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  529. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  530. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  531. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  532. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  533. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  534. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  535. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  536. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  537. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  538. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  539. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  540. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  541. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  542. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  543. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  544. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  545. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -0,0 +1,447 @@
1
+ /**
2
+ * Component Loader
3
+ *
4
+ * Multi-format loader that handles:
5
+ * 1. New format: component.yaml + SKILL.md/AGENT.md
6
+ * 2. Legacy skill format: SKILL.md with YAML frontmatter
7
+ * 3. Legacy agent format: .md with YAML frontmatter (name, description, tools, model)
8
+ *
9
+ * Auto-detects format by checking for component.yaml first, then falling back
10
+ * to legacy formats based on file naming conventions.
11
+ */
12
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
13
+ import { basename, dirname, join } from 'node:path';
14
+ import { parse as parseYaml } from 'yaml';
15
+ import { parseFrontmatter } from '@gsd/pi-coding-agent';
16
+ import { validateComponentName, validateComponentDescription, computeComponentId, } from './component-types.js';
17
+ const SUPPORTED_COMPONENT_KINDS = ['skill', 'agent'];
18
+ const SUPPORTED_API_VERSIONS = ['gsd/v1'];
19
+ // ============================================================================
20
+ // Single Component Loading
21
+ // ============================================================================
22
+ /**
23
+ * Load a component from a directory.
24
+ * Checks for component.yaml first, then legacy formats.
25
+ */
26
+ export function loadComponentFromDir(dir, source) {
27
+ const diagnostics = [];
28
+ // Try new format first: component.yaml
29
+ const componentYamlPath = join(dir, 'component.yaml');
30
+ if (existsSync(componentYamlPath)) {
31
+ return loadFromComponentYaml(componentYamlPath, dir, source);
32
+ }
33
+ // Try legacy skill format: SKILL.md
34
+ const skillMdPath = join(dir, 'SKILL.md');
35
+ if (existsSync(skillMdPath)) {
36
+ return loadFromLegacySkill(skillMdPath, dir, source);
37
+ }
38
+ // No recognized component format found
39
+ return { component: null, diagnostics };
40
+ }
41
+ /**
42
+ * Load a component from a legacy agent .md file (flat file, not directory).
43
+ */
44
+ export function loadComponentFromAgentFile(filePath, source) {
45
+ return loadFromLegacyAgent(filePath, source);
46
+ }
47
+ // ============================================================================
48
+ // New Format: component.yaml
49
+ // ============================================================================
50
+ function loadFromComponentYaml(yamlPath, dir, source) {
51
+ const diagnostics = [];
52
+ let raw;
53
+ try {
54
+ raw = readFileSync(yamlPath, 'utf-8');
55
+ }
56
+ catch (error) {
57
+ const msg = error instanceof Error ? error.message : 'failed to read component.yaml';
58
+ diagnostics.push({ type: 'error', message: msg, path: yamlPath });
59
+ return { component: null, diagnostics };
60
+ }
61
+ let definition;
62
+ try {
63
+ definition = parseYaml(raw);
64
+ }
65
+ catch (error) {
66
+ const msg = error instanceof Error ? error.message : 'failed to parse component.yaml';
67
+ diagnostics.push({ type: 'error', message: `invalid YAML: ${msg}`, path: yamlPath });
68
+ return { component: null, diagnostics };
69
+ }
70
+ // Validate required fields
71
+ if (!definition?.apiVersion) {
72
+ diagnostics.push({ type: 'error', message: 'missing apiVersion', path: yamlPath });
73
+ return { component: null, diagnostics };
74
+ }
75
+ if (!SUPPORTED_API_VERSIONS.includes(definition.apiVersion)) {
76
+ diagnostics.push({
77
+ type: 'error',
78
+ message: `unsupported apiVersion "${String(definition.apiVersion)}"`,
79
+ path: yamlPath,
80
+ });
81
+ return { component: null, diagnostics };
82
+ }
83
+ if (!definition.kind) {
84
+ diagnostics.push({ type: 'error', message: 'missing kind', path: yamlPath });
85
+ return { component: null, diagnostics };
86
+ }
87
+ if (!SUPPORTED_COMPONENT_KINDS.includes(definition.kind)) {
88
+ diagnostics.push({
89
+ type: 'error',
90
+ message: `unsupported kind "${definition.kind}"`,
91
+ path: yamlPath,
92
+ });
93
+ return { component: null, diagnostics };
94
+ }
95
+ if (!definition.metadata?.name) {
96
+ diagnostics.push({ type: 'error', message: 'missing metadata.name', path: yamlPath });
97
+ return { component: null, diagnostics };
98
+ }
99
+ if (!definition.metadata?.description) {
100
+ diagnostics.push({ type: 'error', message: 'missing metadata.description', path: yamlPath });
101
+ return { component: null, diagnostics };
102
+ }
103
+ const nameErrors = validateComponentName(definition.metadata.name);
104
+ for (const err of nameErrors) {
105
+ diagnostics.push({ type: 'error', message: err, path: yamlPath });
106
+ }
107
+ const descErrors = validateComponentDescription(definition.metadata.description);
108
+ for (const err of descErrors) {
109
+ diagnostics.push({ type: 'error', message: err, path: yamlPath });
110
+ }
111
+ if (nameErrors.length > 0 || descErrors.length > 0) {
112
+ return { component: null, diagnostics };
113
+ }
114
+ // Validate kind-specific spec
115
+ if (!definition.spec) {
116
+ diagnostics.push({ type: 'error', message: 'missing spec', path: yamlPath });
117
+ return { component: null, diagnostics };
118
+ }
119
+ const entryFileDiagnostic = validateEntryFile(definition.kind, definition.spec, dir, yamlPath);
120
+ if (entryFileDiagnostic) {
121
+ diagnostics.push(entryFileDiagnostic);
122
+ return { component: null, diagnostics };
123
+ }
124
+ const id = computeComponentId(definition.metadata.name, definition.metadata.namespace);
125
+ const component = {
126
+ id,
127
+ kind: definition.kind,
128
+ metadata: definition.metadata,
129
+ spec: definition.spec,
130
+ requires: definition.requires,
131
+ compatibility: definition.compatibility,
132
+ routing: definition.routing,
133
+ dirPath: dir,
134
+ filePath: yamlPath,
135
+ source,
136
+ format: 'component-yaml',
137
+ enabled: true,
138
+ };
139
+ return { component, diagnostics };
140
+ }
141
+ function loadFromLegacySkill(filePath, dir, source) {
142
+ const diagnostics = [];
143
+ let raw;
144
+ try {
145
+ raw = readFileSync(filePath, 'utf-8');
146
+ }
147
+ catch (error) {
148
+ const msg = error instanceof Error ? error.message : 'failed to read SKILL.md';
149
+ diagnostics.push({ type: 'warning', message: msg, path: filePath });
150
+ return { component: null, diagnostics };
151
+ }
152
+ const { frontmatter } = parseFrontmatter(raw);
153
+ const parentDirName = basename(dir);
154
+ const name = frontmatter.name || parentDirName;
155
+ // Validate
156
+ const nameErrors = validateComponentName(name);
157
+ for (const err of nameErrors) {
158
+ diagnostics.push({ type: 'warning', message: err, path: filePath });
159
+ }
160
+ const descErrors = validateComponentDescription(frontmatter.description);
161
+ for (const err of descErrors) {
162
+ diagnostics.push({ type: 'warning', message: err, path: filePath });
163
+ }
164
+ if (!frontmatter.description || frontmatter.description.trim() === '') {
165
+ return { component: null, diagnostics };
166
+ }
167
+ const spec = {
168
+ prompt: 'SKILL.md',
169
+ disableModelInvocation: frontmatter['disable-model-invocation'] === true,
170
+ };
171
+ const id = computeComponentId(name);
172
+ const component = {
173
+ id,
174
+ kind: 'skill',
175
+ metadata: {
176
+ name,
177
+ description: frontmatter.description,
178
+ },
179
+ spec,
180
+ dirPath: dir,
181
+ filePath,
182
+ source,
183
+ format: 'skill-md',
184
+ enabled: true,
185
+ };
186
+ return { component, diagnostics };
187
+ }
188
+ function loadFromLegacyAgent(filePath, source) {
189
+ const diagnostics = [];
190
+ let raw;
191
+ try {
192
+ raw = readFileSync(filePath, 'utf-8');
193
+ }
194
+ catch (error) {
195
+ const msg = error instanceof Error ? error.message : 'failed to read agent file';
196
+ diagnostics.push({ type: 'warning', message: msg, path: filePath });
197
+ return { component: null, diagnostics };
198
+ }
199
+ const { frontmatter } = parseFrontmatter(raw);
200
+ if (!frontmatter.name || !frontmatter.description) {
201
+ diagnostics.push({
202
+ type: 'warning',
203
+ message: 'agent file missing name or description in frontmatter',
204
+ path: filePath,
205
+ });
206
+ return { component: null, diagnostics };
207
+ }
208
+ // Parse tools from comma-separated string
209
+ const tools = frontmatter.tools
210
+ ? {
211
+ allow: frontmatter.tools
212
+ .split(',')
213
+ .map((t) => t.trim())
214
+ .filter(Boolean),
215
+ }
216
+ : undefined;
217
+ const spec = {
218
+ systemPrompt: basename(filePath),
219
+ model: frontmatter.model,
220
+ tools,
221
+ };
222
+ const id = computeComponentId(frontmatter.name);
223
+ const dir = dirname(filePath);
224
+ const component = {
225
+ id,
226
+ kind: 'agent',
227
+ metadata: {
228
+ name: frontmatter.name,
229
+ description: frontmatter.description,
230
+ },
231
+ spec,
232
+ dirPath: dir,
233
+ filePath,
234
+ source,
235
+ format: 'agent-md',
236
+ enabled: true,
237
+ };
238
+ return { component, diagnostics };
239
+ }
240
+ // ============================================================================
241
+ // Directory Scanning
242
+ // ============================================================================
243
+ /**
244
+ * Scan a directory for components (skills format).
245
+ * Handles both new and legacy directory layouts.
246
+ *
247
+ * Expected layouts:
248
+ * - dir/{component-name}/component.yaml (new format)
249
+ * - dir/{component-name}/SKILL.md (legacy skill)
250
+ * - dir/{name}.md (legacy root-level skill)
251
+ */
252
+ export function scanComponentDir(dir, source, kind) {
253
+ const components = [];
254
+ const diagnostics = [];
255
+ if (!existsSync(dir)) {
256
+ return { components, diagnostics };
257
+ }
258
+ let entries;
259
+ try {
260
+ entries = readdirSync(dir, { withFileTypes: true, encoding: 'utf-8' });
261
+ }
262
+ catch {
263
+ return { components, diagnostics };
264
+ }
265
+ for (const entry of entries) {
266
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') {
267
+ continue;
268
+ }
269
+ const fullPath = join(dir, entry.name);
270
+ let isDir = entry.isDirectory();
271
+ let isFile = entry.isFile();
272
+ if (entry.isSymbolicLink()) {
273
+ try {
274
+ const stats = statSync(fullPath);
275
+ isDir = stats.isDirectory();
276
+ isFile = stats.isFile();
277
+ }
278
+ catch {
279
+ continue;
280
+ }
281
+ }
282
+ if (isDir) {
283
+ const result = loadComponentFromDir(fullPath, source);
284
+ if (result.component) {
285
+ if (!kind || result.component.kind === kind) {
286
+ components.push(result.component);
287
+ }
288
+ }
289
+ diagnostics.push(...result.diagnostics);
290
+ }
291
+ else if (isFile && entry.name.endsWith('.md')) {
292
+ // Root-level .md files — could be legacy skills or agents
293
+ // Peek at frontmatter to determine type
294
+ const result = loadFromFile(fullPath, source);
295
+ if (result.component) {
296
+ if (!kind || result.component.kind === kind) {
297
+ components.push(result.component);
298
+ }
299
+ }
300
+ diagnostics.push(...result.diagnostics);
301
+ }
302
+ }
303
+ return { components, diagnostics };
304
+ }
305
+ /**
306
+ * Scan a directory specifically for agent .md files (legacy agent format).
307
+ */
308
+ export function scanAgentDir(dir, source) {
309
+ const components = [];
310
+ const diagnostics = [];
311
+ if (!existsSync(dir)) {
312
+ return { components, diagnostics };
313
+ }
314
+ let entries;
315
+ try {
316
+ entries = readdirSync(dir, { withFileTypes: true, encoding: 'utf-8' });
317
+ }
318
+ catch {
319
+ return { components, diagnostics };
320
+ }
321
+ for (const entry of entries) {
322
+ const fullPath = join(dir, entry.name);
323
+ let isDir = entry.isDirectory();
324
+ let isFile = entry.isFile();
325
+ if (entry.isSymbolicLink()) {
326
+ try {
327
+ const stats = statSync(fullPath);
328
+ isDir = stats.isDirectory();
329
+ isFile = stats.isFile();
330
+ }
331
+ catch {
332
+ continue;
333
+ }
334
+ }
335
+ if (isDir) {
336
+ const result = loadComponentFromDir(fullPath, source);
337
+ if (result.component?.kind === 'agent') {
338
+ components.push(result.component);
339
+ }
340
+ diagnostics.push(...result.diagnostics);
341
+ continue;
342
+ }
343
+ if (!entry.name.endsWith('.md'))
344
+ continue;
345
+ if (!isFile)
346
+ continue;
347
+ // Check if there's a component.yaml in a same-named directory
348
+ const nameWithoutExt = entry.name.replace(/\.md$/, '');
349
+ const componentDir = join(dir, nameWithoutExt);
350
+ if (existsSync(join(componentDir, 'component.yaml'))) {
351
+ // New format takes precedence and is loaded by the directory branch.
352
+ continue;
353
+ }
354
+ const result = loadComponentFromAgentFile(fullPath, source);
355
+ if (result.component) {
356
+ components.push(result.component);
357
+ }
358
+ diagnostics.push(...result.diagnostics);
359
+ }
360
+ return { components, diagnostics };
361
+ }
362
+ // ============================================================================
363
+ // Helpers
364
+ // ============================================================================
365
+ /**
366
+ * Load a single file, detecting whether it's a skill or agent by frontmatter.
367
+ */
368
+ function loadFromFile(filePath, source) {
369
+ const diagnostics = [];
370
+ let raw;
371
+ try {
372
+ raw = readFileSync(filePath, 'utf-8');
373
+ }
374
+ catch (error) {
375
+ const msg = error instanceof Error ? error.message : 'failed to read file';
376
+ diagnostics.push({ type: 'warning', message: msg, path: filePath });
377
+ return { component: null, diagnostics };
378
+ }
379
+ const { frontmatter } = parseFrontmatter(raw);
380
+ // If it has 'tools' field, treat as agent
381
+ if (frontmatter.tools !== undefined) {
382
+ return loadFromLegacyAgent(filePath, source);
383
+ }
384
+ // Otherwise treat as a legacy skill (root-level .md)
385
+ const dir = dirname(filePath);
386
+ const name = frontmatter.name || basename(filePath, '.md');
387
+ const description = frontmatter.description;
388
+ if (!description || description.trim() === '') {
389
+ return { component: null, diagnostics };
390
+ }
391
+ const spec = {
392
+ prompt: basename(filePath),
393
+ disableModelInvocation: frontmatter['disable-model-invocation'] === true,
394
+ };
395
+ const id = computeComponentId(name);
396
+ const component = {
397
+ id,
398
+ kind: 'skill',
399
+ metadata: { name, description },
400
+ spec,
401
+ dirPath: dir,
402
+ filePath,
403
+ source,
404
+ format: 'skill-md',
405
+ enabled: true,
406
+ };
407
+ return { component, diagnostics };
408
+ }
409
+ function validateEntryFile(kind, spec, dir, yamlPath) {
410
+ const relativePath = kind === 'skill'
411
+ ? spec.prompt
412
+ : spec.systemPrompt;
413
+ const field = kind === 'skill' ? 'spec.prompt' : 'spec.systemPrompt';
414
+ if (!relativePath || typeof relativePath !== 'string') {
415
+ return {
416
+ type: 'error',
417
+ message: `missing ${field}`,
418
+ path: yamlPath,
419
+ };
420
+ }
421
+ const entryPath = join(dir, relativePath);
422
+ if (!existsSync(entryPath)) {
423
+ return {
424
+ type: 'error',
425
+ message: `missing referenced file for ${field}: ${relativePath}`,
426
+ path: entryPath,
427
+ };
428
+ }
429
+ try {
430
+ if (!statSync(entryPath).isFile()) {
431
+ return {
432
+ type: 'error',
433
+ message: `referenced ${field} is not a file: ${relativePath}`,
434
+ path: entryPath,
435
+ };
436
+ }
437
+ }
438
+ catch (error) {
439
+ const msg = error instanceof Error ? error.message : 'failed to inspect referenced file';
440
+ return {
441
+ type: 'error',
442
+ message: `${msg}: ${relativePath}`,
443
+ path: entryPath,
444
+ };
445
+ }
446
+ return null;
447
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Unified Component Type Definitions
3
+ *
4
+ * Shared metadata for installable/discoverable skills and agents.
5
+ *
6
+ * Replaces the separate type systems in:
7
+ * - packages/pi-coding-agent/src/core/skills.ts (SkillFrontmatter, Skill)
8
+ * - src/resources/extensions/subagent/agents.ts (AgentConfig)
9
+ *
10
+ * Legacy skill and agent formats are supported via backward-compatible loading.
11
+ */
12
+ // ============================================================================
13
+ // Validation
14
+ // ============================================================================
15
+ /** Max name length per spec */
16
+ export const MAX_NAME_LENGTH = 64;
17
+ /** Max description length per spec */
18
+ export const MAX_DESCRIPTION_LENGTH = 1024;
19
+ /** Valid name pattern: lowercase a-z, 0-9, hyphens, no leading/trailing/consecutive hyphens */
20
+ export const NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
21
+ /**
22
+ * Validate a component name.
23
+ * @returns Array of error messages (empty if valid).
24
+ */
25
+ export function validateComponentName(name) {
26
+ const errors = [];
27
+ if (!name || name.trim() === '') {
28
+ errors.push('name is required');
29
+ return errors;
30
+ }
31
+ if (name.length > MAX_NAME_LENGTH) {
32
+ errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);
33
+ }
34
+ if (name.includes('--')) {
35
+ errors.push('name must not contain consecutive hyphens');
36
+ }
37
+ if (!NAME_PATTERN.test(name)) {
38
+ if (/[A-Z]/.test(name)) {
39
+ errors.push('name must be lowercase');
40
+ }
41
+ else if (name.startsWith('-') || name.endsWith('-')) {
42
+ errors.push('name must not start or end with a hyphen');
43
+ }
44
+ else if (!name.includes('--')) {
45
+ errors.push('name must contain only lowercase a-z, 0-9, and hyphens');
46
+ }
47
+ }
48
+ return errors;
49
+ }
50
+ /**
51
+ * Validate a component description.
52
+ * @returns Array of error messages (empty if valid).
53
+ */
54
+ export function validateComponentDescription(description) {
55
+ const errors = [];
56
+ if (!description || description.trim() === '') {
57
+ errors.push('description is required');
58
+ }
59
+ else if (description.length > MAX_DESCRIPTION_LENGTH) {
60
+ errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);
61
+ }
62
+ return errors;
63
+ }
64
+ /**
65
+ * Compute the canonical ID for a component.
66
+ */
67
+ export function computeComponentId(name, namespace) {
68
+ return namespace ? `${namespace}:${name}` : name;
69
+ }
@@ -180,7 +180,13 @@ export function queryProject() {
180
180
  // ─── Knowledge Query ───────────────────────────────────────────────────────
181
181
  /**
182
182
  * Filter KNOWLEDGE.md sections by keyword matching.
183
- * Uses H2 sections, matches keywords case-insensitively against:
183
+ *
184
+ * Structure-adaptive (issue #4719): files that organise entries as H3 items
185
+ * under one or more H2 topics are filtered at H3 granularity. Files with only
186
+ * H2 topic headers (no H3) fall back to H2-level filtering for backwards
187
+ * compatibility.
188
+ *
189
+ * Matches keywords case-insensitively against:
184
190
  * 1. Section header text
185
191
  * 2. First paragraph of section content (up to first blank line or next heading)
186
192
  *
@@ -189,28 +195,38 @@ export function queryProject() {
189
195
  *
190
196
  * @param content - Full KNOWLEDGE.md content
191
197
  * @param keywords - Keywords to match (case-insensitive)
192
- * @returns Concatenated matching sections with H2 headers, or empty string
198
+ * @returns Concatenated matching sections with their original heading prefix, or empty string
193
199
  */
194
200
  export async function queryKnowledge(content, keywords) {
195
201
  if (!content || keywords.length === 0)
196
202
  return '';
197
203
  // Lazy import to avoid circular dependency
198
204
  const { extractAllSections } = await import('./files.js');
199
- const sections = extractAllSections(content, 2);
205
+ // Prefer H3 granularity when available; fall back to H2 for H2-only files.
206
+ // This prevents single-H2-with-many-H3 layouts from returning the entire
207
+ // file on a keyword match against the H2 header or its first paragraph.
208
+ const h3Sections = extractAllSections(content, 3);
209
+ const useH3 = h3Sections.size > 0;
210
+ const sections = useH3 ? h3Sections : extractAllSections(content, 2);
200
211
  if (sections.size === 0)
201
212
  return '';
202
- // Normalize keywords for case-insensitive matching
203
- const normalizedKeywords = keywords.map(k => k.toLowerCase());
213
+ const prefix = useH3 ? '###' : '##';
214
+ // Trim, lowercase, drop empties, and de-dupe so callers can pass raw
215
+ // user-provided strings without risking empty-string / whitespace matches.
216
+ const normalizedKeywords = [...new Set(keywords
217
+ .map(k => k.trim().toLowerCase())
218
+ .filter(k => k.length > 0))];
219
+ if (normalizedKeywords.length === 0)
220
+ return '';
204
221
  const matchingSections = [];
205
222
  for (const [header, body] of sections) {
206
223
  // Extract first paragraph: everything up to first blank line or next heading
207
224
  const firstParagraph = body.split(/\n\s*\n|\n#/)[0] || '';
208
- // Check if any keyword matches header or first paragraph
209
225
  const headerLower = header.toLowerCase();
210
226
  const paragraphLower = firstParagraph.toLowerCase();
211
227
  const matches = normalizedKeywords.some(kw => headerLower.includes(kw) || paragraphLower.includes(kw));
212
228
  if (matches) {
213
- matchingSections.push(`## ${header}\n\n${body}`);
229
+ matchingSections.push(`${prefix} ${header}\n\n${body}`);
214
230
  }
215
231
  }
216
232
  return matchingSections.join('\n\n');
@@ -6,7 +6,7 @@
6
6
  * flow to show when entering a project directory.
7
7
  */
8
8
  import { existsSync, openSync, readSync, closeSync, readdirSync, readFileSync, statSync } from "node:fs";
9
- import { join } from "node:path";
9
+ import { dirname, join, parse as parsePath } from "node:path";
10
10
  import { homedir } from "node:os";
11
11
  import { gsdRoot } from "./paths.js";
12
12
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
@@ -951,6 +951,54 @@ function resolveVersionCatalogAccessors(basePath, versionCatalogFiles, settingsF
951
951
  }
952
952
  return accessors;
953
953
  }
954
+ /**
955
+ * Walk ancestor directories of `startDir` looking for any file in
956
+ * `PROJECT_FILES`. Stops at the filesystem root or at a `.git` boundary
957
+ * (so ancestors above a git repo root — e.g. `$HOME` or `/usr/local` —
958
+ * can't trigger false positives). Returns true if an ancestor contains
959
+ * one of the project markers.
960
+ *
961
+ * Used by the worktree health check (#2347) to avoid warning about
962
+ * monorepos where package.json / Cargo.toml / etc. live in a parent
963
+ * directory rather than in the worktree's own checkout.
964
+ *
965
+ * `existsFn` is injectable so this remains deterministically testable
966
+ * without touching the real filesystem; defaults to `fs.existsSync`.
967
+ */
968
+ export function hasProjectFileInAncestor(startDir, existsFn = existsSync) {
969
+ let checkDir = dirname(startDir);
970
+ const { root } = parsePath(checkDir);
971
+ while (checkDir !== root) {
972
+ if (PROJECT_FILES.some((f) => existsFn(join(checkDir, f)))) {
973
+ return true;
974
+ }
975
+ // Stop at git repository boundary — ancestors above the repo root
976
+ // may contain unrelated project files. Check AFTER project-file scan
977
+ // so a repo root containing both .git and a marker is still recognized.
978
+ if (existsFn(join(checkDir, ".git")))
979
+ return false;
980
+ checkDir = dirname(checkDir);
981
+ }
982
+ return false;
983
+ }
984
+ /**
985
+ * Check whether a project's `.gsd/` directory contains the bootstrap artifacts
986
+ * (`PREFERENCES.md` or `milestones/`) that indicate a completed init run.
987
+ *
988
+ * A zombie `.gsd/` state — symlink exists but neither artifact is present —
989
+ * must be treated as "needs init wizard". The previous guard checked only
990
+ * `existsSync(gsdRoot(basePath))`, which accepted zombie states and skipped
991
+ * the wizard (#2942).
992
+ *
993
+ * `existsFn` is injectable so tests can run deterministically; defaults to
994
+ * `fs.existsSync`.
995
+ */
996
+ export function hasGsdBootstrapArtifacts(gsdPath, existsFn = existsSync) {
997
+ return (existsFn(gsdPath) &&
998
+ (existsFn(join(gsdPath, "PREFERENCES.md")) ||
999
+ existsFn(join(gsdPath, "preferences.md")) ||
1000
+ existsFn(join(gsdPath, "milestones"))));
1001
+ }
954
1002
  export function scanProjectFiles(basePath) {
955
1003
  const files = [];
956
1004
  const queue = [{ path: basePath, depth: 0 }];
@@ -5,23 +5,8 @@ import { parseUnitId } from "./unit-id.js";
5
5
  import { isDbAvailable, getMilestoneSlices, getMilestone } from "./gsd-db.js";
6
6
  import { parseRoadmap } from "./parsers-legacy.js";
7
7
  import { isClosedStatus } from "./status-guards.js";
8
+ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
8
9
  import { readFileSync } from "node:fs";
9
- /**
10
- * Detect failure-path milestone SUMMARY content (#4663 sibling to #4658).
11
- * A failure SUMMARY must not let the dispatch guard treat an active
12
- * milestone as complete. The markers mirror those produced by
13
- * writeBlockerPlaceholder and the "verification FAILED" retry path.
14
- *
15
- * This is intentionally a minimal local detector so this fix does not
16
- * depend on PR #4660's `classifyMilestoneSummaryContent`. It can migrate
17
- * to the shared classifier once that lands.
18
- */
19
- function isFailureMilestoneSummary(content) {
20
- return (/(?:^|\n)\s*#\s*BLOCKER\b/i.test(content) ||
21
- /auto-mode recovery failed/i.test(content) ||
22
- /verification\s+failed/i.test(content) ||
23
- /\bnot complete\b/i.test(content));
24
- }
25
10
  const SLICE_DISPATCH_TYPES = new Set([
26
11
  "research-slice",
27
12
  "plan-slice",
@@ -78,7 +63,7 @@ export function getPriorSliceCompletionBlocker(base, _mainBranch, unitType, unit
78
63
  summaryContent = readFileSync(summaryPath, "utf-8");
79
64
  }
80
65
  catch { /* ignore */ }
81
- if (!summaryContent || !isFailureMilestoneSummary(summaryContent)) {
66
+ if (!summaryContent || classifyMilestoneSummaryContent(summaryContent) !== "failure") {
82
67
  continue;
83
68
  }
84
69
  }
@@ -159,7 +159,7 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
159
159
 
160
160
  - `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:
161
161
  - `skip_research`: boolean — skip milestone-level research. Default: `false`.
162
- - `reassess_after_slice`: boolean — run roadmap reassessment after each completed slice. Default: `true`.
162
+ - `reassess_after_slice`: boolean — run a dedicated roadmap-reassessment unit after each completed slice. Default: `false` (per ADR-003 §4). The plan-slice agent for the next slice performs JIT reassessment via a prompt preamble at zero additional token cost; a dedicated reassess session is opt-in. Set to `true` (e.g. via the `burn-max` profile) if you want the explicit session.
163
163
  - `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.
164
164
  - `skip_slice_research`: boolean — skip per-slice research. Default: `false`.
165
165