gsd-pi 2.77.0-dev.58d3d4d6c → 2.77.0-dev.cfd69e714

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 (429) hide show
  1. package/README.md +1 -1
  2. package/dist/claude-cli-check.js +5 -1
  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 +5 -1
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/gsd/auto/loop.js +43 -0
  15. package/dist/resources/extensions/gsd/auto/phases.js +15 -21
  16. package/dist/resources/extensions/gsd/auto/session.js +0 -2
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
  18. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
  20. package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
  21. package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
  22. package/dist/resources/extensions/gsd/auto-start.js +34 -24
  23. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  24. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  25. package/dist/resources/extensions/gsd/auto.js +31 -20
  26. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  27. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  28. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  29. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  30. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  31. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  32. package/dist/resources/extensions/gsd/component-types.js +69 -0
  33. package/dist/resources/extensions/gsd/detection.js +49 -1
  34. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  35. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  36. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  37. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  38. package/dist/resources/extensions/gsd/git-service.js +126 -2
  39. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  40. package/dist/resources/extensions/gsd/guided-flow.js +17 -5
  41. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  42. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  43. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  44. package/dist/resources/extensions/gsd/model-router.js +6 -0
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  46. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  47. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  48. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  49. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  50. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  51. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  52. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  53. package/dist/resources/extensions/gsd/state.js +44 -33
  54. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  55. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  56. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  57. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  58. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  59. package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
  60. package/dist/resources/extensions/mcp-client/index.js +3 -1
  61. package/dist/resources/extensions/ollama/index.js +5 -1
  62. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  63. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  64. package/dist/web/standalone/.next/BUILD_ID +1 -1
  65. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  66. package/dist/web/standalone/.next/build-manifest.json +2 -2
  67. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  68. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/index.html +1 -1
  86. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  93. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  94. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  95. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  97. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  98. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  99. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  100. package/package.json +2 -3
  101. package/packages/daemon/src/logger.ts +4 -3
  102. package/packages/mcp-server/dist/server.d.ts +24 -0
  103. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  104. package/packages/mcp-server/dist/server.js +88 -87
  105. package/packages/mcp-server/dist/server.js.map +1 -1
  106. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  107. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  108. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  109. package/packages/mcp-server/src/server.ts +131 -105
  110. package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
  111. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  112. package/packages/native/package.json +1 -1
  113. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  114. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  115. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  116. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  117. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  118. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  119. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  120. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  121. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  122. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  123. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  124. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  125. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  126. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  127. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  128. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  129. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  130. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  131. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  132. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  133. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  134. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  135. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  136. package/packages/pi-ai/dist/models.test.js +36 -11
  137. package/packages/pi-ai/dist/models.test.js.map +1 -1
  138. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  139. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  140. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  141. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  142. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  143. package/packages/pi-ai/src/models.test.ts +48 -11
  144. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  145. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  146. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  148. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  150. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  152. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  154. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  156. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  158. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  160. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  163. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  165. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  167. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  169. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  170. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  171. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  173. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  175. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/index.js +1 -0
  177. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  182. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  189. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  190. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  191. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  192. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  193. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  194. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  195. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  196. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  197. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  198. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  199. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  200. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  201. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  202. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  203. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  204. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  205. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  206. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  207. package/packages/pi-coding-agent/src/index.ts +1 -0
  208. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  209. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  210. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  211. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  212. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  213. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  214. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  215. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  216. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  217. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  218. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  219. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
  220. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  221. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  222. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  223. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  224. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  225. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  226. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  227. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  228. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  229. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  230. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  231. package/packages/pi-tui/dist/components/editor.js +19 -0
  232. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  233. package/packages/pi-tui/dist/components/image.test.js +6 -5
  234. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  235. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  236. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  237. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  238. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  239. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  240. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
  241. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  242. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  243. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  244. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  245. package/packages/pi-tui/src/components/editor.ts +22 -0
  246. package/packages/pi-tui/src/components/image.test.ts +10 -5
  247. package/packages/pi-tui/src/editor-component.ts +3 -0
  248. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  249. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  250. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  251. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  252. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  253. package/scripts/install.js +15 -1
  254. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  255. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  256. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  257. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  258. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  259. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  260. package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
  261. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  262. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  263. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  264. package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
  265. package/src/resources/extensions/gsd/auto/loop.ts +47 -0
  266. package/src/resources/extensions/gsd/auto/phases.ts +16 -20
  267. package/src/resources/extensions/gsd/auto/session.ts +0 -2
  268. package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
  269. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  270. package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
  271. package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
  272. package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
  273. package/src/resources/extensions/gsd/auto-start.ts +54 -6
  274. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  275. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  276. package/src/resources/extensions/gsd/auto.ts +43 -22
  277. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  278. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  279. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  280. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  281. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  282. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  283. package/src/resources/extensions/gsd/component-types.ts +362 -0
  284. package/src/resources/extensions/gsd/detection.ts +58 -1
  285. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  286. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  287. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  288. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  289. package/src/resources/extensions/gsd/git-service.ts +133 -2
  290. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  291. package/src/resources/extensions/gsd/guided-flow.ts +20 -5
  292. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  293. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  294. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  295. package/src/resources/extensions/gsd/model-router.ts +6 -0
  296. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  297. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  298. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  299. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  300. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  301. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  302. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  303. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  304. package/src/resources/extensions/gsd/state.ts +49 -44
  305. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  306. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  307. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  308. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  309. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +94 -289
  310. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  311. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  312. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  313. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  314. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -197
  315. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  316. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  317. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  318. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  319. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  320. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  321. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  322. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  323. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  324. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  325. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  326. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  327. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -3
  328. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  329. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  330. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
  331. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  332. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  333. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  334. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
  335. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  336. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  337. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  338. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  339. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  340. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  341. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  342. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  343. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  344. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -62
  345. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  346. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  347. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  348. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -49
  349. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  350. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
  351. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  352. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  353. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  354. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  355. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  356. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  357. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  358. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  359. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  360. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  361. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  362. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  363. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  364. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  365. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  366. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  367. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  368. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
  369. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  370. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  371. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  372. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +12 -61
  373. package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
  374. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  375. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  376. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  377. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  378. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  379. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  380. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
  381. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
  382. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  383. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  384. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  385. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  386. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  387. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  388. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  389. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  390. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  391. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  392. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  393. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  394. package/src/resources/extensions/gsd/types.ts +3 -3
  395. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  396. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  397. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  398. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  399. package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
  400. package/src/resources/extensions/mcp-client/index.ts +3 -1
  401. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  402. package/src/resources/extensions/ollama/index.ts +5 -1
  403. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  404. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  405. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  406. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  407. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  408. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  409. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  410. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  411. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  412. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  413. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  414. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -144
  415. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  416. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  417. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  418. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  419. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  420. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  421. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -75
  422. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  423. package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
  424. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  425. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  426. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -130
  427. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
  428. /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
  429. /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_ssgManifest.js +0 -0
