gsd-pi 2.38.0-dev.eeb3520 → 2.39.0-dev.20aba06

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 (346) hide show
  1. package/README.md +15 -11
  2. package/dist/app-paths.js +1 -1
  3. package/dist/cli.js +9 -0
  4. package/dist/extension-discovery.d.ts +5 -3
  5. package/dist/extension-discovery.js +14 -9
  6. package/dist/extension-registry.js +2 -2
  7. package/dist/remote-questions-config.js +2 -2
  8. package/dist/resource-loader.js +100 -3
  9. package/dist/resources/extensions/async-jobs/index.js +10 -0
  10. package/dist/resources/extensions/browser-tools/index.js +3 -1
  11. package/dist/resources/extensions/browser-tools/package.json +3 -1
  12. package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
  13. package/dist/resources/extensions/cmux/index.js +55 -1
  14. package/dist/resources/extensions/context7/package.json +1 -1
  15. package/dist/resources/extensions/get-secrets-from-user.js +5 -24
  16. package/dist/resources/extensions/github-sync/cli.js +284 -0
  17. package/dist/resources/extensions/github-sync/index.js +73 -0
  18. package/dist/resources/extensions/github-sync/mapping.js +67 -0
  19. package/dist/resources/extensions/github-sync/sync.js +424 -0
  20. package/dist/resources/extensions/github-sync/templates.js +118 -0
  21. package/dist/resources/extensions/github-sync/types.js +7 -0
  22. package/dist/resources/extensions/google-search/package.json +3 -1
  23. package/dist/resources/extensions/gsd/auto/session.js +6 -23
  24. package/dist/resources/extensions/gsd/auto-dashboard.js +7 -0
  25. package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
  26. package/dist/resources/extensions/gsd/auto-loop.js +923 -787
  27. package/dist/resources/extensions/gsd/auto-post-unit.js +107 -70
  28. package/dist/resources/extensions/gsd/auto-prompts.js +205 -51
  29. package/dist/resources/extensions/gsd/auto-start.js +19 -3
  30. package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
  31. package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
  32. package/dist/resources/extensions/gsd/auto.js +149 -100
  33. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +126 -0
  34. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +233 -0
  35. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +59 -0
  36. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +38 -0
  37. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +156 -0
  38. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +46 -0
  39. package/dist/resources/extensions/gsd/bootstrap/system-context.js +300 -0
  40. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +38 -0
  41. package/dist/resources/extensions/gsd/captures.js +9 -1
  42. package/dist/resources/extensions/gsd/commands/catalog.js +278 -0
  43. package/dist/resources/extensions/gsd/commands/context.js +84 -0
  44. package/dist/resources/extensions/gsd/commands/dispatcher.js +21 -0
  45. package/dist/resources/extensions/gsd/commands/handlers/auto.js +72 -0
  46. package/dist/resources/extensions/gsd/commands/handlers/core.js +246 -0
  47. package/dist/resources/extensions/gsd/commands/handlers/ops.js +166 -0
  48. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +94 -0
  49. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +102 -0
  50. package/dist/resources/extensions/gsd/commands/index.js +11 -0
  51. package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
  52. package/dist/resources/extensions/gsd/commands-handlers.js +17 -4
  53. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  54. package/dist/resources/extensions/gsd/commands.js +8 -1169
  55. package/dist/resources/extensions/gsd/context-budget.js +2 -10
  56. package/dist/resources/extensions/gsd/dashboard-overlay.js +9 -0
  57. package/dist/resources/extensions/gsd/detection.js +1 -2
  58. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  59. package/dist/resources/extensions/gsd/doctor-checks.js +82 -0
  60. package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
  61. package/dist/resources/extensions/gsd/doctor-format.js +15 -0
  62. package/dist/resources/extensions/gsd/doctor-proactive.js +80 -10
  63. package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
  64. package/dist/resources/extensions/gsd/doctor.js +234 -12
  65. package/dist/resources/extensions/gsd/env-utils.js +29 -0
  66. package/dist/resources/extensions/gsd/exit-command.js +2 -1
  67. package/dist/resources/extensions/gsd/export-html.js +46 -0
  68. package/dist/resources/extensions/gsd/export.js +1 -1
  69. package/dist/resources/extensions/gsd/files.js +48 -9
  70. package/dist/resources/extensions/gsd/forensics.js +1 -1
  71. package/dist/resources/extensions/gsd/git-service.js +30 -12
  72. package/dist/resources/extensions/gsd/gitignore.js +16 -3
  73. package/dist/resources/extensions/gsd/guided-flow.js +149 -38
  74. package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
  75. package/dist/resources/extensions/gsd/health-widget.js +4 -87
  76. package/dist/resources/extensions/gsd/index.js +4 -1111
  77. package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
  78. package/dist/resources/extensions/gsd/migrate-external.js +18 -1
  79. package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
  80. package/dist/resources/extensions/gsd/package.json +1 -1
  81. package/dist/resources/extensions/gsd/paths.js +3 -0
  82. package/dist/resources/extensions/gsd/preferences-models.js +0 -12
  83. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  84. package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
  85. package/dist/resources/extensions/gsd/preferences.js +22 -11
  86. package/dist/resources/extensions/gsd/progress-score.js +20 -1
  87. package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
  88. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  89. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  90. package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
  91. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
  92. package/dist/resources/extensions/gsd/prompts/forensics.md +121 -46
  93. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  94. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  95. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  96. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  97. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  98. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  99. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  100. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  101. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  102. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  103. package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
  104. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  105. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  106. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  107. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  108. package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
  109. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  110. package/dist/resources/extensions/gsd/repo-identity.js +21 -4
  111. package/dist/resources/extensions/gsd/resource-version.js +2 -1
  112. package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
  113. package/dist/resources/extensions/gsd/state.js +42 -23
  114. package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
  115. package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
  116. package/dist/resources/extensions/gsd/visualizer-data.js +27 -2
  117. package/dist/resources/extensions/gsd/visualizer-views.js +52 -0
  118. package/dist/resources/extensions/gsd/worktree.js +35 -16
  119. package/dist/resources/extensions/mcp-client/index.js +14 -1
  120. package/dist/resources/extensions/remote-questions/status.js +4 -1
  121. package/dist/resources/extensions/remote-questions/store.js +4 -1
  122. package/dist/resources/extensions/search-the-web/provider.js +2 -1
  123. package/dist/resources/extensions/shared/frontmatter.js +1 -1
  124. package/dist/resources/extensions/subagent/index.js +12 -3
  125. package/dist/resources/extensions/subagent/isolation.js +2 -1
  126. package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
  127. package/dist/resources/extensions/universal-config/package.json +1 -1
  128. package/dist/welcome-screen.d.ts +13 -0
  129. package/dist/welcome-screen.js +97 -0
  130. package/package.json +1 -1
  131. package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
  132. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
  133. package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
  134. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
  135. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/agent-session.js +107 -24
  137. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
  140. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
  143. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  144. package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts +2 -0
  145. package/packages/pi-coding-agent/dist/core/skill-tool.test.d.ts.map +1 -0
  146. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +70 -0
  147. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -0
  148. package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
  149. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/skills.js +8 -2
  151. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  153. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  154. package/packages/pi-coding-agent/dist/index.js +1 -1
  155. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  156. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +17 -0
  157. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -0
  158. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +244 -0
  159. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -0
  160. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts +3 -0
  161. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -0
  162. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +58 -0
  163. package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -0
  164. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +12 -0
  165. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +54 -0
  167. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts +6 -0
  169. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.d.ts.map +1 -0
  170. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js +63 -0
  171. package/packages/pi-coding-agent/dist/modes/interactive/controllers/model-controller.js.map +1 -0
  172. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +38 -0
  173. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -0
  174. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js +2 -0
  175. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -0
  176. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +15 -457
  179. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  180. package/packages/pi-coding-agent/package.json +1 -1
  181. package/packages/pi-coding-agent/src/core/agent-session.ts +122 -23
  182. package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
  183. package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
  184. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +89 -0
  185. package/packages/pi-coding-agent/src/core/skills.ts +11 -2
  186. package/packages/pi-coding-agent/src/index.ts +1 -0
  187. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +302 -0
  188. package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +59 -0
  189. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +68 -0
  190. package/packages/pi-coding-agent/src/modes/interactive/controllers/model-controller.ts +71 -0
  191. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +37 -0
  192. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +18 -510
  193. package/pkg/package.json +1 -1
  194. package/src/resources/extensions/async-jobs/index.ts +11 -0
  195. package/src/resources/extensions/browser-tools/index.ts +3 -0
  196. package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
  197. package/src/resources/extensions/cmux/index.ts +57 -1
  198. package/src/resources/extensions/get-secrets-from-user.ts +5 -24
  199. package/src/resources/extensions/github-sync/cli.ts +364 -0
  200. package/src/resources/extensions/github-sync/index.ts +93 -0
  201. package/src/resources/extensions/github-sync/mapping.ts +81 -0
  202. package/src/resources/extensions/github-sync/sync.ts +556 -0
  203. package/src/resources/extensions/github-sync/templates.ts +183 -0
  204. package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
  205. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
  206. package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
  207. package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
  208. package/src/resources/extensions/github-sync/types.ts +47 -0
  209. package/src/resources/extensions/gsd/auto/session.ts +7 -25
  210. package/src/resources/extensions/gsd/auto-dashboard.ts +10 -0
  211. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
  212. package/src/resources/extensions/gsd/auto-loop.ts +1285 -1138
  213. package/src/resources/extensions/gsd/auto-post-unit.ts +90 -46
  214. package/src/resources/extensions/gsd/auto-prompts.ts +250 -53
  215. package/src/resources/extensions/gsd/auto-start.ts +24 -3
  216. package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
  217. package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
  218. package/src/resources/extensions/gsd/auto.ts +152 -111
  219. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +142 -0
  220. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +238 -0
  221. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +90 -0
  222. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +46 -0
  223. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +167 -0
  224. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +55 -0
  225. package/src/resources/extensions/gsd/bootstrap/system-context.ts +340 -0
  226. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +51 -0
  227. package/src/resources/extensions/gsd/captures.ts +10 -1
  228. package/src/resources/extensions/gsd/commands/catalog.ts +301 -0
  229. package/src/resources/extensions/gsd/commands/context.ts +101 -0
  230. package/src/resources/extensions/gsd/commands/dispatcher.ts +32 -0
  231. package/src/resources/extensions/gsd/commands/handlers/auto.ts +74 -0
  232. package/src/resources/extensions/gsd/commands/handlers/core.ts +274 -0
  233. package/src/resources/extensions/gsd/commands/handlers/ops.ts +169 -0
  234. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +118 -0
  235. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +109 -0
  236. package/src/resources/extensions/gsd/commands/index.ts +14 -0
  237. package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
  238. package/src/resources/extensions/gsd/commands-handlers.ts +18 -3
  239. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  240. package/src/resources/extensions/gsd/commands.ts +10 -1307
  241. package/src/resources/extensions/gsd/context-budget.ts +2 -12
  242. package/src/resources/extensions/gsd/dashboard-overlay.ts +10 -0
  243. package/src/resources/extensions/gsd/detection.ts +2 -2
  244. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  245. package/src/resources/extensions/gsd/doctor-checks.ts +75 -0
  246. package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
  247. package/src/resources/extensions/gsd/doctor-format.ts +20 -0
  248. package/src/resources/extensions/gsd/doctor-proactive.ts +106 -10
  249. package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
  250. package/src/resources/extensions/gsd/doctor-types.ts +16 -1
  251. package/src/resources/extensions/gsd/doctor.ts +243 -14
  252. package/src/resources/extensions/gsd/env-utils.ts +31 -0
  253. package/src/resources/extensions/gsd/exit-command.ts +2 -2
  254. package/src/resources/extensions/gsd/export-html.ts +51 -0
  255. package/src/resources/extensions/gsd/export.ts +1 -1
  256. package/src/resources/extensions/gsd/files.ts +51 -11
  257. package/src/resources/extensions/gsd/forensics.ts +1 -1
  258. package/src/resources/extensions/gsd/git-service.ts +44 -10
  259. package/src/resources/extensions/gsd/gitignore.ts +17 -3
  260. package/src/resources/extensions/gsd/guided-flow.ts +177 -44
  261. package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
  262. package/src/resources/extensions/gsd/health-widget.ts +4 -89
  263. package/src/resources/extensions/gsd/index.ts +12 -1307
  264. package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
  265. package/src/resources/extensions/gsd/migrate-external.ts +18 -1
  266. package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
  267. package/src/resources/extensions/gsd/paths.ts +4 -0
  268. package/src/resources/extensions/gsd/preferences-models.ts +0 -12
  269. package/src/resources/extensions/gsd/preferences-types.ts +4 -4
  270. package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
  271. package/src/resources/extensions/gsd/preferences.ts +25 -11
  272. package/src/resources/extensions/gsd/progress-score.ts +23 -0
  273. package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
  274. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  275. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  276. package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
  277. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
  278. package/src/resources/extensions/gsd/prompts/forensics.md +121 -46
  279. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  280. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  281. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  282. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  283. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  284. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  285. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  286. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  287. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  288. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  289. package/src/resources/extensions/gsd/prompts/queue.md +4 -8
  290. package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  291. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  292. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  294. package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
  295. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  296. package/src/resources/extensions/gsd/repo-identity.ts +23 -4
  297. package/src/resources/extensions/gsd/resource-version.ts +3 -1
  298. package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
  299. package/src/resources/extensions/gsd/state.ts +39 -21
  300. package/src/resources/extensions/gsd/templates/runtime.md +21 -0
  301. package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
  302. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
  303. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -77
  304. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
  305. package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
  306. package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
  307. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
  308. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +3 -3
  309. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
  310. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
  311. package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
  312. package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
  313. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
  314. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
  315. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
  316. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +16 -16
  317. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
  318. package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
  319. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
  320. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +10 -10
  321. package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
  322. package/src/resources/extensions/gsd/types.ts +18 -1
  323. package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
  324. package/src/resources/extensions/gsd/visualizer-data.ts +52 -2
  325. package/src/resources/extensions/gsd/visualizer-views.ts +58 -0
  326. package/src/resources/extensions/gsd/worktree.ts +35 -15
  327. package/src/resources/extensions/mcp-client/index.ts +17 -1
  328. package/src/resources/extensions/remote-questions/status.ts +5 -1
  329. package/src/resources/extensions/remote-questions/store.ts +5 -1
  330. package/src/resources/extensions/search-the-web/provider.ts +2 -1
  331. package/src/resources/extensions/shared/frontmatter.ts +1 -1
  332. package/src/resources/extensions/subagent/index.ts +12 -3
  333. package/src/resources/extensions/subagent/isolation.ts +3 -1
  334. package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
  335. package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
  336. package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
  337. package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
  338. package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
  339. package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
  340. package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
  341. package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
  342. package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
  343. package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
  344. package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
  345. package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
  346. package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
