gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.cf9433f56

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 (443) hide show
  1. package/README.md +4 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +2 -2
  4. package/dist/resources/extensions/github-sync/templates.js +39 -8
  5. package/dist/resources/extensions/gsd/auto/loop.js +48 -10
  6. package/dist/resources/extensions/gsd/auto/phases.js +66 -45
  7. package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
  8. package/dist/resources/extensions/gsd/auto/run-unit.js +32 -16
  9. package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
  12. package/dist/resources/extensions/gsd/auto-prompts.js +124 -2
  13. package/dist/resources/extensions/gsd/auto-recovery.js +197 -9
  14. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  15. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  16. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  17. package/dist/resources/extensions/gsd/auto.js +77 -5
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +36 -3
  19. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
  20. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
  21. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
  22. package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
  23. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  24. package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
  25. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  26. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  27. package/dist/resources/extensions/gsd/custom-workflow-engine.js +22 -2
  28. package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
  29. package/dist/resources/extensions/gsd/db-base-schema.js +18 -2
  30. package/dist/resources/extensions/gsd/db-migration-steps.js +22 -0
  31. package/dist/resources/extensions/gsd/detection.js +106 -0
  32. package/dist/resources/extensions/gsd/git-service.js +36 -4
  33. package/dist/resources/extensions/gsd/graph.js +9 -3
  34. package/dist/resources/extensions/gsd/gsd-db.js +146 -13
  35. package/dist/resources/extensions/gsd/guided-flow.js +82 -16
  36. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  37. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  38. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  39. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  40. package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
  41. package/dist/resources/extensions/gsd/pre-execution-checks.js +7 -0
  42. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  43. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
  44. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  46. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  47. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  48. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  49. package/dist/resources/extensions/gsd/quick.js +34 -2
  50. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  51. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  52. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  53. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  54. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  55. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  56. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  57. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  58. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  59. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  60. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  61. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  62. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  63. package/dist/resources/extensions/gsd/worktree-resolver.js +33 -17
  64. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  65. package/dist/web/standalone/.next/BUILD_ID +1 -1
  66. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  67. package/dist/web/standalone/.next/build-manifest.json +3 -3
  68. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  69. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/index.html +1 -1
  88. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  95. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  96. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  99. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  100. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  101. package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
  102. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
  103. package/package.json +12 -8
  104. package/packages/contracts/package.json +1 -1
  105. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  106. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  107. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  108. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  109. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  110. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  111. package/packages/native/tsconfig.tsbuildinfo +1 -1
  112. package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
  113. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  114. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  115. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  116. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  117. package/packages/pi-ai/dist/models/index.js +8 -0
  118. package/packages/pi-ai/dist/models/index.js.map +1 -1
  119. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  120. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  121. package/packages/pi-ai/dist/providers/fake.js +319 -0
  122. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  123. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  124. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  125. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  126. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  127. package/packages/pi-ai/src/models/index.ts +9 -0
  128. package/packages/pi-ai/src/providers/fake.ts +376 -0
  129. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  130. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  131. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
  132. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  133. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
  135. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +76 -0
  137. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  139. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  141. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  143. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  144. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  145. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  146. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  147. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  148. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  149. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  150. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  151. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  152. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  153. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  154. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  155. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/core/extensions/runner.js +17 -1
  157. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +99 -0
  159. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  161. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  165. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +24 -0
  167. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/settings-manager.js +33 -0
  169. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  171. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  172. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
  180. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  181. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  182. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  183. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  185. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  188. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  189. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  191. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  192. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  193. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  194. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
  195. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  196. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +17 -0
  197. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +109 -17
  199. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  201. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +69 -2
  202. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +93 -1
  204. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  205. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
  206. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  207. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  208. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  211. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +26 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  214. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  215. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  216. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  218. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  220. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  222. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  226. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  227. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  229. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  231. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  233. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  234. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  235. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  236. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  237. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  238. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
  239. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  240. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  241. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  242. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  243. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  244. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  245. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  246. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  247. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
  248. package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
  249. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +89 -0
  250. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  251. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  252. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  253. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  254. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +110 -0
  255. package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -1
  256. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  257. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  258. package/packages/pi-coding-agent/src/core/settings-manager.ts +51 -1
  259. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  260. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  261. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
  262. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
  263. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
  264. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  265. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  266. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  267. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
  268. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +122 -17
  269. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +99 -1
  270. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +92 -3
  271. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  272. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  273. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -0
  274. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  275. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  276. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  277. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
  278. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  279. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
  280. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  281. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  282. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  283. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  284. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  285. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  286. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  287. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  288. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  289. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  290. package/packages/pi-tui/dist/index.d.ts +1 -0
  291. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  292. package/packages/pi-tui/dist/index.js +2 -0
  293. package/packages/pi-tui/dist/index.js.map +1 -1
  294. package/packages/pi-tui/dist/style.d.ts +41 -0
  295. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  296. package/packages/pi-tui/dist/style.js +158 -0
  297. package/packages/pi-tui/dist/style.js.map +1 -0
  298. package/packages/pi-tui/dist/tui.d.ts +0 -1
  299. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  300. package/packages/pi-tui/dist/tui.js +21 -16
  301. package/packages/pi-tui/dist/tui.js.map +1 -1
  302. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  303. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  304. package/packages/pi-tui/src/index.ts +9 -0
  305. package/packages/pi-tui/src/style.ts +225 -0
  306. package/packages/pi-tui/src/tui.ts +23 -16
  307. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  308. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  309. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  310. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  311. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  312. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  313. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  314. package/pkg/dist/modes/interactive/theme/theme.js +18 -1
  315. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  316. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  317. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  318. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  319. package/src/resources/GSD-WORKFLOW.md +2 -2
  320. package/src/resources/extensions/github-sync/templates.ts +38 -8
  321. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  322. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  323. package/src/resources/extensions/gsd/auto/loop.ts +67 -18
  324. package/src/resources/extensions/gsd/auto/phases.ts +77 -48
  325. package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
  326. package/src/resources/extensions/gsd/auto/run-unit.ts +42 -15
  327. package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
  328. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
  329. package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
  330. package/src/resources/extensions/gsd/auto-prompts.ts +133 -2
  331. package/src/resources/extensions/gsd/auto-recovery.ts +207 -7
  332. package/src/resources/extensions/gsd/auto-start.ts +7 -6
  333. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  334. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  335. package/src/resources/extensions/gsd/auto.ts +92 -4
  336. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +37 -2
  337. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
  338. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -1
  339. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
  340. package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
  341. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  342. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  343. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  344. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  345. package/src/resources/extensions/gsd/custom-workflow-engine.ts +24 -1
  346. package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
  347. package/src/resources/extensions/gsd/db-base-schema.ts +19 -2
  348. package/src/resources/extensions/gsd/db-migration-steps.ts +25 -0
  349. package/src/resources/extensions/gsd/detection.ts +128 -0
  350. package/src/resources/extensions/gsd/git-service.ts +46 -8
  351. package/src/resources/extensions/gsd/graph.ts +12 -5
  352. package/src/resources/extensions/gsd/gsd-db.ts +168 -13
  353. package/src/resources/extensions/gsd/guided-flow.ts +98 -16
  354. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  355. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  356. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  357. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  358. package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
  359. package/src/resources/extensions/gsd/pre-execution-checks.ts +7 -0
  360. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  361. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  362. package/src/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
  363. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  364. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  365. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  366. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  367. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  368. package/src/resources/extensions/gsd/quick.ts +37 -2
  369. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  370. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
  371. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
  372. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +155 -5
  373. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
  374. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +184 -2
  375. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
  376. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  377. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  378. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  379. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  380. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  381. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +112 -6
  382. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
  383. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  384. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
  385. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  386. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  387. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  388. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  389. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  390. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  391. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  392. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  393. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  394. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
  395. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  396. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
  397. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
  398. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  399. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  400. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  401. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  402. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  403. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  404. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  405. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +38 -0
  406. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  407. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
  408. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  409. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  410. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  411. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  412. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  413. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
  414. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  415. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
  416. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  417. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  418. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
  419. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  420. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  421. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  422. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  423. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
  424. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  425. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  426. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +63 -1
  427. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  428. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  429. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  430. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  431. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  432. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  433. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  434. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  435. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  436. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  437. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  438. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  439. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  440. package/src/resources/extensions/gsd/worktree-resolver.ts +36 -15
  441. package/packages/contracts/tsconfig.tsbuildinfo +0 -1
  442. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → -5nHJWzSdG-WkPMul_khA}/_buildManifest.js +0 -0
  443. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → -5nHJWzSdG-WkPMul_khA}/_ssgManifest.js +0 -0