@@ -0,0 +1,301 @@
1
+ // GSD-2 — #4781 phase 2: dispatch-rule gates read pipeline variant from DB.
2
+ // Behavior tests (not source-grep) — construct a real tmpdir DB, insert a
3
+ // milestone whose planning fields classify to the target variant, exercise
4
+ // DISPATCH_RULES.match(), assert the gate result.
5
+
6
+ import test from "node:test";
7
+ import assert from "node:assert/strict";
8
+ import { mkdtempSync, mkdirSync, rmSync, existsSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { tmpdir } from "node:os";
11
+
12
+ import { DISPATCH_RULES, type DispatchContext } from "../auto-dispatch.ts";
13
+ import {
14
+ openDatabase,
15
+ closeDatabase,
16
+ insertMilestone,
17
+ upsertMilestonePlanning,
18
+ insertSlice,
19
+ } from "../gsd-db.ts";
20
+ import { invalidateAllCaches } from "../cache.ts";
21
+ import type { GSDState } from "../types.ts";
22
+
23
+ const PARALLEL_RESEARCH_RULE = "planning (multiple slices need research) → parallel-research-slices";
24
+ const SINGLE_RESEARCH_RULE = "planning (no research, not S01) → research-slice";
25
+ const VALIDATE_RULE = "validating-milestone → validate-milestone";
26
+
27
+ // ─── Fixture helpers ──────────────────────────────────────────────────────
28
+
29
+ function makeBase(): string {
30
+ const base = mkdtempSync(join(tmpdir(), "gsd-pipeline-variant-"));
31
+ mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
32
+ mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S02", "tasks"), { recursive: true });
33
+ return base;
34
+ }
35
+
36
+ function cleanup(base: string): void {
37
+ try { closeDatabase(); } catch { /* noop */ }
38
+ invalidateAllCaches();
39
+ rmSync(base, { recursive: true, force: true });
40
+ }
41
+
42
+ interface SeedOpts {
43
+ title: string;
44
+ vision: string;
45
+ successCriteria: string[];
46
+ }
47
+
48
+ function seedMilestone(base: string, mid: string, opts: SeedOpts): void {
49
+ openDatabase(join(base, ".gsd", "gsd.db"));
50
+ insertMilestone({
51
+ id: mid,
52
+ title: opts.title,
53
+ status: "active",
54
+ depends_on: [],
55
+ });
56
+ upsertMilestonePlanning(mid, {
57
+ title: opts.title,
58
+ status: "active",
59
+ vision: opts.vision,
60
+ successCriteria: opts.successCriteria,
61
+ keyRisks: [],
62
+ proofStrategy: [],
63
+ verificationContract: "",
64
+ verificationIntegration: "",
65
+ verificationOperational: "",
66
+ verificationUat: "",
67
+ definitionOfDone: [],
68
+ requirementCoverage: "",
69
+ boundaryMapMarkdown: "",
70
+ });
71
+ insertSlice({
72
+ id: "S01",
73
+ milestoneId: mid,
74
+ title: "First",
75
+ status: "pending",
76
+ risk: "low",
77
+ depends: [],
78
+ demo: "",
79
+ sequence: 1,
80
+ });
81
+ insertSlice({
82
+ id: "S02",
83
+ milestoneId: mid,
84
+ title: "Second",
85
+ status: "pending",
86
+ risk: "low",
87
+ depends: ["S01"],
88
+ demo: "",
89
+ sequence: 2,
90
+ });
91
+ }
92
+
93
+ function findRule(name: string) {
94
+ const rule = DISPATCH_RULES.find(r => r.name === name);
95
+ assert.ok(rule, `rule "${name}" must exist`);
96
+ return rule!;
97
+ }
98
+
99
+ function makeCtx(params: {
100
+ base: string;
101
+ mid: string;
102
+ phase: GSDState["phase"];
103
+ activeSlice?: { id: string; title: string };
104
+ }): DispatchContext {
105
+ const state: GSDState = {
106
+ phase: params.phase,
107
+ activeMilestone: { id: params.mid, title: "Test" },
108
+ activeSlice: params.activeSlice ?? null,
109
+ activeTask: null,
110
+ recentDecisions: [],
111
+ blockers: [],
112
+ nextAction: "",
113
+ registry: [{ id: params.mid, title: "Test", status: "active" }],
114
+ };
115
+ return {
116
+ basePath: params.base,
117
+ mid: params.mid,
118
+ midTitle: "Test",
119
+ state,
120
+ prefs: undefined,
121
+ };
122
+ }
123
+
124
+ // Inputs that consistently classify.
125
+ const TRIVIAL_INPUT: SeedOpts = {
126
+ title: "Static To-Do App",
127
+ vision: "A minimal, clean browser-based to-do app. Pure HTML/CSS/JS, no build step, no backend. Tasks persist in localStorage.",
128
+ successCriteria: [
129
+ "Open index.html in any browser without a server",
130
+ "Tasks survive a page reload via localStorage",
131
+ ],
132
+ };
133
+
134
+ const STANDARD_INPUT: SeedOpts = {
135
+ title: "Billing API extension",
136
+ vision: "Extend the billing API to charge usage-tier overages. Touch the invoice service, the entitlements cache, and the webhook handler.",
137
+ successCriteria: [
138
+ "Overage charges generate correct invoices",
139
+ "Integration tests cover tier rollovers",
140
+ "API endpoint returns structured error on webhook failure",
141
+ ],
142
+ };
143
+
144
+ // ─── Research-slice gate (single) ─────────────────────────────────────────
145
+
146
+ test("#4781 phase 2: single research-slice rule skips dispatch for trivial variant", async (t) => {
147
+ const base = makeBase();
148
+ t.after(() => cleanup(base));
149
+
150
+ seedMilestone(base, "M001", TRIVIAL_INPUT);
151
+ const ctx = makeCtx({
152
+ base,
153
+ mid: "M001",
154
+ phase: "planning",
155
+ activeSlice: { id: "S02", title: "Second" },
156
+ });
157
+
158
+ const result = await findRule(SINGLE_RESEARCH_RULE).match(ctx);
159
+ assert.strictEqual(result, null, "trivial variant must skip research-slice dispatch");
160
+ });
161
+
162
+ test("#4781 phase 2: single research-slice rule proceeds normally for standard variant", async (t) => {
163
+ const base = makeBase();
164
+ t.after(() => cleanup(base));
165
+
166
+ seedMilestone(base, "M001", STANDARD_INPUT);
167
+ const ctx = makeCtx({
168
+ base,
169
+ mid: "M001",
170
+ phase: "planning",
171
+ activeSlice: { id: "S02", title: "Second" },
172
+ });
173
+
174
+ // No RESEARCH file exists → rule should reach the dispatch branch.
175
+ // We don't assert "dispatch" because the prompt builder may error with
176
+ // minimal fixture data; we assert "not null AND not a trivial-skip
177
+ // shortcut" by checking that if null was returned, it's for a known
178
+ // reason (research file exists). For this fixture none exists, so the
179
+ // result should be an action object.
180
+ const result = await findRule(SINGLE_RESEARCH_RULE).match(ctx);
181
+ assert.notStrictEqual(result, null, "standard variant must not short-circuit the research-slice gate");
182
+ });
183
+
184
+ // ─── Parallel research-slice gate ─────────────────────────────────────────
185
+
186
+ test("#4781 phase 2: parallel-research-slices rule skips dispatch for trivial variant", async (t) => {
187
+ const base = makeBase();
188
+ t.after(() => cleanup(base));
189
+
190
+ seedMilestone(base, "M001", TRIVIAL_INPUT);
191
+ // Roadmap needs to be readable for the parallel rule to enter its slice
192
+ // analysis. Write a minimal one.
193
+ const { writeFileSync } = await import("node:fs");
194
+ writeFileSync(
195
+ join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
196
+ [
197
+ "# M001",
198
+ "## Slices",
199
+ "- [ ] **S01: First** `risk:low` `depends:[]`",
200
+ "- [ ] **S02: Second** `risk:low` `depends:[]`",
201
+ ].join("\n"),
202
+ );
203
+
204
+ const ctx = makeCtx({ base, mid: "M001", phase: "planning" });
205
+ const result = await findRule(PARALLEL_RESEARCH_RULE).match(ctx);
206
+ assert.strictEqual(result, null, "trivial variant must skip parallel-research dispatch");
207
+ });
208
+
209
+ // ─── Validate-milestone gate ──────────────────────────────────────────────
210
+
211
+ test("#4781 phase 2: validate-milestone rule writes pass-through VALIDATION for trivial variant", async (t) => {
212
+ const base = makeBase();
213
+ t.after(() => cleanup(base));
214
+
215
+ seedMilestone(base, "M001", TRIVIAL_INPUT);
216
+ // findMissingSummaries checks slice SUMMARY files — write empty ones so
217
+ // the safety guard doesn't stop first.
218
+ const { writeFileSync } = await import("node:fs");
219
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md"), "# S01\n");
220
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "slices", "S02", "S02-SUMMARY.md"), "# S02\n");
221
+ // Write a roadmap so findMissingSummaries can enumerate slice IDs.
222
+ writeFileSync(
223
+ join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
224
+ [
225
+ "# M001",
226
+ "## Slices",
227
+ "- [x] **S01: First** `risk:low` `depends:[]`",
228
+ "- [x] **S02: Second** `risk:low` `depends:[]`",
229
+ ].join("\n"),
230
+ );
231
+
232
+ const ctx = makeCtx({ base, mid: "M001", phase: "validating-milestone" });
233
+ const result = await findRule(VALIDATE_RULE).match(ctx);
234
+
235
+ assert.ok(result, "rule must return a result, not null");
236
+ assert.strictEqual(result!.action, "skip", "trivial variant must return skip action");
237
+
238
+ const validationPath = join(base, ".gsd", "milestones", "M001", "M001-VALIDATION.md");
239
+ assert.ok(existsSync(validationPath), "pass-through VALIDATION.md must be written");
240
+
241
+ const { readFileSync } = await import("node:fs");
242
+ const content = readFileSync(validationPath, "utf-8");
243
+ assert.match(content, /verdict: pass/);
244
+ assert.match(content, /trivial-scope pipeline variant \(#4781\)/);
245
+ });
246
+
247
+ test("#4781 phase 2: validate-milestone rule dispatches normally for standard variant", async (t) => {
248
+ const base = makeBase();
249
+ t.after(() => cleanup(base));
250
+
251
+ seedMilestone(base, "M001", STANDARD_INPUT);
252
+ const { writeFileSync } = await import("node:fs");
253
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md"), "# S01\n");
254
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "slices", "S02", "S02-SUMMARY.md"), "# S02\n");
255
+ writeFileSync(
256
+ join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
257
+ [
258
+ "# M001",
259
+ "## Slices",
260
+ "- [x] **S01: First** `risk:low` `depends:[]`",
261
+ "- [x] **S02: Second** `risk:low` `depends:[]`",
262
+ ].join("\n"),
263
+ );
264
+
265
+ const ctx = makeCtx({ base, mid: "M001", phase: "validating-milestone" });
266
+ const result = await findRule(VALIDATE_RULE).match(ctx);
267
+
268
+ assert.ok(result, "standard variant must produce a result");
269
+ assert.strictEqual(result!.action, "dispatch", "standard variant must dispatch validate-milestone");
270
+ if (result!.action === "dispatch") {
271
+ assert.strictEqual(result!.unitType, "validate-milestone");
272
+ }
273
+ });
274
+
275
+ // ─── Fallback safety: no DB, missing milestone ────────────────────────────
276
+
277
+ test("#4781 phase 2: null variant (no milestone row) does NOT gate dispatch — safe fallback", async (t) => {
278
+ const base = makeBase();
279
+ t.after(() => cleanup(base));
280
+
281
+ // Open DB but do NOT seed any milestone — getMilestone returns null,
282
+ // which makes getMilestonePipelineVariant return null. Rules must NOT
283
+ // short-circuit on null (silent downshift is the hazard we're guarding
284
+ // against).
285
+ openDatabase(join(base, ".gsd", "gsd.db"));
286
+
287
+ const ctx = makeCtx({
288
+ base,
289
+ mid: "M999",
290
+ phase: "planning",
291
+ activeSlice: { id: "S02", title: "Second" },
292
+ });
293
+
294
+ // Rule should NOT return null from the variant gate. It may still return
295
+ // null for other reasons (e.g. missing active slice), but our assertion
296
+ // is specifically about the variant-gate not short-circuiting.
297
+ const result = await findRule(SINGLE_RESEARCH_RULE).match(ctx);
298
+ // Rule reaches its normal logic; with an active slice and no RESEARCH file,
299
+ // it should produce a dispatch action, not null from the variant gate.
300
+ assert.notStrictEqual(result, null, "null variant must not cause the research-slice gate to short-circuit");
301
+ });
@@ -191,7 +191,12 @@ function createFailingTasks(): void {
191
191
  estimate: "1h",
192
192
  files: [],
193
193
  verify: "npm test",
194
- inputs: ["nonexistent-file-that-does-not-exist.ts"],
194
+ inputs: [
195
+ "nonexistent-file-that-does-not-exist.ts",
196
+ "missing-second-file.ts",
197
+ "missing-third-file.ts",
198
+ "missing-fourth-file.ts",
199
+ ],
195
200
  expectedOutput: [],
196
201
  observabilityImpact: "",
197
202
  },
