@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.72e3af2a

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 (357) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
  3. package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
  4. package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
  5. package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
  6. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  7. package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
  9. package/dist/resources/extensions/gsd/auto-prompts.js +26 -11
  10. package/dist/resources/extensions/gsd/auto-recovery.js +6 -507
  11. package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
  12. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
  13. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
  14. package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +38 -0
  15. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +6 -1
  16. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +10 -19
  18. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
  19. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +68 -10
  20. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
  21. package/dist/resources/extensions/gsd/commands-context.js +19 -1
  22. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +16 -10
  23. package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
  24. package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
  25. package/dist/resources/extensions/gsd/db/queries.js +60 -0
  26. package/dist/resources/extensions/gsd/db-workspace.js +55 -3
  27. package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
  28. package/dist/resources/extensions/gsd/exec-sandbox.js +45 -9
  29. package/dist/resources/extensions/gsd/forensics.js +2 -32
  30. package/dist/resources/extensions/gsd/git-service.js +4 -4
  31. package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
  32. package/dist/resources/extensions/gsd/health-widget.js +55 -29
  33. package/dist/resources/extensions/gsd/layout-policy.js +3 -1
  34. package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
  35. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
  36. package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
  37. package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
  38. package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
  39. package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
  40. package/dist/resources/extensions/gsd/quick.js +45 -2
  41. package/dist/resources/extensions/gsd/session-forensics.js +11 -1
  42. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  43. package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
  44. package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
  45. package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
  46. package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
  47. package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
  48. package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +45 -2
  49. package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
  50. package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
  51. package/dist/resources/extensions/gsd/state.js +12 -611
  52. package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
  53. package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
  54. package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
  55. package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
  56. package/dist/resources/extensions/gsd/unit-registry.js +32 -4
  57. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
  58. package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
  59. package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
  60. package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
  61. package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
  62. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  63. package/dist/web/standalone/.next/BUILD_ID +1 -1
  64. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  65. package/dist/web/standalone/.next/build-manifest.json +3 -3
  66. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  67. package/dist/web/standalone/.next/react-loadable-manifest.json +9 -9
  68. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/index.html +1 -1
  88. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  89. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  90. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  91. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  96. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  99. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  100. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  101. package/dist/web/standalone/.next/static/chunks/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
  102. package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
  103. package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
  104. package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
  105. package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
  106. package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
  107. package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
  108. package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
  109. package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
  110. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  111. package/package.json +1 -1
  112. package/packages/cloud-mcp-gateway/package.json +2 -2
  113. package/packages/contracts/dist/workflow.d.ts +1 -0
  114. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  115. package/packages/contracts/dist/workflow.js +2 -0
  116. package/packages/contracts/dist/workflow.js.map +1 -1
  117. package/packages/contracts/package.json +1 -1
  118. package/packages/daemon/package.json +4 -4
  119. package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
  120. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  121. package/packages/gsd-agent-core/dist/agent-session.js +3 -0
  122. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  123. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
  124. package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
  125. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
  126. package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
  127. package/packages/gsd-agent-core/dist/index.d.ts +2 -0
  128. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  129. package/packages/gsd-agent-core/dist/index.js +2 -0
  130. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  131. package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
  132. package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
  133. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
  134. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  135. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  136. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
  137. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  138. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
  139. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  140. package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
  141. package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
  142. package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
  143. package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
  144. package/packages/gsd-agent-core/package.json +5 -5
  145. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  146. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  147. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -11
  148. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  149. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
  150. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
  151. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
  152. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
  153. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
  154. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  155. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -829
  156. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  157. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
  158. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
  159. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
  160. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
  161. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
  162. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
  163. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
  164. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
  165. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
  166. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
  167. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
  168. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
  169. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
  170. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
  171. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
  172. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
  173. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
  174. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  175. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
  176. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  177. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
  178. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
  179. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
  180. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
  181. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
  186. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
  187. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
  188. package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
  189. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
  190. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
  191. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
  192. package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
  193. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  194. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
  195. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  196. package/packages/gsd-agent-modes/package.json +7 -7
  197. package/packages/mcp-server/README.md +1 -1
  198. package/packages/mcp-server/dist/server.d.ts +1 -1
  199. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  200. package/packages/mcp-server/dist/server.js +3 -3
  201. package/packages/mcp-server/dist/server.js.map +1 -1
  202. package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
  203. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  204. package/packages/mcp-server/dist/workflow-tools.js +34 -20
  205. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  206. package/packages/mcp-server/package.json +4 -4
  207. package/packages/native/package.json +1 -1
  208. package/packages/pi-agent-core/package.json +1 -1
  209. package/packages/pi-ai/package.json +1 -1
  210. package/packages/pi-coding-agent/README.md +3 -2
  211. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
  212. package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
  213. package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
  214. package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
  215. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
  216. package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
  217. package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
  218. package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
  219. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
  220. package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
  221. package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
  222. package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
  223. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
  224. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
  225. package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
  226. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
  227. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
  228. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  229. package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
  230. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  231. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
  232. package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
  233. package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
  234. package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  236. package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
  237. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  238. package/packages/pi-coding-agent/package.json +7 -7
  239. package/packages/pi-tui/package.json +2 -2
  240. package/packages/rpc-client/package.json +2 -2
  241. package/pkg/dist/theme/theme-schema.d.ts +75 -75
  242. package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
  243. package/pkg/dist/theme/theme-schema.js +1 -1
  244. package/pkg/dist/theme/theme-schema.js.map +1 -1
  245. package/pkg/dist/theme/theme.d.ts.map +1 -1
  246. package/pkg/dist/theme/theme.js +11 -7
  247. package/pkg/dist/theme/theme.js.map +1 -1
  248. package/pkg/package.json +1 -1
  249. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
  250. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
  251. package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
  252. package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
  253. package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
  254. package/src/resources/extensions/gsd/auto/session.ts +5 -0
  255. package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
  256. package/src/resources/extensions/gsd/auto-dispatch.ts +21 -23
  257. package/src/resources/extensions/gsd/auto-prompts.ts +38 -12
  258. package/src/resources/extensions/gsd/auto-recovery.ts +10 -508
  259. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
  260. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
  261. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
  262. package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +43 -0
  263. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +6 -1
  264. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
  265. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -19
  266. package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
  267. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +74 -10
  268. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
  269. package/src/resources/extensions/gsd/commands-context.ts +18 -1
  270. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +14 -9
  271. package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
  272. package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
  273. package/src/resources/extensions/gsd/db/queries.ts +79 -0
  274. package/src/resources/extensions/gsd/db-workspace.ts +61 -3
  275. package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
  276. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  277. package/src/resources/extensions/gsd/forensics.ts +2 -33
  278. package/src/resources/extensions/gsd/git-service.ts +5 -5
  279. package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
  280. package/src/resources/extensions/gsd/health-widget.ts +69 -32
  281. package/src/resources/extensions/gsd/layout-policy.ts +2 -1
  282. package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
  283. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
  284. package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
  285. package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
  286. package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
  287. package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
  288. package/src/resources/extensions/gsd/quick.ts +43 -2
  289. package/src/resources/extensions/gsd/session-forensics.ts +11 -1
  290. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
  291. package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
  292. package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
  293. package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
  294. package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
  295. package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
  296. package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +81 -7
  297. package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
  298. package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
  299. package/src/resources/extensions/gsd/state.ts +32 -732
  300. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
  301. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -1
  302. package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
  303. package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
  304. package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
  305. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
  306. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
  307. package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
  308. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
  309. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
  310. package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
  311. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
  312. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
  313. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
  314. package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
  315. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
  316. package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
  317. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +119 -1
  318. package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
  319. package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
  320. package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
  321. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
  322. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
  323. package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
  324. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
  325. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +2 -1
  326. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
  327. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
  328. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
  329. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
  330. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
  331. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
  332. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +7 -0
  333. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
  334. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
  335. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +151 -0
  336. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +26 -0
  337. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
  338. package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
  339. package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
  340. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
  341. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
  342. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
  343. package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
  344. package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
  345. package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
  346. package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
  347. package/src/resources/extensions/gsd/unit-registry.ts +32 -4
  348. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
  349. package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
  350. package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
  351. package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
  352. package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
  353. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
  354. package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
  355. package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
  356. /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → O7xDYXO0r4zFhIzY1hrWV}/_buildManifest.js +0 -0
  357. /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → O7xDYXO0r4zFhIzY1hrWV}/_ssgManifest.js +0 -0
