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
@@ -15,50 +15,30 @@ import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updat
15
15
  import { isValidationTerminal } from "./state.js";
16
16
  import { getErrorMessage } from "./error-utils.js";
17
17
  import { logWarning, logError } from "./workflow-logger.js";
18
- import { splitFrontmatter, parseFrontmatterMap } from "./files.js";
18
+ import { readIntegrationBranch } from "./git-service.js";
19
19
  import { isClosedStatus } from "./status-guards.js";
20
- import { nativeConflictFiles, nativeCommit, nativeCheckoutTheirs, nativeAddPaths, nativeMergeAbort, nativeResetHard, } from "./native-git-bridge.js";
20
+ import { nativeConflictFiles, nativeCommit, nativeCheckoutTheirs, nativeAddPaths, nativeMergeAbort, nativeRebaseAbort, nativeResetHard, } from "./native-git-bridge.js";
21
21
  import { resolveSlicePath, resolveSliceFile, resolveTasksDir, resolveTaskFiles, relMilestoneFile, relSliceFile, buildSliceFileName, resolveMilestoneFile, clearPathCache, resolveGsdRootFile, } from "./paths.js";
22
22
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, } from "node:fs";
23
23
  import { execFileSync } from "node:child_process";
24
24
  import { dirname, join } from "node:path";
25
25
  import { resolveExpectedArtifactPath, diagnoseExpectedArtifact, } from "./auto-artifact-paths.js";
26
+ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
26
27
  // Re-export so existing consumers of auto-recovery.ts keep working.
27
28
  export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
28
- /**
29
- * Classify milestone summary content for recovery/dispatch decisions.
30
- * - success: canonical completion summary (frontmatter status is closed)
31
- * - failure: explicit blocker/failure markers
32
- * - unknown: ambiguous content
33
- */
34
- export function classifyMilestoneSummaryContent(content) {
35
- const [fmLines] = splitFrontmatter(content);
36
- const fm = fmLines ? parseFrontmatterMap(fmLines) : null;
37
- const rawStatus = typeof fm?.status === "string" ? fm.status.trim().toLowerCase() : "";
38
- if (rawStatus) {
39
- if (isClosedStatus(rawStatus))
40
- return "success";
41
- if (["active", "pending", "blocked", "failed", "incomplete"].includes(rawStatus))
42
- return "failure";
43
- }
44
- const failureSignal = /(?:^|\n)\s*#\s*BLOCKER\b/i.test(content)
45
- || /auto-mode recovery failed/i.test(content)
46
- || /verification\s+failed/i.test(content)
47
- || /\bnot complete\b/i.test(content);
48
- if (failureSignal)
49
- return "failure";
50
- return "unknown";
51
- }
29
+ export { classifyMilestoneSummaryContent, } from "./milestone-summary-classifier.js";
52
30
  // ─── Artifact Resolution & Verification ───────────────────────────────────────
53
31
  /**
54
- * Check whether a milestone produced implementation artifacts (non-`.gsd/` files)
55
- * in the git history. Uses `git log --name-only` to inspect all commits on the
56
- * current branch that touch files outside `.gsd/`.
32
+ * Check whether a milestone produced implementation artifacts (non-`.gsd/`
33
+ * files) in git history. The primary signal is the branch diff against the
34
+ * integration branch. When a retry is already on the integration branch, that
35
+ * diff is a self-diff; if a milestone ID is available, fall back to recent
36
+ * GSD-tagged commits for that milestone.
57
37
  *
58
38
  * Returns "present" if implementation files found, "absent" if only .gsd/ files,
59
39
  * "unknown" if git is unavailable or check failed (callers decide how to handle).
60
40
  */
