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