@opengsd/gsd-core 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/README.ja-JP.md +46 -791
  2. package/README.ko-KR.md +44 -780
  3. package/README.md +42 -218
  4. package/README.pt-BR.md +47 -414
  5. package/README.zh-CN.md +46 -763
  6. package/agents/gsd-ai-researcher.md +2 -2
  7. package/agents/gsd-debug-session-manager.md +1 -1
  8. package/agents/gsd-debugger.md +8 -8
  9. package/agents/gsd-doc-writer.md +7 -6
  10. package/agents/gsd-domain-researcher.md +15 -2
  11. package/agents/gsd-eval-auditor.md +1 -1
  12. package/agents/gsd-eval-planner.md +2 -2
  13. package/agents/gsd-executor.md +21 -8
  14. package/agents/gsd-framework-selector.md +1 -1
  15. package/agents/gsd-intel-updater.md +4 -4
  16. package/agents/gsd-phase-researcher.md +19 -6
  17. package/agents/gsd-plan-checker.md +3 -3
  18. package/agents/gsd-planner.md +36 -23
  19. package/agents/gsd-project-researcher.md +13 -0
  20. package/agents/gsd-research-synthesizer.md +6 -2
  21. package/agents/gsd-roadmapper.md +6 -6
  22. package/agents/gsd-ui-researcher.md +16 -3
  23. package/agents/gsd-user-profiler.md +2 -2
  24. package/agents/gsd-verifier.md +8 -8
  25. package/assets/gsd-logo-2000-transparent.png +0 -0
  26. package/assets/gsd-logo-2000-transparent.svg +17 -0
  27. package/assets/gsd-logo-2000.png +0 -0
  28. package/assets/gsd-logo-2000.svg +21 -0
  29. package/assets/terminal.svg +68 -0
  30. package/bin/install.js +255 -103
  31. package/commands/gsd/add-tests.md +1 -1
  32. package/commands/gsd/ai-integration-phase.md +3 -3
  33. package/commands/gsd/audit-fix.md +1 -1
  34. package/commands/gsd/audit-milestone.md +1 -1
  35. package/commands/gsd/audit-uat.md +1 -1
  36. package/commands/gsd/autonomous.md +2 -2
  37. package/commands/gsd/capture.md +6 -6
  38. package/commands/gsd/cleanup.md +1 -1
  39. package/commands/gsd/code-review.md +1 -1
  40. package/commands/gsd/complete-milestone.md +2 -2
  41. package/commands/gsd/config.md +3 -3
  42. package/commands/gsd/debug.md +1 -1
  43. package/commands/gsd/discuss-phase.md +5 -4
  44. package/commands/gsd/docs-update.md +1 -1
  45. package/commands/gsd/eval-review.md +2 -2
  46. package/commands/gsd/execute-phase.md +2 -2
  47. package/commands/gsd/explore.md +1 -1
  48. package/commands/gsd/extract-learnings.md +2 -2
  49. package/commands/gsd/fast.md +1 -1
  50. package/commands/gsd/forensics.md +1 -1
  51. package/commands/gsd/graphify.md +9 -9
  52. package/commands/gsd/health.md +1 -1
  53. package/commands/gsd/help.md +2 -2
  54. package/commands/gsd/import.md +5 -5
  55. package/commands/gsd/inbox.md +1 -1
  56. package/commands/gsd/ingest-docs.md +4 -4
  57. package/commands/gsd/manager.md +3 -3
  58. package/commands/gsd/map-codebase.md +1 -1
  59. package/commands/gsd/milestone-summary.md +1 -1
  60. package/commands/gsd/mvp-phase.md +4 -4
  61. package/commands/gsd/new-milestone.md +5 -5
  62. package/commands/gsd/new-project.md +5 -5
  63. package/commands/gsd/pause-work.md +2 -2
  64. package/commands/gsd/phase.md +4 -4
  65. package/commands/gsd/plan-phase.md +2 -2
  66. package/commands/gsd/plan-review-convergence.md +4 -4
  67. package/commands/gsd/pr-branch.md +1 -1
  68. package/commands/gsd/profile-user.md +2 -2
  69. package/commands/gsd/progress.md +4 -4
  70. package/commands/gsd/quick.md +1 -1
  71. package/commands/gsd/resume-work.md +1 -1
  72. package/commands/gsd/review.md +3 -2
  73. package/commands/gsd/secure-phase.md +1 -1
  74. package/commands/gsd/settings.md +1 -1
  75. package/commands/gsd/ship.md +2 -2
  76. package/commands/gsd/sketch.md +7 -7
  77. package/commands/gsd/spec-phase.md +2 -2
  78. package/commands/gsd/spike.md +3 -3
  79. package/commands/gsd/stats.md +1 -1
  80. package/commands/gsd/surface.md +4 -4
  81. package/commands/gsd/thread.md +1 -1
  82. package/commands/gsd/ui-phase.md +2 -2
  83. package/commands/gsd/ui-review.md +2 -2
  84. package/commands/gsd/ultraplan-phase.md +2 -2
  85. package/commands/gsd/undo.md +3 -3
  86. package/commands/gsd/update.md +3 -3
  87. package/commands/gsd/validate-phase.md +1 -1
  88. package/commands/gsd/verify-work.md +2 -2
  89. package/commands/gsd/workspace.md +4 -4
  90. package/{get-shit-done → gsd-core}/bin/check-latest-version.cjs +1 -1
  91. package/{get-shit-done → gsd-core}/bin/gsd-tools.cjs +50 -4
  92. package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
  93. package/gsd-core/bin/lib/adr-parser.cjs +399 -0
  94. package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
  95. package/gsd-core/bin/lib/artifacts.cjs +51 -0
  96. package/gsd-core/bin/lib/audit.cjs +743 -0
  97. package/gsd-core/bin/lib/check-command-router.cjs +342 -0
  98. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  99. package/gsd-core/bin/lib/clock.cjs +95 -0
  100. package/gsd-core/bin/lib/clusters.cjs +128 -0
  101. package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
  102. package/gsd-core/bin/lib/command-aliases.cjs +809 -0
  103. package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
  104. package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
  105. package/gsd-core/bin/lib/commands.cjs +1202 -0
  106. package/gsd-core/bin/lib/config-schema.cjs +29 -0
  107. package/gsd-core/bin/lib/config-types.cjs +19 -0
  108. package/gsd-core/bin/lib/config.cjs +714 -0
  109. package/{get-shit-done → gsd-core}/bin/lib/configuration.cjs +76 -85
  110. package/gsd-core/bin/lib/context-utilization.cjs +48 -0
  111. package/gsd-core/bin/lib/core.cjs +2007 -0
  112. package/{get-shit-done → gsd-core}/bin/lib/decisions.cjs +9 -7
  113. package/gsd-core/bin/lib/docs.cjs +252 -0
  114. package/gsd-core/bin/lib/drift.cjs +364 -0
  115. package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
  116. package/gsd-core/bin/lib/frontmatter.cjs +442 -0
  117. package/gsd-core/bin/lib/gap-checker.cjs +257 -0
  118. package/gsd-core/bin/lib/graphify.cjs +496 -0
  119. package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
  120. package/gsd-core/bin/lib/init-command-router.cjs +62 -0
  121. package/gsd-core/bin/lib/init.cjs +1799 -0
  122. package/gsd-core/bin/lib/install-profiles.cjs +526 -0
  123. package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
  124. package/gsd-core/bin/lib/installer-migration-report.cjs +347 -0
  125. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
  126. package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  127. package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  128. package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  129. package/gsd-core/bin/lib/installer-migrations.cjs +784 -0
  130. package/gsd-core/bin/lib/intel.cjs +607 -0
  131. package/gsd-core/bin/lib/learnings.cjs +270 -0
  132. package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
  133. package/gsd-core/bin/lib/milestone.cjs +373 -0
  134. package/gsd-core/bin/lib/model-catalog.cjs +154 -0
  135. package/gsd-core/bin/lib/model-profiles.cjs +24 -0
  136. package/gsd-core/bin/lib/observability/event.cjs +51 -0
  137. package/gsd-core/bin/lib/observability/logger.cjs +146 -0
  138. package/{get-shit-done → gsd-core}/bin/lib/observability/redaction.cjs +19 -21
  139. package/{get-shit-done → gsd-core}/bin/lib/package-identity.cjs +5 -1
  140. package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
  141. package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
  142. package/gsd-core/bin/lib/phase.cjs +1307 -0
  143. package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
  144. package/{get-shit-done → gsd-core}/bin/lib/plan-scan.cjs +18 -24
  145. package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
  146. package/gsd-core/bin/lib/profile-output.cjs +1120 -0
  147. package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
  148. package/gsd-core/bin/lib/project-root.cjs +119 -0
  149. package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
  150. package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
  151. package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
  152. package/gsd-core/bin/lib/roadmap-upgrade.cjs +491 -0
  153. package/gsd-core/bin/lib/roadmap.cjs +600 -0
  154. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +254 -0
  155. package/gsd-core/bin/lib/runtime-homes.cjs +169 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
  157. package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
  158. package/{get-shit-done → gsd-core}/bin/lib/schema-detect.cjs +20 -26
  159. package/gsd-core/bin/lib/secrets.cjs +34 -0
  160. package/gsd-core/bin/lib/security.cjs +407 -0
  161. package/gsd-core/bin/lib/semver-compare.cjs +42 -0
  162. package/gsd-core/bin/lib/shell-command-projection.cjs +524 -0
  163. package/gsd-core/bin/lib/state-command-router.cjs +160 -0
  164. package/{get-shit-done → gsd-core}/bin/lib/state-document.cjs +78 -82
  165. package/gsd-core/bin/lib/state.cjs +2010 -0
  166. package/gsd-core/bin/lib/surface.cjs +406 -0
  167. package/gsd-core/bin/lib/task-command-router.cjs +85 -0
  168. package/gsd-core/bin/lib/template.cjs +237 -0
  169. package/gsd-core/bin/lib/uat.cjs +297 -0
  170. package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
  171. package/gsd-core/bin/lib/update-context.cjs +218 -0
  172. package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
  173. package/gsd-core/bin/lib/validate.cjs +112 -0
  174. package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
  175. package/gsd-core/bin/lib/verify.cjs +1451 -0
  176. package/{get-shit-done → gsd-core}/bin/lib/workstream-inventory-builder.cjs +19 -12
  177. package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
  178. package/{get-shit-done → gsd-core}/bin/lib/workstream-name-policy.cjs +28 -31
  179. package/gsd-core/bin/lib/workstream.cjs +380 -0
  180. package/gsd-core/bin/lib/worktree-safety.cjs +912 -0
  181. package/{get-shit-done → gsd-core}/bin/shared/config-defaults.manifest.json +1 -0
  182. package/{get-shit-done → gsd-core}/bin/shared/config-schema.manifest.json +17 -1
  183. package/{get-shit-done → gsd-core}/bin/shared/model-catalog.json +27 -0
  184. package/{get-shit-done → gsd-core}/references/artifact-types.md +1 -1
  185. package/{get-shit-done → gsd-core}/references/checkpoints.md +1 -1
  186. package/{get-shit-done → gsd-core}/references/few-shot-examples/plan-checker.md +2 -2
  187. package/{get-shit-done → gsd-core}/references/few-shot-examples/verifier.md +12 -12
  188. package/{get-shit-done → gsd-core}/references/model-profile-resolution.md +1 -1
  189. package/{get-shit-done → gsd-core}/references/mvp-concepts.md +1 -1
  190. package/{get-shit-done → gsd-core}/references/planner-graphify-auto-update.md +2 -2
  191. package/{get-shit-done → gsd-core}/references/planner-human-verify-mode.md +1 -1
  192. package/{get-shit-done → gsd-core}/references/planner-mvp-mode.md +1 -1
  193. package/{get-shit-done → gsd-core}/references/ui-brand.md +4 -2
  194. package/{get-shit-done → gsd-core}/references/verification-patterns.md +1 -1
  195. package/gsd-core/references/worktree-branch-check.md +38 -0
  196. package/{get-shit-done → gsd-core}/references/worktree-path-safety.md +4 -26
  197. package/{get-shit-done → gsd-core}/templates/README.md +2 -2
  198. package/{get-shit-done → gsd-core}/templates/codebase/structure.md +10 -10
  199. package/{get-shit-done → gsd-core}/templates/copilot-instructions.md +1 -1
  200. package/{get-shit-done → gsd-core}/templates/phase-prompt.md +10 -10
  201. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
  202. package/{get-shit-done → gsd-core}/workflows/add-backlog.md +1 -1
  203. package/{get-shit-done → gsd-core}/workflows/add-phase.md +1 -1
  204. package/{get-shit-done → gsd-core}/workflows/add-tests.md +1 -1
  205. package/{get-shit-done → gsd-core}/workflows/add-todo.md +1 -1
  206. package/{get-shit-done → gsd-core}/workflows/ai-integration-phase.md +4 -4
  207. package/{get-shit-done → gsd-core}/workflows/audit-fix.md +2 -2
  208. package/{get-shit-done → gsd-core}/workflows/audit-milestone.md +3 -1
  209. package/{get-shit-done → gsd-core}/workflows/audit-uat.md +1 -1
  210. package/{get-shit-done → gsd-core}/workflows/autonomous.md +10 -8
  211. package/{get-shit-done → gsd-core}/workflows/check-todos.md +1 -1
  212. package/{get-shit-done → gsd-core}/workflows/cleanup.md +44 -4
  213. package/{get-shit-done → gsd-core}/workflows/code-review-fix.md +4 -4
  214. package/{get-shit-done → gsd-core}/workflows/code-review.md +6 -4
  215. package/{get-shit-done → gsd-core}/workflows/complete-milestone.md +2 -2
  216. package/{get-shit-done → gsd-core}/workflows/debug.md +7 -2
  217. package/{get-shit-done → gsd-core}/workflows/diagnose-issues.md +6 -2
  218. package/{get-shit-done → gsd-core}/workflows/discovery-phase.md +5 -5
  219. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/advisor.md +5 -5
  220. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/auto.md +1 -1
  221. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/chain.md +1 -1
  222. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/power.md +1 -1
  223. package/{get-shit-done → gsd-core}/workflows/discuss-phase-assumptions.md +4 -4
  224. package/{get-shit-done → gsd-core}/workflows/discuss-phase.md +6 -6
  225. package/{get-shit-done → gsd-core}/workflows/do.md +1 -1
  226. package/{get-shit-done → gsd-core}/workflows/docs-update.md +19 -5
  227. package/{get-shit-done → gsd-core}/workflows/edit-phase.md +1 -1
  228. package/{get-shit-done → gsd-core}/workflows/eval-review.md +3 -3
  229. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/codebase-drift-gate.md +16 -3
  230. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  231. package/{get-shit-done → gsd-core}/workflows/execute-phase.md +89 -57
  232. package/{get-shit-done → gsd-core}/workflows/execute-plan.md +8 -8
  233. package/{get-shit-done → gsd-core}/workflows/explore.md +5 -3
  234. package/{get-shit-done → gsd-core}/workflows/extract-learnings.md +1 -1
  235. package/{get-shit-done → gsd-core}/workflows/forensics.md +1 -1
  236. package/{get-shit-done → gsd-core}/workflows/graduation.md +1 -1
  237. package/{get-shit-done → gsd-core}/workflows/health.md +1 -1
  238. package/{get-shit-done → gsd-core}/workflows/help/modes/default.md +3 -3
  239. package/{get-shit-done → gsd-core}/workflows/help/modes/full.md +6 -6
  240. package/{get-shit-done → gsd-core}/workflows/import.md +3 -1
  241. package/{get-shit-done → gsd-core}/workflows/ingest-docs.md +5 -5
  242. package/{get-shit-done → gsd-core}/workflows/insert-phase.md +1 -1
  243. package/{get-shit-done → gsd-core}/workflows/list-workspaces.md +1 -1
  244. package/{get-shit-done → gsd-core}/workflows/manager.md +3 -3
  245. package/{get-shit-done → gsd-core}/workflows/map-codebase.md +3 -1
  246. package/{get-shit-done → gsd-core}/workflows/milestone-summary.md +1 -1
  247. package/{get-shit-done → gsd-core}/workflows/mvp-phase.md +7 -7
  248. package/{get-shit-done → gsd-core}/workflows/new-milestone.md +5 -5
  249. package/{get-shit-done → gsd-core}/workflows/new-project.md +8 -8
  250. package/{get-shit-done → gsd-core}/workflows/new-workspace.md +1 -1
  251. package/{get-shit-done → gsd-core}/workflows/next.md +1 -1
  252. package/{get-shit-done → gsd-core}/workflows/pause-work.md +1 -1
  253. package/{get-shit-done → gsd-core}/workflows/plan-milestone-gaps.md +1 -1
  254. package/{get-shit-done → gsd-core}/workflows/plan-phase.md +29 -28
  255. package/{get-shit-done → gsd-core}/workflows/plan-review-convergence.md +10 -10
  256. package/{get-shit-done → gsd-core}/workflows/plant-seed.md +1 -1
  257. package/{get-shit-done → gsd-core}/workflows/profile-user.md +11 -11
  258. package/{get-shit-done → gsd-core}/workflows/progress.md +1 -1
  259. package/{get-shit-done → gsd-core}/workflows/quick.md +7 -29
  260. package/{get-shit-done → gsd-core}/workflows/reapply-patches.md +2 -2
  261. package/{get-shit-done → gsd-core}/workflows/remove-phase.md +1 -1
  262. package/{get-shit-done → gsd-core}/workflows/remove-workspace.md +1 -1
  263. package/{get-shit-done → gsd-core}/workflows/resume-project.md +2 -2
  264. package/{get-shit-done → gsd-core}/workflows/review.md +110 -2
  265. package/{get-shit-done → gsd-core}/workflows/scan.md +3 -1
  266. package/{get-shit-done → gsd-core}/workflows/secure-phase.md +5 -3
  267. package/{get-shit-done → gsd-core}/workflows/settings-advanced.md +196 -6
  268. package/{get-shit-done → gsd-core}/workflows/settings-integrations.md +2 -2
  269. package/{get-shit-done → gsd-core}/workflows/settings.md +16 -2
  270. package/{get-shit-done → gsd-core}/workflows/ship.md +56 -4
  271. package/{get-shit-done → gsd-core}/workflows/sketch-wrap-up.md +1 -1
  272. package/{get-shit-done → gsd-core}/workflows/sketch.md +5 -5
  273. package/{get-shit-done → gsd-core}/workflows/spec-phase.md +2 -2
  274. package/{get-shit-done → gsd-core}/workflows/spike-wrap-up.md +1 -1
  275. package/{get-shit-done → gsd-core}/workflows/spike.md +1 -1
  276. package/{get-shit-done → gsd-core}/workflows/stats.md +1 -1
  277. package/{get-shit-done → gsd-core}/workflows/sync-skills.md +3 -3
  278. package/{get-shit-done → gsd-core}/workflows/thread.md +1 -1
  279. package/{get-shit-done → gsd-core}/workflows/transition.md +2 -2
  280. package/{get-shit-done → gsd-core}/workflows/ui-phase.md +5 -5
  281. package/{get-shit-done → gsd-core}/workflows/ui-review.md +3 -3
  282. package/{get-shit-done → gsd-core}/workflows/ultraplan-phase.md +1 -1
  283. package/{get-shit-done → gsd-core}/workflows/undo.md +2 -2
  284. package/{get-shit-done → gsd-core}/workflows/update.md +41 -16
  285. package/{get-shit-done → gsd-core}/workflows/validate-phase.md +5 -3
  286. package/{get-shit-done → gsd-core}/workflows/verify-phase.md +4 -4
  287. package/{get-shit-done → gsd-core}/workflows/verify-work.md +7 -7
  288. package/hooks/dist/gsd-check-update-worker.js +16 -3
  289. package/hooks/dist/gsd-check-update.js +7 -5
  290. package/hooks/dist/gsd-context-monitor.js +2 -2
  291. package/hooks/dist/gsd-statusline.js +39 -21
  292. package/hooks/dist/gsd-update-banner.js +6 -2
  293. package/hooks/dist/gsd-worktree-path-guard.js +169 -0
  294. package/hooks/dist/managed-hooks-registry.cjs +35 -0
  295. package/hooks/gsd-check-update-worker.js +16 -3
  296. package/hooks/gsd-check-update.js +7 -5
  297. package/hooks/gsd-context-monitor.js +2 -2
  298. package/hooks/gsd-statusline.js +39 -21
  299. package/hooks/gsd-update-banner.js +6 -2
  300. package/hooks/gsd-worktree-path-guard.js +169 -0
  301. package/hooks/managed-hooks-registry.cjs +1 -0
  302. package/package.json +17 -11
  303. package/scripts/affected-tests-lib.cjs +1 -1
  304. package/scripts/base64-scan.sh +12 -0
  305. package/scripts/build-hooks.js +5 -1
  306. package/scripts/changeset/cli.cjs +2 -2
  307. package/scripts/changeset/github-release-notes.cjs +1 -1
  308. package/scripts/changeset/lint.cjs +1 -1
  309. package/scripts/check-alias-drift.cjs +8 -8
  310. package/scripts/check-env.cjs +5 -1
  311. package/scripts/ci-test-scope.cjs +34 -9
  312. package/scripts/command-contract-helpers.cjs +1 -1
  313. package/scripts/fix-slash-commands.cjs +5 -5
  314. package/scripts/gen-inventory-manifest.cjs +3 -3
  315. package/scripts/generate-package-identity.cjs +28 -7
  316. package/scripts/lib/allowlist-ratchet.cjs +136 -0
  317. package/scripts/lint-command-contract.cjs +1 -1
  318. package/scripts/lint-legacy-dir-name.cjs +156 -0
  319. package/scripts/lint-package-identity-drift.cjs +8 -8
  320. package/scripts/lint-pr-check-project-dir.cjs +0 -1
  321. package/scripts/lint-shell-command-projection-drift.cjs +1 -1
  322. package/scripts/lint-skill-deps.cjs +1 -1
  323. package/scripts/lint-test-file-count.allowlist.json +129 -32
  324. package/scripts/lint-test-file-count.cjs +85 -30
  325. package/scripts/mutation-matrix.cjs +219 -0
  326. package/scripts/prompt-injection-scan.sh +5 -1
  327. package/scripts/release-notes/format-github-release-notes.cjs +256 -0
  328. package/scripts/release-tarball-smoke.cjs +9 -9
  329. package/scripts/run-tests.cjs +34 -2
  330. package/scripts/strip-prose-atrefs.cjs +2 -2
  331. package/scripts/sync-runtime-launcher.cjs +2 -2
  332. package/scripts/verify-npm-publish.cjs +252 -0
  333. package/get-shit-done/bin/lib/active-workstream-store.cjs +0 -302
  334. package/get-shit-done/bin/lib/adr-parser.cjs +0 -394
  335. package/get-shit-done/bin/lib/agent-command-router.cjs +0 -65
  336. package/get-shit-done/bin/lib/artifacts.cjs +0 -53
  337. package/get-shit-done/bin/lib/audit.cjs +0 -755
  338. package/get-shit-done/bin/lib/check-command-router.cjs +0 -333
  339. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +0 -118
  340. package/get-shit-done/bin/lib/clock.cjs +0 -96
  341. package/get-shit-done/bin/lib/clusters.cjs +0 -135
  342. package/get-shit-done/bin/lib/code-review-flags.cjs +0 -74
  343. package/get-shit-done/bin/lib/command-aliases.cjs +0 -815
  344. package/get-shit-done/bin/lib/command-arg-projection.cjs +0 -62
  345. package/get-shit-done/bin/lib/command-routing-hub.cjs +0 -388
  346. package/get-shit-done/bin/lib/commands.cjs +0 -1188
  347. package/get-shit-done/bin/lib/config-schema.cjs +0 -31
  348. package/get-shit-done/bin/lib/config.cjs +0 -728
  349. package/get-shit-done/bin/lib/context-utilization.cjs +0 -47
  350. package/get-shit-done/bin/lib/core.cjs +0 -2121
  351. package/get-shit-done/bin/lib/docs.cjs +0 -270
  352. package/get-shit-done/bin/lib/drift.cjs +0 -388
  353. package/get-shit-done/bin/lib/fallow-runner.cjs +0 -109
  354. package/get-shit-done/bin/lib/frontmatter.cjs +0 -389
  355. package/get-shit-done/bin/lib/gap-checker.cjs +0 -205
  356. package/get-shit-done/bin/lib/graphify.cjs +0 -592
  357. package/get-shit-done/bin/lib/gsd2-import.cjs +0 -514
  358. package/get-shit-done/bin/lib/init-command-router.cjs +0 -58
  359. package/get-shit-done/bin/lib/init.cjs +0 -2112
  360. package/get-shit-done/bin/lib/install-profiles.cjs +0 -603
  361. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +0 -117
  362. package/get-shit-done/bin/lib/installer-migration-report.cjs +0 -354
  363. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +0 -220
  364. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +0 -41
  365. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +0 -80
  366. package/get-shit-done/bin/lib/installer-migrations.cjs +0 -778
  367. package/get-shit-done/bin/lib/intel.cjs +0 -708
  368. package/get-shit-done/bin/lib/learnings.cjs +0 -421
  369. package/get-shit-done/bin/lib/milestone.cjs +0 -314
  370. package/get-shit-done/bin/lib/model-catalog.cjs +0 -212
  371. package/get-shit-done/bin/lib/model-profiles.cjs +0 -31
  372. package/get-shit-done/bin/lib/observability/event.cjs +0 -82
  373. package/get-shit-done/bin/lib/observability/logger.cjs +0 -174
  374. package/get-shit-done/bin/lib/phase-command-router.cjs +0 -191
  375. package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -80
  376. package/get-shit-done/bin/lib/phase.cjs +0 -1607
  377. package/get-shit-done/bin/lib/phases-command-router.cjs +0 -39
  378. package/get-shit-done/bin/lib/planning-workspace.cjs +0 -238
  379. package/get-shit-done/bin/lib/profile-output.cjs +0 -1141
  380. package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
  381. package/get-shit-done/bin/lib/project-root.cjs +0 -112
  382. package/get-shit-done/bin/lib/prompt-budget.cjs +0 -399
  383. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +0 -125
  384. package/get-shit-done/bin/lib/roadmap-command-router.cjs +0 -28
  385. package/get-shit-done/bin/lib/roadmap.cjs +0 -650
  386. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +0 -301
  387. package/get-shit-done/bin/lib/runtime-homes.cjs +0 -222
  388. package/get-shit-done/bin/lib/runtime-name-policy.cjs +0 -83
  389. package/get-shit-done/bin/lib/runtime-slash.cjs +0 -112
  390. package/get-shit-done/bin/lib/secrets.cjs +0 -32
  391. package/get-shit-done/bin/lib/security.cjs +0 -600
  392. package/get-shit-done/bin/lib/semver-compare.cjs +0 -35
  393. package/get-shit-done/bin/lib/shell-command-projection.cjs +0 -500
  394. package/get-shit-done/bin/lib/state-command-router.cjs +0 -252
  395. package/get-shit-done/bin/lib/state.cjs +0 -2038
  396. package/get-shit-done/bin/lib/surface.cjs +0 -470
  397. package/get-shit-done/bin/lib/task-command-router.cjs +0 -81
  398. package/get-shit-done/bin/lib/template.cjs +0 -228
  399. package/get-shit-done/bin/lib/uat.cjs +0 -289
  400. package/get-shit-done/bin/lib/update-context.cjs +0 -209
  401. package/get-shit-done/bin/lib/validate-command-router.cjs +0 -83
  402. package/get-shit-done/bin/lib/validate.cjs +0 -92
  403. package/get-shit-done/bin/lib/verify-command-router.cjs +0 -40
  404. package/get-shit-done/bin/lib/verify.cjs +0 -1511
  405. package/get-shit-done/bin/lib/workstream-inventory.cjs +0 -146
  406. package/get-shit-done/bin/lib/workstream.cjs +0 -389
  407. package/get-shit-done/bin/lib/worktree-safety.cjs +0 -985
  408. package/get-shit-done/workflows/_runtime-launcher.snippet.sh +0 -1
  409. package/scripts/lint-no-source-grep-extras.cjs +0 -81
  410. package/scripts/lint-no-source-grep.cjs +0 -174
  411. package/scripts/lint-shared-module-handsync.cjs +0 -388
  412. package/scripts/shared-module-handsync-allowlist.json +0 -183
  413. /package/{get-shit-done → gsd-core}/bin/shared/runtime-aliases.manifest.json +0 -0
  414. /package/{get-shit-done → gsd-core}/bin/verify-reapply-patches.cjs +0 -0
  415. /package/{get-shit-done → gsd-core}/contexts/dev.md +0 -0
  416. /package/{get-shit-done → gsd-core}/contexts/research.md +0 -0
  417. /package/{get-shit-done → gsd-core}/contexts/review.md +0 -0
  418. /package/{get-shit-done → gsd-core}/references/agent-contracts.md +0 -0
  419. /package/{get-shit-done → gsd-core}/references/ai-evals.md +0 -0
  420. /package/{get-shit-done → gsd-core}/references/ai-frameworks.md +0 -0
  421. /package/{get-shit-done → gsd-core}/references/autonomous-smart-discuss.md +0 -0
  422. /package/{get-shit-done → gsd-core}/references/common-bug-patterns.md +0 -0
  423. /package/{get-shit-done → gsd-core}/references/context-budget.md +0 -0
  424. /package/{get-shit-done → gsd-core}/references/continuation-format.md +0 -0
  425. /package/{get-shit-done → gsd-core}/references/debugger-philosophy.md +0 -0
  426. /package/{get-shit-done → gsd-core}/references/decimal-phase-calculation.md +0 -0
  427. /package/{get-shit-done → gsd-core}/references/doc-conflict-engine.md +0 -0
  428. /package/{get-shit-done → gsd-core}/references/domain-probes.md +0 -0
  429. /package/{get-shit-done → gsd-core}/references/execute-mvp-tdd.md +0 -0
  430. /package/{get-shit-done → gsd-core}/references/executor-examples.md +0 -0
  431. /package/{get-shit-done → gsd-core}/references/gate-prompts.md +0 -0
  432. /package/{get-shit-done → gsd-core}/references/gates.md +0 -0
  433. /package/{get-shit-done → gsd-core}/references/git-integration.md +0 -0
  434. /package/{get-shit-done → gsd-core}/references/git-planning-commit.md +0 -0
  435. /package/{get-shit-done → gsd-core}/references/ios-scaffold.md +0 -0
  436. /package/{get-shit-done → gsd-core}/references/mandatory-initial-read.md +0 -0
  437. /package/{get-shit-done → gsd-core}/references/model-profiles.md +0 -0
  438. /package/{get-shit-done → gsd-core}/references/phase-argument-parsing.md +0 -0
  439. /package/{get-shit-done → gsd-core}/references/planner-antipatterns.md +0 -0
  440. /package/{get-shit-done → gsd-core}/references/planner-chunked.md +0 -0
  441. /package/{get-shit-done → gsd-core}/references/planner-gap-closure.md +0 -0
  442. /package/{get-shit-done → gsd-core}/references/planner-interface-context.md +0 -0
  443. /package/{get-shit-done → gsd-core}/references/planner-reviews.md +0 -0
  444. /package/{get-shit-done → gsd-core}/references/planner-revision.md +0 -0
  445. /package/{get-shit-done → gsd-core}/references/planner-source-audit.md +0 -0
  446. /package/{get-shit-done → gsd-core}/references/planning-config.md +0 -0
  447. /package/{get-shit-done → gsd-core}/references/project-skills-discovery.md +0 -0
  448. /package/{get-shit-done → gsd-core}/references/questioning.md +0 -0
  449. /package/{get-shit-done → gsd-core}/references/revision-loop.md +0 -0
  450. /package/{get-shit-done → gsd-core}/references/scout-codebase.md +0 -0
  451. /package/{get-shit-done → gsd-core}/references/skeleton-template.md +0 -0
  452. /package/{get-shit-done → gsd-core}/references/sketch-interactivity.md +0 -0
  453. /package/{get-shit-done → gsd-core}/references/sketch-theme-system.md +0 -0
  454. /package/{get-shit-done → gsd-core}/references/sketch-tooling.md +0 -0
  455. /package/{get-shit-done → gsd-core}/references/sketch-variant-patterns.md +0 -0
  456. /package/{get-shit-done → gsd-core}/references/spidr-splitting.md +0 -0
  457. /package/{get-shit-done → gsd-core}/references/tdd.md +0 -0
  458. /package/{get-shit-done → gsd-core}/references/thinking-models-debug.md +0 -0
  459. /package/{get-shit-done → gsd-core}/references/thinking-models-execution.md +0 -0
  460. /package/{get-shit-done → gsd-core}/references/thinking-models-planning.md +0 -0
  461. /package/{get-shit-done → gsd-core}/references/thinking-models-research.md +0 -0
  462. /package/{get-shit-done → gsd-core}/references/thinking-models-verification.md +0 -0
  463. /package/{get-shit-done → gsd-core}/references/thinking-partner.md +0 -0
  464. /package/{get-shit-done → gsd-core}/references/universal-anti-patterns.md +0 -0
  465. /package/{get-shit-done → gsd-core}/references/user-profiling.md +0 -0
  466. /package/{get-shit-done → gsd-core}/references/user-story-template.md +0 -0
  467. /package/{get-shit-done → gsd-core}/references/verification-overrides.md +0 -0
  468. /package/{get-shit-done → gsd-core}/references/verify-mvp-mode.md +0 -0
  469. /package/{get-shit-done → gsd-core}/references/workstream-flag.md +0 -0
  470. /package/{get-shit-done → gsd-core}/templates/AI-SPEC.md +0 -0
  471. /package/{get-shit-done → gsd-core}/templates/DEBUG.md +0 -0
  472. /package/{get-shit-done → gsd-core}/templates/SECURITY.md +0 -0
  473. /package/{get-shit-done → gsd-core}/templates/UAT.md +0 -0
  474. /package/{get-shit-done → gsd-core}/templates/UI-SPEC.md +0 -0
  475. /package/{get-shit-done → gsd-core}/templates/VALIDATION.md +0 -0
  476. /package/{get-shit-done → gsd-core}/templates/claude-md.md +0 -0
  477. /package/{get-shit-done → gsd-core}/templates/codebase/architecture.md +0 -0
  478. /package/{get-shit-done → gsd-core}/templates/codebase/concerns.md +0 -0
  479. /package/{get-shit-done → gsd-core}/templates/codebase/conventions.md +0 -0
  480. /package/{get-shit-done → gsd-core}/templates/codebase/integrations.md +0 -0
  481. /package/{get-shit-done → gsd-core}/templates/codebase/stack.md +0 -0
  482. /package/{get-shit-done → gsd-core}/templates/codebase/testing.md +0 -0
  483. /package/{get-shit-done → gsd-core}/templates/config.json +0 -0
  484. /package/{get-shit-done → gsd-core}/templates/context.md +0 -0
  485. /package/{get-shit-done → gsd-core}/templates/continue-here.md +0 -0
  486. /package/{get-shit-done → gsd-core}/templates/debug-subagent-prompt.md +0 -0
  487. /package/{get-shit-done → gsd-core}/templates/dev-preferences.md +0 -0
  488. /package/{get-shit-done → gsd-core}/templates/discovery.md +0 -0
  489. /package/{get-shit-done → gsd-core}/templates/discussion-log.md +0 -0
  490. /package/{get-shit-done → gsd-core}/templates/milestone-archive.md +0 -0
  491. /package/{get-shit-done → gsd-core}/templates/milestone.md +0 -0
  492. /package/{get-shit-done → gsd-core}/templates/planner-subagent-prompt.md +0 -0
  493. /package/{get-shit-done → gsd-core}/templates/project.md +0 -0
  494. /package/{get-shit-done → gsd-core}/templates/requirements.md +0 -0
  495. /package/{get-shit-done → gsd-core}/templates/research-project/ARCHITECTURE.md +0 -0
  496. /package/{get-shit-done → gsd-core}/templates/research-project/FEATURES.md +0 -0
  497. /package/{get-shit-done → gsd-core}/templates/research-project/PITFALLS.md +0 -0
  498. /package/{get-shit-done → gsd-core}/templates/research-project/STACK.md +0 -0
  499. /package/{get-shit-done → gsd-core}/templates/research-project/SUMMARY.md +0 -0
  500. /package/{get-shit-done → gsd-core}/templates/research.md +0 -0
  501. /package/{get-shit-done → gsd-core}/templates/retrospective.md +0 -0
  502. /package/{get-shit-done → gsd-core}/templates/roadmap.md +0 -0
  503. /package/{get-shit-done → gsd-core}/templates/spec.md +0 -0
  504. /package/{get-shit-done → gsd-core}/templates/state.md +0 -0
  505. /package/{get-shit-done → gsd-core}/templates/summary-complex.md +0 -0
  506. /package/{get-shit-done → gsd-core}/templates/summary-minimal.md +0 -0
  507. /package/{get-shit-done → gsd-core}/templates/summary-standard.md +0 -0
  508. /package/{get-shit-done → gsd-core}/templates/summary.md +0 -0
  509. /package/{get-shit-done → gsd-core}/templates/user-profile.md +0 -0
  510. /package/{get-shit-done → gsd-core}/templates/user-setup.md +0 -0
  511. /package/{get-shit-done → gsd-core}/templates/verification-report.md +0 -0
  512. /package/{get-shit-done → gsd-core}/workflows/analyze-dependencies.md +0 -0
  513. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/all.md +0 -0
  514. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/analyze.md +0 -0
  515. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/batch.md +0 -0
  516. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/default.md +0 -0
  517. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/text.md +0 -0
  518. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/checkpoint.json +0 -0
  519. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/context.md +0 -0
  520. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/discussion-log.md +0 -0
  521. /package/{get-shit-done → gsd-core}/workflows/discuss-phase-power.md +0 -0
  522. /package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -0
  523. /package/{get-shit-done → gsd-core}/workflows/fast.md +0 -0
  524. /package/{get-shit-done → gsd-core}/workflows/help/modes/brief.md +0 -0
  525. /package/{get-shit-done → gsd-core}/workflows/help/modes/topic.md +0 -0
  526. /package/{get-shit-done → gsd-core}/workflows/help.md +0 -0
  527. /package/{get-shit-done → gsd-core}/workflows/inbox.md +0 -0
  528. /package/{get-shit-done → gsd-core}/workflows/list-phase-assumptions.md +0 -0
  529. /package/{get-shit-done → gsd-core}/workflows/node-repair.md +0 -0
  530. /package/{get-shit-done → gsd-core}/workflows/note.md +0 -0
  531. /package/{get-shit-done → gsd-core}/workflows/pr-branch.md +0 -0
  532. /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
+ };