61
- export function hasImplementationArtifacts(basePath) {
41
+ export function hasImplementationArtifacts(basePath, milestoneId) {
62
42
  try {
63
43
  // Verify we're in a git repo
64
44
  try {
@@ -74,19 +54,31 @@ export function hasImplementationArtifacts(basePath) {
74
54
  }
75
55
  // Strategy: check `git diff --name-only` against the merge-base with the
76
56
  // main branch. This captures ALL files changed during the milestone's
77
- // lifetime. If no merge-base exists (e.g., single-branch workflow), fall
78
- // back to checking the last N commits.
79
- const mainBranch = detectMainBranch(basePath);
80
- const changedFiles = getChangedFilesSinceBranch(basePath, mainBranch);
81
- // No files changed at all — unknown (could be detached HEAD, single-
82
- // commit repo, or other edge case where git diff returns nothing).
83
- if (changedFiles.length === 0)
57
+ // lifetime while running on a milestone branch.
58
+ const integrationBranch = milestoneId
59
+ ? readIntegrationBranch(basePath, milestoneId) ?? detectMainBranch(basePath)
60
+ : detectMainBranch(basePath);
61
+ const currentBranch = getCurrentBranch(basePath);
62
+ const branchDiff = getChangedFilesSinceBranch(basePath, integrationBranch);
63
+ if (!branchDiff.ok)
84
64
  return "unknown";
85
- // Filter out .gsd/ files — only implementation files count.
86
- // If every changed file is under .gsd/, the milestone produced no
87
- // implementation code (#1703).
88
- const implFiles = changedFiles.filter(f => !f.startsWith(".gsd/") && !f.startsWith(".gsd\\"));
89
- return implFiles.length > 0 ? "present" : "absent";
65
+ const changedFiles = branchDiff.files;
66
+ // No branch-diff files can mean the unit retried on main after milestone
67
+ // commits already landed there. In that topology, inspect GSD-tagged
68
+ // milestone commits instead of treating the self-diff as proof of no work.
69
+ if (changedFiles.length === 0) {
70
+ if (milestoneId && currentBranch === integrationBranch) {
71
+ const tagged = getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId);
72
+ if (!tagged.ok)
73
+ return "unknown";
74
+ if (tagged.matched)
75
+ return classifyImplementationFiles(tagged.files);
76
+ }
77
+ if (currentBranch && currentBranch !== "HEAD")
78
+ return "absent";
79
+ return "unknown";
80
+ }
81
+ return classifyImplementationFiles(changedFiles);
90
82
  }
91
83
  catch (e) {
92
84
  // Non-fatal — if git operations fail, return unknown so callers can decide
@@ -94,6 +86,26 @@ export function hasImplementationArtifacts(basePath) {
94
86
  return "unknown";
95
87
  }
96
88
  }
89
+ function getCurrentBranch(basePath) {
90
+ try {
91
+ const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
92
+ cwd: basePath,
93
+ stdio: ["ignore", "pipe", "pipe"],
94
+ encoding: "utf-8",
95
+ }).trim();
96
+ return branch || null;
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ function classifyImplementationFiles(files) {
103
+ const implFiles = files.filter(isImplementationPath);
104
+ return implFiles.length > 0 ? "present" : "absent";
105
+ }
106
+ function isImplementationPath(file) {
107
+ return !file.startsWith(".gsd/") && !file.startsWith(".gsd\\");
108
+ }
97
109
  /**
98
110
  * Detect the main/master branch name.
99
111
  */
@@ -138,7 +150,7 @@ function getChangedFilesSinceBranch(basePath, targetBranch) {
138
150
  const mergeBase = execFileSync("git", ["merge-base", targetBranch, "HEAD"], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
139
151
  if (mergeBase) {
140
152
  const result = execFileSync("git", ["diff", "--name-only", mergeBase, "HEAD"], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
141
- return result ? result.split("\n").filter(Boolean) : [];
153
+ return { ok: true, files: result ? result.split("\n").filter(Boolean) : [] };
142
154
  }
143
155
  }
144
156
  catch (err) {
@@ -148,13 +160,75 @@ function getChangedFilesSinceBranch(basePath, targetBranch) {
148
160
  // Fallback: check last 20 commits
149
161
  try {
150
162
  const result = execFileSync("git", ["log", "--name-only", "--pretty=format:", "-20", "HEAD"], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
151
- return result ? [...new Set(result.split("\n").filter(Boolean))] : [];
163
+ return { ok: true, files: result ? [...new Set(result.split("\n").filter(Boolean))] : [] };
152
164
  }
153
165
  catch (e) {
154
166
  logWarning("recovery", `git log fallback failed: ${e.message}`);
155
- return [];
167
+ return { ok: false, files: [] };
168
+ }
169
+ }
170
+ function getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId) {
171
+ try {
172
+ const logOutput = execFileSync("git", ["log", "--format=%H%x1f%B%x1e", "HEAD", "--", `.gsd/milestones/${milestoneId}`], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
173
+ const records = logOutput
174
+ .split("\x1e")
175
+ .map((record) => record.trim())
176
+ .filter(Boolean)
177
+ .flatMap((record) => {
178
+ const sep = record.indexOf("\x1f");
179
+ if (sep === -1)
180
+ return [];
181
+ const hash = record.slice(0, sep).trim();
182
+ const message = record.slice(sep + 1);
183
+ return [{ hash, message }];
184
+ });
185
+ const files = new Set();
186
+ let matched = false;
187
+ for (const { hash, message } of records) {
188
+ if (!commitMessageHasGsdTrailer(message))
189
+ continue;
190
+ const commitFiles = getChangedFilesForCommit(basePath, hash);
191
+ if (!commitMatchesMilestone(message, milestoneId, commitFiles))
192
+ continue;
193
+ matched = true;
194
+ for (const file of commitFiles) {
195
+ files.add(file);
196
+ }
197
+ }
198
+ return { ok: true, matched, files: [...files] };
199
+ }
200
+ catch (e) {
201
+ logWarning("recovery", `milestone-tagged commit scan failed: ${e.message}`);
202
+ return { ok: false, matched: false, files: [] };
156
203
  }
157
204
  }
205
+ function getChangedFilesForCommit(basePath, hash) {
206
+ const fileOutput = execFileSync("git", ["diff-tree", "--root", "--no-commit-id", "-r", "--name-only", hash], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
207
+ return fileOutput.split("\n").map((f) => f.trim()).filter(Boolean);
208
+ }
209
+ function commitMessageHasGsdTrailer(message) {
210
+ return /^GSD-(?:Task|Unit):\s*\S+/m.test(message);
211
+ }
212
+ function commitMatchesMilestone(message, milestoneId, files) {
213
+ if (commitTrailerStartsWithMilestone(message, milestoneId))
214
+ return true;
215
+ // Meaningful execute-task commits currently store task scope as Sxx/Tyy
216
+ // rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone only
217
+ // when the commit also touched this milestone's artifacts.
218
+ if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
219
+ return files.some((file) => isMilestoneArtifactPath(file, milestoneId));
220
+ }
221
+ return false;
222
+ }
223
+ function commitTrailerStartsWithMilestone(message, milestoneId) {
224
+ const escapedMilestone = milestoneId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
225
+ const trailerPattern = new RegExp(`^GSD-(?:Task|Unit):\\s*${escapedMilestone}(?:$|[\\s/])`, "m");
226
+ return trailerPattern.test(message);
227
+ }
228
+ function isMilestoneArtifactPath(file, milestoneId) {
229
+ return file.startsWith(`.gsd/milestones/${milestoneId}/`)
230
+ || file.startsWith(`.gsd\\milestones\\${milestoneId}\\`);
231
+ }
158
232
  /**
159
233
  * Check whether the expected artifact(s) for a unit exist on disk.
160
234
  * Returns true if all required artifacts exist, or if the unit type has no
@@ -470,7 +544,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
470
544
  if (!isClosedStatus(dbMilestone.status) && summaryOutcome !== "success")
471
545
  return false;
472
546
  }
473
- if (hasImplementationArtifacts(base) === "absent")
547
+ if (hasImplementationArtifacts(base, mid) === "absent")
474
548
  return false;
475
549
  }
476
550
  return true;
@@ -600,6 +674,72 @@ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
600
674
  logError("recovery", `git reset failed: ${err instanceof Error ? err.message : String(err)}`);
601
675
  }
602
676
  }
677
+ /**
678
+ * Detect and abort other in-progress git operations left behind by a SIGKILL'd
679
+ * worker (rebase, cherry-pick, revert). Without this, a killed worker mid-rebase
680
+ * leaves `.git/rebase-merge/` or `.git/CHERRY_PICK_HEAD` and the worktree is
681
+ * wedged until the user manually runs the matching `--abort`.
682
+ *
683
+ * Called before merge-state reconciliation because these states block any
684
+ * subsequent merge/commit operation. (Issue #4980 HIGH-7)
685
+ */
686
+ function reconcileOtherInProgressGitOps(basePath, ctx) {
687
+ const gitDir = join(basePath, ".git");
688
+ const states = [
689
+ {
690
+ label: "rebase",
691
+ indicators: [join(gitDir, "rebase-merge"), join(gitDir, "rebase-apply")],
692
+ abort: () => nativeRebaseAbort(basePath),
693
+ },
694
+ {
695
+ label: "cherry-pick",
696
+ indicators: [join(gitDir, "CHERRY_PICK_HEAD")],
697
+ abort: () => {
698
+ // No native helper; fall back to git CLI.
699
+ try {
700
+ execFileSync("git", ["cherry-pick", "--abort"], {
701
+ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
702
+ });
703
+ }
704
+ catch (err) {
705
+ logWarning("recovery", `cherry-pick --abort failed: ${getErrorMessage(err)}`);
706
+ }
707
+ },
708
+ },
709
+ {
710
+ label: "revert",
711
+ indicators: [join(gitDir, "REVERT_HEAD")],
712
+ abort: () => {
713
+ try {
714
+ execFileSync("git", ["revert", "--abort"], {
715
+ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
716
+ });
717
+ }
718
+ catch (err) {
719
+ logWarning("recovery", `revert --abort failed: ${getErrorMessage(err)}`);
720
+ }
721
+ },
722
+ },
723
+ ];
724
+ let reconciled = false;
725
+ for (const s of states) {
726
+ const present = s.indicators.some((p) => existsSync(p));
727
+ if (!present)
728
+ continue;
729
+ try {
730
+ s.abort();
731
+ ctx.ui.notify(`Detected leftover ${s.label} state from prior session — aborted.`, "warning");
732
+ reconciled = true;
733
+ }
734
+ catch (err) {
735
+ logError("recovery", `${s.label} abort failed: ${getErrorMessage(err)}`);
736
+ ctx.ui.notify(`Detected leftover ${s.label} state but auto-abort failed. ` +
737
+ `Run \`git ${s.label} --abort\` manually before retrying.`, "error");
738
+ return "blocked";
739
+ }
740
+ }
741
+ return reconciled ? "reconciled" : "clean";
742
+ }
603
743
  /**
604
744
  * Detect leftover merge state from a prior session and reconcile it.
605
745
  * If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
@@ -607,12 +747,21 @@ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
607
747
  * If code conflicts remain: fail safe without modifying the worktree.
608
748
  */
609
749
  export function reconcileMergeState(basePath, ctx) {
750
+ // First, abort any rebase/cherry-pick/revert left over from a SIGKILL'd
751
+ // worker. Doing this before the merge-state check unblocks any merge that
752
+ // would otherwise refuse with "you have unfinished operation". (HIGH-7)
753
+ const otherOpsResult = reconcileOtherInProgressGitOps(basePath, ctx);
754
+ if (otherOpsResult === "blocked")
755
+ return "blocked";
610
756
  const mergeHeadPath = join(basePath, ".git", "MERGE_HEAD");
611
757
  const squashMsgPath = join(basePath, ".git", "SQUASH_MSG");
612
758
  const hasMergeHead = existsSync(mergeHeadPath);
613
759
  const hasSquashMsg = existsSync(squashMsgPath);
614
- if (!hasMergeHead && !hasSquashMsg)
615
- return "clean";
760
+ if (!hasMergeHead && !hasSquashMsg) {
761
+ // If we cleaned up another op type, return "reconciled" so the caller
762
+ // re-derives state from a known-good baseline.
763
+ return otherOpsResult === "reconciled" ? "reconciled" : "clean";
764
+ }
616
765
  const conflictedFiles = nativeConflictFiles(basePath);
617
766
  if (conflictedFiles.length === 0) {
618
767
  // All conflicts resolved — finalize the merge/squash commit
@@ -19,12 +19,13 @@ import { invalidateAllCaches } from "./cache.js";
19
19
  import { writeLock, clearLock } from "./crash-recovery.js";
20
20
  import { acquireSessionLock, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
21
21
  import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
22
- import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeCheckoutBranch, nativeBranchList, nativeBranchListMerged, nativeBranchDelete, nativeWorktreeRemove, } from "./native-git-bridge.js";
22
+ import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeCheckoutBranch, nativeBranchList, nativeBranchListMerged, nativeBranchDelete, nativeWorktreeRemove, nativeCommitCountBetween, } from "./native-git-bridge.js";
23
23
  import { GitServiceImpl } from "./git-service.js";
24
24
  import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
25
25
  import { getAutoWorktreePath } from "./auto-worktree.js";
26
26
  import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
27
27
  import { worktreePath as getWorktreeDir, isInsideWorktreesDir } from "./worktree-manager.js";
28
+ import { emitWorktreeOrphaned } from "./worktree-telemetry.js";
28
29
  import { initMetrics } from "./metrics.js";
29
30
  import { initRoutingHistory } from "./routing-history.js";
30
31
  import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
@@ -32,9 +33,10 @@ import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactiv
32
33
  import { snapshotSkills } from "./skill-discovery.js";
33
34
  import { isDbAvailable, getMilestone, openDatabase, getDbStatus } from "./gsd-db.js";
34
35
  import { isClosedStatus } from "./status-guards.js";
36
+ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
35
37
  import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
36
38
  import { logWarning, logError } from "./workflow-logger.js";
37
- import { existsSync, mkdirSync, readdirSync, rmSync, statSync, unlinkSync, } from "node:fs";
39
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, unlinkSync, } from "node:fs";
38
40
  import { join } from "node:path";
39
41
  import { sep as pathSep } from "node:path";
40
42
  import { resolveProjectRootDbPath } from "./bootstrap/dynamic-tools.js";
@@ -62,25 +64,15 @@ export async function openProjectDbIfPresent(basePath) {
62
64
  logWarning("engine", `gsd-db: failed to open existing database: ${err instanceof Error ? err.message : String(err)}`);
63
65
  }
64
66
  }
65
- /**
66
- * Audit for orphaned milestone branches at bootstrap.
67
- *
68
- * After a milestone completes, the teardown step (merge branch → main,
69
- * delete branch, remove worktree) runs as a post-completion engine step.
70
- * If the session ends between completion and teardown, the branch and
71
- * worktree are orphaned — the DB says "complete" so auto-mode won't
72
- * re-enter the milestone, and the teardown is never retried.
73
- *
74
- * This audit runs on every fresh bootstrap to catch that gap:
75
- * 1. Lists all local `milestone/*` branches.
76
- * 2. For each, checks if the milestone's DB status is "complete".
77
- * 3. If the branch is already merged into main → deletes the branch
78
- * and cleans up any orphaned worktree directory (safe, no data loss).
79
- * 4. If the branch is NOT merged → preserves it and warns the user
80
- * so they can merge manually (data safety first).
81
- *
82
- * Returns a summary of actions taken for the caller to surface via notify.
83
- */
67
+ export function decideSurvivorAction(hasSurvivorBranch, phase) {
68
+ if (!hasSurvivorBranch)
69
+ return "none";
70
+ if (phase === "needs-discussion")
71
+ return "discuss";
72
+ if (phase === "complete")
73
+ return "finalize";
74
+ return "none";
75
+ }
84
76
  export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
85
77
  const recovered = [];
86
78
  const warnings = [];
@@ -119,10 +111,58 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
119
111
  for (const branch of milestoneBranches) {
120
112
  const milestoneId = branch.replace(/^milestone\//, "");
121
113
  const milestone = getMilestone(milestoneId);
122
- // Only audit completed milestones
123
- if (!milestone || milestone.status !== "complete")
114
+ if (!milestone)
124
115
  continue;
125
116
  const isMerged = mergedBranches.has(branch);
117
+ // #4762 — in-progress milestone branch with unmerged commits ahead of
118
+ // main. This is the pre-completion orphan case: auto-mode exited without
119
+ // completing the milestone (pause, stop, crash, merge error, blocker) and
120
+ // work is stranded on the branch or in the worktree. Data safety first:
121
+ // we never delete or touch; we just surface a warning so the user knows
122
+ // where to look.
123
+ //
124
+ // Gate on isClosedStatus so we only warn about genuinely open milestones.
125
+ // Parked/other closed statuses go through the legacy complete/unmerged
126
+ // path below where appropriate.
127
+ if (!isClosedStatus(milestone.status)) {
128
+ if (isMerged)
129
+ continue; // nothing to recover
130
+ let commitsAhead = 0;
131
+ try {
132
+ commitsAhead = nativeCommitCountBetween(basePath, mainBranch, branch);
133
+ }
134
+ catch {
135
+ // Rev-walk failure — skip rather than noise
136
+ continue;
137
+ }
138
+ if (commitsAhead === 0)
139
+ continue;
140
+ const wtDir = getWorktreeDir(basePath, milestoneId);
141
+ const wtDirExists = existsSync(wtDir);
142
+ const wtSuffix = wtDirExists
143
+ ? ` Worktree directory at .gsd/worktrees/${milestoneId}/ holds the live work.`
144
+ : "";
145
+ warnings.push(`Branch ${branch} has ${commitsAhead} commit(s) ahead of ${mainBranch} for in-progress milestone ${milestoneId}.` +
146
+ wtSuffix +
147
+ ` Run \`/gsd auto\` to resume, or merge manually if abandoning.`);
148
+ // #4764 telemetry
149
+ try {
150
+ emitWorktreeOrphaned(basePath, milestoneId, {
151
+ reason: "in-progress-unmerged",
152
+ commitsAhead,
153
+ worktreeDirExists: wtDirExists,
154
+ });
155
+ }
156
+ catch (err) {
157
+ logWarning("engine", `worktree-orphaned telemetry failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`);
158
+ }
159
+ continue;
160
+ }
161
+ // Only the "complete" status participates in the merged/unmerged cleanup
162
+ // paths below — other closed statuses (parked, etc.) are intentionally
163
+ // left alone.
164
+ if (milestone.status !== "complete")
165
+ continue;
126
166
  if (isMerged) {
127
167
  // Branch is merged — safe to delete branch and clean up worktree dir
128
168
  try {
@@ -169,6 +209,16 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
169
209
  // Branch is NOT merged — preserve for safety, warn the user
170
210
  warnings.push(`Branch ${branch} exists for completed milestone ${milestoneId} but is NOT merged into ${mainBranch}. ` +
171
211
  `This may contain unmerged work. Merge manually or run \`/gsd health --fix\` to resolve.`);
212
+ // #4764 telemetry
213
+ try {
214
+ emitWorktreeOrphaned(basePath, milestoneId, {
215
+ reason: "complete-unmerged",
216
+ worktreeDirExists: existsSync(getWorktreeDir(basePath, milestoneId)),
217
+ });
218
+ }
219
+ catch (err) {
220
+ logWarning("engine", `worktree-orphaned telemetry failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`);
221
+ }
172
222
  }
173
223
  }
174
224
  return { recovered, warnings };
@@ -328,7 +378,15 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
328
378
  const row = getMilestone(mid);
329
379
  return !!row && isClosedStatus(row.status);
330
380
  }
331
- return !!resolveMilestoneFile(base, mid, "SUMMARY");
381
+ const summaryFile = resolveMilestoneFile(base, mid, "SUMMARY");
382
+ if (!summaryFile)
383
+ return false;
384
+ try {
385
+ return classifyMilestoneSummaryContent(readFileSync(summaryFile, "utf-8")) !== "failure";
386
+ }
387
+ catch {
388
+ return false;
389
+ }
332
390
  });
333
391
  // ── Orphaned milestone branch audit ──
334
392
  // Catches completed milestones whose teardown (merge + branch delete)
@@ -382,7 +440,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
382
440
  // The worktree/branch was created but the milestone only has CONTEXT-DRAFT.md.
383
441
  // Route to the interactive discussion handler instead of falling through to
384
442
  // auto-mode, which would immediately stop with "needs discussion".
385
- if (hasSurvivorBranch && state.phase === "needs-discussion") {
443
+ if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "discuss") {
386
444
  const { showSmartEntry } = await import("./guided-flow.js");
387
445
  await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
388
446
  invalidateAllCaches();
@@ -402,7 +460,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
402
460
  // The milestone artifacts were written but finalization (merge, worktree
403
461
  // cleanup) never ran. Run mergeAndExit to finalize, then re-derive state
404
462
  // so the normal "all milestones complete" or "next milestone" path runs.
405
- if (hasSurvivorBranch && state.phase === "complete") {
463
+ // Re-evaluate via the helper the discuss branch above may have cleared
464
+ // hasSurvivorBranch after a successful promotion.
465
+ if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
406
466
  const mid = state.activeMilestone.id;
407
467
  ctx.ui.notify(`Milestone ${mid} is complete but branch/worktree was not finalized. Running merge now.`, "info");
408
468
  const resolver = buildResolver();
@@ -708,14 +768,32 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
708
768
  catch (err) {
709
769
  ctx.ui.notify(`Secrets collection error: ${err instanceof Error ? err.message : String(err)}. Continuing with next task.`, "warning");
710
770
  }
711
- // Self-heal: remove stale .git/index.lock
771
+ // Self-heal: remove stale .git/index.lock.
772
+ //
773
+ // Threshold raised from 60s → 5min because a 60s-old lock is not
774
+ // definitively stale: `git gc --auto` triggered by a heavy commit, NFS
775
+ // delays, or concurrent worktree writes can hold .git/index.lock for
776
+ // minutes on large repos. Force-removing a live lock causes the holder
777
+ // to encounter `fatal: Unable to create '.git/index.lock'` on its next
778
+ // write, or worse, operate on a partially-written index → corruption
779
+ // requiring `git fsck`/`git reset` to recover.
780
+ // (Issue #4980 CRIT-3)
712
781
  try {
713
782
  const gitLockFile = join(base, ".git", "index.lock");
714
783
  if (existsSync(gitLockFile)) {
715
784
  const lockAge = Date.now() - statSync(gitLockFile).mtimeMs;
716
- if (lockAge > 60_000) {
785
+ const STALE_GIT_LOCK_THRESHOLD_MS = 5 * 60_000;
786
+ if (lockAge > STALE_GIT_LOCK_THRESHOLD_MS) {
717
787
  unlinkSync(gitLockFile);
718
- ctx.ui.notify("Removed stale .git/index.lock from prior crash.", "info");
788
+ ctx.ui.notify(`Removed stale .git/index.lock (age ${Math.round(lockAge / 1000)}s, > 5min threshold).`, "warning");
789
+ }
790
+ else {
791
+ // Lock present but not yet stale — surface so the user knows why
792
+ // git ops may be queueing instead of silently waiting.
793
+ debugLog("git-lock-present-not-stale", {
794
+ ageMs: lockAge,
795
+ thresholdMs: STALE_GIT_LOCK_THRESHOLD_MS,
796
+ });
719
797
  }
720
798
  }
721
799
  }
@@ -77,20 +77,21 @@ export function clearInFlightTools() {
77
77
  }
78
78
  // ─── Tool invocation error classification (#2883) ────────────────────────
79
79
  /**
80
- * Patterns that indicate a tool invocation failed due to malformed or truncated
81
- * JSON arguments — as opposed to a normal business-logic error from the tool
82
- * handler. When these errors occur, retrying the same unit will produce the same
83
- * failure, so the retry loop must be broken.
80
+ * Patterns that indicate a tool invocation failed deterministically before
81
+ * useful work could be completed — as opposed to a normal business-logic error
82
+ * from the tool handler. When these errors occur, retrying the same unit will
83
+ * produce the same failure, so the retry loop must be broken.
84
84
  */
85
85
  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;
86
+ 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;
86
87
  /**
87
- * Returns true if the error message indicates a tool invocation failure due to
88
- * malformed/truncated arguments (as opposed to a normal tool execution error).
88
+ * Returns true if the error message indicates a deterministic invocation or
89
+ * policy failure (as opposed to a normal tool execution error).
89
90
  */
90
91
  export function isToolInvocationError(errorMsg) {
91
92
  if (!errorMsg)
92
93
  return false;
93
- return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
94
+ return TOOL_INVOCATION_ERROR_RE.test(errorMsg) || isDeterministicPolicyError(errorMsg);
94
95
  }
95
96
  /**
96
97
  * Returns true if the error message indicates the tool was skipped because
@@ -102,3 +103,42 @@ export function isQueuedUserMessageSkip(errorMsg) {
102
103
  return false;
103
104
  return /^Skipped due to queued user message\.?$/i.test(errorMsg.trim());
104
105
  }
106
+ // ─── Deterministic policy error classification (#4973, #4974) ──────────────
107
+ /**
108
+ * Known deterministic policy error substrings. Each entry is a stable string
109
+ * that will appear in the tool error text content when the corresponding
110
+ * policy gate fires. Retrying these errors will always produce the same outcome.
111
+ *
112
+ * Add new entries here as new deterministic gates are introduced. Do NOT use
113
+ * regex — explicit substrings keep the list auditable.
114
+ */
115
+ export const DETERMINISTIC_POLICY_ERROR_STRINGS = [
116
+ // gsd_summary_save write-gate: CONTEXT artifact blocked pending depth verification (#4973).
117
+ // Matches the fallback text in workflow-tool-executors.ts and the verbose reason
118
+ // from shouldBlockContextArtifactSaveInSnapshot at write-gate.ts:432-442.
119
+ "context write blocked",
120
+ "CONTEXT without depth verification",
121
+ // Raw write tool gate (#4973): shouldBlockContextWrite at write-gate.ts:390-399 emits
122
+ // "Cannot write to milestone CONTEXT.md without depth verification." for direct
123
+ // write tool calls to *-CONTEXT.md paths (different code path than gsd_summary_save).
124
+ "CONTEXT.md without depth verification",
125
+ ];
126
+ /**
127
+ * Returns true if the error message indicates a deterministic policy gate
128
+ * blocked the tool call before execution. Retrying the same unit without
129
+ * changing behavior will hit the same gate, so auto-mode should pause instead
130
+ * of re-dispatching.
131
+ *
132
+ * Combines the regex-based gate set from #4974 (HARD BLOCK / queue planning /
133
+ * STATE.md / mechanical gate) and the substring-based set from #4973 (context
134
+ * write block / CONTEXT depth verification). Both branches landed on main
135
+ * independently and their parallel `isDeterministicPolicyError` declarations
136
+ * were not deduplicated at merge — this consolidated form preserves both
137
+ * matchers under a single export.
138
+ */
139
+ export function isDeterministicPolicyError(errorMsg) {
140
+ if (!errorMsg)
141
+ return false;
142
+ return (DETERMINISTIC_POLICY_ERROR_RE.test(errorMsg) ||
143
+ DETERMINISTIC_POLICY_ERROR_STRINGS.some(s => errorMsg.includes(s)));
144
+ }