@@ -32,13 +32,13 @@ import { detectStuck } from "./detect-stuck.js";
32
32
  import { runUnit } from "./run-unit.js";
33
33
  import { debugLog } from "../debug-logger.js";
34
34
  import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare } from "../worktree-root.js";
35
- import { PROJECT_FILES, hasProjectFileInAncestor } from "../detection.js";
35
+ import { classifyProject } from "../detection.js";
36
36
  import { MergeConflictError } from "../git-service.js";
37
37
  import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
38
38
  import { pauseAutoForProviderError } from "../provider-error-pause.js";
39
39
  import { resumeAutoAfterProviderDelay } from "../bootstrap/provider-error-resume.js";
40
40
  import { join, basename } from "node:path";
41
- import { existsSync, cpSync, readdirSync } from "node:fs";
41
+ import { existsSync, cpSync } from "node:fs";
42
42
  import {
43
43
  logWarning,
44
44
  logError,
@@ -50,12 +50,12 @@ import {
50
50
  } from "../workflow-logger.js";
51
51
  import { gsdRoot } from "../paths.js";
52
52
  import { atomicWriteSync } from "../atomic-write.js";
53
- import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps } from "../auto-recovery.js";
53
+ import { verifyExpectedArtifact, diagnoseExpectedArtifact, buildLoopRemediationSteps, refreshRecoveryDbForArtifact } from "../auto-recovery.js";
54
54
  import { writeUnitRuntimeRecord } from "../unit-runtime.js";
55
55
  import { withTimeout, FINALIZE_PRE_TIMEOUT_MS, FINALIZE_POST_TIMEOUT_MS } from "./finalize-timeout.js";
56
56
  import { getEligibleSlices } from "../slice-parallel-eligibility.js";
57
57
  import { startSliceParallel } from "../slice-parallel-orchestrator.js";
58
- import { isDbAvailable, getMilestoneSlices, refreshOpenDatabaseFromDisk } from "../gsd-db.js";
58
+ import { isDbAvailable, getMilestoneSlices } from "../gsd-db.js";
59
59
  import type { MinimalModelRegistry } from "../context-budget.js";
