@opengsd/gsd-core 1.3.0-rc.1 → 1.3.1

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 (521) hide show
  1. package/README.ja-JP.md +44 -790
  2. package/README.ko-KR.md +41 -778
  3. package/README.md +39 -180
  4. package/README.pt-BR.md +45 -413
  5. package/README.zh-CN.md +43 -761
  6. package/agents/gsd-ai-researcher.md +1 -1
  7. package/agents/gsd-debugger.md +8 -8
  8. package/agents/gsd-domain-researcher.md +14 -1
  9. package/agents/gsd-eval-auditor.md +1 -1
  10. package/agents/gsd-eval-planner.md +1 -1
  11. package/agents/gsd-executor.md +21 -8
  12. package/agents/gsd-framework-selector.md +1 -1
  13. package/agents/gsd-intel-updater.md +4 -4
  14. package/agents/gsd-phase-researcher.md +18 -5
  15. package/agents/gsd-plan-checker.md +3 -3
  16. package/agents/gsd-planner.md +36 -23
  17. package/agents/gsd-project-researcher.md +13 -0
  18. package/agents/gsd-research-synthesizer.md +6 -2
  19. package/agents/gsd-roadmapper.md +6 -6
  20. package/agents/gsd-ui-researcher.md +15 -2
  21. package/agents/gsd-user-profiler.md +2 -2
  22. package/agents/gsd-verifier.md +7 -7
  23. package/bin/install.js +169 -59
  24. package/commands/gsd/add-tests.md +1 -1
  25. package/commands/gsd/ai-integration-phase.md +3 -3
  26. package/commands/gsd/audit-fix.md +1 -1
  27. package/commands/gsd/audit-milestone.md +1 -1
  28. package/commands/gsd/audit-uat.md +1 -1
  29. package/commands/gsd/autonomous.md +2 -2
  30. package/commands/gsd/capture.md +6 -6
  31. package/commands/gsd/cleanup.md +1 -1
  32. package/commands/gsd/code-review.md +1 -1
  33. package/commands/gsd/complete-milestone.md +2 -2
  34. package/commands/gsd/config.md +3 -3
  35. package/commands/gsd/debug.md +1 -1
  36. package/commands/gsd/discuss-phase.md +5 -4
  37. package/commands/gsd/docs-update.md +1 -1
  38. package/commands/gsd/eval-review.md +2 -2
  39. package/commands/gsd/execute-phase.md +2 -2
  40. package/commands/gsd/explore.md +1 -1
  41. package/commands/gsd/extract-learnings.md +2 -2
  42. package/commands/gsd/fast.md +1 -1
  43. package/commands/gsd/forensics.md +1 -1
  44. package/commands/gsd/graphify.md +9 -9
  45. package/commands/gsd/health.md +1 -1
  46. package/commands/gsd/help.md +2 -2
  47. package/commands/gsd/import.md +5 -5
  48. package/commands/gsd/inbox.md +1 -1
  49. package/commands/gsd/ingest-docs.md +4 -4
  50. package/commands/gsd/manager.md +3 -3
  51. package/commands/gsd/map-codebase.md +1 -1
  52. package/commands/gsd/milestone-summary.md +1 -1
  53. package/commands/gsd/mvp-phase.md +4 -4
  54. package/commands/gsd/new-milestone.md +5 -5
  55. package/commands/gsd/new-project.md +5 -5
  56. package/commands/gsd/pause-work.md +2 -2
  57. package/commands/gsd/phase.md +4 -4
  58. package/commands/gsd/plan-phase.md +2 -2
  59. package/commands/gsd/plan-review-convergence.md +4 -4
  60. package/commands/gsd/pr-branch.md +1 -1
  61. package/commands/gsd/profile-user.md +2 -2
  62. package/commands/gsd/progress.md +4 -4
  63. package/commands/gsd/quick.md +1 -1
  64. package/commands/gsd/resume-work.md +1 -1
  65. package/commands/gsd/review.md +1 -1
  66. package/commands/gsd/secure-phase.md +1 -1
  67. package/commands/gsd/settings.md +1 -1
  68. package/commands/gsd/ship.md +2 -2
  69. package/commands/gsd/sketch.md +7 -7
  70. package/commands/gsd/spec-phase.md +2 -2
  71. package/commands/gsd/spike.md +3 -3
  72. package/commands/gsd/stats.md +1 -1
  73. package/commands/gsd/surface.md +4 -4
  74. package/commands/gsd/thread.md +1 -1
  75. package/commands/gsd/ui-phase.md +2 -2
  76. package/commands/gsd/ui-review.md +2 -2
  77. package/commands/gsd/ultraplan-phase.md +2 -2
  78. package/commands/gsd/undo.md +3 -3
  79. package/commands/gsd/update.md +3 -3
  80. package/commands/gsd/validate-phase.md +1 -1
  81. package/commands/gsd/verify-work.md +2 -2
  82. package/commands/gsd/workspace.md +4 -4
  83. package/{get-shit-done → gsd-core}/bin/check-latest-version.cjs +1 -1
  84. package/{get-shit-done → gsd-core}/bin/gsd-tools.cjs +13 -3
  85. package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
  86. package/gsd-core/bin/lib/adr-parser.cjs +399 -0
  87. package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
  88. package/gsd-core/bin/lib/artifacts.cjs +51 -0
  89. package/gsd-core/bin/lib/audit.cjs +743 -0
  90. package/gsd-core/bin/lib/check-command-router.cjs +342 -0
  91. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  92. package/gsd-core/bin/lib/clock.cjs +95 -0
  93. package/gsd-core/bin/lib/clusters.cjs +128 -0
  94. package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
  95. package/gsd-core/bin/lib/command-aliases.cjs +809 -0
  96. package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
  97. package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
  98. package/gsd-core/bin/lib/commands.cjs +1202 -0
  99. package/gsd-core/bin/lib/config-schema.cjs +29 -0
  100. package/{get-shit-done → gsd-core}/bin/lib/config-types.cjs +1 -1
  101. package/gsd-core/bin/lib/config.cjs +714 -0
  102. package/{get-shit-done → gsd-core}/bin/lib/configuration.cjs +76 -85
  103. package/gsd-core/bin/lib/context-utilization.cjs +48 -0
  104. package/gsd-core/bin/lib/core.cjs +2007 -0
  105. package/{get-shit-done → gsd-core}/bin/lib/decisions.cjs +9 -7
  106. package/gsd-core/bin/lib/docs.cjs +252 -0
  107. package/gsd-core/bin/lib/drift.cjs +364 -0
  108. package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
  109. package/gsd-core/bin/lib/frontmatter.cjs +442 -0
  110. package/gsd-core/bin/lib/gap-checker.cjs +257 -0
  111. package/gsd-core/bin/lib/graphify.cjs +496 -0
  112. package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
  113. package/gsd-core/bin/lib/init-command-router.cjs +62 -0
  114. package/gsd-core/bin/lib/init.cjs +1799 -0
  115. package/gsd-core/bin/lib/install-profiles.cjs +526 -0
  116. package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
  117. package/gsd-core/bin/lib/installer-migration-report.cjs +347 -0
  118. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
  119. package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  120. package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  121. package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  122. package/gsd-core/bin/lib/installer-migrations.cjs +823 -0
  123. package/gsd-core/bin/lib/intel.cjs +607 -0
  124. package/gsd-core/bin/lib/learnings.cjs +270 -0
  125. package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
  126. package/gsd-core/bin/lib/milestone.cjs +373 -0
  127. package/gsd-core/bin/lib/model-catalog.cjs +154 -0
  128. package/gsd-core/bin/lib/model-profiles.cjs +24 -0
  129. package/gsd-core/bin/lib/observability/event.cjs +51 -0
  130. package/gsd-core/bin/lib/observability/logger.cjs +146 -0
  131. package/{get-shit-done → gsd-core}/bin/lib/observability/redaction.cjs +19 -21
  132. package/{get-shit-done → gsd-core}/bin/lib/package-identity.cjs +5 -1
  133. package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
  134. package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
  135. package/gsd-core/bin/lib/phase.cjs +1307 -0
  136. package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
  137. package/{get-shit-done → gsd-core}/bin/lib/plan-scan.cjs +18 -24
  138. package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
  139. package/gsd-core/bin/lib/profile-output.cjs +1120 -0
  140. package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
  141. package/gsd-core/bin/lib/project-root.cjs +119 -0
  142. package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
  143. package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
  144. package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
  145. package/gsd-core/bin/lib/roadmap-upgrade.cjs +491 -0
  146. package/gsd-core/bin/lib/roadmap.cjs +600 -0
  147. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +254 -0
  148. package/gsd-core/bin/lib/runtime-homes.cjs +169 -0
  149. package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
  150. package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
  151. package/{get-shit-done → gsd-core}/bin/lib/schema-detect.cjs +20 -26
  152. package/gsd-core/bin/lib/secrets.cjs +34 -0
  153. package/gsd-core/bin/lib/security.cjs +407 -0
  154. package/{get-shit-done → gsd-core}/bin/lib/semver-compare.cjs +1 -1
  155. package/gsd-core/bin/lib/shell-command-projection.cjs +524 -0
  156. package/gsd-core/bin/lib/state-command-router.cjs +160 -0
  157. package/{get-shit-done → gsd-core}/bin/lib/state-document.cjs +78 -78
  158. package/gsd-core/bin/lib/state.cjs +2010 -0
  159. package/gsd-core/bin/lib/surface.cjs +406 -0
  160. package/gsd-core/bin/lib/task-command-router.cjs +85 -0
  161. package/gsd-core/bin/lib/template.cjs +237 -0
  162. package/gsd-core/bin/lib/uat.cjs +297 -0
  163. package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
  164. package/gsd-core/bin/lib/update-context.cjs +218 -0
  165. package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
  166. package/gsd-core/bin/lib/validate.cjs +112 -0
  167. package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
  168. package/gsd-core/bin/lib/verify.cjs +1451 -0
  169. package/{get-shit-done → gsd-core}/bin/lib/workstream-inventory-builder.cjs +19 -12
  170. package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
  171. package/{get-shit-done → gsd-core}/bin/lib/workstream-name-policy.cjs +28 -31
  172. package/gsd-core/bin/lib/workstream.cjs +380 -0
  173. package/gsd-core/bin/lib/worktree-safety.cjs +912 -0
  174. package/{get-shit-done → gsd-core}/bin/shared/config-schema.manifest.json +5 -0
  175. package/{get-shit-done → gsd-core}/references/artifact-types.md +1 -1
  176. package/{get-shit-done → gsd-core}/references/few-shot-examples/plan-checker.md +2 -2
  177. package/{get-shit-done → gsd-core}/references/few-shot-examples/verifier.md +12 -12
  178. package/{get-shit-done → gsd-core}/references/model-profile-resolution.md +1 -1
  179. package/{get-shit-done → gsd-core}/references/mvp-concepts.md +1 -1
  180. package/{get-shit-done → gsd-core}/references/planner-graphify-auto-update.md +2 -2
  181. package/{get-shit-done → gsd-core}/references/planner-mvp-mode.md +1 -1
  182. package/{get-shit-done → gsd-core}/references/verification-patterns.md +1 -1
  183. package/gsd-core/references/worktree-branch-check.md +38 -0
  184. package/{get-shit-done → gsd-core}/references/worktree-path-safety.md +4 -26
  185. package/{get-shit-done → gsd-core}/templates/README.md +2 -2
  186. package/{get-shit-done → gsd-core}/templates/codebase/structure.md +10 -10
  187. package/{get-shit-done → gsd-core}/templates/copilot-instructions.md +1 -1
  188. package/{get-shit-done → gsd-core}/templates/phase-prompt.md +10 -10
  189. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
  190. package/{get-shit-done → gsd-core}/workflows/add-backlog.md +1 -1
  191. package/{get-shit-done → gsd-core}/workflows/add-phase.md +1 -1
  192. package/{get-shit-done → gsd-core}/workflows/add-tests.md +1 -1
  193. package/{get-shit-done → gsd-core}/workflows/add-todo.md +1 -1
  194. package/{get-shit-done → gsd-core}/workflows/ai-integration-phase.md +4 -4
  195. package/{get-shit-done → gsd-core}/workflows/audit-fix.md +1 -1
  196. package/{get-shit-done → gsd-core}/workflows/audit-milestone.md +1 -1
  197. package/{get-shit-done → gsd-core}/workflows/audit-uat.md +1 -1
  198. package/{get-shit-done → gsd-core}/workflows/autonomous.md +4 -4
  199. package/{get-shit-done → gsd-core}/workflows/check-todos.md +1 -1
  200. package/{get-shit-done → gsd-core}/workflows/cleanup.md +1 -1
  201. package/{get-shit-done → gsd-core}/workflows/code-review-fix.md +1 -1
  202. package/{get-shit-done → gsd-core}/workflows/code-review.md +4 -4
  203. package/{get-shit-done → gsd-core}/workflows/complete-milestone.md +2 -2
  204. package/{get-shit-done → gsd-core}/workflows/debug.md +1 -1
  205. package/{get-shit-done → gsd-core}/workflows/diagnose-issues.md +4 -2
  206. package/{get-shit-done → gsd-core}/workflows/discovery-phase.md +5 -5
  207. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/advisor.md +4 -4
  208. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/auto.md +1 -1
  209. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/chain.md +1 -1
  210. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/power.md +1 -1
  211. package/{get-shit-done → gsd-core}/workflows/discuss-phase-assumptions.md +2 -2
  212. package/{get-shit-done → gsd-core}/workflows/discuss-phase.md +6 -6
  213. package/{get-shit-done → gsd-core}/workflows/do.md +1 -1
  214. package/{get-shit-done → gsd-core}/workflows/docs-update.md +1 -1
  215. package/{get-shit-done → gsd-core}/workflows/edit-phase.md +1 -1
  216. package/{get-shit-done → gsd-core}/workflows/eval-review.md +2 -2
  217. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/codebase-drift-gate.md +15 -2
  218. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  219. package/{get-shit-done → gsd-core}/workflows/execute-phase.md +68 -46
  220. package/{get-shit-done → gsd-core}/workflows/execute-plan.md +8 -8
  221. package/{get-shit-done → gsd-core}/workflows/explore.md +3 -3
  222. package/{get-shit-done → gsd-core}/workflows/extract-learnings.md +1 -1
  223. package/{get-shit-done → gsd-core}/workflows/forensics.md +1 -1
  224. package/{get-shit-done → gsd-core}/workflows/graduation.md +1 -1
  225. package/{get-shit-done → gsd-core}/workflows/health.md +1 -1
  226. package/{get-shit-done → gsd-core}/workflows/help/modes/full.md +1 -1
  227. package/{get-shit-done → gsd-core}/workflows/import.md +1 -1
  228. package/{get-shit-done → gsd-core}/workflows/ingest-docs.md +3 -3
  229. package/{get-shit-done → gsd-core}/workflows/insert-phase.md +1 -1
  230. package/{get-shit-done → gsd-core}/workflows/list-workspaces.md +1 -1
  231. package/{get-shit-done → gsd-core}/workflows/manager.md +1 -1
  232. package/{get-shit-done → gsd-core}/workflows/map-codebase.md +1 -1
  233. package/{get-shit-done → gsd-core}/workflows/milestone-summary.md +1 -1
  234. package/{get-shit-done → gsd-core}/workflows/mvp-phase.md +7 -7
  235. package/{get-shit-done → gsd-core}/workflows/new-milestone.md +3 -3
  236. package/{get-shit-done → gsd-core}/workflows/new-project.md +6 -6
  237. package/{get-shit-done → gsd-core}/workflows/new-workspace.md +1 -1
  238. package/{get-shit-done → gsd-core}/workflows/next.md +1 -1
  239. package/{get-shit-done → gsd-core}/workflows/pause-work.md +1 -1
  240. package/{get-shit-done → gsd-core}/workflows/plan-milestone-gaps.md +1 -1
  241. package/{get-shit-done → gsd-core}/workflows/plan-phase.md +15 -15
  242. package/{get-shit-done → gsd-core}/workflows/plan-review-convergence.md +7 -7
  243. package/{get-shit-done → gsd-core}/workflows/plant-seed.md +1 -1
  244. package/{get-shit-done → gsd-core}/workflows/profile-user.md +11 -11
  245. package/{get-shit-done → gsd-core}/workflows/progress.md +1 -1
  246. package/{get-shit-done → gsd-core}/workflows/quick.md +2 -26
  247. package/{get-shit-done → gsd-core}/workflows/reapply-patches.md +2 -2
  248. package/{get-shit-done → gsd-core}/workflows/remove-phase.md +1 -1
  249. package/{get-shit-done → gsd-core}/workflows/remove-workspace.md +1 -1
  250. package/{get-shit-done → gsd-core}/workflows/resume-project.md +2 -2
  251. package/{get-shit-done → gsd-core}/workflows/review.md +1 -1
  252. package/{get-shit-done → gsd-core}/workflows/scan.md +1 -1
  253. package/{get-shit-done → gsd-core}/workflows/secure-phase.md +3 -3
  254. package/{get-shit-done → gsd-core}/workflows/settings-advanced.md +1 -1
  255. package/{get-shit-done → gsd-core}/workflows/settings-integrations.md +2 -2
  256. package/{get-shit-done → gsd-core}/workflows/settings.md +1 -1
  257. package/{get-shit-done → gsd-core}/workflows/ship.md +56 -4
  258. package/{get-shit-done → gsd-core}/workflows/sketch-wrap-up.md +1 -1
  259. package/{get-shit-done → gsd-core}/workflows/sketch.md +5 -5
  260. package/{get-shit-done → gsd-core}/workflows/spec-phase.md +2 -2
  261. package/{get-shit-done → gsd-core}/workflows/spike-wrap-up.md +1 -1
  262. package/{get-shit-done → gsd-core}/workflows/spike.md +1 -1
  263. package/{get-shit-done → gsd-core}/workflows/stats.md +1 -1
  264. package/{get-shit-done → gsd-core}/workflows/sync-skills.md +3 -3
  265. package/{get-shit-done → gsd-core}/workflows/thread.md +1 -1
  266. package/{get-shit-done → gsd-core}/workflows/transition.md +2 -2
  267. package/{get-shit-done → gsd-core}/workflows/ui-phase.md +3 -3
  268. package/{get-shit-done → gsd-core}/workflows/ui-review.md +2 -2
  269. package/{get-shit-done → gsd-core}/workflows/ultraplan-phase.md +1 -1
  270. package/{get-shit-done → gsd-core}/workflows/undo.md +2 -2
  271. package/{get-shit-done → gsd-core}/workflows/update.md +41 -16
  272. package/{get-shit-done → gsd-core}/workflows/validate-phase.md +3 -3
  273. package/{get-shit-done → gsd-core}/workflows/verify-phase.md +4 -4
  274. package/{get-shit-done → gsd-core}/workflows/verify-work.md +5 -5
  275. package/hooks/dist/gsd-check-update-worker.js +16 -3
  276. package/hooks/dist/gsd-check-update.js +7 -5
  277. package/hooks/dist/gsd-context-monitor.js +2 -2
  278. package/hooks/dist/gsd-statusline.js +39 -21
  279. package/hooks/dist/gsd-update-banner.js +6 -2
  280. package/hooks/dist/managed-hooks-registry.cjs +35 -0
  281. package/hooks/gsd-check-update-worker.js +16 -3
  282. package/hooks/gsd-check-update.js +7 -5
  283. package/hooks/gsd-context-monitor.js +2 -2
  284. package/hooks/gsd-statusline.js +39 -21
  285. package/hooks/gsd-update-banner.js +6 -2
  286. package/package.json +9 -6
  287. package/scripts/affected-tests-lib.cjs +1 -1
  288. package/scripts/base64-scan.sh +12 -0
  289. package/scripts/build-hooks.js +4 -1
  290. package/scripts/changeset/cli.cjs +2 -2
  291. package/scripts/changeset/github-release-notes.cjs +1 -1
  292. package/scripts/changeset/lint.cjs +1 -1
  293. package/scripts/check-alias-drift.cjs +8 -8
  294. package/scripts/check-env.cjs +5 -1
  295. package/scripts/ci-test-scope.cjs +25 -10
  296. package/scripts/command-contract-helpers.cjs +1 -1
  297. package/scripts/fix-slash-commands.cjs +5 -5
  298. package/scripts/gen-inventory-manifest.cjs +3 -3
  299. package/scripts/generate-package-identity.cjs +28 -7
  300. package/scripts/lib/allowlist-ratchet.cjs +136 -0
  301. package/scripts/lint-command-contract.cjs +1 -1
  302. package/scripts/lint-legacy-dir-name.cjs +156 -0
  303. package/scripts/lint-package-identity-drift.cjs +8 -8
  304. package/scripts/lint-pr-check-project-dir.cjs +0 -1
  305. package/scripts/lint-shell-command-projection-drift.cjs +1 -1
  306. package/scripts/lint-skill-deps.cjs +1 -1
  307. package/scripts/lint-test-file-count.allowlist.json +129 -32
  308. package/scripts/lint-test-file-count.cjs +85 -30
  309. package/scripts/mutation-matrix.cjs +219 -0
  310. package/scripts/prompt-injection-scan.sh +5 -1
  311. package/scripts/release-notes/format-github-release-notes.cjs +256 -0
  312. package/scripts/release-tarball-smoke.cjs +9 -9
  313. package/scripts/run-tests.cjs +11 -3
  314. package/scripts/strip-prose-atrefs.cjs +2 -2
  315. package/scripts/sync-runtime-launcher.cjs +2 -2
  316. package/scripts/verify-npm-publish.cjs +252 -0
  317. package/get-shit-done/bin/lib/active-workstream-store.cjs +0 -302
  318. package/get-shit-done/bin/lib/adr-parser.cjs +0 -394
  319. package/get-shit-done/bin/lib/agent-command-router.cjs +0 -65
  320. package/get-shit-done/bin/lib/artifacts.cjs +0 -53
  321. package/get-shit-done/bin/lib/audit.cjs +0 -755
  322. package/get-shit-done/bin/lib/check-command-router.cjs +0 -333
  323. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +0 -118
  324. package/get-shit-done/bin/lib/clock.cjs +0 -96
  325. package/get-shit-done/bin/lib/clusters.cjs +0 -135
  326. package/get-shit-done/bin/lib/code-review-flags.cjs +0 -74
  327. package/get-shit-done/bin/lib/command-aliases.cjs +0 -831
  328. package/get-shit-done/bin/lib/command-arg-projection.cjs +0 -62
  329. package/get-shit-done/bin/lib/command-routing-hub.cjs +0 -388
  330. package/get-shit-done/bin/lib/commands.cjs +0 -1292
  331. package/get-shit-done/bin/lib/config-schema.cjs +0 -31
  332. package/get-shit-done/bin/lib/config.cjs +0 -728
  333. package/get-shit-done/bin/lib/context-utilization.cjs +0 -47
  334. package/get-shit-done/bin/lib/core.cjs +0 -2513
  335. package/get-shit-done/bin/lib/docs.cjs +0 -270
  336. package/get-shit-done/bin/lib/drift.cjs +0 -388
  337. package/get-shit-done/bin/lib/fallow-runner.cjs +0 -109
  338. package/get-shit-done/bin/lib/frontmatter.cjs +0 -389
  339. package/get-shit-done/bin/lib/gap-checker.cjs +0 -254
  340. package/get-shit-done/bin/lib/graphify.cjs +0 -592
  341. package/get-shit-done/bin/lib/gsd2-import.cjs +0 -514
  342. package/get-shit-done/bin/lib/init-command-router.cjs +0 -58
  343. package/get-shit-done/bin/lib/init.cjs +0 -2112
  344. package/get-shit-done/bin/lib/install-profiles.cjs +0 -603
  345. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +0 -117
  346. package/get-shit-done/bin/lib/installer-migration-report.cjs +0 -355
  347. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +0 -220
  348. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +0 -41
  349. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +0 -80
  350. package/get-shit-done/bin/lib/installer-migrations.cjs +0 -778
  351. package/get-shit-done/bin/lib/intel.cjs +0 -708
  352. package/get-shit-done/bin/lib/learnings.cjs +0 -421
  353. package/get-shit-done/bin/lib/milestone.cjs +0 -372
  354. package/get-shit-done/bin/lib/model-catalog.cjs +0 -229
  355. package/get-shit-done/bin/lib/model-profiles.cjs +0 -31
  356. package/get-shit-done/bin/lib/observability/event.cjs +0 -82
  357. package/get-shit-done/bin/lib/observability/logger.cjs +0 -174
  358. package/get-shit-done/bin/lib/phase-command-router.cjs +0 -191
  359. package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -79
  360. package/get-shit-done/bin/lib/phase.cjs +0 -1607
  361. package/get-shit-done/bin/lib/phases-command-router.cjs +0 -39
  362. package/get-shit-done/bin/lib/planning-workspace.cjs +0 -238
  363. package/get-shit-done/bin/lib/profile-output.cjs +0 -1141
  364. package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
  365. package/get-shit-done/bin/lib/project-root.cjs +0 -112
  366. package/get-shit-done/bin/lib/prompt-budget.cjs +0 -399
  367. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +0 -126
  368. package/get-shit-done/bin/lib/roadmap-command-router.cjs +0 -162
  369. package/get-shit-done/bin/lib/roadmap-upgrade.cjs +0 -569
  370. package/get-shit-done/bin/lib/roadmap.cjs +0 -651
  371. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +0 -301
  372. package/get-shit-done/bin/lib/runtime-homes.cjs +0 -222
  373. package/get-shit-done/bin/lib/runtime-name-policy.cjs +0 -83
  374. package/get-shit-done/bin/lib/runtime-slash.cjs +0 -112
  375. package/get-shit-done/bin/lib/secrets.cjs +0 -32
  376. package/get-shit-done/bin/lib/security.cjs +0 -600
  377. package/get-shit-done/bin/lib/shell-command-projection.cjs +0 -535
  378. package/get-shit-done/bin/lib/state-command-router.cjs +0 -252
  379. package/get-shit-done/bin/lib/state.cjs +0 -2073
  380. package/get-shit-done/bin/lib/surface.cjs +0 -470
  381. package/get-shit-done/bin/lib/task-command-router.cjs +0 -81
  382. package/get-shit-done/bin/lib/template.cjs +0 -228
  383. package/get-shit-done/bin/lib/uat.cjs +0 -289
  384. package/get-shit-done/bin/lib/ui-safety-gate.cjs +0 -111
  385. package/get-shit-done/bin/lib/update-context.cjs +0 -209
  386. package/get-shit-done/bin/lib/validate-command-router.cjs +0 -83
  387. package/get-shit-done/bin/lib/validate.cjs +0 -118
  388. package/get-shit-done/bin/lib/verify-command-router.cjs +0 -40
  389. package/get-shit-done/bin/lib/verify.cjs +0 -1614
  390. package/get-shit-done/bin/lib/workstream-inventory.cjs +0 -146
  391. package/get-shit-done/bin/lib/workstream.cjs +0 -389
  392. package/get-shit-done/bin/lib/worktree-safety.cjs +0 -985
  393. package/get-shit-done/workflows/_runtime-launcher.snippet.sh +0 -1
  394. package/scripts/lint-no-source-grep-extras.cjs +0 -81
  395. package/scripts/lint-no-source-grep.cjs +0 -174
  396. /package/{get-shit-done → gsd-core}/bin/shared/config-defaults.manifest.json +0 -0
  397. /package/{get-shit-done → gsd-core}/bin/shared/model-catalog.json +0 -0
  398. /package/{get-shit-done → gsd-core}/bin/shared/runtime-aliases.manifest.json +0 -0
  399. /package/{get-shit-done → gsd-core}/bin/verify-reapply-patches.cjs +0 -0
  400. /package/{get-shit-done → gsd-core}/contexts/dev.md +0 -0
  401. /package/{get-shit-done → gsd-core}/contexts/research.md +0 -0
  402. /package/{get-shit-done → gsd-core}/contexts/review.md +0 -0
  403. /package/{get-shit-done → gsd-core}/references/agent-contracts.md +0 -0
  404. /package/{get-shit-done → gsd-core}/references/ai-evals.md +0 -0
  405. /package/{get-shit-done → gsd-core}/references/ai-frameworks.md +0 -0
  406. /package/{get-shit-done → gsd-core}/references/autonomous-smart-discuss.md +0 -0
  407. /package/{get-shit-done → gsd-core}/references/checkpoints.md +0 -0
  408. /package/{get-shit-done → gsd-core}/references/common-bug-patterns.md +0 -0
  409. /package/{get-shit-done → gsd-core}/references/context-budget.md +0 -0
  410. /package/{get-shit-done → gsd-core}/references/continuation-format.md +0 -0
  411. /package/{get-shit-done → gsd-core}/references/debugger-philosophy.md +0 -0
  412. /package/{get-shit-done → gsd-core}/references/decimal-phase-calculation.md +0 -0
  413. /package/{get-shit-done → gsd-core}/references/doc-conflict-engine.md +0 -0
  414. /package/{get-shit-done → gsd-core}/references/domain-probes.md +0 -0
  415. /package/{get-shit-done → gsd-core}/references/execute-mvp-tdd.md +0 -0
  416. /package/{get-shit-done → gsd-core}/references/executor-examples.md +0 -0
  417. /package/{get-shit-done → gsd-core}/references/gate-prompts.md +0 -0
  418. /package/{get-shit-done → gsd-core}/references/gates.md +0 -0
  419. /package/{get-shit-done → gsd-core}/references/git-integration.md +0 -0
  420. /package/{get-shit-done → gsd-core}/references/git-planning-commit.md +0 -0
  421. /package/{get-shit-done → gsd-core}/references/ios-scaffold.md +0 -0
  422. /package/{get-shit-done → gsd-core}/references/mandatory-initial-read.md +0 -0
  423. /package/{get-shit-done → gsd-core}/references/model-profiles.md +0 -0
  424. /package/{get-shit-done → gsd-core}/references/phase-argument-parsing.md +0 -0
  425. /package/{get-shit-done → gsd-core}/references/planner-antipatterns.md +0 -0
  426. /package/{get-shit-done → gsd-core}/references/planner-chunked.md +0 -0
  427. /package/{get-shit-done → gsd-core}/references/planner-gap-closure.md +0 -0
  428. /package/{get-shit-done → gsd-core}/references/planner-human-verify-mode.md +0 -0
  429. /package/{get-shit-done → gsd-core}/references/planner-interface-context.md +0 -0
  430. /package/{get-shit-done → gsd-core}/references/planner-reviews.md +0 -0
  431. /package/{get-shit-done → gsd-core}/references/planner-revision.md +0 -0
  432. /package/{get-shit-done → gsd-core}/references/planner-source-audit.md +0 -0
  433. /package/{get-shit-done → gsd-core}/references/planning-config.md +0 -0
  434. /package/{get-shit-done → gsd-core}/references/project-skills-discovery.md +0 -0
  435. /package/{get-shit-done → gsd-core}/references/questioning.md +0 -0
  436. /package/{get-shit-done → gsd-core}/references/revision-loop.md +0 -0
  437. /package/{get-shit-done → gsd-core}/references/scout-codebase.md +0 -0
  438. /package/{get-shit-done → gsd-core}/references/skeleton-template.md +0 -0
  439. /package/{get-shit-done → gsd-core}/references/sketch-interactivity.md +0 -0
  440. /package/{get-shit-done → gsd-core}/references/sketch-theme-system.md +0 -0
  441. /package/{get-shit-done → gsd-core}/references/sketch-tooling.md +0 -0
  442. /package/{get-shit-done → gsd-core}/references/sketch-variant-patterns.md +0 -0
  443. /package/{get-shit-done → gsd-core}/references/spidr-splitting.md +0 -0
  444. /package/{get-shit-done → gsd-core}/references/tdd.md +0 -0
  445. /package/{get-shit-done → gsd-core}/references/thinking-models-debug.md +0 -0
  446. /package/{get-shit-done → gsd-core}/references/thinking-models-execution.md +0 -0
  447. /package/{get-shit-done → gsd-core}/references/thinking-models-planning.md +0 -0
  448. /package/{get-shit-done → gsd-core}/references/thinking-models-research.md +0 -0
  449. /package/{get-shit-done → gsd-core}/references/thinking-models-verification.md +0 -0
  450. /package/{get-shit-done → gsd-core}/references/thinking-partner.md +0 -0
  451. /package/{get-shit-done → gsd-core}/references/ui-brand.md +0 -0
  452. /package/{get-shit-done → gsd-core}/references/universal-anti-patterns.md +0 -0
  453. /package/{get-shit-done → gsd-core}/references/user-profiling.md +0 -0
  454. /package/{get-shit-done → gsd-core}/references/user-story-template.md +0 -0
  455. /package/{get-shit-done → gsd-core}/references/verification-overrides.md +0 -0
  456. /package/{get-shit-done → gsd-core}/references/verify-mvp-mode.md +0 -0
  457. /package/{get-shit-done → gsd-core}/references/workstream-flag.md +0 -0
  458. /package/{get-shit-done → gsd-core}/templates/AI-SPEC.md +0 -0
  459. /package/{get-shit-done → gsd-core}/templates/DEBUG.md +0 -0
  460. /package/{get-shit-done → gsd-core}/templates/SECURITY.md +0 -0
  461. /package/{get-shit-done → gsd-core}/templates/UAT.md +0 -0
  462. /package/{get-shit-done → gsd-core}/templates/UI-SPEC.md +0 -0
  463. /package/{get-shit-done → gsd-core}/templates/VALIDATION.md +0 -0
  464. /package/{get-shit-done → gsd-core}/templates/claude-md.md +0 -0
  465. /package/{get-shit-done → gsd-core}/templates/codebase/architecture.md +0 -0
  466. /package/{get-shit-done → gsd-core}/templates/codebase/concerns.md +0 -0
  467. /package/{get-shit-done → gsd-core}/templates/codebase/conventions.md +0 -0
  468. /package/{get-shit-done → gsd-core}/templates/codebase/integrations.md +0 -0
  469. /package/{get-shit-done → gsd-core}/templates/codebase/stack.md +0 -0
  470. /package/{get-shit-done → gsd-core}/templates/codebase/testing.md +0 -0
  471. /package/{get-shit-done → gsd-core}/templates/config.json +0 -0
  472. /package/{get-shit-done → gsd-core}/templates/context.md +0 -0
  473. /package/{get-shit-done → gsd-core}/templates/continue-here.md +0 -0
  474. /package/{get-shit-done → gsd-core}/templates/debug-subagent-prompt.md +0 -0
  475. /package/{get-shit-done → gsd-core}/templates/dev-preferences.md +0 -0
  476. /package/{get-shit-done → gsd-core}/templates/discovery.md +0 -0
  477. /package/{get-shit-done → gsd-core}/templates/discussion-log.md +0 -0
  478. /package/{get-shit-done → gsd-core}/templates/milestone-archive.md +0 -0
  479. /package/{get-shit-done → gsd-core}/templates/milestone.md +0 -0
  480. /package/{get-shit-done → gsd-core}/templates/planner-subagent-prompt.md +0 -0
  481. /package/{get-shit-done → gsd-core}/templates/project.md +0 -0
  482. /package/{get-shit-done → gsd-core}/templates/requirements.md +0 -0
  483. /package/{get-shit-done → gsd-core}/templates/research-project/ARCHITECTURE.md +0 -0
  484. /package/{get-shit-done → gsd-core}/templates/research-project/FEATURES.md +0 -0
  485. /package/{get-shit-done → gsd-core}/templates/research-project/PITFALLS.md +0 -0
  486. /package/{get-shit-done → gsd-core}/templates/research-project/STACK.md +0 -0
  487. /package/{get-shit-done → gsd-core}/templates/research-project/SUMMARY.md +0 -0
  488. /package/{get-shit-done → gsd-core}/templates/research.md +0 -0
  489. /package/{get-shit-done → gsd-core}/templates/retrospective.md +0 -0
  490. /package/{get-shit-done → gsd-core}/templates/roadmap.md +0 -0
  491. /package/{get-shit-done → gsd-core}/templates/spec.md +0 -0
  492. /package/{get-shit-done → gsd-core}/templates/state.md +0 -0
  493. /package/{get-shit-done → gsd-core}/templates/summary-complex.md +0 -0
  494. /package/{get-shit-done → gsd-core}/templates/summary-minimal.md +0 -0
  495. /package/{get-shit-done → gsd-core}/templates/summary-standard.md +0 -0
  496. /package/{get-shit-done → gsd-core}/templates/summary.md +0 -0
  497. /package/{get-shit-done → gsd-core}/templates/user-profile.md +0 -0
  498. /package/{get-shit-done → gsd-core}/templates/user-setup.md +0 -0
  499. /package/{get-shit-done → gsd-core}/templates/verification-report.md +0 -0
  500. /package/{get-shit-done → gsd-core}/workflows/analyze-dependencies.md +0 -0
  501. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/all.md +0 -0
  502. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/analyze.md +0 -0
  503. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/batch.md +0 -0
  504. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/default.md +0 -0
  505. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/text.md +0 -0
  506. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/checkpoint.json +0 -0
  507. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/context.md +0 -0
  508. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/discussion-log.md +0 -0
  509. /package/{get-shit-done → gsd-core}/workflows/discuss-phase-power.md +0 -0
  510. /package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -0
  511. /package/{get-shit-done → gsd-core}/workflows/fast.md +0 -0
  512. /package/{get-shit-done → gsd-core}/workflows/help/modes/brief.md +0 -0
  513. /package/{get-shit-done → gsd-core}/workflows/help/modes/default.md +0 -0
  514. /package/{get-shit-done → gsd-core}/workflows/help/modes/topic.md +0 -0
  515. /package/{get-shit-done → gsd-core}/workflows/help.md +0 -0
  516. /package/{get-shit-done → gsd-core}/workflows/inbox.md +0 -0
  517. /package/{get-shit-done → gsd-core}/workflows/list-phase-assumptions.md +0 -0
  518. /package/{get-shit-done → gsd-core}/workflows/node-repair.md +0 -0
  519. /package/{get-shit-done → gsd-core}/workflows/note.md +0 -0
  520. /package/{get-shit-done → gsd-core}/workflows/pr-branch.md +0 -0
  521. /package/{get-shit-done → gsd-core}/workflows/session-report.md +0 -0
