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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (521) hide show
  1. package/README.ja-JP.md +44 -790
  2. package/README.ko-KR.md +41 -778
  3. package/README.md +39 -180
  4. package/README.pt-BR.md +45 -413
  5. package/README.zh-CN.md +43 -761
  6. package/agents/gsd-ai-researcher.md +1 -1
  7. package/agents/gsd-debugger.md +8 -8
  8. package/agents/gsd-domain-researcher.md +14 -1
  9. package/agents/gsd-eval-auditor.md +1 -1
  10. package/agents/gsd-eval-planner.md +1 -1
  11. package/agents/gsd-executor.md +21 -8
  12. package/agents/gsd-framework-selector.md +1 -1
  13. package/agents/gsd-intel-updater.md +4 -4
  14. package/agents/gsd-phase-researcher.md +18 -5
  15. package/agents/gsd-plan-checker.md +3 -3
  16. package/agents/gsd-planner.md +36 -23
  17. package/agents/gsd-project-researcher.md +13 -0
  18. package/agents/gsd-research-synthesizer.md +6 -2
  19. package/agents/gsd-roadmapper.md +6 -6
  20. package/agents/gsd-ui-researcher.md +15 -2
  21. package/agents/gsd-user-profiler.md +2 -2
  22. package/agents/gsd-verifier.md +7 -7
  23. package/bin/install.js +169 -59
  24. package/commands/gsd/add-tests.md +1 -1
  25. package/commands/gsd/ai-integration-phase.md +3 -3
  26. package/commands/gsd/audit-fix.md +1 -1
  27. package/commands/gsd/audit-milestone.md +1 -1
  28. package/commands/gsd/audit-uat.md +1 -1
  29. package/commands/gsd/autonomous.md +2 -2
  30. package/commands/gsd/capture.md +6 -6
  31. package/commands/gsd/cleanup.md +1 -1
  32. package/commands/gsd/code-review.md +1 -1
  33. package/commands/gsd/complete-milestone.md +2 -2
  34. package/commands/gsd/config.md +3 -3
  35. package/commands/gsd/debug.md +1 -1
  36. package/commands/gsd/discuss-phase.md +5 -4
  37. package/commands/gsd/docs-update.md +1 -1
  38. package/commands/gsd/eval-review.md +2 -2
  39. package/commands/gsd/execute-phase.md +2 -2
  40. package/commands/gsd/explore.md +1 -1
  41. package/commands/gsd/extract-learnings.md +2 -2
  42. package/commands/gsd/fast.md +1 -1
  43. package/commands/gsd/forensics.md +1 -1
  44. package/commands/gsd/graphify.md +9 -9
  45. package/commands/gsd/health.md +1 -1
  46. package/commands/gsd/help.md +2 -2
  47. package/commands/gsd/import.md +5 -5
  48. package/commands/gsd/inbox.md +1 -1
  49. package/commands/gsd/ingest-docs.md +4 -4
  50. package/commands/gsd/manager.md +3 -3
  51. package/commands/gsd/map-codebase.md +1 -1
  52. package/commands/gsd/milestone-summary.md +1 -1
  53. package/commands/gsd/mvp-phase.md +4 -4
  54. package/commands/gsd/new-milestone.md +5 -5
  55. package/commands/gsd/new-project.md +5 -5
  56. package/commands/gsd/pause-work.md +2 -2
  57. package/commands/gsd/phase.md +4 -4
  58. package/commands/gsd/plan-phase.md +2 -2
  59. package/commands/gsd/plan-review-convergence.md +4 -4
  60. package/commands/gsd/pr-branch.md +1 -1
  61. package/commands/gsd/profile-user.md +2 -2
  62. package/commands/gsd/progress.md +4 -4
  63. package/commands/gsd/quick.md +1 -1
  64. package/commands/gsd/resume-work.md +1 -1
  65. package/commands/gsd/review.md +1 -1
  66. package/commands/gsd/secure-phase.md +1 -1
  67. package/commands/gsd/settings.md +1 -1
  68. package/commands/gsd/ship.md +2 -2
  69. package/commands/gsd/sketch.md +7 -7
  70. package/commands/gsd/spec-phase.md +2 -2
  71. package/commands/gsd/spike.md +3 -3
  72. package/commands/gsd/stats.md +1 -1
  73. package/commands/gsd/surface.md +4 -4
  74. package/commands/gsd/thread.md +1 -1
  75. package/commands/gsd/ui-phase.md +2 -2
  76. package/commands/gsd/ui-review.md +2 -2
  77. package/commands/gsd/ultraplan-phase.md +2 -2
  78. package/commands/gsd/undo.md +3 -3
  79. package/commands/gsd/update.md +3 -3
  80. package/commands/gsd/validate-phase.md +1 -1
  81. package/commands/gsd/verify-work.md +2 -2
  82. package/commands/gsd/workspace.md +4 -4
  83. package/{get-shit-done → gsd-core}/bin/check-latest-version.cjs +1 -1
  84. package/{get-shit-done → gsd-core}/bin/gsd-tools.cjs +13 -3
  85. package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
  86. package/gsd-core/bin/lib/adr-parser.cjs +399 -0
  87. package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
  88. package/gsd-core/bin/lib/artifacts.cjs +51 -0
  89. package/gsd-core/bin/lib/audit.cjs +743 -0
  90. package/gsd-core/bin/lib/check-command-router.cjs +342 -0
  91. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  92. package/gsd-core/bin/lib/clock.cjs +95 -0
  93. package/gsd-core/bin/lib/clusters.cjs +128 -0
  94. package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
  95. package/gsd-core/bin/lib/command-aliases.cjs +809 -0
  96. package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
  97. package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
  98. package/gsd-core/bin/lib/commands.cjs +1202 -0
  99. package/gsd-core/bin/lib/config-schema.cjs +29 -0
  100. package/{get-shit-done → gsd-core}/bin/lib/config-types.cjs +1 -1
  101. package/gsd-core/bin/lib/config.cjs +714 -0
  102. package/{get-shit-done → gsd-core}/bin/lib/configuration.cjs +76 -85
  103. package/gsd-core/bin/lib/context-utilization.cjs +48 -0
  104. package/gsd-core/bin/lib/core.cjs +2007 -0
  105. package/{get-shit-done → gsd-core}/bin/lib/decisions.cjs +9 -7
  106. package/gsd-core/bin/lib/docs.cjs +252 -0
  107. package/gsd-core/bin/lib/drift.cjs +364 -0
  108. package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
  109. package/gsd-core/bin/lib/frontmatter.cjs +442 -0
  110. package/gsd-core/bin/lib/gap-checker.cjs +257 -0
  111. package/gsd-core/bin/lib/graphify.cjs +496 -0
  112. package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
  113. package/gsd-core/bin/lib/init-command-router.cjs +62 -0
  114. package/gsd-core/bin/lib/init.cjs +1799 -0
  115. package/gsd-core/bin/lib/install-profiles.cjs +526 -0
  116. package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
  117. package/gsd-core/bin/lib/installer-migration-report.cjs +347 -0
  118. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
  119. package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  120. package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  121. package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  122. package/gsd-core/bin/lib/installer-migrations.cjs +823 -0
  123. package/gsd-core/bin/lib/intel.cjs +607 -0
  124. package/gsd-core/bin/lib/learnings.cjs +270 -0
  125. package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
  126. package/gsd-core/bin/lib/milestone.cjs +373 -0
  127. package/gsd-core/bin/lib/model-catalog.cjs +154 -0
  128. package/gsd-core/bin/lib/model-profiles.cjs +24 -0
  129. package/gsd-core/bin/lib/observability/event.cjs +51 -0
  130. package/gsd-core/bin/lib/observability/logger.cjs +146 -0
  131. package/{get-shit-done → gsd-core}/bin/lib/observability/redaction.cjs +19 -21
  132. package/{get-shit-done → gsd-core}/bin/lib/package-identity.cjs +5 -1
  133. package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
  134. package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
  135. package/gsd-core/bin/lib/phase.cjs +1307 -0
  136. package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
  137. package/{get-shit-done → gsd-core}/bin/lib/plan-scan.cjs +18 -24
  138. package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
  139. package/gsd-core/bin/lib/profile-output.cjs +1120 -0
  140. package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
  141. package/gsd-core/bin/lib/project-root.cjs +119 -0
  142. package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
  143. package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
  144. package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
  145. package/gsd-core/bin/lib/roadmap-upgrade.cjs +491 -0
  146. package/gsd-core/bin/lib/roadmap.cjs +600 -0
  147. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +254 -0
  148. package/gsd-core/bin/lib/runtime-homes.cjs +169 -0
  149. package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
  150. package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
  151. package/{get-shit-done → gsd-core}/bin/lib/schema-detect.cjs +20 -26
  152. package/gsd-core/bin/lib/secrets.cjs +34 -0
  153. package/gsd-core/bin/lib/security.cjs +407 -0
  154. package/{get-shit-done → gsd-core}/bin/lib/semver-compare.cjs +1 -1
  155. package/gsd-core/bin/lib/shell-command-projection.cjs +524 -0
  156. package/gsd-core/bin/lib/state-command-router.cjs +160 -0
  157. package/{get-shit-done → gsd-core}/bin/lib/state-document.cjs +78 -78
  158. package/gsd-core/bin/lib/state.cjs +2010 -0
  159. package/gsd-core/bin/lib/surface.cjs +406 -0
  160. package/gsd-core/bin/lib/task-command-router.cjs +85 -0
  161. package/gsd-core/bin/lib/template.cjs +237 -0
  162. package/gsd-core/bin/lib/uat.cjs +297 -0
  163. package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
  164. package/gsd-core/bin/lib/update-context.cjs +218 -0
  165. package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
  166. package/gsd-core/bin/lib/validate.cjs +112 -0
  167. package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
  168. package/gsd-core/bin/lib/verify.cjs +1451 -0
  169. package/{get-shit-done → gsd-core}/bin/lib/workstream-inventory-builder.cjs +19 -12
  170. package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
  171. package/{get-shit-done → gsd-core}/bin/lib/workstream-name-policy.cjs +28 -31
  172. package/gsd-core/bin/lib/workstream.cjs +380 -0
  173. package/gsd-core/bin/lib/worktree-safety.cjs +912 -0
  174. package/{get-shit-done → gsd-core}/bin/shared/config-schema.manifest.json +5 -0
  175. package/{get-shit-done → gsd-core}/references/artifact-types.md +1 -1
  176. package/{get-shit-done → gsd-core}/references/few-shot-examples/plan-checker.md +2 -2
  177. package/{get-shit-done → gsd-core}/references/few-shot-examples/verifier.md +12 -12
  178. package/{get-shit-done → gsd-core}/references/model-profile-resolution.md +1 -1
  179. package/{get-shit-done → gsd-core}/references/mvp-concepts.md +1 -1
  180. package/{get-shit-done → gsd-core}/references/planner-graphify-auto-update.md +2 -2
  181. package/{get-shit-done → gsd-core}/references/planner-mvp-mode.md +1 -1
  182. package/{get-shit-done → gsd-core}/references/verification-patterns.md +1 -1
  183. package/gsd-core/references/worktree-branch-check.md +38 -0
  184. package/{get-shit-done → gsd-core}/references/worktree-path-safety.md +4 -26
  185. package/{get-shit-done → gsd-core}/templates/README.md +2 -2
  186. package/{get-shit-done → gsd-core}/templates/codebase/structure.md +10 -10
  187. package/{get-shit-done → gsd-core}/templates/copilot-instructions.md +1 -1
  188. package/{get-shit-done → gsd-core}/templates/phase-prompt.md +10 -10
  189. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
  190. package/{get-shit-done → gsd-core}/workflows/add-backlog.md +1 -1
  191. package/{get-shit-done → gsd-core}/workflows/add-phase.md +1 -1
  192. package/{get-shit-done → gsd-core}/workflows/add-tests.md +1 -1
  193. package/{get-shit-done → gsd-core}/workflows/add-todo.md +1 -1
  194. package/{get-shit-done → gsd-core}/workflows/ai-integration-phase.md +4 -4
  195. package/{get-shit-done → gsd-core}/workflows/audit-fix.md +1 -1
  196. package/{get-shit-done → gsd-core}/workflows/audit-milestone.md +1 -1
  197. package/{get-shit-done → gsd-core}/workflows/audit-uat.md +1 -1
  198. package/{get-shit-done → gsd-core}/workflows/autonomous.md +4 -4
  199. package/{get-shit-done → gsd-core}/workflows/check-todos.md +1 -1
  200. package/{get-shit-done → gsd-core}/workflows/cleanup.md +1 -1
  201. package/{get-shit-done → gsd-core}/workflows/code-review-fix.md +1 -1
  202. package/{get-shit-done → gsd-core}/workflows/code-review.md +4 -4
  203. package/{get-shit-done → gsd-core}/workflows/complete-milestone.md +2 -2
  204. package/{get-shit-done → gsd-core}/workflows/debug.md +1 -1
  205. package/{get-shit-done → gsd-core}/workflows/diagnose-issues.md +4 -2
  206. package/{get-shit-done → gsd-core}/workflows/discovery-phase.md +5 -5
  207. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/advisor.md +4 -4
  208. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/auto.md +1 -1
  209. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/chain.md +1 -1
  210. package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/power.md +1 -1
  211. package/{get-shit-done → gsd-core}/workflows/discuss-phase-assumptions.md +2 -2
  212. package/{get-shit-done → gsd-core}/workflows/discuss-phase.md +6 -6
  213. package/{get-shit-done → gsd-core}/workflows/do.md +1 -1
  214. package/{get-shit-done → gsd-core}/workflows/docs-update.md +1 -1
  215. package/{get-shit-done → gsd-core}/workflows/edit-phase.md +1 -1
  216. package/{get-shit-done → gsd-core}/workflows/eval-review.md +2 -2
  217. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/codebase-drift-gate.md +15 -2
  218. package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  219. package/{get-shit-done → gsd-core}/workflows/execute-phase.md +68 -46
  220. package/{get-shit-done → gsd-core}/workflows/execute-plan.md +8 -8
  221. package/{get-shit-done → gsd-core}/workflows/explore.md +3 -3
  222. package/{get-shit-done → gsd-core}/workflows/extract-learnings.md +1 -1
  223. package/{get-shit-done → gsd-core}/workflows/forensics.md +1 -1
  224. package/{get-shit-done → gsd-core}/workflows/graduation.md +1 -1
  225. package/{get-shit-done → gsd-core}/workflows/health.md +1 -1
  226. package/{get-shit-done → gsd-core}/workflows/help/modes/full.md +1 -1
  227. package/{get-shit-done → gsd-core}/workflows/import.md +1 -1
  228. package/{get-shit-done → gsd-core}/workflows/ingest-docs.md +3 -3
  229. package/{get-shit-done → gsd-core}/workflows/insert-phase.md +1 -1
  230. package/{get-shit-done → gsd-core}/workflows/list-workspaces.md +1 -1
  231. package/{get-shit-done → gsd-core}/workflows/manager.md +1 -1
  232. package/{get-shit-done → gsd-core}/workflows/map-codebase.md +1 -1
  233. package/{get-shit-done → gsd-core}/workflows/milestone-summary.md +1 -1
  234. package/{get-shit-done → gsd-core}/workflows/mvp-phase.md +7 -7
  235. package/{get-shit-done → gsd-core}/workflows/new-milestone.md +3 -3
  236. package/{get-shit-done → gsd-core}/workflows/new-project.md +6 -6
  237. package/{get-shit-done → gsd-core}/workflows/new-workspace.md +1 -1
  238. package/{get-shit-done → gsd-core}/workflows/next.md +1 -1
  239. package/{get-shit-done → gsd-core}/workflows/pause-work.md +1 -1
  240. package/{get-shit-done → gsd-core}/workflows/plan-milestone-gaps.md +1 -1
  241. package/{get-shit-done → gsd-core}/workflows/plan-phase.md +15 -15
  242. package/{get-shit-done → gsd-core}/workflows/plan-review-convergence.md +7 -7
  243. package/{get-shit-done → gsd-core}/workflows/plant-seed.md +1 -1
  244. package/{get-shit-done → gsd-core}/workflows/profile-user.md +11 -11
  245. package/{get-shit-done → gsd-core}/workflows/progress.md +1 -1
  246. package/{get-shit-done → gsd-core}/workflows/quick.md +2 -26
  247. package/{get-shit-done → gsd-core}/workflows/reapply-patches.md +2 -2
  248. package/{get-shit-done → gsd-core}/workflows/remove-phase.md +1 -1
  249. package/{get-shit-done → gsd-core}/workflows/remove-workspace.md +1 -1
  250. package/{get-shit-done → gsd-core}/workflows/resume-project.md +2 -2
  251. package/{get-shit-done → gsd-core}/workflows/review.md +1 -1
  252. package/{get-shit-done → gsd-core}/workflows/scan.md +1 -1
  253. package/{get-shit-done → gsd-core}/workflows/secure-phase.md +3 -3
  254. package/{get-shit-done → gsd-core}/workflows/settings-advanced.md +1 -1
  255. package/{get-shit-done → gsd-core}/workflows/settings-integrations.md +2 -2
  256. package/{get-shit-done → gsd-core}/workflows/settings.md +1 -1
  257. package/{get-shit-done → gsd-core}/workflows/ship.md +56 -4
  258. package/{get-shit-done → gsd-core}/workflows/sketch-wrap-up.md +1 -1
  259. package/{get-shit-done → gsd-core}/workflows/sketch.md +5 -5
  260. package/{get-shit-done → gsd-core}/workflows/spec-phase.md +2 -2
  261. package/{get-shit-done → gsd-core}/workflows/spike-wrap-up.md +1 -1
  262. package/{get-shit-done → gsd-core}/workflows/spike.md +1 -1
  263. package/{get-shit-done → gsd-core}/workflows/stats.md +1 -1
  264. package/{get-shit-done → gsd-core}/workflows/sync-skills.md +3 -3
  265. package/{get-shit-done → gsd-core}/workflows/thread.md +1 -1
  266. package/{get-shit-done → gsd-core}/workflows/transition.md +2 -2
  267. package/{get-shit-done → gsd-core}/workflows/ui-phase.md +3 -3
  268. package/{get-shit-done → gsd-core}/workflows/ui-review.md +2 -2
  269. package/{get-shit-done → gsd-core}/workflows/ultraplan-phase.md +1 -1
  270. package/{get-shit-done → gsd-core}/workflows/undo.md +2 -2
  271. package/{get-shit-done → gsd-core}/workflows/update.md +41 -16
  272. package/{get-shit-done → gsd-core}/workflows/validate-phase.md +3 -3
  273. package/{get-shit-done → gsd-core}/workflows/verify-phase.md +4 -4
  274. package/{get-shit-done → gsd-core}/workflows/verify-work.md +5 -5
  275. package/hooks/dist/gsd-check-update-worker.js +16 -3
  276. package/hooks/dist/gsd-check-update.js +7 -5
  277. package/hooks/dist/gsd-context-monitor.js +2 -2
  278. package/hooks/dist/gsd-statusline.js +39 -21
  279. package/hooks/dist/gsd-update-banner.js +6 -2
  280. package/hooks/dist/managed-hooks-registry.cjs +35 -0
  281. package/hooks/gsd-check-update-worker.js +16 -3
  282. package/hooks/gsd-check-update.js +7 -5
  283. package/hooks/gsd-context-monitor.js +2 -2
  284. package/hooks/gsd-statusline.js +39 -21
  285. package/hooks/gsd-update-banner.js +6 -2
  286. package/package.json +9 -6
  287. package/scripts/affected-tests-lib.cjs +1 -1
  288. package/scripts/base64-scan.sh +12 -0
  289. package/scripts/build-hooks.js +4 -1
  290. package/scripts/changeset/cli.cjs +2 -2
  291. package/scripts/changeset/github-release-notes.cjs +1 -1
  292. package/scripts/changeset/lint.cjs +1 -1
  293. package/scripts/check-alias-drift.cjs +8 -8
  294. package/scripts/check-env.cjs +5 -1
  295. package/scripts/ci-test-scope.cjs +25 -10
  296. package/scripts/command-contract-helpers.cjs +1 -1
  297. package/scripts/fix-slash-commands.cjs +5 -5
  298. package/scripts/gen-inventory-manifest.cjs +3 -3
  299. package/scripts/generate-package-identity.cjs +28 -7
  300. package/scripts/lib/allowlist-ratchet.cjs +136 -0
  301. package/scripts/lint-command-contract.cjs +1 -1
  302. package/scripts/lint-legacy-dir-name.cjs +156 -0
  303. package/scripts/lint-package-identity-drift.cjs +8 -8
  304. package/scripts/lint-pr-check-project-dir.cjs +0 -1
  305. package/scripts/lint-shell-command-projection-drift.cjs +1 -1
  306. package/scripts/lint-skill-deps.cjs +1 -1
  307. package/scripts/lint-test-file-count.allowlist.json +129 -32
  308. package/scripts/lint-test-file-count.cjs +85 -30
  309. package/scripts/mutation-matrix.cjs +219 -0
  310. package/scripts/prompt-injection-scan.sh +5 -1
  311. package/scripts/release-notes/format-github-release-notes.cjs +256 -0
  312. package/scripts/release-tarball-smoke.cjs +9 -9
  313. package/scripts/run-tests.cjs +11 -3
  314. package/scripts/strip-prose-atrefs.cjs +2 -2
  315. package/scripts/sync-runtime-launcher.cjs +2 -2
  316. package/scripts/verify-npm-publish.cjs +252 -0
  317. package/get-shit-done/bin/lib/active-workstream-store.cjs +0 -302
  318. package/get-shit-done/bin/lib/adr-parser.cjs +0 -394
  319. package/get-shit-done/bin/lib/agent-command-router.cjs +0 -65
  320. package/get-shit-done/bin/lib/artifacts.cjs +0 -53
  321. package/get-shit-done/bin/lib/audit.cjs +0 -755
  322. package/get-shit-done/bin/lib/check-command-router.cjs +0 -333
  323. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +0 -118
  324. package/get-shit-done/bin/lib/clock.cjs +0 -96
  325. package/get-shit-done/bin/lib/clusters.cjs +0 -135
  326. package/get-shit-done/bin/lib/code-review-flags.cjs +0 -74
  327. package/get-shit-done/bin/lib/command-aliases.cjs +0 -831
  328. package/get-shit-done/bin/lib/command-arg-projection.cjs +0 -62
  329. package/get-shit-done/bin/lib/command-routing-hub.cjs +0 -388
  330. package/get-shit-done/bin/lib/commands.cjs +0 -1292
  331. package/get-shit-done/bin/lib/config-schema.cjs +0 -31
  332. package/get-shit-done/bin/lib/config.cjs +0 -728
  333. package/get-shit-done/bin/lib/context-utilization.cjs +0 -47
  334. package/get-shit-done/bin/lib/core.cjs +0 -2513
  335. package/get-shit-done/bin/lib/docs.cjs +0 -270
  336. package/get-shit-done/bin/lib/drift.cjs +0 -388
  337. package/get-shit-done/bin/lib/fallow-runner.cjs +0 -109
  338. package/get-shit-done/bin/lib/frontmatter.cjs +0 -389
  339. package/get-shit-done/bin/lib/gap-checker.cjs +0 -254
  340. package/get-shit-done/bin/lib/graphify.cjs +0 -592
  341. package/get-shit-done/bin/lib/gsd2-import.cjs +0 -514
  342. package/get-shit-done/bin/lib/init-command-router.cjs +0 -58
  343. package/get-shit-done/bin/lib/init.cjs +0 -2112
  344. package/get-shit-done/bin/lib/install-profiles.cjs +0 -603
  345. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +0 -117
  346. package/get-shit-done/bin/lib/installer-migration-report.cjs +0 -355
  347. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +0 -220
  348. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +0 -41
  349. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +0 -80
  350. package/get-shit-done/bin/lib/installer-migrations.cjs +0 -778
  351. package/get-shit-done/bin/lib/intel.cjs +0 -708
  352. package/get-shit-done/bin/lib/learnings.cjs +0 -421
  353. package/get-shit-done/bin/lib/milestone.cjs +0 -372
  354. package/get-shit-done/bin/lib/model-catalog.cjs +0 -229
  355. package/get-shit-done/bin/lib/model-profiles.cjs +0 -31
  356. package/get-shit-done/bin/lib/observability/event.cjs +0 -82
  357. package/get-shit-done/bin/lib/observability/logger.cjs +0 -174
  358. package/get-shit-done/bin/lib/phase-command-router.cjs +0 -191
  359. package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -79
  360. package/get-shit-done/bin/lib/phase.cjs +0 -1607
  361. package/get-shit-done/bin/lib/phases-command-router.cjs +0 -39
  362. package/get-shit-done/bin/lib/planning-workspace.cjs +0 -238
  363. package/get-shit-done/bin/lib/profile-output.cjs +0 -1141
  364. package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
  365. package/get-shit-done/bin/lib/project-root.cjs +0 -112
  366. package/get-shit-done/bin/lib/prompt-budget.cjs +0 -399
  367. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +0 -126
  368. package/get-shit-done/bin/lib/roadmap-command-router.cjs +0 -162
  369. package/get-shit-done/bin/lib/roadmap-upgrade.cjs +0 -569
  370. package/get-shit-done/bin/lib/roadmap.cjs +0 -651
  371. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +0 -301
  372. package/get-shit-done/bin/lib/runtime-homes.cjs +0 -222
  373. package/get-shit-done/bin/lib/runtime-name-policy.cjs +0 -83
  374. package/get-shit-done/bin/lib/runtime-slash.cjs +0 -112
  375. package/get-shit-done/bin/lib/secrets.cjs +0 -32
  376. package/get-shit-done/bin/lib/security.cjs +0 -600
  377. package/get-shit-done/bin/lib/shell-command-projection.cjs +0 -535
  378. package/get-shit-done/bin/lib/state-command-router.cjs +0 -252
  379. package/get-shit-done/bin/lib/state.cjs +0 -2073
  380. package/get-shit-done/bin/lib/surface.cjs +0 -470
  381. package/get-shit-done/bin/lib/task-command-router.cjs +0 -81
  382. package/get-shit-done/bin/lib/template.cjs +0 -228
  383. package/get-shit-done/bin/lib/uat.cjs +0 -289
  384. package/get-shit-done/bin/lib/ui-safety-gate.cjs +0 -111
  385. package/get-shit-done/bin/lib/update-context.cjs +0 -209
  386. package/get-shit-done/bin/lib/validate-command-router.cjs +0 -83
  387. package/get-shit-done/bin/lib/validate.cjs +0 -118
  388. package/get-shit-done/bin/lib/verify-command-router.cjs +0 -40
  389. package/get-shit-done/bin/lib/verify.cjs +0 -1614
  390. package/get-shit-done/bin/lib/workstream-inventory.cjs +0 -146
  391. package/get-shit-done/bin/lib/workstream.cjs +0 -389
  392. package/get-shit-done/bin/lib/worktree-safety.cjs +0 -985
  393. package/get-shit-done/workflows/_runtime-launcher.snippet.sh +0 -1
  394. package/scripts/lint-no-source-grep-extras.cjs +0 -81
  395. package/scripts/lint-no-source-grep.cjs +0 -174
  396. /package/{get-shit-done → gsd-core}/bin/shared/config-defaults.manifest.json +0 -0
  397. /package/{get-shit-done → gsd-core}/bin/shared/model-catalog.json +0 -0
  398. /package/{get-shit-done → gsd-core}/bin/shared/runtime-aliases.manifest.json +0 -0
  399. /package/{get-shit-done → gsd-core}/bin/verify-reapply-patches.cjs +0 -0
  400. /package/{get-shit-done → gsd-core}/contexts/dev.md +0 -0
  401. /package/{get-shit-done → gsd-core}/contexts/research.md +0 -0
  402. /package/{get-shit-done → gsd-core}/contexts/review.md +0 -0
  403. /package/{get-shit-done → gsd-core}/references/agent-contracts.md +0 -0
  404. /package/{get-shit-done → gsd-core}/references/ai-evals.md +0 -0
  405. /package/{get-shit-done → gsd-core}/references/ai-frameworks.md +0 -0
  406. /package/{get-shit-done → gsd-core}/references/autonomous-smart-discuss.md +0 -0
  407. /package/{get-shit-done → gsd-core}/references/checkpoints.md +0 -0
  408. /package/{get-shit-done → gsd-core}/references/common-bug-patterns.md +0 -0
  409. /package/{get-shit-done → gsd-core}/references/context-budget.md +0 -0
  410. /package/{get-shit-done → gsd-core}/references/continuation-format.md +0 -0
  411. /package/{get-shit-done → gsd-core}/references/debugger-philosophy.md +0 -0
  412. /package/{get-shit-done → gsd-core}/references/decimal-phase-calculation.md +0 -0
  413. /package/{get-shit-done → gsd-core}/references/doc-conflict-engine.md +0 -0
  414. /package/{get-shit-done → gsd-core}/references/domain-probes.md +0 -0
  415. /package/{get-shit-done → gsd-core}/references/execute-mvp-tdd.md +0 -0
  416. /package/{get-shit-done → gsd-core}/references/executor-examples.md +0 -0
  417. /package/{get-shit-done → gsd-core}/references/gate-prompts.md +0 -0
  418. /package/{get-shit-done → gsd-core}/references/gates.md +0 -0
  419. /package/{get-shit-done → gsd-core}/references/git-integration.md +0 -0
  420. /package/{get-shit-done → gsd-core}/references/git-planning-commit.md +0 -0
  421. /package/{get-shit-done → gsd-core}/references/ios-scaffold.md +0 -0
  422. /package/{get-shit-done → gsd-core}/references/mandatory-initial-read.md +0 -0
  423. /package/{get-shit-done → gsd-core}/references/model-profiles.md +0 -0
  424. /package/{get-shit-done → gsd-core}/references/phase-argument-parsing.md +0 -0
  425. /package/{get-shit-done → gsd-core}/references/planner-antipatterns.md +0 -0
  426. /package/{get-shit-done → gsd-core}/references/planner-chunked.md +0 -0
  427. /package/{get-shit-done → gsd-core}/references/planner-gap-closure.md +0 -0
  428. /package/{get-shit-done → gsd-core}/references/planner-human-verify-mode.md +0 -0
  429. /package/{get-shit-done → gsd-core}/references/planner-interface-context.md +0 -0
  430. /package/{get-shit-done → gsd-core}/references/planner-reviews.md +0 -0
  431. /package/{get-shit-done → gsd-core}/references/planner-revision.md +0 -0
  432. /package/{get-shit-done → gsd-core}/references/planner-source-audit.md +0 -0
  433. /package/{get-shit-done → gsd-core}/references/planning-config.md +0 -0
  434. /package/{get-shit-done → gsd-core}/references/project-skills-discovery.md +0 -0
  435. /package/{get-shit-done → gsd-core}/references/questioning.md +0 -0
  436. /package/{get-shit-done → gsd-core}/references/revision-loop.md +0 -0
  437. /package/{get-shit-done → gsd-core}/references/scout-codebase.md +0 -0
  438. /package/{get-shit-done → gsd-core}/references/skeleton-template.md +0 -0
  439. /package/{get-shit-done → gsd-core}/references/sketch-interactivity.md +0 -0
  440. /package/{get-shit-done → gsd-core}/references/sketch-theme-system.md +0 -0
  441. /package/{get-shit-done → gsd-core}/references/sketch-tooling.md +0 -0
  442. /package/{get-shit-done → gsd-core}/references/sketch-variant-patterns.md +0 -0
  443. /package/{get-shit-done → gsd-core}/references/spidr-splitting.md +0 -0
  444. /package/{get-shit-done → gsd-core}/references/tdd.md +0 -0
  445. /package/{get-shit-done → gsd-core}/references/thinking-models-debug.md +0 -0
  446. /package/{get-shit-done → gsd-core}/references/thinking-models-execution.md +0 -0
  447. /package/{get-shit-done → gsd-core}/references/thinking-models-planning.md +0 -0
  448. /package/{get-shit-done → gsd-core}/references/thinking-models-research.md +0 -0
  449. /package/{get-shit-done → gsd-core}/references/thinking-models-verification.md +0 -0
  450. /package/{get-shit-done → gsd-core}/references/thinking-partner.md +0 -0
  451. /package/{get-shit-done → gsd-core}/references/ui-brand.md +0 -0
  452. /package/{get-shit-done → gsd-core}/references/universal-anti-patterns.md +0 -0
  453. /package/{get-shit-done → gsd-core}/references/user-profiling.md +0 -0
  454. /package/{get-shit-done → gsd-core}/references/user-story-template.md +0 -0
  455. /package/{get-shit-done → gsd-core}/references/verification-overrides.md +0 -0
  456. /package/{get-shit-done → gsd-core}/references/verify-mvp-mode.md +0 -0
  457. /package/{get-shit-done → gsd-core}/references/workstream-flag.md +0 -0
  458. /package/{get-shit-done → gsd-core}/templates/AI-SPEC.md +0 -0
  459. /package/{get-shit-done → gsd-core}/templates/DEBUG.md +0 -0
  460. /package/{get-shit-done → gsd-core}/templates/SECURITY.md +0 -0
  461. /package/{get-shit-done → gsd-core}/templates/UAT.md +0 -0
  462. /package/{get-shit-done → gsd-core}/templates/UI-SPEC.md +0 -0
  463. /package/{get-shit-done → gsd-core}/templates/VALIDATION.md +0 -0
  464. /package/{get-shit-done → gsd-core}/templates/claude-md.md +0 -0
  465. /package/{get-shit-done → gsd-core}/templates/codebase/architecture.md +0 -0
  466. /package/{get-shit-done → gsd-core}/templates/codebase/concerns.md +0 -0
  467. /package/{get-shit-done → gsd-core}/templates/codebase/conventions.md +0 -0
  468. /package/{get-shit-done → gsd-core}/templates/codebase/integrations.md +0 -0
  469. /package/{get-shit-done → gsd-core}/templates/codebase/stack.md +0 -0
  470. /package/{get-shit-done → gsd-core}/templates/codebase/testing.md +0 -0
  471. /package/{get-shit-done → gsd-core}/templates/config.json +0 -0
  472. /package/{get-shit-done → gsd-core}/templates/context.md +0 -0
  473. /package/{get-shit-done → gsd-core}/templates/continue-here.md +0 -0
  474. /package/{get-shit-done → gsd-core}/templates/debug-subagent-prompt.md +0 -0
  475. /package/{get-shit-done → gsd-core}/templates/dev-preferences.md +0 -0
  476. /package/{get-shit-done → gsd-core}/templates/discovery.md +0 -0
  477. /package/{get-shit-done → gsd-core}/templates/discussion-log.md +0 -0
  478. /package/{get-shit-done → gsd-core}/templates/milestone-archive.md +0 -0
  479. /package/{get-shit-done → gsd-core}/templates/milestone.md +0 -0
  480. /package/{get-shit-done → gsd-core}/templates/planner-subagent-prompt.md +0 -0
  481. /package/{get-shit-done → gsd-core}/templates/project.md +0 -0
  482. /package/{get-shit-done → gsd-core}/templates/requirements.md +0 -0
  483. /package/{get-shit-done → gsd-core}/templates/research-project/ARCHITECTURE.md +0 -0
  484. /package/{get-shit-done → gsd-core}/templates/research-project/FEATURES.md +0 -0
  485. /package/{get-shit-done → gsd-core}/templates/research-project/PITFALLS.md +0 -0
  486. /package/{get-shit-done → gsd-core}/templates/research-project/STACK.md +0 -0
  487. /package/{get-shit-done → gsd-core}/templates/research-project/SUMMARY.md +0 -0
  488. /package/{get-shit-done → gsd-core}/templates/research.md +0 -0
  489. /package/{get-shit-done → gsd-core}/templates/retrospective.md +0 -0
  490. /package/{get-shit-done → gsd-core}/templates/roadmap.md +0 -0
  491. /package/{get-shit-done → gsd-core}/templates/spec.md +0 -0
  492. /package/{get-shit-done → gsd-core}/templates/state.md +0 -0
  493. /package/{get-shit-done → gsd-core}/templates/summary-complex.md +0 -0
  494. /package/{get-shit-done → gsd-core}/templates/summary-minimal.md +0 -0
  495. /package/{get-shit-done → gsd-core}/templates/summary-standard.md +0 -0
  496. /package/{get-shit-done → gsd-core}/templates/summary.md +0 -0
  497. /package/{get-shit-done → gsd-core}/templates/user-profile.md +0 -0
  498. /package/{get-shit-done → gsd-core}/templates/user-setup.md +0 -0
  499. /package/{get-shit-done → gsd-core}/templates/verification-report.md +0 -0
  500. /package/{get-shit-done → gsd-core}/workflows/analyze-dependencies.md +0 -0
  501. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/all.md +0 -0
  502. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/analyze.md +0 -0
  503. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/batch.md +0 -0
  504. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/default.md +0 -0
  505. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/text.md +0 -0
  506. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/checkpoint.json +0 -0
  507. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/context.md +0 -0
  508. /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/discussion-log.md +0 -0
  509. /package/{get-shit-done → gsd-core}/workflows/discuss-phase-power.md +0 -0
  510. /package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -0
  511. /package/{get-shit-done → gsd-core}/workflows/fast.md +0 -0
  512. /package/{get-shit-done → gsd-core}/workflows/help/modes/brief.md +0 -0
  513. /package/{get-shit-done → gsd-core}/workflows/help/modes/default.md +0 -0
  514. /package/{get-shit-done → gsd-core}/workflows/help/modes/topic.md +0 -0
  515. /package/{get-shit-done → gsd-core}/workflows/help.md +0 -0
  516. /package/{get-shit-done → gsd-core}/workflows/inbox.md +0 -0
  517. /package/{get-shit-done → gsd-core}/workflows/list-phase-assumptions.md +0 -0
  518. /package/{get-shit-done → gsd-core}/workflows/node-repair.md +0 -0
  519. /package/{get-shit-done → gsd-core}/workflows/note.md +0 -0
  520. /package/{get-shit-done → gsd-core}/workflows/pr-branch.md +0 -0
  521. /package/{get-shit-done → gsd-core}/workflows/session-report.md +0 -0