@@ -24,7 +24,7 @@ import {
24
24
  nativeDetectMainBranch,
25
25
  nativeBranchExists,
26
26
  nativeHasChanges,
27
- nativeAddAll,
27
+ nativeAddAllWithExclusions,
28
28
  nativeResetPaths,
29
29
  nativeHasStagedChanges,
30
30
  nativeCommit,
@@ -95,6 +95,8 @@ export interface TaskCommitContext {
95
95
  oneLiner?: string;
96
96
  /** Files modified by this task (from task summary frontmatter) */
97
97
  keyFiles?: string[];
98
+ /** GitHub issue number — appends "Resolves #N" trailer when set. */
99
+ issueNumber?: number;
98
100
  }
99
101
 
100
102
  /**
@@ -118,12 +120,22 @@ export function buildTaskCommitMessage(ctx: TaskCommitContext): string {
118
120
  const subject = `${type}(${scope}): ${truncated}`;
119
121
 
120
122
  // Build body with key files if available
123
+ const bodyParts: string[] = [];
124
+
121
125
  if (ctx.keyFiles && ctx.keyFiles.length > 0) {
122
126
  const fileLines = ctx.keyFiles
123
127
  .slice(0, 8) // cap at 8 files to keep commit concise
124
128
  .map(f => `- ${f}`)
125
129
  .join("\n");
126
- return `${subject}\n\n${fileLines}`;
130
+ bodyParts.push(fileLines);
131
+ }
132
+
133
+ if (ctx.issueNumber) {
134
+ bodyParts.push(`Resolves #${ctx.issueNumber}`);
135
+ }
136
+
137
+ if (bodyParts.length > 0) {
138
+ return `${subject}\n\n${bodyParts.join("\n\n")}`;
127
139
  }
128
140
 
129
141
  return subject;
@@ -373,7 +385,9 @@ export class GitServiceImpl {
373
385
  this._runtimeFilesCleanedUp = true;
374
386
  }
375
387
 
376
- // Stage everything, then unstage excluded paths.
388
+ // Stage everything using pathspec exclusions so excluded paths are never
389
+ // hashed by git. The old approach of `git add -A` followed by unstaging
390
+ // hangs indefinitely on repos with large untracked artifact trees (#1605).
377
391
  //
378
392
  // Exclude only RUNTIME paths from staging — not the entire .gsd/ directory.
379
393
  // When .gsd/milestones/ files are already tracked in the index (projects
@@ -383,13 +397,9 @@ export class GitServiceImpl {
383
397
  // the second half of a milestone's artifacts are never committed (#1326).
384
398
  //
385
399
  // If .gsd/ IS in .gitignore (the default for external state projects),
386
- // git add -A already skips it and the reset is a harmless no-op.
387
- nativeAddAll(this.basePath);
388
-
389
- const runtimeExclusions = [...RUNTIME_EXCLUSION_PATHS, ...extraExclusions];
390
- for (const exclusion of runtimeExclusions) {
391
- try { nativeResetPaths(this.basePath, [exclusion]); } catch { /* path not staged — ignore */ }
392
- }
400
+ // git add -A already skips it and the exclusions are harmless no-ops.
401
+ const allExclusions = [...RUNTIME_EXCLUSION_PATHS, ...extraExclusions];
402
+ nativeAddAllWithExclusions(this.basePath, allExclusions);
393
403
  }
