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
@@ -50,6 +50,15 @@ export interface FileEditEvidence {
50
50
 
51
51
  export type EvidenceEntry = BashEvidence | FileWriteEvidence | FileEditEvidence;
52
52
 
53
+ const EXECUTION_TOOL_NAMES = new Set([
54
+ "bash",
55
+ "Bash",
56
+ "gsd_exec",
57
+ "gsd_exec_search",
58
+ "mcp__gsd-workflow__gsd_exec",
59
+ "mcp__gsd-workflow__gsd_exec_search",
60
+ ]);
61
+
53
62
  // ─── Module State ───────────────────────────────────────────────────────────
54
63
 
55
64
  let unitEvidence: EvidenceEntry[] = [];
@@ -188,11 +197,11 @@ export function clearEvidenceFromDisk(
188
197
  * Exit codes and output are filled in by recordToolResult after execution.
189
198
  */
190
199
  export function recordToolCall(toolCallId: string, toolName: string, input: Record<string, unknown>): void {
191
- if (toolName === "bash" || toolName === "Bash") {
200
+ if (EXECUTION_TOOL_NAMES.has(toolName)) {
192
201
  unitEvidence.push({
193
202
  kind: "bash",
194
203
  toolCallId,
195
- command: String(input.command ?? ""),
204
+ command: String(input.command ?? input.cmd ?? input.query ?? ""),
196
205
  exitCode: -1,
197
206
  outputSnippet: "",
198
207
  timestamp: Date.now(),
@@ -1,7 +1,7 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
 
4
- import { _buildAbortedPauseContext } from "../bootstrap/agent-end-recovery.js";
4
+ import { _buildAbortedPauseContext, isUserInitiatedAbortMessage } from "../bootstrap/agent-end-recovery.js";
5
5
  import { _buildCancelledUnitStopReason } from "../auto/phases.js";
6
6
 
7
7
  test("aborted agent_end maps errorMessage into structured aborted pause context", () => {
@@ -30,3 +30,9 @@ test("cancelled non-session failures are labeled as unit aborts (not session-cre
30
30
  assert.equal(cancelled.stopReason, "Unit aborted: tool invocation cancelled");
31
31
  assert.equal(cancelled.loopReason, "unit-aborted");
32
32
  });
33
+
34
+ test("provider user-abort errors are recognized as cancellations, not provider outages", () => {
35
+ assert.equal(isUserInitiatedAbortMessage("Claude Code process aborted by user"), true);
36
+ assert.equal(isUserInitiatedAbortMessage("Request aborted by user"), true);
37
+ assert.equal(isUserInitiatedAbortMessage("HTTP 503 Service Unavailable"), false);
38
+ });
@@ -23,6 +23,8 @@ import {
23
23
  _refreshLastCommitForTests,
24
24
  _getLastCommitForTests,
25
25
  _getLastCommitFetchedAtForTests,
26
+ formatRuntimeHealthSignal,
27
+ shouldRenderRoadmapProgress,
26
28
  } from "../auto-dashboard.ts";
27
29
  import {
28
30
  openDatabase,
@@ -193,6 +195,37 @@ test("formatWidgetTokens formats millions with M", () => {
193
195
  assert.equal(formatWidgetTokens(25_000_000), "25M");
194
196
  });
195
197
 
198
+ test("formatRuntimeHealthSignal surfaces idle recovery instead of generic progress", () => {
199
+ const signal = formatRuntimeHealthSignal({
200
+ version: 1,
201
+ unitType: "research-milestone",
202
+ unitId: "M001",
203
+ startedAt: 1_000,
204
+ updatedAt: 600_000,
205
+ phase: "recovered",
206
+ wrapupWarningSent: false,
207
+ continueHereFired: false,
208
+ timeoutAt: null,
209
+ lastProgressAt: 1_000,
210
+ progressCount: 1,
211
+ lastProgressKind: "idle-recovery-retry",
212
+ recoveryAttempts: 1,
213
+ lastRecoveryReason: "idle",
214
+ }, 600_000);
215
+
216
+ assert.deepEqual(signal, {
217
+ level: "yellow",
218
+ summary: "Recovering",
219
+ detail: "retry 1 after idle stall",
220
+ });
221
+ });
222
+
223
+ test("shouldRenderRoadmapProgress hides pre-roadmap zero-slice progress", () => {
224
+ assert.equal(shouldRenderRoadmapProgress(null), false);
225
+ assert.equal(shouldRenderRoadmapProgress({ done: 0, total: 0, activeSliceTasks: null } as any), false);
226
+ assert.equal(shouldRenderRoadmapProgress({ done: 0, total: 1, activeSliceTasks: null } as any), true);
227
+ });
228
+
196
229
  // ─── estimateTimeRemaining ──────────────────────────────────────────────
197
230
 
198
231
  test("estimateTimeRemaining returns null when no ledger data", () => {
@@ -10,6 +10,8 @@ import {
10
10
  _resetPendingResolve,
11
11
  _hasPendingResolveForTest,
12
12
  _setActiveSession,
13
+ _setSessionSwitchInFlight,
14
+ _consumePendingSwitchCancellation,
13
15
  isSessionSwitchInFlight,
14
16
  } from "../auto/resolve.js";
15
17
  import { runUnit } from "../auto/run-unit.js";
@@ -206,6 +208,28 @@ test("runUnit returns cancelled when session creation fails", async () => {
206
208
  assert.equal(pi.calls.length, 0);
207
209
  });
208
210
 
211
+ test("runUnit clears queued switch cancellation when session creation fails", async () => {
212
+ _resetPendingResolve();
213
+
214
+ const ctx = makeMockCtx();
215
+ const pi = makeMockPi();
216
+ const s = makeMockSession({
217
+ newSessionThrows: "connection refused",
218
+ onNewSessionStart: () => {
219
+ resolveAgentEndCancelled({
220
+ message: "Claude Code process aborted by user",
221
+ category: "aborted",
222
+ isTransient: false,
223
+ });
224
+ },
225
+ });
226
+
227
+ const result = await runUnit(ctx, pi, s, "task", "T01", "prompt");
228
+
229
+ assert.equal(result.status, "cancelled");
230
+ assert.equal(_consumePendingSwitchCancellation(), null);
231
+ });
232
+
209
233
  test("runUnit returns cancelled when session creation times out", async () => {
210
234
  _resetPendingResolve();
211
235
 
@@ -221,6 +245,34 @@ test("runUnit returns cancelled when session creation times out", async () => {
221
245
  assert.equal(pi.calls.length, 0);
222
246
  });
223
247
 
248
+ test("runUnit consumes a cancellation queued during session switch before dispatch", async () => {
249
+ _resetPendingResolve();
250
+
251
+ const ctx = makeMockCtx();
252
+ const pi = makeMockPi();
253
+ let cancellationQueued = false;
254
+ const s = makeMockSession({
255
+ newSessionDelayMs: 10,
256
+ onNewSessionStart: () => {
257
+ setTimeout(() => {
258
+ cancellationQueued = !resolveAgentEndCancelled({
259
+ message: "Claude Code process aborted by user",
260
+ category: "aborted",
261
+ isTransient: false,
262
+ });
263
+ }, 0);
264
+ },
265
+ });
266
+
267
+ const result = await runUnit(ctx, pi, s, "plan-slice", "M009/S01", "prompt");
268
+
269
+ assert.equal(cancellationQueued, true);
270
+ assert.equal(result.status, "cancelled");
271
+ assert.equal(result.errorContext?.category, "aborted");
272
+ assert.equal(result.errorContext?.message, "Claude Code process aborted by user");
273
+ assert.equal(pi.calls.length, 0, "queued switch cancellation must prevent prompt dispatch");
274
+ });
275
+
224
276
  test("runUnit keeps the session-switch guard across a late newSession settlement", async () => {
225
277
  _resetPendingResolve();
226
278
  mock.timers.enable();
@@ -879,7 +931,11 @@ test("autoLoop passes structured session-lock failure details to the handler", a
879
931
  );
880
932
  });
881
933
 
882
- test("autoLoop keeps queued sidecar work when the session lock is lost", async () => {
934
+ // Regression for #5308: the iteration prelude must dequeue sidecar items
935
+ // (popping the queue and emitting the `sidecar-dequeue` journal event) BEFORE
936
+ // validateSessionLock + break-on-invalid. Inverting that order silently drops
937
+ // queued sidecar work on lock-loss. Covers first-iteration and mid-session.
938
+ test("autoLoop dequeues sidecar item before session-lock break (first iteration, #5308)", async () => {
883
939
  _resetPendingResolve();
884
940
 
885
941
  const ctx = makeMockCtx();
@@ -911,12 +967,87 @@ test("autoLoop keeps queued sidecar work when the session lock is lost", async (
911
967
 
912
968
  await autoLoop(ctx, pi, s, deps);
913
969
 
914
- assert.equal(s.sidecarQueue.length, 1, "lost session lock must not consume queued sidecar work");
915
- assert.equal(s.sidecarQueue[0]?.unitId, "M001/S01/T01/review");
916
- assert.ok(!journalEvents.includes("sidecar-dequeue"), "sidecar dequeue must happen only after lock validation");
970
+ assert.equal(
971
+ s.sidecarQueue.length,
972
+ 0,
973
+ "sidecar item must be popped on lock-loss iteration (pre-#5308 ordering)",
974
+ );
975
+ assert.ok(
976
+ journalEvents.includes("sidecar-dequeue"),
977
+ "sidecar-dequeue journal event must be emitted before session-lock break",
978
+ );
979
+ assert.ok(
980
+ deps.callLog.includes("handleLostSessionLock"),
981
+ "session lock handler must still fire after sidecar dequeue",
982
+ );
917
983
  assert.ok(!deps.callLog.includes("deriveState"), "lock loss should stop before deriving state");
918
984
  });
919
985
 
986
+ test("autoLoop dequeues sidecar item before session-lock break (mid-session, #5308)", async () => {
987
+ _resetPendingResolve();
988
+
989
+ const ctx = makeMockCtx();
990
+ ctx.ui.setStatus = () => {};
991
+ const pi = makeMockPi();
992
+ const s = makeLoopSession();
993
+
994
+ const journalEvents: string[] = [];
995
+ let lockCheckCount = 0;
996
+ const deps = makeMockDeps({
997
+ // First iteration: lock valid; second iteration: lock invalidates.
998
+ validateSessionLock: () => {
999
+ lockCheckCount += 1;
1000
+ if (lockCheckCount === 1) {
1001
+ return { valid: true } as SessionLockStatus;
1002
+ }
1003
+ return {
1004
+ valid: false,
1005
+ failureReason: "compromised",
1006
+ expectedPid: process.pid,
1007
+ } as SessionLockStatus;
1008
+ },
1009
+ handleLostSessionLock: () => {
1010
+ deps.callLog.push("handleLostSessionLock");
1011
+ },
1012
+ emitJournalEvent: (entry) => {
1013
+ journalEvents.push(entry.eventType);
1014
+ },
1015
+ // Enqueue a sidecar item at the end of iteration 1, so iteration 2 begins
1016
+ // with a non-empty queue and an invalid lock.
1017
+ postUnitPostVerification: async () => {
1018
+ deps.callLog.push("postUnitPostVerification");
1019
+ s.sidecarQueue.push({
1020
+ kind: "hook" as const,
1021
+ unitType: "hook/review",
1022
+ unitId: "M001/S01/T01/review",
1023
+ prompt: "review the code",
1024
+ });
1025
+ return "continue" as const;
1026
+ },
1027
+ });
1028
+
1029
+ const loopPromise = autoLoop(ctx, pi, s, deps);
1030
+ // Allow the loop to reach runUnit's await on iteration 1.
1031
+ await new Promise((r) => setTimeout(r, 50));
1032
+ resolveAgentEnd(makeEvent());
1033
+ await loopPromise;
1034
+
1035
+ assert.ok(lockCheckCount >= 2, "lock validator must run on iteration 2");
1036
+ assert.equal(
1037
+ s.sidecarQueue.length,
1038
+ 0,
1039
+ "queued sidecar item must be popped on the lock-loss iteration",
1040
+ );
1041
+ assert.ok(
1042
+ journalEvents.includes("sidecar-dequeue"),
1043
+ "sidecar-dequeue journal event must be emitted before session-lock break",
1044
+ );
1045
+ assert.ok(
1046
+ deps.callLog.includes("handleLostSessionLock"),
1047
+ "lock-loss handler must still fire on iteration 2",
1048
+ );
1049
+ });
1050
+
920
1051
  test("autoLoop exits on terminal blocked state", async (t) => {
921
1052
  _resetPendingResolve();
922
1053
 
@@ -2010,6 +2141,25 @@ test("resolveAgentEndCancelled without args produces no errorContext field", asy
2010
2141
  assert.equal(resolved.errorContext, undefined, "errorContext must not be present when no args passed");
2011
2142
  });
2012
2143
 
2144
+ test("resolveAgentEndCancelled queues cancellation that arrives during session switch", () => {
2145
+ _resetPendingResolve();
2146
+
2147
+ _setSessionSwitchInFlight(true);
2148
+ const resolved = resolveAgentEndCancelled({
2149
+ message: "Claude Code process aborted by user",
2150
+ category: "aborted",
2151
+ isTransient: false,
2152
+ });
2153
+
2154
+ assert.equal(resolved, false);
2155
+ const pending = _consumePendingSwitchCancellation();
2156
+ assert.ok(pending?.errorContext, "queued cancellation should preserve errorContext");
2157
+ assert.equal(pending.errorContext.category, "aborted");
2158
+ assert.equal(pending.errorContext.message, "Claude Code process aborted by user");
2159
+ assert.equal(_consumePendingSwitchCancellation(), null);
2160
+ _resetPendingResolve();
2161
+ });
2162
+
2013
2163
  // ─── #1571: artifact verification retry ──────────────────────────────────────
2014
2164
 
2015
2165
  test("autoLoop re-iterates when postUnitPreVerification returns retry (#1571)", async () => {
@@ -2477,7 +2627,7 @@ test("autoLoop warns but proceeds for greenfield project (no project files) (#18
2477
2627
  "should not stop with health check failure for greenfield project",
2478
2628
  );
2479
2629
  const greenfieldWarning = notifications.find(
2480
- (n) => n.includes("no recognized project files") && n.includes("greenfield"),
2630
+ (n) => n.includes("no project content yet") && n.includes("greenfield"),
2481
2631
  );
2482
2632
  assert.ok(
2483
2633
  greenfieldWarning,
@@ -1,17 +1,20 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
+ import { mkdtempSync, rmSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
3
6
 
4
7
  import { runFinalize } from "../auto/phases.ts";
5
8
  import { AutoSession } from "../auto/session.ts";
9
+ import { readUnitRuntimeRecord, writeUnitRuntimeRecord } from "../unit-runtime.ts";
6
10
 
7
- test("runFinalize clears currentUnit after successful finalize", async () => {
8
- const s = new AutoSession();
9
- s.basePath = "/tmp/gsd-finalize-current-unit";
10
- s.currentUnit = {
11
- type: "execute-task",
12
- id: "M001/S01/T01",
13
- startedAt: Date.now(),
14
- };
11
+ async function runSuccessfulFinalize(s: AutoSession) {
12
+ const unit = s.currentUnit;
13
+ assert.ok(unit, "test setup must provide currentUnit");
14
+
15
+ writeUnitRuntimeRecord(s.basePath, unit.type, unit.id, unit.startedAt, {
16
+ phase: "dispatched",
17
+ });
15
18
 
16
19
  const deps = {
17
20
  clearUnitTimeout() {},
@@ -26,7 +29,7 @@ test("runFinalize clears currentUnit after successful finalize", async () => {
26
29
  postUnitPostVerification: async () => "continue",
27
30
  };
28
31
 
29
- const result = await runFinalize(
32
+ return runFinalize(
30
33
  {
31
34
  ctx: { ui: { notify() {} } },
32
35
  pi: {},
@@ -38,8 +41,8 @@ test("runFinalize clears currentUnit after successful finalize", async () => {
38
41
  nextSeq: () => 1,
39
42
  } as any,
40
43
  {
41
- unitType: "execute-task",
42
- unitId: "M001/S01/T01",
44
+ unitType: unit.type,
45
+ unitId: unit.id,
43
46
  prompt: "",
44
47
  finalPrompt: "",
45
48
  pauseAfterUatDispatch: false,
@@ -55,7 +58,47 @@ test("runFinalize clears currentUnit after successful finalize", async () => {
55
58
  consecutiveFinalizeTimeouts: 0,
56
59
  },
57
60
  );
61
+ }
62
+
63
+ test("runFinalize clears currentUnit after successful finalize", async () => {
64
+ const base = mkdtempSync(join(tmpdir(), "gsd-finalize-current-unit-"));
65
+ const s = new AutoSession();
66
+ s.basePath = base;
67
+ s.currentUnit = {
68
+ type: "execute-task",
69
+ id: "M001/S01/T01",
70
+ startedAt: Date.now(),
71
+ };
72
+
73
+ try {
74
+ const result = await runSuccessfulFinalize(s);
75
+
76
+ assert.equal(result.action, "next");
77
+ assert.equal(s.currentUnit, null);
78
+ } finally {
79
+ rmSync(base, { recursive: true, force: true });
80
+ }
81
+ });
82
+
83
+ test("runFinalize marks unit runtime finalized after successful finalize", async () => {
84
+ const base = mkdtempSync(join(tmpdir(), "gsd-finalize-runtime-"));
85
+ const s = new AutoSession();
86
+ const startedAt = Date.now();
87
+ s.basePath = base;
88
+ s.currentUnit = {
89
+ type: "complete-milestone",
90
+ id: "M001",
91
+ startedAt,
92
+ };
93
+
94
+ try {
95
+ const result = await runSuccessfulFinalize(s);
96
+ const runtime = readUnitRuntimeRecord(base, "complete-milestone", "M001");
58
97
 
59
- assert.equal(result.action, "next");
60
- assert.equal(s.currentUnit, null);
98
+ assert.equal(result.action, "next");
99
+ assert.equal(runtime?.phase, "finalized");
100
+ assert.equal(runtime?.lastProgressKind, "finalize-success");
101
+ } finally {
102
+ rmSync(base, { recursive: true, force: true });
103
+ }
61
104
  });
@@ -5,13 +5,14 @@ import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { randomUUID } from "node:crypto";
7
7
 
8
- import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, buildLoopRemediationSteps, writeBlockerPlaceholder } from "../auto-recovery.ts";
8
+ import { verifyExpectedArtifact, hasImplementationArtifacts, resolveExpectedArtifactPath, diagnoseExpectedArtifact, buildLoopRemediationSteps, writeBlockerPlaceholder, refreshRecoveryDbForArtifact } from "../auto-recovery.ts";
9
9
  import { resolveMilestoneFile } from "../paths.ts";
10
- import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask } from "../gsd-db.ts";
10
+ import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertGateRow, insertTask, getMilestoneCommitAttributionShas } from "../gsd-db.ts";
11
11
  import { clearParseCache } from "../files.ts";
12
12
  import { parseRoadmap } from "../parsers-legacy.ts";
13
13
  import { invalidateAllCaches } from "../cache.ts";
14
14
  import { deriveState, invalidateStateCache } from "../state.ts";
15
+ import { writeIntegrationBranch } from "../git-service.ts";
15
16
 
16
17
  const tmpDirs: string[] = [];
17
18
 
@@ -174,6 +175,19 @@ test("resolveExpectedArtifactPath returns correct path for all slice-level types
174
175
  }
175
176
  });
176
177
 
178
+ test("refreshRecoveryDbForArtifact treats missing execute-task DB rows as fatal mismatches", () => {
179
+ makeTmpProject();
180
+
181
+ const result = refreshRecoveryDbForArtifact("execute-task", "M001/S01/T01");
182
+
183
+ assert.deepEqual(result, {
184
+ ok: false,
185
+ fatal: true,
186
+ reason: "execute-task-artifact-db-missing",
187
+ message: "Stuck recovery found execute-task M001/S01/T01 artifacts, but no matching DB task row exists after refresh.",
188
+ });
189
+ });
190
+
177
191
  // ─── diagnoseExpectedArtifact ─────────────────────────────────────────────
178
192
 
179
193
  test("diagnoseExpectedArtifact returns description for known types", () => {
@@ -735,6 +749,174 @@ test("hasImplementationArtifacts rejects milestone-scoped main history with only
735
749
  }
736
750
  });
737
751
 
752
+ test("hasImplementationArtifacts finds integration implementation-only commits when milestone branch diff is .gsd-only", () => {
753
+ const base = makeGitBase();
754
+ try {
755
+ mkdirSync(join(base, "src"), { recursive: true });
756
+ writeFileSync(join(base, "src", "feature.ts"), "export function feature() {}\n");
757
+ execFileSync("git", ["add", "src/feature.ts"], { cwd: base, stdio: "ignore" });
758
+ execFileSync("git", ["commit", "-m", "feat: add milestone feature\n\nGSD-Task: S01/T01"], { cwd: base, stdio: "ignore" });
759
+
760
+ mkdirSync(join(base, ".gsd"), { recursive: true });
761
+ openDatabase(join(base, ".gsd", "gsd.db"));
762
+ insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
763
+ insertSlice({
764
+ id: "S01",
765
+ milestoneId: "M001",
766
+ title: "Slice One",
767
+ status: "complete",
768
+ risk: "low",
769
+ depends: [],
770
+ });
771
+ insertTask({
772
+ id: "T01",
773
+ sliceId: "S01",
774
+ milestoneId: "M001",
775
+ title: "Task One",
776
+ status: "complete",
777
+ });
778
+
779
+ execFileSync("git", ["checkout", "-b", "milestone/M001"], { cwd: base, stdio: "ignore" });
780
+ writeIntegrationBranch(base, "M001", "main");
781
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
782
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
783
+ execFileSync("git", ["commit", "-m", "chore: auto-commit after complete-milestone\n\nGSD-Unit: M001"], { cwd: base, stdio: "ignore" });
784
+
785
+ const result = hasImplementationArtifacts(base, "M001");
786
+ assert.equal(
787
+ result,
788
+ "present",
789
+ ".gsd-only milestone closeout diffs should still honor implementation commits already on the integration branch",
790
+ );
791
+ } finally {
792
+ cleanup(base);
793
+ }
794
+ });
795
+
796
+ test("hasImplementationArtifacts backfills untagged main implementation commits from completed task file hints", () => {
797
+ const base = makeGitBase();
798
+ try {
799
+ mkdirSync(join(base, ".gsd"), { recursive: true });
800
+ openDatabase(join(base, ".gsd", "gsd.db"));
801
+ insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
802
+ insertSlice({
803
+ id: "S01",
804
+ milestoneId: "M001",
805
+ title: "Slice One",
806
+ status: "complete",
807
+ risk: "low",
808
+ depends: [],
809
+ });
810
+ insertTask({
811
+ id: "T01",
812
+ sliceId: "S01",
813
+ milestoneId: "M001",
814
+ title: "Task One",
815
+ status: "complete",
816
+ keyFiles: ["index.html", "style.css", "app.js"],
817
+ planning: { files: ["index.html", "style.css", "app.js"] },
818
+ });
819
+
820
+ writeFileSync(join(base, "index.html"), "<main></main>\n");
821
+ writeFileSync(join(base, "style.css"), "main { display: block; }\n");
822
+ writeFileSync(join(base, "app.js"), "document.body.dataset.ready = 'true';\n");
823
+ execFileSync("git", ["add", "index.html", "style.css", "app.js"], { cwd: base, stdio: "ignore" });
824
+ execFileSync("git", ["commit", "-m", "feat: add to-do app with CRUD and localStorage persistence"], { cwd: base, stdio: "ignore" });
825
+ const commitSha = execFileSync("git", ["rev-parse", "HEAD"], { cwd: base, encoding: "utf-8" }).trim();
826
+
827
+ const result = hasImplementationArtifacts(base, "M001");
828
+ assert.equal(
829
+ result,
830
+ "present",
831
+ "completed task file hints should repair prior untagged implementation commits on main",
832
+ );
833
+ assert.deepEqual(getMilestoneCommitAttributionShas("M001"), [commitSha]);
834
+ } finally {
835
+ cleanup(base);
836
+ }
837
+ });
838
+
839
+ test("hasImplementationArtifacts does not backfill untagged commits before milestone creation", () => {
840
+ const base = makeGitBase();
841
+ try {
842
+ writeFileSync(join(base, "app.js"), "document.body.dataset.ready = 'old';\n");
843
+ execFileSync("git", ["add", "app.js"], { cwd: base, stdio: "ignore" });
844
+ execFileSync("git", ["commit", "-m", "feat: old app work"], {
845
+ cwd: base,
846
+ stdio: "ignore",
847
+ env: {
848
+ ...process.env,
849
+ GIT_AUTHOR_DATE: "2020-01-01T00:00:00Z",
850
+ GIT_COMMITTER_DATE: "2020-01-01T00:00:00Z",
851
+ },
852
+ });
853
+
854
+ mkdirSync(join(base, ".gsd"), { recursive: true });
855
+ openDatabase(join(base, ".gsd", "gsd.db"));
856
+ insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
857
+ insertSlice({
858
+ id: "S01",
859
+ milestoneId: "M001",
860
+ title: "Slice One",
861
+ status: "complete",
862
+ risk: "low",
863
+ depends: [],
864
+ });
865
+ insertTask({
866
+ id: "T01",
867
+ sliceId: "S01",
868
+ milestoneId: "M001",
869
+ title: "Task One",
870
+ status: "complete",
871
+ keyFiles: ["app.js"],
872
+ planning: { files: ["app.js"] },
873
+ });
874
+
875
+ const result = hasImplementationArtifacts(base, "M001");
876
+ assert.equal(result, "absent", "pre-milestone commits must not be attributed to the milestone");
877
+ assert.deepEqual(getMilestoneCommitAttributionShas("M001"), []);
878
+ } finally {
879
+ cleanup(base);
880
+ }
881
+ });
882
+
883
+ test("hasImplementationArtifacts does not backfill unrelated untagged implementation commits", () => {
884
+ const base = makeGitBase();
885
+ try {
886
+ mkdirSync(join(base, ".gsd"), { recursive: true });
887
+ openDatabase(join(base, ".gsd", "gsd.db"));
888
+ insertMilestone({ id: "M001", title: "Milestone One", status: "active" });
889
+ insertSlice({
890
+ id: "S01",
891
+ milestoneId: "M001",
892
+ title: "Slice One",
893
+ status: "complete",
894
+ risk: "low",
895
+ depends: [],
896
+ });
897
+ insertTask({
898
+ id: "T01",
899
+ sliceId: "S01",
900
+ milestoneId: "M001",
901
+ title: "Task One",
902
+ status: "complete",
903
+ keyFiles: ["src/expected.ts"],
904
+ planning: { files: ["src/expected.ts"] },
905
+ });
906
+
907
+ mkdirSync(join(base, "src"), { recursive: true });
908
+ writeFileSync(join(base, "src", "unrelated.ts"), "export const unrelated = true;\n");
909
+ execFileSync("git", ["add", "src/unrelated.ts"], { cwd: base, stdio: "ignore" });
910
+ execFileSync("git", ["commit", "-m", "feat: unrelated work"], { cwd: base, stdio: "ignore" });
911
+
912
+ const result = hasImplementationArtifacts(base, "M001");
913
+ assert.equal(result, "absent", "backfill must require overlap with completed task file hints");
914
+ assert.deepEqual(getMilestoneCommitAttributionShas("M001"), []);
915
+ } finally {
916
+ cleanup(base);
917
+ }
918
+ });
919
+
738
920
  test("hasImplementationArtifacts treats empty non-integration branch diff as absent (#4699)", () => {
739
921
  const base = makeGitBase();
740
922
  try {