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
@@ -17,7 +17,7 @@ import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updat
17
17
  import { isValidationTerminal } from "./state.js";
18
18
  import { getErrorMessage } from "./error-utils.js";
19
19
  import { logWarning, logError } from "./workflow-logger.js";
20
- import { splitFrontmatter, parseFrontmatterMap } from "./files.js";
20
+ import { readIntegrationBranch } from "./git-service.js";
21
21
  import { isClosedStatus } from "./status-guards.js";
22
22
  import {
23
23
  nativeConflictFiles,
@@ -25,6 +25,7 @@ import {
25
25
  nativeCheckoutTheirs,
26
26
  nativeAddPaths,
27
27
  nativeMergeAbort,
28
+ nativeRebaseAbort,
28
29
  nativeResetHard,
29
30
  } from "./native-git-bridge.js";
30
31
  import {
@@ -52,47 +53,28 @@ import {
52
53
  resolveExpectedArtifactPath,
53
54
  diagnoseExpectedArtifact,
54
55
  } from "./auto-artifact-paths.js";
56
+ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
55
57
 
56
58
  // Re-export so existing consumers of auto-recovery.ts keep working.
57
59
  export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
58
-
59
- export type MilestoneSummaryOutcome = "success" | "failure" | "unknown";
60
-
61
- /**
62
- * Classify milestone summary content for recovery/dispatch decisions.
63
- * - success: canonical completion summary (frontmatter status is closed)
64
- * - failure: explicit blocker/failure markers
65
- * - unknown: ambiguous content
66
- */
67
- export function classifyMilestoneSummaryContent(content: string): MilestoneSummaryOutcome {
68
- const [fmLines] = splitFrontmatter(content);
69
- const fm = fmLines ? parseFrontmatterMap(fmLines) : null;
70
- const rawStatus = typeof fm?.status === "string" ? fm.status.trim().toLowerCase() : "";
71
- if (rawStatus) {
72
- if (isClosedStatus(rawStatus)) return "success";
73
- if (["active", "pending", "blocked", "failed", "incomplete"].includes(rawStatus)) return "failure";
74
- }
75
-
76
- const failureSignal =
77
- /(?:^|\n)\s*#\s*BLOCKER\b/i.test(content)
78
- || /auto-mode recovery failed/i.test(content)
79
- || /verification\s+failed/i.test(content)
80
- || /\bnot complete\b/i.test(content);
81
- if (failureSignal) return "failure";
82
- return "unknown";
83
- }
60
+ export {
61
+ classifyMilestoneSummaryContent,
62
+ type MilestoneSummaryOutcome,
63
+ } from "./milestone-summary-classifier.js";
84
64
 
85
65
  // ─── Artifact Resolution & Verification ───────────────────────────────────────
86
66
 
87
67
  /**
88
- * Check whether a milestone produced implementation artifacts (non-`.gsd/` files)
89
- * in the git history. Uses `git log --name-only` to inspect all commits on the
90
- * current branch that touch files outside `.gsd/`.
68
+ * Check whether a milestone produced implementation artifacts (non-`.gsd/`
69
+ * files) in git history. The primary signal is the branch diff against the
70
+ * integration branch. When a retry is already on the integration branch, that
71
+ * diff is a self-diff; if a milestone ID is available, fall back to recent
72
+ * GSD-tagged commits for that milestone.
91
73
  *
92
74
  * Returns "present" if implementation files found, "absent" if only .gsd/ files,
93
75
  * "unknown" if git is unavailable or check failed (callers decide how to handle).
94
76
  */
95
- export function hasImplementationArtifacts(basePath: string): "present" | "absent" | "unknown" {
77
+ export function hasImplementationArtifacts(basePath: string, milestoneId?: string): "present" | "absent" | "unknown" {
96
78
  try {
97
79
  // Verify we're in a git repo
98
80
  try {
@@ -108,20 +90,29 @@ export function hasImplementationArtifacts(basePath: string): "present" | "absen
108
90
 
109
91
  // Strategy: check `git diff --name-only` against the merge-base with the
110
92
  // main branch. This captures ALL files changed during the milestone's
111
- // lifetime. If no merge-base exists (e.g., single-branch workflow), fall
112
- // back to checking the last N commits.
113
- const mainBranch = detectMainBranch(basePath);
114
- const changedFiles = getChangedFilesSinceBranch(basePath, mainBranch);
115
-
116
- // No files changed at all — unknown (could be detached HEAD, single-
117
- // commit repo, or other edge case where git diff returns nothing).
118
- if (changedFiles.length === 0) return "unknown";
119
-
120
- // Filter out .gsd/ files only implementation files count.
121
- // If every changed file is under .gsd/, the milestone produced no
122
- // implementation code (#1703).
123
- const implFiles = changedFiles.filter(f => !f.startsWith(".gsd/") && !f.startsWith(".gsd\\"));
124
- return implFiles.length > 0 ? "present" : "absent";
93
+ // lifetime while running on a milestone branch.
94
+ const integrationBranch = milestoneId
95
+ ? readIntegrationBranch(basePath, milestoneId) ?? detectMainBranch(basePath)
96
+ : detectMainBranch(basePath);
97
+ const currentBranch = getCurrentBranch(basePath);
98
+ const branchDiff = getChangedFilesSinceBranch(basePath, integrationBranch);
99
+ if (!branchDiff.ok) return "unknown";
100
+ const changedFiles = branchDiff.files;
101
+
102
+ // No branch-diff files can mean the unit retried on main after milestone
103
+ // commits already landed there. In that topology, inspect GSD-tagged
104
+ // milestone commits instead of treating the self-diff as proof of no work.
105
+ if (changedFiles.length === 0) {
106
+ if (milestoneId && currentBranch === integrationBranch) {
107
+ const tagged = getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId);
108
+ if (!tagged.ok) return "unknown";
109
+ if (tagged.matched) return classifyImplementationFiles(tagged.files);
110
+ }
111
+ if (currentBranch && currentBranch !== "HEAD") return "absent";
112
+ return "unknown";
113
+ }
114
+
115
+ return classifyImplementationFiles(changedFiles);
125
116
  } catch (e) {
126
117
  // Non-fatal — if git operations fail, return unknown so callers can decide
127
118
  logWarning("recovery", `implementation artifact check failed: ${(e as Error).message}`);
@@ -129,6 +120,28 @@ export function hasImplementationArtifacts(basePath: string): "present" | "absen
129
120
  }
130
121
  }
131
122
 
123
+ function getCurrentBranch(basePath: string): string | null {
124
+ try {
125
+ const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
126
+ cwd: basePath,
127
+ stdio: ["ignore", "pipe", "pipe"],
128
+ encoding: "utf-8",
129
+ }).trim();
130
+ return branch || null;
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+
136
+ function classifyImplementationFiles(files: readonly string[]): "present" | "absent" {
137
+ const implFiles = files.filter(isImplementationPath);
138
+ return implFiles.length > 0 ? "present" : "absent";
139
+ }
140
+
141
+ function isImplementationPath(file: string): boolean {
142
+ return !file.startsWith(".gsd/") && !file.startsWith(".gsd\\");
143
+ }
144
+
132
145
  /**
133
146
  * Detect the main/master branch name.
134
147
  */
@@ -164,7 +177,7 @@ function detectMainBranch(basePath: string): string {
164
177
  * Get files changed since the branch diverged from the target branch.
165
178
  * Falls back to checking HEAD~20 if merge-base detection fails.
166
179
  */
167
- function getChangedFilesSinceBranch(basePath: string, targetBranch: string): string[] {
180
+ function getChangedFilesSinceBranch(basePath: string, targetBranch: string): { ok: boolean; files: string[] } {
168
181
  try {
169
182
  // Try merge-base approach first
170
183
  const mergeBase = execFileSync(
@@ -177,7 +190,7 @@ function getChangedFilesSinceBranch(basePath: string, targetBranch: string): str
177
190
  "git", ["diff", "--name-only", mergeBase, "HEAD"],
178
191
  { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
179
192
  ).trim();
180
- return result ? result.split("\n").filter(Boolean) : [];
193
+ return { ok: true, files: result ? result.split("\n").filter(Boolean) : [] };
181
194
  }
182
195
  } catch (err) {
183
196
  // merge-base failed — fall back
@@ -190,13 +203,96 @@ function getChangedFilesSinceBranch(basePath: string, targetBranch: string): str
190
203
  "git", ["log", "--name-only", "--pretty=format:", "-20", "HEAD"],
191
204
  { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
192
205
  ).trim();
193
- return result ? [...new Set(result.split("\n").filter(Boolean))] : [];
206
+ return { ok: true, files: result ? [...new Set(result.split("\n").filter(Boolean))] : [] };
194
207
  } catch (e) {
195
208
  logWarning("recovery", `git log fallback failed: ${(e as Error).message}`);
196
- return [];
209
+ return { ok: false, files: [] };
197
210
  }
198
211
  }
199
212
 
213
+ function getChangedFilesFromMilestoneTaggedCommits(
214
+ basePath: string,
215
+ milestoneId: string,
216
+ ): { ok: boolean; matched: boolean; files: string[] } {
217
+ try {
218
+ const logOutput = execFileSync(
219
+ "git",
220
+ ["log", "--format=%H%x1f%B%x1e", "HEAD", "--", `.gsd/milestones/${milestoneId}`],
221
+ { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
222
+ );
223
+ const records = logOutput
224
+ .split("\x1e")
225
+ .map((record) => record.trim())
226
+ .filter(Boolean)
227
+ .flatMap((record) => {
228
+ const sep = record.indexOf("\x1f");
229
+ if (sep === -1) return [];
230
+ const hash = record.slice(0, sep).trim();
231
+ const message = record.slice(sep + 1);
232
+ return [{ hash, message }];
233
+ });
234
+
235
+ const files = new Set<string>();
236
+ let matched = false;
237
+ for (const { hash, message } of records) {
238
+ if (!commitMessageHasGsdTrailer(message)) continue;
239
+
240
+ const commitFiles = getChangedFilesForCommit(basePath, hash);
241
+ if (!commitMatchesMilestone(message, milestoneId, commitFiles)) continue;
242
+
243
+ matched = true;
244
+ for (const file of commitFiles) {
245
+ files.add(file);
246
+ }
247
+ }
248
+
249
+ return { ok: true, matched, files: [...files] };
250
+ } catch (e) {
251
+ logWarning("recovery", `milestone-tagged commit scan failed: ${(e as Error).message}`);
252
+ return { ok: false, matched: false, files: [] };
253
+ }
254
+ }
255
+
256
+ function getChangedFilesForCommit(basePath: string, hash: string): string[] {
257
+ const fileOutput = execFileSync(
258
+ "git",
259
+ ["diff-tree", "--root", "--no-commit-id", "-r", "--name-only", hash],
260
+ { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
261
+ ).trim();
262
+ return fileOutput.split("\n").map((f) => f.trim()).filter(Boolean);
263
+ }
264
+
265
+ function commitMessageHasGsdTrailer(message: string): boolean {
266
+ return /^GSD-(?:Task|Unit):\s*\S+/m.test(message);
267
+ }
268
+
269
+ function commitMatchesMilestone(message: string, milestoneId: string, files: readonly string[]): boolean {
270
+ if (commitTrailerStartsWithMilestone(message, milestoneId)) return true;
271
+
272
+ // Meaningful execute-task commits currently store task scope as Sxx/Tyy
273
+ // rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone only
274
+ // when the commit also touched this milestone's artifacts.
275
+ if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
276
+ return files.some((file) => isMilestoneArtifactPath(file, milestoneId));
277
+ }
278
+
279
+ return false;
280
+ }
281
+
282
+ function commitTrailerStartsWithMilestone(message: string, milestoneId: string): boolean {
283
+ const escapedMilestone = milestoneId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
284
+ const trailerPattern = new RegExp(
285
+ `^GSD-(?:Task|Unit):\\s*${escapedMilestone}(?:$|[\\s/])`,
286
+ "m",
287
+ );
288
+ return trailerPattern.test(message);
289
+ }
290
+
291
+ function isMilestoneArtifactPath(file: string, milestoneId: string): boolean {
292
+ return file.startsWith(`.gsd/milestones/${milestoneId}/`)
293
+ || file.startsWith(`.gsd\\milestones\\${milestoneId}\\`);
294
+ }
295
+
200
296
  /**
201
297
  * Check whether the expected artifact(s) for a unit exist on disk.
202
298
  * Returns true if all required artifacts exist, or if the unit type has no
@@ -513,7 +609,7 @@ export function verifyExpectedArtifact(
513
609
  if (!dbMilestone) return false;
514
610
  if (!isClosedStatus(dbMilestone.status) && summaryOutcome !== "success") return false;
515
611
  }
516
- if (hasImplementationArtifacts(base) === "absent") return false;
612
+ if (hasImplementationArtifacts(base, mid) === "absent") return false;
517
613
  }
518
614
 
519
615
  return true;
@@ -634,6 +730,79 @@ function abortAndResetMerge(
634
730
 
635
731
  export type MergeReconcileResult = "clean" | "reconciled" | "blocked";
636
732
 
733
+ /**
734
+ * Detect and abort other in-progress git operations left behind by a SIGKILL'd
735
+ * worker (rebase, cherry-pick, revert). Without this, a killed worker mid-rebase
736
+ * leaves `.git/rebase-merge/` or `.git/CHERRY_PICK_HEAD` and the worktree is
737
+ * wedged until the user manually runs the matching `--abort`.
738
+ *
739
+ * Called before merge-state reconciliation because these states block any
740
+ * subsequent merge/commit operation. (Issue #4980 HIGH-7)
741
+ */
742
+ function reconcileOtherInProgressGitOps(
743
+ basePath: string,
744
+ ctx: ExtensionContext,
745
+ ): "clean" | "reconciled" | "blocked" {
746
+ const gitDir = join(basePath, ".git");
747
+ const states: Array<{
748
+ label: string;
749
+ indicators: string[];
750
+ abort: () => void;
751
+ }> = [
752
+ {
753
+ label: "rebase",
754
+ indicators: [join(gitDir, "rebase-merge"), join(gitDir, "rebase-apply")],
755
+ abort: () => nativeRebaseAbort(basePath),
756
+ },
757
+ {
758
+ label: "cherry-pick",
759
+ indicators: [join(gitDir, "CHERRY_PICK_HEAD")],
760
+ abort: () => {
761
+ // No native helper; fall back to git CLI.
762
+ try {
763
+ execFileSync("git", ["cherry-pick", "--abort"], {
764
+ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
765
+ });
766
+ } catch (err) { logWarning("recovery", `cherry-pick --abort failed: ${getErrorMessage(err)}`); }
767
+ },
768
+ },
769
+ {
770
+ label: "revert",
771
+ indicators: [join(gitDir, "REVERT_HEAD")],
772
+ abort: () => {
773
+ try {
774
+ execFileSync("git", ["revert", "--abort"], {
775
+ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
776
+ });
777
+ } catch (err) { logWarning("recovery", `revert --abort failed: ${getErrorMessage(err)}`); }
778
+ },
779
+ },
780
+ ];
781
+
782
+ let reconciled = false;
783
+ for (const s of states) {
784
+ const present = s.indicators.some((p) => existsSync(p));
785
+ if (!present) continue;
786
+ try {
787
+ s.abort();
788
+ ctx.ui.notify(
789
+ `Detected leftover ${s.label} state from prior session — aborted.`,
790
+ "warning",
791
+ );
792
+ reconciled = true;
793
+ } catch (err) {
794
+ logError("recovery", `${s.label} abort failed: ${getErrorMessage(err)}`);
795
+ ctx.ui.notify(
796
+ `Detected leftover ${s.label} state but auto-abort failed. ` +
797
+ `Run \`git ${s.label} --abort\` manually before retrying.`,
798
+ "error",
799
+ );
800
+ return "blocked";
801
+ }
802
+ }
803
+ return reconciled ? "reconciled" : "clean";
804
+ }
805
+
637
806
  /**
638
807
  * Detect leftover merge state from a prior session and reconcile it.
639
808
  * If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
@@ -644,11 +813,21 @@ export function reconcileMergeState(
644
813
  basePath: string,
645
814
  ctx: ExtensionContext,
646
815
  ): MergeReconcileResult {
816
+ // First, abort any rebase/cherry-pick/revert left over from a SIGKILL'd
817
+ // worker. Doing this before the merge-state check unblocks any merge that
818
+ // would otherwise refuse with "you have unfinished operation". (HIGH-7)
819
+ const otherOpsResult = reconcileOtherInProgressGitOps(basePath, ctx);
820
+ if (otherOpsResult === "blocked") return "blocked";
821
+
647
822
  const mergeHeadPath = join(basePath, ".git", "MERGE_HEAD");
648
823
  const squashMsgPath = join(basePath, ".git", "SQUASH_MSG");
649
824
  const hasMergeHead = existsSync(mergeHeadPath);
650
825
  const hasSquashMsg = existsSync(squashMsgPath);
651
- if (!hasMergeHead && !hasSquashMsg) return "clean";
826
+ if (!hasMergeHead && !hasSquashMsg) {
827
+ // If we cleaned up another op type, return "reconciled" so the caller
828
+ // re-derives state from a known-good baseline.
829
+ return otherOpsResult === "reconciled" ? "reconciled" : "clean";
830
+ }
652
831
 
653
832
  const conflictedFiles = nativeConflictFiles(basePath);
654
833
  if (conflictedFiles.length === 0) {
@@ -45,6 +45,7 @@ import {
45
45
  nativeBranchListMerged,
46
46
  nativeBranchDelete,
47
47
  nativeWorktreeRemove,
48
+ nativeCommitCountBetween,
48
49
  } from "./native-git-bridge.js";
49
50
  import { GitServiceImpl } from "./git-service.js";
50
51
  import {
@@ -55,6 +56,7 @@ import {
55
56
  import { getAutoWorktreePath, isInAutoWorktree } from "./auto-worktree.js";
56
57
  import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
57
58
  import { worktreePath as getWorktreeDir, isInsideWorktreesDir } from "./worktree-manager.js";
59
+ import { emitWorktreeOrphaned } from "./worktree-telemetry.js";
58
60
  import { initMetrics } from "./metrics.js";
59
61
  import { initRoutingHistory } from "./routing-history.js";
60
62
  import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
@@ -62,6 +64,7 @@ import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactiv
62
64
  import { snapshotSkills } from "./skill-discovery.js";
63
65
  import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
64
66
  import { isClosedStatus } from "./status-guards.js";
67
+ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
65
68
 
66
69
  import {
67
70
  debugLog,
@@ -75,6 +78,7 @@ import type { AutoSession } from "./auto/session.js";
75
78
  import {
76
79
  existsSync,
77
80
  mkdirSync,
81
+ readFileSync,
78
82
  readdirSync,
79
83
  rmSync,
80
84
  statSync,
@@ -142,6 +146,35 @@ export async function openProjectDbIfPresent(basePath: string): Promise<void> {
142
146
  *
143
147
  * Returns a summary of actions taken for the caller to surface via notify.
144
148
  */
149
+ /**
150
+ * Decide which survivor-branch recovery action bootstrapAutoSession must
151
+ * run for the current (hasSurvivorBranch, phase) combination. Extracted
152
+ * from the inline chain at `bootstrapAutoSession` (around line 604) so
153
+ * the decision table is testable without constructing a full session.
154
+ *
155
+ * - `none` — no survivor, or phase doesn't call for recovery. Fall
156
+ * through to normal bootstrap flow.
157
+ * - `discuss` — survivor + phase=needs-discussion (#1726). Route to
158
+ * showSmartEntry.
159
+ * - `finalize` — survivor + phase=complete (#2358). Run mergeAndExit to
160
+ * merge the milestone branch and clear the worktree.
161
+ *
162
+ * Any other phase with a survivor (pre-planning, planning, executing…)
163
+ * returns `none` — the caller continues its normal flow and the
164
+ * survivor branch participates in whatever auto-mode happens next.
165
+ */
166
+ export type SurvivorAction = "none" | "discuss" | "finalize";
167
+
168
+ export function decideSurvivorAction(
169
+ hasSurvivorBranch: boolean,
170
+ phase: string | null | undefined,
171
+ ): SurvivorAction {
172
+ if (!hasSurvivorBranch) return "none";
173
+ if (phase === "needs-discussion") return "discuss";
174
+ if (phase === "complete") return "finalize";
175
+ return "none";
176
+ }
177
+
145
178
  export function auditOrphanedMilestoneBranches(
146
179
  basePath: string,
147
180
  isolationMode: "worktree" | "branch" | "none",
@@ -185,11 +218,61 @@ export function auditOrphanedMilestoneBranches(
185
218
  const milestoneId = branch.replace(/^milestone\//, "");
186
219
  const milestone = getMilestone(milestoneId);
187
220
 
188
- // Only audit completed milestones
189
- if (!milestone || milestone.status !== "complete") continue;
221
+ if (!milestone) continue;
190
222
 
191
223
  const isMerged = mergedBranches.has(branch);
192
224
 
225
+ // #4762 — in-progress milestone branch with unmerged commits ahead of
226
+ // main. This is the pre-completion orphan case: auto-mode exited without
227
+ // completing the milestone (pause, stop, crash, merge error, blocker) and
228
+ // work is stranded on the branch or in the worktree. Data safety first:
229
+ // we never delete or touch; we just surface a warning so the user knows
230
+ // where to look.
231
+ //
232
+ // Gate on isClosedStatus so we only warn about genuinely open milestones.
233
+ // Parked/other closed statuses go through the legacy complete/unmerged
234
+ // path below where appropriate.
235
+ if (!isClosedStatus(milestone.status)) {
236
+ if (isMerged) continue; // nothing to recover
237
+ let commitsAhead = 0;
238
+ try {
239
+ commitsAhead = nativeCommitCountBetween(basePath, mainBranch, branch);
240
+ } catch {
241
+ // Rev-walk failure — skip rather than noise
242
+ continue;
243
+ }
244
+ if (commitsAhead === 0) continue;
245
+
246
+ const wtDir = getWorktreeDir(basePath, milestoneId);
247
+ const wtDirExists = existsSync(wtDir);
248
+ const wtSuffix = wtDirExists
249
+ ? ` Worktree directory at .gsd/worktrees/${milestoneId}/ holds the live work.`
250
+ : "";
251
+ warnings.push(
252
+ `Branch ${branch} has ${commitsAhead} commit(s) ahead of ${mainBranch} for in-progress milestone ${milestoneId}.` +
253
+ wtSuffix +
254
+ ` Run \`/gsd auto\` to resume, or merge manually if abandoning.`,
255
+ );
256
+
257
+ // #4764 telemetry
258
+ try {
259
+ emitWorktreeOrphaned(basePath, milestoneId, {
260
+ reason: "in-progress-unmerged",
261
+ commitsAhead,
262
+ worktreeDirExists: wtDirExists,
263
+ });
264
+ } catch (err) {
265
+ logWarning("engine", `worktree-orphaned telemetry failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`);
266
+ }
267
+
268
+ continue;
269
+ }
270
+
271
+ // Only the "complete" status participates in the merged/unmerged cleanup
272
+ // paths below — other closed statuses (parked, etc.) are intentionally
273
+ // left alone.
274
+ if (milestone.status !== "complete") continue;
275
+
193
276
  if (isMerged) {
194
277
  // Branch is merged — safe to delete branch and clean up worktree dir
195
278
  try {
@@ -234,6 +317,16 @@ export function auditOrphanedMilestoneBranches(
234
317
  `Branch ${branch} exists for completed milestone ${milestoneId} but is NOT merged into ${mainBranch}. ` +
235
318
  `This may contain unmerged work. Merge manually or run \`/gsd health --fix\` to resolve.`,
236
319
  );
320
+
321
+ // #4764 telemetry
322
+ try {
323
+ emitWorktreeOrphaned(basePath, milestoneId, {
324
+ reason: "complete-unmerged",
325
+ worktreeDirExists: existsSync(getWorktreeDir(basePath, milestoneId)),
326
+ });
327
+ } catch (err) {
328
+ logWarning("engine", `worktree-orphaned telemetry failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`);
329
+ }
237
330
  }
238
331
  }
239
332
 
@@ -439,7 +532,13 @@ export async function bootstrapAutoSession(
439
532
  const row = getMilestone(mid);
440
533
  return !!row && isClosedStatus(row.status);
441
534
  }
442
- return !!resolveMilestoneFile(base, mid, "SUMMARY");
535
+ const summaryFile = resolveMilestoneFile(base, mid, "SUMMARY");
536
+ if (!summaryFile) return false;
537
+ try {
538
+ return classifyMilestoneSummaryContent(readFileSync(summaryFile, "utf-8")) !== "failure";
539
+ } catch {
540
+ return false;
541
+ }
443
542
  },
444
543
  );
445
544
 
@@ -505,7 +604,7 @@ export async function bootstrapAutoSession(
505
604
  // The worktree/branch was created but the milestone only has CONTEXT-DRAFT.md.
506
605
  // Route to the interactive discussion handler instead of falling through to
507
606
  // auto-mode, which would immediately stop with "needs discussion".
508
- if (hasSurvivorBranch && state.phase === "needs-discussion") {
607
+ if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "discuss") {
509
608
  const { showSmartEntry } = await import("./guided-flow.js");
510
609
  await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
511
610
 
@@ -531,7 +630,9 @@ export async function bootstrapAutoSession(
531
630
  // The milestone artifacts were written but finalization (merge, worktree
532
631
  // cleanup) never ran. Run mergeAndExit to finalize, then re-derive state
533
632
  // so the normal "all milestones complete" or "next milestone" path runs.
534
- if (hasSurvivorBranch && state.phase === "complete") {
633
+ // Re-evaluate via the helper the discuss branch above may have cleared
634
+ // hasSurvivorBranch after a successful promotion.
635
+ if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
535
636
  const mid = state.activeMilestone!.id;
536
637
  ctx.ui.notify(
537
638
  `Milestone ${mid} is complete but branch/worktree was not finalized. Running merge now.`,
@@ -901,17 +1002,34 @@ export async function bootstrapAutoSession(
901
1002
  );
902
1003
  }
903
1004
 
904
- // Self-heal: remove stale .git/index.lock
1005
+ // Self-heal: remove stale .git/index.lock.
1006
+ //
1007
+ // Threshold raised from 60s → 5min because a 60s-old lock is not
1008
+ // definitively stale: `git gc --auto` triggered by a heavy commit, NFS
1009
+ // delays, or concurrent worktree writes can hold .git/index.lock for
1010
+ // minutes on large repos. Force-removing a live lock causes the holder
1011
+ // to encounter `fatal: Unable to create '.git/index.lock'` on its next
1012
+ // write, or worse, operate on a partially-written index → corruption
1013
+ // requiring `git fsck`/`git reset` to recover.
1014
+ // (Issue #4980 CRIT-3)
905
1015
  try {
906
1016
  const gitLockFile = join(base, ".git", "index.lock");
907
1017
  if (existsSync(gitLockFile)) {
908
1018
  const lockAge = Date.now() - statSync(gitLockFile).mtimeMs;
909
- if (lockAge > 60_000) {
1019
+ const STALE_GIT_LOCK_THRESHOLD_MS = 5 * 60_000;
1020
+ if (lockAge > STALE_GIT_LOCK_THRESHOLD_MS) {
910
1021
  unlinkSync(gitLockFile);
911
1022
  ctx.ui.notify(
912
- "Removed stale .git/index.lock from prior crash.",
913
- "info",
1023
+ `Removed stale .git/index.lock (age ${Math.round(lockAge / 1000)}s, > 5min threshold).`,
1024
+ "warning",
914
1025
  );
1026
+ } else {
1027
+ // Lock present but not yet stale — surface so the user knows why
1028
+ // git ops may be queueing instead of silently waiting.
1029
+ debugLog("git-lock-present-not-stale", {
1030
+ ageMs: lockAge,
1031
+ thresholdMs: STALE_GIT_LOCK_THRESHOLD_MS,
1032
+ });
915
1033
  }
916
1034
  }
917
1035
  } catch (e) {
@@ -87,20 +87,21 @@ export function clearInFlightTools(): void {
87
87
  // ─── Tool invocation error classification (#2883) ────────────────────────
88
88
 
89
89
  /**
90
- * Patterns that indicate a tool invocation failed due to malformed or truncated
91
- * JSON arguments — as opposed to a normal business-logic error from the tool
92
- * handler. When these errors occur, retrying the same unit will produce the same
93
- * failure, so the retry loop must be broken.
90
+ * Patterns that indicate a tool invocation failed deterministically before
91
+ * useful work could be completed — as opposed to a normal business-logic error
92
+ * from the tool handler. When these errors occur, retrying the same unit will
93
+ * produce the same failure, so the retry loop must be broken.
94
94
  */
95
95
  const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON/i;
96
+ const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
96
97
 
97
98
  /**
98
- * Returns true if the error message indicates a tool invocation failure due to
99
- * malformed/truncated arguments (as opposed to a normal tool execution error).
99
+ * Returns true if the error message indicates a deterministic invocation or
100
+ * policy failure (as opposed to a normal tool execution error).
100
101
  */
101
102
  export function isToolInvocationError(errorMsg: string): boolean {
102
103
  if (!errorMsg) return false;
103
- return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
104
+ return TOOL_INVOCATION_ERROR_RE.test(errorMsg) || isDeterministicPolicyError(errorMsg);
104
105
  }
105
106
 
106
107
  /**
@@ -112,3 +113,46 @@ export function isQueuedUserMessageSkip(errorMsg: string): boolean {
112
113
  if (!errorMsg) return false;
113
114
  return /^Skipped due to queued user message\.?$/i.test(errorMsg.trim());
114
115
  }
116
+
117
+ // ─── Deterministic policy error classification (#4973, #4974) ──────────────
118
+
119
+ /**
120
+ * Known deterministic policy error substrings. Each entry is a stable string
121
+ * that will appear in the tool error text content when the corresponding
122
+ * policy gate fires. Retrying these errors will always produce the same outcome.
123
+ *
124
+ * Add new entries here as new deterministic gates are introduced. Do NOT use
125
+ * regex — explicit substrings keep the list auditable.
126
+ */
127
+ export const DETERMINISTIC_POLICY_ERROR_STRINGS = [
128
+ // gsd_summary_save write-gate: CONTEXT artifact blocked pending depth verification (#4973).
129
+ // Matches the fallback text in workflow-tool-executors.ts and the verbose reason
130
+ // from shouldBlockContextArtifactSaveInSnapshot at write-gate.ts:432-442.
131
+ "context write blocked",
132
+ "CONTEXT without depth verification",
133
+ // Raw write tool gate (#4973): shouldBlockContextWrite at write-gate.ts:390-399 emits
134
+ // "Cannot write to milestone CONTEXT.md without depth verification." for direct
135
+ // write tool calls to *-CONTEXT.md paths (different code path than gsd_summary_save).
136
+ "CONTEXT.md without depth verification",
137
+ ] as const;
138
+
139
+ /**
140
+ * Returns true if the error message indicates a deterministic policy gate
141
+ * blocked the tool call before execution. Retrying the same unit without
142
+ * changing behavior will hit the same gate, so auto-mode should pause instead
143
+ * of re-dispatching.
144
+ *
145
+ * Combines the regex-based gate set from #4974 (HARD BLOCK / queue planning /
146
+ * STATE.md / mechanical gate) and the substring-based set from #4973 (context
147
+ * write block / CONTEXT depth verification). Both branches landed on main
148
+ * independently and their parallel `isDeterministicPolicyError` declarations
149
+ * were not deduplicated at merge — this consolidated form preserves both
150
+ * matchers under a single export.
151
+ */
152
+ export function isDeterministicPolicyError(errorMsg: string): boolean {
153
+ if (!errorMsg) return false;
154
+ return (
155
+ DETERMINISTIC_POLICY_ERROR_RE.test(errorMsg) ||
156
+ DETERMINISTIC_POLICY_ERROR_STRINGS.some(s => errorMsg.includes(s))
157
+ );
158
+ }