@opengsd/gsd-core 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) hide show
  1. package/README.ja-JP.md +46 -791
  2. package/README.ko-KR.md +44 -780
  3. package/README.md +42 -218
  4. package/README.pt-BR.md +47 -414
  5. package/README.zh-CN.md +46 -763
  6. package/agents/gsd-ai-researcher.md +2 -2
  7. package/agents/gsd-debug-session-manager.md +1 -1
  8. package/agents/gsd-debugger.md +8 -8
  9. package/agents/gsd-doc-writer.md +7 -6
  10. package/agents/gsd-domain-researcher.md +15 -2
  11. package/agents/gsd-eval-auditor.md +1 -1
  12. package/agents/gsd-eval-planner.md +2 -2
  13. package/agents/gsd-executor.md +21 -8
  14. package/agents/gsd-framework-selector.md +1 -1
  15. package/agents/gsd-intel-updater.md +4 -4
  16. package/agents/gsd-phase-researcher.md +19 -6
  17. package/agents/gsd-plan-checker.md +3 -3
  18. package/agents/gsd-planner.md +36 -23
  19. package/agents/gsd-project-researcher.md +13 -0
  20. package/agents/gsd-research-synthesizer.md +6 -2
  21. package/agents/gsd-roadmapper.md +6 -6
  22. package/agents/gsd-ui-researcher.md +16 -3
  23. package/agents/gsd-user-profiler.md +2 -2
  24. package/agents/gsd-verifier.md +8 -8
  25. package/assets/gsd-logo-2000-transparent.png +0 -0
  26. package/assets/gsd-logo-2000-transparent.svg +17 -0
  27. package/assets/gsd-logo-2000.png +0 -0
  28. package/assets/gsd-logo-2000.svg +21 -0
  29. package/assets/terminal.svg +68 -0
  30. package/bin/install.js +255 -103
  31. package/commands/gsd/add-tests.md +1 -1
  32. package/commands/gsd/ai-integration-phase.md +3 -3
  33. package/commands/gsd/audit-fix.md +1 -1
  34. package/commands/gsd/audit-milestone.md +1 -1
  35. package/commands/gsd/audit-uat.md +1 -1
  36. package/commands/gsd/autonomous.md +2 -2
  37. package/commands/gsd/capture.md +6 -6
  38. package/commands/gsd/cleanup.md +1 -1
  39. package/commands/gsd/code-review.md +1 -1
  40. package/commands/gsd/complete-milestone.md +2 -2
  41. package/commands/gsd/config.md +3 -3
  42. package/commands/gsd/debug.md +1 -1
  43. package/commands/gsd/discuss-phase.md +5 -4
  44. package/commands/gsd/docs-update.md +1 -1
  45. package/commands/gsd/eval-review.md +2 -2
  46. package/commands/gsd/execute-phase.md +2 -2
  47. package/commands/gsd/explore.md +1 -1
  48. package/commands/gsd/extract-learnings.md +2 -2
  49. package/commands/gsd/fast.md +1 -1
  50. package/commands/gsd/forensics.md +1 -1
  51. package/commands/gsd/graphify.md +9 -9
  52. package/commands/gsd/health.md +1 -1
  53. package/commands/gsd/help.md +2 -2
  54. package/commands/gsd/import.md +5 -5
  55. package/commands/gsd/inbox.md +1 -1
  56. package/commands/gsd/ingest-docs.md +4 -4
  57. package/commands/gsd/manager.md +3 -3
  58. package/commands/gsd/map-codebase.md +1 -1
  59. package/commands/gsd/milestone-summary.md +1 -1
  60. package/commands/gsd/mvp-phase.md +4 -4
  61. package/commands/gsd/new-milestone.md +5 -5
  62. package/commands/gsd/new-project.md +5 -5
  63. package/commands/gsd/pause-work.md +2 -2
  64. package/commands/gsd/phase.md +4 -4
  65. package/commands/gsd/plan-phase.md +2 -2
  66. package/commands/gsd/plan-review-convergence.md +4 -4
  67. package/commands/gsd/pr-branch.md +1 -1
  68. package/commands/gsd/profile-user.md +2 -2
  69. package/commands/gsd/progress.md +4 -4
  70. package/commands/gsd/quick.md +1 -1
  71. package/commands/gsd/resume-work.md +1 -1
  72. package/commands/gsd/review.md +3 -2
  73. package/commands/gsd/secure-phase.md +1 -1
  74. package/commands/gsd/settings.md +1 -1
  75. package/commands/gsd/ship.md +2 -2
  76. package/commands/gsd/sketch.md +7 -7
  77. package/commands/gsd/spec-phase.md +2 -2
  78. package/commands/gsd/spike.md +3 -3
  79. package/commands/gsd/stats.md +1 -1
  80. package/commands/gsd/surface.md +4 -4
  81. package/commands/gsd/thread.md +1 -1
  82. package/commands/gsd/ui-phase.md +2 -2
  83. package/commands/gsd/ui-review.md +2 -2
  84. package/commands/gsd/ultraplan-phase.md +2 -2
  85. package/commands/gsd/undo.md +3 -3
  86. package/commands/gsd/update.md +3 -3
  87. package/commands/gsd/validate-phase.md +1 -1
  88. package/commands/gsd/verify-work.md +2 -2
  89. package/commands/gsd/workspace.md +4 -4
  90. package/{get-shit-done → gsd-core}/bin/check-latest-version.cjs +1 -1
  91. package/{get-shit-done → gsd-core}/bin/gsd-tools.cjs +50 -4
  92. package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
  93. package/gsd-core/bin/lib/adr-parser.cjs +399 -0
  94. package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
  95. package/gsd-core/bin/lib/artifacts.cjs +51 -0
  96. package/gsd-core/bin/lib/audit.cjs +743 -0
  97. package/gsd-core/bin/lib/check-command-router.cjs +342 -0
  98. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  99. package/gsd-core/bin/lib/clock.cjs +95 -0
  100. package/gsd-core/bin/lib/clusters.cjs +128 -0
  101. package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
  102. package/gsd-core/bin/lib/command-aliases.cjs +809 -0
  103. package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
  104. package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
  105. package/gsd-core/bin/lib/commands.cjs +1202 -0
  106. package/gsd-core/bin/lib/config-schema.cjs +29 -0
  107. package/gsd-core/bin/lib/config-types.cjs +19 -0
  108. package/gsd-core/bin/lib/config.cjs +714 -0
  109. package/{get-shit-done → gsd-core}/bin/lib/configuration.cjs +76 -85
  110. package/gsd-core/bin/lib/context-utilization.cjs +48 -0
  111. package/gsd-core/bin/lib/core.cjs +2007 -0
  112. package/{get-shit-done → gsd-core}/bin/lib/decisions.cjs +9 -7
  113. package/gsd-core/bin/lib/docs.cjs +252 -0
  114. package/gsd-core/bin/lib/drift.cjs +364 -0
  115. package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
  116. package/gsd-core/bin/lib/frontmatter.cjs +442 -0
  117. package/gsd-core/bin/lib/gap-checker.cjs +257 -0
  118. package/gsd-core/bin/lib/graphify.cjs +496 -0
  119. package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
  120. package/gsd-core/bin/lib/init-command-router.cjs +62 -0
  121. package/gsd-core/bin/lib/init.cjs +1799 -0
  122. package/gsd-core/bin/lib/install-profiles.cjs +526 -0
  123. package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
  124. package/gsd-core/bin/lib/installer-migration-report.cjs +347 -0
  125. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
  126. package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  127. package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  128. package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  129. package/gsd-core/bin/lib/installer-migrations.cjs +784 -0
  130. package/gsd-core/bin/lib/intel.cjs +607 -0
  131. package/gsd-core/bin/lib/learnings.cjs +270 -0
  132. package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
  133. package/gsd-core/bin/lib/milestone.cjs +373 -0
  134. package/gsd-core/bin/lib/model-catalog.cjs +154 -0
  135. package/gsd-core/bin/lib/model-profiles.cjs +24 -0
  136. package/gsd-core/bin/lib/observability/event.cjs +51 -0
  137. package/gsd-core/bin/lib/observability/logger.cjs +146 -0
  138. package/{get-shit-done → gsd-core}/bin/lib/observability/redaction.cjs +19 -21
  139. package/{get-shit-done → gsd-core}/bin/lib/package-identity.cjs +5 -1
  140. package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
  141. package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
  142. package/gsd-core/bin/lib/phase.cjs +1307 -0
  143. package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
  144. package/{get-shit-done → gsd-core}/bin/lib/plan-scan.cjs +18 -24
  145. package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
  146. package/gsd-core/bin/lib/profile-output.cjs +1120 -0
  147. package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
  148. package/gsd-core/bin/lib/project-root.cjs +119 -0
  149. package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
  150. package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
  151. package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
  152. package/gsd-core/bin/lib/roadmap-upgrade.cjs +491 -0
  153. package/gsd-core/bin/lib/roadmap.cjs +600 -0
  154. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +254 -0
  155. package/gsd-core/bin/lib/runtime-homes.cjs +169 -0
  156. package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
  157. package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
  158. package/{get-shit-done → gsd-core}/bin/lib/schema-detect.cjs +20 -26
  159. package/gsd-core/bin/lib/secrets.cjs +34 -0
  160. package/gsd-core/bin/lib/security.cjs +407 -0
  161. package/gsd-core/bin/lib/semver-compare.cjs +42 -0
  162. package/gsd-core/bin/lib/shell-command-projection.cjs +524 -0
  163. package/gsd-core/bin/lib/state-command-router.cjs +160 -0
  164. package/{get-shit-done → gsd-core}/bin/lib/state-document.cjs +78 -82
  165. package/gsd-core/bin/lib/state.cjs +2010 -0
  166. package/gsd-core/bin/lib/surface.cjs +406 -0
  167. package/gsd-core/bin/lib/task-command-router.cjs +85 -0
  168. package/gsd-core/bin/lib/template.cjs +237 -0
  169. package/gsd-core/bin/lib/uat.cjs +297 -0
  170. package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
  171. package/gsd-core/bin/lib/update-context.cjs +218 -0
  172. package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
  173. package/gsd-core/bin/lib/validate.cjs +112 -0
  174. package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
  175. package/gsd-core/bin/lib/verify.cjs +1451 -0
  176. package/{get-shit-done → gsd-core}/bin/lib/workstream-inventory-builder.cjs +19 -12
  177. package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
  178. package/{get-shit-done → gsd-core}/bin/lib/workstream-name-policy.cjs +28 -31
  179. package/gsd-core/bin/lib/workstream.cjs +380 -0
  180. package/gsd-core/bin/lib/worktree-safety.cjs +912 -0
  181. package/{get-shit-done → gsd-core}/bin/shared/config-defaults.manifest.json +1 -0
  182. package/{get-shit-done → gsd-core}/bin/shared/config-schema.manifest.json +17 -1
  183. package/{get-shit-done → gsd-core}/bin/shared/model-catalog.json +27 -0
  184. package/{get-shit-done → gsd-core}/references/artifact-types.md +1 -1
  185. package/{get-shit-done → gsd-core}/references/checkpoints.md +1 -1
  186. package/{get-shit-done → gsd-core}/references/few-shot-examples/plan-checker.md +2 -2
  187. package/{get-shit-done → gsd-core}/references/few-shot-examples/verifier.md +12 -12
  188. package/{get-shit-done → gsd-core}/references/model-profile-resolution.md +1 -1
  189. package/{get-shit-done → gsd-core}/references/mvp-concepts.md +1 -1
  190. package/{get-shit-done → gsd-core}/references/planner-graphify-auto-update.md +2 -2
  191. package/{get-shit-done → gsd-core}/references/planner-human-verify-mode.md +1 -1
  192. package/{get-shit-done → gsd-core}/references/planner-mvp-mode.md +1 -1
  193. package/{get-shit-done → gsd-core}/references/ui-brand.md +4 -2
  194. package/{get-shit-done → gsd-core}/references/verification-patterns.md +1 -1
  195. package/gsd-core/references/worktree-branch-check.md +38 -0
  196. package/{get-shit-done → gsd-core}/references/worktree-path-safety.md +4 -26
  197. package/{get-shit-done → gsd-core}/templates/README.md +2 -2
  198. package/{get-shit-done → gsd-core}/templates/codebase/structure.md +10 -10
  199. package/{get-shit-done → gsd-core}/templates/copilot-instructions.md +1 -1
  200. package/{get-shit-done → gsd-core}/templates/phase-prompt.md +10 -10
  201. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
  202. package/{get-shit-done → gsd-core}/workflows/add-backlog.md +1 -1
  203. package/{get-shit-done → gsd-core}/workflows/add-phase.md +1 -1
  204. package/{get-shit-done → gsd-core}/workflows/add-tests.md +1 -1
  205. package/{get-shit-done → gsd-core}/workflows/add-todo.md +1 -1
  206. package/{get-shit-done → gsd-core}/workflows/ai-integration-phase.md +4 -4
  207. package/{get-shit-done → gsd-core}/workflows/audit-fix.md +2 -2
  208. package/{get-shit-done → gsd-core}/workflows/audit-milestone.md +3 -1
  209. package/{get-shit-done → gsd-core}/workflows/audit-uat.md +1 -1
  210. package/{get-shit-done → gsd-core}/workflows/autonomous.md +10 -8
  211. package/{get-shit-done → gsd-core}/workflows/check-todos.md +1 -1
  212. package/{get-shit-done → gsd-core}/workflows/cleanup.md +44 -4
  213. package/{get-shit-done → gsd-core}/workflows/code-review-fix.md +4 -4
  214. package/{get-shit-done → gsd-core}/workflows/code-review.md +6 -4
  215. package/{get-shit-done → gsd-core}/workflows/complete-milestone.md +2 -2
  216. package/{get-shit-done → gsd-core}/workflows/debug.md +7 -2
  217. package/{get-shit-done → gsd-core}/workflows/diagnose-issues.md +6 -2
  218. package/{get-shit-done → gsd-core}/workflows/discovery-phase.md +5 -5
  219. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/advisor.md +5 -5
  220. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/auto.md +1 -1
  221. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/chain.md +1 -1
  222. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/power.md +1 -1
  223. package/{get-shit-done → gsd-core}/workflows/discuss-phase-assumptions.md +4 -4
  224. package/{get-shit-done → gsd-core}/workflows/discuss-phase.md +6 -6
  225. package/{get-shit-done → gsd-core}/workflows/do.md +1 -1
  226. package/{get-shit-done → gsd-core}/workflows/docs-update.md +19 -5
  227. package/{get-shit-done → gsd-core}/workflows/edit-phase.md +1 -1
  228. package/{get-shit-done → gsd-core}/workflows/eval-review.md +3 -3
  229. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/codebase-drift-gate.md +16 -3
  230. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  231. package/{get-shit-done → gsd-core}/workflows/execute-phase.md +89 -57
  232. package/{get-shit-done → gsd-core}/workflows/execute-plan.md +8 -8
  233. package/{get-shit-done → gsd-core}/workflows/explore.md +5 -3
  234. package/{get-shit-done → gsd-core}/workflows/extract-learnings.md +1 -1
  235. package/{get-shit-done → gsd-core}/workflows/forensics.md +1 -1
  236. package/{get-shit-done → gsd-core}/workflows/graduation.md +1 -1
  237. package/{get-shit-done → gsd-core}/workflows/health.md +1 -1
  238. package/{get-shit-done → gsd-core}/workflows/help/modes/default.md +3 -3
  239. package/{get-shit-done → gsd-core}/workflows/help/modes/full.md +6 -6
  240. package/{get-shit-done → gsd-core}/workflows/import.md +3 -1
  241. package/{get-shit-done → gsd-core}/workflows/ingest-docs.md +5 -5
  242. package/{get-shit-done → gsd-core}/workflows/insert-phase.md +1 -1
  243. package/{get-shit-done → gsd-core}/workflows/list-workspaces.md +1 -1
  244. package/{get-shit-done → gsd-core}/workflows/manager.md +3 -3
  245. package/{get-shit-done → gsd-core}/workflows/map-codebase.md +3 -1
  246. package/{get-shit-done → gsd-core}/workflows/milestone-summary.md +1 -1
  247. package/{get-shit-done → gsd-core}/workflows/mvp-phase.md +7 -7
  248. package/{get-shit-done → gsd-core}/workflows/new-milestone.md +5 -5
  249. package/{get-shit-done → gsd-core}/workflows/new-project.md +8 -8
  250. package/{get-shit-done → gsd-core}/workflows/new-workspace.md +1 -1
  251. package/{get-shit-done → gsd-core}/workflows/next.md +1 -1
  252. package/{get-shit-done → gsd-core}/workflows/pause-work.md +1 -1
  253. package/{get-shit-done → gsd-core}/workflows/plan-milestone-gaps.md +1 -1
  254. package/{get-shit-done → gsd-core}/workflows/plan-phase.md +29 -28
  255. package/{get-shit-done → gsd-core}/workflows/plan-review-convergence.md +10 -10
  256. package/{get-shit-done → gsd-core}/workflows/plant-seed.md +1 -1
  257. package/{get-shit-done → gsd-core}/workflows/profile-user.md +11 -11
  258. package/{get-shit-done → gsd-core}/workflows/progress.md +1 -1
  259. package/{get-shit-done → gsd-core}/workflows/quick.md +7 -29
  260. package/{get-shit-done → gsd-core}/workflows/reapply-patches.md +2 -2
  261. package/{get-shit-done → gsd-core}/workflows/remove-phase.md +1 -1
  262. package/{get-shit-done → gsd-core}/workflows/remove-workspace.md +1 -1
  263. package/{get-shit-done → gsd-core}/workflows/resume-project.md +2 -2
  264. package/{get-shit-done → gsd-core}/workflows/review.md +110 -2
  265. package/{get-shit-done → gsd-core}/workflows/scan.md +3 -1
  266. package/{get-shit-done → gsd-core}/workflows/secure-phase.md +5 -3
  267. package/{get-shit-done → gsd-core}/workflows/settings-advanced.md +196 -6
  268. package/{get-shit-done → gsd-core}/workflows/settings-integrations.md +2 -2
  269. package/{get-shit-done → gsd-core}/workflows/settings.md +16 -2
  270. package/{get-shit-done → gsd-core}/workflows/ship.md +56 -4
  271. package/{get-shit-done → gsd-core}/workflows/sketch-wrap-up.md +1 -1
  272. package/{get-shit-done → gsd-core}/workflows/sketch.md +5 -5
  273. package/{get-shit-done → gsd-core}/workflows/spec-phase.md +2 -2
  274. package/{get-shit-done → gsd-core}/workflows/spike-wrap-up.md +1 -1
  275. package/{get-shit-done → gsd-core}/workflows/spike.md +1 -1
  276. package/{get-shit-done → gsd-core}/workflows/stats.md +1 -1
  277. package/{get-shit-done → gsd-core}/workflows/sync-skills.md +3 -3
  278. package/{get-shit-done → gsd-core}/workflows/thread.md +1 -1
  279. package/{get-shit-done → gsd-core}/workflows/transition.md +2 -2
  280. package/{get-shit-done → gsd-core}/workflows/ui-phase.md +5 -5
  281. package/{get-shit-done → gsd-core}/workflows/ui-review.md +3 -3
  282. package/{get-shit-done → gsd-core}/workflows/ultraplan-phase.md +1 -1
  283. package/{get-shit-done → gsd-core}/workflows/undo.md +2 -2
  284. package/{get-shit-done → gsd-core}/workflows/update.md +41 -16
  285. package/{get-shit-done → gsd-core}/workflows/validate-phase.md +5 -3
  286. package/{get-shit-done → gsd-core}/workflows/verify-phase.md +4 -4
  287. package/{get-shit-done → gsd-core}/workflows/verify-work.md +7 -7
  288. package/hooks/dist/gsd-check-update-worker.js +16 -3
  289. package/hooks/dist/gsd-check-update.js +7 -5
  290. package/hooks/dist/gsd-context-monitor.js +2 -2
  291. package/hooks/dist/gsd-statusline.js +39 -21
  292. package/hooks/dist/gsd-update-banner.js +6 -2
  293. package/hooks/dist/gsd-worktree-path-guard.js +169 -0
  294. package/hooks/dist/managed-hooks-registry.cjs +35 -0
  295. package/hooks/gsd-check-update-worker.js +16 -3
  296. package/hooks/gsd-check-update.js +7 -5
  297. package/hooks/gsd-context-monitor.js +2 -2
  298. package/hooks/gsd-statusline.js +39 -21
  299. package/hooks/gsd-update-banner.js +6 -2
  300. package/hooks/gsd-worktree-path-guard.js +169 -0
  301. package/hooks/managed-hooks-registry.cjs +1 -0
  302. package/package.json +17 -11
  303. package/scripts/affected-tests-lib.cjs +1 -1
  304. package/scripts/base64-scan.sh +12 -0
  305. package/scripts/build-hooks.js +5 -1
  306. package/scripts/changeset/cli.cjs +2 -2
  307. package/scripts/changeset/github-release-notes.cjs +1 -1
  308. package/scripts/changeset/lint.cjs +1 -1
  309. package/scripts/check-alias-drift.cjs +8 -8
  310. package/scripts/check-env.cjs +5 -1
  311. package/scripts/ci-test-scope.cjs +34 -9
  312. package/scripts/command-contract-helpers.cjs +1 -1
  313. package/scripts/fix-slash-commands.cjs +5 -5
  314. package/scripts/gen-inventory-manifest.cjs +3 -3
  315. package/scripts/generate-package-identity.cjs +28 -7
  316. package/scripts/lib/allowlist-ratchet.cjs +136 -0
  317. package/scripts/lint-command-contract.cjs +1 -1
  318. package/scripts/lint-legacy-dir-name.cjs +156 -0
  319. package/scripts/lint-package-identity-drift.cjs +8 -8
  320. package/scripts/lint-pr-check-project-dir.cjs +0 -1
  321. package/scripts/lint-shell-command-projection-drift.cjs +1 -1
  322. package/scripts/lint-skill-deps.cjs +1 -1
  323. package/scripts/lint-test-file-count.allowlist.json +129 -32
  324. package/scripts/lint-test-file-count.cjs +85 -30
  325. package/scripts/mutation-matrix.cjs +219 -0
  326. package/scripts/prompt-injection-scan.sh +5 -1
  327. package/scripts/release-notes/format-github-release-notes.cjs +256 -0
  328. package/scripts/release-tarball-smoke.cjs +9 -9
  329. package/scripts/run-tests.cjs +34 -2
  330. package/scripts/strip-prose-atrefs.cjs +2 -2
  331. package/scripts/sync-runtime-launcher.cjs +2 -2
  332. package/scripts/verify-npm-publish.cjs +252 -0
  333. package/get-shit-done/bin/lib/active-workstream-store.cjs +0 -302
  334. package/get-shit-done/bin/lib/adr-parser.cjs +0 -394
  335. package/get-shit-done/bin/lib/agent-command-router.cjs +0 -65
  336. package/get-shit-done/bin/lib/artifacts.cjs +0 -53
  337. package/get-shit-done/bin/lib/audit.cjs +0 -755
  338. package/get-shit-done/bin/lib/check-command-router.cjs +0 -333
  339. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +0 -118
  340. package/get-shit-done/bin/lib/clock.cjs +0 -96
  341. package/get-shit-done/bin/lib/clusters.cjs +0 -135
  342. package/get-shit-done/bin/lib/code-review-flags.cjs +0 -74
  343. package/get-shit-done/bin/lib/command-aliases.cjs +0 -815
  344. package/get-shit-done/bin/lib/command-arg-projection.cjs +0 -62
  345. package/get-shit-done/bin/lib/command-routing-hub.cjs +0 -388
  346. package/get-shit-done/bin/lib/commands.cjs +0 -1188
  347. package/get-shit-done/bin/lib/config-schema.cjs +0 -31
  348. package/get-shit-done/bin/lib/config.cjs +0 -728
  349. package/get-shit-done/bin/lib/context-utilization.cjs +0 -47
  350. package/get-shit-done/bin/lib/core.cjs +0 -2121
  351. package/get-shit-done/bin/lib/docs.cjs +0 -270
  352. package/get-shit-done/bin/lib/drift.cjs +0 -388
  353. package/get-shit-done/bin/lib/fallow-runner.cjs +0 -109
  354. package/get-shit-done/bin/lib/frontmatter.cjs +0 -389
  355. package/get-shit-done/bin/lib/gap-checker.cjs +0 -205
  356. package/get-shit-done/bin/lib/graphify.cjs +0 -592
  357. package/get-shit-done/bin/lib/gsd2-import.cjs +0 -514
  358. package/get-shit-done/bin/lib/init-command-router.cjs +0 -58
  359. package/get-shit-done/bin/lib/init.cjs +0 -2112
  360. package/get-shit-done/bin/lib/install-profiles.cjs +0 -603
  361. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +0 -117
  362. package/get-shit-done/bin/lib/installer-migration-report.cjs +0 -354
  363. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +0 -220
  364. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +0 -41
  365. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +0 -80
  366. package/get-shit-done/bin/lib/installer-migrations.cjs +0 -778
  367. package/get-shit-done/bin/lib/intel.cjs +0 -708
  368. package/get-shit-done/bin/lib/learnings.cjs +0 -421
  369. package/get-shit-done/bin/lib/milestone.cjs +0 -314
  370. package/get-shit-done/bin/lib/model-catalog.cjs +0 -212
  371. package/get-shit-done/bin/lib/model-profiles.cjs +0 -31
  372. package/get-shit-done/bin/lib/observability/event.cjs +0 -82
  373. package/get-shit-done/bin/lib/observability/logger.cjs +0 -174
  374. package/get-shit-done/bin/lib/phase-command-router.cjs +0 -191
  375. package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -80
  376. package/get-shit-done/bin/lib/phase.cjs +0 -1607
  377. package/get-shit-done/bin/lib/phases-command-router.cjs +0 -39
  378. package/get-shit-done/bin/lib/planning-workspace.cjs +0 -238
  379. package/get-shit-done/bin/lib/profile-output.cjs +0 -1141
  380. package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
  381. package/get-shit-done/bin/lib/project-root.cjs +0 -112
  382. package/get-shit-done/bin/lib/prompt-budget.cjs +0 -399
  383. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +0 -125
  384. package/get-shit-done/bin/lib/roadmap-command-router.cjs +0 -28
  385. package/get-shit-done/bin/lib/roadmap.cjs +0 -650
  386. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +0 -301
  387. package/get-shit-done/bin/lib/runtime-homes.cjs +0 -222
  388. package/get-shit-done/bin/lib/runtime-name-policy.cjs +0 -83
  389. package/get-shit-done/bin/lib/runtime-slash.cjs +0 -112
  390. package/get-shit-done/bin/lib/secrets.cjs +0 -32
  391. package/get-shit-done/bin/lib/security.cjs +0 -600
  392. package/get-shit-done/bin/lib/semver-compare.cjs +0 -35
  393. package/get-shit-done/bin/lib/shell-command-projection.cjs +0 -500
  394. package/get-shit-done/bin/lib/state-command-router.cjs +0 -252
  395. package/get-shit-done/bin/lib/state.cjs +0 -2038
  396. package/get-shit-done/bin/lib/surface.cjs +0 -470
  397. package/get-shit-done/bin/lib/task-command-router.cjs +0 -81
  398. package/get-shit-done/bin/lib/template.cjs +0 -228
  399. package/get-shit-done/bin/lib/uat.cjs +0 -289
  400. package/get-shit-done/bin/lib/update-context.cjs +0 -209
  401. package/get-shit-done/bin/lib/validate-command-router.cjs +0 -83
  402. package/get-shit-done/bin/lib/validate.cjs +0 -92
  403. package/get-shit-done/bin/lib/verify-command-router.cjs +0 -40
  404. package/get-shit-done/bin/lib/verify.cjs +0 -1511
  405. package/get-shit-done/bin/lib/workstream-inventory.cjs +0 -146
  406. package/get-shit-done/bin/lib/workstream.cjs +0 -389
  407. package/get-shit-done/bin/lib/worktree-safety.cjs +0 -985
  408. package/get-shit-done/workflows/_runtime-launcher.snippet.sh +0 -1
  409. package/scripts/lint-no-source-grep-extras.cjs +0 -81
  410. package/scripts/lint-no-source-grep.cjs +0 -174
  411. package/scripts/lint-shared-module-handsync.cjs +0 -388
  412. package/scripts/shared-module-handsync-allowlist.json +0 -183
  413. /package/{get-shit-done → gsd-core}/bin/shared/runtime-aliases.manifest.json +0 -0
  414. /package/{get-shit-done → gsd-core}/bin/verify-reapply-patches.cjs +0 -0
  415. /package/{get-shit-done → gsd-core}/contexts/dev.md +0 -0
  416. /package/{get-shit-done → gsd-core}/contexts/research.md +0 -0
  417. /package/{get-shit-done → gsd-core}/contexts/review.md +0 -0
  418. /package/{get-shit-done → gsd-core}/references/agent-contracts.md +0 -0
  419. /package/{get-shit-done → gsd-core}/references/ai-evals.md +0 -0
  420. /package/{get-shit-done → gsd-core}/references/ai-frameworks.md +0 -0
  421. /package/{get-shit-done → gsd-core}/references/autonomous-smart-discuss.md +0 -0
  422. /package/{get-shit-done → gsd-core}/references/common-bug-patterns.md +0 -0
  423. /package/{get-shit-done → gsd-core}/references/context-budget.md +0 -0
  424. /package/{get-shit-done → gsd-core}/references/continuation-format.md +0 -0
  425. /package/{get-shit-done → gsd-core}/references/debugger-philosophy.md +0 -0
  426. /package/{get-shit-done → gsd-core}/references/decimal-phase-calculation.md +0 -0
  427. /package/{get-shit-done → gsd-core}/references/doc-conflict-engine.md +0 -0
  428. /package/{get-shit-done → gsd-core}/references/domain-probes.md +0 -0
  429. /package/{get-shit-done → gsd-core}/references/execute-mvp-tdd.md +0 -0
  430. /package/{get-shit-done → gsd-core}/references/executor-examples.md +0 -0
  431. /package/{get-shit-done → gsd-core}/references/gate-prompts.md +0 -0
  432. /package/{get-shit-done → gsd-core}/references/gates.md +0 -0
  433. /package/{get-shit-done → gsd-core}/references/git-integration.md +0 -0
  434. /package/{get-shit-done → gsd-core}/references/git-planning-commit.md +0 -0
  435. /package/{get-shit-done → gsd-core}/references/ios-scaffold.md +0 -0
  436. /package/{get-shit-done → gsd-core}/references/mandatory-initial-read.md +0 -0
  437. /package/{get-shit-done → gsd-core}/references/model-profiles.md +0 -0
  438. /package/{get-shit-done → gsd-core}/references/phase-argument-parsing.md +0 -0
  439. /package/{get-shit-done → gsd-core}/references/planner-antipatterns.md +0 -0
  440. /package/{get-shit-done → gsd-core}/references/planner-chunked.md +0 -0
  441. /package/{get-shit-done → gsd-core}/references/planner-gap-closure.md +0 -0
  442. /package/{get-shit-done → gsd-core}/references/planner-interface-context.md +0 -0
  443. /package/{get-shit-done → gsd-core}/references/planner-reviews.md +0 -0
  444. /package/{get-shit-done → gsd-core}/references/planner-revision.md +0 -0
  445. /package/{get-shit-done → gsd-core}/references/planner-source-audit.md +0 -0
  446. /package/{get-shit-done → gsd-core}/references/planning-config.md +0 -0
  447. /package/{get-shit-done → gsd-core}/references/project-skills-discovery.md +0 -0
  448. /package/{get-shit-done → gsd-core}/references/questioning.md +0 -0
  449. /package/{get-shit-done → gsd-core}/references/revision-loop.md +0 -0
  450. /package/{get-shit-done → gsd-core}/references/scout-codebase.md +0 -0
  451. /package/{get-shit-done → gsd-core}/references/skeleton-template.md +0 -0
  452. /package/{get-shit-done → gsd-core}/references/sketch-interactivity.md +0 -0
  453. /package/{get-shit-done → gsd-core}/references/sketch-theme-system.md +0 -0
  454. /package/{get-shit-done → gsd-core}/references/sketch-tooling.md +0 -0
  455. /package/{get-shit-done → gsd-core}/references/sketch-variant-patterns.md +0 -0
  456. /package/{get-shit-done → gsd-core}/references/spidr-splitting.md +0 -0
  457. /package/{get-shit-done → gsd-core}/references/tdd.md +0 -0
  458. /package/{get-shit-done → gsd-core}/references/thinking-models-debug.md +0 -0
  459. /package/{get-shit-done → gsd-core}/references/thinking-models-execution.md +0 -0
  460. /package/{get-shit-done → gsd-core}/references/thinking-models-planning.md +0 -0
  461. /package/{get-shit-done → gsd-core}/references/thinking-models-research.md +0 -0
  462. /package/{get-shit-done → gsd-core}/references/thinking-models-verification.md +0 -0
  463. /package/{get-shit-done → gsd-core}/references/thinking-partner.md +0 -0
  464. /package/{get-shit-done → gsd-core}/references/universal-anti-patterns.md +0 -0
  465. /package/{get-shit-done → gsd-core}/references/user-profiling.md +0 -0
  466. /package/{get-shit-done → gsd-core}/references/user-story-template.md +0 -0
  467. /package/{get-shit-done → gsd-core}/references/verification-overrides.md +0 -0
  468. /package/{get-shit-done → gsd-core}/references/verify-mvp-mode.md +0 -0
  469. /package/{get-shit-done → gsd-core}/references/workstream-flag.md +0 -0
  470. /package/{get-shit-done → gsd-core}/templates/AI-SPEC.md +0 -0
  471. /package/{get-shit-done → gsd-core}/templates/DEBUG.md +0 -0
  472. /package/{get-shit-done → gsd-core}/templates/SECURITY.md +0 -0
  473. /package/{get-shit-done → gsd-core}/templates/UAT.md +0 -0
  474. /package/{get-shit-done → gsd-core}/templates/UI-SPEC.md +0 -0
  475. /package/{get-shit-done → gsd-core}/templates/VALIDATION.md +0 -0
  476. /package/{get-shit-done → gsd-core}/templates/claude-md.md +0 -0
  477. /package/{get-shit-done → gsd-core}/templates/codebase/architecture.md +0 -0
  478. /package/{get-shit-done → gsd-core}/templates/codebase/concerns.md +0 -0
  479. /package/{get-shit-done → gsd-core}/templates/codebase/conventions.md +0 -0
  480. /package/{get-shit-done → gsd-core}/templates/codebase/integrations.md +0 -0
  481. /package/{get-shit-done → gsd-core}/templates/codebase/stack.md +0 -0
  482. /package/{get-shit-done → gsd-core}/templates/codebase/testing.md +0 -0
  483. /package/{get-shit-done → gsd-core}/templates/config.json +0 -0
  484. /package/{get-shit-done → gsd-core}/templates/context.md +0 -0
  485. /package/{get-shit-done → gsd-core}/templates/continue-here.md +0 -0
  486. /package/{get-shit-done → gsd-core}/templates/debug-subagent-prompt.md +0 -0
  487. /package/{get-shit-done → gsd-core}/templates/dev-preferences.md +0 -0
  488. /package/{get-shit-done → gsd-core}/templates/discovery.md +0 -0
  489. /package/{get-shit-done → gsd-core}/templates/discussion-log.md +0 -0
  490. /package/{get-shit-done → gsd-core}/templates/milestone-archive.md +0 -0
  491. /package/{get-shit-done → gsd-core}/templates/milestone.md +0 -0
  492. /package/{get-shit-done → gsd-core}/templates/planner-subagent-prompt.md +0 -0
  493. /package/{get-shit-done → gsd-core}/templates/project.md +0 -0
  494. /package/{get-shit-done → gsd-core}/templates/requirements.md +0 -0
  495. /package/{get-shit-done → gsd-core}/templates/research-project/ARCHITECTURE.md +0 -0
  496. /package/{get-shit-done → gsd-core}/templates/research-project/FEATURES.md +0 -0
  497. /package/{get-shit-done → gsd-core}/templates/research-project/PITFALLS.md +0 -0
  498. /package/{get-shit-done → gsd-core}/templates/research-project/STACK.md +0 -0
  499. /package/{get-shit-done → gsd-core}/templates/research-project/SUMMARY.md +0 -0
  500. /package/{get-shit-done → gsd-core}/templates/research.md +0 -0
  501. /package/{get-shit-done → gsd-core}/templates/retrospective.md +0 -0
  502. /package/{get-shit-done → gsd-core}/templates/roadmap.md +0 -0
  503. /package/{get-shit-done → gsd-core}/templates/spec.md +0 -0
  504. /package/{get-shit-done → gsd-core}/templates/state.md +0 -0
  505. /package/{get-shit-done → gsd-core}/templates/summary-complex.md +0 -0
  506. /package/{get-shit-done → gsd-core}/templates/summary-minimal.md +0 -0
  507. /package/{get-shit-done → gsd-core}/templates/summary-standard.md +0 -0
  508. /package/{get-shit-done → gsd-core}/templates/summary.md +0 -0
  509. /package/{get-shit-done → gsd-core}/templates/user-profile.md +0 -0
  510. /package/{get-shit-done → gsd-core}/templates/user-setup.md +0 -0
  511. /package/{get-shit-done → gsd-core}/templates/verification-report.md +0 -0
  512. /package/{get-shit-done → gsd-core}/workflows/analyze-dependencies.md +0 -0
  513. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/all.md +0 -0
  514. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/analyze.md +0 -0
  515. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/batch.md +0 -0
  516. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/default.md +0 -0
  517. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/text.md +0 -0
  518. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/checkpoint.json +0 -0
  519. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/context.md +0 -0
  520. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/discussion-log.md +0 -0
  521. /package/{get-shit-done → gsd-core}/workflows/discuss-phase-power.md +0 -0
  522. /package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -0
  523. /package/{get-shit-done → gsd-core}/workflows/fast.md +0 -0
  524. /package/{get-shit-done → gsd-core}/workflows/help/modes/brief.md +0 -0
  525. /package/{get-shit-done → gsd-core}/workflows/help/modes/topic.md +0 -0
  526. /package/{get-shit-done → gsd-core}/workflows/help.md +0 -0
  527. /package/{get-shit-done → gsd-core}/workflows/inbox.md +0 -0
  528. /package/{get-shit-done → gsd-core}/workflows/list-phase-assumptions.md +0 -0
  529. /package/{get-shit-done → gsd-core}/workflows/node-repair.md +0 -0
  530. /package/{get-shit-done → gsd-core}/workflows/note.md +0 -0
  531. /package/{get-shit-done → gsd-core}/workflows/pr-branch.md +0 -0
  532. /package/{get-shit-done → gsd-core}/workflows/session-report.md +0 -0
