@opengsd/gsd-pi 1.1.1-dev.b2556262 → 1.2.0-dev.4813ead6

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 (500) hide show
  1. package/dist/cli-web-branch.d.ts +2 -0
  2. package/dist/cli-web-branch.js +9 -2
  3. package/dist/help-text.js +5 -0
  4. package/dist/project-sessions.js +4 -2
  5. package/dist/resources/.managed-resources-content-hash +1 -1
  6. package/dist/resources/extensions/ask-user-questions.js +78 -23
  7. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +101 -237
  8. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  9. package/dist/resources/extensions/github-sync/templates.js +3 -3
  10. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  11. package/dist/resources/extensions/gsd/auto/contracts.js +8 -1
  12. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  13. package/dist/resources/extensions/gsd/auto/orchestrator.js +763 -63
  14. package/dist/resources/extensions/gsd/auto/phases.js +28 -3
  15. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  16. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  17. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
  19. package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
  20. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  21. package/dist/resources/extensions/gsd/auto-prompts.js +191 -9
  22. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  23. package/dist/resources/extensions/gsd/auto-runtime-state.js +17 -0
  24. package/dist/resources/extensions/gsd/auto-start.js +12 -23
  25. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  26. package/dist/resources/extensions/gsd/auto-tool-tracking.js +37 -0
  27. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +33 -29
  28. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  29. package/dist/resources/extensions/gsd/auto-worktree.js +45 -36
  30. package/dist/resources/extensions/gsd/auto.js +73 -471
  31. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  32. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
  33. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  34. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +103 -138
  35. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
  36. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  37. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  38. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  39. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  40. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  41. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  42. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  43. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  44. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  45. package/dist/resources/extensions/gsd/debug-logger.js +10 -0
  46. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  47. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  48. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  49. package/dist/resources/extensions/gsd/doctor-proactive.js +7 -2
  50. package/dist/resources/extensions/gsd/doctor.js +16 -9
  51. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  52. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  53. package/dist/resources/extensions/gsd/gsd-db.js +12 -0
  54. package/dist/resources/extensions/gsd/guided-flow.js +36 -470
  55. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  56. package/dist/resources/extensions/gsd/markdown-renderer.js +33 -33
  57. package/dist/resources/extensions/gsd/mcp-filter.js +8 -1
  58. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  59. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  60. package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
  61. package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
  62. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  63. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  64. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  65. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  66. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  67. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  68. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  69. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  70. package/dist/resources/extensions/gsd/native-git-bridge.js +45 -0
  71. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  72. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  73. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  74. package/dist/resources/extensions/gsd/preferences.js +147 -29
  75. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  76. package/dist/resources/extensions/gsd/prompts/discuss.md +6 -7
  77. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  78. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  79. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  80. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  81. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  82. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  83. package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -1
  84. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  85. package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  86. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  87. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  88. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  89. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  90. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  91. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  92. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  93. package/dist/resources/extensions/gsd/schemas/parsers.js +6 -1
  94. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  95. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
  96. package/dist/resources/extensions/gsd/state.js +13 -5
  97. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  98. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  99. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  100. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  101. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  102. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  103. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  104. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  105. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  106. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  107. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +169 -20
  108. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  109. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  110. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  111. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  112. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  113. package/dist/resources/extensions/gsd/user-input-boundary.js +65 -4
  114. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  115. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  116. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  117. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  118. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  119. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  120. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  121. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  122. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  123. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  124. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  125. package/dist/update-cmd.js +20 -0
  126. package/dist/web/standalone/.next/BUILD_ID +1 -1
  127. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  128. package/dist/web/standalone/.next/build-manifest.json +3 -3
  129. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  130. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  131. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  176. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/index.html +1 -1
  183. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  184. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  185. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  186. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  187. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  188. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  190. package/dist/web/standalone/.next/server/chunks/5047.js +2 -0
  191. package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
  192. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  193. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  196. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  197. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  198. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  199. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  200. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  201. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  202. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  203. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  204. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  205. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  206. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  207. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  208. package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
  209. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
  210. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  211. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  212. package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
  213. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
  214. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
  215. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
  216. package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
  217. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  218. package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
  219. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  220. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
  221. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  222. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  223. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  224. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
  225. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
  226. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  227. package/dist/web-mode.d.ts +2 -0
  228. package/dist/web-mode.js +20 -8
  229. package/package.json +17 -11
  230. package/packages/cloud-mcp-gateway/package.json +2 -2
  231. package/packages/contracts/package.json +1 -1
  232. package/packages/daemon/package.json +4 -4
  233. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  234. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  235. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  236. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  237. package/packages/gsd-agent-core/package.json +5 -5
  238. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  239. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
  240. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  241. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +1 -1
  242. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  243. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  244. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  245. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  246. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  247. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  248. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  249. package/packages/gsd-agent-modes/package.json +7 -7
  250. package/packages/mcp-server/dist/server.d.ts +10 -0
  251. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  252. package/packages/mcp-server/dist/server.js +8 -0
  253. package/packages/mcp-server/dist/server.js.map +1 -1
  254. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  255. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  256. package/packages/mcp-server/dist/workflow-tools.js +2 -1
  257. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  258. package/packages/mcp-server/package.json +3 -3
  259. package/packages/native/package.json +1 -1
  260. package/packages/pi-agent-core/package.json +1 -1
  261. package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
  262. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  263. package/packages/pi-ai/dist/image-models.generated.js +30 -0
  264. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  265. package/packages/pi-ai/dist/models.generated.d.ts +8 -127
  266. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  267. package/packages/pi-ai/dist/models.generated.js +47 -166
  268. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  269. package/packages/pi-ai/package.json +1 -1
  270. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/auth-storage.js +11 -3
  272. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  273. package/packages/pi-coding-agent/package.json +7 -7
  274. package/packages/pi-tui/dist/components/input.js +1 -1
  275. package/packages/pi-tui/dist/components/input.js.map +1 -1
  276. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  277. package/packages/pi-tui/dist/keys.js +39 -30
  278. package/packages/pi-tui/dist/keys.js.map +1 -1
  279. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  280. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  281. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  282. package/packages/pi-tui/package.json +2 -2
  283. package/packages/rpc-client/package.json +2 -2
  284. package/pkg/package.json +1 -1
  285. package/scripts/install/deps.js +10 -0
  286. package/scripts/link-workspace-packages.cjs +7 -40
  287. package/src/resources/extensions/ask-user-questions.ts +87 -24
  288. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +126 -289
  289. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +242 -2
  290. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  291. package/src/resources/extensions/github-sync/templates.ts +3 -3
  292. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  293. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  294. package/src/resources/extensions/gsd/auto/contracts.ts +40 -121
  295. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
  296. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  297. package/src/resources/extensions/gsd/auto/orchestrator.ts +913 -64
  298. package/src/resources/extensions/gsd/auto/phases.ts +35 -3
  299. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  300. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  301. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  302. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  303. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  304. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
  305. package/src/resources/extensions/gsd/auto-prompts.ts +220 -9
  306. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  307. package/src/resources/extensions/gsd/auto-runtime-state.ts +30 -0
  308. package/src/resources/extensions/gsd/auto-start.ts +17 -20
  309. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  310. package/src/resources/extensions/gsd/auto-tool-tracking.ts +40 -0
  311. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +42 -30
  312. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  313. package/src/resources/extensions/gsd/auto-worktree.ts +57 -42
  314. package/src/resources/extensions/gsd/auto.ts +96 -508
  315. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  316. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
  317. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  318. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +120 -151
  319. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
  320. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  321. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  322. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  323. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  324. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  325. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  326. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  327. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  328. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  329. package/src/resources/extensions/gsd/debug-logger.ts +11 -0
  330. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  331. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  332. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  333. package/src/resources/extensions/gsd/doctor-proactive.ts +8 -2
  334. package/src/resources/extensions/gsd/doctor.ts +15 -5
  335. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  336. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  337. package/src/resources/extensions/gsd/gsd-db.ts +12 -0
  338. package/src/resources/extensions/gsd/guided-flow.ts +49 -560
  339. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  340. package/src/resources/extensions/gsd/markdown-renderer.ts +40 -20
  341. package/src/resources/extensions/gsd/mcp-filter.ts +9 -1
  342. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  343. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  344. package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
  345. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  346. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  347. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  348. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  349. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  350. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  351. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  352. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  353. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  354. package/src/resources/extensions/gsd/native-git-bridge.ts +48 -0
  355. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  356. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  357. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  358. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  359. package/src/resources/extensions/gsd/preferences.ts +173 -28
  360. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  361. package/src/resources/extensions/gsd/prompts/discuss.md +6 -7
  362. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  363. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  364. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  365. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  366. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  367. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  368. package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -1
  369. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  370. package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  371. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  372. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  373. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  374. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  375. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  376. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  377. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  378. package/src/resources/extensions/gsd/schemas/parsers.ts +6 -1
  379. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  380. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
  381. package/src/resources/extensions/gsd/state.ts +15 -5
  382. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  383. package/src/resources/extensions/gsd/templates/project.md +1 -0
  384. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  385. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  386. package/src/resources/extensions/gsd/tests/artifact-db-drift-memo.test.ts +66 -0
  387. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  388. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  389. package/src/resources/extensions/gsd/tests/auto-dispatch-baseline-harness.test.ts +53 -0
  390. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
  391. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  392. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  393. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +709 -845
  394. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +38 -10
  395. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  396. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  397. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  398. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  399. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  400. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +15 -0
  401. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  402. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  403. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  404. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +64 -1
  405. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  406. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  407. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  408. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  409. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +157 -0
  410. package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
  411. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  412. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
  413. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  414. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  415. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  416. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  417. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  418. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  419. package/src/resources/extensions/gsd/tests/native-merge-regular.test.ts +139 -0
  420. package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
  421. package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
  422. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  423. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +6 -2
  424. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  425. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  426. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  427. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +75 -2
  428. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  429. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  430. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  431. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
  432. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +65 -0
  433. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  434. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  435. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  436. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
  437. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  438. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +21 -6
  439. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +38 -0
  440. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  441. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  442. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  444. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +147 -0
  445. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  446. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  447. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  448. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  449. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
  450. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  451. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +24 -0
  452. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  453. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
  454. package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
  455. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  456. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  457. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  458. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  459. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  460. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  461. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +183 -21
  462. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  463. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  464. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  465. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  466. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  467. package/src/resources/extensions/gsd/user-input-boundary.ts +55 -5
  468. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  469. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  470. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  471. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  472. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  473. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  474. package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
  475. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  476. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  477. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  478. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  479. package/dist/web/standalone/.next/server/chunks/678.js +0 -2
  480. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  481. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  482. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  483. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  484. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  485. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  486. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +0 -21
  487. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +0 -1
  488. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +0 -213
  489. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +0 -1
  490. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts +0 -28
  491. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts.map +0 -1
  492. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js +0 -249
  493. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js.map +0 -1
  494. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts +0 -19
  495. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts.map +0 -1
  496. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js +0 -797
  497. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js.map +0 -1
  498. package/scripts/ensure-workspace-builds.cjs +0 -129
  499. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_buildManifest.js +0 -0
  500. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_ssgManifest.js +0 -0
