@opengsd/gsd-pi 1.3.0-dev.eed73bea → 1.4.0

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 (505) hide show
  1. package/README.md +10 -10
  2. package/dist/cli.js +17 -4
  3. package/dist/headless-answers.js +1 -1
  4. package/dist/headless-ui.d.ts +1 -1
  5. package/dist/headless-ui.js +1 -1
  6. package/dist/headless.js +1 -1
  7. package/dist/resources/.managed-resources-content-hash +1 -1
  8. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  9. package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
  10. package/dist/resources/extensions/gsd/auto/session.js +11 -0
  11. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
  12. package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
  13. package/dist/resources/extensions/gsd/auto-budget.js +5 -1
  14. package/dist/resources/extensions/gsd/auto-dispatch.js +17 -6
  15. package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
  16. package/dist/resources/extensions/gsd/auto-prompts.js +8 -24
  17. package/dist/resources/extensions/gsd/auto-recovery.js +9 -517
  18. package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
  19. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
  20. package/dist/resources/extensions/gsd/auto-verification.js +5 -2
  21. package/dist/resources/extensions/gsd/auto.js +19 -10
  22. package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +39 -0
  23. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +5 -4
  24. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -18
  26. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +48 -36
  27. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +15 -4
  28. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
  29. package/dist/resources/extensions/gsd/commands/handlers/auto.js +1 -1
  30. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  31. package/dist/resources/extensions/gsd/commands-usage.js +1 -1
  32. package/dist/resources/extensions/gsd/db/engine.js +4 -1
  33. package/dist/resources/extensions/gsd/db-memory-fts-schema.js +34 -0
  34. package/dist/resources/extensions/gsd/db-workspace.js +55 -3
  35. package/dist/resources/extensions/gsd/delegation-policy.js +1 -1
  36. package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -2
  37. package/dist/resources/extensions/gsd/doctor-engine-checks.js +192 -4
  38. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
  39. package/dist/resources/extensions/gsd/exec-sandbox.js +8 -2
  40. package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
  41. package/dist/resources/extensions/gsd/git-service.js +57 -0
  42. package/dist/resources/extensions/gsd/gitignore.js +4 -1
  43. package/dist/resources/extensions/gsd/guided-flow-queue.js +20 -13
  44. package/dist/resources/extensions/gsd/json-persistence.js +20 -0
  45. package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
  46. package/dist/resources/extensions/gsd/layout-policy.js +3 -1
  47. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -7
  48. package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
  49. package/dist/resources/extensions/gsd/metrics.js +4 -4
  50. package/dist/resources/extensions/gsd/migrate-external.js +11 -2
  51. package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
  52. package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
  53. package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
  54. package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
  55. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
  56. package/dist/resources/extensions/gsd/prompts/plan-slice.md +3 -3
  57. package/dist/resources/extensions/gsd/root-write-leak-guard.js +7 -1
  58. package/dist/resources/extensions/gsd/safety/destructive-guard.js +8 -1
  59. package/dist/resources/extensions/gsd/safety/evidence-collector.js +16 -1
  60. package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
  61. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  62. package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
  63. package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
  64. package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
  65. package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
  66. package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
  67. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +27 -33
  68. package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
  69. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
  70. package/dist/resources/extensions/gsd/state.js +12 -611
  71. package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
  72. package/dist/resources/extensions/gsd/tools/complete-slice.js +3 -34
  73. package/dist/resources/extensions/gsd/tools/complete-task.js +8 -41
  74. package/dist/resources/extensions/gsd/tools/plan-slice.js +59 -44
  75. package/dist/resources/extensions/gsd/tools/plan-task.js +28 -5
  76. package/dist/resources/extensions/gsd/undo.js +43 -6
  77. package/dist/resources/extensions/gsd/unit-registry.js +11 -3
  78. package/dist/resources/extensions/gsd/verification-gate.js +7 -0
  79. package/dist/resources/extensions/gsd/workflow-manifest.js +126 -13
  80. package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
  81. package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
  82. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  83. package/dist/web/standalone/.next/BUILD_ID +1 -1
  84. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  85. package/dist/web/standalone/.next/build-manifest.json +4 -4
  86. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  87. package/dist/web/standalone/.next/react-loadable-manifest.json +9 -9
  88. package/dist/web/standalone/.next/required-server-files.json +3 -3
  89. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  90. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  100. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  116. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  128. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  160. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  166. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  182. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  186. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/index.html +1 -1
  196. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  197. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  198. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  199. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  200. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  201. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  202. package/dist/web/standalone/.next/server/app/page.js +2 -2
  203. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  205. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  206. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  207. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/middleware.js +3 -3
  210. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  211. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  212. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  213. package/dist/web/standalone/.next/static/chunks/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
  214. package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
  215. package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
  216. package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
  217. package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
  218. package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
  219. package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
  220. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/app/{layout-4ae2d68984392bbf.js → layout-b35cbfff38aaf4cf.js} +1 -1
  222. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +1 -0
  223. package/dist/web/standalone/.next/static/chunks/{main-app-90d1d8d5e5d2dc6b.js → main-app-590a74400e35f685.js} +1 -1
  224. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
  226. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  227. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  228. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  229. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  230. package/dist/web/standalone/server.js +1 -1
  231. package/package.json +6 -6
  232. package/packages/cloud-mcp-gateway/package.json +2 -2
  233. package/packages/contracts/package.json +1 -1
  234. package/packages/daemon/package.json +4 -4
  235. package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
  236. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  237. package/packages/gsd-agent-core/dist/agent-session.js +3 -0
  238. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  239. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
  240. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
  241. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
  242. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
  243. package/packages/gsd-agent-core/dist/index.d.ts +2 -0
  244. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  245. package/packages/gsd-agent-core/dist/index.js +2 -0
  246. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  247. package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
  248. package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
  249. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
  250. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  251. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  252. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
  253. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  254. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
  255. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  256. package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
  257. package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
  258. package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
  259. package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
  260. package/packages/gsd-agent-core/package.json +5 -5
  261. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  262. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  263. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -11
  264. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  265. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
  266. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
  267. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
  268. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
  269. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
  270. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  271. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -841
  272. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  273. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
  274. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
  275. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
  276. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
  277. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
  278. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
  279. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
  280. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
  281. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
  282. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
  283. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
  284. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
  285. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
  286. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
  287. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
  288. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
  289. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
  290. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  291. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
  292. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  293. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
  294. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
  295. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
  296. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
  297. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
  298. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  299. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
  300. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  301. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
  302. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
  303. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
  304. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
  305. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
  306. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
  307. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
  308. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
  309. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts +2 -0
  310. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  311. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +23 -5
  312. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
  313. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  314. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
  315. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  316. package/packages/gsd-agent-modes/package.json +7 -7
  317. package/packages/mcp-server/dist/workflow-tools.js +1 -1
  318. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  319. package/packages/mcp-server/package.json +4 -4
  320. package/packages/native/package.json +1 -1
  321. package/packages/pi-agent-core/dist/agent-loop.js +3 -2
  322. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  323. package/packages/pi-agent-core/package.json +1 -1
  324. package/packages/pi-ai/dist/models.generated.d.ts +46 -0
  325. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  326. package/packages/pi-ai/dist/models.generated.js +38 -0
  327. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  328. package/packages/pi-ai/package.json +1 -1
  329. package/packages/pi-coding-agent/README.md +3 -2
  330. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
  331. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
  332. package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
  333. package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
  335. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
  336. package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
  337. package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
  338. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
  339. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
  341. package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
  342. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
  343. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
  344. package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
  345. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
  346. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
  347. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
  349. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
  351. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
  352. package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
  353. package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
  354. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
  356. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  357. package/packages/pi-coding-agent/package.json +7 -7
  358. package/packages/pi-tui/package.json +2 -2
  359. package/packages/rpc-client/package.json +2 -2
  360. package/pkg/dist/theme/theme-schema.d.ts +75 -75
  361. package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
  362. package/pkg/dist/theme/theme-schema.js +1 -1
  363. package/pkg/dist/theme/theme-schema.js.map +1 -1
  364. package/pkg/dist/theme/theme.d.ts.map +1 -1
  365. package/pkg/dist/theme/theme.js +11 -7
  366. package/pkg/dist/theme/theme.js.map +1 -1
  367. package/pkg/package.json +1 -1
  368. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  369. package/src/resources/extensions/claude-code-cli/tests/index.test.ts +14 -0
  370. package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
  371. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  372. package/src/resources/extensions/gsd/auto/session.ts +14 -0
  373. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
  374. package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
  375. package/src/resources/extensions/gsd/auto-budget.ts +12 -1
  376. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -7
  377. package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
  378. package/src/resources/extensions/gsd/auto-prompts.ts +7 -23
  379. package/src/resources/extensions/gsd/auto-recovery.ts +13 -518
  380. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
  381. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
  382. package/src/resources/extensions/gsd/auto-verification.ts +5 -1
  383. package/src/resources/extensions/gsd/auto.ts +23 -8
  384. package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +44 -0
  385. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +5 -4
  386. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  387. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +43 -18
  388. package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +49 -1
  389. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +50 -37
  390. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +16 -4
  391. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
  392. package/src/resources/extensions/gsd/commands/handlers/auto.ts +1 -1
  393. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  394. package/src/resources/extensions/gsd/commands-usage.ts +1 -1
  395. package/src/resources/extensions/gsd/db/engine.ts +8 -1
  396. package/src/resources/extensions/gsd/db-memory-fts-schema.ts +45 -0
  397. package/src/resources/extensions/gsd/db-workspace.ts +61 -3
  398. package/src/resources/extensions/gsd/delegation-policy.ts +1 -1
  399. package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -2
  400. package/src/resources/extensions/gsd/doctor-engine-checks.ts +233 -5
  401. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
  402. package/src/resources/extensions/gsd/doctor-types.ts +3 -0
  403. package/src/resources/extensions/gsd/exec-sandbox.ts +7 -2
  404. package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
  405. package/src/resources/extensions/gsd/git-service.ts +64 -0
  406. package/src/resources/extensions/gsd/gitignore.ts +4 -1
  407. package/src/resources/extensions/gsd/guided-flow-queue.ts +20 -13
  408. package/src/resources/extensions/gsd/json-persistence.ts +20 -0
  409. package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
  410. package/src/resources/extensions/gsd/layout-policy.ts +2 -1
  411. package/src/resources/extensions/gsd/markdown-renderer.ts +2 -10
  412. package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
  413. package/src/resources/extensions/gsd/metrics.ts +4 -4
  414. package/src/resources/extensions/gsd/migrate-external.ts +8 -2
  415. package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
  416. package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
  417. package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
  418. package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
  419. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
  420. package/src/resources/extensions/gsd/prompts/plan-slice.md +3 -3
  421. package/src/resources/extensions/gsd/root-write-leak-guard.ts +13 -1
  422. package/src/resources/extensions/gsd/safety/destructive-guard.ts +9 -1
  423. package/src/resources/extensions/gsd/safety/evidence-collector.ts +16 -1
  424. package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
  425. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  426. package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
  427. package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
  428. package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
  429. package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
  430. package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
  431. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +36 -30
  432. package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
  433. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
  434. package/src/resources/extensions/gsd/state.ts +32 -732
  435. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
  436. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
  437. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +14 -5
  438. package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +36 -0
  439. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +182 -4
  440. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +35 -0
  441. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +30 -0
  442. package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
  443. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
  444. package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
  445. package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +58 -3
  446. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
  447. package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +44 -0
  448. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +143 -0
  449. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +239 -2
  450. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +16 -0
  451. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
  452. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
  453. package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
  454. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +11 -2
  455. package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
  456. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
  457. package/src/resources/extensions/gsd/tests/memory-store.test.ts +48 -0
  458. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
  459. package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
  460. package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
  461. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +57 -0
  462. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
  463. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
  464. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -1
  465. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
  466. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +103 -4
  467. package/src/resources/extensions/gsd/tests/plan-task.test.ts +44 -1
  468. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +4 -2
  469. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
  470. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +58 -0
  471. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -6
  472. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +103 -0
  473. package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +20 -1
  474. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +15 -3
  475. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
  476. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +115 -0
  477. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +140 -0
  478. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +6 -3
  479. package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
  480. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +38 -0
  481. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
  482. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +96 -15
  483. package/src/resources/extensions/gsd/tests/workflow-mcp-preflight.test.ts +1 -0
  484. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -4
  485. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +6 -5
  486. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
  487. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  488. package/src/resources/extensions/gsd/tools/complete-slice.ts +3 -30
  489. package/src/resources/extensions/gsd/tools/complete-task.ts +7 -39
  490. package/src/resources/extensions/gsd/tools/plan-slice.ts +60 -47
  491. package/src/resources/extensions/gsd/tools/plan-task.ts +30 -5
  492. package/src/resources/extensions/gsd/undo.ts +47 -6
  493. package/src/resources/extensions/gsd/unit-registry.ts +11 -3
  494. package/src/resources/extensions/gsd/verification-gate.ts +8 -0
  495. package/src/resources/extensions/gsd/workflow-manifest.ts +141 -7
  496. package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
  497. package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
  498. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
  499. package/dist/web/standalone/.next/static/chunks/796.3976108148518f7d.js +0 -10
  500. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +0 -1
  501. package/dist/web/standalone/.next/static/chunks/app/page-6644fc6ee8ca1247.js +0 -1
  502. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +0 -1
  503. package/dist/web/standalone/.next/static/chunks/webpack-7c1d97e39be2da11.js +0 -1
  504. /package/dist/web/standalone/.next/static/{SzEuqWX37DR9MEpEuQjP1 → zQLcXm0Za8lexoXtgDpMG}/_buildManifest.js +0 -0
  505. /package/dist/web/standalone/.next/static/{SzEuqWX37DR9MEpEuQjP1 → zQLcXm0Za8lexoXtgDpMG}/_ssgManifest.js +0 -0