@@ -1,23 +1,32 @@
1
- 'use strict';
2
-
1
+ "use strict";
3
2
  /**
4
3
  * Workstream Inventory Builder — pure projection from pre-collected
5
4
  * filesystem data to typed WorkstreamInventory. No I/O. No async.
5
+ *
6
+ * ADR-457 build-at-publish: the hand-written
7
+ * bin/lib/workstream-inventory-builder.cjs collapsed to a TypeScript source
8
+ * of truth. Behaviour is preserved byte-for-behaviour from the prior
9
+ * hand-written .cjs; only types are added.
6
10
  */
7
-
8
- const path = require('path');
9
- const relative = path.relative;
10
-
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.isCompletedInventory = isCompletedInventory;
16
+ exports.buildWorkstreamInventory = buildWorkstreamInventory;
17
+ const node_path_1 = __importDefault(require("node:path"));
11
18
  // Internal helpers
12
19
  function toPosixPath(p) {
13
20
  return p.split('\\').join('/');
14
21
  }
15
-
16
22
  function isCompletedInventory(status) {
17
- const s = String(status ?? '').trim().toLowerCase();
23
+ const s = (typeof status === 'string'
24
+ ? status
25
+ : typeof status === 'number' || typeof status === 'boolean'
26
+ ? String(status)
27
+ : '').trim().toLowerCase();
18
28
  return /\bmilestone\s+complete\b/.test(s) || /\barchived\b/.test(s);
19
29
  }
