gsd-pi 2.10.12 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (504) hide show
  1. package/dist/bundled-extension-paths.d.ts +2 -0
  2. package/dist/bundled-extension-paths.js +10 -0
  3. package/dist/loader.js +45 -28
  4. package/dist/onboarding.js +100 -0
  5. package/dist/resource-loader.js +12 -3
  6. package/dist/resources/GSD-WORKFLOW.md +661 -0
  7. package/dist/resources/agents/researcher.md +29 -0
  8. package/dist/resources/agents/scout.md +56 -0
  9. package/dist/resources/agents/worker.md +31 -0
  10. package/dist/resources/extensions/ask-user-questions.ts +289 -0
  11. package/dist/resources/extensions/async-jobs/async-bash-tool.ts +211 -0
  12. package/dist/resources/extensions/async-jobs/await-tool.ts +101 -0
  13. package/dist/resources/extensions/async-jobs/cancel-job-tool.ts +34 -0
  14. package/dist/resources/extensions/async-jobs/index.ts +133 -0
  15. package/dist/resources/extensions/async-jobs/job-manager.ts +211 -0
  16. package/dist/resources/extensions/bg-shell/index.ts +3179 -0
  17. package/dist/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
  18. package/dist/resources/extensions/browser-tools/capture.ts +165 -0
  19. package/dist/resources/extensions/browser-tools/core.d.ts +205 -0
  20. package/dist/resources/extensions/browser-tools/core.js +1057 -0
  21. package/dist/resources/extensions/browser-tools/evaluate-helpers.ts +184 -0
  22. package/dist/resources/extensions/browser-tools/index.ts +51 -0
  23. package/dist/resources/extensions/browser-tools/lifecycle.ts +270 -0
  24. package/dist/resources/extensions/browser-tools/package.json +24 -0
  25. package/dist/resources/extensions/browser-tools/refs.ts +264 -0
  26. package/dist/resources/extensions/browser-tools/settle.ts +197 -0
  27. package/dist/resources/extensions/browser-tools/state.ts +408 -0
  28. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +652 -0
  29. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +614 -0
  30. package/dist/resources/extensions/browser-tools/tools/assertions.ts +342 -0
  31. package/dist/resources/extensions/browser-tools/tools/forms.ts +801 -0
  32. package/dist/resources/extensions/browser-tools/tools/inspection.ts +492 -0
  33. package/dist/resources/extensions/browser-tools/tools/intent.ts +614 -0
  34. package/dist/resources/extensions/browser-tools/tools/interaction.ts +865 -0
  35. package/dist/resources/extensions/browser-tools/tools/navigation.ts +232 -0
  36. package/dist/resources/extensions/browser-tools/tools/pages.ts +303 -0
  37. package/dist/resources/extensions/browser-tools/tools/refs.ts +541 -0
  38. package/dist/resources/extensions/browser-tools/tools/screenshot.ts +83 -0
  39. package/dist/resources/extensions/browser-tools/tools/session.ts +400 -0
  40. package/dist/resources/extensions/browser-tools/tools/wait.ts +247 -0
  41. package/dist/resources/extensions/browser-tools/utils.ts +660 -0
  42. package/dist/resources/extensions/context7/index.ts +428 -0
  43. package/dist/resources/extensions/context7/package.json +11 -0
  44. package/dist/resources/extensions/get-secrets-from-user.ts +625 -0
  45. package/dist/resources/extensions/google-search/index.ts +336 -0
  46. package/dist/resources/extensions/google-search/package.json +9 -0
  47. package/dist/resources/extensions/gsd/activity-log.ts +116 -0
  48. package/dist/resources/extensions/gsd/auto.ts +3732 -0
  49. package/dist/resources/extensions/gsd/commands.ts +544 -0
  50. package/dist/resources/extensions/gsd/crash-recovery.ts +105 -0
  51. package/dist/resources/extensions/gsd/dashboard-overlay.ts +564 -0
  52. package/dist/resources/extensions/gsd/dispatch-guard.ts +78 -0
  53. package/dist/resources/extensions/gsd/docs/preferences-reference.md +278 -0
  54. package/dist/resources/extensions/gsd/doctor.ts +766 -0
  55. package/dist/resources/extensions/gsd/exit-command.ts +18 -0
  56. package/dist/resources/extensions/gsd/files.ts +857 -0
  57. package/dist/resources/extensions/gsd/git-service.ts +904 -0
  58. package/dist/resources/extensions/gsd/gitignore.ts +200 -0
  59. package/dist/resources/extensions/gsd/guided-flow.ts +1054 -0
  60. package/dist/resources/extensions/gsd/index.ts +735 -0
  61. package/dist/resources/extensions/gsd/metrics.ts +374 -0
  62. package/dist/resources/extensions/gsd/migrate/command.ts +218 -0
  63. package/dist/resources/extensions/gsd/migrate/index.ts +42 -0
  64. package/dist/resources/extensions/gsd/migrate/parser.ts +323 -0
  65. package/dist/resources/extensions/gsd/migrate/parsers.ts +624 -0
  66. package/dist/resources/extensions/gsd/migrate/preview.ts +48 -0
  67. package/dist/resources/extensions/gsd/migrate/transformer.ts +346 -0
  68. package/dist/resources/extensions/gsd/migrate/types.ts +370 -0
  69. package/dist/resources/extensions/gsd/migrate/validator.ts +55 -0
  70. package/dist/resources/extensions/gsd/migrate/writer.ts +539 -0
  71. package/dist/resources/extensions/gsd/native-git-bridge.ts +181 -0
  72. package/dist/resources/extensions/gsd/native-parser-bridge.ts +135 -0
  73. package/dist/resources/extensions/gsd/observability-validator.ts +408 -0
  74. package/dist/resources/extensions/gsd/package.json +11 -0
  75. package/dist/resources/extensions/gsd/paths.ts +339 -0
  76. package/dist/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  77. package/dist/resources/extensions/gsd/preferences.ts +988 -0
  78. package/dist/resources/extensions/gsd/prompt-loader.ts +92 -0
  79. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +25 -0
  80. package/dist/resources/extensions/gsd/prompts/complete-slice.md +27 -0
  81. package/dist/resources/extensions/gsd/prompts/discuss.md +237 -0
  82. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +29 -0
  83. package/dist/resources/extensions/gsd/prompts/execute-task.md +63 -0
  84. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -0
  85. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -0
  86. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +61 -0
  87. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +3 -0
  88. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +29 -0
  89. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -0
  90. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +13 -0
  91. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
  92. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +78 -0
  93. package/dist/resources/extensions/gsd/prompts/plan-slice.md +55 -0
  94. package/dist/resources/extensions/gsd/prompts/queue.md +100 -0
  95. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +48 -0
  96. package/dist/resources/extensions/gsd/prompts/replan-slice.md +39 -0
  97. package/dist/resources/extensions/gsd/prompts/research-milestone.md +37 -0
  98. package/dist/resources/extensions/gsd/prompts/research-slice.md +28 -0
  99. package/dist/resources/extensions/gsd/prompts/review-migration.md +66 -0
  100. package/dist/resources/extensions/gsd/prompts/run-uat.md +109 -0
  101. package/dist/resources/extensions/gsd/prompts/system.md +190 -0
  102. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +123 -0
  103. package/dist/resources/extensions/gsd/roadmap-slices.ts +50 -0
  104. package/dist/resources/extensions/gsd/session-forensics.ts +500 -0
  105. package/dist/resources/extensions/gsd/skill-discovery.ts +137 -0
  106. package/dist/resources/extensions/gsd/state.ts +569 -0
  107. package/dist/resources/extensions/gsd/templates/context.md +76 -0
  108. package/dist/resources/extensions/gsd/templates/decisions.md +8 -0
  109. package/dist/resources/extensions/gsd/templates/milestone-summary.md +73 -0
  110. package/dist/resources/extensions/gsd/templates/plan.md +131 -0
  111. package/dist/resources/extensions/gsd/templates/preferences.md +23 -0
  112. package/dist/resources/extensions/gsd/templates/project.md +31 -0
  113. package/dist/resources/extensions/gsd/templates/reassessment.md +28 -0
  114. package/dist/resources/extensions/gsd/templates/requirements.md +81 -0
  115. package/dist/resources/extensions/gsd/templates/research.md +46 -0
  116. package/dist/resources/extensions/gsd/templates/roadmap.md +118 -0
  117. package/dist/resources/extensions/gsd/templates/secrets-manifest.md +22 -0
  118. package/dist/resources/extensions/gsd/templates/slice-context.md +58 -0
  119. package/dist/resources/extensions/gsd/templates/slice-summary.md +99 -0
  120. package/dist/resources/extensions/gsd/templates/state.md +19 -0
  121. package/dist/resources/extensions/gsd/templates/task-plan.md +52 -0
  122. package/dist/resources/extensions/gsd/templates/task-summary.md +57 -0
  123. package/dist/resources/extensions/gsd/templates/uat.md +54 -0
  124. package/dist/resources/extensions/gsd/tests/activity-log-prune.test.ts +297 -0
  125. package/dist/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
  126. package/dist/resources/extensions/gsd/tests/auto-draft-pause.test.ts +109 -0
  127. package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +45 -0
  128. package/dist/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +196 -0
  129. package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +53 -0
  130. package/dist/resources/extensions/gsd/tests/collect-from-manifest.test.ts +469 -0
  131. package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +200 -0
  132. package/dist/resources/extensions/gsd/tests/cost-projection.test.ts +134 -0
  133. package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +312 -0
  134. package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +299 -0
  135. package/dist/resources/extensions/gsd/tests/derive-state.test.ts +660 -0
  136. package/dist/resources/extensions/gsd/tests/discuss-prompt.test.ts +27 -0
  137. package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +91 -0
  138. package/dist/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +170 -0
  139. package/dist/resources/extensions/gsd/tests/doctor.test.ts +594 -0
  140. package/dist/resources/extensions/gsd/tests/draft-promotion.test.ts +169 -0
  141. package/dist/resources/extensions/gsd/tests/exit-command.test.ts +50 -0
  142. package/dist/resources/extensions/gsd/tests/git-service.test.ts +1788 -0
  143. package/dist/resources/extensions/gsd/tests/idle-recovery.test.ts +577 -0
  144. package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +580 -0
  145. package/dist/resources/extensions/gsd/tests/manifest-status.test.ts +283 -0
  146. package/dist/resources/extensions/gsd/tests/metrics-io.test.ts +176 -0
  147. package/dist/resources/extensions/gsd/tests/metrics.test.ts +188 -0
  148. package/dist/resources/extensions/gsd/tests/migrate-command.test.ts +369 -0
  149. package/dist/resources/extensions/gsd/tests/migrate-parser.test.ts +757 -0
  150. package/dist/resources/extensions/gsd/tests/migrate-transformer.test.ts +635 -0
  151. package/dist/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +414 -0
  152. package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +297 -0
  153. package/dist/resources/extensions/gsd/tests/migrate-writer.test.ts +398 -0
  154. package/dist/resources/extensions/gsd/tests/must-have-parser.test.ts +291 -0
  155. package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
  156. package/dist/resources/extensions/gsd/tests/next-milestone-id.test.ts +66 -0
  157. package/dist/resources/extensions/gsd/tests/orphaned-branch.test.ts +353 -0
  158. package/dist/resources/extensions/gsd/tests/parsers.test.ts +1664 -0
  159. package/dist/resources/extensions/gsd/tests/plan-milestone.test.ts +133 -0
  160. package/dist/resources/extensions/gsd/tests/plan-quality-validator.test.ts +363 -0
  161. package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  162. package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  163. package/dist/resources/extensions/gsd/tests/queue-draft-detection.test.ts +126 -0
  164. package/dist/resources/extensions/gsd/tests/reassess-prompt.test.ts +142 -0
  165. package/dist/resources/extensions/gsd/tests/regex-hardening.test.ts +281 -0
  166. package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +155 -0
  167. package/dist/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
  168. package/dist/resources/extensions/gsd/tests/replan-slice.test.ts +493 -0
  169. package/dist/resources/extensions/gsd/tests/requirements.test.ts +106 -0
  170. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +35 -0
  171. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +11 -0
  172. package/dist/resources/extensions/gsd/tests/roadmap-slices.test.ts +41 -0
  173. package/dist/resources/extensions/gsd/tests/run-uat.test.ts +316 -0
  174. package/dist/resources/extensions/gsd/tests/secure-env-collect.test.ts +185 -0
  175. package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +123 -0
  176. package/dist/resources/extensions/gsd/tests/test-helpers.ts +61 -0
  177. package/dist/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +219 -0
  178. package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +234 -0
  179. package/dist/resources/extensions/gsd/tests/workspace-index.test.ts +75 -0
  180. package/dist/resources/extensions/gsd/tests/worktree-integration.test.ts +234 -0
  181. package/dist/resources/extensions/gsd/tests/worktree-manager.test.ts +141 -0
  182. package/dist/resources/extensions/gsd/tests/worktree.test.ts +597 -0
  183. package/dist/resources/extensions/gsd/tests/write-gate.test.ts +122 -0
  184. package/dist/resources/extensions/gsd/types.ts +296 -0
  185. package/dist/resources/extensions/gsd/unit-runtime.ts +184 -0
  186. package/dist/resources/extensions/gsd/workspace-index.ts +189 -0
  187. package/dist/resources/extensions/gsd/worktree-command.ts +845 -0
  188. package/dist/resources/extensions/gsd/worktree-manager.ts +459 -0
  189. package/dist/resources/extensions/gsd/{worktree.js → worktree.ts} +92 -61
  190. package/dist/resources/extensions/mac-tools/index.ts +852 -0
  191. package/dist/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
  192. package/dist/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
  193. package/dist/resources/extensions/mcporter/index.ts +429 -0
  194. package/dist/resources/extensions/remote-questions/config.ts +81 -0
  195. package/dist/resources/extensions/remote-questions/discord-adapter.ts +128 -0
  196. package/dist/resources/extensions/remote-questions/format.ts +163 -0
  197. package/dist/resources/extensions/remote-questions/manager.ts +192 -0
  198. package/dist/resources/extensions/remote-questions/remote-command.ts +361 -0
  199. package/dist/resources/extensions/remote-questions/slack-adapter.ts +92 -0
  200. package/dist/resources/extensions/remote-questions/status.ts +31 -0
  201. package/dist/resources/extensions/remote-questions/store.ts +77 -0
  202. package/dist/resources/extensions/remote-questions/types.ts +75 -0
  203. package/dist/resources/extensions/search-the-web/cache.ts +78 -0
  204. package/dist/resources/extensions/search-the-web/command-search-provider.ts +99 -0
  205. package/dist/resources/extensions/search-the-web/format.ts +258 -0
  206. package/dist/resources/extensions/search-the-web/http.ts +238 -0
  207. package/dist/resources/extensions/search-the-web/index.ts +65 -0
  208. package/dist/resources/extensions/search-the-web/native-search.ts +165 -0
  209. package/dist/resources/extensions/search-the-web/provider.ts +136 -0
  210. package/dist/resources/extensions/search-the-web/tavily.ts +116 -0
  211. package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +581 -0
  212. package/dist/resources/extensions/search-the-web/tool-llm-context.ts +620 -0
  213. package/dist/resources/extensions/search-the-web/tool-search.ts +635 -0
  214. package/dist/resources/extensions/search-the-web/url-utils.ts +91 -0
  215. package/dist/resources/extensions/shared/bundled-extension-paths.ts +11 -0
  216. package/dist/resources/extensions/shared/confirm-ui.ts +126 -0
  217. package/dist/resources/extensions/shared/interview-ui.ts +613 -0
  218. package/dist/resources/extensions/shared/next-action-ui.ts +197 -0
  219. package/dist/resources/extensions/shared/progress-widget.ts +282 -0
  220. package/dist/resources/extensions/shared/terminal.ts +23 -0
  221. package/dist/resources/extensions/shared/thinking-widget.ts +107 -0
  222. package/dist/resources/extensions/shared/ui.ts +400 -0
  223. package/dist/resources/extensions/shared/wizard-ui.ts +551 -0
  224. package/dist/resources/extensions/slash-commands/audit.ts +88 -0
  225. package/dist/resources/extensions/slash-commands/clear.ts +10 -0
  226. package/dist/resources/extensions/slash-commands/create-extension.ts +297 -0
  227. package/dist/resources/extensions/slash-commands/create-slash-command.ts +234 -0
  228. package/dist/resources/extensions/slash-commands/index.ts +12 -0
  229. package/dist/resources/extensions/subagent/agents.ts +126 -0
  230. package/dist/resources/extensions/subagent/index.ts +1072 -0
  231. package/dist/resources/extensions/subagent/isolation.ts +498 -0
  232. package/dist/resources/extensions/ttsr/index.ts +163 -0
  233. package/dist/resources/extensions/ttsr/rule-loader.ts +121 -0
  234. package/dist/resources/extensions/ttsr/ttsr-interrupt.md +6 -0
  235. package/dist/resources/extensions/ttsr/ttsr-manager.ts +430 -0
  236. package/dist/resources/extensions/universal-config/discovery.ts +78 -0
  237. package/dist/resources/extensions/universal-config/format.ts +160 -0
  238. package/dist/resources/extensions/universal-config/index.ts +118 -0
  239. package/dist/resources/extensions/universal-config/package.json +11 -0
  240. package/dist/resources/extensions/universal-config/scanners.ts +579 -0
  241. package/dist/resources/extensions/universal-config/tests/discovery.test.ts +111 -0
  242. package/dist/resources/extensions/universal-config/tests/format.test.ts +111 -0
  243. package/dist/resources/extensions/universal-config/tests/scanners.test.ts +438 -0
  244. package/dist/resources/extensions/universal-config/tools.ts +60 -0
  245. package/dist/resources/extensions/universal-config/types.ts +116 -0
  246. package/dist/resources/extensions/voice/index.ts +271 -0
  247. package/dist/resources/extensions/voice/speech-recognizer.py +504 -0
  248. package/dist/resources/extensions/voice/speech-recognizer.swift +154 -0
  249. package/dist/resources/skills/debug-like-expert/SKILL.md +231 -0
  250. package/dist/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
  251. package/dist/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
  252. package/dist/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
  253. package/dist/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
  254. package/dist/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
  255. package/dist/resources/skills/frontend-design/SKILL.md +45 -0
  256. package/dist/resources/skills/github-workflows/SKILL.md +92 -0
  257. package/dist/resources/skills/github-workflows/references/gh/SKILL.md +255 -0
  258. package/dist/resources/skills/github-workflows/references/gh/references/issue-stories.md +204 -0
  259. package/dist/resources/skills/github-workflows/references/gh/references/labels.md +170 -0
  260. package/dist/resources/skills/github-workflows/references/gh/references/milestones.md +158 -0
  261. package/dist/resources/skills/github-workflows/references/gh/references/projects-v2.md +177 -0
  262. package/dist/resources/skills/github-workflows/references/gh/scripts/experiment_cleanup.py +191 -0
  263. package/dist/resources/skills/github-workflows/references/gh/scripts/github_project_setup.py +799 -0
  264. package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
  265. package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +608 -0
  266. package/dist/resources/skills/swiftui/SKILL.md +208 -0
  267. package/dist/resources/skills/swiftui/references/animations.md +921 -0
  268. package/dist/resources/skills/swiftui/references/architecture.md +1561 -0
  269. package/dist/resources/skills/swiftui/references/layout-system.md +1186 -0
  270. package/dist/resources/skills/swiftui/references/navigation.md +1492 -0
  271. package/dist/resources/skills/swiftui/references/networking-async.md +214 -0
  272. package/dist/resources/skills/swiftui/references/performance.md +1706 -0
  273. package/dist/resources/skills/swiftui/references/platform-integration.md +204 -0
  274. package/dist/resources/skills/swiftui/references/state-management.md +1443 -0
  275. package/dist/resources/skills/swiftui/references/swiftdata.md +297 -0
  276. package/dist/resources/skills/swiftui/references/testing-debugging.md +247 -0
  277. package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
  278. package/dist/resources/skills/swiftui/workflows/add-feature.md +191 -0
  279. package/dist/resources/skills/swiftui/workflows/build-new-app.md +311 -0
  280. package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
  281. package/dist/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
  282. package/dist/resources/skills/swiftui/workflows/ship-app.md +203 -0
  283. package/dist/resources/skills/swiftui/workflows/write-tests.md +235 -0
  284. package/dist/wizard.js +1 -0
  285. package/package.json +8 -6
  286. package/packages/native/dist/fd/index.d.ts +1 -0
  287. package/packages/native/dist/fd/index.js +1 -0
  288. package/packages/native/dist/grep/index.d.ts +2 -1
  289. package/packages/native/dist/grep/index.js +1 -0
  290. package/packages/native/src/__tests__/fd.test.mjs +35 -0
  291. package/packages/native/src/__tests__/grep.test.mjs +26 -9
  292. package/packages/native/src/fd/index.ts +1 -0
  293. package/packages/native/src/grep/index.ts +3 -2
  294. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  295. package/packages/pi-agent-core/dist/agent-loop.js +169 -55
  296. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  297. package/packages/pi-agent-core/dist/agent.d.ts +13 -1
  298. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  299. package/packages/pi-agent-core/dist/agent.js +16 -0
  300. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  301. package/packages/pi-agent-core/dist/types.d.ts +91 -1
  302. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  303. package/packages/pi-agent-core/dist/types.js.map +1 -1
  304. package/packages/pi-agent-core/src/agent-loop.ts +273 -63
  305. package/packages/pi-agent-core/src/agent.ts +24 -0
  306. package/packages/pi-agent-core/src/types.ts +98 -0
  307. package/packages/pi-ai/dist/env-api-keys.js +2 -0
  308. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  309. package/packages/pi-ai/dist/models.generated.d.ts +314 -0
  310. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  311. package/packages/pi-ai/dist/models.generated.js +236 -0
  312. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  313. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  314. package/packages/pi-ai/dist/providers/google-gemini-cli.js +6 -0
  315. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  316. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  317. package/packages/pi-ai/dist/providers/openai-completions.js +2 -0
  318. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  319. package/packages/pi-ai/dist/types.d.ts +1 -1
  320. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  321. package/packages/pi-ai/dist/types.js.map +1 -1
  322. package/packages/pi-ai/src/env-api-keys.ts +2 -0
  323. package/packages/pi-ai/src/models.generated.ts +236 -0
  324. package/packages/pi-ai/src/providers/google-gemini-cli.ts +8 -0
  325. package/packages/pi-ai/src/providers/openai-completions.ts +3 -0
  326. package/packages/pi-ai/src/types.ts +2 -1
  327. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  328. package/packages/pi-coding-agent/dist/cli/args.js +1 -0
  329. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  330. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +26 -0
  331. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/agent-session.js +137 -22
  333. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +20 -0
  335. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  336. package/packages/pi-coding-agent/dist/core/auth-storage.js +43 -0
  337. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts +51 -0
  339. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +119 -0
  341. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -0
  342. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts +2 -0
  343. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts.map +1 -0
  344. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +183 -0
  345. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -0
  346. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  347. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  349. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  351. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  352. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  353. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +12 -1
  354. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/core/session-manager.js +37 -1
  356. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  357. package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts +2 -0
  358. package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts.map +1 -0
  359. package/packages/pi-coding-agent/dist/core/session-manager.test.js +61 -0
  360. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -0
  361. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  362. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  363. package/packages/pi-coding-agent/dist/core/settings-manager.js +47 -0
  364. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  365. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  366. package/packages/pi-coding-agent/dist/core/tools/find.js +1 -0
  367. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  368. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +6 -15
  370. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +18 -1
  372. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  373. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +46 -4
  374. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  375. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  376. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -2
  377. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  378. package/packages/pi-coding-agent/src/cli/args.ts +1 -0
  379. package/packages/pi-coding-agent/src/core/agent-session.ts +167 -22
  380. package/packages/pi-coding-agent/src/core/auth-storage.ts +45 -0
  381. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +229 -0
  382. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +165 -0
  383. package/packages/pi-coding-agent/src/core/index.ts +1 -0
  384. package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
  385. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -0
  386. package/packages/pi-coding-agent/src/core/session-manager.ts +51 -1
  387. package/packages/pi-coding-agent/src/core/settings-manager.ts +66 -0
  388. package/packages/pi-coding-agent/src/core/tools/find.ts +1 -0
  389. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +6 -16
  390. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +49 -4
  391. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -2
  392. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  393. package/packages/pi-tui/dist/autocomplete.js +3 -4
  394. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  395. package/packages/pi-tui/dist/components/editor.d.ts +7 -0
  396. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  397. package/packages/pi-tui/dist/components/editor.js +57 -50
  398. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  399. package/packages/pi-tui/src/autocomplete.ts +3 -5
  400. package/packages/pi-tui/src/components/editor.ts +70 -49
  401. package/pkg/dist/core/export-html/ansi-to-html.d.ts +22 -0
  402. package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
  403. package/pkg/dist/core/export-html/ansi-to-html.js +249 -0
  404. package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -0
  405. package/pkg/dist/core/export-html/index.d.ts +37 -0
  406. package/pkg/dist/core/export-html/index.d.ts.map +1 -0
  407. package/pkg/dist/core/export-html/index.js +223 -0
  408. package/pkg/dist/core/export-html/index.js.map +1 -0
  409. package/pkg/dist/core/export-html/template.css +971 -0
  410. package/pkg/dist/core/export-html/template.html +54 -0
  411. package/pkg/dist/core/export-html/template.js +1583 -0
  412. package/pkg/dist/core/export-html/tool-renderer.d.ts +38 -0
  413. package/pkg/dist/core/export-html/tool-renderer.d.ts.map +1 -0
  414. package/pkg/dist/core/export-html/tool-renderer.js +70 -0
  415. package/pkg/dist/core/export-html/tool-renderer.js.map +1 -0
  416. package/pkg/dist/core/export-html/vendor/highlight.min.js +1213 -0
  417. package/pkg/dist/core/export-html/vendor/marked.min.js +6 -0
  418. package/scripts/postinstall.js +30 -17
  419. package/src/resources/extensions/bg-shell/index.ts +51 -7
  420. package/src/resources/extensions/gsd/activity-log.ts +61 -14
  421. package/src/resources/extensions/gsd/auto.ts +288 -19
  422. package/src/resources/extensions/gsd/commands.ts +9 -3
  423. package/src/resources/extensions/gsd/dashboard-overlay.ts +55 -12
  424. package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -0
  425. package/src/resources/extensions/gsd/doctor.ts +60 -3
  426. package/src/resources/extensions/gsd/files.ts +45 -1
  427. package/src/resources/extensions/gsd/git-service.ts +46 -41
  428. package/src/resources/extensions/gsd/guided-flow.ts +81 -9
  429. package/src/resources/extensions/gsd/index.ts +62 -1
  430. package/src/resources/extensions/gsd/native-git-bridge.ts +181 -0
  431. package/src/resources/extensions/gsd/paths.ts +35 -4
  432. package/src/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  433. package/src/resources/extensions/gsd/preferences.ts +232 -1
  434. package/src/resources/extensions/gsd/prompt-loader.ts +45 -3
  435. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  436. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -3
  437. package/src/resources/extensions/gsd/prompts/discuss.md +10 -8
  438. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  439. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -1
  440. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -1
  441. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  442. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +3 -1
  443. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +4 -2
  444. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -1
  445. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +3 -1
  446. package/src/resources/extensions/gsd/prompts/plan-milestone.md +9 -12
  447. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -3
  448. package/src/resources/extensions/gsd/prompts/queue.md +3 -1
  449. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  450. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  451. package/src/resources/extensions/gsd/state.ts +130 -18
  452. package/src/resources/extensions/gsd/templates/context.md +1 -1
  453. package/src/resources/extensions/gsd/templates/state.md +3 -3
  454. package/src/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
  455. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +5 -1
  456. package/src/resources/extensions/gsd/tests/doctor.test.ts +115 -1
  457. package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +6 -2
  458. package/src/resources/extensions/gsd/tests/git-service.test.ts +35 -35
  459. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +8 -8
  460. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +4 -1
  461. package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
  462. package/src/resources/extensions/gsd/tests/orphaned-branch.test.ts +5 -5
  463. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  464. package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  465. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +12 -0
  466. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +6 -0
  467. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +4 -4
  468. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +4 -4
  469. package/src/resources/extensions/gsd/tests/worktree.test.ts +19 -19
  470. package/src/resources/extensions/gsd/types.ts +109 -0
  471. package/src/resources/extensions/gsd/worktree-manager.ts +72 -13
  472. package/src/resources/extensions/gsd/worktree.ts +5 -4
  473. package/src/resources/extensions/search-the-web/command-search-provider.ts +8 -4
  474. package/src/resources/extensions/search-the-web/native-search.ts +32 -23
  475. package/src/resources/extensions/search-the-web/provider.ts +19 -2
  476. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +62 -0
  477. package/src/resources/extensions/search-the-web/tool-llm-context.ts +62 -3
  478. package/src/resources/extensions/search-the-web/tool-search.ts +62 -3
  479. package/src/resources/extensions/shared/bundled-extension-paths.ts +11 -0
  480. package/src/resources/extensions/subagent/index.ts +2 -1
  481. package/src/resources/skills/github-workflows/SKILL.md +5 -0
  482. package/dist/resources/extensions/gsd/git-service.d.ts +0 -225
  483. package/dist/resources/extensions/gsd/git-service.js +0 -756
  484. package/dist/resources/extensions/gsd/preferences.d.ts +0 -122
  485. package/dist/resources/extensions/gsd/preferences.js +0 -616
  486. package/dist/resources/extensions/gsd/worktree.d.ts +0 -106
  487. package/dist/resources/extensions/remote-questions/config.d.ts +0 -14
  488. package/dist/resources/extensions/remote-questions/config.js +0 -68
  489. package/dist/resources/extensions/remote-questions/discord-adapter.d.ts +0 -17
  490. package/dist/resources/extensions/remote-questions/discord-adapter.js +0 -118
  491. package/dist/resources/extensions/remote-questions/format.d.ts +0 -38
  492. package/dist/resources/extensions/remote-questions/format.js +0 -119
  493. package/dist/resources/extensions/remote-questions/manager.d.ts +0 -23
  494. package/dist/resources/extensions/remote-questions/manager.js +0 -161
  495. package/dist/resources/extensions/remote-questions/remote-command.d.ts +0 -6
  496. package/dist/resources/extensions/remote-questions/remote-command.js +0 -358
  497. package/dist/resources/extensions/remote-questions/slack-adapter.d.ts +0 -15
  498. package/dist/resources/extensions/remote-questions/slack-adapter.js +0 -82
  499. package/dist/resources/extensions/remote-questions/status.d.ts +0 -9
  500. package/dist/resources/extensions/remote-questions/status.js +0 -25
  501. package/dist/resources/extensions/remote-questions/store.d.ts +0 -11
  502. package/dist/resources/extensions/remote-questions/store.js +0 -66
  503. package/dist/resources/extensions/remote-questions/types.d.ts +0 -68
  504. package/dist/resources/extensions/remote-questions/types.js +0 -4
