gsd-pi 2.80.0 → 2.81.0-dev.3cddbbba2

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 (1345) hide show
  1. package/README.md +47 -59
  2. package/dist/claude-cli-check.d.ts +30 -0
  3. package/dist/claude-cli-check.js +18 -7
  4. package/dist/cli.js +0 -19
  5. package/dist/headless-query.d.ts +10 -0
  6. package/dist/headless-query.js +6 -4
  7. package/dist/loader-entrypoint.d.ts +8 -0
  8. package/dist/loader-entrypoint.js +27 -0
  9. package/dist/loader.js +2 -11
  10. package/dist/mcp-server.d.ts +1 -0
  11. package/dist/mcp-server.js +6 -3
  12. package/dist/resources/.managed-resources-content-hash +1 -1
  13. package/dist/resources/GSD-WORKFLOW.md +2 -2
  14. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  15. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +40 -3
  16. package/dist/resources/extensions/github-sync/sync.js +4 -1
  17. package/dist/resources/extensions/github-sync/templates.js +90 -74
  18. package/dist/resources/extensions/gsd/auto/contracts.js +2 -0
  19. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +53 -0
  20. package/dist/resources/extensions/gsd/auto/loop.js +566 -526
  21. package/dist/resources/extensions/gsd/auto/orchestrator.js +48 -4
  22. package/dist/resources/extensions/gsd/auto/phases.js +402 -157
  23. package/dist/resources/extensions/gsd/auto/resolve.js +29 -0
  24. package/dist/resources/extensions/gsd/auto/run-unit.js +105 -46
  25. package/dist/resources/extensions/gsd/auto/session.js +18 -1
  26. package/dist/resources/extensions/gsd/auto/unit-runner-events.js +7 -0
  27. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  28. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-dispatch-outcome.js +12 -0
  29. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-iteration.js +24 -0
  30. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-reconcile-outcome.js +33 -0
  31. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-reconcile.js +26 -0
  32. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-retry.js +49 -0
  33. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-verify-outcome.js +25 -0
  34. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +80 -0
  35. package/dist/resources/extensions/gsd/auto/workflow-dispatch-ledger.js +26 -0
  36. package/dist/resources/extensions/gsd/auto/workflow-iteration-completion.js +10 -0
  37. package/dist/resources/extensions/gsd/auto/workflow-journal-reporter.js +16 -0
  38. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +263 -0
  39. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +36 -0
  40. package/dist/resources/extensions/gsd/auto/workflow-phase-reporter.js +9 -0
  41. package/dist/resources/extensions/gsd/auto/workflow-session-lock.js +35 -0
  42. package/dist/resources/extensions/gsd/auto/workflow-sidecar-iteration.js +24 -0
  43. package/dist/resources/extensions/gsd/auto/workflow-sidecar-queue.js +26 -0
  44. package/dist/resources/extensions/gsd/auto/workflow-turn-reporter.js +36 -0
  45. package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +44 -0
  46. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +23 -0
  47. package/dist/resources/extensions/gsd/auto-dashboard.js +248 -187
  48. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  49. package/dist/resources/extensions/gsd/auto-dispatch.js +40 -11
  50. package/dist/resources/extensions/gsd/auto-post-unit.js +129 -89
  51. package/dist/resources/extensions/gsd/auto-prompts.js +382 -20
  52. package/dist/resources/extensions/gsd/auto-recovery.js +197 -9
  53. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  54. package/dist/resources/extensions/gsd/auto-start.js +253 -19
  55. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  56. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  57. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  58. package/dist/resources/extensions/gsd/auto-verification.js +14 -17
  59. package/dist/resources/extensions/gsd/auto-worktree.js +324 -374
  60. package/dist/resources/extensions/gsd/auto.js +502 -130
  61. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +147 -12
  62. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +54 -37
  63. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
  64. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +30 -20
  65. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
  66. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
  67. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
  68. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  69. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +356 -58
  70. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  71. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  72. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  73. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +147 -2
  74. package/dist/resources/extensions/gsd/clean-root-preflight.js +65 -9
  75. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  76. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  77. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  78. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  79. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  80. package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
  81. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  82. package/dist/resources/extensions/gsd/commands-ship.js +23 -46
  83. package/dist/resources/extensions/gsd/commands-workflow-templates.js +12 -7
  84. package/dist/resources/extensions/gsd/component-loader.js +5 -11
  85. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  86. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  87. package/dist/resources/extensions/gsd/custom-workflow-engine.js +25 -1
  88. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  89. package/dist/resources/extensions/gsd/db/unit-dispatches.js +92 -0
  90. package/dist/resources/extensions/gsd/db-adapter.js +47 -0
  91. package/dist/resources/extensions/gsd/db-base-schema.js +353 -0
  92. package/dist/resources/extensions/gsd/db-connection-cache.js +31 -0
  93. package/dist/resources/extensions/gsd/db-coordination-schema.js +104 -0
  94. package/dist/resources/extensions/gsd/db-decision-requirement-rows.js +71 -0
  95. package/dist/resources/extensions/gsd/db-gate-rows.js +16 -0
  96. package/dist/resources/extensions/gsd/db-lightweight-query-rows.js +29 -0
  97. package/dist/resources/extensions/gsd/db-memory-fts-schema.js +56 -0
  98. package/dist/resources/extensions/gsd/db-migration-backup.js +22 -0
  99. package/dist/resources/extensions/gsd/db-migration-steps.js +416 -0
  100. package/dist/resources/extensions/gsd/db-milestone-artifact-rows.js +35 -0
  101. package/dist/resources/extensions/gsd/db-open-state.js +32 -0
  102. package/dist/resources/extensions/gsd/db-provider.js +108 -0
  103. package/dist/resources/extensions/gsd/db-runtime-kv-schema.js +27 -0
  104. package/dist/resources/extensions/gsd/db-schema-metadata.js +23 -0
  105. package/dist/resources/extensions/gsd/db-task-slice-rows.js +86 -0
  106. package/dist/resources/extensions/gsd/db-transaction.js +63 -0
  107. package/dist/resources/extensions/gsd/db-verification-evidence-rows.js +3 -0
  108. package/dist/resources/extensions/gsd/db-verification-evidence-schema.js +19 -0
  109. package/dist/resources/extensions/gsd/detection.js +106 -0
  110. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  111. package/dist/resources/extensions/gsd/escalation.js +2 -0
  112. package/dist/resources/extensions/gsd/git-service.js +75 -6
  113. package/dist/resources/extensions/gsd/graph.js +9 -3
  114. package/dist/resources/extensions/gsd/gsd-db.js +331 -1535
  115. package/dist/resources/extensions/gsd/guided-flow.js +149 -48
  116. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  117. package/dist/resources/extensions/gsd/health-widget.js +6 -9
  118. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  119. package/dist/resources/extensions/gsd/legacy-telemetry.js +70 -0
  120. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -0
  121. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  122. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  123. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  124. package/dist/resources/extensions/gsd/model-router.js +9 -6
  125. package/dist/resources/extensions/gsd/native-git-bridge.js +46 -22
  126. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  127. package/dist/resources/extensions/gsd/notification-widget.js +21 -3
  128. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  129. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  130. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  131. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  132. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  133. package/dist/resources/extensions/gsd/post-execution-checks.js +2 -0
  134. package/dist/resources/extensions/gsd/pr-evidence.js +117 -0
  135. package/dist/resources/extensions/gsd/pre-execution-checks.js +24 -0
  136. package/dist/resources/extensions/gsd/process-task-path.js +61 -0
  137. package/dist/resources/extensions/gsd/prompt-loader.js +37 -7
  138. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +41 -35
  139. package/dist/resources/extensions/gsd/prompts/complete-slice.md +25 -34
  140. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +70 -98
  141. package/dist/resources/extensions/gsd/prompts/discuss.md +101 -183
  142. package/dist/resources/extensions/gsd/prompts/execute-task.md +42 -67
  143. package/dist/resources/extensions/gsd/prompts/forensics.md +41 -84
  144. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +29 -39
  145. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +30 -65
  146. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +25 -52
  147. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +36 -36
  148. package/dist/resources/extensions/gsd/prompts/guided-research-project.md +20 -38
  149. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  150. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +47 -59
  151. package/dist/resources/extensions/gsd/prompts/plan-slice.md +25 -87
  152. package/dist/resources/extensions/gsd/prompts/queue.md +46 -53
  153. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  154. package/dist/resources/extensions/gsd/prompts/refine-slice.md +23 -23
  155. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  156. package/dist/resources/extensions/gsd/prompts/research-slice.md +23 -23
  157. package/dist/resources/extensions/gsd/prompts/rethink.md +10 -10
  158. package/dist/resources/extensions/gsd/prompts/system.md +65 -107
  159. package/dist/resources/extensions/gsd/prompts/triage-captures.md +15 -15
  160. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +24 -24
  161. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +35 -35
  162. package/dist/resources/extensions/gsd/quick.js +34 -2
  163. package/dist/resources/extensions/gsd/recovery-classification.js +94 -0
  164. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  165. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  166. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  167. package/dist/resources/extensions/gsd/state-reconciliation.js +27 -0
  168. package/dist/resources/extensions/gsd/state.js +4 -0
  169. package/dist/resources/extensions/gsd/tool-contract.js +50 -0
  170. package/dist/resources/extensions/gsd/tools/complete-milestone.js +20 -16
  171. package/dist/resources/extensions/gsd/tools/complete-task.js +3 -1
  172. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  173. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  174. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  175. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  176. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  177. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  178. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  179. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +7 -2
  180. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  181. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  182. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  183. package/dist/resources/extensions/gsd/uok/kernel.js +8 -3
  184. package/dist/resources/extensions/gsd/uok/plan-v2.js +2 -0
  185. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  186. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  187. package/dist/resources/extensions/gsd/workflow-logger.js +13 -13
  188. package/dist/resources/extensions/gsd/workflow-manifest.js +2 -0
  189. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  190. package/dist/resources/extensions/gsd/workflow-projections.js +2 -0
  191. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  192. package/dist/resources/extensions/gsd/workflow-templates.js +9 -0
  193. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  194. package/dist/resources/extensions/gsd/worktree-lifecycle.js +1364 -0
  195. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  196. package/dist/resources/extensions/gsd/worktree-safety.js +119 -0
  197. package/dist/resources/extensions/gsd/worktree-state-projection.js +317 -0
  198. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  199. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  200. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  201. package/dist/web/standalone/.next/BUILD_ID +1 -1
  202. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  203. package/dist/web/standalone/.next/build-manifest.json +4 -4
  204. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  205. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  206. package/dist/web/standalone/.next/required-server-files.json +4 -4
  207. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  208. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  210. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  211. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  212. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  213. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  214. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  215. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  216. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  217. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  218. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  219. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  220. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  221. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  222. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  223. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  224. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  225. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  226. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  227. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  229. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  230. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  231. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  232. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  233. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  235. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  236. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  237. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  238. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  239. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  240. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  241. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  242. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  243. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  244. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  245. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  246. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  247. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  248. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  249. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  250. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  251. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  252. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  253. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  254. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  255. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  256. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  257. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  258. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  259. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  260. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  261. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  262. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  263. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  264. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  265. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  266. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  267. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  268. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  269. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  270. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  271. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  272. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  273. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  274. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  275. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  276. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  277. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  278. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  279. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  280. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  281. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  282. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  283. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  284. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  285. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  286. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  287. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  288. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  289. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  290. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  291. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  292. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  293. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  294. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  295. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  296. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  297. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  298. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  299. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  300. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  301. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  302. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  303. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  304. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  305. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  306. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  307. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  308. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  309. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  310. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  311. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  312. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  313. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  314. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  315. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  316. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  317. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  318. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  319. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  320. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  321. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  322. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  323. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  324. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  325. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  326. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  327. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  328. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  329. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  330. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  331. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  332. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  333. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  334. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  335. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  336. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  337. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  338. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  339. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  340. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  341. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  342. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  343. package/dist/web/standalone/.next/server/app/index.html +1 -1
  344. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  345. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  346. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  347. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  348. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  349. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  350. package/dist/web/standalone/.next/server/app/page.js +2 -2
  351. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  352. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  353. package/dist/web/standalone/.next/server/chunks/167.js +2 -0
  354. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  355. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  356. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  357. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  358. package/dist/web/standalone/.next/server/middleware.js +2 -2
  359. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  360. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  361. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  362. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  363. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  364. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  365. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  366. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  367. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  368. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  369. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  370. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-de742b64187e13fe.js} +1 -1
  371. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  372. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  373. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  374. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  375. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  376. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  377. package/dist/web/standalone/package.json +1 -0
  378. package/dist/web/standalone/server.js +1 -1
  379. package/dist/welcome-screen.d.ts +2 -7
  380. package/dist/welcome-screen.js +68 -75
  381. package/package.json +20 -9
  382. package/packages/contracts/dist/index.d.ts +3 -0
  383. package/packages/contracts/dist/index.d.ts.map +1 -0
  384. package/packages/contracts/dist/index.js +5 -0
  385. package/packages/contracts/dist/index.js.map +1 -0
  386. package/packages/contracts/dist/rpc.d.ts +549 -0
  387. package/packages/contracts/dist/rpc.d.ts.map +1 -0
  388. package/packages/contracts/dist/rpc.js +53 -0
  389. package/packages/contracts/dist/rpc.js.map +1 -0
  390. package/packages/contracts/dist/rpc.test.d.ts +2 -0
  391. package/packages/contracts/dist/rpc.test.d.ts.map +1 -0
  392. package/packages/contracts/dist/rpc.test.js +47 -0
  393. package/packages/contracts/dist/rpc.test.js.map +1 -0
  394. package/packages/contracts/dist/workflow.d.ts +180 -0
  395. package/packages/contracts/dist/workflow.d.ts.map +1 -0
  396. package/packages/contracts/dist/workflow.js +201 -0
  397. package/packages/contracts/dist/workflow.js.map +1 -0
  398. package/packages/contracts/package.json +39 -0
  399. package/packages/contracts/src/index.ts +5 -0
  400. package/packages/contracts/src/rpc.test.ts +72 -0
  401. package/packages/contracts/src/rpc.ts +286 -0
  402. package/packages/contracts/src/workflow.ts +213 -0
  403. package/packages/contracts/tsconfig.json +25 -0
  404. package/packages/daemon/package.json +3 -2
  405. package/packages/daemon/src/event-bridge.test.ts +2 -1
  406. package/packages/daemon/src/event-bridge.ts +1 -1
  407. package/packages/daemon/src/event-formatter.test.ts +1 -2
  408. package/packages/daemon/src/event-formatter.ts +1 -2
  409. package/packages/daemon/src/session-manager.ts +2 -2
  410. package/packages/daemon/src/types.ts +3 -18
  411. package/packages/mcp-server/dist/server.d.ts +13 -0
  412. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  413. package/packages/mcp-server/dist/server.js +77 -0
  414. package/packages/mcp-server/dist/server.js.map +1 -1
  415. package/packages/mcp-server/dist/session-manager.js +1 -1
  416. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  417. package/packages/mcp-server/dist/types.d.ts +3 -11
  418. package/packages/mcp-server/dist/types.d.ts.map +1 -1
  419. package/packages/mcp-server/dist/types.js.map +1 -1
  420. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  421. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  422. package/packages/mcp-server/dist/workflow-tools.js +24 -57
  423. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  424. package/packages/mcp-server/package.json +3 -2
  425. package/packages/mcp-server/src/mcp-server.test.ts +138 -0
  426. package/packages/mcp-server/src/server.ts +99 -1
  427. package/packages/mcp-server/src/session-manager.ts +2 -2
  428. package/packages/mcp-server/src/types.ts +7 -18
  429. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  430. package/packages/mcp-server/src/workflow-tools.ts +32 -56
  431. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  432. package/packages/native/package.json +1 -1
  433. package/packages/native/tsconfig.tsbuildinfo +1 -1
  434. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  435. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  436. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  437. package/packages/pi-agent-core/dist/agent.d.ts +9 -2
  438. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  439. package/packages/pi-agent-core/dist/agent.js +43 -11
  440. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  441. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  442. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  443. package/packages/pi-agent-core/dist/index.js +2 -0
  444. package/packages/pi-agent-core/dist/index.js.map +1 -1
  445. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  446. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  447. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  448. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  449. package/packages/pi-agent-core/dist/types.d.ts +31 -0
  450. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  451. package/packages/pi-agent-core/dist/types.js.map +1 -1
  452. package/packages/pi-agent-core/package.json +1 -1
  453. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  454. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  455. package/packages/pi-agent-core/src/agent.ts +52 -11
  456. package/packages/pi-agent-core/src/index.ts +2 -0
  457. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  458. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  459. package/packages/pi-agent-core/src/types.ts +26 -10
  460. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  461. package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
  462. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  463. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  464. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  465. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  466. package/packages/pi-ai/dist/models/index.js +8 -0
  467. package/packages/pi-ai/dist/models/index.js.map +1 -1
  468. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  469. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  470. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  471. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  472. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  473. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  474. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  475. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  476. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  477. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  478. package/packages/pi-ai/dist/providers/fake.js +319 -0
  479. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  480. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  481. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  482. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  483. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  484. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  485. package/packages/pi-ai/dist/types.d.ts +2 -0
  486. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  487. package/packages/pi-ai/dist/types.js.map +1 -1
  488. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  489. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  490. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  491. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  492. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  493. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  494. package/packages/pi-ai/package.json +1 -1
  495. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  496. package/packages/pi-ai/src/models/index.ts +9 -0
  497. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  498. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  499. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  500. package/packages/pi-ai/src/providers/fake.ts +376 -0
  501. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  502. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  503. package/packages/pi-ai/src/types.ts +3 -0
  504. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  505. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  506. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  507. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  508. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +36 -1
  509. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  510. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +30 -1
  511. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  512. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +21 -2
  513. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  514. package/packages/pi-coding-agent/dist/core/agent-session.js +94 -16
  515. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  516. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +78 -0
  517. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  518. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  519. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  520. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  521. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  522. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  523. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  524. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  525. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  526. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  527. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  528. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  529. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  530. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  531. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  532. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  533. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  534. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  535. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  536. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  537. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +5 -0
  538. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  539. package/packages/pi-coding-agent/dist/core/extensions/runner.js +20 -7
  540. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  541. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +102 -3
  542. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  543. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +60 -4
  544. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  545. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  546. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  547. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  548. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  549. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  550. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  551. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  552. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  553. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  554. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  555. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  556. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  557. package/packages/pi-coding-agent/dist/core/sdk.js +81 -4
  558. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  559. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +24 -0
  560. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  561. package/packages/pi-coding-agent/dist/core/settings-manager.js +33 -0
  562. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  563. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  564. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  565. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  566. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  567. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  568. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  569. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  570. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  571. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  572. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  573. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  574. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  575. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  576. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  577. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  578. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  579. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  580. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  581. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  582. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  583. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  584. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  585. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  586. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  587. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  588. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  589. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  590. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  591. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  592. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  593. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  594. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  595. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  596. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  597. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  598. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  599. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  600. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  601. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  602. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  603. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  604. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  605. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  606. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  607. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  608. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  609. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  610. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  611. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  612. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  613. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  614. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  615. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  616. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  617. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  618. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  619. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  620. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  621. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  622. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  623. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  624. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  625. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  626. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +225 -18
  627. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  628. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  629. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  630. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  631. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  632. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +25 -0
  633. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  634. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +113 -0
  635. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  636. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  637. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  638. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +58 -0
  639. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  640. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  641. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  642. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  643. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  644. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  645. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  646. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  647. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  648. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  649. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  650. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  651. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  652. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  653. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  654. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  655. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  656. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  657. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  658. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  659. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  660. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  661. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +51 -6
  662. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  663. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +21 -0
  664. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  665. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +302 -56
  666. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  667. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  668. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  669. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  670. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  671. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  672. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  673. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  674. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  675. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  676. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  677. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  678. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  679. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  680. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +86 -2
  681. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  682. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +111 -1
  683. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  684. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
  685. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  686. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  687. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  688. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  689. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +14 -1
  690. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  691. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +77 -11
  692. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  693. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  694. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  695. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  696. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  697. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  698. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  699. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  700. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  701. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  702. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  703. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  704. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  705. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  706. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  707. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  708. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  709. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  710. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +123 -2
  711. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  712. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  713. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +39 -29
  714. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  715. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  716. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  717. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  718. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  719. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  720. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  721. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +51 -0
  722. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  723. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  724. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  725. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -512
  726. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  727. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js +3 -7
  728. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  729. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  730. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  731. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +28 -0
  732. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  733. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  734. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  735. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  736. package/packages/pi-coding-agent/package.json +2 -1
  737. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +40 -1
  738. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +40 -1
  739. package/packages/pi-coding-agent/src/core/agent-session.ts +102 -16
  740. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +91 -0
  741. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  742. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  743. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  744. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  745. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  746. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +113 -3
  747. package/packages/pi-coding-agent/src/core/extensions/runner.ts +24 -6
  748. package/packages/pi-coding-agent/src/core/extensions/types.ts +63 -2
  749. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  750. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  751. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  752. package/packages/pi-coding-agent/src/core/sdk.ts +92 -4
  753. package/packages/pi-coding-agent/src/core/settings-manager.ts +51 -1
  754. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  755. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  756. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  757. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  758. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  759. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  760. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  761. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  762. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  763. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  764. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  765. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  766. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  767. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  768. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  769. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  770. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  771. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  772. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +325 -20
  773. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  774. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +66 -0
  775. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +161 -0
  776. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -13
  777. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  778. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  779. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  780. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  781. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  782. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +71 -9
  783. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +327 -68
  784. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  785. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  786. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  787. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +118 -1
  788. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +108 -3
  789. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  790. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  791. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +101 -11
  792. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  793. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  794. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  795. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  796. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +138 -3
  797. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +39 -29
  798. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +68 -0
  799. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  800. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
  801. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +3 -336
  802. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +31 -0
  803. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  804. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  805. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  806. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  807. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  808. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  809. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  810. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  811. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  812. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  813. package/packages/pi-tui/dist/index.d.ts +1 -0
  814. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  815. package/packages/pi-tui/dist/index.js +2 -0
  816. package/packages/pi-tui/dist/index.js.map +1 -1
  817. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  818. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  819. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  820. package/packages/pi-tui/dist/style.d.ts +41 -0
  821. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  822. package/packages/pi-tui/dist/style.js +158 -0
  823. package/packages/pi-tui/dist/style.js.map +1 -0
  824. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  825. package/packages/pi-tui/dist/tui.js +19 -8
  826. package/packages/pi-tui/dist/tui.js.map +1 -1
  827. package/packages/pi-tui/package.json +1 -1
  828. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  829. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  830. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  831. package/packages/pi-tui/src/index.ts +9 -0
  832. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  833. package/packages/pi-tui/src/style.ts +225 -0
  834. package/packages/pi-tui/src/tui.ts +21 -8
  835. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  836. package/packages/rpc-client/README.md +10 -3
  837. package/packages/rpc-client/dist/index.d.ts +1 -1
  838. package/packages/rpc-client/dist/index.d.ts.map +1 -1
  839. package/packages/rpc-client/dist/index.js.map +1 -1
  840. package/packages/rpc-client/dist/rpc-client.d.ts +2 -6
  841. package/packages/rpc-client/dist/rpc-client.d.ts.map +1 -1
  842. package/packages/rpc-client/dist/rpc-client.js.map +1 -1
  843. package/packages/rpc-client/dist/rpc-types.d.ts +1 -565
  844. package/packages/rpc-client/dist/rpc-types.d.ts.map +1 -1
  845. package/packages/rpc-client/dist/rpc-types.js +3 -11
  846. package/packages/rpc-client/dist/rpc-types.js.map +1 -1
  847. package/packages/rpc-client/package.json +4 -1
  848. package/packages/rpc-client/src/index.ts +1 -1
  849. package/packages/rpc-client/src/rpc-client.ts +3 -6
  850. package/packages/rpc-client/src/rpc-types.ts +3 -398
  851. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  852. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  853. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  854. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  855. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  856. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  857. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  858. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  859. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  860. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  861. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  862. package/pkg/dist/modes/interactive/theme/theme.js +123 -2
  863. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  864. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  865. package/pkg/dist/modes/interactive/theme/themes.js +39 -29
  866. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  867. package/pkg/package.json +1 -1
  868. package/src/resources/GSD-WORKFLOW.md +2 -2
  869. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  870. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +42 -3
  871. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +67 -0
  872. package/src/resources/extensions/github-sync/sync.ts +8 -1
  873. package/src/resources/extensions/github-sync/templates.ts +93 -88
  874. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  875. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  876. package/src/resources/extensions/github-sync/tests/templates.test.ts +10 -2
  877. package/src/resources/extensions/gsd/auto/contracts.ts +19 -2
  878. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +72 -0
  879. package/src/resources/extensions/gsd/auto/loop-deps.ts +20 -16
  880. package/src/resources/extensions/gsd/auto/loop.ts +645 -603
  881. package/src/resources/extensions/gsd/auto/orchestrator.ts +52 -4
  882. package/src/resources/extensions/gsd/auto/phases.ts +546 -222
  883. package/src/resources/extensions/gsd/auto/resolve.ts +42 -1
  884. package/src/resources/extensions/gsd/auto/run-unit.ts +119 -46
  885. package/src/resources/extensions/gsd/auto/session.ts +19 -1
  886. package/src/resources/extensions/gsd/auto/types.ts +3 -0
  887. package/src/resources/extensions/gsd/auto/unit-runner-events.ts +15 -0
  888. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  889. package/src/resources/extensions/gsd/auto/workflow-custom-engine-dispatch-outcome.ts +28 -0
  890. package/src/resources/extensions/gsd/auto/workflow-custom-engine-iteration.ts +52 -0
  891. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile-outcome.ts +58 -0
  892. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile.ts +71 -0
  893. package/src/resources/extensions/gsd/auto/workflow-custom-engine-retry.ts +90 -0
  894. package/src/resources/extensions/gsd/auto/workflow-custom-engine-verify-outcome.ts +50 -0
  895. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +159 -0
  896. package/src/resources/extensions/gsd/auto/workflow-dispatch-ledger.ts +45 -0
  897. package/src/resources/extensions/gsd/auto/workflow-iteration-completion.ts +26 -0
  898. package/src/resources/extensions/gsd/auto/workflow-journal-reporter.ts +33 -0
  899. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +520 -0
  900. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +58 -0
  901. package/src/resources/extensions/gsd/auto/workflow-phase-reporter.ts +22 -0
  902. package/src/resources/extensions/gsd/auto/workflow-session-lock.ts +68 -0
  903. package/src/resources/extensions/gsd/auto/workflow-sidecar-iteration.ts +46 -0
  904. package/src/resources/extensions/gsd/auto/workflow-sidecar-queue.ts +46 -0
  905. package/src/resources/extensions/gsd/auto/workflow-turn-reporter.ts +68 -0
  906. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +89 -0
  907. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +51 -0
  908. package/src/resources/extensions/gsd/auto-dashboard.ts +304 -184
  909. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  910. package/src/resources/extensions/gsd/auto-dispatch.ts +48 -1
  911. package/src/resources/extensions/gsd/auto-post-unit.ts +141 -91
  912. package/src/resources/extensions/gsd/auto-prompts.ts +398 -19
  913. package/src/resources/extensions/gsd/auto-recovery.ts +207 -7
  914. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  915. package/src/resources/extensions/gsd/auto-start.ts +328 -27
  916. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  917. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  918. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  919. package/src/resources/extensions/gsd/auto-verification.ts +17 -7
  920. package/src/resources/extensions/gsd/auto-worktree.ts +352 -396
  921. package/src/resources/extensions/gsd/auto.ts +590 -127
  922. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +181 -12
  923. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +56 -37
  924. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
  925. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +32 -19
  926. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
  927. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
  928. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
  929. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  930. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +411 -58
  931. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  932. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  933. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  934. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +153 -2
  935. package/src/resources/extensions/gsd/clean-root-preflight.ts +72 -9
  936. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  937. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  938. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  939. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  940. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  941. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  942. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  943. package/src/resources/extensions/gsd/commands-ship.ts +24 -51
  944. package/src/resources/extensions/gsd/commands-workflow-templates.ts +13 -0
  945. package/src/resources/extensions/gsd/component-loader.ts +5 -11
  946. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  947. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  948. package/src/resources/extensions/gsd/custom-workflow-engine.ts +29 -0
  949. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  950. package/src/resources/extensions/gsd/db/unit-dispatches.ts +107 -0
  951. package/src/resources/extensions/gsd/db-adapter.ts +75 -0
  952. package/src/resources/extensions/gsd/db-base-schema.ts +385 -0
  953. package/src/resources/extensions/gsd/db-connection-cache.ts +45 -0
  954. package/src/resources/extensions/gsd/db-coordination-schema.ts +109 -0
  955. package/src/resources/extensions/gsd/db-decision-requirement-rows.ts +77 -0
  956. package/src/resources/extensions/gsd/db-gate-rows.ts +19 -0
  957. package/src/resources/extensions/gsd/db-lightweight-query-rows.ts +50 -0
  958. package/src/resources/extensions/gsd/db-memory-fts-schema.ts +66 -0
  959. package/src/resources/extensions/gsd/db-migration-backup.ts +34 -0
  960. package/src/resources/extensions/gsd/db-migration-steps.ts +459 -0
  961. package/src/resources/extensions/gsd/db-milestone-artifact-rows.ts +70 -0
  962. package/src/resources/extensions/gsd/db-open-state.ts +47 -0
  963. package/src/resources/extensions/gsd/db-provider.ts +148 -0
  964. package/src/resources/extensions/gsd/db-runtime-kv-schema.ts +30 -0
  965. package/src/resources/extensions/gsd/db-schema-metadata.ts +33 -0
  966. package/src/resources/extensions/gsd/db-task-slice-rows.ts +146 -0
  967. package/src/resources/extensions/gsd/db-transaction.ts +76 -0
  968. package/src/resources/extensions/gsd/db-verification-evidence-rows.ts +14 -0
  969. package/src/resources/extensions/gsd/db-verification-evidence-schema.ts +22 -0
  970. package/src/resources/extensions/gsd/detection.ts +128 -0
  971. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  972. package/src/resources/extensions/gsd/escalation.ts +3 -1
  973. package/src/resources/extensions/gsd/git-service.ts +89 -10
  974. package/src/resources/extensions/gsd/graph.ts +12 -5
  975. package/src/resources/extensions/gsd/gsd-db.ts +399 -1677
  976. package/src/resources/extensions/gsd/guided-flow.ts +175 -55
  977. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  978. package/src/resources/extensions/gsd/health-widget.ts +8 -9
  979. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  980. package/src/resources/extensions/gsd/journal.ts +2 -0
  981. package/src/resources/extensions/gsd/legacy-telemetry.ts +99 -0
  982. package/src/resources/extensions/gsd/markdown-renderer.ts +4 -1
  983. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  984. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  985. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  986. package/src/resources/extensions/gsd/model-router.ts +10 -6
  987. package/src/resources/extensions/gsd/native-git-bridge.ts +53 -19
  988. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  989. package/src/resources/extensions/gsd/notification-widget.ts +25 -4
  990. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  991. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  992. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  993. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  994. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  995. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -1
  996. package/src/resources/extensions/gsd/pr-evidence.ts +182 -0
  997. package/src/resources/extensions/gsd/pre-execution-checks.ts +27 -1
  998. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  999. package/src/resources/extensions/gsd/process-task-path.ts +81 -0
  1000. package/src/resources/extensions/gsd/prompt-loader.ts +36 -7
  1001. package/src/resources/extensions/gsd/prompts/complete-milestone.md +41 -35
  1002. package/src/resources/extensions/gsd/prompts/complete-slice.md +25 -34
  1003. package/src/resources/extensions/gsd/prompts/discuss-headless.md +70 -98
  1004. package/src/resources/extensions/gsd/prompts/discuss.md +101 -183
  1005. package/src/resources/extensions/gsd/prompts/execute-task.md +42 -67
  1006. package/src/resources/extensions/gsd/prompts/forensics.md +41 -84
  1007. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +29 -39
  1008. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +30 -65
  1009. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +25 -52
  1010. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +36 -36
  1011. package/src/resources/extensions/gsd/prompts/guided-research-project.md +20 -38
  1012. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  1013. package/src/resources/extensions/gsd/prompts/plan-milestone.md +47 -59
  1014. package/src/resources/extensions/gsd/prompts/plan-slice.md +25 -87
  1015. package/src/resources/extensions/gsd/prompts/queue.md +46 -53
  1016. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  1017. package/src/resources/extensions/gsd/prompts/refine-slice.md +23 -23
  1018. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  1019. package/src/resources/extensions/gsd/prompts/research-slice.md +23 -23
  1020. package/src/resources/extensions/gsd/prompts/rethink.md +10 -10
  1021. package/src/resources/extensions/gsd/prompts/system.md +65 -107
  1022. package/src/resources/extensions/gsd/prompts/triage-captures.md +15 -15
  1023. package/src/resources/extensions/gsd/prompts/validate-milestone.md +24 -24
  1024. package/src/resources/extensions/gsd/prompts/worktree-merge.md +35 -35
  1025. package/src/resources/extensions/gsd/quick.ts +37 -2
  1026. package/src/resources/extensions/gsd/recovery-classification.ts +122 -0
  1027. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  1028. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  1029. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  1030. package/src/resources/extensions/gsd/state-reconciliation.ts +57 -0
  1031. package/src/resources/extensions/gsd/state.ts +6 -3
  1032. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  1033. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  1034. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  1035. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
  1036. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +232 -9
  1037. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1269 -242
  1038. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  1039. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +119 -2
  1040. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  1041. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +363 -18
  1042. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +175 -11
  1043. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -76
  1044. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  1045. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +184 -2
  1046. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  1047. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  1048. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  1049. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  1050. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  1051. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  1052. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +160 -0
  1053. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  1054. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  1055. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  1056. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  1057. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  1058. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
  1059. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  1060. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  1061. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +97 -2
  1062. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  1063. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  1064. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  1065. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  1066. package/src/resources/extensions/gsd/tests/commands-eval-review.test.ts +2 -2
  1067. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  1068. package/src/resources/extensions/gsd/tests/commands-ship-eval-warn.test.ts +3 -2
  1069. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  1070. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  1071. package/src/resources/extensions/gsd/tests/complete-milestone-prompt-rendering.test.ts +47 -0
  1072. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +159 -5
  1073. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  1074. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  1075. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  1076. package/src/resources/extensions/gsd/tests/component-loader.test.ts +2 -9
  1077. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  1078. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  1079. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +90 -31
  1080. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  1081. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +190 -11
  1082. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +139 -0
  1083. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +50 -0
  1084. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  1085. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  1086. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +82 -0
  1087. package/src/resources/extensions/gsd/tests/db-base-schema.test.ts +62 -0
  1088. package/src/resources/extensions/gsd/tests/db-connection-cache.test.ts +60 -0
  1089. package/src/resources/extensions/gsd/tests/db-coordination-schema.test.ts +39 -0
  1090. package/src/resources/extensions/gsd/tests/db-decision-requirement-rows.test.ts +135 -0
  1091. package/src/resources/extensions/gsd/tests/db-gate-rows.test.ts +53 -0
  1092. package/src/resources/extensions/gsd/tests/db-lightweight-query-rows.test.ts +45 -0
  1093. package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +86 -0
  1094. package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +105 -0
  1095. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  1096. package/src/resources/extensions/gsd/tests/db-migration-steps.test.ts +159 -0
  1097. package/src/resources/extensions/gsd/tests/db-milestone-artifact-rows.test.ts +53 -0
  1098. package/src/resources/extensions/gsd/tests/db-open-state.test.ts +56 -0
  1099. package/src/resources/extensions/gsd/tests/db-provider.test.ts +105 -0
  1100. package/src/resources/extensions/gsd/tests/db-runtime-kv-schema.test.ts +37 -0
  1101. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +115 -0
  1102. package/src/resources/extensions/gsd/tests/db-task-slice-rows.test.ts +128 -0
  1103. package/src/resources/extensions/gsd/tests/db-transaction.test.ts +110 -0
  1104. package/src/resources/extensions/gsd/tests/db-verification-evidence-schema.test.ts +76 -0
  1105. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +24 -11
  1106. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  1107. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  1108. package/src/resources/extensions/gsd/tests/discuss-headless-rendering.test.ts +37 -0
  1109. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  1110. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +100 -38
  1111. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  1112. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  1113. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  1114. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  1115. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  1116. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  1117. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  1118. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +62 -0
  1119. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  1120. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +151 -0
  1121. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  1122. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  1123. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  1124. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  1125. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  1126. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +36 -0
  1127. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  1128. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  1129. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
  1130. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +43 -0
  1131. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +41 -0
  1132. package/src/resources/extensions/gsd/tests/guided-discuss-requirements-prompt-rendering.test.ts +45 -0
  1133. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  1134. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  1135. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  1136. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  1137. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  1138. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +77 -0
  1139. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  1140. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  1141. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +92 -0
  1142. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  1143. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  1144. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +5 -3
  1145. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  1146. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
  1147. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +248 -11
  1148. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  1149. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  1150. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  1151. package/src/resources/extensions/gsd/tests/legacy-component-format-telemetry.test.ts +62 -0
  1152. package/src/resources/extensions/gsd/tests/legacy-telemetry.test.ts +144 -0
  1153. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  1154. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +53 -43
  1155. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +77 -12
  1156. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  1157. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  1158. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +267 -0
  1159. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +88 -98
  1160. package/src/resources/extensions/gsd/tests/model-router.test.ts +33 -12
  1161. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  1162. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  1163. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  1164. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  1165. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  1166. package/src/resources/extensions/gsd/tests/notification-store.test.ts +8 -0
  1167. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +40 -1
  1168. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  1169. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -182
  1170. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +144 -0
  1171. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  1172. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  1173. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  1174. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  1175. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  1176. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +95 -75
  1177. package/src/resources/extensions/gsd/tests/plan-milestone-rendering.test.ts +45 -0
  1178. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +65 -16
  1179. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  1180. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  1181. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  1182. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  1183. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  1184. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  1185. package/src/resources/extensions/gsd/tests/pr-evidence.test.ts +79 -0
  1186. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  1187. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  1188. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  1189. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  1190. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  1191. package/src/resources/extensions/gsd/tests/process-task-path.test.ts +51 -0
  1192. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  1193. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  1194. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  1195. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
  1196. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  1197. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  1198. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -91
  1199. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  1200. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  1201. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  1202. package/src/resources/extensions/gsd/tests/queue-prompt-rendering.test.ts +37 -0
  1203. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  1204. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  1205. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  1206. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  1207. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  1208. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  1209. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
  1210. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +36 -164
  1211. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  1212. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  1213. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +91 -0
  1214. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  1215. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  1216. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  1217. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  1218. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  1219. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +222 -0
  1220. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  1221. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  1222. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  1223. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  1224. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  1225. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  1226. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  1227. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  1228. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -59
  1229. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  1230. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  1231. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  1232. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  1233. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  1234. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  1235. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
  1236. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -56
  1237. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +35 -40
  1238. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  1239. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  1240. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  1241. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  1242. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  1243. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  1244. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  1245. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +295 -0
  1246. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +32 -9
  1247. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  1248. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +330 -0
  1249. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  1250. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +140 -8
  1251. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  1252. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +80 -1
  1253. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  1254. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
  1255. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +12 -0
  1256. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  1257. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  1258. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  1259. package/src/resources/extensions/gsd/tests/workflow-custom-engine-dispatch-outcome.test.ts +55 -0
  1260. package/src/resources/extensions/gsd/tests/workflow-custom-engine-iteration.test.ts +93 -0
  1261. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile-outcome.test.ts +108 -0
  1262. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile.test.ts +146 -0
  1263. package/src/resources/extensions/gsd/tests/workflow-custom-engine-retry.test.ts +136 -0
  1264. package/src/resources/extensions/gsd/tests/workflow-custom-engine-verify-outcome.test.ts +95 -0
  1265. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +300 -0
  1266. package/src/resources/extensions/gsd/tests/workflow-dispatch-ledger.test.ts +82 -0
  1267. package/src/resources/extensions/gsd/tests/workflow-iteration-completion.test.ts +44 -0
  1268. package/src/resources/extensions/gsd/tests/workflow-journal-reporter.test.ts +49 -0
  1269. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +607 -0
  1270. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  1271. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +20 -4
  1272. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -57
  1273. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +71 -0
  1274. package/src/resources/extensions/gsd/tests/workflow-phase-reporter.test.ts +40 -0
  1275. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  1276. package/src/resources/extensions/gsd/tests/workflow-session-lock.test.ts +135 -0
  1277. package/src/resources/extensions/gsd/tests/workflow-sidecar-iteration.test.ts +110 -0
  1278. package/src/resources/extensions/gsd/tests/workflow-sidecar-queue.test.ts +116 -0
  1279. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +21 -0
  1280. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +35 -0
  1281. package/src/resources/extensions/gsd/tests/workflow-turn-reporter.test.ts +87 -0
  1282. package/src/resources/extensions/gsd/tests/workflow-unit-dispatch.test.ts +160 -0
  1283. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +154 -0
  1284. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  1285. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  1286. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  1287. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +38 -6
  1288. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +197 -78
  1289. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +888 -0
  1290. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  1291. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  1292. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  1293. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  1294. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  1295. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +327 -0
  1296. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +120 -0
  1297. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +17 -33
  1298. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  1299. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  1300. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  1301. package/src/resources/extensions/gsd/tests/write-gate.test.ts +40 -1
  1302. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  1303. package/src/resources/extensions/gsd/tool-contract.ts +82 -0
  1304. package/src/resources/extensions/gsd/tools/complete-milestone.ts +29 -24
  1305. package/src/resources/extensions/gsd/tools/complete-task.ts +5 -2
  1306. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  1307. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  1308. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  1309. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  1310. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  1311. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  1312. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  1313. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +7 -2
  1314. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  1315. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  1316. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  1317. package/src/resources/extensions/gsd/uok/kernel.ts +10 -3
  1318. package/src/resources/extensions/gsd/uok/plan-v2.ts +5 -1
  1319. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  1320. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  1321. package/src/resources/extensions/gsd/workflow-logger.ts +13 -13
  1322. package/src/resources/extensions/gsd/workflow-manifest.ts +6 -15
  1323. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  1324. package/src/resources/extensions/gsd/workflow-projections.ts +5 -1
  1325. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  1326. package/src/resources/extensions/gsd/workflow-templates.ts +11 -0
  1327. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  1328. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1882 -0
  1329. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  1330. package/src/resources/extensions/gsd/worktree-safety.ts +282 -0
  1331. package/src/resources/extensions/gsd/worktree-state-projection.ts +404 -0
  1332. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  1333. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  1334. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  1335. package/dist/resources/extensions/gsd/worktree-resolver.js +0 -733
  1336. package/dist/web/standalone/.next/server/chunks/6336.js +0 -1
  1337. package/dist/web/standalone/.next/static/chunks/8336.6f6f30e410419aff.js +0 -10
  1338. package/dist/web/standalone/.next/static/chunks/app/page-ff639266d978f2a0.js +0 -1
  1339. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  1340. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  1341. package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +0 -434
  1342. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1247
  1343. package/src/resources/extensions/gsd/worktree-resolver.ts +0 -909
  1344. /package/dist/web/standalone/.next/static/{V-3Ehy4B24f9FCGiLPWIM → F5x9E6H9k_52fjqyql93y}/_buildManifest.js +0 -0
  1345. /package/dist/web/standalone/.next/static/{V-3Ehy4B24f9FCGiLPWIM → F5x9E6H9k_52fjqyql93y}/_ssgManifest.js +0 -0
