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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (429) hide show
  1. package/README.md +1 -1
  2. package/dist/claude-cli-check.js +5 -1
  3. package/dist/headless.js +49 -4
  4. package/dist/resource-loader.d.ts +40 -0
  5. package/dist/resource-loader.js +32 -13
  6. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  7. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  8. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  9. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  10. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  11. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +5 -1
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
  14. package/dist/resources/extensions/gsd/auto/loop.js +43 -0
  15. package/dist/resources/extensions/gsd/auto/phases.js +15 -21
  16. package/dist/resources/extensions/gsd/auto/session.js +0 -2
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
  18. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
  20. package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
  21. package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
  22. package/dist/resources/extensions/gsd/auto-start.js +34 -24
  23. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  24. package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
  25. package/dist/resources/extensions/gsd/auto.js +31 -20
  26. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  27. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  28. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
  29. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  30. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  31. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  32. package/dist/resources/extensions/gsd/component-types.js +69 -0
  33. package/dist/resources/extensions/gsd/detection.js +49 -1
  34. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  35. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  36. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  37. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  38. package/dist/resources/extensions/gsd/git-service.js +126 -2
  39. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  40. package/dist/resources/extensions/gsd/guided-flow.js +17 -5
  41. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  42. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  43. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  44. package/dist/resources/extensions/gsd/model-router.js +6 -0
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  46. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  47. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  48. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  49. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  50. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  51. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  52. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  53. package/dist/resources/extensions/gsd/state.js +44 -33
  54. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  55. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  56. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  57. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  58. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  59. package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
  60. package/dist/resources/extensions/mcp-client/index.js +3 -1
  61. package/dist/resources/extensions/ollama/index.js +5 -1
  62. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  63. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  64. package/dist/web/standalone/.next/BUILD_ID +1 -1
  65. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  66. package/dist/web/standalone/.next/build-manifest.json +2 -2
  67. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  68. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/index.html +1 -1
  86. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  93. package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
  94. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  95. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  97. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  98. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  99. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  100. package/package.json +2 -3
  101. package/packages/daemon/src/logger.ts +4 -3
  102. package/packages/mcp-server/dist/server.d.ts +24 -0
  103. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  104. package/packages/mcp-server/dist/server.js +88 -87
  105. package/packages/mcp-server/dist/server.js.map +1 -1
  106. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  107. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  108. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  109. package/packages/mcp-server/src/server.ts +131 -105
  110. package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
  111. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  112. package/packages/native/package.json +1 -1
  113. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  114. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  115. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  116. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  117. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  118. package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
  119. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  120. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  121. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  122. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  123. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  124. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  125. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  126. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  127. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  128. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  129. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  130. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  131. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  132. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  133. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  134. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  135. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  136. package/packages/pi-ai/dist/models.test.js +36 -11
  137. package/packages/pi-ai/dist/models.test.js.map +1 -1
  138. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  139. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  140. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  141. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  142. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  143. package/packages/pi-ai/src/models.test.ts +48 -11
  144. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  145. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  146. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  148. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  150. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
  152. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
  154. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
  156. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
  158. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  160. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  163. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  165. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  167. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  169. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  170. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  171. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
  173. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  175. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/index.js +1 -0
  177. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  182. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  189. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  190. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  191. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  192. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  193. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  194. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  195. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  196. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  197. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  198. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  199. package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
  200. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
  201. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
  202. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  203. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  204. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  205. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  206. package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
  207. package/packages/pi-coding-agent/src/index.ts +1 -0
  208. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  209. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
  210. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  211. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  212. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  213. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  214. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  215. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
  216. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  217. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  218. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  219. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
  220. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  221. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  222. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  223. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  224. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  225. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  226. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  227. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  228. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  229. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  230. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  231. package/packages/pi-tui/dist/components/editor.js +19 -0
  232. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  233. package/packages/pi-tui/dist/components/image.test.js +6 -5
  234. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  235. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  236. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  237. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  238. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
  239. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  240. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
  241. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  242. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  243. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  244. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  245. package/packages/pi-tui/src/components/editor.ts +22 -0
  246. package/packages/pi-tui/src/components/image.test.ts +10 -5
  247. package/packages/pi-tui/src/editor-component.ts +3 -0
  248. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  249. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  250. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  251. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  252. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  253. package/scripts/install.js +15 -1
  254. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  255. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  256. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  257. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  258. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  259. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  260. package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
  261. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
  262. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
  263. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  264. package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
  265. package/src/resources/extensions/gsd/auto/loop.ts +47 -0
  266. package/src/resources/extensions/gsd/auto/phases.ts +16 -20
  267. package/src/resources/extensions/gsd/auto/session.ts +0 -2
  268. package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
  269. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  270. package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
  271. package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
  272. package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
  273. package/src/resources/extensions/gsd/auto-start.ts +54 -6
  274. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  275. package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
  276. package/src/resources/extensions/gsd/auto.ts +43 -22
  277. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
  278. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  279. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
  280. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  281. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  282. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  283. package/src/resources/extensions/gsd/component-types.ts +362 -0
  284. package/src/resources/extensions/gsd/detection.ts +58 -1
  285. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  286. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  287. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  288. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  289. package/src/resources/extensions/gsd/git-service.ts +133 -2
  290. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  291. package/src/resources/extensions/gsd/guided-flow.ts +20 -5
  292. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  293. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  294. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  295. package/src/resources/extensions/gsd/model-router.ts +6 -0
  296. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  297. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  298. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  299. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  300. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  301. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  302. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  303. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  304. package/src/resources/extensions/gsd/state.ts +49 -44
  305. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  306. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  307. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  308. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  309. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +94 -289
  310. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  311. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  312. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  313. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
  314. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -197
  315. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  316. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  317. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  318. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  319. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  320. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  321. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  322. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  323. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  324. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  325. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  326. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  327. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -3
  328. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  329. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  330. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
  331. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  332. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  333. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  334. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
  335. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  336. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  337. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  338. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  339. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  340. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  341. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  342. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
  343. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  344. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -62
  345. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  346. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  347. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  348. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -49
  349. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  350. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
  351. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  352. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  353. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
  354. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
  355. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  356. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  357. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  358. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  359. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  360. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  361. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  362. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  363. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  364. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  365. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  366. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  367. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  368. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
  369. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  370. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  371. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  372. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +12 -61
  373. package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
  374. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  375. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  376. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  377. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  378. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  379. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  380. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
  381. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
  382. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  383. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  384. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  385. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  386. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  387. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  388. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  389. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  390. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  391. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  392. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  393. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  394. package/src/resources/extensions/gsd/types.ts +3 -3
  395. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  396. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  397. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  398. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  399. package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
  400. package/src/resources/extensions/mcp-client/index.ts +3 -1
  401. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  402. package/src/resources/extensions/ollama/index.ts +5 -1
  403. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  404. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  405. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  406. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  407. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  408. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  409. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  410. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  411. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  412. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  413. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  414. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -144
  415. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
  416. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  417. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  418. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  419. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  420. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  421. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -75
  422. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  423. package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
  424. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  425. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  426. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -130
  427. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
  428. /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
  429. /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_ssgManifest.js +0 -0