@@ -0,0 +1,156 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Persist planned milestone roadmaps and their DB-backed projections.
3
+ import { clearParseCache } from "./files.js";
4
+ import { isClosedStatus } from "./status-guards.js";
5
+ import { transaction, getMilestone, getMilestoneSlices, getSlice, insertMilestone, insertSlice, upsertMilestonePlanning, upsertSlicePlanning, } from "./gsd-db.js";
6
+ import { invalidateStateCache } from "./state.js";
7
+ import { renderRoadmapFromDb } from "./markdown-renderer.js";
8
+ import { renderAllProjections } from "./workflow-projections.js";
9
+ import { writeManifest } from "./workflow-manifest.js";
10
+ import { appendEvent } from "./workflow-events.js";
11
+ import { logWarning } from "./workflow-logger.js";
12
+ function validatePlanPromotion(params) {
13
+ const existingMilestone = getMilestone(params.milestoneId);
14
+ if (existingMilestone && isClosedStatus(existingMilestone.status)) {
15
+ return `cannot re-plan milestone ${params.milestoneId}: it is already complete`;
16
+ }
17
+ // Guard: refuse to re-plan a milestone that would drop completed slices (#2960).
18
+ // Allow re-planning when all completed slices are still present in the
19
+ // incoming plan — their status is preserved below (#2558). Block only when
20
+ // the new plan omits a completed slice, which could shadow completed work.
21
+ const existingSlices = getMilestoneSlices(params.milestoneId);
22
+ const completedSlices = existingSlices.filter(s => isClosedStatus(s.status));
23
+ if (completedSlices.length > 0) {
24
+ const incomingSliceIds = new Set(params.slices.map(s => s.sliceId));
25
+ const droppedCompleted = completedSlices.filter(s => !incomingSliceIds.has(s.id));
26
+ if (droppedCompleted.length > 0) {
27
+ return `cannot re-plan milestone ${params.milestoneId}: ${droppedCompleted.length} completed slice(s) would be dropped (${droppedCompleted.map(s => s.id).join(", ")}). Use gsd_reassess_roadmap to modify the roadmap.`;
28
+ }
29
+ }
30
+ // Validate depends_on: all dependencies must exist and be complete
31
+ if (params.dependsOn && params.dependsOn.length > 0) {
32
+ for (const depId of params.dependsOn) {
33
+ const dep = getMilestone(depId);
34
+ if (!dep) {
35
+ return `depends_on references unknown milestone: ${depId}`;
36
+ }
37
+ if (!isClosedStatus(dep.status)) {
38
+ return `depends_on milestone ${depId} is not yet complete (status: ${dep.status})`;
39
+ }
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ function writePlanRows(params) {
45
+ insertMilestone({
46
+ id: params.milestoneId,
47
+ title: params.title,
48
+ status: params.status ?? "active",
49
+ depends_on: params.dependsOn ?? [],
50
+ });
51
+ upsertMilestonePlanning(params.milestoneId, {
52
+ title: params.title,
53
+ status: params.status ?? "active",
54
+ depends_on: params.dependsOn ?? [],
55
+ vision: params.vision,
56
+ successCriteria: params.successCriteria,
57
+ keyRisks: params.keyRisks,
58
+ proofStrategy: params.proofStrategy,
59
+ verificationContract: params.verificationContract,
60
+ verificationIntegration: params.verificationIntegration,
61
+ verificationOperational: params.verificationOperational,
62
+ verificationUat: params.verificationUat,
63
+ definitionOfDone: params.definitionOfDone,
64
+ requirementCoverage: params.requirementCoverage,
65
+ boundaryMapMarkdown: params.boundaryMapMarkdown,
66
+ });
67
+ for (let i = 0; i < params.slices.length; i++) {
68
+ const slice = params.slices[i];
69
+ // Preserve completed/done status on re-plan (#2558).
70
+ // Without this, a re-plan after milestone transition would reset
71
+ // already-completed slices back to "pending".
72
+ const existing = getSlice(params.milestoneId, slice.sliceId);
73
+ const status = existing && (existing.status === "complete" || existing.status === "done")
74
+ ? existing.status
75
+ : "pending";
76
+ insertSlice({
77
+ id: slice.sliceId,
78
+ milestoneId: params.milestoneId,
79
+ title: slice.title,
80
+ status,
81
+ risk: slice.risk,
82
+ depends: slice.depends,
83
+ demo: slice.demo,
84
+ sequence: i + 1, // Preserve agent-ordered sequence (#3356)
85
+ // ADR-011: pass undefined through so ON CONFLICT preserves existing values
86
+ // when the caller omitted the fields on a re-plan.
87
+ isSketch: slice.isSketch,
88
+ sketchScope: slice.sketchScope,
89
+ });
90
+ upsertSlicePlanning(params.milestoneId, slice.sliceId, {
91
+ goal: slice.goal,
92
+ successCriteria: slice.successCriteria,
93
+ proofLevel: slice.proofLevel,
94
+ integrationClosure: slice.integrationClosure,
95
+ observabilityImpact: slice.observabilityImpact,
96
+ });
97
+ }
98
+ }
99
+ async function renderPlanArtifacts(basePath, params) {
100
+ try {
101
+ const renderResult = await renderRoadmapFromDb(basePath, params.milestoneId);
102
+ return renderResult.roadmapPath;
103
+ }
104
+ catch (renderErr) {
105
+ logWarning("tool", `plan_milestone — render failed (DB rows preserved for debugging): ${renderErr.message}`);
106
+ invalidateStateCache();
107
+ return { error: `render failed: ${renderErr.message}` };
108
+ }
109
+ }
110
+ async function runPostPlanHooks(basePath, params) {
111
+ try {
112
+ await renderAllProjections(basePath, params.milestoneId);
113
+ writeManifest(basePath);
114
+ appendEvent(basePath, {
115
+ cmd: "plan-milestone",
116
+ params: { milestoneId: params.milestoneId },
117
+ ts: new Date().toISOString(),
118
+ actor: "agent",
119
+ actor_name: params.actorName,
120
+ trigger_reason: params.triggerReason,
121
+ });
122
+ }
123
+ catch (hookErr) {
124
+ logWarning("tool", `plan-milestone post-mutation hook warning: ${hookErr.message}`);
125
+ }
126
+ }
127
+ export async function persistMilestonePlan(params, basePath) {
128
+ // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
129
+ // Guards must be inside the transaction so the state they check cannot
130
+ // change between the read and the write (#2723).
131
+ let guardError = null;
132
+ try {
133
+ transaction(() => {
134
+ guardError = validatePlanPromotion(params);
135
+ if (guardError)
136
+ return;
137
+ writePlanRows(params);
138
+ });
139
+ }
140
+ catch (err) {
141
+ return { error: `db write failed: ${err.message}` };
142
+ }
143
+ if (guardError) {
144
+ return { error: guardError };
145
+ }
146
+ const roadmapPath = await renderPlanArtifacts(basePath, params);
147
+ if (typeof roadmapPath !== "string")
148
+ return roadmapPath;
149
+ invalidateStateCache();
150
+ clearParseCache();
151
+ await runPostPlanHooks(basePath, params);
152
+ return {
153
+ milestoneId: params.milestoneId,
154
+ roadmapPath,
155
+ };
156
+ }
@@ -0,0 +1,77 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Classify milestone readiness from DB status, slices, and artifacts.
3
+ import { readFileSync } from "node:fs";
4
+ import { getMilestone, getMilestoneSlices, isDbAvailable } from "./gsd-db.js";
5
+ import { parseRoadmapSlices } from "./roadmap-slices.js";
6
+ import { logWarning } from "./workflow-logger.js";
7
+ export function classifyMilestoneReadiness(input) {
8
+ const hasContext = input.hasContext === true;
9
+ const hasDraftContext = !hasContext && input.hasDraftContext === true;
10
+ const hasSummary = input.hasSummary === true;
11
+ const sliceCount = input.sliceCount ?? 0;
12
+ const hasExecutablePlan = sliceCount > 0;
13
+ const status = input.status ?? null;
14
+ if (status === "complete" || hasSummary) {
15
+ return { kind: "terminal", hasContext, hasDraftContext, hasExecutablePlan };
16
+ }
17
+ if (status === "queued" && !hasContext && sliceCount === 0) {
18
+ return { kind: "queued-shell", hasContext, hasDraftContext, hasExecutablePlan };
19
+ }
20
+ if ((status === "needs-discussion" && !hasContext) || hasDraftContext) {
21
+ return { kind: "needs-discussion", hasContext, hasDraftContext, hasExecutablePlan };
22
+ }
23
+ if (hasExecutablePlan) {
24
+ return { kind: "executable-plan", hasContext, hasDraftContext, hasExecutablePlan };
25
+ }
26
+ return { kind: "planning-pending", hasContext, hasDraftContext, hasExecutablePlan };
27
+ }
28
+ export function readinessNeedsDiscussion(readiness) {
29
+ return readiness.kind === "needs-discussion" ||
30
+ (readiness.kind === "queued-shell" && readiness.hasDraftContext);
31
+ }
32
+ export function describeMilestoneReadinessPhase(phase) {
33
+ switch (phase) {
34
+ case "needs-discussion":
35
+ return {
36
+ label: "Discuss milestone draft",
37
+ description: "Milestone has a draft context — needs discussion before planning.",
38
+ };
39
+ case "pre-planning":
40
+ return {
41
+ label: "Research & plan milestone",
42
+ description: "Scout the landscape and create the roadmap.",
43
+ };
44
+ default:
45
+ return null;
46
+ }
47
+ }
48
+ function executablePlanSliceCount(milestoneId, roadmapFile) {
49
+ if (isDbAvailable()) {
50
+ return getMilestoneSlices(milestoneId).length;
51
+ }
52
+ if (!roadmapFile)
53
+ return 0;
54
+ try {
55
+ return parseRoadmapSlices(readFileSync(roadmapFile, "utf-8")).length;
56
+ }
57
+ catch (e) {
58
+ logWarning("guided", `failed to parse roadmap slices for ${milestoneId}: ${e.message}`);
59
+ return 0;
60
+ }
61
+ }
62
+ export function assessMilestoneHandoffReadiness(input) {
63
+ const milestone = isDbAvailable() ? getMilestone(input.milestoneId) : null;
64
+ return classifyMilestoneReadiness({
65
+ status: milestone?.status,
66
+ hasContext: input.contextFile != null,
67
+ sliceCount: executablePlanSliceCount(input.milestoneId, input.roadmapFile),
68
+ });
69
+ }
70
+ export function formatAcceptedDiscussHandoffMessage(milestoneId, readiness) {
71
+ if (readiness.hasExecutablePlan)
72
+ return `Milestone ${milestoneId} ready.`;
73
+ if (readiness.hasContext) {
74
+ return `Milestone ${milestoneId} context captured. Continuing the planning pipeline.`;
75
+ }
76
+ return `Milestone ${milestoneId} planning artifacts captured. Continuing the planning pipeline.`;
77
+ }
@@ -0,0 +1,50 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Milestone closeout settlement state across DB proof, artifacts, merge, and cleanup.
3
+ import { isInAutoWorktree } from "./auto-worktree.js";
4
+ import { formatCloseoutProofBlock, proveMilestoneCloseout, } from "./milestone-closeout-proof.js";
5
+ import { resolveCloseoutArtifactProjection } from "./artifact-projection.js";
6
+ function isActiveUnmergedWorktree(input) {
7
+ if (!input.milestoneId || input.milestoneMerged)
8
+ return false;
9
+ return isInAutoWorktree(input.basePath);
10
+ }
11
+ export function evaluateAllCompleteSettlement(input) {
12
+ if (input.statePhase !== "complete") {
13
+ return { ok: true, reason: "not-applicable" };
14
+ }
15
+ if (!isActiveUnmergedWorktree(input)) {
16
+ return { ok: true, reason: "settled" };
17
+ }
18
+ const milestoneId = input.milestoneId;
19
+ if (!milestoneId) {
20
+ return { ok: true, reason: "settled" };
21
+ }
22
+ const projection = resolveCloseoutArtifactProjection({
23
+ milestoneId,
24
+ basePath: input.basePath,
25
+ originalBasePath: input.originalBasePath,
26
+ });
27
+ const proof = proveMilestoneCloseout(milestoneId, {
28
+ refreshFromDisk: true,
29
+ summaryArtifactBasePath: projection.summaryArtifactBasePath,
30
+ });
31
+ if (!proof.ok) {
32
+ return {
33
+ ok: false,
34
+ reason: "closeout-blocked",
35
+ action: "pause",
36
+ message: `${formatCloseoutProofBlock(proof)} The milestone branch has not been merged to main.`,
37
+ nextAction: `Resolve closeout blockers, then retry \`/gsd dispatch complete-milestone ${milestoneId}\`.`,
38
+ milestoneId,
39
+ };
40
+ }
41
+ return {
42
+ ok: false,
43
+ reason: "merge-pending",
44
+ action: "pause",
45
+ message: `Milestone ${milestoneId} is complete, but its worktree branch has not been merged to main. ` +
46
+ `Retry with \`/gsd dispatch complete-milestone ${milestoneId}\` or merge manually.`,
47
+ nextAction: `Retry \`/gsd dispatch complete-milestone ${milestoneId}\` or merge manually.`,
48
+ milestoneId,
49
+ };
50
+ }
@@ -0,0 +1,73 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Forwarded validation evidence rules for milestone validation.
3
+ import { getArtifact, getMilestone, getMilestoneSlices } from "./gsd-db.js";
4
+ import { loadFile } from "./files.js";
5
+ import { resolveSliceFile } from "./paths.js";
6
+ import { compactTextParts, hasBrowserEvidenceText, hasBrowserRequiredText, } from "./browser-evidence.js";
7
+ export function hasRuntimeExecutableUatEvidenceText(text) {
8
+ if (!/\buatType:\s*runtime-executable\b/i.test(text))
9
+ return false;
10
+ if (!/\bverdict:\s*PASS\b/i.test(text))
11
+ return false;
12
+ return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
13
+ }
14
+ export async function browserEvidenceGateRequiresAttention(params, basePath) {
15
+ if (params.verdict !== "pass")
16
+ return false;
17
+ const milestone = getMilestone(params.milestoneId);
18
+ const slices = getMilestoneSlices(params.milestoneId);
19
+ const requirementText = compactTextParts([
20
+ milestone?.vision,
21
+ milestone?.success_criteria,
22
+ milestone?.verification_uat,
23
+ params.successCriteriaChecklist,
24
+ params.verificationClasses,
25
+ ...slices.flatMap((slice) => [
26
+ slice.demo,
27
+ slice.goal,
28
+ slice.success_criteria,
29
+ ]),
30
+ ]);
31
+ if (!hasBrowserRequiredText(requirementText))
32
+ return false;
33
+ const sliceEvidencePairs = [];
34
+ for (const slice of slices) {
35
+ const chunks = [];
36
+ const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
37
+ const artifact = getArtifact(artifactPath);
38
+ if (artifact?.full_content)
39
+ chunks.push(artifact.full_content);
40
+ const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
41
+ const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
42
+ if (assessmentContent)
43
+ chunks.push(assessmentContent);
44
+ sliceEvidencePairs.push({
45
+ sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
46
+ evidenceText: chunks.join("\n\n"),
47
+ });
48
+ }
49
+ const browserRequiringSlices = sliceEvidencePairs.filter((slice) => hasBrowserRequiredText(slice.sliceRequirementText));
50
+ const runtimeBypasses = browserRequiringSlices.length > 0
51
+ ? browserRequiringSlices.every((slice) => hasRuntimeExecutableUatEvidenceText(slice.evidenceText))
52
+ : sliceEvidencePairs.some((slice) => hasRuntimeExecutableUatEvidenceText(slice.evidenceText));
53
+ if (runtimeBypasses)
54
+ return false;
55
+ const persistedEvidence = sliceEvidencePairs.map((slice) => slice.evidenceText).join("\n\n");
56
+ const validationEvidence = compactTextParts([
57
+ params.successCriteriaChecklist,
58
+ params.verificationClasses,
59
+ params.verdictRationale,
60
+ params.remediationPlan,
61
+ ]);
62
+ return !hasBrowserEvidenceText(`${persistedEvidence}\n\n${validationEvidence}`);
63
+ }
64
+ export function applyBrowserEvidenceGate(params) {
65
+ const note = "Browser evidence gate: Browser-observable acceptance criteria were detected, but no persisted ASSESSMENT or validation evidence recorded browser actions with assertions. Downgraded from pass to needs-attention.";
66
+ return {
67
+ ...params,
68
+ verdict: "needs-attention",
69
+ verdictRationale: params.verdictRationale.trim()
70
+ ? `${params.verdictRationale.trim()}\n\n${note}`
71
+ : note,
72
+ };
73
+ }
@@ -0,0 +1,57 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Resolve the authoritative milestone validation verdict across DB and disk projections.
3
+ import { existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
6
+ import { loadFile } from "./files.js";
7
+ import { getLatestAssessmentByScope, isDbAvailable } from "./gsd-db.js";
8
+ import { gsdProjectionRoot } from "./paths.js";
9
+ import { extractVerdict, isValidMilestoneVerdict, } from "./verdict-parser.js";
10
+ import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
11
+ import { resolveWorktreeProjectRoot } from "./worktree-root.js";
12
+ function verdictFromContent(content) {
13
+ if (!content)
14
+ return undefined;
15
+ const verdict = extractVerdict(content);
16
+ return verdict && isValidMilestoneVerdict(verdict) ? verdict : undefined;
17
+ }
18
+ function verdictFromDb(milestoneId) {
19
+ if (!isDbAvailable())
20
+ return undefined;
21
+ const assessment = getLatestAssessmentByScope(milestoneId, "milestone-validation");
22
+ const status = typeof assessment?.status === "string" ? assessment.status : undefined;
23
+ return status && isValidMilestoneVerdict(status) ? status : undefined;
24
+ }
25
+ async function verdictFromValidationPath(path) {
26
+ if (!path || !existsSync(path))
27
+ return undefined;
28
+ return verdictFromContent(await loadFile(path));
29
+ }
30
+ /**
31
+ * Resolve the milestone validation verdict using the same authority order as
32
+ * DB-backed state derivation, with filesystem fallbacks that mirror
33
+ * `resolveExpectedArtifactPath` (canonical worktree projection, then project
34
+ * root). Manual `/gsd verdict` overrides persist to the DB first; a stale
35
+ * worktree-local VALIDATION.md must not re-block auto-mode after the override.
36
+ */
37
+ export async function resolveMilestoneValidationVerdict(basePath, milestoneId) {
38
+ const dbVerdict = verdictFromDb(milestoneId);
39
+ if (dbVerdict)
40
+ return dbVerdict;
41
+ const canonicalBase = resolveCanonicalMilestoneRoot(basePath, milestoneId);
42
+ const canonicalPath = resolveExpectedArtifactPath("validate-milestone", milestoneId, canonicalBase);
43
+ const canonicalVerdict = await verdictFromValidationPath(canonicalPath);
44
+ if (canonicalVerdict)
45
+ return canonicalVerdict;
46
+ const projectRoot = resolveWorktreeProjectRoot(basePath);
47
+ if (projectRoot !== canonicalBase) {
48
+ const projectPath = resolveExpectedArtifactPath("validate-milestone", milestoneId, projectRoot);
49
+ const projectVerdict = await verdictFromValidationPath(projectPath);
50
+ if (projectVerdict)
51
+ return projectVerdict;
52
+ }
53
+ // Last resort: direct canonical projection path even when resolveDir helpers
54
+ // have not materialized the milestone directory yet.
55
+ const directPath = join(gsdProjectionRoot(canonicalBase), "milestones", milestoneId, `${milestoneId}-VALIDATION.md`);
56
+ return verdictFromValidationPath(directPath);
57
+ }
@@ -11,6 +11,7 @@ import { GSDError, GSD_GIT_ERROR } from "./errors.js";
11
11
  import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
12
12
  import { getErrorMessage } from "./error-utils.js";
13
13
  import { isInfrastructureError } from "./auto/infra-errors.js";
14
+ import { debugCount } from "./debug-logger.js";
14
15
  // Issue #453: keep auto-mode bookkeeping on the stable git CLI path unless a
15
16
  // caller explicitly opts into the native helper.
16
17
  const NATIVE_GSD_GIT_ENABLED = process.env.GSD_ENABLE_NATIVE_GSD_GIT === "1";
@@ -40,6 +41,8 @@ function loadNative() {
40
41
  // ─── Fallback Helpers ──────────────────────────────────────────────────────
41
42
  /** Run a git command via execFileSync. Returns trimmed stdout. */
42
43
  function gitExec(basePath, args, allowFailure = false) {
44
+ // Counts git CLI shell-outs only (native libgit2 paths bypass this helper).
45
+ debugCount("gitInvocations");
43
46
  try {
44
47
  return execFileSync("git", args, {
45
48
  cwd: basePath,
@@ -64,6 +67,8 @@ function isRetryableGitError(err) {
64
67
  return code !== null && TRANSIENT_GIT_RETRY_CODES.has(code);
65
68
  }
66
69
  function execGitFileSyncWithRetry(basePath, args, options) {
70
+ // Counts git CLI shell-outs only (native libgit2 paths bypass this helper).
71
+ debugCount("gitInvocations");
67
72
  try {
68
73
  return execFileSync("git", args, {
69
74
  cwd: basePath,
@@ -77,6 +82,8 @@ function execGitFileSyncWithRetry(basePath, args, options) {
77
82
  if (!isRetryableGitError(err))
78
83
  throw err;
79
84
  sleepSync(GIT_RETRY_DELAY_MS);
85
+ // Retry is a second physical shell-out — count it too.
86
+ debugCount("gitInvocations");
80
87
  return execFileSync("git", args, {
81
88
  cwd: basePath,
82
89
  stdio: ["ignore", "pipe", "pipe"],
@@ -88,6 +95,8 @@ function execGitFileSyncWithRetry(basePath, args, options) {
88
95
  }
89
96
  /** Run a git command via execFileSync. Returns trimmed stdout. */
90
97
  function gitFileExec(basePath, args, allowFailure = false) {
98
+ // Counts git CLI shell-outs only (native libgit2 paths bypass this helper).
99
+ debugCount("gitInvocations");
91
100
  try {
92
101
  return execFileSync("git", args, {
93
102
  cwd: basePath,
@@ -921,6 +930,42 @@ export function nativeMergeSquash(basePath, branch) {
921
930
  throw err;
922
931
  }
923
932
  }
933
+ /**
934
+ * Regular (non-squash) merge a branch (stages changes, does NOT commit).
935
+ * Uses --no-ff to ensure a proper merge commit and --no-commit so the caller
936
+ * can supply a custom commit message via nativeCommit.
937
+ * Respects the user's global git merge.ff config; --no-ff is additive here.
938
+ */
939
+ export function nativeMergeRegular(basePath, branch) {
940
+ try {
941
+ execFileSync("git", ["merge", "--no-ff", "--no-commit", branch], {
942
+ cwd: basePath,
943
+ stdio: ["ignore", "pipe", "pipe"],
944
+ encoding: "utf-8",
945
+ env: GIT_NO_PROMPT_ENV,
946
+ });
947
+ return { success: true, conflicts: [] };
948
+ }
949
+ catch (err) {
950
+ const stderr = err instanceof Error ? err.stderr ?? err.message : String(err);
951
+ if (stderr.includes("local changes would be overwritten") ||
952
+ stderr.includes("not possible because you have unmerged files") ||
953
+ stderr.includes("overwritten by merge")) {
954
+ const dirtyFiles = stderr
955
+ .split("\n")
956
+ .filter((line) => line.startsWith("\t"))
957
+ .map((line) => line.trim())
958
+ .filter(Boolean);
959
+ return { success: false, conflicts: ["__dirty_working_tree__"], dirtyFiles };
960
+ }
961
+ const conflictOutput = gitExec(basePath, ["diff", "--name-only", "--diff-filter=U"], true);
962
+ const conflicts = conflictOutput ? conflictOutput.split("\n").filter(Boolean) : [];
963
+ if (conflicts.length > 0) {
964
+ return { success: false, conflicts };
965
+ }
966
+ throw err;
967
+ }
968
+ }
924
969
  /**
925
970
  * Abort an in-progress merge.
926
971
  * Native: libgit2 reset + cleanup.
@@ -4,11 +4,10 @@
4
4
  * Analyzes which milestones can safely run in parallel by checking
5
5
  * dependency satisfaction and file overlap across slice plans.
6
6
  */
7
- import { existsSync } from "node:fs";
8
7
  import { deriveState } from "./state.js";
9
- import { resolveGsdPathContract } from "./paths.js";
10
8
  import { findMilestoneIds } from "./guided-flow.js";
11
- import { isDbAvailable, getMilestoneSlices, getSliceTasks, openDatabase } from "./gsd-db.js";
9
+ import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
10
+ import { openExistingWorkflowDatabase } from "./db-workspace.js";
12
11
  // ─── File Collection ─────────────────────────────────────────────────────────
13
12
  /**
14
13
  * Collect all `filesLikelyTouched` across every slice plan in a milestone.
@@ -64,9 +63,7 @@ function detectFileOverlaps(fileSets) {
64
63
  */
65
64
  export async function analyzeParallelEligibility(basePath) {
66
65
  if (!isDbAvailable()) {
67
- const { projectDb } = resolveGsdPathContract(basePath);
68
- if (existsSync(projectDb))
69
- openDatabase(projectDb);
66
+ openExistingWorkflowDatabase(basePath);
70
67
  }
71
68
  const milestoneIds = findMilestoneIds(basePath);
72
69
  const state = await deriveState(basePath);
@@ -12,9 +12,10 @@ import { join, dirname } from "node:path";
12
12
  import { fileURLToPath } from "node:url";
13
13
  import { gsdRoot } from "./paths.js";
14
14
  import { createWorktree, worktreePath } from "./worktree-manager.js";
15
- import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe, runWorktreePostCreateHook, syncGsdStateToWorktree } from "./auto-worktree.js";
15
+ import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe, runWorktreePostCreateHook, syncGsdStateToWorktreeByScope } from "./auto-worktree.js";
16
16
  import { nativeBranchExists } from "./native-git-bridge.js";
17
17
  import { readIntegrationBranch } from "./git-service.js";
18
+ import { createWorkspace, scopeMilestone } from "./workspace.js";
18
19
  import { resolveParallelConfig } from "./preferences.js";
19
20
  import { writeSessionStatus, readAllSessionStatuses, readSessionStatus, removeSessionStatus, sendSignal, cleanupStaleSessions, } from "./session-status-io.js";
20
21
  import { analyzeParallelEligibility, } from "./parallel-eligibility.js";
@@ -448,7 +449,7 @@ export function _createMilestoneWorktree(basePath, milestoneId) {
448
449
  // Copy .gsd/ planning artifacts (milestones, CONTEXT, ROADMAP, etc.) from the
449
450
  // project root into the worktree. Without this, workers for newly-planned
450
451
  // milestones can't find their roadmap and exit immediately (#2184 Bug 4).
451
- syncGsdStateToWorktree(basePath, info.path);
452
+ syncGsdStateToWorktreeByScope(scopeMilestone(createWorkspace(basePath), milestoneId), scopeMilestone(createWorkspace(info.path), milestoneId));
452
453
  return info.path;
453
454
  }
454
455
  // ─── Worker Spawning ───────────────────────────────────────────────────
@@ -0,0 +1,67 @@
1
+ import { loadGlobalGSDPreferences, loadProjectGSDPreferences, } from "./preferences.js";
2
+ const notifiedPreferenceDiagnostics = new Set();
3
+ export function collectPreferenceDiagnostics(basePath) {
4
+ const diagnostics = [
5
+ ...(loadGlobalGSDPreferences()?.diagnostics ?? []),
6
+ ...(loadProjectGSDPreferences(basePath)?.diagnostics ?? []),
7
+ ];
8
+ const seen = new Set();
9
+ const unique = [];
10
+ for (const diagnostic of diagnostics) {
11
+ const signature = preferenceDiagnosticSignature(diagnostic);
12
+ if (seen.has(signature))
13
+ continue;
14
+ seen.add(signature);
15
+ unique.push(diagnostic);
16
+ }
17
+ return unique;
18
+ }
19
+ export function formatPreferenceDiagnostic(diagnostic) {
20
+ const scope = diagnostic.scope === "global" ? "global" : "project";
21
+ const level = diagnostic.severity === "error" ? "error" : "warning";
22
+ const heading = diagnostic.kind === "parse"
23
+ ? `GSD ${scope} preferences ${level}: ${diagnostic.path} could not be parsed.`
24
+ : `GSD ${scope} preferences ${level}: ${diagnostic.path} contains invalid settings.`;
25
+ const detail = formatPreferenceDiagnosticDetail(diagnostic);
26
+ const impact = diagnostic.ignored
27
+ ? "Preferences from this file were ignored; auto-mode may be using defaults."
28
+ : "Invalid settings were ignored or sanitized; auto-mode may be using defaults for them.";
29
+ return `${heading}\n${detail}\n${impact}\nRun /gsd doctor for details.`;
30
+ }
31
+ export function formatPreferenceDiagnosticDetail(diagnostic) {
32
+ if (diagnostic.line !== undefined && diagnostic.column !== undefined) {
33
+ return `YAML error at line ${diagnostic.line}, column ${diagnostic.column}: ${diagnostic.message}`;
34
+ }
35
+ return diagnostic.message;
36
+ }
37
+ export function notifyPreferenceDiagnostics(ctx, basePath, options) {
38
+ let notified = 0;
39
+ for (const diagnostic of collectPreferenceDiagnostics(basePath)) {
40
+ const signature = preferenceDiagnosticNotificationSignature(diagnostic, options?.surface);
41
+ if (notifiedPreferenceDiagnostics.has(signature))
42
+ continue;
43
+ notifiedPreferenceDiagnostics.add(signature);
44
+ ctx.ui.notify(formatPreferenceDiagnostic(diagnostic), diagnostic.severity === "error" ? "error" : "warning");
45
+ notified++;
46
+ }
47
+ return notified;
48
+ }
49
+ export function _resetPreferenceDiagnosticNotificationsForTests() {
50
+ notifiedPreferenceDiagnostics.clear();
51
+ }
52
+ function preferenceDiagnosticSignature(diagnostic) {
53
+ return [
54
+ diagnostic.path,
55
+ diagnostic.scope,
56
+ diagnostic.severity,
57
+ diagnostic.kind,
58
+ diagnostic.message,
59
+ diagnostic.line ?? "",
60
+ diagnostic.column ?? "",
61
+ diagnostic.ignored === true ? "ignored" : "",
62
+ diagnostic.sanitized === true ? "sanitized" : "",
63
+ ].join("\u0000");
64
+ }
65
+ function preferenceDiagnosticNotificationSignature(diagnostic, surface = "default") {
66
+ return `${surface}\u0000${preferenceDiagnosticSignature(diagnostic)}`;
67
+ }