@@ -1,6 +1,9 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Auto-loop execution, dispatch, recovery, and cancellation regression tests.
3
+
1
4
  import test, { mock } from "node:test";
2
5
  import assert from "node:assert/strict";
3
- import { mkdtempSync } from "node:fs";
6
+ import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
4
7
  import { tmpdir } from "node:os";
5
8
  import { join } from "node:path";
6
9
 
@@ -10,13 +13,21 @@ import {
10
13
  _resetPendingResolve,
11
14
  _hasPendingResolveForTest,
12
15
  _setActiveSession,
16
+ _setSessionSwitchInFlight,
17
+ _markSessionSwitchAbortGraceWindow,
18
+ _clearSessionSwitchAbortGraceWindow,
19
+ _consumePendingSwitchCancellation,
13
20
  isSessionSwitchInFlight,
21
+ isSessionSwitchAbortGraceActive,
14
22
  } from "../auto/resolve.js";
15
- import { runUnit } from "../auto/run-unit.js";
23
+ import { runUnit, shouldDeferUnitFailsafeTimeout } from "../auto/run-unit.js";
24
+ import { writeUnitRuntimeRecord, readUnitRuntimeRecord } from "../unit-runtime.js";
16
25
  import { autoLoop } from "../auto/loop.js";
26
+ import { runDispatch, runUnitPhase } from "../auto/phases.js";
17
27
  import { detectStuck } from "../auto/detect-stuck.js";
