@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.
- package/.claude-plugin/plugin.json +23 -0
- package/GEMINI.md +53 -0
- package/LICENSE +21 -0
- package/README.ja-JP.md +125 -0
- package/README.ko-KR.md +125 -0
- package/README.md +144 -0
- package/README.pt-BR.md +125 -0
- package/README.zh-CN.md +125 -0
- package/agents/gsd-advisor-researcher.md +108 -0
- package/agents/gsd-ai-researcher.md +114 -0
- package/agents/gsd-assumptions-analyzer.md +105 -0
- package/agents/gsd-code-fixer.md +668 -0
- package/agents/gsd-code-reviewer.md +387 -0
- package/agents/gsd-codebase-mapper.md +853 -0
- package/agents/gsd-debug-session-manager.md +314 -0
- package/agents/gsd-debugger.md +1452 -0
- package/agents/gsd-doc-classifier.md +168 -0
- package/agents/gsd-doc-synthesizer.md +204 -0
- package/agents/gsd-doc-verifier.md +217 -0
- package/agents/gsd-doc-writer.md +616 -0
- package/agents/gsd-domain-researcher.md +147 -0
- package/agents/gsd-eval-auditor.md +191 -0
- package/agents/gsd-eval-planner.md +154 -0
- package/agents/gsd-executor.md +785 -0
- package/agents/gsd-framework-selector.md +160 -0
- package/agents/gsd-integration-checker.md +470 -0
- package/agents/gsd-intel-updater.md +342 -0
- package/agents/gsd-nyquist-auditor.md +203 -0
- package/agents/gsd-pattern-mapper.md +335 -0
- package/agents/gsd-phase-researcher.md +867 -0
- package/agents/gsd-plan-checker.md +978 -0
- package/agents/gsd-planner.md +1204 -0
- package/agents/gsd-project-researcher.md +611 -0
- package/agents/gsd-research-synthesizer.md +259 -0
- package/agents/gsd-roadmapper.md +688 -0
- package/agents/gsd-security-auditor.md +155 -0
- package/agents/gsd-ui-auditor.md +495 -0
- package/agents/gsd-ui-checker.md +309 -0
- package/agents/gsd-ui-researcher.md +374 -0
- package/agents/gsd-user-profiler.md +171 -0
- package/agents/gsd-verifier.md +923 -0
- package/assets/gsd-logo-2000-transparent.png +0 -0
- package/assets/gsd-logo-2000-transparent.svg +17 -0
- package/assets/gsd-logo-2000.png +0 -0
- package/assets/gsd-logo-2000.svg +21 -0
- package/assets/terminal.svg +68 -0
- package/bin/install.js +12726 -0
- package/bin/lib/ui-safety-gate.cjs +107 -0
- package/commands/gsd/add-tests.md +42 -0
- package/commands/gsd/ai-integration-phase.md +37 -0
- package/commands/gsd/audit-fix.md +34 -0
- package/commands/gsd/audit-milestone.md +37 -0
- package/commands/gsd/audit-uat.md +24 -0
- package/commands/gsd/autonomous.md +48 -0
- package/commands/gsd/capture.md +62 -0
- package/commands/gsd/cleanup.md +24 -0
- package/commands/gsd/code-review.md +59 -0
- package/commands/gsd/complete-milestone.md +143 -0
- package/commands/gsd/config.md +56 -0
- package/commands/gsd/debug.md +52 -0
- package/commands/gsd/discover-product.md +65 -0
- package/commands/gsd/discuss-phase.md +77 -0
- package/commands/gsd/docs-update.md +49 -0
- package/commands/gsd/eval-review.md +33 -0
- package/commands/gsd/execute-phase.md +66 -0
- package/commands/gsd/explore.md +27 -0
- package/commands/gsd/extract-learnings.md +23 -0
- package/commands/gsd/fast.md +31 -0
- package/commands/gsd/forensics.md +57 -0
- package/commands/gsd/graphify.md +204 -0
- package/commands/gsd/health.md +31 -0
- package/commands/gsd/help.md +28 -0
- package/commands/gsd/import.md +45 -0
- package/commands/gsd/inbox.md +39 -0
- package/commands/gsd/ingest-docs.md +42 -0
- package/commands/gsd/manager.md +45 -0
- package/commands/gsd/map-codebase.md +83 -0
- package/commands/gsd/milestone-summary.md +51 -0
- package/commands/gsd/model-domain.md +65 -0
- package/commands/gsd/mvp-phase.md +45 -0
- package/commands/gsd/new-milestone.md +45 -0
- package/commands/gsd/new-project.md +47 -0
- package/commands/gsd/ns-context.md +23 -0
- package/commands/gsd/ns-ideate.md +24 -0
- package/commands/gsd/ns-manage.md +29 -0
- package/commands/gsd/ns-project.md +22 -0
- package/commands/gsd/ns-review.md +26 -0
- package/commands/gsd/ns-workflow.md +28 -0
- package/commands/gsd/pause-work.md +43 -0
- package/commands/gsd/phase.md +56 -0
- package/commands/gsd/plan-phase.md +64 -0
- package/commands/gsd/plan-review-convergence.md +59 -0
- package/commands/gsd/pr-branch.md +26 -0
- package/commands/gsd/profile-user.md +46 -0
- package/commands/gsd/progress.md +48 -0
- package/commands/gsd/quick.md +174 -0
- package/commands/gsd/recommend-architecture.md +64 -0
- package/commands/gsd/resume-work.md +30 -0
- package/commands/gsd/review-backlog.md +63 -0
- package/commands/gsd/review.md +42 -0
- package/commands/gsd/secure-phase.md +36 -0
- package/commands/gsd/settings.md +29 -0
- package/commands/gsd/ship.md +24 -0
- package/commands/gsd/sketch.md +60 -0
- package/commands/gsd/spec-phase.md +63 -0
- package/commands/gsd/spike.md +57 -0
- package/commands/gsd/stats.md +20 -0
- package/commands/gsd/surface.md +155 -0
- package/commands/gsd/testing-strategy.md +65 -0
- package/commands/gsd/thread.md +24 -0
- package/commands/gsd/ui-phase.md +35 -0
- package/commands/gsd/ui-review.md +33 -0
- package/commands/gsd/ultraplan-phase.md +34 -0
- package/commands/gsd/undo.md +35 -0
- package/commands/gsd/update.md +49 -0
- package/commands/gsd/validate-phase.md +36 -0
- package/commands/gsd/verify-work.md +39 -0
- package/commands/gsd/workspace.md +52 -0
- package/commands/gsd/workstreams.md +70 -0
- package/gemini-extension.json +6 -0
- package/gsd-core/bin/check-latest-version.cjs +161 -0
- package/gsd-core/bin/gsd-tools.cjs +1928 -0
- package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
- package/gsd-core/bin/lib/adr-parser.cjs +399 -0
- package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
- package/gsd-core/bin/lib/artifacts.cjs +51 -0
- package/gsd-core/bin/lib/audit.cjs +743 -0
- package/gsd-core/bin/lib/check-command-router.cjs +343 -0
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
- package/gsd-core/bin/lib/cli-exit.cjs +42 -0
- package/gsd-core/bin/lib/clock.cjs +95 -0
- package/gsd-core/bin/lib/clusters.cjs +132 -0
- package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
- package/gsd-core/bin/lib/command-aliases.cjs +809 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
- package/gsd-core/bin/lib/commands.cjs +1203 -0
- package/gsd-core/bin/lib/config-schema.cjs +29 -0
- package/gsd-core/bin/lib/config-types.cjs +19 -0
- package/gsd-core/bin/lib/config.cjs +738 -0
- package/gsd-core/bin/lib/configuration.cjs +239 -0
- package/gsd-core/bin/lib/context-utilization.cjs +48 -0
- package/gsd-core/bin/lib/core.cjs +2051 -0
- package/gsd-core/bin/lib/decisions.cjs +118 -0
- package/gsd-core/bin/lib/docs.cjs +252 -0
- package/gsd-core/bin/lib/drift.cjs +364 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
- package/gsd-core/bin/lib/frontmatter.cjs +442 -0
- package/gsd-core/bin/lib/gap-checker.cjs +257 -0
- package/gsd-core/bin/lib/graphify.cjs +496 -0
- package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
- package/gsd-core/bin/lib/init-command-router.cjs +62 -0
- package/gsd-core/bin/lib/init.cjs +1815 -0
- package/gsd-core/bin/lib/install-profiles.cjs +584 -0
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +350 -0
- package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
- package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
- package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
- package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +823 -0
- package/gsd-core/bin/lib/intel.cjs +590 -0
- package/gsd-core/bin/lib/learnings.cjs +270 -0
- package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
- package/gsd-core/bin/lib/milestone.cjs +373 -0
- package/gsd-core/bin/lib/model-catalog.cjs +154 -0
- package/gsd-core/bin/lib/model-profiles.cjs +24 -0
- package/gsd-core/bin/lib/observability/event.cjs +51 -0
- package/gsd-core/bin/lib/observability/logger.cjs +146 -0
- package/gsd-core/bin/lib/observability/redaction.cjs +48 -0
- package/gsd-core/bin/lib/package-identity.cjs +35 -0
- package/gsd-core/bin/lib/package-legitimacy.cjs +368 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
- package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
- package/gsd-core/bin/lib/phase.cjs +1307 -0
- package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
- package/gsd-core/bin/lib/plan-scan.cjs +91 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
- package/gsd-core/bin/lib/profile-output.cjs +1120 -0
- package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
- package/gsd-core/bin/lib/project-root.cjs +119 -0
- package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
- package/gsd-core/bin/lib/research-provider.cjs +137 -0
- package/gsd-core/bin/lib/research-store.cjs +167 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +476 -0
- package/gsd-core/bin/lib/roadmap.cjs +600 -0
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +312 -0
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +56 -0
- package/gsd-core/bin/lib/runtime-homes.cjs +190 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
- package/gsd-core/bin/lib/schema-detect.cjs +159 -0
- package/gsd-core/bin/lib/secrets.cjs +34 -0
- package/gsd-core/bin/lib/security.cjs +480 -0
- package/gsd-core/bin/lib/semver-compare.cjs +42 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +533 -0
- package/gsd-core/bin/lib/state-command-router.cjs +160 -0
- package/gsd-core/bin/lib/state-document.cjs +259 -0
- package/gsd-core/bin/lib/state.cjs +2010 -0
- package/gsd-core/bin/lib/surface.cjs +449 -0
- package/gsd-core/bin/lib/task-command-router.cjs +85 -0
- package/gsd-core/bin/lib/template.cjs +237 -0
- package/gsd-core/bin/lib/uat.cjs +297 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
- package/gsd-core/bin/lib/update-context.cjs +218 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
- package/gsd-core/bin/lib/validate.cjs +112 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +31 -0
- package/gsd-core/bin/lib/verification.cjs +193 -0
- package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
- package/gsd-core/bin/lib/verify.cjs +1451 -0
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +81 -0
- package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
- package/gsd-core/bin/lib/workstream-name-policy.cjs +91 -0
- package/gsd-core/bin/lib/workstream.cjs +380 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +325 -0
- package/gsd-core/bin/lib/worktree-safety.cjs +943 -0
- package/gsd-core/bin/shared/config-defaults.manifest.json +98 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +192 -0
- package/gsd-core/bin/shared/model-catalog.json +149 -0
- package/gsd-core/bin/shared/runtime-aliases.manifest.json +75 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +349 -0
- package/gsd-core/contexts/dev.md +21 -0
- package/gsd-core/contexts/research.md +22 -0
- package/gsd-core/contexts/review.md +23 -0
- package/gsd-core/references/agent-contracts.md +79 -0
- package/gsd-core/references/ai-evals.md +156 -0
- package/gsd-core/references/ai-frameworks.md +186 -0
- package/gsd-core/references/architecture-decision.md +74 -0
- package/gsd-core/references/artifact-types.md +131 -0
- package/gsd-core/references/auth-in-tests.md +91 -0
- package/gsd-core/references/autonomous-smart-discuss.md +277 -0
- package/gsd-core/references/checkpoints.md +814 -0
- package/gsd-core/references/common-bug-patterns.md +114 -0
- package/gsd-core/references/context-budget.md +85 -0
- package/gsd-core/references/continuation-format.md +253 -0
- package/gsd-core/references/db-test-isolation.md +54 -0
- package/gsd-core/references/debugger-philosophy.md +76 -0
- package/gsd-core/references/decimal-phase-calculation.md +64 -0
- package/gsd-core/references/doc-conflict-engine.md +91 -0
- package/gsd-core/references/domain-modeling.md +80 -0
- package/gsd-core/references/domain-probes.md +125 -0
- package/gsd-core/references/e2e-tiering.md +35 -0
- package/gsd-core/references/execute-mvp-tdd.md +81 -0
- package/gsd-core/references/executor-examples.md +110 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +73 -0
- package/gsd-core/references/few-shot-examples/verifier.md +109 -0
- package/gsd-core/references/flaky-test-checklist.md +22 -0
- package/gsd-core/references/gate-prompts.md +100 -0
- package/gsd-core/references/gates.md +70 -0
- package/gsd-core/references/git-integration.md +298 -0
- package/gsd-core/references/git-planning-commit.md +40 -0
- package/gsd-core/references/ios-scaffold.md +123 -0
- package/gsd-core/references/mandatory-initial-read.md +2 -0
- package/gsd-core/references/model-profile-resolution.md +38 -0
- package/gsd-core/references/model-profiles.md +245 -0
- package/gsd-core/references/mvp-concepts.md +49 -0
- package/gsd-core/references/phase-argument-parsing.md +61 -0
- package/gsd-core/references/planner-antipatterns.md +89 -0
- package/gsd-core/references/planner-chunked.md +49 -0
- package/gsd-core/references/planner-gap-closure.md +62 -0
- package/gsd-core/references/planner-graphify-auto-update.md +67 -0
- package/gsd-core/references/planner-human-verify-mode.md +57 -0
- package/gsd-core/references/planner-interface-context.md +62 -0
- package/gsd-core/references/planner-load-graph-context.md +36 -0
- package/gsd-core/references/planner-mvp-mode.md +53 -0
- package/gsd-core/references/planner-reviews.md +39 -0
- package/gsd-core/references/planner-revision.md +87 -0
- package/gsd-core/references/planner-source-audit.md +73 -0
- package/gsd-core/references/planning-config.md +473 -0
- package/gsd-core/references/product-discovery.md +49 -0
- package/gsd-core/references/project-skills-discovery.md +19 -0
- package/gsd-core/references/questioning.md +162 -0
- package/gsd-core/references/realistic-test-data.md +44 -0
- package/gsd-core/references/research-documentation-lookup.md +29 -0
- package/gsd-core/references/research-philosophy.md +29 -0
- package/gsd-core/references/research-verification-protocol.md +27 -0
- package/gsd-core/references/revision-loop.md +97 -0
- package/gsd-core/references/scout-codebase.md +51 -0
- package/gsd-core/references/skeleton-template.md +48 -0
- package/gsd-core/references/sketch-interactivity.md +41 -0
- package/gsd-core/references/sketch-theme-system.md +94 -0
- package/gsd-core/references/sketch-tooling.md +45 -0
- package/gsd-core/references/sketch-variant-patterns.md +81 -0
- package/gsd-core/references/spidr-splitting.md +69 -0
- package/gsd-core/references/tdd.md +330 -0
- package/gsd-core/references/test-containers.md +55 -0
- package/gsd-core/references/test-strategy.md +75 -0
- package/gsd-core/references/thinking-models-debug.md +44 -0
- package/gsd-core/references/thinking-models-execution.md +50 -0
- package/gsd-core/references/thinking-models-planning.md +62 -0
- package/gsd-core/references/thinking-models-research.md +50 -0
- package/gsd-core/references/thinking-models-verification.md +55 -0
- package/gsd-core/references/thinking-partner.md +96 -0
- package/gsd-core/references/ui-brand.md +162 -0
- package/gsd-core/references/universal-anti-patterns.md +63 -0
- package/gsd-core/references/user-profiling.md +681 -0
- package/gsd-core/references/user-story-template.md +58 -0
- package/gsd-core/references/verification-overrides.md +227 -0
- package/gsd-core/references/verification-patterns.md +612 -0
- package/gsd-core/references/verify-mvp-mode.md +85 -0
- package/gsd-core/references/workstream-flag.md +111 -0
- package/gsd-core/references/worktree-branch-check.md +38 -0
- package/gsd-core/references/worktree-path-safety.md +67 -0
- package/gsd-core/templates/AI-SPEC.md +246 -0
- package/gsd-core/templates/DEBUG.md +169 -0
- package/gsd-core/templates/README.md +77 -0
- package/gsd-core/templates/SECURITY.md +61 -0
- package/gsd-core/templates/UAT.md +265 -0
- package/gsd-core/templates/UI-SPEC.md +100 -0
- package/gsd-core/templates/VALIDATION.md +76 -0
- package/gsd-core/templates/adr.md +58 -0
- package/gsd-core/templates/claude-md.md +145 -0
- package/gsd-core/templates/codebase/architecture.md +255 -0
- package/gsd-core/templates/codebase/concerns.md +310 -0
- package/gsd-core/templates/codebase/conventions.md +307 -0
- package/gsd-core/templates/codebase/integrations.md +280 -0
- package/gsd-core/templates/codebase/stack.md +186 -0
- package/gsd-core/templates/codebase/structure.md +285 -0
- package/gsd-core/templates/codebase/testing.md +480 -0
- package/gsd-core/templates/config.json +62 -0
- package/gsd-core/templates/context.md +352 -0
- package/gsd-core/templates/continue-here.md +78 -0
- package/gsd-core/templates/copilot-instructions.md +7 -0
- package/gsd-core/templates/debug-subagent-prompt.md +91 -0
- package/gsd-core/templates/dev-preferences.md +21 -0
- package/gsd-core/templates/discovery.md +146 -0
- package/gsd-core/templates/discussion-log.md +63 -0
- package/gsd-core/templates/domain-model.md +54 -0
- package/gsd-core/templates/milestone-archive.md +123 -0
- package/gsd-core/templates/milestone.md +115 -0
- package/gsd-core/templates/phase-prompt.md +610 -0
- package/gsd-core/templates/planner-subagent-prompt.md +117 -0
- package/gsd-core/templates/product-brief.md +55 -0
- package/gsd-core/templates/project.md +186 -0
- package/gsd-core/templates/requirements.md +231 -0
- package/gsd-core/templates/research-project/ARCHITECTURE.md +204 -0
- package/gsd-core/templates/research-project/FEATURES.md +147 -0
- package/gsd-core/templates/research-project/PITFALLS.md +200 -0
- package/gsd-core/templates/research-project/STACK.md +120 -0
- package/gsd-core/templates/research-project/SUMMARY.md +170 -0
- package/gsd-core/templates/research.md +592 -0
- package/gsd-core/templates/retrospective.md +54 -0
- package/gsd-core/templates/roadmap.md +202 -0
- package/gsd-core/templates/spec.md +307 -0
- package/gsd-core/templates/state.md +195 -0
- package/gsd-core/templates/summary-complex.md +59 -0
- package/gsd-core/templates/summary-minimal.md +41 -0
- package/gsd-core/templates/summary-standard.md +48 -0
- package/gsd-core/templates/summary.md +248 -0
- package/gsd-core/templates/test-strategy.md +50 -0
- package/gsd-core/templates/user-profile.md +146 -0
- package/gsd-core/templates/user-setup.md +311 -0
- package/gsd-core/templates/verification-report.md +322 -0
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
- package/gsd-core/workflows/add-backlog.md +91 -0
- package/gsd-core/workflows/add-phase.md +113 -0
- package/gsd-core/workflows/add-tests.md +355 -0
- package/gsd-core/workflows/add-todo.md +161 -0
- package/gsd-core/workflows/ai-integration-phase.md +295 -0
- package/gsd-core/workflows/analyze-dependencies.md +96 -0
- package/gsd-core/workflows/audit-fix.md +178 -0
- package/gsd-core/workflows/audit-milestone.md +360 -0
- package/gsd-core/workflows/audit-uat.md +110 -0
- package/gsd-core/workflows/autonomous.md +797 -0
- package/gsd-core/workflows/check-todos.md +180 -0
- package/gsd-core/workflows/cleanup.md +195 -0
- package/gsd-core/workflows/code-review-fix.md +502 -0
- package/gsd-core/workflows/code-review.md +658 -0
- package/gsd-core/workflows/complete-milestone.md +855 -0
- package/gsd-core/workflows/debug.md +237 -0
- package/gsd-core/workflows/diagnose-issues.md +245 -0
- package/gsd-core/workflows/discover-product.md +112 -0
- package/gsd-core/workflows/discovery-phase.md +291 -0
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +176 -0
- package/gsd-core/workflows/discuss-phase/modes/all.md +28 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +44 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +57 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +52 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +98 -0
- package/gsd-core/workflows/discuss-phase/modes/default.md +141 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +44 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +55 -0
- package/gsd-core/workflows/discuss-phase/templates/checkpoint.json +18 -0
- package/gsd-core/workflows/discuss-phase/templates/context.md +136 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +50 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +675 -0
- package/gsd-core/workflows/discuss-phase-power.md +291 -0
- package/gsd-core/workflows/discuss-phase.md +499 -0
- package/gsd-core/workflows/do.md +111 -0
- package/gsd-core/workflows/docs-update.md +1176 -0
- package/gsd-core/workflows/edit-phase.md +295 -0
- package/gsd-core/workflows/eval-review.md +156 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +95 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +117 -0
- package/gsd-core/workflows/execute-phase.md +1752 -0
- package/gsd-core/workflows/execute-plan.md +526 -0
- package/gsd-core/workflows/explore.md +146 -0
- package/gsd-core/workflows/extract-learnings.md +243 -0
- package/gsd-core/workflows/fast.md +124 -0
- package/gsd-core/workflows/forensics.md +279 -0
- package/gsd-core/workflows/graduation.md +196 -0
- package/gsd-core/workflows/health.md +224 -0
- package/gsd-core/workflows/help/modes/brief.md +22 -0
- package/gsd-core/workflows/help/modes/default.md +50 -0
- package/gsd-core/workflows/help/modes/full.md +789 -0
- package/gsd-core/workflows/help/modes/topic.md +74 -0
- package/gsd-core/workflows/help.md +24 -0
- package/gsd-core/workflows/import.md +256 -0
- package/gsd-core/workflows/inbox.md +387 -0
- package/gsd-core/workflows/ingest-docs.md +340 -0
- package/gsd-core/workflows/insert-phase.md +152 -0
- package/gsd-core/workflows/list-phase-assumptions.md +178 -0
- package/gsd-core/workflows/list-workspaces.md +57 -0
- package/gsd-core/workflows/manager.md +393 -0
- package/gsd-core/workflows/map-codebase.md +446 -0
- package/gsd-core/workflows/milestone-summary.md +224 -0
- package/gsd-core/workflows/model-domain.md +162 -0
- package/gsd-core/workflows/mvp-phase.md +222 -0
- package/gsd-core/workflows/new-milestone.md +635 -0
- package/gsd-core/workflows/new-project.md +1555 -0
- package/gsd-core/workflows/new-workspace.md +240 -0
- package/gsd-core/workflows/next.md +299 -0
- package/gsd-core/workflows/node-repair.md +92 -0
- package/gsd-core/workflows/note.md +158 -0
- package/gsd-core/workflows/pause-work.md +244 -0
- package/gsd-core/workflows/plan-milestone-gaps.md +281 -0
- package/gsd-core/workflows/plan-phase.md +1814 -0
- package/gsd-core/workflows/plan-review-convergence.md +346 -0
- package/gsd-core/workflows/plant-seed.md +230 -0
- package/gsd-core/workflows/pr-branch.md +157 -0
- package/gsd-core/workflows/profile-user.md +453 -0
- package/gsd-core/workflows/progress.md +699 -0
- package/gsd-core/workflows/quick.md +1017 -0
- package/gsd-core/workflows/reapply-patches.md +426 -0
- package/gsd-core/workflows/recommend-architecture.md +135 -0
- package/gsd-core/workflows/remove-phase.md +156 -0
- package/gsd-core/workflows/remove-workspace.md +108 -0
- package/gsd-core/workflows/resume-project.md +332 -0
- package/gsd-core/workflows/review.md +748 -0
- package/gsd-core/workflows/scan.md +107 -0
- package/gsd-core/workflows/secure-phase.md +182 -0
- package/gsd-core/workflows/session-report.md +146 -0
- package/gsd-core/workflows/settings-advanced.md +810 -0
- package/gsd-core/workflows/settings-integrations.md +312 -0
- package/gsd-core/workflows/settings.md +566 -0
- package/gsd-core/workflows/ship.md +405 -0
- package/gsd-core/workflows/sketch-wrap-up.md +286 -0
- package/gsd-core/workflows/sketch.md +361 -0
- package/gsd-core/workflows/spec-phase.md +263 -0
- package/gsd-core/workflows/spike-wrap-up.md +307 -0
- package/gsd-core/workflows/spike.md +453 -0
- package/gsd-core/workflows/stats.md +80 -0
- package/gsd-core/workflows/sync-skills.md +182 -0
- package/gsd-core/workflows/testing-strategy.md +122 -0
- package/gsd-core/workflows/thread.md +222 -0
- package/gsd-core/workflows/transition.md +694 -0
- package/gsd-core/workflows/ui-phase.md +328 -0
- package/gsd-core/workflows/ui-review.md +193 -0
- package/gsd-core/workflows/ultraplan-phase.md +199 -0
- package/gsd-core/workflows/undo.md +314 -0
- package/gsd-core/workflows/update.md +496 -0
- package/gsd-core/workflows/validate-phase.md +181 -0
- package/gsd-core/workflows/verify-phase.md +544 -0
- package/gsd-core/workflows/verify-work.md +781 -0
- package/hooks/dist/gsd-check-update-worker.js +108 -0
- package/hooks/dist/gsd-check-update.js +66 -0
- package/hooks/dist/gsd-config-reload.js +133 -0
- package/hooks/dist/gsd-context-monitor.js +195 -0
- package/hooks/dist/gsd-cursor-post-tool.js +75 -0
- package/hooks/dist/gsd-cursor-session-start.js +52 -0
- package/hooks/dist/gsd-graphify-update.sh +158 -0
- package/hooks/dist/gsd-phase-boundary.sh +47 -0
- package/hooks/dist/gsd-prompt-guard.js +97 -0
- package/hooks/dist/gsd-read-guard.js +101 -0
- package/hooks/dist/gsd-read-injection-scanner.js +203 -0
- package/hooks/dist/gsd-session-state.sh +59 -0
- package/hooks/dist/gsd-statusline.js +566 -0
- package/hooks/dist/gsd-update-banner.js +138 -0
- package/hooks/dist/gsd-validate-commit.sh +57 -0
- package/hooks/dist/gsd-workflow-guard.js +167 -0
- package/hooks/dist/gsd-worktree-path-guard.js +169 -0
- package/hooks/dist/lib/git-cmd.js +150 -0
- package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
- package/hooks/dist/managed-hooks-registry.cjs +38 -0
- package/hooks/gsd-check-update-worker.js +108 -0
- package/hooks/gsd-check-update.js +66 -0
- package/hooks/gsd-config-reload.js +133 -0
- package/hooks/gsd-context-monitor.js +195 -0
- package/hooks/gsd-cursor-post-tool.js +75 -0
- package/hooks/gsd-cursor-session-start.js +52 -0
- package/hooks/gsd-graphify-update.sh +158 -0
- package/hooks/gsd-phase-boundary.sh +47 -0
- package/hooks/gsd-prompt-guard.js +97 -0
- package/hooks/gsd-read-guard.js +101 -0
- package/hooks/gsd-read-injection-scanner.js +203 -0
- package/hooks/gsd-session-state.sh +59 -0
- package/hooks/gsd-statusline.js +566 -0
- package/hooks/gsd-update-banner.js +138 -0
- package/hooks/gsd-validate-commit.sh +57 -0
- package/hooks/gsd-workflow-guard.js +167 -0
- package/hooks/gsd-worktree-path-guard.js +169 -0
- package/hooks/hooks.json +69 -0
- package/hooks/lib/git-cmd.js +150 -0
- package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
- package/hooks/managed-hooks-registry.cjs +38 -0
- package/package.json +115 -0
- package/scripts/affected-tests-lib.cjs +542 -0
- package/scripts/audit-workflow-script-paths.cjs +73 -0
- package/scripts/base64-scan.sh +351 -0
- package/scripts/build-hooks.js +247 -0
- package/scripts/changeset/README.md +129 -0
- package/scripts/changeset/cli.cjs +590 -0
- package/scripts/changeset/github-release-notes.cjs +199 -0
- package/scripts/changeset/lint.cjs +111 -0
- package/scripts/changeset/new.cjs +137 -0
- package/scripts/changeset/parse.cjs +114 -0
- package/scripts/changeset/render.cjs +34 -0
- package/scripts/changeset/serialize.cjs +130 -0
- package/scripts/check-alias-drift.cjs +114 -0
- package/scripts/check-env.cjs +312 -0
- package/scripts/check-npm-integrity.cjs +215 -0
- package/scripts/ci-guard-runner.cjs +22 -0
- package/scripts/ci-prepare-test-scope.cjs +51 -0
- package/scripts/ci-rebase-check.cjs +86 -0
- package/scripts/ci-test-scope.cjs +431 -0
- package/scripts/command-contract-helpers.cjs +64 -0
- package/scripts/diff-touches-shipped-paths.cjs +155 -0
- package/scripts/fix-slash-commands.cjs +147 -0
- package/scripts/gen-inventory-manifest.cjs +115 -0
- package/scripts/gen-research-agents.cjs +276 -0
- package/scripts/generate-package-identity.cjs +125 -0
- package/scripts/issue-dedupe.cjs +278 -0
- package/scripts/lib/allowlist-ratchet.cjs +136 -0
- package/scripts/lib/cli-exit.cjs +56 -0
- package/scripts/lint-command-contract.cjs +114 -0
- package/scripts/lint-descriptions.cjs +87 -0
- package/scripts/lint-docs-required.cjs +222 -0
- package/scripts/lint-legacy-dir-name.cjs +160 -0
- package/scripts/lint-package-identity-drift.cjs +141 -0
- package/scripts/lint-pr-check-project-dir.cjs +99 -0
- package/scripts/lint-shell-command-projection-drift.cjs +62 -0
- package/scripts/lint-skill-deps.cjs +185 -0
- package/scripts/lint-test-file-count.allowlist.json +135 -0
- package/scripts/lint-test-file-count.cjs +246 -0
- package/scripts/mutation-matrix.cjs +222 -0
- package/scripts/pr-template-policy.cjs +268 -0
- package/scripts/prompt-injection-scan.sh +207 -0
- package/scripts/release-notes/discord-release-summary.cjs +373 -0
- package/scripts/release-notes/format-github-release-notes.cjs +261 -0
- package/scripts/release-tarball-smoke.cjs +629 -0
- package/scripts/research-profiles.cjs +149 -0
- package/scripts/run-affected-tests.cjs +7 -0
- package/scripts/run-cross-platform-tests.cjs +67 -0
- package/scripts/run-tests.cjs +315 -0
- package/scripts/secret-scan-lint.sh +231 -0
- package/scripts/secret-scan.sh +358 -0
- package/scripts/setup-branch-protection.sh +236 -0
- package/scripts/strip-prose-atrefs.cjs +106 -0
- package/scripts/sync-manifest-versions.cjs +119 -0
- package/scripts/sync-rulesets.sh +34 -0
- package/scripts/sync-runtime-launcher.cjs +399 -0
- package/scripts/test-failure-reasons.cjs +34 -0
- package/scripts/verify-npm-publish.cjs +240 -0
- 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
|
+
});
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-check-update.js\"" }
|
|
7
|
+
]
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"PreToolUse": [
|
|
11
|
+
{
|
|
12
|
+
"matcher": "Write|Edit",
|
|
13
|
+
"hooks": [
|
|
14
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-prompt-guard.js\"", "timeout": 5 },
|
|
15
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-read-guard.js\"", "timeout": 5 }
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
20
|
+
"hooks": [
|
|
21
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-worktree-path-guard.js\"", "timeout": 5 }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"PostToolUse": [
|
|
26
|
+
{
|
|
27
|
+
"matcher": "Bash|Edit|Write|MultiEdit|Agent|Task",
|
|
28
|
+
"hooks": [
|
|
29
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-context-monitor.js\"", "timeout": 10 }
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"matcher": "Read",
|
|
34
|
+
"hooks": [
|
|
35
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-read-injection-scanner.js\"", "timeout": 5 }
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"SubagentStop": [
|
|
40
|
+
{
|
|
41
|
+
"hooks": [
|
|
42
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-context-monitor.js\"", "timeout": 10 }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"Stop": [
|
|
47
|
+
{
|
|
48
|
+
"hooks": [
|
|
49
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-context-monitor.js\"", "timeout": 10 }
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"PreCompact": [
|
|
54
|
+
{
|
|
55
|
+
"hooks": [
|
|
56
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-context-monitor.js\"", "timeout": 10 }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"FileChanged": [
|
|
61
|
+
{
|
|
62
|
+
"matcher": "config.json",
|
|
63
|
+
"hooks": [
|
|
64
|
+
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/gsd-config-reload.js\"", "timeout": 8 }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|