@opengsd/gsd-core 1.2.0-rc.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 (503) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja-JP.md +870 -0
  3. package/README.ko-KR.md +861 -0
  4. package/README.md +301 -0
  5. package/README.pt-BR.md +492 -0
  6. package/README.zh-CN.md +842 -0
  7. package/agents/gsd-advisor-researcher.md +127 -0
  8. package/agents/gsd-ai-researcher.md +133 -0
  9. package/agents/gsd-assumptions-analyzer.md +105 -0
  10. package/agents/gsd-code-fixer.md +668 -0
  11. package/agents/gsd-code-reviewer.md +387 -0
  12. package/agents/gsd-codebase-mapper.md +853 -0
  13. package/agents/gsd-debug-session-manager.md +314 -0
  14. package/agents/gsd-debugger.md +1452 -0
  15. package/agents/gsd-doc-classifier.md +168 -0
  16. package/agents/gsd-doc-synthesizer.md +204 -0
  17. package/agents/gsd-doc-verifier.md +217 -0
  18. package/agents/gsd-doc-writer.md +615 -0
  19. package/agents/gsd-domain-researcher.md +153 -0
  20. package/agents/gsd-eval-auditor.md +191 -0
  21. package/agents/gsd-eval-planner.md +154 -0
  22. package/agents/gsd-executor.md +772 -0
  23. package/agents/gsd-framework-selector.md +160 -0
  24. package/agents/gsd-integration-checker.md +470 -0
  25. package/agents/gsd-intel-updater.md +342 -0
  26. package/agents/gsd-nyquist-auditor.md +203 -0
  27. package/agents/gsd-pattern-mapper.md +335 -0
  28. package/agents/gsd-phase-researcher.md +928 -0
  29. package/agents/gsd-plan-checker.md +978 -0
  30. package/agents/gsd-planner.md +1218 -0
  31. package/agents/gsd-project-researcher.md +677 -0
  32. package/agents/gsd-research-synthesizer.md +255 -0
  33. package/agents/gsd-roadmapper.md +688 -0
  34. package/agents/gsd-security-auditor.md +155 -0
  35. package/agents/gsd-ui-auditor.md +495 -0
  36. package/agents/gsd-ui-checker.md +309 -0
  37. package/agents/gsd-ui-researcher.md +380 -0
  38. package/agents/gsd-user-profiler.md +171 -0
  39. package/agents/gsd-verifier.md +917 -0
  40. package/bin/install.js +10936 -0
  41. package/bin/lib/ui-safety-gate.cjs +107 -0
  42. package/commands/gsd/add-tests.md +42 -0
  43. package/commands/gsd/ai-integration-phase.md +37 -0
  44. package/commands/gsd/audit-fix.md +34 -0
  45. package/commands/gsd/audit-milestone.md +37 -0
  46. package/commands/gsd/audit-uat.md +24 -0
  47. package/commands/gsd/autonomous.md +46 -0
  48. package/commands/gsd/capture.md +62 -0
  49. package/commands/gsd/cleanup.md +24 -0
  50. package/commands/gsd/code-review.md +59 -0
  51. package/commands/gsd/complete-milestone.md +143 -0
  52. package/commands/gsd/config.md +56 -0
  53. package/commands/gsd/debug.md +52 -0
  54. package/commands/gsd/discuss-phase.md +76 -0
  55. package/commands/gsd/docs-update.md +49 -0
  56. package/commands/gsd/eval-review.md +33 -0
  57. package/commands/gsd/execute-phase.md +64 -0
  58. package/commands/gsd/explore.md +27 -0
  59. package/commands/gsd/extract-learnings.md +23 -0
  60. package/commands/gsd/fast.md +31 -0
  61. package/commands/gsd/forensics.md +57 -0
  62. package/commands/gsd/graphify.md +199 -0
  63. package/commands/gsd/health.md +31 -0
  64. package/commands/gsd/help.md +28 -0
  65. package/commands/gsd/import.md +41 -0
  66. package/commands/gsd/inbox.md +39 -0
  67. package/commands/gsd/ingest-docs.md +42 -0
  68. package/commands/gsd/manager.md +45 -0
  69. package/commands/gsd/map-codebase.md +83 -0
  70. package/commands/gsd/milestone-summary.md +51 -0
  71. package/commands/gsd/mvp-phase.md +45 -0
  72. package/commands/gsd/new-milestone.md +45 -0
  73. package/commands/gsd/new-project.md +47 -0
  74. package/commands/gsd/ns-context.md +23 -0
  75. package/commands/gsd/ns-ideate.md +24 -0
  76. package/commands/gsd/ns-manage.md +29 -0
  77. package/commands/gsd/ns-project.md +22 -0
  78. package/commands/gsd/ns-review.md +26 -0
  79. package/commands/gsd/ns-workflow.md +28 -0
  80. package/commands/gsd/pause-work.md +43 -0
  81. package/commands/gsd/phase.md +56 -0
  82. package/commands/gsd/plan-phase.md +62 -0
  83. package/commands/gsd/plan-review-convergence.md +59 -0
  84. package/commands/gsd/pr-branch.md +26 -0
  85. package/commands/gsd/profile-user.md +46 -0
  86. package/commands/gsd/progress.md +47 -0
  87. package/commands/gsd/quick.md +174 -0
  88. package/commands/gsd/resume-work.md +30 -0
  89. package/commands/gsd/review-backlog.md +63 -0
  90. package/commands/gsd/review.md +41 -0
  91. package/commands/gsd/secure-phase.md +36 -0
  92. package/commands/gsd/settings.md +29 -0
  93. package/commands/gsd/ship.md +24 -0
  94. package/commands/gsd/sketch.md +60 -0
  95. package/commands/gsd/spec-phase.md +63 -0
  96. package/commands/gsd/spike.md +57 -0
  97. package/commands/gsd/stats.md +19 -0
  98. package/commands/gsd/surface.md +155 -0
  99. package/commands/gsd/thread.md +24 -0
  100. package/commands/gsd/ui-phase.md +35 -0
  101. package/commands/gsd/ui-review.md +33 -0
  102. package/commands/gsd/ultraplan-phase.md +34 -0
  103. package/commands/gsd/undo.md +35 -0
  104. package/commands/gsd/update.md +48 -0
  105. package/commands/gsd/validate-phase.md +36 -0
  106. package/commands/gsd/verify-work.md +39 -0
  107. package/commands/gsd/workspace.md +52 -0
  108. package/commands/gsd/workstreams.md +70 -0
  109. package/get-shit-done/bin/check-latest-version.cjs +106 -0
  110. package/get-shit-done/bin/gsd-tools.cjs +1676 -0
  111. package/get-shit-done/bin/lib/active-workstream-store.cjs +302 -0
  112. package/get-shit-done/bin/lib/adr-parser.cjs +394 -0
  113. package/get-shit-done/bin/lib/agent-command-router.cjs +65 -0
  114. package/get-shit-done/bin/lib/artifacts.cjs +53 -0
  115. package/get-shit-done/bin/lib/audit.cjs +755 -0
  116. package/get-shit-done/bin/lib/check-command-router.cjs +333 -0
  117. package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +118 -0
  118. package/get-shit-done/bin/lib/clock.cjs +96 -0
  119. package/get-shit-done/bin/lib/clusters.cjs +135 -0
  120. package/get-shit-done/bin/lib/code-review-flags.cjs +74 -0
  121. package/get-shit-done/bin/lib/command-aliases.cjs +815 -0
  122. package/get-shit-done/bin/lib/command-arg-projection.cjs +62 -0
  123. package/get-shit-done/bin/lib/command-routing-hub.cjs +388 -0
  124. package/get-shit-done/bin/lib/commands.cjs +1188 -0
  125. package/get-shit-done/bin/lib/config-schema.cjs +31 -0
  126. package/get-shit-done/bin/lib/config.cjs +728 -0
  127. package/get-shit-done/bin/lib/configuration.cjs +248 -0
  128. package/get-shit-done/bin/lib/context-utilization.cjs +47 -0
  129. package/get-shit-done/bin/lib/core.cjs +2121 -0
  130. package/get-shit-done/bin/lib/decisions.cjs +116 -0
  131. package/get-shit-done/bin/lib/docs.cjs +270 -0
  132. package/get-shit-done/bin/lib/drift.cjs +388 -0
  133. package/get-shit-done/bin/lib/fallow-runner.cjs +109 -0
  134. package/get-shit-done/bin/lib/frontmatter.cjs +389 -0
  135. package/get-shit-done/bin/lib/gap-checker.cjs +205 -0
  136. package/get-shit-done/bin/lib/graphify.cjs +592 -0
  137. package/get-shit-done/bin/lib/gsd2-import.cjs +514 -0
  138. package/get-shit-done/bin/lib/init-command-router.cjs +58 -0
  139. package/get-shit-done/bin/lib/init.cjs +2112 -0
  140. package/get-shit-done/bin/lib/install-profiles.cjs +603 -0
  141. package/get-shit-done/bin/lib/installer-migration-authoring.cjs +117 -0
  142. package/get-shit-done/bin/lib/installer-migration-report.cjs +354 -0
  143. package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +220 -0
  144. package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +41 -0
  145. package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +80 -0
  146. package/get-shit-done/bin/lib/installer-migrations.cjs +778 -0
  147. package/get-shit-done/bin/lib/intel.cjs +708 -0
  148. package/get-shit-done/bin/lib/learnings.cjs +421 -0
  149. package/get-shit-done/bin/lib/milestone.cjs +314 -0
  150. package/get-shit-done/bin/lib/model-catalog.cjs +212 -0
  151. package/get-shit-done/bin/lib/model-profiles.cjs +31 -0
  152. package/get-shit-done/bin/lib/observability/event.cjs +82 -0
  153. package/get-shit-done/bin/lib/observability/logger.cjs +174 -0
  154. package/get-shit-done/bin/lib/observability/redaction.cjs +50 -0
  155. package/get-shit-done/bin/lib/package-identity.cjs +31 -0
  156. package/get-shit-done/bin/lib/phase-command-router.cjs +191 -0
  157. package/get-shit-done/bin/lib/phase-lifecycle.cjs +80 -0
  158. package/get-shit-done/bin/lib/phase.cjs +1607 -0
  159. package/get-shit-done/bin/lib/phases-command-router.cjs +39 -0
  160. package/get-shit-done/bin/lib/plan-scan.cjs +97 -0
  161. package/get-shit-done/bin/lib/planning-workspace.cjs +238 -0
  162. package/get-shit-done/bin/lib/profile-output.cjs +1141 -0
  163. package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
  164. package/get-shit-done/bin/lib/project-root.cjs +112 -0
  165. package/get-shit-done/bin/lib/prompt-budget.cjs +399 -0
  166. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +125 -0
  167. package/get-shit-done/bin/lib/roadmap-command-router.cjs +28 -0
  168. package/get-shit-done/bin/lib/roadmap.cjs +650 -0
  169. package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +301 -0
  170. package/get-shit-done/bin/lib/runtime-homes.cjs +222 -0
  171. package/get-shit-done/bin/lib/runtime-name-policy.cjs +83 -0
  172. package/get-shit-done/bin/lib/runtime-slash.cjs +112 -0
  173. package/get-shit-done/bin/lib/schema-detect.cjs +165 -0
  174. package/get-shit-done/bin/lib/secrets.cjs +32 -0
  175. package/get-shit-done/bin/lib/security.cjs +600 -0
  176. package/get-shit-done/bin/lib/semver-compare.cjs +35 -0
  177. package/get-shit-done/bin/lib/shell-command-projection.cjs +500 -0
  178. package/get-shit-done/bin/lib/state-command-router.cjs +252 -0
  179. package/get-shit-done/bin/lib/state-document.cjs +263 -0
  180. package/get-shit-done/bin/lib/state.cjs +2038 -0
  181. package/get-shit-done/bin/lib/surface.cjs +470 -0
  182. package/get-shit-done/bin/lib/task-command-router.cjs +81 -0
  183. package/get-shit-done/bin/lib/template.cjs +228 -0
  184. package/get-shit-done/bin/lib/uat.cjs +289 -0
  185. package/get-shit-done/bin/lib/update-context.cjs +209 -0
  186. package/get-shit-done/bin/lib/validate-command-router.cjs +83 -0
  187. package/get-shit-done/bin/lib/validate.cjs +92 -0
  188. package/get-shit-done/bin/lib/verify-command-router.cjs +40 -0
  189. package/get-shit-done/bin/lib/verify.cjs +1511 -0
  190. package/get-shit-done/bin/lib/workstream-inventory-builder.cjs +74 -0
  191. package/get-shit-done/bin/lib/workstream-inventory.cjs +146 -0
  192. package/get-shit-done/bin/lib/workstream-name-policy.cjs +94 -0
  193. package/get-shit-done/bin/lib/workstream.cjs +389 -0
  194. package/get-shit-done/bin/lib/worktree-safety.cjs +985 -0
  195. package/get-shit-done/bin/shared/config-defaults.manifest.json +97 -0
  196. package/get-shit-done/bin/shared/config-schema.manifest.json +175 -0
  197. package/get-shit-done/bin/shared/model-catalog.json +122 -0
  198. package/get-shit-done/bin/shared/runtime-aliases.manifest.json +75 -0
  199. package/get-shit-done/bin/verify-reapply-patches.cjs +352 -0
  200. package/get-shit-done/contexts/dev.md +21 -0
  201. package/get-shit-done/contexts/research.md +22 -0
  202. package/get-shit-done/contexts/review.md +23 -0
  203. package/get-shit-done/references/agent-contracts.md +79 -0
  204. package/get-shit-done/references/ai-evals.md +156 -0
  205. package/get-shit-done/references/ai-frameworks.md +186 -0
  206. package/get-shit-done/references/artifact-types.md +131 -0
  207. package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
  208. package/get-shit-done/references/checkpoints.md +814 -0
  209. package/get-shit-done/references/common-bug-patterns.md +114 -0
  210. package/get-shit-done/references/context-budget.md +85 -0
  211. package/get-shit-done/references/continuation-format.md +253 -0
  212. package/get-shit-done/references/debugger-philosophy.md +76 -0
  213. package/get-shit-done/references/decimal-phase-calculation.md +64 -0
  214. package/get-shit-done/references/doc-conflict-engine.md +91 -0
  215. package/get-shit-done/references/domain-probes.md +125 -0
  216. package/get-shit-done/references/execute-mvp-tdd.md +81 -0
  217. package/get-shit-done/references/executor-examples.md +110 -0
  218. package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
  219. package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
  220. package/get-shit-done/references/gate-prompts.md +100 -0
  221. package/get-shit-done/references/gates.md +70 -0
  222. package/get-shit-done/references/git-integration.md +298 -0
  223. package/get-shit-done/references/git-planning-commit.md +40 -0
  224. package/get-shit-done/references/ios-scaffold.md +123 -0
  225. package/get-shit-done/references/mandatory-initial-read.md +2 -0
  226. package/get-shit-done/references/model-profile-resolution.md +38 -0
  227. package/get-shit-done/references/model-profiles.md +245 -0
  228. package/get-shit-done/references/mvp-concepts.md +49 -0
  229. package/get-shit-done/references/phase-argument-parsing.md +61 -0
  230. package/get-shit-done/references/planner-antipatterns.md +89 -0
  231. package/get-shit-done/references/planner-chunked.md +49 -0
  232. package/get-shit-done/references/planner-gap-closure.md +62 -0
  233. package/get-shit-done/references/planner-graphify-auto-update.md +67 -0
  234. package/get-shit-done/references/planner-human-verify-mode.md +57 -0
  235. package/get-shit-done/references/planner-interface-context.md +62 -0
  236. package/get-shit-done/references/planner-mvp-mode.md +53 -0
  237. package/get-shit-done/references/planner-reviews.md +39 -0
  238. package/get-shit-done/references/planner-revision.md +87 -0
  239. package/get-shit-done/references/planner-source-audit.md +73 -0
  240. package/get-shit-done/references/planning-config.md +471 -0
  241. package/get-shit-done/references/project-skills-discovery.md +19 -0
  242. package/get-shit-done/references/questioning.md +162 -0
  243. package/get-shit-done/references/revision-loop.md +97 -0
  244. package/get-shit-done/references/scout-codebase.md +51 -0
  245. package/get-shit-done/references/skeleton-template.md +48 -0
  246. package/get-shit-done/references/sketch-interactivity.md +41 -0
  247. package/get-shit-done/references/sketch-theme-system.md +94 -0
  248. package/get-shit-done/references/sketch-tooling.md +45 -0
  249. package/get-shit-done/references/sketch-variant-patterns.md +81 -0
  250. package/get-shit-done/references/spidr-splitting.md +69 -0
  251. package/get-shit-done/references/tdd.md +330 -0
  252. package/get-shit-done/references/thinking-models-debug.md +44 -0
  253. package/get-shit-done/references/thinking-models-execution.md +50 -0
  254. package/get-shit-done/references/thinking-models-planning.md +62 -0
  255. package/get-shit-done/references/thinking-models-research.md +50 -0
  256. package/get-shit-done/references/thinking-models-verification.md +55 -0
  257. package/get-shit-done/references/thinking-partner.md +96 -0
  258. package/get-shit-done/references/ui-brand.md +160 -0
  259. package/get-shit-done/references/universal-anti-patterns.md +63 -0
  260. package/get-shit-done/references/user-profiling.md +681 -0
  261. package/get-shit-done/references/user-story-template.md +58 -0
  262. package/get-shit-done/references/verification-overrides.md +227 -0
  263. package/get-shit-done/references/verification-patterns.md +612 -0
  264. package/get-shit-done/references/verify-mvp-mode.md +85 -0
  265. package/get-shit-done/references/workstream-flag.md +111 -0
  266. package/get-shit-done/references/worktree-path-safety.md +89 -0
  267. package/get-shit-done/templates/AI-SPEC.md +246 -0
  268. package/get-shit-done/templates/DEBUG.md +169 -0
  269. package/get-shit-done/templates/README.md +77 -0
  270. package/get-shit-done/templates/SECURITY.md +61 -0
  271. package/get-shit-done/templates/UAT.md +265 -0
  272. package/get-shit-done/templates/UI-SPEC.md +100 -0
  273. package/get-shit-done/templates/VALIDATION.md +76 -0
  274. package/get-shit-done/templates/claude-md.md +145 -0
  275. package/get-shit-done/templates/codebase/architecture.md +255 -0
  276. package/get-shit-done/templates/codebase/concerns.md +310 -0
  277. package/get-shit-done/templates/codebase/conventions.md +307 -0
  278. package/get-shit-done/templates/codebase/integrations.md +280 -0
  279. package/get-shit-done/templates/codebase/stack.md +186 -0
  280. package/get-shit-done/templates/codebase/structure.md +285 -0
  281. package/get-shit-done/templates/codebase/testing.md +480 -0
  282. package/get-shit-done/templates/config.json +62 -0
  283. package/get-shit-done/templates/context.md +352 -0
  284. package/get-shit-done/templates/continue-here.md +78 -0
  285. package/get-shit-done/templates/copilot-instructions.md +7 -0
  286. package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
  287. package/get-shit-done/templates/dev-preferences.md +21 -0
  288. package/get-shit-done/templates/discovery.md +146 -0
  289. package/get-shit-done/templates/discussion-log.md +63 -0
  290. package/get-shit-done/templates/milestone-archive.md +123 -0
  291. package/get-shit-done/templates/milestone.md +115 -0
  292. package/get-shit-done/templates/phase-prompt.md +610 -0
  293. package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
  294. package/get-shit-done/templates/project.md +186 -0
  295. package/get-shit-done/templates/requirements.md +231 -0
  296. package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
  297. package/get-shit-done/templates/research-project/FEATURES.md +147 -0
  298. package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
  299. package/get-shit-done/templates/research-project/STACK.md +120 -0
  300. package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
  301. package/get-shit-done/templates/research.md +592 -0
  302. package/get-shit-done/templates/retrospective.md +54 -0
  303. package/get-shit-done/templates/roadmap.md +202 -0
  304. package/get-shit-done/templates/spec.md +307 -0
  305. package/get-shit-done/templates/state.md +195 -0
  306. package/get-shit-done/templates/summary-complex.md +59 -0
  307. package/get-shit-done/templates/summary-minimal.md +41 -0
  308. package/get-shit-done/templates/summary-standard.md +48 -0
  309. package/get-shit-done/templates/summary.md +248 -0
  310. package/get-shit-done/templates/user-profile.md +146 -0
  311. package/get-shit-done/templates/user-setup.md +311 -0
  312. package/get-shit-done/templates/verification-report.md +322 -0
  313. package/get-shit-done/workflows/_runtime-launcher.snippet.sh +1 -0
  314. package/get-shit-done/workflows/add-backlog.md +91 -0
  315. package/get-shit-done/workflows/add-phase.md +113 -0
  316. package/get-shit-done/workflows/add-tests.md +355 -0
  317. package/get-shit-done/workflows/add-todo.md +161 -0
  318. package/get-shit-done/workflows/ai-integration-phase.md +295 -0
  319. package/get-shit-done/workflows/analyze-dependencies.md +96 -0
  320. package/get-shit-done/workflows/audit-fix.md +178 -0
  321. package/get-shit-done/workflows/audit-milestone.md +358 -0
  322. package/get-shit-done/workflows/audit-uat.md +110 -0
  323. package/get-shit-done/workflows/autonomous.md +795 -0
  324. package/get-shit-done/workflows/check-todos.md +180 -0
  325. package/get-shit-done/workflows/cleanup.md +155 -0
  326. package/get-shit-done/workflows/code-review-fix.md +502 -0
  327. package/get-shit-done/workflows/code-review.md +656 -0
  328. package/get-shit-done/workflows/complete-milestone.md +855 -0
  329. package/get-shit-done/workflows/debug.md +232 -0
  330. package/get-shit-done/workflows/diagnose-issues.md +241 -0
  331. package/get-shit-done/workflows/discovery-phase.md +291 -0
  332. package/get-shit-done/workflows/discuss-phase/modes/advisor.md +176 -0
  333. package/get-shit-done/workflows/discuss-phase/modes/all.md +28 -0
  334. package/get-shit-done/workflows/discuss-phase/modes/analyze.md +44 -0
  335. package/get-shit-done/workflows/discuss-phase/modes/auto.md +57 -0
  336. package/get-shit-done/workflows/discuss-phase/modes/batch.md +52 -0
  337. package/get-shit-done/workflows/discuss-phase/modes/chain.md +98 -0
  338. package/get-shit-done/workflows/discuss-phase/modes/default.md +141 -0
  339. package/get-shit-done/workflows/discuss-phase/modes/power.md +44 -0
  340. package/get-shit-done/workflows/discuss-phase/modes/text.md +55 -0
  341. package/get-shit-done/workflows/discuss-phase/templates/checkpoint.json +18 -0
  342. package/get-shit-done/workflows/discuss-phase/templates/context.md +136 -0
  343. package/get-shit-done/workflows/discuss-phase/templates/discussion-log.md +50 -0
  344. package/get-shit-done/workflows/discuss-phase-assumptions.md +675 -0
  345. package/get-shit-done/workflows/discuss-phase-power.md +291 -0
  346. package/get-shit-done/workflows/discuss-phase.md +499 -0
  347. package/get-shit-done/workflows/do.md +111 -0
  348. package/get-shit-done/workflows/docs-update.md +1162 -0
  349. package/get-shit-done/workflows/edit-phase.md +295 -0
  350. package/get-shit-done/workflows/eval-review.md +156 -0
  351. package/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +82 -0
  352. package/get-shit-done/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  353. package/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md +117 -0
  354. package/get-shit-done/workflows/execute-phase.md +1709 -0
  355. package/get-shit-done/workflows/execute-plan.md +526 -0
  356. package/get-shit-done/workflows/explore.md +144 -0
  357. package/get-shit-done/workflows/extract-learnings.md +243 -0
  358. package/get-shit-done/workflows/fast.md +124 -0
  359. package/get-shit-done/workflows/forensics.md +279 -0
  360. package/get-shit-done/workflows/graduation.md +196 -0
  361. package/get-shit-done/workflows/health.md +224 -0
  362. package/get-shit-done/workflows/help/modes/brief.md +22 -0
  363. package/get-shit-done/workflows/help/modes/default.md +50 -0
  364. package/get-shit-done/workflows/help/modes/full.md +784 -0
  365. package/get-shit-done/workflows/help/modes/topic.md +74 -0
  366. package/get-shit-done/workflows/help.md +24 -0
  367. package/get-shit-done/workflows/import.md +254 -0
  368. package/get-shit-done/workflows/inbox.md +387 -0
  369. package/get-shit-done/workflows/ingest-docs.md +339 -0
  370. package/get-shit-done/workflows/insert-phase.md +152 -0
  371. package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
  372. package/get-shit-done/workflows/list-workspaces.md +57 -0
  373. package/get-shit-done/workflows/manager.md +393 -0
  374. package/get-shit-done/workflows/map-codebase.md +444 -0
  375. package/get-shit-done/workflows/milestone-summary.md +224 -0
  376. package/get-shit-done/workflows/mvp-phase.md +222 -0
  377. package/get-shit-done/workflows/new-milestone.md +635 -0
  378. package/get-shit-done/workflows/new-project.md +1555 -0
  379. package/get-shit-done/workflows/new-workspace.md +240 -0
  380. package/get-shit-done/workflows/next.md +299 -0
  381. package/get-shit-done/workflows/node-repair.md +92 -0
  382. package/get-shit-done/workflows/note.md +158 -0
  383. package/get-shit-done/workflows/pause-work.md +244 -0
  384. package/get-shit-done/workflows/plan-milestone-gaps.md +281 -0
  385. package/get-shit-done/workflows/plan-phase.md +1809 -0
  386. package/get-shit-done/workflows/plan-review-convergence.md +346 -0
  387. package/get-shit-done/workflows/plant-seed.md +230 -0
  388. package/get-shit-done/workflows/pr-branch.md +157 -0
  389. package/get-shit-done/workflows/profile-user.md +453 -0
  390. package/get-shit-done/workflows/progress.md +699 -0
  391. package/get-shit-done/workflows/quick.md +1039 -0
  392. package/get-shit-done/workflows/reapply-patches.md +426 -0
  393. package/get-shit-done/workflows/remove-phase.md +156 -0
  394. package/get-shit-done/workflows/remove-workspace.md +108 -0
  395. package/get-shit-done/workflows/resume-project.md +332 -0
  396. package/get-shit-done/workflows/review.md +623 -0
  397. package/get-shit-done/workflows/scan.md +105 -0
  398. package/get-shit-done/workflows/secure-phase.md +180 -0
  399. package/get-shit-done/workflows/session-report.md +146 -0
  400. package/get-shit-done/workflows/settings-advanced.md +620 -0
  401. package/get-shit-done/workflows/settings-integrations.md +312 -0
  402. package/get-shit-done/workflows/settings.md +552 -0
  403. package/get-shit-done/workflows/ship.md +356 -0
  404. package/get-shit-done/workflows/sketch-wrap-up.md +286 -0
  405. package/get-shit-done/workflows/sketch.md +361 -0
  406. package/get-shit-done/workflows/spec-phase.md +262 -0
  407. package/get-shit-done/workflows/spike-wrap-up.md +307 -0
  408. package/get-shit-done/workflows/spike.md +453 -0
  409. package/get-shit-done/workflows/stats.md +80 -0
  410. package/get-shit-done/workflows/sync-skills.md +182 -0
  411. package/get-shit-done/workflows/thread.md +222 -0
  412. package/get-shit-done/workflows/transition.md +694 -0
  413. package/get-shit-done/workflows/ui-phase.md +328 -0
  414. package/get-shit-done/workflows/ui-review.md +193 -0
  415. package/get-shit-done/workflows/ultraplan-phase.md +199 -0
  416. package/get-shit-done/workflows/undo.md +314 -0
  417. package/get-shit-done/workflows/update.md +443 -0
  418. package/get-shit-done/workflows/validate-phase.md +179 -0
  419. package/get-shit-done/workflows/verify-phase.md +544 -0
  420. package/get-shit-done/workflows/verify-work.md +781 -0
  421. package/hooks/dist/gsd-check-update-worker.js +95 -0
  422. package/hooks/dist/gsd-check-update.js +64 -0
  423. package/hooks/dist/gsd-context-monitor.js +195 -0
  424. package/hooks/dist/gsd-graphify-update.sh +158 -0
  425. package/hooks/dist/gsd-phase-boundary.sh +47 -0
  426. package/hooks/dist/gsd-prompt-guard.js +97 -0
  427. package/hooks/dist/gsd-read-guard.js +101 -0
  428. package/hooks/dist/gsd-read-injection-scanner.js +203 -0
  429. package/hooks/dist/gsd-session-state.sh +59 -0
  430. package/hooks/dist/gsd-statusline.js +548 -0
  431. package/hooks/dist/gsd-update-banner.js +134 -0
  432. package/hooks/dist/gsd-validate-commit.sh +57 -0
  433. package/hooks/dist/gsd-workflow-guard.js +166 -0
  434. package/hooks/dist/lib/git-cmd.js +150 -0
  435. package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
  436. package/hooks/gsd-check-update-worker.js +95 -0
  437. package/hooks/gsd-check-update.js +64 -0
  438. package/hooks/gsd-context-monitor.js +195 -0
  439. package/hooks/gsd-graphify-update.sh +158 -0
  440. package/hooks/gsd-phase-boundary.sh +47 -0
  441. package/hooks/gsd-prompt-guard.js +97 -0
  442. package/hooks/gsd-read-guard.js +101 -0
  443. package/hooks/gsd-read-injection-scanner.js +203 -0
  444. package/hooks/gsd-session-state.sh +59 -0
  445. package/hooks/gsd-statusline.js +548 -0
  446. package/hooks/gsd-update-banner.js +134 -0
  447. package/hooks/gsd-validate-commit.sh +57 -0
  448. package/hooks/gsd-workflow-guard.js +166 -0
  449. package/hooks/lib/git-cmd.js +150 -0
  450. package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
  451. package/hooks/managed-hooks-registry.cjs +34 -0
  452. package/package.json +102 -0
  453. package/scripts/affected-tests-lib.cjs +541 -0
  454. package/scripts/audit-workflow-script-paths.cjs +73 -0
  455. package/scripts/base64-scan.sh +339 -0
  456. package/scripts/build-hooks.js +236 -0
  457. package/scripts/changeset/README.md +129 -0
  458. package/scripts/changeset/cli.cjs +392 -0
  459. package/scripts/changeset/github-release-notes.cjs +199 -0
  460. package/scripts/changeset/lint.cjs +110 -0
  461. package/scripts/changeset/new.cjs +137 -0
  462. package/scripts/changeset/parse.cjs +114 -0
  463. package/scripts/changeset/render.cjs +34 -0
  464. package/scripts/changeset/serialize.cjs +130 -0
  465. package/scripts/check-alias-drift.cjs +108 -0
  466. package/scripts/check-env.cjs +302 -0
  467. package/scripts/check-npm-integrity.cjs +209 -0
  468. package/scripts/ci-guard-runner.cjs +16 -0
  469. package/scripts/ci-prepare-test-scope.cjs +46 -0
  470. package/scripts/ci-rebase-check.cjs +85 -0
  471. package/scripts/ci-test-scope.cjs +302 -0
  472. package/scripts/command-contract-helpers.cjs +64 -0
  473. package/scripts/diff-touches-shipped-paths.cjs +147 -0
  474. package/scripts/fix-slash-commands.cjs +147 -0
  475. package/scripts/gen-inventory-manifest.cjs +109 -0
  476. package/scripts/generate-package-identity.cjs +104 -0
  477. package/scripts/lint-command-contract.cjs +108 -0
  478. package/scripts/lint-descriptions.cjs +83 -0
  479. package/scripts/lint-docs-required.cjs +222 -0
  480. package/scripts/lint-no-source-grep-extras.cjs +81 -0
  481. package/scripts/lint-no-source-grep.cjs +174 -0
  482. package/scripts/lint-package-identity-drift.cjs +141 -0
  483. package/scripts/lint-pr-check-project-dir.cjs +98 -0
  484. package/scripts/lint-shared-module-handsync.cjs +388 -0
  485. package/scripts/lint-shell-command-projection-drift.cjs +57 -0
  486. package/scripts/lint-skill-deps.cjs +180 -0
  487. package/scripts/lint-test-file-count.allowlist.json +36 -0
  488. package/scripts/lint-test-file-count.cjs +190 -0
  489. package/scripts/pr-template-policy.cjs +268 -0
  490. package/scripts/prompt-injection-scan.sh +203 -0
  491. package/scripts/release-tarball-smoke.cjs +627 -0
  492. package/scripts/run-affected-tests.cjs +6 -0
  493. package/scripts/run-cross-platform-tests.cjs +63 -0
  494. package/scripts/run-tests.cjs +282 -0
  495. package/scripts/secret-scan-lint.sh +231 -0
  496. package/scripts/secret-scan.sh +358 -0
  497. package/scripts/setup-branch-protection.sh +236 -0
  498. package/scripts/shared-module-handsync-allowlist.json +183 -0
  499. package/scripts/strip-prose-atrefs.cjs +106 -0
  500. package/scripts/sync-rulesets.sh +34 -0
  501. package/scripts/sync-runtime-launcher.cjs +402 -0
  502. package/scripts/test-failure-reasons.cjs +34 -0
  503. package/scripts/workflow-policy.cjs +450 -0