18
28
  import type { UnitResult, AgentEndEvent } from "../auto/types.js";
19
29
  import type { LoopDeps } from "../auto/loop-deps.js";
30
+ import { WorktreeStateProjection } from "../worktree-state-projection.js";
20
31
  import { ModelPolicyDispatchBlockedError } from "../auto-model-selection.js";
21
32
  import type { SessionLockStatus } from "../session-lock.js";
22
33
 
@@ -64,7 +75,7 @@ function makeMockSession(opts?: {
64
75
  verbose: false,
65
76
  basePath: process.cwd(),
66
77
  cmdCtx: {
67
- newSession: (options?: { abortSignal?: AbortSignal }) => {
78
+ newSession: (options?: { abortSignal?: AbortSignal; workspaceRoot?: string }) => {
68
79
  opts?.onNewSessionStart?.(session);
69
80
  if (opts?.newSessionThrows) {
70
81
  return Promise.reject(new Error(opts.newSessionThrows));
@@ -76,7 +87,7 @@ function makeMockSession(opts?: {
76
87
  setTimeout(() => {
77
88
  // Simulate AgentSession.newSession() checking abortSignal after
78
89
  // its internal async work (abort()) completes — this is where the
79
- // real code captures process.cwd() and rebuilds the tool runtime.
90
+ // real code selects a workspace root and rebuilds the tool runtime.
80
91
  // If the signal is aborted, the real code discards the session.
81
92
  opts?.onSignalCheck?.(options?.abortSignal?.aborted ?? false);
82
93
  opts?.onNewSessionSettle?.(session);
@@ -155,6 +166,109 @@ test("resolveAgentEnd resolves a pending runUnit promise", async () => {
155
166
  assert.deepEqual(result.event, event);
156
167
  });
157
168
 
169
+ test("runUnit failsafe defers cancellation while timeout recovery is making fresh progress", async () => {
170
+ _resetPendingResolve();
171
+ mock.timers.enable();
172
+ const originalCwd = process.cwd();
173
+
174
+ try {
175
+ mock.timers.setTime(10_000);
176
+ const ctx = makeMockCtx();
177
+ const pi = makeMockPi();
178
+ const s = makeMockSession();
179
+ s.basePath = mkdtempSync(join(tmpdir(), "gsd-rununit-recovery-"));
180
+ s.currentUnit = { type: "task", id: "T01", startedAt: 1234 };
181
+
182
+ const resultPromise = runUnit(ctx, pi, s, "task", "T01", "prompt");
183
+ await waitForMicrotasks(() => pi.calls.length === 1, "unit dispatch");
184
+
185
+ writeUnitRuntimeRecord(s.basePath, "task", "T01", 1234, {
186
+ phase: "recovered",
187
+ recoveryAttempts: 1,
188
+ lastProgressKind: "hard-recovery-retry",
189
+ lastProgressAt: Date.now(),
190
+ });
191
+ assert.equal(
192
+ shouldDeferUnitFailsafeTimeout(readUnitRuntimeRecord(s.basePath, "task", "T01"), {
193
+ nowMs: Date.now(),
194
+ currentUnitStartedAt: s.currentUnit.startedAt,
195
+ freshProgressMs: 30_000,
196
+ }),
197
+ true,
198
+ "fresh recovery runtime should defer the failsafe",
199
+ );
200
+
201
+ setTimeout(() => {
202
+ writeUnitRuntimeRecord(s.basePath, "task", "T01", 1234, {
203
+ phase: "recovered",
204
+ recoveryAttempts: 1,
205
+ lastProgressKind: "hard-recovery-retry",
206
+ lastProgressAt: Date.now(),
207
+ });
208
+ }, (30 * 60 * 1000) + 29_000);
209
+
210
+ mock.timers.tick((30 * 60 * 1000) + 31_000);
211
+ await Promise.resolve();
212
+
213
+ resolveAgentEnd(makeEvent());
214
+ const result = await resultPromise;
215
+ assert.equal(result.status, "completed");
216
+ } finally {
217
+ mock.timers.reset();
218
+ process.chdir(originalCwd);
219
+ }
220
+ });
221
+
222
+ test("shouldDeferUnitFailsafeTimeout rejects stale runtime progress", () => {
223
+ assert.equal(
224
+ shouldDeferUnitFailsafeTimeout({
225
+ version: 1,
226
+ unitType: "task",
227
+ unitId: "T01",
228
+ startedAt: 1234,
229
+ updatedAt: 1,
230
+ phase: "recovered",
231
+ wrapupWarningSent: false,
232
+ continueHereFired: false,
233
+ timeoutAt: 1,
234
+ lastProgressAt: 1,
235
+ progressCount: 1,
236
+ lastProgressKind: "hard-recovery-retry",
237
+ recoveryAttempts: 1,
238
+ }, {
239
+ nowMs: 120_000,
240
+ currentUnitStartedAt: 1234,
241
+ freshProgressMs: 30_000,
242
+ }),
243
+ false,
244
+ );
245
+ });
246
+
247
+ test("shouldDeferUnitFailsafeTimeout rejects future runtime progress", () => {
248
+ assert.equal(
249
+ shouldDeferUnitFailsafeTimeout({
250
+ version: 1,
251
+ unitType: "task",
252
+ unitId: "T01",
253
+ startedAt: 1234,
254
+ updatedAt: 1,
255
+ phase: "recovered",
256
+ wrapupWarningSent: false,
257
+ continueHereFired: false,
258
+ timeoutAt: 1,
259
+ lastProgressAt: 150_000,
260
+ progressCount: 1,
261
+ lastProgressKind: "hard-recovery-retry",
262
+ recoveryAttempts: 1,
263
+ }, {
264
+ nowMs: 120_000,
265
+ currentUnitStartedAt: 1234,
266
+ freshProgressMs: 30_000,
267
+ }),
268
+ false,
269
+ );
270
+ });
271
+
158
272
  test("resolveAgentEnd drops event when no promise is pending", () => {
159
273
  _resetPendingResolve();
160
274
 
@@ -206,6 +320,28 @@ test("runUnit returns cancelled when session creation fails", async () => {
206
320
  assert.equal(pi.calls.length, 0);
207
321
  });
208
322
 
323
+ test("runUnit clears queued switch cancellation when session creation fails", async () => {
324
+ _resetPendingResolve();
325
+
326
+ const ctx = makeMockCtx();
327
+ const pi = makeMockPi();
328
+ const s = makeMockSession({
329
+ newSessionThrows: "connection refused",
330
+ onNewSessionStart: () => {
331
+ resolveAgentEndCancelled({
332
+ message: "Claude Code process aborted by user",
333
+ category: "aborted",
334
+ isTransient: false,
335
+ });
336
+ },
337
+ });
338
+
339
+ const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
340
+
341
+ assert.equal(result.status, "cancelled");
342
+ assert.equal(_consumePendingSwitchCancellation(), null);
343
+ });
344
+
209
345
  test("runUnit returns cancelled when session creation times out", async () => {
210
346
  _resetPendingResolve();
211
347
 
@@ -221,6 +357,34 @@ test("runUnit returns cancelled when session creation times out", async () => {
221
357
  assert.equal(pi.calls.length, 0);
222
358
  });
223
359
 
360
+ test("runUnit consumes a cancellation queued during session switch before dispatch", async () => {
361
+ _resetPendingResolve();
362
+
363
+ const ctx = makeMockCtx();
364
+ const pi = makeMockPi();
365
+ let cancellationQueued = false;
366
+ const s = makeMockSession({
367
+ newSessionDelayMs: 10,
368
+ onNewSessionStart: () => {
369
+ setTimeout(() => {
370
+ cancellationQueued = !resolveAgentEndCancelled({
371
+ message: "Claude Code process aborted by user",
372
+ category: "aborted",
373
+ isTransient: false,
374
+ });
375
+ }, 0);
376
+ },
377
+ });
378
+
379
+ const result = await runUnit(ctx, pi, s, "plan-slice", "M009/S01", "prompt");
380
+
381
+ assert.equal(cancellationQueued, true);
382
+ assert.equal(result.status, "cancelled");
383
+ assert.equal(result.errorContext?.category, "aborted");
384
+ assert.equal(result.errorContext?.message, "Claude Code process aborted by user");
385
+ assert.equal(pi.calls.length, 0, "queued switch cancellation must prevent prompt dispatch");
386
+ });
387
+
224
388
  test("runUnit keeps the session-switch guard across a late newSession settlement", async () => {
225
389
  _resetPendingResolve();
226
390
  mock.timers.enable();
@@ -496,10 +660,9 @@ test("runUnit proceeds when isProviderRequestReady throws (defensive) (#4555)",
496
660
  assert.equal(pi.calls.length, 0);
497
661
  });
498
662
 
499
- test("late-resolving newSession() after timeout receives aborted signal so tool runtime is not configured with root cwd (#3731)", async () => {
500
- // When newSession() times out in runUnit(), auto-mode restores cwd to project
501
- // root. If newSession() later resolves, it must NOT use process.cwd() to
502
- // configure the tool runtime (which would give it root cwd, not worktree cwd).
663
+ test("late-resolving newSession() after timeout receives aborted signal so tool runtime is not configured with stale workspace root (#3731)", async () => {
664
+ // When newSession() times out in runUnit(), a late resolution must not
665
+ // configure the tool runtime against a stale workspace root.
503
666
  //
504
667
  // The fix: runUnit creates an AbortController, aborts it on timeout, and passes
505
668
  // the signal to newSession(). AgentSession.newSession() checks the signal after
@@ -514,8 +677,8 @@ test("late-resolving newSession() after timeout receives aborted signal so tool
514
677
 
515
678
  // newSession mock simulates AgentSession.newSession() behavior:
516
679
  // after an internal delay (representing await this.abort()), it checks the
517
- // abortSignal that's where the real code would capture process.cwd() and
518
- // call _buildRuntime. If aborted, the real code must discard the session.
680
+ // abortSignal before selecting the workspace root and calling _buildRuntime.
681
+ // If aborted, the real code must discard the session.
519
682
  const s = makeMockSession({
520
683
  newSessionDelayMs: 200_000, // longer than NEW_SESSION_TIMEOUT_MS (120s)
521
684
  onSignalCheck: (aborted) => {
@@ -548,7 +711,7 @@ test("late-resolving newSession() after timeout receives aborted signal so tool
548
711
  abortedWhenLateSessionSettled,
549
712
  true,
550
713
  "runUnit must pass an aborted AbortSignal to newSession() when it resolves after the session-creation timeout (#3731). " +
551
- "Without this, AgentSession.newSession() captures root process.cwd() and rebuilds the tool runtime with wrong cwd.",
714
+ "Without this, AgentSession.newSession() can rebuild the tool runtime with a stale workspace root.",
552
715
  );
553
716
  } finally {
554
717
  mock.timers.reset();
@@ -613,7 +776,6 @@ function makeMockDeps(
613
776
  preferences: { uok: { plan_v2: { enabled: false } } },
614
777
  }),
615
778
  preDispatchHealthGate: async () => ({ proceed: true, fixesApplied: [] }),
616
- syncProjectRootToWorktree: () => {},
617
779
  checkResourcesStale: () => null,
618
780
  validateSessionLock: () => ({ valid: true } as SessionLockStatus),
619
781
  updateSessionLock: () => {
@@ -627,7 +789,6 @@ function makeMockDeps(
627
789
  pruneQueueOrder: () => {},
628
790
  isInAutoWorktree: () => false,
629
791
  shouldUseWorktreeIsolation: () => false,
630
- mergeMilestoneToMain: () => ({ pushed: false, codeFilesChanged: true }),
631
792
  teardownAutoWorktree: () => {},
632
793
  createAutoWorktree: () => "/tmp/wt",
633
794
  captureIntegrationBranch: () => {},
@@ -637,7 +798,11 @@ function makeMockDeps(
637
798
  resolveMilestoneFile: () => null,
638
799
  reconcileMergeState: () => "clean",
639
800
  preflightCleanRoot: () => ({ stashPushed: false, summary: "" }),
640
- postflightPopStash: () => {},
801
+ postflightPopStash: () => ({
802
+ restored: true,
803
+ needsManualRecovery: false,
804
+ message: "restored",
805
+ }),
641
806
  getLedger: () => null,
642
807
  getProjectTotals: () => ({ cost: 0 }),
643
808
  formatCost: (c: number) => `$${c.toFixed(2)}`,
@@ -673,21 +838,15 @@ function makeMockDeps(
673
838
  readFileSync: () => "",
674
839
  atomicWriteSync: () => {},
675
840
  GitServiceImpl: class {} as any,
676
- resolver: {
677
- get workPath() {
678
- return "/tmp/project";
679
- },
680
- get projectRoot() {
681
- return "/tmp/project";
682
- },
683
- get lockPath() {
684
- return "/tmp/project";
685
- },
686
- enterMilestone: () => {},
687
- exitMilestone: () => {},
688
- mergeAndExit: () => {},
689
- mergeAndEnterNext: () => {},
841
+ lifecycle: {
842
+ enterMilestone: () => ({ ok: true, mode: "worktree", path: "/tmp/project" }),
843
+ exitMilestone: (_mid: string, opts: { merge: boolean }) => ({
844
+ ok: true,
845
+ merged: opts.merge,
846
+ codeFilesChanged: false,
847
+ }),
690
848
  } as any,
849
+ worktreeProjection: new WorktreeStateProjection(),
691
850
  postUnitPreVerification: async () => {
692
851
  callLog.push("postUnitPreVerification");
693
852
  return "continue" as const;
@@ -732,6 +891,7 @@ function makeLoopSession(overrides?: Partial<Record<string, unknown>>) {
732
891
  lastBudgetAlertLevel: 0,
733
892
  pendingVerificationRetry: null,
734
893
  pendingCrashRecovery: null,
894
+ verificationRetryFailureHashes: new Map<string, string>(),
735
895
  pendingQuickTasks: [],
736
896
  sidecarQueue: [],
737
897
  autoModeStartModel: null,
@@ -805,6 +965,139 @@ test("autoLoop exits on terminal complete state", async (t) => {
805
965
  );
806
966
  });
807
967
 
968
+ test("autoLoop stops before success notification when postflight stash restore needs recovery", async () => {
969
+ _resetPendingResolve();
970
+
971
+ const notifications: Array<{ msg: string; level: string }> = [];
972
+ const ctx = makeMockCtx();
973
+ ctx.ui.setStatus = () => {};
974
+ ctx.ui.notify = (msg: string, level: string) => {
975
+ notifications.push({ msg, level });
976
+ };
977
+ const pi = makeMockPi();
978
+ const s = makeLoopSession();
979
+ let stopReason = "";
980
+
981
+ const deps = makeMockDeps({
982
+ deriveState: async () => {
983
+ deps.callLog.push("deriveState");
984
+ return {
985
+ phase: "complete",
986
+ activeMilestone: { id: "M001", title: "Test", status: "complete" },
987
+ activeSlice: null,
988
+ activeTask: null,
989
+ registry: [{ id: "M001", status: "complete" }],
990
+ blockers: [],
991
+ } as any;
992
+ },
993
+ preflightCleanRoot: () => ({
994
+ stashPushed: true,
995
+ stashMarker: "gsd-preflight-stash:M001:test",
996
+ summary: "stashed",
997
+ }),
998
+ postflightPopStash: () => ({
999
+ restored: false,
1000
+ needsManualRecovery: true,
1001
+ message: "git stash pop stash@{0} failed after merge of milestone M001",
1002
+ stashRef: "stash@{0}",
1003
+ }),
1004
+ sendDesktopNotification: () => {
1005
+ deps.callLog.push("sendDesktopNotification");
1006
+ },
1007
+ logCmuxEvent: () => {
1008
+ deps.callLog.push("logCmuxEvent");
1009
+ },
1010
+ stopAuto: async (_ctx, _pi, reason) => {
1011
+ deps.callLog.push("stopAuto");
1012
+ stopReason = reason ?? "";
1013
+ },
1014
+ });
1015
+
1016
+ await autoLoop(ctx, pi, s, deps);
1017
+
1018
+ assert.equal(stopReason, "Post-merge stash restore failed for milestone M001");
1019
+ assert.ok(
1020
+ notifications.some(
1021
+ (n) => n.level === "error" && n.msg.includes("Post-merge stash restore failed for milestone M001"),
1022
+ ),
1023
+ "failed postflight restore must be surfaced as an error",
1024
+ );
1025
+ assert.ok(
1026
+ !deps.callLog.includes("sendDesktopNotification"),
1027
+ "must not emit milestone success desktop notification after stash restore failure",
1028
+ );
1029
+ assert.ok(
1030
+ !deps.callLog.includes("logCmuxEvent"),
1031
+ "must not emit milestone success cmux event after stash restore failure",
1032
+ );
1033
+ });
1034
+
1035
+ test("autoLoop marks transition merge complete before postflight recovery stop", async () => {
1036
+ _resetPendingResolve();
1037
+
1038
+ const ctx = makeMockCtx();
1039
+ ctx.ui.setStatus = () => {};
1040
+ ctx.ui.notify = () => {};
1041
+ const pi = makeMockPi();
1042
+ const s = makeLoopSession();
1043
+ let mergeCalls = 0;
1044
+ let stopReason = "";
1045
+
1046
+ const deps = makeMockDeps({
1047
+ deriveState: async () => {
1048
+ deps.callLog.push("deriveState");
1049
+ return {
1050
+ phase: "executing",
1051
+ activeMilestone: { id: "M002", title: "Next", status: "active" },
1052
+ activeSlice: null,
1053
+ activeTask: null,
1054
+ registry: [
1055
+ { id: "M001", title: "Done", status: "complete" },
1056
+ { id: "M002", title: "Next", status: "active" },
1057
+ ],
1058
+ blockers: [],
1059
+ } as any;
1060
+ },
1061
+ preflightCleanRoot: () => ({
1062
+ stashPushed: true,
1063
+ stashMarker: "gsd-preflight-stash:M001:test",
1064
+ summary: "stashed",
1065
+ }),
1066
+ postflightPopStash: () => ({
1067
+ restored: false,
1068
+ needsManualRecovery: true,
1069
+ message: "git stash pop stash@{0} failed after merge of milestone M001",
1070
+ stashRef: "stash@{0}",
1071
+ }),
1072
+ lifecycle: {
1073
+ enterMilestone: () => {
1074
+ assert.fail("must not enter the next milestone after postflight recovery fails");
1075
+ },
1076
+ exitMilestone: (_mid: string, opts: { merge: boolean }) => {
1077
+ if (opts.merge) mergeCalls += 1;
1078
+ return { ok: true, merged: opts.merge, codeFilesChanged: false };
1079
+ },
1080
+ } as any,
1081
+ stopAuto: async (_ctx, _pi, reason) => {
1082
+ deps.callLog.push("stopAuto");
1083
+ stopReason = reason ?? "";
1084
+ if (!s.milestoneMergedInPhases) {
1085
+ deps.lifecycle.exitMilestone(
1086
+ "M001",
1087
+ { merge: true },
1088
+ { notify: ctx.ui.notify.bind(ctx.ui) },
1089
+ );
1090
+ }
1091
+ },
1092
+ });
1093
+
1094
+ await autoLoop(ctx, pi, s, deps);
1095
+
1096
+ assert.equal(stopReason, "Post-merge stash restore failed for milestone M001");
1097
+ assert.equal(s.milestoneMergedInPhases, true);
1098
+ assert.equal(mergeCalls, 1, "postflight recovery stop must not re-run an already completed transition merge");
1099
+ });
1100
+
808
1101
  test("autoLoop pauses when provider readiness cancels before dispatch", async () => {
809
1102
  _resetPendingResolve();
810
1103
 
@@ -879,6 +1172,123 @@ test("autoLoop passes structured session-lock failure details to the handler", a
879
1172
  );
880
1173
  });
881
1174
 
1175
+ // Regression for #5308: the iteration prelude must dequeue sidecar items
1176
+ // (popping the queue and emitting the `sidecar-dequeue` journal event) BEFORE
1177
+ // validateSessionLock + break-on-invalid. Inverting that order silently drops
1178
+ // queued sidecar work on lock-loss. Covers first-iteration and mid-session.
1179
+ test("autoLoop dequeues sidecar item before session-lock break (first iteration, #5308)", async () => {
1180
+ _resetPendingResolve();
1181
+
1182
+ const ctx = makeMockCtx();
1183
+ ctx.ui.setStatus = () => {};
1184
+ const pi = makeMockPi();
1185
+ const s = makeLoopSession();
1186
+ s.sidecarQueue.push({
1187
+ kind: "hook" as const,
1188
+ unitType: "hook/review",
1189
+ unitId: "M001/S01/T01/review",
1190
+ prompt: "review the code",
1191
+ });
1192
+
1193
+ const journalEvents: string[] = [];
1194
+ const deps = makeMockDeps({
1195
+ validateSessionLock: () =>
1196
+ ({
1197
+ valid: false,
1198
+ failureReason: "compromised",
1199
+ expectedPid: process.pid,
1200
+ }) as SessionLockStatus,
1201
+ handleLostSessionLock: () => {
1202
+ deps.callLog.push("handleLostSessionLock");
1203
+ },
1204
+ emitJournalEvent: (entry) => {
1205
+ journalEvents.push(entry.eventType);
1206
+ },
1207
+ });
1208
+
1209
+ await autoLoop(ctx, pi, s, deps);
1210
+
1211
+ assert.equal(
1212
+ s.sidecarQueue.length,
1213
+ 0,
1214
+ "sidecar item must be popped on lock-loss iteration (pre-#5308 ordering)",
1215
+ );
1216
+ assert.ok(
1217
+ journalEvents.includes("sidecar-dequeue"),
1218
+ "sidecar-dequeue journal event must be emitted before session-lock break",
1219
+ );
1220
+ assert.ok(
1221
+ deps.callLog.includes("handleLostSessionLock"),
1222
+ "session lock handler must still fire after sidecar dequeue",
1223
+ );
1224
+ assert.ok(!deps.callLog.includes("deriveState"), "lock loss should stop before deriving state");
1225
+ });
1226
+
1227
+ test("autoLoop dequeues sidecar item before session-lock break (mid-session, #5308)", async () => {
1228
+ _resetPendingResolve();
1229
+
1230
+ const ctx = makeMockCtx();
1231
+ ctx.ui.setStatus = () => {};
1232
+ const pi = makeMockPi();
1233
+ const s = makeLoopSession();
1234
+
1235
+ const journalEvents: string[] = [];
1236
+ let lockCheckCount = 0;
1237
+ const deps = makeMockDeps({
1238
+ // First iteration: lock valid; second iteration: lock invalidates.
1239
+ validateSessionLock: () => {
1240
+ lockCheckCount += 1;
1241
+ if (lockCheckCount === 1) {
1242
+ return { valid: true } as SessionLockStatus;
1243
+ }
1244
+ return {
1245
+ valid: false,
1246
+ failureReason: "compromised",
1247
+ expectedPid: process.pid,
1248
+ } as SessionLockStatus;
1249
+ },
1250
+ handleLostSessionLock: () => {
1251
+ deps.callLog.push("handleLostSessionLock");
1252
+ },
1253
+ emitJournalEvent: (entry) => {
1254
+ journalEvents.push(entry.eventType);
1255
+ },
1256
+ // Enqueue a sidecar item at the end of iteration 1, so iteration 2 begins
1257
+ // with a non-empty queue and an invalid lock.
1258
+ postUnitPostVerification: async () => {
1259
+ deps.callLog.push("postUnitPostVerification");
1260
+ s.sidecarQueue.push({
1261
+ kind: "hook" as const,
1262
+ unitType: "run-uat",
1263
+ unitId: "M001/S01/T01/review",
1264
+ prompt: "review the code",
1265
+ });
1266
+ return "continue" as const;
1267
+ },
1268
+ });
1269
+
1270
+ const loopPromise = autoLoop(ctx, pi, s, deps);
1271
+ // Allow the loop to reach runUnit's await on iteration 1.
1272
+ await new Promise((r) => setTimeout(r, 50));
1273
+ resolveAgentEnd(makeEvent());
1274
+ await loopPromise;
1275
+
1276
+ assert.ok(lockCheckCount >= 2, "lock validator must run on iteration 2");
1277
+ assert.equal(
1278
+ s.sidecarQueue.length,
1279
+ 0,
1280
+ "queued sidecar item must be popped on the lock-loss iteration",
1281
+ );
1282
+ assert.ok(
1283
+ journalEvents.includes("sidecar-dequeue"),
1284
+ "sidecar-dequeue journal event must be emitted before session-lock break",
1285
+ );
1286
+ assert.ok(
1287
+ deps.callLog.includes("handleLostSessionLock"),
1288
+ "lock-loss handler must still fire on iteration 2",
1289
+ );
1290
+ });
1291
+
882
1292
  test("autoLoop exits on terminal blocked state", async (t) => {
883
1293
  _resetPendingResolve();
884
1294
 
@@ -991,45 +1401,146 @@ test("autoLoop calls deriveState → resolveDispatch → runUnit in sequence", a
991
1401
  );
992
1402
  });
993
1403
 
994
- test("crash lock records session file from AFTER newSession, not before (#1710)", async (t) => {
1404
+ test("autoLoop journals post-unit finalize stop after completed unit", async () => {
995
1405
  _resetPendingResolve();
996
1406
 
997
1407
  const ctx = makeMockCtx();
998
1408
  ctx.ui.setStatus = () => {};
999
-
1000
- // Simulate newSession changing the session file path.
1001
- // newSession() in runUnit changes the underlying session, so getSessionFile
1002
- // returns a different path after newSession completes.
1003
- let currentSessionFile = "/tmp/old-session.json";
1004
- ctx.sessionManager = {
1005
- getSessionFile: () => currentSessionFile,
1006
- };
1409
+ ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
1007
1410
  const pi = makeMockPi();
1411
+ const s = makeLoopSession();
1412
+ const journalEvents: Array<{ eventType: string; data?: any }> = [];
1008
1413
 
1009
- const s = makeLoopSession({
1010
- cmdCtx: {
1011
- newSession: () => {
1012
- // When newSession completes, the session file changes
1013
- currentSessionFile = "/tmp/new-session-after-newSession.json";
1014
- return Promise.resolve({ cancelled: false });
1015
- },
1016
- getContextUsage: () => ({ percent: 10, tokens: 1000, limit: 10000 }),
1414
+ const deps = makeMockDeps({
1415
+ postUnitPreVerification: async () => {
1416
+ deps.callLog.push("postUnitPreVerification");
1417
+ s.lastGitActionFailure = "commit failed";
1418
+ return "dispatched" as const;
1419
+ },
1420
+ emitJournalEvent: (entry: any) => {
1421
+ journalEvents.push(entry);
1017
1422
  },
1018
1423
  });
1019
1424
 
1020
- // Track all writeLock calls with their sessionFile argument
1021
- const writeLockCalls: { sessionFile: string | undefined }[] = [];
1022
- const updateSessionLockCalls: { sessionFile: string | undefined }[] = [];
1425
+ const loopPromise = autoLoop(ctx, pi, s, deps);
1426
+ await new Promise((r) => setTimeout(r, 50));
1427
+ resolveAgentEnd(makeEvent());
1428
+ await loopPromise;
1023
1429
 
1024
- const deps = makeMockDeps({
1025
- deriveState: async () => {
1026
- deps.callLog.push("deriveState");
1027
- return {
1028
- phase: "executing",
1029
- activeMilestone: { id: "M001", title: "Test", status: "active" },
1030
- activeSlice: { id: "S01", title: "Slice 1" },
1031
- activeTask: { id: "T01" },
1032
- registry: [{ id: "M001", status: "active" }],
1430
+ assert.ok(
1431
+ deps.callLog.includes("postUnitPreVerification"),
1432
+ "completed units must enter post-unit pre-verification before stopping",
1433
+ );
1434
+ assert.ok(
1435
+ !deps.callLog.includes("runPostUnitVerification"),
1436
+ "git-closeout stop should not run later verification phases",
1437
+ );
1438
+
1439
+ const unitEndIndex = journalEvents.findIndex((e) => e.eventType === "unit-end");
1440
+ const finalizeStartIndex = journalEvents.findIndex((e) => e.eventType === "post-unit-finalize-start");
1441
+ const finalizeEndIndex = journalEvents.findIndex((e) => e.eventType === "post-unit-finalize-end");
1442
+ const iterationEndIndex = journalEvents.findIndex((e) => e.eventType === "iteration-end");
1443
+
1444
+ assert.ok(unitEndIndex >= 0, "unit-end should be journaled after agent completion");
1445
+ assert.ok(finalizeStartIndex > unitEndIndex, "post-unit finalize must start after unit-end");
1446
+ assert.ok(finalizeEndIndex > finalizeStartIndex, "post-unit finalize must journal its stop result");
1447
+ assert.ok(iterationEndIndex > finalizeEndIndex, "iteration-end must be emitted even when finalize stops");
1448
+
1449
+ assert.deepEqual(journalEvents[finalizeEndIndex]!.data, {
1450
+ iteration: 1,
1451
+ unitType: "execute-task",
1452
+ unitId: "M001/S01/T01",
1453
+ status: "stopped",
1454
+ action: "break",
1455
+ reason: "git-closeout-failure",
1456
+ });
1457
+ assert.deepEqual(journalEvents[iterationEndIndex]!.data, {
1458
+ iteration: 1,
1459
+ status: "stopped",
1460
+ reason: "git-closeout-failure",
1461
+ unitType: "execute-task",
1462
+ unitId: "M001/S01/T01",
1463
+ failureClass: "git",
1464
+ });
1465
+ });
1466
+
1467
+ test("autoLoop journals iteration-end when unit phase breaks after cancelled unit", async () => {
1468
+ _resetPendingResolve();
1469
+
1470
+ const ctx = makeMockCtx();
1471
+ ctx.ui.setStatus = () => {};
1472
+ ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
1473
+ const pi = makeMockPi();
1474
+ const s = makeLoopSession();
1475
+ const journalEvents: Array<{ eventType: string; data?: any }> = [];
1476
+
1477
+ const deps = makeMockDeps({
1478
+ emitJournalEvent: (entry: any) => {
1479
+ journalEvents.push(entry);
1480
+ },
1481
+ });
1482
+
1483
+ const loopPromise = autoLoop(ctx, pi, s, deps);
1484
+ await new Promise((r) => setTimeout(r, 50));
1485
+ resolveAgentEndCancelled();
1486
+ await loopPromise;
1487
+
1488
+ const unitEndIndex = journalEvents.findIndex(
1489
+ (e) => e.eventType === "unit-end" && e.data?.status === "cancelled",
1490
+ );
1491
+ const iterationEndIndex = journalEvents.findIndex((e) => e.eventType === "iteration-end");
1492
+
1493
+ assert.ok(unitEndIndex >= 0, "cancelled unit should still emit unit-end");
1494
+ assert.ok(iterationEndIndex > unitEndIndex, "unit-phase break must close the iteration after unit-end");
1495
+ assert.deepEqual(journalEvents[iterationEndIndex]!.data, {
1496
+ iteration: 1,
1497
+ status: "stopped",
1498
+ reason: "unit-aborted",
1499
+ unitType: "execute-task",
1500
+ unitId: "M001/S01/T01",
1501
+ failureClass: "execution",
1502
+ });
1503
+ });
1504
+
1505
+ test("crash lock records session file from AFTER newSession, not before (#1710)", async (t) => {
1506
+ _resetPendingResolve();
1507
+
1508
+ const ctx = makeMockCtx();
1509
+ ctx.ui.setStatus = () => {};
1510
+
1511
+ // Simulate newSession changing the session file path.
1512
+ // newSession() in runUnit changes the underlying session, so getSessionFile
1513
+ // returns a different path after newSession completes.
1514
+ let currentSessionFile = "/tmp/old-session.json";
1515
+ ctx.sessionManager = {
1516
+ getSessionFile: () => currentSessionFile,
1517
+ };
1518
+ const pi = makeMockPi();
1519
+
1520
+ const s = makeLoopSession({
1521
+ cmdCtx: {
1522
+ newSession: () => {
1523
+ // When newSession completes, the session file changes
1524
+ currentSessionFile = "/tmp/new-session-after-newSession.json";
1525
+ return Promise.resolve({ cancelled: false });
1526
+ },
1527
+ getContextUsage: () => ({ percent: 10, tokens: 1000, limit: 10000 }),
1528
+ },
1529
+ });
1530
+
1531
+ // Track all writeLock calls with their sessionFile argument
1532
+ const writeLockCalls: { sessionFile: string | undefined }[] = [];
1533
+ const updateSessionLockCalls: { sessionFile: string | undefined }[] = [];
1534
+
1535
+ const deps = makeMockDeps({
1536
+ deriveState: async () => {
1537
+ deps.callLog.push("deriveState");
1538
+ return {
1539
+ phase: "executing",
1540
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
1541
+ activeSlice: { id: "S01", title: "Slice 1" },
1542
+ activeTask: { id: "T01" },
1543
+ registry: [{ id: "M001", status: "active" }],
1033
1544
  blockers: [],
1034
1545
  } as any;
1035
1546
  },
@@ -1101,86 +1612,152 @@ test("crash lock records session file from AFTER newSession, not before (#1710)"
1101
1612
 
1102
1613
  test("autoLoop handles verification retry by continuing loop", async (t) => {
1103
1614
  _resetPendingResolve();
1615
+ mock.timers.enable({ apis: ["Date", "setTimeout"], now: 10_000 });
1104
1616
 
1105
- const ctx = makeMockCtx();
1106
- ctx.ui.setStatus = () => {};
1107
- ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
1108
- const pi = makeMockPi();
1617
+ try {
1618
+ const ctx = makeMockCtx();
1619
+ ctx.ui.setStatus = () => {};
1620
+ ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
1621
+ const pi = makeMockPi();
1109
1622
 
1110
- let verifyCallCount = 0;
1111
- let deriveCallCount = 0;
1112
- const s = makeLoopSession();
1623
+ let verifyCallCount = 0;
1624
+ let deriveCallCount = 0;
1625
+ const s = makeLoopSession();
1113
1626
 
1114
- // Pre-queued verification actions: each entry provides a side-effect + return value
1115
- type VerifyAction = { sideEffect?: () => void; response: "retry" | "continue" };
1116
- const verificationActions: VerifyAction[] = [
1117
- {
1118
- sideEffect: () => {
1119
- // Simulate retry — set pendingVerificationRetry on session
1627
+ // Pre-queued verification actions: each entry provides a side-effect + return value
1628
+ type VerifyAction = { sideEffect?: () => void; response: "retry" | "continue" };
1629
+ const verificationActions: VerifyAction[] = [
1630
+ {
1631
+ sideEffect: () => {
1632
+ // Simulate retry — set pendingVerificationRetry on session
1633
+ s.pendingVerificationRetry = {
1634
+ unitId: "M001/S01/T01",
1635
+ failureContext: "test failed: expected X got Y",
1636
+ attempt: 1,
1637
+ };
1638
+ },
1639
+ response: "retry",
1640
+ },
1641
+ { response: "continue" },
1642
+ ];
1643
+
1644
+ const deps = makeMockDeps({
1645
+ deriveState: async () => {
1646
+ deriveCallCount++;
1647
+ deps.callLog.push("deriveState");
1648
+ return {
1649
+ phase: "executing",
1650
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
1651
+ activeSlice: { id: "S01", title: "Slice 1" },
1652
+ activeTask: { id: "T01" },
1653
+ registry: [{ id: "M001", status: "active" }],
1654
+ blockers: [],
1655
+ } as any;
1656
+ },
1657
+ runPostUnitVerification: async () => {
1658
+ const action = verificationActions[verifyCallCount] ?? { response: "continue" as const };
1659
+ verifyCallCount++;
1660
+ deps.callLog.push("runPostUnitVerification");
1661
+ action.sideEffect?.();
1662
+ return action.response;
1663
+ },
1664
+ postUnitPostVerification: async () => {
1665
+ deps.callLog.push("postUnitPostVerification");
1666
+ // After the retry cycle completes, deactivate
1667
+ s.active = false;
1668
+ return "continue" as const;
1669
+ },
1670
+ });
1671
+
1672
+ const loopPromise = autoLoop(ctx, pi, s, deps);
1673
+
1674
+ // First iteration: runUnit → verification returns "retry" → loop continues
1675
+ await waitForMicrotasks(() => pi.calls.length === 1, "first dispatch");
1676
+ resolveAgentEnd(makeEvent()); // resolve first unit
1677
+
1678
+ await drainMicrotasks(100);
1679
+ mock.timers.tick(30_000);
1680
+ await waitForMicrotasks(() => pi.calls.length === 2, "retry dispatch");
1681
+ resolveAgentEnd(makeEvent()); // resolve retry unit
1682
+
1683
+ await loopPromise;
1684
+
1685
+ // Verify deriveState was called twice (two iterations)
1686
+ const deriveCount = deps.callLog.filter((c) => c === "deriveState").length;
1687
+ assert.ok(
1688
+ deriveCount >= 2,
1689
+ `deriveState should be called at least 2 times (got ${deriveCount})`,
1690
+ );
1691
+
1692
+ // Verify verification was called twice
1693
+ assert.equal(
1694
+ verifyCallCount,
1695
+ 2,
1696
+ "verification should have been called twice (once retry, once pass)",
1697
+ );
1698
+ } finally {
1699
+ mock.timers.reset();
1700
+ }
1701
+ });
1702
+
1703
+ test("autoLoop pauses instead of redispatching identical verification failure context", async () => {
1704
+ _resetPendingResolve();
1705
+ mock.timers.enable({ apis: ["Date", "setTimeout"], now: 15_000 });
1706
+
1707
+ try {
1708
+ const ctx = makeMockCtx();
1709
+ ctx.ui.setStatus = () => {};
1710
+ ctx.ui.notify = () => {};
1711
+ ctx.sessionManager = { getSessionFile: () => "/tmp/session.json" };
1712
+ const pi = makeMockPi();
1713
+ const s = makeLoopSession();
1714
+ let verifyCallCount = 0;
1715
+ let pauseCallCount = 0;
1716
+
1717
+ const deps = makeMockDeps({
1718
+ deriveState: async () =>
1719
+ ({
1720
+ phase: "executing",
1721
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
1722
+ activeSlice: { id: "S01", title: "Slice 1" },
1723
+ activeTask: { id: "T01" },
1724
+ registry: [{ id: "M001", status: "active" }],
1725
+ blockers: [],
1726
+ }) as any,
1727
+ runPostUnitVerification: async () => {
1728
+ verifyCallCount++;
1729
+ deps.callLog.push("runPostUnitVerification");
1120
1730
  s.pendingVerificationRetry = {
1121
1731
  unitId: "M001/S01/T01",
1122
1732
  failureContext: "test failed: expected X got Y",
1123
- attempt: 1,
1733
+ attempt: verifyCallCount,
1124
1734
  };
1735
+ return "retry" as const;
1125
1736
  },
1126
- response: "retry",
1127
- },
1128
- { response: "continue" },
1129
- ];
1130
-
1131
- const deps = makeMockDeps({
1132
- deriveState: async () => {
1133
- deriveCallCount++;
1134
- deps.callLog.push("deriveState");
1135
- return {
1136
- phase: "executing",
1137
- activeMilestone: { id: "M001", title: "Test", status: "active" },
1138
- activeSlice: { id: "S01", title: "Slice 1" },
1139
- activeTask: { id: "T01" },
1140
- registry: [{ id: "M001", status: "active" }],
1141
- blockers: [],
1142
- } as any;
1143
- },
1144
- runPostUnitVerification: async () => {
1145
- const action = verificationActions[verifyCallCount] ?? { response: "continue" as const };
1146
- verifyCallCount++;
1147
- deps.callLog.push("runPostUnitVerification");
1148
- action.sideEffect?.();
1149
- return action.response;
1150
- },
1151
- postUnitPostVerification: async () => {
1152
- deps.callLog.push("postUnitPostVerification");
1153
- // After the retry cycle completes, deactivate
1154
- s.active = false;
1155
- return "continue" as const;
1156
- },
1157
- });
1158
-
1159
- const loopPromise = autoLoop(ctx, pi, s, deps);
1737
+ pauseAuto: async () => {
1738
+ pauseCallCount++;
1739
+ s.active = false;
1740
+ },
1741
+ });
1160
1742
 
1161
- // First iteration: runUnit verification returns "retry" → loop continues
1162
- await new Promise((r) => setTimeout(r, 50));
1163
- resolveAgentEnd(makeEvent()); // resolve first unit
1743
+ const loopPromise = autoLoop(ctx, pi, s, deps);
1164
1744
 
1165
- // Second iteration: runUnit verification returns "continue"
1166
- await new Promise((r) => setTimeout(r, 50));
1167
- resolveAgentEnd(makeEvent()); // resolve retry unit
1745
+ await waitForMicrotasks(() => pi.calls.length === 1, "first dispatch");
1746
+ resolveAgentEnd(makeEvent());
1747
+ await drainMicrotasks(100);
1748
+ mock.timers.tick(30_000);
1168
1749
 
1169
- await loopPromise;
1750
+ await waitForMicrotasks(() => pi.calls.length === 2, "retry dispatch");
1751
+ resolveAgentEnd(makeEvent());
1170
1752
 
1171
- // Verify deriveState was called twice (two iterations)
1172
- const deriveCount = deps.callLog.filter((c) => c === "deriveState").length;
1173
- assert.ok(
1174
- deriveCount >= 2,
1175
- `deriveState should be called at least 2 times (got ${deriveCount})`,
1176
- );
1753
+ await loopPromise;
1177
1754
 
1178
- // Verify verification was called twice
1179
- assert.equal(
1180
- verifyCallCount,
1181
- 2,
1182
- "verification should have been called twice (once retry, once pass)",
1183
- );
1755
+ assert.equal(verifyCallCount, 2);
1756
+ assert.equal(pi.calls.length, 2, "duplicate failure should not be redispatched a third time");
1757
+ assert.equal(pauseCallCount, 1, "duplicate failure should pause auto-mode");
1758
+ } finally {
1759
+ mock.timers.reset();
1760
+ }
1184
1761
  });
1185
1762
 
1186
1763
  test("autoLoop handles dispatch stop action", async (t) => {
@@ -1336,7 +1913,7 @@ test("autoLoop drains sidecar queue after postUnitPostVerification enqueues item
1336
1913
  // First call (main unit): enqueue a sidecar item
1337
1914
  s.sidecarQueue.push({
1338
1915
  kind: "hook" as const,
1339
- unitType: "hook/review",
1916
+ unitType: "run-uat",
1340
1917
  unitId: "M001/S01/T01/review",
1341
1918
  prompt: "review the code",
1342
1919
  });
@@ -1358,11 +1935,17 @@ test("autoLoop drains sidecar queue after postUnitPostVerification enqueues item
1358
1935
  const loopPromise = autoLoop(ctx, pi, s, deps);
1359
1936
 
1360
1937
  // Wait for main unit's runUnit to be awaiting
1361
- await new Promise((r) => setTimeout(r, 50));
1938
+ for (let i = 0; !_hasPendingResolveForTest() && i < 100; i++) {
1939
+ await new Promise((r) => setTimeout(r, 5));
1940
+ }
1941
+ assert.equal(_hasPendingResolveForTest(), true, "main unit should be awaiting agent_end");
1362
1942
  resolveAgentEnd(makeEvent()); // resolve main unit
1363
1943
 
1364
1944
  // Wait for the sidecar unit's runUnit to be awaiting
1365
- await new Promise((r) => setTimeout(r, 50));
1945
+ for (let i = 0; !_hasPendingResolveForTest() && postVerCallCount < 2 && i < 100; i++) {
1946
+ await new Promise((r) => setTimeout(r, 5));
1947
+ }
1948
+ assert.equal(_hasPendingResolveForTest(), true, "sidecar unit should be awaiting agent_end");
1366
1949
  resolveAgentEnd(makeEvent()); // resolve sidecar unit
1367
1950
 
1368
1951
  await loopPromise;
@@ -1563,74 +2146,83 @@ test("stuck detection: window resets recovery when deriveState returns a differe
1563
2146
 
1564
2147
  test("stuck detection: does not push to window during verification retry", async () => {
1565
2148
  _resetPendingResolve();
2149
+ mock.timers.enable({ apis: ["Date", "setTimeout"], now: 20_000 });
1566
2150
 
1567
- const ctx = makeMockCtx();
1568
- ctx.ui.setStatus = () => {};
1569
- ctx.ui.notify = () => {};
1570
- const pi = makeMockPi();
1571
- const s = makeLoopSession();
2151
+ try {
2152
+ const ctx = makeMockCtx();
2153
+ ctx.ui.setStatus = () => {};
2154
+ ctx.ui.notify = () => {};
2155
+ const pi = makeMockPi();
2156
+ const s = makeLoopSession();
1572
2157
 
1573
- let verifyCallCount = 0;
1574
- let stopReason = "";
2158
+ let verifyCallCount = 0;
2159
+ let stopReason = "";
1575
2160
 
1576
- // Pre-queued responses: 3 retries then a continue (exit)
1577
- const verifyActions: Array<() => "retry" | "continue"> = [
1578
- () => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed", attempt: 1 }; return "retry"; },
1579
- () => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed", attempt: 2 }; return "retry"; },
1580
- () => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed", attempt: 3 }; return "retry"; },
1581
- () => { s.active = false; return "continue"; },
1582
- ];
2161
+ // Pre-queued responses: 3 retries then a continue (exit). Failure
2162
+ // contexts differ so this test exercises stuck-window behavior without
2163
+ // tripping duplicate-failure suppression.
2164
+ const verifyActions: Array<() => "retry" | "continue"> = [
2165
+ () => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed: 1", attempt: 1 }; return "retry"; },
2166
+ () => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed: 2", attempt: 2 }; return "retry"; },
2167
+ () => { s.pendingVerificationRetry = { unitId: "M001/S01/T01", failureContext: "test failed: 3", attempt: 3 }; return "retry"; },
2168
+ () => { s.active = false; return "continue"; },
2169
+ ];
1583
2170
 
1584
- const deps = makeMockDeps({
1585
- deriveState: async () =>
1586
- ({
1587
- phase: "executing",
1588
- activeMilestone: { id: "M001", title: "Test", status: "active" },
1589
- activeSlice: { id: "S01", title: "Slice 1" },
1590
- activeTask: { id: "T01" },
1591
- registry: [{ id: "M001", status: "active" }],
1592
- blockers: [],
1593
- }) as any,
1594
- resolveDispatch: async () => ({
1595
- action: "dispatch" as const,
1596
- unitType: "execute-task",
1597
- unitId: "M001/S01/T01",
1598
- prompt: "do the thing",
1599
- }),
1600
- runPostUnitVerification: async () => {
1601
- const action = verifyActions[verifyCallCount] ?? (() => { s.active = false; return "continue" as const; });
1602
- verifyCallCount++;
1603
- deps.callLog.push("runPostUnitVerification");
1604
- return action();
1605
- },
1606
- stopAuto: async (_ctx?: any, _pi?: any, reason?: string) => {
1607
- deps.callLog.push("stopAuto");
1608
- stopReason = reason ?? "";
1609
- s.active = false;
1610
- },
1611
- });
2171
+ const deps = makeMockDeps({
2172
+ deriveState: async () =>
2173
+ ({
2174
+ phase: "executing",
2175
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
2176
+ activeSlice: { id: "S01", title: "Slice 1" },
2177
+ activeTask: { id: "T01" },
2178
+ registry: [{ id: "M001", status: "active" }],
2179
+ blockers: [],
2180
+ }) as any,
2181
+ resolveDispatch: async () => ({
2182
+ action: "dispatch" as const,
2183
+ unitType: "execute-task",
2184
+ unitId: "M001/S01/T01",
2185
+ prompt: "do the thing",
2186
+ }),
2187
+ runPostUnitVerification: async () => {
2188
+ const action = verifyActions[verifyCallCount] ?? (() => { s.active = false; return "continue" as const; });
2189
+ verifyCallCount++;
2190
+ deps.callLog.push("runPostUnitVerification");
2191
+ return action();
2192
+ },
2193
+ stopAuto: async (_ctx?: any, _pi?: any, reason?: string) => {
2194
+ deps.callLog.push("stopAuto");
2195
+ stopReason = reason ?? "";
2196
+ s.active = false;
2197
+ },
2198
+ });
1612
2199
 
1613
- const loopPromise = autoLoop(ctx, pi, s, deps);
2200
+ const loopPromise = autoLoop(ctx, pi, s, deps);
1614
2201
 
1615
- // Resolve agent_end for 4 iterations (1 initial + 3 retries)
1616
- for (let i = 0; i < 4; i++) {
1617
- await new Promise((r) => setTimeout(r, 30));
1618
- resolveAgentEnd(makeEvent());
1619
- }
2202
+ // Resolve agent_end for 4 iterations (1 initial + 3 retries)
2203
+ for (let i = 1; i <= 4; i++) {
2204
+ await waitForMicrotasks(() => pi.calls.length === i, `dispatch ${i}`);
2205
+ resolveAgentEnd(makeEvent());
2206
+ await drainMicrotasks(100);
2207
+ mock.timers.tick(30_000);
2208
+ }
1620
2209
 
1621
- await loopPromise;
2210
+ await loopPromise;
1622
2211
 
1623
- // Even though same unit was derived 4 times, verification retries should
1624
- // not push to the sliding window, so stuck detection should not have fired
1625
- assert.ok(
1626
- !stopReason.includes("Stuck"),
1627
- `stuck detection should not fire during verification retries, got: ${stopReason}`,
1628
- );
1629
- assert.equal(
1630
- verifyCallCount,
1631
- 4,
1632
- "verification should have been called 4 times (1 initial + 3 retries)",
1633
- );
2212
+ // Even though same unit was derived 4 times, verification retries should
2213
+ // not push to the sliding window, so stuck detection should not have fired
2214
+ assert.ok(
2215
+ !stopReason.includes("Stuck"),
2216
+ `stuck detection should not fire during verification retries, got: ${stopReason}`,
2217
+ );
2218
+ assert.equal(
2219
+ verifyCallCount,
2220
+ 4,
2221
+ "verification should have been called 4 times (1 initial + 3 retries)",
2222
+ );
2223
+ } finally {
2224
+ mock.timers.reset();
2225
+ }
1634
2226
  });
1635
2227
 
1636
2228
  // ── detectStuck unit tests ────────────────────────────────────────────────────
@@ -1781,7 +2373,7 @@ test("autoLoop lifecycle: advances through research → plan → execute → ver
1781
2373
  { unitType: "research-slice", unitId: "M001/S01", prompt: "research" },
1782
2374
  { unitType: "plan-slice", unitId: "M001/S01", prompt: "plan" },
1783
2375
  { unitType: "execute-task", unitId: "M001/S01/T01", prompt: "execute" },
1784
- { unitType: "verify-slice", unitId: "M001/S01", prompt: "verify" },
2376
+ { unitType: "run-uat", unitId: "M001/S01", prompt: "verify" },
1785
2377
  { unitType: "complete-slice", unitId: "M001/S01", prompt: "complete" },
1786
2378
  ];
1787
2379
 
@@ -1851,8 +2443,8 @@ test("autoLoop lifecycle: advances through research → plan → execute → ver
1851
2443
  `should have dispatched execute-task, got: ${dispatchedUnitTypes.join(", ")}`,
1852
2444
  );
1853
2445
  assert.ok(
1854
- dispatchedUnitTypes.includes("verify-slice"),
1855
- `should have dispatched verify-slice, got: ${dispatchedUnitTypes.join(", ")}`,
2446
+ dispatchedUnitTypes.includes("run-uat"),
2447
+ `should have dispatched run-uat, got: ${dispatchedUnitTypes.join(", ")}`,
1856
2448
  );
1857
2449
  assert.ok(
1858
2450
  dispatchedUnitTypes.includes("complete-slice"),
@@ -1884,7 +2476,7 @@ test("autoLoop lifecycle: advances through research → plan → execute → ver
1884
2476
  "research-slice",
1885
2477
  "plan-slice",
1886
2478
  "execute-task",
1887
- "verify-slice",
2479
+ "run-uat",
1888
2480
  "complete-slice",
1889
2481
  ],
1890
2482
  "dispatched unit types should follow the full lifecycle sequence",
@@ -1956,6 +2548,108 @@ test("resolveAgentEndCancelled with errorContext passes it through to resolved p
1956
2548
  assert.equal(resolved.errorContext!.isTransient, true);
1957
2549
  });
1958
2550
 
2551
+ test("runUnitPhase pauses ghost completions before closeout and finalize side effects", async (t) => {
2552
+ _resetPendingResolve();
2553
+
2554
+ const basePath = mkdtempSync(join(tmpdir(), "gsd-ghost-completion-"));
2555
+ t.after(() => {
2556
+ _resetPendingResolve();
2557
+ rmSync(basePath, { recursive: true, force: true });
2558
+ });
2559
+
2560
+ let closeoutCalls = 0;
2561
+ let preVerificationCalls = 0;
2562
+ let postVerificationCalls = 0;
2563
+ const journalEvents: any[] = [];
2564
+ const deps = makeMockDeps({
2565
+ closeoutUnit: async () => {
2566
+ closeoutCalls++;
2567
+ },
2568
+ postUnitPreVerification: async () => {
2569
+ preVerificationCalls++;
2570
+ return "continue";
2571
+ },
2572
+ postUnitPostVerification: async () => {
2573
+ postVerificationCalls++;
2574
+ return "continue";
2575
+ },
2576
+ emitJournalEvent: (event: any) => {
2577
+ journalEvents.push(event);
2578
+ },
2579
+ });
2580
+ const ctx = {
2581
+ ...makeMockCtx(),
2582
+ ui: {
2583
+ notify: () => {},
2584
+ setStatus: () => {},
2585
+ setWorkingMessage: () => {},
2586
+ },
2587
+ sessionManager: {
2588
+ getEntries: () => [],
2589
+ },
2590
+ modelRegistry: {
2591
+ getProviderAuthMode: () => undefined,
2592
+ isProviderRequestReady: () => true,
2593
+ },
2594
+ } as any;
2595
+ const pi = {
2596
+ ...makeMockPi(),
2597
+ sendMessage: () => {
2598
+ queueMicrotask(() => resolveAgentEnd({ messages: [] }));
2599
+ },
2600
+ } as any;
2601
+ const s = makeLoopSession({
2602
+ basePath,
2603
+ canonicalProjectRoot: basePath,
2604
+ originalBasePath: basePath,
2605
+ });
2606
+ let seq = 0;
2607
+
2608
+ const result = await runUnitPhase(
2609
+ { ctx, pi, s, deps, prefs: undefined, iteration: 1, flowId: "flow-ghost", nextSeq: () => ++seq },
2610
+ {
2611
+ unitType: "execute-task",
2612
+ unitId: "M001/S01/T01",
2613
+ prompt: "do work",
2614
+ finalPrompt: "do work",
2615
+ pauseAfterUatDispatch: false,
2616
+ state: {
2617
+ phase: "executing",
2618
+ activeMilestone: { id: "M001", title: "Milestone" },
2619
+ activeSlice: { id: "S01", title: "Slice" },
2620
+ activeTask: { id: "T01", title: "Task" },
2621
+ registry: [{ id: "M001", title: "Milestone", status: "active" }],
2622
+ recentDecisions: [],
2623
+ blockers: [],
2624
+ nextAction: "",
2625
+ progress: { milestones: { done: 0, total: 1 } },
2626
+ requirements: { active: 0, validated: 0, deferred: 0, outOfScope: 0, blocked: 0, total: 0 },
2627
+ } as any,
2628
+ mid: "M001",
2629
+ midTitle: "Milestone",
2630
+ isRetry: false,
2631
+ previousTier: undefined,
2632
+ },
2633
+ { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 },
2634
+ );
2635
+
2636
+ assert.equal(result.action, "break");
2637
+ assert.equal((result as any).reason, "ghost-completion");
2638
+ assert.equal(deps.callLog.includes("pauseAuto"), true);
2639
+ assert.equal(closeoutCalls, 0);
2640
+ assert.equal(preVerificationCalls, 0);
2641
+ assert.equal(postVerificationCalls, 0);
2642
+ assert.equal(s.currentUnit, null);
2643
+ assert.ok(
2644
+ journalEvents.some((event) =>
2645
+ event.eventType === "unit-end" &&
2646
+ event.data?.status === "cancelled" &&
2647
+ event.data?.errorContext?.message.includes("stale ghost completion")
2648
+ ),
2649
+ "ghost completion should emit a cancelled unit-end",
2650
+ );
2651
+ });
2652
+
1959
2653
  test("resolveAgentEndCancelled without args produces no errorContext field", async () => {
1960
2654
  _resetPendingResolve();
1961
2655
 
@@ -1972,64 +2666,110 @@ test("resolveAgentEndCancelled without args produces no errorContext field", asy
1972
2666
  assert.equal(resolved.errorContext, undefined, "errorContext must not be present when no args passed");
1973
2667
  });
1974
2668
 
2669
+ test("resolveAgentEndCancelled queues cancellation that arrives during session switch", () => {
2670
+ _resetPendingResolve();
2671
+
2672
+ _setSessionSwitchInFlight(true);
2673
+ const resolved = resolveAgentEndCancelled({
2674
+ message: "Claude Code process aborted by user",
2675
+ category: "aborted",
2676
+ isTransient: false,
2677
+ });
2678
+
2679
+ assert.equal(resolved, false);
2680
+ const pending = _consumePendingSwitchCancellation();
2681
+ assert.ok(pending?.errorContext, "queued cancellation should preserve errorContext");
2682
+ assert.equal(pending.errorContext.category, "aborted");
2683
+ assert.equal(pending.errorContext.message, "Claude Code process aborted by user");
2684
+ assert.equal(_consumePendingSwitchCancellation(), null);
2685
+ _resetPendingResolve();
2686
+ });
2687
+
2688
+ test("session-switch abort grace window is short-lived and resettable", () => {
2689
+ _resetPendingResolve();
2690
+
2691
+ _markSessionSwitchAbortGraceWindow(1_000);
2692
+
2693
+ assert.equal(isSessionSwitchAbortGraceActive(Date.now()), true);
2694
+ assert.equal(isSessionSwitchAbortGraceActive(Date.now() + 10_000), false);
2695
+
2696
+ _clearSessionSwitchAbortGraceWindow();
2697
+ assert.equal(isSessionSwitchAbortGraceActive(), false);
2698
+ });
2699
+
1975
2700
  // ─── #1571: artifact verification retry ──────────────────────────────────────
1976
2701
 
1977
2702
  test("autoLoop re-iterates when postUnitPreVerification returns retry (#1571)", async () => {
1978
2703
  _resetPendingResolve();
2704
+ mock.timers.enable({ apis: ["Date", "setTimeout"], now: 30_000 });
1979
2705
 
1980
- const ctx = makeMockCtx();
1981
- ctx.ui.setStatus = () => {};
1982
- const pi = makeMockPi();
1983
- const s = makeLoopSession();
2706
+ try {
2707
+ const ctx = makeMockCtx();
2708
+ ctx.ui.setStatus = () => {};
2709
+ const pi = makeMockPi();
2710
+ const s = makeLoopSession();
1984
2711
 
1985
- let preVerifyCallCount = 0;
1986
- // Pre-queued responses: first call returns "retry", second returns "continue"
1987
- const preVerifyResponses = ["retry", "continue"] as const;
2712
+ let preVerifyCallCount = 0;
2713
+ // Pre-queued responses: first call returns "retry", second returns "continue"
2714
+ const preVerifyResponses = ["retry", "continue"] as const;
1988
2715
 
1989
- const deps = makeMockDeps({
1990
- deriveState: async () => {
1991
- deps.callLog.push("deriveState");
1992
- return {
1993
- phase: "executing",
1994
- activeMilestone: { id: "M001", title: "Test", status: "active" },
1995
- activeSlice: { id: "S01", title: "Slice 1" },
1996
- activeTask: { id: "T01" },
1997
- registry: [{ id: "M001", status: "active" }],
1998
- blockers: [],
1999
- } as any;
2000
- },
2001
- postUnitPreVerification: async () => {
2002
- deps.callLog.push("postUnitPreVerification");
2003
- return preVerifyResponses[preVerifyCallCount++] ?? "continue";
2004
- },
2005
- postUnitPostVerification: async () => {
2006
- deps.callLog.push("postUnitPostVerification");
2007
- s.active = false;
2008
- return "continue" as const;
2009
- },
2010
- });
2716
+ const deps = makeMockDeps({
2717
+ deriveState: async () => {
2718
+ deps.callLog.push("deriveState");
2719
+ return {
2720
+ phase: "executing",
2721
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
2722
+ activeSlice: { id: "S01", title: "Slice 1" },
2723
+ activeTask: { id: "T01" },
2724
+ registry: [{ id: "M001", status: "active" }],
2725
+ blockers: [],
2726
+ } as any;
2727
+ },
2728
+ postUnitPreVerification: async () => {
2729
+ deps.callLog.push("postUnitPreVerification");
2730
+ const response = preVerifyResponses[preVerifyCallCount++] ?? "continue";
2731
+ if (response === "retry") {
2732
+ s.pendingVerificationRetry = {
2733
+ unitId: "M001/S01/T01",
2734
+ failureContext: "missing artifact",
2735
+ attempt: 1,
2736
+ };
2737
+ }
2738
+ return response;
2739
+ },
2740
+ postUnitPostVerification: async () => {
2741
+ deps.callLog.push("postUnitPostVerification");
2742
+ s.active = false;
2743
+ return "continue" as const;
2744
+ },
2745
+ });
2011
2746
 
2012
- const loopPromise = autoLoop(ctx, pi, s, deps);
2747
+ const loopPromise = autoLoop(ctx, pi, s, deps);
2013
2748
 
2014
- await new Promise((r) => setTimeout(r, 50));
2015
- resolveAgentEnd(makeEvent());
2749
+ await waitForMicrotasks(() => pi.calls.length === 1, "first dispatch");
2750
+ resolveAgentEnd(makeEvent());
2016
2751
 
2017
- await new Promise((r) => setTimeout(r, 50));
2018
- resolveAgentEnd(makeEvent());
2752
+ await drainMicrotasks(100);
2753
+ mock.timers.tick(30_000);
2754
+ await waitForMicrotasks(() => pi.calls.length === 2, "retry dispatch");
2755
+ resolveAgentEnd(makeEvent());
2019
2756
 
2020
- await loopPromise;
2757
+ await loopPromise;
2021
2758
 
2022
- assert.equal(preVerifyCallCount, 2, "preVerification should be called twice");
2759
+ assert.equal(preVerifyCallCount, 2, "preVerification should be called twice");
2023
2760
 
2024
- const postVerifyCalls = deps.callLog.filter(
2025
- (c: string) => c === "runPostUnitVerification",
2026
- );
2027
- const postPostVerifyCalls = deps.callLog.filter(
2028
- (c: string) => c === "postUnitPostVerification",
2029
- );
2761
+ const postVerifyCalls = deps.callLog.filter(
2762
+ (c: string) => c === "runPostUnitVerification",
2763
+ );
2764
+ const postPostVerifyCalls = deps.callLog.filter(
2765
+ (c: string) => c === "postUnitPostVerification",
2766
+ );
2030
2767
 
2031
- assert.equal(postVerifyCalls.length, 1, "runPostUnitVerification should only be called once");
2032
- assert.equal(postPostVerifyCalls.length, 1, "postUnitPostVerification should only be called once");
2768
+ assert.equal(postVerifyCalls.length, 1, "runPostUnitVerification should only be called once");
2769
+ assert.equal(postPostVerifyCalls.length, 1, "postUnitPostVerification should only be called once");
2770
+ } finally {
2771
+ mock.timers.reset();
2772
+ }
2033
2773
  });
2034
2774
 
2035
2775
  // ─── stopAuto unitPromise leak regression (#1799) ────────────────────────────
@@ -2348,7 +3088,7 @@ test("autoLoop rejects complete-slice with 0 tool calls as context-exhausted (#2
2348
3088
 
2349
3089
  // ─── Worktree health check (#1833) ────────────────────────────────────────
2350
3090
 
2351
- test("autoLoop stops when worktree has no .git for execute-task (#1833)", async () => {
3091
+ test("autoLoop stops when Worktree Safety finds no .git marker for execute-task (#1833)", async (t) => {
2352
3092
  _resetPendingResolve();
2353
3093
 
2354
3094
  const ctx = makeMockCtx();
@@ -2359,7 +3099,16 @@ test("autoLoop stops when worktree has no .git for execute-task (#1833)", async
2359
3099
  const notifications: string[] = [];
2360
3100
  ctx.ui.notify = (msg: string) => { notifications.push(msg); };
2361
3101
 
2362
- const s = makeLoopSession({ basePath: "/tmp/broken-worktree" });
3102
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-loop-"));
3103
+ const worktreeRoot = join(projectRoot, ".gsd", "worktrees", "M001");
3104
+ mkdirSync(worktreeRoot, { recursive: true });
3105
+ t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
3106
+
3107
+ const s = makeLoopSession({
3108
+ basePath: worktreeRoot,
3109
+ originalBasePath: projectRoot,
3110
+ canonicalProjectRoot: projectRoot,
3111
+ });
2363
3112
 
2364
3113
  const deps = makeMockDeps({
2365
3114
  deriveState: async () => {
@@ -2373,8 +3122,7 @@ test("autoLoop stops when worktree has no .git for execute-task (#1833)", async
2373
3122
  blockers: [],
2374
3123
  } as any;
2375
3124
  },
2376
- // .git does not exist in the broken worktree
2377
- existsSync: (p: string) => !p.endsWith(".git"),
3125
+ getIsolationMode: () => "worktree",
2378
3126
  });
2379
3127
 
2380
3128
  await autoLoop(ctx, pi, s, deps);
@@ -2384,11 +3132,283 @@ test("autoLoop stops when worktree has no .git for execute-task (#1833)", async
2384
3132
  "should stop auto-mode when worktree is invalid",
2385
3133
  );
2386
3134
  const healthNotification = notifications.find(
2387
- (n) => n.includes("Worktree health check failed") && n.includes("no .git"),
3135
+ (n) => n.includes("Worktree Safety failed") && n.includes("worktree-git-marker-missing"),
2388
3136
  );
2389
3137
  assert.ok(
2390
3138
  healthNotification,
2391
- "should notify about missing .git in worktree",
3139
+ "should notify about missing worktree .git marker",
3140
+ );
3141
+ });
3142
+
3143
+ test("dispatch Worktree Safety wins before stuck detection for execute-task without .git", async (t) => {
3144
+ _resetPendingResolve();
3145
+
3146
+ const ctx = makeMockCtx();
3147
+ const pi = makeMockPi();
3148
+ const notifications: string[] = [];
3149
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
3150
+
3151
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-dispatch-"));
3152
+ const worktreeRoot = join(projectRoot, ".gsd", "worktrees", "M001");
3153
+ mkdirSync(worktreeRoot, { recursive: true });
3154
+ t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
3155
+
3156
+ const s = makeLoopSession({
3157
+ basePath: worktreeRoot,
3158
+ originalBasePath: projectRoot,
3159
+ canonicalProjectRoot: projectRoot,
3160
+ });
3161
+ const deps = makeMockDeps({
3162
+ getIsolationMode: () => "worktree",
3163
+ });
3164
+ const result = await runDispatch(
3165
+ {
3166
+ ctx,
3167
+ pi,
3168
+ s,
3169
+ deps,
3170
+ prefs: undefined,
3171
+ iteration: 1,
3172
+ flowId: "test-flow",
3173
+ nextSeq: () => 1,
3174
+ },
3175
+ {
3176
+ state: {
3177
+ phase: "executing",
3178
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
3179
+ activeSlice: { id: "S01", title: "Slice 1" },
3180
+ activeTask: { id: "T01" },
3181
+ registry: [{ id: "M001", status: "active" }],
3182
+ blockers: [],
3183
+ } as any,
3184
+ mid: "M001",
3185
+ midTitle: "Test",
3186
+ },
3187
+ {
3188
+ recentUnits: [
3189
+ { key: "execute-task/M001/S01/T01" },
3190
+ { key: "execute-task/M001/S01/T01" },
3191
+ ],
3192
+ stuckRecoveryAttempts: 1,
3193
+ consecutiveFinalizeTimeouts: 0,
3194
+ },
3195
+ );
3196
+
3197
+ assert.equal(result.action, "break");
3198
+ assert.equal(result.reason, "worktree-git-marker-missing");
3199
+ assert.ok(deps.callLog.includes("stopAuto"), "should stop through Worktree Safety");
3200
+ assert.ok(
3201
+ notifications.some((n) => n.includes("Worktree Safety failed") && n.includes("worktree-git-marker-missing")),
3202
+ "should notify about missing worktree .git marker",
3203
+ );
3204
+ assert.ok(
3205
+ !notifications.some((n) => n.includes("Stuck on execute-task")),
3206
+ "stuck-loop message must not mask the worktree health failure",
3207
+ );
3208
+ });
3209
+
3210
+ test("dispatch Worktree Safety stops unknown unit types with missing Tool Contract", async (t) => {
3211
+ _resetPendingResolve();
3212
+
3213
+ const ctx = makeMockCtx();
3214
+ const pi = makeMockPi();
3215
+ const notifications: string[] = [];
3216
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
3217
+
3218
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-missing-contract-"));
3219
+ const worktreeRoot = join(projectRoot, ".gsd", "worktrees", "M001");
3220
+ mkdirSync(worktreeRoot, { recursive: true });
3221
+ t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
3222
+
3223
+ const s = makeLoopSession({
3224
+ basePath: worktreeRoot,
3225
+ originalBasePath: projectRoot,
3226
+ canonicalProjectRoot: projectRoot,
3227
+ });
3228
+ const deps = makeMockDeps({
3229
+ getIsolationMode: () => "worktree",
3230
+ resolveDispatch: async () => {
3231
+ deps.callLog.push("resolveDispatch");
3232
+ return {
3233
+ action: "dispatch" as const,
3234
+ unitType: "new-source-writing-unit-without-manifest",
3235
+ unitId: "M001/S01/T01",
3236
+ prompt: "do the thing",
3237
+ };
3238
+ },
3239
+ });
3240
+
3241
+ const result = await runDispatch(
3242
+ {
3243
+ ctx,
3244
+ pi,
3245
+ s,
3246
+ deps,
3247
+ prefs: undefined,
3248
+ iteration: 1,
3249
+ flowId: "test-flow",
3250
+ nextSeq: () => 1,
3251
+ },
3252
+ {
3253
+ state: {
3254
+ phase: "executing",
3255
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
3256
+ activeSlice: { id: "S01", title: "Slice 1" },
3257
+ activeTask: { id: "T01" },
3258
+ registry: [{ id: "M001", status: "active" }],
3259
+ blockers: [],
3260
+ } as any,
3261
+ mid: "M001",
3262
+ midTitle: "Test",
3263
+ },
3264
+ {
3265
+ recentUnits: [],
3266
+ stuckRecoveryAttempts: 0,
3267
+ consecutiveFinalizeTimeouts: 0,
3268
+ },
3269
+ );
3270
+
3271
+ assert.equal(result.action, "break");
3272
+ assert.equal(result.reason, "missing-tool-contract");
3273
+ assert.ok(deps.callLog.includes("stopAuto"), "should stop when the Tool Contract is missing");
3274
+ assert.ok(
3275
+ notifications.some((n) => n.includes("missing Tool Contract for new-source-writing-unit-without-manifest")),
3276
+ "should notify with an actionable missing Tool Contract reason",
3277
+ );
3278
+ });
3279
+
3280
+ test("pre-dispatch skip resolves before dispatch health and stuck accounting", async () => {
3281
+ _resetPendingResolve();
3282
+
3283
+ const ctx = makeMockCtx();
3284
+ const pi = makeMockPi();
3285
+ const notifications: string[] = [];
3286
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
3287
+
3288
+ const s = makeLoopSession({ basePath: "/tmp/broken-worktree" });
3289
+ const deps = makeMockDeps({
3290
+ existsSync: (p: string) => !p.endsWith(".git"),
3291
+ runPreDispatchHooks: () => ({ firedHooks: ["skip-execute"], action: "skip" }),
3292
+ });
3293
+ const loopState = {
3294
+ recentUnits: [
3295
+ { key: "execute-task/M001/S01/T01" },
3296
+ { key: "execute-task/M001/S01/T01" },
3297
+ ],
3298
+ stuckRecoveryAttempts: 1,
3299
+ consecutiveFinalizeTimeouts: 0,
3300
+ };
3301
+
3302
+ const result = await runDispatch(
3303
+ {
3304
+ ctx,
3305
+ pi,
3306
+ s,
3307
+ deps,
3308
+ prefs: undefined,
3309
+ iteration: 1,
3310
+ flowId: "test-flow",
3311
+ nextSeq: () => 1,
3312
+ },
3313
+ {
3314
+ state: {
3315
+ phase: "executing",
3316
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
3317
+ activeSlice: { id: "S01", title: "Slice 1" },
3318
+ activeTask: { id: "T01" },
3319
+ registry: [{ id: "M001", status: "active" }],
3320
+ blockers: [],
3321
+ } as any,
3322
+ mid: "M001",
3323
+ midTitle: "Test",
3324
+ },
3325
+ loopState,
3326
+ );
3327
+
3328
+ assert.equal(result.action, "continue");
3329
+ assert.ok(!deps.callLog.includes("stopAuto"), "skip hook should not stop on worktree health");
3330
+ assert.equal(loopState.recentUnits.length, 2, "skip hook should not update stuck accounting");
3331
+ assert.ok(
3332
+ notifications.some((n) => n.includes("Skipping execute-task M001/S01/T01")),
3333
+ "should notify about the skip hook",
3334
+ );
3335
+ assert.ok(
3336
+ !notifications.some((n) => n.includes("Worktree health check failed") || n.includes("Stuck on execute-task")),
3337
+ "health and stuck notifications must not run before skip hook resolution",
3338
+ );
3339
+ });
3340
+
3341
+ test("pre-dispatch replace resolves final unit before dispatch health and stuck accounting", async () => {
3342
+ _resetPendingResolve();
3343
+
3344
+ const ctx = makeMockCtx();
3345
+ const pi = makeMockPi();
3346
+ const notifications: string[] = [];
3347
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
3348
+
3349
+ const s = makeLoopSession({ basePath: "/tmp/broken-worktree" });
3350
+ const deps = makeMockDeps({
3351
+ existsSync: (p: string) => !p.endsWith(".git"),
3352
+ runPreDispatchHooks: () => ({
3353
+ firedHooks: ["review"],
3354
+ action: "replace",
3355
+ unitType: "run-uat",
3356
+ prompt: "review before executing",
3357
+ model: "review-model",
3358
+ }),
3359
+ });
3360
+ const loopState = {
3361
+ recentUnits: [
3362
+ { key: "execute-task/M001/S01/T01" },
3363
+ { key: "execute-task/M001/S01/T01" },
3364
+ ],
3365
+ stuckRecoveryAttempts: 1,
3366
+ consecutiveFinalizeTimeouts: 0,
3367
+ };
3368
+
3369
+ const result = await runDispatch(
3370
+ {
3371
+ ctx,
3372
+ pi,
3373
+ s,
3374
+ deps,
3375
+ prefs: undefined,
3376
+ iteration: 1,
3377
+ flowId: "test-flow",
3378
+ nextSeq: () => 1,
3379
+ },
3380
+ {
3381
+ state: {
3382
+ phase: "executing",
3383
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
3384
+ activeSlice: { id: "S01", title: "Slice 1" },
3385
+ activeTask: { id: "T01" },
3386
+ registry: [{ id: "M001", status: "active" }],
3387
+ blockers: [],
3388
+ } as any,
3389
+ mid: "M001",
3390
+ midTitle: "Test",
3391
+ },
3392
+ loopState,
3393
+ );
3394
+
3395
+ assert.equal(result.action, "next");
3396
+ assert.equal(result.data?.unitType, "run-uat");
3397
+ assert.equal(result.data?.finalPrompt, "review before executing");
3398
+ assert.equal(result.data?.hookModelOverride, "review-model");
3399
+ assert.ok(!deps.callLog.includes("stopAuto"), "replace hook should not stop on execute-task health");
3400
+ assert.deepEqual(
3401
+ loopState.recentUnits.map((u) => u.key),
3402
+ [
3403
+ "execute-task/M001/S01/T01",
3404
+ "execute-task/M001/S01/T01",
3405
+ "run-uat/M001/S01/T01",
3406
+ ],
3407
+ "stuck accounting should record the final replaced unit",
3408
+ );
3409
+ assert.ok(
3410
+ !notifications.some((n) => n.includes("Worktree health check failed") || n.includes("Stuck on execute-task")),
3411
+ "health and stuck notifications must use the final replaced unit",
2392
3412
  );
2393
3413
  });
2394
3414
 
@@ -2439,7 +3459,7 @@ test("autoLoop warns but proceeds for greenfield project (no project files) (#18
2439
3459
  "should not stop with health check failure for greenfield project",
2440
3460
  );
2441
3461
  const greenfieldWarning = notifications.find(
2442
- (n) => n.includes("no recognized project files") && n.includes("greenfield"),
3462
+ (n) => n.includes("no project content yet") && n.includes("greenfield"),
2443
3463
  );
2444
3464
  assert.ok(
2445
3465
  greenfieldWarning,
@@ -2652,6 +3672,13 @@ test("autoLoop classifies ModelPolicyDispatchBlockedError as blocked, not a retr
2652
3672
  );
2653
3673
  assert.ok(unitEnd, "should emit unit-end with status=blocked");
2654
3674
  assert.equal(unitEnd!.data.reason, "model-policy-dispatch-blocked");
3675
+ const unitEndIndex = journalEvents.findIndex(
3676
+ e => e.eventType === "unit-end" && e.data?.status === "blocked",
3677
+ );
3678
+ const iterationEndIndex = journalEvents.findIndex(
3679
+ e => e.eventType === "iteration-end" && e.data?.status === "blocked",
3680
+ );
3681
+ assert.ok(iterationEndIndex > unitEndIndex, "blocked policy iterations must close after unit-end");
2655
3682
 
2656
3683
  // Loop must pause for manual attention, NOT retry until 3-strike hard stop.
2657
3684
  assert.equal(pauseAutoCalls, 1, "should pause once on policy block");