gsd-pi 2.44.0-dev.d25d507 → 2.45.0-dev.1afbdaa

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 (407) hide show
  1. package/dist/help-text.js +1 -1
  2. package/dist/loader.js +34 -0
  3. package/dist/resources/extensions/gsd/activity-log.js +7 -0
  4. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  5. package/dist/resources/extensions/gsd/auto/phases.js +63 -77
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  7. package/dist/resources/extensions/gsd/auto/session.js +0 -11
  8. package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
  9. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
  10. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  11. package/dist/resources/extensions/gsd/auto-start.js +23 -5
  12. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  13. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  14. package/dist/resources/extensions/gsd/auto-worktree.js +14 -10
  15. package/dist/resources/extensions/gsd/auto.js +42 -60
  16. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +170 -11
  17. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
  18. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  19. package/dist/resources/extensions/gsd/commands/context.js +0 -4
  20. package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
  21. package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
  22. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
  23. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  24. package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
  25. package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
  26. package/dist/resources/extensions/gsd/db-writer.js +40 -22
  27. package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
  28. package/dist/resources/extensions/gsd/doctor.js +13 -3
  29. package/dist/resources/extensions/gsd/git-service.js +8 -3
  30. package/dist/resources/extensions/gsd/gsd-db.js +28 -4
  31. package/dist/resources/extensions/gsd/guided-flow.js +1 -2
  32. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  33. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  34. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
  35. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  36. package/dist/resources/extensions/gsd/preferences.js +8 -4
  37. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  38. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  39. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  40. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
  41. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  42. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  43. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  47. package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
  48. package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
  49. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  50. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  51. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  52. package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
  53. package/dist/resources/extensions/gsd/prompts/rethink.md +83 -0
  54. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  56. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  57. package/dist/resources/extensions/gsd/repo-identity.js +45 -7
  58. package/dist/resources/extensions/gsd/rethink.js +115 -0
  59. package/dist/resources/extensions/gsd/session-lock.js +1 -3
  60. package/dist/resources/extensions/gsd/state.js +48 -3
  61. package/dist/resources/extensions/gsd/sync-lock.js +89 -0
  62. package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
  63. package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
  64. package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
  65. package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
  66. package/dist/resources/extensions/gsd/tools/plan-slice.js +31 -1
  67. package/dist/resources/extensions/gsd/tools/plan-task.js +28 -1
  68. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
  69. package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
  70. package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
  71. package/dist/resources/extensions/gsd/tools/replan-slice.js +34 -2
  72. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  73. package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
  74. package/dist/resources/extensions/gsd/workflow-events.js +102 -0
  75. package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
  76. package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
  77. package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
  78. package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
  79. package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
  80. package/dist/resources/extensions/gsd/worktree-manager.js +34 -3
  81. package/dist/resources/extensions/gsd/worktree-resolver.js +43 -0
  82. package/dist/resources/extensions/gsd/write-intercept.js +84 -0
  83. package/dist/resources/extensions/mcp-client/index.js +14 -0
  84. package/dist/resources/extensions/voice/index.js +11 -16
  85. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  86. package/dist/web/standalone/.next/BUILD_ID +1 -1
  87. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  88. package/dist/web/standalone/.next/build-manifest.json +3 -3
  89. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  90. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  91. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  93. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found/page.js +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  105. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  107. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  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_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/index.html +1 -1
  151. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  152. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  153. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  154. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  156. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  157. package/dist/web/standalone/.next/server/app/page.js +1 -1
  158. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  160. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  163. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  164. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  165. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
  166. package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
  167. package/dist/web/standalone/.next/static/chunks/app/{page-b9367c5ae13b99c6.js → page-6654a8cca61a3d1c.js} +1 -1
  168. package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
  169. package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
  170. package/package.json +2 -1
  171. package/packages/native/dist/stream-process/index.js +2 -2
  172. package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
  173. package/packages/native/src/stream-process/index.ts +2 -2
  174. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  175. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  177. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  178. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  180. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  182. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  185. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  187. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  189. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  191. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  192. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  193. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  194. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  195. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  196. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  197. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +13 -1
  199. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  201. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  203. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  205. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  207. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/main.js +17 -0
  210. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  212. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  214. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  215. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  216. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  218. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  219. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  220. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  221. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  222. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  224. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  225. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  226. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  227. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  229. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  231. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  233. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  235. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  236. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  237. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  238. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  239. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  240. package/packages/pi-coding-agent/package.json +1 -1
  241. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  242. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  243. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  244. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  245. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  246. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  247. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  248. package/packages/pi-coding-agent/src/core/model-registry.ts +51 -4
  249. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  250. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  251. package/packages/pi-coding-agent/src/main.ts +19 -0
  252. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  253. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  254. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  255. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  256. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  257. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  258. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  259. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  260. package/pkg/package.json +1 -1
  261. package/src/resources/extensions/gsd/activity-log.ts +1 -0
  262. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  263. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
  264. package/src/resources/extensions/gsd/auto/phases.ts +69 -91
  265. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  266. package/src/resources/extensions/gsd/auto/session.ts +0 -18
  267. package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
  268. package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
  269. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
  270. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  271. package/src/resources/extensions/gsd/auto-start.ts +26 -5
  272. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  273. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  274. package/src/resources/extensions/gsd/auto-worktree.ts +17 -11
  275. package/src/resources/extensions/gsd/auto.ts +44 -86
  276. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +162 -11
  277. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  278. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  279. package/src/resources/extensions/gsd/commands/context.ts +0 -5
  280. package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
  281. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  282. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
  283. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  284. package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
  285. package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
  286. package/src/resources/extensions/gsd/db-writer.ts +41 -27
  287. package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
  288. package/src/resources/extensions/gsd/doctor-types.ts +7 -1
  289. package/src/resources/extensions/gsd/doctor.ts +13 -4
  290. package/src/resources/extensions/gsd/git-service.ts +6 -2
  291. package/src/resources/extensions/gsd/gsd-db.ts +32 -4
  292. package/src/resources/extensions/gsd/guided-flow.ts +1 -2
  293. package/src/resources/extensions/gsd/journal.ts +6 -1
  294. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  295. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  296. package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
  297. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  298. package/src/resources/extensions/gsd/preferences.ts +7 -3
  299. package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
  300. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  301. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  302. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
  303. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  304. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  305. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  306. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  307. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  308. package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -3
  309. package/src/resources/extensions/gsd/prompts/queue.md +2 -2
  310. package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
  311. package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  312. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  313. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  314. package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
  315. package/src/resources/extensions/gsd/prompts/rethink.md +83 -0
  316. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  317. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  318. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  319. package/src/resources/extensions/gsd/repo-identity.ts +46 -7
  320. package/src/resources/extensions/gsd/rethink.ts +154 -0
  321. package/src/resources/extensions/gsd/session-lock.ts +0 -4
  322. package/src/resources/extensions/gsd/state.ts +49 -1
  323. package/src/resources/extensions/gsd/sync-lock.ts +94 -0
  324. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +5 -13
  325. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
  326. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  327. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
  328. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +264 -228
  329. package/src/resources/extensions/gsd/tests/complete-task.test.ts +317 -250
  330. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  331. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +2 -8
  332. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
  333. package/src/resources/extensions/gsd/tests/db-writer.test.ts +79 -0
  334. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
  335. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +60 -0
  336. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  337. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  338. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +1 -1
  339. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  340. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
  341. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +15 -24
  342. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  343. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  344. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  345. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  346. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  347. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
  348. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
  349. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
  350. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -7
  351. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
  352. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
  353. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -2
  354. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
  355. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
  356. package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
  357. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
  358. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -21
  359. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
  360. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
  361. package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
  362. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +1 -4
  363. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  364. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
  365. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
  366. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
  367. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  368. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
  369. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
  370. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
  371. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  372. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
  373. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
  374. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  375. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
  376. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
  377. package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
  378. package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
  379. package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
  380. package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
  381. package/src/resources/extensions/gsd/tools/plan-slice.ts +40 -0
  382. package/src/resources/extensions/gsd/tools/plan-task.ts +37 -1
  383. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
  384. package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
  385. package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
  386. package/src/resources/extensions/gsd/tools/replan-slice.ts +41 -1
  387. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  388. package/src/resources/extensions/gsd/types.ts +8 -0
  389. package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
  390. package/src/resources/extensions/gsd/workflow-events.ts +154 -0
  391. package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
  392. package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
  393. package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
  394. package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
  395. package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
  396. package/src/resources/extensions/gsd/worktree-manager.ts +41 -5
  397. package/src/resources/extensions/gsd/worktree-resolver.ts +44 -0
  398. package/src/resources/extensions/gsd/write-intercept.ts +90 -0
  399. package/src/resources/extensions/mcp-client/index.ts +20 -0
  400. package/src/resources/extensions/voice/index.ts +11 -21
  401. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  402. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  403. package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
  404. package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
  405. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
  406. /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_buildManifest.js +0 -0
  407. /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_ssgManifest.js +0 -0
