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
@@ -38,6 +38,7 @@ import { _getAdapter, isDbAvailable } from "./gsd-db.js";
38
38
  import { gsdRoot, normalizeRealPath } from "./paths.js";
39
39
  import { atomicWriteSync } from "./atomic-write.js";
40
40
  import { effectiveLockFile } from "./session-lock.js";
41
+ import { isInFlightRuntimePhase, listUnitRuntimeRecords, type AutoUnitRuntimeRecord } from "./unit-runtime.js";
41
42
 
42
43
  export interface LockData {
43
44
  pid: number;
@@ -103,10 +104,40 @@ function getLatestDispatchForWorker(workerId: string):
103
104
  return row ?? null;
104
105
  }
105
106
 
106
- function workerToLockData(worker: AutoWorkerRow): LockData {
107
+ function latestInFlightRuntimeRecord(basePath: string): AutoUnitRuntimeRecord | null {
108
+ const records = listUnitRuntimeRecords(basePath).filter((record) =>
109
+ isInFlightRuntimePhase(record.phase),
110
+ );
111
+ if (records.length === 0) return null;
112
+ return records.sort((a, b) => {
113
+ const bTime = b.updatedAt || b.startedAt || 0;
114
+ const aTime = a.updatedAt || a.startedAt || 0;
115
+ return bTime - aTime;
116
+ })[0] ?? null;
117
+ }
118
+
119
+ function runtimeRecordToLockData(worker: AutoWorkerRow, record: AutoUnitRuntimeRecord, sessionFile?: string): LockData {
120
+ const startedAt = Number.isFinite(record.startedAt)
121
+ ? new Date(record.startedAt).toISOString()
122
+ : worker.started_at;
123
+ return {
124
+ pid: worker.pid,
125
+ startedAt: worker.started_at,
126
+ unitType: record.unitType,
127
+ unitId: record.unitId,
128
+ unitStartedAt: startedAt,
129
+ sessionFile,
130
+ };
131
+ }
132
+
133
+ function workerToLockData(basePath: string, worker: AutoWorkerRow): LockData {
107
134
  const dispatch = getLatestDispatchForWorker(worker.worker_id);
108
135
  const sessionFile =
109
136
  getRuntimeKv<string>("worker", worker.worker_id, SESSION_FILE_KV_KEY) ?? undefined;
137
+ if (!dispatch) {
138
+ const runtimeRecord = latestInFlightRuntimeRecord(basePath);
139
+ if (runtimeRecord) return runtimeRecordToLockData(worker, runtimeRecord, sessionFile);
140
+ }
110
141
  return {
111
142
  pid: worker.pid,
112
143
  startedAt: worker.started_at,
@@ -204,7 +235,7 @@ export function readCrashLock(basePath: string): LockData | null {
204
235
  try {
205
236
  const projectRoot = normalizeRealPath(basePath);
206
237
  const stale = findStaleWorkerForProject(projectRoot);
207
- if (stale) return workerToLockData(stale);
238
+ if (stale) return workerToLockData(basePath, stale);
208
239
  } catch {
209
240
  // Fall through to the legacy lock-file compatibility path.
210
241
  }
@@ -260,25 +291,48 @@ export function formatCrashInfo(lock: LockData): string {
260
291
  */
261
292
  export function emitCrashRecoveredUnitEnd(basePath: string, lock: LockData): void {
262
293
  if (!lock.unitType || !lock.unitId || lock.unitType === "starting") return;
294
+ emitOpenUnitEndForUnit(basePath, lock.unitType, lock.unitId, "crash-recovered");
295
+ }
263
296
 
297
+ export function emitOpenUnitEndForUnit(
298
+ basePath: string,
299
+ unitType: string,
300
+ unitId: string,
301
+ status: string,
302
+ errorContext?: { message: string; category: string; stopReason?: string; isTransient?: boolean; retryAfterMs?: number },
303
+ ): boolean {
264
304
  try {
265
305
  const all = queryJournal(basePath);
266
306
 
267
307
  const starts = all.filter(
268
- (e) => e.eventType === "unit-start" && e.data?.unitId === lock.unitId,
308
+ (e) =>
309
+ e.eventType === "unit-start" &&
310
+ e.data?.unitType === unitType &&
311
+ e.data?.unitId === unitId,
269
312
  );
270
- if (starts.length === 0) return;
313
+ if (starts.length === 0) return false;
271
314
 
272
- const lastStart = starts[starts.length - 1];
315
+ const lastStart = [...starts].reverse().find((start) => {
316
+ return !all.some(
317
+ (e) =>
318
+ e.eventType === "unit-end" &&
319
+ e.data?.unitType === unitType &&
320
+ e.data?.unitId === unitId &&
321
+ e.causedBy?.flowId === start.flowId &&
322
+ e.causedBy?.seq === start.seq,
323
+ );
324
+ });
325
+ if (!lastStart) return false;
273
326
 
274
327
  const alreadyClosed = all.some(
275
328
  (e) =>
276
329
  e.eventType === "unit-end" &&
277
- e.data?.unitId === lock.unitId &&
330
+ e.data?.unitType === unitType &&
331
+ e.data?.unitId === unitId &&
278
332
  e.causedBy?.flowId === lastStart.flowId &&
279
333
  e.causedBy?.seq === lastStart.seq,
280
334
  );
281
- if (alreadyClosed) return;
335
+ if (alreadyClosed) return false;
282
336
 
283
337
  const maxSeq = all
284
338
  .filter((e) => e.flowId === lastStart.flowId)
@@ -290,15 +344,18 @@ export function emitCrashRecoveredUnitEnd(basePath: string, lock: LockData): voi
290
344
  seq: maxSeq + 1,
291
345
  eventType: "unit-end",
292
346
  data: {
293
- unitType: lock.unitType,
294
- unitId: lock.unitId,
295
- status: "crash-recovered",
347
+ unitType,
348
+ unitId,
349
+ status,
296
350
  artifactVerified: false,
351
+ ...(errorContext ? { errorContext } : {}),
297
352
  },
298
353
  causedBy: { flowId: lastStart.flowId, seq: lastStart.seq },
299
354
  });
355
+ return true;
300
356
  } catch {
301
357
  // Never throw from crash recovery path.
358
+ return false;
302
359
  }
303
360
  }
304
361
 
@@ -29,6 +29,7 @@ import {
29
29
  markStepActive,
30
30
  markStepComplete,
31
31
  expandIteration,
32
+ isTerminalStepStatus,
32
33
  type WorkflowGraph,
33
34
  } from "./graph.js";
34
35
  import { injectContext } from "./context-injector.js";
@@ -40,6 +41,24 @@ import { withFileLock } from "./file-lock.js";
40
41
  // Re-export for downstream consumers
41
42
  export { readFrozenDefinition } from "./definition-io.js";
42
43
 
44
+ function formatBlockedWorkflowReason(graph: WorkflowGraph): string {
45
+ const statusById = new Map(graph.steps.map((step) => [step.id, step.status]));
46
+ const blockedSteps = graph.steps
47
+ .filter((step) => step.status === "pending")
48
+ .map((step) => {
49
+ const blockers = step.dependsOn
50
+ .filter((depId) => !isTerminalStepStatus(statusById.get(depId)))
51
+ .map((depId) => `${depId} (${statusById.get(depId) ?? "missing"})`);
52
+ return blockers.length > 0
53
+ ? `${step.id} waiting on ${blockers.join(", ")}`
54
+ : `${step.id} has no runnable dependency path`;
55
+ });
56
+
57
+ return blockedSteps.length > 0
58
+ ? `Workflow blocked: no pending steps are ready. Blocked steps: ${blockedSteps.join("; ")}`
59
+ : "Workflow blocked: no pending steps are ready.";
60
+ }
61
+
43
62
  export class CustomWorkflowEngine implements WorkflowEngine {
44
63
  readonly engineId = "custom";
45
64
  private readonly runDir: string;
@@ -114,7 +133,11 @@ export class CustomWorkflowEngine implements WorkflowEngine {
114
133
  (step) => step.status === "complete" || step.status === "expanded",
115
134
  );
116
135
  if (!allDone) {
117
- return { action: "skip" };
136
+ return {
137
+ action: "stop",
138
+ reason: formatBlockedWorkflowReason(graph),
139
+ level: "error",
140
+ };
118
141
  }
119
142
  return {
120
143
  action: "stop",
@@ -359,6 +359,47 @@ export function markCanceled(dispatchId: number, reason: string): void {
359
359
  ).run({ ":id": dispatchId, ":ended_at": now, ":reason": reason });
360
360
  }
361
361
 
362
+ /**
363
+ * Best-effort signal/crash cleanup: cancel the latest active dispatch owned by
364
+ * a worker when the process is exiting before the normal loop can settle it.
365
+ */
366
+ export function markLatestActiveForWorkerCanceled(workerId: string, reason: string): boolean {
367
+ if (!isDbAvailable()) return false;
368
+ const now = new Date().toISOString();
369
+ const db = _getAdapter()!;
370
+ const result = transaction(() => {
371
+ return db.prepare(
372
+ `UPDATE unit_dispatches
373
+ SET status = 'canceled', ended_at = :ended_at, exit_reason = :reason
374
+ WHERE id = (
375
+ SELECT id FROM unit_dispatches
376
+ WHERE worker_id = :worker_id
377
+ AND status IN ('pending','claimed','running')
378
+ ORDER BY id DESC
379
+ LIMIT 1
380
+ )`,
381
+ ).run({
382
+ ":ended_at": now,
383
+ ":reason": reason,
384
+ ":worker_id": workerId,
385
+ });
386
+ });
387
+ const changes =
388
+ typeof (result as { changes?: unknown }).changes === "number"
389
+ ? (result as { changes: number }).changes
390
+ : 0;
391
+ if (changes <= 0) return false;
392
+ insertAuditEvent({
393
+ eventId: randomUUID(),
394
+ traceId: workerId,
395
+ category: "orchestration",
396
+ type: "dispatch-canceled",
397
+ ts: now,
398
+ payload: { workerId, reason },
399
+ });
400
+ return true;
401
+ }
402
+
362
403
  /**
363
404
  * Fetch the most recent N dispatches for a unit. Used by recordDispatchClaim
364
405
  * callers to compute attempt_n and by detect-stuck.ts (B3) to consult
@@ -57,7 +57,8 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
57
57
  slice_id TEXT DEFAULT NULL,
58
58
  task_id TEXT DEFAULT NULL,
59
59
  full_content TEXT NOT NULL DEFAULT '',
60
- imported_at TEXT NOT NULL DEFAULT ''
60
+ imported_at TEXT NOT NULL DEFAULT '',
61
+ content_hash TEXT DEFAULT NULL
61
62
  )
62
63
  `);
63
64
 
@@ -76,7 +77,8 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
76
77
  hit_count INTEGER NOT NULL DEFAULT 0,
77
78
  scope TEXT NOT NULL DEFAULT 'project',
78
79
  tags TEXT NOT NULL DEFAULT '[]',
79
- structured_fields TEXT DEFAULT NULL
80
+ structured_fields TEXT DEFAULT NULL,
81
+ last_hit_at TEXT DEFAULT NULL
80
82
  )
81
83
  `);
82
84
 
@@ -323,6 +325,20 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
323
325
  )
324
326
  `);
325
327
 
328
+ db.exec(`
329
+ CREATE TABLE IF NOT EXISTS milestone_commit_attributions (
330
+ commit_sha TEXT NOT NULL,
331
+ milestone_id TEXT NOT NULL,
332
+ slice_id TEXT DEFAULT NULL,
333
+ task_id TEXT DEFAULT NULL,
334
+ source TEXT NOT NULL DEFAULT 'recorded',
335
+ confidence REAL NOT NULL DEFAULT 1.0,
336
+ files_json TEXT NOT NULL DEFAULT '[]',
337
+ created_at TEXT NOT NULL DEFAULT '',
338
+ PRIMARY KEY (commit_sha, milestone_id)
339
+ )
340
+ `);
341
+
326
342
  db.exec(`
327
343
  CREATE TABLE IF NOT EXISTS audit_events (
328
344
  event_id TEXT PRIMARY KEY,
@@ -359,6 +375,7 @@ export function createBaseSchemaObjects(db: DbAdapter, hooks: BaseSchemaHooks):
359
375
  db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_turn ON gate_runs(trace_id, turn_id)");
360
376
  db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_lookup ON gate_runs(milestone_id, slice_id, task_id, gate_id)");
361
377
  db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
378
+ db.exec("CREATE INDEX IF NOT EXISTS idx_milestone_commit_attr_milestone ON milestone_commit_attributions(milestone_id)");
362
379
  db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
363
380
  db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
364
381
 
@@ -399,6 +399,31 @@ export function applyMigrationV23MilestoneQueue(db: DbAdapter): void {
399
399
  ensureColumn(db, "milestones", "sequence", "ALTER TABLE milestones ADD COLUMN sequence INTEGER DEFAULT 0");
400
400
  }
401
401
 
402
+ export function applyMigrationV26MilestoneCommitAttributions(db: DbAdapter): void {
403
+ db.exec(`
404
+ CREATE TABLE IF NOT EXISTS milestone_commit_attributions (
405
+ commit_sha TEXT NOT NULL,
406
+ milestone_id TEXT NOT NULL,
407
+ slice_id TEXT DEFAULT NULL,
408
+ task_id TEXT DEFAULT NULL,
409
+ source TEXT NOT NULL DEFAULT 'recorded',
410
+ confidence REAL NOT NULL DEFAULT 1.0,
411
+ files_json TEXT NOT NULL DEFAULT '[]',
412
+ created_at TEXT NOT NULL DEFAULT '',
413
+ PRIMARY KEY (commit_sha, milestone_id)
414
+ )
415
+ `);
416
+ db.exec("CREATE INDEX IF NOT EXISTS idx_milestone_commit_attr_milestone ON milestone_commit_attributions(milestone_id)");
417
+ }
418
+
419
+ export function applyMigrationV27ArtifactHash(db: DbAdapter): void {
420
+ ensureColumn(db, "artifacts", "content_hash", "ALTER TABLE artifacts ADD COLUMN content_hash TEXT DEFAULT NULL");
421
+ }
422
+
423
+ export function applyMigrationV28MemoryLastHitAt(db: DbAdapter): void {
424
+ ensureColumn(db, "memories", "last_hit_at", "ALTER TABLE memories ADD COLUMN last_hit_at TEXT DEFAULT NULL");
425
+ }
426
+
402
427
  export interface MigrationV22Hooks {
403
428
  copyQualityGateRowsToRepairedTable(db: DbAdapter): void;
404
429
  }
@@ -6,6 +6,7 @@
6
6
  * flow to show when entering a project directory.
7
7
  */
8
8
 
9
+ import { execFileSync } from "node:child_process";
9
10
  import { existsSync, openSync, readSync, closeSync, readdirSync, readFileSync, statSync } from "node:fs";
10
11
  import { dirname, join, parse as parsePath } from "node:path";
11
12
  import { homedir } from "node:os";
@@ -72,6 +73,22 @@ export interface ProjectSignals {
72
73
  verificationCommands: string[];
73
74
  }
74
75
 
76
+ export type ProjectClassificationKind =
77
+ | "invalid-repo"
78
+ | "greenfield"
79
+ | "untyped-existing"
80
+ | "typed-existing";
81
+
82
+ export interface ProjectClassification {
83
+ kind: ProjectClassificationKind;
84
+ signals: ProjectSignals;
85
+ trackedFiles: string[];
86
+ untrackedFiles: string[];
87
+ contentFiles: string[];
88
+ markers: string[];
89
+ reason: string;
90
+ }
91
+
75
92
  // ─── Project File Markers ───────────────────────────────────────────────────────
76
93
 
77
94
  export const PROJECT_FILES = [
@@ -243,6 +260,7 @@ const TEST_MARKERS = [
243
260
  const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
244
261
  ".git",
245
262
  ".gsd",
263
+ ".bg-shell",
246
264
  ".planning",
247
265
  ".plans",
248
266
  ".claude",
@@ -267,6 +285,8 @@ const RECURSIVE_SCAN_IGNORED_DIRS = new Set([
267
285
  "out",
268
286
  ]) as ReadonlySet<string>;
269
287
 
288
+ const PROJECT_CONTENT_EXCLUDE_DIRS = RECURSIVE_SCAN_IGNORED_DIRS;
289
+
270
290
  /** Project file markers safe to detect recursively via suffix matching. */
271
291
  const ROOT_ONLY_PROJECT_FILES = new Set<string>([
272
292
  ".github/workflows",
@@ -536,6 +556,114 @@ export function detectProjectSignals(basePath: string): ProjectSignals {
536
556
  };
537
557
  }
538
558
 
559
+ function normalizeGitPath(file: string): string {
560
+ return file.replaceAll("\\", "/").replace(/^\.\//, "");
561
+ }
562
+
563
+ function isProjectContentFile(file: string): boolean {
564
+ const normalized = normalizeGitPath(file);
565
+ if (!normalized || normalized.endsWith("/")) return false;
566
+ if (normalized === ".gitignore" || normalized === ".gitattributes") return false;
567
+ const parts = normalized.split("/");
568
+ if (parts.some((part) => PROJECT_CONTENT_EXCLUDE_DIRS.has(part))) return false;
569
+ if (normalized.endsWith(".DS_Store")) return false;
570
+ return true;
571
+ }
572
+
573
+ function runGitLines(basePath: string, args: string[]): string[] {
574
+ try {
575
+ const output = execFileSync("git", args, {
576
+ cwd: basePath,
577
+ stdio: ["ignore", "pipe", "ignore"],
578
+ encoding: "utf-8",
579
+ }).trim();
580
+ return output ? output.split("\n").map((line) => line.trim()).filter(Boolean) : [];
581
+ } catch {
582
+ return [];
583
+ }
584
+ }
585
+
586
+ function listTrackedProjectFiles(basePath: string): string[] {
587
+ return runGitLines(basePath, ["ls-files"])
588
+ .map(normalizeGitPath)
589
+ .filter(isProjectContentFile);
590
+ }
591
+
592
+ function listUntrackedProjectFiles(basePath: string): string[] {
593
+ return runGitLines(basePath, ["ls-files", "--others", "--exclude-standard"])
594
+ .map(normalizeGitPath)
595
+ .filter(isProjectContentFile);
596
+ }
597
+
598
+ function hasKnownProjectMarkers(basePath: string, signals: ProjectSignals): boolean {
599
+ if (signals.detectedFiles.length > 0) return true;
600
+ if (signals.xcodePlatforms.length > 0) return true;
601
+ return false;
602
+ }
603
+
604
+ /**
605
+ * Classify repo presence separately from ecosystem/tooling markers.
606
+ *
607
+ * Known project files identify tooling. Git-tracked/non-ignored content
608
+ * identifies whether this is an existing project at all. This keeps small
609
+ * static or documentation repos from being mislabeled as greenfield.
610
+ */
611
+ export function classifyProject(basePath: string): ProjectClassification {
612
+ const signals = detectProjectSignals(basePath);
613
+ const markers = [...signals.detectedFiles];
614
+
615
+ if (!signals.isGitRepo) {
616
+ return {
617
+ kind: "invalid-repo",
618
+ signals,
619
+ trackedFiles: [],
620
+ untrackedFiles: [],
621
+ contentFiles: [],
622
+ markers,
623
+ reason: "missing .git",
624
+ };
625
+ }
626
+
627
+ const trackedFiles = listTrackedProjectFiles(basePath);
628
+ const untrackedFiles = listUntrackedProjectFiles(basePath);
629
+ const contentFiles = [...new Set([...trackedFiles, ...untrackedFiles])];
630
+ const hasMarkers = hasKnownProjectMarkers(basePath, signals);
631
+
632
+ if (hasMarkers) {
633
+ return {
634
+ kind: "typed-existing",
635
+ signals,
636
+ trackedFiles,
637
+ untrackedFiles,
638
+ contentFiles,
639
+ markers,
640
+ reason: markers.length > 0 ? `detected markers: ${markers.join(", ")}` : "detected project structure",
641
+ };
642
+ }
643
+
644
+ if (contentFiles.length > 0) {
645
+ return {
646
+ kind: "untyped-existing",
647
+ signals,
648
+ trackedFiles,
649
+ untrackedFiles,
650
+ contentFiles,
651
+ markers,
652
+ reason: "project content exists but no recognized tooling markers were found",
653
+ };
654
+ }
655
+
656
+ return {
657
+ kind: "greenfield",
658
+ signals,
659
+ trackedFiles,
660
+ untrackedFiles,
661
+ contentFiles,
662
+ markers,
663
+ reason: "no tracked or non-ignored project content",
664
+ };
665
+ }
666
+
539
667
  // ─── Xcode Platform Detection ───────────────────────────────────────────────────
540
668
 
541
669
  /** Known SDKROOT values → canonical platform names. */
@@ -14,6 +14,7 @@ import { isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
14
14
  import { gsdRoot } from "./paths.js";
15
15
  import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
16
16
  import { loadEffectiveGSDPreferences } from "./preferences.js";
17
+ import { logWarning } from "./workflow-logger.js";
17
18
 
18
19
 
19
20
  import {
@@ -722,16 +723,53 @@ export class GitServiceImpl {
722
723
  if (keyFiles.length === 0) return false;
723
724
 
724
725
  const allExclusions = [...RUNTIME_EXCLUSION_PATHS, ...extraExclusions];
725
- const paths = Array.from(new Set(
726
- keyFiles
727
- .map(file => normalizeRepoRelativePath(this.basePath, file))
728
- .filter((file): file is string => file !== null)
729
- .filter(file => !isExcludedScopedPath(file, allExclusions)),
730
- ));
726
+ const normalized = keyFiles
727
+ .map(file => normalizeRepoRelativePath(this.basePath, file))
728
+ .filter((file): file is string => file !== null)
729
+ .filter(file => !isExcludedScopedPath(file, allExclusions));
730
+
731
+ // Drop entries that don't exist on disk. The LLM occasionally lists files
732
+ // it intended to write but didn't (or names them with wrong casing/path).
733
+ // Pre-`b304f738b` `git add -A` swallowed these silently; the scoped
734
+ // pathspec form passes each path explicitly, so a single bad entry made
735
+ // the whole commit fail (see #5500). Filter so valid paths still commit.
736
+ const missing: string[] = [];
737
+ const existing: string[] = [];
738
+ for (const path of normalized) {
739
+ if (existsSync(join(this.basePath, path))) {
740
+ existing.push(path);
741
+ } else {
742
+ missing.push(path);
743
+ }
744
+ }
745
+ if (missing.length > 0) {
746
+ logWarning(
747
+ "engine",
748
+ `scoped stage: dropping ${missing.length} non-existent keyFile(s) from task commit: ${missing.join(", ")}`,
749
+ { file: "git-service.ts" },
750
+ );
751
+ }
752
+
753
+ const paths = Array.from(new Set(existing));
731
754
  if (paths.length === 0) return false;
732
755
 
733
- nativeAddPaths(this.basePath, paths);
734
- return true;
756
+ try {
757
+ nativeAddPaths(this.basePath, paths);
758
+ return true;
759
+ } catch (err) {
760
+ // Defense-in-depth: even after existence filtering, libgit2/git can
761
+ // still reject paths (gitignore matches, case-only differences on
762
+ // case-insensitive FS, submodule boundaries). Returning false lets
763
+ // autoCommit fall through to smartStage so the commit still goes out
764
+ // — restoring the resilience the unscoped path used to provide.
765
+ const msg = err instanceof Error ? err.message : String(err);
766
+ logWarning(
767
+ "engine",
768
+ `scoped stage failed (${msg}); falling back to smartStage`,
769
+ { file: "git-service.ts" },
770
+ );
771
+ return false;
772
+ }
735
773
  }
736
774
 
737
775
  /** Tracks whether runtime file cleanup has run this session. */
@@ -31,7 +31,7 @@ export interface GraphStep {
31
31
  status: "pending" | "active" | "complete" | "expanded";
32
32
  /** The prompt to dispatch for this step. */
33
33
  prompt: string;
34
- /** IDs of steps that must be "complete" before this step can run. */
34
+ /** IDs of steps that must be terminal before this step can run. */
35
35
  dependsOn: string[];
36
36
  /** For iteration instances: ID of the parent step that was expanded. */
37
37
  parentStepId?: string;
@@ -152,10 +152,17 @@ export function writeGraph(runDir: string, graph: WorkflowGraph): void {
152
152
  }
153
153
 
154
154
  /**
155
- * Get the next pending step whose dependencies are all complete.
155
+ * Return whether a graph step status satisfies dependency edges.
156
+ */
157
+ export function isTerminalStepStatus(status: GraphStep["status"] | undefined): boolean {
158
+ return status === "complete" || status === "expanded";
159
+ }
160
+
161
+ /**
162
+ * Get the next pending step whose dependencies are all terminal.
156
163
  *
157
164
  * Returns the first step (in array order) with status "pending" where
158
- * every step in its `dependsOn` list has status "complete".
165
+ * every step in its `dependsOn` list has status "complete" or "expanded".
159
166
  *
160
167
  * @param graph — the workflow graph to query
161
168
  * @returns The next dispatchable step, or null if none available
@@ -165,8 +172,8 @@ export function getNextPendingStep(graph: WorkflowGraph): GraphStep | null {
165
172
 
166
173
  for (const step of graph.steps) {
167
174
  if (step.status !== "pending") continue;
168
- const depsComplete = step.dependsOn.every(
169
- (depId) => statusMap.get(depId) === "complete",
175
+ const depsComplete = step.dependsOn.every((depId) =>
176
+ isTerminalStepStatus(statusMap.get(depId)),
170
177
  );
171
178
  if (depsComplete) return step;
172
179
  }