@@ -48,6 +48,8 @@ export interface ExecSandboxOptions {
48
48
  now?: () => Date;
49
49
  /** Optional override for id generation (tests). */
50
50
  generateId?: () => string;
51
+ /** Optional request cancellation signal. Aborting kills the child process tree. */
52
+ signal?: AbortSignal;
51
53
  /**
52
54
  * Grace period (ms) between SIGTERM and SIGKILL on timeout.
53
55
  * Defaults to SIGKILL_GRACE_MS. Exposed as a test seam.
@@ -67,6 +69,8 @@ export interface ExecSandboxResult {
67
69
  exit_code: number | null;
68
70
  signal: NodeJS.Signals | null;
69
71
  timed_out: boolean;
72
+ /** True when an external AbortSignal terminated the child process tree. */
73
+ aborted?: boolean;
70
74
  /**
71
75
  * True when the result came from the hard-deadline force-resolve (a non-closing
72
76
  * D-state child that never emitted 'close') rather than an observed process exit.
@@ -260,11 +264,23 @@ export function runExecSandbox(
260
264
  const effectiveForceResolveDelay = opts.force_resolve_delay_ms ?? (effectiveGraceMs + HARD_DEADLINE_MS);
261
265
 
262
266
  let timedOut = false;
267
+ let aborted = false;
263
268
  let settled = false;
269
+ let killInitiated = false;
270
+ let timer: NodeJS.Timeout | undefined;
264
271
  let forceResolveTimer: NodeJS.Timeout | undefined;
272
+ let abortListener: (() => void) | undefined;
265
273
 
266
- const timer = setTimeout(() => {
267
- timedOut = true;
274
+ const removeAbortListener = () => {
275
+ if (opts.signal && abortListener) {
276
+ opts.signal.removeEventListener("abort", abortListener);
277
+ abortListener = undefined;
278
+ }
279
+ };
280
+
281
+ const initiateKill = () => {
282
+ if (killInitiated) return;
283
+ killInitiated = true;
268
284
  // killProcessTree handles both platforms and kills the whole tree: on Unix
269
285
  // it signals the process group (SIGTERM -> grace -> SIGKILL); on Windows it
270
286
  // force-kills the tree via taskkill /F /T. Using child.kill("SIGTERM") here
@@ -281,14 +297,14 @@ export function runExecSandbox(
281
297
  finalize(null, "SIGKILL", true);
282
298
  }, effectiveForceResolveDelay);
283
299
  forceResolveTimer.unref?.();
284
- }, timeoutMs);
285
- timer.unref?.();
300
+ };
286
301
 
287
302
  const finalize = (exitCode: number | null, signal: NodeJS.Signals | null, forceResolved = false) => {
288
303
  if (settled) return;
289
304
  settled = true;
290
305
  clearTimeout(timer);
291
306
  clearTimeout(forceResolveTimer);
307
+ removeAbortListener();
292
308
  const duration = Date.now() - started;
293
309
  const stdoutBuf = Buffer.concat(stdoutChunks);
294
310
  const stderrBuf = Buffer.concat(stderrChunks);
@@ -301,11 +317,13 @@ export function runExecSandbox(
301
317
  const digest =
302
318
  digestBody.length > 0
303
319
  ? digestBody
304
- : timedOut
305
- ? "[no stdout — timed out]"
306
- : stderrBuf.length > 0
307
- ? `[no stdout — tail of stderr]\n${tail(stderrBuf, opts.digest_chars)}`
308
- : "[no output]";
320
+ : aborted
321
+ ? "[no stdout — aborted]"
322
+ : timedOut
323
+ ? "[no stdout — timed out]"
324
+ : stderrBuf.length > 0
325
+ ? `[no stdout — tail of stderr]\n${tail(stderrBuf, opts.digest_chars)}`
326
+ : "[no output]";
309
327
 
310
328
  const result: ExecSandboxResult = {
311
329
  id,
@@ -313,6 +331,7 @@ export function runExecSandbox(
313
331
  exit_code: exitCode,
314
332
  signal,
315
333
  timed_out: timedOut,
334
+ aborted,
316
335
  force_resolved: forceResolved,
317
336
  duration_ms: duration,
318
337
  stdout_bytes: stdoutBytes,
@@ -328,6 +347,26 @@ export function runExecSandbox(
328
347
  resolveP(result);
329
348
  };
330
349
 
350
+ timer = setTimeout(() => {
351
+ timedOut = true;
352
+ initiateKill();
353
+ }, timeoutMs);
354
+ timer.unref?.();
355
+
356
+ if (opts.signal) {
357
+ abortListener = () => {
358
+ if (settled || timedOut) return;
359
+ aborted = true;
360
+ clearTimeout(timer);
361
+ initiateKill();
362
+ };
363
+ if (opts.signal.aborted) {
364
+ abortListener();
365
+ } else {
366
+ opts.signal.addEventListener("abort", abortListener, { once: true });
367
+ }
368
+ }
369
+
331
370
  child.on("error", (err) => {
332
371
  const message = err instanceof Error ? err.message : String(err);
333
372
  const line = `child error: ${message}\n`;
@@ -364,6 +403,7 @@ function writeMeta(
364
403
  exit_code: result.exit_code,
365
404
  signal: result.signal,
366
405
  timed_out: result.timed_out,
406
+ aborted: result.aborted === true,
367
407
  force_resolved: result.force_resolved,
368
408
  duration_ms: result.duration_ms,
369
409
  stdout_bytes: result.stdout_bytes,
@@ -28,8 +28,7 @@ import { deriveState } from "./state.js";
28
28
  import { isAutoActive } from "./auto.js";
29
29
  import { loadPrompt } from "./prompt-loader.js";
30
30
  import { gsdRoot } from "./paths.js";
31
- import { isDbAvailable, getAllMilestones, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
32
- import { isClosedStatus } from "./status-guards.js";
31
+ import { isDbAvailable, getHierarchyCompletionCounts } from "./gsd-db.js";
33
32
  import { formatDuration } from "../shared/format-utils.js";
34
33
  import { getAutoWorktreePath } from "./auto-worktree.js";
35
34
  import { clearGSDPreferencesCache, loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
@@ -759,37 +758,7 @@ function loadCompletedKeys(basePath: string): string[] {
759
758
  function getDbCompletionCounts(): DbCompletionCounts | null {
760
759
  if (!isDbAvailable()) return null;
761
760
 
762
- const milestones = getAllMilestones();
763
- let completedMilestones = 0;
764
- let totalSlices = 0;
765
- let completedSlices = 0;
766
- let totalTasks = 0;
767
- let completedTasks = 0;
768
-
769
- for (const m of milestones) {
770
- if (isClosedStatus(m.status)) completedMilestones++;
771
-
772
- const slices = getMilestoneSlices(m.id);
773
- for (const s of slices) {
774
- totalSlices++;
775
- if (isClosedStatus(s.status)) completedSlices++;
776
-
777
- const tasks = getSliceTasks(m.id, s.id);
778
- for (const t of tasks) {
779
- totalTasks++;
780
- if (isClosedStatus(t.status)) completedTasks++;
781
- }
782
- }
783
- }
784
-
785
- return {
786
- milestones: completedMilestones,
787
- milestonesTotal: milestones.length,
788
- slices: completedSlices,
789
- slicesTotal: totalSlices,
790
- tasks: completedTasks,
791
- tasksTotal: totalTasks,
792
- };
761
+ return getHierarchyCompletionCounts();
793
762
  }
794
763
 
795
764
  // ─── Anomaly Detectors ───────────────────────────────────────────────────────
@@ -378,6 +378,8 @@ export const RUNTIME_EXCLUSION_PATHS: readonly string[] = [
378
378
  ".gsd/DISCUSSION-MANIFEST.json",
379
379
  ];
380
380
 
381
+ const runtimeFilesCleanedUpRepos = new Set<string>();
382
+
381
383
  // ─── Integration Branch Metadata ───────────────────────────────────────────
382
384
 
383
385
  /**
@@ -755,7 +757,8 @@ export class GitServiceImpl {
755
757
  // and the worktree is torn down. This prevents a mid-execution behavioral
756
758
  // discontinuity where the first half of a milestone has .gsd/ artifacts
757
759
  // committed but the second half doesn't (#1326).
758
- if (!this._runtimeFilesCleanedUp) {
760
+ const cleanupRepoKey = resolve(this.basePath);
761
+ if (!runtimeFilesCleanedUpRepos.has(cleanupRepoKey)) {
759
762
  let cleaned = false;
760
763
  for (const exclusion of RUNTIME_EXCLUSION_PATHS) {
761
764
  const removed = nativeRmCached(this.basePath, [exclusion]);
@@ -764,7 +767,7 @@ export class GitServiceImpl {
764
767
  if (cleaned) {
765
768
  nativeCommit(this.basePath, "chore: untrack .gsd/ runtime files from git index", { allowEmpty: false });
766
769
  }
767
- this._runtimeFilesCleanedUp = true;
770
+ runtimeFilesCleanedUpRepos.add(cleanupRepoKey);
768
771
  }
769
772
 
770
773
  // Stage everything using pathspec exclusions so excluded paths are never
@@ -893,9 +896,6 @@ export class GitServiceImpl {
893
896
  }
894
897
  }
895
898
 
896
- /** Tracks whether runtime file cleanup has run this session. */
897
- private _runtimeFilesCleanedUp = false;
898
-
899
899
  /**
900
900
  * Stage files (smart staging) and commit.
901
901
  * Returns the commit message string on success, or null if nothing to commit.
@@ -20,6 +20,7 @@ import { invalidateAllCaches } from "./cache.js";
20
20
  import {
21
21
  gsdRoot, resolveMilestoneFile, resolveSliceFile,
22
22
  resolveGsdRootFile, relGsdRootFile, relSliceFile,
23
+ relMilestoneFile,
23
24
  } from "./paths.js";
24
25
  import { readFileSync, writeFileSync, existsSync } from "node:fs";
25
26
  import { atomicWriteSync } from "./atomic-write.js";
@@ -29,6 +30,10 @@ import { loadQueueOrder, sortByQueueOrder, saveQueueOrder } from "./queue-order.
29
30
  import { findMilestoneIds, nextMilestoneId } from "./milestone-ids.js";
30
31
  import { isFutureMilestoneStatus } from "./status-guards.js";
31
32
 
33
+ const QUEUE_ARTIFACT_EXCERPT_MAX_CHARS = 20_000;
34
+ const QUEUE_EXISTING_MILESTONES_CONTEXT_MAX_CHARS = 120_000;
35
+ const QUEUE_CONTEXT_SECTION_SEPARATOR = "\n\n---\n\n";
36
+
32
37
  // ─── Queue Entry Point ──────────────────────────────────────────────────────
33
38
 
34
39
  /**
@@ -280,7 +285,9 @@ export async function buildExistingMilestonesContext(
280
285
  if (contextFile) {
281
286
  const content = await loadFile(contextFile);
282
287
  if (content) {
283
- parts.push(`\n**Context:**\n${content.trim()}`);
288
+ parts.push(
289
+ `\n**Context:**\n${summarizeArtifactForQueue(content, relMilestoneFile(basePath, mid, "CONTEXT"))}`,
290
+ );
284
291
  }
285
292
  } else {
286
293
  // No full CONTEXT.md — check for CONTEXT-DRAFT.md (draft seed from prior discussion)
@@ -288,7 +295,9 @@ export async function buildExistingMilestonesContext(
288
295
  if (draftFile) {
289
296
  const draftContent = await loadFile(draftFile);
290
297
  if (draftContent) {
291
- parts.push(`\n**Draft context available:**\n${draftContent.trim()}`);
298
+ parts.push(
299
+ `\n**Draft context available:**\n${summarizeArtifactForQueue(draftContent, relMilestoneFile(basePath, mid, "CONTEXT-DRAFT"))}`,
300
+ );
292
301
  }
293
302
  }
294
303
  }
@@ -300,7 +309,9 @@ export async function buildExistingMilestonesContext(
300
309
  if (roadmapFile) {
301
310
  const content = await loadFile(roadmapFile);
302
311
  if (content) {
303
- parts.push(`\n**Roadmap:**\n${content.trim()}`);
312
+ parts.push(
313
+ `\n**Roadmap:**\n${summarizeArtifactForQueue(content, relMilestoneFile(basePath, mid, "ROADMAP"))}`,
314
+ );
304
315
  }
305
316
  }
306
317
  }
@@ -317,7 +328,81 @@ export async function buildExistingMilestonesContext(
317
328
  }
318
329
  }
319
330
 
320
- return sections.join("\n\n---\n\n");
331
+ return capExistingMilestonesContext(sections);
332
+ }
333
+
334
+ function summarizeArtifactForQueue(
335
+ content: string,
336
+ sourcePath: string,
337
+ cap = QUEUE_ARTIFACT_EXCERPT_MAX_CHARS,
338
+ ): string {
339
+ const trimmed = content.trim();
340
+ if (trimmed.length <= cap) {
341
+ return `Source: \`${sourcePath}\`\n\n${trimmed}`;
342
+ }
343
+
344
+ const excerpt = trimmed.slice(0, cap).trimEnd();
345
+ const omittedChars = trimmed.length - excerpt.length;
346
+ return [
347
+ `Source: \`${sourcePath}\``,
348
+ "",
349
+ excerpt,
350
+ "",
351
+ `[Truncated ${omittedChars} chars. Read \`${sourcePath}\` for full content.]`,
352
+ ].join("\n");
353
+ }
354
+
355
+ function capExistingMilestonesContext(
356
+ sections: string[],
357
+ cap = QUEUE_EXISTING_MILESTONES_CONTEXT_MAX_CHARS,
358
+ ): string {
359
+ const fullContext = sections.join(QUEUE_CONTEXT_SECTION_SEPARATOR);
360
+ if (fullContext.length <= cap) return fullContext;
361
+
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 noticeSuffix = `${QUEUE_CONTEXT_SECTION_SEPARATOR}${notice}`;
364
+
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
+ }
374
+
375
+ if (selected.length === sections.length) {
376
+ return selected.join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
377
+ }
378
+
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;
386
+
387
+ return `${compactContext.slice(0, Math.max(0, cap - notice.length - 2)).trimEnd()}\n\n${notice}`;
388
+ }
389
+
390
+ function compactSectionForQueueBudget(section: string): string {
391
+ const lines = section.split("\n");
392
+ const compact: string[] = [];
393
+
394
+ if (lines[0]) compact.push(lines[0]);
395
+
396
+ const statusLine = lines.find(line => line.startsWith("**Status:**"));
397
+ if (statusLine) compact.push(statusLine);
398
+
399
+ const sourceLines = lines.filter(line => line.startsWith("Source: `"));
400
+ if (sourceLines.length > 0) {
401
+ compact.push("", "**Sources:**", ...sourceLines);
402
+ compact.push("", "[Artifact excerpts omitted due to total queue/rethink context budget.]");
403
+ }
404
+
405
+ return compact.join("\n");
321
406
  }
322
407
 
323
408
  // ─── Internal Helpers ───────────────────────────────────────────────────────
@@ -2,11 +2,12 @@
2
2
  // File Purpose: Always-on ambient health signal rendered below the editor.
3
3
 
4
4
  import type { ExtensionContext } from "@gsd/pi-coding-agent";
5
+ import { execFile } from "node:child_process";
5
6
  import type { GSDState } from "./types.js";
6
- import { runProviderChecks, summariseProviderIssues } from "./doctor-providers.js";
7
+ import { runProviderChecks, runProviderChecksAsync, summariseProviderIssues } from "./doctor-providers.js";
7
8
  import { runEnvironmentChecks, runEnvironmentChecksAsync } from "./doctor-environment.js";
8
9
  import { loadEffectiveGSDPreferences } from "./preferences.js";
9
- import { nativeIsRepo, nativeLastCommitEpoch, nativeGetCurrentBranch, nativeCommitSubject } from "./native-git-bridge.js";
10
+ import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
10
11
  import { loadLedgerFromDisk, getProjectTotals } from "./metrics.js";
11
12
  import { describeNextUnit, estimateTimeRemaining, updateSliceProgressCache } from "./auto-dashboard.js";
12
13
  import { projectRoot } from "./commands/context.js";
@@ -15,32 +16,75 @@ import {
15
16
  buildHealthLines,
16
17
  detectHealthWidgetProjectState,
17
18
  type HealthWidgetData,
19
+ type HealthWidgetProjectState,
18
20
  } from "./health-widget-core.js";
19
21
 
20
22
  export const HEALTH_WIDGET_ACTIVE_HINTS =
21
23
  " /gsd auto to run · /gsd status to inspect · /gsd report for snapshots · /gsd notifications for history · /gsd help";
22
24
 
25
+ const LAST_COMMIT_LOOKUP_TIMEOUT_MS = 3_000;
26
+ const REFRESH_INTERVAL_MS = 60_000;
27
+ const PROJECT_STATE_CACHE_TTL_MS = REFRESH_INTERVAL_MS;
28
+
23
29
  // ── Data loader ────────────────────────────────────────────────────────────────
24
30
 
25
- // Last-commit lookup is subprocess-backed (native-git-bridge git spawns),
26
- // so it is treated like the other expensive checks: skipped on first paint,
27
- // run only by the background refresh.
28
- function loadLastCommitInfo(basePath: string): { epoch: number | null; message: string | null } {
31
+ const projectStateCache = new Map<string, { state: HealthWidgetProjectState; computedAt: number }>();
32
+
33
+ export function getCachedProjectState(basePath: string, force?: boolean): HealthWidgetProjectState {
34
+ const now = Date.now();
35
+ const cached = projectStateCache.get(basePath);
36
+ if (!force && cached && now - cached.computedAt <= PROJECT_STATE_CACHE_TTL_MS) {
37
+ return cached.state;
38
+ }
39
+
40
+ const state = detectHealthWidgetProjectState(basePath);
41
+ projectStateCache.set(basePath, { state, computedAt: now });
42
+ return state;
43
+ }
44
+
45
+ function runHealthWidgetGit(basePath: string, args: string[]): Promise<string | null> {
46
+ return new Promise((resolve) => {
47
+ const child = execFile(
48
+ "git",
49
+ args,
50
+ {
51
+ cwd: basePath,
52
+ timeout: LAST_COMMIT_LOOKUP_TIMEOUT_MS,
53
+ encoding: "utf-8",
54
+ env: GIT_NO_PROMPT_ENV,
55
+ },
56
+ (err, stdout) => resolve(err ? null : String(stdout).trimEnd()),
57
+ );
58
+ child.on("error", () => resolve(null));
59
+ });
60
+ }
61
+
62
+ async function loadLastCommitInfoAsync(basePath: string): Promise<{ epoch: number | null; message: string | null }> {
29
63
  try {
30
- if (nativeIsRepo(basePath)) {
31
- const branch = nativeGetCurrentBranch(basePath);
32
- const epoch = nativeLastCommitEpoch(basePath, branch || "HEAD");
33
- if (epoch > 0) {
34
- return { epoch, message: nativeCommitSubject(basePath, branch || "HEAD") || null };
35
- }
64
+ if ((await runHealthWidgetGit(basePath, ["rev-parse", "--git-dir"])) === null) {
65
+ return { epoch: null, message: null };
36
66
  }
37
- } catch { /* non-fatal */ }
38
- return { epoch: null, message: null };
67
+
68
+ const branch = await runHealthWidgetGit(basePath, ["branch", "--show-current"]);
69
+ const ref = branch || "HEAD";
70
+ const raw = await runHealthWidgetGit(basePath, ["log", "-1", "--format=%ct%x00%s", ref]);
71
+ if (!raw) return { epoch: null, message: null };
72
+
73
+ const separator = raw.indexOf("\0");
74
+ const epochText = separator >= 0 ? raw.slice(0, separator) : raw;
75
+ const epoch = parseInt(epochText.trim(), 10) || 0;
76
+ if (epoch <= 0) return { epoch: null, message: null };
77
+
78
+ const message = separator >= 0 ? raw.slice(separator + 1).trim() : "";
79
+ return { epoch, message: message || null };
80
+ } catch {
81
+ return { epoch: null, message: null };
82
+ }
39
83
  }