@@ -188,10 +188,20 @@ Examples:
188
188
  await handleFast(trimmed.replace(/^fast\s*/, "").trim(), ctx);
189
189
  return true;
190
190
  }
191
+ if (trimmed === "mcp" || trimmed.startsWith("mcp ")) {
192
+ const { handleMcpStatus } = await import("../../commands-mcp-status.js");
193
+ await handleMcpStatus(trimmed.replace(/^mcp\s*/, "").trim(), ctx);
194
+ return true;
195
+ }
191
196
  if (trimmed === "extensions" || trimmed.startsWith("extensions ")) {
192
197
  const { handleExtensions } = await import("../../commands-extensions.js");
193
198
  await handleExtensions(trimmed.replace(/^extensions\s*/, "").trim(), ctx);
194
199
  return true;
195
200
  }
201
+ if (trimmed === "rethink") {
202
+ const { handleRethink } = await import("../../rethink.js");
203
+ await handleRethink(trimmed, ctx, pi);
204
+ return true;
205
+ }
196
206
  return false;
197
207
  }
@@ -44,7 +44,7 @@ export async function handleParallelCommand(trimmed, _ctx, pi) {
44
44
  }
45
45
  const lines = ["# Parallel Workers\n"];
46
46
  for (const worker of workers) {
47
- lines.push(`- **${worker.milestoneId}** (${worker.title}) — ${worker.state} — ${worker.completedUnits} units — $${worker.cost.toFixed(2)}`);
47
+ lines.push(`- **${worker.milestoneId}** (${worker.title}) — ${worker.state} — $${worker.cost.toFixed(2)}`);
48
48
  }
