@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.965d1788

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 (411) hide show
  1. package/README.md +1 -1
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
  4. package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
  5. package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
  6. package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
  7. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  8. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
  9. package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
  12. package/dist/resources/extensions/gsd/auto-prompts.js +26 -11
  13. package/dist/resources/extensions/gsd/auto-recovery.js +6 -507
  14. package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
  15. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
  16. package/dist/resources/extensions/gsd/auto-verification.js +5 -2
  17. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
  18. package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +38 -0
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +6 -1
  20. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
  21. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +16 -19
  22. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
  23. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +68 -10
  24. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
  25. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
  26. package/dist/resources/extensions/gsd/commands-context.js +19 -1
  27. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +16 -10
  28. package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
  29. package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
  30. package/dist/resources/extensions/gsd/db/queries.js +60 -0
  31. package/dist/resources/extensions/gsd/db-workspace.js +55 -3
  32. package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
  33. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
  34. package/dist/resources/extensions/gsd/exec-sandbox.js +45 -9
  35. package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
  36. package/dist/resources/extensions/gsd/forensics.js +2 -32
  37. package/dist/resources/extensions/gsd/git-service.js +5 -4
  38. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  39. package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
  40. package/dist/resources/extensions/gsd/health-widget.js +55 -29
  41. package/dist/resources/extensions/gsd/json-persistence.js +20 -0
  42. package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
  43. package/dist/resources/extensions/gsd/layout-policy.js +3 -1
  44. package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
  45. package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
  46. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
  47. package/dist/resources/extensions/gsd/metrics.js +4 -4
  48. package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
  49. package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
  50. package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
  51. package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
  52. package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
  53. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/quick.js +45 -2
  55. package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
  56. package/dist/resources/extensions/gsd/session-forensics.js +11 -1
  57. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  58. package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
  59. package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
  60. package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
  61. package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
  62. package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
  63. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +45 -2
  64. package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
  65. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
  66. package/dist/resources/extensions/gsd/state.js +12 -611
  67. package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
  68. package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
  69. package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
  70. package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
  71. package/dist/resources/extensions/gsd/undo.js +43 -6
  72. package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
  73. package/dist/resources/extensions/gsd/unit-registry.js +32 -4
  74. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
  75. package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
  76. package/dist/resources/extensions/gsd/verification-gate.js +7 -0
  77. package/dist/resources/extensions/gsd/workflow-manifest.js +4 -1
  78. package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
  79. package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
  80. package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
  81. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  82. package/dist/web/standalone/.next/BUILD_ID +1 -1
  83. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  84. package/dist/web/standalone/.next/build-manifest.json +3 -3
  85. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  86. package/dist/web/standalone/.next/react-loadable-manifest.json +9 -9
  87. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/index.html +1 -1
  107. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  108. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  109. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  110. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  115. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  118. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  119. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  120. package/dist/web/standalone/.next/static/chunks/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
  121. package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
  122. package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
  123. package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
  124. package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
  125. package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
  126. package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
  127. package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
  128. package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
  129. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  130. package/package.json +1 -1
  131. package/packages/cloud-mcp-gateway/package.json +2 -2
  132. package/packages/contracts/dist/workflow.d.ts +1 -0
  133. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  134. package/packages/contracts/dist/workflow.js +2 -0
  135. package/packages/contracts/dist/workflow.js.map +1 -1
  136. package/packages/contracts/package.json +1 -1
  137. package/packages/daemon/package.json +4 -4
  138. package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
  139. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  140. package/packages/gsd-agent-core/dist/agent-session.js +3 -0
  141. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  142. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
  143. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
  144. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
  145. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
  146. package/packages/gsd-agent-core/dist/index.d.ts +2 -0
  147. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  148. package/packages/gsd-agent-core/dist/index.js +2 -0
  149. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  150. package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
  151. package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
  152. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
  153. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  154. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  155. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
  156. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  157. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
  158. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  159. package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
  160. package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
  161. package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
  162. package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
  163. package/packages/gsd-agent-core/package.json +5 -5
  164. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  165. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  166. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -11
  167. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  168. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
  169. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
  170. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
  171. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
  172. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
  173. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  174. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -829
  175. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  176. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
  177. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
  178. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
  179. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
  180. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
  181. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
  182. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
  183. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
  185. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
  186. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
  187. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
  188. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
  189. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
  190. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
  191. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
  192. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
  193. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  194. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  196. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
  197. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
  198. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
  199. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
  200. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
  201. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  202. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
  203. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  204. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
  205. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
  206. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
  207. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
  208. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
  209. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
  210. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
  211. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
  212. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  213. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
  214. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  215. package/packages/gsd-agent-modes/package.json +7 -7
  216. package/packages/mcp-server/README.md +1 -1
  217. package/packages/mcp-server/dist/server.d.ts +1 -1
  218. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  219. package/packages/mcp-server/dist/server.js +3 -3
  220. package/packages/mcp-server/dist/server.js.map +1 -1
  221. package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
  222. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  223. package/packages/mcp-server/dist/workflow-tools.js +34 -20
  224. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  225. package/packages/mcp-server/package.json +4 -4
  226. package/packages/native/package.json +1 -1
  227. package/packages/pi-agent-core/package.json +1 -1
  228. package/packages/pi-ai/package.json +1 -1
  229. package/packages/pi-coding-agent/README.md +3 -2
  230. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
  231. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
  232. package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
  233. package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
  234. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
  235. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
  236. package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
  237. package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
  238. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
  239. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
  240. package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
  241. package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
  242. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
  243. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
  244. package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
  245. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
  246. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
  247. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  248. package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
  249. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
  251. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
  252. package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
  253. package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  255. package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
  256. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  257. package/packages/pi-coding-agent/package.json +7 -7
  258. package/packages/pi-tui/package.json +2 -2
  259. package/packages/rpc-client/package.json +2 -2
  260. package/pkg/dist/theme/theme-schema.d.ts +75 -75
  261. package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
  262. package/pkg/dist/theme/theme-schema.js +1 -1
  263. package/pkg/dist/theme/theme-schema.js.map +1 -1
  264. package/pkg/dist/theme/theme.d.ts.map +1 -1
  265. package/pkg/dist/theme/theme.js +11 -7
  266. package/pkg/dist/theme/theme.js.map +1 -1
  267. package/pkg/package.json +1 -1
  268. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
  269. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
  270. package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
  271. package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
  272. package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
  273. package/src/resources/extensions/gsd/auto/session.ts +6 -0
  274. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
  275. package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
  276. package/src/resources/extensions/gsd/auto-dispatch.ts +21 -23
  277. package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
  278. package/src/resources/extensions/gsd/auto-prompts.ts +38 -12
  279. package/src/resources/extensions/gsd/auto-recovery.ts +10 -508
  280. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
  281. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
  282. package/src/resources/extensions/gsd/auto-verification.ts +5 -1
  283. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
  284. package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +43 -0
  285. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +6 -1
  286. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
  287. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -19
  288. package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
  289. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +74 -10
  290. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
  291. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
  292. package/src/resources/extensions/gsd/commands-context.ts +18 -1
  293. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +14 -9
  294. package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
  295. package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
  296. package/src/resources/extensions/gsd/db/queries.ts +79 -0
  297. package/src/resources/extensions/gsd/db-workspace.ts +61 -3
  298. package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
  299. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
  300. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  301. package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
  302. package/src/resources/extensions/gsd/forensics.ts +2 -33
  303. package/src/resources/extensions/gsd/git-service.ts +6 -5
  304. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  305. package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
  306. package/src/resources/extensions/gsd/health-widget.ts +69 -32
  307. package/src/resources/extensions/gsd/json-persistence.ts +20 -0
  308. package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
  309. package/src/resources/extensions/gsd/layout-policy.ts +2 -1
  310. package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
  311. package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
  312. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
  313. package/src/resources/extensions/gsd/metrics.ts +4 -4
  314. package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
  315. package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
  316. package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
  317. package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
  318. package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
  319. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  320. package/src/resources/extensions/gsd/quick.ts +43 -2
  321. package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
  322. package/src/resources/extensions/gsd/session-forensics.ts +11 -1
  323. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  324. package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
  325. package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
  326. package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
  327. package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
  328. package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
  329. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +81 -7
  330. package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
  331. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
  332. package/src/resources/extensions/gsd/state.ts +32 -732
  333. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
  334. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
  335. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -1
  336. package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
  337. package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
  338. package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
  339. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
  340. package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
  341. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
  342. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
  343. package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
  344. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
  345. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
  346. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
  347. package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
  348. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
  349. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
  350. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
  351. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
  352. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
  353. package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
  354. package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
  355. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
  356. package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
  357. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +130 -3
  358. package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
  359. package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
  360. package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
  361. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
  362. package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
  363. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
  364. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
  365. package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
  366. package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
  367. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
  368. package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
  369. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
  370. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
  371. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +2 -1
  372. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
  373. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
  374. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
  375. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
  376. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
  377. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
  378. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
  379. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +7 -0
  380. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
  381. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  382. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +151 -0
  383. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +26 -0
  384. package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
  385. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
  386. package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
  387. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
  388. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
  389. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
  390. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +54 -0
  391. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
  392. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
  393. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  394. package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
  395. package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
  396. package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
  397. package/src/resources/extensions/gsd/undo.ts +47 -6
  398. package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
  399. package/src/resources/extensions/gsd/unit-registry.ts +32 -4
  400. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
  401. package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
  402. package/src/resources/extensions/gsd/verification-gate.ts +8 -0
  403. package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
  404. package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
  405. package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
  406. package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
  407. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
  408. package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
  409. package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
  410. /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → -ji77QJck2IKIwrGza1Bs}/_buildManifest.js +0 -0
  411. /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → -ji77QJck2IKIwrGza1Bs}/_ssgManifest.js +0 -0