@@ -1,11 +1,10 @@
1
1
  // GSD Extension — Advisory Sync Lock
2
2
  // Prevents concurrent worktree syncs from colliding via a simple file lock.
3
- // Stale locks (mtime > 60s) are auto-overridden. Lock acquisition waits up
4
- // to 5 seconds then skips non-fatally.
3
+ // Stale locks (mtime > 60s, owner PID confirmed dead) are overridden. Lock
4
+ // acquisition waits up to 5 seconds then skips non-fatally.
5
5
 
6
- import { existsSync, statSync, unlinkSync } from "node:fs";
7
- import { join } from "node:path";
8
- import { atomicWriteSync } from "./atomic-write.js";
6
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, writeSync } from "node:fs";
7
+ import { dirname, join } from "node:path";
9
8
 
10
9
  const STALE_THRESHOLD_MS = 60_000; // 60 seconds
11
10
  const DEFAULT_TIMEOUT_MS = 5_000; // 5 seconds
@@ -23,13 +22,59 @@ function sleepSync(ms: number): void {
23
22
  Atomics.wait(SLEEP_VIEW, 0, 0, ms);
24
23
  }
25
24
 
25
+ /** True if the given PID is alive in the current process namespace. */
26
+ function isPidAlive(pid: number): boolean {
27
+ try {
28
+ process.kill(pid, 0);
29
+ return true;
30
+ } catch (err) {
31
+ if ((err as NodeJS.ErrnoException).code === "EPERM") return true;
32
+ return false;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Atomically create the lock file with `O_EXCL` semantics. Returns true on
38
+ * exclusive create, false if the file already existed. Any other error
39
+ * propagates.
40
+ */
41
+ function tryCreateLockFile(lp: string, payload: string): boolean {
42
+ // Ensure parent dir exists (`atomicWriteSync` previously did this implicitly).
43
+ try {
44
+ mkdirSync(dirname(lp), { recursive: true });
45
+ } catch {
46
+ /* best-effort */
47
+ }
48
+ let fd: number;
49
+ try {
50
+ // "wx" → O_WRONLY | O_CREAT | O_EXCL — atomic create-if-not-exists on POSIX.
51
+ fd = openSync(lp, "wx");
52
+ } catch (err) {
53
+ const code = (err as NodeJS.ErrnoException).code;
54
+ if (code === "EEXIST") return false;
55
+ throw err;
56
+ }
57
+ try {
58
+ writeSync(fd, payload);
59
+ } finally {
60
+ closeSync(fd);
61
+ }
62
+ return true;
63
+ }
64
+
26
65
  /**
27
66
  * Acquire an advisory sync lock for the given basePath.
28
67
  * Returns { acquired: true } on success, { acquired: false } after timeout.
29
68
  *
30
- * - Creates lock file at {basePath}/.gsd/sync.lock with JSON { pid, acquired_at }
31
- * - If lock exists and mtime > 60s (stale), overrides it
32
- * - If lock exists and not stale, spins up to timeoutMs before giving up
69
+ * Replaces a non-atomic `existsSync` + `atomicWriteSync` (write-temp+rename,
70
+ * which is not exclusive-create) sequence that allowed two callers to both
71
+ * believe they had acquired the lock, corrupting the event log.
72
+ * (Issue #4980 CRIT-4)
73
+ *
74
+ * Stale-lock override now also verifies the recorded owner PID is dead
75
+ * before stealing — prevents a slow event-loop pause (>60s under heavy I/O)
76
+ * from making a legitimately-held lock appear stale and get stolen.
77
+ * (Issue #4980 M-concurrency-3)
33
78
  */
34
79
  export function acquireSyncLock(
35
80
  basePath: string,
@@ -37,45 +82,58 @@ export function acquireSyncLock(
37
82
  ): { acquired: boolean } {
38
83
  const lp = lockFilePath(basePath);
39
84
  const deadline = Date.now() + timeoutMs;
85
+ const lockData = JSON.stringify(
86
+ { pid: process.pid, acquired_at: new Date().toISOString() },
87
+ null,
88
+ 2,
89
+ );
40
90
 
41
91
  while (true) {
42
- // Check if lock file exists
43
- if (existsSync(lp)) {
44
- // Check staleness
45
- try {
46
- const stat = statSync(lp);
47
- const age = Date.now() - stat.mtimeMs;
48
- if (age > STALE_THRESHOLD_MS) {
49
- // Stale lock — override it
50
- try { unlinkSync(lp); } catch { /* race: already removed */ }
51
- } else {
52
- // Lock is held and not stale — wait or give up
53
- if (Date.now() >= deadline) {
54
- return { acquired: false };
55
- }
56
- sleepSync(SPIN_INTERVAL_MS);
57
- continue;
58
- }
59
- } catch {
60
- // stat failed (file removed between exists check and stat) — try to acquire
92
+ // First try the fast path: atomic create. No check-then-write race.
93
+ try {
94
+ if (tryCreateLockFile(lp, lockData)) {
95
+ return { acquired: true };
61
96
  }
97
+ } catch {
98
+ /* unexpected — fall through to retry */
62
99
  }
63
100
 
64
- // Lock file does not exist (or was just removed) try to write it
101
+ // File exists. Decide whether to steal (stale + owner dead) or wait.
102
+ let canSteal = false;
65
103
  try {
66
- const lockData = {
67
- pid: process.pid,
68
- acquired_at: new Date().toISOString(),
69
- };
70
- atomicWriteSync(lp, JSON.stringify(lockData, null, 2));
71
- return { acquired: true };
72
- } catch {
73
- // Write failed (race condition with another process) — retry or give up
74
- if (Date.now() >= deadline) {
75
- return { acquired: false };
104
+ const stat = statSync(lp);
105
+ const age = Date.now() - stat.mtimeMs;
106
+ if (age > STALE_THRESHOLD_MS) {
107
+ // Verify the recorded owner PID is dead before stealing.
108
+ let ownerAlive = false;
109
+ try {
110
+ const data = JSON.parse(readFileSync(lp, "utf-8")) as { pid?: number };
111
+ if (typeof data.pid === "number" && data.pid !== process.pid) {
112
+ ownerAlive = isPidAlive(data.pid);
113
+ }
114
+ } catch {
115
+ // Lock contents unreadable — be conservative and steal only on age.
116
+ // A garbage lock file that we cannot parse is safer to remove than
117
+ // to leave wedging the lock indefinitely.
118
+ }
119
+ canSteal = !ownerAlive;
76
120
  }
77
- sleepSync(SPIN_INTERVAL_MS);
121
+ } catch {
122
+ // stat failed (file removed between exists and stat) — retry create.
123
+ continue;
124
+ }
125
+
126
+ if (canSteal) {
127
+ try { unlinkSync(lp); } catch { /* race: already removed */ }
128
+ // Loop back to retry create.
129
+ continue;
130
+ }
131
+
132
+ // Lock is held and not stale (or owner is alive) — wait or give up.
133
+ if (Date.now() >= deadline) {
134
+ return { acquired: false };
78
135
  }
136
+ sleepSync(SPIN_INTERVAL_MS);
79
137
  }
80
138
  }
81
139
 
@@ -0,0 +1,270 @@
1
+ /**
2
+ * artifact-retry-cap.test.ts — Regression tests for #2007.
3
+ *
4
+ * Three interacting bugs caused unbounded artifact-verification retry loops
5
+ * that burned unlimited budget (202 dispatches observed in production):
6
+ *
7
+ * Bug 1: postUnitPreVerification in auto-post-unit.ts had no MAX check before
8
+ * returning "retry" when an expected artifact was missing. The attempt
9
+ * counter incremented forever.
10
+ *
11
+ * Bug 2: runDispatch in auto/phases.ts only pushed to loopState.recentUnits
12
+ * when pendingVerificationRetry was falsy, so the sliding-window stuck
13
+ * detector never saw artifact-retry dispatches and could not fire.
14
+ *
15
+ * Bug 3: MAX_UNIT_DISPATCHES and MAX_LIFETIME_DISPATCHES were exported from
16
+ * auto/session.ts but never compared against unitDispatchCount anywhere
17
+ * in the codebase — dead constants that provided false confidence.
18
+ */
19
+
20
+ import test from "node:test";
21
+ import assert from "node:assert/strict";
22
+ import { readFileSync } from "node:fs";
23
+ import { join } from "node:path";
24
+ import ts from "typescript";
25
+
26
+ const dir = join(import.meta.dirname, "..");
27
+
28
+ const postUnitSrc = readFileSync(join(dir, "auto-post-unit.ts"), "utf-8");
29
+ const phasesSrc = readFileSync(join(dir, "auto", "phases.ts"), "utf-8");
30
+ const sessionSrc = readFileSync(join(dir, "auto", "session.ts"), "utf-8");
31
+ const autoSrc = readFileSync(join(dir, "auto.ts"), "utf-8");
32
+
33
+ function extractFunctionBody(source: string, functionName: string): string {
34
+ const sourceFile = ts.createSourceFile(
35
+ "auto-post-unit.ts",
36
+ source,
37
+ ts.ScriptTarget.Latest,
38
+ true,
39
+ ts.ScriptKind.TS,
40
+ );
41
+ let body: ts.Block | undefined;
42
+
43
+ function visit(node: ts.Node): void {
44
+ if (
45
+ ts.isFunctionDeclaration(node) &&
46
+ node.name?.text === functionName
47
+ ) {
48
+ body = node.body;
49
+ return;
50
+ }
51
+ ts.forEachChild(node, visit);
52
+ }
53
+
54
+ visit(sourceFile);
55
+
56
+ assert.ok(body, `${functionName} must have a function body`);
57
+ return source.slice(body.getStart(sourceFile) + 1, body.end - 1);
58
+ }
59
+
60
+ function extractStuckDetectionSection(source: string): string {
61
+ const stuckSectionIdx = source.indexOf("Sliding-window stuck detection");
62
+ assert.ok(stuckSectionIdx !== -1, "stuck-detection section must exist");
63
+
64
+ const preDispatchIdx = source.indexOf("// Pre-dispatch hooks", stuckSectionIdx);
65
+ assert.ok(preDispatchIdx !== -1, "pre-dispatch hooks section must follow stuck detection");
66
+
67
+ return source.slice(stuckSectionIdx, preDispatchIdx);
68
+ }
69
+
70
+ const postUnitPreVerificationBody = extractFunctionBody(
71
+ postUnitSrc,
72
+ "postUnitPreVerification",
73
+ );
74
+
75
+ // ─── Bug 1: artifact retry must be bounded ───────────────────────────────────
76
+
77
+ test("#2007 bug 1: MAX_ARTIFACT_VERIFICATION_RETRIES constant is defined", () => {
78
+ assert.ok(
79
+ postUnitSrc.includes("MAX_ARTIFACT_VERIFICATION_RETRIES"),
80
+ "auto-post-unit.ts must define MAX_ARTIFACT_VERIFICATION_RETRIES",
81
+ );
82
+ });
83
+
84
+ test("#2007 bug 1: attempt is compared against MAX_ARTIFACT_VERIFICATION_RETRIES before returning retry", () => {
85
+ const retryBlockIdx = postUnitPreVerificationBody.indexOf("const retryKey =");
86
+ assert.ok(retryBlockIdx !== -1, "retry block must exist in postUnitPreVerification");
87
+
88
+ const retryIdx = postUnitPreVerificationBody.indexOf("return \"retry\"", retryBlockIdx);
89
+ assert.ok(retryIdx !== -1, "return \"retry\" must exist in postUnitPreVerification");
90
+
91
+ const maxIdx = postUnitPreVerificationBody.indexOf(
92
+ "if (attempt > MAX_ARTIFACT_VERIFICATION_RETRIES)",
93
+ retryBlockIdx,
94
+ );
95
+ assert.ok(maxIdx !== -1, "retry block must compare attempt against MAX");
96
+ assert.ok(
97
+ maxIdx < retryIdx,
98
+ "MAX_ARTIFACT_VERIFICATION_RETRIES check must appear before return \"retry\"",
99
+ );
100
+ });
101
+
102
+ test("#2007 bug 1: exhaustion path pauses auto-mode instead of silently continuing", () => {
103
+ const exhaustionIdx = postUnitPreVerificationBody.indexOf("phase: \"artifact-verify-exhausted\"");
104
+ assert.ok(exhaustionIdx !== -1, "exhaustion branch must log artifact-verify-exhausted");
105
+
106
+ const pauseIdx = postUnitPreVerificationBody.indexOf("await pauseAuto", exhaustionIdx);
107
+ const dispatchedIdx = postUnitPreVerificationBody.indexOf("return \"dispatched\"", exhaustionIdx);
108
+
109
+ assert.ok(
110
+ pauseIdx !== -1 && dispatchedIdx !== -1 && pauseIdx < dispatchedIdx,
111
+ "exhaustion branch must pause auto-mode before returning \"dispatched\"",
112
+ );
113
+ });
114
+
115
+ test("#2007 bug 1: failure context message includes attempt count and max", () => {
116
+ const failureContextIdx = postUnitPreVerificationBody.indexOf("failureContext:");
117
+ assert.ok(failureContextIdx !== -1, "failureContext assignment must exist");
118
+ assert.ok(
119
+ postUnitPreVerificationBody.includes(
120
+ "attempt ${attempt}/${MAX_ARTIFACT_VERIFICATION_RETRIES}",
121
+ failureContextIdx,
122
+ ),
123
+ "failure context should include attempt progress (attempt/current-max)",
124
+ );
125
+ });
126
+
127
+ // ─── Bug 2: stuck detection must see all dispatches ──────────────────────────
128
+
129
+ test("#2007 bug 2: recentUnits.push is unconditional — not gated on pendingVerificationRetry", () => {
130
+ const stuckSection = extractStuckDetectionSection(phasesSrc);
131
+ const pushIdx = stuckSection.indexOf("recentUnits.push");
132
+ assert.ok(pushIdx !== -1, "recentUnits.push must exist in phases.ts");
133
+
134
+ const pendingCheckIdx = stuckSection.indexOf("!s.pendingVerificationRetry");
135
+ assert.ok(pendingCheckIdx !== -1, "pendingVerificationRetry guard must exist");
136
+
137
+ // The push must come BEFORE the pendingVerificationRetry guard
138
+ assert.ok(
139
+ pushIdx < pendingCheckIdx,
140
+ "recentUnits.push must be unconditional — it must appear before the !pendingVerificationRetry check",
141
+ );
142
+ });
143
+
144
+ test("#2007 bug 2: detectStuck is still inside the pendingVerificationRetry guard", () => {
145
+ // detectStuck should only run when NOT in a retry — to avoid false positives
146
+ // during legitimate retries, but now the window is always populated.
147
+ const stuckSection = extractStuckDetectionSection(phasesSrc);
148
+ const pendingCheckIdx = stuckSection.indexOf("!s.pendingVerificationRetry");
149
+ assert.ok(
150
+ pendingCheckIdx !== -1,
151
+ "pendingVerificationRetry guard must exist in the stuck-detection section",
152
+ );
153
+ const detectStuckIdx = stuckSection.indexOf("detectStuck(", pendingCheckIdx);
154
+
155
+ assert.ok(
156
+ detectStuckIdx !== -1 && detectStuckIdx > pendingCheckIdx,
157
+ "detectStuck call must remain inside the !pendingVerificationRetry block",
158
+ );
159
+ });
160
+
161
+ // ─── Bug 3: dead dispatch-limit constants removed ────────────────────────────
162
+
163
+ test("#2007 bug 3: MAX_UNIT_DISPATCHES is removed from session.ts", () => {
164
+ assert.ok(
165
+ !sessionSrc.includes("MAX_UNIT_DISPATCHES"),
166
+ "MAX_UNIT_DISPATCHES was never enforced and must be removed to prevent false confidence",
167
+ );
168
+ });
169
+
170
+ test("#2007 bug 3: MAX_LIFETIME_DISPATCHES is removed from session.ts", () => {
171
+ assert.ok(
172
+ !sessionSrc.includes("MAX_LIFETIME_DISPATCHES"),
173
+ "MAX_LIFETIME_DISPATCHES was never enforced and must be removed to prevent false confidence",
174
+ );
175
+ });
176
+
177
+ test("#2007 bug 3: dead constants are not re-exported from auto.ts", () => {
178
+ assert.ok(
179
+ !autoSrc.includes("MAX_UNIT_DISPATCHES"),
180
+ "MAX_UNIT_DISPATCHES must not be re-exported from auto.ts",
181
+ );
182
+ assert.ok(
183
+ !autoSrc.includes("MAX_LIFETIME_DISPATCHES"),
184
+ "MAX_LIFETIME_DISPATCHES must not be re-exported from auto.ts",
185
+ );
186
+ });
187
+
188
+ // ─── No stray dead constants left behind by the fix ──────────────────────────
189
+
190
+ test("#2007 fix does not introduce a new dead constant (STATE_REBUILD_MIN_INTERVAL_MS)", () => {
191
+ // Bug 3 was about removing dead constants. A draft of this PR added
192
+ // STATE_REBUILD_MIN_INTERVAL_MS without referencing it — the same anti-pattern
193
+ // it set out to remove. Lock that down so it cannot regress.
194
+ assert.ok(
195
+ !postUnitSrc.includes("STATE_REBUILD_MIN_INTERVAL_MS"),
196
+ "STATE_REBUILD_MIN_INTERVAL_MS was added but never referenced — must be removed",
197
+ );
198
+ });
199
+
200
+ // ─── Behavioral: retry counter is cleared on success ─────────────────────────
201
+
202
+ test("#2007 verificationRetryCount is cleared on artifact verification success", () => {
203
+ // Find the success-clear we just added: when triggerArtifactVerified is
204
+ // true, the retry counter for the current unit must be deleted so a future
205
+ // failure of the same unit type+id gets the full retry budget instead of
206
+ // a stale leftover count.
207
+ //
208
+ // We assert on the structural shape because a behavioral test would need
209
+ // to mock 30+ imports of postUnitPreVerification. The AutoSession-level
210
+ // test below covers the Map contract.
211
+ const successClearIdx = postUnitPreVerificationBody.indexOf(
212
+ "if (triggerArtifactVerified)",
213
+ );
214
+ assert.ok(
215
+ successClearIdx !== -1,
216
+ "Must guard the retry-count clear behind a triggerArtifactVerified check",
217
+ );
218
+ const deleteIdx = postUnitPreVerificationBody.indexOf(
219
+ "verificationRetryCount.delete",
220
+ successClearIdx,
221
+ );
222
+ assert.ok(
223
+ deleteIdx !== -1,
224
+ "verificationRetryCount.delete must be called on the verification-success path",
225
+ );
226
+ });
227
+
228
+ // ─── AutoSession.verificationRetryCount Map behavior ─────────────────────────
229
+
230
+ import { AutoSession } from "../auto/session.ts";
231
+
232
+ test("AutoSession.verificationRetryCount tracks attempts per retry key", () => {
233
+ const s = new AutoSession();
234
+ const key = "execute-task:M01/S01/T01";
235
+
236
+ assert.equal(s.verificationRetryCount.get(key), undefined);
237
+
238
+ s.verificationRetryCount.set(key, 1);
239
+ assert.equal(s.verificationRetryCount.get(key), 1);
240
+
241
+ s.verificationRetryCount.set(key, 2);
242
+ assert.equal(s.verificationRetryCount.get(key), 2);
243
+
244
+ // Simulate the success-clear path
245
+ s.verificationRetryCount.delete(key);
246
+ assert.equal(s.verificationRetryCount.get(key), undefined);
247
+ });
248
+
249
+ test("AutoSession.verificationRetryCount is cleared on session reset", () => {
250
+ const s = new AutoSession();
251
+ s.verificationRetryCount.set("execute-task:M01/S01/T01", 2);
252
+ s.verificationRetryCount.set("plan-slice:M01/S02", 1);
253
+
254
+ s.reset();
255
+
256
+ assert.equal(s.verificationRetryCount.size, 0);
257
+ });
258
+
259
+ test("AutoSession.verificationRetryCount independence across retry keys", () => {
260
+ // Critical: if retries for unit A fail twice and unit A then succeeds, the
261
+ // counter for A should be cleared but B's counter must remain untouched.
262
+ const s = new AutoSession();
263
+ s.verificationRetryCount.set("execute-task:M01/S01/T01", 2);
264
+ s.verificationRetryCount.set("execute-task:M01/S01/T02", 1);
265
+
266
+ s.verificationRetryCount.delete("execute-task:M01/S01/T01");
267
+
268
+ assert.equal(s.verificationRetryCount.get("execute-task:M01/S01/T01"), undefined);
269
+ assert.equal(s.verificationRetryCount.get("execute-task:M01/S01/T02"), 1);
270
+ });