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
@@ -1,108 +1,109 @@
1
1
  /**
2
- * Regression test for #2358: Survivor branch recovery skipped in phase=complete.
2
+ * survivor-branch-complete.test.ts #2358
3
3
  *
4
- * When bootstrapAutoSession finds a survivor milestone branch and the derived
5
- * state phase is "complete", recovery/finalization is skipped entirely because
6
- * the survivor branch detection only triggers when phase === "pre-planning".
7
- * The milestone finalization (merge, cleanup) never runs, leaving the worktree
8
- * and branch alive.
4
+ * The bug: `bootstrapAutoSession` found a survivor milestone branch
5
+ * (previous session's worktree/branch that was never merged) but only
6
+ * triggered recovery when `state.phase === "pre-planning"`. In
7
+ * `phase === "complete"` the milestone artifacts existed but the
8
+ * finalization path (merge + cleanup) never ran, leaving the worktree
9
+ * and branch alive indefinitely.
9
10
  *
10
- * The fix broadens the survivor branch detection to also check phase === "complete",
11
- * and adds a finalization path that runs mergeAndExit before falling through to
12
- * the normal "complete" handling.
11
+ * The fix broadens the detection to include `phase === "complete"` and
12
+ * routes to a finalize-via-mergeAndExit path.
13
+ *
14
+ * The previous version of this file was 4 scenarios that re-implemented
15
+ * the decision logic inline and called `.includes(phase)` on
16
+ * locally-declared arrays — testing the test, not the code. Called out
17
+ * in #4832 and parent #4784 as a pure-tautology case (zero imports
18
+ * from production).
19
+ *
20
+ * This rewrite imports `decideSurvivorAction` from auto-start.ts (a
21
+ * helper extracted in the accompanying refactor) and drives the full
22
+ * decision table through the real function. The helper is wired into
23
+ * `bootstrapAutoSession` at the two call sites that previously used
24
+ * inline conditionals, so the assertions here fail if someone reverts
25
+ * the helper or narrows its branches.
13
26
  */
14
27
 
