gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.3065f7bfa

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 (377) hide show
  1. package/README.md +4 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/loop.js +32 -1
  4. package/dist/resources/extensions/gsd/auto/phases.js +178 -108
  5. package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +20 -30
  7. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  8. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +17 -4
  11. package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
  12. package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
  13. package/dist/resources/extensions/gsd/auto-start.js +197 -6
  14. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  15. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  16. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  17. package/dist/resources/extensions/gsd/auto.js +86 -26
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +42 -2
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +49 -36
  20. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +15 -5
  21. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +33 -20
  22. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +7 -1
  23. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +9 -3
  24. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +8 -2
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +259 -28
  26. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  27. package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
  28. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  29. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  30. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  31. package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
  32. package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
  33. package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
  34. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  35. package/dist/resources/extensions/gsd/git-service.js +36 -4
  36. package/dist/resources/extensions/gsd/gsd-db.js +46 -13
  37. package/dist/resources/extensions/gsd/guided-flow.js +99 -38
  38. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  39. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  40. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  41. package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
  42. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  43. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  44. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  45. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  46. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  47. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
  48. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  49. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  50. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  53. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  54. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  55. package/dist/resources/extensions/gsd/quick.js +34 -2
  56. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  57. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  58. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  59. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  60. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  61. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  62. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  63. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  64. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  65. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  66. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  67. package/dist/resources/extensions/gsd/worktree-resolver.js +68 -21
  68. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  69. package/dist/web/standalone/.next/BUILD_ID +1 -1
  70. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  71. package/dist/web/standalone/.next/build-manifest.json +2 -2
  72. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  73. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.html +1 -1
  90. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  97. package/dist/web/standalone/.next/server/middleware-build-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/package.json +3 -3
  102. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  103. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  104. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  105. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  106. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  107. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  108. package/packages/native/tsconfig.tsbuildinfo +1 -1
  109. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  110. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  111. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  112. package/packages/pi-agent-core/dist/agent.d.ts +5 -0
  113. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  114. package/packages/pi-agent-core/dist/agent.js +2 -0
  115. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  116. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  117. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  118. package/packages/pi-agent-core/dist/index.js +2 -0
  119. package/packages/pi-agent-core/dist/index.js.map +1 -1
  120. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  121. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  122. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  123. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  124. package/packages/pi-agent-core/dist/types.d.ts +9 -0
  125. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  126. package/packages/pi-agent-core/dist/types.js.map +1 -1
  127. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  128. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  129. package/packages/pi-agent-core/src/agent.ts +8 -0
  130. package/packages/pi-agent-core/src/index.ts +2 -0
  131. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  132. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  133. package/packages/pi-agent-core/src/types.ts +14 -0
  134. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  135. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
  136. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
  138. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
  140. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/agent-session.js +44 -7
  142. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  144. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  146. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  148. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  150. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  151. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  152. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  153. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  154. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  155. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  156. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  157. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  158. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  159. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  160. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  161. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  163. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  165. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/extensions/runner.js +6 -6
  167. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
  169. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +39 -1
  171. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  174. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  178. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  180. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
  182. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  184. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  186. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  188. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  190. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  192. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  194. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
  196. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -5
  199. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  201. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  204. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  205. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  206. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  207. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  208. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  209. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  210. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  211. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  212. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
  213. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
  214. package/packages/pi-coding-agent/src/core/agent-session.ts +48 -7
  215. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  216. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  217. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  218. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  219. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  220. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  221. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
  222. package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
  223. package/packages/pi-coding-agent/src/core/extensions/types.ts +42 -1
  224. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  225. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  226. package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
  227. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  228. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  229. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  230. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
  231. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  232. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
  233. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  234. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  235. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  236. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  237. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  238. package/packages/pi-tui/dist/tui.js +18 -8
  239. package/packages/pi-tui/dist/tui.js.map +1 -1
  240. package/packages/pi-tui/src/tui.ts +20 -8
  241. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  242. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
  243. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  244. package/src/resources/extensions/gsd/auto/phases.ts +251 -172
  245. package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
  246. package/src/resources/extensions/gsd/auto/run-unit.ts +25 -30
  247. package/src/resources/extensions/gsd/auto/session.ts +8 -0
  248. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  249. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
  250. package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
  251. package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
  252. package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
  253. package/src/resources/extensions/gsd/auto-start.ts +230 -9
  254. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  255. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  256. package/src/resources/extensions/gsd/auto-worktree.ts +123 -0
  257. package/src/resources/extensions/gsd/auto.ts +98 -21
  258. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +49 -1
  259. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +50 -36
  260. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +16 -5
  261. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +34 -19
  262. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +8 -1
  263. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +10 -3
  264. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +9 -2
  265. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +305 -28
  266. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  267. package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
  268. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  269. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  270. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  271. package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
  272. package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
  273. package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
  274. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  275. package/src/resources/extensions/gsd/git-service.ts +46 -8
  276. package/src/resources/extensions/gsd/gsd-db.ts +50 -13
  277. package/src/resources/extensions/gsd/guided-flow.ts +123 -45
  278. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  279. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  280. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  281. package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
  282. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  283. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  284. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  285. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  286. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  287. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  288. package/src/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
  289. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  290. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  291. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  292. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  294. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  295. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  296. package/src/resources/extensions/gsd/quick.ts +37 -2
  297. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +2 -2
  298. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +417 -10
  299. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
  300. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
  301. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +168 -6
  302. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
  303. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  304. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  305. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  306. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  307. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  308. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  309. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  310. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
  311. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  312. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  313. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  314. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  315. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  316. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
  317. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
  318. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +6 -3
  319. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +239 -1
  320. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  321. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  322. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  323. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
  324. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  325. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  326. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
  327. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  328. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
  329. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
  330. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  331. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  332. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  333. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  334. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  335. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  336. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  337. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
  338. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +3 -3
  339. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  340. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +38 -17
  341. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  342. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  343. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +106 -0
  344. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  345. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
  346. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  347. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
  348. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  349. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  350. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  351. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  352. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
  353. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  354. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
  355. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  356. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -4
  357. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  358. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  359. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
  360. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  361. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  362. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +167 -4
  363. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  364. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  365. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  366. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  367. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  368. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  369. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  370. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  371. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  372. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  373. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  374. package/src/resources/extensions/gsd/worktree-resolver.ts +85 -19
  375. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -97
  376. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_buildManifest.js +0 -0
  377. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_ssgManifest.js +0 -0
