@therocketcode/gsd-core 1.4.0

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 (568) hide show
  1. package/.claude-plugin/plugin.json +23 -0
  2. package/GEMINI.md +53 -0
  3. package/LICENSE +21 -0
  4. package/README.ja-JP.md +125 -0
  5. package/README.ko-KR.md +125 -0
  6. package/README.md +144 -0
  7. package/README.pt-BR.md +125 -0
  8. package/README.zh-CN.md +125 -0
  9. package/agents/gsd-advisor-researcher.md +108 -0
  10. package/agents/gsd-ai-researcher.md +114 -0
  11. package/agents/gsd-assumptions-analyzer.md +105 -0
  12. package/agents/gsd-code-fixer.md +668 -0
  13. package/agents/gsd-code-reviewer.md +387 -0
  14. package/agents/gsd-codebase-mapper.md +853 -0
  15. package/agents/gsd-debug-session-manager.md +314 -0
  16. package/agents/gsd-debugger.md +1452 -0
  17. package/agents/gsd-doc-classifier.md +168 -0
  18. package/agents/gsd-doc-synthesizer.md +204 -0
  19. package/agents/gsd-doc-verifier.md +217 -0
  20. package/agents/gsd-doc-writer.md +616 -0
  21. package/agents/gsd-domain-researcher.md +147 -0
  22. package/agents/gsd-eval-auditor.md +191 -0
  23. package/agents/gsd-eval-planner.md +154 -0
  24. package/agents/gsd-executor.md +785 -0
  25. package/agents/gsd-framework-selector.md +160 -0
  26. package/agents/gsd-integration-checker.md +470 -0
  27. package/agents/gsd-intel-updater.md +342 -0
  28. package/agents/gsd-nyquist-auditor.md +203 -0
  29. package/agents/gsd-pattern-mapper.md +335 -0
  30. package/agents/gsd-phase-researcher.md +867 -0
  31. package/agents/gsd-plan-checker.md +978 -0
  32. package/agents/gsd-planner.md +1204 -0
  33. package/agents/gsd-project-researcher.md +611 -0
  34. package/agents/gsd-research-synthesizer.md +259 -0
  35. package/agents/gsd-roadmapper.md +688 -0
  36. package/agents/gsd-security-auditor.md +155 -0
  37. package/agents/gsd-ui-auditor.md +495 -0
  38. package/agents/gsd-ui-checker.md +309 -0
  39. package/agents/gsd-ui-researcher.md +374 -0
  40. package/agents/gsd-user-profiler.md +171 -0
  41. package/agents/gsd-verifier.md +923 -0
  42. package/assets/gsd-logo-2000-transparent.png +0 -0
  43. package/assets/gsd-logo-2000-transparent.svg +17 -0
  44. package/assets/gsd-logo-2000.png +0 -0
  45. package/assets/gsd-logo-2000.svg +21 -0
  46. package/assets/terminal.svg +68 -0
  47. package/bin/install.js +12726 -0
  48. package/bin/lib/ui-safety-gate.cjs +107 -0
  49. package/commands/gsd/add-tests.md +42 -0
  50. package/commands/gsd/ai-integration-phase.md +37 -0
  51. package/commands/gsd/audit-fix.md +34 -0
  52. package/commands/gsd/audit-milestone.md +37 -0
  53. package/commands/gsd/audit-uat.md +24 -0
  54. package/commands/gsd/autonomous.md +48 -0
  55. package/commands/gsd/capture.md +62 -0
  56. package/commands/gsd/cleanup.md +24 -0
  57. package/commands/gsd/code-review.md +59 -0
  58. package/commands/gsd/complete-milestone.md +143 -0
  59. package/commands/gsd/config.md +56 -0
  60. package/commands/gsd/debug.md +52 -0
  61. package/commands/gsd/discover-product.md +65 -0
  62. package/commands/gsd/discuss-phase.md +77 -0
  63. package/commands/gsd/docs-update.md +49 -0
  64. package/commands/gsd/eval-review.md +33 -0
  65. package/commands/gsd/execute-phase.md +66 -0
  66. package/commands/gsd/explore.md +27 -0
  67. package/commands/gsd/extract-learnings.md +23 -0
  68. package/commands/gsd/fast.md +31 -0
  69. package/commands/gsd/forensics.md +57 -0
  70. package/commands/gsd/graphify.md +204 -0
  71. package/commands/gsd/health.md +31 -0
  72. package/commands/gsd/help.md +28 -0
  73. package/commands/gsd/import.md +45 -0
  74. package/commands/gsd/inbox.md +39 -0
  75. package/commands/gsd/ingest-docs.md +42 -0
  76. package/commands/gsd/manager.md +45 -0
  77. package/commands/gsd/map-codebase.md +83 -0
  78. package/commands/gsd/milestone-summary.md +51 -0
  79. package/commands/gsd/model-domain.md +65 -0
  80. package/commands/gsd/mvp-phase.md +45 -0
  81. package/commands/gsd/new-milestone.md +45 -0
  82. package/commands/gsd/new-project.md +47 -0
  83. package/commands/gsd/ns-context.md +23 -0
  84. package/commands/gsd/ns-ideate.md +24 -0
  85. package/commands/gsd/ns-manage.md +29 -0
  86. package/commands/gsd/ns-project.md +22 -0
  87. package/commands/gsd/ns-review.md +26 -0
  88. package/commands/gsd/ns-workflow.md +28 -0
  89. package/commands/gsd/pause-work.md +43 -0
  90. package/commands/gsd/phase.md +56 -0
  91. package/commands/gsd/plan-phase.md +64 -0
  92. package/commands/gsd/plan-review-convergence.md +59 -0
  93. package/commands/gsd/pr-branch.md +26 -0
  94. package/commands/gsd/profile-user.md +46 -0
  95. package/commands/gsd/progress.md +48 -0
  96. package/commands/gsd/quick.md +174 -0
  97. package/commands/gsd/recommend-architecture.md +64 -0
  98. package/commands/gsd/resume-work.md +30 -0
  99. package/commands/gsd/review-backlog.md +63 -0
  100. package/commands/gsd/review.md +42 -0
  101. package/commands/gsd/secure-phase.md +36 -0
  102. package/commands/gsd/settings.md +29 -0
  103. package/commands/gsd/ship.md +24 -0
  104. package/commands/gsd/sketch.md +60 -0
  105. package/commands/gsd/spec-phase.md +63 -0
  106. package/commands/gsd/spike.md +57 -0
  107. package/commands/gsd/stats.md +20 -0
  108. package/commands/gsd/surface.md +155 -0
  109. package/commands/gsd/testing-strategy.md +65 -0
  110. package/commands/gsd/thread.md +24 -0
  111. package/commands/gsd/ui-phase.md +35 -0
  112. package/commands/gsd/ui-review.md +33 -0
  113. package/commands/gsd/ultraplan-phase.md +34 -0
  114. package/commands/gsd/undo.md +35 -0
  115. package/commands/gsd/update.md +49 -0
  116. package/commands/gsd/validate-phase.md +36 -0
  117. package/commands/gsd/verify-work.md +39 -0
  118. package/commands/gsd/workspace.md +52 -0
  119. package/commands/gsd/workstreams.md +70 -0
  120. package/gemini-extension.json +6 -0
  121. package/gsd-core/bin/check-latest-version.cjs +161 -0
  122. package/gsd-core/bin/gsd-tools.cjs +1928 -0
  123. package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
  124. package/gsd-core/bin/lib/adr-parser.cjs +399 -0
  125. package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
  126. package/gsd-core/bin/lib/artifacts.cjs +51 -0
  127. package/gsd-core/bin/lib/audit.cjs +743 -0
  128. package/gsd-core/bin/lib/check-command-router.cjs +343 -0
  129. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
  130. package/gsd-core/bin/lib/cli-exit.cjs +42 -0
  131. package/gsd-core/bin/lib/clock.cjs +95 -0
  132. package/gsd-core/bin/lib/clusters.cjs +132 -0
  133. package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
  134. package/gsd-core/bin/lib/command-aliases.cjs +809 -0
  135. package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
  136. package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
  137. package/gsd-core/bin/lib/commands.cjs +1203 -0
  138. package/gsd-core/bin/lib/config-schema.cjs +29 -0
  139. package/gsd-core/bin/lib/config-types.cjs +19 -0
  140. package/gsd-core/bin/lib/config.cjs +738 -0
  141. package/gsd-core/bin/lib/configuration.cjs +239 -0
  142. package/gsd-core/bin/lib/context-utilization.cjs +48 -0
  143. package/gsd-core/bin/lib/core.cjs +2051 -0
  144. package/gsd-core/bin/lib/decisions.cjs +118 -0
  145. package/gsd-core/bin/lib/docs.cjs +252 -0
  146. package/gsd-core/bin/lib/drift.cjs +364 -0
  147. package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
  148. package/gsd-core/bin/lib/frontmatter.cjs +442 -0
  149. package/gsd-core/bin/lib/gap-checker.cjs +257 -0
  150. package/gsd-core/bin/lib/graphify.cjs +496 -0
  151. package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
  152. package/gsd-core/bin/lib/init-command-router.cjs +62 -0
  153. package/gsd-core/bin/lib/init.cjs +1815 -0
  154. package/gsd-core/bin/lib/install-profiles.cjs +584 -0
  155. package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
  156. package/gsd-core/bin/lib/installer-migration-report.cjs +350 -0
  157. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
  158. package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
  159. package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
  160. package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
  161. package/gsd-core/bin/lib/installer-migrations.cjs +823 -0
  162. package/gsd-core/bin/lib/intel.cjs +590 -0
  163. package/gsd-core/bin/lib/learnings.cjs +270 -0
  164. package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
  165. package/gsd-core/bin/lib/milestone.cjs +373 -0
  166. package/gsd-core/bin/lib/model-catalog.cjs +154 -0
  167. package/gsd-core/bin/lib/model-profiles.cjs +24 -0
  168. package/gsd-core/bin/lib/observability/event.cjs +51 -0
  169. package/gsd-core/bin/lib/observability/logger.cjs +146 -0
  170. package/gsd-core/bin/lib/observability/redaction.cjs +48 -0
  171. package/gsd-core/bin/lib/package-identity.cjs +35 -0
  172. package/gsd-core/bin/lib/package-legitimacy.cjs +368 -0
  173. package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
  174. package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
  175. package/gsd-core/bin/lib/phase.cjs +1307 -0
  176. package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
  177. package/gsd-core/bin/lib/plan-scan.cjs +91 -0
  178. package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
  179. package/gsd-core/bin/lib/profile-output.cjs +1120 -0
  180. package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
  181. package/gsd-core/bin/lib/project-root.cjs +119 -0
  182. package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
  183. package/gsd-core/bin/lib/research-provider.cjs +137 -0
  184. package/gsd-core/bin/lib/research-store.cjs +167 -0
  185. package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
  186. package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
  187. package/gsd-core/bin/lib/roadmap-upgrade.cjs +476 -0
  188. package/gsd-core/bin/lib/roadmap.cjs +600 -0
  189. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +312 -0
  190. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +56 -0
  191. package/gsd-core/bin/lib/runtime-homes.cjs +190 -0
  192. package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
  193. package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
  194. package/gsd-core/bin/lib/schema-detect.cjs +159 -0
  195. package/gsd-core/bin/lib/secrets.cjs +34 -0
  196. package/gsd-core/bin/lib/security.cjs +480 -0
  197. package/gsd-core/bin/lib/semver-compare.cjs +42 -0
  198. package/gsd-core/bin/lib/shell-command-projection.cjs +533 -0
  199. package/gsd-core/bin/lib/state-command-router.cjs +160 -0
  200. package/gsd-core/bin/lib/state-document.cjs +259 -0
  201. package/gsd-core/bin/lib/state.cjs +2010 -0
  202. package/gsd-core/bin/lib/surface.cjs +449 -0
  203. package/gsd-core/bin/lib/task-command-router.cjs +85 -0
  204. package/gsd-core/bin/lib/template.cjs +237 -0
  205. package/gsd-core/bin/lib/uat.cjs +297 -0
  206. package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
  207. package/gsd-core/bin/lib/update-context.cjs +218 -0
  208. package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
  209. package/gsd-core/bin/lib/validate.cjs +112 -0
  210. package/gsd-core/bin/lib/verification-command-router.cjs +31 -0
  211. package/gsd-core/bin/lib/verification.cjs +193 -0
  212. package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
  213. package/gsd-core/bin/lib/verify.cjs +1451 -0
  214. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +81 -0
  215. package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
  216. package/gsd-core/bin/lib/workstream-name-policy.cjs +91 -0
  217. package/gsd-core/bin/lib/workstream.cjs +380 -0
  218. package/gsd-core/bin/lib/worktree-base-ref.cjs +325 -0
  219. package/gsd-core/bin/lib/worktree-safety.cjs +943 -0
  220. package/gsd-core/bin/shared/config-defaults.manifest.json +98 -0
  221. package/gsd-core/bin/shared/config-schema.manifest.json +192 -0
  222. package/gsd-core/bin/shared/model-catalog.json +149 -0
  223. package/gsd-core/bin/shared/runtime-aliases.manifest.json +75 -0
  224. package/gsd-core/bin/verify-reapply-patches.cjs +349 -0
  225. package/gsd-core/contexts/dev.md +21 -0
  226. package/gsd-core/contexts/research.md +22 -0
  227. package/gsd-core/contexts/review.md +23 -0
  228. package/gsd-core/references/agent-contracts.md +79 -0
  229. package/gsd-core/references/ai-evals.md +156 -0
  230. package/gsd-core/references/ai-frameworks.md +186 -0
  231. package/gsd-core/references/architecture-decision.md +74 -0
  232. package/gsd-core/references/artifact-types.md +131 -0
  233. package/gsd-core/references/auth-in-tests.md +91 -0
  234. package/gsd-core/references/autonomous-smart-discuss.md +277 -0
  235. package/gsd-core/references/checkpoints.md +814 -0
  236. package/gsd-core/references/common-bug-patterns.md +114 -0
  237. package/gsd-core/references/context-budget.md +85 -0
  238. package/gsd-core/references/continuation-format.md +253 -0
  239. package/gsd-core/references/db-test-isolation.md +54 -0
  240. package/gsd-core/references/debugger-philosophy.md +76 -0
  241. package/gsd-core/references/decimal-phase-calculation.md +64 -0
  242. package/gsd-core/references/doc-conflict-engine.md +91 -0
  243. package/gsd-core/references/domain-modeling.md +80 -0
  244. package/gsd-core/references/domain-probes.md +125 -0
  245. package/gsd-core/references/e2e-tiering.md +35 -0
  246. package/gsd-core/references/execute-mvp-tdd.md +81 -0
  247. package/gsd-core/references/executor-examples.md +110 -0
  248. package/gsd-core/references/few-shot-examples/plan-checker.md +73 -0
  249. package/gsd-core/references/few-shot-examples/verifier.md +109 -0
  250. package/gsd-core/references/flaky-test-checklist.md +22 -0
  251. package/gsd-core/references/gate-prompts.md +100 -0
  252. package/gsd-core/references/gates.md +70 -0
  253. package/gsd-core/references/git-integration.md +298 -0
  254. package/gsd-core/references/git-planning-commit.md +40 -0
  255. package/gsd-core/references/ios-scaffold.md +123 -0
  256. package/gsd-core/references/mandatory-initial-read.md +2 -0
  257. package/gsd-core/references/model-profile-resolution.md +38 -0
  258. package/gsd-core/references/model-profiles.md +245 -0
  259. package/gsd-core/references/mvp-concepts.md +49 -0
  260. package/gsd-core/references/phase-argument-parsing.md +61 -0
  261. package/gsd-core/references/planner-antipatterns.md +89 -0
  262. package/gsd-core/references/planner-chunked.md +49 -0
  263. package/gsd-core/references/planner-gap-closure.md +62 -0
  264. package/gsd-core/references/planner-graphify-auto-update.md +67 -0
  265. package/gsd-core/references/planner-human-verify-mode.md +57 -0
  266. package/gsd-core/references/planner-interface-context.md +62 -0
  267. package/gsd-core/references/planner-load-graph-context.md +36 -0
  268. package/gsd-core/references/planner-mvp-mode.md +53 -0
  269. package/gsd-core/references/planner-reviews.md +39 -0
  270. package/gsd-core/references/planner-revision.md +87 -0
  271. package/gsd-core/references/planner-source-audit.md +73 -0
  272. package/gsd-core/references/planning-config.md +473 -0
  273. package/gsd-core/references/product-discovery.md +49 -0
  274. package/gsd-core/references/project-skills-discovery.md +19 -0
  275. package/gsd-core/references/questioning.md +162 -0
  276. package/gsd-core/references/realistic-test-data.md +44 -0
  277. package/gsd-core/references/research-documentation-lookup.md +29 -0
  278. package/gsd-core/references/research-philosophy.md +29 -0
  279. package/gsd-core/references/research-verification-protocol.md +27 -0
  280. package/gsd-core/references/revision-loop.md +97 -0
  281. package/gsd-core/references/scout-codebase.md +51 -0
  282. package/gsd-core/references/skeleton-template.md +48 -0
  283. package/gsd-core/references/sketch-interactivity.md +41 -0
  284. package/gsd-core/references/sketch-theme-system.md +94 -0
  285. package/gsd-core/references/sketch-tooling.md +45 -0
  286. package/gsd-core/references/sketch-variant-patterns.md +81 -0
  287. package/gsd-core/references/spidr-splitting.md +69 -0
  288. package/gsd-core/references/tdd.md +330 -0
  289. package/gsd-core/references/test-containers.md +55 -0
  290. package/gsd-core/references/test-strategy.md +75 -0
  291. package/gsd-core/references/thinking-models-debug.md +44 -0
  292. package/gsd-core/references/thinking-models-execution.md +50 -0
  293. package/gsd-core/references/thinking-models-planning.md +62 -0
  294. package/gsd-core/references/thinking-models-research.md +50 -0
  295. package/gsd-core/references/thinking-models-verification.md +55 -0
  296. package/gsd-core/references/thinking-partner.md +96 -0
  297. package/gsd-core/references/ui-brand.md +162 -0
  298. package/gsd-core/references/universal-anti-patterns.md +63 -0
  299. package/gsd-core/references/user-profiling.md +681 -0
  300. package/gsd-core/references/user-story-template.md +58 -0
  301. package/gsd-core/references/verification-overrides.md +227 -0
  302. package/gsd-core/references/verification-patterns.md +612 -0
  303. package/gsd-core/references/verify-mvp-mode.md +85 -0
  304. package/gsd-core/references/workstream-flag.md +111 -0
  305. package/gsd-core/references/worktree-branch-check.md +38 -0
  306. package/gsd-core/references/worktree-path-safety.md +67 -0
  307. package/gsd-core/templates/AI-SPEC.md +246 -0
  308. package/gsd-core/templates/DEBUG.md +169 -0
  309. package/gsd-core/templates/README.md +77 -0
  310. package/gsd-core/templates/SECURITY.md +61 -0
  311. package/gsd-core/templates/UAT.md +265 -0
  312. package/gsd-core/templates/UI-SPEC.md +100 -0
  313. package/gsd-core/templates/VALIDATION.md +76 -0
  314. package/gsd-core/templates/adr.md +58 -0
  315. package/gsd-core/templates/claude-md.md +145 -0
  316. package/gsd-core/templates/codebase/architecture.md +255 -0
  317. package/gsd-core/templates/codebase/concerns.md +310 -0
  318. package/gsd-core/templates/codebase/conventions.md +307 -0
  319. package/gsd-core/templates/codebase/integrations.md +280 -0
  320. package/gsd-core/templates/codebase/stack.md +186 -0
  321. package/gsd-core/templates/codebase/structure.md +285 -0
  322. package/gsd-core/templates/codebase/testing.md +480 -0
  323. package/gsd-core/templates/config.json +62 -0
  324. package/gsd-core/templates/context.md +352 -0
  325. package/gsd-core/templates/continue-here.md +78 -0
  326. package/gsd-core/templates/copilot-instructions.md +7 -0
  327. package/gsd-core/templates/debug-subagent-prompt.md +91 -0
  328. package/gsd-core/templates/dev-preferences.md +21 -0
  329. package/gsd-core/templates/discovery.md +146 -0
  330. package/gsd-core/templates/discussion-log.md +63 -0
  331. package/gsd-core/templates/domain-model.md +54 -0
  332. package/gsd-core/templates/milestone-archive.md +123 -0
  333. package/gsd-core/templates/milestone.md +115 -0
  334. package/gsd-core/templates/phase-prompt.md +610 -0
  335. package/gsd-core/templates/planner-subagent-prompt.md +117 -0
  336. package/gsd-core/templates/product-brief.md +55 -0
  337. package/gsd-core/templates/project.md +186 -0
  338. package/gsd-core/templates/requirements.md +231 -0
  339. package/gsd-core/templates/research-project/ARCHITECTURE.md +204 -0
  340. package/gsd-core/templates/research-project/FEATURES.md +147 -0
  341. package/gsd-core/templates/research-project/PITFALLS.md +200 -0
  342. package/gsd-core/templates/research-project/STACK.md +120 -0
  343. package/gsd-core/templates/research-project/SUMMARY.md +170 -0
  344. package/gsd-core/templates/research.md +592 -0
  345. package/gsd-core/templates/retrospective.md +54 -0
  346. package/gsd-core/templates/roadmap.md +202 -0
  347. package/gsd-core/templates/spec.md +307 -0
  348. package/gsd-core/templates/state.md +195 -0
  349. package/gsd-core/templates/summary-complex.md +59 -0
  350. package/gsd-core/templates/summary-minimal.md +41 -0
  351. package/gsd-core/templates/summary-standard.md +48 -0
  352. package/gsd-core/templates/summary.md +248 -0
  353. package/gsd-core/templates/test-strategy.md +50 -0
  354. package/gsd-core/templates/user-profile.md +146 -0
  355. package/gsd-core/templates/user-setup.md +311 -0
  356. package/gsd-core/templates/verification-report.md +322 -0
  357. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
  358. package/gsd-core/workflows/add-backlog.md +91 -0
  359. package/gsd-core/workflows/add-phase.md +113 -0
  360. package/gsd-core/workflows/add-tests.md +355 -0
  361. package/gsd-core/workflows/add-todo.md +161 -0
  362. package/gsd-core/workflows/ai-integration-phase.md +295 -0
  363. package/gsd-core/workflows/analyze-dependencies.md +96 -0
  364. package/gsd-core/workflows/audit-fix.md +178 -0
  365. package/gsd-core/workflows/audit-milestone.md +360 -0
  366. package/gsd-core/workflows/audit-uat.md +110 -0
  367. package/gsd-core/workflows/autonomous.md +797 -0
  368. package/gsd-core/workflows/check-todos.md +180 -0
  369. package/gsd-core/workflows/cleanup.md +195 -0
  370. package/gsd-core/workflows/code-review-fix.md +502 -0
  371. package/gsd-core/workflows/code-review.md +658 -0
  372. package/gsd-core/workflows/complete-milestone.md +855 -0
  373. package/gsd-core/workflows/debug.md +237 -0
  374. package/gsd-core/workflows/diagnose-issues.md +245 -0
  375. package/gsd-core/workflows/discover-product.md +112 -0
  376. package/gsd-core/workflows/discovery-phase.md +291 -0
  377. package/gsd-core/workflows/discuss-phase/modes/advisor.md +176 -0
  378. package/gsd-core/workflows/discuss-phase/modes/all.md +28 -0
  379. package/gsd-core/workflows/discuss-phase/modes/analyze.md +44 -0
  380. package/gsd-core/workflows/discuss-phase/modes/auto.md +57 -0
  381. package/gsd-core/workflows/discuss-phase/modes/batch.md +52 -0
  382. package/gsd-core/workflows/discuss-phase/modes/chain.md +98 -0
  383. package/gsd-core/workflows/discuss-phase/modes/default.md +141 -0
  384. package/gsd-core/workflows/discuss-phase/modes/power.md +44 -0
  385. package/gsd-core/workflows/discuss-phase/modes/text.md +55 -0
  386. package/gsd-core/workflows/discuss-phase/templates/checkpoint.json +18 -0
  387. package/gsd-core/workflows/discuss-phase/templates/context.md +136 -0
  388. package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +50 -0
  389. package/gsd-core/workflows/discuss-phase-assumptions.md +675 -0
  390. package/gsd-core/workflows/discuss-phase-power.md +291 -0
  391. package/gsd-core/workflows/discuss-phase.md +499 -0
  392. package/gsd-core/workflows/do.md +111 -0
  393. package/gsd-core/workflows/docs-update.md +1176 -0
  394. package/gsd-core/workflows/edit-phase.md +295 -0
  395. package/gsd-core/workflows/eval-review.md +156 -0
  396. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +95 -0
  397. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  398. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +117 -0
  399. package/gsd-core/workflows/execute-phase.md +1752 -0
  400. package/gsd-core/workflows/execute-plan.md +526 -0
  401. package/gsd-core/workflows/explore.md +146 -0
  402. package/gsd-core/workflows/extract-learnings.md +243 -0
  403. package/gsd-core/workflows/fast.md +124 -0
  404. package/gsd-core/workflows/forensics.md +279 -0
  405. package/gsd-core/workflows/graduation.md +196 -0
  406. package/gsd-core/workflows/health.md +224 -0
  407. package/gsd-core/workflows/help/modes/brief.md +22 -0
  408. package/gsd-core/workflows/help/modes/default.md +50 -0
  409. package/gsd-core/workflows/help/modes/full.md +789 -0
  410. package/gsd-core/workflows/help/modes/topic.md +74 -0
  411. package/gsd-core/workflows/help.md +24 -0
  412. package/gsd-core/workflows/import.md +256 -0
  413. package/gsd-core/workflows/inbox.md +387 -0
  414. package/gsd-core/workflows/ingest-docs.md +340 -0
  415. package/gsd-core/workflows/insert-phase.md +152 -0
  416. package/gsd-core/workflows/list-phase-assumptions.md +178 -0
  417. package/gsd-core/workflows/list-workspaces.md +57 -0
  418. package/gsd-core/workflows/manager.md +393 -0
  419. package/gsd-core/workflows/map-codebase.md +446 -0
  420. package/gsd-core/workflows/milestone-summary.md +224 -0
  421. package/gsd-core/workflows/model-domain.md +162 -0
  422. package/gsd-core/workflows/mvp-phase.md +222 -0
  423. package/gsd-core/workflows/new-milestone.md +635 -0
  424. package/gsd-core/workflows/new-project.md +1555 -0
  425. package/gsd-core/workflows/new-workspace.md +240 -0
  426. package/gsd-core/workflows/next.md +299 -0
  427. package/gsd-core/workflows/node-repair.md +92 -0
  428. package/gsd-core/workflows/note.md +158 -0
  429. package/gsd-core/workflows/pause-work.md +244 -0
  430. package/gsd-core/workflows/plan-milestone-gaps.md +281 -0
  431. package/gsd-core/workflows/plan-phase.md +1814 -0
  432. package/gsd-core/workflows/plan-review-convergence.md +346 -0
  433. package/gsd-core/workflows/plant-seed.md +230 -0
  434. package/gsd-core/workflows/pr-branch.md +157 -0
  435. package/gsd-core/workflows/profile-user.md +453 -0
  436. package/gsd-core/workflows/progress.md +699 -0
  437. package/gsd-core/workflows/quick.md +1017 -0
  438. package/gsd-core/workflows/reapply-patches.md +426 -0
  439. package/gsd-core/workflows/recommend-architecture.md +135 -0
  440. package/gsd-core/workflows/remove-phase.md +156 -0
  441. package/gsd-core/workflows/remove-workspace.md +108 -0
  442. package/gsd-core/workflows/resume-project.md +332 -0
  443. package/gsd-core/workflows/review.md +748 -0
  444. package/gsd-core/workflows/scan.md +107 -0
  445. package/gsd-core/workflows/secure-phase.md +182 -0
  446. package/gsd-core/workflows/session-report.md +146 -0
  447. package/gsd-core/workflows/settings-advanced.md +810 -0
  448. package/gsd-core/workflows/settings-integrations.md +312 -0
  449. package/gsd-core/workflows/settings.md +566 -0
  450. package/gsd-core/workflows/ship.md +405 -0
  451. package/gsd-core/workflows/sketch-wrap-up.md +286 -0
  452. package/gsd-core/workflows/sketch.md +361 -0
  453. package/gsd-core/workflows/spec-phase.md +263 -0
  454. package/gsd-core/workflows/spike-wrap-up.md +307 -0
  455. package/gsd-core/workflows/spike.md +453 -0
  456. package/gsd-core/workflows/stats.md +80 -0
  457. package/gsd-core/workflows/sync-skills.md +182 -0
  458. package/gsd-core/workflows/testing-strategy.md +122 -0
  459. package/gsd-core/workflows/thread.md +222 -0
  460. package/gsd-core/workflows/transition.md +694 -0
  461. package/gsd-core/workflows/ui-phase.md +328 -0
  462. package/gsd-core/workflows/ui-review.md +193 -0
  463. package/gsd-core/workflows/ultraplan-phase.md +199 -0
  464. package/gsd-core/workflows/undo.md +314 -0
  465. package/gsd-core/workflows/update.md +496 -0
  466. package/gsd-core/workflows/validate-phase.md +181 -0
  467. package/gsd-core/workflows/verify-phase.md +544 -0
  468. package/gsd-core/workflows/verify-work.md +781 -0
  469. package/hooks/dist/gsd-check-update-worker.js +108 -0
  470. package/hooks/dist/gsd-check-update.js +66 -0
  471. package/hooks/dist/gsd-config-reload.js +133 -0
  472. package/hooks/dist/gsd-context-monitor.js +195 -0
  473. package/hooks/dist/gsd-cursor-post-tool.js +75 -0
  474. package/hooks/dist/gsd-cursor-session-start.js +52 -0
  475. package/hooks/dist/gsd-graphify-update.sh +158 -0
  476. package/hooks/dist/gsd-phase-boundary.sh +47 -0
  477. package/hooks/dist/gsd-prompt-guard.js +97 -0
  478. package/hooks/dist/gsd-read-guard.js +101 -0
  479. package/hooks/dist/gsd-read-injection-scanner.js +203 -0
  480. package/hooks/dist/gsd-session-state.sh +59 -0
  481. package/hooks/dist/gsd-statusline.js +566 -0
  482. package/hooks/dist/gsd-update-banner.js +138 -0
  483. package/hooks/dist/gsd-validate-commit.sh +57 -0
  484. package/hooks/dist/gsd-workflow-guard.js +167 -0
  485. package/hooks/dist/gsd-worktree-path-guard.js +169 -0
  486. package/hooks/dist/lib/git-cmd.js +150 -0
  487. package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
  488. package/hooks/dist/managed-hooks-registry.cjs +38 -0
  489. package/hooks/gsd-check-update-worker.js +108 -0
  490. package/hooks/gsd-check-update.js +66 -0
  491. package/hooks/gsd-config-reload.js +133 -0
  492. package/hooks/gsd-context-monitor.js +195 -0
  493. package/hooks/gsd-cursor-post-tool.js +75 -0
  494. package/hooks/gsd-cursor-session-start.js +52 -0
  495. package/hooks/gsd-graphify-update.sh +158 -0
  496. package/hooks/gsd-phase-boundary.sh +47 -0
  497. package/hooks/gsd-prompt-guard.js +97 -0
  498. package/hooks/gsd-read-guard.js +101 -0
  499. package/hooks/gsd-read-injection-scanner.js +203 -0
  500. package/hooks/gsd-session-state.sh +59 -0
  501. package/hooks/gsd-statusline.js +566 -0
  502. package/hooks/gsd-update-banner.js +138 -0
  503. package/hooks/gsd-validate-commit.sh +57 -0
  504. package/hooks/gsd-workflow-guard.js +167 -0
  505. package/hooks/gsd-worktree-path-guard.js +169 -0
  506. package/hooks/hooks.json +69 -0
  507. package/hooks/lib/git-cmd.js +150 -0
  508. package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
  509. package/hooks/managed-hooks-registry.cjs +38 -0
  510. package/package.json +115 -0
  511. package/scripts/affected-tests-lib.cjs +542 -0
  512. package/scripts/audit-workflow-script-paths.cjs +73 -0
  513. package/scripts/base64-scan.sh +351 -0
  514. package/scripts/build-hooks.js +247 -0
  515. package/scripts/changeset/README.md +129 -0
  516. package/scripts/changeset/cli.cjs +590 -0
  517. package/scripts/changeset/github-release-notes.cjs +199 -0
  518. package/scripts/changeset/lint.cjs +111 -0
  519. package/scripts/changeset/new.cjs +137 -0
  520. package/scripts/changeset/parse.cjs +114 -0
  521. package/scripts/changeset/render.cjs +34 -0
  522. package/scripts/changeset/serialize.cjs +130 -0
  523. package/scripts/check-alias-drift.cjs +114 -0
  524. package/scripts/check-env.cjs +312 -0
  525. package/scripts/check-npm-integrity.cjs +215 -0
  526. package/scripts/ci-guard-runner.cjs +22 -0
  527. package/scripts/ci-prepare-test-scope.cjs +51 -0
  528. package/scripts/ci-rebase-check.cjs +86 -0
  529. package/scripts/ci-test-scope.cjs +431 -0
  530. package/scripts/command-contract-helpers.cjs +64 -0
  531. package/scripts/diff-touches-shipped-paths.cjs +155 -0
  532. package/scripts/fix-slash-commands.cjs +147 -0
  533. package/scripts/gen-inventory-manifest.cjs +115 -0
  534. package/scripts/gen-research-agents.cjs +276 -0
  535. package/scripts/generate-package-identity.cjs +125 -0
  536. package/scripts/issue-dedupe.cjs +278 -0
  537. package/scripts/lib/allowlist-ratchet.cjs +136 -0
  538. package/scripts/lib/cli-exit.cjs +56 -0
  539. package/scripts/lint-command-contract.cjs +114 -0
  540. package/scripts/lint-descriptions.cjs +87 -0
  541. package/scripts/lint-docs-required.cjs +222 -0
  542. package/scripts/lint-legacy-dir-name.cjs +160 -0
  543. package/scripts/lint-package-identity-drift.cjs +141 -0
  544. package/scripts/lint-pr-check-project-dir.cjs +99 -0
  545. package/scripts/lint-shell-command-projection-drift.cjs +62 -0
  546. package/scripts/lint-skill-deps.cjs +185 -0
  547. package/scripts/lint-test-file-count.allowlist.json +135 -0
  548. package/scripts/lint-test-file-count.cjs +246 -0
  549. package/scripts/mutation-matrix.cjs +222 -0
  550. package/scripts/pr-template-policy.cjs +268 -0
  551. package/scripts/prompt-injection-scan.sh +207 -0
  552. package/scripts/release-notes/discord-release-summary.cjs +373 -0
  553. package/scripts/release-notes/format-github-release-notes.cjs +261 -0
  554. package/scripts/release-tarball-smoke.cjs +629 -0
  555. package/scripts/research-profiles.cjs +149 -0
  556. package/scripts/run-affected-tests.cjs +7 -0
  557. package/scripts/run-cross-platform-tests.cjs +67 -0
  558. package/scripts/run-tests.cjs +315 -0
  559. package/scripts/secret-scan-lint.sh +231 -0
  560. package/scripts/secret-scan.sh +358 -0
  561. package/scripts/setup-branch-protection.sh +236 -0
  562. package/scripts/strip-prose-atrefs.cjs +106 -0
  563. package/scripts/sync-manifest-versions.cjs +119 -0
  564. package/scripts/sync-rulesets.sh +34 -0
  565. package/scripts/sync-runtime-launcher.cjs +399 -0
  566. package/scripts/test-failure-reasons.cjs +34 -0
  567. package/scripts/verify-npm-publish.cjs +240 -0
  568. package/scripts/workflow-policy.cjs +450 -0