@@ -308,6 +313,32 @@ describe("Pre-execution checks → pauseAuto wiring", () => {
308
313
  String(call.arguments[0]).includes("Pre-execution checks failed")
309
314
  );
310
315
  assert.ok(errorNotify, "Should show error notification about pre-execution check failure");
316
+ const errorMessage = String(errorNotify.arguments[0]);
317
+ assert.match(
318
+ errorMessage,
319
+ /Pre-execution checks failed: \d+ blocking issue/,
320
+ "failure notification should include the blocking issue count",
321
+ );
322
+ assert.ok(
323
+ errorMessage.includes("[file] nonexistent-file-that-does-not-exist.ts: Task T01 references"),
324
+ "failure notification should include category, target, and message details",
325
+ );
326
+ assert.ok(
327
+ errorMessage.includes("[file] missing-third-file.ts: Task T01 references"),
328
+ "failure notification should include up to three actionable check details",
329
+ );
330
+ assert.ok(
331
+ !errorMessage.includes("missing-fourth-file.ts"),
332
+ "failure notification should truncate details beyond the display limit",
333
+ );
334
+ assert.ok(
335
+ errorMessage.includes("...and 1 more"),
336
+ "failure notification should summarize truncated blocking checks",
337
+ );
338
+ assert.ok(
339
+ errorMessage.includes(join(".gsd", "milestones", "M001", "slices", "S01", "S01-PRE-EXEC-VERIFY.json")),
340
+ "failure notification should point to the relative pre-exec evidence file path",
341
+ );
311
342
  });