@@ -0,0 +1,96 @@
1
+ // GSD-2 + src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts
2
+ // Regression: bootstrap must rederive `currentMilestoneId` from an unmerged
3
+ // completed milestone branch when in-memory state was lost across a process
4
+ // restart (#5538-followup).
5
+
6
+ import test from "node:test";
7
+ import assert from "node:assert/strict";
8
+
9
+ import { _selectResumableMilestone } from "../auto-start.js";
10
+
11
+ const ALL_COMPLETE = (_id: string) => true;
12
+ const NEVER_COMPLETE = (_id: string) => false;
13
+ const HAS_COMMITS = (_branch: string) => 1;
14
+ const NO_COMMITS = (_branch: string) => 0;
15
+
16
+ test("returns null when no branches exist", () => {
17
+ const result = _selectResumableMilestone([], new Set(), ALL_COMPLETE, HAS_COMMITS);
18
+ assert.equal(result, null);
19
+ });
20
+
21
+ test("returns null when every milestone branch is already merged", () => {
22
+ const branches = ["milestone/M001", "milestone/M002"];
23
+ const merged = new Set(branches);
24
+ const result = _selectResumableMilestone(branches, merged, ALL_COMPLETE, HAS_COMMITS);
25
+ assert.equal(result, null);
26
+ });
27
+
28
+ test("returns null when no candidate milestones are complete", () => {
29
+ const branches = ["milestone/M002"];
30
+ const result = _selectResumableMilestone(branches, new Set(), NEVER_COMPLETE, HAS_COMMITS);
31
+ assert.equal(result, null);
32
+ });
33
+
34
+ test("returns null when no branch has commits ahead", () => {
35
+ const branches = ["milestone/M002"];
36
+ const result = _selectResumableMilestone(branches, new Set(), ALL_COMPLETE, NO_COMMITS);
37
+ assert.equal(result, null);
38
+ });
39
+
40
+ test("returns the unmerged completed milestone (regression: M002 stranded after restart)", () => {
41
+ // Repro of test12345 state: M001 ✅ merged, M002 ✅ unmerged, M003 🔄.
42
+ // Bootstrap must seed currentMilestoneId = "M002" so the loop's transition
43
+ // guard fires when the next iteration sees mid="M003".
44
+ const branches = ["milestone/M002", "milestone/M003"];
45
+ const merged = new Set<string>(); // none merged from this list
46
+ const isComplete = (id: string) => id === "M002"; // M003 still in progress
47
+ const result = _selectResumableMilestone(branches, merged, isComplete, HAS_COMMITS);
48
+ assert.equal(result, "M002");
49
+ });
50
+
51
+ test("picks the lex-greatest milestone when multiple candidates exist", () => {
52
+ // M001, M002 both unmerged complete -> pick M002 (the most recent).
53
+ const branches = ["milestone/M001", "milestone/M002"];
54
+ const result = _selectResumableMilestone(
55
+ branches,
56
+ new Set(),
57
+ ALL_COMPLETE,
58
+ HAS_COMMITS,
59
+ );
60
+ assert.equal(result, "M002");
61
+ });
62
+
63
+ test("ignores branch names that don't follow the milestone/ prefix", () => {
64
+ const branches = ["feature/something", "milestone/M002", "fix/bug-1"];
65
+ const result = _selectResumableMilestone(
66
+ branches,
67
+ new Set(),
68
+ ALL_COMPLETE,
69
+ HAS_COMMITS,
70
+ );
71
+ assert.equal(result, "M002");
72
+ });
73
+
74
+ test("isComplete callback throwing skips that milestone but does not crash", () => {
75
+ const branches = ["milestone/M001", "milestone/M002"];
76
+ const isComplete = (id: string) => {
77
+ if (id === "M001") throw new Error("db unavailable for M001");
78
+ return true;
79
+ };
80
+ // Implementation choice: a thrown isComplete is propagated. Wrapping in
81
+ // try/catch happens at the production wrapper level (findUnmergedCompletedMilestone).
82
+ // Verify the helper itself surfaces the error so callers see real failures.
83
+ assert.throws(() => _selectResumableMilestone(branches, new Set(), isComplete, HAS_COMMITS));
84
+ });
85
+
86
+ test("commitsAhead callback throwing for one branch falls through to others", () => {
87
+ // Production wrapper: commits-ahead failures should not abort the search.
88
+ // The helper catches throws from commitsAhead per-branch and treats as 0.
89
+ const branches = ["milestone/M001", "milestone/M002"];
90
+ const commitsAhead = (branch: string) => {
91
+ if (branch === "milestone/M001") throw new Error("rev-walk failed");
92
+ return 5;
93
+ };
94
+ const result = _selectResumableMilestone(branches, new Set(), ALL_COMPLETE, commitsAhead);
95
+ assert.equal(result, "M002");
96
+ });
@@ -0,0 +1,106 @@
1
+ // GSD-2 + src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts
2
+ // Regression: session-transition aborts must not be classified as user cancellations.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+
7
+ import { _handleSessionSwitchAgentEnd } from "../bootstrap/agent-end-recovery.js";
8
+ import type { ErrorContext } from "../auto/types.js";
9
+
10
+ test("user-abort message during session-switch is dropped (not propagated as cancellation)", () => {
11
+ // The Anthropic SDK emits this exact string when newSession() aborts an
12
+ // in-flight stream during a unit-to-unit session transition. Before the fix
13
+ // this was misclassified as a user cancellation and killed auto-mode with
14
+ // "Auto-mode stopped — Unit aborted: Claude Code process aborted by user".
15
+ let cancelledWith: ErrorContext | null = null;
16
+ const resolveCancelled = (ctx: ErrorContext) => {
17
+ cancelledWith = ctx;
18
+ return true;
19
+ };
20
+
21
+ _handleSessionSwitchAgentEnd(
22
+ { stopReason: "error", errorMessage: "Claude Code process aborted by user" },
23
+ resolveCancelled,
24
+ );
25
+ assert.equal(cancelledWith, null, "SDK user-abort during session-switch must not propagate cancellation");
26
+
27
+ _handleSessionSwitchAgentEnd(
28
+ { stopReason: "error", errorMessage: "Request aborted by user" },
29
+ resolveCancelled,
30
+ );
31
+ assert.equal(cancelledWith, null, "proxy user-abort during session-switch must not propagate cancellation");
32
+ });
33
+
34
+ test("genuine stopReason='aborted' with errorMessage during session-switch still propagates", () => {
35
+ // Regression guard for prior behavior: genuine aborts with diagnostic content
36
+ // continue to surface as cancellations so transient-pause recovery can run.
37
+ let cancelledWith: { message: string; category: string; isTransient?: boolean } | null = null;
38
+ const resolveCancelled = (ctx: ErrorContext) => {
39
+ cancelledWith = ctx;
40
+ return true;
41
+ };
42
+
43
+ _handleSessionSwitchAgentEnd(
44
+ {
45
+ stopReason: "aborted",
46
+ errorMessage: "stream torn down mid-flight",
47
+ content: [{ type: "text", text: "partial output" }],
48
+ },
49
+ resolveCancelled,
50
+ );
51
+
52
+ assert.deepEqual(cancelledWith, {
53
+ message: "stream torn down mid-flight",
54
+ category: "aborted",
55
+ isTransient: true,
56
+ });
57
+ });
58
+
59
+ test("empty-content aborted during session-switch is silently ignored", () => {
60
+ // Empty-content aborted is a non-fatal LLM stop; we must not pause/cancel.
61
+ let cancelledWith: unknown = null;
62
+ const resolveCancelled = (ctx: ErrorContext) => {
63
+ cancelledWith = ctx;
64
+ return true;
65
+ };
66
+
67
+ _handleSessionSwitchAgentEnd(
68
+ { stopReason: "aborted", content: [] },
69
+ resolveCancelled,
70
+ );
71
+
72
+ assert.equal(cancelledWith, null);
73
+ });
74
+
75
+ test("non-abort errors during session-switch are not propagated through this helper", () => {
76
+ // Real provider errors (rate-limit, network, unsupported-model) are handled
77
+ // by the post-switch retry pipeline — not by the in-flight switch handler.
78
+ let cancelledWith: unknown = null;
79
+ const resolveCancelled = (ctx: ErrorContext) => {
80
+ cancelledWith = ctx;
81
+ return true;
82
+ };
83
+
84
+ _handleSessionSwitchAgentEnd(
85
+ { stopReason: "error", errorMessage: "rate limit exceeded" },
86
+ resolveCancelled,
87
+ );
88
+
89
+ assert.equal(cancelledWith, null);
90
+ });
91
+
92
+ test("malformed lastMsg is rejected gracefully", () => {
93
+ let calls = 0;
94
+ const resolveCancelled = (_ctx: unknown) => {
95
+ calls += 1;
96
+ return true;
97
+ };
98
+
99
+ _handleSessionSwitchAgentEnd(undefined, resolveCancelled as never);
100
+ _handleSessionSwitchAgentEnd(null, resolveCancelled as never);
101
+ _handleSessionSwitchAgentEnd("not an object", resolveCancelled as never);
102
+ _handleSessionSwitchAgentEnd({}, resolveCancelled as never);
103
+ _handleSessionSwitchAgentEnd({ stopReason: "completed" }, resolveCancelled as never);
104
+
105
+ assert.equal(calls, 0, "malformed or non-abort lastMsg must not invoke cancellation");
106
+ });
@@ -101,3 +101,30 @@ test("registerSigtermHandler deregisters previous handler from all signals", ()
101
101
  // Clean up
102
102
  deregisterSigtermHandler(handler2);
103
103
  });