@@ -0,0 +1,351 @@
1
+ #!/usr/bin/env bash
2
+ # base64-scan.sh — Detect base64-obfuscated prompt injection in source files
3
+ #
4
+ # Extracts base64 blobs >= 40 chars, decodes them, and checks decoded content
5
+ # against the same injection patterns used by prompt-injection-scan.sh.
6
+ #
7
+ # Usage:
8
+ # scripts/base64-scan.sh --diff origin/main # CI mode: scan changed files
9
+ # scripts/base64-scan.sh --file path/to/file # Scan a single file
10
+ # scripts/base64-scan.sh --dir agents/ # Scan all files in a directory
11
+ #
12
+ # Exit codes:
13
+ # 0 = clean
14
+ # 1 = findings detected
15
+ # 2 = usage error
16
+ set -euo pipefail
17
+
18
+ # ── Locale hardening (#116) ───────────────────────────────────────────────────
19
+ # BSD tr (macOS) treats input bytes as multi-byte characters under any UTF-8
20
+ # locale. When the input to `tr -cd '[:print:]'` contains bytes that are not
21
+ # valid UTF-8 start sequences (e.g. lone continuation bytes 0x80–0x9F), BSD tr
22
+ # emits "Illegal byte sequence" to stderr and exits non-zero. Setting LC_ALL=C
23
+ # forces the C locale throughout the script so every byte 0x00–0xFF is a valid
24
+ # character — no multi-byte interpretation, no illegal-byte errors.
25
+ #
26
+ # This is safe for our use-case: all injection patterns are ASCII; base64 -d
27
+ # and grep -E POSIX classes ([:space:], [:print:]) behave correctly in C locale.
28
+ #
29
+ # Source: `man tr` on macOS 26.5 — ENVIRONMENT section states LC_ALL / LC_CTYPE
30
+ # control character interpretation; BSD tr rejects invalid multi-byte sequences.
31
+ # Empirically verified: `printf '\x80\x81hello' | LC_ALL=C tr -cd '[:print:]'`
32
+ # exits 0 and strips the high bytes cleanly.
33
+ export LC_ALL=C
34
+
35
+ MIN_BLOB_LENGTH=40
36
+ # Lines longer than this byte count are skipped with a partial-scan warning.
37
+ # This prevents `grep -oE` from spending unbounded time on e.g. minified JS or
38
+ # single-line binary blobs. 1 MiB is large enough for any realistic text file
39
+ # line but small enough to bound blob-extraction cost.
40
+ MAX_LINE_BYTES=1048576
41
+
42
+ # -- Portable timeout wrapper (#116) ------------------------------------------
43
+ # macOS does not ship GNU coreutils timeout. We probe for it (or gtimeout
44
+ # from homebrew coreutils), falling back to perl alarm(N)+exec.
45
+ # Exit codes: GNU timeout uses 124 on timeout; perl SIGALRM produces 142.
46
+ # Both are treated as timeout exits by is_timeout_exit() below.
47
+ # Usage: run_with_timeout <seconds> <command> [args...]
48
+ _TIMEOUT_CMD=""
49
+ # shellcheck disable=SC2329 # intentionally defined for use by callers; not called in main loop
50
+ _init_timeout_cmd() {
51
+ if [[ -n "$_TIMEOUT_CMD" ]]; then return; fi
52
+ if command -v timeout >/dev/null 2>&1; then
53
+ _TIMEOUT_CMD="timeout"
54
+ elif command -v gtimeout >/dev/null 2>&1; then
55
+ _TIMEOUT_CMD="gtimeout"
56
+ else
57
+ _TIMEOUT_CMD="perl_alarm"
58
+ fi
59
+ }
60
+
61
+ # shellcheck disable=SC2329 # intentionally defined for use by callers; not called in main loop
62
+ run_with_timeout() {
63
+ local secs="$1"; shift
64
+ _init_timeout_cmd
65
+ case "$_TIMEOUT_CMD" in
66
+ timeout|gtimeout)
67
+ "$_TIMEOUT_CMD" "$secs" "$@"
68
+ ;;
69
+ perl_alarm)
70
+ # perl sets SIGALRM after N seconds, then exec()s the command.
71
+ # Exit 142 (SIGALRM) when timed out.
72
+ perl -e '
73
+ my $secs = shift @ARGV;
74
+ alarm($secs);
75
+ exec(@ARGV) or die "exec: $!\n";
76
+ ' -- "$secs" "$@"
77
+ ;;
78
+ esac
79
+ }
80
+
81
+ # is_timeout_exit: returns 0 (true) if rc indicates a timeout kill.
82
+ # shellcheck disable=SC2329 # intentionally defined for use by callers; not called in main loop
83
+ is_timeout_exit() { [[ "$1" -eq 124 || "$1" -eq 142 ]]; }
84
+
85
+
86
+ # ─── Injection Patterns (decoded content) ────────────────────────────────────
87
+ # Subset of patterns — if someone base64-encoded something, check for the
88
+ # most common injection indicators.
89
+ DECODED_PATTERNS=(
90
+ 'ignore[[:space:]]+(all[[:space:]]+)?previous[[:space:]]+instructions'
91
+ 'you[[:space:]]+are[[:space:]]+now[[:space:]]+'
92
+ 'system[[:space:]]+prompt'
93
+ '</?system>'
94
+ '</?assistant>'
95
+ '\[SYSTEM\]'
96
+ '\[INST\]'
97
+ '<<SYS>>'
98
+ 'override[[:space:]]+(system|safety|security)'
99
+ 'pretend[[:space:]]+(you|to)[[:space:]]'
100
+ 'act[[:space:]]+as[[:space:]]+(a|an|if)'
101
+ 'jailbreak'
102
+ 'bypass[[:space:]]+(safety|content|security)'
103
+ 'eval[[:space:]]*\('
104
+ 'exec[[:space:]]*\('
105
+ 'rm[[:space:]]+-rf'
106
+ 'curl[[:space:]].*\|[[:space:]]*sh'
107
+ 'wget[[:space:]].*\|[[:space:]]*sh'
108
+ )
109
+
110
+ # ─── Ignorelist ──────────────────────────────────────────────────────────────
111
+
112
+ IGNOREFILE=".base64scanignore"
113
+ IGNORED_PATTERNS=()
114
+
115
+ load_ignorelist() {
116
+ if [[ -f "$IGNOREFILE" ]]; then
117
+ while IFS= read -r line; do
118
+ # Skip comments and empty lines
119
+ [[ "$line" =~ ^[[:space:]]*# ]] && continue
120
+ [[ -z "${line// }" ]] && continue
121
+ IGNORED_PATTERNS+=("$line")
122
+ done < "$IGNOREFILE"
123
+ fi
124
+ }
125
+
126
+ is_ignored() {
127
+ local blob="$1"
128
+ if [[ ${#IGNORED_PATTERNS[@]} -eq 0 ]]; then
129
+ return 1
130
+ fi
131
+ for pattern in "${IGNORED_PATTERNS[@]}"; do
132
+ if [[ "$blob" == "$pattern" ]]; then
133
+ return 0
134
+ fi
135
+ done
136
+ return 1
137
+ }
138
+
139
+ # ─── Skip Rules ──────────────────────────────────────────────────────────────
140
+
141
+ should_skip_file() {
142
+ local file="$1"
143
+ # Skip binary files
144
+ case "$file" in
145
+ *.png|*.jpg|*.jpeg|*.gif|*.ico|*.woff|*.woff2|*.ttf|*.eot|*.otf) return 0 ;;
146
+ *.zip|*.tar|*.gz|*.bz2|*.xz|*.7z) return 0 ;;
147
+ *.pdf|*.doc|*.docx|*.xls|*.xlsx) return 0 ;;
148
+ esac
149
+ # Skip lockfiles and node_modules
150
+ case "$file" in
151
+ */node_modules/*) return 0 ;;
152
+ */package-lock.json) return 0 ;;
153
+ */yarn.lock) return 0 ;;
154
+ */pnpm-lock.yaml) return 0 ;;
155
+ esac
156
+ # Skip the scan scripts themselves and test files
157
+ case "$file" in
158
+ */base64-scan.sh) return 0 ;;
159
+ */security-scan.test.cjs) return 0 ;;
160
+ esac
161
+ # Skip scanner fixture directories — they contain deliberate injection samples
162
+ case "$file" in
163
+ tests/fixtures/*) return 0 ;;
164
+ esac
165
+ return 1
166
+ }
167
+
168
+ is_data_uri() {
169
+ local context="$1"
170
+ # data:image/png;base64,... or data:application/font-woff;base64,...
171
+ echo "$context" | grep -qE 'data:[a-zA-Z]+/[a-zA-Z0-9.+-]+;base64,' 2>/dev/null
172
+ }
173
+
174
+ # ─── File Collection ─────────────────────────────────────────────────────────
175
+
176
+ collect_files() {
177
+ local mode="$1"
178
+ shift
179
+
180
+ case "$mode" in
181
+ --diff)
182
+ local base="${1:-origin/main}"
183
+ git diff --name-only --diff-filter=ACMR "$base"...HEAD 2>/dev/null \
184
+ | grep -vE '\.(png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot|otf|zip|tar|gz|pdf)$' || true
185
+ ;;
186
+ --file)
187
+ if [[ -f "$1" ]]; then
188
+ echo "$1"
189
+ else
190
+ echo "Error: file not found: $1" >&2
191
+ exit 2
192
+ fi
193
+ ;;
194
+ --dir)
195
+ local dir="$1"
196
+ if [[ ! -d "$dir" ]]; then
197
+ echo "Error: directory not found: $dir" >&2
198
+ exit 2
199
+ fi
200
+ find "$dir" -type f ! -path '*/node_modules/*' ! -path '*/.git/*' ! -path '*/dist/*' \
201
+ ! -name '*.png' ! -name '*.jpg' ! -name '*.gif' ! -name '*.woff*' 2>/dev/null || true
202
+ ;;
203
+ --stdin)
204
+ cat
205
+ ;;
206
+ *)
207
+ echo "Usage: $0 --diff [base] | --file <path> | --dir <path> | --stdin" >&2
208
+ exit 2
209
+ ;;
210
+ esac
211
+ }
212
+
213
+ # ─── Scanner ─────────────────────────────────────────────────────────────────
214
+
215
+ extract_and_check_blobs() {
216
+ local file="$1"
217
+ local found=0
218
+ local line_num=0
219
+
220
+ # Skip binary-by-content files (e.g. adversarial parser fixtures with embedded
221
+ # non-UTF8 / NUL bytes). They cannot meaningfully carry base64-obfuscated *text*,
222
+ # and feeding NUL bytes through the per-line scanner spawns thousands of bogus
223
+ # `base64 -d` subprocesses (the "ignored null byte" warnings) — slow enough to
224
+ # blow the job timeout on a large diff. `grep -Iq .` treats a binary file as
225
+ # non-matching, so this skips it with a coverage notice (collect_files already
226
+ # filters binary *extensions*; this catches binary *content* in text extensions).
227
+ if ! LC_ALL=C grep -Iq . "$file" 2>/dev/null; then
228
+ echo "SKIP: $file (binary content — base64 text scan not applicable)" >&2
229
+ return 0
230
+ fi
231
+
232
+ while IFS= read -r line; do
233
+ line_num=$((line_num + 1))
234
+
235
+ # Guard: skip lines that exceed MAX_LINE_BYTES. Very long lines (e.g. a
236
+ # minified JS bundle stored as one line, or a binary file with no newlines)
237
+ # would cause `grep -oE` to spend unbounded time. We emit a partial-scan
238
+ # warning to stderr so the caller can see coverage was reduced.
239
+ if [[ ${#line} -gt $MAX_LINE_BYTES ]]; then
240
+ echo "SKIP: $file line $line_num (${#line} bytes > ${MAX_LINE_BYTES} limit — partial scan)" >&2
241
+ continue
242
+ fi
243
+
244
+ # Skip data URIs — legitimate base64 usage
245
+ if is_data_uri "$line"; then
246
+ continue
247
+ fi
248
+
249
+ # Extract base64-like blobs (alphanumeric + / + = padding, >= MIN_BLOB_LENGTH)
250
+ local blobs
251
+ blobs=$(echo "$line" | grep -oE '[A-Za-z0-9+/]{'"$MIN_BLOB_LENGTH"',}={0,3}' 2>/dev/null || true)
252
+
253
+ if [[ -z "$blobs" ]]; then
254
+ continue
255
+ fi
256
+
257
+ while IFS= read -r blob; do
258
+ [[ -z "$blob" ]] && continue
259
+
260
+ # Check ignorelist
261
+ if [[ ${#IGNORED_PATTERNS[@]} -gt 0 ]] && is_ignored "$blob"; then
262
+ continue
263
+ fi
264
+
265
+ # Try to decode — if it fails, not valid base64
266
+ local decoded
267
+ decoded=$(echo "$blob" | base64 -d 2>/dev/null || echo "")
268
+
269
+ if [[ -z "$decoded" ]]; then
270
+ continue
271
+ fi
272
+
273
+ # Check if decoded content is mostly printable text (not random binary)
274
+ local total_chars=${#decoded}
275
+ if [[ $total_chars -eq 0 ]]; then
276
+ continue
277
+ fi
278
+
279
+ # Count printable ASCII characters
280
+ local printable_count
281
+ printable_count=$(echo -n "$decoded" | tr -cd '[:print:]' | wc -c | tr -d ' ')
282
+ # Skip if less than 70% printable (likely binary data, not obfuscated text)
283
+ if [[ $((printable_count * 100 / total_chars)) -lt 70 ]]; then
284
+ continue
285
+ fi
286
+
287
+ # Scan decoded content against injection patterns
288
+ for pattern in "${DECODED_PATTERNS[@]}"; do
289
+ if echo "$decoded" | grep -iqE "$pattern" 2>/dev/null; then
290
+ if [[ $found -eq 0 ]]; then
291
+ echo "FAIL: $file"
292
+ found=1
293
+ fi
294
+ echo " line $line_num: base64 blob decodes to suspicious content"
295
+ echo " blob: ${blob:0:60}..."
296
+ echo " decoded: ${decoded:0:120}"
297
+ echo " matched: $pattern"
298
+ break
299
+ fi
300
+ done
301
+ done <<< "$blobs"
302
+ done < "$file"
303
+
304
+ return $found
305
+ }
306
+
307
+ # ─── Main ────────────────────────────────────────────────────────────────────
308
+
309
+ main() {
310
+ if [[ $# -eq 0 ]]; then
311
+ echo "Usage: $0 --diff [base] | --file <path> | --dir <path>" >&2
312
+ exit 2
313
+ fi
314
+
315
+ load_ignorelist
316
+
317
+ local mode="$1"
318
+ shift
319
+
320
+ local files
321
+ files=$(collect_files "$mode" "$@")
322
+
323
+ if [[ -z "$files" ]]; then
324
+ echo "base64-scan: no files to scan"
325
+ exit 0
326
+ fi
327
+
328
+ local total=0
329
+ local failed=0
330
+
331
+ while IFS= read -r file; do
332
+ [[ -z "$file" ]] && continue
333
+ if should_skip_file "$file"; then
334
+ continue
335
+ fi
336
+ total=$((total + 1))
337
+ if ! extract_and_check_blobs "$file"; then
338
+ failed=$((failed + 1))
339
+ fi
340
+ done <<< "$files"
341
+
342
+ echo ""
343
+ echo "base64-scan: scanned $total files, $failed with findings"
344
+
345
+ if [[ $failed -gt 0 ]]; then
346
+ exit 1
347
+ fi
348
+ exit 0
349
+ }
350
+
351
+ main "$@"
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Copy GSD hooks to dist for installation.
4
+ * Validates JavaScript syntax before copying to prevent shipping broken hooks.
5
+ * See #1107, #1109, #1125, #1161 — a duplicate const declaration shipped
6
+ * in dist and caused PostToolUse hook errors for all users.
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const vm = require('vm');
12
+
13
+ const HOOKS_DIR = path.join(__dirname, '..', 'hooks');
14
+ const DIST_DIR = path.join(HOOKS_DIR, 'dist');
15
+ // Per-process staging directory for atomic writes. Using process.pid in the
16
+ // name eliminates all contention between concurrent builders: each process
17
+ // owns its own staging dir and never races with another builder's cleanup.
18
+ // Lives under hooks/ so it shares a filesystem with DIST_DIR (POSIX
19
+ // rename(2) is only atomic within the same filesystem) but is NOT inside
20
+ // DIST_DIR — so readers that readdirSync(DIST_DIR) (e.g. bin/install.js,
21
+ // install-hooks-copy tests) never observe a transient ".tmp" sibling.
22
+ // The parent pattern hooks/.dist-staging-*/ is gitignored.
23
+ const STAGE_DIR = path.join(HOOKS_DIR, `.dist-staging-${process.pid}`);
24
+
25
+ // Hooks to copy (pure Node.js, no bundling needed)
26
+ const HOOKS_TO_COPY = [
27
+ 'gsd-check-update-worker.js',
28
+ 'gsd-check-update.js',
29
+ // Required by gsd-check-update-worker.js at runtime — must ship alongside it
30
+ // so require('./managed-hooks-registry.cjs') resolves in the installed hooks/ dir.
31
+ 'managed-hooks-registry.cjs',
32
+ 'gsd-context-monitor.js',
33
+ // Cursor lifecycle hooks (issue #777): sessionStart context injection + postToolUse monitor
34
+ 'gsd-cursor-session-start.js',
35
+ 'gsd-cursor-post-tool.js',
36
+ // Claude Code FileChanged hook (#770) — hot-reloads gsd config when
37
+ // .planning/config.json changes mid-session. Must ship to dist so the
38
+ // installer can copy it to the target hooks/ dir and register FileChanged.
39
+ 'gsd-config-reload.js',
40
+ 'gsd-prompt-guard.js',
41
+ 'gsd-read-guard.js',
42
+ 'gsd-read-injection-scanner.js',
43
+ 'gsd-statusline.js',
44
+ 'gsd-update-banner.js',
45
+ 'gsd-workflow-guard.js',
46
+ 'gsd-worktree-path-guard.js',
47
+ // Community hooks (bash, opt-in via .planning/config.json hooks.community)
48
+ 'gsd-session-state.sh',
49
+ 'gsd-validate-commit.sh',
50
+ 'gsd-phase-boundary.sh',
51
+ // Graphify auto-update hook (#3347 / PR #3557 / #3579). Opt-in via
52
+ // .planning/config.json graphify.auto_update; off by default.
53
+ 'gsd-graphify-update.sh'
54
+ ];
55
+
56
+ // Subdirectories under hooks/ whose contents must also ship to dist. Each
57
+ // entry is copied as `hooks/<dir>/*` → `hooks/dist/<dir>/*` so detached
58
+ // helpers (e.g. hooks/lib/gsd-graphify-rebuild.sh) resolve from the hook's
59
+ // installed runtime path. See #3579.
60
+ const HOOKS_SUBDIRS_TO_COPY = ['lib'];
61
+
62
+ // Sync millisecond sleep using Atomics.wait on a throwaway SharedArrayBuffer.
63
+ // Used between Windows rename retries; this script is sync end-to-end so
64
+ // setTimeout would not work. Total worst-case backoff across MAX_ATTEMPTS
65
+ // is bounded (~400ms) — acceptable for a one-shot build script.
66
+ function sleepSync(ms) {
67
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
68
+ }
69
+
70
+ /**
71
+ * Atomic-replace via fs.renameSync, with Windows-only retry and fallback.
72
+ *
73
+ * POSIX rename(2) atomically replaces dest even when readers hold open
74
+ * handles on it. Windows MoveFileEx (which fs.renameSync uses with
75
+ * MOVEFILE_REPLACE_EXISTING) cannot — it throws EPERM/EBUSY when another
76
+ * process has the destination open. Concurrent install.js readers and
77
+ * antivirus scanners are the realistic triggers; both release handles
78
+ * within milliseconds, so a short backoff resolves the race. After
79
+ * retries are exhausted, fall back to copy-then-unlink (re-introduces
80
+ * the truncate-then-write race for this single file but keeps the build
81
+ * moving rather than crashing). If even copy fails because dest is hard-
82
+ * locked, log a non-fatal warning and leave the prior dest in place — a
83
+ * subsequent build invocation will retry from a fresh state.
84
+ */
85
+ function renameAtomicWithRetry(stagedDest, dest, hook) {
86
+ if (process.platform !== 'win32') {
87
+ fs.renameSync(stagedDest, dest);
88
+ return;
89
+ }
90
+ const BACKOFFS_MS = [10, 30, 90, 270];
91
+ for (let attempt = 0; attempt <= BACKOFFS_MS.length; attempt++) {
92
+ try {
93
+ fs.renameSync(stagedDest, dest);
94
+ return;
95
+ } catch (e) {
96
+ const transient = e && (e.code === 'EPERM' || e.code === 'EBUSY');
97
+ if (!transient) throw e;
98
+ if (attempt < BACKOFFS_MS.length) {
99
+ sleepSync(BACKOFFS_MS[attempt]);
100
+ continue;
101
+ }
102
+ // Retries exhausted; fall back to copy-then-unlink.
103
+ try {
104
+ fs.copyFileSync(stagedDest, dest);
105
+ try { fs.unlinkSync(stagedDest); } catch (_) { /* tolerate */ }
106
+ console.warn(`\x1b[33m! ${hook}: rename failed (${e.code}) after ${BACKOFFS_MS.length} retries; used copy-fallback\x1b[0m`);
107
+ return;
108
+ } catch (fallbackErr) {
109
+ try { fs.unlinkSync(stagedDest); } catch (_) { /* tolerate */ }
110
+ console.warn(`\x1b[33m! ${hook}: rename + copy fallback both failed (${e.code} → ${fallbackErr.code || fallbackErr.message}); leaving prior dest in place\x1b[0m`);
111
+ return;
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Validate JavaScript syntax without executing the file.
119
+ * Catches SyntaxError (duplicate const, missing brackets, etc.)
120
+ * before the hook gets shipped to users.
121
+ */
122
+ function validateSyntax(filePath) {
123
+ const content = fs.readFileSync(filePath, 'utf8');
124
+ try {
125
+ // Use vm.compileFunction to check syntax without executing
126
+ new vm.Script(content, { filename: path.basename(filePath) });
127
+ return null; // No error
128
+ } catch (e) {
129
+ if (e instanceof SyntaxError) {
130
+ return e.message;
131
+ }
132
+ throw e;
133
+ }
134
+ }
135
+
136
+ function build() {
137
+ // Ensure dist and staging directories exist (staging is a sibling of dist
138
+ // used to make writes atomic — see STAGE_DIR comment above).
139
+ if (!fs.existsSync(DIST_DIR)) {
140
+ fs.mkdirSync(DIST_DIR, { recursive: true });
141
+ }
142
+ if (!fs.existsSync(STAGE_DIR)) {
143
+ fs.mkdirSync(STAGE_DIR, { recursive: true });
144
+ }
145
+
146
+ let hasErrors = false;
147
+
148
+ // Copy hooks to dist with syntax validation
149
+ for (const hook of HOOKS_TO_COPY) {
150
+ const src = path.join(HOOKS_DIR, hook);
151
+ const dest = path.join(DIST_DIR, hook);
152
+
153
+ if (!fs.existsSync(src)) {
154
+ console.warn(`Warning: ${hook} not found, skipping`);
155
+ continue;
156
+ }
157
+
158
+ // Validate JS syntax before copying (.sh files skip — not Node.js)
159
+ if (hook.endsWith('.js')) {
160
+ const syntaxError = validateSyntax(src);
161
+ if (syntaxError) {
162
+ console.error(`\x1b[31m✗ ${hook}: SyntaxError — ${syntaxError}\x1b[0m`);
163
+ hasErrors = true;
164
+ continue;
165
+ }
166
+ }
167
+
168
+ console.log(`\x1b[32m✓\x1b[0m Copying ${hook}...`);
169
+ // Atomic write: copy to a per-process staging file in the per-PID sibling
170
+ // STAGE_DIR (same filesystem as DIST_DIR so rename(2) is atomic), then
171
+ // rename into place. Multiple test files invoke this script concurrently
172
+ // from their before() hooks; fs.copyFileSync truncates then writes the
173
+ // destination — readers (install.js subprocesses spawned by parallel
174
+ // install tests) can observe the dest empty or partial mid-write,
175
+ // producing flaky failures such as bug-2136 part 4 where installed .sh
176
+ // hooks lacked their "# gsd-hook-version:" header. POSIX rename(2)
177
+ // makes the swap atomic so readers see either the old file or the new
178
+ // file. The staging file lives outside DIST_DIR so readdirSync(DIST_DIR)
179
+ // (in install.js and tests) never observes a transient ".tmp" sibling.
180
+ // Each process uses its own STAGE_DIR (keyed by PID) so concurrent
181
+ // builders never race on staging-dir creation or cleanup.
182
+ const stagedDest = path.join(STAGE_DIR, `${hook}.${Date.now()}`);
183
+ fs.copyFileSync(src, stagedDest);
184
+ // Preserve executable bit for shell scripts before rename so the
185
+ // installed file is executable from the very first observation.
186
+ if (hook.endsWith('.sh')) {
187
+ try { fs.chmodSync(stagedDest, 0o755); } catch (e) { /* Windows */ }
188
+ }
189
+ renameAtomicWithRetry(stagedDest, dest, hook);
190
+ }
191
+
192
+ // Copy whitelisted hook subdirectories (e.g. hooks/lib/) into dist so the
193
+ // installer's readdir-and-isFile loop in bin/install.js sees them and
194
+ // detached hook helpers resolve from the installed runtime path (#3579).
195
+ for (const subdir of HOOKS_SUBDIRS_TO_COPY) {
196
+ const srcDir = path.join(HOOKS_DIR, subdir);
197
+ if (!fs.existsSync(srcDir)) continue;
198
+ const destDir = path.join(DIST_DIR, subdir);
199
+ fs.mkdirSync(destDir, { recursive: true });
200
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
201
+ for (const ent of entries) {
202
+ if (!ent.isFile()) continue;
203
+ const srcFile = path.join(srcDir, ent.name);
204
+ const destFile = path.join(destDir, ent.name);
205
+ if (ent.name.endsWith('.js')) {
206
+ const syntaxError = validateSyntax(srcFile);
207
+ if (syntaxError) {
208
+ console.error(`\x1b[31m✗ ${subdir}/${ent.name}: SyntaxError — ${syntaxError}\x1b[0m`);
209
+ hasErrors = true;
210
+ continue;
211
+ }
212
+ }
213
+ console.log(`\x1b[32m✓\x1b[0m Copying ${subdir}/${ent.name}...`);
214
+ const stagedDest = path.join(STAGE_DIR, `${subdir}__${ent.name}.${Date.now()}`);
215
+ fs.copyFileSync(srcFile, stagedDest);
216
+ if (ent.name.endsWith('.sh')) {
217
+ try { fs.chmodSync(stagedDest, 0o755); } catch (e) { /* Windows */ }
218
+ }
219
+ renameAtomicWithRetry(stagedDest, destFile, `${subdir}/${ent.name}`);
220
+ }
221
+ }
222
+
223
+ // Best-effort cleanup of this process's own staging dir. Since STAGE_DIR
224
+ // is per-PID (`.dist-staging-<pid>/`), no other builder touches it — so
225
+ // rmSync with recursive:true is safe and leaves no race window.
226
+ try {
227
+ fs.rmSync(STAGE_DIR, { recursive: true, force: true });
228
+ } catch (e) { /* tolerate ENOENT if the dir was never created (e.g. all hooks skipped) */ }
229
+
230
+ if (hasErrors) {
231
+ console.error('\n\x1b[31mBuild failed: fix syntax errors above before publishing.\x1b[0m');
232
+ process.exit(1);
233
+ }
234
+
235
+ console.log('\nBuild complete.');
236
+ }
237
+
238
+ // Export HOOKS_TO_COPY so tests can require() this file and assert against
239
+ // the typed value instead of regex-parsing the source text (retires
240
+ // pending-migration-to-typed-ir for orphaned-hooks.test.cjs, per #455).
241
+ // Guard the build() call so requiring this file as a module does not trigger
242
+ // a full build run (which copies files and writes to disk).
243
+ if (require.main === module) {
244
+ build();
245
+ }
246
+
247
+ module.exports = { HOOKS_TO_COPY, HOOKS_SUBDIRS_TO_COPY };