394
404
 
395
405
  /** Tracks whether runtime file cleanup has run this session. */
@@ -574,6 +584,30 @@ export class GitServiceImpl {
574
584
 
575
585
  }
576
586
 
587
+ // ─── Draft PR Creation ─────────────────────────────────────────────────────
588
+
589
+ /**
590
+ * Create a draft pull request for a completed milestone using `gh pr create`.
591
+ * Returns the PR URL on success, or null on failure.
592
+ * Non-fatal: callers should treat failure as best-effort.
593
+ */
594
+ export function createDraftPR(
595
+ basePath: string,
596
+ milestoneId: string,
597
+ title: string,
598
+ body: string,
599
+ ): string | null {
600
+ try {
601
+ const result = execSync(
602
+ `gh pr create --draft --title ${JSON.stringify(title)} --body ${JSON.stringify(body)}`,
603
+ { cwd: basePath, encoding: "utf8", timeout: 30000, env: GIT_NO_PROMPT_ENV },
604
+ );
605
+ return result.trim();
606
+ } catch {
607
+ return null;
608
+ }
609
+ }
610
+
577
611
  // ─── Factory ───────────────────────────────────────────────────────────────
578
612
 
579
613
  /** Create a GitServiceImpl with the current effective git preferences. */
@@ -7,9 +7,11 @@
7
7
  */