49
49
  const state = getOrchestratorState();
50
50
  if (state) {
@@ -0,0 +1,187 @@
1
+ /**
2
+ * MCP Status — `/gsd mcp` command handler.
3
+ *
4
+ * Shows configured MCP servers, their connection status, and available tools.
5
+ *
6
+ * Subcommands:
7
+ * /gsd mcp — Overview of all servers (alias: /gsd mcp status)
8
+ * /gsd mcp status — Same as bare /gsd mcp
9
+ * /gsd mcp check <srv> — Detailed status for a specific server
10
+ */
11
+ import { existsSync, readFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ function readMcpConfigs() {
14
+ const servers = [];
15
+ const seen = new Set();
16
+ const configPaths = [
17
+ join(process.cwd(), ".mcp.json"),
18
+ join(process.cwd(), ".gsd", "mcp.json"),
19
+ ];
20
+ for (const configPath of configPaths) {
21
+ try {
22
+ if (!existsSync(configPath))
23
+ continue;
24
+ const raw = readFileSync(configPath, "utf-8");
25
+ const data = JSON.parse(raw);
26
+ const mcpServers = (data.mcpServers ?? data.servers);
27
+ if (!mcpServers || typeof mcpServers !== "object")
28
+ continue;
29
+ for (const [name, config] of Object.entries(mcpServers)) {
30
+ if (seen.has(name))
31
+ continue;
32
+ seen.add(name);
33
+ const hasCommand = typeof config.command === "string";
34
+ const hasUrl = typeof config.url === "string";
35
+ const transport = hasCommand
36
+ ? "stdio"
37
+ : hasUrl
38
+ ? "http"
39
+ : "unknown";
40
+ servers.push({
41
+ name,
42
+ transport,
43
+ ...(hasCommand && {
44
+ command: config.command,
45
+ args: Array.isArray(config.args) ? config.args : undefined,
46
+ }),
47
+ ...(hasUrl && { url: config.url }),
48
+ });
49
+ }
50
+ }
51
+ catch {
52
+ // Non-fatal — config file may not exist or be malformed
53
+ }
54
+ }
55
+ return servers;
56
+ }
57
+ // ─── Formatters (exported for testing) ──────────────────────────────────────
58
+ export function formatMcpStatusReport(servers) {
59
+ if (servers.length === 0) {
60
+ return [
61
+ "No MCP servers configured.",
62
+ "",
63
+ "Add servers to .mcp.json or .gsd/mcp.json to enable MCP integrations.",
64
+ "See: https://modelcontextprotocol.io/quickstart",
65
+ ].join("\n");
66
+ }
67
+ const lines = [`MCP Server Status — ${servers.length} server(s)\n`];
68
+ for (const s of servers) {
69
+ const icon = s.error ? "✗" : s.connected ? "✓" : "○";
70
+ const status = s.error
71
+ ? `error: ${s.error}`
72
+ : s.connected
73
+ ? `connected — ${s.toolCount} tools`
74
+ : "disconnected";
75
+ lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}`);
76
+ }
77
+ lines.push("");
78
+ lines.push("Use /gsd mcp check <server> for details on a specific server.");
79
+ lines.push("Use mcp_discover to connect and list tools for a server.");
80
+ return lines.join("\n");
81
+ }
82
+ export function formatMcpServerDetail(server) {
83
+ const lines = [`MCP Server: ${server.name}\n`];
84
+ lines.push(` Transport: ${server.transport}`);
85
+ if (server.error) {
86
+ lines.push(` Status: error`);
87
+ lines.push(` Error: ${server.error}`);
88
+ }
89
+ else if (server.connected) {
90
+ lines.push(` Status: connected`);
91
+ lines.push(` Tools: ${server.toolCount}`);
92
+ if (server.tools.length > 0) {
93
+ lines.push("");
94
+ lines.push(" Available tools:");
95
+ for (const tool of server.tools) {
96
+ lines.push(` - ${tool}`);
97
+ }
98
+ }
99
+ }
100
+ else {
101
+ lines.push(` Status: disconnected`);
102
+ lines.push("");
103
+ lines.push(` Run mcp_discover("${server.name}") to connect and list tools.`);
104
+ }
105
+ return lines.join("\n");
106
+ }
107
+ // ─── Command handler ────────────────────────────────────────────────────────
108
+ /**
109
+ * Handle `/gsd mcp [status|check <server>]`.
110
+ */
111
+ export async function handleMcpStatus(args, ctx) {
112
+ const trimmed = args.trim().toLowerCase();
113
+ const configs = readMcpConfigs();
114
+ // /gsd mcp check <server>
115
+ if (trimmed.startsWith("check ")) {
116
+ const serverName = args.trim().slice("check ".length).trim();
117
+ const config = configs.find((c) => c.name === serverName);
118
+ if (!config) {
119
+ const available = configs.map((c) => c.name).join(", ") || "(none)";
120
+ ctx.ui.notify(`Unknown MCP server: "${serverName}"\n\nAvailable: ${available}`, "warning");
121
+ return;
122
+ }
123
+ // Try to get connection/tool info from the mcp-client module if available
124
+ let connected = false;
125
+ let toolNames = [];
126
+ let error;
127
+ try {
128
+ const mcpClient = await import("../mcp-client/index.js");
129
+ // Access the module's connection state if exported; fall back gracefully
130
+ const mod = mcpClient;
131
+ if (typeof mod.getConnectionStatus === "function") {
132
+ const status = mod.getConnectionStatus(serverName);
133
+ connected = status.connected;
134
+ toolNames = status.tools;
135
+ error = status.error;
136
+ }
137
+ }
138
+ catch {
139
+ // mcp-client may not expose status helpers — that's fine
140
+ }
141
+ ctx.ui.notify(formatMcpServerDetail({
142
+ name: config.name,
143
+ transport: config.transport,
144
+ connected,
145
+ toolCount: toolNames.length,
146
+ tools: toolNames,
147
+ error,
148
+ }), "info");
149
+ return;
150
+ }
151
+ // /gsd mcp or /gsd mcp status
152
+ if (!trimmed || trimmed === "status") {
153
+ // Build status for each server
154
+ const statuses = [];
155
+ for (const config of configs) {
156
+ let connected = false;
157
+ let toolCount = 0;
158
+ let error;
159
+ try {
160
+ const mcpClient = await import("../mcp-client/index.js");
161
+ const mod = mcpClient;
162
+ if (typeof mod.getConnectionStatus === "function") {
163
+ const status = mod.getConnectionStatus(config.name);
164
+ connected = status.connected;
165
+ toolCount = status.tools.length;
166
+ error = status.error;
167
+ }
168
+ }
169
+ catch {
170
+ // Fall back to unknown state
171
+ }
172
+ statuses.push({
173
+ name: config.name,
174
+ transport: config.transport,
175
+ connected,
176
+ toolCount,
177
+ error,
178
+ });
179
+ }
180
+ ctx.ui.notify(formatMcpStatusReport(statuses), "info");
181
+ return;
182
+ }
183
+ // Unknown subcommand
184
+ ctx.ui.notify("Usage: /gsd mcp [status|check <server>]\n\n" +
185
+ " status Show all MCP server statuses (default)\n" +
186
+ " check <server> Detailed status for a specific server", "warning");
187
+ }
@@ -18,7 +18,7 @@ function lockPath(basePath) {
18
18
  return join(gsdRoot(basePath), LOCK_FILE);
19
19
  }
20
20
  /** Write or update the lock file with current auto-mode state. */
21
- export function writeLock(basePath, unitType, unitId, completedUnits, sessionFile) {
21
+ export function writeLock(basePath, unitType, unitId, sessionFile) {
22
22
  try {
23
23
  const data = {
24
24
  pid: process.pid,
@@ -26,7 +26,6 @@ export function writeLock(basePath, unitType, unitId, completedUnits, sessionFil
26
26
  unitType,
27
27
  unitId,
28
28
  unitStartedAt: new Date().toISOString(),
29
- completedUnits,
30
29
  sessionFile,
31
30
  };
32
31
  const lp = lockPath(basePath);
@@ -90,11 +89,10 @@ export function formatCrashInfo(lock) {
90
89
  `Previous auto-mode session was interrupted.`,
91
90
  ` Was executing: ${lock.unitType} (${lock.unitId})`,
92
91
  ` Started at: ${lock.unitStartedAt}`,
93
- ` Units completed before crash: ${lock.completedUnits}`,
94
92
  ` PID: ${lock.pid}`,
95
93
  ];
96
94
  // Add recovery guidance based on what was happening when it crashed
97
- if (lock.unitType === "starting" && lock.unitId === "bootstrap" && lock.completedUnits === 0) {
95
+ if (lock.unitType === "starting" && lock.unitId === "bootstrap") {
98
96
  lines.push(`No work was lost. Run /gsd auto to restart.`);
99
97
  }
100
98
  else if (lock.unitType.includes("research") || lock.unitType.includes("plan")) {
@@ -81,18 +81,11 @@ export class GSDDashboardOverlay {
81
81
  const currentUnit = dashData.currentUnit
82
82
  ? `${dashData.currentUnit.type}:${dashData.currentUnit.id}:${dashData.currentUnit.startedAt}`
83
83
  : "-";
84
- const lastCompleted = dashData.completedUnits.length > 0
85
- ? dashData.completedUnits[dashData.completedUnits.length - 1]
86
- : null;
87
- const completedKey = lastCompleted
88
- ? `${dashData.completedUnits.length}:${lastCompleted.type}:${lastCompleted.id}:${lastCompleted.finishedAt}`
89
- : "0";
90
84
  return [
91
85
  base,
92
86
  dashData.active ? "1" : "0",
93
87
  dashData.paused ? "1" : "0",
94
88
  currentUnit,
95
- completedKey,
96
89
  ].join("|");
97
90
  }
98
91
  async refreshDashboard(initial = false) {
@@ -393,43 +386,6 @@ export class GSDDashboardOverlay {
393
386
  else {
394
387
  lines.push(centered(th.fg("dim", "No active milestone.")));
395
388
  }
396
- if (this.dashData.completedUnits.length > 0) {
397
- lines.push(blank());
398
- lines.push(hr());
399
- lines.push(row(th.fg("text", th.bold("Completed"))));
400
- lines.push(blank());
401
- // Build ledger lookup for budget indicators (last entry wins for retries)
402
- const ledgerLookup = new Map();
403
- const currentLedger = getLedger();
404
- if (currentLedger) {
405
- for (const lu of currentLedger.units) {
406
- ledgerLookup.set(`${lu.type}:${lu.id}`, lu);
407
- }
408
- }
409
- const recent = [...this.dashData.completedUnits].reverse().slice(0, 10);
410
- for (const u of recent) {
411
- // Budget indicators from ledger — use warning glyph for pressured units
412
- const ledgerEntry = ledgerLookup.get(`${u.type}:${u.id}`);
413
- const hadPressure = ledgerEntry?.continueHereFired === true;
414
- const hadTruncation = (ledgerEntry?.truncationSections ?? 0) > 0;
415
- const unitGlyph = hadPressure
416
- ? th.fg(STATUS_COLOR.warning, STATUS_GLYPH.warning)
417
- : th.fg(STATUS_COLOR.done, STATUS_GLYPH.done);
418
- const left = ` ${unitGlyph} ${th.fg("muted", unitLabel(u.type))} ${th.fg("muted", u.id)}`;
419
- let budgetMarkers = "";
420
- if (hadTruncation) {
421
- budgetMarkers += th.fg("warning", ` ▼${ledgerEntry.truncationSections}`);
422
- }
423
- if (hadPressure) {
424
- budgetMarkers += th.fg("error", " → wrap-up");
425
- }
426
- const right = th.fg("dim", formatDuration(u.finishedAt - u.startedAt));
427
- lines.push(row(joinColumns(`${left}${budgetMarkers}`, right, contentWidth)));
428
- }
429
- if (this.dashData.completedUnits.length > 10) {
430
- lines.push(row(th.fg("dim", ` ...and ${this.dashData.completedUnits.length - 10} more`)));
431
- }
432
- }
433
389
  const ledger = getLedger();
434
390
  if (ledger && ledger.units.length > 0) {
435
391
  const totals = getProjectTotals(ledger.units);
@@ -8,10 +8,11 @@
8
8
  // Critical invariant: generated markdown must round-trip through
9
9
  // parseDecisionsTable() and parseRequirementsSections() with field fidelity.
10
10
  import { resolve } from 'node:path';
11
- import { readFileSync, existsSync } from 'node:fs';
11
+ import { readFileSync, existsSync, statSync } from 'node:fs';
12
12
  import { resolveGsdRootFile } from './paths.js';
13
13
  import { saveFile } from './files.js';
14
14
  import { GSDError, GSD_STALE_STATE, GSD_IO_ERROR } from './errors.js';
15
+ import { logWarning, logError } from './workflow-logger.js';
15
16
  import { invalidateStateCache } from './state.js';
16
17
  import { clearPathCache } from './paths.js';
17
18
  import { clearParseCache } from './files.js';
@@ -200,7 +201,7 @@ export async function nextDecisionId() {
200
201
  return `D${String(next).padStart(3, '0')}`;
201
202
  }
202
203
  catch (err) {
203
- process.stderr.write(`gsd-db: nextDecisionId failed: ${err.message}\n`);
204
+ logError('manifest', 'nextDecisionId failed', { fn: 'nextDecisionId', error: String(err.message) });
204
205
  return 'D001';
205
206
  }
206
207
  }
@@ -269,7 +270,7 @@ export async function saveDecisionToDb(fields, basePath) {
269
270
  await saveFile(filePath, md);
270
271
  }
271
272
  catch (diskErr) {
272
- process.stderr.write(`gsd-db: saveDecisionToDb — disk write failed, rolling back DB row: ${diskErr.message}\n`);
273
+ logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveDecisionToDb', error: String(diskErr.message) });
273
274
  adapter?.prepare('DELETE FROM decisions WHERE id = :id').run({ ':id': id });
274
275
  throw diskErr;
275
276
  }
@@ -281,7 +282,7 @@ export async function saveDecisionToDb(fields, basePath) {
281
282
  return { id };
282
283
  }
283
284
  catch (err) {
284
- process.stderr.write(`gsd-db: saveDecisionToDb failed: ${err.message}\n`);
285
+ logError('manifest', 'saveDecisionToDb failed', { fn: 'saveDecisionToDb', error: String(err.message) });
285
286
  throw err;
286
287
  }
287
288
  }
@@ -333,7 +334,7 @@ export async function updateRequirementInDb(id, updates, basePath) {
333
334
  await saveFile(filePath, md);
334
335
  }
335
336
  catch (diskErr) {
336
- process.stderr.write(`gsd-db: updateRequirementInDb — disk write failed, reverting DB row: ${diskErr.message}\n`);
337
+ logError('manifest', 'disk write failed, reverting DB row', { fn: 'updateRequirementInDb', error: String(diskErr.message) });
337
338
  db.upsertRequirement(existing);
338
339
  throw diskErr;
339
340
  }
@@ -344,7 +345,7 @@ export async function updateRequirementInDb(id, updates, basePath) {
344
345
  clearParseCache();
345
346
  }
346
347
  catch (err) {
347
- process.stderr.write(`gsd-db: updateRequirementInDb failed: ${err.message}\n`);
348
+ logError('manifest', 'updateRequirementInDb failed', { fn: 'updateRequirementInDb', error: String(err.message) });
348
349
  throw err;
349
350
  }
350
351
  }
@@ -356,28 +357,45 @@ export async function updateRequirementInDb(id, updates, basePath) {
356
357
  export async function saveArtifactToDb(opts, basePath) {
357
358
  try {
358
359
  const db = await import('./gsd-db.js');
360
+ // Guard against path traversal before any reads/writes
361
+ const gsdDir = resolve(basePath, '.gsd');
362
+ const fullPath = resolve(basePath, '.gsd', opts.path);
363
+ if (!fullPath.startsWith(gsdDir)) {
364
+ throw new GSDError(GSD_IO_ERROR, `saveArtifactToDb: path escapes .gsd/ directory: ${opts.path}`);
365
+ }
366
+ // Shrinkage guard: if the file already exists and the new content is
367
+ // significantly smaller (<50%), preserve the richer file on disk and
368
+ // store its content in the DB instead of the abbreviated version.
369
+ let dbContent = opts.content;
370
+ let skipDiskWrite = false;
371
+ if (existsSync(fullPath)) {
372
+ const existingSize = statSync(fullPath).size;
373
+ const newSize = Buffer.byteLength(opts.content, 'utf-8');
374
+ if (existingSize > 0 && newSize < existingSize * 0.5) {
375
+ logWarning('manifest', `new content (${newSize}B) is <50% of existing file (${existingSize}B), preserving disk file`, { fn: 'saveArtifactToDb', path: opts.path });
376
+ dbContent = readFileSync(fullPath, 'utf-8');
377
+ skipDiskWrite = true;
378
+ }
379
+ }
359
380
  db.insertArtifact({
360
381
  path: opts.path,
361
382
  artifact_type: opts.artifact_type,
362
383
  milestone_id: opts.milestone_id ?? null,
363
384
  slice_id: opts.slice_id ?? null,
364
385
  task_id: opts.task_id ?? null,
365
- full_content: opts.content,
386
+ full_content: dbContent,
366
387
  });
367
- // Write the file to disk (guard against path traversal)
368
- const gsdDir = resolve(basePath, '.gsd');
369
- const fullPath = resolve(basePath, '.gsd', opts.path);
370
- if (!fullPath.startsWith(gsdDir)) {
371
- throw new GSDError(GSD_IO_ERROR, `saveArtifactToDb: path escapes .gsd/ directory: ${opts.path}`);
372
- }
373
- try {
374
- await saveFile(fullPath, opts.content);
375
- }
376
- catch (diskErr) {
377
- process.stderr.write(`gsd-db: saveArtifactToDb — disk write failed, rolling back DB row: ${diskErr.message}\n`);
378
- const rollbackAdapter = db._getAdapter();
379
- rollbackAdapter?.prepare('DELETE FROM artifacts WHERE path = :path').run({ ':path': opts.path });
380
- throw diskErr;
388
+ // Write the file to disk (only if we're not preserving a richer existing file)
389
+ if (!skipDiskWrite) {
390
+ try {
391
+ await saveFile(fullPath, opts.content);
392
+ }
393
+ catch (diskErr) {
394
+ logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveArtifactToDb', error: String(diskErr.message) });
395
+ const rollbackAdapter = db._getAdapter();
396
+ rollbackAdapter?.prepare('DELETE FROM artifacts WHERE path = :path').run({ ':path': opts.path });
397
+ throw diskErr;
398
+ }
381
399
  }
382
400
  // Invalidate file-read caches so deriveState() sees the updated markdown.
383
401
  // Do NOT clear the artifacts table — we just wrote to it intentionally.
@@ -386,7 +404,7 @@ export async function saveArtifactToDb(opts, basePath) {
386
404
  clearParseCache();
387
405
  }
388
406
  catch (err) {
389
- process.stderr.write(`gsd-db: saveArtifactToDb failed: ${err.message}\n`);
407
+ logError('manifest', 'saveArtifactToDb failed', { fn: 'saveArtifactToDb', error: String(err.message) });
390
408
  throw err;
391
409
  }
392
410
  }
@@ -3,7 +3,7 @@ import { basename, dirname, join, sep } from "node:path";
3
3
  import { readRepoMeta, externalProjectsRoot, cleanNumberedGsdVariants } from "./repo-identity.js";
4
4
  import { loadFile } from "./files.js";
5
5
  import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
6
- import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
6
+ import { isDbAvailable, _getAdapter, getMilestoneSlices } from "./gsd-db.js";
7
7
  import { resolveMilestoneFile, milestonesDir, gsdRoot, resolveGsdRootFile } from "./paths.js";
8
8
  import { deriveState, isMilestoneComplete } from "./state.js";
9
9
  import { saveFile } from "./files.js";
@@ -17,7 +17,9 @@ import { getAllWorktreeHealth } from "./worktree-health.js";
17
17
  import { readAllSessionStatuses, isSessionStale, removeSessionStatus } from "./session-status-io.js";
18
18
  import { recoverFailedMigration } from "./migrate-external.js";
19
19
  import { loadEffectiveGSDPreferences } from "./preferences.js";
20
- export async function checkGitHealth(basePath, issues, fixesApplied, shouldFix, isolationMode = "worktree") {
20
+ import { readEvents } from "./workflow-events.js";
21
+ import { renderAllProjections } from "./workflow-projections.js";
22
+ export async function checkGitHealth(basePath, issues, fixesApplied, shouldFix, isolationMode = "none") {
21
23
  // Degrade gracefully if not a git repo
22
24
  if (!nativeIsRepo(basePath)) {
23
25
  return; // Not a git repo — skip all git health checks
@@ -1067,3 +1069,166 @@ export async function checkGlobalHealth(issues, fixesApplied, shouldFix) {
1067
1069
  // Non-fatal — global health check must not block per-project doctor
1068
1070
  }
1069
1071
  }
1072
+ // ── Engine Health Checks ────────────────────────────────────────────────────
1073
+ // DB constraint violation detection and projection drift checks.
1074
+ export async function checkEngineHealth(basePath, issues, fixesApplied) {
1075
+ // ── DB constraint violation detection (full doctor only, not pre-dispatch per D-10) ──
1076
+ try {
1077
+ if (isDbAvailable()) {
1078
+ const adapter = _getAdapter();
1079
+ // a. Orphaned tasks (task.slice_id points to non-existent slice)
1080
+ try {
1081
+ const orphanedTasks = adapter
1082
+ .prepare(`SELECT t.id, t.slice_id, t.milestone_id
1083
+ FROM tasks t
1084
+ LEFT JOIN slices s ON t.milestone_id = s.milestone_id AND t.slice_id = s.id
1085
+ WHERE s.id IS NULL`)
1086
+ .all();
1087
+ for (const row of orphanedTasks) {
1088
+ issues.push({
1089
+ severity: "error",
1090
+ code: "db_orphaned_task",
1091
+ scope: "task",
1092
+ unitId: `${row.milestone_id}/${row.slice_id}/${row.id}`,
1093
+ message: `Task ${row.id} references slice ${row.slice_id} in milestone ${row.milestone_id} but no such slice exists in the database`,
1094
+ fixable: false,
1095
+ });
1096
+ }
1097
+ }
1098
+ catch {
1099
+ // Non-fatal — orphaned task check failed
1100
+ }
1101
+ // b. Orphaned slices (slice.milestone_id points to non-existent milestone)
1102
+ try {
1103
+ const orphanedSlices = adapter
1104
+ .prepare(`SELECT s.id, s.milestone_id
1105
+ FROM slices s
1106
+ LEFT JOIN milestones m ON s.milestone_id = m.id
1107
+ WHERE m.id IS NULL`)
1108
+ .all();
1109
+ for (const row of orphanedSlices) {
1110
+ issues.push({
1111
+ severity: "error",
1112
+ code: "db_orphaned_slice",
1113
+ scope: "slice",
1114
+ unitId: `${row.milestone_id}/${row.id}`,
1115
+ message: `Slice ${row.id} references milestone ${row.milestone_id} but no such milestone exists in the database`,
1116
+ fixable: false,
1117
+ });
1118
+ }
1119
+ }
1120
+ catch {
1121
+ // Non-fatal — orphaned slice check failed
1122
+ }
1123
+ // c. Tasks marked complete without summaries
1124
+ try {
1125
+ const doneTasks = adapter
1126
+ .prepare(`SELECT id, slice_id, milestone_id FROM tasks
1127
+ WHERE status = 'done' AND (summary IS NULL OR summary = '')`)
1128
+ .all();
1129
+ for (const row of doneTasks) {
1130
+ issues.push({
1131
+ severity: "warning",
1132
+ code: "db_done_task_no_summary",
1133
+ scope: "task",
1134
+ unitId: `${row.milestone_id}/${row.slice_id}/${row.id}`,
1135
+ message: `Task ${row.id} is marked done but has no summary in the database`,
1136
+ fixable: false,
1137
+ });
1138
+ }
1139
+ }
1140
+ catch {
1141
+ // Non-fatal — done-task-no-summary check failed
1142
+ }
1143
+ // d. Duplicate entity IDs (safety check)
1144
+ try {
1145
+ const dupMilestones = adapter
1146
+ .prepare("SELECT id, COUNT(*) as cnt FROM milestones GROUP BY id HAVING cnt > 1")
1147
+ .all();
1148
+ for (const row of dupMilestones) {
1149
+ issues.push({
1150
+ severity: "error",
1151
+ code: "db_duplicate_id",
1152
+ scope: "milestone",
1153
+ unitId: row.id,
1154
+ message: `Duplicate milestone ID "${row.id}" appears ${row.cnt} times in the database`,
1155
+ fixable: false,
1156
+ });
1157
+ }
1158
+ const dupSlices = adapter
1159
+ .prepare("SELECT id, milestone_id, COUNT(*) as cnt FROM slices GROUP BY id, milestone_id HAVING cnt > 1")
1160
+ .all();
1161
+ for (const row of dupSlices) {
1162
+ issues.push({
1163
+ severity: "error",
1164
+ code: "db_duplicate_id",
1165
+ scope: "slice",
1166
+ unitId: `${row.milestone_id}/${row.id}`,
1167
+ message: `Duplicate slice ID "${row.id}" in milestone ${row.milestone_id} appears ${row.cnt} times`,
1168
+ fixable: false,
1169
+ });
1170
+ }
1171
+ const dupTasks = adapter
1172
+ .prepare("SELECT id, slice_id, milestone_id, COUNT(*) as cnt FROM tasks GROUP BY id, slice_id, milestone_id HAVING cnt > 1")
1173
+ .all();
1174
+ for (const row of dupTasks) {
1175
+ issues.push({
1176
+ severity: "error",
1177
+ code: "db_duplicate_id",
1178
+ scope: "task",
1179
+ unitId: `${row.milestone_id}/${row.slice_id}/${row.id}`,
1180
+ message: `Duplicate task ID "${row.id}" in slice ${row.slice_id} appears ${row.cnt} times`,
1181
+ fixable: false,
1182
+ });
1183
+ }
1184
+ }
1185
+ catch {
1186
+ // Non-fatal — duplicate ID check failed
1187
+ }
1188
+ }
1189
+ }
1190
+ catch {
1191
+ // Non-fatal — DB constraint checks failed entirely
1192
+ }
1193
+ // ── Projection drift detection ──────────────────────────────────────────
1194
+ // If the DB is available, check whether markdown projections are stale
1195
+ // relative to the event log and re-render them.
1196
+ try {
1197
+ if (isDbAvailable()) {
1198
+ const eventLogPath = join(basePath, ".gsd", "event-log.jsonl");
1199
+ const events = readEvents(eventLogPath);
1200
+ if (events.length > 0) {
1201
+ const lastEventTs = new Date(events[events.length - 1].ts).getTime();
1202
+ const state = await deriveState(basePath);
1203
+ for (const milestone of state.registry) {
1204
+ if (milestone.status === "complete")
1205
+ continue;
1206
+ const roadmapPath = resolveMilestoneFile(basePath, milestone.id, "ROADMAP");
1207
+ if (!roadmapPath || !existsSync(roadmapPath)) {
1208
+ try {
1209
+ await renderAllProjections(basePath, milestone.id);
1210
+ fixesApplied.push(`re-rendered missing projections for ${milestone.id}`);
1211
+ }
1212
+ catch {
1213
+ // Non-fatal — projection re-render failed
1214
+ }
1215
+ continue;
1216
+ }
1217
+ const projectionMtime = statSync(roadmapPath).mtimeMs;
1218
+ if (lastEventTs > projectionMtime) {
1219
+ try {
1220
+ await renderAllProjections(basePath, milestone.id);
1221
+ fixesApplied.push(`re-rendered stale projections for ${milestone.id}`);
1222
+ }
1223
+ catch {
1224
+ // Non-fatal — projection re-render failed
1225
+ }
1226
+ }
1227
+ }
1228
+ }
1229
+ }
1230
+ }
1231
+ catch {
1232
+ // Non-fatal — projection drift check must never block doctor
1233
+ }
1234
+ }