@@ -0,0 +1,388 @@
1
+ /**
2
+ * Codebase Drift Detection (#2003)
3
+ *
4
+ * Detects structural drift between a committed codebase and the
5
+ * `.planning/codebase/STRUCTURE.md` map produced by `gsd-codebase-mapper`.
6
+ *
7
+ * Four categories of drift element:
8
+ * - new_dir → a newly-added file whose directory prefix does not appear
9
+ * in STRUCTURE.md
10
+ * - barrel → a newly-added barrel export at
11
+ * (packages|apps)/<name>/src/index.(ts|tsx|js|mjs|cjs)
12
+ * - migration → a newly-added migration file under one of the recognized
13
+ * migration directories (supabase, prisma, drizzle, src/migrations, …)
14
+ * - route → a newly-added route module under a `routes/` or `api/` dir
15
+ *
16
+ * Each file is counted at most once; when a file matches multiple categories
17
+ * the most specific category wins (migration > route > barrel > new_dir).
18
+ *
19
+ * Design decisions (see PR for full rubber-duck):
20
+ * - The library is pure. It takes parsed git diff output and returns a
21
+ * structured result. The CLI/workflow layer is responsible for running
22
+ * git and for spawning mappers.
23
+ * - `last_mapped_commit` is stored as YAML-style frontmatter at the top of
24
+ * each `.planning/codebase/*.md` file. This keeps the baseline attached
25
+ * to the file, survives git moves, and avoids a sidecar JSON.
26
+ * - The detector NEVER throws on malformed input — it returns a
27
+ * `{ skipped: true }` result. The phase workflow depends on this
28
+ * non-blocking guarantee.
29
+ */
30
+
31
+ 'use strict';
32
+
33
+ const fs = require('node:fs');
34
+ const { platformWriteSync } = require('./shell-command-projection.cjs');
35
+
36
+ // ─── Constants ───────────────────────────────────────────────────────────────
37
+
38
+ const DRIFT_CATEGORIES = Object.freeze(['new_dir', 'barrel', 'migration', 'route']);
39
+
40
+ // Category priority when a single file matches multiple rules.
41
+ // Higher index = more specific = wins.
42
+ const CATEGORY_PRIORITY = { new_dir: 0, barrel: 1, route: 2, migration: 3 };
43
+
44
+ const BARREL_RE = /^(packages|apps)\/[^/]+\/src\/index\.(ts|tsx|js|mjs|cjs)$/;
45
+
46
+ const MIGRATION_RES = [
47
+ /^supabase\/migrations\/.+\.sql$/,
48
+ /^prisma\/migrations\/.+/,
49
+ /^drizzle\/meta\/.+/,
50
+ /^drizzle\/migrations\/.+/,
51
+ /^src\/migrations\/.+\.(ts|js|sql)$/,
52
+ /^db\/migrations\/.+\.(sql|ts|js)$/,
53
+ /^migrations\/.+\.(sql|ts|js)$/,
54
+ ];
55
+
56
+ const ROUTE_RES = [
57
+ /^(apps|packages)\/[^/]+\/src\/routes\/.+\.(ts|tsx|js|jsx|mjs|cjs)$/,
58
+ /^src\/routes\/.+\.(ts|tsx|js|jsx|mjs|cjs)$/,
59
+ /^src\/api\/.+\.(ts|tsx|js|jsx|mjs|cjs)$/,
60
+ /^(apps|packages)\/[^/]+\/src\/api\/.+\.(ts|tsx|js|jsx|mjs|cjs)$/,
61
+ ];
62
+
63
+ // A conservative allowlist for `--paths` arguments passed to the mapper:
64
+ // repo-relative path components separated by /, containing only
65
+ // alphanumerics, dash, underscore, and dot (no `..`, no `/..`).
66
+ const SAFE_PATH_RE = /^(?!.*\.\.)(?:[A-Za-z0-9_.][A-Za-z0-9_.\-]*)(?:\/[A-Za-z0-9_.][A-Za-z0-9_.\-]*)*$/;
67
+
68
+ // ─── Classification ──────────────────────────────────────────────────────────
69
+
70
+ /**
71
+ * Classify a single file path into a drift category or null.
72
+ *
73
+ * @param {string} file - repo-relative path, forward slashes.
74
+ * @returns {'barrel'|'migration'|'route'|null}
75
+ */
76
+ function classifyFile(file) {
77
+ if (typeof file !== 'string' || !file) return null;
78
+ const norm = file.replace(/\\/g, '/');
79
+ if (MIGRATION_RES.some((r) => r.test(norm))) return 'migration';
80
+ if (ROUTE_RES.some((r) => r.test(norm))) return 'route';
81
+ if (BARREL_RE.test(norm)) return 'barrel';
82
+ return null;
83
+ }
84
+
85
+ /**
86
+ * True iff any prefix of `file` (dir1, dir1/dir2, …) appears as a substring
87
+ * of `structureMd`. Used to decide whether a file is in "mapped territory".
88
+ *
89
+ * Matching is deliberately substring-based — STRUCTURE.md is free-form
90
+ * markdown, not a structured manifest. If the map mentions `src/lib/` the
91
+ * check `structureMd.includes('src/lib')` holds.
92
+ */
93
+ function isPathMapped(file, structureMd) {
94
+ const norm = file.replace(/\\/g, '/');
95
+ const parts = norm.split('/');
96
+ // Check prefixes from longest to shortest; any hit means "mapped".
97
+ for (let i = parts.length - 1; i >= 1; i--) {
98
+ const prefix = parts.slice(0, i).join('/');
99
+ if (structureMd.includes(prefix)) return true;
100
+ }
101
+ // Finally, if even the top-level dir is mentioned, count as mapped.
102
+ if (parts.length > 0 && structureMd.includes(parts[0] + '/')) return true;
103
+ if (parts.length > 0 && structureMd.includes('`' + parts[0] + '`')) return true;
104
+ return false;
105
+ }
106
+
107
+ // ─── Main detection ──────────────────────────────────────────────────────────
108
+
109
+ /**
110
+ * Detect codebase drift.
111
+ *
112
+ * @param {object} input
113
+ * @param {string[]} input.addedFiles - files with git status A (new)
114
+ * @param {string[]} input.modifiedFiles - files with git status M
115
+ * @param {string[]} input.deletedFiles - files with git status D
116
+ * @param {string|null|undefined} input.structureMd - contents of STRUCTURE.md
117
+ * @param {number} [input.threshold=3] - min number of drift elements that triggers action
118
+ * @param {'warn'|'auto-remap'} [input.action='warn']
119
+ * @param {string} [input.runtime='claude'] - runtime name (claude, codex, ...) used
120
+ * to format the slash-command in the remediation message. Caller resolves and
121
+ * passes this in to keep drift.cjs a pure library with no env/config reads.
122
+ * @returns {object} result
123
+ */
124
+ function detectDrift(input) {
125
+ try {
126
+ if (!input || typeof input !== 'object') {
127
+ return skipped('invalid-input');
128
+ }
129
+ const {
130
+ addedFiles,
131
+ modifiedFiles,
132
+ deletedFiles,
133
+ structureMd,
134
+ } = input;
135
+ const threshold = Number.isInteger(input.threshold) && input.threshold >= 1
136
+ ? input.threshold
137
+ : 3;
138
+ const action = input.action === 'auto-remap' ? 'auto-remap' : 'warn';
139
+
140
+ if (structureMd === null || structureMd === undefined) {
141
+ return skipped('missing-structure-md');
142
+ }
143
+ if (typeof structureMd !== 'string') {
144
+ return skipped('invalid-structure-md');
145
+ }
146
+
147
+ const added = Array.isArray(addedFiles) ? addedFiles.filter((x) => typeof x === 'string') : [];
148
+ const modified = Array.isArray(modifiedFiles) ? modifiedFiles : [];
149
+ const deleted = Array.isArray(deletedFiles) ? deletedFiles : [];
150
+
151
+ // Build elements. One element per file, highest-priority category wins.
152
+ /** @type {{category: string, path: string}[]} */
153
+ const elements = [];
154
+ const seen = new Map();
155
+
156
+ for (const rawFile of added) {
157
+ const file = rawFile.replace(/\\/g, '/');
158
+ const specific = classifyFile(file);
159
+ let category = specific;
160
+ if (!category) {
161
+ if (!isPathMapped(file, structureMd)) {
162
+ category = 'new_dir';
163
+ } else {
164
+ continue; // mapped, known, ordinary file — not drift
165
+ }
166
+ }
167
+ // Dedup: if we've already counted this path at higher-or-equal priority, skip
168
+ const prior = seen.get(file);
169
+ if (prior && CATEGORY_PRIORITY[prior] >= CATEGORY_PRIORITY[category]) continue;
170
+ seen.set(file, category);
171
+ }
172
+
173
+ for (const [file, category] of seen.entries()) {
174
+ elements.push({ category, path: file });
175
+ }
176
+
177
+ // Sort for stable output.
178
+ elements.sort((a, b) =>
179
+ a.category === b.category
180
+ ? a.path.localeCompare(b.path)
181
+ : a.category.localeCompare(b.category),
182
+ );
183
+
184
+ const actionRequired = elements.length >= threshold;
185
+ let directive = 'none';
186
+ let spawnMapper = false;
187
+ let affectedPaths = [];
188
+ let message = '';
189
+
190
+ if (actionRequired) {
191
+ directive = action;
192
+ affectedPaths = chooseAffectedPaths(elements.map((e) => e.path));
193
+ if (action === 'auto-remap') {
194
+ spawnMapper = true;
195
+ }
196
+ message = buildMessage(elements, affectedPaths, action, input.runtime);
197
+ }
198
+
199
+ return {
200
+ skipped: false,
201
+ elements,
202
+ actionRequired,
203
+ directive,
204
+ spawnMapper,
205
+ affectedPaths,
206
+ threshold,
207
+ action,
208
+ message,
209
+ counts: {
210
+ added: added.length,
211
+ modified: modified.length,
212
+ deleted: deleted.length,
213
+ },
214
+ };
215
+ } catch (err) {
216
+ // Non-blocking: never throw from this function.
217
+ return skipped('exception:' + (err && err.message ? err.message : String(err)));
218
+ }
219
+ }
220
+
221
+ function skipped(reason) {
222
+ return {
223
+ skipped: true,
224
+ reason,
225
+ elements: [],
226
+ actionRequired: false,
227
+ directive: 'none',
228
+ spawnMapper: false,
229
+ affectedPaths: [],
230
+ message: '',
231
+ };
232
+ }
233
+
234
+ function buildMessage(elements, affectedPaths, action, runtime) {
235
+ const byCat = {};
236
+ for (const e of elements) {
237
+ (byCat[e.category] ||= []).push(e.path);
238
+ }
239
+ const lines = [
240
+ `Codebase drift detected: ${elements.length} structural element(s) since last mapping.`,
241
+ '',
242
+ ];
243
+ const labels = {
244
+ new_dir: 'New directories',
245
+ barrel: 'New barrel exports',
246
+ migration: 'New migrations',
247
+ route: 'New route modules',
248
+ };
249
+ for (const cat of ['new_dir', 'barrel', 'migration', 'route']) {
250
+ if (byCat[cat]) {
251
+ lines.push(`${labels[cat]}:`);
252
+ for (const p of byCat[cat]) lines.push(` - ${p}`);
253
+ }
254
+ }
255
+ lines.push('');
256
+ if (action === 'auto-remap') {
257
+ lines.push(`Auto-remap scheduled for paths: ${affectedPaths.join(', ')}`);
258
+ } else {
259
+ // drift.cjs is a pure library — it must never read env/config. The
260
+ // caller (verify.cmdVerifyCodebaseDrift) resolves the runtime once and
261
+ // passes it in via input.runtime so emitted commands match the project
262
+ // the caller is targeting, not the current process directory.
263
+ const { formatGsdSlash } = require('./runtime-slash.cjs');
264
+ const mapCmd = formatGsdSlash('map-codebase', runtime || 'claude');
265
+ lines.push(
266
+ `Run ${mapCmd} --paths ${affectedPaths.join(',')} to refresh planning context.`,
267
+ );
268
+ }
269
+ return lines.join('\n');
270
+ }
271
+
272
+ // ─── Affected paths ──────────────────────────────────────────────────────────
273
+
274
+ /**
275
+ * Collapse a list of drifted file paths into a sorted, deduplicated list of
276
+ * the top-level directory prefixes (depth 2 when the repo uses an
277
+ * `<apps|packages>/<name>/…` layout; depth 1 otherwise).
278
+ */
279
+ function chooseAffectedPaths(paths) {
280
+ const out = new Set();
281
+ for (const raw of paths || []) {
282
+ if (typeof raw !== 'string' || !raw) continue;
283
+ const file = raw.replace(/\\/g, '/');
284
+ const parts = file.split('/');
285
+ if (parts.length === 0) continue;
286
+ const top = parts[0];
287
+ if ((top === 'apps' || top === 'packages') && parts.length >= 2) {
288
+ out.add(`${top}/${parts[1]}`);
289
+ } else {
290
+ out.add(top);
291
+ }
292
+ }
293
+ return [...out].sort();
294
+ }
295
+
296
+ /**
297
+ * Filter `paths` to only those that are safe to splice into a mapper prompt.
298
+ * Any path that is absolute, contains traversal, or includes shell
299
+ * metacharacters is dropped.
300
+ */
301
+ function sanitizePaths(paths) {
302
+ if (!Array.isArray(paths)) return [];
303
+ const out = [];
304
+ for (const p of paths) {
305
+ if (typeof p !== 'string') continue;
306
+ if (p.startsWith('/')) continue;
307
+ if (!SAFE_PATH_RE.test(p)) continue;
308
+ out.push(p);
309
+ }
310
+ return out;
311
+ }
312
+
313
+ // ─── Frontmatter helpers ─────────────────────────────────────────────────────
314
+
315
+ const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
316
+
317
+ function parseFrontmatter(content) {
318
+ if (typeof content !== 'string') return { data: {}, body: '' };
319
+ const m = content.match(FRONTMATTER_RE);
320
+ if (!m) return { data: {}, body: content };
321
+ const data = {};
322
+ for (const line of m[1].split(/\r?\n/)) {
323
+ const kv = line.match(/^([A-Za-z0-9_][A-Za-z0-9_-]*):\s*(.*)$/);
324
+ if (!kv) continue;
325
+ data[kv[1]] = kv[2];
326
+ }
327
+ return { data, body: content.slice(m[0].length) };
328
+ }
329
+
330
+ function serializeFrontmatter(data, body) {
331
+ const keys = Object.keys(data);
332
+ if (keys.length === 0) return body;
333
+ const lines = ['---'];
334
+ for (const k of keys) lines.push(`${k}: ${data[k]}`);
335
+ lines.push('---');
336
+ return lines.join('\n') + '\n' + body;
337
+ }
338
+
339
+ /**
340
+ * Read `last_mapped_commit` from the frontmatter of a `.planning/codebase/*.md`
341
+ * file. Returns null if the file does not exist or has no frontmatter.
342
+ */
343
+ function readMappedCommit(filePath) {
344
+ let content;
345
+ try {
346
+ content = fs.readFileSync(filePath, 'utf8');
347
+ } catch {
348
+ return null;
349
+ }
350
+ const { data } = parseFrontmatter(content);
351
+ const sha = data.last_mapped_commit;
352
+ return typeof sha === 'string' && sha.length > 0 ? sha : null;
353
+ }
354
+
355
+ /**
356
+ * Upsert `last_mapped_commit` and `last_mapped_at` into the frontmatter of
357
+ * the given file, preserving any other frontmatter keys and the body.
358
+ */
359
+ function writeMappedCommit(filePath, commitSha, isoDate) {
360
+ // Symmetric with readMappedCommit (which returns null on missing files):
361
+ // tolerate a missing target by creating a minimal frontmatter-only file
362
+ // rather than throwing ENOENT. This matters when a mapper produces a new
363
+ // doc and the caller stamps it before any prior content existed.
364
+ let content = '';
365
+ try {
366
+ content = fs.readFileSync(filePath, 'utf8');
367
+ } catch (err) {
368
+ if (err.code !== 'ENOENT') throw err;
369
+ }
370
+ const { data, body } = parseFrontmatter(content);
371
+ data.last_mapped_commit = commitSha;
372
+ if (isoDate) data.last_mapped_at = isoDate;
373
+ platformWriteSync(filePath, serializeFrontmatter(data, body));
374
+ }
375
+
376
+ // ─── Exports ─────────────────────────────────────────────────────────────────
377
+
378
+ module.exports = {
379
+ DRIFT_CATEGORIES,
380
+ classifyFile,
381
+ detectDrift,
382
+ chooseAffectedPaths,
383
+ sanitizePaths,
384
+ readMappedCommit,
385
+ writeMappedCommit,
386
+ // Exposed for the CLI layer to reuse the same parser.
387
+ parseFrontmatter,
388
+ };
@@ -0,0 +1,109 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ function candidateNames() {
7
+ return process.platform === 'win32'
8
+ ? ['fallow.exe', 'fallow.cmd', 'fallow.bat', 'fallow']
9
+ : ['fallow'];
10
+ }
11
+
12
+ function isExecutableFile(filePath) {
13
+ try {
14
+ const stat = fs.statSync(filePath);
15
+ if (!stat.isFile()) return false;
16
+ if (process.platform === 'win32') return true;
17
+ fs.accessSync(filePath, fs.constants.X_OK);
18
+ return true;
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+
24
+ function findInPath(envPath) {
25
+ if (!envPath) return null;
26
+ const names = candidateNames();
27
+ const segments = envPath.split(path.delimiter).filter(Boolean);
28
+ for (const segment of segments) {
29
+ for (const name of names) {
30
+ const candidate = path.join(segment, name);
31
+ if (isExecutableFile(candidate)) return candidate;
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+
37
+ function findInNodeModules(cwd) {
38
+ const names = candidateNames();
39
+ const binDir = path.join(cwd, 'node_modules', '.bin');
40
+ for (const name of names) {
41
+ const candidate = path.join(binDir, name);
42
+ if (isExecutableFile(candidate)) return candidate;
43
+ }
44
+ return null;
45
+ }
46
+
47
+ function resolveFallowBinary({ cwd, envPath = process.env.PATH || '' }) {
48
+ return findInNodeModules(cwd) || findInPath(envPath) || null;
49
+ }
50
+
51
+ function requireFallowBinary({ cwd, envPath = process.env.PATH || '' }) {
52
+ const binary = resolveFallowBinary({ cwd, envPath });
53
+ if (binary) return binary;
54
+ throw new Error(
55
+ 'Fallow is enabled but no binary was found. Please install fallow via `npm install -D fallow` or `cargo install fallow`.',
56
+ );
57
+ }
58
+
59
+ function normalizeFallowReport(report) {
60
+ const unused = Array.isArray(report?.unusedExports) ? report.unusedExports : [];
61
+ const duplicates = Array.isArray(report?.duplicates) ? report.duplicates : [];
62
+ const circular = Array.isArray(report?.circularDependencies) ? report.circularDependencies : [];
63
+
64
+ const findings = [];
65
+
66
+ for (const item of unused) {
67
+ findings.push({
68
+ type: 'unused_export',
69
+ message: `Unused export ${item.symbol || '<unknown>'}`,
70
+ file: item.file || '',
71
+ line: item.line ?? null,
72
+ });
73
+ }
74
+
75
+ for (const item of duplicates) {
76
+ findings.push({
77
+ type: 'duplicate_block',
78
+ message: `Duplicate block (${Math.round((item.similarity || 0) * 100)}% similarity)`,
79
+ file: item.left?.file || '',
80
+ line: item.left?.start ?? null,
81
+ related_file: item.right?.file || '',
82
+ });
83
+ }
84
+
85
+ for (const item of circular) {
86
+ findings.push({
87
+ type: 'circular_dependency',
88
+ message: `Circular dependency: ${(item.cycle || []).join(' -> ')}`,
89
+ file: Array.isArray(item.cycle) && item.cycle.length > 0 ? item.cycle[0] : '',
90
+ line: null,
91
+ });
92
+ }
93
+
94
+ return {
95
+ summary: {
96
+ unused_exports: unused.length,
97
+ duplicates: duplicates.length,
98
+ circular_dependencies: circular.length,
99
+ total: findings.length,
100
+ },
101
+ findings,
102
+ };
103
+ }
104
+
105
+ module.exports = {
106
+ normalizeFallowReport,
107
+ requireFallowBinary,
108
+ resolveFallowBinary,
109
+ };