@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,1799 @@
1
+ "use strict";
2
+ /**
3
+ * Init — Compound init commands for workflow bootstrapping
4
+ *
5
+ * ADR-457 build-at-publish: the hand-written bin/lib/init.cjs collapsed to
6
+ * a TypeScript source of truth, compiled by tsc to a gitignored .cjs at the
7
+ * same require() path. Behaviour preserved byte-for-behaviour; only 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
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
16
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- core.cjs is an export= CommonJS module
17
+ const core = require("./core.cjs");
18
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module
19
+ const planningWorkspace = require("./planning-workspace.cjs");
20
+ const secrets_cjs_1 = require("./secrets.cjs");
21
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- plan-scan.cjs is an export= CommonJS module
22
+ const scanPhasePlans = require("./plan-scan.cjs");
23
+ const state_document_cjs_1 = require("./state-document.cjs");
24
+ const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
25
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- commands.cjs is an export= CommonJS module
26
+ const commandsMod = require("./commands.cjs");
27
+ const security_cjs_1 = require("./security.cjs");
28
+ const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
29
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- frontmatter.cjs is an export= CommonJS module
30
+ const frontmatterMod = require("./frontmatter.cjs");
31
+ const { loadConfig, resolveModelInternal, findPhaseInternal, getRoadmapPhaseInternal, pathExistsInternal, gitWorktreeInfoInternal, generateSlugInternal, getMilestoneInfo, getMilestonePhaseFilter, stripShippedMilestones, extractCurrentMilestone, normalizePhaseName, toPosixPath, output, error, checkAgentsInstalled, phaseTokenMatches, } = core;
32
+ const { planningPaths, planningDir, planningRoot, findContextMdIn, } = planningWorkspace;
33
+ const { determinePhaseStatus } = commandsMod;
34
+ const { extractFrontmatter } = frontmatterMod;
35
+ // Unused but imported for structural parity
36
+ void stripShippedMilestones;
37
+ // Accept all bold/colon variants of the Requirements header (#2769)
38
+ const REQUIREMENTS_HEADER_RE = /^\*\*Requirements:?\*\*[^\S\n]*:?[^\S\n]*([^\n]*)$/m;
39
+ function listPhaseSummaryFiles(phaseDir) {
40
+ return scanPhasePlans(phaseDir)['summaryFiles'];
41
+ }
42
+ function listPhasePlanFiles(phaseDir) {
43
+ return scanPhasePlans(phaseDir)['planFiles'];
44
+ }
45
+ function getLatestCompletedMilestone(cwd) {
46
+ const milestonesPath = node_path_1.default.join(planningRoot(cwd), 'MILESTONES.md');
47
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(milestonesPath);
48
+ if (content === null)
49
+ return null;
50
+ const match = content.match(/^##\s+(v[\d.]+)\s+(.+?)\s+\(Shipped:/m);
51
+ if (!match)
52
+ return null;
53
+ return {
54
+ version: match[1],
55
+ name: match[2].trim(),
56
+ };
57
+ }
58
+ function withProjectRoot(cwd, result) {
59
+ result['project_root'] = cwd;
60
+ const activeRuntime = (0, runtime_slash_cjs_1.resolveRuntime)(cwd);
61
+ const agentStatus = checkAgentsInstalled(activeRuntime);
62
+ result['agents_installed'] = agentStatus.agents_installed;
63
+ result['missing_agents'] = agentStatus.missing_agents;
64
+ result['agents_dir'] = agentStatus.agents_dir;
65
+ result['agent_runtime'] = agentStatus.agent_runtime;
66
+ const config = loadConfig(cwd);
67
+ if (config.response_language) {
68
+ result['response_language'] = config.response_language;
69
+ }
70
+ if (config.project_code) {
71
+ result['project_code'] = config.project_code;
72
+ }
73
+ const projectMdPath = node_path_1.default.join(planningDir(cwd), 'PROJECT.md');
74
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(projectMdPath);
75
+ if (content) {
76
+ const h1Match = content.match(/^#\s+(.+)$/m);
77
+ if (h1Match) {
78
+ result['project_title'] = h1Match[1].trim();
79
+ }
80
+ }
81
+ return result;
82
+ }
83
+ function getInitGitState(cwd) {
84
+ const info = gitWorktreeInfoInternal(cwd);
85
+ const worktreeRoot = info['worktreeRoot'];
86
+ const normalizeForCompare = (p) => {
87
+ if (typeof p !== 'string' || p.length === 0)
88
+ return null;
89
+ let resolved;
90
+ try {
91
+ resolved = node_fs_1.default.realpathSync.native(p);
92
+ }
93
+ catch {
94
+ resolved = node_path_1.default.resolve(p);
95
+ }
96
+ resolved = node_path_1.default.resolve(resolved);
97
+ if (process.platform === 'win32') {
98
+ return resolved.replace(/\//g, '\\').toLowerCase();
99
+ }
100
+ return resolved;
101
+ };
102
+ let inNestedSubdir = false;
103
+ if (info['inside']) {
104
+ let resolvedByGitPrefix = false;
105
+ try {
106
+ const prefixResult = (0, shell_command_projection_cjs_1.execGit)(['rev-parse', '--show-prefix'], { cwd, timeout: 5000 });
107
+ if (prefixResult['exitCode'] === 0) {
108
+ const prefix = (typeof prefixResult['stdout'] === 'string' ? prefixResult['stdout'] : '').trim().replace(/\\/g, '/');
109
+ inNestedSubdir = prefix.length > 0 && prefix !== '.' && prefix !== './';
110
+ resolvedByGitPrefix = true;
111
+ }
112
+ }
113
+ catch {
114
+ /* intentionally empty */
115
+ }
116
+ if (!resolvedByGitPrefix) {
117
+ const rootNorm = normalizeForCompare(worktreeRoot);
118
+ const cwdNorm = normalizeForCompare(cwd);
119
+ if (rootNorm && cwdNorm) {
120
+ if (rootNorm === cwdNorm) {
121
+ inNestedSubdir = false;
122
+ }
123
+ else {
124
+ const rel = node_path_1.default.relative(rootNorm, cwdNorm);
125
+ const relNorm = process.platform === 'win32' ? rel.replace(/\//g, '\\') : rel;
126
+ inNestedSubdir =
127
+ relNorm !== '' &&
128
+ relNorm !== '.' &&
129
+ !relNorm.startsWith('..') &&
130
+ !node_path_1.default.isAbsolute(relNorm);
131
+ }
132
+ }
133
+ else {
134
+ inNestedSubdir = worktreeRoot !== null;
135
+ }
136
+ }
137
+ }
138
+ if (inNestedSubdir && typeof worktreeRoot === 'string') {
139
+ const toComparableRaw = (p) => p.replace(/\\/g, '/').replace(/\/+$/g, '').toLowerCase();
140
+ if (toComparableRaw(worktreeRoot) === toComparableRaw(String(cwd))) {
141
+ inNestedSubdir = false;
142
+ }
143
+ }
144
+ return {
145
+ has_git: info['inside'],
146
+ git_worktree_root: worktreeRoot,
147
+ in_nested_subdir: inNestedSubdir,
148
+ };
149
+ }
150
+ function cmdInitExecutePhase(cwd, phase, raw, options = {}) {
151
+ if (!phase) {
152
+ error('phase required for init execute-phase');
153
+ }
154
+ const config = loadConfig(cwd);
155
+ let phaseInfo = findPhaseInternal(cwd, phase);
156
+ const milestone = getMilestoneInfo(cwd);
157
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
158
+ if (phaseInfo?.['archived'] && roadmapPhase?.['found']) {
159
+ phaseInfo = null;
160
+ }
161
+ if (!phaseInfo && roadmapPhase?.['found']) {
162
+ const phaseName = roadmapPhase['phase_name'];
163
+ phaseInfo = {
164
+ found: true,
165
+ directory: null,
166
+ phase_number: roadmapPhase['phase_number'],
167
+ phase_name: phaseName,
168
+ phase_slug: phaseName
169
+ ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
170
+ : null,
171
+ plans: [],
172
+ summaries: [],
173
+ incomplete_plans: [],
174
+ has_research: false,
175
+ has_context: false,
176
+ has_verification: false,
177
+ has_reviews: false,
178
+ };
179
+ }
180
+ const reqMatch = roadmapPhase?.['section']?.match(REQUIREMENTS_HEADER_RE);
181
+ const reqExtracted = reqMatch
182
+ ? reqMatch[1].replace(/[\[\]]/g, '').split(',').map((s) => s.trim()).filter(Boolean).join(', ')
183
+ : null;
184
+ const phase_req_ids = reqExtracted && reqExtracted !== 'TBD' ? reqExtracted : null;
185
+ const result = {
186
+ executor_model: resolveModelInternal(cwd, 'gsd-executor'),
187
+ verifier_model: resolveModelInternal(cwd, 'gsd-verifier'),
188
+ tdd_mode: options['tdd'] || config.tdd_mode || false,
189
+ commit_docs: config.commit_docs,
190
+ sub_repos: config.sub_repos,
191
+ parallelization: config.parallelization,
192
+ context_window: config.context_window,
193
+ branching_strategy: config.branching_strategy,
194
+ phase_branch_template: config.phase_branch_template,
195
+ milestone_branch_template: config.milestone_branch_template,
196
+ verifier_enabled: config.verifier,
197
+ phase_found: !!phaseInfo,
198
+ phase_dir: phaseInfo?.['directory'] || null,
199
+ phase_number: phaseInfo?.['phase_number'] || null,
200
+ phase_name: phaseInfo?.['phase_name'] || null,
201
+ phase_slug: phaseInfo?.['phase_slug'] || null,
202
+ phase_req_ids,
203
+ plans: phaseInfo?.['plans'] || [],
204
+ summaries: phaseInfo?.['summaries'] || [],
205
+ incomplete_plans: phaseInfo?.['incomplete_plans'] || [],
206
+ plan_count: phaseInfo?.['plans']?.length || 0,
207
+ incomplete_count: phaseInfo?.['incomplete_plans']?.length || 0,
208
+ branch_name: config.branching_strategy === 'phase' && phaseInfo
209
+ ? config.phase_branch_template
210
+ .replace('{project}', config.project_code || '')
211
+ .replace('{phase}', phaseInfo['phase_number'])
212
+ .replace('{slug}', phaseInfo['phase_slug'] || 'phase')
213
+ : config.branching_strategy === 'milestone'
214
+ ? config.milestone_branch_template
215
+ .replace('{milestone}', milestone['version'])
216
+ .replace('{slug}', generateSlugInternal(milestone['name']) || 'milestone')
217
+ : null,
218
+ milestone_version: milestone['version'],
219
+ milestone_name: milestone['name'],
220
+ milestone_slug: generateSlugInternal(milestone['name']),
221
+ state_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'STATE.md')),
222
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
223
+ config_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'config.json')),
224
+ state_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'STATE.md'))),
225
+ roadmap_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'))),
226
+ config_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'config.json'))),
227
+ };
228
+ if (options['validate']) {
229
+ try {
230
+ const statePath = node_path_1.default.join(planningDir(cwd), 'STATE.md');
231
+ const stateContent = (0, shell_command_projection_cjs_1.platformReadSync)(statePath);
232
+ if (stateContent !== null) {
233
+ result['state_validation_ran'] = true;
234
+ const stateWarnings = [];
235
+ if (phaseInfo?.['directory'] && node_fs_1.default.existsSync(node_path_1.default.join(cwd, phaseInfo['directory']))) {
236
+ const diskPlans = listPhasePlanFiles(node_path_1.default.join(cwd, phaseInfo['directory'])).length;
237
+ const totalPlansRaw = (0, state_document_cjs_1.stateExtractField)(stateContent, 'Total Plans in Phase');
238
+ const totalPlansInPhase = totalPlansRaw ? parseInt(totalPlansRaw, 10) : null;
239
+ if (totalPlansInPhase !== null && diskPlans !== totalPlansInPhase) {
240
+ stateWarnings.push(`Plan count mismatch: STATE.md says ${totalPlansInPhase}, disk has ${diskPlans}`);
241
+ }
242
+ }
243
+ result['state_warnings'] = stateWarnings;
244
+ }
245
+ }
246
+ catch {
247
+ /* intentionally empty */
248
+ }
249
+ }
250
+ output(withProjectRoot(cwd, result), raw);
251
+ }
252
+ function cmdInitPlanPhase(cwd, phase, raw, options = {}) {
253
+ if (!phase) {
254
+ error('phase required for init plan-phase');
255
+ }
256
+ const config = loadConfig(cwd);
257
+ let phaseInfo = findPhaseInternal(cwd, phase);
258
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
259
+ if (phaseInfo?.['archived'] && roadmapPhase?.['found']) {
260
+ phaseInfo = null;
261
+ }
262
+ if (!phaseInfo && roadmapPhase?.['found']) {
263
+ const phaseName = roadmapPhase['phase_name'];
264
+ phaseInfo = {
265
+ found: true,
266
+ directory: null,
267
+ phase_number: roadmapPhase['phase_number'],
268
+ phase_name: phaseName,
269
+ phase_slug: phaseName
270
+ ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
271
+ : null,
272
+ plans: [],
273
+ summaries: [],
274
+ incomplete_plans: [],
275
+ has_research: false,
276
+ has_context: false,
277
+ has_verification: false,
278
+ has_reviews: false,
279
+ };
280
+ }
281
+ const reqMatch = roadmapPhase?.['section']?.match(REQUIREMENTS_HEADER_RE);
282
+ const reqExtracted = reqMatch
283
+ ? reqMatch[1].replace(/[\[\]]/g, '').split(',').map((s) => s.trim()).filter(Boolean).join(', ')
284
+ : null;
285
+ const phase_req_ids = reqExtracted && reqExtracted !== 'TBD' ? reqExtracted : null;
286
+ const phaseDirPlan = phaseInfo?.['directory'] || null;
287
+ const phaseNumberPlan = phaseInfo?.['phase_number'] || null;
288
+ const phaseNamePlan = phaseInfo?.['phase_name'] || null;
289
+ const rawProjectCodePlan = config.project_code || '';
290
+ let expectedPhaseDirPlan = null;
291
+ if (!phaseDirPlan && phaseNumberPlan && phaseNamePlan) {
292
+ const paddedNum = normalizePhaseName(phaseNumberPlan);
293
+ const slug = (generateSlugInternal(phaseNamePlan) || '').substring(0, 60);
294
+ if (slug) {
295
+ const prefix = rawProjectCodePlan ? `${rawProjectCodePlan}-` : '';
296
+ const dirName = `${prefix}${paddedNum}-${slug}`;
297
+ expectedPhaseDirPlan = toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningPaths(cwd).phases, dirName)));
298
+ }
299
+ }
300
+ const result = {
301
+ researcher_model: resolveModelInternal(cwd, 'gsd-phase-researcher'),
302
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
303
+ checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
304
+ tdd_mode: options['tdd'] || config.tdd_mode || false,
305
+ research_enabled: config.research,
306
+ plan_checker_enabled: config.plan_checker,
307
+ nyquist_validation_enabled: config.nyquist_validation,
308
+ commit_docs: config.commit_docs,
309
+ text_mode: config.text_mode,
310
+ auto_advance: !!(config.auto_advance),
311
+ auto_chain_active: !!(config._auto_chain_active),
312
+ mode: config.mode || 'interactive',
313
+ phase_found: !!phaseInfo,
314
+ phase_dir: phaseDirPlan,
315
+ expected_phase_dir: expectedPhaseDirPlan,
316
+ phase_number: phaseNumberPlan,
317
+ phase_name: phaseNamePlan,
318
+ phase_slug: phaseInfo?.['phase_slug'] || null,
319
+ padded_phase: phaseNumberPlan ? normalizePhaseName(phaseNumberPlan) : null,
320
+ phase_req_ids,
321
+ phase_status: phaseDirPlan
322
+ ? determinePhaseStatus(phaseInfo?.['plans']?.length || 0, phaseInfo?.['summaries']?.length || 0, node_path_1.default.join(cwd, phaseDirPlan), 'Pending')
323
+ : 'Pending',
324
+ has_research: phaseInfo?.['has_research'] || false,
325
+ has_context: phaseInfo?.['has_context'] || false,
326
+ has_reviews: phaseInfo?.['has_reviews'] || false,
327
+ has_plans: (phaseInfo?.['plans']?.length || 0) > 0,
328
+ plan_count: phaseInfo?.['plans']?.length || 0,
329
+ planning_exists: node_fs_1.default.existsSync(planningDir(cwd)),
330
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
331
+ state_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'STATE.md'))),
332
+ roadmap_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'))),
333
+ requirements_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'REQUIREMENTS.md'))),
334
+ patterns_path: null,
335
+ };
336
+ if (phaseInfo?.['directory']) {
337
+ const phaseDirFull = node_path_1.default.join(cwd, phaseInfo['directory']);
338
+ try {
339
+ const files = node_fs_1.default.readdirSync(phaseDirFull);
340
+ const contextFile = findContextMdIn(phaseDirFull);
341
+ if (contextFile) {
342
+ result['context_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], contextFile));
343
+ }
344
+ const researchFile = files.find((f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
345
+ if (researchFile) {
346
+ result['research_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], researchFile));
347
+ }
348
+ const verificationFile = files.find((f) => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
349
+ if (verificationFile) {
350
+ result['verification_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], verificationFile));
351
+ }
352
+ const uatFile = files.find((f) => f.endsWith('-UAT.md') || f === 'UAT.md');
353
+ if (uatFile) {
354
+ result['uat_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], uatFile));
355
+ }
356
+ const reviewsFile = files.find((f) => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md');
357
+ if (reviewsFile) {
358
+ result['reviews_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], reviewsFile));
359
+ }
360
+ const patternsFile = files.find((f) => f.endsWith('-PATTERNS.md') || f === 'PATTERNS.md');
361
+ if (patternsFile) {
362
+ result['patterns_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], patternsFile));
363
+ }
364
+ }
365
+ catch {
366
+ /* intentionally empty */
367
+ }
368
+ }
369
+ if (options['validate']) {
370
+ try {
371
+ const statePath = node_path_1.default.join(planningDir(cwd), 'STATE.md');
372
+ const stateContent = (0, shell_command_projection_cjs_1.platformReadSync)(statePath);
373
+ if (stateContent !== null) {
374
+ const stateWarnings = [];
375
+ result['state_validation_ran'] = true;
376
+ const totalPlansRaw = (0, state_document_cjs_1.stateExtractField)(stateContent, 'Total Plans in Phase');
377
+ const totalPlansInPhase = totalPlansRaw ? parseInt(totalPlansRaw, 10) : null;
378
+ if (totalPlansInPhase !== null &&
379
+ phaseInfo &&
380
+ totalPlansInPhase !==
381
+ (phaseInfo['plans']?.length || 0)) {
382
+ stateWarnings.push(`Plan count mismatch: STATE.md says ${totalPlansInPhase}, disk has ${phaseInfo['plans']?.length || 0}`);
383
+ }
384
+ result['state_warnings'] = stateWarnings;
385
+ }
386
+ }
387
+ catch {
388
+ /* intentionally empty */
389
+ }
390
+ }
391
+ output(withProjectRoot(cwd, result), raw);
392
+ }
393
+ function cmdInitNewProject(cwd, raw) {
394
+ const config = loadConfig(cwd);
395
+ const homedir = node_os_1.default.homedir();
396
+ const braveKeyFile = node_path_1.default.join(homedir, '.gsd', 'brave_api_key');
397
+ const hasBraveSearch = !!(process.env['BRAVE_API_KEY'] || node_fs_1.default.existsSync(braveKeyFile));
398
+ const firecrawlKeyFile = node_path_1.default.join(homedir, '.gsd', 'firecrawl_api_key');
399
+ const hasFirecrawl = !!(process.env['FIRECRAWL_API_KEY'] || node_fs_1.default.existsSync(firecrawlKeyFile));
400
+ const exaKeyFile = node_path_1.default.join(homedir, '.gsd', 'exa_api_key');
401
+ const hasExaSearch = !!(process.env['EXA_API_KEY'] || node_fs_1.default.existsSync(exaKeyFile));
402
+ let hasCode = false;
403
+ let hasPackageFile = false;
404
+ try {
405
+ const codeExtensions = new Set([
406
+ '.ts', '.js', '.py', '.go', '.rs', '.swift', '.java',
407
+ '.kt', '.kts',
408
+ '.c', '.cpp', '.h',
409
+ '.cs',
410
+ '.rb',
411
+ '.php',
412
+ '.dart',
413
+ '.m', '.mm',
414
+ '.scala',
415
+ '.groovy',
416
+ '.lua',
417
+ '.r', '.R',
418
+ '.zig',
419
+ '.ex', '.exs',
420
+ '.clj',
421
+ ]);
422
+ const skipDirs = new Set([
423
+ 'node_modules', '.git', '.planning', '.claude', '.codex',
424
+ '__pycache__', 'target', 'dist', 'build',
425
+ ]);
426
+ function findCodeFiles(dir, depth) {
427
+ if (depth > 3)
428
+ return false;
429
+ let entries;
430
+ try {
431
+ entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
432
+ }
433
+ catch {
434
+ return false;
435
+ }
436
+ for (const entry of entries) {
437
+ if (entry.isFile() && codeExtensions.has(node_path_1.default.extname(entry.name)))
438
+ return true;
439
+ if (entry.isDirectory() && !skipDirs.has(entry.name)) {
440
+ if (findCodeFiles(node_path_1.default.join(dir, entry.name), depth + 1))
441
+ return true;
442
+ }
443
+ }
444
+ return false;
445
+ }
446
+ hasCode = findCodeFiles(cwd, 0);
447
+ }
448
+ catch {
449
+ /* intentionally empty — best-effort detection */
450
+ }
451
+ hasPackageFile =
452
+ pathExistsInternal(cwd, 'package.json') ||
453
+ pathExistsInternal(cwd, 'requirements.txt') ||
454
+ pathExistsInternal(cwd, 'Cargo.toml') ||
455
+ pathExistsInternal(cwd, 'go.mod') ||
456
+ pathExistsInternal(cwd, 'Package.swift') ||
457
+ pathExistsInternal(cwd, 'build.gradle') ||
458
+ pathExistsInternal(cwd, 'build.gradle.kts') ||
459
+ pathExistsInternal(cwd, 'pom.xml') ||
460
+ pathExistsInternal(cwd, 'Gemfile') ||
461
+ pathExistsInternal(cwd, 'composer.json') ||
462
+ pathExistsInternal(cwd, 'pubspec.yaml') ||
463
+ pathExistsInternal(cwd, 'CMakeLists.txt') ||
464
+ pathExistsInternal(cwd, 'Makefile') ||
465
+ pathExistsInternal(cwd, 'build.zig') ||
466
+ pathExistsInternal(cwd, 'mix.exs') ||
467
+ pathExistsInternal(cwd, 'project.clj');
468
+ const result = {
469
+ researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
470
+ synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
471
+ roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
472
+ commit_docs: config.commit_docs,
473
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
474
+ has_codebase_map: pathExistsInternal(cwd, '.planning/codebase'),
475
+ planning_exists: pathExistsInternal(cwd, '.planning'),
476
+ has_existing_code: hasCode,
477
+ has_package_file: hasPackageFile,
478
+ is_brownfield: hasCode || hasPackageFile,
479
+ needs_codebase_map: (hasCode || hasPackageFile) && !pathExistsInternal(cwd, '.planning/codebase'),
480
+ ...getInitGitState(cwd),
481
+ brave_search_available: hasBraveSearch,
482
+ firecrawl_available: hasFirecrawl,
483
+ exa_search_available: hasExaSearch,
484
+ project_path: '.planning/PROJECT.md',
485
+ };
486
+ output(withProjectRoot(cwd, result), raw);
487
+ }
488
+ function cmdInitNewMilestone(cwd, raw) {
489
+ const config = loadConfig(cwd);
490
+ const milestone = getMilestoneInfo(cwd);
491
+ const latestCompleted = getLatestCompletedMilestone(cwd);
492
+ const phasesDir = node_path_1.default.join(planningDir(cwd), 'phases');
493
+ let phaseDirCount = 0;
494
+ try {
495
+ if (node_fs_1.default.existsSync(phasesDir)) {
496
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
497
+ phaseDirCount = node_fs_1.default
498
+ .readdirSync(phasesDir, { withFileTypes: true })
499
+ .filter((entry) => entry.isDirectory() && isDirInMilestone(entry.name))
500
+ .length;
501
+ }
502
+ }
503
+ catch {
504
+ /* intentionally empty */
505
+ }
506
+ const result = {
507
+ researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
508
+ synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
509
+ roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
510
+ commit_docs: config.commit_docs,
511
+ research_enabled: config.research,
512
+ current_milestone: milestone['version'],
513
+ current_milestone_name: milestone['name'],
514
+ latest_completed_milestone: latestCompleted?.version || null,
515
+ latest_completed_milestone_name: latestCompleted?.name || null,
516
+ phase_dir_count: phaseDirCount,
517
+ phase_archive_path: latestCompleted
518
+ ? toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningRoot(cwd), 'milestones', `${latestCompleted.version}-phases`)))
519
+ : null,
520
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
521
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
522
+ state_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'STATE.md')),
523
+ project_path: '.planning/PROJECT.md',
524
+ roadmap_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'))),
525
+ state_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'STATE.md'))),
526
+ };
527
+ output(withProjectRoot(cwd, result), raw);
528
+ }
529
+ function cmdInitQuick(cwd, description, raw) {
530
+ const config = loadConfig(cwd);
531
+ const now = new Date();
532
+ const slug = description ? generateSlugInternal(description)?.substring(0, 40) : null;
533
+ const yy = String(now.getFullYear()).slice(-2);
534
+ const mm = String(now.getMonth() + 1).padStart(2, '0');
535
+ const dd = String(now.getDate()).padStart(2, '0');
536
+ const dateStr = yy + mm + dd;
537
+ const secondsSinceMidnight = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
538
+ const timeBlocks = Math.floor(secondsSinceMidnight / 2);
539
+ const timeEncoded = timeBlocks.toString(36).padStart(3, '0');
540
+ const quickId = dateStr + '-' + timeEncoded;
541
+ const branchSlug = slug || 'quick';
542
+ const quickBranchName = config.quick_branch_template
543
+ ? config.quick_branch_template
544
+ .replace('{num}', quickId)
545
+ .replace('{quick}', quickId)
546
+ .replace('{slug}', branchSlug)
547
+ : null;
548
+ const result = {
549
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
550
+ executor_model: resolveModelInternal(cwd, 'gsd-executor'),
551
+ checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
552
+ verifier_model: resolveModelInternal(cwd, 'gsd-verifier'),
553
+ commit_docs: config.commit_docs,
554
+ branch_name: quickBranchName,
555
+ quick_id: quickId,
556
+ slug: slug,
557
+ description: description || null,
558
+ date: now.toISOString().split('T')[0],
559
+ timestamp: now.toISOString(),
560
+ quick_dir: '.planning/quick',
561
+ task_dir: slug ? `.planning/quick/${quickId}-${slug}` : null,
562
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
563
+ planning_exists: node_fs_1.default.existsSync(planningRoot(cwd)),
564
+ };
565
+ output(withProjectRoot(cwd, result), raw);
566
+ }
567
+ function cmdInitIngestDocs(cwd, raw) {
568
+ const config = loadConfig(cwd);
569
+ const result = {
570
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
571
+ planning_exists: node_fs_1.default.existsSync(planningRoot(cwd)),
572
+ ...getInitGitState(cwd),
573
+ project_path: '.planning/PROJECT.md',
574
+ commit_docs: config.commit_docs,
575
+ };
576
+ output(withProjectRoot(cwd, result), raw);
577
+ }
578
+ function cmdInitResume(cwd, raw) {
579
+ const config = loadConfig(cwd);
580
+ let interruptedAgentId = null;
581
+ const agentIdRaw = (0, shell_command_projection_cjs_1.platformReadSync)(node_path_1.default.join(planningRoot(cwd), 'current-agent-id.txt'));
582
+ if (agentIdRaw !== null)
583
+ interruptedAgentId = agentIdRaw.trim();
584
+ const result = {
585
+ state_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'STATE.md')),
586
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
587
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
588
+ planning_exists: node_fs_1.default.existsSync(planningRoot(cwd)),
589
+ state_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'STATE.md'))),
590
+ roadmap_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'))),
591
+ project_path: '.planning/PROJECT.md',
592
+ has_interrupted_agent: !!interruptedAgentId,
593
+ interrupted_agent_id: interruptedAgentId,
594
+ commit_docs: config.commit_docs,
595
+ };
596
+ output(withProjectRoot(cwd, result), raw);
597
+ }
598
+ function cmdInitVerifyWork(cwd, phase, raw) {
599
+ if (!phase) {
600
+ error('phase required for init verify-work');
601
+ }
602
+ const config = loadConfig(cwd);
603
+ let phaseInfo = findPhaseInternal(cwd, phase);
604
+ if (phaseInfo?.['archived']) {
605
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
606
+ if (roadmapPhase?.['found']) {
607
+ phaseInfo = null;
608
+ }
609
+ }
610
+ if (!phaseInfo) {
611
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
612
+ if (roadmapPhase?.['found']) {
613
+ const phaseName = roadmapPhase['phase_name'];
614
+ phaseInfo = {
615
+ found: true,
616
+ directory: null,
617
+ phase_number: roadmapPhase['phase_number'],
618
+ phase_name: phaseName,
619
+ phase_slug: phaseName
620
+ ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
621
+ : null,
622
+ plans: [],
623
+ summaries: [],
624
+ incomplete_plans: [],
625
+ has_research: false,
626
+ has_context: false,
627
+ has_verification: false,
628
+ };
629
+ }
630
+ }
631
+ const result = {
632
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
633
+ checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
634
+ commit_docs: config.commit_docs,
635
+ phase_found: !!phaseInfo,
636
+ phase_dir: phaseInfo?.['directory'] || null,
637
+ phase_number: phaseInfo?.['phase_number'] || null,
638
+ phase_name: phaseInfo?.['phase_name'] || null,
639
+ has_verification: phaseInfo?.['has_verification'] || false,
640
+ };
641
+ output(withProjectRoot(cwd, result), raw);
642
+ }
643
+ function cmdInitPhaseOp(cwd, phase, raw) {
644
+ const config = loadConfig(cwd);
645
+ let phaseInfo = findPhaseInternal(cwd, phase);
646
+ if (phaseInfo?.['archived']) {
647
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
648
+ if (roadmapPhase?.['found']) {
649
+ const phaseName = roadmapPhase['phase_name'];
650
+ phaseInfo = {
651
+ found: true,
652
+ directory: null,
653
+ phase_number: roadmapPhase['phase_number'],
654
+ phase_name: phaseName,
655
+ phase_slug: phaseName
656
+ ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
657
+ : null,
658
+ plans: [],
659
+ summaries: [],
660
+ incomplete_plans: [],
661
+ has_research: false,
662
+ has_context: false,
663
+ has_verification: false,
664
+ };
665
+ }
666
+ }
667
+ if (!phaseInfo) {
668
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
669
+ if (roadmapPhase?.['found']) {
670
+ const phaseName = roadmapPhase['phase_name'];
671
+ phaseInfo = {
672
+ found: true,
673
+ directory: null,
674
+ phase_number: roadmapPhase['phase_number'],
675
+ phase_name: phaseName,
676
+ phase_slug: phaseName
677
+ ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
678
+ : null,
679
+ plans: [],
680
+ summaries: [],
681
+ incomplete_plans: [],
682
+ has_research: false,
683
+ has_context: false,
684
+ has_verification: false,
685
+ };
686
+ }
687
+ }
688
+ const phaseDir = phaseInfo?.['directory'] || null;
689
+ const phaseNumber = phaseInfo?.['phase_number'] || null;
690
+ const phaseName = phaseInfo?.['phase_name'] || null;
691
+ const rawProjectCode = config.project_code || '';
692
+ let expectedPhaseDir = null;
693
+ if (!phaseDir && phaseNumber && phaseName) {
694
+ const paddedNum = normalizePhaseName(phaseNumber);
695
+ const slug = (generateSlugInternal(phaseName) || '').substring(0, 60);
696
+ if (slug) {
697
+ const prefix = rawProjectCode ? `${rawProjectCode}-` : '';
698
+ const dirName = `${prefix}${paddedNum}-${slug}`;
699
+ expectedPhaseDir = toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningPaths(cwd).phases, dirName)));
700
+ }
701
+ }
702
+ const result = {
703
+ commit_docs: config.commit_docs,
704
+ brave_search: typeof config.brave_search === 'string'
705
+ ? (0, secrets_cjs_1.maskIfSecret)('brave_search', config.brave_search)
706
+ : config.brave_search,
707
+ firecrawl: typeof config.firecrawl === 'string'
708
+ ? (0, secrets_cjs_1.maskIfSecret)('firecrawl', config.firecrawl)
709
+ : config.firecrawl,
710
+ exa_search: typeof config.exa_search === 'string'
711
+ ? (0, secrets_cjs_1.maskIfSecret)('exa_search', config.exa_search)
712
+ : config.exa_search,
713
+ phase_found: !!phaseInfo,
714
+ phase_dir: phaseDir,
715
+ expected_phase_dir: expectedPhaseDir,
716
+ phase_number: phaseNumber,
717
+ phase_name: phaseName,
718
+ phase_slug: phaseInfo?.['phase_slug'] || null,
719
+ padded_phase: phaseNumber ? normalizePhaseName(phaseNumber) : null,
720
+ has_research: phaseInfo?.['has_research'] || false,
721
+ has_context: phaseInfo?.['has_context'] || false,
722
+ has_plans: (phaseInfo?.['plans']?.length || 0) > 0,
723
+ has_verification: phaseInfo?.['has_verification'] || false,
724
+ has_reviews: phaseInfo?.['has_reviews'] || false,
725
+ plan_count: phaseInfo?.['plans']?.length || 0,
726
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
727
+ planning_exists: node_fs_1.default.existsSync(planningDir(cwd)),
728
+ state_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'STATE.md'))),
729
+ roadmap_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'))),
730
+ requirements_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'REQUIREMENTS.md'))),
731
+ };
732
+ if (phaseInfo?.['directory']) {
733
+ const phaseDirFull = node_path_1.default.join(cwd, phaseInfo['directory']);
734
+ try {
735
+ const files = node_fs_1.default.readdirSync(phaseDirFull);
736
+ const contextFile = findContextMdIn(phaseDirFull);
737
+ if (contextFile) {
738
+ result['context_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], contextFile));
739
+ }
740
+ const researchFile = files.find((f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
741
+ if (researchFile) {
742
+ result['research_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], researchFile));
743
+ }
744
+ const verificationFile = files.find((f) => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
745
+ if (verificationFile) {
746
+ result['verification_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], verificationFile));
747
+ }
748
+ const uatFile = files.find((f) => f.endsWith('-UAT.md') || f === 'UAT.md');
749
+ if (uatFile) {
750
+ result['uat_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], uatFile));
751
+ }
752
+ const reviewsFile = files.find((f) => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md');
753
+ if (reviewsFile) {
754
+ result['reviews_path'] = toPosixPath(node_path_1.default.join(phaseInfo['directory'], reviewsFile));
755
+ }
756
+ }
757
+ catch {
758
+ /* intentionally empty */
759
+ }
760
+ }
761
+ output(withProjectRoot(cwd, result), raw);
762
+ }
763
+ function cmdInitTodos(cwd, area, raw) {
764
+ const config = loadConfig(cwd);
765
+ const now = new Date();
766
+ const pendingDir = node_path_1.default.join(planningDir(cwd), 'todos', 'pending');
767
+ let count = 0;
768
+ const todos = [];
769
+ try {
770
+ const files = node_fs_1.default.readdirSync(pendingDir).filter((f) => f.endsWith('.md'));
771
+ for (const file of files) {
772
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(node_path_1.default.join(pendingDir, file));
773
+ if (content === null)
774
+ continue;
775
+ try {
776
+ const createdMatch = content.match(/^created:\s*(.+)$/m);
777
+ const titleMatch = content.match(/^title:\s*(.+)$/m);
778
+ const areaMatch = content.match(/^area:\s*(.+)$/m);
779
+ const todoArea = areaMatch ? areaMatch[1].trim() : 'general';
780
+ if (area && todoArea !== area)
781
+ continue;
782
+ count++;
783
+ todos.push({
784
+ file,
785
+ created: createdMatch ? createdMatch[1].trim() : 'unknown',
786
+ title: titleMatch ? titleMatch[1].trim() : 'Untitled',
787
+ area: todoArea,
788
+ path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'todos', 'pending', file))),
789
+ });
790
+ }
791
+ catch {
792
+ /* intentionally empty */
793
+ }
794
+ }
795
+ }
796
+ catch {
797
+ /* intentionally empty */
798
+ }
799
+ const result = {
800
+ commit_docs: config.commit_docs,
801
+ date: now.toISOString().split('T')[0],
802
+ timestamp: now.toISOString(),
803
+ todo_count: count,
804
+ todos,
805
+ area_filter: area || null,
806
+ pending_dir: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'todos', 'pending'))),
807
+ completed_dir: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'todos', 'completed'))),
808
+ planning_exists: node_fs_1.default.existsSync(planningDir(cwd)),
809
+ todos_dir_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'todos')),
810
+ pending_dir_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'todos', 'pending')),
811
+ };
812
+ output(withProjectRoot(cwd, result), raw);
813
+ }
814
+ function cmdInitMilestoneOp(cwd, raw) {
815
+ const config = loadConfig(cwd);
816
+ const milestone = getMilestoneInfo(cwd);
817
+ let phaseCount = 0;
818
+ let completedPhases = 0;
819
+ const phasesDir = node_path_1.default.join(planningDir(cwd), 'phases');
820
+ const roadmapPhaseNumbers = [];
821
+ try {
822
+ const roadmapPath = node_path_1.default.join(planningDir(cwd), 'ROADMAP.md');
823
+ const roadmapRaw = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
824
+ const currentSection = extractCurrentMilestone(roadmapRaw, cwd);
825
+ const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
826
+ let m;
827
+ while ((m = phasePattern.exec(currentSection)) !== null) {
828
+ roadmapPhaseNumbers.push(m[1]);
829
+ }
830
+ }
831
+ catch {
832
+ /* intentionally empty */
833
+ }
834
+ const canonicalizePhase = (tok) => {
835
+ const m = tok.match(/^(\d+)([A-Z]?(?:\.\d+)*)$/);
836
+ return m ? String(parseInt(m[1], 10)) + m[2] : tok;
837
+ };
838
+ const diskPhaseDirs = new Map();
839
+ try {
840
+ const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
841
+ for (const e of entries) {
842
+ if (!e.isDirectory())
843
+ continue;
844
+ const m = e.name.match(/^(\d+[A-Z]?(?:\.\d+)*)/);
845
+ if (!m)
846
+ continue;
847
+ diskPhaseDirs.set(canonicalizePhase(m[1]), e.name);
848
+ }
849
+ }
850
+ catch {
851
+ /* intentionally empty */
852
+ }
853
+ if (roadmapPhaseNumbers.length > 0) {
854
+ phaseCount = roadmapPhaseNumbers.length;
855
+ for (const num of roadmapPhaseNumbers) {
856
+ const dirName = diskPhaseDirs.get(canonicalizePhase(num));
857
+ if (!dirName)
858
+ continue;
859
+ try {
860
+ const hasSummary = listPhaseSummaryFiles(node_path_1.default.join(phasesDir, dirName)).length > 0;
861
+ if (hasSummary)
862
+ completedPhases++;
863
+ }
864
+ catch {
865
+ /* intentionally empty */
866
+ }
867
+ }
868
+ }
869
+ else {
870
+ try {
871
+ const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
872
+ const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
873
+ phaseCount = dirs.length;
874
+ for (const dir of dirs) {
875
+ try {
876
+ const hasSummary = listPhaseSummaryFiles(node_path_1.default.join(phasesDir, dir)).length > 0;
877
+ if (hasSummary)
878
+ completedPhases++;
879
+ }
880
+ catch {
881
+ /* intentionally empty */
882
+ }
883
+ }
884
+ }
885
+ catch {
886
+ /* intentionally empty */
887
+ }
888
+ }
889
+ const archiveDir = node_path_1.default.join(planningRoot(cwd), 'archive');
890
+ let archivedMilestones = [];
891
+ try {
892
+ archivedMilestones = node_fs_1.default
893
+ .readdirSync(archiveDir, { withFileTypes: true })
894
+ .filter((e) => e.isDirectory())
895
+ .map((e) => e.name);
896
+ }
897
+ catch {
898
+ /* intentionally empty */
899
+ }
900
+ const result = {
901
+ commit_docs: config.commit_docs,
902
+ milestone_version: milestone['version'],
903
+ milestone_name: milestone['name'],
904
+ milestone_slug: generateSlugInternal(milestone['name']),
905
+ phase_count: phaseCount,
906
+ completed_phases: completedPhases,
907
+ all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
908
+ archived_milestones: archivedMilestones,
909
+ archive_count: archivedMilestones.length,
910
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
911
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
912
+ state_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'STATE.md')),
913
+ archive_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningRoot(cwd), 'archive')),
914
+ phases_dir_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'phases')),
915
+ };
916
+ output(withProjectRoot(cwd, result), raw);
917
+ }
918
+ function cmdInitMapCodebase(cwd, raw) {
919
+ const config = loadConfig(cwd);
920
+ const now = new Date();
921
+ const codebaseDir = node_path_1.default.join(planningRoot(cwd), 'codebase');
922
+ let existingMaps = [];
923
+ try {
924
+ existingMaps = node_fs_1.default.readdirSync(codebaseDir).filter((f) => f.endsWith('.md'));
925
+ }
926
+ catch {
927
+ /* intentionally empty */
928
+ }
929
+ const result = {
930
+ mapper_model: resolveModelInternal(cwd, 'gsd-codebase-mapper'),
931
+ commit_docs: config.commit_docs,
932
+ search_gitignored: config.search_gitignored,
933
+ parallelization: config.parallelization,
934
+ subagent_timeout: config.subagent_timeout,
935
+ date: now.toISOString().split('T')[0],
936
+ timestamp: now.toISOString(),
937
+ codebase_dir: '.planning/codebase',
938
+ existing_maps: existingMaps,
939
+ has_maps: existingMaps.length > 0,
940
+ planning_exists: pathExistsInternal(cwd, '.planning'),
941
+ codebase_dir_exists: pathExistsInternal(cwd, '.planning/codebase'),
942
+ };
943
+ output(withProjectRoot(cwd, result), raw);
944
+ }
945
+ function cmdInitManager(cwd, raw) {
946
+ const config = loadConfig(cwd);
947
+ const milestone = getMilestoneInfo(cwd);
948
+ const _slashRuntime = (0, runtime_slash_cjs_1.resolveRuntime)(cwd);
949
+ const paths = planningPaths(cwd);
950
+ if (!node_fs_1.default.existsSync(paths.roadmap)) {
951
+ error(`No ROADMAP.md found. Run ${(0, runtime_slash_cjs_1.formatGsdSlash)('new-milestone', _slashRuntime)} first.`);
952
+ }
953
+ if (!node_fs_1.default.existsSync(paths.state)) {
954
+ error(`No STATE.md found. Run ${(0, runtime_slash_cjs_1.formatGsdSlash)('new-milestone', _slashRuntime)} first.`);
955
+ }
956
+ const rawContent = node_fs_1.default.readFileSync(paths.roadmap, 'utf-8');
957
+ const content = extractCurrentMilestone(rawContent, cwd);
958
+ const phasesDir = paths.phases;
959
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
960
+ const _phaseDirEntries = (() => {
961
+ try {
962
+ return node_fs_1.default
963
+ .readdirSync(phasesDir, { withFileTypes: true })
964
+ .filter((e) => e.isDirectory())
965
+ .map((e) => e.name);
966
+ }
967
+ catch {
968
+ return [];
969
+ }
970
+ })();
971
+ const _checkboxStates = new Map();
972
+ const _cbPattern = /-\s*\[(x| )\]\s*.*Phase\s+(\d+[A-Z]?(?:\.\d+)*)[:\s]/gi;
973
+ let _cbMatch;
974
+ while ((_cbMatch = _cbPattern.exec(content)) !== null) {
975
+ _checkboxStates.set(_cbMatch[2], _cbMatch[1].toLowerCase() === 'x');
976
+ }
977
+ const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:\s*([^\n]+)/gi;
978
+ const phases = [];
979
+ let match;
980
+ while ((match = phasePattern.exec(content)) !== null) {
981
+ const phaseNum = match[1];
982
+ const phaseName = match[2].replace(/\(INSERTED\)/i, '').trim();
983
+ const sectionStart = match.index;
984
+ const restOfContent = content.slice(sectionStart);
985
+ const nextHeader = restOfContent.match(/\n#{2,4}\s+Phase\s+\d[\d.]*/i);
986
+ const sectionEnd = nextHeader
987
+ ? sectionStart + nextHeader.index
988
+ : content.length;
989
+ const section = content.slice(sectionStart, sectionEnd);
990
+ const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
991
+ const goal = goalMatch ? goalMatch[1].trim() : null;
992
+ const dependsMatch = section.match(/\*\*Depends on(?::\*\*|\*\*:)\s*([^\n]+)/i);
993
+ const depends_on = dependsMatch ? dependsMatch[1].trim() : null;
994
+ const normalized = normalizePhaseName(phaseNum);
995
+ let diskStatus = 'no_directory';
996
+ let planCount = 0;
997
+ let summaryCount = 0;
998
+ let hasContext = false;
999
+ let hasResearch = false;
1000
+ let lastActivity = null;
1001
+ let isActive = false;
1002
+ try {
1003
+ const dirs = _phaseDirEntries.filter(isDirInMilestone);
1004
+ const dirMatch = dirs.find((d) => phaseTokenMatches(d, normalized));
1005
+ if (dirMatch) {
1006
+ const fullDir = node_path_1.default.join(phasesDir, dirMatch);
1007
+ const phaseFiles = node_fs_1.default.readdirSync(fullDir);
1008
+ planCount = listPhasePlanFiles(fullDir).length;
1009
+ summaryCount = listPhaseSummaryFiles(fullDir).length;
1010
+ hasContext = findContextMdIn(fullDir) !== null;
1011
+ hasResearch = phaseFiles.some((f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
1012
+ if (summaryCount >= planCount && planCount > 0)
1013
+ diskStatus = 'complete';
1014
+ else if (summaryCount > 0)
1015
+ diskStatus = 'partial';
1016
+ else if (planCount > 0)
1017
+ diskStatus = 'planned';
1018
+ else if (hasResearch)
1019
+ diskStatus = 'researched';
1020
+ else if (hasContext)
1021
+ diskStatus = 'discussed';
1022
+ else
1023
+ diskStatus = 'empty';
1024
+ const nowMs = Date.now();
1025
+ let newestMtime = 0;
1026
+ for (const f of phaseFiles) {
1027
+ try {
1028
+ const stat = node_fs_1.default.statSync(node_path_1.default.join(fullDir, f));
1029
+ if (stat.mtimeMs > newestMtime)
1030
+ newestMtime = stat.mtimeMs;
1031
+ }
1032
+ catch {
1033
+ /* intentionally empty */
1034
+ }
1035
+ }
1036
+ if (newestMtime > 0) {
1037
+ lastActivity = new Date(newestMtime).toISOString();
1038
+ isActive = nowMs - newestMtime < 300000;
1039
+ }
1040
+ }
1041
+ }
1042
+ catch {
1043
+ /* intentionally empty */
1044
+ }
1045
+ const roadmapComplete = _checkboxStates.get(phaseNum) || false;
1046
+ if (roadmapComplete && diskStatus !== 'complete') {
1047
+ diskStatus = 'complete';
1048
+ }
1049
+ phases.push({
1050
+ number: phaseNum,
1051
+ name: phaseName,
1052
+ goal,
1053
+ depends_on,
1054
+ disk_status: diskStatus,
1055
+ has_context: hasContext,
1056
+ has_research: hasResearch,
1057
+ plan_count: planCount,
1058
+ summary_count: summaryCount,
1059
+ roadmap_complete: roadmapComplete,
1060
+ last_activity: lastActivity,
1061
+ is_active: isActive,
1062
+ });
1063
+ }
1064
+ const MAX_NAME_WIDTH = 20;
1065
+ for (const phase of phases) {
1066
+ const name = phase['name'];
1067
+ if (name.length > MAX_NAME_WIDTH) {
1068
+ phase['display_name'] = name.slice(0, MAX_NAME_WIDTH - 1) + '…';
1069
+ }
1070
+ else {
1071
+ phase['display_name'] = name;
1072
+ }
1073
+ }
1074
+ const completedNums = new Set(phases.filter((p) => p['disk_status'] === 'complete').map((p) => p['number']));
1075
+ const _allCompletedPattern = /-\s*\[x\]\s*.*Phase\s+(\d+[A-Z]?(?:\.\d+)*)[:\s]/gi;
1076
+ let _allMatch;
1077
+ while ((_allMatch = _allCompletedPattern.exec(rawContent)) !== null) {
1078
+ completedNums.add(_allMatch[1]);
1079
+ }
1080
+ const phaseMap = new Map(phases.map((p) => [p['number'], p]));
1081
+ function reaches(from, to, visited = new Set()) {
1082
+ if (visited.has(from))
1083
+ return false;
1084
+ visited.add(from);
1085
+ const p = phaseMap.get(from);
1086
+ if (!p || !p['dep_phases'] || p['dep_phases'].length === 0)
1087
+ return false;
1088
+ if (p['dep_phases'].includes(to))
1089
+ return true;
1090
+ return p['dep_phases'].some((dep) => reaches(dep, to, visited));
1091
+ }
1092
+ function hasDepRelationship(numA, numB) {
1093
+ return reaches(numA, numB) || reaches(numB, numA);
1094
+ }
1095
+ for (const phase of phases) {
1096
+ if (!phase['depends_on'] ||
1097
+ /^none$/i.test(phase['depends_on'].trim())) {
1098
+ phase['deps_satisfied'] = true;
1099
+ }
1100
+ else {
1101
+ const depNums = phase['depends_on'].match(/\d+(?:\.\d+)*/g) || [];
1102
+ phase['deps_satisfied'] = depNums.every((n) => completedNums.has(n));
1103
+ phase['dep_phases'] = depNums;
1104
+ }
1105
+ }
1106
+ for (const phase of phases) {
1107
+ phase['deps_display'] =
1108
+ phase['dep_phases'] && phase['dep_phases'].length > 0
1109
+ ? phase['dep_phases'].join(',')
1110
+ : '—';
1111
+ }
1112
+ for (const phase of phases) {
1113
+ phase['is_next_to_discuss'] =
1114
+ (phase['disk_status'] === 'empty' || phase['disk_status'] === 'no_directory') &&
1115
+ phase['deps_satisfied'];
1116
+ }
1117
+ let waitingSignal = null;
1118
+ try {
1119
+ const waitingPath = node_path_1.default.join(cwd, '.planning', 'WAITING.json');
1120
+ const waitingRaw = (0, shell_command_projection_cjs_1.platformReadSync)(waitingPath);
1121
+ if (waitingRaw !== null) {
1122
+ waitingSignal = JSON.parse(waitingRaw);
1123
+ }
1124
+ }
1125
+ catch {
1126
+ /* intentionally empty */
1127
+ }
1128
+ const recommendedActions = [];
1129
+ for (const phase of phases) {
1130
+ if (phase['disk_status'] === 'complete')
1131
+ continue;
1132
+ if (/^999(?:\.|$)/.test(phase['number']))
1133
+ continue;
1134
+ if (phase['disk_status'] === 'planned' && phase['deps_satisfied']) {
1135
+ recommendedActions.push({
1136
+ phase: phase['number'],
1137
+ phase_name: phase['name'],
1138
+ action: 'execute',
1139
+ reason: `${phase['plan_count']} plans ready, dependencies met`,
1140
+ command: `${(0, runtime_slash_cjs_1.formatGsdSlash)('execute-phase', _slashRuntime)} ${phase['number']}`,
1141
+ });
1142
+ }
1143
+ else if (phase['disk_status'] === 'discussed' ||
1144
+ phase['disk_status'] === 'researched') {
1145
+ recommendedActions.push({
1146
+ phase: phase['number'],
1147
+ phase_name: phase['name'],
1148
+ action: 'plan',
1149
+ reason: 'Context gathered, ready for planning',
1150
+ command: `${(0, runtime_slash_cjs_1.formatGsdSlash)('plan-phase', _slashRuntime)} ${phase['number']}`,
1151
+ });
1152
+ }
1153
+ else if ((phase['disk_status'] === 'empty' || phase['disk_status'] === 'no_directory') &&
1154
+ phase['is_next_to_discuss']) {
1155
+ recommendedActions.push({
1156
+ phase: phase['number'],
1157
+ phase_name: phase['name'],
1158
+ action: 'discuss',
1159
+ reason: 'Unblocked, ready to gather context',
1160
+ command: `${(0, runtime_slash_cjs_1.formatGsdSlash)('discuss-phase', _slashRuntime)} ${phase['number']}`,
1161
+ });
1162
+ }
1163
+ }
1164
+ const activeExecuting = phases.filter((p) => p['disk_status'] === 'partial' ||
1165
+ (p['disk_status'] === 'planned' && p['is_active']));
1166
+ const activePlanning = phases.filter((p) => p['is_active'] &&
1167
+ (p['disk_status'] === 'discussed' || p['disk_status'] === 'researched'));
1168
+ const filteredActions = recommendedActions.filter((action) => {
1169
+ if (action['action'] === 'execute' && activeExecuting.length > 0) {
1170
+ return activeExecuting.every((active) => !hasDepRelationship(action['phase'], active['number']));
1171
+ }
1172
+ if (action['action'] === 'plan' && activePlanning.length > 0) {
1173
+ return activePlanning.every((active) => !hasDepRelationship(action['phase'], active['number']));
1174
+ }
1175
+ return true;
1176
+ });
1177
+ const nonBacklogPhases = phases.filter((p) => !/^999(?:\.|$)/.test(p['number']));
1178
+ const completedCount = nonBacklogPhases.filter((p) => p['disk_status'] === 'complete').length;
1179
+ const sanitizeFlags = (rawVal) => {
1180
+ const val = typeof rawVal === 'string' ? rawVal : '';
1181
+ if (!val)
1182
+ return '';
1183
+ const tokens = val.split(/\s+/).filter(Boolean);
1184
+ const safe = tokens.every((t) => /^--[a-zA-Z0-9][-a-zA-Z0-9]*$/.test(t) ||
1185
+ /^[a-zA-Z0-9][-a-zA-Z0-9_.]*$/.test(t));
1186
+ if (!safe) {
1187
+ process.stderr.write(`gsd-tools: warning: manager.flags contains invalid tokens, ignoring: ${val}\n`);
1188
+ return '';
1189
+ }
1190
+ return val;
1191
+ };
1192
+ const mgr = config.manager;
1193
+ const mgrFlags = mgr?.['flags'];
1194
+ const managerFlags = {
1195
+ discuss: sanitizeFlags(mgrFlags?.['discuss']),
1196
+ plan: sanitizeFlags(mgrFlags?.['plan']),
1197
+ execute: sanitizeFlags(mgrFlags?.['execute']),
1198
+ };
1199
+ const result = {
1200
+ milestone_version: milestone['version'],
1201
+ milestone_name: milestone['name'],
1202
+ phases,
1203
+ phase_count: phases.length,
1204
+ completed_count: completedCount,
1205
+ in_progress_count: phases.filter((p) => ['partial', 'planned', 'discussed', 'researched'].includes(p['disk_status'])).length,
1206
+ recommended_actions: filteredActions,
1207
+ waiting_signal: waitingSignal,
1208
+ all_complete: completedCount === nonBacklogPhases.length && nonBacklogPhases.length > 0,
1209
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
1210
+ roadmap_exists: true,
1211
+ state_exists: true,
1212
+ manager_flags: managerFlags,
1213
+ };
1214
+ output(withProjectRoot(cwd, result), raw);
1215
+ }
1216
+ function cmdInitProgress(cwd, raw) {
1217
+ try {
1218
+ const { pruneOrphanedWorktrees } = core;
1219
+ pruneOrphanedWorktrees(cwd);
1220
+ }
1221
+ catch {
1222
+ /* intentionally empty */
1223
+ }
1224
+ const config = loadConfig(cwd);
1225
+ const milestone = getMilestoneInfo(cwd);
1226
+ const phasesDir = node_path_1.default.join(planningDir(cwd), 'phases');
1227
+ const phases = [];
1228
+ let currentPhase = null;
1229
+ let nextPhase = null;
1230
+ const roadmapPhaseNums = new Set();
1231
+ const roadmapPhaseNames = new Map();
1232
+ const roadmapCheckboxStates = new Map();
1233
+ try {
1234
+ const roadmapContent = extractCurrentMilestone(node_fs_1.default.readFileSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'), 'utf-8'), cwd);
1235
+ const headingPattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:\s*([^\n]+)/gi;
1236
+ let hm;
1237
+ while ((hm = headingPattern.exec(roadmapContent)) !== null) {
1238
+ roadmapPhaseNums.add(hm[1]);
1239
+ roadmapPhaseNames.set(hm[1], hm[2].replace(/\(INSERTED\)/i, '').trim());
1240
+ }
1241
+ const cbPattern = /-\s*\[(x| )\]\s*.*Phase\s+(\d+[A-Z]?(?:\.\d+)*)[:\s]/gi;
1242
+ let cbm;
1243
+ while ((cbm = cbPattern.exec(roadmapContent)) !== null) {
1244
+ roadmapCheckboxStates.set(cbm[2], cbm[1].toLowerCase() === 'x');
1245
+ }
1246
+ }
1247
+ catch {
1248
+ /* intentionally empty */
1249
+ }
1250
+ const isDirInMilestone = getMilestonePhaseFilter(cwd);
1251
+ const seenPhaseNums = new Set();
1252
+ try {
1253
+ const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
1254
+ const dirs = entries
1255
+ .filter((e) => e.isDirectory())
1256
+ .map((e) => e.name)
1257
+ .filter(isDirInMilestone)
1258
+ .sort((a, b) => {
1259
+ const pa = a.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
1260
+ const pb = b.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
1261
+ if (!pa || !pb)
1262
+ return a.localeCompare(b);
1263
+ return parseInt(pa[1], 10) - parseInt(pb[1], 10);
1264
+ });
1265
+ for (const dir of dirs) {
1266
+ const dirMatch = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)-?(.*)/i);
1267
+ const phaseNumber = dirMatch ? dirMatch[1] : dir;
1268
+ const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
1269
+ seenPhaseNums.add(phaseNumber.replace(/^0+/, '') || '0');
1270
+ const phasePath = node_path_1.default.join(phasesDir, dir);
1271
+ const phaseFiles = node_fs_1.default.readdirSync(phasePath);
1272
+ const plans = listPhasePlanFiles(phasePath);
1273
+ const summaries = listPhaseSummaryFiles(phasePath);
1274
+ const hasResearch = phaseFiles.some((f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
1275
+ const status = summaries.length >= plans.length && plans.length > 0
1276
+ ? 'complete'
1277
+ : plans.length > 0
1278
+ ? 'in_progress'
1279
+ : hasResearch
1280
+ ? 'researched'
1281
+ : 'pending';
1282
+ const phaseInfo = {
1283
+ number: phaseNumber,
1284
+ name: phaseName,
1285
+ directory: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'phases', dir))),
1286
+ status,
1287
+ plan_count: plans.length,
1288
+ summary_count: summaries.length,
1289
+ has_research: hasResearch,
1290
+ };
1291
+ phases.push(phaseInfo);
1292
+ if (!currentPhase && (status === 'in_progress' || status === 'researched')) {
1293
+ currentPhase = phaseInfo;
1294
+ }
1295
+ if (!nextPhase && status === 'pending') {
1296
+ nextPhase = phaseInfo;
1297
+ }
1298
+ }
1299
+ }
1300
+ catch {
1301
+ /* intentionally empty */
1302
+ }
1303
+ for (const [num, name] of roadmapPhaseNames) {
1304
+ const stripped = num.replace(/^0+/, '') || '0';
1305
+ if (!seenPhaseNums.has(stripped)) {
1306
+ const checkboxComplete = roadmapCheckboxStates.get(num) === true ||
1307
+ roadmapCheckboxStates.get(stripped) === true;
1308
+ const status = checkboxComplete ? 'complete' : 'not_started';
1309
+ const phaseInfo = {
1310
+ number: num,
1311
+ name: name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, ''),
1312
+ directory: null,
1313
+ status,
1314
+ plan_count: 0,
1315
+ summary_count: 0,
1316
+ has_research: false,
1317
+ };
1318
+ phases.push(phaseInfo);
1319
+ if (!nextPhase && !currentPhase && status !== 'complete') {
1320
+ nextPhase = phaseInfo;
1321
+ }
1322
+ }
1323
+ }
1324
+ phases.sort((a, b) => parseInt(a['number'], 10) - parseInt(b['number'], 10));
1325
+ let pausedAt = null;
1326
+ const state = (0, shell_command_projection_cjs_1.platformReadSync)(node_path_1.default.join(planningDir(cwd), 'STATE.md'));
1327
+ if (state !== null) {
1328
+ const pauseMatch = state.match(/\*\*Paused At:\*\*\s*(.+)/);
1329
+ if (pauseMatch)
1330
+ pausedAt = pauseMatch[1].trim();
1331
+ }
1332
+ const result = {
1333
+ executor_model: resolveModelInternal(cwd, 'gsd-executor'),
1334
+ planner_model: resolveModelInternal(cwd, 'gsd-planner'),
1335
+ commit_docs: config.commit_docs,
1336
+ milestone_version: milestone['version'],
1337
+ milestone_name: milestone['name'],
1338
+ phases,
1339
+ phase_count: phases.length,
1340
+ completed_count: phases.filter((p) => p['status'] === 'complete').length,
1341
+ in_progress_count: phases.filter((p) => p['status'] === 'in_progress').length,
1342
+ current_phase: currentPhase,
1343
+ next_phase: nextPhase,
1344
+ paused_at: pausedAt,
1345
+ has_work_in_progress: !!currentPhase,
1346
+ project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
1347
+ roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
1348
+ state_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'STATE.md')),
1349
+ state_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'STATE.md'))),
1350
+ roadmap_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'ROADMAP.md'))),
1351
+ project_path: '.planning/PROJECT.md',
1352
+ config_path: toPosixPath(node_path_1.default.relative(cwd, node_path_1.default.join(planningDir(cwd), 'config.json'))),
1353
+ };
1354
+ output(withProjectRoot(cwd, result), raw);
1355
+ }
1356
+ function detectChildRepos(dir) {
1357
+ const repos = [];
1358
+ let entries;
1359
+ try {
1360
+ entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
1361
+ }
1362
+ catch {
1363
+ return repos;
1364
+ }
1365
+ for (const entry of entries) {
1366
+ if (!entry.isDirectory())
1367
+ continue;
1368
+ if (entry.name.startsWith('.'))
1369
+ continue;
1370
+ const fullPath = node_path_1.default.join(dir, entry.name);
1371
+ const gitDir = node_path_1.default.join(fullPath, '.git');
1372
+ if (node_fs_1.default.existsSync(gitDir)) {
1373
+ const statusResult = (0, shell_command_projection_cjs_1.execGit)(['status', '--porcelain'], {
1374
+ cwd: fullPath,
1375
+ timeout: 5000,
1376
+ });
1377
+ const hasUncommitted = statusResult['exitCode'] === 0 &&
1378
+ statusResult['stdout'].length > 0;
1379
+ repos.push({ name: entry.name, path: fullPath, has_uncommitted: hasUncommitted });
1380
+ }
1381
+ }
1382
+ return repos;
1383
+ }
1384
+ function cmdInitNewWorkspace(cwd, raw) {
1385
+ const homedir = process.env['HOME'] || node_os_1.default.homedir();
1386
+ const defaultBase = node_path_1.default.join(homedir, 'gsd-workspaces');
1387
+ const childRepos = detectChildRepos(cwd);
1388
+ const gitVersion = (0, shell_command_projection_cjs_1.execGit)(['--version'], { timeout: 5000 });
1389
+ const worktreeAvailable = gitVersion['exitCode'] === 0;
1390
+ const result = {
1391
+ default_workspace_base: defaultBase,
1392
+ child_repos: childRepos,
1393
+ child_repo_count: childRepos.length,
1394
+ worktree_available: worktreeAvailable,
1395
+ is_git_repo: pathExistsInternal(cwd, '.git'),
1396
+ cwd_repo_name: node_path_1.default.basename(cwd),
1397
+ };
1398
+ output(withProjectRoot(cwd, result), raw);
1399
+ }
1400
+ function cmdInitListWorkspaces(cwd, raw) {
1401
+ const homedir = process.env['HOME'] || node_os_1.default.homedir();
1402
+ const defaultBase = node_path_1.default.join(homedir, 'gsd-workspaces');
1403
+ const workspaces = [];
1404
+ if (node_fs_1.default.existsSync(defaultBase)) {
1405
+ let entries;
1406
+ try {
1407
+ entries = node_fs_1.default.readdirSync(defaultBase, { withFileTypes: true });
1408
+ }
1409
+ catch {
1410
+ entries = [];
1411
+ }
1412
+ for (const entry of entries) {
1413
+ if (!entry.isDirectory())
1414
+ continue;
1415
+ const wsPath = node_path_1.default.join(defaultBase, entry.name);
1416
+ const manifestPath = node_path_1.default.join(wsPath, 'WORKSPACE.md');
1417
+ if (!node_fs_1.default.existsSync(manifestPath))
1418
+ continue;
1419
+ let repoCount = 0;
1420
+ let hasProject = false;
1421
+ let strategy = 'unknown';
1422
+ const manifest = (0, shell_command_projection_cjs_1.platformReadSync)(manifestPath);
1423
+ if (manifest !== null) {
1424
+ const strategyMatch = manifest.match(/^Strategy:\s*(.+)$/m);
1425
+ if (strategyMatch)
1426
+ strategy = strategyMatch[1].trim();
1427
+ const tableRows = manifest
1428
+ .split('\n')
1429
+ .filter((l) => l.match(/^\|\s*\w/) && !l.includes('Repo') && !l.includes('---'));
1430
+ repoCount = tableRows.length;
1431
+ }
1432
+ hasProject = node_fs_1.default.existsSync(node_path_1.default.join(wsPath, '.planning', 'PROJECT.md'));
1433
+ workspaces.push({
1434
+ name: entry.name,
1435
+ path: wsPath,
1436
+ repo_count: repoCount,
1437
+ strategy,
1438
+ has_project: hasProject,
1439
+ });
1440
+ }
1441
+ }
1442
+ const result = {
1443
+ workspace_base: defaultBase,
1444
+ workspaces,
1445
+ workspace_count: workspaces.length,
1446
+ };
1447
+ output(result, raw);
1448
+ }
1449
+ function cmdInitRemoveWorkspace(cwd, name, raw) {
1450
+ const homedir = process.env['HOME'] || node_os_1.default.homedir();
1451
+ const defaultBase = node_path_1.default.join(homedir, 'gsd-workspaces');
1452
+ if (!name) {
1453
+ error('workspace name required for init remove-workspace');
1454
+ }
1455
+ const wsPath = node_path_1.default.join(defaultBase, name);
1456
+ const manifestPath = node_path_1.default.join(wsPath, 'WORKSPACE.md');
1457
+ if (!node_fs_1.default.existsSync(wsPath)) {
1458
+ error(`Workspace not found: ${wsPath}`);
1459
+ }
1460
+ const repos = [];
1461
+ let strategy = 'unknown';
1462
+ const manifestContent = (0, shell_command_projection_cjs_1.platformReadSync)(manifestPath);
1463
+ if (manifestContent !== null) {
1464
+ try {
1465
+ const manifest = manifestContent;
1466
+ const strategyMatch = manifest.match(/^Strategy:\s*(.+)$/m);
1467
+ if (strategyMatch)
1468
+ strategy = strategyMatch[1].trim();
1469
+ const lines = manifest.split('\n');
1470
+ for (const line of lines) {
1471
+ const lineMatch = line.match(/^\|\s*(\S+)\s*\|\s*(\S+)\s*\|\s*(\S+)\s*\|\s*(\S+)\s*\|$/);
1472
+ if (lineMatch && lineMatch[1] !== 'Repo' && !lineMatch[1].includes('---')) {
1473
+ repos.push({
1474
+ name: lineMatch[1],
1475
+ source: lineMatch[2],
1476
+ branch: lineMatch[3],
1477
+ strategy: lineMatch[4],
1478
+ });
1479
+ }
1480
+ }
1481
+ }
1482
+ catch {
1483
+ /* best-effort */
1484
+ }
1485
+ }
1486
+ const dirtyRepos = [];
1487
+ for (const repo of repos) {
1488
+ const repoPath = node_path_1.default.join(wsPath, repo.name);
1489
+ if (!node_fs_1.default.existsSync(repoPath))
1490
+ continue;
1491
+ const statusResult = (0, shell_command_projection_cjs_1.execGit)(['status', '--porcelain'], {
1492
+ cwd: repoPath,
1493
+ timeout: 5000,
1494
+ });
1495
+ if (statusResult['exitCode'] === 0 &&
1496
+ statusResult['stdout'].length > 0) {
1497
+ dirtyRepos.push(repo.name);
1498
+ }
1499
+ }
1500
+ const result = {
1501
+ workspace_name: name,
1502
+ workspace_path: wsPath,
1503
+ has_manifest: node_fs_1.default.existsSync(manifestPath),
1504
+ strategy,
1505
+ repos,
1506
+ repo_count: repos.length,
1507
+ dirty_repos: dirtyRepos,
1508
+ has_dirty_repos: dirtyRepos.length > 0,
1509
+ };
1510
+ output(result, raw);
1511
+ }
1512
+ function buildAgentSkillsBlock(config, agentType, projectRoot) {
1513
+ const runtime = (config && config['runtime']) || 'claude';
1514
+ const globalSkillsBase = (0, runtime_homes_cjs_1.getGlobalSkillsBase)(runtime);
1515
+ if (!config || !config['agent_skills'] || !agentType)
1516
+ return '';
1517
+ let skillPaths = config['agent_skills'][agentType];
1518
+ if (!skillPaths)
1519
+ return '';
1520
+ if (typeof skillPaths === 'string')
1521
+ skillPaths = [skillPaths];
1522
+ if (!Array.isArray(skillPaths) || skillPaths.length === 0)
1523
+ return '';
1524
+ const validPaths = [];
1525
+ for (const skillPath of skillPaths) {
1526
+ if (typeof skillPath !== 'string')
1527
+ continue;
1528
+ if (skillPath.startsWith('global:')) {
1529
+ const skillName = skillPath.slice(7);
1530
+ if (!skillName) {
1531
+ process.stderr.write(`[agent-skills] WARNING: "global:" prefix with empty skill name — skipping\n`);
1532
+ continue;
1533
+ }
1534
+ if (!/^[a-zA-Z0-9_-]+$/.test(skillName)) {
1535
+ process.stderr.write(`[agent-skills] WARNING: Invalid global skill name "${skillName}" — skipping\n`);
1536
+ continue;
1537
+ }
1538
+ if (globalSkillsBase === null) {
1539
+ process.stderr.write(`[agent-skills] WARNING: Runtime "${runtime}" does not use a skills directory — "global:${skillName}" is not supported on this runtime\n`);
1540
+ continue;
1541
+ }
1542
+ const globalSkillDir = (0, runtime_homes_cjs_1.getGlobalSkillDir)(runtime, skillName);
1543
+ const globalSkillMd = node_path_1.default.join(globalSkillDir, 'SKILL.md');
1544
+ const displayPath = (0, runtime_homes_cjs_1.getGlobalSkillDisplayPath)(runtime, skillName);
1545
+ if (!node_fs_1.default.existsSync(globalSkillMd)) {
1546
+ process.stderr.write(`[agent-skills] WARNING: Global skill not found at "${displayPath}/SKILL.md" — skipping\n`);
1547
+ continue;
1548
+ }
1549
+ const pathCheck = (0, security_cjs_1.validatePath)(globalSkillMd, globalSkillsBase, { allowAbsolute: true });
1550
+ if (!pathCheck['safe']) {
1551
+ process.stderr.write(`[agent-skills] WARNING: Global skill "${skillName}" failed path check (symlink escape?) — skipping\n`);
1552
+ continue;
1553
+ }
1554
+ validPaths.push({ ref: `${globalSkillDir}/SKILL.md`, display: displayPath });
1555
+ continue;
1556
+ }
1557
+ const pathCheck = (0, security_cjs_1.validatePath)(skillPath, projectRoot);
1558
+ if (!pathCheck['safe']) {
1559
+ process.stderr.write(`[agent-skills] WARNING: Skipping unsafe path "${skillPath}": ${pathCheck['error']}\n`);
1560
+ continue;
1561
+ }
1562
+ const skillMdPath = node_path_1.default.join(projectRoot, skillPath, 'SKILL.md');
1563
+ if (!node_fs_1.default.existsSync(skillMdPath)) {
1564
+ process.stderr.write(`[agent-skills] WARNING: Skill not found at "${skillPath}/SKILL.md" — skipping\n`);
1565
+ continue;
1566
+ }
1567
+ validPaths.push({ ref: `${skillPath}/SKILL.md`, display: skillPath });
1568
+ }
1569
+ if (validPaths.length === 0)
1570
+ return '';
1571
+ const lines = validPaths.map((p) => `- @${p.ref}`).join('\n');
1572
+ return `<agent_skills>\nRead these user-configured skills:\n${lines}\n</agent_skills>`;
1573
+ }
1574
+ function cmdAgentSkills(cwd, agentType, raw, jsonMode) {
1575
+ if (!agentType) {
1576
+ output('', raw, '');
1577
+ return;
1578
+ }
1579
+ const config = loadConfig(cwd);
1580
+ const block = buildAgentSkillsBlock(config, agentType, cwd);
1581
+ if (jsonMode) {
1582
+ const skillPaths = (config && config.agent_skills && config.agent_skills[agentType]) || [];
1583
+ const normalizedPaths = Array.isArray(skillPaths)
1584
+ ? skillPaths
1585
+ : skillPaths
1586
+ ? [skillPaths]
1587
+ : [];
1588
+ output({ agent_type: agentType, block: block || '', skills_count: normalizedPaths.length }, raw);
1589
+ return;
1590
+ }
1591
+ if (block) {
1592
+ process.stdout.write(block);
1593
+ }
1594
+ process.exit(0);
1595
+ }
1596
+ function buildSkillManifest(cwd, skillsDir = null) {
1597
+ const canonicalRoots = skillsDir
1598
+ ? [
1599
+ {
1600
+ root: node_path_1.default.resolve(skillsDir),
1601
+ path: node_path_1.default.resolve(skillsDir),
1602
+ scope: 'custom',
1603
+ present: node_fs_1.default.existsSync(skillsDir),
1604
+ kind: 'skills',
1605
+ },
1606
+ ]
1607
+ : [
1608
+ {
1609
+ root: '.claude/skills',
1610
+ path: node_path_1.default.join(cwd, '.claude', 'skills'),
1611
+ scope: 'project',
1612
+ kind: 'skills',
1613
+ },
1614
+ {
1615
+ root: '.agents/skills',
1616
+ path: node_path_1.default.join(cwd, '.agents', 'skills'),
1617
+ scope: 'project',
1618
+ kind: 'skills',
1619
+ },
1620
+ {
1621
+ root: '.cursor/skills',
1622
+ path: node_path_1.default.join(cwd, '.cursor', 'skills'),
1623
+ scope: 'project',
1624
+ kind: 'skills',
1625
+ },
1626
+ {
1627
+ root: '.github/skills',
1628
+ path: node_path_1.default.join(cwd, '.github', 'skills'),
1629
+ scope: 'project',
1630
+ kind: 'skills',
1631
+ },
1632
+ {
1633
+ root: '.codex/skills',
1634
+ path: node_path_1.default.join(cwd, '.codex', 'skills'),
1635
+ scope: 'project',
1636
+ kind: 'skills',
1637
+ },
1638
+ {
1639
+ root: '~/.claude/skills',
1640
+ path: (0, runtime_homes_cjs_1.getGlobalSkillsBase)('claude'),
1641
+ scope: 'global',
1642
+ kind: 'skills',
1643
+ },
1644
+ {
1645
+ root: '~/.codex/skills',
1646
+ path: (0, runtime_homes_cjs_1.getGlobalSkillsBase)('codex'),
1647
+ scope: 'global',
1648
+ kind: 'skills',
1649
+ },
1650
+ {
1651
+ root: '.claude/gsd-core/skills',
1652
+ path: node_path_1.default.join(node_os_1.default.homedir(), '.claude', 'gsd-core', 'skills'),
1653
+ scope: 'import-only',
1654
+ kind: 'skills',
1655
+ deprecated: true,
1656
+ },
1657
+ {
1658
+ root: '.claude/commands/gsd',
1659
+ path: node_path_1.default.join(node_os_1.default.homedir(), '.claude', 'commands', 'gsd'),
1660
+ scope: 'legacy-commands',
1661
+ kind: 'commands',
1662
+ deprecated: true,
1663
+ },
1664
+ ];
1665
+ const skills = [];
1666
+ const roots = [];
1667
+ let legacyClaudeCommandsInstalled = false;
1668
+ for (const rootInfo of canonicalRoots) {
1669
+ const rootPath = rootInfo.path;
1670
+ const rootSummary = {
1671
+ root: rootInfo.root,
1672
+ path: rootPath,
1673
+ scope: rootInfo.scope,
1674
+ present: node_fs_1.default.existsSync(rootPath),
1675
+ deprecated: !!rootInfo.deprecated,
1676
+ };
1677
+ if (!rootSummary.present) {
1678
+ roots.push(rootSummary);
1679
+ continue;
1680
+ }
1681
+ if (rootInfo.kind === 'commands') {
1682
+ let entries = [];
1683
+ try {
1684
+ entries = node_fs_1.default.readdirSync(rootPath, { withFileTypes: true });
1685
+ }
1686
+ catch {
1687
+ roots.push(rootSummary);
1688
+ continue;
1689
+ }
1690
+ const commandFiles = entries.filter((entry) => entry.isFile() && entry.name.endsWith('.md'));
1691
+ rootSummary.command_count = commandFiles.length;
1692
+ if (rootSummary.command_count > 0)
1693
+ legacyClaudeCommandsInstalled = true;
1694
+ roots.push(rootSummary);
1695
+ continue;
1696
+ }
1697
+ let entries;
1698
+ try {
1699
+ entries = node_fs_1.default.readdirSync(rootPath, { withFileTypes: true });
1700
+ }
1701
+ catch {
1702
+ roots.push(rootSummary);
1703
+ continue;
1704
+ }
1705
+ let skillCount = 0;
1706
+ for (const entry of entries) {
1707
+ if (!entry.isDirectory())
1708
+ continue;
1709
+ const skillMdPath = node_path_1.default.join(rootPath, entry.name, 'SKILL.md');
1710
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(skillMdPath);
1711
+ if (content === null)
1712
+ continue;
1713
+ const frontmatter = extractFrontmatter(content);
1714
+ const name = frontmatter['name'] || entry.name;
1715
+ const description = frontmatter['description'] || '';
1716
+ const triggers = [];
1717
+ const bodyMatch = content.match(/^---[\s\S]*?---\s*\n([\s\S]*)$/);
1718
+ if (bodyMatch) {
1719
+ const body = bodyMatch[1];
1720
+ const triggerLines = body.match(/^TRIGGER\s+when:\s*(.+)$/gmi);
1721
+ if (triggerLines) {
1722
+ for (const line of triggerLines) {
1723
+ const m = line.match(/^TRIGGER\s+when:\s*(.+)$/i);
1724
+ if (m)
1725
+ triggers.push(m[1].trim());
1726
+ }
1727
+ }
1728
+ }
1729
+ skills.push({
1730
+ name,
1731
+ description,
1732
+ triggers,
1733
+ path: entry.name,
1734
+ file_path: `${entry.name}/SKILL.md`,
1735
+ root: rootInfo.root,
1736
+ scope: rootInfo.scope,
1737
+ installed: rootInfo.scope !== 'import-only',
1738
+ deprecated: !!rootInfo.deprecated,
1739
+ });
1740
+ skillCount++;
1741
+ }
1742
+ rootSummary.skill_count = skillCount;
1743
+ roots.push(rootSummary);
1744
+ }
1745
+ skills.sort((a, b) => {
1746
+ const rootCmp = a.root.localeCompare(b.root);
1747
+ return rootCmp !== 0 ? rootCmp : a.name.localeCompare(b.name);
1748
+ });
1749
+ const gsdSkillsInstalled = skills.some((skill) => skill.name.startsWith('gsd-'));
1750
+ return {
1751
+ skills,
1752
+ roots,
1753
+ installation: {
1754
+ gsd_skills_installed: gsdSkillsInstalled,
1755
+ legacy_claude_commands_installed: legacyClaudeCommandsInstalled,
1756
+ },
1757
+ counts: {
1758
+ skills: skills.length,
1759
+ roots: roots.length,
1760
+ },
1761
+ };
1762
+ }
1763
+ function cmdSkillManifest(cwd, args, raw) {
1764
+ const skillsDirIdx = args.indexOf('--skills-dir');
1765
+ const skillsDir = skillsDirIdx >= 0 && args[skillsDirIdx + 1] ? args[skillsDirIdx + 1] : null;
1766
+ const manifest = buildSkillManifest(cwd, skillsDir);
1767
+ if (args.includes('--write')) {
1768
+ const planDir = node_path_1.default.join(cwd, '.planning');
1769
+ if (node_fs_1.default.existsSync(planDir)) {
1770
+ const manifestPath = node_path_1.default.join(planDir, 'skill-manifest.json');
1771
+ (0, shell_command_projection_cjs_1.platformWriteSync)(manifestPath, JSON.stringify(manifest, null, 2));
1772
+ }
1773
+ }
1774
+ output(manifest, raw);
1775
+ }
1776
+ module.exports = {
1777
+ cmdInitExecutePhase,
1778
+ cmdInitPlanPhase,
1779
+ cmdInitNewProject,
1780
+ cmdInitNewMilestone,
1781
+ cmdInitQuick,
1782
+ cmdInitIngestDocs,
1783
+ cmdInitResume,
1784
+ cmdInitVerifyWork,
1785
+ cmdInitPhaseOp,
1786
+ cmdInitTodos,
1787
+ cmdInitMilestoneOp,
1788
+ cmdInitMapCodebase,
1789
+ cmdInitProgress,
1790
+ cmdInitManager,
1791
+ cmdInitNewWorkspace,
1792
+ cmdInitListWorkspaces,
1793
+ cmdInitRemoveWorkspace,
1794
+ detectChildRepos,
1795
+ buildAgentSkillsBlock,
1796
+ cmdAgentSkills,
1797
+ buildSkillManifest,
1798
+ cmdSkillManifest,
1799
+ };