@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,138 @@
1
+ #!/usr/bin/env node
2
+ // gsd-hook-version: {{GSD_VERSION}}
3
+ // SessionStart banner that surfaces GSD update availability when GSD's
4
+ // statusline isn't installed. Reads the cache that
5
+ // gsd-check-update-worker.js writes to ~/.cache/gsd/<updateCacheFileName> (per-package).
6
+ //
7
+ // Opt-in by design: bin/install.js only registers this hook when the user
8
+ // declines to install (or replace) the GSD statusline. The presence of the
9
+ // SessionStart entry IS the opt-in — there is no separate runtime flag.
10
+ //
11
+ // See issue #2795 for the rationale.
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const os = require('os');
18
+ const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
19
+
20
+ // Suppress repeat parse-error banners for 24 hours so a genuinely broken
21
+ // cache file doesn't nag the user every session.
22
+ const RATE_LIMIT_SECONDS = 24 * 60 * 60;
23
+
24
+ /**
25
+ * Build the SessionStart JSON envelope to emit, given parsed cache state.
26
+ * Pure function — no I/O. Returns null when the hook should print nothing.
27
+ *
28
+ * @param {object} state
29
+ * @param {object|null} state.cache Parsed cache, or null if missing/unreadable.
30
+ * @param {boolean} state.parseError True iff cache file existed but JSON.parse failed.
31
+ * @param {boolean} state.suppressFailureWarning True when a recent failure warning already fired.
32
+ * @returns {{systemMessage: string}|null} JSON envelope, or null for silent exit.
33
+ */
34
+ function buildBannerOutput(state) {
35
+ const { cache, parseError, suppressFailureWarning } = state || {};
36
+ if (parseError) {
37
+ if (suppressFailureWarning) return null;
38
+ return { systemMessage: 'GSD update check failed.' };
39
+ }
40
+ if (!cache) return null;
41
+ // Lineage guard: package_name must be present and match this package.
42
+ // Absent package_name means the cache predates lineage tracking — treat as untrusted.
43
+ if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return null;
44
+ if (!cache.update_available) return null;
45
+ const installed = cache.installed || 'unknown';
46
+ const latest = cache.latest || 'unknown';
47
+ return {
48
+ systemMessage: `GSD update available: ${installed} → ${latest}. Run /gsd:update.`,
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Read and parse the update-check cache file.
54
+ *
55
+ * @param {string} cacheFile
56
+ * @returns {{cache: object|null, parseError: boolean}}
57
+ */
58
+ function readCache(cacheFile) {
59
+ let cache = null;
60
+ let parseError = false;
61
+ try {
62
+ if (fs.existsSync(cacheFile)) {
63
+ const raw = fs.readFileSync(cacheFile, 'utf8');
64
+ cache = JSON.parse(raw);
65
+ }
66
+ } catch (e) {
67
+ // Distinguish "file unreadable" from "JSON malformed": both fail-open to
68
+ // null cache, but a JSON parse error becomes a one-time diagnostic.
69
+ parseError = e instanceof SyntaxError;
70
+ }
71
+ return { cache, parseError };
72
+ }
73
+
74
+ /**
75
+ * Has a failure warning been emitted within the rate-limit window?
76
+ *
77
+ * @param {string} sentinelFile
78
+ * @param {number} nowSeconds
79
+ * @returns {boolean}
80
+ */
81
+ function shouldSuppressFailureWarning(sentinelFile, nowSeconds) {
82
+ try {
83
+ if (!fs.existsSync(sentinelFile)) return false;
84
+ const last = parseInt(fs.readFileSync(sentinelFile, 'utf8').trim(), 10);
85
+ if (!Number.isFinite(last)) return false;
86
+ return nowSeconds - last < RATE_LIMIT_SECONDS;
87
+ } catch (e) {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ function recordFailureWarning(sentinelFile, nowSeconds) {
93
+ try {
94
+ fs.writeFileSync(sentinelFile, String(nowSeconds));
95
+ } catch (e) {
96
+ // Best-effort: a non-writable cache dir means we'll re-warn next session,
97
+ // which is no worse than the un-instrumented baseline.
98
+ }
99
+ }
100
+
101
+ function main() {
102
+ const cacheDir = path.join(os.homedir(), '.cache', 'gsd');
103
+ const cacheFile = path.join(cacheDir, updateCacheFileName);
104
+ const sentinelFile = path.join(cacheDir, 'banner-failure-warned-at');
105
+ const now = Math.floor(Date.now() / 1000);
106
+
107
+ const { cache, parseError } = readCache(cacheFile);
108
+ const suppressFailureWarning = parseError
109
+ ? shouldSuppressFailureWarning(sentinelFile, now)
110
+ : false;
111
+ const output = buildBannerOutput({ cache, parseError, suppressFailureWarning });
112
+
113
+ if (parseError && !suppressFailureWarning) {
114
+ // Ensure cache dir exists before writing the sentinel — first-run case
115
+ // where ~/.cache/gsd was created by check-update but the parent dir got
116
+ // wiped between runs.
117
+ try {
118
+ fs.mkdirSync(cacheDir, { recursive: true });
119
+ } catch (e) {
120
+ // Best-effort: failure to create the dir means we'll re-warn next
121
+ // session, which is no worse than the un-instrumented baseline.
122
+ }
123
+ recordFailureWarning(sentinelFile, now);
124
+ }
125
+
126
+ if (output) {
127
+ process.stdout.write(JSON.stringify(output));
128
+ }
129
+ }
130
+
131
+ if (require.main === module) main();
132
+
133
+ module.exports = {
134
+ buildBannerOutput,
135
+ readCache,
136
+ shouldSuppressFailureWarning,
137
+ RATE_LIMIT_SECONDS,
138
+ };
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ # gsd-hook-version: {{GSD_VERSION}}
3
+ # gsd-validate-commit.sh — PreToolUse hook: enforce Conventional Commits format
4
+ # Blocks git commit commands with non-conforming messages (exit 2).
5
+ # Allows conforming messages and all non-commit commands (exit 0).
6
+ # Uses Node.js for JSON parsing (always available in GSD projects, no jq dependency).
7
+ #
8
+ # OPT-IN: This hook is a no-op unless config.json has hooks.community: true.
9
+ # Enable with: "hooks": { "community": true } in .planning/config.json
10
+
11
+ # Check opt-in config — exit silently if not enabled
12
+ if [ -f .planning/config.json ]; then
13
+ ENABLED=$(node -e "try{const c=require('./.planning/config.json');process.stdout.write(c.hooks?.community===true?'1':'0')}catch{process.stdout.write('0')}" 2>/dev/null)
14
+ if [ "$ENABLED" != "1" ]; then exit 0; fi
15
+ else
16
+ exit 0
17
+ fi
18
+
19
+ INPUT=$(cat)
20
+
21
+ # Extract command from JSON using Node (handles escaping correctly, no jq needed)
22
+ CMD=$(echo "$INPUT" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{process.stdout.write(JSON.parse(d).tool_input?.command||'')}catch{}})" 2>/dev/null)
23
+
24
+ # Only check git commit commands.
25
+ # Delegates to hooks/lib/git-cmd.js isGitSubcommand() — the canonical token-walk
26
+ # classifier that handles env-prefix, -C path, and full-path git invocations.
27
+ # A naive `^git\s+commit` regex misses all three; this guard fixes that (#3129).
28
+ HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
29
+ if GIT_CMD_LIB="$HOOK_DIR/lib/git-cmd.js" node -e "
30
+ const {isGitSubcommand}=require(process.env.GIT_CMD_LIB);
31
+ process.exit(isGitSubcommand(process.argv[1],'commit')?0:1);
32
+ " "$CMD" 2>/dev/null; then
33
+ # Extract message from -m flag
34
+ MSG=""
35
+ if [[ "$CMD" =~ -m[[:space:]]+\"([^\"]+)\" ]]; then
36
+ MSG="${BASH_REMATCH[1]}"
37
+ elif [[ "$CMD" =~ -m[[:space:]]+\'([^\']+)\' ]]; then
38
+ MSG="${BASH_REMATCH[1]}"
39
+ fi
40
+
41
+ if [ -n "$MSG" ]; then
42
+ SUBJECT=$(echo "$MSG" | head -1)
43
+ # Validate Conventional Commits format
44
+ if ! [[ "$SUBJECT" =~ ^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\(.+\))?:[[:space:]].+ ]]; then
45
+ # Emit a typed `code` field alongside `reason` (#2974). Tests assert
46
+ # on the stable code string; the reason is the human-readable copy.
47
+ echo '{"decision": "block", "code": "CONVENTIONAL_COMMITS_VIOLATION", "reason": "Commit message must follow Conventional Commits: <type>(<scope>): <subject>. Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore. Subject must be <=72 chars, lowercase, imperative mood, no trailing period."}'
48
+ exit 2
49
+ fi
50
+ if [ ${#SUBJECT} -gt 72 ]; then
51
+ echo '{"decision": "block", "code": "COMMIT_SUBJECT_TOO_LONG", "reason": "Commit subject must be 72 characters or less."}'
52
+ exit 2
53
+ fi
54
+ fi
55
+ fi
56
+
57
+ exit 0
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env node
2
+ // gsd-hook-version: {{GSD_VERSION}}
3
+ // GSD Workflow Guard — PreToolUse hook
4
+ // Detects when Claude attempts file edits outside a GSD workflow context
5
+ // (no active /gsd- skill or Task subagent) and injects an advisory warning.
6
+ //
7
+ // This is a SOFT guard — it advises, not blocks. The edit still proceeds.
8
+ // The warning nudges Claude to use /gsd:quick or /gsd:fast instead of
9
+ // making direct edits that bypass state tracking.
10
+ //
11
+ // Enable via config: hooks.workflow_guard: true (default: false)
12
+ // Only triggers on Write/Edit tool calls to non-.planning/ files.
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const { spawnSync } = require('child_process');
17
+ const { tokenize } = require('./lib/git-cmd.js');
18
+
19
+ function forceGitAddCwds(command, defaultCwd) {
20
+ const tokens = tokenize(command || '');
21
+ const separators = new Set(['&&', '||', ';', '|']);
22
+ const cwdList = [];
23
+ for (let i = 0; i < tokens.length; i++) {
24
+ if (path.basename(tokens[i]) !== 'git') continue;
25
+
26
+ let j = i + 1;
27
+ let gitCwd = defaultCwd;
28
+ while (j < tokens.length) {
29
+ const token = tokens[j];
30
+ const flagName = token.includes('=') ? token.slice(0, token.indexOf('=')) : token;
31
+ if (token === '-C' && tokens[j + 1]) {
32
+ gitCwd = path.resolve(gitCwd, tokens[j + 1]);
33
+ j += 2;
34
+ continue;
35
+ }
36
+ if (['-C', '--git-dir', '--work-tree'].includes(flagName) && !token.includes('=')) {
37
+ j += 2;
38
+ continue;
39
+ }
40
+ if (['--git-dir', '--work-tree', '--no-pager', '-p', '-P'].includes(flagName)) {
41
+ j++;
42
+ continue;
43
+ }
44
+ break;
45
+ }
46
+
47
+ if (tokens[j] !== 'add') continue;
48
+ for (let k = j + 1; k < tokens.length && !separators.has(tokens[k]); k++) {
49
+ if (tokens[k] === '--') break;
50
+ if (tokens[k] === '--force' || tokens[k] === '-f' || /^-[A-Za-z]*f[A-Za-z]*$/.test(tokens[k])) {
51
+ cwdList.push(gitCwd);
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ return cwdList;
57
+ }
58
+
59
+ function currentBranch(cwd) {
60
+ const result = spawnSync('git', ['branch', '--show-current'], {
61
+ cwd,
62
+ encoding: 'utf8',
63
+ stdio: ['ignore', 'pipe', 'ignore'],
64
+ windowsHide: true,
65
+ });
66
+ if (result.status !== 0) return '';
67
+ return result.stdout.trim();
68
+ }
69
+
70
+ function workflowGuardEnabled(cwd) {
71
+ const configPath = path.join(cwd, '.planning', 'config.json');
72
+ if (!fs.existsSync(configPath)) return false;
73
+ try {
74
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
75
+ return Boolean(config.hooks?.workflow_guard);
76
+ } catch (e) {
77
+ return false;
78
+ }
79
+ }
80
+
81
+ let input = '';
82
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
83
+ process.stdin.setEncoding('utf8');
84
+ process.stdin.on('data', chunk => input += chunk);
85
+ process.stdin.on('end', () => {
86
+ clearTimeout(stdinTimeout);
87
+ try {
88
+ const data = JSON.parse(input);
89
+ const toolName = data.tool_name;
90
+ const cwd = data.cwd || process.cwd();
91
+ const isWorkflowGuardEnabled = workflowGuardEnabled(cwd);
92
+
93
+ if (toolName === 'Bash') {
94
+ if (!isWorkflowGuardEnabled) {
95
+ process.exit(0);
96
+ }
97
+ const command = data.tool_input?.command || '';
98
+ for (const gitCwd of forceGitAddCwds(command, cwd)) {
99
+ const branch = currentBranch(gitCwd);
100
+ if (branch.startsWith('worktree-agent-')) {
101
+ process.stdout.write(JSON.stringify({
102
+ decision: 'block',
103
+ code: 'WORKTREE_AGENT_FORCE_ADD_FORBIDDEN',
104
+ reason: 'worktree-agent branches must not run git add -f or git add --force. Respect the SDK skipped_gitignored/skipped_commit_docs_false contract and leave gitignored files untracked.',
105
+ }));
106
+ process.exit(2);
107
+ }
108
+ }
109
+ process.exit(0);
110
+ }
111
+
112
+ // Only guard Write, Edit, and MultiEdit tool calls
113
+ if (!['Write', 'Edit', 'MultiEdit'].includes(toolName)) {
114
+ process.exit(0);
115
+ }
116
+
117
+ // Check if we're inside a GSD workflow (Task subagent or /gsd- skill)
118
+ // Subagents have a session_id that differs from the parent
119
+ // and typically have a description field set by the orchestrator
120
+ if (data.tool_input?.is_subagent || data.session_type === 'task') {
121
+ process.exit(0);
122
+ }
123
+
124
+ // Check the file being edited
125
+ const filePath = data.tool_input?.file_path || data.tool_input?.path || '';
126
+
127
+ // Allow edits to .planning/ files (GSD state management)
128
+ if (filePath.includes('.planning/') || filePath.includes('.planning\\')) {
129
+ process.exit(0);
130
+ }
131
+
132
+ // Allow edits to common config/docs files that don't need GSD tracking
133
+ const allowedPatterns = [
134
+ /\.gitignore$/,
135
+ /\.env/,
136
+ /CLAUDE\.md$/,
137
+ /AGENTS\.md$/,
138
+ /GEMINI\.md$/,
139
+ /settings\.json$/,
140
+ ];
141
+ if (allowedPatterns.some(p => p.test(filePath))) {
142
+ process.exit(0);
143
+ }
144
+
145
+ if (!isWorkflowGuardEnabled) {
146
+ process.exit(0); // Guard disabled (default) or no GSD project
147
+ }
148
+
149
+ // If we get here: GSD project, guard enabled, file edit outside .planning/,
150
+ // not in a subagent context. Inject advisory warning.
151
+ const output = {
152
+ hookSpecificOutput: {
153
+ hookEventName: "PreToolUse",
154
+ additionalContext: `⚠️ WORKFLOW ADVISORY: You're editing ${path.basename(filePath)} directly without a GSD command. ` +
155
+ 'This edit will not be tracked in STATE.md or produce a SUMMARY.md. ' +
156
+ 'Consider using /gsd:fast for trivial fixes or /gsd:quick for larger changes ' +
157
+ 'to maintain project state tracking. ' +
158
+ 'If this is intentional (e.g., user explicitly asked for a direct edit), proceed normally.'
159
+ }
160
+ };
161
+
162
+ process.stdout.write(JSON.stringify(output));
163
+ } catch (e) {
164
+ // Silent fail — never block tool execution
165
+ process.exit(0);
166
+ }
167
+ });
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ // gsd-hook-version: {{GSD_VERSION}}
3
+ // GSD Worktree Path Guard — PreToolUse hook
4
+ // Blocks Edit/Write/MultiEdit tool calls that target absolute paths outside the worktree root.
5
+ //
6
+ // Problem: gsd-executor agents spawned with isolation="worktree" sometimes issue
7
+ // Edit/Write calls with absolute paths rooted at the MAIN repository instead of
8
+ // the worktree (issue #260). The prose guard in agents/gsd-executor.md step 0b
9
+ // is never enforced because the model under load skips it.
10
+ //
11
+ // This hook enforces the constraint at the tooling layer, making it HARD-BLOCKING.
12
+ //
13
+ // Triggers on: Edit, Write, and MultiEdit tool calls
14
+ // Action: BLOCK (exit 2) if file_path is absolute and outside the worktree root
15
+ // No-op: relative paths, non-worktree CWDs, hook errors (silent fail)
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const { spawnSync } = require('child_process');
20
+
21
+ const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000, windowsHide: true };
22
+
23
+ function git(args, cwd) {
24
+ return spawnSync('git', args, { ...SPAWNOPT, cwd });
25
+ }
26
+
27
+ // Walk up from `start` to find the nearest existing directory.
28
+ // Returns null if we reach the filesystem root without finding one.
29
+ function nearestExistingDir(start) {
30
+ let dir = start;
31
+ let prev;
32
+ do {
33
+ prev = dir;
34
+ try { fs.accessSync(dir, fs.constants.F_OK); return dir; } catch { /* keep walking */ }
35
+ dir = path.dirname(dir);
36
+ } while (dir !== prev);
37
+ return null;
38
+ }
39
+
40
+ let input = '';
41
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
42
+ process.stdin.setEncoding('utf8');
43
+ process.stdin.on('data', chunk => input += chunk);
44
+ process.stdin.on('end', () => {
45
+ clearTimeout(stdinTimeout);
46
+ try {
47
+ const data = JSON.parse(input);
48
+ const toolName = data.tool_name;
49
+
50
+ // Only guard Edit, Write, and MultiEdit tool calls
51
+ if (toolName !== 'Edit' && toolName !== 'Write' && toolName !== 'MultiEdit') {
52
+ process.exit(0);
53
+ }
54
+
55
+ const cwd = data.cwd || process.cwd();
56
+
57
+ // Detect whether CWD is inside a linked git worktree by inspecting
58
+ // the git-dir path. In a linked worktree, git rev-parse --git-dir
59
+ // returns a path containing .git/worktrees/ as a component.
60
+ // In the main repo or a submodule it returns .git (or a path without /worktrees/).
61
+ // This approach works even when cwd is a subdirectory of the worktree.
62
+ const gitDirResult = git(['rev-parse', '--git-dir'], cwd);
63
+ if (gitDirResult.status !== 0 || !gitDirResult.stdout) {
64
+ process.exit(0); // not a git repo — pass through
65
+ }
66
+
67
+ const gitDir = gitDirResult.stdout.trim();
68
+ // A linked worktree's --git-dir contains .git/worktrees/ as a path component
69
+ const isLinkedWorktree = /[/\\]\.git[/\\]worktrees[/\\]/.test(gitDir);
70
+ if (!isLinkedWorktree) {
71
+ process.exit(0); // main repo, submodule, or separate-git-dir — no-op
72
+ }
73
+
74
+ // Get the raw --show-toplevel output for the worktree (cwd).
75
+ // We keep it raw (not path.resolve'd) to compare directly with the
76
+ // file's toplevel — same git binary, same format, no normalization needed.
77
+ const wtTopResult = git(['rev-parse', '--show-toplevel'], cwd);
78
+ if (wtTopResult.status !== 0 || !wtTopResult.stdout) {
79
+ process.exit(0); // can't determine root — fail open
80
+ }
81
+ const wtTopRaw = wtTopResult.stdout.trim();
82
+
83
+ const rawFilePath = data.tool_input?.file_path || '';
84
+ if (!rawFilePath) {
85
+ process.exit(0);
86
+ }
87
+
88
+ // Relative paths are always safe — they resolve relative to CWD inside the worktree
89
+ if (!path.isAbsolute(rawFilePath)) {
90
+ process.exit(0);
91
+ }
92
+
93
+ // Normalise .. traversal so /worktree/src/../../../main/file
94
+ // resolves to its true location before we check containment.
95
+ const filePath = path.resolve(rawFilePath);
96
+
97
+ // Find the nearest existing ancestor of filePath so we can ask git
98
+ // for its toplevel. The file itself may not exist yet (Write creates
99
+ // new files), but at least one ancestor directory must exist.
100
+ // We check the file itself first in case it already exists.
101
+ const checkDir = nearestExistingDir(
102
+ (() => {
103
+ try {
104
+ return fs.statSync(filePath).isDirectory() ? filePath : path.dirname(filePath);
105
+ } catch {
106
+ return path.dirname(filePath);
107
+ }
108
+ })()
109
+ );
110
+
111
+ if (!checkDir) {
112
+ // Walked to root without finding any directory — path is synthetic.
113
+ // Block conservatively.
114
+ const output = {
115
+ decision: 'block',
116
+ reason:
117
+ `Worktree path guard: '${filePath}' has no existing ancestor directory — ` +
118
+ `cannot verify it is inside the worktree '${wtTopRaw}'. Use a relative path instead.`,
119
+ };
120
+ process.stdout.write(JSON.stringify(output));
121
+ process.exit(2);
122
+ }
123
+
124
+ // Ask git for the toplevel of the file's location.
125
+ // Comparing two raw git --show-toplevel outputs avoids every
126
+ // platform-specific path normalisation pitfall (Windows 8.3 short names,
127
+ // case differences between realpathSync and path.resolve, forward- vs
128
+ // back-slash inconsistencies) — both values come from the same git binary
129
+ // in the same format by definition.
130
+ const fileTopResult = git(['rev-parse', '--show-toplevel'], checkDir);
131
+
132
+ if (fileTopResult.status !== 0 || !fileTopResult.stdout) {
133
+ // checkDir is not inside any git repo → cannot be inside the worktree.
134
+ const output = {
135
+ decision: 'block',
136
+ reason:
137
+ `Worktree path guard: '${filePath}' is not inside any git repository — ` +
138
+ `it cannot be inside the worktree at '${wtTopRaw}'. Use a relative path instead.`,
139
+ };
140
+ process.stdout.write(JSON.stringify(output));
141
+ process.exit(2);
142
+ }
143
+
144
+ const fileTopRaw = fileTopResult.stdout.trim();
145
+
146
+ // Same git toplevel → file is inside the worktree → allow
147
+ if (fileTopRaw === wtTopRaw) {
148
+ process.exit(0);
149
+ }
150
+
151
+ // BLOCK: file resolves to a different git root than the active worktree
152
+ const output = {
153
+ decision: 'block',
154
+ reason:
155
+ `Worktree path guard: '${filePath}' resolves to git root '${fileTopRaw}' which ` +
156
+ `differs from the active worktree root '${wtTopRaw}'. This likely means an ` +
157
+ `absolute path was derived from the orchestrator's main repository instead of ` +
158
+ `the active worktree. To fix: use a relative path, or re-derive the base ` +
159
+ `directory with \`git rev-parse --show-toplevel\` from within the worktree ` +
160
+ `(hook cwd: '${cwd}').`,
161
+ };
162
+
163
+ process.stdout.write(JSON.stringify(output));
164
+ process.exit(2);
165
+ } catch {
166
+ // Silent fail — never block valid tool calls due to hook errors
167
+ process.exit(0);
168
+ }
169
+ });
@@ -0,0 +1,150 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * git-cmd.js — token-walk git command classifier.
5
+ *
6
+ * Determines whether a shell command string invokes a specific git
7
+ * subcommand. Handles the four forms that a naive `^git\s+commit` regex
8
+ * misses:
9
+ *
10
+ * bare: git commit -m "..." ✓
11
+ * -C path: git -C /some/path commit -m "..." ✓ (missed by regex)
12
+ * env-prefix: GIT_AUTHOR_NAME=x git commit "..." ✓ (missed by regex)
13
+ * full-path: /usr/bin/git commit -m "..." ✓ (missed by regex)
14
+ *
15
+ * This module is the single source of truth for git-commit detection so all
16
+ * hooks that need to gate on git commits share one implementation.
17
+ *
18
+ * Exported by the hooks/lib/ directory — require via a path relative to the
19
+ * hook's own __dirname:
20
+ *
21
+ * const { isGitSubcommand } = require(path.join(__dirname, 'lib', 'git-cmd.js'));
22
+ */
23
+
24
+ const path = require('path');
25
+
26
+ /**
27
+ * Git global options that take a following argument.
28
+ * These must be consumed as (option, argument) pairs when walking tokens.
29
+ */
30
+ const ARGUMENT_TAKING_FLAGS = new Set([
31
+ '-C', // working directory
32
+ '--git-dir', // path to git repository
33
+ '--work-tree', // path to working tree
34
+ '--namespace', // git namespace
35
+ '--super-prefix', // superproject-relative prefix
36
+ '--exec-path', // path to core git programs (when given an arg)
37
+ '--html-path',
38
+ '--man-path',
39
+ '--info-path',
40
+ '--list-cmds',
41
+ ]);
42
+
43
+ /**
44
+ * Git global flags that consume no extra argument.
45
+ */
46
+ const BOOLEAN_FLAGS = new Set([
47
+ '-p', '--paginate', '--no-pager',
48
+ '--no-replace-objects', '--bare',
49
+ '--literal-pathspecs', '--glob-pathspecs', '--noglob-pathspecs',
50
+ '--icase-pathspecs', '--no-optional-locks',
51
+ '-P', '--no-lazy-fetch',
52
+ '--version', '--help',
53
+ ]);
54
+
55
+ /**
56
+ * Tokenize a shell command string.
57
+ * Handles single-quoted strings, double-quoted strings, and unquoted tokens.
58
+ * Does NOT perform variable expansion or brace expansion.
59
+ *
60
+ * @param {string} cmd
61
+ * @returns {string[]}
62
+ */
63
+ function tokenize(cmd) {
64
+ const tokens = [];
65
+ let i = 0;
66
+ const len = cmd.length;
67
+
68
+ while (i < len) {
69
+ // Skip whitespace
70
+ while (i < len && /\s/.test(cmd[i])) i++;
71
+ if (i >= len) break;
72
+
73
+ let token = '';
74
+ while (i < len && !/\s/.test(cmd[i])) {
75
+ if (cmd[i] === "'") {
76
+ // Single-quoted string: take everything until closing '
77
+ i++;
78
+ while (i < len && cmd[i] !== "'") token += cmd[i++];
79
+ if (i < len) i++; // consume closing '
80
+ } else if (cmd[i] === '"') {
81
+ // Double-quoted string: take everything until closing " (no escape handling)
82
+ i++;
83
+ while (i < len && cmd[i] !== '"') token += cmd[i++];
84
+ if (i < len) i++; // consume closing "
85
+ } else {
86
+ token += cmd[i++];
87
+ }
88
+ }
89
+ if (token) tokens.push(token);
90
+ }
91
+
92
+ return tokens;
93
+ }
94
+
95
+ /**
96
+ * Return true if `cmd` invokes the git subcommand `sub`.
97
+ *
98
+ * @param {string} cmd - Full shell command string (may include env vars, full paths)
99
+ * @param {string} sub - Subcommand to test for, e.g. 'commit'
100
+ * @returns {boolean}
101
+ */
102
+ function isGitSubcommand(cmd, sub) {
103
+ if (!cmd || !sub) return false;
104
+
105
+ const tokens = tokenize(cmd);
106
+ let i = 0;
107
+
108
+ // Phase 1: skip leading VAR=VALUE environment assignments
109
+ while (i < tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[i])) {
110
+ i++;
111
+ }
112
+
113
+ // Phase 2: the next token must be the git executable
114
+ if (i >= tokens.length) return false;
115
+ const gitToken = tokens[i++];
116
+ if (path.basename(gitToken) !== 'git') return false;
117
+
118
+ // Phase 3: consume git global options
119
+ while (i < tokens.length) {
120
+ const t = tokens[i];
121
+
122
+ // --flag=value form for argument-taking flags
123
+ const eqIdx = t.indexOf('=');
124
+ const flagName = eqIdx !== -1 ? t.slice(0, eqIdx) : t;
125
+ if (ARGUMENT_TAKING_FLAGS.has(flagName)) {
126
+ if (eqIdx !== -1) {
127
+ // consumed as one token: --git-dir=.git
128
+ i++;
129
+ } else {
130
+ // consumed as two tokens: -C /path
131
+ i += 2;
132
+ }
133
+ continue;
134
+ }
135
+
136
+ if (BOOLEAN_FLAGS.has(t)) {
137
+ i++;
138
+ continue;
139
+ }
140
+
141
+ // Not a global option — this is the subcommand
142
+ break;
143
+ }
144
+
145
+ // Phase 4: check the subcommand
146
+ if (i >= tokens.length) return false;
147
+ return tokens[i] === sub;
148
+ }
149
+
150
+ module.exports = { isGitSubcommand, tokenize };