8
8
 
9
9
  import { join } from "node:path";
10
+ import { execFileSync } from "node:child_process";
10
11
  import { existsSync, lstatSync, readFileSync, writeFileSync } from "node:fs";
11
12
  import { nativeRmCached, nativeLsFiles } from "./native-git-bridge.js";
12
13
  import { gsdRoot } from "./paths.js";
14
+ import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
13
15
 
14
16
  /**
15
17
  * GSD runtime patterns for git index cleanup.
@@ -104,10 +106,22 @@ export function hasGitTrackedGsdFiles(basePath: string): boolean {
104
106
  // Check if git tracks any files under .gsd/
105
107
  try {
106
108
  const tracked = nativeLsFiles(basePath, ".gsd");
107
- return tracked.length > 0;
108
- } catch {
109
- // Not a git repo or git not available safe to proceed
109
+ if (tracked.length > 0) return true;
110
+
111
+ // nativeLsFiles swallows git failures and returns []. An empty result
112
+ // could mean "nothing tracked" OR "git failed silently". Verify git is
113
+ // reachable before trusting the empty result — if it isn't, fail safe
114
+ // by assuming files ARE tracked to prevent data loss.
115
+ execFileSync("git", ["rev-parse", "--git-dir"], {
116
+ cwd: basePath,
117
+ stdio: "pipe",
118
+ env: GIT_NO_PROMPT_ENV,
119
+ });
120
+
110
121
  return false;
122
+ } catch {
123
+ // git unavailable, index locked, or repo corrupt — fail safe
124
+ return true;
111
125
  }
112
126
  }
113
127
 
@@ -10,6 +10,7 @@ import type { ExtensionAPI, ExtensionContext, ExtensionCommandContext } from "@g
10
10
  import { showNextAction } from "../shared/mod.js";
11
11
  import { loadFile, parseRoadmap } from "./files.js";
12
12
  import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
13
+ import { buildSkillActivationBlock } from "./auto-prompts.js";
13
14
  import { deriveState } from "./state.js";
14
15
  import { invalidateAllCaches } from "./cache.js";
15
16
  import { startAuto } from "./auto.js";
@@ -34,6 +35,7 @@ import { showConfirm } from "../shared/mod.js";
34
35
  import { debugLog } from "./debug-logger.js";
35
36
  import { findMilestoneIds, nextMilestoneId } from "./milestone-ids.js";
36
37
  import { parkMilestone, discardMilestone } from "./milestone-actions.js";
38
+ import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
37
39
 
38
40
  // ─── Re-exports (preserve public API for existing importers) ────────────────
39
41
  export {
@@ -190,8 +192,40 @@ type UIContext = ExtensionContext;
190
192
  /**
191
193
  * Read GSD-WORKFLOW.md and dispatch it to the LLM with a contextual note.
192
194
  * This is the only way the wizard triggers work — everything else is the LLM's job.
195
+ *
196
+ * When a unitType is provided, resolves the user's model preference for that
197
+ * phase (e.g., models.planning → "plan-milestone") and applies it before
198
+ * dispatching. This ensures guided-flow dispatches respect the same
199
+ * per-phase model preferences that auto-mode uses.
193
200
  */