104
+
105
+ test("registered signal handler runs best-effort cleanup before exiting", () => {
106
+ let cleanupCalled = false;
107
+ let exitCode: number | string | null | undefined;
108
+ const originalExit = process.exit;
109
+ const handler = registerSigtermHandler(
110
+ "/tmp/test-signal-cleanup",
111
+ null,
112
+ () => {
113
+ cleanupCalled = true;
114
+ },
115
+ );
116
+
117
+ (process as any).exit = ((code?: number | string | null) => {
118
+ exitCode = code;
119
+ throw new Error("process.exit intercepted");
120
+ }) as never;
121
+
122
+ try {
123
+ assert.throws(() => handler(), /process\.exit intercepted/);
124
+ assert.equal(cleanupCalled, true);
125
+ assert.equal(exitCode, 0);
126
+ } finally {
127
+ (process as any).exit = originalExit;
128
+ deregisterSigtermHandler(handler);
129
+ }
130
+ });
@@ -59,6 +59,26 @@ test("guided-flow complete branch offers a chooser for next milestone or status"
59
59
  assert.match(branchChunk, /dispatchWorkflow\(pi, await prepareAndBuildDiscussPrompt\(/, "complete branch should dispatch the prepared discuss prompt");
60
60
  });
61
61
 
62
+ test("guided-flow quick task choices prompt for text and route through /gsd quick", () => {
63
+ const guidedFlowSource = readFileSync(join(import.meta.dirname, "..", "guided-flow.ts"), "utf-8");
64
+
65
+ assert.match(
66
+ guidedFlowSource,
67
+ /async function runQuickTaskChoice\([\s\S]*ctx\.ui\.input\("Quick task"[\s\S]*await import\("\.\/quick\.js"\)[\s\S]*await handleQuick\(task,\s*ctx,\s*pi\)/,
68
+ "quick task chooser should prompt for task text and route through handleQuick",
69
+ );
70
+
71
+ const notifyOnlyPattern = /if \(choice === "quick_task"\) \{\s*ctx\.ui\.notify\("Run \/gsd quick <task>/;
72
+ assert.doesNotMatch(
73
+ guidedFlowSource,
74
+ notifyOnlyPattern,
75
+ "quick task chooser must not merely print instructions after selection",
76
+ );
77
+
78
+ const quickChoiceCalls = guidedFlowSource.match(/if \(choice === "quick_task"\) \{\s*await runQuickTaskChoice\(ctx,\s*pi\);/g) ?? [];
79
+ assert.equal(quickChoiceCalls.length, 3, "all guided-flow quick task choices should dispatch the helper");
80
+ });
81
+
62
82
  test("dispatcher routes multi-word freeform /gsd input through /gsd do", () => {
63
83
  const dispatcherSource = readFileSync(join(import.meta.dirname, "..", "commands", "dispatcher.ts"), "utf-8");
64
84
 
@@ -15,10 +15,11 @@
15
15
  * (the fix) and verifies it does not crash.
16
16
  */
17
17
 
18
- import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
18
+ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
19
19
  import { join } from "node:path";
20
20
  import { tmpdir } from "node:os";
21
21
  import { recoverTimedOutUnit, type RecoveryContext } from "../auto-timeout-recovery.ts";
22
+ import { closeDatabase, insertMilestone, insertSlice, insertTask, openDatabase } from "../gsd-db.ts";
22
23
  import { test } from 'node:test';
23
24
  import assert from 'node:assert/strict';
24
25
 
@@ -39,6 +40,14 @@ function makeMockPi() {
39
40
  } as any;
40
41
  }
41
42
 
43
+ function makeRecordingPi() {
44
+ const messages: unknown[] = [];
45
+ return {
46
+ messages,
47
+ sendMessage: (message: unknown) => { messages.push(message); },
48
+ } as any;
49
+ }
50
+
42
51
  // ═══ #1855: empty RecoveryContext (basePath undefined) crashes ════════════════
43
52
 
44
53
  {
@@ -63,6 +72,45 @@ function makeMockPi() {
63
72
  assert.ok(crashed, "should crash when basePath is undefined (reproduces #1855)");
64
73
  }
65
74
 
75
+ // ═══ DB-complete execute-task recovery advances without steering ═════════════
76
+
77
+ {
78
+ console.log("\n=== execute-task timeout recovery trusts closed DB status ===");
79
+ const base = mkdtempSync(join(tmpdir(), "gsd-timeout-db-complete-"));
80
+ mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
81
+
82
+ try {
83
+ openDatabase(join(base, ".gsd", "gsd.db"));
84
+ insertMilestone({ id: "M001", title: "Milestone", status: "active" });
85
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "in_progress" });
86
+ insertTask({ id: "T01", milestoneId: "M001", sliceId: "S01", title: "Task", status: "complete" });
87
+ writeFileSync(
88
+ join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md"),
89
+ "# S01\n\n## Tasks\n\n- [ ] **T01: Task** `est:10m`\n",
90
+ "utf-8",
91
+ );
92
+ writeFileSync(join(base, ".gsd", "STATE.md"), "## Next Action\nExecute T01 for S01: Task\n", "utf-8");
93
+
94
+ const ctx = makeMockCtx();
95
+ const pi = makeRecordingPi();
96
+ const result = await recoverTimedOutUnit(ctx, pi, "execute-task", "M001/S01/T01", "idle", {
97
+ basePath: base,
98
+ verbose: false,
99
+ currentUnitStartedAt: Date.now(),
100
+ unitRecoveryCount: new Map(),
101
+ });
102
+
103
+ assert.equal(result, "recovered", "db-complete task should recover immediately");
104
+ assert.equal(pi.messages.length, 0, "db-complete task should not send steering recovery");
105
+ const runtime = JSON.parse(readFileSync(join(base, ".gsd", "runtime", "units", "execute-task-M001-S01-T01.json"), "utf-8"));
106
+ assert.equal(runtime.phase, "finalized", "db-complete task should be finalized");
107
+ assert.equal(runtime.recovery.dbComplete, true, "runtime recovery should record DB completion");
108
+ } finally {
109
+ closeDatabase();
110
+ rmSync(base, { recursive: true, force: true });
111
+ }
112
+ }
113
+
66
114
  // ═══ #1855: valid RecoveryContext does not crash ═════════════════════════════
67
115
 
68
116
  {
@@ -4,6 +4,7 @@ import { readFileSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
5
 
6
6
  import { _withDetachedAutoKeepaliveForTest } from "../auto.ts";
7
+ import { _scheduleAutoStartAfterIdleForTest } from "../guided-flow.ts";
7
8
 
8
9
  const gsdDir = resolve(import.meta.dirname, "..");
9
10
 
@@ -96,6 +97,23 @@ test("auto bootstrap validates blocked directories before touching .gsd migratio
96
97
  );
97
98
  });
98
99
 
100
+ test("fresh start registers the auto worker before bootstrap enters worktree flow (#5405)", () => {
101
+ const autoSrc = readGsdFile("auto.ts");
102
+ const startAutoIdx = autoSrc.indexOf("export async function startAuto(");
103
+ const startAutoBody = autoSrc.slice(startAutoIdx);
104
+
105
+ const preBootstrapRegisterIdx = startAutoBody.indexOf("registerAutoWorkerForSession(s, base);");
106
+ const bootstrapCallIdx = startAutoBody.indexOf("const ready = await bootstrapAutoSession(");
107
+
108
+ assert.ok(startAutoIdx > -1, "startAuto should exist");
109
+ assert.ok(preBootstrapRegisterIdx > -1, "startAuto should register worker before bootstrap");
110
+ assert.ok(bootstrapCallIdx > -1, "startAuto should call bootstrapAutoSession");
111
+ assert.ok(
112
+ preBootstrapRegisterIdx < bootstrapCallIdx,
113
+ "worker registration must happen before bootstrap so enterMilestone can claim milestone leases on first entry",
114
+ );
115
+ });
116
+
99
117
  test("startAutoDetached reports failures asynchronously (#3733)", () => {
100
118
  const autoSrc = readGsdFile("auto.ts");
101
119
 
@@ -185,3 +203,40 @@ test("detached auto-start preserves milestone lock across pause/stop cleanup (#3
185
203
  "AutoSession should track the detached milestone lock explicitly",
186
204
  );
187
205
  });
206
+
207
+ test("discussion auto-start waits for the current command context to become idle", async () => {
208
+ let releaseIdle!: () => void;
209
+ const idle = new Promise<void>((resolveIdle) => {
210
+ releaseIdle = resolveIdle;
211
+ });
212
+ const launches: unknown[][] = [];
213
+ const ctx = {
214
+ waitForIdle: () => idle,
215
+ ui: {
216
+ notify: () => {},
217
+ },
218
+ } as any;
219
+
220
+ _scheduleAutoStartAfterIdleForTest(
221
+ ctx,
222
+ {} as any,
223
+ "/tmp/gsd-auto-start-idle-test",
224
+ false,
225
+ { step: true },
226
+ (...args: unknown[]) => {
227
+ launches.push(args);
228
+ },
229
+ );
230
+
231
+ await Promise.resolve();
232
+ assert.equal(launches.length, 0, "auto-start must not launch before waitForIdle resolves");
233
+
234
+ releaseIdle();
235
+ await Promise.resolve();
236
+ assert.equal(launches.length, 0, "auto-start should defer launch to the next timer turn");
237
+
238
+ await new Promise((resolveTimer) => setTimeout(resolveTimer, 0));
239
+ assert.equal(launches.length, 1);
240
+ assert.equal(launches[0][2], "/tmp/gsd-auto-start-idle-test");
241
+ assert.deepEqual(launches[0][4], { step: true });
242
+ });
@@ -291,6 +291,7 @@ describe("#2945 Bug 3: mergeAndExit must teardown worktree after successful merg
291
291
  getAutoWorktreePath: () => null,
292
292
  autoCommitCurrentBranch: () => {},
293
293
  getCurrentBranch: () => "main",
294
+ checkoutBranch: () => {},
294
295
  autoWorktreeBranch: () => "gsd/M001",
295
296
  resolveMilestoneFile: () => "/mock/roadmap.md",
296
297
  readFileSync: () => "# Roadmap content",
@@ -44,4 +44,13 @@ describe('status opens DB before deriveState (#3691)', () => {
44
44
  assert.match(quickSrc, /getIsolationMode\(\)\s*!==\s*"none"/,
45
45
  'quick.ts should compare isolation mode against "none"');
46
46
  });
47
+
48
+ test('quick task prompt handles external .gsd without staging quick files', () => {
49
+ assert.match(quickSrc, /isExternalGsdRoot/,
50
+ 'quick.ts should detect whether .gsd resolves outside the project repo');
51
+ assert.match(quickSrc, /do not stage or commit `\.gsd\/quick\/\.\.\.`/,
52
+ 'external-state quick tasks must tell the agent not to stage .gsd/quick files');
53
+ assert.match(quickSrc, /nothing in the project repo to commit/,
54
+ 'external-state quick tasks should allow summary-only work without a git commit');
55
+ });
47
56
  });
@@ -0,0 +1,112 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: System context memory gating regression tests.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+
7
+ import { buildContextMessage, isLowEntropyResumePrompt, loadMemoryBlock } from "../bootstrap/system-context.ts";
8
+ import { closeDatabase, openDatabase } from "../gsd-db.ts";
9
+ import { createMemory } from "../memory-store.ts";
10
+
11
+ test("buildContextMessage marks hidden guided context when memory is supplied", () => {
12
+ const message = buildContextMessage({
13
+ memoryBlock: "\n\n[MEMORY]\n\n- keep this",
14
+ injection: "[GSD Guided Execute Context]\nUse the task plan.",
15
+ forensicsInjection: null,
16
+ });
17
+
18
+ assert.ok(message, "expected hidden context message");
19
+ assert.equal(message.customType, "gsd-guided-context");
20
+ assert.equal(message.display, false);
21
+ assert.match(message.content, /\[GSD Context Metadata\]\n- Memory supplied: yes/);
22
+ assert.ok(
23
+ message.content.indexOf("Memory supplied: yes") < message.content.indexOf("[GSD Guided Execute Context]"),
24
+ "memory marker should appear before guided context",
25
+ );
26
+ });
27
+
28
+ test("buildContextMessage caps hidden context by default", () => {
29
+ const original = process.env.PI_GSD_CONTEXT_MAX_CHARS;
30
+ delete process.env.PI_GSD_CONTEXT_MAX_CHARS;
31
+ try {
32
+ const message = buildContextMessage({
33
+ memoryBlock: "",
34
+ injection: `[GSD Guided Execute Context]\n${"large context\n".repeat(500)}`,
35
+ forensicsInjection: null,
36
+ });
37
+
38
+ assert.ok(message, "expected hidden context message");
39
+ assert.equal(message.customType, "gsd-guided-context");
40
+ assert.ok(message.content.length <= 4000);
41
+ assert.match(message.content, /\[GSD Context Truncated\]/);
42
+ } finally {
43
+ if (original === undefined) delete process.env.PI_GSD_CONTEXT_MAX_CHARS;
44
+ else process.env.PI_GSD_CONTEXT_MAX_CHARS = original;
45
+ }
46
+ });
47
+
48
+ test("buildContextMessage supports explicit context cap override", () => {
49
+ const original = process.env.PI_GSD_CONTEXT_MAX_CHARS;
50
+ process.env.PI_GSD_CONTEXT_MAX_CHARS = "1200";
51
+ try {
52
+ const message = buildContextMessage({
53
+ memoryBlock: "",
54
+ injection: `[GSD Guided Execute Context]\n${"large context\n".repeat(200)}`,
55
+ forensicsInjection: null,
56
+ });
57
+
58
+ assert.ok(message, "expected hidden context message");
59
+ assert.equal(message.customType, "gsd-guided-context");
60
+ assert.ok(message.content.length <= 1200);
61
+ assert.match(message.content, /\[GSD Context Truncated\]/);
62
+ } finally {
63
+ if (original === undefined) delete process.env.PI_GSD_CONTEXT_MAX_CHARS;
64
+ else process.env.PI_GSD_CONTEXT_MAX_CHARS = original;
65
+ }
66
+ });
67
+
68
+ test("buildContextMessage does not add memory marker when only guided context is supplied", () => {
69
+ const message = buildContextMessage({
70
+ memoryBlock: "",
71
+ injection: "[GSD Guided Execute Context]\nUse the task plan.",
72
+ forensicsInjection: null,
73
+ });
74
+
75
+ assert.ok(message, "expected guided context message");
76
+ assert.equal(message.customType, "gsd-guided-context");
77
+ assert.doesNotMatch(message.content, /Memory supplied: yes/);
78
+ });
79
+
80
+ test("loadMemoryBlock keeps critical memories while gating prompt-relevant query hits", async () => {
81
+ closeDatabase();
82
+ assert.equal(openDatabase(":memory:"), true);
83
+ try {
84
+ createMemory({
85
+ category: "gotcha",
86
+ content: "Always preserve critical resume safety context.",
87
+ confidence: 0.95,
88
+ });
89
+ createMemory({
90
+ category: "preference",
91
+ content: "React dashboard preference should only appear for a React prompt query.",
92
+ confidence: 0.95,
93
+ });
94
+
95
+ const withPromptRelevant = await loadMemoryBlock("React dashboard", { includePromptRelevant: true });
96
+ assert.match(withPromptRelevant, /critical resume safety context/);
97
+ assert.match(withPromptRelevant, /React dashboard preference/);
98
+
99
+ const withoutPromptRelevant = await loadMemoryBlock("React dashboard", { includePromptRelevant: false });
100
+ assert.match(withoutPromptRelevant, /critical resume safety context/);
101
+ assert.doesNotMatch(withoutPromptRelevant, /React dashboard preference/);
102
+ } finally {
103
+ closeDatabase();
104
+ }
105
+ });
106
+
107
+ test("isLowEntropyResumePrompt identifies bare resume prompts only", () => {
108
+ assert.equal(isLowEntropyResumePrompt("continue"), true);
109
+ assert.equal(isLowEntropyResumePrompt("Go ahead."), true);
110
+ assert.equal(isLowEntropyResumePrompt("run the tests"), false);
111
+ assert.equal(isLowEntropyResumePrompt("/gsd auto"), false);
112
+ });
@@ -1,9 +1,5 @@
1
- // GSD bootstrap + system-context-message-routing.test — regression coverage
2
- // for #5019. `memoryBlock` is FTS-queried against the user prompt and changes
3
- // per call; embedding it in the cached system prefix invalidates Anthropic
4
- // prompt-cache hits on every request. The fix routes memory through the
5
- // existing context-message channel (volatile user-message suffix) and combines
6
- // it with any active guided-execute or forensics injection.
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression coverage for volatile system-context message routing.
7
3
 
8
4
  import { describe, test } from "node:test";
9
5
  import assert from "node:assert/strict";
@@ -11,6 +7,8 @@ import assert from "node:assert/strict";
11
7
  import { buildContextMessage } from "../bootstrap/system-context.ts";
12
8
 
13
9
  describe("buildContextMessage (#5019 — memory routing)", () => {
10
+ const markedMemory = "[GSD Context Metadata]\n- Memory supplied: yes\n\n[MEMORY]\nrule one";
11
+
14
12
  test("returns null when nothing to inject", () => {
15
13
  const result = buildContextMessage({
16
14
  memoryBlock: "",
@@ -37,7 +35,7 @@ describe("buildContextMessage (#5019 — memory routing)", () => {
37
35
  });
38
36
  assert.ok(result, "expected a context message");
39
37
  assert.equal(result.customType, "gsd-memory");
40
- assert.equal(result.content, "[MEMORY]\nrule one\nrule two");
38
+ assert.equal(result.content, "[GSD Context Metadata]\n- Memory supplied: yes\n\n[MEMORY]\nrule one\nrule two");
41
39
  assert.equal(result.display, false);
42
40
  });
43
41
 
@@ -71,7 +69,7 @@ describe("buildContextMessage (#5019 — memory routing)", () => {
71
69
  });
72
70
  assert.ok(result);
73
71
  assert.equal(result.customType, "gsd-guided-context");
74
- assert.equal(result.content, "[MEMORY]\nrule one\n\n[GUIDED]\nexecute T01");
72
+ assert.equal(result.content, `${markedMemory}\n\n[GUIDED]\nexecute T01`);
75
73
  });
76
74
 
77
75
  test("memory + forensics: memory prepended, customType is gsd-forensics", () => {
@@ -82,7 +80,7 @@ describe("buildContextMessage (#5019 — memory routing)", () => {
82
80
  });
83
81
  assert.ok(result);
84
82
  assert.equal(result.customType, "gsd-forensics");
85
- assert.equal(result.content, "[MEMORY]\nrule one\n\n[FORENSICS]\ninvestigation context");
83
+ assert.equal(result.content, `${markedMemory}\n\n[FORENSICS]\ninvestigation context`);
86
84
  });
87
85
 
88
86
  test("guided takes precedence over forensics when both are somehow present", () => {