@@ -0,0 +1,766 @@
1
+ import { existsSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { loadFile, parsePlan, parseRoadmap, parseSummary, saveFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
5
+ import { resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTaskFiles, resolveTasksDir, milestonesDir, gsdRoot, relMilestoneFile, relSliceFile, relTaskFile, relSlicePath, relGsdRootFile, resolveGsdRootFile } from "./paths.js";
6
+ import { deriveState, isMilestoneComplete } from "./state.js";
7
+ import { loadEffectiveGSDPreferences, type GSDPreferences } from "./preferences.js";
8
+
9
+ export type DoctorSeverity = "info" | "warning" | "error";
10
+ export type DoctorIssueCode =
11
+ | "invalid_preferences"
12
+ | "missing_tasks_dir"
13
+ | "missing_slice_plan"
14
+ | "task_done_missing_summary"
15
+ | "task_summary_without_done_checkbox"
16
+ | "all_tasks_done_missing_slice_summary"
17
+ | "all_tasks_done_missing_slice_uat"
18
+ | "all_tasks_done_roadmap_not_checked"
19
+ | "slice_checked_missing_summary"
20
+ | "slice_checked_missing_uat"
21
+ | "all_slices_done_missing_milestone_summary"
22
+ | "task_done_must_haves_not_verified"
23
+ | "active_requirement_missing_owner"
24
+ | "blocked_requirement_missing_reason"
25
+ | "blocker_discovered_no_replan"
26
+ | "delimiter_in_title";
27
+
28
+ export interface DoctorIssue {
29
+ severity: DoctorSeverity;
30
+ code: DoctorIssueCode;
31
+ scope: "project" | "milestone" | "slice" | "task";
32
+ unitId: string;
33
+ message: string;
34
+ file?: string;
35
+ fixable: boolean;
36
+ }
37
+
38
+ export interface DoctorReport {
39
+ ok: boolean;
40
+ basePath: string;
41
+ issues: DoctorIssue[];
42
+ fixesApplied: string[];
43
+ }
44
+
45
+ export interface DoctorSummary {
46
+ total: number;
47
+ errors: number;
48
+ warnings: number;
49
+ infos: number;
50
+ fixable: number;
51
+ byCode: Array<{ code: DoctorIssueCode; count: number }>;
52
+ }
53
+
54
+ function normalizeStringArray(value: unknown): string[] | undefined {
55
+ if (!Array.isArray(value)) return undefined;
56
+ const items = value.filter((item): item is string => typeof item === "string").map(item => item.trim()).filter(Boolean);
57
+ return items.length > 0 ? Array.from(new Set(items)) : undefined;
58
+ }
59
+
60
+ function validatePreferenceShape(preferences: GSDPreferences): string[] {
61
+ const issues: string[] = [];
62
+ const listFields = ["always_use_skills", "prefer_skills", "avoid_skills", "custom_instructions"] as const;
63
+ for (const field of listFields) {
64
+ const value = preferences[field];
65
+ if (value !== undefined && !Array.isArray(value)) {
66
+ issues.push(`${field} must be a list`);
67
+ }
68
+ }
69
+
70
+ if (preferences.skill_rules !== undefined) {
71
+ if (!Array.isArray(preferences.skill_rules)) {
72
+ issues.push("skill_rules must be a list");
73
+ } else {
74
+ for (const [index, rule] of preferences.skill_rules.entries()) {
75
+ if (!rule || typeof rule !== "object") {
76
+ issues.push(`skill_rules[${index}] must be an object`);
77
+ continue;
78
+ }
79
+ if (typeof rule.when !== "string") {
80
+ issues.push(`skill_rules[${index}].when must be a string`);
81
+ }
82
+ for (const key of ["use", "prefer", "avoid"] as const) {
83
+ const value = (rule as unknown as Record<string, unknown>)[key];
84
+ if (value !== undefined && !Array.isArray(value)) {
85
+ issues.push(`skill_rules[${index}].${key} must be a list`);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ return issues;
93
+ }
94
+
95
+ /**
96
+ * Characters that are used as delimiters in GSD state management documents
97
+ * and should not appear in milestone or slice titles.
98
+ *
99
+ * - "—" (em dash, U+2014): used as a display separator in STATE.md and other docs.
100
+ * A title containing "—" makes the separator ambiguous, corrupting state display
101
+ * and confusing the LLM agent that reads and writes these files.
102
+ * - "–" (en dash, U+2013): visually similar to em dash; same ambiguity risk.
103
+ * - "/" (forward slash, U+002F): used as the path separator in unit IDs (M001/S01)
104
+ * and git branch names (gsd/M001/S01). A slash in a title can break path resolution.
105
+ */
106
+ const TITLE_DELIMITER_RE = /[\u2014\u2013\/]/; // em dash, en dash, forward slash
107
+
108
+ /**
109
+ * Check whether a milestone or slice title contains characters that conflict
110
+ * with GSD's state document delimiter conventions.
111
+ * Returns a human-readable description of the problem, or null if the title is safe.
112
+ */
113
+ export function validateTitle(title: string): string | null {
114
+ if (TITLE_DELIMITER_RE.test(title)) {
115
+ const found: string[] = [];
116
+ if (/[\u2014\u2013]/.test(title)) found.push("em/en dash (\u2014 or \u2013)");
117
+ if (/\//.test(title)) found.push("forward slash (/)");
118
+ return `title contains ${found.join(" and ")}, which conflict with GSD state document delimiters`;
119
+ }
120
+ return null;
121
+ }
122
+
123
+ function buildStateMarkdown(state: Awaited<ReturnType<typeof deriveState>>): string {
124
+ const lines: string[] = [];
125
+ lines.push("# GSD State", "");
126
+
127
+ const activeMilestone = state.activeMilestone
128
+ ? `${state.activeMilestone.id}: ${state.activeMilestone.title}`
129
+ : "None";
130
+ const activeSlice = state.activeSlice
131
+ ? `${state.activeSlice.id}: ${state.activeSlice.title}`
132
+ : "None";
133
+
134
+ lines.push(`**Active Milestone:** ${activeMilestone}`);
135
+ lines.push(`**Active Slice:** ${activeSlice}`);
136
+ lines.push(`**Phase:** ${state.phase}`);
137
+ if (state.requirements) {
138
+ lines.push(`**Requirements Status:** ${state.requirements.active} active · ${state.requirements.validated} validated · ${state.requirements.deferred} deferred · ${state.requirements.outOfScope} out of scope`);
139
+ }
140
+ lines.push("");
141
+ lines.push("## Milestone Registry");
142
+
143
+ for (const entry of state.registry) {
144
+ const glyph = entry.status === "complete" ? "✅" : entry.status === "active" ? "🔄" : "⬜";
145
+ lines.push(`- ${glyph} **${entry.id}:** ${entry.title}`);
146
+ }
147
+
148
+ lines.push("");
149
+ lines.push("## Recent Decisions");
150
+ if (state.recentDecisions.length > 0) {
151
+ for (const decision of state.recentDecisions) lines.push(`- ${decision}`);
152
+ } else {
153
+ lines.push("- None recorded");
154
+ }
155
+
156
+ lines.push("");
157
+ lines.push("## Blockers");
158
+ if (state.blockers.length > 0) {
159
+ for (const blocker of state.blockers) lines.push(`- ${blocker}`);
160
+ } else {
161
+ lines.push("- None");
162
+ }
163
+
164
+ lines.push("");
165
+ lines.push("## Next Action");
166
+ lines.push(state.nextAction || "None");
167
+ lines.push("");
168
+
169
+ return lines.join("\n");
170
+ }
171
+
172
+ async function updateStateFile(basePath: string, fixesApplied: string[]): Promise<void> {
173
+ const state = await deriveState(basePath);
174
+ const path = resolveGsdRootFile(basePath, "STATE");
175
+ await saveFile(path, buildStateMarkdown(state));
176
+ fixesApplied.push(`updated ${path}`);
177
+ }
178
+
179
+ /** Rebuild STATE.md from current disk state. Exported for auto-mode post-hooks. */
180
+ export async function rebuildState(basePath: string): Promise<void> {
181
+ const state = await deriveState(basePath);
182
+ const path = resolveGsdRootFile(basePath, "STATE");
183
+ await saveFile(path, buildStateMarkdown(state));
184
+ }
185
+
186
+ async function ensureSliceSummaryStub(basePath: string, milestoneId: string, sliceId: string, fixesApplied: string[]): Promise<void> {
187
+ const path = join(resolveSlicePath(basePath, milestoneId, sliceId) ?? relSlicePath(basePath, milestoneId, sliceId), `${sliceId}-SUMMARY.md`);
188
+ const absolute = resolveSliceFile(basePath, milestoneId, sliceId, "SUMMARY") ?? join(resolveSlicePath(basePath, milestoneId, sliceId)!, `${sliceId}-SUMMARY.md`);
189
+ const content = [
190
+ "---",
191
+ `id: ${sliceId}`,
192
+ `parent: ${milestoneId}`,
193
+ `milestone: ${milestoneId}`,
194
+ "provides: []",
195
+ "requires: []",
196
+ "affects: []",
197
+ "key_files: []",
198
+ "key_decisions: []",
199
+ "patterns_established: []",
200
+ "observability_surfaces:",
201
+ " - none yet — doctor created placeholder summary; replace with real diagnostics before treating as complete",
202
+ "drill_down_paths: []",
203
+ "duration: unknown",
204
+ "verification_result: unknown",
205
+ `completed_at: ${new Date().toISOString()}`,
206
+ "---",
207
+ "",
208
+ `# ${sliceId}: Recovery placeholder summary`,
209
+ "",
210
+ "**Doctor-created placeholder.**",
211
+ "",
212
+ "## What Happened",
213
+ "Doctor detected that all tasks were complete but the slice summary was missing. Replace this with a real compressed slice summary before relying on it.",
214
+ "",
215
+ "## Verification",
216
+ "Not re-run by doctor.",
217
+ "",
218
+ "## Deviations",
219
+ "Recovery placeholder created to restore required artifact shape.",
220
+ "",
221
+ "## Known Limitations",
222
+ "This file is intentionally incomplete and should be replaced by a real summary.",
223
+ "",
224
+ "## Follow-ups",
225
+ "- Regenerate this summary from task summaries.",
226
+ "",
227
+ "## Files Created/Modified",
228
+ `- \`${relSliceFile(basePath, milestoneId, sliceId, "SUMMARY")}\` — doctor-created placeholder summary`,
229
+ "",
230
+ "## Forward Intelligence",
231
+ "",
232
+ "### What the next slice should know",
233
+ "- Doctor had to reconstruct completion artifacts; inspect task summaries before continuing.",
234
+ "",
235
+ "### What's fragile",
236
+ "- Placeholder summary exists solely to unblock invariant checks.",
237
+ "",
238
+ "### Authoritative diagnostics",
239
+ "- Task summaries in the slice tasks/ directory — they are the actual authoritative source until this summary is rewritten.",
240
+ "",
241
+ "### What assumptions changed",
242
+ "- The system assumed completion would always write a slice summary; in practice doctor may need to restore missing artifacts.",
243
+ "",
244
+ ].join("\n");
245
+ await saveFile(absolute, content);
246
+ fixesApplied.push(`created placeholder ${absolute}`);
247
+ }
248
+
249
+ async function ensureSliceUatStub(basePath: string, milestoneId: string, sliceId: string, fixesApplied: string[]): Promise<void> {
250
+ const sDir = resolveSlicePath(basePath, milestoneId, sliceId);
251
+ if (!sDir) return;
252
+ const absolute = join(sDir, `${sliceId}-UAT.md`);
253
+ const content = [
254
+ `# ${sliceId}: Recovery placeholder UAT`,
255
+ "",
256
+ `**Milestone:** ${milestoneId}`,
257
+ `**Written:** ${new Date().toISOString()}`,
258
+ "",
259
+ "## Preconditions",
260
+ "- Doctor created this placeholder because the expected UAT file was missing.",
261
+ "",
262
+ "## Smoke Test",
263
+ "- Re-run the slice verification from the slice plan before shipping.",
264
+ "",
265
+ "## Test Cases",
266
+ "### 1. Replace this placeholder",
267
+ "1. Read the slice plan and task summaries.",
268
+ "2. Write a real UAT script.",
269
+ "3. **Expected:** This placeholder is replaced with meaningful human checks.",
270
+ "",
271
+ "## Edge Cases",
272
+ "### Missing completion artifacts",
273
+ "1. Confirm the summary, roadmap checkbox, and state file are coherent.",
274
+ "2. **Expected:** GSD doctor reports no remaining completion drift for this slice.",
275
+ "",
276
+ "## Failure Signals",
277
+ "- Placeholder content still present when treating the slice as done",
278
+ "",
279
+ "## Notes for Tester",
280
+ "Doctor created this file only to restore the required artifact shape. Replace it with a real UAT script.",
281
+ "",
282
+ ].join("\n");
283
+ await saveFile(absolute, content);
284
+ fixesApplied.push(`created placeholder ${absolute}`);
285
+ }
286
+
287
+ async function markTaskDoneInPlan(basePath: string, milestoneId: string, sliceId: string, taskId: string, fixesApplied: string[]): Promise<void> {
288
+ const planPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN");
289
+ if (!planPath) return;
290
+ const content = await loadFile(planPath);
291
+ if (!content) return;
292
+ const updated = content.replace(new RegExp(`^-\\s+\\[ \\]\\s+\\*\\*${taskId}:`, "m"), `- [x] **${taskId}:`);
293
+ if (updated !== content) {
294
+ await saveFile(planPath, updated);
295
+ fixesApplied.push(`marked ${taskId} done in ${planPath}`);
296
+ }
297
+ }
298
+
299
+ async function markSliceDoneInRoadmap(basePath: string, milestoneId: string, sliceId: string, fixesApplied: string[]): Promise<void> {
300
+ const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
301
+ if (!roadmapPath) return;
302
+ const content = await loadFile(roadmapPath);
303
+ if (!content) return;
304
+ const updated = content.replace(new RegExp(`^-\\s+\\[ \\]\\s+\\*\\*${sliceId}:`, "m"), `- [x] **${sliceId}:`);
305
+ if (updated !== content) {
306
+ await saveFile(roadmapPath, updated);
307
+ fixesApplied.push(`marked ${sliceId} done in ${roadmapPath}`);
308
+ }
309
+ }
310
+
311
+ function matchesScope(unitId: string, scope?: string): boolean {
312
+ if (!scope) return true;
313
+ return unitId === scope || unitId.startsWith(`${scope}/`) || unitId.startsWith(`${scope}`);
314
+ }
315
+
316
+ function auditRequirements(content: string | null): DoctorIssue[] {
317
+ if (!content) return [];
318
+ const issues: DoctorIssue[] = [];
319
+ const blocks = content.split(/^###\s+/m).slice(1);
320
+
321
+ for (const block of blocks) {
322
+ const idMatch = block.match(/^(R\d+)/);
323
+ if (!idMatch) continue;
324
+ const requirementId = idMatch[1];
325
+ const status = block.match(/^-\s+Status:\s+(.+)$/m)?.[1]?.trim().toLowerCase() ?? "";
326
+ const owner = block.match(/^-\s+Primary owning slice:\s+(.+)$/m)?.[1]?.trim().toLowerCase() ?? "";
327
+ const notes = block.match(/^-\s+Notes:\s+(.+)$/m)?.[1]?.trim().toLowerCase() ?? "";
328
+
329
+ if (status === "active" && (!owner || owner === "none" || owner === "none yet")) {
330
+ issues.push({
331
+ severity: "error",
332
+ code: "active_requirement_missing_owner",
333
+ scope: "project",
334
+ unitId: requirementId,
335
+ message: `${requirementId} is Active but has no primary owning slice`,
336
+ file: relGsdRootFile("REQUIREMENTS"),
337
+ fixable: false,
338
+ });
339
+ }
340
+
341
+ if (status === "blocked" && !notes) {
342
+ issues.push({
343
+ severity: "warning",
344
+ code: "blocked_requirement_missing_reason",
345
+ scope: "project",
346
+ unitId: requirementId,
347
+ message: `${requirementId} is Blocked but has no reason in Notes`,
348
+ file: relGsdRootFile("REQUIREMENTS"),
349
+ fixable: false,
350
+ });
351
+ }
352
+ }
353
+
354
+ return issues;
355
+ }
356
+
357
+ export function summarizeDoctorIssues(issues: DoctorIssue[]): DoctorSummary {
358
+ const errors = issues.filter(issue => issue.severity === "error").length;
359
+ const warnings = issues.filter(issue => issue.severity === "warning").length;
360
+ const infos = issues.filter(issue => issue.severity === "info").length;
361
+ const fixable = issues.filter(issue => issue.fixable).length;
362
+ const byCodeMap = new Map<DoctorIssueCode, number>();
363
+ for (const issue of issues) {
364
+ byCodeMap.set(issue.code, (byCodeMap.get(issue.code) ?? 0) + 1);
365
+ }
366
+ const byCode = [...byCodeMap.entries()]
367
+ .map(([code, count]) => ({ code, count }))
368
+ .sort((a, b) => b.count - a.count || a.code.localeCompare(b.code));
369
+ return { total: issues.length, errors, warnings, infos, fixable, byCode };
370
+ }
371
+
372
+ export async function selectDoctorScope(basePath: string, requestedScope?: string): Promise<string | undefined> {
373
+ if (requestedScope) return requestedScope;
374
+
375
+ const state = await deriveState(basePath);
376
+ if (state.activeMilestone?.id && state.activeSlice?.id) {
377
+ return `${state.activeMilestone.id}/${state.activeSlice.id}`;
378
+ }
379
+ if (state.activeMilestone?.id) {
380
+ return state.activeMilestone.id;
381
+ }
382
+
383
+ const milestonesPath = milestonesDir(basePath);
384
+ if (!existsSync(milestonesPath)) return undefined;
385
+
386
+ for (const milestone of state.registry) {
387
+ const roadmapPath = resolveMilestoneFile(basePath, milestone.id, "ROADMAP");
388
+ const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
389
+ if (!roadmapContent) continue;
390
+ const roadmap = parseRoadmap(roadmapContent);
391
+ if (!isMilestoneComplete(roadmap)) return milestone.id;
392
+ }
393
+
394
+ return state.registry[0]?.id;
395
+ }
396
+
397
+ export function filterDoctorIssues(issues: DoctorIssue[], options?: { scope?: string; includeWarnings?: boolean; includeHistorical?: boolean }): DoctorIssue[] {
398
+ let filtered = issues;
399
+ if (options?.scope) filtered = filtered.filter(issue => matchesScope(issue.unitId, options.scope));
400
+ if (!options?.includeWarnings) filtered = filtered.filter(issue => issue.severity === "error");
401
+ return filtered;
402
+ }
403
+
404
+ export function formatDoctorReport(
405
+ report: DoctorReport,
406
+ options?: { scope?: string; includeWarnings?: boolean; maxIssues?: number; title?: string },
407
+ ): string {
408
+ const scopedIssues = filterDoctorIssues(report.issues, {
409
+ scope: options?.scope,
410
+ includeWarnings: options?.includeWarnings ?? true,
411
+ });
412
+ const summary = summarizeDoctorIssues(scopedIssues);
413
+ const maxIssues = options?.maxIssues ?? 12;
414
+ const lines: string[] = [];
415
+ lines.push(options?.title ?? (summary.errors > 0 ? "GSD doctor found blocking issues." : "GSD doctor report."));
416
+ lines.push(`Scope: ${options?.scope ?? "all milestones"}`);
417
+ lines.push(`Issues: ${summary.total} total · ${summary.errors} error(s) · ${summary.warnings} warning(s) · ${summary.fixable} fixable`);
418
+
419
+ if (summary.byCode.length > 0) {
420
+ lines.push("Top issue types:");
421
+ for (const item of summary.byCode.slice(0, 5)) {
422
+ lines.push(`- ${item.code}: ${item.count}`);
423
+ }
424
+ }
425
+
426
+ if (scopedIssues.length > 0) {
427
+ lines.push("Priority issues:");
428
+ for (const issue of scopedIssues.slice(0, maxIssues)) {
429
+ const prefix = issue.severity === "error" ? "ERROR" : issue.severity === "warning" ? "WARN" : "INFO";
430
+ lines.push(`- [${prefix}] ${issue.unitId}: ${issue.message}${issue.file ? ` (${issue.file})` : ""}`);
431
+ }
432
+ if (scopedIssues.length > maxIssues) {
433
+ lines.push(`- ...and ${scopedIssues.length - maxIssues} more in scope`);
434
+ }
435
+ }
436
+
437
+ if (report.fixesApplied.length > 0) {
438
+ lines.push("Fixes applied:");
439
+ for (const fix of report.fixesApplied.slice(0, maxIssues)) lines.push(`- ${fix}`);
440
+ if (report.fixesApplied.length > maxIssues) lines.push(`- ...and ${report.fixesApplied.length - maxIssues} more`);
441
+ }
442
+
443
+ return lines.join("\n");
444
+ }
445
+
446
+ export function formatDoctorIssuesForPrompt(issues: DoctorIssue[]): string {
447
+ if (issues.length === 0) return "- No remaining issues in scope.";
448
+ return issues.map(issue => {
449
+ const prefix = issue.severity === "error" ? "ERROR" : issue.severity === "warning" ? "WARN" : "INFO";
450
+ return `- [${prefix}] ${issue.unitId} | ${issue.code} | ${issue.message}${issue.file ? ` | file: ${issue.file}` : ""} | fixable: ${issue.fixable ? "yes" : "no"}`;
451
+ }).join("\n");
452
+ }
453
+
454
+ export async function runGSDDoctor(basePath: string, options?: { fix?: boolean; scope?: string; fixLevel?: "task" | "all" }): Promise<DoctorReport> {
455
+ const issues: DoctorIssue[] = [];
456
+ const fixesApplied: string[] = [];
457
+ const fix = options?.fix === true;
458
+ const fixLevel = options?.fixLevel ?? "all";
459
+
460
+ // Issue codes that represent completion state transitions — creating summary
461
+ // stubs, marking slices/milestones done in the roadmap. These belong to the
462
+ // dispatch lifecycle (complete-slice, complete-milestone units), not to
463
+ // mechanical post-hook bookkeeping. When fixLevel is "task", these are
464
+ // detected and reported but never auto-fixed.
465
+ const completionTransitionCodes = new Set<DoctorIssueCode>([
466
+ "all_tasks_done_missing_slice_summary",
467
+ "all_tasks_done_missing_slice_uat",
468
+ "all_tasks_done_roadmap_not_checked",
469
+ ]);
470
+
471
+ /** Whether a given issue code should be auto-fixed at the current fixLevel. */
472
+ const shouldFix = (code: DoctorIssueCode): boolean => {
473
+ if (!fix) return false;
474
+ if (fixLevel === "task" && completionTransitionCodes.has(code)) return false;
475
+ return true;
476
+ };
477
+
478
+ const prefs = loadEffectiveGSDPreferences();
479
+ if (prefs) {
480
+ const prefIssues = validatePreferenceShape(prefs.preferences);
481
+ for (const issue of prefIssues) {
482
+ issues.push({
483
+ severity: "warning",
484
+ code: "invalid_preferences",
485
+ scope: "project",
486
+ unitId: "project",
487
+ message: `GSD preferences invalid: ${issue}`,
488
+ file: prefs.path,
489
+ fixable: false,
490
+ });
491
+ }
492
+ }
493
+
494
+ const milestonesPath = milestonesDir(basePath);
495
+ if (!existsSync(milestonesPath)) {
496
+ return { ok: issues.every(issue => issue.severity !== "error"), basePath, issues, fixesApplied };
497
+ }
498
+
499
+ const requirementsPath = resolveGsdRootFile(basePath, "REQUIREMENTS");
500
+ const requirementsContent = await loadFile(requirementsPath);
501
+ issues.push(...auditRequirements(requirementsContent));
502
+
503
+ const state = await deriveState(basePath);
504
+ for (const milestone of state.registry) {
505
+ const milestoneId = milestone.id;
506
+ const milestonePath = resolveMilestonePath(basePath, milestoneId);
507
+ if (!milestonePath) continue;
508
+
509
+ // Validate milestone title for delimiter characters that break state documents.
510
+ const milestoneTitleIssue = validateTitle(milestone.title);
511
+ if (milestoneTitleIssue) {
512
+ issues.push({
513
+ severity: "warning",
514
+ code: "delimiter_in_title",
515
+ scope: "milestone",
516
+ unitId: milestoneId,
517
+ message: `Milestone ${milestoneId} ${milestoneTitleIssue}. Rename the milestone to remove these characters to prevent state corruption.`,
518
+ file: relMilestoneFile(basePath, milestoneId, "ROADMAP"),
519
+ fixable: false,
520
+ });
521
+ }
522
+
523
+ const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
524
+ const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
525
+ if (!roadmapContent) continue;
526
+ const roadmap = parseRoadmap(roadmapContent);
527
+
528
+ for (const slice of roadmap.slices) {
529
+ const unitId = `${milestoneId}/${slice.id}`;
530
+ if (options?.scope && !matchesScope(unitId, options.scope) && options.scope !== milestoneId) continue;
531
+
532
+ // Validate slice title for delimiter characters.
533
+ const sliceTitleIssue = validateTitle(slice.title);
534
+ if (sliceTitleIssue) {
535
+ issues.push({
536
+ severity: "warning",
537
+ code: "delimiter_in_title",
538
+ scope: "slice",
539
+ unitId,
540
+ message: `Slice ${unitId} ${sliceTitleIssue}. Rename the slice to remove these characters to prevent state corruption.`,
541
+ file: relMilestoneFile(basePath, milestoneId, "ROADMAP"),
542
+ fixable: false,
543
+ });
544
+ }
545
+
546
+ const slicePath = resolveSlicePath(basePath, milestoneId, slice.id);
547
+ if (!slicePath) continue;
548
+
549
+ const tasksDir = resolveTasksDir(basePath, milestoneId, slice.id);
550
+ if (!tasksDir) {
551
+ issues.push({
552
+ severity: "error",
553
+ code: "missing_tasks_dir",
554
+ scope: "slice",
555
+ unitId,
556
+ message: `Missing tasks directory for ${unitId}`,
557
+ file: relSlicePath(basePath, milestoneId, slice.id),
558
+ fixable: true,
559
+ });
560
+ if (fix) {
561
+ mkdirSync(join(slicePath, "tasks"), { recursive: true });
562
+ fixesApplied.push(`created ${join(slicePath, "tasks")}`);
563
+ }
564
+ }
565
+
566
+ const planPath = resolveSliceFile(basePath, milestoneId, slice.id, "PLAN");
567
+ const planContent = planPath ? await loadFile(planPath) : null;
568
+ const plan = planContent ? parsePlan(planContent) : null;
569
+ if (!plan) {
570
+ issues.push({
571
+ severity: "warning",
572
+ code: "missing_slice_plan",
573
+ scope: "slice",
574
+ unitId,
575
+ message: `Slice ${unitId} has no plan file`,
576
+ file: relSliceFile(basePath, milestoneId, slice.id, "PLAN"),
577
+ fixable: false,
578
+ });
579
+ continue;
580
+ }
581
+
582
+ let allTasksDone = plan.tasks.length > 0;
583
+ for (const task of plan.tasks) {
584
+ const taskUnitId = `${unitId}/${task.id}`;
585
+ const summaryPath = resolveTaskFile(basePath, milestoneId, slice.id, task.id, "SUMMARY");
586
+ const hasSummary = !!(summaryPath && await loadFile(summaryPath));
587
+
588
+ if (task.done && !hasSummary) {
589
+ issues.push({
590
+ severity: "error",
591
+ code: "task_done_missing_summary",
592
+ scope: "task",
593
+ unitId: taskUnitId,
594
+ message: `Task ${task.id} is marked done but summary is missing`,
595
+ file: relTaskFile(basePath, milestoneId, slice.id, task.id, "SUMMARY"),
596
+ fixable: false,
597
+ });
598
+ }
599
+
600
+ if (!task.done && hasSummary) {
601
+ issues.push({
602
+ severity: "warning",
603
+ code: "task_summary_without_done_checkbox",
604
+ scope: "task",
605
+ unitId: taskUnitId,
606
+ message: `Task ${task.id} has a summary but is not marked done in the slice plan`,
607
+ file: relSliceFile(basePath, milestoneId, slice.id, "PLAN"),
608
+ fixable: true,
609
+ });
610
+ if (fix) await markTaskDoneInPlan(basePath, milestoneId, slice.id, task.id, fixesApplied);
611
+ }
612
+
613
+ // Must-have verification: done task with summary — check if must-haves are addressed
614
+ if (task.done && hasSummary) {
615
+ const taskPlanPath = resolveTaskFile(basePath, milestoneId, slice.id, task.id, "PLAN");
616
+ if (taskPlanPath) {
617
+ const taskPlanContent = await loadFile(taskPlanPath);
618
+ if (taskPlanContent) {
619
+ const mustHaves = parseTaskPlanMustHaves(taskPlanContent);
620
+ if (mustHaves.length > 0) {
621
+ const summaryContent = await loadFile(summaryPath!);
622
+ const mentionedCount = summaryContent
623
+ ? countMustHavesMentionedInSummary(mustHaves, summaryContent)
624
+ : 0;
625
+ if (mentionedCount < mustHaves.length) {
626
+ issues.push({
627
+ severity: "warning",
628
+ code: "task_done_must_haves_not_verified",
629
+ scope: "task",
630
+ unitId: taskUnitId,
631
+ message: `Task ${task.id} has ${mustHaves.length} must-haves but summary addresses only ${mentionedCount}`,
632
+ file: relTaskFile(basePath, milestoneId, slice.id, task.id, "SUMMARY"),
633
+ fixable: false,
634
+ });
635
+ }
636
+ }
637
+ }
638
+ }
639
+ }
640
+
641
+ allTasksDone = allTasksDone && task.done;
642
+ }
643
+
644
+ // Blocker-without-replan detection: a completed task reported blocker_discovered
645
+ // but no REPLAN.md exists yet — the slice is stuck
646
+ const replanPath = resolveSliceFile(basePath, milestoneId, slice.id, "REPLAN");
647
+ if (!replanPath) {
648
+ for (const task of plan.tasks) {
649
+ if (!task.done) continue;
650
+ const summaryPath = resolveTaskFile(basePath, milestoneId, slice.id, task.id, "SUMMARY");
651
+ if (!summaryPath) continue;
652
+ const summaryContent = await loadFile(summaryPath);
653
+ if (!summaryContent) continue;
654
+ const summary = parseSummary(summaryContent);
655
+ if (summary.frontmatter.blocker_discovered) {
656
+ issues.push({
657
+ severity: "warning",
658
+ code: "blocker_discovered_no_replan",
659
+ scope: "slice",
660
+ unitId,
661
+ message: `Task ${task.id} reported blocker_discovered but no REPLAN.md exists for ${slice.id} — slice may be stuck`,
662
+ file: relSliceFile(basePath, milestoneId, slice.id, "REPLAN"),
663
+ fixable: false,
664
+ });
665
+ break; // one issue per slice is sufficient
666
+ }
667
+ }
668
+ }
669
+
670
+ const sliceSummaryPath = resolveSliceFile(basePath, milestoneId, slice.id, "SUMMARY");
671
+ const sliceUatPath = join(slicePath, `${slice.id}-UAT.md`);
672
+ const hasSliceSummary = !!(sliceSummaryPath && await loadFile(sliceSummaryPath));
673
+ const hasSliceUat = existsSync(sliceUatPath);
674
+
675
+ if (allTasksDone && !hasSliceSummary) {
676
+ issues.push({
677
+ severity: "error",
678
+ code: "all_tasks_done_missing_slice_summary",
679
+ scope: "slice",
680
+ unitId,
681
+ message: `All tasks are done but ${slice.id}-SUMMARY.md is missing`,
682
+ file: relSliceFile(basePath, milestoneId, slice.id, "SUMMARY"),
683
+ fixable: true,
684
+ });
685
+ if (shouldFix("all_tasks_done_missing_slice_summary")) await ensureSliceSummaryStub(basePath, milestoneId, slice.id, fixesApplied);
686
+ }
687
+
688
+ if (allTasksDone && !hasSliceUat) {
689
+ issues.push({
690
+ severity: "warning",
691
+ code: "all_tasks_done_missing_slice_uat",
692
+ scope: "slice",
693
+ unitId,
694
+ message: `All tasks are done but ${slice.id}-UAT.md is missing`,
695
+ file: `${relSlicePath(basePath, milestoneId, slice.id)}/${slice.id}-UAT.md`,
696
+ fixable: true,
697
+ });
698
+ if (shouldFix("all_tasks_done_missing_slice_uat")) await ensureSliceUatStub(basePath, milestoneId, slice.id, fixesApplied);
699
+ }
700
+
701
+ if (allTasksDone && !slice.done) {
702
+ issues.push({
703
+ severity: "error",
704
+ code: "all_tasks_done_roadmap_not_checked",
705
+ scope: "slice",
706
+ unitId,
707
+ message: `All tasks are done but roadmap still shows ${slice.id} as incomplete`,
708
+ file: relMilestoneFile(basePath, milestoneId, "ROADMAP"),
709
+ fixable: true,
710
+ });
711
+ if (shouldFix("all_tasks_done_roadmap_not_checked") && (hasSliceSummary || issues.some(issue => issue.code === "all_tasks_done_missing_slice_summary" && issue.unitId === unitId))) {
712
+ await markSliceDoneInRoadmap(basePath, milestoneId, slice.id, fixesApplied);
713
+ }
714
+ }
715
+
716
+ if (slice.done && !hasSliceSummary) {
717
+ issues.push({
718
+ severity: "error",
719
+ code: "slice_checked_missing_summary",
720
+ scope: "slice",
721
+ unitId,
722
+ message: `Roadmap marks ${slice.id} complete but slice summary is missing`,
723
+ file: relSliceFile(basePath, milestoneId, slice.id, "SUMMARY"),
724
+ fixable: true,
725
+ });
726
+ }
727
+
728
+ if (slice.done && !hasSliceUat) {
729
+ issues.push({
730
+ severity: "warning",
731
+ code: "slice_checked_missing_uat",
732
+ scope: "slice",
733
+ unitId,
734
+ message: `Roadmap marks ${slice.id} complete but UAT file is missing`,
735
+ file: `${relSlicePath(basePath, milestoneId, slice.id)}/${slice.id}-UAT.md`,
736
+ fixable: true,
737
+ });
738
+ }
739
+ }
740
+
741
+ // Milestone-level check: all slices done but no milestone summary
742
+ if (isMilestoneComplete(roadmap) && !resolveMilestoneFile(basePath, milestoneId, "SUMMARY")) {
743
+ issues.push({
744
+ severity: "warning",
745
+ code: "all_slices_done_missing_milestone_summary",
746
+ scope: "milestone",
747
+ unitId: milestoneId,
748
+ message: `All slices are done but ${milestoneId}-SUMMARY.md is missing — milestone is stuck in completing-milestone phase`,
749
+ file: relMilestoneFile(basePath, milestoneId, "SUMMARY"),
750
+ fixable: false,
751
+ });
752
+ }
753
+ }
754
+
755
+ if (fix && fixesApplied.length > 0) {
756
+ await updateStateFile(basePath, fixesApplied);
757
+ }
758
+
759
+ return {
760
+ ok: issues.every(issue => issue.severity !== "error"),
761
+ basePath,
762
+ issues,
763
+ fixesApplied,
764
+ };
765
+ }
766
+