@opengsd/gsd-core 1.9.1 → 1.11.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/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -3
- package/.opencode/plugins/gsd-core.js +8 -1
- package/agents/gsd-code-fixer.md +27 -3
- package/agents/gsd-debug-session-manager.md +11 -0
- package/agents/gsd-debugger.md +12 -246
- package/agents/gsd-doc-synthesizer.md +2 -4
- package/agents/gsd-executor.md +12 -10
- package/agents/gsd-integration-checker.md +3 -0
- package/agents/gsd-mempalace-curator.md +5 -2
- package/agents/gsd-phase-researcher.md +20 -1
- package/agents/gsd-plan-checker.md +46 -0
- package/agents/gsd-planner.md +49 -54
- package/agents/gsd-roadmapper.md +21 -3
- package/agents/gsd-user-profiler.md +3 -0
- package/agents/gsd-verifier.md +26 -73
- package/bin/install.js +1272 -1238
- package/bin/lib/ui-safety-gate.cjs +2 -0
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/mempalace-capture.md +2 -2
- package/commands/gsd/mempalace-recall.md +1 -1
- package/commands/gsd/new-milestone.md +2 -2
- package/commands/gsd/plan-phase.md +1 -1
- package/commands/gsd/quick.md +1 -1
- package/commands/gsd/review-backlog.md +2 -1
- package/commands/gsd/verify-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +1009 -115
- package/gsd-core/bin/lib/active-workstream-store.cjs +153 -12
- package/gsd-core/bin/lib/agent-install-check.cjs +268 -38
- package/gsd-core/bin/lib/api-coverage.cjs +123 -5
- package/gsd-core/bin/lib/artifacts.cjs +3 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
- package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
- package/gsd-core/bin/lib/audit.cjs +926 -202
- package/gsd-core/bin/lib/broken-windows.cjs +36 -6
- package/gsd-core/bin/lib/capability-consent.cjs +149 -15
- package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
- package/gsd-core/bin/lib/capability-registry.cjs +608 -148
- package/gsd-core/bin/lib/capability-source.cjs +92 -0
- package/gsd-core/bin/lib/capability-trust.cjs +444 -25
- package/gsd-core/bin/lib/capability-validator.cjs +507 -24
- package/gsd-core/bin/lib/capability-writer.cjs +3 -2
- package/gsd-core/bin/lib/check-command-router.cjs +114 -38
- package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
- package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
- package/gsd-core/bin/lib/command-aliases.cjs +94 -0
- package/gsd-core/bin/lib/command-roster.cjs +44 -1
- package/gsd-core/bin/lib/commands.cjs +665 -99
- package/gsd-core/bin/lib/commonjs-marker.cjs +142 -0
- package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
- package/gsd-core/bin/lib/config-loader.cjs +76 -0
- package/gsd-core/bin/lib/config.cjs +22 -2
- package/gsd-core/bin/lib/context-composer.cjs +278 -0
- package/gsd-core/bin/lib/context-predicates.cjs +506 -0
- package/gsd-core/bin/lib/core-utils.cjs +217 -40
- package/gsd-core/bin/lib/decisions.cjs +23 -0
- package/gsd-core/bin/lib/docs.cjs +3 -2
- package/gsd-core/bin/lib/external-job.cjs +19 -4
- package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
- package/gsd-core/bin/lib/frontmatter.cjs +239 -32
- package/gsd-core/bin/lib/gap-checker.cjs +68 -7
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
- package/gsd-core/bin/lib/git-base-branch.cjs +160 -15
- package/gsd-core/bin/lib/graphify.cjs +142 -27
- package/gsd-core/bin/lib/gsd2-import.cjs +37 -5
- package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
- package/gsd-core/bin/lib/host-integration.cjs +13 -1
- package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
- package/gsd-core/bin/lib/init-command-router.cjs +83 -8
- package/gsd-core/bin/lib/init.cjs +1325 -169
- package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
- package/gsd-core/bin/lib/install-engine.cjs +805 -264
- package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
- package/gsd-core/bin/lib/install-profiles.cjs +160 -57
- package/gsd-core/bin/lib/install-scope.cjs +270 -0
- package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
- package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
- package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
- package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
- package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +206 -13
- package/gsd-core/bin/lib/io.cjs +38 -3
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +8 -1
- package/gsd-core/bin/lib/markdown-table.cjs +133 -20
- package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
- package/gsd-core/bin/lib/mcp-server.cjs +135 -3
- package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
- package/gsd-core/bin/lib/milestone.cjs +821 -109
- package/gsd-core/bin/lib/model-catalog.cjs +59 -1
- package/gsd-core/bin/lib/model-resolver.cjs +183 -40
- package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
- package/gsd-core/bin/lib/pattern.cjs +122 -0
- package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
- package/gsd-core/bin/lib/phase-id.cjs +507 -36
- package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
- package/gsd-core/bin/lib/phase-locator.cjs +258 -58
- package/gsd-core/bin/lib/phase.cjs +891 -156
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +303 -0
- package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
- package/gsd-core/bin/lib/plan-scan.cjs +86 -2
- package/gsd-core/bin/lib/planning-scope.cjs +31 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +60 -6
- package/gsd-core/bin/lib/probe-core.cjs +1 -1
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +85 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +108 -0
- package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +447 -68
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
- package/gsd-core/bin/lib/roadmap-command-router.cjs +76 -9
- package/gsd-core/bin/lib/roadmap-parser.cjs +1035 -194
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
- package/gsd-core/bin/lib/roadmap.cjs +405 -84
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +795 -100
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +440 -57
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
- package/gsd-core/bin/lib/runtime-homes.cjs +220 -41
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +220 -44
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
- package/gsd-core/bin/lib/section-manifest.cjs +209 -0
- package/gsd-core/bin/lib/security.cjs +104 -5
- package/gsd-core/bin/lib/shell-command-projection.cjs +388 -30
- package/gsd-core/bin/lib/smart-entry.cjs +154 -22
- package/gsd-core/bin/lib/state-command-router.cjs +5 -1
- package/gsd-core/bin/lib/state-document.cjs +152 -8
- package/gsd-core/bin/lib/state-transition.cjs +424 -105
- package/gsd-core/bin/lib/state.cjs +1927 -401
- package/gsd-core/bin/lib/surface.cjs +35 -10
- package/gsd-core/bin/lib/text-lines.cjs +80 -0
- package/gsd-core/bin/lib/token-scanner.cjs +76 -0
- package/gsd-core/bin/lib/uat-predicate.cjs +20 -4
- package/gsd-core/bin/lib/uat.cjs +706 -64
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
- package/gsd-core/bin/lib/unusable-input.cjs +33 -0
- package/gsd-core/bin/lib/update-context.cjs +8 -2
- package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
- package/gsd-core/bin/lib/validate.cjs +20 -6
- package/gsd-core/bin/lib/vendor/README.md +37 -0
- package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
- package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +287 -20
- package/gsd-core/bin/lib/verify.cjs +368 -880
- package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +203 -19
- package/gsd-core/bin/lib/workstream-inventory.cjs +576 -31
- package/gsd-core/bin/lib/workstream.cjs +8 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
- package/gsd-core/bin/lib/worktree-safety.cjs +450 -125
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +9 -1
- package/gsd-core/references/agent-contracts.md +43 -26
- package/gsd-core/references/artifact-types.md +10 -3
- package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
- package/gsd-core/references/checkpoints.md +2 -2
- package/gsd-core/references/context-budget.md +1 -1
- package/gsd-core/references/debugger-techniques.md +255 -0
- package/gsd-core/references/dispatch-isolation-gate.md +138 -0
- package/gsd-core/references/doc-conflict-engine.md +1 -1
- package/gsd-core/references/execute-mvp-tdd.md +3 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
- package/gsd-core/references/execute-phase-context-guard.md +1 -1
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +6 -2
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-planning-commit.md +2 -1
- package/gsd-core/references/loop-hook-dispatch.md +39 -2
- package/gsd-core/references/model-profiles.md +12 -4
- package/gsd-core/references/mvp-concepts.md +9 -9
- package/gsd-core/references/planner-guidance.md +3 -9
- package/gsd-core/references/planner-preconditions.md +1 -1
- package/gsd-core/references/planner-reviews.md +1 -1
- package/gsd-core/references/planning-config.md +8 -6
- package/gsd-core/references/research-documentation-lookup.md +5 -3
- package/gsd-core/references/revision-loop.md +1 -1
- package/gsd-core/references/specless-probe-fallback.md +8 -7
- package/gsd-core/references/universal-anti-patterns.md +3 -3
- package/gsd-core/references/verifier-phase-gates.md +192 -0
- package/gsd-core/references/verifier-wiring-patterns.md +100 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +22 -6
- package/gsd-core/references/worktree-branch-check.md +2 -2
- package/gsd-core/templates/discussion-log.md +1 -1
- package/gsd-core/templates/phase-prompt.md +2 -4
- package/gsd-core/templates/state.md +4 -4
- package/gsd-core/templates/summary-complex.md +2 -0
- package/gsd-core/templates/summary-minimal.md +2 -0
- package/gsd-core/templates/summary-standard.md +2 -0
- package/gsd-core/templates/summary.md +2 -0
- package/gsd-core/templates/verification-report.md +9 -1
- package/gsd-core/workflows/ai-integration-phase.md +9 -11
- package/gsd-core/workflows/audit-milestone.md +3 -0
- package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
- package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
- package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
- package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
- package/gsd-core/workflows/autonomous.md +33 -70
- package/gsd-core/workflows/cleanup.md +62 -3
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +93 -0
- package/gsd-core/workflows/code-review-fix.md +37 -10
- package/gsd-core/workflows/code-review.md +74 -166
- package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
- package/gsd-core/workflows/complete-milestone.md +160 -95
- package/gsd-core/workflows/debug.md +16 -17
- package/gsd-core/workflows/diagnose-issues.md +56 -8
- package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
- package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +7 -17
- package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
- package/gsd-core/workflows/docs-update.md +8 -51
- package/gsd-core/workflows/edit-phase.md +26 -1
- package/gsd-core/workflows/eval-review.md +3 -5
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +64 -7
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
- package/gsd-core/workflows/execute-phase.md +103 -187
- package/gsd-core/workflows/execute-plan.md +36 -4
- package/gsd-core/workflows/explore.md +131 -4
- package/gsd-core/workflows/fast.md +10 -2
- package/gsd-core/workflows/health.md +73 -4
- package/gsd-core/workflows/help/modes/full.md +6 -1
- package/gsd-core/workflows/import.md +4 -4
- package/gsd-core/workflows/ingest-docs.md +7 -6
- package/gsd-core/workflows/mvp-phase.md +6 -3
- package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
- package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
- package/gsd-core/workflows/new-milestone.md +35 -47
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
- package/gsd-core/workflows/new-project.md +27 -240
- package/gsd-core/workflows/next.md +12 -0
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
- package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
- package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
- package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
- package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
- package/gsd-core/workflows/plan-phase.md +89 -209
- package/gsd-core/workflows/plan-review-convergence.md +50 -2
- package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
- package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
- package/gsd-core/workflows/progress.md +45 -159
- package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +67 -0
- package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
- package/gsd-core/workflows/quick.md +55 -405
- package/gsd-core/workflows/resume-project.md +3 -0
- package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
- package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
- package/gsd-core/workflows/review.md +41 -13
- package/gsd-core/workflows/section-manifest.json +219 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -1
- package/gsd-core/workflows/settings.md +66 -2
- package/gsd-core/workflows/ship.md +104 -44
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/spec-phase.md +41 -20
- package/gsd-core/workflows/spike-wrap-up.md +20 -5
- package/gsd-core/workflows/spike.md +50 -16
- package/gsd-core/workflows/sync-skills.md +106 -13
- package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
- package/gsd-core/workflows/transition.md +53 -31
- package/gsd-core/workflows/ui-phase.md +13 -12
- package/gsd-core/workflows/ui-review.md +2 -2
- package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
- package/gsd-core/workflows/update.md +19 -8
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
- package/gsd-core/workflows/verify-work.md +17 -65
- package/hooks/dist/gsd-agent-isolation-guard.js +517 -0
- package/hooks/dist/gsd-check-update-worker.js +64 -12
- package/hooks/dist/gsd-check-update.js +19 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
- package/hooks/dist/gsd-cursor-subagent-start.js +607 -26
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
- package/hooks/dist/gsd-prompt-guard.js +21 -20
- package/hooks/dist/gsd-read-injection-scanner.js +45 -24
- package/hooks/dist/gsd-statusline.js +90 -6
- package/hooks/dist/gsd-update-banner.js +22 -1
- package/hooks/dist/gsd-workflow-guard.js +134 -36
- package/hooks/dist/gsd-worktree-path-guard.js +2 -1
- package/hooks/dist/gsd-write-guard.js +359 -0
- package/hooks/dist/lib/git-cmd.js +92 -59
- package/hooks/dist/lib/injection-patterns.js +45 -0
- package/hooks/dist/lib/isolation-deny-reason.js +39 -0
- package/hooks/dist/lib/isolation-sentinel.js +277 -0
- package/hooks/dist/managed-hooks-registry.cjs +2 -0
- package/hooks/gsd-agent-isolation-guard.js +517 -0
- package/hooks/gsd-check-update-worker.js +64 -12
- package/hooks/gsd-check-update.js +19 -1
- package/hooks/gsd-cursor-pre-tool.js +0 -3
- package/hooks/gsd-cursor-subagent-start.js +607 -26
- package/hooks/gsd-cursor-subagent-stop.js +3 -2
- package/hooks/gsd-prompt-guard.js +21 -20
- package/hooks/gsd-read-injection-scanner.js +45 -24
- package/hooks/gsd-statusline.js +90 -6
- package/hooks/gsd-update-banner.js +22 -1
- package/hooks/gsd-workflow-guard.js +134 -36
- package/hooks/gsd-worktree-path-guard.js +2 -1
- package/hooks/gsd-write-guard.js +359 -0
- package/hooks/hooks.json +12 -0
- package/hooks/lib/git-cmd.js +92 -59
- package/hooks/lib/injection-patterns.js +45 -0
- package/hooks/lib/isolation-deny-reason.js +39 -0
- package/hooks/lib/isolation-sentinel.js +277 -0
- package/hooks/managed-hooks-registry.cjs +2 -0
- package/package.json +31 -10
- package/pi/gsd.cjs +71 -12
- package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
- package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
- package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
- package/scripts/build-hooks.js +9 -0
- package/scripts/changeset/lint.cjs +68 -6
- package/scripts/changeset/serialize.cjs +5 -1
- package/scripts/check-alias-drift.cjs +7 -43
- package/scripts/check-contract-drift.cjs +297 -0
- package/scripts/ci-test-scope.cjs +19 -2
- package/scripts/command-contract-helpers.cjs +903 -1
- package/scripts/gen-adr-index.cjs +728 -38
- package/scripts/gen-capability-matrix.cjs +1 -1
- package/scripts/gen-capability-registry.cjs +3 -15
- package/scripts/gen-context-index.cjs +439 -0
- package/scripts/gen-health-docs.cjs +390 -0
- package/scripts/gen-inventory-manifest.cjs +150 -4
- package/scripts/gen-loop-host-contract.cjs +4 -24
- package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
- package/scripts/gen-registry.cjs +3 -14
- package/scripts/gen-section-manifest.cjs +638 -0
- package/scripts/generate-package-identity.cjs +4 -2
- package/scripts/lib/alias-drift-families.cjs +46 -0
- package/scripts/lib/drift-scan.cjs +278 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +15 -54
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
- package/scripts/lint-canary-version-leak.cjs +73 -0
- package/scripts/lint-command-contract.cjs +96 -13
- package/scripts/lint-compiled-artifact-sync.cjs +6 -1
- package/scripts/lint-completion-predicate-drift.cjs +933 -0
- package/scripts/lint-completion-ratio-drift.cjs +214 -0
- package/scripts/lint-default-flip-documentation.cjs +193 -0
- package/scripts/lint-docs-command-form.cjs +195 -0
- package/scripts/lint-docs-required.cjs +9 -1
- package/scripts/lint-emitted-drift-ack.cjs +215 -20
- package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
- package/scripts/lint-eslint-glob-coverage.cjs +340 -0
- package/scripts/lint-example-parser-parity.cjs +395 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
- package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
- package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
- package/scripts/lint-milestone-window-drift.cjs +468 -0
- package/scripts/lint-phase-enumeration-drift.cjs +479 -0
- package/scripts/lint-plan-count-drift.cjs +318 -0
- package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
- package/scripts/lint-planning-prompt-drift.cjs +434 -0
- package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
- package/scripts/lint-regression-test-names.cjs +15 -13
- package/scripts/lint-removed-but-needed.cjs +320 -0
- package/scripts/lint-state-field-drift.cjs +805 -0
- package/scripts/lint-state-write-path-drift.cjs +1045 -0
- package/scripts/lint-test-file-count.allowlist.json +40 -3
- package/scripts/lint-unreachable-guard-drift.cjs +843 -0
- package/scripts/lint-vendored-deps.cjs +124 -0
- package/scripts/mutation-matrix.cjs +13 -0
- package/scripts/pr-changed-files.cjs +63 -0
- package/scripts/pr-template-policy.cjs +14 -4
- package/scripts/prompt-injection-scan.sh +52 -6
- package/scripts/require-issue-link-policy.cjs +192 -0
- package/scripts/state-write-path-drift-baseline.json +19 -0
- package/scripts/sync-runtime-launcher.cjs +2 -4
- package/skills/gsd-autonomous/SKILL.md +0 -1
- package/skills/gsd-code-review/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -2
- package/skills/gsd-map-codebase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +2 -2
- package/skills/gsd-mempalace-recall/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +2 -2
- package/skills/gsd-next/SKILL.md +0 -1
- package/skills/gsd-plan-phase/SKILL.md +1 -2
- package/skills/gsd-progress/SKILL.md +0 -1
- package/skills/gsd-quick/SKILL.md +1 -1
- package/skills/gsd-review-backlog/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +0 -1
- package/skills/gsd-verify-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/discovery-phase.md +0 -298
- package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
- package/gsd-core/workflows/verify-phase.md +0 -577
- package/scripts/affected-tests-lib.cjs +0 -554
- package/scripts/gen-emitted-baseline.cjs +0 -145
- package/scripts/lint-allow-test-rule-refs.cjs +0 -162
- package/scripts/run-affected-tests.cjs +0 -7
- package/scripts/run-tests.cjs +0 -1050
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* lint-vendored-deps.cjs — freshness gate for gsd-core/bin/lib/vendor/.
|
|
6
|
+
*
|
|
7
|
+
* #3477 follow-up: gsd-core/bin/** is copied by the installer into trees
|
|
8
|
+
* that have NO node_modules, so it must carry zero external requires
|
|
9
|
+
* (local/no-external-require-in-bin, eslint-rules/no-external-require-in-bin.cjs).
|
|
10
|
+
* `re2js` (src/pattern.cts's RE2 engine) is vendored verbatim under
|
|
11
|
+
* gsd-core/bin/lib/vendor/ instead — see gsd-core/bin/lib/vendor/README.md.
|
|
12
|
+
*
|
|
13
|
+
* A vendored artifact that silently drifts from its upstream package is
|
|
14
|
+
* just as dangerous as never vendoring it in the first place (a stale
|
|
15
|
+
* copy ships a different engine than the one actually reviewed/audited).
|
|
16
|
+
* This guard fails CI when:
|
|
17
|
+
* 1. gsd-core/bin/lib/vendor/re2js.cjs no longer matches
|
|
18
|
+
* node_modules/re2js/build/index.cjs byte-for-byte.
|
|
19
|
+
* 2. gsd-core/bin/lib/vendor/re2js.d.cts no longer matches
|
|
20
|
+
* node_modules/re2js/build/index.d.cts byte-for-byte.
|
|
21
|
+
* 3. src/vendor/re2js.d.cts (the source-side twin tsc needs to resolve
|
|
22
|
+
* types for src/pattern.cts's relative './vendor/re2js.cjs' import —
|
|
23
|
+
* module resolution for a .cts source is relative to src/, not the
|
|
24
|
+
* output dir) no longer matches gsd-core/bin/lib/vendor/re2js.d.cts.
|
|
25
|
+
* 4. The `re2js` version pinned in package.json `devDependencies` no
|
|
26
|
+
* longer matches the version actually installed at
|
|
27
|
+
* node_modules/re2js/package.json (read there, per the dispatch
|
|
28
|
+
* brief, rather than duplicating a second pin).
|
|
29
|
+
*
|
|
30
|
+
* Usage: node scripts/lint-vendored-deps.cjs
|
|
31
|
+
* Exit 0 when every vendored copy is fresh; 1 otherwise.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const fs = require('node:fs');
|
|
35
|
+
const path = require('node:path');
|
|
36
|
+
const { ExitError, runMain } = require('./lib/cli-exit.cjs');
|
|
37
|
+
|
|
38
|
+
const ROOT = path.join(__dirname, '..');
|
|
39
|
+
|
|
40
|
+
const REFRESH_COMMAND =
|
|
41
|
+
'cp node_modules/re2js/build/index.cjs gsd-core/bin/lib/vendor/re2js.cjs && '
|
|
42
|
+
+ 'cp node_modules/re2js/build/index.d.cts gsd-core/bin/lib/vendor/re2js.d.cts && '
|
|
43
|
+
+ 'cp node_modules/re2js/build/index.d.cts src/vendor/re2js.d.cts';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Compare two files byte-for-byte. Returns null when equal, or a short
|
|
47
|
+
* mismatch description (missing file / byte-length delta) otherwise.
|
|
48
|
+
* @param {string} relA
|
|
49
|
+
* @param {string} relB
|
|
50
|
+
* @returns {string | null}
|
|
51
|
+
*/
|
|
52
|
+
function compareFiles(relA, relB) {
|
|
53
|
+
const absA = path.join(ROOT, relA);
|
|
54
|
+
const absB = path.join(ROOT, relB);
|
|
55
|
+
if (!fs.existsSync(absA)) return `${relA} does not exist`;
|
|
56
|
+
if (!fs.existsSync(absB)) return `${relB} does not exist`;
|
|
57
|
+
const a = fs.readFileSync(absA);
|
|
58
|
+
const b = fs.readFileSync(absB);
|
|
59
|
+
if (a.equals(b)) return null;
|
|
60
|
+
return `${relA} (${a.length} bytes) != ${relB} (${b.length} bytes)`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Strip a leading semver range operator (^, ~, >=, >, <=, <, =) from a
|
|
65
|
+
* package.json dependency spec, leaving a bare version.
|
|
66
|
+
* @param {string} spec
|
|
67
|
+
* @returns {string}
|
|
68
|
+
*/
|
|
69
|
+
function stripRangeOperator(spec) {
|
|
70
|
+
return String(spec || '').trim().replace(/^[\^~]|^>=|^<=|^>|^<|^=/, '').trim();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function main() {
|
|
74
|
+
const findings = [];
|
|
75
|
+
|
|
76
|
+
const cjsDrift = compareFiles('gsd-core/bin/lib/vendor/re2js.cjs', 'node_modules/re2js/build/index.cjs');
|
|
77
|
+
if (cjsDrift) findings.push(cjsDrift);
|
|
78
|
+
|
|
79
|
+
const dctsDrift = compareFiles('gsd-core/bin/lib/vendor/re2js.d.cts', 'node_modules/re2js/build/index.d.cts');
|
|
80
|
+
if (dctsDrift) findings.push(dctsDrift);
|
|
81
|
+
|
|
82
|
+
const srcTwinDrift = compareFiles('src/vendor/re2js.d.cts', 'gsd-core/bin/lib/vendor/re2js.d.cts');
|
|
83
|
+
if (srcTwinDrift) findings.push(srcTwinDrift);
|
|
84
|
+
|
|
85
|
+
const pkgPath = path.join(ROOT, 'package.json');
|
|
86
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
87
|
+
const pinnedSpec = pkg.devDependencies && pkg.devDependencies.re2js;
|
|
88
|
+
if (!pinnedSpec) {
|
|
89
|
+
findings.push('package.json devDependencies.re2js is missing');
|
|
90
|
+
} else {
|
|
91
|
+
const installedPkgPath = path.join(ROOT, 'node_modules', 're2js', 'package.json');
|
|
92
|
+
if (!fs.existsSync(installedPkgPath)) {
|
|
93
|
+
findings.push('node_modules/re2js/package.json does not exist (run npm install)');
|
|
94
|
+
} else {
|
|
95
|
+
const installed = JSON.parse(fs.readFileSync(installedPkgPath, 'utf8'));
|
|
96
|
+
const pinned = stripRangeOperator(pinnedSpec);
|
|
97
|
+
if (pinned !== installed.version) {
|
|
98
|
+
findings.push(
|
|
99
|
+
`package.json devDependencies.re2js ("${pinnedSpec}" -> "${pinned}") != `
|
|
100
|
+
+ `node_modules/re2js/package.json version ("${installed.version}")`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (findings.length > 0) {
|
|
107
|
+
const detail = findings.map((f) => ` ${f}`).join('\n');
|
|
108
|
+
throw new ExitError(
|
|
109
|
+
1,
|
|
110
|
+
'lint-vendored-deps: gsd-core/bin/lib/vendor/re2js.* has drifted from its\n'
|
|
111
|
+
+ 'upstream package (or its version pin). Refresh with:\n'
|
|
112
|
+
+ ` ${REFRESH_COMMAND}\n`
|
|
113
|
+
+ 'Findings:\n'
|
|
114
|
+
+ detail,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
process.stdout.write('ok lint-vendored-deps: gsd-core/bin/lib/vendor/re2js.* matches node_modules/re2js and its pinned version\n');
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (require.main === module) runMain(main);
|
|
123
|
+
|
|
124
|
+
module.exports = { compareFiles, stripRangeOperator };
|
|
@@ -130,6 +130,19 @@ const COVERED = {
|
|
|
130
130
|
// minScore raised to TARGET (80) — module now meets ADR-456 goal.
|
|
131
131
|
minScore: 80,
|
|
132
132
|
},
|
|
133
|
+
// context-composer: extracted from prompt-budget by #2929. Needs its own entry because
|
|
134
|
+
// mutation coverage does not migrate with relocated code — scoring only prompt-budget.cjs
|
|
135
|
+
// would leave the extracted ladder unmeasured.
|
|
136
|
+
'context-composer': {
|
|
137
|
+
cjs: 'gsd-core/bin/lib/context-composer.cjs',
|
|
138
|
+
tests: [
|
|
139
|
+
'tests/prompt-budget-parity.test.cjs',
|
|
140
|
+
'tests/prompt-budget.unit.test.cjs',
|
|
141
|
+
'tests/context-composer.test.cjs',
|
|
142
|
+
'tests/context-composer.property.test.cjs',
|
|
143
|
+
],
|
|
144
|
+
minScore: 66,
|
|
145
|
+
},
|
|
133
146
|
'prompt-budget': {
|
|
134
147
|
cjs: 'gsd-core/bin/lib/prompt-budget.cjs',
|
|
135
148
|
tests: [
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared truncation-detection helper for `gh pr view --json files` (#3211).
|
|
5
|
+
*
|
|
6
|
+
* GitHub's GraphQL `files` connection on a pull request is a paginated
|
|
7
|
+
* connection. `gh pr view --json files` requests it with a single page at
|
|
8
|
+
* `first: 100` and does NOT paginate through the rest — so any PR touching
|
|
9
|
+
* more than 100 files silently returns only the first 100, with no error and
|
|
10
|
+
* no indication in the `files` array itself that entries are missing.
|
|
11
|
+
* `changedFiles` (a separate, non-paginated scalar field) reports the true
|
|
12
|
+
* total. A policy that relaxes a gate based on "every changed file matches
|
|
13
|
+
* pattern X" must treat a `files` list it cannot confirm is complete as
|
|
14
|
+
* incomplete — i.e. fail closed — rather than silently approving a PR whose
|
|
15
|
+
* 101st+ file might violate the policy.
|
|
16
|
+
*
|
|
17
|
+
* This file lives at the top level of scripts/ rather than in scripts/lib/
|
|
18
|
+
* because scripts/lib/** is enumerated in bin/install.js and ships to users
|
|
19
|
+
* on install; this is CI-only tooling with no reason to be installed.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// GitHub's GraphQL `files` connection is requested at `first: 100` by
|
|
23
|
+
// `gh pr view --json files`; `gh` does not paginate this field.
|
|
24
|
+
const FILE_LIST_PAGE_LIMIT = 100;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns true iff `changedFiles` can be trusted as the COMPLETE list of
|
|
28
|
+
* files changed in the PR (i.e. it was not silently truncated).
|
|
29
|
+
*
|
|
30
|
+
* - An empty/non-array list cannot confirm anything about the PR — mirror
|
|
31
|
+
* the fail-closed stance `allPathsAreTooling` already takes on an empty
|
|
32
|
+
* list in scripts/pr-template-policy.cjs.
|
|
33
|
+
* - When the true total is known it is the AUTHORITY, at every list size —
|
|
34
|
+
* not just when the list has hit the page cap. The 100-entry page cap is
|
|
35
|
+
* only ONE way a list can be short of the truth; a `$GITHUB_OUTPUT`
|
|
36
|
+
* heredoc terminated early by an attacker-named file, or a path
|
|
37
|
+
* containing a newline, truncates or inflates the list just as
|
|
38
|
+
* effectively, and at any length. Comparing against the total catches all
|
|
39
|
+
* of them without enumerating the mechanisms.
|
|
40
|
+
* - Only when no total is supplied do we fall back to the page-cap
|
|
41
|
+
* heuristic: a list below the cap cannot have been truncated BY THE CAP,
|
|
42
|
+
* which is the only mechanism a caller without a total can rule out.
|
|
43
|
+
*/
|
|
44
|
+
function fileListIsComplete(changedFiles, changedFilesTotal) {
|
|
45
|
+
if (!Array.isArray(changedFiles) || changedFiles.length === 0) return false;
|
|
46
|
+
if (Number.isInteger(changedFilesTotal)) return changedFilesTotal === changedFiles.length;
|
|
47
|
+
return changedFiles.length < FILE_LIST_PAGE_LIMIT;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parses a newline-delimited env var (as produced by `git diff --name-only`
|
|
52
|
+
* or `gh pr view --json files -q '.files[].path'`) into a trimmed,
|
|
53
|
+
* empty-line-free array. Returns [] for null/undefined/empty input.
|
|
54
|
+
*/
|
|
55
|
+
function parseChangedFilesEnv(value) {
|
|
56
|
+
if (!value) return [];
|
|
57
|
+
return String(value)
|
|
58
|
+
.split(/\r?\n/)
|
|
59
|
+
.map((line) => line.trim())
|
|
60
|
+
.filter(Boolean);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = { fileListIsComplete, FILE_LIST_PAGE_LIMIT, parseChangedFilesEnv };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { matchesGlob } = require('path');
|
|
4
|
+
const { fileListIsComplete, parseChangedFilesEnv } = require('./pr-changed-files.cjs');
|
|
4
5
|
|
|
5
6
|
const TRUSTED_AUTHOR_ASSOCIATIONS = new Set([
|
|
6
7
|
'CONTRIBUTOR',
|
|
@@ -142,8 +143,12 @@ function matchingTemplate(body) {
|
|
|
142
143
|
* pattern in the allowlist. Returns false for an empty file list (no
|
|
143
144
|
* files means we cannot confirm it is a tooling-only PR).
|
|
144
145
|
*/
|
|
145
|
-
function allPathsAreTooling(changedFiles, allowlist) {
|
|
146
|
+
function allPathsAreTooling(changedFiles, allowlist, changedFilesTotal) {
|
|
146
147
|
if (!Array.isArray(changedFiles) || changedFiles.length === 0) return false;
|
|
148
|
+
// #3211: `gh pr view --json files` truncates at 100 entries with no
|
|
149
|
+
// in-band signal. A truncated list must not relax enforcement — an unseen
|
|
150
|
+
// 101st+ file could fall outside the tooling allowlist entirely.
|
|
151
|
+
if (!fileListIsComplete(changedFiles, changedFilesTotal)) return false;
|
|
147
152
|
return changedFiles.every((file) =>
|
|
148
153
|
allowlist.some((pattern) => matchesGlob(file, pattern)),
|
|
149
154
|
);
|
|
@@ -159,13 +164,13 @@ function hasExemptMarker(body, regex) {
|
|
|
159
164
|
return match[1].trim().length > 0;
|
|
160
165
|
}
|
|
161
166
|
|
|
162
|
-
function evaluatePrTemplate(body, authorAssociation, changedFiles) {
|
|
167
|
+
function evaluatePrTemplate(body, authorAssociation, changedFiles, changedFilesTotal) {
|
|
163
168
|
const association = String(authorAssociation || '').toUpperCase();
|
|
164
169
|
const trusted = TRUSTED_AUTHOR_ASSOCIATIONS.has(association);
|
|
165
170
|
const normalizedBody = String(body || '').trim();
|
|
166
171
|
|
|
167
172
|
// --- Carve-out 1: all changed files are in the tooling allowlist ---
|
|
168
|
-
if (allPathsAreTooling(changedFiles, TOOLING_PATH_ALLOWLIST)) {
|
|
173
|
+
if (allPathsAreTooling(changedFiles, TOOLING_PATH_ALLOWLIST, changedFilesTotal)) {
|
|
169
174
|
return {
|
|
170
175
|
valid: true,
|
|
171
176
|
action: 'pass',
|
|
@@ -235,13 +240,18 @@ function evaluatePrTemplate(body, authorAssociation, changedFiles) {
|
|
|
235
240
|
}
|
|
236
241
|
|
|
237
242
|
function main() {
|
|
243
|
+
// Preserve the existing distinction between "unset" (undefined) and
|
|
244
|
+
// "set but empty" ([]) — allPathsAreTooling treats them differently.
|
|
238
245
|
const changedFiles = process.env.CHANGED_FILES
|
|
239
|
-
? process.env.CHANGED_FILES
|
|
246
|
+
? parseChangedFilesEnv(process.env.CHANGED_FILES)
|
|
240
247
|
: undefined;
|
|
248
|
+
const parsedTotal = Number.parseInt(process.env.CHANGED_FILES_TOTAL, 10);
|
|
249
|
+
const changedFilesTotal = Number.isNaN(parsedTotal) ? undefined : parsedTotal;
|
|
241
250
|
const result = evaluatePrTemplate(
|
|
242
251
|
process.env.PR_BODY || '',
|
|
243
252
|
process.env.AUTHOR_ASSOCIATION || '',
|
|
244
253
|
changedFiles,
|
|
254
|
+
changedFilesTotal,
|
|
245
255
|
);
|
|
246
256
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
247
257
|
if (process.env.GITHUB_OUTPUT) {
|
|
@@ -14,6 +14,19 @@ set -euo pipefail
|
|
|
14
14
|
|
|
15
15
|
# ─── Patterns ────────────────────────────────────────────────────────────────
|
|
16
16
|
# Each pattern is a POSIX extended regex. Keep alphabetized by category.
|
|
17
|
+
#
|
|
18
|
+
# Left-boundary prefix `(^|[^[:alnum:]])`: several trigger words are also
|
|
19
|
+
# suffixes of ordinary English words or camelCase identifiers (fact/impact/
|
|
20
|
+
# contract/artifact/interact all end in "act"; retrieval/medieval end in
|
|
21
|
+
# "eval"; blueprint/reprint/fingerprint end in "print"; describeFunction/
|
|
22
|
+
# wrapFunction end in "Function"; Jordan/Sudan end in "dan"), so an
|
|
23
|
+
# unanchored keyword matches as a false-positive substring. `\b` is a GNU
|
|
24
|
+
# grep extension and this script must also run under BSD/macOS grep, so the
|
|
25
|
+
# boundary is spelled out as `(^|[^[:alnum:]])` instead. This never narrows
|
|
26
|
+
# real detections: a genuine attack phrase is always preceded by start-of-
|
|
27
|
+
# line, whitespace, or punctuation, never by another alnum character glued
|
|
28
|
+
# directly onto the keyword. Only patterns whose leading keyword is provably
|
|
29
|
+
# not a real-word suffix are left unanchored (#3175 audit).
|
|
17
30
|
|
|
18
31
|
PATTERNS=(
|
|
19
32
|
# Instruction override
|
|
@@ -27,7 +40,7 @@ PATTERNS=(
|
|
|
27
40
|
'you[[:space:]]+are[[:space:]]+now[[:space:]]+(a|an|my)[[:space:]]'
|
|
28
41
|
'from[[:space:]]+now[[:space:]]+on[[:space:]]+(you|pretend|act|behave)'
|
|
29
42
|
'pretend[[:space:]]+(you[[:space:]]+are|to[[:space:]]+be)[[:space:]]'
|
|
30
|
-
'act[[:space:]]+as[[:space:]]+(a|an|if|my)[[:space:]]'
|
|
43
|
+
'(^|[^[:alnum:]])act[[:space:]]+as[[:space:]]+(a|an|if|my)[[:space:]]'
|
|
31
44
|
'roleplay[[:space:]]+as[[:space:]]'
|
|
32
45
|
'assume[[:space:]]+the[[:space:]]+role[[:space:]]+of[[:space:]]'
|
|
33
46
|
|
|
@@ -35,7 +48,7 @@ PATTERNS=(
|
|
|
35
48
|
'output[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
36
49
|
'reveal[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
37
50
|
'show[[:space:]]+me[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
38
|
-
'print[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
51
|
+
'(^|[^[:alnum:]])print[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
39
52
|
'what[[:space:]]+(is|are)[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
40
53
|
'repeat[[:space:]]+(your|the|all)[[:space:]]+(system[[:space:]]+)?(prompt|instructions|rules)'
|
|
41
54
|
|
|
@@ -51,13 +64,30 @@ PATTERNS=(
|
|
|
51
64
|
'<</SYS>>'
|
|
52
65
|
|
|
53
66
|
# Tool call injection / code execution in markdown
|
|
54
|
-
|
|
55
|
-
'
|
|
56
|
-
'
|
|
67
|
+
#
|
|
68
|
+
# The quote-or-apostrophe class below is spelled ["'"'"'"] (a literal `'`
|
|
69
|
+
# via bash's close-quote/escape/reopen idiom), not `["\x27]` — `\x27` is a
|
|
70
|
+
# GNU-grep-only hex escape; BSD/macOS grep treats it as four literal
|
|
71
|
+
# characters (", \, x, 2, 7) and never matches an actual apostrophe, so
|
|
72
|
+
# `eval('...')` (single-quoted) silently went undetected on macOS while
|
|
73
|
+
# passing on GNU-grep CI runners. Found auditing #3175; fixed here since it
|
|
74
|
+
# is the same unanchored/portability defect class as the boundary fix.
|
|
75
|
+
#
|
|
76
|
+
# `exec` stays receiver-blind on purpose. A left boundary that excludes a
|
|
77
|
+
# preceding `.` would drop every member-position `.exec('…')` — including
|
|
78
|
+
# `require('child_process').exec('…')`, the single most common Node spelling
|
|
79
|
+
# of the vector this pattern exists to catch — and a receiver allowlist
|
|
80
|
+
# cannot restore it, because the literal `child_process` is not adjacent to
|
|
81
|
+
# `.exec`. The cost is that `RegExp.prototype.exec`, which takes a subject
|
|
82
|
+
# string rather than code, also matches; files that legitimately call it are
|
|
83
|
+
# handled by ALLOWLIST below, never by narrowing the pattern.
|
|
84
|
+
'(^|[^[:alnum:]])eval[[:space:]]*\([[:space:]]*["'"'"']'
|
|
85
|
+
'exec[[:space:]]*\([[:space:]]*["'"'"']'
|
|
86
|
+
'(^|[^[:alnum:]])Function[[:space:]]*\([[:space:]]*["'"'"'].*return'
|
|
57
87
|
|
|
58
88
|
# Jailbreak / DAN patterns
|
|
59
89
|
'do[[:space:]]+anything[[:space:]]+now'
|
|
60
|
-
'DAN[[:space:]]+mode'
|
|
90
|
+
'(^|[^[:alnum:]])DAN[[:space:]]+mode'
|
|
61
91
|
'developer[[:space:]]+mode[[:space:]]+(enabled|output|activated)'
|
|
62
92
|
'jailbreak'
|
|
63
93
|
'bypass[[:space:]]+(safety|content|security)[[:space:]]+(filter|check|rule|guard)'
|
|
@@ -108,6 +138,22 @@ ALLOWLIST=(
|
|
|
108
138
|
# asserts nothing: it is the payload the guard is required to catch, carried
|
|
109
139
|
# as test DATA. Same class as the read-injection-scanner suites above.
|
|
110
140
|
'tests/kimi-payload-field-shadowing.security.test.cjs'
|
|
141
|
+
# Phase-ID grammar regression tests exercise `RegExp.prototype.exec` via
|
|
142
|
+
# `re.exec('<phase-id>')` against fixtures like 'MANIFOLD-64-auth' / 'CK-64-auth'.
|
|
143
|
+
# The scanner's `exec('` code-execution pattern matches that benign method call,
|
|
144
|
+
# not an attack vector — same DEFECT.PROMPT-INJECTION-SCAN-COLLISION class as the
|
|
145
|
+
# test fixtures above. Pre-existing content (16 such calls on `next`); it surfaces
|
|
146
|
+
# here only because #2573's W024 `state_head` assertions make the file appear in
|
|
147
|
+
# the changed-file set the diff-mode scan walks.
|
|
148
|
+
'tests/health-validation.test.cjs'
|
|
149
|
+
# #2528 — same collision, same disposition: the continuation-grammar suite
|
|
150
|
+
# drives the tokenizer regexes directly via `re.exec('05-80-20')`, so the
|
|
151
|
+
# argument is the subject string, not a command. Exempted per file rather
|
|
152
|
+
# than by narrowing the `exec(` pattern: a left boundary excluding a preceding
|
|
153
|
+
# `.` would drop `require('child_process').exec('…')`, and a receiver
|
|
154
|
+
# allowlist cannot reach it either, because the literal `child_process` is
|
|
155
|
+
# not adjacent to `.exec`. See the note at the pattern itself.
|
|
156
|
+
'tests/continuation-grammar-parity.test.cjs'
|
|
111
157
|
)
|
|
112
158
|
|
|
113
159
|
is_allowlisted() {
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Require-issue-link policy (#3211, preserving #1389).
|
|
6
|
+
*
|
|
7
|
+
* Replaces the shell-only `grep -qiE '(closes|fixes|resolves)\s+#[0-9]+'`
|
|
8
|
+
* step with a pure, testable `evaluateIssueLink` verdict function so a PR
|
|
9
|
+
* that only REFERENCES an issue (rather than closing it — e.g. a follow-up
|
|
10
|
+
* regression-coverage PR) is not forced to fabricate a closing keyword, while
|
|
11
|
+
* two pre-existing constraints are preserved exactly:
|
|
12
|
+
*
|
|
13
|
+
* 1. (#1389, anti-forgery) The backmerge exemption only fires when the
|
|
14
|
+
* head ref carries the backmerge prefix AND the PR is same-repo (not a
|
|
15
|
+
* fork) — dropping the `sameRepo` conjunct would let a fork forge a
|
|
16
|
+
* branch name to bypass the issue-link requirement entirely.
|
|
17
|
+
* 2. (#3211, truncation) `gh pr view --json files` truncates the file list
|
|
18
|
+
* at 100 entries with no in-band signal that it did so (see
|
|
19
|
+
* scripts/pr-changed-files.cjs). The reference-only carve-out below
|
|
20
|
+
* only applies when every changed file is a test/doc file, so a PR
|
|
21
|
+
* whose file list may be truncated must fail closed rather than let an
|
|
22
|
+
* unseen 101st+ file (which could touch `src/`) slip through.
|
|
23
|
+
*
|
|
24
|
+
* Tests assert on the typed ISSUE_LINK_REASON enum, never on free text.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const { fileListIsComplete, parseChangedFilesEnv } = require('./pr-changed-files.cjs');
|
|
28
|
+
const { runMain } = require('./lib/cli-exit.cjs');
|
|
29
|
+
|
|
30
|
+
const ISSUE_LINK_REASON = Object.freeze({
|
|
31
|
+
OK_CLOSING_KEYWORD: 'ok_closing_keyword',
|
|
32
|
+
OK_BACKMERGE_EXEMPT: 'ok_backmerge_exempt',
|
|
33
|
+
OK_FOLLOWUP_REFERENCE: 'ok_followup_reference',
|
|
34
|
+
FAIL_NO_ISSUE_REFERENCE: 'fail_no_issue_reference',
|
|
35
|
+
FAIL_REFERENCE_NEEDS_CLOSING: 'fail_reference_needs_closing',
|
|
36
|
+
FAIL_FILE_LIST_INCOMPLETE: 'fail_file_list_incomplete',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// #1389: backmerge PRs are opened by CI against `next`, never by a human or a
|
|
40
|
+
// fork, so they are exempt from the issue-link requirement outright — but
|
|
41
|
+
// ONLY when combined with `sameRepo === true` below (see header comment).
|
|
42
|
+
const BACKMERGE_BRANCH_PREFIX = 'chore/backmerge-main-to-next-';
|
|
43
|
+
|
|
44
|
+
// A follow-up-only PR (references an issue without closing it) is only
|
|
45
|
+
// allowed to skip the closing keyword when every changed file is a test or
|
|
46
|
+
// doc file — i.e. it cannot be the PR that actually implements the fix.
|
|
47
|
+
const EXEMPT_PATH_PREFIXES = ['tests/', 'docs/'];
|
|
48
|
+
|
|
49
|
+
// Root-level markdown is documentation — this mirrors the repo's own doc-only
|
|
50
|
+
// classifier (.claude/hooks/pre-pr-gate.sh:111), whose `[^/]+\.md` anchor is
|
|
51
|
+
// deliberately root-only so runtime-loaded text under a subdirectory
|
|
52
|
+
// (gsd-core/workflows/*.md, agents/*.md, commands/**/*.md) stays gated.
|
|
53
|
+
// CHANGELOG.md is excluded: scripts/changeset/lint.cjs classes a direct edit to
|
|
54
|
+
// it as user-facing precisely to close a bypass, so it must not ride in on the
|
|
55
|
+
// docs carve-out either.
|
|
56
|
+
const EXCLUDED_ROOT_DOCS = new Set(['CHANGELOG.md']);
|
|
57
|
+
|
|
58
|
+
// Case-insensitive lookup set derived from EXCLUDED_ROOT_DOCS. The exclusion
|
|
59
|
+
// check below is case-insensitive because the `.md` extension test above it
|
|
60
|
+
// already is (`/\.md$/i`) — `changelog.md` or `CHANGELOG.MD` would otherwise
|
|
61
|
+
// slip past the exclusion while still passing the extension test. In
|
|
62
|
+
// practice this is defense in depth rather than a live bypass: the GitHub
|
|
63
|
+
// API always reports the real path with its actual, fixed casing (the
|
|
64
|
+
// filesystem is case-sensitive on the runners this executes on), so a PR
|
|
65
|
+
// cannot rename CHANGELOG.md to bypass the check by casing alone.
|
|
66
|
+
const EXCLUDED_ROOT_DOCS_UPPER = new Set(
|
|
67
|
+
Array.from(EXCLUDED_ROOT_DOCS, (name) => name.toUpperCase()),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
function isRootLevelDoc(normalizedPath) {
|
|
71
|
+
if (!normalizedPath) return false;
|
|
72
|
+
if (normalizedPath.includes('/')) return false;
|
|
73
|
+
if (!/\.md$/i.test(normalizedPath)) return false;
|
|
74
|
+
if (EXCLUDED_ROOT_DOCS_UPPER.has(normalizedPath.toUpperCase())) return false;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Mirrors the shipped `grep -qiE '(closes|fixes|resolves)\s+#[0-9]+'` exactly:
|
|
79
|
+
// no additional keywords, no `\b` anchors (the shell grep it replaces has
|
|
80
|
+
// none either) — see the corpus-parity test in
|
|
81
|
+
// tests/require-issue-link-policy.test.cjs.
|
|
82
|
+
const CLOSING_KEYWORD_REGEX = /(?:closes|fixes|resolves)\s+#[0-9]+/i;
|
|
83
|
+
|
|
84
|
+
// Accepts a soft "this PR relates to #N" reference without claiming to close
|
|
85
|
+
// it. The leading `\b` prevents matching inside a longer word (e.g. `xref#1`,
|
|
86
|
+
// `prefs #1`) because there is no word-boundary transition between the
|
|
87
|
+
// preceding word character and the start of the alternative — verified
|
|
88
|
+
// explicitly for `preferences #1` / `unreferenced #1` in the test suite.
|
|
89
|
+
const FOLLOWUP_REFERENCE_REGEX = /\b(?:refs?|references?|relates\s+to|related\s+to|follow[-\s]?up\s+to)\s+#[0-9]+/i;
|
|
90
|
+
|
|
91
|
+
function hasClosingKeyword(body) {
|
|
92
|
+
return CLOSING_KEYWORD_REGEX.test(String(body || ''));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function hasFollowUpReference(body) {
|
|
96
|
+
return FOLLOWUP_REFERENCE_REGEX.test(String(body || ''));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Path separator normalization — unconditional, per repo convention (see
|
|
100
|
+
// CLAUDE.md "Path-sep normalization"), so a Windows-style diff entry like
|
|
101
|
+
// `tests\windows\a.test.cjs` is still recognized as tests/-prefixed.
|
|
102
|
+
function normalizePath(p) {
|
|
103
|
+
return String(p).replace(/\\/g, '/');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Returns true iff every changed file qualifies as a test/doc file, i.e. each
|
|
108
|
+
* one is one of:
|
|
109
|
+
* 1. under one of EXEMPT_PATH_PREFIXES (`tests/`, `docs/`) — the trailing
|
|
110
|
+
* slash on each prefix makes this directory-boundary aware, so
|
|
111
|
+
* lookalikes like `tests-e2e/`, `testsuite/`, or `docsite/` are
|
|
112
|
+
* correctly rejected (they are not `tests/` or `docs/`); or
|
|
113
|
+
* 2. a root-level markdown file (no `/`, `.md` extension, case-insensitive)
|
|
114
|
+
* that is not in EXCLUDED_ROOT_DOCS — see isRootLevelDoc.
|
|
115
|
+
*/
|
|
116
|
+
function allPathsAreTestsOrDocs(changedFiles) {
|
|
117
|
+
if (!Array.isArray(changedFiles) || changedFiles.length === 0) return false;
|
|
118
|
+
return changedFiles.every((file) => {
|
|
119
|
+
const normalized = normalizePath(file);
|
|
120
|
+
if (EXEMPT_PATH_PREFIXES.some((prefix) => normalized.startsWith(prefix))) return true;
|
|
121
|
+
return isRootLevelDoc(normalized);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function evaluateIssueLink({ prBody, headRef, sameRepo, changedFiles, changedFilesTotal }) {
|
|
126
|
+
if (hasClosingKeyword(prBody)) {
|
|
127
|
+
return { ok: true, reason: ISSUE_LINK_REASON.OK_CLOSING_KEYWORD };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// #1389: `sameRepo === true` is required, not just the branch-name prefix —
|
|
131
|
+
// a fork PR could otherwise name its branch to forge this exemption.
|
|
132
|
+
if (String(headRef || '').startsWith(BACKMERGE_BRANCH_PREFIX) && sameRepo === true) {
|
|
133
|
+
return { ok: true, reason: ISSUE_LINK_REASON.OK_BACKMERGE_EXEMPT };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!hasFollowUpReference(prBody)) {
|
|
137
|
+
return { ok: false, reason: ISSUE_LINK_REASON.FAIL_NO_ISSUE_REFERENCE };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// #3211: a truncated file list cannot be trusted to prove "tests/docs
|
|
141
|
+
// only" — fail closed rather than risk approving on an unseen file.
|
|
142
|
+
if (!fileListIsComplete(changedFiles, changedFilesTotal)) {
|
|
143
|
+
return { ok: false, reason: ISSUE_LINK_REASON.FAIL_FILE_LIST_INCOMPLETE };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (allPathsAreTestsOrDocs(changedFiles)) {
|
|
147
|
+
return { ok: true, reason: ISSUE_LINK_REASON.OK_FOLLOWUP_REFERENCE };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { ok: false, reason: ISSUE_LINK_REASON.FAIL_REFERENCE_NEEDS_CLOSING };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function main() {
|
|
154
|
+
const changedFiles = parseChangedFilesEnv(process.env.CHANGED_FILES);
|
|
155
|
+
const parsedTotal = Number.parseInt(process.env.CHANGED_FILES_TOTAL, 10);
|
|
156
|
+
const changedFilesTotal = Number.isNaN(parsedTotal) ? undefined : parsedTotal;
|
|
157
|
+
|
|
158
|
+
const result = evaluateIssueLink({
|
|
159
|
+
prBody: process.env.PR_BODY || '',
|
|
160
|
+
headRef: process.env.HEAD_REF || '',
|
|
161
|
+
sameRepo: process.env.SAME_REPO === 'true',
|
|
162
|
+
changedFiles,
|
|
163
|
+
changedFilesTotal,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
167
|
+
if (process.env.GITHUB_OUTPUT) {
|
|
168
|
+
const fs = require('node:fs');
|
|
169
|
+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `ok=${result.ok ? 'true' : 'false'}\n`);
|
|
170
|
+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `reason=${result.reason}\n`);
|
|
171
|
+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `result=${JSON.stringify(result)}\n`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return result.ok ? 0 : 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (require.main === module) runMain(main);
|
|
178
|
+
|
|
179
|
+
module.exports = {
|
|
180
|
+
ISSUE_LINK_REASON,
|
|
181
|
+
BACKMERGE_BRANCH_PREFIX,
|
|
182
|
+
EXEMPT_PATH_PREFIXES,
|
|
183
|
+
EXCLUDED_ROOT_DOCS,
|
|
184
|
+
CLOSING_KEYWORD_REGEX,
|
|
185
|
+
FOLLOWUP_REFERENCE_REGEX,
|
|
186
|
+
hasClosingKeyword,
|
|
187
|
+
hasFollowUpReference,
|
|
188
|
+
normalizePath,
|
|
189
|
+
isRootLevelDoc,
|
|
190
|
+
allPathsAreTestsOrDocs,
|
|
191
|
+
evaluateIssueLink,
|
|
192
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "ADR-3408 Decision 5 write-seam ratchet baseline (issue #3468, Phase 1; Phase 2 / #3469 lands the single write seam and Amendment 2). Every entry here is a `writeStateMd(`/`syncStateFrontmatter(`/`applyPostSyncPreservation(` bypass this guard found by a whole-repo scan (Decision 4(a)) — it is ACKNOWLEDGED, not endorsed: acknowledgment is in writing (this file), with the issue owning its removal recorded in the entry's \"owner\" field. This baseline is SHRINK-ONLY — an entry that stops firing goes STALE and fails the plain run until `--baseline` is re-run to drop it (ADR-3180 Decision 4(e)'s \"the baseline may only shrink\", adopted verbatim by ADR-3408). Phase 2 (#3469) removed the `cmdPhaseComplete` (`src/phase.cts`) and `cmdMilestoneComplete` (`src/milestone.cts`) entries by routing both through the single write-seam composition (`syncAndPreserveStateMd`, `src/state.cts`). ADR-3408 Amendment 2: \"0 bypasses\" was never this baseline's target — TWO entries are SANCTIONED PERMANENT, not debt, and Phase 4 (#3471) does NOT drive this file to empty: `cmdStateSync` (`src/state.cts`) exists precisely to let the body win (#905 — `state sync` re-derives frontmatter FROM the body), so routing it through preservation would invert the command rather than fix a bug; `REGENERATE_STATE` (`src/health-diagnostic.cts`) is `/gsd-health --repair`'s factory reset, which rebuilds STATE.md from scratch, so preservation would restore exactly the values it was invoked to discard. Neither entry may be \"consolidated\" away — a guard reporting them is reporting correctly, and a change that removes one is a regression, not progress.",
|
|
3
|
+
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"file": "src/health-diagnostic.cts",
|
|
6
|
+
"source": "writeStateMd(statePath, stateContent, cwd);",
|
|
7
|
+
"symbol": "writeStateMd",
|
|
8
|
+
"count": 1,
|
|
9
|
+
"owner": "sanctioned-permanent"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"file": "src/state.cts",
|
|
13
|
+
"source": "writeStateMd(statePath, modified, cwd);",
|
|
14
|
+
"symbol": "writeStateMd",
|
|
15
|
+
"count": 1,
|
|
16
|
+
"owner": "sanctioned-permanent"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
const fs = require('node:fs');
|
|
20
20
|
const path = require('node:path');
|
|
21
21
|
|
|
22
|
+
const { escapeRegex: escapeRegExp } = require('../gsd-core/bin/lib/pattern.cjs');
|
|
23
|
+
|
|
22
24
|
const WORKFLOWS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows');
|
|
23
25
|
const AGENTS_DIR = path.join(__dirname, '..', 'agents');
|
|
24
26
|
const SNIPPET_FILE = path.join(WORKFLOWS_DIR, '_runtime-launcher.snippet.sh');
|
|
@@ -373,10 +375,6 @@ function transformFile(content, preamble) {
|
|
|
373
375
|
return outputLines.join('\n');
|
|
374
376
|
}
|
|
375
377
|
|
|
376
|
-
function escapeRegExp(str) {
|
|
377
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
378
|
-
}
|
|
379
|
-
|
|
380
378
|
/**
|
|
381
379
|
* A file "delegates to the shared resolver" when it pulls the canonical gsd_run
|
|
382
380
|
* preamble in from gsd-core/references/gsd-run-resolver.md via an @-include
|
|
@@ -41,7 +41,7 @@ Optional flags parsed from $ARGUMENTS:
|
|
|
41
41
|
- `--depth=VALUE` — Depth override (quick|standard|deep). If provided, overrides workflow.code_review_depth config.
|
|
42
42
|
- `--files=file1,file2,...` — Explicit file list override. Has highest precedence for file scoping per D-08. When provided, workflow skips SUMMARY.md extraction and git diff fallback entirely.
|
|
43
43
|
|
|
44
|
-
Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `<
|
|
44
|
+
Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `<required_reading>` blocks.
|
|
45
45
|
</context>
|
|
46
46
|
|
|
47
47
|
<process>
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
name: gsd-execute-phase
|
|
3
3
|
description: "Execute all plans in a phase with wave-based parallelization"
|
|
4
4
|
argument-hint: "<phase-number> [--wave N] [--gaps-only] [--interactive] [--tdd]"
|
|
5
|
-
effort: max
|
|
6
5
|
allowed-tools:
|
|
7
6
|
- Read
|
|
8
7
|
- Write
|
|
@@ -56,7 +55,7 @@ Phase: $ARGUMENTS
|
|
|
56
55
|
- If none of these tokens appear, run the standard full-phase execution flow with no flag-specific filtering
|
|
57
56
|
- Do not infer that a flag is active just because it is documented in this prompt
|
|
58
57
|
|
|
59
|
-
Context files are resolved inside the workflow via `gsd-tools query init.execute-phase` and per-subagent `<
|
|
58
|
+
Context files are resolved inside the workflow via `gsd-tools query init.execute-phase` and per-subagent `<required_reading>` blocks.
|
|
60
59
|
</context>
|
|
61
60
|
|
|
62
61
|
<process>
|
|
@@ -34,7 +34,7 @@ Output: .planning/codebase/ folder with 7 structured documents about the codebas
|
|
|
34
34
|
Arguments: $ARGUMENTS
|
|
35
35
|
|
|
36
36
|
Parse the first token of $ARGUMENTS:
|
|
37
|
-
- If it is `--fast`: strip the flag,
|
|
37
|
+
- If it is `--fast`: strip the flag, then read and execute `~/.claude/gsd-core/workflows/scan.md` (passing remaining args including optional --focus). Load it on demand here — it is deliberately not in `<execution_context>`, so the common full-map path does not pay for it.
|
|
38
38
|
- If it is `--query`: strip the flag, run the intel workflow (passing remaining args as the subcommand).
|
|
39
39
|
- Otherwise: pass all of $ARGUMENTS as focus area to the map-codebase workflow.
|
|
40
40
|
|