@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,83 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lint-descriptions.cjs
4
+ *
5
+ * Enforces the 100-char description budget for commands/gsd/*.md files.
6
+ *
7
+ * Usage:
8
+ * node scripts/lint-descriptions.cjs [file.md ...]
9
+ *
10
+ * If no args are given, scans commands/gsd/ automatically.
11
+ * Exits 1 if any description exceeds 100 chars; exits 0 if all pass.
12
+ */
13
+
14
+ 'use strict';
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+
19
+ const MAX_LENGTH = 100;
20
+ const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
21
+
22
+ /**
23
+ * Parse the description field from frontmatter in a .md file.
24
+ * Returns null if no description is found.
25
+ */
26
+ function parseDescription(content) {
27
+ const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
28
+ if (!fmMatch) return null;
29
+ const fm = fmMatch[1];
30
+
31
+ const quoted = fm.match(/^description:\s+"((?:[^"\\]|\\.)*)"\s*$/m);
32
+ if (quoted) return quoted[1];
33
+
34
+ const plain = fm.match(/^description:\s+(.+)$/m);
35
+ if (plain) return plain[1].trim();
36
+
37
+ return null;
38
+ }
39
+
40
+ function getFiles() {
41
+ if (process.argv.length > 2) {
42
+ return process.argv.slice(2);
43
+ }
44
+ return fs.readdirSync(COMMANDS_DIR)
45
+ .filter(f => f.endsWith('.md'))
46
+ .map(f => path.join(COMMANDS_DIR, f));
47
+ }
48
+
49
+ const files = getFiles();
50
+ const violations = [];
51
+
52
+ for (const filePath of files) {
53
+ let content;
54
+ try {
55
+ content = fs.readFileSync(filePath, 'utf-8');
56
+ } catch (err) {
57
+ process.stderr.write(`ERROR: Cannot read file: ${filePath}\n ${err.message}\n`);
58
+ process.exit(1);
59
+ }
60
+
61
+ const description = parseDescription(content);
62
+ if (description === null) continue;
63
+
64
+ if (description.length > MAX_LENGTH) {
65
+ violations.push({ filePath, length: description.length, description });
66
+ }
67
+ }
68
+
69
+ if (violations.length === 0) {
70
+ const checked = files.length;
71
+ process.stdout.write(`ok lint-descriptions: ${checked} file(s) checked, 0 violations\n`);
72
+ process.exit(0);
73
+ }
74
+
75
+ process.stderr.write(`\nERROR lint-descriptions: ${violations.length} violation(s) found\n\n`);
76
+ for (const v of violations) {
77
+ const preview = v.description.length > 120 ? v.description.slice(0, 117) + '...' : v.description;
78
+ process.stderr.write(` ${v.filePath}\n`);
79
+ process.stderr.write(` Length : ${v.length} (max ${MAX_LENGTH})\n`);
80
+ process.stderr.write(` Desc : ${preview}\n\n`);
81
+ }
82
+ process.stderr.write(`Trim descriptions to <= ${MAX_LENGTH} chars. Flag docs belong in argument-hint:.\n\n`);
83
+ process.exit(1);
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Docs-required lint (#3213).
6
+ *
7
+ * Mirrors scripts/changeset/lint.cjs. Pure verdict function
8
+ * evaluateLint({ changedFiles, fragments, labels, malformed }) returns
9
+ * { ok, reason, triggering } using the LINT_REASON enum. The CLI wrapper
10
+ * reads the PR diff (`git diff --name-only origin/${base}...HEAD`), parses
11
+ * each touched `.changeset/*.md` fragment, then calls evaluateLint.
12
+ *
13
+ * Tests assert on the structured verdict, never on free text.
14
+ */
15
+
16
+ const { parseFragment, FRAGMENT_ERROR } = require('./changeset/parse.cjs');
17
+
18
+ const LINT_REASON = Object.freeze({
19
+ OK_NO_TRIGGERING_FRAGMENTS: 'ok_no_triggering_fragments',
20
+ OK_DOCS_UPDATED: 'ok_docs_updated',
21
+ OK_OPT_OUT_LABEL: 'ok_opt_out_label',
22
+ OK_FRAGMENTS_EXEMPT: 'ok_fragments_exempt',
23
+ FAIL_DOCS_MISSING: 'fail_docs_missing',
24
+ FAIL_MALFORMED_FRAGMENT: 'fail_malformed_fragment',
25
+ });
26
+
27
+ const OPT_OUT_LABEL = 'no-docs';
28
+
29
+ // Fragment types that require a docs update. `Fixed` and `Security` are
30
+ // bug-class — they describe regressions or vulnerabilities, not new
31
+ // behavior to document.
32
+ const TRIGGERING_TYPES = new Set(['Added', 'Changed', 'Deprecated', 'Removed']);
33
+
34
+ const DOCS_PREFIX = 'docs/';
35
+
36
+ function isFragmentPath(file) {
37
+ return /^\.changeset\/[^/]+\.md$/.test(file) && !file.endsWith('/README.md');
38
+ }
39
+
40
+ function isDocsFile(file) {
41
+ return file.startsWith(DOCS_PREFIX);
42
+ }
43
+
44
+ // Per-fragment escape hatch: parse.cjs extracts `<!-- docs-exempt: <reason> -->`
45
+ // from the body into `fragment.docsExempt` (a non-empty reason string when the
46
+ // marker was present and well-formed; `null` otherwise). A non-empty audit
47
+ // trail is required — the lint defends in depth here too: even if a caller
48
+ // constructs a fragment with `docsExempt: ''`, that does not count as exempt.
49
+ function isExemptFragment(fragment) {
50
+ return typeof fragment.docsExempt === 'string' && fragment.docsExempt.trim().length > 0;
51
+ }
52
+
53
+ /**
54
+ * Pure verdict — no fs, no git.
55
+ *
56
+ * Malformed fragments fail closed: a triggering fragment with bad frontmatter
57
+ * cannot silently bypass docs enforcement. The changeset-required lint only
58
+ * checks fragment _presence_, not _validity_, so docs lint takes responsibility
59
+ * for any fragment it tries to consume.
60
+ *
61
+ * @param {object} args
62
+ * @param {string[]} args.changedFiles - file paths changed in the PR
63
+ * @param {Array<{ path: string, type: string, body: string, docsExempt: string|null }>} args.fragments
64
+ * - parsed records for well-formed `.changeset/*.md` files in `changedFiles`
65
+ * @param {Array<{ path: string, reason: string }>} [args.malformed]
66
+ * - records for `.changeset/*.md` files that failed `parseFragment`
67
+ * @param {string[]} args.labels - PR labels
68
+ * @returns {{ ok: boolean, reason: string, triggering: string[], malformed?: Array<{path:string,reason:string}> }}
69
+ */
70
+ function evaluateLint({ changedFiles, fragments, labels, malformed = [] }) {
71
+ if (malformed.length > 0) {
72
+ return {
73
+ ok: false,
74
+ reason: LINT_REASON.FAIL_MALFORMED_FRAGMENT,
75
+ triggering: [],
76
+ malformed,
77
+ };
78
+ }
79
+
80
+ const triggering = fragments.filter((f) => TRIGGERING_TYPES.has(f.type));
81
+ const triggeringPaths = triggering.map((f) => f.path);
82
+
83
+ if (triggering.length === 0) {
84
+ return { ok: true, reason: LINT_REASON.OK_NO_TRIGGERING_FRAGMENTS, triggering: [] };
85
+ }
86
+
87
+ // Per-fragment exempt path: every triggering fragment must carry the marker.
88
+ // Partial exemption fails closed — one un-marked Added fragment still requires docs.
89
+ if (triggering.every(isExemptFragment)) {
90
+ return { ok: true, reason: LINT_REASON.OK_FRAGMENTS_EXEMPT, triggering: triggeringPaths };
91
+ }
92
+
93
+ if (labels.includes(OPT_OUT_LABEL)) {
94
+ return { ok: true, reason: LINT_REASON.OK_OPT_OUT_LABEL, triggering: triggeringPaths };
95
+ }
96
+
97
+ if (changedFiles.some(isDocsFile)) {
98
+ return { ok: true, reason: LINT_REASON.OK_DOCS_UPDATED, triggering: triggeringPaths };
99
+ }
100
+
101
+ return { ok: false, reason: LINT_REASON.FAIL_DOCS_MISSING, triggering: triggeringPaths };
102
+ }
103
+
104
+ function readFragmentsFromDisk(changedFiles, rootDir) {
105
+ const fs = require('node:fs');
106
+ const path = require('node:path');
107
+ const fragments = [];
108
+ const malformed = [];
109
+ for (const rel of changedFiles) {
110
+ if (!isFragmentPath(rel)) continue;
111
+ const abs = path.join(rootDir, rel);
112
+ if (!fs.existsSync(abs)) continue; // fragment deleted in PR — skip
113
+ let src;
114
+ try {
115
+ src = fs.readFileSync(abs, 'utf8');
116
+ } catch (e) {
117
+ malformed.push({ path: rel, reason: 'read_error', detail: e.code || e.message });
118
+ continue;
119
+ }
120
+ const parsed = parseFragment(src);
121
+ if (!parsed.ok) {
122
+ malformed.push({ path: rel, reason: parsed.reason, detail: parsed.detail || null });
123
+ continue;
124
+ }
125
+ fragments.push({
126
+ path: rel,
127
+ type: parsed.fragment.type,
128
+ body: parsed.fragment.body,
129
+ docsExempt: parsed.fragment.docsExempt,
130
+ });
131
+ }
132
+ return { fragments, malformed };
133
+ }
134
+
135
+ function main() {
136
+ const fs = require('node:fs');
137
+ const cp = require('node:child_process');
138
+ const path = require('node:path');
139
+
140
+ const rootDir = path.join(__dirname, '..');
141
+
142
+ const eventPath = process.env.GITHUB_EVENT_PATH;
143
+ let labels = [];
144
+ if (eventPath && fs.existsSync(eventPath)) {
145
+ try {
146
+ const event = JSON.parse(fs.readFileSync(eventPath, 'utf8'));
147
+ labels = (event.pull_request?.labels || []).map((l) => l.name);
148
+ } catch { /* fall through */ }
149
+ }
150
+
151
+ const base = process.env.GITHUB_BASE_REF || 'main';
152
+ let changedFiles = [];
153
+ try {
154
+ // execFileSync with argv — no shell, so a malicious GITHUB_BASE_REF
155
+ // cannot inject shell syntax. Git's own ref-name validator rejects
156
+ // any metacharacters it would otherwise interpret.
157
+ const out = cp.execFileSync(
158
+ 'git',
159
+ ['diff', '--name-only', `origin/${base}...HEAD`],
160
+ { encoding: 'utf8', cwd: rootDir },
161
+ );
162
+ changedFiles = out.split('\n').filter(Boolean);
163
+ } catch (e) {
164
+ process.stderr.write(`could not compute diff: ${e.message}\n`);
165
+ process.exit(2);
166
+ }
167
+
168
+ const { fragments, malformed } = readFragmentsFromDisk(changedFiles, rootDir);
169
+ const verdict = evaluateLint({ changedFiles, fragments, labels, malformed });
170
+
171
+ if (process.argv.includes('--json')) {
172
+ process.stdout.write(
173
+ JSON.stringify({ ...verdict, changedFiles, fragments, malformed, labels }, null, 2) + '\n',
174
+ );
175
+ } else if (verdict.ok) {
176
+ process.stdout.write(`ok docs-lint: ${verdict.reason}\n`);
177
+ } else if (verdict.reason === LINT_REASON.FAIL_MALFORMED_FRAGMENT) {
178
+ process.stderr.write(`\nERROR docs-lint: ${verdict.reason}\n`);
179
+ process.stderr.write(
180
+ `${malformed.length} changeset fragment(s) failed to parse — docs lint cannot consume them:\n`,
181
+ );
182
+ for (const m of malformed) {
183
+ process.stderr.write(` ${m.path} (reason: ${m.reason}${m.detail ? `, detail: ${m.detail}` : ''})\n`);
184
+ }
185
+ process.stderr.write(
186
+ `\nFix the fragment frontmatter (\`type:\` + \`pr:\`) before this PR can pass.\n`,
187
+ );
188
+ } else {
189
+ process.stderr.write(`\nERROR docs-lint: ${verdict.reason}\n`);
190
+ process.stderr.write(
191
+ `${verdict.triggering.length} changeset fragment(s) require documentation updates:\n`,
192
+ );
193
+ for (const f of fragments.filter((f) => TRIGGERING_TYPES.has(f.type))) {
194
+ process.stderr.write(` ${f.path} (type: ${f.type})\n`);
195
+ }
196
+ process.stderr.write(`\nNo files under docs/ were modified in this PR.\n\n`);
197
+ process.stderr.write(
198
+ `Update the relevant docs/ file(s), or add the \`${OPT_OUT_LABEL}\` label if this change\n`,
199
+ );
200
+ process.stderr.write(
201
+ `is genuinely internal-only (infrastructure, refactor, test-only). Per-fragment\n`,
202
+ );
203
+ process.stderr.write(
204
+ `exemption via \`<!-- docs-exempt: <reason> -->\` inside the fragment body also works.\n`,
205
+ );
206
+ }
207
+ process.exit(verdict.ok ? 0 : 1);
208
+ }
209
+
210
+ if (require.main === module) main();
211
+
212
+ module.exports = {
213
+ evaluateLint,
214
+ readFragmentsFromDisk,
215
+ LINT_REASON,
216
+ OPT_OUT_LABEL,
217
+ TRIGGERING_TYPES,
218
+ FRAGMENT_ERROR,
219
+ isFragmentPath,
220
+ isDocsFile,
221
+ isExemptFragment,
222
+ };
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Extended detector for the no-source-grep rule (#2982).
5
+ *
6
+ * The base lint (scripts/lint-no-source-grep.cjs) only catches the
7
+ * direct-chain form: readFileSync(...).includes(...). The much more common
8
+ * var-binding form escapes it:
9
+ *
10
+ * const src = fs.readFileSync(p, 'utf8');
11
+ * // ... 50 lines later ...
12
+ * assert.ok(src.includes('foo')); // ← still source-grep, lint missed it
13
+ *
14
+ * This module exposes pure detectors that scan source text and return
15
+ * structured violation records. The CLI wrapper (in the base lint) calls
16
+ * these for each test file.
17
+ *
18
+ * Tests assert on the typed VIOLATION enum codes, not on prose messages.
19
+ */
20
+
21
+ const VIOLATION = Object.freeze({
22
+ VAR_FROM_READFILE_USED_IN_TEXT_MATCH: 'var_from_readfile_used_in_text_match',
23
+ WRAPPED_ASSERT_OK_MATCH: 'wrapped_assert_ok_match',
24
+ });
25
+
26
+ const TEXT_MATCH_METHODS = ['includes', 'startsWith', 'endsWith', 'match', 'search'];
27
+
28
+ /**
29
+ * Single-pass scanner. Tracks variables bound from a readFileSync call,
30
+ * then flags any subsequent <var>.<method>( use where method is one of
31
+ * TEXT_MATCH_METHODS.
32
+ */
33
+ function detectVarBindingViolations(src) {
34
+ // Pass 1: collect variables bound from readFileSync.
35
+ // Matches: const|let|var <name> = [fs.]readFileSync(
36
+ const bindRe = /(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:[A-Za-z_$][\w$.]*\.)?readFileSync\s*\(/g;
37
+ const boundVars = new Set();
38
+ let m;
39
+ while ((m = bindRe.exec(src)) !== null) {
40
+ boundVars.add(m[1]);
41
+ }
42
+ if (boundVars.size === 0) return [];
43
+
44
+ // Pass 2: find <var>.<method>( on any bound var.
45
+ const findings = [];
46
+ // Build a regex alternation from the bound var names.
47
+ const alt = [...boundVars].map((v) => v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
48
+ const useRe = new RegExp(
49
+ `\\b(${alt})\\s*\\.\\s*(${TEXT_MATCH_METHODS.join('|')})\\s*\\(`,
50
+ 'g',
51
+ );
52
+ while ((m = useRe.exec(src)) !== null) {
53
+ findings.push({
54
+ kind: VIOLATION.VAR_FROM_READFILE_USED_IN_TEXT_MATCH,
55
+ variable: m[1],
56
+ method: m[2],
57
+ });
58
+ }
59
+ return findings;
60
+ }
61
+
62
+ /**
63
+ * Detects assert.ok(<expr>.match(/.../)) and assert.ok(<expr>.match(<expr>))
64
+ * which is the same anti-pattern as assert.match but escapes the simpler
65
+ * regex used by the base lint.
66
+ */
67
+ function detectWrappedAssertOkMatch(src) {
68
+ const re = /assert\.ok\s*\(\s*[A-Za-z_$][\w$.]*\.match\s*\(/g;
69
+ const findings = [];
70
+ let m;
71
+ while ((m = re.exec(src)) !== null) {
72
+ findings.push({ kind: VIOLATION.WRAPPED_ASSERT_OK_MATCH });
73
+ }
74
+ return findings;
75
+ }
76
+
77
+ function detectAll(src) {
78
+ return [...detectVarBindingViolations(src), ...detectWrappedAssertOkMatch(src)];
79
+ }
80
+
81
+ module.exports = { detectVarBindingViolations, detectWrappedAssertOkMatch, detectAll, VIOLATION };
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lint-no-source-grep.cjs
4
+ *
5
+ * Enforces the "no source-grep tests" rule:
6
+ * Tests must NOT read source-code .cjs files with readFileSync to assert string
7
+ * presence. That pattern (source-grep theater) proves a literal exists in source,
8
+ * not that the runtime behavior is correct.
9
+ *
10
+ * ALLOWED:
11
+ * - require('../get-shit-done/bin/lib/foo.cjs') -- runs the module, not text inspection
12
+ * - readFileSync on .md / .json / .txt files -- product-content or config output
13
+ * - Files annotated: // allow-test-rule: <reason>
14
+ *
15
+ * DISALLOWED (without allow-test-rule):
16
+ * - readFileSync where the path argument ends in a .cjs filename literal
17
+ * - A path constant (e.g. CONFIG_PATH) assigned to a .cjs lib file, used in readFileSync
18
+ *
19
+ * Exit 0 = clean. Exit 1 = violations found (with diagnostics).
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ const fs = require('fs');
25
+ const path = require('path');
26
+
27
+ const TESTS_DIR = path.join(__dirname, '..', 'tests');
28
+ const ALLOW_ANNOTATION = /\/\/\s*allow-test-rule:\s*\S/;
29
+
30
+ // Matches constant definitions that hold a .cjs path in a SOURCE directory.
31
+ // Requires a source-dir indicator ('bin', 'lib', 'get-shit-done') to avoid
32
+ // flagging temp files like path.join(tmpDir, 'example.cjs').
33
+ // const CONFIG_PATH = path.join(__dirname, '..', 'get-shit-done', 'bin', 'lib', 'config-schema.cjs');
34
+ const CJS_PATH_CONST_RE = /(?:const|let|var)\s+(\w+)\s*=\s*path\.join\s*\([^)]*(?:'bin'|"bin"|'lib'|"lib"|'get-shit-done'|"get-shit-done")[^)]*['"][^'"]*\.cjs['"]/gm;
35
+
36
+ // Matches readFileSync with a named variable as first arg
37
+ const READ_WITH_CONST_RE = /readFileSync\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,/gm;
38
+
39
+ // Matches readFileSync with an inline path.join(.cjs) as first arg
40
+ const READ_WITH_INLINE_CJS_RE = /readFileSync\s*\([^,)]*path\.join\s*\([^)]*(?:'bin'|"bin"|'lib'|"lib"|'get-shit-done'|"get-shit-done")[^)]*['"][^'"]*\.cjs['"]/;
41
+
42
+ /**
43
+ * #2962-class violations: raw text matching against process output or file
44
+ * content. The rule from CONTRIBUTING.md "Prohibited: Raw Text Matching on
45
+ * Test Outputs": tests assert on typed structured fields, never on rendered
46
+ * text. Patterns below are the obvious anti-patterns; subtler hidden forms
47
+ * (e.g. wrapping the same logic in a parser function) are still forbidden
48
+ * by the prose rule but cannot be detected lexically without an AST.
49
+ */
50
+ const RAW_MATCH_PATTERNS = [
51
+ {
52
+ re: /assert\.(?:match|doesNotMatch)\s*\(\s*[A-Za-z_$][A-Za-z0-9_$]*\.(?:stdout|stderr)\b/,
53
+ label: 'assert.match/doesNotMatch on .stdout/.stderr (emit --json from the SUT and assert on typed fields)',
54
+ },
55
+ {
56
+ re: /\.(?:stdout|stderr)\.(?:includes|startsWith|endsWith)\s*\(/,
57
+ label: '.stdout/.stderr substring match (emit --json and assert on typed fields)',
58
+ },
59
+ {
60
+ re: /readFileSync\s*\([^)]*\)\s*\.(?:includes|startsWith|endsWith)\s*\(/,
61
+ label: 'readFileSync(...).<includes|startsWith|endsWith> (expose an IR from production code; assert on its fields)',
62
+ },
63
+ ];
64
+
65
+ function setFromMatches(content, re) {
66
+ const found = new Set();
67
+ let m;
68
+ const cloned = new RegExp(re.source, re.flags);
69
+ while ((m = cloned.exec(content)) !== null) found.add(m[1]);
70
+ return found;
71
+ }
72
+
73
+ function check(filepath) {
74
+ const content = fs.readFileSync(filepath, 'utf-8');
75
+ const rel = path.relative(path.join(__dirname, '..'), filepath);
76
+
77
+ if (ALLOW_ANNOTATION.test(content)) return null;
78
+
79
+ const violations = [];
80
+
81
+ // Pattern A: readFileSync(path.join(..., 'foo.cjs'), ...)
82
+ if (READ_WITH_INLINE_CJS_RE.test(content)) {
83
+ violations.push({
84
+ reason: 'readFileSync with inline .cjs path literal',
85
+ fix: 'Replace with runGsdTools() behavioral test, or add // allow-test-rule: <reason>',
86
+ });
87
+ }
88
+
89
+ // Pattern B: const FOO_PATH = path.join(..., 'foo.cjs') + readFileSync(FOO_PATH, ...)
90
+ const cjsConsts = setFromMatches(content, CJS_PATH_CONST_RE);
91
+ if (cjsConsts.size > 0) {
92
+ const readConsts = setFromMatches(content, READ_WITH_CONST_RE);
93
+ const overlap = [...cjsConsts].filter(c => readConsts.has(c));
94
+ if (overlap.length > 0) {
95
+ violations.push({
96
+ reason: `source .cjs path constant(s) used in readFileSync: ${overlap.join(', ')}`,
97
+ fix: 'Replace with runGsdTools() behavioral test, or add // allow-test-rule: <reason>',
98
+ });
99
+ }
100
+ }
101
+
102
+ // Patterns C..E: raw text matching against process output or file content.
103
+ // See CONTRIBUTING.md "Prohibited: Raw Text Matching on Test Outputs".
104
+ for (const { re, label } of RAW_MATCH_PATTERNS) {
105
+ if (re.test(content)) {
106
+ violations.push({
107
+ reason: label,
108
+ fix: 'Expose typed IR from production code; assert on structured fields. Or add // allow-test-rule: <reason>',
109
+ });
110
+ }
111
+ }
112
+
113
+ // Patterns F..G (#2982): var-binding readFileSync().<text-method>() and
114
+ // assert.ok(<expr>.match(...)). These escape the simpler patterns above
115
+ // because the bind and the use are on different lines or wrapped.
116
+ const extras = require('./lint-no-source-grep-extras.cjs');
117
+ const varBindFindings = extras.detectVarBindingViolations(content);
118
+ if (varBindFindings.length > 0) {
119
+ const samples = varBindFindings.slice(0, 3)
120
+ .map((f) => `${f.variable}.${f.method}()`)
121
+ .join(', ');
122
+ violations.push({
123
+ reason: `readFileSync-bound variable used in text-match method: ${samples}${varBindFindings.length > 3 ? `, …+${varBindFindings.length - 3} more` : ''}`,
124
+ fix: 'Expose typed IR; assert on structured fields. Or // allow-test-rule: <reason>',
125
+ });
126
+ }
127
+ const wrappedFindings = extras.detectWrappedAssertOkMatch(content);
128
+ if (wrappedFindings.length > 0) {
129
+ violations.push({
130
+ reason: `assert.ok(<expr>.match(...)) — escapes assert.match rule (${wrappedFindings.length} occurrence${wrappedFindings.length > 1 ? 's' : ''})`,
131
+ fix: 'Use assert.equal on a typed field, not regex match on text. Or // allow-test-rule: <reason>',
132
+ });
133
+ }
134
+
135
+ if (violations.length === 0) return null;
136
+ return { file: rel, violations };
137
+ }
138
+
139
+ function findTestFiles(dir) {
140
+ const results = [];
141
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
142
+ const full = path.join(dir, entry.name);
143
+ if (entry.isDirectory()) {
144
+ results.push(...findTestFiles(full));
145
+ } else if (entry.name.endsWith('.test.cjs')) {
146
+ results.push(full);
147
+ }
148
+ }
149
+ return results;
150
+ }
151
+
152
+ const testFiles = findTestFiles(TESTS_DIR);
153
+
154
+ const violations = testFiles.map(check).filter(Boolean);
155
+
156
+ if (violations.length === 0) {
157
+ console.log(`ok lint-no-source-grep: ${testFiles.length} test files checked, 0 violations`);
158
+ process.exit(0);
159
+ }
160
+
161
+ const totalIssues = violations.reduce((n, v) => n + v.violations.length, 0);
162
+ process.stderr.write(`\nERROR lint-no-source-grep: ${totalIssues} violation(s) across ${violations.length} file(s)\n\n`);
163
+ for (const f of violations) {
164
+ process.stderr.write(` ${f.file}\n`);
165
+ for (const v of f.violations) {
166
+ process.stderr.write(` Problem : ${v.reason}\n`);
167
+ process.stderr.write(` Fix : ${v.fix}\n`);
168
+ }
169
+ process.stderr.write('\n');
170
+ }
171
+ process.stderr.write('See CONTRIBUTING.md "Prohibited: Source-Grep Tests" and\n');
172
+ process.stderr.write('"Prohibited: Raw Text Matching on Test Outputs" for guidance.\n');
173
+ process.stderr.write('Structural tests that legitimately read source files: add // allow-test-rule: <reason>\n\n');
174
+ process.exit(1);