312
343
 
313
344
  test("pauseAuto is called when enhanced_verification_strict: true and pre-execution returns warn", async () => {
@@ -13,7 +13,12 @@ import { fileURLToPath } from "node:url";
13
13
  import { classifyError, isTransient, isTransientNetworkError } from "../error-classifier.ts";
14
14
  import { pauseAutoForProviderError } from "../provider-error-pause.ts";
15
15
  import { resumeAutoAfterProviderDelay } from "../bootstrap/provider-error-resume.ts";
16
+ import { MAX_TRANSIENT_AUTO_RESUMES } from "../bootstrap/agent-end-recovery.ts";
16
17
  import { getNextFallbackModel } from "../preferences.ts";
18
+ // Zero-import module — imported by path rather than through the package
19
+ // barrel to avoid pulling the full AgentSession / @gsd/pi-ai dep graph into
20
+ // this unit test (see #4837).
21
+ import { RETRYABLE_ERROR_RE } from "../../../../../packages/pi-coding-agent/src/core/retryable-error-regex.ts";
17
22
 
18
23
  const __dirname = dirname(fileURLToPath(import.meta.url));
19
24
 
@@ -405,7 +410,6 @@ test("resumeAutoAfterProviderDelay restarts paused auto-mode from the recorded b
405
410
  basePath: "/tmp/project",
406
411
  }),
407
412
  resetTransientRetryState: () => {},
408
- resetSessionTimeoutState: () => {},
409
413
  startAuto: async (_ctx, _pi, base, verboseMode, options) => {
410
414
  startCalls.push({ base, verboseMode, step: options?.step });
411
415
  },
@@ -431,7 +435,6 @@ test("resumeAutoAfterProviderDelay does not double-start when auto-mode is alrea
431
435
  basePath: "/tmp/project",
432
436
  }),
