@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,130 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Markdown serializer + parser for the changelog IR. The two are inverses
5
+ * over the well-formed subset; tests assert via round-trip (parse(serialize(ir)))
6
+ * rather than by inspecting serialized text — see CONTRIBUTING.md
7
+ * "Prohibited: Raw Text Matching on Test Outputs".
8
+ *
9
+ * Serialized form (Keep a Changelog):
10
+ *
11
+ * ## [1.42.0] - 2026-05-01
12
+ *
13
+ * ### Fixed
14
+ *
15
+ * - body of the bullet (#NNNN)
16
+ *
17
+ * <priorChangelog appended verbatim>
18
+ */
19
+
20
+ function serializeChangelog(ir) {
21
+ const lines = [];
22
+ const { version, date } = ir.releaseHeader;
23
+ lines.push(`## [${version}] - ${date}`);
24
+ lines.push('');
25
+ for (const section of ir.sections) {
26
+ lines.push(`### ${section.type}`);
27
+ lines.push('');
28
+ for (const b of section.bullets) {
29
+ lines.push(`- ${b.body} (#${b.pr})`);
30
+ }
31
+ lines.push('');
32
+ }
33
+ let out = lines.join('\n');
34
+ if (ir.priorChangelog) {
35
+ out += '\n' + ir.priorChangelog;
36
+ }
37
+ return out;
38
+ }
39
+
40
+ /**
41
+ * Inverse parser: extracts the structured releases from a CHANGELOG.md
42
+ * text. Returns { releases: [{ version, date, sections: [{ type, bullets:
43
+ * [{ pr, body }] }] }] }. Tolerates the actual repo's CHANGELOG dialect.
44
+ *
45
+ * Multi-line bullets are supported: a bullet opens on a line starting with
46
+ * `- ` and continues on lines starting with two or more spaces (or a tab).
47
+ * The `(#NNNN)` PR trailer may appear on any continuation line. Single-line
48
+ * bullets (entire entry on one `- ` line) are still handled as before.
49
+ *
50
+ * Fix for #3496: the previous implementation only matched single-line bullets
51
+ * whose `(#NNNN)` suffix was on the same line as the opening `- `. Long
52
+ * bullets — which wrap onto indented continuation lines — returned 0 entries
53
+ * for their section even when the markdown was well-formed.
54
+ */
55
+ function parseChangelog(text) {
56
+ const releases = [];
57
+ const lines = text.split(/\r?\n/);
58
+ let cur = null;
59
+ let curSection = null;
60
+ // Accumulates lines belonging to the current in-flight bullet (may span
61
+ // multiple lines). Flushed when a new block-level element is encountered.
62
+ let bulletLines = null;
63
+
64
+ function flushBullet() {
65
+ if (bulletLines === null || !curSection) return;
66
+ const joined = bulletLines.join(' ').trim();
67
+ // Locate the (# pr) trailer anywhere in the joined text. The trailer is
68
+ // expected to be at the very end, but we tolerate trailing whitespace.
69
+ const trailMatch = joined.match(/^(.*?)\s*\(#(\d+)\)\s*$/);
70
+ if (trailMatch) {
71
+ curSection.bullets.push({ body: trailMatch[1].trim(), pr: Number(trailMatch[2]) });
72
+ } else {
73
+ // Bullet has no PR trailer — preserve it with pr: null so callers
74
+ // (e.g. cmdExtract) do not silently drop authored content.
75
+ curSection.bullets.push({ body: joined, pr: null });
76
+ }
77
+ bulletLines = null;
78
+ }
79
+
80
+ for (const line of lines) {
81
+ // F3: match linked headers: ## [1.42.1](url) - 2026-05-15
82
+ // The (?:\([^)]*\))? group skips an optional (url) after the closing ]
83
+ // before looking for the optional date suffix.
84
+ // F6: strip a leading `v` from the captured version so `## [v1.0.0]`
85
+ // parses as version "1.0.0" instead of "v1.0.0".
86
+ const releaseMatch = line.match(/^##\s+\[([^\]]+)\](?:\([^)]*\))?\s*(?:-\s*(\S+))?/);
87
+ if (releaseMatch) {
88
+ flushBullet();
89
+ const rawVersion = releaseMatch[1];
90
+ const version = rawVersion.replace(/^v/, '');
91
+ cur = { version, date: releaseMatch[2] || null, sections: [] };
92
+ curSection = null;
93
+ releases.push(cur);
94
+ continue;
95
+ }
96
+ if (!cur) continue;
97
+ const sectionMatch = line.match(/^###\s+(.+?)\s*$/);
98
+ if (sectionMatch) {
99
+ flushBullet();
100
+ curSection = { type: sectionMatch[1], bullets: [] };
101
+ cur.sections.push(curSection);
102
+ continue;
103
+ }
104
+ if (!curSection) continue;
105
+
106
+ // New bullet: line begins with `- ` (after optional leading spaces that
107
+ // would indicate a nested list — we only handle top-level bullets here).
108
+ if (/^-\s+/.test(line)) {
109
+ flushBullet();
110
+ bulletLines = [line.replace(/^-\s+/, '')];
111
+ continue;
112
+ }
113
+
114
+ // Continuation line: any indentation (F7: relaxed from /^[ \t]{2}/ so that
115
+ // 1-space-indented continuations also fold) BUT NOT a nested bullet marker
116
+ // (F4: ` - nested item` terminates the current bullet rather than folding).
117
+ if (bulletLines !== null && /^\s+/.test(line) && !/^\s+-\s/.test(line)) {
118
+ bulletLines.push(line.trim());
119
+ continue;
120
+ }
121
+
122
+ // Any other line (blank, heading, nested bullet, etc.) terminates a pending bullet.
123
+ flushBullet();
124
+ }
125
+ flushBullet();
126
+
127
+ return { releases };
128
+ }
129
+
130
+ module.exports = { serializeChangelog, parseChangelog };
@@ -0,0 +1,108 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const ROOT = path.resolve(__dirname, '..');
7
+ const aliasesPath = path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'command-aliases.cjs');
8
+
9
+ function fail(message) {
10
+ process.stderr.write(`${message}\n`);
11
+ process.exit(1);
12
+ }
13
+
14
+ function ensureArray(value, name) {
15
+ if (!Array.isArray(value)) {
16
+ fail(`check:alias-drift: expected ${name} to be an array`);
17
+ }
18
+ }
19
+
20
+ function assertNoDuplicates(values, label) {
21
+ const seen = new Set();
22
+ for (const value of values) {
23
+ if (seen.has(value)) {
24
+ fail(`check:alias-drift: duplicate ${label} value "${value}"`);
25
+ }
26
+ seen.add(value);
27
+ }
28
+ }
29
+
30
+ if (!fs.existsSync(aliasesPath)) {
31
+ fail(`check:alias-drift: missing ${path.relative(ROOT, aliasesPath)}`);
32
+ }
33
+
34
+ const aliases = require(aliasesPath);
35
+
36
+ const families = [
37
+ {
38
+ commandAliases: 'STATE_COMMAND_ALIASES',
39
+ subcommands: 'STATE_SUBCOMMANDS',
40
+ routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'state-command-router.cjs'),
41
+ },
42
+ {
43
+ commandAliases: 'VERIFY_COMMAND_ALIASES',
44
+ subcommands: 'VERIFY_SUBCOMMANDS',
45
+ routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'verify-command-router.cjs'),
46
+ },
47
+ {
48
+ commandAliases: 'INIT_COMMAND_ALIASES',
49
+ subcommands: 'INIT_SUBCOMMANDS',
50
+ routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'init-command-router.cjs'),
51
+ },
52
+ {
53
+ commandAliases: 'PHASE_COMMAND_ALIASES',
54
+ subcommands: 'PHASE_SUBCOMMANDS',
55
+ routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'phase-command-router.cjs'),
56
+ },
57
+ {
58
+ commandAliases: 'PHASES_COMMAND_ALIASES',
59
+ subcommands: 'PHASES_SUBCOMMANDS',
60
+ routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'phases-command-router.cjs'),
61
+ },
62
+ {
63
+ commandAliases: 'VALIDATE_COMMAND_ALIASES',
64
+ subcommands: 'VALIDATE_SUBCOMMANDS',
65
+ routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'validate-command-router.cjs'),
66
+ },
67
+ {
68
+ commandAliases: 'ROADMAP_COMMAND_ALIASES',
69
+ subcommands: 'ROADMAP_SUBCOMMANDS',
70
+ routerPath: path.join(ROOT, 'get-shit-done', 'bin', 'lib', 'roadmap-command-router.cjs'),
71
+ },
72
+ ];
73
+
74
+ for (const family of families) {
75
+ const commandAliases = aliases[family.commandAliases];
76
+ const subcommands = aliases[family.subcommands];
77
+
78
+ ensureArray(commandAliases, family.commandAliases);
79
+ ensureArray(subcommands, family.subcommands);
80
+
81
+ const derivedSubcommands = commandAliases.map((entry) => entry && entry.subcommand);
82
+ assertNoDuplicates(derivedSubcommands, `${family.commandAliases}.subcommand`);
83
+
84
+ if (derivedSubcommands.length !== subcommands.length) {
85
+ fail(
86
+ `check:alias-drift: ${family.subcommands} length ${subcommands.length} does not match ` +
87
+ `${family.commandAliases} length ${derivedSubcommands.length}`,
88
+ );
89
+ }
90
+
91
+ for (let i = 0; i < derivedSubcommands.length; i++) {
92
+ if (derivedSubcommands[i] !== subcommands[i]) {
93
+ fail(
94
+ `check:alias-drift: ${family.subcommands}[${i}] = "${subcommands[i]}" ` +
95
+ `does not match ${family.commandAliases}[${i}].subcommand = "${derivedSubcommands[i]}"`,
96
+ );
97
+ }
98
+ }
99
+
100
+ const routerSource = fs.readFileSync(family.routerPath, 'utf8');
101
+ if (!routerSource.includes(family.subcommands)) {
102
+ fail(
103
+ `check:alias-drift: ${path.relative(ROOT, family.routerPath)} does not reference ${family.subcommands}`,
104
+ );
105
+ }
106
+ }
107
+
108
+ process.stdout.write('check:alias-drift ok\n');
@@ -0,0 +1,302 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // scripts/check-env.cjs — Environment parity validator for contributors (issue #117).
4
+ //
5
+ // Node.js port of scripts/check-env.sh. Behaviorally identical output and
6
+ // exit codes; shell-agnostic so it runs on Windows, macOS, and Linux.
7
+ //
8
+ // Checks that the developer's environment matches project requirements before
9
+ // running tests or audits. Designed to catch mismatches early rather than
10
+ // through cryptic test failures.
11
+ //
12
+ // Exit codes:
13
+ // 0 All checks passed
14
+ // 1 One or more checks failed
15
+ // 2 Tool error (missing required tool, corrupt package.json, etc.)
16
+ //
17
+ // Usage:
18
+ // node scripts/check-env.cjs # Human-readable report
19
+ // node scripts/check-env.cjs --json # Structured JSON report
20
+ // node scripts/check-env.cjs --help # This message
21
+ //
22
+ // Sources:
23
+ // npm engines: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines
24
+ // Reproducible builds: https://reproducible-builds.org/docs/source-tree/
25
+ // npm ci docs: https://docs.npmjs.com/cli/v10/commands/npm-ci
26
+ // gsd-test-runner: https://github.com/open-gsd/gsd-test-runner
27
+
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+ const { execFileSync, spawnSync } = require('child_process');
31
+
32
+ // On Windows, npm ships as npm.cmd (a batch wrapper); spawnSync without
33
+ // shell:true requires the exact filename including extension.
34
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Argument parsing
38
+ // ---------------------------------------------------------------------------
39
+ let jsonMode = false;
40
+
41
+ for (const arg of process.argv.slice(2)) {
42
+ if (arg === '--json') {
43
+ jsonMode = true;
44
+ } else if (arg === '--help' || arg === '-h') {
45
+ process.stdout.write(
46
+ 'scripts/check-env.cjs — Environment parity validator for contributors (issue #117).\n' +
47
+ '\n' +
48
+ 'Checks that the developer\'s environment matches project requirements before\n' +
49
+ 'running tests or audits. Designed to catch mismatches early rather than\n' +
50
+ 'through cryptic test failures.\n' +
51
+ '\n' +
52
+ 'Exit codes:\n' +
53
+ ' 0 All checks passed\n' +
54
+ ' 1 One or more checks failed\n' +
55
+ ' 2 Tool error (missing required tool, corrupt package.json, etc.)\n' +
56
+ '\n' +
57
+ 'Usage:\n' +
58
+ ' node scripts/check-env.cjs # Human-readable report\n' +
59
+ ' node scripts/check-env.cjs --json # Structured JSON report\n' +
60
+ ' node scripts/check-env.cjs --help # This message\n'
61
+ );
62
+ process.exit(0);
63
+ } else {
64
+ process.stderr.write(`Unknown option: ${arg}\n`);
65
+ process.exit(2);
66
+ }
67
+ }
68
+
69
+ // ---------------------------------------------------------------------------
70
+ // Locate the project root (directory containing package.json)
71
+ // ---------------------------------------------------------------------------
72
+ const PROJECT_ROOT = process.cwd();
73
+ const PACKAGE_JSON = path.join(PROJECT_ROOT, 'package.json');
74
+
75
+ if (!fs.existsSync(PACKAGE_JSON)) {
76
+ process.stderr.write(`ERROR: package.json not found in ${PROJECT_ROOT}\n`);
77
+ process.exit(2);
78
+ }
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Helpers
82
+ // ---------------------------------------------------------------------------
83
+
84
+ /** @type {Array<{name: string, status: 'pass'|'fail'|'skip', message: string}>} */
85
+ const checks = [];
86
+
87
+ function addCheck(name, status, message) {
88
+ checks.push({ name, status, message });
89
+ }
90
+
91
+ /**
92
+ * Semver comparison: does `version` satisfy `constraint`?
93
+ * Constraint forms: >=X.Y.Z, >X.Y.Z, <=X.Y.Z, <X.Y.Z, =X.Y.Z, X.Y.Z
94
+ * Returns true if satisfied, false otherwise.
95
+ */
96
+ function satisfiesConstraint(version, constraint) {
97
+ // Strip leading 'v' and pre-release/build suffixes
98
+ version = version.replace(/^v/, '').replace(/-.*$/, '').replace(/\+.*$/, '');
99
+
100
+ let op, reqVer;
101
+ const opMatch = constraint.match(/^(>=|>|<=|<|=)(.+)$/);
102
+ if (opMatch) {
103
+ op = opMatch[1];
104
+ reqVer = opMatch[2];
105
+ } else {
106
+ op = '=';
107
+ reqVer = constraint;
108
+ }
109
+ reqVer = reqVer.replace(/^v/, '').replace(/-.*$/, '').replace(/\+.*$/, '');
110
+
111
+ function parseTuple(v) {
112
+ const parts = (v + '.0.0').split('.');
113
+ return [
114
+ parseInt(parts[0], 10) || 0,
115
+ parseInt(parts[1], 10) || 0,
116
+ parseInt(parts[2], 10) || 0,
117
+ ];
118
+ }
119
+
120
+ const [vMaj, vMin, vPat] = parseTuple(version);
121
+ const [rMaj, rMin, rPat] = parseTuple(reqVer);
122
+
123
+ const vNum = vMaj * 1_000_000 + vMin * 1_000 + vPat;
124
+ const rNum = rMaj * 1_000_000 + rMin * 1_000 + rPat;
125
+
126
+ switch (op) {
127
+ case '>=': return vNum >= rNum;
128
+ case '>': return vNum > rNum;
129
+ case '<=': return vNum <= rNum;
130
+ case '<': return vNum < rNum;
131
+ case '=': return vNum === rNum;
132
+ default: return false;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Read a field from package.json using dot-notation (e.g. 'engines.node').
138
+ * Returns the string value or empty string if absent.
139
+ * Uses './package.json' so Node resolves relative to CWD on all platforms.
140
+ */
141
+ function pkgField(fieldPath) {
142
+ try {
143
+ const pkg = JSON.parse(fs.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf8'));
144
+ let val = pkg;
145
+ for (const key of fieldPath.split('.')) {
146
+ if (val == null || typeof val !== 'object') return '';
147
+ val = val[key];
148
+ }
149
+ return val != null ? String(val) : '';
150
+ } catch {
151
+ return '';
152
+ }
153
+ }
154
+
155
+ // ---------------------------------------------------------------------------
156
+ // Check 1: Node version vs engines.node
157
+ // ---------------------------------------------------------------------------
158
+ const enginesNode = pkgField('engines.node');
159
+ let currentNode = '';
160
+ try {
161
+ currentNode = process.version.replace(/^v/, '');
162
+ } catch { /* ignore */ }
163
+
164
+ if (!currentNode) {
165
+ addCheck('node-version', 'fail', 'node binary not found on PATH');
166
+ } else if (!enginesNode) {
167
+ addCheck('node-version', 'fail', 'engines.node missing from package.json — add it (see D2 in docs/contributing/bootstrap.md)');
168
+ } else {
169
+ if (satisfiesConstraint(currentNode, enginesNode)) {
170
+ addCheck('node-version', 'pass', `Node ${currentNode} satisfies ${enginesNode}`);
171
+ } else {
172
+ addCheck('node-version', 'fail', `Node ${currentNode} does NOT satisfy engines.node ${enginesNode}`);
173
+ }
174
+ }
175
+
176
+ // ---------------------------------------------------------------------------
177
+ // Check 2: npm version vs engines.npm (skip if field absent)
178
+ // ---------------------------------------------------------------------------
179
+ const enginesNpm = pkgField('engines.npm');
180
+ let currentNpm = '';
181
+ try {
182
+ const res = spawnSync(npmCmd, ['--version'], { encoding: 'utf8', timeout: 10_000, shell: process.platform === 'win32' });
183
+ if (res.status === 0 && res.stdout) {
184
+ currentNpm = res.stdout.trim();
185
+ }
186
+ } catch { /* ignore */ }
187
+
188
+ if (!enginesNpm) {
189
+ addCheck('npm-version', 'skip', 'engines.npm not set in package.json — skipping');
190
+ } else if (!currentNpm) {
191
+ addCheck('npm-version', 'fail', 'npm binary not found on PATH');
192
+ } else {
193
+ if (satisfiesConstraint(currentNpm, enginesNpm)) {
194
+ addCheck('npm-version', 'pass', `npm ${currentNpm} satisfies ${enginesNpm}`);
195
+ } else {
196
+ addCheck('npm-version', 'fail', `npm ${currentNpm} does NOT satisfy engines.npm ${enginesNpm}`);
197
+ }
198
+ }
199
+
200
+ // ---------------------------------------------------------------------------
201
+ // Check 3: Lockfile presence
202
+ // ---------------------------------------------------------------------------
203
+ const LOCKFILE = path.join(PROJECT_ROOT, 'package-lock.json');
204
+ if (fs.existsSync(LOCKFILE)) {
205
+ addCheck('lockfile-present', 'pass', 'package-lock.json exists');
206
+ } else {
207
+ addCheck('lockfile-present', 'fail', "package-lock.json missing — run 'npm install' to generate it");
208
+ }
209
+
210
+ // ---------------------------------------------------------------------------
211
+ // Check 4: Lockfile sync (npm ci --dry-run)
212
+ // ---------------------------------------------------------------------------
213
+ if (fs.existsSync(LOCKFILE)) {
214
+ try {
215
+ const res = spawnSync(npmCmd, ['ci', '--dry-run'], {
216
+ cwd: PROJECT_ROOT,
217
+ encoding: 'utf8',
218
+ shell: process.platform === 'win32',
219
+ });
220
+ if (res.status === 0) {
221
+ addCheck('lockfile-sync', 'pass', 'package-lock.json is in sync with package.json');
222
+ } else {
223
+ addCheck('lockfile-sync', 'fail', "package-lock.json is out of sync — run 'npm ci' to restore");
224
+ }
225
+ } catch {
226
+ addCheck('lockfile-sync', 'fail', "package-lock.json is out of sync — run 'npm ci' to restore");
227
+ }
228
+ } else {
229
+ addCheck('lockfile-sync', 'skip', 'skipped — lockfile missing');
230
+ }
231
+
232
+ // ---------------------------------------------------------------------------
233
+ // Check 5: Version manager pin vs active Node
234
+ // Looks for .nvmrc, .node-version, or .tool-versions at project root.
235
+ // ---------------------------------------------------------------------------
236
+ const NVMRC = path.join(PROJECT_ROOT, '.nvmrc');
237
+ const NODE_VERSION_FILE = path.join(PROJECT_ROOT, '.node-version');
238
+ const TOOL_VERSIONS = path.join(PROJECT_ROOT, '.tool-versions');
239
+
240
+ let pinnedMajor = '';
241
+ let pinSource = '';
242
+
243
+ if (fs.existsSync(NVMRC)) {
244
+ const content = fs.readFileSync(NVMRC, 'utf8').split('\n')[0].trim().replace(/^v/, '');
245
+ pinnedMajor = content.split('.')[0];
246
+ pinSource = '.nvmrc';
247
+ } else if (fs.existsSync(NODE_VERSION_FILE)) {
248
+ const content = fs.readFileSync(NODE_VERSION_FILE, 'utf8').split('\n')[0].trim().replace(/^v/, '');
249
+ pinnedMajor = content.split('.')[0];
250
+ pinSource = '.node-version';
251
+ } else if (fs.existsSync(TOOL_VERSIONS)) {
252
+ const lines = fs.readFileSync(TOOL_VERSIONS, 'utf8').split('\n');
253
+ const nodeLine = lines.find(l => /^nodejs\s+/.test(l));
254
+ if (nodeLine) {
255
+ const ver = nodeLine.split(/\s+/)[1] || '';
256
+ pinnedMajor = ver.replace(/^v/, '').split('.')[0];
257
+ pinSource = '.tool-versions';
258
+ }
259
+ }
260
+
261
+ if (!pinnedMajor) {
262
+ addCheck('version-manager-pin', 'skip', 'no .nvmrc, .node-version, or .tool-versions found — skipping');
263
+ } else if (process.env.CI === 'true') {
264
+ addCheck('version-manager-pin', 'skip', 'CI=true — version-manager pin check skipped (matrix tests multiple Node majors)');
265
+ } else {
266
+ const activeMajor = process.version.replace(/^v/, '').split('.')[0];
267
+ if (activeMajor === pinnedMajor) {
268
+ addCheck('version-manager-pin', 'pass', `Active Node major (${activeMajor}) matches ${pinSource} pin (${pinnedMajor})`);
269
+ } else {
270
+ addCheck('version-manager-pin', 'fail', `Active Node major (${activeMajor}) does NOT match ${pinSource} pin (${pinnedMajor}) — run 'nvm use' or equivalent`);
271
+ }
272
+ }
273
+
274
+ // ---------------------------------------------------------------------------
275
+ // Output
276
+ // ---------------------------------------------------------------------------
277
+ const overallPass = checks.every(c => c.status !== 'fail');
278
+
279
+ if (jsonMode) {
280
+ // Structured JSON: {pass: bool, checks: [{name, status, message}]}
281
+ const out = {
282
+ pass: overallPass,
283
+ checks: checks.map(c => ({ name: c.name, status: c.status, message: c.message })),
284
+ };
285
+ process.stdout.write(JSON.stringify(out, null, 2) + '\n');
286
+ } else {
287
+ // Human-readable report
288
+ process.stdout.write('=== Environment Check ===\n');
289
+ for (const { name, status, message } of checks) {
290
+ const icon = status === 'pass' ? '[PASS]' : status === 'fail' ? '[FAIL]' : '[SKIP]';
291
+ const namePadded = name.padEnd(25);
292
+ process.stdout.write(` ${icon} ${namePadded} ${message}\n`);
293
+ }
294
+ process.stdout.write('\n');
295
+ if (overallPass) {
296
+ process.stdout.write('Result: ALL CHECKS PASSED\n');
297
+ } else {
298
+ process.stdout.write('Result: ONE OR MORE CHECKS FAILED — see above\n');
299
+ }
300
+ }
301
+
302
+ process.exit(overallPass ? 0 : 1);