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
@@ -26,14 +26,6 @@ import { MAX_FINALIZE_TIMEOUTS } from "../auto/types.ts";
26
26
 
27
27
  const { assertTrue, assertEq, report } = createTestContext();
28
28
 
29
- function getRunFinalizeBody(phasesSource: string): string {
30
- const fnIdx = phasesSource.indexOf("export async function runFinalize(");
31
- assertTrue(fnIdx > 0, "runFinalize function should exist in phases.ts");
32
-
33
- const nextExportIdx = phasesSource.indexOf("\nexport ", fnIdx + 1);
34
- return phasesSource.slice(fnIdx, nextExportIdx > fnIdx ? nextExportIdx : undefined);
35
- }
36
-
37
29
  // ═══ Test: withTimeout resolves when inner promise resolves promptly ══════════
38
30
 
39
31
  {
@@ -142,45 +134,6 @@ function getRunFinalizeBody(phasesSource: string): string {
142
134
  assertEq(result.timedOut, false, "should not time out");
143
135
  }
144
136
 
145
- // ═══ Test: runFinalize wraps BOTH pre and post verification with withTimeout ═
146
-
147
- {
148
- console.log("\n=== #3757: runFinalize wraps preVerification with timeout guard ===");
149
-
150
- const { readFileSync } = await import("node:fs");
151
- const phasesSource = readFileSync(
152
- new URL("../auto/phases.ts", import.meta.url),
153
- "utf-8",
154
- );
155
-
156
- const fnBody = getRunFinalizeBody(phasesSource);
157
-
158
- // postUnitPreVerification must be wrapped in withTimeout
159
- const preTimeoutIdx = fnBody.indexOf("withTimeout(");
160
- assertTrue(preTimeoutIdx > 0, "withTimeout should appear in runFinalize");
161
-
162
- const preVerIdx = fnBody.indexOf("postUnitPreVerification");
163
- assertTrue(preVerIdx > 0, "postUnitPreVerification should appear in runFinalize");
164
-
165
- // The first withTimeout should wrap postUnitPreVerification (not postUnitPostVerification)
166
- const firstWithTimeout = fnBody.slice(preTimeoutIdx, preTimeoutIdx + 200);
167
- assertTrue(
168
- firstWithTimeout.includes("postUnitPreVerification"),
169
- "first withTimeout in runFinalize should wrap postUnitPreVerification",
170
- );
171
-
172
- // postUnitPostVerification must also be wrapped
173
- const postVerIdx = fnBody.indexOf("postUnitPostVerification");
174
- assertTrue(postVerIdx > 0, "postUnitPostVerification should appear in runFinalize");
175
-
176
- // Count withTimeout occurrences — should be at least 2 (pre + post)
177
- const timeoutCount = (fnBody.match(/withTimeout\(/g) || []).length;
178
- assertTrue(
179
- timeoutCount >= 2,
180
- `runFinalize should have at least 2 withTimeout guards (found ${timeoutCount})`,
181
- );
182
- }
183
-
184
137
  // ═══ Test: MAX_FINALIZE_TIMEOUTS is defined and reasonable ═══════════════════
185
138
 
186
139
  {
@@ -200,62 +153,13 @@ function getRunFinalizeBody(phasesSource: string): string {
200
153
  );
201
154
  }
202
155
 
203
- // ═══ Test: timeout handlers escalate after consecutive timeouts ══════════════
204
-
205
- {
206
- console.log("\n=== #3757: timeout handlers escalate and detach currentUnit ===");
207
-
208
- const { readFileSync } = await import("node:fs");
209
- const phasesSource = readFileSync(
210
- new URL("../auto/phases.ts", import.meta.url),
211
- "utf-8",
212
- );
213
-
214
- const fnBody = getRunFinalizeBody(phasesSource);
215
-
216
- const helperCallCount = (fnBody.match(/failClosedOnFinalizeTimeout\(/g) || []).length;
217
- assertTrue(
218
- helperCallCount >= 2,
219
- `runFinalize should route both timeout branches through failClosedOnFinalizeTimeout (found ${helperCallCount})`,
220
- );
221
-
222
- const helperStart = phasesSource.indexOf("async function failClosedOnFinalizeTimeout");
223
- assertTrue(helperStart > 0, "failClosedOnFinalizeTimeout helper should exist");
224
- const helperEnd = phasesSource.indexOf("// ─── runPreDispatch", helperStart);
225
- const helperBody = phasesSource.slice(helperStart, helperEnd > helperStart ? helperEnd : undefined);
226
-
227
- const incrementCount = (helperBody.match(/consecutiveFinalizeTimeouts\+\+/g) || []).length;
228
- assertTrue(
229
- incrementCount >= 1,
230
- `timeout helper should increment consecutiveFinalizeTimeouts (found ${incrementCount})`,
231
- );
232
-
233
- const detachCount = (helperBody.match(/s\.currentUnit\s*=\s*null/g) || []).length;
234
- assertTrue(
235
- detachCount >= 1,
236
- `timeout helper should detach s.currentUnit (found ${detachCount})`,
237
- );
238
-
239
- const pauseCount = (helperBody.match(/pauseAuto\(/g) || []).length;
240
- assertTrue(
241
- pauseCount >= 1,
242
- `timeout helper should pause auto-mode (found ${pauseCount})`,
243
- );
244
-
245
- assertTrue(
246
- helperBody.includes('eventType: "unit-end"'),
247
- "timeout helper should emit a terminal unit-end event",
248
- );
249
- assertTrue(
250
- helperBody.includes('phase: "finalize-timeout"'),
251
- "timeout helper should persist finalize-timeout runtime state",
252
- );
253
-
254
- // Successful finalize should reset the counter
255
- assertTrue(
256
- fnBody.includes("consecutiveFinalizeTimeouts = 0"),
257
- "should reset consecutiveFinalizeTimeouts on successful finalize",
258
- );
259
- }
156
+ // Note: the two previous source-grep blocks that scanned phases.ts for
157
+ // `withTimeout(` / `failClosedOnFinalizeTimeout(` occurrences were removed
158
+ // under #4825 — they encoded implementation shape (Goodhart) and broke on
159
+ // any helper/loop refactor without catching a real regression. The intended
160
+ // behavioural invariant (pre+post verification hangs → pauseAuto called,
161
+ // unit-end emitted, escalation counter incremented) should be covered by a
162
+ // runFinalize integration test with mocked hanging verification — tracked
163
+ // separately. Refs #4825.
260
164
 
261
165
  report();
@@ -0,0 +1,102 @@
1
+ // GSD Gate State Canonicalization Tests
2
+ // Regression tests for #4950: canonical omitted state and GateVerdict type narrowing.
3
+
4
+ import { describe, test, beforeEach, afterEach } from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { mkdtempSync, rmSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import { tmpdir } from "node:os";
9
+
10
+ import {
11
+ openDatabase,
12
+ closeDatabase,
13
+ insertGateRow,
14
+ markAllGatesOmitted,
15
+ getGateResults,
16
+ getPendingGates,
17
+ insertMilestone,
18
+ insertSlice,
19
+ } from "../gsd-db.ts";
20
+ import type { GateVerdict } from "../types.ts";
21
+
22
+ describe("gate-state canonicalization (#4950)", () => {
23
+ let tmpDir: string;
24
+ let dbPath: string;
25
+
26
+ beforeEach(() => {
27
+ tmpDir = mkdtempSync(join(tmpdir(), "gate-canon-test-"));
28
+ dbPath = join(tmpDir, "gsd.db");
29
+ openDatabase(dbPath);
30
+ insertMilestone({ id: "M001", title: "Test Milestone", status: "active" });
31
+ insertSlice({
32
+ milestoneId: "M001",
33
+ id: "S01",
34
+ title: "Test Slice",
35
+ status: "pending",
36
+ risk: "medium",
37
+ depends: [],
38
+ });
39
+ });
40
+
41
+ afterEach(() => {
42
+ closeDatabase();
43
+ rmSync(tmpDir, { recursive: true, force: true });
44
+ });
45
+
46
+ test("markAllGatesOmitted produces status=complete, verdict=omitted (not status=omitted)", () => {
47
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
48
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
49
+
50
+ markAllGatesOmitted("M001", "S01");
51
+
52
+ const all = getGateResults("M001", "S01");
53
+ assert.equal(all.length, 2);
54
+ for (const g of all) {
55
+ assert.equal(g.status, "complete", `expected status=complete for gate ${g.gate_id}`);
56
+ assert.equal(g.verdict, "omitted", `expected verdict=omitted for gate ${g.gate_id}`);
57
+ }
58
+ });
59
+
60
+ test("markAllGatesOmitted leaves no pending gates", () => {
61
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
62
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
63
+
64
+ markAllGatesOmitted("M001", "S01");
65
+
66
+ const pending = getPendingGates("M001", "S01");
67
+ assert.equal(pending.length, 0);
68
+ });
69
+
70
+ test("pending gate verdict is null, not empty string", () => {
71
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
72
+
73
+ const pending = getPendingGates("M001", "S01");
74
+ assert.equal(pending.length, 1);
75
+ assert.equal(pending[0].verdict, null, "pending gate verdict must be null, not empty string");
76
+ });
77
+
78
+ test("complete gate verdict round-trips as a valid GateVerdict (pass/flag/omitted only)", () => {
79
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
80
+ markAllGatesOmitted("M001", "S01");
81
+
82
+ const results = getGateResults("M001", "S01");
83
+ const q4 = results.find((g) => g.gate_id === "Q4");
84
+ assert.ok(q4, "Q4 gate must exist");
85
+
86
+ const validVerdicts: GateVerdict[] = ["pass", "flag", "omitted"];
87
+ assert.ok(
88
+ q4.verdict !== null && validVerdicts.includes(q4.verdict),
89
+ `verdict "${q4.verdict}" must be one of: ${validVerdicts.join(", ")}`,
90
+ );
91
+ });
92
+
93
+ test("empty-string verdict is not reachable after round-trip through DB", () => {
94
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
95
+ markAllGatesOmitted("M001", "S01");
96
+
97
+ const results = getGateResults("M001", "S01");
98
+ for (const g of results) {
99
+ assert.notEqual(g.verdict, "", `gate ${g.gate_id} verdict must not be empty string`);
100
+ }
101
+ });
102
+ });
@@ -109,7 +109,7 @@ describe("quality_gates CRUD", () => {
109
109
  const all = getGateResults("M001", "S01");
110
110
  assert.equal(all.length, 3);
111
111
  for (const g of all) {
112
- assert.equal(g.status, "omitted");
112
+ assert.equal(g.status, "complete");
113
113
  assert.equal(g.verdict, "omitted");
114
114
  }
115
115
  });
@@ -85,8 +85,10 @@ test("google-search stub: session_start warning contains package name", async (_
85
85
  );
86
86
  });
87
87
 
88
- test("google-search stub: session_start warning contains install command", async (_t) => {
89
- // STUB-01: warning includes "gsd extensions install"
88
+ test("google-search stub: session_start warning explains package is not yet published", async (_t) => {
89
+ // STUB-01: stub must NOT advise `gsd extensions install` — the replacement
90
+ // package is not yet on npm, so that command would 404. The message must
91
+ // explain the extraction is in progress and no user action is required.
90
92
  const mod = await import("../../google-search/index.ts");
91
93
  const stubFn = mod.default;
92
94
 
@@ -115,7 +117,15 @@ test("google-search stub: session_start warning contains install command", async
115
117
  await capturedHandler!({}, mockCtx);
116
118
 
117
119
  assert.ok(
118
- capturedMessage?.includes("gsd extensions install"),
119
- `Expected message to include "gsd extensions install", got: "${capturedMessage}"`,
120
+ !capturedMessage?.includes("gsd extensions install"),
121
+ `Expected message NOT to include unpublished install command, got: "${capturedMessage}"`,
122
+ );
123
+ assert.ok(
124
+ capturedMessage?.includes("not yet published"),
125
+ `Expected message to include "not yet published", got: "${capturedMessage}"`,
126
+ );
127
+ assert.ok(
128
+ capturedMessage?.includes("No action needed"),
129
+ `Expected message to include "No action needed", got: "${capturedMessage}"`,
120
130
  );
121
131
  });
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Regression tests for the headless vs interactive milestone-bootstrap divergence.
3
+ *
4
+ * Two defects were covered here:
5
+ * 1. `showHeadlessMilestoneCreation` dispatched with `unitType: "plan-milestone"`
6
+ * instead of `"discuss-milestone"`. The `discuss-` prefix drives tool
7
+ * scoping (`guided-flow.ts:583`) and enables the `checkAutoStartAfterDiscuss`
8
+ * guardrails — routing through `plan-milestone` bypassed them even
9
+ * though headless is semantically a discuss flow.
10
+ * 2. The `discuss-headless.md` ready-phrase pre-condition was a prose
11
+ * sentence, so models that treated it as advisory could skip ahead to
12
+ * the ready phrase without actually writing the artifacts. The checkbox
13
+ * format from `discuss.md` has lower abstraction cost and is harder to
14
+ * rationalize past.
15
+ */
16
+
17
+ import { test, describe } from "node:test";
18
+ import assert from "node:assert/strict";
19
+ import { readFileSync } from "node:fs";
20
+ import { dirname, join } from "node:path";
21
+ import { fileURLToPath } from "node:url";
22
+
23
+ const __dirname = dirname(fileURLToPath(import.meta.url));
24
+
25
+ const GUIDED_FLOW_PATH = join(__dirname, "..", "guided-flow.ts");
26
+ const DISCUSS_HEADLESS_PATH = join(__dirname, "..", "prompts", "discuss-headless.md");
27
+
28
+ function getGuidedFlowSource(): string {
29
+ return readFileSync(GUIDED_FLOW_PATH, "utf-8");
30
+ }
31
+
32
+ function getHeadlessPromptSource(): string {
33
+ return readFileSync(DISCUSS_HEADLESS_PATH, "utf-8");
34
+ }
35
+
36
+ describe("headless milestone bootstrap — parity with interactive flow", () => {
37
+ test("showHeadlessMilestoneCreation dispatches as discuss-milestone, not plan-milestone", () => {
38
+ const source = getGuidedFlowSource();
39
+ const fnStart = source.indexOf("export async function showHeadlessMilestoneCreation");
40
+ assert.ok(fnStart > -1, "showHeadlessMilestoneCreation must exist");
41
+
42
+ // Scope: from the function start to the next top-level export (or EOF).
43
+ const nextExport = source.indexOf("\nexport ", fnStart + 1);
44
+ const fnBody = source.slice(fnStart, nextExport === -1 ? source.length : nextExport);
45
+
46
+ // Match only the actual dispatchWorkflow call — comments in the body
47
+ // may mention "plan-milestone" as part of the fix rationale.
48
+ const dispatchMatches = [...fnBody.matchAll(/dispatchWorkflow\([^)]*,\s*"([^"]+)"\s*\)/g)];
49
+ assert.strictEqual(
50
+ dispatchMatches.length,
51
+ 1,
52
+ `expected exactly one dispatchWorkflow call, found ${dispatchMatches.length}`,
53
+ );
54
+ assert.strictEqual(
55
+ dispatchMatches[0][1],
56
+ "discuss-milestone",
57
+ `showHeadlessMilestoneCreation must dispatch as "discuss-milestone" so tool scoping and discuss-flow guardrails apply; got "${dispatchMatches[0][1]}"`,
58
+ );
59
+ });
60
+
61
+ test("discuss-headless single-milestone pre-condition uses the non-bypassable checkbox format", () => {
62
+ const source = getHeadlessPromptSource();
63
+ const section = source.split("### Multi-Milestone")[0];
64
+ assert.ok(
65
+ /### Ready-phrase pre-condition \(NON-BYPASSABLE\)/.test(section),
66
+ "single-milestone ready-phrase section must be present",
67
+ );
68
+ // All four required artifacts must appear as checkboxes, not a prose list.
69
+ for (const artifact of [
70
+ "`.gsd/PROJECT.md`",
71
+ "`.gsd/REQUIREMENTS.md`",
72
+ "`{{contextPath}}`",
73
+ "`gsd_plan_milestone`",
74
+ ]) {
75
+ assert.ok(
76
+ new RegExp(`- \\[ \\] [A-Za-z]+ ${artifact.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`).test(section),
77
+ `single-milestone pre-condition must include a checkbox for ${artifact}`,
78
+ );
79
+ }
80
+ assert.ok(
81
+ /If ANY box is unchecked, \*\*STOP\*\*/.test(section),
82
+ "single-milestone pre-condition must include the 'If ANY box is unchecked, STOP' sentinel",
83
+ );
84
+ assert.ok(
85
+ /Do not announce the ready phrase as something you are "about to" do/.test(section),
86
+ "single-milestone pre-condition must include the 'do not announce intent' guard",
87
+ );
88
+ });
89
+
90
+ test("discuss-headless multi-milestone pre-condition uses the non-bypassable checkbox format", () => {
91
+ const source = getHeadlessPromptSource();
92
+ const multiIdx = source.indexOf("### Multi-Milestone");
93
+ assert.ok(multiIdx > -1, "multi-milestone section must be present");
94
+ const multiSection = source.slice(multiIdx);
95
+
96
+ assert.ok(
97
+ /### Ready-phrase pre-condition \(NON-BYPASSABLE\)/.test(multiSection),
98
+ "multi-milestone ready-phrase section must be present",
99
+ );
100
+ for (const artifact of [
101
+ "`.gsd/PROJECT.md`",
102
+ "`.gsd/REQUIREMENTS.md`",
103
+ "`gsd_plan_milestone`",
104
+ "`.gsd/DISCUSSION-MANIFEST.json`",
105
+ ]) {
106
+ const escaped = artifact.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
107
+ assert.ok(
108
+ new RegExp(`- \\[ \\] [\\s\\S]*?${escaped}`).test(multiSection),
109
+ `multi-milestone pre-condition must include a checkbox referencing ${artifact}`,
110
+ );
111
+ }
112
+ assert.ok(
113
+ /gates_completed === total/.test(multiSection),
114
+ "multi-milestone pre-condition must still enforce gates_completed === total",
115
+ );
116
+ });
117
+ });
@@ -1,11 +1,5 @@
1
1
  import { describe, it } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { readFileSync } from "node:fs";
4
- import { join, dirname } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
-
7
- const __dirname = dirname(fileURLToPath(import.meta.url));
8
- const gsdDir = join(__dirname, "..");
9
3
 
10
4
  /**
11
5
  * Regression tests for #2826: hook/* completed-unit keys were parsed
@@ -15,17 +9,13 @@ const gsdDir = join(__dirname, "..");
15
9
  * The root cause: `key.indexOf("/")` splits "hook/telegram-progress/M007/S01"
16
10
  * into unitType="hook" + unitId="telegram-progress/M007/S01" instead of
17
11
  * unitType="hook/telegram-progress" + unitId="M007/S01".
12
+ *
13
+ * These tests exercise the real `splitCompletedKey` helper — the previous
14
+ * source-grep "does not use indexOf" blocks were dropped under #4825 as
15
+ * they over-specified implementation shape.
18
16
  */
19
17
 
20
18
  describe("splitCompletedKey (#2826)", () => {
21
- it("is exported from forensics.ts", () => {
22
- const source = readFileSync(join(gsdDir, "forensics.ts"), "utf-8");
23
- assert.ok(
24
- source.includes("export function splitCompletedKey"),
25
- "forensics.ts must export splitCompletedKey helper",
26
- );
27
- });
28
-
29
19
  it("splits simple unit types correctly", async () => {
30
20
  const { splitCompletedKey } = await import("../forensics.ts");
31
21
  const result = splitCompletedKey("execute-task/M007/S01/T01");
@@ -64,44 +54,3 @@ describe("splitCompletedKey (#2826)", () => {
64
54
  assert.strictEqual(splitCompletedKey("hook/someName"), null);
65
55
  });
66
56
  });
67
-
68
- describe("forensics detectMissingArtifacts uses splitCompletedKey (#2826)", () => {
69
- it("does not use indexOf for key splitting", () => {
70
- const source = readFileSync(join(gsdDir, "forensics.ts"), "utf-8");
71
- // Extract only the detectMissingArtifacts function body
72
- const fnStart = source.indexOf("function detectMissingArtifacts");
73
- assert.ok(fnStart !== -1, "detectMissingArtifacts must exist");
74
- const fnBody = source.slice(fnStart, source.indexOf("\n}\n", fnStart) + 3);
75
-
76
- assert.ok(
77
- !fnBody.includes('key.indexOf("/")'),
78
- "detectMissingArtifacts must not use key.indexOf('/') — use splitCompletedKey instead",
79
- );
80
- assert.ok(
81
- fnBody.includes("splitCompletedKey"),
82
- "detectMissingArtifacts must use splitCompletedKey helper",
83
- );
84
- });
85
- });
86
-
87
- describe("doctor-runtime-checks uses splitCompletedKey (#2826)", () => {
88
- it("does not use indexOf for key splitting in orphaned-key check", () => {
89
- const source = readFileSync(
90
- join(gsdDir, "doctor-runtime-checks.ts"),
91
- "utf-8",
92
- );
93
- // Find the orphaned completed-units section
94
- const sectionStart = source.indexOf("Orphaned completed-units");
95
- assert.ok(sectionStart !== -1, "orphaned completed-units section must exist");
96
- const sectionBody = source.slice(sectionStart, source.indexOf("} catch", sectionStart));
97
-
98
- assert.ok(
99
- !sectionBody.includes('key.indexOf("/")'),
100
- "doctor orphaned-key check must not use key.indexOf('/') — use splitCompletedKey instead",
101
- );
102
- assert.ok(
103
- sectionBody.includes("splitCompletedKey"),
104
- "doctor orphaned-key check must use splitCompletedKey helper",
105
- );
106
- });
107
- });
@@ -21,10 +21,9 @@ import {
21
21
  realpathSync,
22
22
  readFileSync,
23
23
  } from "node:fs";
24
- import { join, dirname } from "node:path";
24
+ import { join } from "node:path";
25
25
  import { tmpdir } from "node:os";
26
26
  import { execSync } from "node:child_process";
27
- import { fileURLToPath } from "node:url";
28
27
 
29
28
  import {
30
29
  createAutoWorktree,
@@ -33,8 +32,6 @@ import {
33
32
  mergeMilestoneToMain,
34
33
  } from "../../auto-worktree.ts";
35
34
 
36
- const __dirname = dirname(fileURLToPath(import.meta.url));
37
-
38
35
  function run(command: string, cwd: string): string {
39
36
  return execSync(command, {
40
37
  cwd,
@@ -75,58 +72,12 @@ function createMilestoneArtifacts(dir: string, mid: string): void {
75
72
  writeFileSync(join(msDir, `${mid}-ROADMAP.md`), roadmap);
76
73
  }
77
74
 
78
- // ─── Source-level: verify the merge code exists in the "all complete" path ────
79
-
80
- test("auto-loop 'all milestones complete' path merges before stopping (#962)", () => {
81
- const loopSrc = readFileSync(join(__dirname, "../..", "auto", "phases.ts"), "utf-8");
82
- const resolverSrc = readFileSync(
83
- join(__dirname, "../..", "worktree-resolver.ts"),
84
- "utf-8",
85
- );
86
-
87
- // Find the "incomplete.length === 0" block
88
- const incompleteIdx = loopSrc.indexOf("incomplete.length === 0");
89
- assert.ok(
90
- incompleteIdx > -1,
91
- "auto/phases.ts should have 'incomplete.length === 0' check",
92
- );
93
-
94
- // The merge call must appear BETWEEN the incomplete check and the stopAuto call.
95
- const blockAfterIncomplete = loopSrc.slice(
96
- incompleteIdx,
97
- incompleteIdx + 3000,
98
- );
99
-
100
- assert.ok(
101
- blockAfterIncomplete.includes("deps.resolver.mergeAndExit"),
102
- "auto/phases.ts should call resolver.mergeAndExit in the 'all milestones complete' path",
103
- );
104
-
105
- // The merge should come before stopAuto in this block
106
- const mergePos = blockAfterIncomplete.indexOf("deps.resolver.mergeAndExit");
107
- const stopPos = blockAfterIncomplete.indexOf("stopAuto");
108
- assert.ok(
109
- mergePos < stopPos,
110
- "resolver.mergeAndExit should be called before stopAuto in the 'all complete' path",
111
- );
112
-
113
- const helperIdx = resolverSrc.indexOf("mergeAndExit(milestoneId");
114
- assert.ok(
115
- helperIdx > -1,
116
- "WorktreeResolver.mergeAndExit helper should exist",
117
- );
118
- const helperBlock = resolverSrc.slice(helperIdx, helperIdx + 2600);
119
- assert.ok(
120
- helperBlock.includes('mode === "worktree"') ||
121
- helperBlock.includes('mode: "worktree"'),
122
- "WorktreeResolver.mergeAndExit should handle worktree mode",
123
- );
124
- assert.ok(
125
- helperBlock.includes('mode === "branch"') ||
126
- helperBlock.includes('mode: "branch"'),
127
- "WorktreeResolver.mergeAndExit should handle branch mode",
128
- );
129
- });
75
+ // Note: the prior phases.ts / worktree-resolver.ts source-grep block was
76
+ // removed under #4825 — it asserted `deps.resolver.mergeAndExit` appears
77
+ // before `stopAuto` via indexOf positions in the source text, which broke
78
+ // on any helper refactor without catching a real regression. The two
79
+ // integration tests below exercise the merge-before-stop behaviour end
80
+ // to end through real git worktrees.
130
81
 
131
82
  // ─── Integration: single milestone completes → merged to main ────────────────
132
83
 
@@ -717,6 +717,26 @@ test("hasImplementationArtifacts returns 'present' when implementation files com
717
717
  assert.equal(result, "present", "should return 'present' when implementation files are present");
718
718
  });
719
719
 
720
+ test("hasImplementationArtifacts finds production execute-task commits after retry resumes on main (#4699)", (t) => {
721
+ const base = makeGitBase();
722
+ t.after(() => cleanup(base));
723
+
724
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
725
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap");
726
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
727
+ execFileSync("git", ["commit", "-m", "chore: auto-commit after plan-milestone\n\nGSD-Unit: M001"], { cwd: base, stdio: "ignore" });
728
+
729
+ mkdirSync(join(base, "src"), { recursive: true });
730
+ mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
731
+ writeFileSync(join(base, "src", "feature.ts"), "export function feature() {}");
732
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-SUMMARY.md"), "# Summary");
733
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
734
+ execFileSync("git", ["commit", "-m", "feat: add milestone feature\n\nGSD-Task: S01/T01"], { cwd: base, stdio: "ignore" });
735
+
736
+ const result = hasImplementationArtifacts(base, "M001");
737
+ assert.equal(result, "present", "main self-diff retry should find production execute-task commits");
738
+ });
739
+
720
740
  test("hasImplementationArtifacts returns 'unknown' on non-git directory (fail-open)", (t) => {
721
741
  const base = join(tmpdir(), `gsd-test-nogit-${randomUUID()}`);
722
742
  mkdirSync(base, { recursive: true });
@@ -161,11 +161,27 @@ describe('doctor-proactive', async () => {
161
161
  });
162
162
 
163
163
  test('escalation: no double escalation', () => {
164
- // Don't reset should already be escalated from previous test
164
+ // Self-contained: drive the escalated state from scratch in this test.
165
+ // Previously this relied on module-singleton state left over from the
166
+ // preceding 'escalation: at threshold' test, which silently broke under
167
+ // filtered/parallel/reordered runs (the fallback `shouldEscalate: false`
168
+ // path was satisfied by the wrong reason — see #4828).
169
+ resetProactiveHealing();
170
+ for (let i = 0; i < 5; i++) {
171
+ recordHealthSnapshot(0, 0, 0); // older clean snapshots
172
+ }
173
+ for (let i = 0; i < 5; i++) {
174
+ recordHealthSnapshot(2, 1, 0); // recent error snapshots → degrading trend
175
+ }
176
+ // First check: trigger escalation.
177
+ const first = checkHealEscalation(2, [{ code: "test", message: "test error", unitId: "M001/S01" }]);
178
+ assert.deepStrictEqual(first.shouldEscalate, true, "precondition: first call escalates");
179
+
180
+ // Second check: same session, must NOT double-escalate.
165
181
  recordHealthSnapshot(2, 0, 0);
166
182
  const result = checkHealEscalation(2, [{ code: "test", message: "test error", unitId: "M001/S01" }]);
167
183
  assert.deepStrictEqual(result.shouldEscalate, false, "no double escalation in same session");
168
- assert.ok(result.reason.includes("already escalated"), "reason explains why no escalation");
184
+ assert.ok(result.reason.includes("already escalated"), `reason must explain no-re-escalation (got: ${result.reason})`);
169
185
  });
170
186
 
171
187
  test('escalation: deferred when improving', () => {
@@ -140,12 +140,18 @@ for (let i = 1; i <= COMPLETED_COUNT; i++) {
140
140
 
141
141
  // ─── Test: the overall context should be reasonable in size ──────────────
142
142
 
143
- // With 25 completed milestones NOT loading files, the context should be
144
- // significantly smaller than if all files were loaded
143
+ // Invariant (not absolute budget): the per-completed-milestone line
144
+ // contribution should stay small and CONSTANT (not proportional to the
145
+ // size of its CONTEXT.md / SUMMARY.md). With 50 lines of fixture text
146
+ // per completed CONTEXT.md, a naive loader would produce >=50 lines per
147
+ // completed milestone (>1250 lines for 25 milestones). The fix emits a
148
+ // short summary section plus separator per completed milestone, which
149
+ // stays well under 10 lines/milestone regardless of CONTEXT.md size.
145
150
  const contextLines = context.split("\n").length;
151
+ const avgLinesPerCompletedMilestone = contextLines / COMPLETED_COUNT;
146
152
  assertTrue(
147
- contextLines < 200,
148
- `Context should be concise (got ${contextLines} lines); completed milestones should not inflate it`,
153
+ avgLinesPerCompletedMilestone < 10,
154
+ `Completed milestones should not inflate the context: got ${contextLines} lines across ${COMPLETED_COUNT} completed milestones (~${avgLinesPerCompletedMilestone.toFixed(1)}/milestone)`,
149
155
  );
150
156
 
151
157
  // ─── Cleanup ──────────────────────────────────────────────────────────────