@@ -24,8 +24,9 @@ import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
24
24
  * With external state (symlink), these are a no-op in most cases,
25
25
  * but retained for backwards compatibility during migration.
26
26
  */
27
- const GSD_RUNTIME_PATTERNS = [
27
+ export const GSD_RUNTIME_PATTERNS = [
28
28
  ".gsd-worktrees/",
29
+ ".gsd-backups/",
29
30
  ".gsd/activity/",
30
31
  ".gsd/audit/",
31
32
  ".gsd/forensics/",
@@ -51,6 +52,8 @@ const BASELINE_PATTERNS = [
51
52
  ".gsd",
52
53
  // Worktree container sibling — NOT covered by the ".gsd" pattern above.
53
54
  ".gsd-worktrees/",
55
+ // Flat-phase migration snapshots — NOT covered by the ".gsd" pattern above.
56
+ ".gsd-backups/",
54
57
  ".gsd-id",
55
58
  ".mcp.json",
56
59
  ".bg-shell/",
@@ -360,24 +360,31 @@ function capExistingMilestonesContext(
360
360
  if (fullContext.length <= cap) return fullContext;
361
361
 
362
362
  const notice = `[Existing milestones context truncated to ${cap} chars. Read source paths in this prompt or the corresponding .gsd artifacts for full details.]`;
363
- const compactSections = sections.map(compactSectionForQueueBudget);
364
- const selected: string[] = [];
363
+ const noticeSuffix = `${QUEUE_CONTEXT_SECTION_SEPARATOR}${notice}`;
365
364
 
366
- for (let i = 0; i < sections.length; i++) {
367
- const withFullSection = [
368
- ...selected,
369
- sections[i],
370
- ...compactSections.slice(i + 1),
371
- notice,
372
- ].join(QUEUE_CONTEXT_SECTION_SEPARATOR);
365
+ const selected: string[] = [];
366
+ for (const section of sections) {
367
+ const candidate = [...selected, section].join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
368
+ if (candidate.length <= cap) {
369
+ selected.push(section);
370
+ continue;
371
+ }
372
+ break;
373
+ }
373
374
 
374
- selected.push(withFullSection.length <= cap ? sections[i] : compactSections[i]);
375
+ if (selected.length === sections.length) {
376
+ return selected.join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
375
377
  }
376
378
 
377
- const capped = [...selected, notice].join(QUEUE_CONTEXT_SECTION_SEPARATOR);
378
- if (capped.length <= cap) return capped;
379
+ const compactTail = sections.slice(selected.length).map(compactSectionForQueueBudget);
380
+ const hybrid = [...selected, ...compactTail].join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
381
+ if (hybrid.length <= cap) return hybrid;
382
+
383
+ const compact = sections.map(compactSectionForQueueBudget);
384
+ const compactContext = compact.join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
385
+ if (compactContext.length <= cap) return compactContext;
379
386
 
380
- return `${capped.slice(0, Math.max(0, cap - notice.length - 2)).trimEnd()}\n\n${notice}`;
387
+ return `${compactContext.slice(0, Math.max(0, cap - notice.length - 2)).trimEnd()}\n\n${notice}`;
381
388
  }
382
389
 
383
390
  function compactSectionForQueueBudget(section: string): string {
@@ -62,6 +62,26 @@ export function saveJsonFile<T>(filePath: string, data: T): void {
62
62
  }
63
63
  }
64
64
 
65
+ /**
66
+ * Save a JSON file atomically using compact serialization.
67
+ *
68
+ * Intended for machine-only ledgers where pretty-printing has no consumer.
69
+ * Keeps the same write-tmp-rename safety and non-fatal error behavior as
70
+ * saveJsonFile.
71
+ */
72
+ export function saveJsonFileCompact<T>(filePath: string, data: T): void {
73
+ try {
74
+ mkdirSync(dirname(filePath), { recursive: true });
75
+ // Use randomized tmp suffix to prevent concurrent-write data loss
76
+ const tmp = `${filePath}.tmp.${randomBytes(4).toString("hex")}`;
77
+ writeFileSync(tmp, JSON.stringify(data) + "\n", "utf-8");
78
+ renameSync(tmp, filePath);
79
+ // No cleanup needed — renameSync atomically removes tmp on success
80
+ } catch {
81
+ // Non-fatal — don't let persistence failures break operation
82
+ }
83
+ }
84
+
65
85
  /**
66
86
  * Write a JSON file atomically (write to .tmp, then rename).
67
87
  * Creates parent directories as needed. Non-fatal on error.
@@ -35,8 +35,8 @@ interface SynthesizedRow {
35
35
  * - Idempotent (per-row): each migrated memory carries
36
36
  * `structured_fields.sourceKnowledgeId = "<P|L>NNN"`. Rows whose ID is
37
37
  * already present in the memory store are skipped.
38
- * - Best-effort: never throws. Logs and returns 0 on failure so a broken
39
- * backfill cannot block agent startup.
38
+ * - Best-effort: never throws. Failed memory inserts are logged and skipped;
39
+ * setup/read failures log and return 0 so backfill cannot block startup.
40
40
  * - Rules (K###) are intentionally skipped — they remain manually maintained
41
41
  * in `KNOWLEDGE.md` per ADR-013.
42
42
  *
@@ -69,14 +69,20 @@ export function backfillKnowledgeToMemories(basePath: string): number {
69
69
  const matchPattern = `%"sourceKnowledgeId":"${synth.id}"%`;
70
70
  if (checkExisting.get({ ":pattern": matchPattern })) continue;
71
71
 
72
- const id = createMemory({
73
- category: synth.category,
74
- content: synth.content,
75
- scope: synth.scope,
76
- confidence: 0.85,
77
- structuredFields: synth.structuredFields,
78
- });
79
- if (id) written += 1;
72
+ try {
73
+ const id = createMemory({
74
+ category: synth.category,
75
+ content: synth.content,
76
+ scope: synth.scope,
77
+ confidence: 0.85,
78
+ structuredFields: synth.structuredFields,
79
+ });
80
+ if (id) written += 1;
81
+ } catch (rowErr) {
82
+ const message = rowErr instanceof Error ? rowErr.message : String(rowErr);
83
+ logWarning("knowledge-backfill", `KNOWLEDGE.md -> memories backfill skipped ${synth.id}: ${message}`);
84
+ continue;
85
+ }
80
86
  }
81
87
 
82
88
  return written;
@@ -47,8 +47,9 @@ export function dbPath(basePath: string): string {
47
47
  * Used by the renderer to derive the phase number from the DB's milestone_id.
48
48
  */
49
49
  export function milestoneIdToPhaseNum(milestoneId: string): number {
50
- // No $ anchor: accepts bare (M012) and team-suffixed (M012-abc123) IDs.
50
+ // No $ anchor: accepts bare (M012), team-suffixed (M012-abc123), and legacy numeric IDs.
51
51
  const m = milestoneId.match(/^M0*(\d+)/i);
52
+ if (!m && /^\d+$/.test(milestoneId)) return Number.parseInt(milestoneId, 10);
52
53
  return m ? Number.parseInt(m[1]!, 10) : 1;
53
54
  }
54
55
 
@@ -632,16 +632,8 @@ export async function renderRoadmapCheckboxes(
632
632
  basePath: string,
633
633
  milestoneId: string,
634
634
  ): Promise<boolean> {
635
- const slices = getMilestoneSlices(milestoneId);
636
- if (slices.length === 0) {
637
- process.stderr.write(
638
- `markdown-renderer: no slices found for milestone ${milestoneId}\n`,
639
- );
640
- return false;
641
- }
642
-
643
- await renderRoadmapFromDb(basePath, milestoneId);
644
- return true;
635
+ const rendered = await renderRoadmapFromDb(basePath, milestoneId);
636
+ return !("skipped" in rendered);
645
637
  }
646
638
 
647
639
  /**
@@ -49,8 +49,8 @@ type DecisionContentFields = Pick<DecisionRow, "decision" | "choice" | "rational
49
49
  * decision is checked individually; only decisions whose id is already
50
50
  * present in the memory store are skipped. A user-authored memory with
51
51
  * their own `sourceDecisionId` does NOT abort the backfill.
52
- * - Best-effort: never throws. Logs and returns 0 on failure so a broken
53
- * backfill cannot block agent startup.
52
+ * - Best-effort: never throws. Failed memory inserts are logged and skipped;
53
+ * setup/read failures log and return 0 so backfill cannot block startup.
54
54
  * - Full migration (ADR-013 Stage 2a): both active and superseded rows are
55
55
  * migrated. `structured_fields.superseded_by` preserves the supersedes
56
56
  * chain so the DECISIONS.md projection regen can source from memories
@@ -146,24 +146,30 @@ export function backfillDecisionsToMemories(): number {
146
146
  }
147
147
 
148
148
  const content = synthesizeDecisionMemoryContent(row);
149
- const id = createMemory({
150
- category: "architecture",
151
- content,
152
- scope: row.scope || "project",
153
- confidence: 0.85,
154
- structuredFields: {
155
- sourceDecisionId: row.id,
156
- when_context: row.when_context,
157
- scope: row.scope,
158
- decision: row.decision,
159
- choice: row.choice,
160
- rationale: row.rationale,
161
- made_by: row.made_by,
162
- revisable: row.revisable,
163
- superseded_by: row.superseded_by,
164
- },
165
- });
166
- if (id) written += 1;
149
+ try {
150
+ const id = createMemory({
151
+ category: "architecture",
152
+ content,
153
+ scope: row.scope || "project",
154
+ confidence: 0.85,
155
+ structuredFields: {
156
+ sourceDecisionId: row.id,
157
+ when_context: row.when_context,
158
+ scope: row.scope,
159
+ decision: row.decision,
160
+ choice: row.choice,
161
+ rationale: row.rationale,
162
+ made_by: row.made_by,
163
+ revisable: row.revisable,
164
+ superseded_by: row.superseded_by,
165
+ },
166
+ });
167
+ if (id) written += 1;
168
+ } catch (rowErr) {
169
+ const message = rowErr instanceof Error ? rowErr.message : String(rowErr);
170
+ logWarning("memory-backfill", `decisions->memories backfill skipped ${row.id}: ${message}`);
171
+ continue;
172
+ }
167
173
  }
168
174
 
169
175
  if (healed > 0) {
@@ -19,7 +19,7 @@ import { openSync, closeSync, unlinkSync, statSync, writeFileSync } from "node:f
19
19
  import type { ExtensionContext } from "@gsd/pi-coding-agent";
20
20
  import { gsdRoot } from "./paths.js";
21
21
  import { getAndClearSkills } from "./skill-telemetry.js";
22
- import { loadJsonFile, loadJsonFileOrNull, saveJsonFile } from "./json-persistence.js";
22
+ import { loadJsonFile, loadJsonFileOrNull, saveJsonFileCompact } from "./json-persistence.js";
23
23
  import { parseUnitId } from "./unit-id.js";
24
24
  import { buildAuditEnvelope, emitUokAuditEvent } from "./uok/audit.js";
25
25
  import { isUnifiedAuditEnabled } from "./uok/audit-toggle.js";
@@ -873,7 +873,7 @@ export function pruneMetricsLedger(base: string, keepCount: number): number {
873
873
  if (!disk || disk.units.length <= keepCount) return 0;
874
874
  const removed = disk.units.length - keepCount;
875
875
  disk.units = keepNewestUnits(disk.units, keepCount);
876
- saveJsonFile(metricsPath(base), disk);
876
+ saveJsonFileCompact(metricsPath(base), disk);
877
877
  // Keep the in-memory ledger in sync if it is loaded for this session.
878
878
  if (ledger) {
879
879
  ledger.units = keepNewestUnits(ledger.units, keepCount);
@@ -1041,7 +1041,7 @@ function saveLedger(base: string, data: MetricsLedger): void {
1041
1041
  : dataUnits;
1042
1042
  merged.sort(compareUnitsByTime);
1043
1043
  data.units = keepNewestUnits(merged);
1044
- saveJsonFile(path, data);
1044
+ saveJsonFileCompact(path, data);
1045
1045
  } finally {
1046
1046
  releaseLock(lockPath);
1047
1047
  }
@@ -1053,6 +1053,6 @@ function saveLedger(base: string, data: MetricsLedger): void {
1053
1053
  // read-merge-write sequence without mutual exclusion.
1054
1054
  logWarning("fs", "saveLedger: lock not acquired — falling back to direct write (no merge)");
1055
1055
  data.units = keepNewestUnits(data.units);
1056
- saveJsonFile(path, data);
1056
+ saveJsonFileCompact(path, data);
1057
1057
  }
1058
1058
  }
@@ -118,6 +118,7 @@ export function migrateToExternalState(basePath: string): MigrationResult {
118
118
 
119
119
  // Copy contents to external dir, skipping worktrees/
120
120
  const entries = readdirSync(migratingPath, { withFileTypes: true });
121
+ const copyFailures: string[] = [];
121
122
  for (const entry of entries) {
122
123
  if (entry.name === "worktrees") continue; // worktrees stay local
123
124
 
@@ -130,10 +131,15 @@ export function migrateToExternalState(basePath: string): MigrationResult {
130
131
  } else {
131
132
  cpSync(src, dst, { force: true });
132
133
  }
133
- } catch {
134
- // Non-fatal: continue with other files
134
+ } catch (copyErr) {
135
+ copyFailures.push(`${entry.name}: ${getErrorMessage(copyErr)}`);
135
136
  }
136
137
  }
138
+ if (copyFailures.length > 0) {
139
+ try { rmSync(localGsd, { force: true }); } catch { /* may not exist */ }
140
+ renameSync(migratingPath, localGsd);
141
+ return { migrated: false, error: `Migration copy failed: ${copyFailures.join("; ")}` };
142
+ }
137
143
 
138
144
  // Create symlink .gsd -> external path
139
145
  symlinkSync(externalPath, localGsd, "junction");
@@ -90,6 +90,28 @@ function scanHasExtraIdentities(a: HierarchyScan, b: HierarchyScan): boolean {
90
90
  );
91
91
  }
92
92
 
93
+ function paddedMilestoneId(id: string): string | null {
94
+ return /^\d+$/.test(id) ? `M${id.padStart(3, "0")}` : null;
95
+ }
96
+
97
+ function replaceSetPrefix(values: Set<string>, from: string, to: string): void {
98
+ for (const value of [...values]) {
99
+ if (value !== from && !value.startsWith(`${from}/`)) continue;
100
+ values.delete(value);
101
+ values.add(`${to}${value.slice(from.length)}`);
102
+ }
103
+ }
104
+
105
+ function alignNumericMarkdownIdsWithDb(markdownScan: HierarchyScan, dbScan: HierarchyScan): void {
106
+ for (const dbId of dbScan.milestones) {
107
+ const paddedId = paddedMilestoneId(dbId);
108
+ if (!paddedId || dbScan.milestones.has(paddedId) || !markdownScan.milestones.has(paddedId)) continue;
109
+ replaceSetPrefix(markdownScan.milestones, paddedId, dbId);
110
+ replaceSetPrefix(markdownScan.slices, paddedId, dbId);
111
+ replaceSetPrefix(markdownScan.tasks, paddedId, dbId);
112
+ }
113
+ }
114
+
93
115
  /**
94
116
  * True when the DB holds any milestone/slice/task identity the markdown lacks —
95
117
  * i.e. a `/gsd recover --confirm` (markdown → DB) would DELETE authoritative DB
@@ -185,6 +207,7 @@ export async function checkMarkdownHierarchyAgainstDb(
185
207
 
186
208
  const dbScan = scanDbHierarchy();
187
209
  const beforeDb = dbScan.counts;
210
+ alignNumericMarkdownIdsWithDb(markdownScan, dbScan);
188
211
 
189
212
  // Discussion-phase scratch: a milestone dir with no ROADMAP and no DB row is
190
213
  // a pre-registration discussion artifact (CONTEXT/CONTEXT-DRAFT only — the
@@ -141,7 +141,8 @@ export function clearReservedMilestoneIds(): void {
141
141
 
142
142
  // ─── Discovery ──────────────────────────────────────────────────────────────
143
143
 
144
- function scanMilestoneIdsFromDir(dir: string): string[] {
144
+ function scanMilestoneIdsFromDir(basePath: string, dir: string): string[] {
145
+ const legacyNumericIds = idsWithLegacyNumericDirs(basePath);
145
146
  return readdirSync(dir, { withFileTypes: true })
146
147
  .filter((d) => d.isDirectory())
147
148
  .map((d) => {
@@ -149,6 +150,12 @@ function scanMilestoneIdsFromDir(dir: string): string[] {
149
150
  if (MILESTONE_ID_RE.test(d.name)) {
150
151
  return d.name;
151
152
  }
153
+ // Legacy recovery/imports may contain bare numeric milestone directories
154
+ // (for example `milestones/15/15-ROADMAP.md`). The DB can preserve that
155
+ // id, and rebuild renders it, so drift scans must see it too.
156
+ if (/^\d+$/.test(d.name)) {
157
+ return d.name;
158
+ }
152
159
  // Legacy layout: M001-abcdef-slug descriptor directories
153
160
  const legacyMatch = d.name.match(/^(M\d{3}(?:-[a-z0-9]{6})?)-/);
154
161
  if (legacyMatch) {
@@ -162,6 +169,10 @@ function scanMilestoneIdsFromDir(dir: string): string[] {
162
169
  if (MILESTONE_ID_RE.test(fromSlug)) {
163
170
  return fromSlug;
164
171
  }
172
+ const numericId = String(phaseNum);
173
+ if (legacyNumericIds.has(numericId)) {
174
+ return numericId;
175
+ }
165
176
  return `M${String(phaseNum).padStart(3, "0")}`;
166
177
  }
167
178
  return null;
@@ -169,6 +180,24 @@ function scanMilestoneIdsFromDir(dir: string): string[] {
169
180
  .filter((id): id is string => id !== null);
170
181
  }
171
182
 
183
+ function idsWithLegacyNumericDirs(basePath: string): Set<string> {
184
+ const legacyDir = join(gsdProjectionRoot(basePath), "milestones");
185
+ const ids = new Set<string>();
186
+ try {
187
+ for (const entry of readdirSync(legacyDir, { withFileTypes: true })) {
188
+ if (entry.isDirectory() && /^\d+$/.test(entry.name)) ids.add(entry.name);
189
+ }
190
+ } catch (err) {
191
+ // A missing legacy directory is the common, benign case (nothing to
192
+ // consult). Only surface a real failure when the directory exists but
193
+ // could not be read.
194
+ if (existsSync(legacyDir)) {
195
+ logWarning("engine", `idsWithLegacyNumericDirs: ${legacyDir} exists but readdirSync failed — ${getErrorMessage(err)}`);
196
+ }
197
+ }
198
+ return ids;
199
+ }
200
+
172
201
  /** Scan the milestones directory and return IDs sorted by queue order (or numeric fallback). */
173
202
  export function findMilestoneIds(basePath: string): string[] {
174
203
  const root = gsdProjectionRoot(basePath);
@@ -181,7 +210,7 @@ export function findMilestoneIds(basePath: string): string[] {
181
210
  const ids = new Set<string>();
182
211
  for (const dir of dirs) {
183
212
  try {
184
- for (const id of scanMilestoneIdsFromDir(dir)) ids.add(id);
213
+ for (const id of scanMilestoneIdsFromDir(basePath, dir)) ids.add(id);
185
214
  } catch (err) {
186
215
  if (existsSync(dir)) {
187
216
  logWarning("engine", `findMilestoneIds: ${dir} exists but readdirSync failed — ${getErrorMessage(err)}`);
@@ -33,16 +33,87 @@ function _isAlreadyRestoredApplyError(err: unknown): boolean {
33
33
 
34
34
  export { _isAlreadyRestoredApplyError };
35
35
 
36
+ function gitOutput(basePath: string, args: string[]): string {
37
+ return execFileSync("git", args, {
38
+ cwd: basePath,
39
+ stdio: ["ignore", "pipe", "pipe"],
40
+ encoding: "utf-8",
41
+ env: GIT_NO_PROMPT_ENV,
42
+ });
43
+ }
44
+
45
+ function listStashUntrackedPaths(basePath: string, stashRef: string): string[] | null {
46
+ try {
47
+ return gitOutput(basePath, ["ls-tree", "-r", "-z", "--name-only", `${stashRef}^3`]).split("\0").filter(Boolean);
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+
53
+ function listStashTrackedPaths(basePath: string, stashRef: string): string[] | null {
54
+ try {
55
+ return gitOutput(basePath, ["diff", "--name-only", "-z", `${stashRef}^1`, stashRef]).split("\0").filter(Boolean);
56
+ } catch {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ interface PorcelainEntry {
62
+ code: string;
63
+ path: string;
64
+ }
65
+
66
+ function readWorkingTreeStatus(basePath: string): PorcelainEntry[] | null {
67
+ try {
68
+ return gitOutput(basePath, ["status", "--porcelain", "-z", "--untracked-files=all"])
69
+ .split("\0")
70
+ .filter(Boolean)
71
+ .map((entry) => ({ code: entry.slice(0, 2), path: entry.slice(3) }));
72
+ } catch {
73
+ return null;
74
+ }
75
+ }
76
+
77
+ function isAlreadyRestoredUntrackedStatus(basePath: string, stashRef: string, statusEntries: PorcelainEntry[]): boolean {
78
+ if (statusEntries.length === 0 || statusEntries.some((entry) => entry.code !== "??")) return false;
79
+ const stashTrackedPaths = listStashTrackedPaths(basePath, stashRef);
80
+ if (!stashTrackedPaths || stashTrackedPaths.length > 0) return false;
81
+ const stashUntrackedPaths = listStashUntrackedPaths(basePath, stashRef);
82
+ if (!stashUntrackedPaths || stashUntrackedPaths.length === 0) return false;
83
+ const stashUntrackedPathSet = new Set(stashUntrackedPaths);
84
+ const workingTreeUntrackedPathSet = new Set(statusEntries.map((entry) => entry.path));
85
+ // "Already restored" requires the working tree's untracked paths to match the
86
+ // stash's untracked paths exactly, in BOTH directions:
87
+ // 1. every current untracked path comes from the stash (no unexplained user
88
+ // work that an apply would clobber), AND
89
+ // 2. every stash untracked path is already present in the working tree.
90
+ // Without (2), a partial restore (where only some stash files were recovered)
91
+ // would be misread as fully restored: the audit would no-op without applying
92
+ // or warning, leaving the remaining pre-merge files missing.
93
+ return (
94
+ statusEntries.every((entry) => stashUntrackedPathSet.has(entry.path)) &&
95
+ stashUntrackedPaths.every((path) => workingTreeUntrackedPathSet.has(path))
96
+ );
97
+ }
98
+
99
+ function manualApplyWarning(stashRef: string, milestoneId: string, reason: string): string {
100
+ return (
101
+ `Pre-merge stash ${stashRef} for milestone ${milestoneId} not auto-applied: ${reason}; ` +
102
+ `run \`git stash apply ${stashRef}\` manually to restore your pre-merge changes.`
103
+ );
104
+ }
105
+
36
106
  /**
37
107
  * Audit `git stash list` for orphaned `gsd-preflight-stash:M00x:*` entries.
38
108
  *
39
109
  * The matching merge code in `phases.ts` previously skipped the postflight
40
110
  * pop whenever `mergeAndExit` threw, leaking the user's pre-merge working
41
- * tree into the stash list. For every preflight-stash entry whose milestone
42
- * is now complete (per the supplied callback), `git stash apply` is invoked
111
+ * tree into the stash list. Completed-milestone stashes are only auto-applied
112
+ * when the working tree is clean and the stash does not modify tracked files.
113
+ * Dirty trees and tracked-file stashes are left untouched with a manual
114
+ * recovery warning. When auto-apply is safe, `git stash apply` is invoked —
43
115
  * NOT `pop`. The stash entry stays in the list so the user retains a backup
44
- * if the apply produces unexpected merge results. Idempotent across repeated
45
- * startup runs.
116
+ * if the apply produces unexpected merge results.
46
117
  *
47
118
  * Failures are best-effort: a list error (no repo, git unavailable) returns
48
119
  * an empty result. An apply error becomes a warning the user sees alongside
@@ -56,16 +127,7 @@ export function auditOrphanedPreflightStashes(
56
127
 
57
128
  let listOutput: string;
58
129
  try {
59
- listOutput = execFileSync(
60
- "git",
61
- ["stash", "list", "--format=%gd%x00%s"],
62
- {
63
- cwd: basePath,
64
- stdio: ["ignore", "pipe", "pipe"],
65
- encoding: "utf-8",
66
- env: GIT_NO_PROMPT_ENV,
67
- },
68
- );
130
+ listOutput = gitOutput(basePath, ["stash", "list", "--format=%gd%x00%s"]);
69
131
  } catch {
70
132
  return result;
71
133
  }
@@ -93,13 +155,39 @@ export function auditOrphanedPreflightStashes(
93
155
  }
94
156
  if (!complete) continue;
95
157
 
158
+ const statusEntries = readWorkingTreeStatus(basePath);
159
+ if (!statusEntries) {
160
+ result.warnings.push(
161
+ manualApplyWarning(ref, milestoneId, "could not verify working tree status"),
162
+ );
163
+ continue;
164
+ }
165
+ if (statusEntries.length > 0) {
166
+ if (isAlreadyRestoredUntrackedStatus(basePath, ref, statusEntries)) continue;
167
+ result.warnings.push(manualApplyWarning(ref, milestoneId, "working tree not clean"));
168
+ continue;
169
+ }
170
+
171
+ const trackedPaths = listStashTrackedPaths(basePath, ref);
172
+ if (trackedPaths === null) {
173
+ result.warnings.push(
174
+ manualApplyWarning(ref, milestoneId, "could not inspect tracked paths in stash"),
175
+ );
176
+ continue;
177
+ }
178
+ if (trackedPaths.length > 0) {
179
+ // A retained tracked-file stash has no durable marker showing whether a
180
+ // clean tree needs first recovery or would be re-mutated by an old backup.
181
+ const preview = trackedPaths.slice(0, 5).join(", ");
182
+ const suffix = trackedPaths.length > 5 ? `, and ${trackedPaths.length - 5} more` : "";
183
+ result.warnings.push(
184
+ manualApplyWarning(ref, milestoneId, `stash modifies tracked files (${preview}${suffix})`),
185
+ );
186
+ continue;
187
+ }
188
+
96
189
  try {
97
- execFileSync("git", ["stash", "apply", "--quiet", ref], {
98
- cwd: basePath,
99
- stdio: ["ignore", "pipe", "pipe"],
100
- encoding: "utf-8",
101
- env: GIT_NO_PROMPT_ENV,
102
- });
190
+ gitOutput(basePath, ["stash", "apply", "--quiet", ref]);
103
191
  result.applied.push({ milestoneId, stashRef: ref });
104
192
  } catch (err) {
105
193
  // Idempotent steady state: stash was already applied in a prior audit
@@ -16,18 +16,20 @@ You are running the GSD **code-review** workflow — review source files changed
16
16
 
17
17
  1. **Determine the file set.** Use the explicit `--files` list if provided. Otherwise derive the changed source files from the active slice's recent commits / SUMMARY, or fall back to the git diff against the base branch. Exclude `.gsd/`, lockfiles, generated/vendored code, and docs unless `--files` names them.
18
18
 
19
- 2. **Review each file** at the requested depth:
19
+ 2. **Gather diff-first context.** Run `git diff` for the file set (or the relevant commit range) and use that as the primary review evidence. Use `read` only when the diff is insufficient — new/untracked files, truncated hunks, or missing surrounding context needed for a finding. Do **not** read every changed file when the diff already covers the edits. If the Tool Call Loop Guard blocks a tool, stop calling tools for the rest of this turn and continue in text.
20
+
21
+ 3. **Review at the requested depth:**
20
22
  - **quick** — bugs, security, and correctness only.
21
23
  - **standard** (default) — quick + maintainability, error handling, edge cases.
22
24
  - **deep** — standard + performance, concurrency, API design, test coverage gaps.
23
25
 
24
26
  Ground every finding in the actual code with file path + line reference. Categorize each by severity (critical / warning / nit) and type (bug, security, quality, performance).
25
27
 
26
- 3. **Write the review.** Produce `.gsd/reviews/{{reviewId}}-REVIEW.md` with the findings table and per-finding detail (location, issue, suggested fix).
28
+ 4. **Write the review.** Produce `.gsd/reviews/{{reviewId}}-REVIEW.md` with the findings table and per-finding detail (location, issue, suggested fix).
27
29
 
28
- 4. **Present results.** Summarize counts by severity and list the critical findings first.
30
+ 5. **Present results.** Summarize counts by severity and list the critical findings first.
29
31
 
30
- 5. **Fix mode** (only when `--fix` is set): for each finding that is safely auto-fixable (deterministic, no behavior change beyond the fix), apply it. After each fix batch, run the project's tests. Commit atomically with the finding IDs referenced in the message. Do not auto-apply findings that are ambiguous or that change public behavior — surface those for a human decision instead.
32
+ 6. **Fix mode** (only when `--fix` is set): for each finding that is safely auto-fixable (deterministic, no behavior change beyond the fix), apply it. After each fix batch, run the project's tests. Commit atomically with the finding IDs referenced in the message. Do not auto-apply findings that are ambiguous or that change public behavior — surface those for a human decision instead.
31
33
 
32
34
  ## Success criteria
33
35
 
@@ -104,8 +104,8 @@ If the preference is off, ignore this section and plan every slice fully.
104
104
 
105
105
  If the roadmap has one slice, also plan S01 and its tasks inline:
106
106
 
107
- 1. After `gsd_plan_milestone` returns, call `gsd_plan_slice` for S01 with full task breakdown.
108
- 2. Use inlined **Slice Plan** and **Task Plan** templates for tool parameters.
107
+ 1. After `gsd_plan_milestone` returns, call `gsd_plan_slice` for S01 with slice metadata only; omit `tasks`.
108
+ 2. Then call `gsd_plan_task` once per S01 task. Use inlined **Slice Plan** and **Task Plan** templates for tool parameters.
109
109
  3. Keep simple slices lean. Omit Proof Level, Integration Closure, and Observability if all would be "none"; executable verification commands are enough.
110
110
 
111
111
  Do **not** write plan files manually; use DB-backed tools so state stays consistent.
@@ -45,8 +45,8 @@ If slice research is inlined, trust its architectural findings, but verify every
45
45
  6. Include Threat Surface (Q3), Requirement Impact (Q4), proof level, observability, integration closure, Failure Modes (Q5), Load Profile (Q6), and Negative Tests (Q7) only where applicable.
46
46
  7. Right-size tasks. Simple slices can be one task; split only when context, ownership, or verification boundaries justify it.
47
47
  8. Task `verify` commands must be safe, simple commands. Do not use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`. If multiple checks are needed, create a small test file and run it with `node --test` or a package test script, or use separate simple commands joined only with `&&`. For absence checks, verify a pattern does not exist with `! grep -q 'pattern' file` or `! rg -q 'pattern' file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches, and the verification gate treats that as failure.
48
- 9. Each task needs the exact `gsd_plan_slice.tasks[]` shape: `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. `description` should contain the Why / Do / Done-when narrative. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even when there is only one path (for example, `"inputs": ["src/index.ts"]`, never `"inputs": "src/index.ts"`). Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands. **`expectedOutput` must only list files the task actually creates or overwrites on disk.** Do NOT include files the task merely reads, verifies, tests, or describes — those belong in `inputs`, `verify`, `description`, or slice success criteria. If a task is a pure verification or test task that produces no new files, `expectedOutput` must be `[]`; if it writes a test-result log or assertion output file, list only that concrete file path. A file that does not yet exist on disk and is needed as an `input` must be produced by an earlier task's `expectedOutput` — if no prior task creates it, add a task before this one that does. Never list GSD planning artifacts — anything under `.gsd/`, `.planning/`, or `.audits/`, or artifact names like `M001-CONTEXT.md` / `S01-PLAN.md` — in `inputs`, `files`, or `expectedOutput`: their content is preloaded as context, and they are written by workflow tools, not by tasks.
49
- 10. Persist with `gsd_plan_slice` using `milestoneId`, `sliceId`, `goal`, optional `successCriteria`/`proofLevel`/`integrationClosure`/`observabilityImpact`, and `tasks`. `gsd_plan_slice` handles task persistence transactionally and renders `{{outputPath}}` plus task plans; do not call `gsd_plan_task`. The DB-backed tool is the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
48
+ 9. Each task persisted with `gsd_plan_task` needs the exact shape: `milestoneId`, `sliceId`, `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. `description` should contain the Why / Do / Done-when narrative. Any npm package name in a task description's install/add instructions (`npm install`, `yarn add`, `pnpm add`) or in `require('...')` or `import ... from '...'` code examples is subject to pre-execution registry validation; reference only packages that exist on the public npm registry, and remove or correct any package name that is not real. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even when there is only one path (for example, `"inputs": ["src/index.ts"]`, never `"inputs": "src/index.ts"`). Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands. **`expectedOutput` must only list files the task actually creates or overwrites on disk.** Do NOT include files the task merely reads, verifies, tests, or describes — those belong in `inputs`, `verify`, `description`, or slice success criteria. If a task is a pure verification or test task that produces no new files, `expectedOutput` must be `[]`; if it writes a test-result log or assertion output file, list only that concrete file path. A file that does not yet exist on disk and is needed as an `input` must be produced by an earlier task's `expectedOutput` — if no prior task creates it, add a task before this one that does. Never list GSD planning artifacts — anything under `.gsd/`, `.planning/`, or `.audits/`, or artifact names like `M001-CONTEXT.md` / `S01-PLAN.md` — in `inputs`, `files`, or `expectedOutput`: their content is preloaded as context, and they are written by workflow tools, not by tasks.
49
+ 10. Persist incrementally through DB-backed tools. First call `gsd_plan_slice` with `milestoneId`, `sliceId`, `goal`, and optional `successCriteria`/`proofLevel`/`integrationClosure`/`observabilityImpact`; omit `tasks` for this metadata call. Then call `gsd_plan_task` once per task, using the task shape above. Each successful tool call saves progress and re-renders `{{outputPath}}` from DB. The DB-backed tools are the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
50
50
  11. Self-audit before finishing: goal/demo closure, requirement coverage, deliverable coverage audit (cross-check every file listed in CONTEXT.md `## Scope` / `### In Scope` against task `files` or `expectedOutput`), locked decisions, concrete paths, dependency order, wiring, scope size, proof truthfulness, feature completeness, and quality gates. Quality gates: non-trivial slices/tasks include specific Q3-Q7 coverage where applicable.
51
51
  12. If planning creates structural decisions, call `gsd_decision_save` for each; the tool persists the decision and regenerates `.gsd/DECISIONS.md`.
52
52
  13. {{commitInstruction}}
@@ -55,6 +55,6 @@ The slice directory already exists. Do not mkdir.
55
55
 
56
56
  **Autonomous execution:** no human is available. Do not call `ask_user_questions` or `secure_env_collect`; make reasonable assumptions and document them.
57
57
 
58
- **You MUST call `gsd_plan_slice` to persist planning state before finishing, unless the stale-path safety rule above stops the unit before safe planning can occur.**
58
+ **You MUST call `gsd_plan_slice` and then `gsd_plan_task` once for each planned task before finishing, unless the stale-path safety rule above stops the unit before safe planning can occur.**
59
59
 
60
60
  When done, say: "Slice {{sliceId}} planned." Say this exactly once — if you already said it in a prior message, do not repeat it.
@@ -5,8 +5,18 @@ import { execFileSync } from "node:child_process";
5
5
  import { createHash } from "node:crypto";
6
6
  import { existsSync, readFileSync, statSync } from "node:fs";
7
7
  import { join } from "node:path";
8
+ import { GSD_RUNTIME_PATTERNS } from "./gitignore.js";
8
9
 
9
10
  const MAX_SYNC_FINGERPRINT_BYTES = 1_500_000_000;
11
+ const ROOT_RUNTIME_PATH_PREFIXES = Array.from(
12
+ new Set(
13
+ GSD_RUNTIME_PATTERNS.map((pattern) => {
14
+ const path = pattern.replace(/\/+$/, "");
15
+ const slash = path.indexOf("/");
16
+ return slash === -1 ? path : path.slice(0, slash);
17
+ }),
18
+ ),
19
+ );
10
20
 
11
21
  export interface RootDirtyEntry {
12
22
  path: string;
@@ -25,7 +35,9 @@ export interface RootWriteLeak {
25
35
  export type RootDirtySnapshot = Map<string, RootDirtyEntry>;
26
36
 
27
37
  function isRootRuntimePath(path: string): boolean {
28
- return path === ".gsd" || path.startsWith(".gsd/");
38
+ return ROOT_RUNTIME_PATH_PREFIXES.some(
39
+ (prefix) => path === prefix || path.startsWith(`${prefix}/`),
40
+ );
29
41
  }
30
42
 
31
43
  function fileFingerprint(rootPath: string, relPath: string): string {