433
437
  resetTransientRetryState: () => {},
434
- resetSessionTimeoutState: () => {},
435
438
  startAuto: async () => {
436
439
  startCalls += 1;
437
440
  },
@@ -463,7 +466,6 @@ test("resumeAutoAfterProviderDelay leaves auto paused when no base path is avail
463
466
  basePath: "",
464
467
  }),
465
468
  resetTransientRetryState: () => {},
466
- resetSessionTimeoutState: () => {},
467
469
  startAuto: async () => {
468
470
  startCalls += 1;
469
471
  },
@@ -480,7 +482,7 @@ test("resumeAutoAfterProviderDelay leaves auto paused when no base path is avail
480
482
  ]);
481
483
  });
482
484
 
483
- test("resumeAutoAfterProviderDelay resets provider retry state before restarting auto-mode", async () => {
485
+ test("resumeAutoAfterProviderDelay resets provider retry state without clearing session-timeout attempts", async () => {
484
486
  const calls: string[] = [];
485
487
 
486
488
  const result = await resumeAutoAfterProviderDelay(
@@ -496,9 +498,6 @@ test("resumeAutoAfterProviderDelay resets provider retry state before restarting
496
498
  resetTransientRetryState: () => {
497
499
  calls.push("reset-transient");
498
500
  },
499
- resetSessionTimeoutState: () => {
500
- calls.push("reset-session-timeout");
501
- },
502
501
  startAuto: async () => {
503
502
  calls.push("start-auto");
504
503
  },
@@ -508,7 +507,6 @@ test("resumeAutoAfterProviderDelay resets provider retry state before restarting
508
507
  assert.equal(result, "resumed");
509
508
  assert.deepEqual(calls, [
510
509
  "reset-transient",
511
- "reset-session-timeout",
512
510
  "start-auto",
513
511
  ]);
514
512
  });
@@ -684,13 +682,12 @@ test("phases.ts resets session timeout counter on successful unit completion", (
684
682
  // ── Fix 3: MAX_TRANSIENT_AUTO_RESUMES raised to 8 ───────────────────────────
685
683
 
686
684
  test("MAX_TRANSIENT_AUTO_RESUMES is at least 8 for sustained overload resilience", () => {
687
- const src = readFileSync(join(__dirname, "..", "bootstrap", "agent-end-recovery.ts"), "utf-8");
688
- const match = src.match(/MAX_TRANSIENT_AUTO_RESUMES\s*=\s*(\d+)/);
689
- assert.ok(match, "MAX_TRANSIENT_AUTO_RESUMES must be defined");
690
- const value = Number(match![1]);
685
+ // Import the real constant rather than regex-scraping the source literal —
686
+ // this way the assertion cannot silently drift if the symbol is renamed or
687
+ // the value is moved. See #4837.
691
688
  assert.ok(
692
- value >= 8,
693
- `MAX_TRANSIENT_AUTO_RESUMES must be >= 8 for sustained overload resilience, got ${value}`,
689
+ MAX_TRANSIENT_AUTO_RESUMES >= 8,
690
+ `MAX_TRANSIENT_AUTO_RESUMES must be >= 8 for sustained overload resilience, got ${MAX_TRANSIENT_AUTO_RESUMES}`,
694
691
  );
695
692
  });
696
693
 
@@ -738,20 +735,22 @@ test("classifyError: 'context window' with 'exceed' is transient server", () =>
738
735
  // ── agent-session retryable regex handles server_error (#1166) ──────────────
739
736
 
740
737
  test("agent-session retryable error regex matches server_error (underscore)", () => {
741
- // This regex is extracted from _isRetryableError in agent-session.ts.
742
- // It must match both "server error" (space) and "server_error" (underscore)
743
- // to properly classify Codex streaming errors as retryable.
744
- // "temporarily backed off" intentionally excluded — see #3429
745
- const retryableRegex = /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated|retry delay|network.?(?:is\s+)?unavailable|credentials.*expired|extra usage is required/i;
738
+ // Import the real regex from the retry-handler so this test can never
739
+ // silently drift from runtime behaviour. The regex must match both
740
+ // "server error" (space) and "server_error" (underscore) to properly
741
+ // classify Codex streaming errors as retryable.
742
+ // "temporarily backed off" is intentionally excluded see #3429 / #4837.
746
743
 
747
744
  // server_error (with underscore — Codex streaming error format)
748
- assert.ok(retryableRegex.test("Codex server_error: An error occurred"));
745
+ assert.ok(RETRYABLE_ERROR_RE.test("Codex server_error: An error occurred"));
749
746
  // server error (with space — traditional HTTP error format)
750
- assert.ok(retryableRegex.test("server error occurred"));
747
+ assert.ok(RETRYABLE_ERROR_RE.test("server error occurred"));
751
748
  // internal_error (with underscore)
752
- assert.ok(retryableRegex.test("internal_error: something went wrong"));
749
+ assert.ok(RETRYABLE_ERROR_RE.test("internal_error: something went wrong"));
753
750
  // internal error (with space)
754
- assert.ok(retryableRegex.test("internal error"));
751
+ assert.ok(RETRYABLE_ERROR_RE.test("internal error"));
755
752
  // non-retryable errors must not match
756
- assert.ok(!retryableRegex.test("model not found"));
753
+ assert.ok(!RETRYABLE_ERROR_RE.test("model not found"));
754
+ // "temporarily backed off" must NOT be matched (intentional exclusion #3429)
755
+ assert.ok(!RETRYABLE_ERROR_RE.test("temporarily backed off"));
757
756
  });
@@ -178,4 +178,36 @@ describe("Windows pre-merge DB release (#4704)", () => {
178
178
  "openDatabase() called after the pre-merge stash",
179
179
  );
180
180
  });
181
+
182
+ it("pre-merge stash targets entries by marker instead of refs/stash or stash@{0}", () => {
183
+ const src = readFileSync(
184
+ join(import.meta.dirname, "..", "auto-worktree.ts"),
185
+ "utf-8",
186
+ );
187
+
188
+ assert.ok(src.includes("stashMarker"), "stash marker is tracked");
189
+ assert.ok(
190
+ src.includes('"stash", "list", "--format=%gd%x00%s"'),
191
+ "stash lookup reads ref and message together",
192
+ );
193
+ assert.ok(!src.includes('"rev-parse", "refs/stash"'), "refs/stash is not used for identity");
194
+ assert.ok(!src.includes('["stash", "pop"]'), "stash pop is never unqualified");
195
+ assert.ok(!src.includes('["stash", "drop"]'), "stash drop is never unqualified");
196
+ });
197
+
198
+ it("stash drop after pop failure requires auto-resolved .gsd conflicts", () => {
199
+ const src = readFileSync(
200
+ join(import.meta.dirname, "..", "auto-worktree.ts"),
201
+ "utf-8",
202
+ );
203
+
204
+ assert.ok(
205
+ src.includes("gsdUU.length > 0 && nonGsdUU.length === 0"),
206
+ "stash drop must only run after detected .gsd conflicts were auto-resolved",
207
+ );
208
+ assert.ok(
209
+ src.includes("git stash pop failed without resolvable conflict files; leaving stash for manual recovery"),
210
+ "non-conflict stash pop failures must leave the stash for manual recovery",
211
+ );
212
+ });
181
213
  });
@@ -60,10 +60,24 @@ function mkBase(): string {
60
60
  return base;
61
61
  }
62
62
 
63
- function assistantMsg(text: string, opts: { toolUse?: boolean } = {}): any {
63
+ function assistantMsg(
64
+ text: string,
65
+ opts: { toolUse?: boolean | "toolCall" | "serverToolUse" } = {},
66
+ ): any {
64
67
  const content: any[] = [];
65
68
  if (text) content.push({ type: "text", text });
66
- if (opts.toolUse) content.push({ type: "tool_use", name: "whatever", input: {} });
69
+ if (opts.toolUse) {
70
+ // The canonical pi-ai AssistantMessage uses "toolCall" / "serverToolUse"
71
+ // (see packages/pi-ai/src/types.ts). Every provider — anthropic-direct,
72
+ // claude-code-cli, openai — normalizes incoming tool blocks into these
73
+ // shapes before they reach guided-flow. The Anthropic-wire literal
74
+ // "tool_use" never appears here.
75
+ if (opts.toolUse === "serverToolUse") {
76
+ content.push({ type: "serverToolUse", id: "test-id", name: "web_search", input: {} });
77
+ } else {
78
+ content.push({ type: "toolCall", id: "test-id", name: "whatever", arguments: {} });
79
+ }
80
+ }
67
81
  return { role: "assistant", content };
68
82
  }
69
83
 
@@ -314,6 +328,65 @@ describe("#4573 maybeHandleEmptyIntentTurn", () => {
314
328
  }
315
329
  });
316
330
 
331
+ // Regression for #4658 — under claude-code-cli, MCP tool calls (e.g.
332
+ // ask_user_questions) reach guided-flow as canonical "toolCall" / "serverToolUse"
333
+ // blocks. Pre-fix, hasToolUse only matched the Anthropic-wire literal "tool_use",
334
+ // so the empty-turn nudge fired during pre-question narration and pre-empted the
335
+ // user's chance to answer.
336
+ test("cc-cli MCP tool call surfaced as canonical toolCall → not flagged", () => {
337
+ const base = mkBase();
338
+ try {
339
+ const cap = mkCapture();
340
+ setPendingAutoStart(base, {
341
+ basePath: base,
342
+ milestoneId: "M001",
343
+ ctx: mkCtx(cap),
344
+ pi: mkPi(cap),
345
+ });
346
+ const handled = maybeHandleEmptyIntentTurn(
347
+ {
348
+ messages: [
349
+ assistantMsg("Let me call ask_user_questions to gather your preferences.", {
350
+ toolUse: "toolCall",
351
+ }),
352
+ ],
353
+ },
354
+ false,
355
+ );
356
+ assert.equal(handled, false);
357
+ assert.equal(cap.messages.length, 0);
358
+ } finally {
359
+ clearPendingAutoStart();
360
+ }
361
+ });
362
+
363
+ test("serverToolUse block (cc-cli web search etc.) → not flagged", () => {
364
+ const base = mkBase();
365
+ try {
366
+ const cap = mkCapture();
367
+ setPendingAutoStart(base, {
368
+ basePath: base,
369
+ milestoneId: "M001",
370
+ ctx: mkCtx(cap),
371
+ pi: mkPi(cap),
372
+ });
373
+ const handled = maybeHandleEmptyIntentTurn(
374
+ {
375
+ messages: [
376
+ assistantMsg("Let me invoke the search tool now.", {
377
+ toolUse: "serverToolUse",
378
+ }),
379
+ ],
380
+ },
381
+ false,
382
+ );
383
+ assert.equal(handled, false);
384
+ assert.equal(cap.messages.length, 0);
385
+ } finally {
386
+ clearPendingAutoStart();
387
+ }
388
+ });
389
+
317
390
  test("ready phrase is NOT treated as empty-turn (handled by other recovery path)", () => {
318
391
  const base = mkBase();
319
392
  try {