15
- import { createTestContext } from "./test-helpers.ts";
16
-
17
- const { assertTrue, assertEq, report } = createTestContext();
18
-
19
- // ═══ Test: survivor branch detection conditions ══════════════════════════════
20
-
21
- // The survivor branch detection block in auto-start.ts checks:
22
- // state.activeMilestone &&
23
- // state.phase === "pre-planning" && // <-- BUG: too restrictive
24
- // shouldUseWorktreeIsolation() &&
25
- // !detectWorktreeName(base) &&
26
- // !base.includes(...)
27
- //
28
- // The fix should also include state.phase === "complete".
29
-
30
- {
31
- console.log("\n=== #2358: survivor branch should be detected in phase=complete ===");
32
-
33
- // Simulate the condition check before the fix (only pre-planning)
34
- const phasesBeforeFix = ["pre-planning"];
35
- const phasesAfterFix = ["pre-planning", "complete"];
36
-
37
- const testPhase = "complete";
38
-
39
- const detectedBefore = phasesBeforeFix.includes(testPhase);
40
- assertEq(detectedBefore, false, "before fix: phase=complete should NOT trigger survivor detection");
41
-
42
- const detectedAfter = phasesAfterFix.includes(testPhase);
43
- assertEq(detectedAfter, true, "after fix: phase=complete SHOULD trigger survivor detection");
44
- }
45
-
46
- // ═══ Test: pre-planning survivor detection still works ═══════════════════════
47
-
48
- {
49
- console.log("\n=== #2358: pre-planning survivor detection is not broken ===");
50
-
51
- const phasesAfterFix = ["pre-planning", "complete"];
52
- const testPhase = "pre-planning";
53
-
54
- const detected = phasesAfterFix.includes(testPhase);
55
- assertEq(detected, true, "pre-planning should still trigger survivor detection after fix");
56
- }
57
-
58
- // ═══ Test: other phases do NOT trigger survivor detection ════════════════════
59
-
60
- {
61
- console.log("\n=== #2358: other phases should NOT trigger survivor detection ===");
62
-
63
- const phasesAfterFix = ["pre-planning", "complete"];
64
-
65
- for (const phase of ["planning", "executing", "blocked", "needs-discussion"]) {
66
- const detected = phasesAfterFix.includes(phase);
67
- assertEq(detected, false, `phase=${phase} should NOT trigger survivor detection`);
68
- }
69
- }
70
-
71
- // ═══ Test: phase=complete + hasSurvivorBranch should trigger finalization ═════
72
-
73
- {
74
- console.log("\n=== #2358: phase=complete + survivor branch triggers finalization path ===");
75
-
76
- // Simulate the decision logic after the fix:
77
- // if (hasSurvivorBranch && state.phase === "complete") -> finalize
78
- // if (hasSurvivorBranch && state.phase === "needs-discussion") -> discuss
79
- // if (!hasSurvivorBranch && state.phase === "complete") -> showSmartEntry
80
-
81
- const scenarios = [
82
- { hasSurvivorBranch: true, phase: "complete", expected: "finalize" },
83
- { hasSurvivorBranch: true, phase: "needs-discussion", expected: "discuss" },
84
- { hasSurvivorBranch: true, phase: "pre-planning", expected: "continue" },
85
- { hasSurvivorBranch: false, phase: "complete", expected: "showSmartEntry" },
86
- ];
87
-
88
- for (const { hasSurvivorBranch, phase, expected } of scenarios) {
89
- let result: string;
90
- if (hasSurvivorBranch && phase === "complete") {
91
- result = "finalize";
92
- } else if (hasSurvivorBranch && phase === "needs-discussion") {
93
- result = "discuss";
94
- } else if (!hasSurvivorBranch && (!phase || phase === "complete")) {
95
- result = "showSmartEntry";
96
- } else {
97
- result = "continue";
28
+ import { describe, test } from "node:test";
29
+ import assert from "node:assert/strict";
30
+
31
+ import { decideSurvivorAction } from "../auto-start.ts";
32
+ import type { SurvivorAction } from "../auto-start.ts";
33
+
34
+ describe("decideSurvivorAction (#2358)", () => {
35
+ test("no survivor branch → no action, regardless of phase", () => {
36
+ const phases = [
37
+ "pre-planning",
38
+ "planning",
39
+ "executing",
40
+ "complete",
41
+ "needs-discussion",
42
+ "blocked",
43
+ "",
44
+ null,
45
+ undefined,
46
+ ];
47
+ for (const phase of phases) {
48
+ const got: SurvivorAction = decideSurvivorAction(false, phase);
49
+ assert.equal(got, "none", `phase=${phase ?? "(nullish)"} → expected 'none', got '${got}'`);
98
50
  }
99
-
100
- assertEq(
101
- result,
102
- expected,
103
- `hasSurvivorBranch=${hasSurvivorBranch}, phase=${phase} -> expected ${expected}, got ${result}`,
51
+ });
52
+
53
+ test("survivor + needs-discussion → 'discuss' (#1726)", () => {
54
+ assert.equal(decideSurvivorAction(true, "needs-discussion"), "discuss");
55
+ });
56
+
57
+ test("survivor + complete → 'finalize' (#2358 — the bug this regression guards)", () => {
58
+ // This is THE assertion that fails if someone reverts the fix and
59
+ // narrows the recovery to pre-planning only.
60
+ assert.equal(decideSurvivorAction(true, "complete"), "finalize");
61
+ });
62
+
63
+ test("survivor + other phase → 'none' (caller continues normal flow)", () => {
64
+ // pre-planning, planning, executing, blocked — survivor alone is
65
+ // not sufficient to trigger recovery. Normal auto-mode picks up
66
+ // from state. This protects against regressions that try to run
67
+ // finalize on every survivor regardless of phase.
68
+ const passThroughPhases = ["pre-planning", "planning", "executing", "blocked", ""];
69
+ for (const phase of passThroughPhases) {
70
+ assert.equal(
71
+ decideSurvivorAction(true, phase),
72
+ "none",
73
+ `survivor + phase=${phase} → expected 'none', got ${decideSurvivorAction(true, phase)}`,
74
+ );
75
+ }
76
+ });
77
+
78
+ test("decision table covers the three outcomes the bootstrap code needs", () => {
79
+ // Belt-and-suspenders: enumerate (hasSurvivor, phase) and assert
80
+ // the complete truth table. If someone adds a 4th outcome, this
81
+ // test fails loudly so they must update both the helper and the
82
+ // bootstrap wiring.
83
+ const cases: Array<{ hasSurvivor: boolean; phase: string | null; expected: SurvivorAction }> = [
84
+ { hasSurvivor: true, phase: "needs-discussion", expected: "discuss" },
85
+ { hasSurvivor: true, phase: "complete", expected: "finalize" },
86
+ { hasSurvivor: true, phase: "pre-planning", expected: "none" },
87
+ { hasSurvivor: true, phase: "planning", expected: "none" },
88
+ { hasSurvivor: true, phase: null, expected: "none" },
89
+ { hasSurvivor: false, phase: "complete", expected: "none" },
90
+ { hasSurvivor: false, phase: "needs-discussion", expected: "none" },
91
+ { hasSurvivor: false, phase: null, expected: "none" },
92
+ ];
93
+ const outcomes = new Set<SurvivorAction>();
94
+ for (const { hasSurvivor, phase, expected } of cases) {
95
+ const got = decideSurvivorAction(hasSurvivor, phase);
96
+ outcomes.add(got);
97
+ assert.equal(
98
+ got,
99
+ expected,
100
+ `(hasSurvivor=${hasSurvivor}, phase=${phase}) → expected '${expected}', got '${got}'`,
101
+ );
102
+ }
103
+ assert.deepEqual(
104
+ [...outcomes].sort(),
105
+ ["discuss", "finalize", "none"],
106
+ "decision function should produce exactly three outcomes",
104
107
  );
105
- }
106
- }
107
-
108
- report();
108
+ });
109
+ });
@@ -120,3 +120,34 @@ test('sync-lock: overrides stale lock file (mtime backdated)', (t) => {
120
120
  cleanupDir(base);
121
121
  }
122
122
  });
123
+
124
+ test('sync-lock: EPERM from live owner PID prevents stale lock stealing', () => {
125
+ const base = tempDir();
126
+ fs.mkdirSync(path.join(base, '.gsd'), { recursive: true });
127
+ const lockPath = path.join(base, '.gsd', 'sync.lock');
128
+ const fakePid = process.pid + 100_000;
129
+ const originalKill = process.kill;
130
+
131
+ try {
132
+ fs.writeFileSync(lockPath, JSON.stringify({ pid: fakePid, acquired_at: new Date(0).toISOString() }));
133
+ const staleTime = new Date(Date.now() - 120_000);
134
+ fs.utimesSync(lockPath, staleTime, staleTime);
135
+
136
+ process.kill = ((pid: number, signal?: NodeJS.Signals | number) => {
137
+ if (pid === fakePid && signal === 0) {
138
+ const err = new Error('operation not permitted') as NodeJS.ErrnoException;
139
+ err.code = 'EPERM';
140
+ throw err;
141
+ }
142
+ return originalKill(pid, signal);
143
+ }) as typeof process.kill;
144
+
145
+ const result = acquireSyncLock(base, 100);
146
+ assert.strictEqual(result.acquired, false, 'EPERM owner should be treated as live');
147
+ const content = JSON.parse(fs.readFileSync(lockPath, 'utf-8'));
148
+ assert.strictEqual(content.pid, fakePid, 'lock file should not be overwritten');
149
+ } finally {
150
+ process.kill = originalKill;
151
+ cleanupDir(base);
152
+ }
153
+ });
@@ -13,6 +13,7 @@ import { describe, it } from 'node:test'
13
13
  import assert from 'node:assert/strict'
14
14
  import { readFileSync } from 'node:fs'
15
15
  import { resolve } from 'node:path'
16
+ import { extractSourceRegion } from "./test-helpers.ts";
16
17
 
17
18
  const src = readFileSync(
18
19
  resolve(process.cwd(), 'src', 'resources', 'extensions', 'gsd', 'auto-worktree.ts'),
@@ -33,14 +34,14 @@ describe('syncWorktreeStateBack skips current milestone (#3641)', () => {
33
34
  assert.ok(fnStart !== -1)
34
35
 
35
36
  // Get a reasonable portion of the function
36
- const fnBlock = src.slice(fnStart, fnStart + 3000)
37
+ const fnBlock = extractSourceRegion(src, 'function syncWorktreeStateBack(', { fromIdx: fnStart })
37
38
 
38
39
  // Find the for loop iterating milestones
39
40
  const loopIdx = fnBlock.indexOf('for (const mid of wtMilestones)')
40
41
  assert.ok(loopIdx !== -1, 'milestone iteration loop must exist')
41
42
 
42
43
  // After the loop, there should be the skip guard
43
- const loopBody = fnBlock.slice(loopIdx, loopIdx + 300)
44
+ const loopBody = extractSourceRegion(fnBlock, 'for (const mid of wtMilestones)', { fromIdx: loopIdx })
44
45
  assert.ok(
45
46
  loopBody.includes('mid === milestoneId'),
46
47
  'mid === milestoneId skip guard must exist inside the milestone loop',
@@ -55,7 +56,7 @@ describe('syncWorktreeStateBack skips current milestone (#3641)', () => {
55
56
  const fnStart = src.indexOf('function syncWorktreeStateBack(')
56
57
  assert.ok(fnStart !== -1)
57
58
 
58
- const fnBlock = src.slice(fnStart, fnStart + 3000)
59
+ const fnBlock = extractSourceRegion(src, 'function syncWorktreeStateBack(', { fromIdx: fnStart })
59
60
 
60
61
  assert.ok(
61
62
  fnBlock.includes('syncMilestoneDir('),
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Tests for test-helpers.ts — the timing helpers (waitForCondition,
3
+ * findLine) used to replace magic-number sleeps and positional line
4
+ * indexing in the test suite.
5
+ *
6
+ * The `extractSourceRegion` helper (introduced in #4773/#4774) is
7
+ * deliberately NOT tested here. It is the source-grep antipattern that
8
+ * #4784 names as the root problem; tests against toy fixtures only
9
+ * legitimize the pattern without validating behaviour. Its test cases
10
+ * were removed as part of #4834 — callers are being migrated to
11
+ * behaviour tests one file at a time, after which the helper is slated
12
+ * for deletion.
13
+ */
14
+
15
+ import test from "node:test";
16
+ import assert from "node:assert/strict";
17
+
18
+ import { waitForCondition, findLine } from "./test-helpers.ts";
19
+
20
+ // ─── waitForCondition ─────────────────────────────────────────────────────
21
+
22
+ test("waitForCondition returns immediately when condition is true", async () => {
23
+ const result = await waitForCondition(() => true);
24
+ assert.equal(result, true);
25
+ });
26
+
27
+ test("waitForCondition waits and returns when condition becomes true", async () => {
28
+ let flipped = false;
29
+ setTimeout(() => { flipped = true; }, 30);
30
+ const result = await waitForCondition(() => flipped, { intervalMs: 5 });
31
+ assert.equal(result, true);
32
+ });
33
+
34
+ test("waitForCondition throws after timeout with description", async () => {
35
+ await assert.rejects(
36
+ waitForCondition(() => false, { timeoutMs: 50, intervalMs: 5, description: "the flag to flip" }),
37
+ /waiting for the flag to flip/i,
38
+ );
39
+ });
40
+
41
+ test("waitForCondition surfaces last error on timeout", async () => {
42
+ await assert.rejects(
43
+ waitForCondition(
44
+ () => { throw new Error("probe failed"); },
45
+ { timeoutMs: 30, intervalMs: 5, description: "probe" },
46
+ ),
47
+ /probe failed/,
48
+ );
49
+ });
50
+
51
+ test("waitForCondition returns the truthy value (not just true)", async () => {
52
+ let n = 0;
53
+ const result = await waitForCondition(() => {
54
+ n++;
55
+ return n >= 3 ? { ready: true, iteration: n } : null;
56
+ }, { intervalMs: 5 });
57
+ // The helper only resolves when the condition returns a truthy value, so
58
+ // result cannot be null here. Assert it and narrow for the follow-ups.
59
+ assert.ok(result, "waitForCondition must resolve with a truthy value, not null");
60
+ assert.equal(result.ready, true);
61
+ assert.equal(result.iteration, 3);
62
+ });
63
+
64
+ // ─── findLine ─────────────────────────────────────────────────────────────
65
+
66
+ test("findLine locates a line by regex", () => {
67
+ const output = "header\nstatus: ok\nfooter";
68
+ const match = findLine(output, /^status:/);
69
+ assert.equal(match.index, 1);
70
+ assert.equal(match.text, "status: ok");
71
+ });
72
+
73
+ test("findLine locates a line by predicate", () => {
74
+ const output = "a\nb\nc";
75
+ const match = findLine(output, (l) => l === "b");
76
+ assert.equal(match.index, 1);
77
+ assert.equal(match.text, "b");
78
+ });
79
+
80
+ test("findLine throws with preview when no line matches", () => {
81
+ assert.throws(
82
+ () => findLine("a\nb\nc", /NOTFOUND/),
83
+ /First 10 lines/,
84
+ );
85
+ });
86
+
87
+ test("findLine resets lastIndex between lines for /g regex patterns", () => {
88
+ // Without the reset, RegExp.test with /g flag stateful-advances lastIndex
89
+ // and can skip matches on subsequent calls. Verify the reset keeps
90
+ // per-line testing deterministic.
91
+ const output = "foo\nfoo\nfoo";
92
+ const globalRe = /foo/g;
93
+ const match = findLine(output, globalRe);
94
+ assert.equal(match.index, 0);
95
+ // Second call on the same pattern must also match — would fail without reset
96
+ const match2 = findLine(output, globalRe);
97
+ assert.equal(match2.index, 0);
98
+ });
@@ -59,3 +59,156 @@ export function createTestContext() {
59
59
 
60
60
  return { assertEq, assertTrue, assertMatch, assertNoMatch, report };
61
61
  }
62
+
63
+ // ─── Source-inspection helpers (DEPRECATED — do not add new callers) ──────────
64
+ //
65
+ // `extractSourceRegion` was introduced in #4773 / #4774 as a more-durable
66
+ // replacement for hand-rolled `src.slice(idx, idx + N)` patterns. Issue
67
+ // #4784 surfaced that the helper is the wrong target: its use case —
68
+ // testing that an identifier or phrase exists in production source text
69
+ // — is the source-grep antipattern that causes false coverage in the
70
+ // first place. Tests should exercise behaviour (call the function,
71
+ // assert on its return value or observable effects) rather than check
72
+ // whether specific identifier strings remain in source.
73
+ //
74
+ // CONTRIBUTING.md forbids new callers of this helper. Existing callers
75
+ // are being migrated one file at a time; the helper is slated for
76
+ // removal once the last caller is converted.
77
+ //
78
+ // Do not add new callers. If you are tempted to, file an issue
79
+ // describing the behavioural invariant you want to test and we will
80
+ // find a runtime assertion instead.
81
+
82
+ /**
83
+ * @deprecated Use a real behaviour test against the function under
84
+ * inspection instead. See #4784 and CONTRIBUTING.md > "Test behaviour,
85
+ * not source shape". No new callers.
86
+ *
87
+ * Extract a region of source between a start anchor and either an explicit
88
+ * end anchor or, if none is given, a set of reasonable structural
89
+ * terminators (next `private `/`export `/`function `/`class `/`interface `/
90
+ * `//` section separator). Falls back to end-of-source if none match.
91
+ *
92
+ * @param src The source text.
93
+ * @param startAnchor Literal substring that marks the start of the region.
94
+ * Typically a function name, a section header comment, or
95
+ * a distinctive statement.
96
+ * @param endAnchor Optional. Either a literal substring that marks the end,
97
+ * or `{ fromIdx: number }` to find the *next* occurrence
98
+ * of `startAnchor` at or after `fromIdx` (useful when the
99
+ * anchor appears multiple times and a positional search
100
+ * is required). When omitted, structural terminators are
101
+ * used.
102
+ *
103
+ * Returns the extracted region (including the start anchor), or an empty
104
+ * string if `startAnchor` is not found.
105
+ */
106
+ export function extractSourceRegion(
107
+ src: string,
108
+ startAnchor: string,
109
+ endAnchor?: string | { fromIdx: number },
110
+ ): string {
111
+ const fromIdx = typeof endAnchor === "object" && endAnchor !== null
112
+ ? endAnchor.fromIdx
113
+ : 0;
114
+ const endLiteral = typeof endAnchor === "string" ? endAnchor : undefined;
115
+
116
+ const startIdx = src.indexOf(startAnchor, fromIdx);
117
+ if (startIdx < 0) return "";
118
+
119
+ if (endLiteral) {
120
+ const endIdx = src.indexOf(endLiteral, startIdx + startAnchor.length);
121
+ return endIdx > 0 ? src.slice(startIdx, endIdx) : src.slice(startIdx);
122
+ }
123
+
124
+ // Heuristic terminators — the next sibling declaration/section.
125
+ const terminators = [
126
+ "\n private ",
127
+ "\n public ",
128
+ "\n protected ",
129
+ "\n static ",
130
+ "\nexport function ",
131
+ "\nexport async function ",
132
+ "\nfunction ",
133
+ "\nasync function ",
134
+ "\nexport class ",
135
+ "\nclass ",
136
+ "\nexport interface ",
137
+ "\ninterface ",
138
+ "\n// ─", // section separator comments
139
+ "\n/** ", // next docblock
140
+ ];
141
+
142
+ let earliestEnd = -1;
143
+ for (const t of terminators) {
144
+ const idx = src.indexOf(t, startIdx + startAnchor.length);
145
+ if (idx > 0 && (earliestEnd < 0 || idx < earliestEnd)) earliestEnd = idx;
146
+ }
147
+
148
+ return earliestEnd > 0 ? src.slice(startIdx, earliestEnd) : src.slice(startIdx);
149
+ }
150
+
151
+ /**
152
+ * Poll `condition()` until it returns truthy or `timeoutMs` elapses.
153
+ * Returns the truthy value from `condition()`, or throws on timeout.
154
+ *
155
+ * Use this instead of `await new Promise(r => setTimeout(r, <magic-ms>))`
156
+ * when waiting for a state change that tests produce. The fixed-sleep
157
+ * pattern is flaky: too short → race; too long → slow tests.
158
+ *
159
+ * @param condition Predicate. Returns truthy when done. May be async.
160
+ * @param opts.timeoutMs Max total wait. Defaults to 2000ms.
161
+ * @param opts.intervalMs Poll interval. Defaults to 10ms.
162
+ * @param opts.description Included in the timeout error for debuggability.
163
+ */
164
+ export async function waitForCondition<T>(
165
+ condition: () => T | Promise<T>,
166
+ opts: { timeoutMs?: number; intervalMs?: number; description?: string } = {},
167
+ ): Promise<T> {
168
+ const timeoutMs = opts.timeoutMs ?? 2000;
169
+ const intervalMs = opts.intervalMs ?? 10;
170
+ const deadline = Date.now() + timeoutMs;
171
+ let lastErr: unknown;
172
+ while (Date.now() < deadline) {
173
+ try {
174
+ const result = await condition();
175
+ if (result) return result;
176
+ } catch (e) {
177
+ lastErr = e;
178
+ }
179
+ await new Promise((r) => setTimeout(r, intervalMs));
180
+ }
181
+ const desc = opts.description ?? "condition";
182
+ const errSuffix = lastErr instanceof Error ? ` (last error: ${lastErr.message})` : "";
183
+ throw new Error(`waitForCondition timed out after ${timeoutMs}ms waiting for ${desc}${errSuffix}`);
184
+ }
185
+
186
+ /**
187
+ * Find the first line in rendered output that matches a predicate. Returns
188
+ * the line's index and text, or throws if no line matches.
189
+ *
190
+ * Use this instead of `lines[N]` indexing when the N is positional and
191
+ * could shift under formatting changes.
192
+ */
193
+ export function findLine(
194
+ output: string,
195
+ predicate: RegExp | ((line: string) => boolean),
196
+ ): { index: number; text: string } {
197
+ const lines = output.split("\n");
198
+ const fn = predicate instanceof RegExp
199
+ ? (l: string) => {
200
+ // RegExp.test is stateful when the pattern has /g or /y flags
201
+ // (maintains lastIndex across calls). Reset before each test so
202
+ // matches on different lines don't silently skip.
203
+ if (predicate.global || predicate.sticky) predicate.lastIndex = 0;
204
+ return predicate.test(l);
205
+ }
206
+ : predicate;
207
+ for (let i = 0; i < lines.length; i++) {
208
+ if (fn(lines[i]!)) return { index: i, text: lines[i]! };
209
+ }
210
+ const preview = lines.slice(0, 10).join("\n");
211
+ throw new Error(
212
+ `findLine: no line matched. First 10 lines were:\n${preview}`,
213
+ );
214
+ }
@@ -14,6 +14,7 @@ import assert from "node:assert/strict";
14
14
  import { readFileSync } from "node:fs";
15
15
  import { join, dirname } from "node:path";
16
16
  import { fileURLToPath } from "node:url";
17
+ import { extractSourceRegion } from "./test-helpers.ts";
17
18
 
18
19
  const __dirname = dirname(fileURLToPath(import.meta.url));
19
20
 
@@ -127,7 +128,13 @@ test("profile: balanced profile skips research, reassess, and slice research (AD
127
128
 
128
129
  test("profile: quality profile skips research, slice research, and reassess (ADR-003)", () => {
129
130
  const qualityIdx = preferencesSrc.indexOf('case "quality":');
130
- const qualityBlock = preferencesSrc.slice(qualityIdx, qualityIdx + 300);
131
+ // preferencesSrc is concatenated from multiple modules — bound the region
132
+ // with the next case marker so the assertion stays tightly scoped.
133
+ const qualityBlock = extractSourceRegion(
134
+ preferencesSrc,
135
+ 'case "quality":',
136
+ 'case "burn-max":',
137
+ );
131
138
  assert.ok(qualityBlock.includes("skip_research: true"), "quality should skip research");
132
139
  assert.ok(qualityBlock.includes("skip_slice_research: true"), "quality should skip slice research");
133
140
  assert.ok(qualityBlock.includes("skip_reassess: true"), "quality should skip reassess");
@@ -44,7 +44,19 @@ describe("#2883: tool invocation error tracking on AutoSession", () => {
44
44
 
45
45
  // ─── isToolInvocationError classifier ────────────────────────────────────
46
46
 
47
- import { isToolInvocationError, isQueuedUserMessageSkip } from "../auto-tool-tracking.ts";
47
+ import {
48
+ isDeterministicPolicyError,
49
+ isToolInvocationError,
50
+ isQueuedUserMessageSkip,
51
+ } from "../auto-tool-tracking.ts";
52
+ import {
53
+ shouldBlockContextWrite,
54
+ shouldBlockPendingGateInSnapshot,
55
+ shouldBlockQueueExecutionInSnapshot,
56
+ resetWriteGateState,
57
+ type WriteGateSnapshot,
58
+ } from "../bootstrap/write-gate.ts";
59
+ import { BLOCKED_WRITE_ERROR } from "../write-intercept.ts";
48
60
 
49
61
  describe("#2883: isToolInvocationError classification", () => {
50
62
  test("detects JSON validation failure pattern", () => {
@@ -89,11 +101,59 @@ describe("#2883: isToolInvocationError classification", () => {
89
101
  );
90
102
  });
91
103
 
104
+ test("detects raw write-gate CONTEXT failures for non-GSD write tools", () => {
105
+ resetWriteGateState();
106
+ const result = shouldBlockContextWrite(
107
+ "write",
108
+ "/tmp/project/.gsd/milestones/M001/M001-CONTEXT.md",
109
+ "M001",
110
+ false,
111
+ );
112
+
113
+ assert.equal(result.block, true);
114
+ assert.equal(isDeterministicPolicyError(result.reason ?? ""), true);
115
+ assert.equal(isToolInvocationError(result.reason ?? ""), true);
116
+ });
117
+
118
+ test("detects raw pending-gate failures for non-GSD write tools", () => {
119
+ const snapshot: WriteGateSnapshot = {
120
+ verifiedDepthMilestones: [],
121
+ activeQueuePhase: false,
122
+ pendingGateId: "depth_verification_M001",
123
+ };
124
+ const result = shouldBlockPendingGateInSnapshot(snapshot, "write", "M001", false);
125
+
126
+ assert.equal(result.block, true);
127
+ assert.equal(isDeterministicPolicyError(result.reason ?? ""), true);
128
+ assert.equal(isToolInvocationError(result.reason ?? ""), true);
129
+ });
130
+
131
+ test("detects queue-mode policy blocks for raw write/edit/bash tools", () => {
132
+ const snapshot: WriteGateSnapshot = {
133
+ verifiedDepthMilestones: [],
134
+ activeQueuePhase: true,
135
+ pendingGateId: null,
136
+ };
137
+ const writeResult = shouldBlockQueueExecutionInSnapshot(snapshot, "write", "src/app.ts", true);
138
+ const bashResult = shouldBlockQueueExecutionInSnapshot(snapshot, "bash", "npm run build", true);
139
+
140
+ assert.equal(writeResult.block, true);
141
+ assert.equal(bashResult.block, true);
142
+ assert.equal(isDeterministicPolicyError(writeResult.reason ?? ""), true);
143
+ assert.equal(isToolInvocationError(bashResult.reason ?? ""), true);
144
+ });
145
+
146
+ test("detects direct STATE.md/gsd.db write-intercept policy blocks", () => {
147
+ assert.equal(isDeterministicPolicyError(BLOCKED_WRITE_ERROR), true);
148
+ assert.equal(isToolInvocationError(BLOCKED_WRITE_ERROR), true);
149
+ });
150
+
92
151
  test("returns false for normal tool errors (business logic)", () => {
93
152
  assert.equal(
94
153
  isToolInvocationError("Slice S01 is already complete"),
95
154
  false,
96
155
  );
156
+ assert.equal(isDeterministicPolicyError("Slice S01 is already complete"), false);
97
157
  });
98
158
 
99
159
  test("returns false for empty string", () => {
@@ -36,6 +36,9 @@ const RENAME_MAP: Array<{ canonical: string; alias: string }> = [
36
36
  { canonical: "gsd_reassess_roadmap", alias: "gsd_roadmap_reassess" },
37
37
  { canonical: "gsd_complete_milestone", alias: "gsd_milestone_complete" },
38
38
  { canonical: "gsd_validate_milestone", alias: "gsd_milestone_validate" },
39
+ { canonical: "gsd_task_reopen", alias: "gsd_reopen_task" },
40
+ { canonical: "gsd_slice_reopen", alias: "gsd_reopen_slice" },
41
+ { canonical: "gsd_milestone_reopen", alias: "gsd_reopen_milestone" },
39
42
  ];
40
43
 
41
44
  // ─── Registration count ──────────────────────────────────────────────────────
@@ -45,7 +48,11 @@ console.log('\n── Tool naming: registration count ──');
45
48
  const pi = makeMockPi();
46
49
  registerDbTools(pi);
47
50
 
48
- assert.deepStrictEqual(pi.tools.length, 30, 'Should register exactly 30 tools (14 canonical + 14 aliases + 1 gate tool + 1 gsd_skip_slice)');
51
+ assert.deepStrictEqual(
52
+ pi.tools.length,
53
+ RENAME_MAP.length * 2 + 2,
54
+ 'Should register canonical/alias tool pairs plus 1 gate tool and 1 gsd_skip_slice',
55
+ );
49
56
 
50
57
  // ─── Both names exist for each pair ──────────────────────────────────────────
51
58