gsd-pi 2.43.0 → 2.44.0-dev.0b97ffd

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 (693) hide show
  1. package/README.md +30 -12
  2. package/dist/cli.js +13 -1
  3. package/dist/help-text.js +24 -0
  4. package/dist/resources/extensions/bg-shell/overlay.js +3 -0
  5. package/dist/resources/extensions/github-sync/sync.js +2 -1
  6. package/dist/resources/extensions/gsd/auto/loop.js +0 -2
  7. package/dist/resources/extensions/gsd/auto/phases.js +7 -12
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +19 -18
  9. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +34 -19
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +36 -21
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +128 -14
  12. package/dist/resources/extensions/gsd/auto-prompts.js +202 -92
  13. package/dist/resources/extensions/gsd/auto-recovery.js +83 -135
  14. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  15. package/dist/resources/extensions/gsd/auto-supervisor.js +14 -0
  16. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -7
  17. package/dist/resources/extensions/gsd/auto-verification.js +5 -10
  18. package/dist/resources/extensions/gsd/auto-worktree.js +123 -30
  19. package/dist/resources/extensions/gsd/auto.js +1 -4
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +611 -0
  21. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +28 -3
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
  23. package/dist/resources/extensions/gsd/commands/catalog.js +3 -1
  24. package/dist/resources/extensions/gsd/commands/handlers/ops.js +15 -1
  25. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  26. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  27. package/dist/resources/extensions/gsd/commands-maintenance.js +78 -3
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -31
  29. package/dist/resources/extensions/gsd/db-writer.js +95 -4
  30. package/dist/resources/extensions/gsd/dispatch-guard.js +35 -30
  31. package/dist/resources/extensions/gsd/doctor-checks.js +28 -11
  32. package/dist/resources/extensions/gsd/doctor-environment.js +28 -0
  33. package/dist/resources/extensions/gsd/doctor-types.js +0 -15
  34. package/dist/resources/extensions/gsd/doctor.js +46 -282
  35. package/dist/resources/extensions/gsd/file-watcher.js +5 -1
  36. package/dist/resources/extensions/gsd/files.js +14 -198
  37. package/dist/resources/extensions/gsd/git-service.js +4 -0
  38. package/dist/resources/extensions/gsd/gitignore.js +4 -0
  39. package/dist/resources/extensions/gsd/gsd-db.js +819 -197
  40. package/dist/resources/extensions/gsd/guided-flow.js +18 -8
  41. package/dist/resources/extensions/gsd/markdown-renderer.js +862 -0
  42. package/dist/resources/extensions/gsd/md-importer.js +182 -4
  43. package/dist/resources/extensions/gsd/native-git-bridge.js +10 -1
  44. package/dist/resources/extensions/gsd/parallel-eligibility.js +14 -19
  45. package/dist/resources/extensions/gsd/parallel-orchestrator.js +38 -0
  46. package/dist/resources/extensions/gsd/parsers-legacy.js +239 -0
  47. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +9 -0
  49. package/dist/resources/extensions/gsd/preferences.js +1 -0
  50. package/dist/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  51. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  52. package/dist/resources/extensions/gsd/prompts/execute-task.md +15 -5
  53. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  58. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  59. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  60. package/dist/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  61. package/dist/resources/extensions/gsd/reactive-graph.js +33 -3
  62. package/dist/resources/extensions/gsd/skill-health.js +3 -1
  63. package/dist/resources/extensions/gsd/state.js +484 -30
  64. package/dist/resources/extensions/gsd/tools/complete-milestone.js +128 -0
  65. package/dist/resources/extensions/gsd/tools/complete-slice.js +244 -0
  66. package/dist/resources/extensions/gsd/tools/complete-task.js +204 -0
  67. package/dist/resources/extensions/gsd/tools/plan-milestone.js +205 -0
  68. package/dist/resources/extensions/gsd/tools/plan-slice.js +155 -0
  69. package/dist/resources/extensions/gsd/tools/plan-task.js +94 -0
  70. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +152 -0
  71. package/dist/resources/extensions/gsd/tools/replan-slice.js +146 -0
  72. package/dist/resources/extensions/gsd/triage-resolution.js +17 -1
  73. package/dist/resources/extensions/gsd/undo.js +197 -3
  74. package/dist/resources/extensions/gsd/visualizer-data.js +53 -16
  75. package/dist/resources/extensions/gsd/workspace-index.js +63 -39
  76. package/dist/web/standalone/.next/BUILD_ID +1 -1
  77. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -17
  78. package/dist/web/standalone/.next/build-manifest.json +4 -4
  79. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  80. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  81. package/dist/web/standalone/.next/required-server-files.json +4 -4
  82. package/dist/web/standalone/.next/routes-manifest.json +6 -0
  83. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  84. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  86. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  94. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  103. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/cleanup/route.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.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  148. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  154. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -0
  166. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -0
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -0
  168. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/index.html +1 -1
  185. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  186. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  187. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  188. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  190. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  191. package/dist/web/standalone/.next/server/app/page.js +2 -2
  192. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -17
  194. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  195. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  196. package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
  197. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/middleware.js +2 -2
  200. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  202. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  203. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  204. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  205. package/dist/web/standalone/.next/static/alS4hoANx0TK4UVZY27da/_buildManifest.js +1 -0
  206. package/dist/web/standalone/.next/static/chunks/{4024.c195dc1fdd2adbea.js → 4024.0de81b543b28b9fe.js} +2 -2
  207. package/dist/web/standalone/.next/static/chunks/app/_global-error/{page-d07a2c023f1aef1e.js → page-d83ba70a25a85472.js} +1 -1
  208. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  209. package/dist/web/standalone/.next/static/chunks/app/api/boot/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  210. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d83ba70a25a85472.js +1 -0
  213. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d83ba70a25a85472.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d83ba70a25a85472.js +1 -0
  215. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d83ba70a25a85472.js +1 -0
  216. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d83ba70a25a85472.js +1 -0
  217. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d83ba70a25a85472.js +1 -0
  218. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d83ba70a25a85472.js +1 -0
  219. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d83ba70a25a85472.js +1 -0
  220. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d83ba70a25a85472.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d83ba70a25a85472.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d83ba70a25a85472.js +1 -0
  223. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d83ba70a25a85472.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d83ba70a25a85472.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d83ba70a25a85472.js +1 -0
  226. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d83ba70a25a85472.js +1 -0
  227. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d83ba70a25a85472.js +1 -0
  228. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d83ba70a25a85472.js +1 -0
  229. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d83ba70a25a85472.js +1 -0
  230. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d83ba70a25a85472.js +1 -0
  231. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d83ba70a25a85472.js +1 -0
  232. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d83ba70a25a85472.js +1 -0
  233. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d83ba70a25a85472.js +1 -0
  234. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d83ba70a25a85472.js +1 -0
  235. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d83ba70a25a85472.js +1 -0
  236. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d83ba70a25a85472.js +1 -0
  237. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d83ba70a25a85472.js +1 -0
  238. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d83ba70a25a85472.js +1 -0
  239. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d83ba70a25a85472.js +1 -0
  240. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-d83ba70a25a85472.js +1 -0
  241. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d83ba70a25a85472.js +1 -0
  242. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d83ba70a25a85472.js +1 -0
  243. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d83ba70a25a85472.js +1 -0
  244. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d83ba70a25a85472.js +1 -0
  245. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d83ba70a25a85472.js +1 -0
  246. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d83ba70a25a85472.js +1 -0
  247. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d83ba70a25a85472.js +1 -0
  248. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d83ba70a25a85472.js +1 -0
  249. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  250. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  251. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  252. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d83ba70a25a85472.js +1 -0
  253. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d83ba70a25a85472.js +1 -0
  254. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  255. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d83ba70a25a85472.js +1 -0
  256. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d83ba70a25a85472.js +1 -0
  257. package/dist/web/standalone/.next/static/chunks/{webpack-fa307370fcf9fb2c.js → webpack-9014b5adb127a98a.js} +1 -1
  258. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +1 -0
  259. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  260. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  261. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  262. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  263. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  264. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  265. package/dist/web/standalone/server.js +1 -1
  266. package/package.json +4 -4
  267. package/packages/pi-ai/dist/models.custom.d.ts +173 -0
  268. package/packages/pi-ai/dist/models.custom.d.ts.map +1 -0
  269. package/packages/pi-ai/dist/models.custom.js +170 -0
  270. package/packages/pi-ai/dist/models.custom.js.map +1 -0
  271. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  272. package/packages/pi-ai/dist/models.js +16 -1
  273. package/packages/pi-ai/dist/models.js.map +1 -1
  274. package/packages/pi-ai/dist/models.test.d.ts +2 -0
  275. package/packages/pi-ai/dist/models.test.d.ts.map +1 -0
  276. package/packages/pi-ai/dist/models.test.js +67 -0
  277. package/packages/pi-ai/dist/models.test.js.map +1 -0
  278. package/packages/pi-ai/src/models.custom.ts +172 -0
  279. package/packages/pi-ai/src/models.test.ts +85 -0
  280. package/packages/pi-ai/src/models.ts +17 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -3
  282. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/agent-session.js +21 -34
  284. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  286. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
  288. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
  291. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
  294. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  296. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +6 -0
  299. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/extensions/loader.js +80 -0
  301. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +63 -0
  303. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  305. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
  307. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  309. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
  311. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
  313. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  315. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
  317. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
  318. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
  319. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
  320. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +5 -0
  321. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/lsp/client.js +69 -21
  323. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
  325. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
  326. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
  327. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
  328. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
  329. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  330. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  331. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
  333. package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
  335. package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
  336. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
  337. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
  338. package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
  339. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  341. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
  344. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  345. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  346. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  347. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  348. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  349. package/packages/pi-coding-agent/dist/index.d.ts +3 -1
  350. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  351. package/packages/pi-coding-agent/dist/index.js +1 -0
  352. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  353. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  354. package/packages/pi-coding-agent/dist/main.js +11 -199
  355. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +6 -0
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +21 -0
  359. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  360. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +8 -15
  363. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  364. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  365. package/packages/pi-coding-agent/dist/modes/print-mode.js +45 -34
  366. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  367. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +1 -0
  368. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +7 -2
  370. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  372. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -1
  373. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  374. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  375. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  376. package/packages/pi-coding-agent/package.json +1 -1
  377. package/packages/pi-coding-agent/src/core/agent-session.ts +26 -37
  378. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  379. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
  380. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
  381. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
  382. package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
  383. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +96 -0
  384. package/packages/pi-coding-agent/src/core/extensions/loader.ts +89 -0
  385. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  386. package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
  387. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
  388. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
  389. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  390. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
  391. package/packages/pi-coding-agent/src/core/lsp/client.ts +83 -21
  392. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
  393. package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
  394. package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
  395. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  396. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  397. package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
  398. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  399. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  400. package/packages/pi-coding-agent/src/index.ts +7 -0
  401. package/packages/pi-coding-agent/src/main.ts +11 -232
  402. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +20 -0
  403. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +9 -16
  404. package/packages/pi-coding-agent/src/modes/print-mode.ts +42 -32
  405. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +8 -2
  406. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -1
  407. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  408. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  409. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  410. package/pkg/dist/modes/interactive/theme/theme.js +8 -15
  411. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  412. package/pkg/package.json +1 -1
  413. package/src/resources/extensions/bg-shell/overlay.ts +4 -0
  414. package/src/resources/extensions/github-sync/sync.ts +2 -1
  415. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -8
  416. package/src/resources/extensions/gsd/auto/loop.ts +0 -2
  417. package/src/resources/extensions/gsd/auto/phases.ts +7 -20
  418. package/src/resources/extensions/gsd/auto/types.ts +0 -1
  419. package/src/resources/extensions/gsd/auto-dashboard.ts +20 -16
  420. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +34 -19
  421. package/src/resources/extensions/gsd/auto-dispatch.ts +38 -21
  422. package/src/resources/extensions/gsd/auto-post-unit.ts +150 -15
  423. package/src/resources/extensions/gsd/auto-prompts.ts +186 -103
  424. package/src/resources/extensions/gsd/auto-recovery.ts +77 -142
  425. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  426. package/src/resources/extensions/gsd/auto-supervisor.ts +14 -0
  427. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +6 -7
  428. package/src/resources/extensions/gsd/auto-verification.ts +4 -9
  429. package/src/resources/extensions/gsd/auto-worktree.ts +126 -30
  430. package/src/resources/extensions/gsd/auto.ts +0 -9
  431. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +675 -4
  432. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +31 -3
  433. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -0
  434. package/src/resources/extensions/gsd/commands/catalog.ts +3 -1
  435. package/src/resources/extensions/gsd/commands/handlers/ops.ts +15 -1
  436. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  437. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  438. package/src/resources/extensions/gsd/commands-maintenance.ts +86 -3
  439. package/src/resources/extensions/gsd/dashboard-overlay.ts +17 -13
  440. package/src/resources/extensions/gsd/db-writer.ts +105 -4
  441. package/src/resources/extensions/gsd/dispatch-guard.ts +32 -30
  442. package/src/resources/extensions/gsd/doctor-checks.ts +25 -11
  443. package/src/resources/extensions/gsd/doctor-environment.ts +31 -0
  444. package/src/resources/extensions/gsd/doctor-types.ts +0 -23
  445. package/src/resources/extensions/gsd/doctor.ts +45 -295
  446. package/src/resources/extensions/gsd/file-watcher.ts +4 -1
  447. package/src/resources/extensions/gsd/files.ts +16 -220
  448. package/src/resources/extensions/gsd/git-service.ts +4 -0
  449. package/src/resources/extensions/gsd/gitignore.ts +4 -0
  450. package/src/resources/extensions/gsd/gsd-db.ts +1157 -370
  451. package/src/resources/extensions/gsd/guided-flow.ts +20 -8
  452. package/src/resources/extensions/gsd/markdown-renderer.ts +1098 -0
  453. package/src/resources/extensions/gsd/md-importer.ts +211 -2
  454. package/src/resources/extensions/gsd/native-git-bridge.ts +12 -1
  455. package/src/resources/extensions/gsd/parallel-eligibility.ts +14 -18
  456. package/src/resources/extensions/gsd/parallel-orchestrator.ts +43 -0
  457. package/src/resources/extensions/gsd/parsers-legacy.ts +271 -0
  458. package/src/resources/extensions/gsd/preferences-types.ts +3 -0
  459. package/src/resources/extensions/gsd/preferences-validation.ts +9 -0
  460. package/src/resources/extensions/gsd/preferences.ts +1 -0
  461. package/src/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  462. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  463. package/src/resources/extensions/gsd/prompts/execute-task.md +15 -5
  464. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  465. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  466. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  467. package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  468. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  469. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  470. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  471. package/src/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  472. package/src/resources/extensions/gsd/reactive-graph.ts +33 -3
  473. package/src/resources/extensions/gsd/skill-health.ts +2 -1
  474. package/src/resources/extensions/gsd/state.ts +547 -29
  475. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  476. package/src/resources/extensions/gsd/tests/atomic-task-closeout.test.ts +8 -120
  477. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  478. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +20 -11
  479. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  480. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  481. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +600 -513
  482. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  483. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  484. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +121 -0
  485. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +540 -668
  486. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  487. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  488. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  489. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  490. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  491. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  492. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  493. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +39 -60
  494. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +375 -0
  495. package/src/resources/extensions/gsd/tests/complete-task.test.ts +387 -0
  496. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  497. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  498. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  499. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  500. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -2
  501. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  502. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  503. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  504. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +512 -0
  505. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +644 -84
  506. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  507. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  508. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  509. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  510. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +192 -161
  511. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  512. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  513. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +30 -90
  514. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  515. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +57 -80
  516. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +164 -0
  517. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  518. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +55 -153
  519. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  520. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  521. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +53 -97
  522. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  523. package/src/resources/extensions/gsd/tests/doctor.test.ts +109 -149
  524. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  525. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  526. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  527. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  528. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +278 -0
  529. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +232 -0
  530. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  531. package/src/resources/extensions/gsd/tests/git-service.test.ts +291 -390
  532. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  533. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  534. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  535. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  536. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +440 -0
  537. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  538. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  539. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  540. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -270
  541. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  542. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  543. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  544. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  545. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +643 -0
  546. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  547. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1161 -0
  548. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  549. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  550. package/src/resources/extensions/gsd/tests/memory-store.test.ts +81 -94
  551. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  552. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +429 -0
  553. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  554. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  555. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  556. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +89 -97
  557. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +127 -164
  558. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  559. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  560. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  561. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  562. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  563. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  564. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  565. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  566. package/src/resources/extensions/gsd/tests/parsers.test.ts +548 -612
  567. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  568. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +176 -113
  569. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +7 -0
  570. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +179 -0
  571. package/src/resources/extensions/gsd/tests/plan-task.test.ts +145 -0
  572. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +305 -0
  573. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  574. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +139 -0
  575. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  576. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  577. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  578. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  579. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  580. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  581. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +325 -0
  582. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  583. package/src/resources/extensions/gsd/tests/replan-handler.test.ts +410 -0
  584. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  585. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  586. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  587. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  588. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  589. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +1 -1
  590. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +296 -0
  591. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  592. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  593. package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +176 -0
  594. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  595. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  596. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +209 -0
  597. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  598. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  599. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  600. package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +118 -0
  601. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  602. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  603. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +19 -13
  604. package/src/resources/extensions/gsd/tests/undo.test.ts +321 -1
  605. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  606. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  607. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -1
  608. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +0 -142
  609. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  610. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  611. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  612. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  613. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  614. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  615. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  616. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  617. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  618. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  619. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  620. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +12 -5
  621. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  622. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  623. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  624. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  625. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  626. package/src/resources/extensions/gsd/tools/complete-milestone.ts +176 -0
  627. package/src/resources/extensions/gsd/tools/complete-slice.ts +300 -0
  628. package/src/resources/extensions/gsd/tools/complete-task.ts +245 -0
  629. package/src/resources/extensions/gsd/tools/plan-milestone.ts +249 -0
  630. package/src/resources/extensions/gsd/tools/plan-slice.ts +194 -0
  631. package/src/resources/extensions/gsd/tools/plan-task.ts +116 -0
  632. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +203 -0
  633. package/src/resources/extensions/gsd/tools/replan-slice.ts +192 -0
  634. package/src/resources/extensions/gsd/triage-resolution.ts +20 -1
  635. package/src/resources/extensions/gsd/types.ts +50 -0
  636. package/src/resources/extensions/gsd/undo.ts +247 -3
  637. package/src/resources/extensions/gsd/visualizer-data.ts +54 -17
  638. package/src/resources/extensions/gsd/workspace-index.ts +64 -46
  639. package/dist/resources/extensions/gsd/auto-observability.js +0 -56
  640. package/dist/resources/extensions/gsd/observability-validator.js +0 -422
  641. package/dist/resources/extensions/gsd/roadmap-mutations.js +0 -110
  642. package/dist/web/standalone/.next/static/VvclDCW6TAWjEyLU-EYL1/_buildManifest.js +0 -1
  643. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  644. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  645. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d07a2c023f1aef1e.js +0 -1
  646. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d07a2c023f1aef1e.js +0 -1
  647. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d07a2c023f1aef1e.js +0 -1
  648. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d07a2c023f1aef1e.js +0 -1
  649. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d07a2c023f1aef1e.js +0 -1
  650. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d07a2c023f1aef1e.js +0 -1
  651. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d07a2c023f1aef1e.js +0 -1
  652. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d07a2c023f1aef1e.js +0 -1
  653. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d07a2c023f1aef1e.js +0 -1
  654. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d07a2c023f1aef1e.js +0 -1
  655. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d07a2c023f1aef1e.js +0 -1
  656. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d07a2c023f1aef1e.js +0 -1
  657. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d07a2c023f1aef1e.js +0 -1
  658. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d07a2c023f1aef1e.js +0 -1
  659. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d07a2c023f1aef1e.js +0 -1
  660. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d07a2c023f1aef1e.js +0 -1
  661. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d07a2c023f1aef1e.js +0 -1
  662. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d07a2c023f1aef1e.js +0 -1
  663. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d07a2c023f1aef1e.js +0 -1
  664. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d07a2c023f1aef1e.js +0 -1
  665. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d07a2c023f1aef1e.js +0 -1
  666. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d07a2c023f1aef1e.js +0 -1
  667. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d07a2c023f1aef1e.js +0 -1
  668. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d07a2c023f1aef1e.js +0 -1
  669. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d07a2c023f1aef1e.js +0 -1
  670. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d07a2c023f1aef1e.js +0 -1
  671. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d07a2c023f1aef1e.js +0 -1
  672. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d07a2c023f1aef1e.js +0 -1
  673. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d07a2c023f1aef1e.js +0 -1
  674. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d07a2c023f1aef1e.js +0 -1
  675. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  676. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d07a2c023f1aef1e.js +0 -1
  677. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d07a2c023f1aef1e.js +0 -1
  678. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d07a2c023f1aef1e.js +0 -1
  679. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d07a2c023f1aef1e.js +0 -1
  680. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  681. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  682. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d07a2c023f1aef1e.js +0 -1
  683. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d07a2c023f1aef1e.js +0 -1
  684. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  685. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d07a2c023f1aef1e.js +0 -1
  686. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d07a2c023f1aef1e.js +0 -1
  687. package/dist/web/standalone/.next/static/css/123c0bb039697968.css +0 -1
  688. package/src/resources/extensions/gsd/auto-observability.ts +0 -74
  689. package/src/resources/extensions/gsd/observability-validator.ts +0 -456
  690. package/src/resources/extensions/gsd/roadmap-mutations.ts +0 -134
  691. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +0 -174
  692. package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +0 -474
  693. /package/dist/web/standalone/.next/static/{VvclDCW6TAWjEyLU-EYL1 → alS4hoANx0TK4UVZY27da}/_ssgManifest.js +0 -0