60
60
  import { ensurePlanV2Graph, isEmptyPlanV2GraphResult, isMissingFinalizedContextResult } from "../uok/plan-v2.js";
61
61
  import { resolveUokFlags } from "../uok/flags.js";
@@ -76,12 +76,6 @@ function isSamePathLocal(a: string, b: string): boolean {
76
76
  return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
77
77
  }
78
78
 
79
- function refreshPlanSliceRecoveryDbIfNeeded(unitType: string): boolean {
80
- if (unitType !== "plan-slice") return true;
81
- if (!isDbAvailable()) return true;
82
- return refreshOpenDatabaseFromDisk();
83
- }
84
-
85
79
  // ─── Session timeout auto-resume state ────────────────────────────────────────
86
80
 
87
81
  let consecutiveSessionTimeouts = 0;
@@ -684,6 +678,7 @@ export async function runPreDispatch(
684
678
  deps.postflightPopStash(
685
679
  s.originalBasePath || s.basePath,
686
680
  s.currentMilestoneId!,
681
+ preflightTransition.stashMarker,
687
682
  ctx.ui.notify.bind(ctx.ui),
688
683
  );
689
684
  }
@@ -797,6 +792,7 @@ export async function runPreDispatch(
797
792
  deps.postflightPopStash(
798
793
  s.originalBasePath || s.basePath,
799
794
  s.currentMilestoneId,
795
+ preflightAllComplete.stashMarker,
800
796
  ctx.ui.notify.bind(ctx.ui),
801
797
  );
802
798
  }
@@ -925,6 +921,7 @@ export async function runPreDispatch(
925
921
  deps.postflightPopStash(
926
922
  s.originalBasePath || s.basePath,
927
923
  s.currentMilestoneId,
924
+ preflightComplete.stashMarker,
928
925
  ctx.ui.notify.bind(ctx.ui),
929
926
  );
930
927
  }
@@ -1097,17 +1094,24 @@ export async function runDispatch(
1097
1094
  level: 1,
1098
1095
  action: "artifact-found",
1099
1096
  });
1100
- ctx.ui.notify(
1101
- `Stuck recovery: artifact for ${unitType} ${unitId} found on disk. Invalidating caches.`,
1102
- "info",
1103
- );
1104
- if (!refreshPlanSliceRecoveryDbIfNeeded(unitType)) {
1097
+ const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
1098
+ if (!recoveryDb.ok) {
1105
1099
  ctx.ui.notify(
1106
- `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed. Keeping stuck state for retry.`,
1100
+ recoveryDb.fatal
1101
+ ? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
1102
+ : `${recoveryDb.message} Keeping stuck state for retry.`,
1107
1103
  "warning",
1108
1104
  );
1105
+ if (recoveryDb.fatal) {
1106
+ await deps.pauseAuto(ctx, pi);
1107
+ return { action: "break", reason: recoveryDb.reason };
1108
+ }
1109
1109
  return { action: "continue" };
1110
1110
  }
1111
+ ctx.ui.notify(
1112
+ `Stuck recovery: artifact for ${unitType} ${unitId} found on disk. Invalidating caches.`,
1113
+ "info",
1114
+ );
1111
1115
  deps.invalidateAllCaches();
1112
1116
  loopState.recentUnits.length = 0;
1113
1117
  loopState.stuckRecoveryAttempts = 0;
@@ -1132,19 +1136,26 @@ export async function runDispatch(
1132
1136
  level: 2,
1133
1137
  action: "artifact-found",
1134
1138
  });
1135
- ctx.ui.notify(
1136
- `Stuck recovery: artifact for ${unitType} ${unitId} found on disk after cache invalidation. Continuing.`,
1137
- "info",
1138
- );
1139
- if (refreshPlanSliceRecoveryDbIfNeeded(unitType)) {
1139
+ const recoveryDb = refreshRecoveryDbForArtifact(unitType, unitId);
1140
+ if (recoveryDb.ok) {
1141
+ ctx.ui.notify(
1142
+ `Stuck recovery: artifact for ${unitType} ${unitId} found on disk after cache invalidation. Continuing.`,
1143
+ "info",
1144
+ );
1140
1145
  loopState.recentUnits.length = 0;
1141
1146
  loopState.stuckRecoveryAttempts = 0;
1142
1147
  return { action: "continue" };
1143
1148
  }
1144
1149
  ctx.ui.notify(
1145
- `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed. Stopping for manual recovery.`,
1150
+ recoveryDb.fatal
1151
+ ? `${recoveryDb.message} Pausing auto-mode for manual recovery.`
1152
+ : `${recoveryDb.message} Stopping for manual recovery.`,
1146
1153
  "warning",
1147
1154
  );
1155
+ if (recoveryDb.fatal) {
1156
+ await deps.pauseAuto(ctx, pi);
1157
+ return { action: "break", reason: recoveryDb.reason };
1158
+ }
1148
1159
  }
