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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (545) hide show
  1. package/README.md +53 -17
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/github-sync/templates.js +103 -0
  15. package/dist/resources/extensions/google-search/index.js +3 -2
  16. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  17. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  18. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  19. package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
  20. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
  22. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  23. package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
  24. package/dist/resources/extensions/gsd/auto-start.js +107 -29
  25. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  26. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  27. package/dist/resources/extensions/gsd/auto.js +76 -21
  28. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  30. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  31. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  33. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  34. package/dist/resources/extensions/gsd/component-types.js +69 -0
  35. package/dist/resources/extensions/gsd/context-store.js +23 -7
  36. package/dist/resources/extensions/gsd/detection.js +49 -1
  37. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
  38. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  39. package/dist/resources/extensions/gsd/forensics.js +106 -0
  40. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  41. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  42. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  43. package/dist/resources/extensions/gsd/git-service.js +126 -2
  44. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  45. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  46. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  47. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  48. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  49. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  50. package/dist/resources/extensions/gsd/model-router.js +6 -0
  51. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  52. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  53. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  54. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  55. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  56. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  58. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  59. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  60. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  61. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  62. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  63. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  64. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  65. package/dist/resources/extensions/gsd/state.js +69 -58
  66. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  67. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  68. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  69. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  70. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  71. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  72. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  73. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  74. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  75. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  76. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  77. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  78. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  79. package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  81. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  82. package/dist/resources/extensions/mcp-client/index.js +3 -1
  83. package/dist/resources/extensions/ollama/index.js +5 -1
  84. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  85. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  88. package/dist/web/standalone/.next/build-manifest.json +2 -2
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/index.html +1 -1
  108. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  115. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  116. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  117. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  119. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  120. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  121. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  122. package/package.json +2 -3
  123. package/packages/daemon/package.json +2 -2
  124. package/packages/daemon/src/logger.ts +4 -3
  125. package/packages/mcp-server/dist/server.d.ts +24 -0
  126. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  127. package/packages/mcp-server/dist/server.js +88 -87
  128. package/packages/mcp-server/dist/server.js.map +1 -1
  129. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  130. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  131. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  132. package/packages/mcp-server/package.json +2 -2
  133. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  134. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  135. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  136. package/packages/mcp-server/src/server.ts +131 -105
  137. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  138. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  139. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  140. package/packages/native/package.json +2 -2
  141. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  142. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  143. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  144. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  145. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  146. package/packages/pi-agent-core/package.json +1 -1
  147. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  148. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  149. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  150. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  151. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  152. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  153. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  154. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  155. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  156. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  157. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  158. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  159. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  160. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  161. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  162. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  163. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  164. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  165. package/packages/pi-ai/dist/models.test.js +36 -11
  166. package/packages/pi-ai/dist/models.test.js.map +1 -1
  167. package/packages/pi-ai/package.json +1 -1
  168. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  169. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  170. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  171. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  172. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  173. package/packages/pi-ai/src/models.test.ts +48 -11
  174. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  175. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  176. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  178. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  180. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  182. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  184. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  186. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  188. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  190. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  193. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  195. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  197. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  198. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  199. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  201. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  203. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/index.js +1 -0
  207. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  209. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  217. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  228. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  229. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  230. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  231. package/packages/pi-coding-agent/package.json +1 -1
  232. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  233. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  234. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  235. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  236. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  237. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  238. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  239. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  240. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  241. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  242. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  243. package/packages/pi-coding-agent/src/index.ts +1 -0
  244. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  245. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  246. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  247. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  248. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  249. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  250. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  251. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  252. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  253. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  254. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  255. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  256. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  257. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
  258. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  259. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  260. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  261. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  262. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  263. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  264. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  265. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  266. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  267. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  268. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  269. package/packages/pi-tui/dist/components/editor.js +19 -0
  270. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  271. package/packages/pi-tui/dist/components/image.test.js +6 -5
  272. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  273. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  274. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  275. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  276. package/packages/pi-tui/package.json +1 -1
  277. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  278. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  279. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
  280. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  281. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  282. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  283. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  284. package/packages/pi-tui/src/components/editor.ts +22 -0
  285. package/packages/pi-tui/src/components/image.test.ts +10 -5
  286. package/packages/pi-tui/src/editor-component.ts +3 -0
  287. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  288. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  289. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  290. package/packages/rpc-client/package.json +1 -1
  291. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  292. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  293. package/pkg/package.json +1 -1
  294. package/scripts/install.js +15 -1
  295. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  296. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  297. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  298. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  299. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  300. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  301. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  302. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  303. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  304. package/src/resources/extensions/github-sync/templates.ts +151 -0
  305. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  306. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  307. package/src/resources/extensions/google-search/index.ts +3 -2
  308. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  309. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  310. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  311. package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
  312. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  313. package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
  314. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  315. package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
  316. package/src/resources/extensions/gsd/auto-start.ts +127 -9
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  318. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  319. package/src/resources/extensions/gsd/auto.ts +90 -23
  320. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  321. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  322. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  323. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  324. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  325. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  326. package/src/resources/extensions/gsd/component-types.ts +362 -0
  327. package/src/resources/extensions/gsd/context-store.ts +25 -8
  328. package/src/resources/extensions/gsd/detection.ts +58 -1
  329. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  331. package/src/resources/extensions/gsd/forensics.ts +118 -1
  332. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  333. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  334. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  335. package/src/resources/extensions/gsd/git-service.ts +149 -2
  336. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  337. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  338. package/src/resources/extensions/gsd/journal.ts +11 -1
  339. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  340. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  341. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  342. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  343. package/src/resources/extensions/gsd/model-router.ts +6 -0
  344. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  345. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  346. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  347. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  348. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  349. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  350. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  351. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  352. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  353. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  354. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  355. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  356. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  357. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  358. package/src/resources/extensions/gsd/state.ts +76 -66
  359. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  360. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  361. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  362. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  363. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  364. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
  365. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  366. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  367. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  368. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  369. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  370. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  371. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
  372. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  373. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  374. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  375. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  376. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  377. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  378. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  379. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  380. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  381. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  382. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  383. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  384. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  385. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  386. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  387. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  389. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  390. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  391. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  392. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  393. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  394. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  395. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  396. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  397. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  398. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
  399. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  400. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  401. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  402. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  403. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  404. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  405. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  406. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  407. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  408. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
  410. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  411. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  412. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  413. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  415. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  416. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  417. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  418. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  419. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  420. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  421. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  422. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  423. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  424. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  425. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  426. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  427. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  428. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  429. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  430. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  431. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  432. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  434. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  435. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  436. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  437. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  438. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  439. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  440. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  442. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  443. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  444. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  445. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  446. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  447. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  448. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  449. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  451. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  452. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  453. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  454. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  455. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  456. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  457. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  458. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  459. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  460. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  461. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  462. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  463. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  464. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  465. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  466. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  467. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  468. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  469. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  470. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  471. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  472. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  473. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  474. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  475. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  476. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  477. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  478. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  479. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  481. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  482. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  483. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  484. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  485. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
  486. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  487. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  488. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  489. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  490. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  491. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  492. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  493. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  494. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  495. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  496. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  497. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  498. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  499. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  500. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  501. package/src/resources/extensions/gsd/types.ts +3 -3
  502. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  503. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  504. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  505. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  506. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  507. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  508. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  509. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  510. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  511. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  512. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  513. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  514. package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
  515. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  516. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  517. package/src/resources/extensions/mcp-client/index.ts +3 -1
  518. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  519. package/src/resources/extensions/ollama/index.ts +5 -1
  520. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  521. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  522. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  523. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  524. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  525. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  526. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  527. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  528. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  529. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  530. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  531. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  532. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  533. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  534. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  535. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  536. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  537. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  538. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  539. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  540. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  541. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  542. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  543. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  544. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  545. /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -0,0 +1,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 () => {
@@ -12,6 +12,7 @@ import assert from "node:assert/strict";
12
12
  import { readFileSync, mkdtempSync, mkdirSync, writeFileSync, existsSync, readdirSync, rmSync } from "node:fs";
13
13
  import { join } from "node:path";
14
14
  import { tmpdir } from "node:os";
15
+ import { extractSourceRegion } from "./test-helpers.ts";
15
16
 
16
17
  test("#2684: preferences files are NOT in ROOT_STATE_FILES (forward-only sync)", () => {
17
18
  const srcPath = join(import.meta.dirname, "..", "auto-worktree.ts");
@@ -49,7 +50,7 @@ test("copyPlanningArtifacts prefers canonical PREFERENCES.md with lowercase fall
49
50
  assert.ok(fnIdx !== -1, "copyPlanningArtifacts function exists");
50
51
 
51
52
  // Extract function body (up to the next top-level function)
52
- const fnBody = src.slice(fnIdx, fnIdx + 2200);
53
+ const fnBody = extractSourceRegion(src, "function copyPlanningArtifacts");
53
54
 
54
55
  assert.ok(
55
56
  fnBody.includes("PROJECT_PREFERENCES_FILE") && fnBody.includes("LEGACY_PROJECT_PREFERENCES_FILE"),
@@ -64,6 +64,18 @@ describe("prompt-cache-optimizer: classifySection", () => {
64
64
  assert.equal(classifySection("overrides"), "semi-static");
65
65
  });
66
66
 
67
+ // Regression: issue #4719 — KNOWLEDGE falls through to dynamic default.
68
+ // Knowledge content is reused across all tasks within a milestone, so it
69
+ // must be classified as semi-static to qualify for prefix caching when the
70
+ // cache optimizer is wired into the prompt path.
71
+ it("classifies knowledge as semi-static (issue #4719)", () => {
72
+ assert.equal(classifySection("knowledge"), "semi-static");
73
+ });
74
+
75
+ it("classifies project-knowledge as semi-static (issue #4719)", () => {
76
+ assert.equal(classifySection("project-knowledge"), "semi-static");
77
+ });
78
+
67
79
  it("classifies task-plan as dynamic", () => {
68
80
  assert.equal(classifySection("task-plan"), "dynamic");
69
81
  });
@@ -13,6 +13,7 @@ import assert from 'node:assert/strict';
13
13
  import { readFileSync } from 'node:fs';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { dirname, join } from 'node:path';
16
+ import { extractSourceRegion } from "./test-helpers.ts";
16
17
 
17
18
  const __filename = fileURLToPath(import.meta.url);
18
19
  const __dirname = dirname(__filename);
@@ -69,11 +70,21 @@ describe('register-extension _gsdEpipeGuard (#3696)', () => {
69
70
 
70
71
  describe('register-hooks session_before_compact (#3696)', () => {
71
72
  test('session_before_compact only checks isAutoActive', () => {
72
- // Extract the session_before_compact handler
73
- const compactIdx = registerHooksSrc.indexOf('session_before_compact');
73
+ // Anchor on the full registration token rather than the bare event name —
74
+ // prevents matching unrelated substring occurrences.
75
+ const compactIdx = registerHooksSrc.indexOf('pi.on("session_before_compact"');
74
76
  assert.ok(compactIdx > -1, 'session_before_compact hook should exist');
75
- // The first check in the handler should be isAutoActive(), not isAutoPaused()
76
- const afterCompact = registerHooksSrc.slice(compactIdx, compactIdx + 300);
77
+ // The first check in the handler should be isAutoActive(), not isAutoPaused().
78
+ // Bound the region to this single handler — register-hooks.ts contains
79
+ // multiple pi.on("session_before_compact") handlers and a later handler
80
+ // legitimately references isAutoPaused.
81
+ const afterCompact = extractSourceRegion(
82
+ registerHooksSrc,
83
+ 'pi.on("session_before_compact"',
84
+ 'pi.on("',
85
+ // NB: endAnchor search starts AFTER the startAnchor, so the next
86
+ // pi.on("... matches the subsequent handler rather than this one.
87
+ );
77
88
  assert.match(afterCompact, /isAutoActive\(\)/,
78
89
  'session_before_compact should check isAutoActive()');
79
90
  // Should NOT block compaction when paused
@@ -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
  });
@@ -6,6 +6,7 @@ import { tmpdir } from "node:os";
6
6
 
7
7
  import { deriveState } from "../state.js";
8
8
  import { buildExistingMilestonesContext } from "../guided-flow.js";
9
+ import { extractSourceRegion } from "./test-helpers.ts";
9
10
 
10
11
  describe('queue-draft-detection', () => {
11
12
  test('draft and context milestone detection', async () => {
@@ -68,7 +69,7 @@ describe('queue-draft-detection', () => {
68
69
 
69
70
  // both files: CONTEXT.md wins, no draft label
70
71
  const m003Idx = context.indexOf("M003:");
71
- const m003Section = context.slice(m003Idx, m003Idx + 500);
72
+ const m003Section = extractSourceRegion(context, "M003:");
72
73
  assert.ok(
73
74
  m003Section.includes("**Context:**"),
74
75
  "M003 (both files) should use 'Context:' label (CONTEXT.md wins)",
@@ -84,7 +85,7 @@ describe('queue-draft-detection', () => {
84
85
 
85
86
  // neither file: no context section
86
87
  const m004Idx = context.indexOf("M004:");
87
- const m004Section = context.slice(m004Idx, m004Idx + 500);
88
+ const m004Section = extractSourceRegion(context, "M004:");
88
89
  assert.ok(
89
90
  !m004Section.includes("**Context:**"),
90
91
  "M004 (neither file) should not have Context: label",
@@ -3,6 +3,7 @@ import assert from "node:assert/strict";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join, dirname } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { extractSourceRegion } from "./test-helpers.ts";
6
7
 
7
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
9
 
@@ -28,7 +29,7 @@ describe("queued-discuss-fast-path", () => {
28
29
  const fnStart = source.indexOf("async function dispatchDiscussForMilestone(");
29
30
  assert.ok(fnStart > 0, "dispatchDiscussForMilestone must exist");
30
31
  const fnEnd = source.indexOf("\nasync function ", fnStart + 1);
31
- const fnBody = fnEnd > 0 ? source.slice(fnStart, fnEnd) : source.slice(fnStart, fnStart + 2000);
32
+ const fnBody = extractSourceRegion(source, "async function dispatchDiscussForMilestone(");
32
33
  assert.ok(
33
34
  fnBody.includes("fastPathInstruction"),
34
35
  "dispatchDiscussForMilestone must compute fastPathInstruction",
@@ -61,8 +62,7 @@ describe("queued-discuss-fast-path", () => {
61
62
  const source = guidedFlowSrc();
62
63
  const fnStart = source.indexOf("async function showDiscussQueuedMilestone(");
63
64
  assert.ok(fnStart > 0, "showDiscussQueuedMilestone must exist");
64
- const fnEnd = source.indexOf("\nasync function ", fnStart + 1);
65
- const fnBody = fnEnd > 0 ? source.slice(fnStart, fnEnd) : source.slice(fnStart, fnStart + 3000);
65
+ const fnBody = extractSourceRegion(source, "async function showDiscussQueuedMilestone(", "\nasync function ");
66
66
  assert.ok(
67
67
  fnBody.includes("hasDraft"),
68
68
  "showDiscussQueuedMilestone must check hasDraft",
@@ -81,8 +81,7 @@ describe("queued-discuss-fast-path", () => {
81
81
  const source = guidedFlowSrc();
82
82
  const fnStart = source.indexOf("async function showDiscussQueuedMilestone(");
83
83
  assert.ok(fnStart > 0, "showDiscussQueuedMilestone must exist");
84
- const fnEnd = source.indexOf("\nasync function ", fnStart + 1);
85
- const fnBody = fnEnd > 0 ? source.slice(fnStart, fnEnd) : source.slice(fnStart, fnStart + 3000);
84
+ const fnBody = extractSourceRegion(source, "async function showDiscussQueuedMilestone(", "\nasync function ");
86
85
  assert.ok(
87
86
  fnBody.includes("let fastPath = hasDraft"),
88
87
  "showDiscussQueuedMilestone must set fastPath = hasDraft so draft presence auto-enables fast path",