@@ -3,7 +3,7 @@
3
3
  import { describe, test } from 'node:test';
4
4
  import assert from 'node:assert/strict';
5
5
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, symlinkSync, readFileSync, chmodSync } from "node:fs";
6
- import { join, dirname } from "node:path";
6
+ import { join, dirname, delimiter } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
8
  import { execFileSync, execSync } from "node:child_process";
9
9
 
@@ -23,6 +23,7 @@ import {
23
23
  type PreMergeCheckResult,
24
24
  type TaskCommitContext,
25
25
  } from "../../git-service.ts";
26
+ import { GIT_NO_PROMPT_ENV } from "../../git-constants.ts";
26
27
  import { nativeAddAllWithExclusions, nativeHasChanges, _resetHasChangesCache } from "../../native-git-bridge.ts";
27
28
  function run(command: string, cwd: string): string {
28
29
  return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
@@ -293,12 +294,13 @@ describe('git-service', async () => {
293
294
 
294
295
  assert.deepStrictEqual(
295
296
  RUNTIME_EXCLUSION_PATHS.length,
296
- 17,
297
- "exactly 17 runtime exclusion paths"
297
+ 18,
298
+ "exactly 18 runtime exclusion paths"
298
299
  );
299
300
 
300
301
  const expectedPaths = [
301
302
  ".gsd-worktrees/",
303
+ ".gsd-backups/**",
302
304
  ".gsd/activity/",
303
305
  ".gsd/audit/",
304
306
  ".gsd/forensics/",
@@ -405,6 +407,49 @@ describe('git-service', async () => {
405
407
  }).trim();
406
408
  }
407
409
 
410
+ function findGitExecutable(): string {
411
+ const command = process.platform === "win32" ? "where git" : "command -v git";
412
+ const output = execSync(command, { encoding: "utf-8" });
413
+ const found = output.split(/\r?\n/).map(line => line.trim()).find(Boolean);
414
+ assert.ok(found, "git executable is available");
415
+ return found;
416
+ }
417
+
418
+ function installGitRmCachedCounterShim(shimDir: string): void {
419
+ const shimScript = join(shimDir, "git-shim.cjs");
420
+ writeFileSync(shimScript, `
421
+ const { appendFileSync } = require("node:fs");
422
+ const { spawnSync } = require("node:child_process");
423
+
424
+ const args = process.argv.slice(2);
425
+ if (args[0] === "rm" && args[1] === "--cached") {
426
+ appendFileSync(process.env.GSD_GIT_SHIM_LOG, args.join("\\0") + "\\n");
427
+ }
428
+
429
+ const result = spawnSync(process.env.GSD_REAL_GIT || "git", args, {
430
+ stdio: "inherit",
431
+ env: process.env,
432
+ });
433
+ if (result.error) {
434
+ console.error(result.error.message);
435
+ process.exit(1);
436
+ }
437
+ process.exit(result.status ?? 0);
438
+ `.trimStart(), "utf-8");
439
+
440
+ const posixShim = join(shimDir, "git");
441
+ const quotedScript = `'${shimScript.replace(/'/g, "'\\''")}'`;
442
+ writeFileSync(posixShim, `#!/bin/sh\nexec node ${quotedScript} "$@"\n`, "utf-8");
443
+ chmodSync(posixShim, 0o755);
444
+
445
+ writeFileSync(join(shimDir, "git.cmd"), "@echo off\r\nnode \"%~dp0git-shim.cjs\" %*\r\n", "utf-8");
446
+ }
447
+
448
+ function countRmCachedInvocations(logFile: string): number {
449
+ if (!existsSync(logFile)) return 0;
450
+ return readFileSync(logFile, "utf-8").split(/\r?\n/).filter(Boolean).length;
451
+ }
452
+
408
453
  // ─── GitServiceImpl: smart staging ─────────────────────────────────────
409
454
 
410
455
  test('GitServiceImpl: smart staging', () => {
@@ -447,6 +492,80 @@ describe('git-service', async () => {
447
492
  rmSync(repo, { recursive: true, force: true });
448
493
  });
449
494
 
495
+ test('GitServiceImpl: runtime cleanup runs once per repo across service instances', () => {
496
+ const repo = initTempRepo();
497
+ const shimDir = mkdtempSync(join(tmpdir(), "gsd-git-rm-shim-"));
498
+ const logFile = join(shimDir, "git-rm-cached.log");
499
+ const originalPath = process.env.PATH;
500
+ const originalRealGit = process.env.GSD_REAL_GIT;
501
+ const originalShimLog = process.env.GSD_GIT_SHIM_LOG;
502
+ const originalSafePath = GIT_NO_PROMPT_ENV.PATH;
503
+ const originalSafeRealGit = GIT_NO_PROMPT_ENV.GSD_REAL_GIT;
504
+ const originalSafeShimLog = GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG;
505
+
506
+ try {
507
+ installGitRmCachedCounterShim(shimDir);
508
+ const realGit = findGitExecutable();
509
+ process.env.GSD_REAL_GIT = realGit;
510
+ process.env.GSD_GIT_SHIM_LOG = logFile;
511
+ process.env.PATH = `${shimDir}${delimiter}${originalPath ?? ""}`;
512
+ GIT_NO_PROMPT_ENV.GSD_REAL_GIT = realGit;
513
+ GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG = logFile;
514
+ GIT_NO_PROMPT_ENV.PATH = process.env.PATH;
515
+
516
+ createFile(repo, "src/first.ts", "first");
517
+ const first = new GitServiceImpl(repo).commit({ message: "test: first cleanup pass" });
518
+ assert.deepStrictEqual(first, "test: first cleanup pass", "first commit succeeds");
519
+ assert.deepStrictEqual(
520
+ countRmCachedInvocations(logFile),
521
+ RUNTIME_EXCLUSION_PATHS.length,
522
+ "first service instance checks each runtime exclusion once",
523
+ );
524
+
525
+ createFile(repo, "src/second.ts", "second");
526
+ const second = new GitServiceImpl(repo).commit({ message: "test: second cleanup pass" });
527
+ assert.deepStrictEqual(second, "test: second cleanup pass", "second commit succeeds");
528
+ assert.deepStrictEqual(
529
+ countRmCachedInvocations(logFile),
530
+ RUNTIME_EXCLUSION_PATHS.length,
531
+ "fresh service instance for the same repo does not rerun runtime cleanup",
532
+ );
533
+ } finally {
534
+ if (originalPath === undefined) {
535
+ delete process.env.PATH;
536
+ } else {
537
+ process.env.PATH = originalPath;
538
+ }
539
+ if (originalRealGit === undefined) {
540
+ delete process.env.GSD_REAL_GIT;
541
+ } else {
542
+ process.env.GSD_REAL_GIT = originalRealGit;
543
+ }
544
+ if (originalShimLog === undefined) {
545
+ delete process.env.GSD_GIT_SHIM_LOG;
546
+ } else {
547
+ process.env.GSD_GIT_SHIM_LOG = originalShimLog;
548
+ }
549
+ if (originalSafePath === undefined) {
550
+ delete GIT_NO_PROMPT_ENV.PATH;
551
+ } else {
552
+ GIT_NO_PROMPT_ENV.PATH = originalSafePath;
553
+ }
554
+ if (originalSafeRealGit === undefined) {
555
+ delete GIT_NO_PROMPT_ENV.GSD_REAL_GIT;
556
+ } else {
557
+ GIT_NO_PROMPT_ENV.GSD_REAL_GIT = originalSafeRealGit;
558
+ }
559
+ if (originalSafeShimLog === undefined) {
560
+ delete GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG;
561
+ } else {
562
+ GIT_NO_PROMPT_ENV.GSD_GIT_SHIM_LOG = originalSafeShimLog;
563
+ }
564
+ rmSync(repo, { recursive: true, force: true });
565
+ rmSync(shimDir, { recursive: true, force: true });
566
+ }
567
+ });
568
+
450
569
  test('GitServiceImpl: task autoCommit skips keyFiles inside submodules', () => {
451
570
  const repo = initTempRepo();
452
571
  const subSrc = mkdtempSync(join(tmpdir(), "gsd-git-submodule-src-"));
@@ -1505,11 +1624,13 @@ describe('git-service', async () => {
1505
1624
  // Create and track runtime files (simulates pre-.gitignore state)
1506
1625
  mkdirSync(join(repo, ".gsd", "activity"), { recursive: true });
1507
1626
  mkdirSync(join(repo, ".gsd", "runtime"), { recursive: true });
1627
+ mkdirSync(join(repo, ".gsd-backups", "migrate-old"), { recursive: true });
1508
1628
  writeFileSync(join(repo, ".gsd", "completed-units.json"), '["u1"]');
1509
1629
  writeFileSync(join(repo, ".gsd", "metrics.json"), '{}');
1510
1630
  writeFileSync(join(repo, ".gsd", "STATE.md"), "# State");
1511
1631
  writeFileSync(join(repo, ".gsd", "activity", "log.jsonl"), "{}");
1512
1632
  writeFileSync(join(repo, ".gsd", "runtime", "data.json"), "{}");
1633
+ writeFileSync(join(repo, ".gsd-backups", "migrate-old", "marker.txt"), "backup");
1513
1634
  writeFileSync(join(repo, "src.ts"), "code");
1514
1635
  runGit(repo, ["add", "-A"]);
1515
1636
  runGit(repo, ["commit", "-m", "init"]);
@@ -1518,6 +1639,8 @@ describe('git-service', async () => {
1518
1639
  const trackedBefore = run("git ls-files .gsd/", repo);
1519
1640
  assert.ok(trackedBefore.includes("completed-units.json"), "untrack: precondition — completed-units tracked");
1520
1641
  assert.ok(trackedBefore.includes("metrics.json"), "untrack: precondition — metrics tracked");
1642
+ const backupTrackedBefore = run("git ls-files .gsd-backups/", repo);
1643
+ assert.ok(backupTrackedBefore.includes("marker.txt"), "untrack: precondition — migration backup tracked");
1521
1644
 
1522
1645
  // Run untrackRuntimeFiles
1523
1646
  untrackRuntimeFiles(repo);
@@ -1525,6 +1648,8 @@ describe('git-service', async () => {
1525
1648
  // Runtime files should be removed from the index
1526
1649
  const trackedAfter = run("git ls-files .gsd/", repo);
1527
1650
  assert.deepStrictEqual(trackedAfter, "", "untrack: all runtime files removed from index");
1651
+ const backupTrackedAfter = run("git ls-files .gsd-backups/", repo);
1652
+ assert.deepStrictEqual(backupTrackedAfter, "", "untrack: migration backups removed from index");
1528
1653
 
1529
1654
  // Non-runtime files remain tracked
1530
1655
  const srcTracked = run("git ls-files src.ts", repo);
@@ -1535,6 +1660,8 @@ describe('git-service', async () => {
1535
1660
  "untrack: completed-units.json still on disk");
1536
1661
  assert.ok(existsSync(join(repo, ".gsd", "metrics.json")),
1537
1662
  "untrack: metrics.json still on disk");
1663
+ assert.ok(existsSync(join(repo, ".gsd-backups", "migrate-old", "marker.txt")),
1664
+ "untrack: migration backup still on disk");
1538
1665
 
1539
1666
  // Idempotent — running again doesn't error
1540
1667
  untrackRuntimeFiles(repo);
@@ -0,0 +1,93 @@
1
+ import { describe, test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+
7
+ import { buildExistingMilestonesContext } from "../../guided-flow-queue.ts";
8
+ import type { GSDState, MilestoneRegistryEntry } from "../../types.ts";
9
+
10
+ const LARGE_BODY = "A".repeat(150_000);
11
+ const LARGE_DRAFT = "D".repeat(150_000);
12
+ const LARGE_ROADMAP = "R".repeat(150_000);
13
+
14
+ function makeState(registry: MilestoneRegistryEntry[]): GSDState {
15
+ return {
16
+ activeMilestone: registry.find(m => m.status === "active") ?? null,
17
+ activeSlice: null,
18
+ activeTask: null,
19
+ phase: "executing",
20
+ recentDecisions: [],
21
+ blockers: [],
22
+ nextAction: "",
23
+ registry,
24
+ };
25
+ }
26
+
27
+ function writeMilestoneArtifact(base: string, mid: string, suffix: string, content: string): void {
28
+ mkdirSync(join(base, ".gsd", "milestones", mid), { recursive: true });
29
+ writeFileSync(join(base, ".gsd", "milestones", mid, `${mid}-${suffix}.md`), content);
30
+ }
31
+
32
+ describe("queue active/pending milestone context budget", () => {
33
+ test("summarizes active and pending artifacts with source paths and bounded excerpts", async () => {
34
+ const tmpBase = mkdtempSync(join(tmpdir(), "gsd-queue-active-budget-"));
35
+ try {
36
+ writeMilestoneArtifact(tmpBase, "M001", "CONTEXT", `# Active context\n\n${LARGE_BODY}\nEND_ACTIVE_CONTEXT`);
37
+ writeMilestoneArtifact(tmpBase, "M001", "ROADMAP", `# Active roadmap\n\n${LARGE_ROADMAP}\nEND_ACTIVE_ROADMAP`);
38
+ writeMilestoneArtifact(tmpBase, "M002", "CONTEXT-DRAFT", `# Pending draft\n\n${LARGE_DRAFT}\nEND_PENDING_DRAFT`);
39
+ writeMilestoneArtifact(tmpBase, "M002", "ROADMAP", `# Pending roadmap\n\n${LARGE_ROADMAP}\nEND_PENDING_ROADMAP`);
40
+
41
+ const registry: MilestoneRegistryEntry[] = [
42
+ { id: "M001", title: "Active milestone", status: "active" },
43
+ { id: "M002", title: "Pending milestone", status: "pending" },
44
+ ];
45
+
46
+ const context = await buildExistingMilestonesContext(tmpBase, ["M001", "M002"], makeState(registry));
47
+
48
+ assert.match(context, /Source: `.gsd\/milestones\/M001\/M001-CONTEXT.md`/);
49
+ assert.match(context, /Source: `.gsd\/milestones\/M001\/M001-ROADMAP.md`/);
50
+ assert.match(context, /Source: `.gsd\/milestones\/M002\/M002-CONTEXT-DRAFT.md`/);
51
+ assert.match(context, /Source: `.gsd\/milestones\/M002\/M002-ROADMAP.md`/);
52
+ assert.match(context, /Read `.gsd\/milestones\/M001\/M001-CONTEXT.md` for full content/);
53
+ assert.equal(context.includes("END_ACTIVE_CONTEXT"), false);
54
+ assert.equal(context.includes("END_ACTIVE_ROADMAP"), false);
55
+ assert.equal(context.includes("END_PENDING_DRAFT"), false);
56
+ assert.equal(context.includes("END_PENDING_ROADMAP"), false);
57
+ } finally {
58
+ rmSync(tmpBase, { recursive: true, force: true });
59
+ }
60
+ });
61
+
62
+ test("caps the total existing milestones context", async () => {
63
+ const tmpBase = mkdtempSync(join(tmpdir(), "gsd-queue-total-budget-"));
64
+ try {
65
+ const registry: MilestoneRegistryEntry[] = [];
66
+ const milestoneIds: string[] = [];
67
+ for (let i = 1; i <= 5; i++) {
68
+ const mid = `M${String(i).padStart(3, "0")}`;
69
+ milestoneIds.push(mid);
70
+ registry.push({ id: mid, title: `Pending milestone ${i}`, status: "pending" });
71
+ writeMilestoneArtifact(tmpBase, mid, "CONTEXT", `# ${mid} context\n\n${LARGE_BODY}\nEND_${mid}_CONTEXT`);
72
+ writeMilestoneArtifact(tmpBase, mid, "ROADMAP", `# ${mid} roadmap\n\n${LARGE_ROADMAP}\nEND_${mid}_ROADMAP`);
73
+ }
74
+
75
+ const context = await buildExistingMilestonesContext(tmpBase, milestoneIds, makeState(registry));
76
+
77
+ assert.ok(
78
+ context.length <= 120_000,
79
+ `expected total context to stay within budget, got ${context.length} chars`,
80
+ );
81
+ assert.match(context, /Existing milestones context truncated/);
82
+ for (let i = 1; i <= 5; i++) {
83
+ const mid = `M${String(i).padStart(3, "0")}`;
84
+ assert.match(context, new RegExp(`### ${mid}: Pending milestone ${i}`));
85
+ assert.match(context, new RegExp(`Source: \`.gsd/milestones/${mid}/${mid}-CONTEXT.md\``));
86
+ assert.match(context, new RegExp(`Source: \`.gsd/milestones/${mid}/${mid}-ROADMAP.md\``));
87
+ }
88
+ assert.equal(context.includes("END_M005_ROADMAP"), false);
89
+ } finally {
90
+ rmSync(tmpBase, { recursive: true, force: true });
91
+ }
92
+ });
93
+ });
@@ -16,6 +16,7 @@ import { execSync } from "node:child_process";
16
16
 
17
17
  import { captureIntegrationBranch, getCurrentBranch } from "../../worktree.ts";
18
18
  import { readIntegrationBranch, QUICK_BRANCH_RE } from "../../git-service.ts";
19
+ import { disableDebug, enableDebug, getDebugCounters } from "../../debug-logger.ts";
19
20
 
20
21
  function run(command: string, cwd: string): string {
21
22
  return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
@@ -205,16 +206,25 @@ test('cleanupQuickBranch: recovers from disk state (cross-session)', async () =>
205
206
  test('cleanupQuickBranch: no-op without pending state', async () => {
206
207
  const repo = createTestRepo();
207
208
  const origCwd = process.cwd();
208
- process.chdir(repo);
209
-
210
- const { cleanupQuickBranch } = await import("../../quick.ts");
211
- const result = cleanupQuickBranch();
212
-
213
- assert.ok(!result, "returns false when no pending state");
214
- assert.deepStrictEqual(getCurrentBranch(repo), "main", "stays on main");
209
+ try {
210
+ process.chdir(repo);
211
+ enableDebug(repo);
215
212
 
216
- process.chdir(origCwd);
217
- rmSync(repo, { recursive: true, force: true });
213
+ const { cleanupQuickBranch } = await import("../../quick.ts");
214
+ const result = cleanupQuickBranch();
215
+ const firstGitInvocations = getDebugCounters().gitInvocations;
216
+ const secondResult = cleanupQuickBranch();
217
+
218
+ assert.ok(!result, "returns false when no pending state");
219
+ assert.ok(!secondResult, "still returns false when no pending state");
220
+ assert.deepStrictEqual(getDebugCounters().gitInvocations, firstGitInvocations,
221
+ "cached no-state cleanup does not re-run git branch inference");
222
+ assert.deepStrictEqual(getCurrentBranch(repo), "main", "stays on main");
223
+ } finally {
224
+ disableDebug();
225
+ process.chdir(origCwd);
226
+ rmSync(repo, { recursive: true, force: true });
227
+ }
218
228
  });
219
229
 
220
230
  test('cleanupQuickBranch: infers return state from current gsd/quick branch', async () => {
@@ -240,6 +250,43 @@ test('cleanupQuickBranch: infers return state from current gsd/quick branch', as
240
250
  }
241
251
  });
242
252
 
253
+ // ═══════════════════════════════════════════════════════════════════════
254
+ // cleanupQuickBranch: stale miss invalidated after mid-session branch switch
255
+ // ═══════════════════════════════════════════════════════════════════════
256
+ test('cleanupQuickBranch: clears stale miss when branch switches to gsd/quick mid-session', async () => {
257
+ const repo = createTestRepo();
258
+ const origCwd = process.cwd();
259
+ try {
260
+ // Create a quick branch with real product work (so inference finds a diff)
261
+ run("git checkout -b gsd/quick/3-stale-miss", repo);
262
+ writeFileSync(join(repo, "stale.txt"), "stale miss test\n");
263
+ run("git add stale.txt", repo);
264
+ run('git commit -m "test: stale miss"', repo);
265
+ // Return to main so the first cleanupQuickBranch call records a miss
266
+ run("git checkout main", repo);
267
+
268
+ process.chdir(repo);
269
+ const { cleanupQuickBranch } = await import("../../quick.ts");
270
+
271
+ // First call: on main with no disk state → miss recorded (keyed to "main")
272
+ const result1 = cleanupQuickBranch();
273
+ assert.ok(!result1, "first call (on main) returns false — miss recorded");
274
+
275
+ // Simulate mid-session external branch switch to the stranded quick branch
276
+ run("git checkout gsd/quick/3-stale-miss", repo);
277
+
278
+ // Second call: branch changed from the recorded miss, so cache is invalidated
279
+ // and inferQuickReturnFromBranch runs — cleanup must succeed
280
+ const result2 = cleanupQuickBranch();
281
+ assert.ok(result2, "second call returns true after mid-session switch to quick branch");
282
+ assert.deepStrictEqual(getCurrentBranch(repo), "main",
283
+ "cleanup merged back to main after stale-miss invalidation");
284
+ } finally {
285
+ process.chdir(origCwd);
286
+ rmSync(repo, { recursive: true, force: true });
287
+ }
288
+ });
289
+
243
290
  // ═══════════════════════════════════════════════════════════════════════
244
291
  // End-to-end: quick branch does NOT contaminate integration branch
245
292
  // ═══════════════════════════════════════════════════════════════════════
@@ -19,6 +19,7 @@ import { tmpdir } from "node:os";
19
19
 
20
20
  import {
21
21
  saveJsonFile,
22
+ saveJsonFileCompact,
22
23
  loadJsonFile,
23
24
  writeJsonFileAtomic,
24
25
  } from "../json-persistence.ts";
@@ -56,6 +57,37 @@ test("saveJsonFile creates file with valid JSON content", () => {
56
57
  }
57
58
  });
58
59
 
60
+ test("saveJsonFile keeps pretty-printed output for human-readable state", () => {
61
+ const dir = makeTempDir();
62
+ const filePath = join(dir, "pretty.json");
63
+
64
+ try {
65
+ const data = { foo: "bar", nested: { count: 42 } };
66
+ saveJsonFile(filePath, data);
67
+
68
+ const content = readFileSync(filePath, "utf-8");
69
+ assert.equal(content, JSON.stringify(data, null, 2) + "\n");
70
+ } finally {
71
+ cleanup(dir);
72
+ }
73
+ });
74
+
75
+ test("saveJsonFileCompact writes valid compact JSON content", () => {
76
+ const dir = makeTempDir();
77
+ const filePath = join(dir, "compact.json");
78
+
79
+ try {
80
+ const data = { foo: "bar", nested: { count: 42 } };
81
+ saveJsonFileCompact(filePath, data);
82
+
83
+ const content = readFileSync(filePath, "utf-8");
84
+ assert.equal(content, JSON.stringify(data) + "\n");
85
+ assert.deepEqual(JSON.parse(content), data);
86
+ } finally {
87
+ cleanup(dir);
88
+ }
89
+ });
90
+
59
91
  test("saveJsonFile does not leave .tmp files on success", () => {
60
92
  const dir = makeTempDir();
61
93
  const filePath = join(dir, "clean.json");
@@ -72,6 +104,21 @@ test("saveJsonFile does not leave .tmp files on success", () => {
72
104
  }
73
105
  });
74
106
 
107
+ test("saveJsonFileCompact does not leave .tmp files on success", () => {
108
+ const dir = makeTempDir();
109
+ const filePath = join(dir, "compact-clean.json");
110
+
111
+ try {
112
+ saveJsonFileCompact(filePath, { test: true });
113
+
114
+ const files = readdirSync(dir);
115
+ const tmpFiles = files.filter(f => f.includes(".tmp"));
116
+ assert.equal(tmpFiles.length, 0, `Unexpected .tmp files: ${tmpFiles.join(", ")}`);
117
+ } finally {
118
+ cleanup(dir);
119
+ }
120
+ });
121
+
75
122
  test("saveJsonFile creates parent directories", () => {
76
123
  const dir = makeTempDir();
77
124
  const filePath = join(dir, "deep", "nested", "data.json");
@@ -161,6 +161,41 @@ test("backfill is idempotent — second run on the same file is a no-op", () =>
161
161
  }
162
162
  });
163
163
 
164
+ test("backfill skips a knowledge row whose memory insert throws and continues later rows", () => {
165
+ const base = makeTmpBase();
166
+ try {
167
+ writeKnowledgeMd(base, FIXTURE);
168
+
169
+ const adapter = _getAdapter();
170
+ assert.ok(adapter);
171
+ adapter.exec(`
172
+ CREATE TRIGGER fail_p002_memory_insert
173
+ BEFORE INSERT ON memories
174
+ WHEN json_extract(NEW.structured_fields, '$.sourceKnowledgeId') = 'P002'
175
+ BEGIN
176
+ SELECT RAISE(ABORT, 'poison knowledge P002');
177
+ END
178
+ `);
179
+
180
+ const written = backfillKnowledgeToMemories(base);
181
+ assert.equal(written, 2, "one poisoned row should not abort the batch");
182
+
183
+ const rows = adapter
184
+ .prepare(
185
+ "SELECT structured_fields FROM memories WHERE structured_fields LIKE '%\"sourceKnowledgeId\":\"%' ORDER BY seq",
186
+ )
187
+ .all() as Array<{ structured_fields: string }>;
188
+
189
+ assert.deepEqual(
190
+ rows.map((row) => JSON.parse(row.structured_fields).sourceKnowledgeId),
191
+ ["P001", "L001"],
192
+ "rows after the poisoned knowledge entry should still be migrated",
193
+ );
194
+ } finally {
195
+ cleanup(base);
196
+ }
197
+ });
198
+
164
199
  test("backfill returns 0 when KNOWLEDGE.md is absent", () => {
165
200
  const base = makeTmpBase();
166
201
  try {
@@ -136,8 +136,10 @@ test("#896 startup maintenance skips repeated sentinel work in one session", asy
136
136
  closeDatabase();
137
137
  assert.equal(isDbAvailable(), false);
138
138
 
139
+ let sessionId = "session-one";
139
140
  const ctx = {
140
141
  projectRoot: base,
142
+ sessionManager: { getSessionId: () => sessionId },
141
143
  ui: { notify: () => undefined },
142
144
  } as unknown as ExtensionContext;
143
145
 
@@ -190,6 +192,18 @@ test("#896 startup maintenance skips repeated sentinel work in one session", asy
190
192
  .prepare("SELECT COUNT(*) AS count FROM memories WHERE structured_fields LIKE '%\"sourceKnowledgeId\":\"P002\"%'")
191
193
  .get() as { count: number };
192
194
  assert.equal(secondPass.count, 0, "second startup in same session should not re-run KNOWLEDGE.md sentinel backfill");
195
+
196
+ sessionId = "session-two";
197
+ await buildBeforeAgentStartResult(
198
+ { prompt: "Inspect project knowledge in a new session", systemPrompt: "base system prompt" },
199
+ ctx,
200
+ );
201
+ await _flushDeferredContextMaintenanceForTest(base);
202
+
203
+ const nextSessionPass = adapter
204
+ .prepare("SELECT COUNT(*) AS count FROM memories WHERE structured_fields LIKE '%\"sourceKnowledgeId\":\"P002\"%'")
205
+ .get() as { count: number };
206
+ assert.equal(nextSessionPass.count, 1, "startup maintenance should run once for a later session");
193
207
  });
194
208
 
195
209
  test("#896 later turns reopen the project DB after startup maintenance is complete", async (t) => {
@@ -16,6 +16,7 @@ import {
16
16
  openDatabase,
17
17
  closeDatabase,
18
18
  insertDecision,
19
+ _getAdapter,
19
20
  } from "../gsd-db.ts";
20
21
  import { createMemory } from "../memory-store.ts";
21
22
  import {
@@ -271,6 +272,83 @@ test("scanConsolidationGaps combines decisions and KNOWLEDGE.md gaps in summary"
271
272
  }
272
273
  });
273
274
 
275
+ test("scanConsolidationGaps collects memory source markers with one memories scan", () => {
276
+ const base = makeTmpBase();
277
+ try {
278
+ insertDecision({
279
+ id: "D001",
280
+ when_context: "2026-01-01",
281
+ scope: "M001",
282
+ decision: "Unmigrated decision",
283
+ choice: "A",
284
+ rationale: "x",
285
+ revisable: "yes",
286
+ made_by: "agent",
287
+ superseded_by: null,
288
+ });
289
+ insertDecision({
290
+ id: "D002",
291
+ when_context: "2026-01-02",
292
+ scope: "M001",
293
+ decision: "Migrated decision",
294
+ choice: "B",
295
+ rationale: "y",
296
+ revisable: "yes",
297
+ made_by: "agent",
298
+ superseded_by: null,
299
+ });
300
+ createMemory({
301
+ category: "architecture",
302
+ content: "Migrated decision Chose: B. Rationale: y.",
303
+ scope: "M001",
304
+ structuredFields: { sourceDecisionId: "D002" },
305
+ });
306
+ createMemory({
307
+ category: "pattern",
308
+ content: "Migrated knowledge pattern",
309
+ scope: "project",
310
+ structuredFields: { sourceKnowledgeId: "P001" },
311
+ });
312
+ writeKnowledgeMd(
313
+ base,
314
+ `## Patterns
315
+
316
+ | # | Pattern | Where | Notes |
317
+ |---|---------|-------|-------|
318
+ | P001 | Migrated knowledge pattern | scanner | covered |
319
+ | P002 | Unmigrated knowledge pattern | scanner | gap |
320
+ `,
321
+ );
322
+
323
+ const adapter = _getAdapter();
324
+ assert.ok(adapter);
325
+ const originalPrepare = adapter.prepare.bind(adapter);
326
+ const memorySql: string[] = [];
327
+ adapter.prepare = (sql: string) => {
328
+ if (sql.includes("FROM memories")) memorySql.push(sql);
329
+ return originalPrepare(sql);
330
+ };
331
+
332
+ const report = scanConsolidationGaps(base);
333
+ assert.equal(report.decisions.migrated, 1);
334
+ assert.equal(report.decisions.unmigrated, 1);
335
+ assert.equal(report.knowledge.migrated, 1);
336
+ assert.equal(report.knowledge.unmigrated, 1);
337
+ assert.equal(
338
+ memorySql.filter((sql) => sql.includes("SELECT structured_fields FROM memories")).length,
339
+ 1,
340
+ "source marker detection should read memories once",
341
+ );
342
+ assert.equal(
343
+ memorySql.some((sql) => sql.includes("LIKE :pattern")),
344
+ false,
345
+ "scanner must not reintroduce per-row LIKE marker probes",
346
+ );
347
+ } finally {
348
+ cleanup(base);
349
+ }
350
+ });
351
+
274
352
  // ─── reportConsolidationGaps ───────────────────────────────────────────────
275
353
 
276
354
  test("reportConsolidationGaps emits a notification + warning when gaps exist", () => {
@@ -9,7 +9,15 @@ import { tmpdir } from "node:os";
9
9
  import { execFileSync } from "node:child_process";
10
10
 
11
11
  import { mergeMilestoneToMain } from "../auto-worktree.ts";
12
- import { closeDatabase, insertMilestone, openDatabase } from "../gsd-db.ts";
12
+ import { checkCloseoutConsistencyGate } from "../closeout-consistency-gate.ts";
13
+ import {
14
+ closeDatabase,
15
+ insertAssessment,
16
+ insertMilestone,
17
+ insertSlice,
18
+ insertTask,
19
+ openDatabase,
20
+ } from "../gsd-db.ts";
13
21
 
14
22
  function git(args: string[], cwd: string): string {
15
23
  return execFileSync("git", args, {
@@ -61,3 +69,25 @@ test("mergeMilestoneToMain blocks when project DB closeout is still open", () =>
61
69
  if (existsSync(repo)) rmSync(repo, { recursive: true, force: true });
62
70
  }
63
71
  });
72
+
73
+ test("closeout consistency treats deferred slices as inactive", () => {
74
+ try {
75
+ assert.equal(openDatabase(":memory:"), true);
76
+ insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
77
+ insertSlice({ milestoneId: "M001", id: "S01", title: "Done", status: "complete" });
78
+ insertTask({ milestoneId: "M001", sliceId: "S01", id: "T01", title: "Done", status: "complete" });
79
+ insertSlice({ milestoneId: "M001", id: "S02", title: "Deferred", status: "deferred" });
80
+ insertTask({ milestoneId: "M001", sliceId: "S02", id: "T02", title: "Deferred", status: "pending" });
81
+ insertAssessment({
82
+ path: "milestones/M001/M001-VALIDATION.md",
83
+ milestoneId: "M001",
84
+ status: "pass",
85
+ scope: "milestone-validation",
86
+ fullContent: "verdict: pass",
87
+ });
88
+
89
+ assert.deepEqual(checkCloseoutConsistencyGate("M001"), { ok: true });
90
+ } finally {
91
+ closeDatabase();
92
+ }
93
+ });
@@ -112,6 +112,12 @@ describe("pruneMetricsLedger: invalidates scoped ledger cache", () => {
112
112
  // 3. Prune to keepCount=2 — should evict 3 old units from disk AND clear scopedLedgers.
113
113
  const removed = pruneMetricsLedger(tmpDir, 2);
114
114
  assert.equal(removed, 3, "pruneMetricsLedger should report 3 removed units");
115
+ const prunedRaw = readFileSync(metricsPath(tmpDir), "utf-8");
116
+ assert.equal(
117
+ prunedRaw,
118
+ JSON.stringify(JSON.parse(prunedRaw)) + "\n",
119
+ "pruneMetricsLedger should persist compact metrics.json",
120
+ );
115
121
 
116
122
  // 4. Snapshot a new unit via scope. This exercises the lazy-reload path
117
123
  // (scopedLedgers was cleared by prune) and writes the result to disk.