@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,282 @@
1
+ #!/usr/bin/env node
2
+ // Cross-platform test runner — resolves test file globs via Node
3
+ // instead of relying on shell expansion (which fails on Windows PowerShell/cmd).
4
+ // Propagates NODE_V8_COVERAGE so c8 collects coverage from the child process.
5
+ //
6
+ // Suite filtering (issue #3597):
7
+ // node scripts/run-tests.cjs # default — runs ALL tests (backcompat)
8
+ // node scripts/run-tests.cjs --suite all # explicit "everything"
9
+ // node scripts/run-tests.cjs --suite unit # only files with no other suite marker
10
+ // node scripts/run-tests.cjs --suite security # *.security.test.cjs
11
+ // node scripts/run-tests.cjs --suite integration # *.integration.test.cjs
12
+ // node scripts/run-tests.cjs --suite install # *.install.test.cjs
13
+ // node scripts/run-tests.cjs --suite slow # *.slow.test.cjs
14
+ // node scripts/run-tests.cjs --files "a.test.cjs b.test.cjs"
15
+ // node scripts/run-tests.cjs --files-from /tmp/selected-tests.txt
16
+ //
17
+ // Suite grouping convention: filename suffix marker before `.test.cjs`.
18
+ // A file named `foo.security.test.cjs` belongs to the `security` suite.
19
+ // A file named `foo.test.cjs` (no marker) belongs to the `unit` suite.
20
+ // See docs/TESTING-SUITES.md for full grouping policy.
21
+ 'use strict';
22
+
23
+ const { readdirSync } = require('fs');
24
+ const { join } = require('path');
25
+ const { execFileSync } = require('child_process');
26
+
27
+ const SUITES = ['all', 'unit', 'integration', 'install', 'security', 'slow'];
28
+ const MARKED_SUITES = ['integration', 'install', 'security', 'slow'];
29
+
30
+ function parseArgs(argv) {
31
+ let suite = null;
32
+ let seen = false;
33
+ let files = null;
34
+ let filesFrom = null;
35
+ for (let i = 0; i < argv.length; i++) {
36
+ const a = argv[i];
37
+ if (a === '--suite') {
38
+ if (seen) {
39
+ return { error: 'duplicate --suite flag' };
40
+ }
41
+ seen = true;
42
+ const v = argv[i + 1];
43
+ if (!v || v.startsWith('--')) {
44
+ return { error: '--suite requires a value' };
45
+ }
46
+ suite = v;
47
+ i++;
48
+ } else if (a.startsWith('--suite=')) {
49
+ if (seen) {
50
+ return { error: 'duplicate --suite flag' };
51
+ }
52
+ seen = true;
53
+ suite = a.slice('--suite='.length);
54
+ if (!suite) {
55
+ return { error: '--suite requires a value' };
56
+ }
57
+ } else if (a === '--files') {
58
+ if (files !== null) {
59
+ return { error: 'duplicate --files flag' };
60
+ }
61
+ const v = argv[i + 1];
62
+ if (!v || v.startsWith('--')) {
63
+ return { error: '--files requires a value' };
64
+ }
65
+ files = v;
66
+ i++;
67
+ } else if (a.startsWith('--files=')) {
68
+ if (files !== null) {
69
+ return { error: 'duplicate --files flag' };
70
+ }
71
+ files = a.slice('--files='.length);
72
+ if (!files) {
73
+ return { error: '--files requires a value' };
74
+ }
75
+ } else if (a === '--files-from') {
76
+ if (filesFrom !== null) {
77
+ return { error: 'duplicate --files-from flag' };
78
+ }
79
+ const v = argv[i + 1];
80
+ if (!v || v.startsWith('--')) {
81
+ return { error: '--files-from requires a value' };
82
+ }
83
+ filesFrom = v;
84
+ i++;
85
+ } else if (a.startsWith('--files-from=')) {
86
+ if (filesFrom !== null) {
87
+ return { error: 'duplicate --files-from flag' };
88
+ }
89
+ filesFrom = a.slice('--files-from='.length);
90
+ if (!filesFrom) {
91
+ return { error: '--files-from requires a value' };
92
+ }
93
+ } else {
94
+ return { error: `unknown argument: ${a}` };
95
+ }
96
+ }
97
+ if (files !== null && filesFrom !== null) {
98
+ return { error: '--files and --files-from cannot be combined' };
99
+ }
100
+ return { suite, files, filesFrom };
101
+ }
102
+
103
+ // Return the marked suite name embedded in a filename, or null if it's unmarked.
104
+ // foo.security.test.cjs -> "security"
105
+ // foo.test.cjs -> null (unit)
106
+ function suiteOf(filename) {
107
+ if (!filename.endsWith('.test.cjs')) return null;
108
+ const base = filename.slice(0, -'.test.cjs'.length);
109
+ const lastDot = base.lastIndexOf('.');
110
+ if (lastDot === -1) return null;
111
+ const marker = base.slice(lastDot + 1);
112
+ return MARKED_SUITES.includes(marker) ? marker : null;
113
+ }
114
+
115
+ function selectFiles(allFiles, suite) {
116
+ if (suite === null || suite === 'all') {
117
+ return allFiles;
118
+ }
119
+ if (suite === 'unit') {
120
+ return allFiles.filter(f => suiteOf(f) === null);
121
+ }
122
+ return allFiles.filter(f => suiteOf(f) === suite);
123
+ }
124
+
125
+ function splitFileList(value) {
126
+ if (!value) return [];
127
+ return value
128
+ .split(/[,\s]+/)
129
+ .map(v => v.trim())
130
+ .filter(Boolean)
131
+ .map(v => v.replace(/^tests[\\/]/, ''));
132
+ }
133
+
134
+ function selectExplicitFiles(allFiles, filesValue, filesFrom) {
135
+ const fs = require('fs');
136
+ const requested = filesFrom
137
+ ? splitFileList(fs.readFileSync(filesFrom, 'utf8'))
138
+ : splitFileList(filesValue);
139
+ const available = new Set(allFiles);
140
+ const selected = [];
141
+ const missing = [];
142
+ for (const file of requested) {
143
+ if (available.has(file)) {
144
+ selected.push(file);
145
+ } else {
146
+ missing.push(file);
147
+ }
148
+ }
149
+ if (missing.length > 0) {
150
+ return {
151
+ error: `requested test file(s) not found: ${missing.join(', ')}`,
152
+ };
153
+ }
154
+ return { files: [...new Set(selected)] };
155
+ }
156
+
157
+ function main() {
158
+ const args = process.argv.slice(2);
159
+ const parsed = parseArgs(args);
160
+ if (parsed.error) {
161
+ console.error(`run-tests: ${parsed.error}`);
162
+ console.error(`Valid suites: ${SUITES.join(', ')}`);
163
+ process.exit(2);
164
+ }
165
+ const suite = parsed.suite;
166
+ if (suite !== null && !SUITES.includes(suite)) {
167
+ console.error(`run-tests: unknown suite "${suite}"`);
168
+ console.error(`Valid suites: ${SUITES.join(', ')}`);
169
+ process.exit(2);
170
+ }
171
+
172
+ const testDir = process.env.GSD_TEST_DIR
173
+ ? process.env.GSD_TEST_DIR
174
+ : join(__dirname, '..', 'tests');
175
+
176
+ const allFiles = readdirSync(testDir)
177
+ .filter(f => f.endsWith('.test.cjs'))
178
+ .sort();
179
+
180
+ if (allFiles.length === 0) {
181
+ console.error(`No test files found in ${testDir}`);
182
+ process.exit(1);
183
+ }
184
+
185
+ let selectedNames;
186
+ if (parsed.files !== null || parsed.filesFrom !== null) {
187
+ const explicit = selectExplicitFiles(allFiles, parsed.files, parsed.filesFrom);
188
+ if (explicit.error) {
189
+ console.error(`run-tests: ${explicit.error}`);
190
+ process.exit(2);
191
+ }
192
+ selectedNames = explicit.files;
193
+ } else {
194
+ selectedNames = selectFiles(allFiles, suite);
195
+ }
196
+ const selected = selectedNames.map(f => join(testDir, f));
197
+
198
+ if (selected.length === 0) {
199
+ // Empty suite: report and exit 0 so empty lanes (e.g. `security` before
200
+ // adversarial tests land) don't gate CI. CI consumers wanting strictness
201
+ // can grep stderr for "no tests in suite".
202
+ console.error(`run-tests: no tests in suite "${suite || 'all'}"`);
203
+ process.exit(0);
204
+ }
205
+
206
+ // Log selected files to stderr for CI / harness-test visibility.
207
+ // node:test default reporter doesn't echo filenames, so this gives
208
+ // operators a single stable line they can grep.
209
+ console.error(
210
+ `run-tests: suite="${suite || 'all'}" files=${selected.length}: ${selected
211
+ .map(f => f.split(/[\\/]/).pop())
212
+ .join(' ')}`,
213
+ );
214
+
215
+ // Default concurrency: 4 on Linux/macOS, 2 on Windows.
216
+ //
217
+ // Windows has significantly higher per-subprocess overhead than Linux/macOS:
218
+ // - Windows Defender scans each spawned process
219
+ // - NTFS has higher file-system latency under concurrent access
220
+ // - synckit worker_threads (used by the SDK bridge in gsd-tools.cjs) spawn
221
+ // native threads that contend on SharedArrayBuffer + Atomics.wait; under
222
+ // Node 24 on Windows, 4-way concurrent gsd-tools invocations (each spawning
223
+ // a synckit worker) caused intermittent process crashes with empty stderr —
224
+ // a signature of OS-level resource exhaustion killing worker threads before
225
+ // they could flush. Reducing to 2 halves the peak concurrent worker count.
226
+ //
227
+ // Operator override via TEST_CONCURRENCY env var for local debugging.
228
+ const defaultConcurrency = process.platform === 'win32' ? 2 : 4;
229
+ const concurrency = process.env.TEST_CONCURRENCY
230
+ ? `--test-concurrency=${process.env.TEST_CONCURRENCY}`
231
+ : `--test-concurrency=${defaultConcurrency}`;
232
+
233
+ // Windows `CreateProcess` caps the full command line at 32,767 chars
234
+ // (lpCommandLine). With 500+ test paths the spawn fails instantly with no
235
+ // test output. Linux/macOS allow ~2 MB (ARG_MAX) so unchunked spawns are
236
+ // fine there. Split into chunks sized for the tightest target so behavior
237
+ // is identical across platforms. (#3597)
238
+ // Operator override (also used by tests to force chunking with short paths).
239
+ const MAX_CMDLINE_CHARS = process.env.RUN_TESTS_MAX_CMDLINE_CHARS
240
+ ? Number(process.env.RUN_TESTS_MAX_CMDLINE_CHARS)
241
+ : 28000; // headroom below the 32,767 Windows ceiling
242
+ const FIXED_OVERHEAD = process.execPath.length + '--test'.length + concurrency.length + 8;
243
+ const chunks = [];
244
+ let current = [];
245
+ let currentLen = FIXED_OVERHEAD;
246
+ for (const file of selected) {
247
+ const add = file.length + 1; // +1 for the inter-arg separator
248
+ if (current.length > 0 && currentLen + add > MAX_CMDLINE_CHARS) {
249
+ chunks.push(current);
250
+ current = [];
251
+ currentLen = FIXED_OVERHEAD;
252
+ }
253
+ current.push(file);
254
+ currentLen += add;
255
+ }
256
+ if (current.length > 0) chunks.push(current);
257
+
258
+ let firstFailureExit = 0;
259
+ for (let i = 0; i < chunks.length; i++) {
260
+ if (chunks.length > 1) {
261
+ console.error(`run-tests: chunk ${i + 1}/${chunks.length} — ${chunks[i].length} files`);
262
+ }
263
+ try {
264
+ execFileSync(process.execPath, ['--test', concurrency, ...chunks[i]], {
265
+ stdio: 'inherit',
266
+ env: { ...process.env },
267
+ });
268
+ } catch (err) {
269
+ const code = err.status || 1;
270
+ // Run every chunk so the operator sees all failures in one pass; report
271
+ // the first non-zero exit at the end.
272
+ if (firstFailureExit === 0) firstFailureExit = code;
273
+ }
274
+ }
275
+ if (firstFailureExit !== 0) process.exit(firstFailureExit);
276
+ }
277
+
278
+ if (require.main === module) {
279
+ main();
280
+ }
281
+
282
+ module.exports = { suiteOf };
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env bash
2
+ # secret-scan-lint.sh — Lint governance policy for .secretscanignore exclusions
3
+ #
4
+ # Usage:
5
+ # scripts/secret-scan-lint.sh --file <path-to-.secretscanignore>
6
+ # scripts/secret-scan-lint.sh --file <path-to-.secretscanignore> --strict
7
+ #
8
+ # Exit codes:
9
+ # 0 = every exclusion has full annotation OR is grandfathered (with deprecation warning)
10
+ # 1 = annotation violation: missing required key, expired date, or unguarded wildcard
11
+ # without rule-id; OR (under --strict) any grandfathered entry is present
12
+ # 2 = usage/config error (file not found, invalid arguments)
13
+ #
14
+ # Annotation syntax (sidecar comment, must immediately precede the path line):
15
+ # # allow: <pattern> reason="..." owner="..." expires="YYYY-MM-DD" [rule-id="..."]
16
+ # <pattern>
17
+ #
18
+ # Required annotation keys: reason, owner, expires
19
+ # Optional annotation key: rule-id (REQUIRED when pattern contains '*' wildcards)
20
+ #
21
+ # Grandfathered entries: paths with any preceding plain comment (not a structured
22
+ # annotation) are treated as grandfathered in default mode — exit 0 with a
23
+ # deprecation warning to stderr. Under --strict, grandfathered entries cause exit 1.
24
+ #
25
+ # Design references:
26
+ # - GitGuardian exclusion annotation convention:
27
+ # https://docs.gitguardian.com/internal-repositories-monitoring/integrations/cli/secrets
28
+ # - CNCF Security TAG threat-model exception lifecycle:
29
+ # https://github.com/cncf/tag-security/blob/main/community/working-groups/threat-modeling/templates/threats.md
30
+ #
31
+ # Exit-code alignment with secret-scan.sh:
32
+ # Both scripts use 0=clean, 1=policy-violation/findings, 2=usage/config-error.
33
+ # The symmetry is intentional — CI can treat either non-zero as a gate failure.
34
+
35
+ set -euo pipefail
36
+
37
+ # ─── Argument Parsing ─────────────────────────────────────────────────────────
38
+
39
+ STRICT=false
40
+ IGNOREFILE=""
41
+
42
+ usage() {
43
+ echo "Usage: $0 --file <path-to-.secretscanignore> [--strict]" >&2
44
+ exit 2
45
+ }
46
+
47
+ while [[ $# -gt 0 ]]; do
48
+ case "$1" in
49
+ --file)
50
+ shift
51
+ [[ $# -eq 0 ]] && usage
52
+ IGNOREFILE="$1"
53
+ shift
54
+ ;;
55
+ --strict)
56
+ STRICT=true
57
+ shift
58
+ ;;
59
+ -h|--help)
60
+ usage
61
+ ;;
62
+ *)
63
+ echo "Error: unknown argument: $1" >&2
64
+ usage
65
+ ;;
66
+ esac
67
+ done
68
+
69
+ if [[ -z "$IGNOREFILE" ]]; then
70
+ usage
71
+ fi
72
+
73
+ if [[ ! -f "$IGNOREFILE" ]]; then
74
+ echo "Error: file not found: $IGNOREFILE" >&2
75
+ exit 2
76
+ fi
77
+
78
+ # ─── Date Helpers ─────────────────────────────────────────────────────────────
79
+
80
+ # Returns today's date as YYYY-MM-DD (portable across macOS and Linux)
81
+ today_date() {
82
+ date +%Y-%m-%d
83
+ }
84
+
85
+ # Returns true (0) if date1 < date2 (both YYYY-MM-DD strings)
86
+ date_is_past() {
87
+ local check_date="$1"
88
+ local today
89
+ today=$(today_date)
90
+ # Lexicographic comparison works for ISO-8601 dates
91
+ [[ "$check_date" < "$today" ]]
92
+ }
93
+
94
+ # ─── Annotation Parser ────────────────────────────────────────────────────────
95
+
96
+ # Returns value of a key="value" or key='value' pair from a string.
97
+ # Usage: extract_key <string> <key>
98
+ extract_key() {
99
+ local str="$1"
100
+ local key="$2"
101
+ # Match key="value" or key='value'
102
+ local val
103
+ val=$(echo "$str" | grep -oE "${key}=['\"][^'\"]+['\"]" | head -1 | sed "s/${key}=['\"]//;s/['\"]$//") || true
104
+ echo "$val"
105
+ }
106
+
107
+ # Returns true (0) if the string contains a wildcard glob character (* or **)
108
+ contains_wildcard() {
109
+ local pattern="$1"
110
+ [[ "$pattern" == *"*"* ]]
111
+ }
112
+
113
+ # Returns true (0) if a comment line is a structured annotation
114
+ # (must start with "# allow:" prefix)
115
+ is_structured_annotation() {
116
+ local comment="$1"
117
+ [[ "$comment" =~ ^#[[:space:]]+allow:[[:space:]] ]]
118
+ }
119
+
120
+ # ─── Main Lint Logic ──────────────────────────────────────────────────────────
121
+
122
+ VIOLATIONS=0
123
+ WARNINGS=0
124
+
125
+ # We process the file line-by-line, tracking the comment immediately preceding
126
+ # each path entry. If the preceding line was a comment, we inspect it.
127
+
128
+ prev_comment=""
129
+ lineno=0
130
+
131
+ while IFS= read -r line || [[ -n "$line" ]]; do
132
+ lineno=$((lineno + 1))
133
+
134
+ # Skip empty lines (reset prev_comment to avoid false association)
135
+ if [[ -z "${line// }" ]]; then
136
+ prev_comment=""
137
+ continue
138
+ fi
139
+
140
+ # Accumulate comment lines
141
+ if [[ "$line" =~ ^[[:space:]]*# ]]; then
142
+ prev_comment="$line"
143
+ continue
144
+ fi
145
+
146
+ # This is a path/pattern entry.
147
+ local_path="$line"
148
+
149
+ # ── Case 1: No preceding comment at all ────────────────────────────────────
150
+ if [[ -z "$prev_comment" ]]; then
151
+ echo "VIOLATION (line $lineno): '$local_path' has no annotation comment." >&2
152
+ echo " Required: # allow: <pattern> reason=\"...\" owner=\"...\" expires=\"YYYY-MM-DD\"" >&2
153
+ VIOLATIONS=$((VIOLATIONS + 1))
154
+ prev_comment=""
155
+ continue
156
+ fi
157
+
158
+ # ── Case 2: Preceding comment exists — check if it's a structured annotation ─
159
+ if is_structured_annotation "$prev_comment"; then
160
+ # Extract required keys
161
+ reason=$(extract_key "$prev_comment" "reason")
162
+ owner=$(extract_key "$prev_comment" "owner")
163
+ expires=$(extract_key "$prev_comment" "expires")
164
+ rule_id=$(extract_key "$prev_comment" "rule-id")
165
+
166
+ local_ok=true
167
+
168
+ if [[ -z "$reason" ]]; then
169
+ echo "VIOLATION (line $lineno): '$local_path' annotation missing required key: reason" >&2
170
+ local_ok=false
171
+ fi
172
+
173
+ if [[ -z "$owner" ]]; then
174
+ echo "VIOLATION (line $lineno): '$local_path' annotation missing required key: owner" >&2
175
+ local_ok=false
176
+ fi
177
+
178
+ if [[ -z "$expires" ]]; then
179
+ echo "VIOLATION (line $lineno): '$local_path' annotation missing required key: expires" >&2
180
+ local_ok=false
181
+ elif date_is_past "$expires"; then
182
+ echo "VIOLATION (line $lineno): '$local_path' annotation 'expires' date is in the past: $expires" >&2
183
+ echo " Review this exclusion and update or remove it." >&2
184
+ local_ok=false
185
+ fi
186
+
187
+ if contains_wildcard "$local_path" && [[ -z "$rule_id" ]]; then
188
+ echo "VIOLATION (line $lineno): '$local_path' uses a wildcard but is missing required key: rule-id" >&2
189
+ echo " Wildcard exclusions (** *.ext) require an explicit rule-id for auditability." >&2
190
+ local_ok=false
191
+ fi
192
+
193
+ if [[ "$local_ok" == false ]]; then
194
+ VIOLATIONS=$((VIOLATIONS + 1))
195
+ fi
196
+
197
+ else
198
+ # ── Case 3: Preceding comment is plain (not structured) — grandfathered ──
199
+ if [[ "$STRICT" == true ]]; then
200
+ echo "VIOLATION (line $lineno): '$local_path' is grandfathered (no structured annotation) — rejected under --strict mode." >&2
201
+ echo " Add: # allow: $local_path reason=\"...\" owner=\"...\" expires=\"YYYY-MM-DD\"" >&2
202
+ VIOLATIONS=$((VIOLATIONS + 1))
203
+ else
204
+ echo "WARNING (line $lineno): '$local_path' is grandfathered (missing structured annotation)." >&2
205
+ echo " DEPRECATION: migrate to structured annotation before removing grandfather status." >&2
206
+ echo " Required: # allow: $local_path reason=\"...\" owner=\"...\" expires=\"YYYY-MM-DD\"" >&2
207
+ echo " See: https://docs.gitguardian.com/internal-repositories-monitoring/integrations/cli/secrets" >&2
208
+ WARNINGS=$((WARNINGS + 1))
209
+ fi
210
+ fi
211
+
212
+ prev_comment=""
213
+
214
+ done < "$IGNOREFILE"
215
+
216
+ # ─── Summary ──────────────────────────────────────────────────────────────────
217
+
218
+ if [[ $VIOLATIONS -gt 0 ]]; then
219
+ echo "secret-scan-lint: $VIOLATIONS violation(s) found" >&2
220
+ if [[ $STRICT == true ]]; then
221
+ echo "secret-scan-lint: --strict mode active — grandfathered entries are not permitted" >&2
222
+ fi
223
+ exit 1
224
+ fi
225
+
226
+ if [[ $WARNINGS -gt 0 ]]; then
227
+ echo "secret-scan-lint: $WARNINGS grandfathered entry/entries (deprecation warning)" >&2
228
+ fi
229
+
230
+ echo "secret-scan-lint: OK"
231
+ exit 0