@@ -0,0 +1,714 @@
1
+ "use strict";
2
+ /**
3
+ * Config — Planning config CRUD operations
4
+ *
5
+ * ADR-457 build-at-publish: the hand-written bin/lib/config.cjs collapsed
6
+ * to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
7
+ * from the prior hand-written .cjs; only strict types are added.
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ const node_fs_1 = __importDefault(require("node:fs"));
13
+ const node_path_1 = __importDefault(require("node:path"));
14
+ const node_os_1 = __importDefault(require("node:os"));
15
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
16
+ const core = require("./core.cjs");
17
+ const { output, error, ERROR_REASON, CONFIG_DEFAULTS } = core;
18
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
19
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
20
+ const planningWorkspace = require("./planning-workspace.cjs");
21
+ const { planningDir, withPlanningLock } = planningWorkspace;
22
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
23
+ const modelProfiles = require("./model-profiles.cjs");
24
+ const { VALID_PROFILES, getAgentToModelMapForProfile, formatAgentToModelMapAsTable } = modelProfiles;
25
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
26
+ const configSchema = require("./config-schema.cjs");
27
+ const { VALID_CONFIG_KEYS, isValidConfigKey } = configSchema;
28
+ const secrets_cjs_1 = require("./secrets.cjs");
29
+ const review_reviewer_selection_cjs_1 = require("./review-reviewer-selection.cjs");
30
+ const configuration_cjs_1 = require("./configuration.cjs");
31
+ // ─── Constants ────────────────────────────────────────────────────────────────
32
+ const CONFIG_KEY_SUGGESTIONS = {
33
+ 'workflow.nyquist_validation_enabled': 'workflow.nyquist_validation',
34
+ 'agents.nyquist_validation_enabled': 'workflow.nyquist_validation',
35
+ 'nyquist.validation_enabled': 'workflow.nyquist_validation',
36
+ 'hooks.research_questions': 'workflow.research_before_questions',
37
+ 'workflow.research_questions': 'workflow.research_before_questions',
38
+ 'workflow.codereview': 'workflow.code_review',
39
+ 'workflow.review_command': 'workflow.code_review_command',
40
+ 'workflow.review': 'workflow.code_review',
41
+ 'workflow.code_review_level': 'workflow.code_review_depth',
42
+ 'workflow.review_depth': 'workflow.code_review_depth',
43
+ 'review.model': 'review.models.<cli-name>',
44
+ 'sub_repos': 'planning.sub_repos',
45
+ 'plan_checker': 'workflow.plan_check',
46
+ };
47
+ const SHIP_PR_BODY_SECTION_KEYS = new Set(['heading', 'enabled', 'source', 'fallback', 'template']);
48
+ const SHIP_PR_BODY_TEMPLATE_TOKENS = new Set([
49
+ 'phase_number',
50
+ 'phase_name',
51
+ 'phase_dir',
52
+ 'base_branch',
53
+ 'padded_phase',
54
+ ]);
55
+ const SHIP_PR_BODY_SOURCE_RE = /^(ROADMAP|PLAN|SUMMARY|VERIFICATION|STATE|REQUIREMENTS|CONTEXT)\.md\s+##\s+[^\r\n#][^\r\n]*$/;
56
+ /**
57
+ * Schema-level defaults for well-known config keys.
58
+ * When a key is absent from config.json and no --default flag was supplied,
59
+ * cmdConfigGet checks here before emitting "Key not found".
60
+ */
61
+ const SCHEMA_DEFAULTS = {
62
+ 'context_window': 200000,
63
+ 'executor.stall_detect_interval_minutes': 5,
64
+ 'executor.stall_threshold_minutes': 10,
65
+ 'git.create_tag': true,
66
+ };
67
+ // ─── Validation helpers ───────────────────────────────────────────────────────
68
+ function validateKnownConfigKeyPath(keyPath) {
69
+ const suggested = CONFIG_KEY_SUGGESTIONS[keyPath];
70
+ if (suggested) {
71
+ error(`Unknown config key: ${keyPath}. Did you mean ${suggested}?`, ERROR_REASON.CONFIG_INVALID_KEY);
72
+ }
73
+ }
74
+ function validateShipPrBodySections(value) {
75
+ if (!Array.isArray(value)) {
76
+ error('Invalid ship.pr_body_sections value. Expected a JSON array of section objects.');
77
+ }
78
+ value.forEach((section, index) => {
79
+ const prefix = `Invalid ship.pr_body_sections[${index}]`;
80
+ if (!section || typeof section !== 'object' || Array.isArray(section)) {
81
+ error(`${prefix}. Expected an object.`);
82
+ }
83
+ const sectionObj = section;
84
+ const unknownKeys = Object.keys(sectionObj).filter((key) => !SHIP_PR_BODY_SECTION_KEYS.has(key));
85
+ if (unknownKeys.length > 0) {
86
+ error(`${prefix}. Unknown field(s): ${unknownKeys.join(', ')}.`);
87
+ }
88
+ if (typeof sectionObj['heading'] !== 'string' || sectionObj['heading'].trim() === '') {
89
+ error(`${prefix}. heading must be a non-empty string.`);
90
+ }
91
+ if (/[\r\n]/.test(sectionObj['heading'])) {
92
+ error(`${prefix}. heading must be a single line.`);
93
+ }
94
+ if ('enabled' in sectionObj && typeof sectionObj['enabled'] !== 'boolean') {
95
+ error(`${prefix}. enabled must be true or false.`);
96
+ }
97
+ for (const field of ['source', 'fallback', 'template']) {
98
+ if (field in sectionObj && typeof sectionObj[field] !== 'string') {
99
+ error(`${prefix}. ${field} must be a string.`);
100
+ }
101
+ }
102
+ const hasContent = ['source', 'fallback', 'template'].some((field) => {
103
+ const v = sectionObj[field];
104
+ return typeof v === 'string' && v.trim() !== '';
105
+ });
106
+ if (!hasContent) {
107
+ error(`${prefix}. Provide at least one of source, fallback, or template.`);
108
+ }
109
+ if (typeof sectionObj['source'] === 'string' && sectionObj['source'].trim() !== '') {
110
+ const selectors = sectionObj['source'].split('||').map((selector) => selector.trim()).filter(Boolean);
111
+ if (selectors.length === 0 || selectors.some((selector) => !SHIP_PR_BODY_SOURCE_RE.test(selector))) {
112
+ error(`${prefix}. source must use selectors like "PLAN.md ## Risks", separated with "||".`);
113
+ }
114
+ }
115
+ if (typeof sectionObj['template'] === 'string') {
116
+ const tokens = sectionObj['template'].matchAll(/\{([a-zA-Z][a-zA-Z0-9_]*)\}/g);
117
+ for (const match of tokens) {
118
+ if (!SHIP_PR_BODY_TEMPLATE_TOKENS.has(match[1])) {
119
+ error(`${prefix}. Unsupported template token: {${match[1]}}.`);
120
+ }
121
+ }
122
+ }
123
+ });
124
+ }
125
+ // ─── Core config operations ───────────────────────────────────────────────────
126
+ /**
127
+ * Build a fully-materialized config object for a new project.
128
+ *
129
+ * Merges (increasing priority):
130
+ * 1. Hardcoded defaults — every key that loadConfig() resolves, plus mode/granularity
131
+ * 2. User-level defaults from ~/.gsd/defaults.json (if present)
132
+ * 3. userChoices — the settings the user explicitly selected during /gsd:new-project
133
+ *
134
+ * Uses the canonical `git` namespace for branching keys (consistent with VALID_CONFIG_KEYS
135
+ * and the settings workflow). loadConfig() handles both flat and nested formats, so this
136
+ * is backward-compatible with existing projects that have flat keys.
137
+ *
138
+ * Returns a plain object — does NOT write any files.
139
+ */
140
+ function buildNewProjectConfig(userChoices) {
141
+ const choices = userChoices || {};
142
+ const homedir = node_os_1.default.homedir();
143
+ // Detect API key availability
144
+ const braveKeyFile = node_path_1.default.join(homedir, '.gsd', 'brave_api_key');
145
+ const hasBraveSearch = !!(process.env['BRAVE_API_KEY'] || node_fs_1.default.existsSync(braveKeyFile));
146
+ const firecrawlKeyFile = node_path_1.default.join(homedir, '.gsd', 'firecrawl_api_key');
147
+ const hasFirecrawl = !!(process.env['FIRECRAWL_API_KEY'] || node_fs_1.default.existsSync(firecrawlKeyFile));
148
+ const exaKeyFile = node_path_1.default.join(homedir, '.gsd', 'exa_api_key');
149
+ const hasExaSearch = !!(process.env['EXA_API_KEY'] || node_fs_1.default.existsSync(exaKeyFile));
150
+ // Load user-level defaults from ~/.gsd/defaults.json if available
151
+ const globalDefaultsPath = node_path_1.default.join(homedir, '.gsd', 'defaults.json');
152
+ let userDefaults = {};
153
+ try {
154
+ if (node_fs_1.default.existsSync(globalDefaultsPath)) {
155
+ userDefaults = JSON.parse(node_fs_1.default.readFileSync(globalDefaultsPath, 'utf-8'));
156
+ // Migrate deprecated "depth" key to "granularity"
157
+ if ('depth' in userDefaults && !('granularity' in userDefaults)) {
158
+ const depthToGranularity = { quick: 'coarse', standard: 'standard', comprehensive: 'fine' };
159
+ userDefaults['granularity'] = depthToGranularity[userDefaults['depth']] || userDefaults['depth'];
160
+ delete userDefaults['depth'];
161
+ try {
162
+ (0, shell_command_projection_cjs_1.platformWriteSync)(globalDefaultsPath, JSON.stringify(userDefaults, null, 2));
163
+ }
164
+ catch { /* intentionally empty */ }
165
+ }
166
+ }
167
+ }
168
+ catch {
169
+ // Ignore malformed global defaults
170
+ }
171
+ const hardcoded = {
172
+ model_profile: CONFIG_DEFAULTS.model_profile,
173
+ commit_docs: CONFIG_DEFAULTS.commit_docs,
174
+ parallelization: CONFIG_DEFAULTS.parallelization,
175
+ search_gitignored: CONFIG_DEFAULTS.search_gitignored,
176
+ brave_search: hasBraveSearch,
177
+ firecrawl: hasFirecrawl,
178
+ exa_search: hasExaSearch,
179
+ git: {
180
+ branching_strategy: CONFIG_DEFAULTS.branching_strategy,
181
+ create_tag: true,
182
+ phase_branch_template: CONFIG_DEFAULTS.phase_branch_template,
183
+ milestone_branch_template: CONFIG_DEFAULTS.milestone_branch_template,
184
+ quick_branch_template: CONFIG_DEFAULTS.quick_branch_template,
185
+ },
186
+ workflow: {
187
+ research: true,
188
+ plan_check: true,
189
+ verifier: true,
190
+ nyquist_validation: true,
191
+ auto_advance: false,
192
+ node_repair: true,
193
+ node_repair_budget: 2,
194
+ ui_phase: true,
195
+ ui_safety_gate: true,
196
+ ai_integration_phase: true,
197
+ tdd_mode: false,
198
+ human_verify_mode: 'end-of-phase',
199
+ text_mode: false,
200
+ research_before_questions: false,
201
+ discuss_mode: 'discuss',
202
+ skip_discuss: false,
203
+ code_review: true,
204
+ code_review_depth: 'standard',
205
+ code_review_command: null,
206
+ pattern_mapper: true,
207
+ plan_bounce: false,
208
+ plan_bounce_script: null,
209
+ plan_bounce_passes: 2,
210
+ auto_prune_state: false,
211
+ post_planning_gaps: CONFIG_DEFAULTS.post_planning_gaps,
212
+ security_enforcement: CONFIG_DEFAULTS.security_enforcement,
213
+ security_asvs_level: CONFIG_DEFAULTS.security_asvs_level,
214
+ security_block_on: CONFIG_DEFAULTS.security_block_on,
215
+ },
216
+ ship: {
217
+ pr_body_sections: [],
218
+ },
219
+ hooks: {
220
+ context_warnings: true,
221
+ },
222
+ project_code: null,
223
+ phase_naming: 'sequential',
224
+ agent_skills: {},
225
+ claude_md_path: './CLAUDE.md',
226
+ plan_review: {
227
+ source_grounding: true,
228
+ source_grounding_authority: 'grep',
229
+ },
230
+ };
231
+ const ud = userDefaults;
232
+ const ch = choices;
233
+ const hd = hardcoded;
234
+ // Three-level deep merge: hardcoded <- userDefaults <- choices
235
+ const config = {
236
+ ...hardcoded,
237
+ ...userDefaults,
238
+ ...choices,
239
+ git: {
240
+ ...hd['git'],
241
+ ...(ud['git'] || {}),
242
+ ...(ch['git'] || {}),
243
+ },
244
+ workflow: {
245
+ ...hd['workflow'],
246
+ ...(ud['workflow'] || {}),
247
+ ...(ch['workflow'] || {}),
248
+ },
249
+ ship: {
250
+ ...hd['ship'],
251
+ ...(ud['ship'] || {}),
252
+ ...(ch['ship'] || {}),
253
+ },
254
+ hooks: {
255
+ ...hd['hooks'],
256
+ ...(ud['hooks'] || {}),
257
+ ...(ch['hooks'] || {}),
258
+ },
259
+ agent_skills: {
260
+ ...hd['agent_skills'],
261
+ ...(ud['agent_skills'] || {}),
262
+ ...(ch['agent_skills'] || {}),
263
+ },
264
+ plan_review: {
265
+ ...hd['plan_review'],
266
+ ...(ud['plan_review'] || {}),
267
+ ...(ch['plan_review'] || {}),
268
+ },
269
+ };
270
+ validateShipPrBodySections(config['ship']['pr_body_sections']);
271
+ return config;
272
+ }
273
+ /**
274
+ * Command: create a fully-materialized .planning/config.json for a new project.
275
+ *
276
+ * Accepts user-chosen settings as a JSON string (the keys the user explicitly
277
+ * configured during /gsd:new-project). All remaining keys are filled from
278
+ * hardcoded defaults and optional ~/.gsd/defaults.json.
279
+ *
280
+ * Idempotent: if config.json already exists, returns { created: false }.
281
+ */
282
+ function cmdConfigNewProject(cwd, choicesJson, raw) {
283
+ const planningBase = planningDir(cwd);
284
+ const configPath = node_path_1.default.join(planningBase, 'config.json');
285
+ // Idempotent: don't overwrite existing config
286
+ if (node_fs_1.default.existsSync(configPath)) {
287
+ output({ created: false, reason: 'already_exists' }, raw, 'exists');
288
+ return;
289
+ }
290
+ // Parse user choices
291
+ let userChoices = {};
292
+ if (choicesJson && choicesJson.trim() !== '') {
293
+ try {
294
+ userChoices = JSON.parse(choicesJson);
295
+ }
296
+ catch (err) {
297
+ error('Invalid JSON for config-new-project: ' + err.message);
298
+ }
299
+ }
300
+ // Ensure .planning directory exists
301
+ try {
302
+ (0, shell_command_projection_cjs_1.platformEnsureDir)(planningBase);
303
+ }
304
+ catch (err) {
305
+ error('Failed to create .planning directory: ' + err.message);
306
+ }
307
+ const config = buildNewProjectConfig(userChoices);
308
+ try {
309
+ (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(config, null, 2));
310
+ output({ created: true, path: '.planning/config.json' }, raw, 'created');
311
+ }
312
+ catch (err) {
313
+ error('Failed to write config.json: ' + err.message);
314
+ }
315
+ }
316
+ /**
317
+ * Ensures the config file exists (creates it if needed).
318
+ *
319
+ * Does not call `output()`, so can be used as one step in a command without triggering `exit(0)` in
320
+ * the happy path. But note that `error()` will still `exit(1)` out of the process.
321
+ */
322
+ function ensureConfigFile(cwd) {
323
+ const planningBase = planningDir(cwd);
324
+ const configPath = node_path_1.default.join(planningBase, 'config.json');
325
+ // Ensure .planning directory exists
326
+ try {
327
+ (0, shell_command_projection_cjs_1.platformEnsureDir)(planningBase);
328
+ }
329
+ catch (err) {
330
+ error('Failed to create .planning directory: ' + err.message);
331
+ }
332
+ // Check if config already exists
333
+ if (node_fs_1.default.existsSync(configPath)) {
334
+ return { created: false, reason: 'already_exists' };
335
+ }
336
+ const config = buildNewProjectConfig({});
337
+ try {
338
+ (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(config, null, 2));
339
+ return { created: true, path: '.planning/config.json' };
340
+ }
341
+ catch (err) {
342
+ error('Failed to create config.json: ' + err.message);
343
+ }
344
+ }
345
+ /**
346
+ * Command to ensure the config file exists (creates it if needed).
347
+ *
348
+ * Note that this exits the process (via `output()`) even in the happy path; use
349
+ * `ensureConfigFile()` directly if you need to avoid this.
350
+ */
351
+ function cmdConfigEnsureSection(cwd, raw) {
352
+ const ensureConfigFileResult = ensureConfigFile(cwd);
353
+ if (ensureConfigFileResult && ensureConfigFileResult.created) {
354
+ output(ensureConfigFileResult, raw, 'created');
355
+ }
356
+ else {
357
+ output(ensureConfigFileResult, raw, 'exists');
358
+ }
359
+ }
360
+ /**
361
+ * Sets a value in the config file, allowing nested values via dot notation (e.g.,
362
+ * "workflow.research").
363
+ *
364
+ * Does not call `output()`, so can be used as one step in a command without triggering `exit(0)` in
365
+ * the happy path. But note that `error()` will still `exit(1)` out of the process.
366
+ */
367
+ function setConfigValue(cwd, keyPath, parsedValue) {
368
+ const configPath = node_path_1.default.join(planningDir(cwd), 'config.json');
369
+ return withPlanningLock(cwd, () => {
370
+ // Load existing config or start with empty object
371
+ let config = {};
372
+ try {
373
+ if (node_fs_1.default.existsSync(configPath)) {
374
+ config = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
375
+ }
376
+ }
377
+ catch (err) {
378
+ error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
379
+ }
380
+ // Set nested value using dot notation (e.g., "workflow.research")
381
+ const keys = keyPath.split('.');
382
+ let current = config;
383
+ for (let i = 0; i < keys.length - 1; i++) {
384
+ const key = keys[i];
385
+ if (current[key] === undefined || typeof current[key] !== 'object') {
386
+ current[key] = {};
387
+ }
388
+ current = current[key];
389
+ }
390
+ const previousValue = current[keys[keys.length - 1]]; // Capture previous value before overwriting
391
+ current[keys[keys.length - 1]] = parsedValue;
392
+ // Write back
393
+ try {
394
+ (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(config, null, 2));
395
+ return { updated: true, key: keyPath, value: parsedValue, previousValue };
396
+ }
397
+ catch (err) {
398
+ error('Failed to write config.json: ' + err.message);
399
+ }
400
+ });
401
+ }
402
+ /**
403
+ * Command to set a value in the config file, allowing nested values via dot notation (e.g.,
404
+ * "workflow.research").
405
+ *
406
+ * Note that this exits the process (via `output()`) even in the happy path; use `setConfigValue()`
407
+ * directly if you need to avoid this.
408
+ */
409
+ function cmdConfigSet(cwd, keyPath, value, raw) {
410
+ if (!keyPath) {
411
+ error('Usage: config-set <key.path> <value>', ERROR_REASON.USAGE);
412
+ }
413
+ // #3593: reject the "key without value" form (e.g. `config-set
414
+ // model_profile` with args[2] === undefined). Without this guard the
415
+ // value passes through as undefined, the number/boolean/json branches
416
+ // all fall through, and the write either silently strips the key
417
+ // (JSON.stringify drops undefined values) or writes a corrupt entry.
418
+ // Typed reason so the negative-matrix test can assert on it instead
419
+ // of greppinng prose.
420
+ if (value === undefined) {
421
+ error('Usage: config-set <key.path> <value>', ERROR_REASON.USAGE);
422
+ }
423
+ // After the two error() guards above, keyPath and value are narrowed to string.
424
+ // TypeScript doesn't always infer never-return narrowing through error(), so we assert.
425
+ const kp = keyPath;
426
+ const val = value;
427
+ validateKnownConfigKeyPath(kp);
428
+ if (!isValidConfigKey(kp)) {
429
+ error(`Unknown config key: "${kp}". Valid keys: ${[...VALID_CONFIG_KEYS].sort().join(', ')}, agent_skills.<agent-type>, features.<feature_name>`, ERROR_REASON.CONFIG_INVALID_KEY);
430
+ }
431
+ // Parse value (handle booleans, numbers, and JSON arrays/objects)
432
+ let parsedValue = val;
433
+ if (val === 'true')
434
+ parsedValue = true;
435
+ else if (val === 'false')
436
+ parsedValue = false;
437
+ else if (!isNaN(Number(val)) && val !== '')
438
+ parsedValue = Number(val);
439
+ else if (typeof val === 'string' && (val.startsWith('[') || val.startsWith('{'))) {
440
+ try {
441
+ parsedValue = JSON.parse(val);
442
+ }
443
+ catch { /* keep as string */ }
444
+ }
445
+ const VALID_CONTEXT_VALUES = ['dev', 'research', 'review'];
446
+ if (kp === 'context' && !VALID_CONTEXT_VALUES.includes(String(parsedValue))) {
447
+ error(`Invalid context value '${val}'. Valid values: ${VALID_CONTEXT_VALUES.join(', ')}`);
448
+ }
449
+ // Codebase drift detector (#2003)
450
+ const VALID_DRIFT_ACTIONS = ['warn', 'auto-remap'];
451
+ if (kp === 'workflow.drift_action' && !VALID_DRIFT_ACTIONS.includes(String(parsedValue))) {
452
+ error(`Invalid workflow.drift_action '${val}'. Valid values: ${VALID_DRIFT_ACTIONS.join(', ')}`);
453
+ }
454
+ if (kp === 'workflow.drift_threshold') {
455
+ if (typeof parsedValue !== 'number' || !Number.isInteger(parsedValue) || parsedValue < 1) {
456
+ error(`Invalid workflow.drift_threshold '${val}'. Must be a positive integer.`);
457
+ }
458
+ }
459
+ // Post-planning gap checker (#2493)
460
+ if (kp === 'workflow.post_planning_gaps') {
461
+ if (typeof parsedValue !== 'boolean') {
462
+ error(`Invalid workflow.post_planning_gaps '${val}'. Must be a boolean (true or false).`);
463
+ }
464
+ }
465
+ // #3086 — git.create_tag: boolean only
466
+ if (kp === 'git.create_tag') {
467
+ if (typeof parsedValue !== 'boolean') {
468
+ error(`Invalid git.create_tag '${val}'. Must be a boolean (true or false).`);
469
+ }
470
+ }
471
+ if (kp === 'ship.pr_body_sections') {
472
+ validateShipPrBodySections(parsedValue);
473
+ }
474
+ // Human verification checkpoint mode (#3309)
475
+ const VALID_HUMAN_VERIFY_MODES = ['mid-flight', 'end-of-phase'];
476
+ if (kp === 'workflow.human_verify_mode' && !VALID_HUMAN_VERIFY_MODES.includes(String(parsedValue))) {
477
+ error(`Invalid workflow.human_verify_mode '${val}'. Valid values: ${VALID_HUMAN_VERIFY_MODES.join(', ')}`);
478
+ }
479
+ // Context position enum validation (#2937)
480
+ const VALID_CONTEXT_POSITIONS = ['front', 'end'];
481
+ if (kp === 'statusline.context_position' && !VALID_CONTEXT_POSITIONS.includes(String(parsedValue))) {
482
+ error(`Invalid statusline.context_position '${val}'. Valid values: ${VALID_CONTEXT_POSITIONS.join(', ')}`);
483
+ }
484
+ // Fallow scope + profile enum validation (#3424)
485
+ const VALID_FALLOW_SCOPES = ['phase', 'repo'];
486
+ if (kp === 'code_quality.fallow.scope' && !VALID_FALLOW_SCOPES.includes(String(parsedValue))) {
487
+ error(`Invalid code_quality.fallow.scope '${val}'. Valid values: ${VALID_FALLOW_SCOPES.join(', ')}`);
488
+ }
489
+ const VALID_FALLOW_PROFILES = ['minimal', 'standard', 'strict'];
490
+ if (kp === 'code_quality.fallow.profile' && !VALID_FALLOW_PROFILES.includes(String(parsedValue))) {
491
+ error(`Invalid code_quality.fallow.profile '${val}'. Valid values: ${VALID_FALLOW_PROFILES.join(', ')}`);
492
+ }
493
+ // plan_review.source_grounding (#22) — boolean only
494
+ if (kp === 'plan_review.source_grounding') {
495
+ if (typeof parsedValue !== 'boolean') {
496
+ error(`Invalid plan_review.source_grounding '${val}'. Must be a boolean (true or false).`);
497
+ }
498
+ }
499
+ // plan_review.source_grounding_authority (#22) — enum
500
+ const VALID_SOURCE_GROUNDING_AUTHORITIES = ['grep', 'intel', 'treesitter', 'lsp', 'scip'];
501
+ if (kp === 'plan_review.source_grounding_authority' && !VALID_SOURCE_GROUNDING_AUTHORITIES.includes(String(parsedValue))) {
502
+ error(`Invalid plan_review.source_grounding_authority '${val}'. Valid values: ${VALID_SOURCE_GROUNDING_AUTHORITIES.join(', ')}`);
503
+ }
504
+ if (kp === 'review.default_reviewers') {
505
+ const normalized = (0, review_reviewer_selection_cjs_1.normalizeConfiguredDefaultReviewers)(parsedValue);
506
+ if (normalized.errors.length > 0) {
507
+ error(normalized.errors[0]);
508
+ }
509
+ parsedValue = normalized.values;
510
+ }
511
+ const setConfigValueResult = setConfigValue(cwd, kp, parsedValue);
512
+ // Mask secrets in both JSON and text output. The plaintext is written
513
+ // to config.json (that's where secrets live on disk); the CLI output
514
+ // must never echo it. See lib/secrets.cjs.
515
+ if ((0, secrets_cjs_1.isSecretKey)(kp)) {
516
+ // parsedValue is unknown at this point; maskSecret accepts MaskableValue
517
+ const masked = (0, secrets_cjs_1.maskSecret)(parsedValue);
518
+ const maskedPrev = setConfigValueResult.previousValue === undefined
519
+ ? undefined
520
+ : (0, secrets_cjs_1.maskSecret)(setConfigValueResult.previousValue);
521
+ const maskedResult = {
522
+ ...setConfigValueResult,
523
+ value: masked,
524
+ previousValue: maskedPrev,
525
+ masked: true,
526
+ };
527
+ output(maskedResult, raw, `${kp}=${masked}`);
528
+ return;
529
+ }
530
+ output(setConfigValueResult, raw, `${kp}=${String(parsedValue)}`);
531
+ }
532
+ function cmdConfigGet(cwd, keyPath, raw, defaultValue) {
533
+ const configPath = node_path_1.default.join(planningDir(cwd), 'config.json');
534
+ const hasDefault = defaultValue !== undefined;
535
+ if (!keyPath) {
536
+ error('Usage: config-get <key.path> [--default <value>]');
537
+ }
538
+ // After the error() guard, keyPath is narrowed to string.
539
+ const kp = keyPath;
540
+ let config = {};
541
+ try {
542
+ if (node_fs_1.default.existsSync(configPath)) {
543
+ config = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
544
+ }
545
+ else if (hasDefault) {
546
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
547
+ output(defaultValue, raw, String(defaultValue));
548
+ return;
549
+ }
550
+ else if (Object.prototype.hasOwnProperty.call(SCHEMA_DEFAULTS, kp)) {
551
+ const def = SCHEMA_DEFAULTS[kp];
552
+ output(def, raw, String(def));
553
+ return;
554
+ }
555
+ else {
556
+ error('No config.json found at ' + configPath, ERROR_REASON.CONFIG_NO_FILE);
557
+ }
558
+ }
559
+ catch (err) {
560
+ if (err.message.startsWith('No config.json'))
561
+ throw err;
562
+ error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
563
+ }
564
+ // Traverse dot-notation path (e.g., "workflow.auto_advance")
565
+ const keys = kp.split('.');
566
+ let current = config;
567
+ for (const key of keys) {
568
+ if (current === undefined || current === null || typeof current !== 'object') {
569
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
570
+ if (hasDefault) {
571
+ output(defaultValue, raw, String(defaultValue));
572
+ return;
573
+ }
574
+ if (Object.prototype.hasOwnProperty.call(SCHEMA_DEFAULTS, kp)) {
575
+ const def = SCHEMA_DEFAULTS[kp];
576
+ output(def, raw, String(def));
577
+ return;
578
+ }
579
+ error(`Key not found: ${kp}`, ERROR_REASON.CONFIG_KEY_NOT_FOUND);
580
+ }
581
+ current = current[key];
582
+ }
583
+ if (current === undefined) {
584
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
585
+ if (hasDefault) {
586
+ output(defaultValue, raw, String(defaultValue));
587
+ return;
588
+ }
589
+ if (Object.prototype.hasOwnProperty.call(SCHEMA_DEFAULTS, kp)) {
590
+ const def = SCHEMA_DEFAULTS[kp];
591
+ output(def, raw, String(def));
592
+ return;
593
+ }
594
+ error(`Key not found: ${kp}`, ERROR_REASON.CONFIG_KEY_NOT_FOUND);
595
+ }
596
+ // Never echo plaintext for sensitive keys via config-get. Plaintext lives
597
+ // in config.json on disk; the CLI surface always shows the masked form.
598
+ if ((0, secrets_cjs_1.isSecretKey)(kp)) {
599
+ const masked = (0, secrets_cjs_1.maskSecret)(current);
600
+ output(masked, raw, masked);
601
+ return;
602
+ }
603
+ output(current, raw, String(current));
604
+ }
605
+ /**
606
+ * Command to set the model profile in the config file.
607
+ *
608
+ * Note that this exits the process (via `output()`) even in the happy path.
609
+ */
610
+ function cmdConfigSetModelProfile(cwd, profile, raw) {
611
+ if (!profile) {
612
+ error(`Usage: config-set-model-profile <${VALID_PROFILES.join('|')}>`);
613
+ }
614
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
615
+ const normalizedProfile = profile.toLowerCase().trim();
616
+ if (!VALID_PROFILES.includes(normalizedProfile)) {
617
+ error(`Invalid profile '${String(profile)}'. Valid profiles: ${VALID_PROFILES.join(', ')}`);
618
+ }
619
+ // Ensure config exists (create if needed)
620
+ ensureConfigFile(cwd);
621
+ // Set the model profile in the config
622
+ const { previousValue } = setConfigValue(cwd, 'model_profile', normalizedProfile);
623
+ const previousProfile = typeof previousValue === 'string' ? previousValue : 'balanced';
624
+ // Build result value / message and return
625
+ const agentToModelMap = getAgentToModelMapForProfile(normalizedProfile);
626
+ const result = {
627
+ updated: true,
628
+ profile: normalizedProfile,
629
+ previousProfile,
630
+ agentToModelMap,
631
+ };
632
+ const rawValue = getCmdConfigSetModelProfileResultMessage(normalizedProfile, previousProfile, agentToModelMap);
633
+ output(result, raw, rawValue);
634
+ }
635
+ /**
636
+ * Returns the message to display for the result of the `config-set-model-profile` command when
637
+ * displaying raw output.
638
+ */
639
+ function getCmdConfigSetModelProfileResultMessage(normalizedProfile, previousProfile, agentToModelMap) {
640
+ const agentToModelTable = formatAgentToModelMapAsTable(agentToModelMap);
641
+ const didChange = previousProfile !== normalizedProfile;
642
+ const paragraphs = didChange
643
+ ? [
644
+ `✓ Model profile set to: ${normalizedProfile} (was: ${previousProfile})`,
645
+ 'Agents will now use:',
646
+ agentToModelTable,
647
+ 'Next spawned agents will use the new profile.',
648
+ ]
649
+ : [
650
+ `✓ Model profile is already set to: ${normalizedProfile}`,
651
+ 'Agents are using:',
652
+ agentToModelTable,
653
+ ];
654
+ return paragraphs.join('\n\n');
655
+ }
656
+ /**
657
+ * Print the resolved config.json path (workstream-aware). Used by settings.md
658
+ * so the workflow writes/reads the correct file when a workstream is active (#2282).
659
+ */
660
+ function cmdConfigPath(cwd, _raw, workstreamContext = null) {
661
+ // Always emit as plain text — a file path is used via shell substitution,
662
+ // never consumed as JSON. Passing raw=true forces plain-text output.
663
+ const configPath = workstreamContext && workstreamContext.configPath
664
+ ? workstreamContext.configPath
665
+ : node_path_1.default.join(planningDir(cwd), 'config.json');
666
+ output(configPath, true, configPath);
667
+ }
668
+ /**
669
+ * Explicit on-disk migration of legacy config keys to canonical nested shape.
670
+ *
671
+ * Wraps the Configuration Module's migrateOnDisk() for the CLI surface. This
672
+ * is the Phase 2 acceptance-criteria deliverable for opt-in migration (#3536):
673
+ * users can run `gsd-tools migrate-config` to apply all four legacy-key
674
+ * migrations to their .planning/config.json without having to load any config
675
+ * implicitly via another command.
676
+ *
677
+ * Output: JSON object with { migrated, normalizations, wrote } or a human-readable
678
+ * summary when --raw is set. Exits 0 in all cases (including no-op).
679
+ *
680
+ * Note: migrateOnDisk() is synchronous; the original CJS used async for
681
+ * forward-compatibility but no await is needed. Dropped async per ADR-457 policy
682
+ * (caller uses `await` which is safe on a sync return value).
683
+ */
684
+ function cmdMigrateConfig(cwd, raw) {
685
+ const ws = process.env['GSD_WORKSTREAM'] || null;
686
+ const report = (0, configuration_cjs_1.migrateOnDisk)(cwd, ws || undefined);
687
+ if (raw) {
688
+ if (!report.migrated) {
689
+ const msg = 'No legacy keys found — config is already canonical.';
690
+ output(msg, true, msg);
691
+ }
692
+ else {
693
+ const lines = [
694
+ `Migrated: ${String(report.wrote)}`,
695
+ ...report.normalizations.map(n => ` ${n.from} → ${n.to}`),
696
+ ].join('\n');
697
+ output(lines, true, lines);
698
+ }
699
+ }
700
+ else {
701
+ // output() JSON.stringify's its first arg when raw=false; pass the report object.
702
+ output(report, false, report);
703
+ }
704
+ }
705
+ module.exports = {
706
+ VALID_CONFIG_KEYS,
707
+ cmdConfigEnsureSection,
708
+ cmdConfigSet,
709
+ cmdConfigGet,
710
+ cmdConfigSetModelProfile,
711
+ cmdConfigNewProject,
712
+ cmdConfigPath,
713
+ cmdMigrateConfig,
714
+ };