1149
1160
  debugLog("autoLoop", {
1150
1161
  phase: "stuck-detected",
@@ -1484,8 +1495,9 @@ export async function runUnitPhase(
1484
1495
  // Verify the working directory is a valid git checkout with project
1485
1496
  // files before dispatching work. A broken worktree causes agents to
1486
1497
  // hallucinate summaries since they cannot read or write any files.
1487
- // Uses the shared PROJECT_FILES list from detection.ts to support all
1488
- // ecosystems (Rust, Go, Python, Java, etc.), not just JS.
1498
+ // Uses project classification so project presence is not conflated with
1499
+ // ecosystem marker detection. Static/minimal repos become untyped-existing.
1500
+ let projectClassification: ReturnType<typeof classifyProject> | null = null;
1489
1501
  if (s.basePath && unitType === "execute-task") {
1490
1502
  const gitMarker = join(s.basePath, ".git");
1491
1503
  const hasGit = deps.existsSync(gitMarker);
@@ -1496,30 +1508,29 @@ export async function runUnitPhase(
1496
1508
  await deps.stopAuto(ctx, pi, msg);
1497
1509
  return { action: "break", reason: "worktree-invalid" };
1498
1510
  }
1499
- const hasProjectFile = PROJECT_FILES.some((f) => deps.existsSync(join(s.basePath, f)));
1500
- const hasSrcDir = deps.existsSync(join(s.basePath, "src"));
1501
- // Xcode bundles have project-specific names (*.xcodeproj, *.xcworkspace)
1502
- // that cannot be matched by exact filename — scan the directory by suffix.
1503
- let hasXcodeBundle = false;
1504
- try {
1505
- const entries = deps.existsSync(s.basePath) ? readdirSync(s.basePath) : [];
1506
- hasXcodeBundle = entries.some((e: string) => e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace"));
1507
- } catch (err) {
1508
- debugLog("runUnitPhase", { phase: "xcode-bundle-scan-failed", basePath: s.basePath, error: String(err) });
1509
- }
1510
- // Monorepo support (#2347): if no project files in the worktree directory,
1511
- // walk parent directories up to the filesystem root. In monorepos,
1512
- // package.json / Cargo.toml etc. live in a parent directory.
1513
- const hasProjectFileInParent =
1514
- !hasProjectFile && !hasSrcDir && !hasXcodeBundle
1515
- ? hasProjectFileInAncestor(s.basePath, deps.existsSync)
1516
- : false;
1517
- if (!hasProjectFile && !hasSrcDir && !hasXcodeBundle && !hasProjectFileInParent) {
1518
- // Greenfield projects won't have project files yet — the first task creates them.
1519
- // Log a warning but allow execution to proceed. The .git check above is sufficient
1520
- // to ensure we're in a valid working directory.
1521
- debugLog("runUnitPhase", { phase: "worktree-health-warn-greenfield", basePath: s.basePath, hasProjectFile, hasSrcDir, hasXcodeBundle });
1522
- ctx.ui.notify(`Warning: ${s.basePath} has no recognized project files — proceeding as greenfield project`, "warning");
1511
+ projectClassification = classifyProject(s.basePath);
1512
+ if (projectClassification.kind === "invalid-repo") {
1513
+ const msg = `Worktree health check failed: ${s.basePath} classified as invalid-repo (${projectClassification.reason}) — refusing to dispatch ${unitType} ${unitId}`;
1514
+ debugLog("runUnitPhase", { phase: "worktree-health-invalid-repo", basePath: s.basePath, classification: projectClassification });
1515
+ if (projectClassification.reason === "missing .git" && hasGit) {
1516
+ ctx.ui.notify(
1517
+ `Warning: ${s.basePath} project classification could not confirm .git; assuming it has no project content yet — proceeding as greenfield project because worktree health reported .git present`,
1518
+ "warning",
1519
+ );
1520
+ } else {
1521
+ ctx.ui.notify(msg, "error");
1522
+ await deps.stopAuto(ctx, pi, msg);
1523
+ return { action: "break", reason: "worktree-invalid" };
1524
+ }
1525
+ } else if (projectClassification.kind === "greenfield") {
1526
+ debugLog("runUnitPhase", { phase: "worktree-health-greenfield", basePath: s.basePath, classification: projectClassification });
1527
+ ctx.ui.notify(`Warning: ${s.basePath} has no project content yet — proceeding as greenfield project`, "warning");
1528
+ } else if (projectClassification.kind === "untyped-existing") {
1529
+ debugLog("runUnitPhase", { phase: "worktree-health-untyped-existing", basePath: s.basePath, classification: projectClassification });
1530
+ ctx.ui.notify(
1531
+ `Notice: ${s.basePath} has existing project content but no recognized tooling markers using generic file-level workflow guidance`,
1532
+ "info",
1533
+ );
1523
1534
  }
1524
1535
  }
1525
1536
 
@@ -1598,6 +1609,17 @@ export async function runUnitPhase(
1598
1609
  // Prompt injection
1599
1610
  let finalPrompt = prompt;
1600
1611
 
1612
+ if (unitType === "execute-task") {
1613
+ projectClassification ??= classifyProject(s.basePath);
1614
+ if (projectClassification.kind === "untyped-existing") {
1615
+ const samples = projectClassification.contentFiles.slice(0, 8).join(", ") || "project files";
1616
+ finalPrompt +=
1617
+ "\n\n**Project classification:** Existing untyped project. No recognized build/tooling markers were detected, " +
1618
+ "so use generic file-level workflow guidance. Task plans and completion summaries must list every concrete " +
1619
+ `project file changed in \`files\` or \`expected_output\`. Detected content sample: ${samples}.`;
1620
+ }
1621
+ }
1622
+
1601
1623
  if (s.pendingVerificationRetry) {
1602
1624
  const retryCtx = s.pendingVerificationRetry;
1603
1625
  s.pendingVerificationRetry = null;
@@ -2251,6 +2273,13 @@ export async function runFinalize(
2251
2273
 
2252
2274
  // Both pre and post verification completed without timeout — reset counter
2253
2275
  loopState.consecutiveFinalizeTimeouts = 0;
2276
+ if (preUnitSnapshot) {
2277
+ writeUnitRuntimeRecord(s.basePath, preUnitSnapshot.type, preUnitSnapshot.id, preUnitSnapshot.startedAt, {
2278
+ phase: "finalized",
2279
+ lastProgressAt: Date.now(),
2280
+ lastProgressKind: "finalize-success",
2281
+ });
2282
+ }
2254
2283
  s.currentUnit = null;
2255
2284
  clearCurrentPhase();
2256
2285
 
@@ -22,6 +22,7 @@ import { bumpTurnGeneration } from "./turn-epoch.js";
22
22
 
23
23
  let _currentResolve: ((result: UnitResult) => void) | null = null;
24
24
  let _sessionSwitchInFlight = false;
25
+ let _pendingSwitchCancellation: { errorContext?: ErrorContext } | null = null;
25
26
 
26
27
  // ─── Setters (needed for cross-module mutation) ─────────────────────────────
27
28
 
@@ -37,6 +38,12 @@ export function _clearCurrentResolve(): void {
37
38
  _currentResolve = null;
38
39
  }
39
40
 
41
+ export function _consumePendingSwitchCancellation(): { errorContext?: ErrorContext } | null {
42
+ const pending = _pendingSwitchCancellation;
43
+ _pendingSwitchCancellation = null;
44
+ return pending;
45
+ }
46
+
40
47
  // ─── resolveAgentEnd ─────────────────────────────────────────────────────────
41
48
 
42
49
  /**
@@ -96,7 +103,7 @@ export function bumpAndResolveSynthetic(reason: string): void {
96
103
  * blocks to ensure the autoLoop is never stuck awaiting a promise that
97
104
  * will never resolve. Safe to call when no resolver is pending (no-op).
98
105
  */
99
- export function resolveAgentEndCancelled(errorContext?: ErrorContext): void {
106
+ export function resolveAgentEndCancelled(errorContext?: ErrorContext): boolean {
100
107
  if (_currentResolve) {
101
108
  // Cancellation supersedes the in-flight turn the same way timeout
102
109
  // recovery does — bump the turn epoch so any lingering writes from the
@@ -107,8 +114,22 @@ export function resolveAgentEndCancelled(errorContext?: ErrorContext): void {
107
114
  debugLog("resolveAgentEndCancelled", { status: "resolving-cancelled" });
108
115
  const r = _currentResolve;
109
116
  _currentResolve = null;
117
+ _pendingSwitchCancellation = null;
110
118
  r({ status: "cancelled", ...(errorContext ? { errorContext } : {}) });
119
+ return true;
120
+ }
121
+
122
+ if (_sessionSwitchInFlight) {
123
+ bumpTurnGeneration(
124
+ `cancelled-during-switch:${errorContext?.category ?? "unknown"}`,
125
+ );
126
+ _pendingSwitchCancellation = errorContext ? { errorContext } : {};
127
+ debugLog("resolveAgentEndCancelled", { status: "queued-during-switch" });
128
+ return false;
111
129
  }
130
+
131
+ debugLog("resolveAgentEndCancelled", { status: "no-pending-resolve" });
132
+ return false;
112
133
  }
113
134
 
114
135
  // ─── resetPendingResolve (test helper) ───────────────────────────────────────
@@ -120,6 +141,7 @@ export function resolveAgentEndCancelled(errorContext?: ErrorContext): void {
120
141
  export function _resetPendingResolve(): void {
121
142
  _currentResolve = null;
122
143
  _sessionSwitchInFlight = false;
144
+ _pendingSwitchCancellation = null;
123
145
  }
124
146
 
125
147
  export function _hasPendingResolveForTest(): boolean {
@@ -1,3 +1,5 @@
1
+ // GSD-2 + src/resources/extensions/gsd/auto/run-unit.ts - Runs one GSD auto-mode unit from session creation through agent completion.
2
+
1
3
  /**
2
4
  * auto/run-unit.ts — Single unit execution: session create → prompt → await agent_end.
3
5
  *
@@ -9,7 +11,12 @@ import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
9
11
  import type { AutoSession } from "./session.js";
10
12
  import { NEW_SESSION_TIMEOUT_MS } from "./session.js";
11
13
  import type { UnitResult } from "./types.js";
12
- import { _clearCurrentResolve, _setCurrentResolve, _setSessionSwitchInFlight } from "./resolve.js";
14
+ import {
15
+ _clearCurrentResolve,
16
+ _consumePendingSwitchCancellation,
17
+ _setCurrentResolve,
18
+ _setSessionSwitchInFlight,
19
+ } from "./resolve.js";
13
20
  import {
14
21
  getCurrentTurnGeneration,
15
22
  runWithTurnGeneration,
@@ -17,6 +24,7 @@ import {
17
24
  import { debugLog } from "../debug-logger.js";
18
25
  import { logWarning, logError } from "../workflow-logger.js";
19
26
  import { resolveAutoSupervisorConfig } from "../preferences.js";
27
+ import { formatAutoUnitWorkingMessage } from "../working-output-messages.js";
20
28
 
21
29
  // Tracks the latest session-switch attempt so a late timeout settlement from an
22
30
  // older runUnit() call cannot clear the guard for a newer one.
@@ -94,6 +102,7 @@ export async function runUnit(
94
102
  sessionResult = await Promise.race([sessionPromise, timeoutPromise]);
95
103
  } catch (sessionErr) {
96
104
  if (sessionTimeoutHandle) clearTimeout(sessionTimeoutHandle);
105
+ _consumePendingSwitchCancellation();
97
106
  const msg =
98
107
  sessionErr instanceof Error ? sessionErr.message : String(sessionErr);
99
108
  debugLog("runUnit", {
@@ -107,17 +116,20 @@ export async function runUnit(
107
116
  if (sessionTimeoutHandle) clearTimeout(sessionTimeoutHandle);
108
117
 
109
118
  if (sessionResult.cancelled) {
119
+ _consumePendingSwitchCancellation();
110
120
  debugLog("runUnit-session-timeout", { unitType, unitId });
111
121
  return { status: "cancelled", errorContext: { message: "Session creation timed out", category: "timeout", isTransient: true } };
112
122
  }
113
123
 
114
124
  if (!s.active) {
125
+ _consumePendingSwitchCancellation();
115
126
  return { status: "cancelled" };
116
127
  }
117
128
 
118
129
  if (s.currentUnitModel && typeof pi.setModel === "function") {
119
130
  const restored = await pi.setModel(s.currentUnitModel, { persist: false });
120
131
  if (!restored) {
132
+ _consumePendingSwitchCancellation();
121
133
  const message =
122
134
  `Failed to restore configured model ${s.currentUnitModel.provider}/${s.currentUnitModel.id} after session creation`;
123
135
  ctx.ui.notify(
@@ -142,6 +154,14 @@ export async function runUnit(
142
154
  const unitPromise = new Promise<UnitResult>((resolve) => {
143
155
  _setCurrentResolve(resolve);
144
156
  });
157
+ const pendingSwitchCancellation = _consumePendingSwitchCancellation();
158
+ if (pendingSwitchCancellation) {
159
+ _clearCurrentResolve();
160
+ return {
161
+ status: "cancelled",
162
+ ...(pendingSwitchCancellation.errorContext ? { errorContext: pendingSwitchCancellation.errorContext } : {}),
163
+ };
164
+ }
145
165
 
146
166
  // ── Provider request-readiness pre-check (#4555) ──
147
167
  // Verify the provider can accept requests before dispatching. If the token
@@ -184,30 +204,37 @@ export async function runUnit(
184
204
  debugLog("runUnit", { phase: "send-message", unitType, unitId });
185
205
 
186
206
  const requestDispatchedAt = Date.now();
187
- pi.sendMessage(
188
- { customType: "gsd-auto", content: prompt, display: s.verbose },
189
- { triggerTurn: true },
190
- );
207
+ ctx.ui.setWorkingMessage?.(formatAutoUnitWorkingMessage(unitType, unitId));
191
208
 
192
209
  // ── Await agent_end with absolute timeout (H4 fix) ──
193
210
  // If supervision fails to resolve unitPromise within 30s, treat as cancelled.
194
211
  // Without this, a crashed agent that never emits agent_end hangs the loop (#3161).
195
- debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
196
212
  const supervisor = resolveAutoSupervisorConfig();
197
213
  const UNIT_HARD_TIMEOUT_MS = Math.max(
198
214
  30_000,
199
215
  ((supervisor.hard_timeout_minutes ?? 30) * 60 * 1000) + 30_000,
200
216
  );
201
217
  let unitTimeoutHandle: ReturnType<typeof setTimeout> | undefined;
202
- const timeoutResult = new Promise<UnitResult>((resolve) => {
203
- unitTimeoutHandle = setTimeout(() => {
204
- resolve({ status: "cancelled", errorContext: { message: "Unit hard timeout — supervision may have failed", category: "timeout", isTransient: true } });
205
- }, UNIT_HARD_TIMEOUT_MS);
206
- });
207
- const result = await runWithTurnGeneration(capturedTurnGen, () =>
208
- Promise.race([unitPromise, timeoutResult]),
209
- );
210
- if (unitTimeoutHandle) clearTimeout(unitTimeoutHandle);
218
+ let result: UnitResult;
219
+ try {
220
+ pi.sendMessage(
221
+ { customType: "gsd-auto", content: prompt, display: s.verbose },
222
+ { triggerTurn: true },
223
+ );
224
+
225
+ debugLog("runUnit", { phase: "awaiting-agent-end", unitType, unitId });
226
+ const timeoutResult = new Promise<UnitResult>((resolve) => {
227
+ unitTimeoutHandle = setTimeout(() => {
228
+ resolve({ status: "cancelled", errorContext: { message: "Unit hard timeout — supervision may have failed", category: "timeout", isTransient: true } });
229
+ }, UNIT_HARD_TIMEOUT_MS);
230
+ });
231
+ result = await runWithTurnGeneration(capturedTurnGen, () =>
232
+ Promise.race([unitPromise, timeoutResult]),
233
+ );
234
+ } finally {
235
+ if (unitTimeoutHandle) clearTimeout(unitTimeoutHandle);
236
+ ctx.ui.setWorkingMessage?.(undefined);
237
+ }
211
238
  debugLog("runUnit", {
212
239
  phase: "agent-end-received",
213
240
  unitType,
@@ -1,3 +1,5 @@
1
+ // GSD-2 + src/resources/extensions/gsd/auto-dashboard.ts - Auto-mode progress widget rendering and dashboard helpers.
2
+
1
3
  /**
2
4
  * Auto-mode Dashboard — progress widget rendering, elapsed time formatting,
3
5
  * unit description helpers, and slice progress caching.
@@ -46,6 +48,7 @@ import {
46
48
  import { logWarning } from "./workflow-logger.js";
47
49
  import { formattedShortcutPair } from "./shortcut-defs.js";
48
50
  import { homedir } from "node:os";
51
+ import { readUnitRuntimeRecord, type AutoUnitRuntimeRecord } from "./unit-runtime.js";
49
52
 
50
53
  // ─── UAT Slice Extraction ─────────────────────────────────────────────────────
51
54
 
@@ -215,6 +218,36 @@ export function formatWidgetTokens(count: number): string {
215
218
  return `${Math.round(count / 1000000)}M`;
216
219
  }
217
220
 
221
+ export function formatRuntimeHealthSignal(
222
+ record: AutoUnitRuntimeRecord | null,
223
+ now = Date.now(),
224
+ ): { level: "green" | "yellow"; summary: string; detail?: string } | null {
225
+ if (!record) return null;
226
+ const idleMs = Math.max(0, now - record.lastProgressAt);
227
+ const idleMinutes = Math.floor(idleMs / 60_000);
228
+ if ((record.recoveryAttempts ?? 0) > 0 || record.phase === "recovered" || record.lastProgressKind.includes("recovery")) {
229
+ return {
230
+ level: "yellow",
231
+ summary: "Recovering",
232
+ detail: `retry ${record.recoveryAttempts ?? 1} after ${record.lastRecoveryReason ?? "idle"} stall`,
233
+ };
234
+ }
235
+ if (record.progressCount === 0 && idleMs >= 60_000) {
236
+ return {
237
+ level: "yellow",
238
+ summary: "Waiting on provider",
239
+ detail: `no output for ${idleMinutes}m`,
240
+ };
241
+ }
242
+ return null;
243
+ }
244
+
245
+ export function shouldRenderRoadmapProgress(
246
+ progress: { total: number; activeSliceTasks?: { total: number } | null } | null,
247
+ ): progress is { total: number; activeSliceTasks?: { total: number } | null } {
248
+ return !!progress && progress.total > 0;
249
+ }
250
+
218
251
  // ─── ETA Estimation ──────────────────────────────────────────────────────────
219
252
 
220
253
  /**
@@ -622,6 +655,7 @@ export function updateProgressWidget(
622
655
  let cachedLines: string[] | undefined;
623
656
  let cachedWidth: number | undefined;
624
657
  let cachedRtkLabel: string | null | undefined;
658
+ let cachedRuntimeRecord: AutoUnitRuntimeRecord | null = null;
625
659
 
626
660
  const refreshRtkLabel = (): void => {
627
661
  try {
@@ -634,7 +668,16 @@ export function updateProgressWidget(
634
668
  }
635
669
  };
636
670
 
671
+ const refreshRuntimeRecord = (): void => {
672
+ try {
673
+ cachedRuntimeRecord = readUnitRuntimeRecord(accessors.getBasePath(), unitType, unitId);
674
+ } catch {
675
+ cachedRuntimeRecord = null;
676
+ }
677
+ };
678
+
637
679
  refreshRtkLabel();
680
+ refreshRuntimeRecord();
638
681
 
639
682
  const pulseTimer = setInterval(() => {
640
683
  pulseBright = !pulseBright;
@@ -652,6 +695,7 @@ export function updateProgressWidget(
652
695
  updateSliceProgressCache(accessors.getBasePath(), mid.id, slice?.id);
653
696
  }
654
697
  refreshRtkLabel();
698
+ refreshRuntimeRecord();
655
699
  cachedLines = undefined;
656
700
  } catch (err) { /* non-fatal */
657
701
  logWarning("dashboard", `DB status update failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -685,13 +729,16 @@ export function updateProgressWidget(
685
729
 
686
730
  // Health indicator in header
687
731
  const score = computeProgressScore();
688
- const healthColor = score.level === "green" ? "success"
689
- : score.level === "yellow" ? "warning"
732
+ const runtimeSignal = formatRuntimeHealthSignal(cachedRuntimeRecord);
733
+ const healthLevel = runtimeSignal?.level ?? score.level;
734
+ const healthSummary = runtimeSignal?.summary ?? score.summary;
735
+ const healthColor = healthLevel === "green" ? "success"
736
+ : healthLevel === "yellow" ? "warning"
690
737
  : "error";
691
- const healthIcon = score.level === "green" ? GLYPH.statusActive
692
- : score.level === "yellow" ? "!"
738
+ const healthIcon = healthLevel === "green" ? GLYPH.statusActive
739
+ : healthLevel === "yellow" ? "!"
693
740
  : "x";
694
- const healthStr = ` ${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, score.summary)}`;
741
+ const healthStr = ` ${theme.fg(healthColor, healthIcon)} ${theme.fg(healthColor, healthSummary)}`;
695
742
 
696
743
  const headerLeft = `${pad}${dot} ${theme.fg("accent", theme.bold("GSD"))} ${theme.fg("success", modeTag)}${healthStr}`;
697
744
 
@@ -706,7 +753,9 @@ export function updateProgressWidget(
706
753
  lines.push(rightAlign(headerLeft, headerRight, width));
707
754
 
708
755
  // Show health signal details when degraded (yellow/red)
709
- if (score.level !== "green" && score.signals.length > 0 && widgetMode !== "min") {
756
+ if (runtimeSignal?.detail && widgetMode !== "min") {
757
+ lines.push(`${pad} ${theme.fg("dim", runtimeSignal.detail)}`);
758
+ } else if (score.level !== "green" && score.signals.length > 0 && widgetMode !== "min") {
710
759
  // Show up to 3 most relevant signals in compact form
711
760
  const topSignals = score.signals
712
761
  .filter(s => s.kind === "negative")
@@ -785,7 +834,7 @@ export function updateProgressWidget(
785
834
 
786
835
  // Progress bar
787
836
  const roadmapSlices = mid ? getRoadmapSlicesSync() : null;
788
- if (roadmapSlices) {
837
+ if (shouldRenderRoadmapProgress(roadmapSlices)) {
789
838
  const { done, total, activeSliceTasks } = roadmapSlices;
790
839
  const barWidth = Math.max(6, Math.min(18, Math.floor(width * 0.25)));
791
840
  const pct = total > 0 ? done / total : 0;
@@ -853,7 +902,7 @@ export function updateProgressWidget(
853
902
 
854
903
  const leftLines: string[] = [];
855
904
 
856
- if (roadmapSlices) {
905
+ if (shouldRenderRoadmapProgress(roadmapSlices)) {
857
906
  const { done, total, activeSliceTasks } = roadmapSlices;
858
907
  const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
859
908
  const pct = total > 0 ? done / total : 0;
@@ -211,6 +211,23 @@ export function hasPendingDeepStage(prefs: GSDPreferences | undefined, basePath:
211
211
  return gate.status === "pending" || gate.status === "blocked";
212
212
  }
213
213
 
214
+ export function shouldRunDeepProjectSetup(
215
+ state: Pick<GSDState, "phase">,
216
+ prefs: GSDPreferences | undefined,
217
+ basePath: string,
218
+ options: { hasSurvivorBranch?: boolean } = {},
219
+ ): boolean {
220
+ if (options.hasSurvivorBranch === true) return false;
221
+ if (
222
+ state.phase !== "pre-planning" &&
223
+ state.phase !== "needs-discussion" &&
224
+ state.phase !== "planning"
225
+ ) {
226
+ return false;
227
+ }
228
+ return hasPendingDeepStage(prefs, basePath);
229
+ }
230
+
214
231
  function missingSliceStop(mid: string, phase: string): DispatchAction {
215
232
  return {
216
233
  action: "stop",
@@ -43,7 +43,7 @@ import {
43
43
  import { regenerateIfMissing } from "./workflow-projections.js";
44
44
  import { syncStateToProjectRoot } from "./auto-worktree.js";
45
45
  import { normalizeWorktreePathForCompare } from "./worktree-root.js";
46
- import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
46
+ import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter, getVerificationEvidence } from "./gsd-db.js";
47
47
  import { renderPlanCheckboxes } from "./markdown-renderer.js";
48
48
  import { consumeSignal } from "./session-status-io.js";
49
49
  import {
@@ -852,22 +852,22 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
852
852
  }
853
853
 
854
854
  // Evidence cross-reference (execute-task only)
855
- // Verification evidence is passed via the complete-task tool call and
856
- // stored in the SUMMARY.md on disk not available as structured data
857
- // in the DB. The evidence collector tracks actual bash tool calls, so
858
- // we can still detect units that claimed success but ran no commands.
855
+ // Only compare against concrete command evidence persisted by the task
856
+ // completion tool. A prose Verify field can be satisfied later by the
857
+ // host verification gate, so it is not enough to accuse the unit.
859
858
  if (safetyConfig.evidence_cross_reference && s.currentUnit.type === "execute-task") {
860
859
  try {
861
860
  const actual = getEvidence();
862
861
  const bashCalls = actual.filter(e => e.kind === "bash");
863
- // If the task is marked complete but zero bash commands were run,
864
- // it's suspicious — the LLM may have fabricated results.
865
862
  if (sMid && sSid && sTid && isDbAvailable()) {
866
863
  const taskRow = getTask(sMid, sSid, sTid);
867
- if (taskRow?.status === "complete" && taskRow.verify && bashCalls.length === 0) {
868
- logWarning("safety", "task marked complete with verification commands but no bash calls were executed");
864
+ const claimedCommands = getVerificationEvidence(sMid, sSid, sTid)
865
+ .map((row) => row.command)
866
+ .filter((command): command is string => typeof command === "string" && command.trim().length > 0);
867
+ if (taskRow?.status === "complete" && claimedCommands.length > 0 && bashCalls.length === 0) {
868
+ logWarning("safety", "task claimed verification command evidence but no execution tool calls were recorded");
869
869
  ctx.ui.notify(
870
- `Safety: task ${sTid} has verification commands but no bash calls were recorded`,
870
+ `Safety: task ${sTid} claimed command evidence but no execution tool calls were recorded`,
871
871
  "warning",
872
872
  );
873
873
  }