40
84
 
41
85
  function loadHealthWidgetData(
42
86
  basePath: string,
43
- options?: { includeChecks?: boolean },
87
+ options?: { includeChecks?: boolean; forceProjectState?: boolean },
44
88
  ): HealthWidgetData {
45
89
  // `includeChecks` gates the expensive subprocess-backed checks (provider +
46
90
  // environment doctor: `lsof`, `docker`, `node --version`, ...). The initial
@@ -55,7 +99,7 @@ function loadHealthWidgetData(
55
99
  let lastCommitEpoch: number | null = null;
56
100
  let lastCommitMessage: string | null = null;
57
101
 
58
- const projectState = detectHealthWidgetProjectState(basePath);
102
+ const projectState = getCachedProjectState(basePath, options?.forceProjectState);
59
103
 
60
104
  try {
61
105
  const prefs = loadEffectiveGSDPreferences();
@@ -83,13 +127,6 @@ function loadHealthWidgetData(
83
127
  } catch { /* non-fatal */ }
84
128
  }
85
129
 
86
- // ── Last commit info ── (git spawns — gated like the other expensive checks)
87
- if (includeChecks) {
88
- const commit = loadLastCommitInfo(basePath);
89
- lastCommitEpoch = commit.epoch;
90
- lastCommitMessage = commit.message;
91
- }
92
-
93
130
  return {
94
131
  projectState,
95
132
  budgetCeiling,
@@ -104,10 +141,8 @@ function loadHealthWidgetData(
104
141
  }
105
142
 
106
143
  // Non-blocking variant used by the widget's background refresh: the cheap fields
107
- // come from the synchronous snapshot, then provider + environment checks are
108
- // layered in off the event-loop critical path (env checks run concurrently via
109
- // runEnvironmentChecksAsync). Keeps the always-on widget from stalling the UI on
110
- // its initial enrichment or its 60s refresh.
144
+ // come from the synchronous snapshot, then provider, environment, and last-commit
145
+ // checks are layered in off the event-loop critical path.
111
146
  async function loadHealthWidgetDataAsync(basePath: string): Promise<HealthWidgetData> {
112
147
  const data = loadHealthWidgetData(basePath, { includeChecks: false });
113
148
  let providerIssue = data.providerIssue;
@@ -115,7 +150,7 @@ async function loadHealthWidgetDataAsync(basePath: string): Promise<HealthWidget
115
150
  let environmentWarningCount = 0;
116
151
 
117
152
  try {
118
- providerIssue = summariseProviderIssues(runProviderChecks());
153
+ providerIssue = summariseProviderIssues(await runProviderChecksAsync());
119
154
  } catch { /* non-fatal */ }
120
155
 
121
156
  try {
@@ -126,7 +161,7 @@ async function loadHealthWidgetDataAsync(basePath: string): Promise<HealthWidget
126
161
  }
127
162
  } catch { /* non-fatal */ }
128
163
 
129
- const commit = loadLastCommitInfo(basePath);
164
+ const commit = await loadLastCommitInfoAsync(basePath);
130
165
 
131
166
  return {
132
167
  ...data,
@@ -141,8 +176,6 @@ async function loadHealthWidgetDataAsync(basePath: string): Promise<HealthWidget
141
176
 
142
177
  // ── Widget init ────────────────────────────────────────────────────────────────
143
178
 
144
- const REFRESH_INTERVAL_MS = 60_000;
145
-
146
179
  /**
147
180
  * Initialize the always-on gsd-health widget (belowEditor).
148
181
  * Call once from the extension entry point after context is available.
@@ -152,13 +185,17 @@ export function initHealthWidget(ctx: ExtensionContext): void {
152
185
 
153
186
  const basePath = projectRoot();
154
187
 
188
+ // Re-init must reflect filesystem changes immediately; the TTL cache is for
189
+ // interval refreshes, not this one-off synchronous paint.
190
+ projectStateCache.delete(basePath);
191
+
155
192
  // String-array fallback — used in RPC mode (factory is a no-op there).
156
193
  // Skip the expensive provider/environment doctor checks here: this runs
157
194
  // synchronously on the interactive-startup path, where running them would
158
195
  // block first paint by ~0.9s (lsof/docker probes, otherwise run again
159
196
  // immediately by the factory below). The factory's async refresh fills in
160
197
  // real health once the screen is up.
161
- const initialData = loadHealthWidgetData(basePath, { includeChecks: false });
198
+ const initialData = loadHealthWidgetData(basePath, { includeChecks: false, forceProjectState: true });
162
199
  ctx.ui.setWidget("gsd-health", buildHealthLines(initialData), { placement: "belowEditor" });
163
200
 
164
201
  // Factory-based widget for TUI mode — replaces the string-array above
@@ -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
 
@@ -25,6 +25,7 @@ import {
25
25
  insertArtifact,
26
26
  deleteArtifactByPath,
27
27
  getGateResults,
28
+ isDbAvailable,
28
29
  } from "./gsd-db.js";
29
30
  import type { MilestoneRow, ArtifactRow } from "./db-milestone-artifact-rows.js";
30
31
  import type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
@@ -631,16 +632,8 @@ export async function renderRoadmapCheckboxes(
631
632
  basePath: string,
632
633
  milestoneId: string,
633
634
  ): Promise<boolean> {
634
- const slices = getMilestoneSlices(milestoneId);
635
- if (slices.length === 0) {
636
- process.stderr.write(
637
- `markdown-renderer: no slices found for milestone ${milestoneId}\n`,
638
- );
639
- return false;
640
- }
641
-
642
- await renderRoadmapFromDb(basePath, milestoneId);
643
- return true;
635
+ const rendered = await renderRoadmapFromDb(basePath, milestoneId);
636
+ return !("skipped" in rendered);
644
637
  }
645
638
 
646
639
  /**
@@ -737,7 +730,8 @@ function isAutoRecoveryPlaceholderPlan(content: string): boolean {
737
730
  * projection (the 4S/0T-vs-5S/13T drift class). The artifacts table is an
738
731
  * output sink, never a render input.
739
732
  *
740
- * @returns true if the plan was written, false on skip/error
733
+ * @returns true if the plan was written, false when the DB slice has no tasks
734
+ * @throws when the DB connection is unavailable or the render write fails
741
735
  */
742
736
  export async function renderPlanCheckboxes(
743
737
  basePath: string,
@@ -747,6 +741,9 @@ export async function renderPlanCheckboxes(
747
741
  ): Promise<boolean> {
748
742
  const tasks = getSliceTasks(milestoneId, sliceId);
749
743
  if (tasks.length === 0) {
744
+ if (!isDbAvailable()) {
745
+ throw new Error(`database unavailable while rendering plan checkboxes for ${milestoneId}/${sliceId}`);
746
+ }
750
747
  process.stderr.write(
751
748
  `markdown-renderer: no tasks found for ${milestoneId}/${sliceId}\n`,
752
749
  );