@@ -0,0 +1,743 @@
1
+ "use strict";
2
+ /**
3
+ * Open Artifact Audit — Cross-type unresolved state scanner
4
+ *
5
+ * Scans all .planning/ artifact categories for items with open/unresolved state.
6
+ * Returns structured JSON for workflow consumption.
7
+ * Called by: gsd-tools.cjs audit-open
8
+ * Used by: /gsd:complete-milestone pre-close gate
9
+ *
10
+ * ADR-457 build-at-publish: the hand-written bin/lib/audit.cjs collapsed
11
+ * to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
12
+ * from the prior hand-written .cjs; only strict types are added.
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ const node_fs_1 = __importDefault(require("node:fs"));
18
+ const node_path_1 = __importDefault(require("node:path"));
19
+ const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
20
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
21
+ const planningWorkspace = require("./planning-workspace.cjs");
22
+ const { planningDir } = planningWorkspace;
23
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
24
+ const frontmatter = require("./frontmatter.cjs");
25
+ const { extractFrontmatter } = frontmatter;
26
+ const security_cjs_1 = require("./security.cjs");
27
+ // Terminal UAT states: `complete` (legacy) and `resolved` (post-gap-closure
28
+ // per workflows/execute-phase.md). Hoisted outside scanUatGaps so the Set is
29
+ // not recreated on each loop iteration.
30
+ const TERMINAL_UAT_STATUSES = new Set(['complete', 'resolved']);
31
+ // ─── scanDebugSessions ────────────────────────────────────────────────────────
32
+ /**
33
+ * Scan .planning/debug/ for open sessions.
34
+ * Open = status NOT in ['resolved', 'complete'].
35
+ * Ignores the resolved/ subdirectory.
36
+ */
37
+ function scanDebugSessions(planDir) {
38
+ const debugDir = node_path_1.default.join(planDir, 'debug');
39
+ if (!node_fs_1.default.existsSync(debugDir))
40
+ return [];
41
+ const results = [];
42
+ let files;
43
+ try {
44
+ files = node_fs_1.default.readdirSync(debugDir, { withFileTypes: true });
45
+ }
46
+ catch {
47
+ return [{ scan_error: true, slug: '', status: '', updated: '', hypothesis: '' }];
48
+ }
49
+ for (const entry of files) {
50
+ if (!entry.isFile())
51
+ continue;
52
+ if (!entry.name.endsWith('.md'))
53
+ continue;
54
+ const filePath = node_path_1.default.join(debugDir, entry.name);
55
+ let safeFilePath;
56
+ try {
57
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'debug session file', { allowAbsolute: true });
58
+ }
59
+ catch {
60
+ continue;
61
+ }
62
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
63
+ if (content === null)
64
+ continue;
65
+ const fm = extractFrontmatter(content);
66
+ const status = (fm.status || 'unknown').toLowerCase();
67
+ if (status === 'resolved' || status === 'complete')
68
+ continue;
69
+ // Extract hypothesis from "Current Focus" block if parseable
70
+ let hypothesis = '';
71
+ const focusMatch = content.match(/##\s*Current Focus[^\n]*\n([\s\S]*?)(?=\n##\s|$)/i);
72
+ if (focusMatch) {
73
+ const focusText = focusMatch[1].trim().split('\n')[0].trim();
74
+ hypothesis = (0, security_cjs_1.sanitizeForDisplay)(focusText.slice(0, 100));
75
+ }
76
+ const slug = node_path_1.default.basename(entry.name, '.md');
77
+ results.push({
78
+ slug: (0, security_cjs_1.sanitizeForDisplay)(slug),
79
+ status: (0, security_cjs_1.sanitizeForDisplay)(status),
80
+ updated: (0, security_cjs_1.sanitizeForDisplay)(fm.updated || fm.date || ''),
81
+ hypothesis,
82
+ });
83
+ }
84
+ return results;
85
+ }
86
+ // ─── scanQuickTasks ───────────────────────────────────────────────────────────
87
+ /**
88
+ * Scan .planning/quick/ for incomplete tasks.
89
+ * Incomplete if SUMMARY.md missing or status !== 'complete'.
90
+ */
91
+ function scanQuickTasks(planDir) {
92
+ const quickDir = node_path_1.default.join(planDir, 'quick');
93
+ if (!node_fs_1.default.existsSync(quickDir))
94
+ return [];
95
+ let entries;
96
+ try {
97
+ entries = node_fs_1.default.readdirSync(quickDir, { withFileTypes: true });
98
+ }
99
+ catch {
100
+ return [{ scan_error: true, slug: '', date: '', status: '', description: '' }];
101
+ }
102
+ const results = [];
103
+ for (const entry of entries) {
104
+ if (!entry.isDirectory())
105
+ continue;
106
+ const dirName = entry.name;
107
+ const taskDir = node_path_1.default.join(quickDir, dirName);
108
+ let safeTaskDir;
109
+ try {
110
+ safeTaskDir = (0, security_cjs_1.requireSafePath)(taskDir, planDir, 'quick task dir', { allowAbsolute: true });
111
+ }
112
+ catch {
113
+ continue;
114
+ }
115
+ // workflows/quick.md mandates `${quick_id}-SUMMARY.md`; older flows used
116
+ // bare `SUMMARY.md`. Accept either to avoid false-positive "missing".
117
+ let summaryPath = null;
118
+ try {
119
+ const summaryFiles = node_fs_1.default.readdirSync(safeTaskDir, { withFileTypes: true })
120
+ .filter(e => e.isFile() && (e.name === 'SUMMARY.md' || e.name.endsWith('-SUMMARY.md')));
121
+ if (summaryFiles.length > 0) {
122
+ // Prefer the per-task `${quick_id}-SUMMARY.md` form when present.
123
+ const preferred = summaryFiles.find(e => e.name === `${dirName}-SUMMARY.md`)
124
+ || summaryFiles.find(e => e.name.endsWith('-SUMMARY.md'))
125
+ || summaryFiles[0];
126
+ summaryPath = node_path_1.default.join(safeTaskDir, preferred.name);
127
+ }
128
+ }
129
+ catch {
130
+ // fall through with summaryPath = null → status: missing
131
+ }
132
+ let status = 'missing';
133
+ const description = '';
134
+ if (summaryPath && node_fs_1.default.existsSync(summaryPath)) {
135
+ let safeSum;
136
+ try {
137
+ safeSum = (0, security_cjs_1.requireSafePath)(summaryPath, planDir, 'quick task summary', { allowAbsolute: true });
138
+ }
139
+ catch {
140
+ continue;
141
+ }
142
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeSum);
143
+ if (content === null) {
144
+ status = 'unreadable';
145
+ }
146
+ else {
147
+ const fm = extractFrontmatter(content);
148
+ status = (fm.status || 'unknown').toLowerCase();
149
+ }
150
+ }
151
+ if (status === 'complete')
152
+ continue;
153
+ // Parse date and slug from directory name: YYYYMMDD-slug or YYYY-MM-DD-slug
154
+ let date = '';
155
+ let slug = (0, security_cjs_1.sanitizeForDisplay)(dirName);
156
+ const dateMatch = dirName.match(/^(\d{4}-?\d{2}-?\d{2})-(.+)$/);
157
+ if (dateMatch) {
158
+ date = dateMatch[1];
159
+ slug = (0, security_cjs_1.sanitizeForDisplay)(dateMatch[2]);
160
+ }
161
+ results.push({
162
+ slug,
163
+ date,
164
+ status: (0, security_cjs_1.sanitizeForDisplay)(status),
165
+ description,
166
+ });
167
+ }
168
+ return results;
169
+ }
170
+ // ─── scanThreads ──────────────────────────────────────────────────────────────
171
+ /**
172
+ * Scan .planning/threads/ for open threads.
173
+ * Open if status in ['open', 'in_progress', 'in progress'] (case-insensitive).
174
+ */
175
+ function scanThreads(planDir) {
176
+ const threadsDir = node_path_1.default.join(planDir, 'threads');
177
+ if (!node_fs_1.default.existsSync(threadsDir))
178
+ return [];
179
+ let files;
180
+ try {
181
+ files = node_fs_1.default.readdirSync(threadsDir, { withFileTypes: true });
182
+ }
183
+ catch {
184
+ return [{ scan_error: true, slug: '', status: '', updated: '', title: '' }];
185
+ }
186
+ const openStatuses = new Set(['open', 'in_progress', 'in progress']);
187
+ const results = [];
188
+ for (const entry of files) {
189
+ if (!entry.isFile())
190
+ continue;
191
+ if (!entry.name.endsWith('.md'))
192
+ continue;
193
+ const filePath = node_path_1.default.join(threadsDir, entry.name);
194
+ let safeFilePath;
195
+ try {
196
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'thread file', { allowAbsolute: true });
197
+ }
198
+ catch {
199
+ continue;
200
+ }
201
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
202
+ if (content === null)
203
+ continue;
204
+ const fm = extractFrontmatter(content);
205
+ let status = (fm.status || '').toLowerCase().trim();
206
+ // Fall back to scanning body for ## Status: OPEN / IN PROGRESS
207
+ if (!status) {
208
+ const bodyStatusMatch = content.match(/##\s*Status:\s*(OPEN|IN PROGRESS|IN_PROGRESS)/i);
209
+ if (bodyStatusMatch) {
210
+ status = bodyStatusMatch[1].toLowerCase().replace(/ /g, '_');
211
+ }
212
+ }
213
+ if (!openStatuses.has(status))
214
+ continue;
215
+ // Extract title from # Thread: heading or frontmatter title
216
+ let title = (0, security_cjs_1.sanitizeForDisplay)(fm.title || '');
217
+ if (!title) {
218
+ const headingMatch = content.match(/^#\s*Thread:\s*(.+)$/m);
219
+ if (headingMatch) {
220
+ title = (0, security_cjs_1.sanitizeForDisplay)(headingMatch[1].trim().slice(0, 100));
221
+ }
222
+ }
223
+ const slug = node_path_1.default.basename(entry.name, '.md');
224
+ results.push({
225
+ slug: (0, security_cjs_1.sanitizeForDisplay)(slug),
226
+ status: (0, security_cjs_1.sanitizeForDisplay)(status),
227
+ updated: (0, security_cjs_1.sanitizeForDisplay)(fm.updated || fm.date || ''),
228
+ title,
229
+ });
230
+ }
231
+ return results;
232
+ }
233
+ // ─── scanTodos ────────────────────────────────────────────────────────────────
234
+ /**
235
+ * Scan .planning/todos/pending/ for pending todos.
236
+ * Returns array of { filename, priority, area, summary }.
237
+ * Display limited to first 5 + count of remainder.
238
+ */
239
+ function scanTodos(planDir) {
240
+ const pendingDir = node_path_1.default.join(planDir, 'todos', 'pending');
241
+ if (!node_fs_1.default.existsSync(pendingDir))
242
+ return [];
243
+ let files;
244
+ try {
245
+ files = node_fs_1.default.readdirSync(pendingDir, { withFileTypes: true });
246
+ }
247
+ catch {
248
+ return [{ scan_error: true, filename: '', priority: '', area: '', summary: '' }];
249
+ }
250
+ const mdFiles = files.filter(e => e.isFile() && e.name.endsWith('.md'));
251
+ const results = [];
252
+ const displayFiles = mdFiles.slice(0, 5);
253
+ for (const entry of displayFiles) {
254
+ const filePath = node_path_1.default.join(pendingDir, entry.name);
255
+ let safeFilePath;
256
+ try {
257
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'todo file', { allowAbsolute: true });
258
+ }
259
+ catch {
260
+ continue;
261
+ }
262
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
263
+ if (content === null)
264
+ continue;
265
+ const fm = extractFrontmatter(content);
266
+ // Extract first line of body after frontmatter
267
+ const bodyMatch = content.replace(/^---[\s\S]*?---\n?/, '');
268
+ const firstLine = bodyMatch.trim().split('\n')[0] || '';
269
+ const summary = (0, security_cjs_1.sanitizeForDisplay)(firstLine.slice(0, 100));
270
+ results.push({
271
+ filename: (0, security_cjs_1.sanitizeForDisplay)(entry.name),
272
+ priority: (0, security_cjs_1.sanitizeForDisplay)(fm.priority || ''),
273
+ area: (0, security_cjs_1.sanitizeForDisplay)(fm.area || ''),
274
+ summary,
275
+ });
276
+ }
277
+ if (mdFiles.length > 5) {
278
+ results.push({ _remainder_count: mdFiles.length - 5, filename: '', priority: '', area: '', summary: '' });
279
+ }
280
+ return results;
281
+ }
282
+ // ─── scanSeeds ────────────────────────────────────────────────────────────────
283
+ /**
284
+ * Scan .planning/seeds/SEED-*.md for unimplemented seeds.
285
+ * Unimplemented if status in ['dormant', 'active', 'triggered'].
286
+ */
287
+ function scanSeeds(planDir) {
288
+ const seedsDir = node_path_1.default.join(planDir, 'seeds');
289
+ if (!node_fs_1.default.existsSync(seedsDir))
290
+ return [];
291
+ let files;
292
+ try {
293
+ files = node_fs_1.default.readdirSync(seedsDir, { withFileTypes: true });
294
+ }
295
+ catch {
296
+ return [{ scan_error: true, seed_id: '', slug: '', status: '', title: '' }];
297
+ }
298
+ const unimplementedStatuses = new Set(['dormant', 'active', 'triggered']);
299
+ const results = [];
300
+ for (const entry of files) {
301
+ if (!entry.isFile())
302
+ continue;
303
+ if (!entry.name.startsWith('SEED-') || !entry.name.endsWith('.md'))
304
+ continue;
305
+ const filePath = node_path_1.default.join(seedsDir, entry.name);
306
+ let safeFilePath;
307
+ try {
308
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'seed file', { allowAbsolute: true });
309
+ }
310
+ catch {
311
+ continue;
312
+ }
313
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
314
+ if (content === null)
315
+ continue;
316
+ const fm = extractFrontmatter(content);
317
+ const status = (fm.status || 'dormant').toLowerCase();
318
+ if (!unimplementedStatuses.has(status))
319
+ continue;
320
+ // Extract seed_id from filename or frontmatter
321
+ const seedIdMatch = entry.name.match(/^(SEED-[\w-]+)\.md$/);
322
+ const seed_id = seedIdMatch ? seedIdMatch[1] : node_path_1.default.basename(entry.name, '.md');
323
+ const slug = (0, security_cjs_1.sanitizeForDisplay)(seed_id.replace(/^SEED-/, ''));
324
+ let title = (0, security_cjs_1.sanitizeForDisplay)(fm.title || '');
325
+ if (!title) {
326
+ const headingMatch = content.match(/^#\s*(.+)$/m);
327
+ if (headingMatch)
328
+ title = (0, security_cjs_1.sanitizeForDisplay)(headingMatch[1].trim().slice(0, 100));
329
+ }
330
+ results.push({
331
+ seed_id: (0, security_cjs_1.sanitizeForDisplay)(seed_id),
332
+ slug,
333
+ status: (0, security_cjs_1.sanitizeForDisplay)(status),
334
+ title,
335
+ });
336
+ }
337
+ return results;
338
+ }
339
+ // ─── scanUatGaps ──────────────────────────────────────────────────────────────
340
+ /**
341
+ * Scan .planning/phases for UAT gaps (UAT files with status != 'complete').
342
+ */
343
+ function scanUatGaps(planDir) {
344
+ const phasesDir = node_path_1.default.join(planDir, 'phases');
345
+ if (!node_fs_1.default.existsSync(phasesDir))
346
+ return [];
347
+ let dirs;
348
+ try {
349
+ dirs = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true })
350
+ .filter(e => e.isDirectory())
351
+ .map(e => e.name)
352
+ .sort();
353
+ }
354
+ catch {
355
+ return [{ scan_error: true, phase: '', file: '', status: '', open_scenario_count: 0 }];
356
+ }
357
+ const results = [];
358
+ for (const dir of dirs) {
359
+ const phaseDir = node_path_1.default.join(phasesDir, dir);
360
+ const phaseMatch = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
361
+ const phaseNum = phaseMatch ? phaseMatch[1] : dir;
362
+ let files;
363
+ try {
364
+ files = node_fs_1.default.readdirSync(phaseDir);
365
+ }
366
+ catch {
367
+ continue;
368
+ }
369
+ for (const file of files.filter(f => f.includes('-UAT') && f.endsWith('.md'))) {
370
+ const filePath = node_path_1.default.join(phaseDir, file);
371
+ let safeFilePath;
372
+ try {
373
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'UAT file', { allowAbsolute: true });
374
+ }
375
+ catch {
376
+ continue;
377
+ }
378
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
379
+ if (content === null)
380
+ continue;
381
+ const fm = extractFrontmatter(content);
382
+ const status = (fm.status || 'unknown').toLowerCase();
383
+ const result = (fm.result || '').toLowerCase();
384
+ // Also accept `result: all_pass` as a fallback when status is absent
385
+ // — covers UATs that omit `status:`.
386
+ if (TERMINAL_UAT_STATUSES.has(status))
387
+ continue;
388
+ if (status === 'unknown' && result === 'all_pass')
389
+ continue;
390
+ // Count open scenarios
391
+ const pendingMatches = (content.match(/result:\s*(?:pending|\[pending\])/gi) || []).length;
392
+ results.push({
393
+ phase: (0, security_cjs_1.sanitizeForDisplay)(phaseNum),
394
+ file: (0, security_cjs_1.sanitizeForDisplay)(file),
395
+ status: (0, security_cjs_1.sanitizeForDisplay)(status),
396
+ open_scenario_count: pendingMatches,
397
+ });
398
+ }
399
+ }
400
+ return results;
401
+ }
402
+ // ─── scanVerificationGaps ─────────────────────────────────────────────────────
403
+ /**
404
+ * Scan .planning/phases for VERIFICATION gaps.
405
+ */
406
+ function scanVerificationGaps(planDir) {
407
+ const phasesDir = node_path_1.default.join(planDir, 'phases');
408
+ if (!node_fs_1.default.existsSync(phasesDir))
409
+ return [];
410
+ let dirs;
411
+ try {
412
+ dirs = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true })
413
+ .filter(e => e.isDirectory())
414
+ .map(e => e.name)
415
+ .sort();
416
+ }
417
+ catch {
418
+ return [{ scan_error: true, phase: '', file: '', status: '' }];
419
+ }
420
+ const results = [];
421
+ for (const dir of dirs) {
422
+ const phaseDir = node_path_1.default.join(phasesDir, dir);
423
+ const phaseMatch = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
424
+ const phaseNum = phaseMatch ? phaseMatch[1] : dir;
425
+ let files;
426
+ try {
427
+ files = node_fs_1.default.readdirSync(phaseDir);
428
+ }
429
+ catch {
430
+ continue;
431
+ }
432
+ for (const file of files.filter(f => f.includes('-VERIFICATION') && f.endsWith('.md'))) {
433
+ const filePath = node_path_1.default.join(phaseDir, file);
434
+ let safeFilePath;
435
+ try {
436
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'VERIFICATION file', { allowAbsolute: true });
437
+ }
438
+ catch {
439
+ continue;
440
+ }
441
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
442
+ if (content === null)
443
+ continue;
444
+ const fm = extractFrontmatter(content);
445
+ const status = (fm.status || 'unknown').toLowerCase();
446
+ if (status !== 'gaps_found' && status !== 'human_needed')
447
+ continue;
448
+ results.push({
449
+ phase: (0, security_cjs_1.sanitizeForDisplay)(phaseNum),
450
+ file: (0, security_cjs_1.sanitizeForDisplay)(file),
451
+ status: (0, security_cjs_1.sanitizeForDisplay)(status),
452
+ });
453
+ }
454
+ }
455
+ return results;
456
+ }
457
+ // ─── scanContextQuestions ─────────────────────────────────────────────────────
458
+ /**
459
+ * Scan .planning/phases for CONTEXT files with open_questions.
460
+ */
461
+ function scanContextQuestions(planDir) {
462
+ const phasesDir = node_path_1.default.join(planDir, 'phases');
463
+ if (!node_fs_1.default.existsSync(phasesDir))
464
+ return [];
465
+ let dirs;
466
+ try {
467
+ dirs = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true })
468
+ .filter(e => e.isDirectory())
469
+ .map(e => e.name)
470
+ .sort();
471
+ }
472
+ catch {
473
+ return [{ scan_error: true, phase: '', file: '', question_count: 0, questions: [] }];
474
+ }
475
+ const results = [];
476
+ for (const dir of dirs) {
477
+ const phaseDir = node_path_1.default.join(phasesDir, dir);
478
+ const phaseMatch = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
479
+ const phaseNum = phaseMatch ? phaseMatch[1] : dir;
480
+ let files;
481
+ try {
482
+ files = node_fs_1.default.readdirSync(phaseDir);
483
+ }
484
+ catch {
485
+ continue;
486
+ }
487
+ for (const file of files.filter(f => f.includes('-CONTEXT') && f.endsWith('.md'))) {
488
+ const filePath = node_path_1.default.join(phaseDir, file);
489
+ let safeFilePath;
490
+ try {
491
+ safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'CONTEXT file', { allowAbsolute: true });
492
+ }
493
+ catch {
494
+ continue;
495
+ }
496
+ const content = (0, shell_command_projection_cjs_1.platformReadSync)(safeFilePath);
497
+ if (content === null)
498
+ continue;
499
+ const fm = extractFrontmatter(content);
500
+ // Check frontmatter open_questions field
501
+ let questions = [];
502
+ if (fm.open_questions) {
503
+ if (Array.isArray(fm.open_questions) && fm.open_questions.length > 0) {
504
+ questions = fm.open_questions.map(q => (0, security_cjs_1.sanitizeForDisplay)(String(q).slice(0, 200)));
505
+ }
506
+ }
507
+ // Also check for ## Open Questions section in body
508
+ if (questions.length === 0) {
509
+ const oqMatch = content.match(/##\s*Open Questions[^\n]*\n([\s\S]*?)(?=\n##\s|$)/i);
510
+ if (oqMatch) {
511
+ const oqBody = oqMatch[1].trim();
512
+ if (oqBody && oqBody.length > 0 && !/^\s*none\s*$/i.test(oqBody)) {
513
+ const items = oqBody.split('\n')
514
+ .map((l) => l.trim())
515
+ .filter((l) => l && l !== '-' && l !== '*')
516
+ .filter((l) => /^[-*\d]/.test(l) || l.includes('?'));
517
+ questions = items.slice(0, 3).map((q) => (0, security_cjs_1.sanitizeForDisplay)(q.slice(0, 200)));
518
+ }
519
+ }
520
+ }
521
+ if (questions.length === 0)
522
+ continue;
523
+ results.push({
524
+ phase: (0, security_cjs_1.sanitizeForDisplay)(phaseNum),
525
+ file: (0, security_cjs_1.sanitizeForDisplay)(file),
526
+ question_count: questions.length,
527
+ questions: questions.slice(0, 3),
528
+ });
529
+ }
530
+ }
531
+ return results;
532
+ }
533
+ // ─── auditOpenArtifacts ───────────────────────────────────────────────────────
534
+ /**
535
+ * Main audit function. Scans all .planning/ artifact categories.
536
+ *
537
+ * @param cwd - Project root directory
538
+ * @returns Structured audit result
539
+ */
540
+ function auditOpenArtifacts(cwd) {
541
+ const planDir = planningDir(cwd);
542
+ const debugSessions = (() => {
543
+ try {
544
+ return scanDebugSessions(planDir);
545
+ }
546
+ catch {
547
+ return [{ scan_error: true, slug: '', status: '', updated: '', hypothesis: '' }];
548
+ }
549
+ })();
550
+ const quickTasks = (() => {
551
+ try {
552
+ return scanQuickTasks(planDir);
553
+ }
554
+ catch {
555
+ return [{ scan_error: true, slug: '', date: '', status: '', description: '' }];
556
+ }
557
+ })();
558
+ const threads = (() => {
559
+ try {
560
+ return scanThreads(planDir);
561
+ }
562
+ catch {
563
+ return [{ scan_error: true, slug: '', status: '', updated: '', title: '' }];
564
+ }
565
+ })();
566
+ const todos = (() => {
567
+ try {
568
+ return scanTodos(planDir);
569
+ }
570
+ catch {
571
+ return [{ scan_error: true, filename: '', priority: '', area: '', summary: '' }];
572
+ }
573
+ })();
574
+ const seeds = (() => {
575
+ try {
576
+ return scanSeeds(planDir);
577
+ }
578
+ catch {
579
+ return [{ scan_error: true, seed_id: '', slug: '', status: '', title: '' }];
580
+ }
581
+ })();
582
+ const uatGaps = (() => {
583
+ try {
584
+ return scanUatGaps(planDir);
585
+ }
586
+ catch {
587
+ return [{ scan_error: true, phase: '', file: '', status: '', open_scenario_count: 0 }];
588
+ }
589
+ })();
590
+ const verificationGaps = (() => {
591
+ try {
592
+ return scanVerificationGaps(planDir);
593
+ }
594
+ catch {
595
+ return [{ scan_error: true, phase: '', file: '', status: '' }];
596
+ }
597
+ })();
598
+ const contextQuestions = (() => {
599
+ try {
600
+ return scanContextQuestions(planDir);
601
+ }
602
+ catch {
603
+ return [{ scan_error: true, phase: '', file: '', question_count: 0, questions: [] }];
604
+ }
605
+ })();
606
+ // Count real items (not scan_error sentinels)
607
+ const countReal = (arr) => arr.filter(i => !i.scan_error && !i._remainder_count).length;
608
+ const counts = {
609
+ debug_sessions: countReal(debugSessions),
610
+ quick_tasks: countReal(quickTasks),
611
+ threads: countReal(threads),
612
+ todos: countReal(todos),
613
+ seeds: countReal(seeds),
614
+ uat_gaps: countReal(uatGaps),
615
+ verification_gaps: countReal(verificationGaps),
616
+ context_questions: countReal(contextQuestions),
617
+ total: 0,
618
+ };
619
+ counts.total = counts.debug_sessions + counts.quick_tasks + counts.threads + counts.todos + counts.seeds + counts.uat_gaps + counts.verification_gaps + counts.context_questions;
620
+ return {
621
+ scanned_at: new Date().toISOString(),
622
+ has_open_items: counts.total > 0,
623
+ counts,
624
+ items: {
625
+ debug_sessions: debugSessions,
626
+ quick_tasks: quickTasks,
627
+ threads,
628
+ todos,
629
+ seeds,
630
+ uat_gaps: uatGaps,
631
+ verification_gaps: verificationGaps,
632
+ context_questions: contextQuestions,
633
+ },
634
+ };
635
+ }
636
+ // ─── formatAuditReport ────────────────────────────────────────────────────────
637
+ /**
638
+ * Format the audit result as a human-readable report.
639
+ *
640
+ * @param auditResult - Result from auditOpenArtifacts()
641
+ * @returns Formatted report
642
+ */
643
+ function formatAuditReport(auditResult) {
644
+ const { counts, items, has_open_items } = auditResult;
645
+ const lines = [];
646
+ const hr = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━';
647
+ lines.push(hr);
648
+ lines.push(' Milestone Close: Open Artifact Audit');
649
+ lines.push(hr);
650
+ if (!has_open_items) {
651
+ lines.push('');
652
+ lines.push(' All artifact types clear. Safe to proceed.');
653
+ lines.push('');
654
+ lines.push(hr);
655
+ return lines.join('\n');
656
+ }
657
+ // Debug sessions (blocking quality — red)
658
+ if (counts.debug_sessions > 0) {
659
+ lines.push('');
660
+ lines.push(`🔴 Debug Sessions (${counts.debug_sessions} open)`);
661
+ for (const item of items.debug_sessions.filter(i => !i.scan_error)) {
662
+ const hyp = item.hypothesis ? ` — ${item.hypothesis}` : '';
663
+ lines.push(` • ${item.slug} [${item.status}]${hyp}`);
664
+ }
665
+ }
666
+ // UAT gaps (blocking quality — red)
667
+ if (counts.uat_gaps > 0) {
668
+ lines.push('');
669
+ lines.push(`🔴 UAT Gaps (${counts.uat_gaps} phases with incomplete UAT)`);
670
+ for (const item of items.uat_gaps.filter(i => !i.scan_error)) {
671
+ lines.push(` • Phase ${item.phase}: ${item.file} [${item.status}] — ${item.open_scenario_count} pending scenarios`);
672
+ }
673
+ }
674
+ // Verification gaps (blocking quality — red)
675
+ if (counts.verification_gaps > 0) {
676
+ lines.push('');
677
+ lines.push(`🔴 Verification Gaps (${counts.verification_gaps} unresolved)`);
678
+ for (const item of items.verification_gaps.filter(i => !i.scan_error)) {
679
+ lines.push(` • Phase ${item.phase}: ${item.file} [${item.status}]`);
680
+ }
681
+ }
682
+ // Quick tasks (incomplete work — yellow)
683
+ if (counts.quick_tasks > 0) {
684
+ lines.push('');
685
+ lines.push(`🟡 Quick Tasks (${counts.quick_tasks} incomplete)`);
686
+ for (const item of items.quick_tasks.filter(i => !i.scan_error)) {
687
+ const d = item.date ? ` (${item.date})` : '';
688
+ lines.push(` • ${item.slug}${d} [${item.status}]`);
689
+ }
690
+ }
691
+ // Todos (incomplete work — yellow)
692
+ if (counts.todos > 0) {
693
+ const realTodos = items.todos.filter(i => !i.scan_error && !i._remainder_count);
694
+ const remainder = items.todos.find(i => i._remainder_count);
695
+ lines.push('');
696
+ lines.push(`🟡 Pending Todos (${counts.todos} pending)`);
697
+ for (const item of realTodos) {
698
+ const area = item.area ? ` [${item.area}]` : '';
699
+ const pri = item.priority ? ` (${item.priority})` : '';
700
+ lines.push(` • ${item.filename}${area}${pri}`);
701
+ if (item.summary)
702
+ lines.push(` ${item.summary}`);
703
+ }
704
+ if (remainder) {
705
+ lines.push(` ... and ${remainder._remainder_count} more`);
706
+ }
707
+ }
708
+ // Threads (deferred decisions — blue)
709
+ if (counts.threads > 0) {
710
+ lines.push('');
711
+ lines.push(`🔵 Open Threads (${counts.threads} active)`);
712
+ for (const item of items.threads.filter(i => !i.scan_error)) {
713
+ const title = item.title ? ` — ${item.title}` : '';
714
+ lines.push(` • ${item.slug} [${item.status}]${title}`);
715
+ }
716
+ }
717
+ // Seeds (deferred decisions — blue)
718
+ if (counts.seeds > 0) {
719
+ lines.push('');
720
+ lines.push(`🔵 Unimplemented Seeds (${counts.seeds} pending)`);
721
+ for (const item of items.seeds.filter(i => !i.scan_error)) {
722
+ const title = item.title ? ` — ${item.title}` : '';
723
+ lines.push(` • ${item.seed_id} [${item.status}]${title}`);
724
+ }
725
+ }
726
+ // Context questions (deferred decisions — blue)
727
+ if (counts.context_questions > 0) {
728
+ lines.push('');
729
+ lines.push(`🔵 CONTEXT Open Questions (${counts.context_questions} phases with open questions)`);
730
+ for (const item of items.context_questions.filter(i => !i.scan_error)) {
731
+ lines.push(` • Phase ${item.phase}: ${item.file} (${item.question_count} question${item.question_count !== 1 ? 's' : ''})`);
732
+ for (const q of item.questions) {
733
+ lines.push(` - ${q}`);
734
+ }
735
+ }
736
+ }
737
+ lines.push('');
738
+ lines.push(hr);
739
+ lines.push(` ${counts.total} item${counts.total !== 1 ? 's' : ''} require decisions before close.`);
740
+ lines.push(hr);
741
+ return lines.join('\n');
742
+ }
743
+ module.exports = { auditOpenArtifacts, formatAuditReport };