194
- function dispatchWorkflow(pi: ExtensionAPI, note: string, customType = "gsd-run"): void {
201
+ async function dispatchWorkflow(
202
+ pi: ExtensionAPI,
203
+ note: string,
204
+ customType = "gsd-run",
205
+ ctx?: ExtensionContext,
206
+ unitType?: string,
207
+ ): Promise<void> {
208
+ // Apply model preference for this unit type (if configured)
209
+ if (ctx && unitType) {
210
+ const modelConfig = resolveModelWithFallbacksForUnit(unitType);
211
+ if (modelConfig) {
212
+ const availableModels = ctx.modelRegistry.getAvailable();
213
+ const modelsToTry = [modelConfig.primary, ...modelConfig.fallbacks];
214
+
215
+ for (const modelId of modelsToTry) {
216
+ // Resolve model from available models (same logic as auto-model-selection)
217
+ const model = resolveAvailableModel(modelId, availableModels, ctx.model?.provider);
218
+ if (!model) continue;
219
+
220
+ const ok = await pi.setModel(model, { persist: false });
221
+ if (ok) {
222
+ debugLog("guided-flow-model-applied", { unitType, model: `${model.provider}/${model.id}` });
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ }
228
+
195
229
  const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(process.env.HOME ?? "~", ".gsd", "agent", "GSD-WORKFLOW.md");
196
230
  const workflow = readFileSync(workflowPath, "utf-8");
197
231
 
@@ -205,6 +239,45 @@ function dispatchWorkflow(pi: ExtensionAPI, note: string, customType = "gsd-run"
205
239
  );
206
240
  }
207
241
 
242
+ /**
243
+ * Resolve a model ID string to a model object from available models.
244
+ * Handles "provider/model" and bare ID formats.
245
+ */
246
+ function resolveAvailableModel<T extends { id: string; provider: string }>(
247
+ modelId: string,
248
+ availableModels: T[],
249
+ currentProvider: string | undefined,
250
+ ): T | undefined {
251
+ const slashIdx = modelId.indexOf("/");
252
+
253
+ if (slashIdx !== -1) {
254
+ const maybeProvider = modelId.substring(0, slashIdx);
255
+ const id = modelId.substring(slashIdx + 1);
256
+
257
+ const knownProviders = new Set(availableModels.map(m => m.provider.toLowerCase()));
258
+ if (knownProviders.has(maybeProvider.toLowerCase())) {
259
+ const match = availableModels.find(
260
+ m => m.provider.toLowerCase() === maybeProvider.toLowerCase()
261
+ && m.id.toLowerCase() === id.toLowerCase(),
262
+ );
263
+ if (match) return match;
264
+ }
265
+
266
+ // Try matching the full string as a model ID (OpenRouter-style)
267
+ const lower = modelId.toLowerCase();
268
+ return availableModels.find(
269
+ m => m.id.toLowerCase() === lower
270
+ || `${m.provider}/${m.id}`.toLowerCase() === lower,
271
+ );
272
+ }
273
+
274
+ // Bare ID — prefer current provider, then first available
275
+ const exactProviderMatch = availableModels.find(
276
+ m => m.id === modelId && m.provider === currentProvider,
277
+ );
278
+ return exactProviderMatch ?? availableModels.find(m => m.id === modelId);
279
+ }
280
+
208
281
  /**
209
282
  * Build the discuss-and-plan prompt for a new milestone.
210
283
  * Used by all three "new milestone" paths (first ever, no active, all complete).
@@ -301,8 +374,8 @@ export async function showHeadlessMilestoneCreation(
301
374
  // Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
302
375
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId };
303
376
 
304
- // Dispatch
305
- dispatchWorkflow(pi, prompt);
377
+ // Dispatch — headless milestone creation is a planning activity
378
+ await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "plan-milestone");
306
379
  }
307
380
 
308
381
 
@@ -467,21 +540,21 @@ export async function showDiscuss(
467
540
  ? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
468
541
  : basePrompt;
469
542
  pendingAutoStart = { ctx, pi, basePath, milestoneId: mid, step: false };
470
- dispatchWorkflow(pi, seed, "gsd-discuss");
543
+ await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "plan-milestone");
471
544
  } else if (choice === "discuss_fresh") {
472
545
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
473
546
  const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
474
547
  pendingAutoStart = { ctx, pi, basePath, milestoneId: mid, step: false };
475
- dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
548
+ await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
476
549
  milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
477
550
  commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
478
- }), "gsd-discuss");
551
+ }), "gsd-discuss", ctx, "plan-milestone");
479
552
  } else if (choice === "skip_milestone") {
480
553
  const milestoneIds = findMilestoneIds(basePath);
481
554
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
482
555
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
483
556
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: false };
484
- dispatchWorkflow(pi, buildDiscussPrompt(nextId, `New milestone ${nextId}.`, basePath));
557
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "plan-milestone");
485
558
  }
486
559
  return;
487
560
  }
@@ -580,7 +653,7 @@ export async function showDiscuss(
580
653
  }
581
654
 
582
655
  const prompt = await buildDiscussSlicePrompt(mid, chosen.id, chosen.title, basePath, { rediscuss: isRediscuss });
583
- dispatchWorkflow(pi, prompt, "gsd-discuss");
656
+ await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "plan-slice");
584
657
 
585
658
  // Wait for the discuss session to finish, then loop back to the picker
586
659
  await ctx.waitForIdle();
@@ -722,10 +795,10 @@ async function handleMilestoneActions(
722
795
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
723
796
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
724
797
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
725
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
798
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
726
799
  `New milestone ${nextId}.`,
727
800
  basePath
728
- ));
801
+ ), "gsd-run", ctx, "plan-milestone");
729
802
  return true;
730
803
  }
731
804
 
@@ -866,10 +939,10 @@ export async function showSmartEntry(
866
939
  if (isFirst) {
867
940
  // First ever — skip wizard, just ask directly
868
941
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
869
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
942
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
870
943
  `New project, milestone ${nextId}. Do NOT read or explore .gsd/ — it's empty scaffolding.`,
871
944
  basePath
872
- ));
945
+ ), "gsd-run", ctx, "plan-milestone");
873
946
  } else {
874
947
  const choice = await showNextAction(ctx, {
875
948
  title: "GSD — Get Shit Done",
@@ -887,10 +960,10 @@ export async function showSmartEntry(
887
960
 
888
961
  if (choice === "new_milestone") {
889
962
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
890
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
963
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
891
964
  `New milestone ${nextId}.`,
892
965
  basePath
893
- ));
966
+ ), "gsd-run", ctx, "plan-milestone");
894
967
  }
895
968
  }
896
969
  return;
@@ -926,10 +999,10 @@ export async function showSmartEntry(
926
999
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
927
1000
 
928
1001
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
929
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1002
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
930
1003
  `New milestone ${nextId}.`,
931
1004
  basePath
932
- ));
1005
+ ), "gsd-run", ctx, "plan-milestone");
933
1006
  } else if (choice === "status") {
934
1007
  const { fireStatusViaCommand } = await import("./commands.js");
935
1008
  await fireStatusViaCommand(ctx);
@@ -977,24 +1050,24 @@ export async function showSmartEntry(
977
1050
  ? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
978
1051
  : basePrompt;
979
1052
  pendingAutoStart = { ctx, pi, basePath, milestoneId, step: stepMode };
980
- dispatchWorkflow(pi, seed, "gsd-discuss");
1053
+ await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "plan-milestone");
981
1054
  } else if (choice === "discuss_fresh") {
982
1055
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
983
1056
  const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
984
1057
  pendingAutoStart = { ctx, pi, basePath, milestoneId, step: stepMode };
985
- dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1058
+ await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
986
1059
  milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
987
1060
  commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
988
- }), "gsd-discuss");
1061
+ }), "gsd-discuss", ctx, "plan-milestone");
989
1062
  } else if (choice === "skip_milestone") {
990
1063
  const milestoneIds = findMilestoneIds(basePath);
991
1064
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
992
1065
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
993
1066
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
994
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1067
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
995
1068
  `New milestone ${nextId}.`,
996
1069
  basePath
997
- ));
1070
+ ), "gsd-run", ctx, "plan-milestone");
998
1071
  }
999
1072
  return;
1000
1073
  }
@@ -1051,25 +1124,34 @@ export async function showSmartEntry(
1051
1124
  inlineTemplate("secrets-manifest", "Secrets Manifest"),
1052
1125
  ].join("\n\n---\n\n");
1053
1126
  const secretsOutputPath = relMilestoneFile(basePath, milestoneId, "SECRETS");
1054
- dispatchWorkflow(pi, loadPrompt("guided-plan-milestone", {
1055
- milestoneId, milestoneTitle, secretsOutputPath, inlinedTemplates: planMilestoneTemplates,
1056
- }));
1127
+ await dispatchWorkflow(pi, loadPrompt("guided-plan-milestone", {
1128
+ milestoneId,
1129
+ milestoneTitle,
1130
+ secretsOutputPath,
1131
+ inlinedTemplates: planMilestoneTemplates,
1132
+ skillActivation: buildSkillActivationBlock({
1133
+ base: basePath,
1134
+ milestoneId,
1135
+ milestoneTitle,
1136
+ extraContext: [planMilestoneTemplates],
1137
+ }),
1138
+ }), "gsd-run", ctx, "plan-milestone");
1057
1139
  } else if (choice === "discuss") {
1058
1140
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
1059
1141
  const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
1060
- dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1142
+ await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1061
1143
  milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
1062
1144
  commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
1063
- }));
1145
+ }), "gsd-run", ctx, "plan-milestone");
1064
1146
  } else if (choice === "skip_milestone") {
1065
1147
  const milestoneIds = findMilestoneIds(basePath);
1066
1148
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1067
1149
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
1068
1150
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
1069
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1151
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1070
1152
  `New milestone ${nextId}.`,
1071
1153
  basePath
1072
- ));
1154
+ ), "gsd-run", ctx, "plan-milestone");
1073
1155
  } else if (choice === "discard_milestone") {
1074
1156
  const confirmed = await showConfirm(ctx, {
1075
1157
  title: "Discard milestone?",
@@ -1181,16 +1263,36 @@ export async function showSmartEntry(
1181
1263
  inlineTemplate("plan", "Slice Plan"),
1182
1264
  inlineTemplate("task-plan", "Task Plan"),
1183
1265
  ].join("\n\n---\n\n");
1184
- dispatchWorkflow(pi, loadPrompt("guided-plan-slice", {
1185
- milestoneId, sliceId, sliceTitle, inlinedTemplates: planSliceTemplates,
1186
- }));
1266
+ await dispatchWorkflow(pi, loadPrompt("guided-plan-slice", {
1267
+ milestoneId,
1268
+ sliceId,
1269
+ sliceTitle,
1270
+ inlinedTemplates: planSliceTemplates,
1271
+ skillActivation: buildSkillActivationBlock({
1272
+ base: basePath,
1273
+ milestoneId,
1274
+ sliceId,
1275
+ sliceTitle,
1276
+ extraContext: [planSliceTemplates],
1277
+ }),
1278
+ }), "gsd-run", ctx, "plan-slice");
1187
1279
  } else if (choice === "discuss") {
1188
- dispatchWorkflow(pi, await buildDiscussSlicePrompt(milestoneId, sliceId, sliceTitle, basePath, { rediscuss: hasContext }));
1280
+ await dispatchWorkflow(pi, await buildDiscussSlicePrompt(milestoneId, sliceId, sliceTitle, basePath, { rediscuss: hasContext }), "gsd-run", ctx, "plan-slice");
1189
1281
  } else if (choice === "research") {
1190
1282
  const researchTemplates = inlineTemplate("research", "Research");
1191
- dispatchWorkflow(pi, loadPrompt("guided-research-slice", {
1192
- milestoneId, sliceId, sliceTitle, inlinedTemplates: researchTemplates,
1193
- }));
1283
+ await dispatchWorkflow(pi, loadPrompt("guided-research-slice", {
1284
+ milestoneId,
1285
+ sliceId,
1286
+ sliceTitle,
1287
+ inlinedTemplates: researchTemplates,
1288
+ skillActivation: buildSkillActivationBlock({
1289
+ base: basePath,
1290
+ milestoneId,
1291
+ sliceId,
1292
+ sliceTitle,
1293
+ extraContext: [researchTemplates],
1294
+ }),
1295
+ }), "gsd-run", ctx, "research-slice");
1194
1296
  } else if (choice === "status") {
1195
1297
  const { fireStatusViaCommand } = await import("./commands.js");
1196
1298
  await fireStatusViaCommand(ctx);
@@ -1232,9 +1334,20 @@ export async function showSmartEntry(
1232
1334
  inlineTemplate("slice-summary", "Slice Summary"),
1233
1335
  inlineTemplate("uat", "UAT"),
1234
1336
  ].join("\n\n---\n\n");
1235
- dispatchWorkflow(pi, loadPrompt("guided-complete-slice", {
1236
- workingDirectory: basePath, milestoneId, sliceId, sliceTitle, inlinedTemplates: completeSliceTemplates,
1237
- }));
1337
+ await dispatchWorkflow(pi, loadPrompt("guided-complete-slice", {
1338
+ workingDirectory: basePath,
1339
+ milestoneId,
1340
+ sliceId,
1341
+ sliceTitle,
1342
+ inlinedTemplates: completeSliceTemplates,
1343
+ skillActivation: buildSkillActivationBlock({
1344
+ base: basePath,
1345
+ milestoneId,
1346
+ sliceId,
1347
+ sliceTitle,
1348
+ extraContext: [completeSliceTemplates],
1349
+ }),
1350
+ }), "gsd-run", ctx, "complete-slice");
1238
1351
  } else if (choice === "status") {
1239
1352
  const { fireStatusViaCommand } = await import("./commands.js");
1240
1353
  await fireStatusViaCommand(ctx);
@@ -1297,14 +1410,34 @@ export async function showSmartEntry(
1297
1410
 
1298
1411
  if (choice === "execute") {
1299
1412
  if (hasInterrupted) {
1300
- dispatchWorkflow(pi, loadPrompt("guided-resume-task", {
1301
- milestoneId, sliceId,
1302
- }));
1413
+ await dispatchWorkflow(pi, loadPrompt("guided-resume-task", {
1414
+ milestoneId,
1415
+ sliceId,
1416
+ skillActivation: buildSkillActivationBlock({
1417
+ base: basePath,
1418
+ milestoneId,
1419
+ sliceId,
1420
+ taskId,
1421
+ taskTitle,
1422
+ }),
1423
+ }), "gsd-run", ctx, "execute-task");
1303
1424
  } else {
1304
1425
  const executeTaskTemplates = inlineTemplate("task-summary", "Task Summary");
1305
- dispatchWorkflow(pi, loadPrompt("guided-execute-task", {
1306
- milestoneId, sliceId, taskId, taskTitle, inlinedTemplates: executeTaskTemplates,
1307
- }));
1426
+ await dispatchWorkflow(pi, loadPrompt("guided-execute-task", {
1427
+ milestoneId,
1428
+ sliceId,
1429
+ taskId,
1430
+ taskTitle,
1431
+ inlinedTemplates: executeTaskTemplates,
1432
+ skillActivation: buildSkillActivationBlock({
1433
+ base: basePath,
1434
+ milestoneId,
1435
+ sliceId,
1436
+ taskId,
1437
+ taskTitle,
1438
+ extraContext: [executeTaskTemplates],
1439
+ }),
1440
+ }), "gsd-run", ctx, "execute-task");
1308
1441
  }
1309
1442
  } else if (choice === "status") {
1310
1443
  const { fireStatusViaCommand } = await import("./commands.js");
@@ -5,10 +5,9 @@
5
5
  * runtime integrations so the regressions can be tested directly.
6
6
  */
7
7
 
8
- import { existsSync, readdirSync } from "node:fs";
8
+ import { existsSync } from "node:fs";
9
+ import { detectProjectState } from "./detection.js";
9
10
  import { gsdRoot } from "./paths.js";
10
- import { join } from "node:path";
11
- import type { GSDState, Phase } from "./types.js";
12
11
 
13
12
  export type HealthWidgetProjectState = "none" | "initialized" | "active";
14
13
 
@@ -20,75 +19,19 @@ export interface HealthWidgetData {
20
19
  environmentErrorCount: number;
21
20
  environmentWarningCount: number;
22
21
  lastRefreshed: number;
23
- executionPhase?: Phase;
24
- executionStatus?: string;
25
- executionTarget?: string;
26
- nextAction?: string;
27
- blocker?: string | null;
28
- activeMilestoneId?: string;
29
- activeSliceId?: string;
30
- activeTaskId?: string;
31
- progress?: GSDState["progress"];
32
- eta?: string | null;
33
22
  }
34
23
 
35
24
  export function detectHealthWidgetProjectState(basePath: string): HealthWidgetProjectState {
36
- const root = gsdRoot(basePath);
37
- if (!existsSync(root)) return "none";
25
+ if (!existsSync(gsdRoot(basePath))) return "none";
38
26
 
39
- // Lightweight milestone count avoids the full detectProjectState() scan
40
- // (CI markers, Makefile targets, etc.) that is unnecessary on the 60s refresh.
41
- try {
42
- const milestonesDir = join(root, "milestones");
43
- if (existsSync(milestonesDir)) {
44
- const entries = readdirSync(milestonesDir, { withFileTypes: true });
45
- if (entries.some(e => e.isDirectory())) return "active";
46
- }
47
- } catch { /* non-fatal */ }
48
-
49
- return "initialized";
27
+ const { state } = detectProjectState(basePath);
28
+ return state === "v2-gsd" ? "active" : "initialized";
50
29
  }
51
30
 
52
31
  function formatCost(n: number): string {
53
32
  return n >= 1 ? `$${n.toFixed(2)}` : `${(n * 100).toFixed(1)}¢`;
54
33
  }
55
34
 
56
- function formatProgress(progress?: GSDState["progress"]): string | null {
57
- if (!progress) return null;
58
-
59
- const parts: string[] = [];
60
- parts.push(`M ${progress.milestones.done}/${progress.milestones.total}`);
61
- if (progress.slices) parts.push(`S ${progress.slices.done}/${progress.slices.total}`);
62
- if (progress.tasks) parts.push(`T ${progress.tasks.done}/${progress.tasks.total}`);
63
- return parts.length > 0 ? `Progress: ${parts.join(" · ")}` : null;
64
- }
65
-
66
- function formatEnvironmentSummary(errorCount: number, warningCount: number): string | null {
67
- if (errorCount <= 0 && warningCount <= 0) return null;
68
-
69
- const parts: string[] = [];
70
- if (errorCount > 0) parts.push(`${errorCount} error${errorCount > 1 ? "s" : ""}`);
71
- if (warningCount > 0) parts.push(`${warningCount} warning${warningCount > 1 ? "s" : ""}`);
72
- return `Env: ${parts.join(", ")}`;
73
- }
74
-
75
- function formatBudgetSummary(data: HealthWidgetData): string | null {
76
- if (data.budgetCeiling !== undefined && data.budgetCeiling > 0) {
77
- const pct = Math.min(100, (data.budgetSpent / data.budgetCeiling) * 100);
78
- return `Budget: ${formatCost(data.budgetSpent)}/${formatCost(data.budgetCeiling)} (${pct.toFixed(0)}%)`;
79
- }
80
- if (data.budgetSpent > 0) {
81
- return `Spent: ${formatCost(data.budgetSpent)}`;
82
- }
83
- return null;
84
- }
85
-
86
- function buildExecutionHeadline(data: HealthWidgetData): string {
87
- const status = data.executionStatus ?? "Active project";
88
- const target = data.executionTarget ?? data.blocker ?? "loading status…";
89
- return ` GSD ${status}${target ? ` - ${target}` : ""}`;
90
- }
91
-
92
35
  /**
93
36
  * Build compact health lines for the widget.
94
37
  * Returns a string array suitable for setWidget().
@@ -102,28 +45,33 @@ export function buildHealthLines(data: HealthWidgetData): string[] {
102
45
  return [" GSD Project initialized — run /gsd to continue setup"];
103
46
  }
104
47
 
105
- const lines = [buildExecutionHeadline(data)];
106
- const details: string[] = [];
107
-
108
- const progress = formatProgress(data.progress);
109
- if (progress) details.push(progress);
110
-
111
- if (data.providerIssue) details.push(data.providerIssue);
48
+ const parts: string[] = [];
112
49
 
113
- const environment = formatEnvironmentSummary(
114
- data.environmentErrorCount,
115
- data.environmentWarningCount,
116
- );
117
- if (environment) details.push(environment);
50
+ const totalIssues = data.environmentErrorCount + data.environmentWarningCount + (data.providerIssue ? 1 : 0);
51
+ if (totalIssues === 0) {
52
+ parts.push("● System OK");
53
+ } else if (data.environmentErrorCount > 0 || data.providerIssue?.includes("✗")) {
54
+ parts.push(`✗ ${totalIssues} issue${totalIssues > 1 ? "s" : ""}`);
55
+ } else {
56
+ parts.push(`⚠ ${totalIssues} warning${totalIssues > 1 ? "s" : ""}`);
57
+ }
118
58
 
119
- const budget = formatBudgetSummary(data);
120
- if (budget) details.push(budget);
59
+ if (data.budgetCeiling !== undefined && data.budgetCeiling > 0) {
60
+ const pct = Math.min(100, (data.budgetSpent / data.budgetCeiling) * 100);
61
+ parts.push(`Budget: ${formatCost(data.budgetSpent)}/${formatCost(data.budgetCeiling)} (${pct.toFixed(0)}%)`);
62
+ } else if (data.budgetSpent > 0) {
63
+ parts.push(`Spent: ${formatCost(data.budgetSpent)}`);
64
+ }
121
65
 
122
- if (data.eta) details.push(data.eta);
66
+ if (data.providerIssue) {
67
+ parts.push(data.providerIssue);
68
+ }
123
69
 
124
- if (details.length > 0) {
125
- lines.push(` ${details.join("")}`);
70
+ if (data.environmentErrorCount > 0) {
71
+ parts.push(`Env: ${data.environmentErrorCount} error${data.environmentErrorCount > 1 ? "s" : ""}`);
72
+ } else if (data.environmentWarningCount > 0) {
73
+ parts.push(`Env: ${data.environmentWarningCount} warning${data.environmentWarningCount > 1 ? "s" : ""}`);
126
74
  }
127
75
 
128
- return lines;
76
+ return [` ${parts.join(" │ ")}`];
129
77
  }