@@ -1,5 +1,5 @@
1
1
  // GSD Extension — State Derivation
2
- // Reads roadmap + plan files to determine current position.
2
+ // DB-primary state derivation with filesystem fallback for unmigrated projects.
3
3
  // Pure TypeScript, zero Pi dependencies.
4
4
 
5
5
  import type {
@@ -14,6 +14,9 @@ import type {
14
14
  import {
15
15
  parseRoadmap,
16
16
  parsePlan,
17
+ } from './parsers-legacy.js';
18
+
19
+ import {
17
20
  parseSummary,
18
21
  loadFile,
19
22
  parseRequirementCounts,
@@ -38,6 +41,18 @@ import { join, resolve } from 'path';
38
41
  import { existsSync, readdirSync } from 'node:fs';
39
42
  import { debugCount, debugTime } from './debug-logger.js';
40
43
 
44
+ import {
45
+ isDbAvailable,
46
+ getAllMilestones,
47
+ getMilestoneSlices,
48
+ getSliceTasks,
49
+ getReplanHistory,
50
+ getSlice,
51
+ type MilestoneRow,
52
+ type SliceRow,
53
+ type TaskRow,
54
+ } from './gsd-db.js';
55
+
41
56
  /**
42
57
  * A "ghost" milestone directory contains only META.json (and no substantive
43
58
  * files like CONTEXT, CONTEXT-DRAFT, ROADMAP, or SUMMARY). These appear when
@@ -114,36 +129,45 @@ export function invalidateStateCache(): void {
114
129
  * Returns the ID of the first incomplete milestone, or null if all are complete.
115
130
  */
116
131
  export async function getActiveMilestoneId(basePath: string): Promise<string | null> {
117
- const milestoneIds = findMilestoneIds(basePath);
118
132
  // Parallel worker isolation
119
133
  const milestoneLock = process.env.GSD_MILESTONE_LOCK;
120
134
  if (milestoneLock) {
135
+ const milestoneIds = findMilestoneIds(basePath);
121
136
  if (!milestoneIds.includes(milestoneLock)) return null;
122
- // Locked milestone that is parked should not be active
123
137
  const lockedParked = resolveMilestoneFile(basePath, milestoneLock, "PARKED");
124
138
  if (lockedParked) return null;
125
139
  return milestoneLock;
126
140
  }
141
+
142
+ // DB-first: query milestones table for the first non-complete, non-parked milestone
143
+ if (isDbAvailable()) {
144
+ const allMilestones = getAllMilestones();
145
+ if (allMilestones.length > 0) {
146
+ const sorted = [...allMilestones].sort((a, b) => a.id.localeCompare(b.id));
147
+ for (const m of sorted) {
148
+ if (m.status === "complete" || m.status === "done" || m.status === "parked") continue;
149
+ return m.id;
150
+ }
151
+ return null;
152
+ }
153
+ }
154
+
155
+ // Filesystem fallback for unmigrated projects or empty DB
156
+ const milestoneIds = findMilestoneIds(basePath);
127
157
  for (const mid of milestoneIds) {
128
- // Skip parked milestones — they are not eligible for active status
129
158
  const parkedFile = resolveMilestoneFile(basePath, mid, "PARKED");
130
159
  if (parkedFile) continue;
131
160
 
132
161
  const roadmapFile = resolveMilestoneFile(basePath, mid, "ROADMAP");
133
162
  const content = roadmapFile ? await loadFile(roadmapFile) : null;
134
163
  if (!content) {
135
- // No roadmap — but if a summary exists, the milestone is already complete
136
164
  const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
137
- if (summaryFile) continue; // completed milestone, skip
138
- if (isGhostMilestone(basePath, mid)) continue; // ghost dir — skip
139
- return mid; // No roadmap and no summary — milestone is incomplete
140
- // Note: draft-awareness (CONTEXT-DRAFT.md) is handled in deriveState(), not here.
141
- // A draft milestone is still "active" — this function only determines which milestone is current.
165
+ if (summaryFile) continue;
166
+ if (isGhostMilestone(basePath, mid)) continue;
167
+ return mid;
142
168
  }
143
169
  const roadmap = parseRoadmap(content);
144
170
  if (!isMilestoneComplete(roadmap)) {
145
- // Summary is the terminal artifact — if it exists, the milestone is
146
- // complete even when roadmap checkboxes weren't ticked (#864).
147
171
  const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
148
172
  if (!summaryFile) return mid;
149
173
  }
@@ -152,13 +176,12 @@ export async function getActiveMilestoneId(basePath: string): Promise<string | n
152
176
  }
153
177
 
154
178
  /**
155
- * Reconstruct GSD state from files on disk.
156
- * This is the source of truth — STATE.md is just a cache of this output.
179
+ * Reconstruct GSD state from DB (primary) or filesystem (fallback).
180
+ * STATE.md is a rendered cache of this output.
157
181
  *
158
- * Uses native batch parsing when available: a single Rust call reads and parses
159
- * every .md file under .gsd/, populating an in-memory cache that replaces all
160
- * individual loadFile() calls during milestone/slice/task traversal.
161
- * Falls back to sequential JS file reads when the native module is absent.
182
+ * When DB is available, queries milestone/slice/task tables directly.
183
+ * Falls back to filesystem parsing for unmigrated projects or when DB
184
+ * has zero milestones (e.g. first run before migration).
162
185
  */
163
186
  export async function deriveState(basePath: string): Promise<GSDState> {
164
187
  // Return cached result if within the TTL window for the same basePath
@@ -171,7 +194,23 @@ export async function deriveState(basePath: string): Promise<GSDState> {
171
194
  }
172
195
 
173
196
  const stopTimer = debugTime("derive-state-impl");
174
- const result = await _deriveStateImpl(basePath);
197
+ let result: GSDState;
198
+
199
+ // Dual-path: try DB-backed derivation first when hierarchy tables are populated
200
+ if (isDbAvailable()) {
201
+ const dbMilestones = getAllMilestones();
202
+ if (dbMilestones.length > 0) {
203
+ const stopDbTimer = debugTime("derive-state-db");
204
+ result = await deriveStateFromDb(basePath);
205
+ stopDbTimer({ phase: result.phase, milestone: result.activeMilestone?.id });
206
+ } else {
207
+ // DB open but empty hierarchy tables — pre-migration project, use filesystem
208
+ result = await _deriveStateImpl(basePath);
209
+ }
210
+ } else {
211
+ result = await _deriveStateImpl(basePath);
212
+ }
213
+
175
214
  stopTimer({ phase: result.phase, milestone: result.activeMilestone?.id });
176
215
  debugCount("deriveStateCalls");
177
216
  _stateCache = { basePath, result, timestamp: Date.now() };
@@ -182,15 +221,497 @@ export async function deriveState(basePath: string): Promise<GSDState> {
182
221
  * Extract milestone title from CONTEXT.md or CONTEXT-DRAFT.md heading.
183
222
  * Falls back to the provided fallback (usually the milestone ID).
184
223
  */
224
+ /**
225
+ * Strip the "M001: " prefix from a milestone title to get the human-readable name.
226
+ * Used by both DB and filesystem paths for consistency.
227
+ */
228
+ function stripMilestonePrefix(title: string): string {
229
+ return title.replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, '') || title;
230
+ }
231
+
185
232
  function extractContextTitle(content: string | null, fallback: string): string {
186
233
  if (!content) return fallback;
187
234
  const h1 = content.split('\n').find(line => line.startsWith('# '));
188
235
  if (!h1) return fallback;
189
236
  // Extract title from "# M005: Platform Foundation & Separation" format
190
- return h1.slice(2).trim().replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, '') || fallback;
237
+ return stripMilestonePrefix(h1.slice(2).trim()) || fallback;
238
+ }
239
+
240
+ // ─── DB-backed State Derivation ────────────────────────────────────────────
241
+
242
+ /**
243
+ * Helper: check if a DB status counts as "done" (handles K002 ambiguity).
244
+ */
245
+ function isStatusDone(status: string): boolean {
246
+ return status === 'complete' || status === 'done';
247
+ }
248
+
249
+ /**
250
+ * Derive GSD state from the milestones/slices/tasks DB tables.
251
+ * Flag files (PARKED, VALIDATION, CONTINUE, REPLAN, REPLAN-TRIGGER, CONTEXT-DRAFT)
252
+ * are still checked on the filesystem since they aren't in DB tables.
253
+ * Requirements also stay file-based via parseRequirementCounts().
254
+ *
255
+ * Must produce field-identical GSDState to _deriveStateImpl() for the same project.
256
+ */
257
+ export async function deriveStateFromDb(basePath: string): Promise<GSDState> {
258
+ const requirements = parseRequirementCounts(await loadFile(resolveGsdRootFile(basePath, "REQUIREMENTS")));
259
+
260
+ const allMilestones = getAllMilestones();
261
+
262
+ // Parallel worker isolation: when locked, filter to just the locked milestone
263
+ const milestoneLock = process.env.GSD_MILESTONE_LOCK;
264
+ const milestones = milestoneLock
265
+ ? allMilestones.filter(m => m.id === milestoneLock)
266
+ : allMilestones;
267
+
268
+ if (milestones.length === 0) {
269
+ return {
270
+ activeMilestone: null,
271
+ activeSlice: null,
272
+ activeTask: null,
273
+ phase: 'pre-planning',
274
+ recentDecisions: [],
275
+ blockers: [],
276
+ nextAction: 'No milestones found. Run /gsd to create one.',
277
+ registry: [],
278
+ requirements,
279
+ progress: { milestones: { done: 0, total: 0 } },
280
+ };
281
+ }
282
+
283
+ // Phase 1: Build completeness set (which milestones count as "done" for dep resolution)
284
+ const completeMilestoneIds = new Set<string>();
285
+ const parkedMilestoneIds = new Set<string>();
286
+
287
+ for (const m of milestones) {
288
+ // Check disk for PARKED flag (not stored in DB status reliably — disk is truth for flag files)
289
+ const parkedFile = resolveMilestoneFile(basePath, m.id, "PARKED");
290
+ if (parkedFile || m.status === 'parked') {
291
+ parkedMilestoneIds.add(m.id);
292
+ continue;
293
+ }
294
+
295
+ if (isStatusDone(m.status)) {
296
+ completeMilestoneIds.add(m.id);
297
+ continue;
298
+ }
299
+
300
+ // Check if milestone has a summary on disk (terminal artifact per #864)
301
+ const summaryFile = resolveMilestoneFile(basePath, m.id, "SUMMARY");
302
+ if (summaryFile) {
303
+ completeMilestoneIds.add(m.id);
304
+ continue;
305
+ }
306
+
307
+ // Check roadmap: all slices done means milestone is complete
308
+ const slices = getMilestoneSlices(m.id);
309
+ if (slices.length > 0 && slices.every(s => isStatusDone(s.status))) {
310
+ // All slices done but no summary — still counts as complete for dep resolution
311
+ // if a summary file exists
312
+ // Note: without summary file, the milestone is in validating/completing state, not complete
313
+ }
314
+ }
315
+
316
+ // Phase 2: Build registry and find active milestone
317
+ const registry: MilestoneRegistryEntry[] = [];
318
+ let activeMilestone: ActiveRef | null = null;
319
+ let activeMilestoneSlices: SliceRow[] = [];
320
+ let activeMilestoneFound = false;
321
+ let activeMilestoneHasDraft = false;
322
+
323
+ for (const m of milestones) {
324
+ if (parkedMilestoneIds.has(m.id)) {
325
+ registry.push({ id: m.id, title: stripMilestonePrefix(m.title) || m.id, status: 'parked' });
326
+ continue;
327
+ }
328
+
329
+ // Ghost milestone check: no slices in DB AND no substantive files on disk
330
+ const slices = getMilestoneSlices(m.id);
331
+ if (slices.length === 0 && !isStatusDone(m.status)) {
332
+ // Check disk for ghost detection
333
+ if (isGhostMilestone(basePath, m.id)) continue;
334
+ }
335
+
336
+ const summaryFile = resolveMilestoneFile(basePath, m.id, "SUMMARY");
337
+
338
+ // Determine if this milestone is complete
339
+ if (completeMilestoneIds.has(m.id) || (summaryFile !== null)) {
340
+ // Get title from DB or summary
341
+ let title = stripMilestonePrefix(m.title) || m.id;
342
+ if (summaryFile && !m.title) {
343
+ const summaryContent = await loadFile(summaryFile);
344
+ if (summaryContent) {
345
+ title = parseSummary(summaryContent).title || m.id;
346
+ }
347
+ }
348
+ registry.push({ id: m.id, title, status: 'complete' });
349
+ completeMilestoneIds.add(m.id); // ensure it's in the set
350
+ continue;
351
+ }
352
+
353
+ // Not complete — determine if it should be active
354
+ const allSlicesDone = slices.length > 0 && slices.every(s => isStatusDone(s.status));
355
+
356
+ // Get title — prefer DB, fall back to context file extraction
357
+ let title = stripMilestonePrefix(m.title) || m.id;
358
+ if (title === m.id) {
359
+ const contextFile = resolveMilestoneFile(basePath, m.id, "CONTEXT");
360
+ const draftFile = resolveMilestoneFile(basePath, m.id, "CONTEXT-DRAFT");
361
+ const contextContent = contextFile ? await loadFile(contextFile) : null;
362
+ const draftContent = draftFile && !contextContent ? await loadFile(draftFile) : null;
363
+ title = extractContextTitle(contextContent || draftContent, m.id);
364
+ }
365
+
366
+ if (!activeMilestoneFound) {
367
+ // Check milestone-level dependencies
368
+ const deps = m.depends_on;
369
+ const depsUnmet = deps.some(dep => !completeMilestoneIds.has(dep));
370
+
371
+ if (depsUnmet) {
372
+ registry.push({ id: m.id, title, status: 'pending', dependsOn: deps });
373
+ continue;
374
+ }
375
+
376
+ // Handle all-slices-done case (validating/completing)
377
+ if (allSlicesDone) {
378
+ const validationFile = resolveMilestoneFile(basePath, m.id, "VALIDATION");
379
+ const validationContent = validationFile ? await loadFile(validationFile) : null;
380
+ const validationTerminal = validationContent ? isValidationTerminal(validationContent) : false;
381
+
382
+ if (!validationTerminal || (validationTerminal && !summaryFile)) {
383
+ // Validating or completing — still active
384
+ activeMilestone = { id: m.id, title };
385
+ activeMilestoneSlices = slices;
386
+ activeMilestoneFound = true;
387
+ registry.push({ id: m.id, title, status: 'active', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
388
+ continue;
389
+ }
390
+ }
391
+
392
+ // Check for context draft (needs-discussion phase)
393
+ const contextFile = resolveMilestoneFile(basePath, m.id, "CONTEXT");
394
+ const draftFile = resolveMilestoneFile(basePath, m.id, "CONTEXT-DRAFT");
395
+ if (!contextFile && draftFile) activeMilestoneHasDraft = true;
396
+
397
+ activeMilestone = { id: m.id, title };
398
+ activeMilestoneSlices = slices;
399
+ activeMilestoneFound = true;
400
+ registry.push({ id: m.id, title, status: 'active', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
401
+ } else {
402
+ // After active milestone found — rest are pending
403
+ const deps = m.depends_on;
404
+ registry.push({ id: m.id, title, status: 'pending', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
405
+ }
406
+ }
407
+
408
+ const milestoneProgress = {
409
+ done: registry.filter(e => e.status === 'complete').length,
410
+ total: registry.length,
411
+ };
412
+
413
+ // ── No active milestone ──────────────────────────────────────────────
414
+ if (!activeMilestone) {
415
+ const pendingEntries = registry.filter(e => e.status === 'pending');
416
+ const parkedEntries = registry.filter(e => e.status === 'parked');
417
+
418
+ if (pendingEntries.length > 0) {
419
+ const blockerDetails = pendingEntries
420
+ .filter(e => e.dependsOn && e.dependsOn.length > 0)
421
+ .map(e => `${e.id} is waiting on unmet deps: ${e.dependsOn!.join(', ')}`);
422
+ return {
423
+ activeMilestone: null, activeSlice: null, activeTask: null,
424
+ phase: 'blocked',
425
+ recentDecisions: [], blockers: blockerDetails.length > 0
426
+ ? blockerDetails
427
+ : ['All remaining milestones are dep-blocked but no deps listed — check CONTEXT.md files'],
428
+ nextAction: 'Resolve milestone dependencies before proceeding.',
429
+ registry, requirements,
430
+ progress: { milestones: milestoneProgress },
431
+ };
432
+ }
433
+
434
+ if (parkedEntries.length > 0) {
435
+ const parkedIds = parkedEntries.map(e => e.id).join(', ');
436
+ return {
437
+ activeMilestone: null, activeSlice: null, activeTask: null,
438
+ phase: 'pre-planning',
439
+ recentDecisions: [], blockers: [],
440
+ nextAction: `All remaining milestones are parked (${parkedIds}). Run /gsd unpark <id> or create a new milestone.`,
441
+ registry, requirements,
442
+ progress: { milestones: milestoneProgress },
443
+ };
444
+ }
445
+
446
+ if (registry.length === 0) {
447
+ return {
448
+ activeMilestone: null, activeSlice: null, activeTask: null,
449
+ phase: 'pre-planning',
450
+ recentDecisions: [], blockers: [],
451
+ nextAction: 'No milestones found. Run /gsd to create one.',
452
+ registry: [], requirements,
453
+ progress: { milestones: { done: 0, total: 0 } },
454
+ };
455
+ }
456
+
457
+ // All milestones complete
458
+ const lastEntry = registry[registry.length - 1];
459
+ const activeReqs = requirements.active ?? 0;
460
+ const completionNote = activeReqs > 0
461
+ ? `All milestones complete. ${activeReqs} active requirement${activeReqs === 1 ? '' : 's'} in REQUIREMENTS.md ${activeReqs === 1 ? 'has' : 'have'} not been mapped to a milestone.`
462
+ : 'All milestones complete.';
463
+ return {
464
+ activeMilestone: lastEntry ? { id: lastEntry.id, title: lastEntry.title } : null,
465
+ activeSlice: null, activeTask: null,
466
+ phase: 'complete',
467
+ recentDecisions: [], blockers: [],
468
+ nextAction: completionNote,
469
+ registry, requirements,
470
+ progress: { milestones: milestoneProgress },
471
+ };
472
+ }
473
+
474
+ // ── Active milestone has no slices or no roadmap ────────────────────
475
+ const hasRoadmap = resolveMilestoneFile(basePath, activeMilestone.id, "ROADMAP") !== null;
476
+
477
+ if (activeMilestoneSlices.length === 0) {
478
+ if (!hasRoadmap) {
479
+ const phase = activeMilestoneHasDraft ? 'needs-discussion' as const : 'pre-planning' as const;
480
+ const nextAction = activeMilestoneHasDraft
481
+ ? `Discuss draft context for milestone ${activeMilestone.id}.`
482
+ : `Plan milestone ${activeMilestone.id}.`;
483
+ return {
484
+ activeMilestone, activeSlice: null, activeTask: null,
485
+ phase, recentDecisions: [], blockers: [],
486
+ nextAction, registry, requirements,
487
+ progress: { milestones: milestoneProgress },
488
+ };
489
+ }
490
+
491
+ // Has roadmap file but zero slices in DB — pre-planning (zero-slice roadmap guard)
492
+ return {
493
+ activeMilestone, activeSlice: null, activeTask: null,
494
+ phase: 'pre-planning',
495
+ recentDecisions: [], blockers: [],
496
+ nextAction: `Milestone ${activeMilestone.id} has a roadmap but no slices defined. Add slices to the roadmap.`,
497
+ registry, requirements,
498
+ progress: {
499
+ milestones: milestoneProgress,
500
+ slices: { done: 0, total: 0 },
501
+ },
502
+ };
503
+ }
504
+
505
+ // ── All slices done → validating/completing ─────────────────────────
506
+ const allSlicesDone = activeMilestoneSlices.every(s => isStatusDone(s.status));
507
+ if (allSlicesDone) {
508
+ const validationFile = resolveMilestoneFile(basePath, activeMilestone.id, "VALIDATION");
509
+ const validationContent = validationFile ? await loadFile(validationFile) : null;
510
+ const validationTerminal = validationContent ? isValidationTerminal(validationContent) : false;
511
+ const sliceProgress = {
512
+ done: activeMilestoneSlices.length,
513
+ total: activeMilestoneSlices.length,
514
+ };
515
+
516
+ if (!validationTerminal) {
517
+ return {
518
+ activeMilestone, activeSlice: null, activeTask: null,
519
+ phase: 'validating-milestone',
520
+ recentDecisions: [], blockers: [],
521
+ nextAction: `Validate milestone ${activeMilestone.id} before completion.`,
522
+ registry, requirements,
523
+ progress: { milestones: milestoneProgress, slices: sliceProgress },
524
+ };
525
+ }
526
+
527
+ return {
528
+ activeMilestone, activeSlice: null, activeTask: null,
529
+ phase: 'completing-milestone',
530
+ recentDecisions: [], blockers: [],
531
+ nextAction: `All slices complete in ${activeMilestone.id}. Write milestone summary.`,
532
+ registry, requirements,
533
+ progress: { milestones: milestoneProgress, slices: sliceProgress },
534
+ };
535
+ }
536
+
537
+ // ── Find active slice (first incomplete with deps satisfied) ─────────
538
+ const sliceProgress = {
539
+ done: activeMilestoneSlices.filter(s => isStatusDone(s.status)).length,
540
+ total: activeMilestoneSlices.length,
541
+ };
542
+
543
+ const doneSliceIds = new Set(
544
+ activeMilestoneSlices.filter(s => isStatusDone(s.status)).map(s => s.id)
545
+ );
546
+
547
+ let activeSlice: ActiveRef | null = null;
548
+ let activeSliceRow: SliceRow | null = null;
549
+
550
+ for (const s of activeMilestoneSlices) {
551
+ if (isStatusDone(s.status)) continue;
552
+ if (s.depends.every(dep => doneSliceIds.has(dep))) {
553
+ activeSlice = { id: s.id, title: s.title };
554
+ activeSliceRow = s;
555
+ break;
556
+ }
557
+ }
558
+
559
+ if (!activeSlice) {
560
+ return {
561
+ activeMilestone, activeSlice: null, activeTask: null,
562
+ phase: 'blocked',
563
+ recentDecisions: [], blockers: ['No slice eligible — check dependency ordering'],
564
+ nextAction: 'Resolve dependency blockers or plan next slice.',
565
+ registry, requirements,
566
+ progress: { milestones: milestoneProgress, slices: sliceProgress },
567
+ };
568
+ }
569
+
570
+ // ── Check for slice plan file on disk ────────────────────────────────
571
+ const planFile = resolveSliceFile(basePath, activeMilestone.id, activeSlice.id, "PLAN");
572
+ if (!planFile) {
573
+ return {
574
+ activeMilestone, activeSlice, activeTask: null,
575
+ phase: 'planning',
576
+ recentDecisions: [], blockers: [],
577
+ nextAction: `Plan slice ${activeSlice.id} (${activeSlice.title}).`,
578
+ registry, requirements,
579
+ progress: { milestones: milestoneProgress, slices: sliceProgress },
580
+ };
581
+ }
582
+
583
+ // ── Get tasks from DB ────────────────────────────────────────────────
584
+ const tasks = getSliceTasks(activeMilestone.id, activeSlice.id);
585
+ const taskProgress = {
586
+ done: tasks.filter(t => isStatusDone(t.status)).length,
587
+ total: tasks.length,
588
+ };
589
+
590
+ const activeTaskRow = tasks.find(t => !isStatusDone(t.status));
591
+
592
+ if (!activeTaskRow && tasks.length > 0) {
593
+ // All tasks done but slice not marked complete → summarizing
594
+ return {
595
+ activeMilestone, activeSlice, activeTask: null,
596
+ phase: 'summarizing',
597
+ recentDecisions: [], blockers: [],
598
+ nextAction: `All tasks done in ${activeSlice.id}. Write slice summary and complete slice.`,
599
+ registry, requirements,
600
+ progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
601
+ };
602
+ }
603
+
604
+ // Empty plan — no tasks defined yet
605
+ if (!activeTaskRow) {
606
+ return {
607
+ activeMilestone, activeSlice, activeTask: null,
608
+ phase: 'planning',
609
+ recentDecisions: [], blockers: [],
610
+ nextAction: `Slice ${activeSlice.id} has a plan file but no tasks. Add tasks to the plan.`,
611
+ registry, requirements,
612
+ progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
613
+ };
614
+ }
615
+
616
+ const activeTask: ActiveRef = { id: activeTaskRow.id, title: activeTaskRow.title };
617
+
618
+ // ── Task plan file check (#909) ─────────────────────────────────────
619
+ const tasksDir = resolveTasksDir(basePath, activeMilestone.id, activeSlice.id);
620
+ if (tasksDir && existsSync(tasksDir) && tasks.length > 0) {
621
+ const allFiles = readdirSync(tasksDir).filter(f => f.endsWith(".md"));
622
+ if (allFiles.length === 0) {
623
+ return {
624
+ activeMilestone, activeSlice, activeTask: null,
625
+ phase: 'planning',
626
+ recentDecisions: [], blockers: [],
627
+ nextAction: `Task plan files missing for ${activeSlice.id}. Run plan-slice to generate task plans.`,
628
+ registry, requirements,
629
+ progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
630
+ };
631
+ }
632
+ }
633
+
634
+ // ── Blocker detection: check completed tasks for blocker_discovered ──
635
+ const completedTasks = tasks.filter(t => isStatusDone(t.status));
636
+ let blockerTaskId: string | null = null;
637
+ for (const ct of completedTasks) {
638
+ if (ct.blocker_discovered) {
639
+ blockerTaskId = ct.id;
640
+ break;
641
+ }
642
+ // Also check disk summary in case DB doesn't have the flag
643
+ const summaryFile = resolveTaskFile(basePath, activeMilestone.id, activeSlice.id, ct.id, "SUMMARY");
644
+ if (!summaryFile) continue;
645
+ const summaryContent = await loadFile(summaryFile);
646
+ if (!summaryContent) continue;
647
+ const summary = parseSummary(summaryContent);
648
+ if (summary.frontmatter.blocker_discovered) {
649
+ blockerTaskId = ct.id;
650
+ break;
651
+ }
652
+ }
653
+
654
+ if (blockerTaskId) {
655
+ // Loop protection: if replan_history has entries for this slice, a replan
656
+ // was already performed — don't re-enter replanning phase.
657
+ const replanHistory = getReplanHistory(activeMilestone.id, activeSlice.id);
658
+ if (replanHistory.length === 0) {
659
+ return {
660
+ activeMilestone, activeSlice, activeTask,
661
+ phase: 'replanning-slice',
662
+ recentDecisions: [],
663
+ blockers: [`Task ${blockerTaskId} discovered a blocker requiring slice replan`],
664
+ nextAction: `Task ${blockerTaskId} reported blocker_discovered. Replan slice ${activeSlice.id} before continuing.`,
665
+ activeWorkspace: undefined,
666
+ registry, requirements,
667
+ progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
668
+ };
669
+ }
670
+ }
671
+
672
+ // ── REPLAN-TRIGGER detection ─────────────────────────────────────────
673
+ if (!blockerTaskId) {
674
+ const sliceRow = getSlice(activeMilestone.id, activeSlice.id);
675
+ if (sliceRow?.replan_triggered_at) {
676
+ // Loop protection: if replan_history has entries, replan was already done
677
+ const replanHistory = getReplanHistory(activeMilestone.id, activeSlice.id);
678
+ if (replanHistory.length === 0) {
679
+ return {
680
+ activeMilestone, activeSlice, activeTask,
681
+ phase: 'replanning-slice',
682
+ recentDecisions: [],
683
+ blockers: ['Triage replan trigger detected — slice replan required'],
684
+ nextAction: `Triage replan triggered for slice ${activeSlice.id}. Replan before continuing.`,
685
+ activeWorkspace: undefined,
686
+ registry, requirements,
687
+ progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
688
+ };
689
+ }
690
+ }
691
+ }
692
+
693
+ // ── Check for interrupted work ───────────────────────────────────────
694
+ const sDir = resolveSlicePath(basePath, activeMilestone.id, activeSlice.id);
695
+ const continueFile = sDir ? resolveSliceFile(basePath, activeMilestone.id, activeSlice.id, "CONTINUE") : null;
696
+ const hasInterrupted = !!(continueFile && await loadFile(continueFile)) ||
697
+ !!(sDir && await loadFile(join(sDir, "continue.md")));
698
+
699
+ return {
700
+ activeMilestone, activeSlice, activeTask,
701
+ phase: 'executing',
702
+ recentDecisions: [], blockers: [],
703
+ nextAction: hasInterrupted
704
+ ? `Resume interrupted work on ${activeTask.id}: ${activeTask.title} in slice ${activeSlice.id}. Read continue.md first.`
705
+ : `Execute ${activeTask.id}: ${activeTask.title} in slice ${activeSlice.id}.`,
706
+ registry, requirements,
707
+ progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
708
+ };
191
709
  }
192
710
 
193
- async function _deriveStateImpl(basePath: string): Promise<GSDState> {
711
+ // LEGACY: Filesystem-based state derivation for unmigrated projects.
712
+ // DB-backed projects use deriveStateFromDb() above. Target: extract to
713
+ // state-legacy.ts when all projects are DB-backed.
714
+ export async function _deriveStateImpl(basePath: string): Promise<GSDState> {
194
715
  const milestoneIds = findMilestoneIds(basePath);
195
716
 
196
717
  // ── Parallel worker isolation ──────────────────────────────────────────
@@ -212,12 +733,9 @@ async function _deriveStateImpl(basePath: string): Promise<GSDState> {
212
733
  const fileContentCache = new Map<string, string>();
213
734
  const gsdDir = gsdRoot(basePath);
214
735
 
215
- // NOTE: We intentionally do NOT load from the SQLite DB here (#759).
216
- // The DB's artifacts table is populated once during migrateFromMarkdown
217
- // and is never updated when files change on disk (e.g. roadmap [x] updates,
218
- // plan checkbox changes). Using stale DB content causes deriveState to
219
- // return incorrect phase/slice state, leading to infinite skip loops.
220
- // The native Rust batch parser is fast enough for state derivation.
736
+ // Filesystem fallback: used when deriveStateFromDb() is not available
737
+ // (pre-migration projects). The DB-backed path is preferred when available
738
+ // see deriveStateFromDb() above.
221
739
  const batchFiles = nativeBatchParseGsdFiles(gsdDir);
222
740
  if (batchFiles) {
223
741
  for (const f of batchFiles) {
@@ -313,7 +831,7 @@ async function _deriveStateImpl(basePath: string): Promise<GSDState> {
313
831
  if (parkedMilestoneIds.has(mid)) {
314
832
  const roadmap = roadmapCache.get(mid) ?? null;
315
833
  const title = roadmap
316
- ? roadmap.title.replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, '')
834
+ ? stripMilestonePrefix(roadmap.title)
317
835
  : mid;
318
836
  registry.push({ id: mid, title, status: 'parked' });
319
837
  continue;
@@ -374,7 +892,7 @@ async function _deriveStateImpl(basePath: string): Promise<GSDState> {
374
892
  continue;
375
893
  }
376
894
 
377
- const title = roadmap.title.replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, '');
895
+ const title = stripMilestonePrefix(roadmap.title);
378
896
  const complete = isMilestoneComplete(roadmap);
379
897
 
380
898
  if (complete) {