20
-
21
30
  function buildWorkstreamInventory(inputs) {
22
31
  const { name, projectDir, workstreamDir, phaseDirNames, activeWorkstreamName, phaseFilesCounts, roadmapPhaseCount, stateProjection, filesExist, } = inputs;
23
32
  // Index counts by directory for O(1) lookup during sort/iteration
@@ -49,7 +58,7 @@ function buildWorkstreamInventory(inputs) {
49
58
  }
50
59
  return {
51
60
  name,
52
- path: toPosixPath(relative(projectDir, workstreamDir)),
61
+ path: toPosixPath(node_path_1.default.relative(projectDir, workstreamDir)),
53
62
  active: name === activeWorkstreamName,
54
63
  files: {
55
64
  roadmap: filesExist.roadmap,
@@ -70,5 +79,3 @@ function buildWorkstreamInventory(inputs) {
70
79
  : 0,
71
80
  };
72
81
  }
73
-
74
- module.exports = { buildWorkstreamInventory, isCompletedInventory };
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ /**
3
+ * Workstream Inventory Module
4
+ *
5
+ * Owns discovery and read-only projection of .planning/workstreams/* state.
6
+ * Command handlers should render outputs from this inventory instead of
7
+ * rescanning workstream directories directly.
8
+ *
9
+ * Pure projection logic lives in workstream-inventory-builder.cts.
10
+ * This module handles I/O orchestration only.
11
+ *
12
+ * ADR-457 build-at-publish: the hand-written bin/lib/workstream-inventory.cjs
13
+ * collapsed to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
14
+ * from the prior hand-written .cjs; only types are added.
15
+ */
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ const node_fs_1 = __importDefault(require("node:fs"));
20
+ const node_path_1 = __importDefault(require("node:path"));
21
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
22
+ const core = require("./core.cjs");
23
+ const { toPosixPath, readSubdirectories } = core;
24
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
25
+ const planScan = require("./plan-scan.cjs");
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ const planningWorkspace = require("./planning-workspace.cjs");
28
+ const { planningPaths, planningRoot, getActiveWorkstream } = planningWorkspace;
29
+ const state_document_cjs_1 = require("./state-document.cjs");
30
+ const workstream_inventory_builder_cjs_1 = require("./workstream-inventory-builder.cjs");
31
+ // ─── Implementation ───────────────────────────────────────────────────────────
32
+ function workstreamsRoot(cwd) {
33
+ return node_path_1.default.join(planningRoot(cwd), 'workstreams');
34
+ }
35
+ function countRoadmapPhases(roadmapPath, fallbackCount) {
36
+ try {
37
+ const roadmapContent = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
38
+ const matches = roadmapContent.match(/^#{2,4}\s+Phase\s+[\w][\w.-]*/gm);
39
+ return matches ? matches.length : fallbackCount;
40
+ }
41
+ catch {
42
+ return fallbackCount;
43
+ }
44
+ }
45
+ function countPhaseFiles(phaseDir) {
46
+ const scan = planScan(phaseDir);
47
+ return { planCount: scan.planCount, summaryCount: scan.summaryCount };
48
+ }
49
+ function readStateProjection(statePath) {
50
+ try {
51
+ const stateContent = node_fs_1.default.readFileSync(statePath, 'utf-8');
52
+ return {
53
+ status: (0, state_document_cjs_1.stateExtractField)(stateContent, 'Status') || 'unknown',
54
+ current_phase: (0, state_document_cjs_1.stateExtractField)(stateContent, 'Current Phase'),
55
+ last_activity: (0, state_document_cjs_1.stateExtractField)(stateContent, 'Last Activity'),
56
+ };
57
+ }
58
+ catch {
59
+ return {
60
+ status: 'unknown',
61
+ current_phase: null,
62
+ last_activity: null,
63
+ };
64
+ }
65
+ }
66
+ function sortWorkstreamInventories(inventories, activeWorkstreamName) {
67
+ return [...inventories].sort((a, b) => {
68
+ const aActive = a.name === activeWorkstreamName ? 1 : 0;
69
+ const bActive = b.name === activeWorkstreamName ? 1 : 0;
70
+ if (aActive !== bActive) {
71
+ return bActive - aActive;
72
+ }
73
+ return a.name.localeCompare(b.name);
74
+ });
75
+ }
76
+ function inspectWorkstream(cwd, name, options = {}) {
77
+ const wsDir = node_path_1.default.join(workstreamsRoot(cwd), name);
78
+ if (!node_fs_1.default.existsSync(wsDir))
79
+ return null;
80
+ const activeWorkstreamName = options.active === undefined ? getActiveWorkstream(cwd) : options.active;
81
+ const p = planningPaths(cwd, name);
82
+ const phaseDirNames = readSubdirectories(p.phases);
83
+ // Collect per-phase file counts
84
+ const phaseFilesCounts = phaseDirNames.map(dir => {
85
+ const counts = countPhaseFiles(node_path_1.default.join(p.phases, dir));
86
+ return { directory: dir, planCount: counts.planCount, summaryCount: counts.summaryCount };
87
+ });
88
+ return (0, workstream_inventory_builder_cjs_1.buildWorkstreamInventory)({
89
+ name,
90
+ projectDir: cwd,
91
+ workstreamDir: wsDir,
92
+ phaseDirNames,
93
+ activeWorkstreamName: activeWorkstreamName ?? '',
94
+ phaseFilesCounts,
95
+ roadmapPhaseCount: countRoadmapPhases(p.roadmap, phaseDirNames.length),
96
+ stateProjection: readStateProjection(p.state),
97
+ filesExist: {
98
+ roadmap: node_fs_1.default.existsSync(p.roadmap),
99
+ state: node_fs_1.default.existsSync(p.state),
100
+ requirements: node_fs_1.default.existsSync(p.requirements),
101
+ },
102
+ });
103
+ }
104
+ function listWorkstreamInventories(cwd) {
105
+ const wsRoot = workstreamsRoot(cwd);
106
+ if (!node_fs_1.default.existsSync(wsRoot)) {
107
+ return {
108
+ mode: 'flat',
109
+ active: null,
110
+ workstreams: [],
111
+ count: 0,
112
+ message: 'No workstreams — operating in flat mode',
113
+ };
114
+ }
115
+ const active = getActiveWorkstream(cwd);
116
+ const entries = node_fs_1.default.readdirSync(wsRoot, { withFileTypes: true });
117
+ const workstreams = [];
118
+ for (const entry of entries) {
119
+ if (!entry.isDirectory())
120
+ continue;
121
+ const inventory = inspectWorkstream(cwd, entry.name, { active });
122
+ if (inventory)
123
+ workstreams.push(inventory);
124
+ }
125
+ const ordered = sortWorkstreamInventories(workstreams, active);
126
+ return {
127
+ mode: 'workstream',
128
+ active,
129
+ workstreams: ordered,
130
+ count: ordered.length,
131
+ };
132
+ }
133
+ function getOtherActiveWorkstreamInventories(cwd, excludeWs) {
134
+ return listWorkstreamInventories(cwd).workstreams
135
+ .filter(inventory => inventory.name !== excludeWs)
136
+ .filter(inventory => !(0, workstream_inventory_builder_cjs_1.isCompletedInventory)(inventory.status));
137
+ }
138
+ module.exports = {
139
+ countPhaseFiles,
140
+ countRoadmapPhases,
141
+ getOtherActiveWorkstreamInventories,
142
+ inspectWorkstream,
143
+ isCompletedInventory: workstream_inventory_builder_cjs_1.isCompletedInventory,
144
+ listWorkstreamInventories,
145
+ sortWorkstreamInventories,
146
+ workstreamsRoot,
147
+ };
@@ -1,18 +1,36 @@
1
- 'use strict';
2
-
1
+ "use strict";
3
2
  /**
4
- * Canonical workstream name validation and slug normalization.
3
+ * Canonical workstream name validation and slug normalization
4
+ * (ADR-457 build-at-publish: the hand-written bin/lib/workstream-name-policy.cjs
5
+ * collapsed to a TypeScript source of truth). Behaviour is preserved
6
+ * byte-for-behaviour from the prior hand-written .cjs; only types are added.
7
+ *
5
8
  * Used by active-workstream-store.cjs, planning-workspace.cjs, workstream.cjs.
6
9
  */
7
-
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = void 0;
12
+ exports.normalizeWorkstreamNameInput = normalizeWorkstreamNameInput;
13
+ exports.hasInvalidPathSegment = hasInvalidPathSegment;
14
+ exports.validateActiveWorkstreamName = validateActiveWorkstreamName;
15
+ exports.validateWorkstreamName = validateWorkstreamName;
16
+ exports.toWorkstreamSlug = toWorkstreamSlug;
17
+ exports.isValidActiveWorkstreamName = isValidActiveWorkstreamName;
18
+ exports.assertValidActiveWorkstreamName = assertValidActiveWorkstreamName;
19
+ exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = 'Invalid workstream name: must be alphanumeric, hyphens, underscores, or dots';
8
20
  const ACTIVE_WORKSTREAM_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
9
- const INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE = 'Invalid workstream name: must be alphanumeric, hyphens, underscores, or dots';
10
-
11
21
  function normalizeWorkstreamNameInput(name) {
12
- const value = String(name || '').trim();
22
+ const value = String(name ?? '').trim();
13
23
  return value || null;
14
24
  }
15
-
25
+ /**
26
+ * Returns true when `name` contains a path separator, a bare dot, or a
27
+ * dot-dot sequence — any of which would make the name unsafe for use as a
28
+ * filesystem path segment.
29
+ */
30
+ function hasInvalidPathSegment(name) {
31
+ const value = String(name ?? '');
32
+ return /[/\\]/.test(value) || value === '.' || value === '..' || value.includes('..');
33
+ }
16
34
  function validateActiveWorkstreamName(name) {
17
35
  const value = normalizeWorkstreamNameInput(name);
18
36
  if (!value) {
@@ -50,20 +68,11 @@ function validateWorkstreamName(name) {
50
68
  * Lowercases, collapses non-alphanumeric runs to hyphens, strips leading/trailing hyphens.
51
69
  */
52
70
  function toWorkstreamSlug(name) {
53
- return String(name || '')
71
+ return String(name ?? '')
54
72
  .toLowerCase()
55
73
  .replace(/[^a-z0-9]+/g, '-')
56
74
  .replace(/^-+|-+$/g, '');
57
75
  }
58
- /**
59
- * Returns true when `name` contains a path separator, a bare dot, or a
60
- * dot-dot sequence — any of which would make the name unsafe for use as a
61
- * filesystem path segment.
62
- */
63
- function hasInvalidPathSegment(name) {
64
- const value = String(name || '');
65
- return /[/\\]/.test(value) || value === '.' || value === '..' || value.includes('..');
66
- }
67
76
  /**
68
77
  * Returns true when `name` is a valid active workstream name:
69
78
  * - Must start with alphanumeric
@@ -73,22 +82,10 @@ function hasInvalidPathSegment(name) {
73
82
  function isValidActiveWorkstreamName(name) {
74
83
  return validateActiveWorkstreamName(name).ok;
75
84
  }
76
-
77
- function assertValidActiveWorkstreamName(name, errorMessage = INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE) {
85
+ function assertValidActiveWorkstreamName(name, errorMessage = exports.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE) {
78
86
  const validation = validateActiveWorkstreamName(name);
79
87
  if (!validation.ok) {
80
88
  throw new Error(errorMessage);
81
89
  }
82
90
  return validation.value;
83
91
  }
84
-
85
- module.exports = {
86
- INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE,
87
- normalizeWorkstreamNameInput,
88
- validateActiveWorkstreamName,
89
- validateWorkstreamName,
90
- toWorkstreamSlug,
91
- hasInvalidPathSegment,
92
- isValidActiveWorkstreamName,
93
- assertValidActiveWorkstreamName,
94
- };
@@ -0,0 +1,380 @@
1
+ "use strict";
2
+ /**
3
+ * Workstream — CRUD operations for workstream namespacing
4
+ *
5
+ * Workstreams enable parallel milestones by scoping ROADMAP.md, STATE.md,
6
+ * REQUIREMENTS.md, and phases/ into .planning/workstreams/{name}/ directories.
7
+ *
8
+ * When no workstreams/ directory exists, GSD operates in "flat mode" with
9
+ * everything at .planning/ — backward compatible with pre-workstream installs.
10
+ *
11
+ * ADR-457 build-at-publish: the hand-written bin/lib/workstream.cjs collapsed
12
+ * to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
13
+ * from the prior hand-written .cjs; only strict types are added.
14
+ */
15
+ var __importDefault = (this && this.__importDefault) || function (mod) {
16
+ return (mod && mod.__esModule) ? mod : { "default": mod };
17
+ };
18
+ const node_fs_1 = __importDefault(require("node:fs"));
19
+ const node_path_1 = __importDefault(require("node:path"));
20
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
21
+ const core = require("./core.cjs");
22
+ const { output, error, toPosixPath, getMilestoneInfo, generateSlugInternal } = core;
23
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
24
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
25
+ const planningWorkspace = require("./planning-workspace.cjs");
26
+ const { planningRoot, setActiveWorkstream, getActiveWorkstream } = planningWorkspace;
27
+ const workstream_name_policy_cjs_1 = require("./workstream-name-policy.cjs");
28
+ const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
29
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
30
+ const workstreamInventory = require("./workstream-inventory.cjs");
31
+ const { getOtherActiveWorkstreamInventories, inspectWorkstream, listWorkstreamInventories, } = workstreamInventory;
32
+ // ─── Migration ───────────────────────────────────────────────────────────────
33
+ /**
34
+ * Migrate flat .planning/ layout to workstream mode.
35
+ * Moves per-workstream files (ROADMAP.md, STATE.md, REQUIREMENTS.md, phases/)
36
+ * into .planning/workstreams/{name}/. Shared files (PROJECT.md, config.json,
37
+ * milestones/, research/, codebase/, todos/) stay in place.
38
+ */
39
+ function migrateToWorkstreams(cwd, workstreamName) {
40
+ try {
41
+ (0, workstream_name_policy_cjs_1.assertValidActiveWorkstreamName)(workstreamName, 'Invalid workstream name for migration');
42
+ }
43
+ catch {
44
+ throw new Error('Invalid workstream name for migration');
45
+ }
46
+ const baseDir = planningRoot(cwd);
47
+ const wsDir = node_path_1.default.join(baseDir, 'workstreams', workstreamName);
48
+ if (node_fs_1.default.existsSync(node_path_1.default.join(baseDir, 'workstreams'))) {
49
+ throw new Error('Already in workstream mode — .planning/workstreams/ exists');
50
+ }
51
+ const toMove = [
52
+ { name: 'ROADMAP.md', type: 'file' },
53
+ { name: 'STATE.md', type: 'file' },
54
+ { name: 'REQUIREMENTS.md', type: 'file' },
55
+ { name: 'phases', type: 'dir' },
56
+ ];
57
+ (0, shell_command_projection_cjs_1.platformEnsureDir)(wsDir);
58
+ const filesMoved = [];
59
+ try {
60
+ for (const item of toMove) {
61
+ const src = node_path_1.default.join(baseDir, item.name);
62
+ if (node_fs_1.default.existsSync(src)) {
63
+ const dest = node_path_1.default.join(wsDir, item.name);
64
+ node_fs_1.default.renameSync(src, dest);
65
+ filesMoved.push(item.name);
66
+ }
67
+ }
68
+ }
69
+ catch (err) {
70
+ for (const name of filesMoved) {
71
+ try {
72
+ node_fs_1.default.renameSync(node_path_1.default.join(wsDir, name), node_path_1.default.join(baseDir, name));
73
+ }
74
+ catch { /* ignore */ }
75
+ }
76
+ try {
77
+ node_fs_1.default.rmSync(wsDir, { recursive: true });
78
+ }
79
+ catch { /* ignore */ }
80
+ try {
81
+ node_fs_1.default.rmdirSync(node_path_1.default.join(baseDir, 'workstreams'));
82
+ }
83
+ catch { /* ignore */ }
84
+ throw err;
85
+ }
86
+ return { migrated: true, workstream: workstreamName, files_moved: filesMoved };
87
+ }
88
+ // ─── CRUD Commands ────────────────────────────────────────────────────────────
89
+ function cmdWorkstreamCreate(cwd, name, options, raw) {
90
+ if (!name) {
91
+ error('workstream name required. Usage: workstream create <name>');
92
+ }
93
+ const slug = (0, workstream_name_policy_cjs_1.toWorkstreamSlug)(name);
94
+ if (!slug) {
95
+ error('Invalid workstream name — must contain at least one alphanumeric character');
96
+ }
97
+ const baseDir = planningRoot(cwd);
98
+ if (!node_fs_1.default.existsSync(baseDir)) {
99
+ error(`.planning/ directory not found — run ${(0, runtime_slash_cjs_1.formatGsdSlash)('new-project', (0, runtime_slash_cjs_1.resolveRuntime)(cwd))} first`);
100
+ }
101
+ const wsRoot = node_path_1.default.join(baseDir, 'workstreams');
102
+ const wsDir = node_path_1.default.join(wsRoot, slug);
103
+ if (node_fs_1.default.existsSync(wsDir) && node_fs_1.default.existsSync(node_path_1.default.join(wsDir, 'STATE.md'))) {
104
+ output({ created: false, error: 'already_exists', workstream: slug, path: toPosixPath(node_path_1.default.relative(cwd, wsDir)) }, raw, undefined);
105
+ return;
106
+ }
107
+ const isFlatMode = !node_fs_1.default.existsSync(wsRoot);
108
+ let migration = null;
109
+ if (isFlatMode && options.migrate !== false) {
110
+ const hasExistingWork = node_fs_1.default.existsSync(node_path_1.default.join(baseDir, 'ROADMAP.md')) ||
111
+ node_fs_1.default.existsSync(node_path_1.default.join(baseDir, 'STATE.md')) ||
112
+ node_fs_1.default.existsSync(node_path_1.default.join(baseDir, 'phases'));
113
+ if (hasExistingWork) {
114
+ const migrateName = options.migrateName || null;
115
+ let existingWsName;
116
+ if (migrateName) {
117
+ const slugged = (0, workstream_name_policy_cjs_1.toWorkstreamSlug)(migrateName);
118
+ if (!slugged) {
119
+ output({
120
+ created: false,
121
+ error: 'migration_failed',
122
+ message: 'Invalid migrate-name — must contain at least one alphanumeric character',
123
+ }, raw, undefined);
124
+ return;
125
+ }
126
+ existingWsName = slugged;
127
+ }
128
+ else {
129
+ try {
130
+ const milestone = getMilestoneInfo(cwd);
131
+ existingWsName = generateSlugInternal(milestone.name) || 'default';
132
+ }
133
+ catch {
134
+ existingWsName = 'default';
135
+ }
136
+ }
137
+ try {
138
+ migration = migrateToWorkstreams(cwd, existingWsName);
139
+ }
140
+ catch (e) {
141
+ output({ created: false, error: 'migration_failed', message: e.message }, raw, undefined);
142
+ return;
143
+ }
144
+ }
145
+ else {
146
+ (0, shell_command_projection_cjs_1.platformEnsureDir)(wsRoot);
147
+ }
148
+ }
149
+ (0, shell_command_projection_cjs_1.platformEnsureDir)(wsDir);
150
+ (0, shell_command_projection_cjs_1.platformEnsureDir)(node_path_1.default.join(wsDir, 'phases'));
151
+ const today = new Date().toISOString().split('T')[0];
152
+ const stateContent = [
153
+ '---',
154
+ `workstream: ${slug}`,
155
+ `created: ${today}`,
156
+ '---',
157
+ '',
158
+ '# Project State',
159
+ '',
160
+ '## Current Position',
161
+ '**Status:** Not started',
162
+ '**Current Phase:** None',
163
+ `**Last Activity:** ${today}`,
164
+ '**Last Activity Description:** Workstream created',
165
+ '',
166
+ '## Progress',
167
+ '**Phases Complete:** 0',
168
+ '**Current Plan:** N/A',
169
+ '',
170
+ '## Session Continuity',
171
+ '**Stopped At:** N/A',
172
+ '**Resume File:** None',
173
+ '',
174
+ ].join('\n');
175
+ const statePath = node_path_1.default.join(wsDir, 'STATE.md');
176
+ if (!node_fs_1.default.existsSync(statePath)) {
177
+ (0, shell_command_projection_cjs_1.platformWriteSync)(statePath, stateContent);
178
+ }
179
+ setActiveWorkstream(cwd, slug);
180
+ const relPath = toPosixPath(node_path_1.default.relative(cwd, wsDir));
181
+ output({
182
+ created: true,
183
+ workstream: slug,
184
+ path: relPath,
185
+ state_path: relPath + '/STATE.md',
186
+ phases_path: relPath + '/phases',
187
+ migration: migration || null,
188
+ active: true,
189
+ }, raw, undefined);
190
+ }
191
+ function cmdWorkstreamList(cwd, raw) {
192
+ const inventory = listWorkstreamInventories(cwd);
193
+ if (inventory.mode === 'flat') {
194
+ output({ mode: 'flat', workstreams: [], message: inventory.message }, raw, undefined);
195
+ return;
196
+ }
197
+ const workstreams = inventory.workstreams.map(ws => ({
198
+ name: ws.name,
199
+ path: ws.path,
200
+ has_roadmap: ws.files.roadmap,
201
+ has_state: ws.files.state,
202
+ status: ws.status,
203
+ current_phase: ws.current_phase,
204
+ phase_count: ws.phase_count,
205
+ completed_phases: ws.completed_phases,
206
+ }));
207
+ output({ mode: 'workstream', workstreams, count: workstreams.length }, raw, undefined);
208
+ }
209
+ function cmdWorkstreamStatus(cwd, name, raw) {
210
+ if (!name)
211
+ error('workstream name required. Usage: workstream status <name>');
212
+ try {
213
+ (0, workstream_name_policy_cjs_1.assertValidActiveWorkstreamName)(name, workstream_name_policy_cjs_1.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE);
214
+ }
215
+ catch {
216
+ error(workstream_name_policy_cjs_1.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE);
217
+ }
218
+ const wsDir = node_path_1.default.join(planningRoot(cwd), 'workstreams', name);
219
+ if (!node_fs_1.default.existsSync(wsDir)) {
220
+ output({ found: false, workstream: name }, raw, undefined);
221
+ return;
222
+ }
223
+ const inv = inspectWorkstream(cwd, name);
224
+ if (!inv) {
225
+ output({ found: false, workstream: name }, raw, undefined);
226
+ return;
227
+ }
228
+ output({
229
+ found: true,
230
+ workstream: name,
231
+ path: inv.path,
232
+ files: inv.files,
233
+ phases: inv.phases,
234
+ phase_count: inv.phase_count,
235
+ completed_phases: inv.completed_phases,
236
+ status: inv.status,
237
+ current_phase: inv.current_phase,
238
+ last_activity: inv.last_activity,
239
+ }, raw, undefined);
240
+ }
241
+ function cmdWorkstreamComplete(cwd, name, options, raw) {
242
+ if (!name)
243
+ error('workstream name required. Usage: workstream complete <name>');
244
+ try {
245
+ (0, workstream_name_policy_cjs_1.assertValidActiveWorkstreamName)(name, workstream_name_policy_cjs_1.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE);
246
+ }
247
+ catch {
248
+ error(workstream_name_policy_cjs_1.INVALID_ACTIVE_WORKSTREAM_NAME_MESSAGE);
249
+ }
250
+ const root = planningRoot(cwd);
251
+ const wsRoot = node_path_1.default.join(root, 'workstreams');
252
+ const wsDir = node_path_1.default.join(wsRoot, name);
253
+ if (!node_fs_1.default.existsSync(wsDir)) {
254
+ output({ completed: false, error: 'not_found', workstream: name }, raw, undefined);
255
+ return;
256
+ }
257
+ const active = getActiveWorkstream(cwd);
258
+ if (active === name)
259
+ setActiveWorkstream(cwd, null);
260
+ const archiveDir = node_path_1.default.join(root, 'milestones');
261
+ const today = new Date().toISOString().split('T')[0];
262
+ let archivePath = node_path_1.default.join(archiveDir, `ws-${name}-${today}`);
263
+ let suffix = 1;
264
+ while (node_fs_1.default.existsSync(archivePath)) {
265
+ archivePath = node_path_1.default.join(archiveDir, `ws-${name}-${today}-${suffix++}`);
266
+ }
267
+ (0, shell_command_projection_cjs_1.platformEnsureDir)(archivePath);
268
+ const filesMoved = [];
269
+ try {
270
+ const entries = node_fs_1.default.readdirSync(wsDir, { withFileTypes: true });
271
+ for (const entry of entries) {
272
+ node_fs_1.default.renameSync(node_path_1.default.join(wsDir, entry.name), node_path_1.default.join(archivePath, entry.name));
273
+ filesMoved.push(entry.name);
274
+ }
275
+ }
276
+ catch (err) {
277
+ for (const fname of filesMoved) {
278
+ try {
279
+ node_fs_1.default.renameSync(node_path_1.default.join(archivePath, fname), node_path_1.default.join(wsDir, fname));
280
+ }
281
+ catch { /* ignore */ }
282
+ }
283
+ try {
284
+ node_fs_1.default.rmSync(archivePath, { recursive: true });
285
+ }
286
+ catch { /* ignore */ }
287
+ if (active === name)
288
+ setActiveWorkstream(cwd, name);
289
+ output({ completed: false, error: 'archive_failed', message: err.message, workstream: name }, raw, undefined);
290
+ return;
291
+ }
292
+ try {
293
+ node_fs_1.default.rmdirSync(wsDir);
294
+ }
295
+ catch { /* ignore */ }
296
+ let remainingWs = 0;
297
+ try {
298
+ remainingWs = node_fs_1.default.readdirSync(wsRoot, { withFileTypes: true }).filter(e => e.isDirectory()).length;
299
+ if (remainingWs === 0)
300
+ node_fs_1.default.rmdirSync(wsRoot);
301
+ }
302
+ catch { /* ignore */ }
303
+ output({
304
+ completed: true,
305
+ workstream: name,
306
+ archived_to: toPosixPath(node_path_1.default.relative(cwd, archivePath)),
307
+ remaining_workstreams: remainingWs,
308
+ reverted_to_flat: remainingWs === 0,
309
+ }, raw, undefined);
310
+ }
311
+ // ─── Active Workstream Commands ───────────────────────────────────────────────
312
+ function cmdWorkstreamSet(cwd, name, raw) {
313
+ if (!name || name === '--clear') {
314
+ if (name !== '--clear') {
315
+ error('Workstream name required. Usage: workstream set <name> (or workstream set --clear to unset)');
316
+ }
317
+ const previous = getActiveWorkstream(cwd);
318
+ setActiveWorkstream(cwd, null);
319
+ output({ active: null, cleared: true, previous: previous || null }, raw, undefined);
320
+ return;
321
+ }
322
+ if (!(0, workstream_name_policy_cjs_1.isValidActiveWorkstreamName)(name)) {
323
+ output({ active: null, error: 'invalid_name', message: 'Workstream name must be alphanumeric, hyphens, underscores, or dots' }, raw, undefined);
324
+ return;
325
+ }
326
+ const wsDir = node_path_1.default.join(planningRoot(cwd), 'workstreams', name);
327
+ if (!node_fs_1.default.existsSync(wsDir)) {
328
+ output({ active: null, error: 'not_found', workstream: name }, raw, undefined);
329
+ return;
330
+ }
331
+ setActiveWorkstream(cwd, name);
332
+ output({ active: name, set: true }, raw, name);
333
+ }
334
+ function cmdWorkstreamGet(cwd, raw) {
335
+ const active = getActiveWorkstream(cwd);
336
+ const wsRoot = node_path_1.default.join(planningRoot(cwd), 'workstreams');
337
+ output({ active, mode: node_fs_1.default.existsSync(wsRoot) ? 'workstream' : 'flat' }, raw, active || 'none');
338
+ }
339
+ function cmdWorkstreamProgress(cwd, raw) {
340
+ const inventory = listWorkstreamInventories(cwd);
341
+ if (inventory.mode === 'flat') {
342
+ output({ mode: 'flat', workstreams: [], message: inventory.message }, raw, undefined);
343
+ return;
344
+ }
345
+ const workstreams = inventory.workstreams.map(ws => ({
346
+ name: ws.name,
347
+ active: ws.active,
348
+ status: ws.status,
349
+ current_phase: ws.current_phase ?? null,
350
+ phases: `${ws.completed_phases}/${ws.roadmap_phase_count}`,
351
+ plans: `${ws.completed_plans}/${ws.total_plans}`,
352
+ progress_percent: ws.progress_percent,
353
+ }));
354
+ output({ mode: 'workstream', active: inventory.active, workstreams, count: workstreams.length }, raw, undefined);
355
+ }
356
+ // ─── Collision Detection ──────────────────────────────────────────────────────
357
+ /**
358
+ * Return other workstreams that are NOT complete.
359
+ * Used to detect whether the milestone has active parallel work
360
+ * when a workstream finishes its last phase.
361
+ */
362
+ function getOtherActiveWorkstreams(cwd, excludeWs) {
363
+ return getOtherActiveWorkstreamInventories(cwd, excludeWs).map(ws => ({
364
+ name: ws.name,
365
+ status: ws.status,
366
+ current_phase: ws.current_phase ?? null,
367
+ phases: `${ws.completed_phases}/${ws.phase_count}`,
368
+ }));
369
+ }
370
+ module.exports = {
371
+ migrateToWorkstreams,
372
+ cmdWorkstreamCreate,
373
+ cmdWorkstreamList,
374
+ cmdWorkstreamStatus,
375
+ cmdWorkstreamComplete,
376
+ cmdWorkstreamSet,
377
+ cmdWorkstreamGet,
378
+ cmdWorkstreamProgress,
379
+ getOtherActiveWorkstreams,
380
+ };