@opengsd/gsd-core 1.11.0 → 1.12.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 +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -9
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +0 -1
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +3 -1
- package/agents/gsd-plan-checker.md +15 -55
- package/agents/gsd-planner.md +6 -4
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +609 -134
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/quick.md +8 -4
- package/gsd-core/bin/gsd-tools.cjs +567 -51
- package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
- package/gsd-core/bin/lib/api-coverage.cjs +30 -9
- package/gsd-core/bin/lib/artifacts.cjs +2 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
- package/gsd-core/bin/lib/audit.cjs +163 -41
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +336 -95
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-validator.cjs +205 -18
- package/gsd-core/bin/lib/check-command-router.cjs +145 -5
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +543 -44
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +118 -29
- package/gsd-core/bin/lib/config.cjs +92 -2
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +84 -7
- package/gsd-core/bin/lib/edge-probe.cjs +9 -1
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/frontmatter.cjs +840 -305
- package/gsd-core/bin/lib/gap-checker.cjs +27 -3
- package/gsd-core/bin/lib/git-base-branch.cjs +174 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +6 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
- package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +120 -41
- package/gsd-core/bin/lib/install-engine.cjs +68 -3
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +33 -1
- package/gsd-core/bin/lib/install-profiles.cjs +78 -4
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +160 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/markdown-table.cjs +52 -4
- package/gsd-core/bin/lib/milestone.cjs +90 -5
- package/gsd-core/bin/lib/model-catalog.cjs +177 -19
- package/gsd-core/bin/lib/model-resolver.cjs +10 -28
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +70 -4
- package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
- package/gsd-core/bin/lib/phase-locator.cjs +138 -17
- package/gsd-core/bin/lib/phase.cjs +405 -84
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-scan.cjs +13 -2
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -14
- package/gsd-core/bin/lib/planning-workspace.cjs +56 -0
- package/gsd-core/bin/lib/probe-core.cjs +4 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +9 -9
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +79 -16
- package/gsd-core/bin/lib/roadmap.cjs +74 -19
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +96 -8
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +34 -1
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +287 -55
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +71 -8
- package/gsd-core/bin/lib/smart-entry.cjs +12 -22
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +47 -18
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +186 -0
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +517 -101
- package/gsd-core/bin/lib/state.cjs +946 -163
- package/gsd-core/bin/lib/surface.cjs +10 -2
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
- package/gsd-core/bin/lib/uat.cjs +1376 -125
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
- package/gsd-core/bin/lib/unusable-input.cjs +13 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/vendor/README.md +43 -5
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/verification.cjs +14 -1
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +95 -40
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +177 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/references/agent-contracts.md +3 -2
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +37 -19
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +1 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +3 -3
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +22 -0
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-revision.md +1 -1
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +37 -8
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/tdd.md +1 -3
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +2 -2
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +11 -11
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/phase-prompt.md +3 -0
- package/gsd-core/templates/state.md +7 -0
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +3 -3
- package/gsd-core/workflows/add-tests.md +3 -8
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +4 -9
- package/gsd-core/workflows/audit-fix.md +12 -3
- package/gsd-core/workflows/audit-milestone.md +9 -9
- package/gsd-core/workflows/audit-uat.md +17 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +10 -26
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +1 -1
- package/gsd-core/workflows/code-review.md +121 -40
- package/gsd-core/workflows/complete-milestone.md +15 -10
- package/gsd-core/workflows/debug.md +5 -3
- package/gsd-core/workflows/diagnose-issues.md +12 -6
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +3 -7
- package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +2 -2
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +3 -6
- package/gsd-core/workflows/docs-update.md +5 -4
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +4 -9
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +113 -11
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +22 -4
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase.md +38 -54
- package/gsd-core/workflows/execute-plan.md +17 -12
- package/gsd-core/workflows/explore.md +1 -1
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +2 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +3 -6
- package/gsd-core/workflows/import.md +14 -11
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +44 -11
- package/gsd-core/workflows/insert-phase.md +5 -5
- package/gsd-core/workflows/list-seeds.md +5 -3
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +12 -23
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +2 -2
- package/gsd-core/workflows/new-milestone.md +9 -21
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +12 -26
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -2
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
- package/gsd-core/workflows/plan-phase.md +121 -42
- package/gsd-core/workflows/plan-review-convergence.md +46 -9
- package/gsd-core/workflows/plant-seed.md +2 -2
- package/gsd-core/workflows/pr-branch.md +187 -51
- package/gsd-core/workflows/profile-user.md +16 -14
- package/gsd-core/workflows/progress.md +27 -12
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -3
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +2 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +20 -29
- package/gsd-core/workflows/remove-phase.md +4 -4
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +8 -12
- package/gsd-core/workflows/review.md +193 -15
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +2 -2
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +3 -5
- package/gsd-core/workflows/ship.md +12 -6
- package/gsd-core/workflows/sketch-wrap-up.md +11 -17
- package/gsd-core/workflows/sketch.md +12 -18
- package/gsd-core/workflows/smart-entry.md +3 -5
- package/gsd-core/workflows/spec-phase.md +23 -1
- package/gsd-core/workflows/spike-wrap-up.md +7 -11
- package/gsd-core/workflows/spike.md +20 -31
- package/gsd-core/workflows/stats.md +2 -2
- package/gsd-core/workflows/sync-skills.md +1 -1
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +5 -5
- package/gsd-core/workflows/ui-phase.md +10 -16
- package/gsd-core/workflows/ui-review.md +6 -10
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +6 -10
- package/gsd-core/workflows/validate-phase.md +2 -2
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +57 -18
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +19 -10
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +16 -7
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +17 -8
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +215 -26
- package/hooks/dist/gsd-validate-commit.sh +80 -6
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +34 -16
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +19 -10
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +3 -1
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +28 -23
- package/hooks/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +16 -7
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +17 -8
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +215 -26
- package/hooks/gsd-validate-commit.sh +80 -6
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +34 -16
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +12 -7
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +5 -0
- package/scripts/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +45 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-capability-registry.cjs +8 -6
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-loop-host-contract.cjs +134 -1
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +32 -2
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +21 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-removed-but-needed.cjs +184 -16
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-write-path-drift.cjs +337 -432
- package/scripts/lint-test-file-count.allowlist.json +122 -4
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +51 -64
- package/scripts/lint-vendored-deps.cjs +208 -35
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/prompt-injection-scan.sh +75 -14
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +22 -3
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -109
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/state-write-path-drift-baseline.json +0 -19
|
@@ -374,6 +374,12 @@ function normalizeCleanupManifestEntry(entry) {
|
|
|
374
374
|
// would make an unrecorded plan look 100% out of scope.
|
|
375
375
|
const filesModified = (Array.isArray(e.files_modified) ? e.files_modified : [])
|
|
376
376
|
.filter((f) => typeof f === 'string' && f.trim().length > 0);
|
|
377
|
+
// #3003: same liberal-in-what-we-accept rule as `files_modified` above — non-array,
|
|
378
|
+
// or non-string / empty elements, are dropped rather than coerced, and an EMPTY
|
|
379
|
+
// result omits the field entirely so "declares nothing" stays indistinguishable
|
|
380
|
+
// from "not recorded" (the guard's own absence-check already treats both as unknown).
|
|
381
|
+
const declaredDeletions = (Array.isArray(e.declared_deletions) ? e.declared_deletions : [])
|
|
382
|
+
.filter((f) => typeof f === 'string' && f.trim().length > 0);
|
|
377
383
|
const normalized = {
|
|
378
384
|
agent_id: typeof e.agent_id === 'string' ? e.agent_id : null,
|
|
379
385
|
worktree_path: worktreePath,
|
|
@@ -383,6 +389,8 @@ function normalizeCleanupManifestEntry(entry) {
|
|
|
383
389
|
};
|
|
384
390
|
if (filesModified.length > 0)
|
|
385
391
|
normalized.files_modified = filesModified;
|
|
392
|
+
if (declaredDeletions.length > 0)
|
|
393
|
+
normalized.declared_deletions = declaredDeletions;
|
|
386
394
|
return normalized;
|
|
387
395
|
}
|
|
388
396
|
function normalizeCleanupManifest(manifest) {
|
|
@@ -480,16 +488,79 @@ function repoRootStillMidMerge(execGit, repoRoot) {
|
|
|
480
488
|
// advisory fire on essentially every wave.
|
|
481
489
|
const SUMMARY_ARTIFACT_DIR = '.planning';
|
|
482
490
|
const SUMMARY_ARTIFACT_SUFFIX = 'SUMMARY.md';
|
|
491
|
+
/**
|
|
492
|
+
* Decode a git-quoted path. With `core.quotepath` left at its default (`true`)
|
|
493
|
+
* git wraps any path containing non-ASCII or special bytes in double quotes
|
|
494
|
+
* and C-escapes it — e.g. `tests/é.ts` is emitted as the literal
|
|
495
|
+
* `"tests/\303\251.ts"`. Both sides of the deletion/scope comparison
|
|
496
|
+
* (a declared path and a git-reported path) must agree on the same decoded
|
|
497
|
+
* shape, and decoding it here — rather than passing `-c core.quotepath=false`
|
|
498
|
+
* on the `execGit` call — keeps the git argv, and therefore every existing
|
|
499
|
+
* test fixture that asserts on exact argv, unchanged. It also works
|
|
500
|
+
* regardless of the user's own `core.quotepath` config.
|
|
501
|
+
*
|
|
502
|
+
* A value that is not wrapped in a leading and trailing `"` is returned
|
|
503
|
+
* completely untouched — this is the overwhelmingly common (plain ASCII)
|
|
504
|
+
* case and must not be altered in any way.
|
|
505
|
+
*
|
|
506
|
+
* Escapes decode to BYTES, collected into a Buffer and decoded as UTF-8 only
|
|
507
|
+
* at the end: `\303\251` is two bytes that together form one character (é),
|
|
508
|
+
* so decoding them one at a time would produce mojibake. Malformed input
|
|
509
|
+
* (a trailing lone backslash, or an octal escape with fewer than three
|
|
510
|
+
* digits) never throws — it degrades to treating the character literally, so
|
|
511
|
+
* a single bad path can never take down the whole cleanup wave.
|
|
512
|
+
*/
|
|
513
|
+
function decodeGitQuotedPath(raw) {
|
|
514
|
+
if (raw.length < 2 || !raw.startsWith('"') || !raw.endsWith('"'))
|
|
515
|
+
return raw;
|
|
516
|
+
const body = raw.slice(1, -1);
|
|
517
|
+
const bytes = [];
|
|
518
|
+
for (let i = 0; i < body.length; i++) {
|
|
519
|
+
const ch = body[i];
|
|
520
|
+
if (ch !== '\\' || i === body.length - 1) {
|
|
521
|
+
// UTF-8 bytes, not the code unit: a DECLARED path may be quoted while
|
|
522
|
+
// still holding a literal `é`, and pushing 0xE9 alone is invalid UTF-8.
|
|
523
|
+
// codePointAt keeps a surrogate pair together.
|
|
524
|
+
const codePoint = body.codePointAt(i);
|
|
525
|
+
const char = codePoint === undefined ? ch : String.fromCodePoint(codePoint);
|
|
526
|
+
bytes.push(...Buffer.from(char, 'utf8'));
|
|
527
|
+
i += char.length - 1;
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
const rest = body.slice(i + 1);
|
|
531
|
+
const octalMatch = /^([0-3][0-7][0-7])/.exec(rest);
|
|
532
|
+
if (octalMatch) {
|
|
533
|
+
bytes.push(parseInt(octalMatch[1], 8));
|
|
534
|
+
i += 3;
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
const next = body[i + 1];
|
|
538
|
+
const CONTROL_ESCAPES = {
|
|
539
|
+
a: 0x07, b: 0x08, f: 0x0c, n: 0x0a, r: 0x0d, t: 0x09, v: 0x0b,
|
|
540
|
+
'\\': 0x5c, '"': 0x22,
|
|
541
|
+
};
|
|
542
|
+
if (Object.prototype.hasOwnProperty.call(CONTROL_ESCAPES, next)) {
|
|
543
|
+
bytes.push(CONTROL_ESCAPES[next]);
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
bytes.push(next.charCodeAt(0));
|
|
547
|
+
}
|
|
548
|
+
i += 1;
|
|
549
|
+
}
|
|
550
|
+
return Buffer.from(bytes).toString('utf8');
|
|
551
|
+
}
|
|
483
552
|
/**
|
|
484
553
|
* Normalize one path for scope comparison. Applied to BOTH sides so a declared
|
|
485
|
-
* path and a git-reported path meet in the same shape:
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
554
|
+
* path and a git-reported path meet in the same shape: any git C-quoting is
|
|
555
|
+
* decoded first (order matters — the backslash-to-slash conversion below
|
|
556
|
+
* would destroy the escape sequences if it ran first), then backslashes
|
|
557
|
+
* become slashes unconditionally (a backslash path is not a Windows-only
|
|
558
|
+
* input), and a leading `./` and any trailing `/` are stripped. This is the
|
|
559
|
+
* single normalizer shared by the SUMMARY-artifact predicate and the scope
|
|
560
|
+
* advisory, so the two can never disagree about what `./a\b/` means.
|
|
490
561
|
*/
|
|
491
562
|
function normalizeScopePath(raw) {
|
|
492
|
-
return String(raw || '')
|
|
563
|
+
return decodeGitQuotedPath(String(raw || '').trim())
|
|
493
564
|
.replace(/\\/g, '/')
|
|
494
565
|
.trim()
|
|
495
566
|
.replace(/^\.\//, '')
|
|
@@ -703,6 +774,42 @@ function planWaveScopeConformance(changedPaths, declaredFiles, branch) {
|
|
|
703
774
|
}
|
|
704
775
|
return warnings;
|
|
705
776
|
}
|
|
777
|
+
/**
|
|
778
|
+
* #3003: split git's reported deletions into declared and undeclared.
|
|
779
|
+
*
|
|
780
|
+
* EXACT match after `normalizeScopePath` — the same normalizer both other path
|
|
781
|
+
* comparisons in this file use, so a declared path and a git-reported path meet in the
|
|
782
|
+
* same shape (`a\b` and `./a/b/` both become `a/b`).
|
|
783
|
+
*
|
|
784
|
+
* Deliberately NOT `declaredScopePrefix`. That helper returns `null` for a glob-leading
|
|
785
|
+
* pattern meaning "matches everything", which is right for the ADVISORY it serves — a
|
|
786
|
+
* false alarm there costs more than a miss — and exactly wrong for a GATE, where it would
|
|
787
|
+
* let `["*.ts"]` disarm the guard. A glob here is simply a literal path that matches
|
|
788
|
+
* nothing. Prefix matching is likewise refused: `["tests"]` must not authorize deleting
|
|
789
|
+
* everything under tests/.
|
|
790
|
+
*
|
|
791
|
+
* Pure — no git, no IO. Returns the undeclared residue in the order git reported it.
|
|
792
|
+
*/
|
|
793
|
+
function partitionDeclaredDeletions(deletedPaths, declared) {
|
|
794
|
+
const allowed = new Set((Array.isArray(declared) ? declared : [])
|
|
795
|
+
.filter((p) => typeof p === 'string')
|
|
796
|
+
.map((p) => normalizeScopePath(p))
|
|
797
|
+
.filter((p) => p.length > 0));
|
|
798
|
+
const undeclared = [];
|
|
799
|
+
const seen = new Set();
|
|
800
|
+
for (const raw of Array.isArray(deletedPaths) ? deletedPaths : []) {
|
|
801
|
+
if (typeof raw !== 'string')
|
|
802
|
+
continue;
|
|
803
|
+
const normalized = normalizeScopePath(raw);
|
|
804
|
+
if (!normalized || seen.has(normalized))
|
|
805
|
+
continue;
|
|
806
|
+
seen.add(normalized);
|
|
807
|
+
if (allowed.has(normalized))
|
|
808
|
+
continue;
|
|
809
|
+
undeclared.push(normalized);
|
|
810
|
+
}
|
|
811
|
+
return undeclared;
|
|
812
|
+
}
|
|
706
813
|
function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
|
|
707
814
|
const execGit = deps.execGit || execGitDefault;
|
|
708
815
|
const entries = Array.isArray(plan?.entries) ? plan.entries : [];
|
|
@@ -762,13 +869,17 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
|
|
|
762
869
|
continue; // #2852: isolate
|
|
763
870
|
}
|
|
764
871
|
if (deletions.stdout) {
|
|
765
|
-
//
|
|
766
|
-
//
|
|
767
|
-
//
|
|
768
|
-
//
|
|
769
|
-
//
|
|
770
|
-
|
|
771
|
-
|
|
872
|
+
// #3003: a deletion the PLAN declared is authorized; anything else still blocks.
|
|
873
|
+
// Only a SUCCESSFUL check reaches here — a failed one blocked above on its own
|
|
874
|
+
// reason, so a broken check can never be filtered into a pass.
|
|
875
|
+
//
|
|
876
|
+
// The block detail carries ONLY the undeclared residue. Listing declared paths
|
|
877
|
+
// there would misdirect the operator toward paths that were fine.
|
|
878
|
+
const undeclaredDeletions = partitionDeclaredDeletions(deletions.stdout.split('\n'), entry.declared_deletions);
|
|
879
|
+
if (undeclaredDeletions.length > 0) {
|
|
880
|
+
blockEntry(result, 'branch_contains_deletions', undeclaredDeletions.join('\n'));
|
|
881
|
+
continue; // #2852: isolate
|
|
882
|
+
}
|
|
772
883
|
}
|
|
773
884
|
// #2596: advisory scope conformance — does the branch's ACTUAL committed
|
|
774
885
|
// diff stay inside the scope the plan declared? Gated on a declared scope
|
|
@@ -779,13 +890,34 @@ function executeWorktreeWaveCleanupPlan(plan, deps = {}) {
|
|
|
779
890
|
// ADVISORY ONLY. Unlike the deletions check above, a finding here does NOT
|
|
780
891
|
// call blockEntry and does NOT touch `ok` — the merge proceeds. Promotion
|
|
781
892
|
// to a hard gate is a separate, disclosed change.
|
|
782
|
-
|
|
893
|
+
// #3003: a declared deletion is in scope by construction — `git diff --name-only`
|
|
894
|
+
// includes deleted paths, so without accounting for the declaration, authorizing a
|
|
895
|
+
// deletion would immediately warn that the same path is out of declared scope.
|
|
896
|
+
//
|
|
897
|
+
// It is SUBTRACTED from the findings rather than UNIONED into the declared scope,
|
|
898
|
+
// and the difference is not cosmetic. `planWaveScopeConformance` reads its scope
|
|
899
|
+
// list with prefix-and-glob semantics, so unioning would silently hand
|
|
900
|
+
// `declared_deletions` a second, WIDER matching rule than the gate gives it:
|
|
901
|
+
// `["*.md"]` (inert at the gate) would yield a null prefix meaning "matches
|
|
902
|
+
// everything" and mute the advisory entirely, and `["src"]` would mute all of
|
|
903
|
+
// `src/`. One field with two matching rules is a trap. Subtracting keeps the
|
|
904
|
+
// field exact-match-only on every surface it touches.
|
|
905
|
+
//
|
|
906
|
+
// Gating stays on `files_modified` alone for the same reason: a plan that declares
|
|
907
|
+
// only deletions has still declared no modification scope, so the advisory stays
|
|
908
|
+
// exactly as silent as it was before this change instead of warning on every
|
|
909
|
+
// modified path.
|
|
910
|
+
const declaredFiles = Array.isArray(entry.files_modified) ? entry.files_modified : [];
|
|
911
|
+
if (declaredFiles.length > 0) {
|
|
783
912
|
const scopeDiff = execGit(['diff', '--name-only', `HEAD...${entry.branch}`], { cwd: plan.repoRoot });
|
|
784
913
|
const scopeWarnings = !gitResultOk(scopeDiff)
|
|
785
914
|
// A broken advisory must never become a gate: record that conformance
|
|
786
915
|
// is unknown rather than blocking (or, worse, silently passing).
|
|
787
916
|
? [{ code: WAVE_CLEANUP_WARNING.SCOPE_CHECK_UNAVAILABLE, branch: entry.branch, path: null }]
|
|
788
|
-
: planWaveScopeConformance((scopeDiff.stdout || '').split('\n'),
|
|
917
|
+
: planWaveScopeConformance((scopeDiff.stdout || '').split('\n'), declaredFiles, entry.branch)
|
|
918
|
+
// A path-less warning (SCOPE_CHECK_UNAVAILABLE) is never subtracted.
|
|
919
|
+
.filter((w) => w.path === null
|
|
920
|
+
|| partitionDeclaredDeletions([w.path], entry.declared_deletions).length > 0);
|
|
789
921
|
result.warnings.push(...scopeWarnings);
|
|
790
922
|
allWarnings.push(...scopeWarnings);
|
|
791
923
|
}
|
|
@@ -973,12 +1105,16 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
973
1105
|
// 2. Shared validation: run the candidate through the reader's normalizer.
|
|
974
1106
|
// If it returns null the reader would drop this entry on read — reject now.
|
|
975
1107
|
const declaredScope = parseDeclaredScopeFlag(fields.files);
|
|
1108
|
+
// #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
|
|
1109
|
+
// entry shape untouched, mirroring the --files rule directly above.
|
|
1110
|
+
const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
|
|
976
1111
|
const candidate = {
|
|
977
1112
|
agent_id: agentId,
|
|
978
1113
|
worktree_path: worktreePath,
|
|
979
1114
|
branch,
|
|
980
1115
|
expected_base: base,
|
|
981
1116
|
...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
|
|
1117
|
+
...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
|
|
982
1118
|
};
|
|
983
1119
|
const entry = normalizeCleanupManifestEntry(candidate);
|
|
984
1120
|
if (!entry) {
|
|
@@ -1072,6 +1208,11 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
1072
1208
|
if (entry.files_modified && entry.files_modified.length > 0) {
|
|
1073
1209
|
recorded.files_modified = entry.files_modified;
|
|
1074
1210
|
}
|
|
1211
|
+
// #3003: same conservative rule as --files above — a blank --deletions
|
|
1212
|
+
// leaves the entry shape untouched.
|
|
1213
|
+
if (entry.declared_deletions && entry.declared_deletions.length > 0) {
|
|
1214
|
+
recorded.declared_deletions = entry.declared_deletions;
|
|
1215
|
+
}
|
|
1075
1216
|
worktrees.push(recorded);
|
|
1076
1217
|
return {
|
|
1077
1218
|
ok: true,
|
|
@@ -1083,7 +1224,7 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
1083
1224
|
/**
|
|
1084
1225
|
* CLI command: append a validated per-agent entry to a wave cleanup manifest.
|
|
1085
1226
|
*
|
|
1086
|
-
* Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"]
|
|
1227
|
+
* Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
|
|
1087
1228
|
*
|
|
1088
1229
|
* Fails loudly (non-zero exit + recovery hint on stderr) when a field is
|
|
1089
1230
|
* missing/garbled or the manifest is absent/malformed, rather than appending an
|
|
@@ -1092,13 +1233,15 @@ function planWorktreeRecordAgent(manifestRaw, fields) {
|
|
|
1092
1233
|
function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
|
|
1093
1234
|
const flag = (name) => {
|
|
1094
1235
|
const i = args.indexOf(name);
|
|
1095
|
-
|
|
1236
|
+
if (i < 0 || i + 1 >= args.length)
|
|
1237
|
+
return '';
|
|
1238
|
+
return args[i + 1];
|
|
1096
1239
|
};
|
|
1097
1240
|
const write = deps.write || ((s) => process.stdout.write(s));
|
|
1098
1241
|
const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
|
|
1099
1242
|
const manifestPath = flag('--manifest');
|
|
1100
1243
|
if (!manifestPath) {
|
|
1101
|
-
writeErr('Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"]\n');
|
|
1244
|
+
writeErr('Usage: worktree record-agent --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]\n');
|
|
1102
1245
|
process.exitCode = 2;
|
|
1103
1246
|
return { ok: false, reason: 'usage', entry: null };
|
|
1104
1247
|
}
|
|
@@ -1121,6 +1264,7 @@ function cmdWorktreeRecordAgent(cwd, args = [], deps = {}) {
|
|
|
1121
1264
|
branch: flag('--branch'),
|
|
1122
1265
|
base: flag('--base'),
|
|
1123
1266
|
files: flag('--files'),
|
|
1267
|
+
deletions: flag('--deletions'),
|
|
1124
1268
|
});
|
|
1125
1269
|
if (!plan.ok || plan.manifest === null) {
|
|
1126
1270
|
writeErr(`[gsd] worktree.record-agent: ${plan.reason} — ${plan.hint || ''}\n`);
|
|
@@ -1165,12 +1309,16 @@ function planWorktreeCreate(fields) {
|
|
|
1165
1309
|
};
|
|
1166
1310
|
}
|
|
1167
1311
|
const declaredScope = parseDeclaredScopeFlag(fields.files);
|
|
1312
|
+
// #3003: reuse parseDeclaredScopeFlag — a blank/absent --deletions leaves the
|
|
1313
|
+
// entry shape untouched, mirroring the --files rule directly above.
|
|
1314
|
+
const declaredDeletions = parseDeclaredScopeFlag(fields.deletions);
|
|
1168
1315
|
const candidate = {
|
|
1169
1316
|
agent_id: agentId,
|
|
1170
1317
|
worktree_path: worktreePath,
|
|
1171
1318
|
branch,
|
|
1172
1319
|
expected_base: base,
|
|
1173
1320
|
...(declaredScope.length > 0 ? { files_modified: declaredScope } : {}),
|
|
1321
|
+
...(declaredDeletions.length > 0 ? { declared_deletions: declaredDeletions } : {}),
|
|
1174
1322
|
};
|
|
1175
1323
|
const entry = normalizeCleanupManifestEntry(candidate);
|
|
1176
1324
|
if (!entry) {
|
|
@@ -1298,7 +1446,7 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
|
|
|
1298
1446
|
* validated manifest entry so the worktree is immediately manageable by
|
|
1299
1447
|
* `worktree cleanup-wave` / `worktree reap-orphans`.
|
|
1300
1448
|
*
|
|
1301
|
-
* Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"]
|
|
1449
|
+
* Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]
|
|
1302
1450
|
*
|
|
1303
1451
|
* #2584 FIX 1 — ORDERING CONTRACT: every manifest read/parse/shape-validate/
|
|
1304
1452
|
* plan step runs BEFORE the git side effect (step 5). The ONLY manifest
|
|
@@ -1312,13 +1460,15 @@ function executeWorktreeCreatePlan(plan, repoRoot, deps = {}) {
|
|
|
1312
1460
|
function cmdWorktreeCreate(cwd, args = [], deps = {}) {
|
|
1313
1461
|
const flag = (name) => {
|
|
1314
1462
|
const i = args.indexOf(name);
|
|
1315
|
-
|
|
1463
|
+
if (i < 0 || i + 1 >= args.length)
|
|
1464
|
+
return '';
|
|
1465
|
+
return args[i + 1];
|
|
1316
1466
|
};
|
|
1317
1467
|
const write = deps.write || ((s) => process.stdout.write(s));
|
|
1318
1468
|
const writeErr = deps.writeErr || ((s) => process.stderr.write(s));
|
|
1319
1469
|
const manifestPath = flag('--manifest');
|
|
1320
1470
|
if (!manifestPath) {
|
|
1321
|
-
writeErr('Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"]\n');
|
|
1471
|
+
writeErr('Usage: worktree create --manifest <path> --agent-id <id> --path <worktree> --branch <branch> --base <sha> --root <dir> [--files "<space-separated paths>"] [--deletions "<space-separated paths>"]\n');
|
|
1322
1472
|
process.exitCode = 2;
|
|
1323
1473
|
return { ok: false, reason: 'usage' };
|
|
1324
1474
|
}
|
|
@@ -1384,6 +1534,7 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
|
|
|
1384
1534
|
branch: flag('--branch'),
|
|
1385
1535
|
base: flag('--base'),
|
|
1386
1536
|
files: flag('--files'),
|
|
1537
|
+
deletions: flag('--deletions'),
|
|
1387
1538
|
});
|
|
1388
1539
|
if (!plan.ok || !plan.entry) {
|
|
1389
1540
|
writeErr(`[gsd] worktree.create: ${plan.reason} — ${plan.hint || ''}\n`);
|
|
@@ -1455,6 +1606,11 @@ function cmdWorktreeCreate(cwd, args = [], deps = {}) {
|
|
|
1455
1606
|
if (Array.isArray(plan.entry.files_modified) && plan.entry.files_modified.length > 0) {
|
|
1456
1607
|
recorded.files_modified = plan.entry.files_modified;
|
|
1457
1608
|
}
|
|
1609
|
+
// #3003: same conservative rule as --files above — a blank --deletions
|
|
1610
|
+
// leaves the entry shape untouched.
|
|
1611
|
+
if (Array.isArray(plan.entry.declared_deletions) && plan.entry.declared_deletions.length > 0) {
|
|
1612
|
+
recorded.declared_deletions = plan.entry.declared_deletions;
|
|
1613
|
+
}
|
|
1458
1614
|
const dedupeKey = `${recorded.worktree_path}\0${recorded.branch}`;
|
|
1459
1615
|
const alreadyPresent = worktrees.some((existing) => {
|
|
1460
1616
|
const normalized = normalizeCleanupManifestEntry(existing);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "Canonical CONFIG_DEFAULTS for the Configuration Module. Nested shape is canonical. CJS flat projection (branching_strategy, sub_repos, etc.) is handled by consumers at the boundary. Security keys (security_enforcement, security_asvs_level, security_block_on) and post_planning_gaps live in workflow.* as their canonical location. resolve_model_ids, context_window, phase_naming are CJS-originated top-level keys included here. brave_search, firecrawl, exa_search default to false in the manifest; at runtime buildNewProjectConfig detects API keys. The plan_checker (CJS flat)
|
|
2
|
+
"_comment": "Canonical CONFIG_DEFAULTS for the Configuration Module. Nested shape is canonical. CJS flat projection (branching_strategy, sub_repos, etc.) is handled by consumers at the boundary. Security keys (security_enforcement, security_asvs_level, security_block_on) and post_planning_gaps live in workflow.* as their canonical location. resolve_model_ids, context_window, phase_naming are CJS-originated top-level keys included here. brave_search, firecrawl, exa_search default to false in the manifest; at runtime buildNewProjectConfig detects API keys. The plan_checker (CJS flat) \u2192 workflow.plan_check (canonical nested) divergence is resolved: canonical name is workflow.plan_check. _auto_chain_active is a runtime-state field included for completeness.",
|
|
3
3
|
"model_profile": "balanced",
|
|
4
4
|
"commit_docs": true,
|
|
5
5
|
"parallelization": true,
|
|
@@ -46,11 +46,13 @@
|
|
|
46
46
|
"context_coverage_gate": true,
|
|
47
47
|
"code_review": true,
|
|
48
48
|
"code_review_depth": "standard",
|
|
49
|
+
"code_review_depth_overrides": [],
|
|
49
50
|
"code_review_command": null,
|
|
50
51
|
"pattern_mapper": true,
|
|
51
52
|
"plan_bounce": false,
|
|
52
53
|
"plan_bounce_script": null,
|
|
53
54
|
"plan_bounce_passes": 2,
|
|
55
|
+
"inline_plan_threshold": 2,
|
|
54
56
|
"auto_prune_state": false,
|
|
55
57
|
"post_planning_gaps": true,
|
|
56
58
|
"security_enforcement": true,
|
|
@@ -60,6 +62,7 @@
|
|
|
60
62
|
},
|
|
61
63
|
"planning": {
|
|
62
64
|
"commit_docs": true,
|
|
65
|
+
"pr_strict": false,
|
|
63
66
|
"search_gitignored": false,
|
|
64
67
|
"sub_repos": [],
|
|
65
68
|
"granularity": "standard"
|
|
@@ -97,6 +100,9 @@
|
|
|
97
100
|
"source_grounding": true,
|
|
98
101
|
"source_grounding_authority": "grep"
|
|
99
102
|
},
|
|
103
|
+
"review": {
|
|
104
|
+
"max_prompt_tokens": null
|
|
105
|
+
},
|
|
100
106
|
"capabilities": {
|
|
101
107
|
"strict_known_registries": null,
|
|
102
108
|
"auto_update": false
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"workflow.use_worktrees",
|
|
30
30
|
"workflow.worktree_skip_hooks",
|
|
31
31
|
"workflow.code_review_command",
|
|
32
|
+
"workflow.code_review_depth_overrides",
|
|
32
33
|
"workflow.plan_bounce",
|
|
33
34
|
"workflow.plan_bounce_script",
|
|
34
35
|
"workflow.plan_bounce_passes",
|
|
@@ -43,16 +44,19 @@
|
|
|
43
44
|
"ship.pr_body_sections",
|
|
44
45
|
"git.branching_strategy",
|
|
45
46
|
"git.base_branch",
|
|
47
|
+
"git.protected_branches",
|
|
46
48
|
"git.create_tag",
|
|
47
49
|
"git.phase_branch_template",
|
|
48
50
|
"git.milestone_branch_template",
|
|
49
51
|
"git.quick_branch_template",
|
|
50
52
|
"planning.commit_docs",
|
|
53
|
+
"planning.pr_strict",
|
|
51
54
|
"planning.search_gitignored",
|
|
52
55
|
"planning.sub_repos",
|
|
53
56
|
"review.default_reviewers",
|
|
54
57
|
"review.max_prompt_tokens",
|
|
55
58
|
"review.max_prompt_tokens_per_reviewer",
|
|
59
|
+
"review.parallel_lanes",
|
|
56
60
|
"workflow.cross_ai_execution",
|
|
57
61
|
"workflow.cross_ai_command",
|
|
58
62
|
"workflow.cross_ai_timeout",
|
|
@@ -75,6 +79,7 @@
|
|
|
75
79
|
"statusline.show_context_tokens",
|
|
76
80
|
"statusline.state_format",
|
|
77
81
|
"statusline.show_git",
|
|
82
|
+
"statusline.show_state_freshness",
|
|
78
83
|
"workflow.max_discuss_passes",
|
|
79
84
|
"features.thinking_partner",
|
|
80
85
|
"context",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
[
|
|
2
|
+
{ "code": 2, "name": "HOOK_DENY", "meaning": "Hook protocol deny — the harness blocks the tool call", "owner": "hook-adapter", "authorizedBy": "ADR-3889" },
|
|
3
|
+
{ "code": 64, "name": "USAGE", "meaning": "Caller error — bad argv, unknown subcommand, missing argument", "owner": "generic", "authorizedBy": "ADR-3889" },
|
|
4
|
+
{ "code": 66, "name": "NO_INPUT", "meaning": "Ran; zero units were in scope, and that emptiness is known to be genuine", "owner": "generic", "authorizedBy": "ADR-3889" },
|
|
5
|
+
{ "code": 69, "name": "UNAVAILABLE", "meaning": "Could not run — prerequisite absent, input unreadable, scope unestablished", "owner": "generic", "authorizedBy": "ADR-3889" },
|
|
6
|
+
{ "code": 70, "name": "INTERNAL", "meaning": "Self-failure — crash, timeout, killed subprocess", "owner": "generic", "authorizedBy": "ADR-3889" },
|
|
7
|
+
{ "code": 80, "name": "DEGRADED", "meaning": "Ran to completion and is reporting a condition through its result payload rather than as a process failure", "owner": "gsd-tools", "authorizedBy": "ADR-3889 + ADR-2980" }
|
|
8
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# GENERATED FILE — DO NOT EDIT BY HAND.
|
|
3
|
+
# Source of truth: gsd-core/bin/shared/exit-codes.json. Regenerate with:
|
|
4
|
+
# node scripts/gen-exit-code-registry.cjs --write
|
|
5
|
+
#
|
|
6
|
+
# One `export EXIT_<NAME>=<code>` per gsd-core/bin/shared/exit-codes.json
|
|
7
|
+
# entry (ADR-3889 §2, #3905/#3906/#3908). POSIX sh, safe under `set -u`:
|
|
8
|
+
# sourcing this file only ever ASSIGNS variables, never reads one, so it
|
|
9
|
+
# cannot trip an unset-variable check regardless of the caller's existing
|
|
10
|
+
# environment.
|
|
11
|
+
#
|
|
12
|
+
# Usage (from a scanner under scripts/):
|
|
13
|
+
# . "$(dirname "$0")/../gsd-core/bin/shared/exit-codes.sh"
|
|
14
|
+
# exit "$EXIT_UNAVAILABLE"
|
|
15
|
+
export EXIT_HOOK_DENY=2
|
|
16
|
+
export EXIT_USAGE=64
|
|
17
|
+
export EXIT_NO_INPUT=66
|
|
18
|
+
export EXIT_UNAVAILABLE=69
|
|
19
|
+
export EXIT_INTERNAL=70
|
|
20
|
+
export EXIT_DEGRADED=80
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"openai": {
|
|
113
113
|
"opus": { "low": { "model": "gpt-5.6-terra", "reasoning_effort": "medium" }, "medium": { "model": "gpt-5.6-sol", "reasoning_effort": "high" }, "high": { "model": "gpt-5.6-sol", "reasoning_effort": "xhigh" } },
|
|
114
114
|
"sonnet": { "low": { "model": "gpt-5.6-luna", "reasoning_effort": "low" }, "medium": { "model": "gpt-5.6-terra", "reasoning_effort": "medium" }, "high": { "model": "gpt-5.6-sol", "reasoning_effort": "medium" } },
|
|
115
|
-
"haiku": { "low": { "model": "gpt-5.6-luna", "reasoning_effort": "
|
|
115
|
+
"haiku": { "low": { "model": "gpt-5.6-luna", "reasoning_effort": "low" }, "medium": { "model": "gpt-5.6-luna", "reasoning_effort": "medium" }, "high": { "model": "gpt-5.6-terra", "reasoning_effort": "medium" } }
|
|
116
116
|
},
|
|
117
117
|
"google": {
|
|
118
118
|
"opus": { "low": { "model": "gemini-2.5-flash-lite" }, "medium": { "model": "gemini-3-flash" }, "high": { "model": "gemini-3.1-pro-preview" } },
|
|
@@ -130,6 +130,12 @@
|
|
|
130
130
|
"haiku": { "low": null, "medium": null, "high": null }
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
|
+
"codexModelEffort": {
|
|
134
|
+
"_baseline": ["low", "medium", "high", "xhigh", "max"],
|
|
135
|
+
"gpt-5.6-sol": ["low", "medium", "high", "xhigh", "max", "ultra"],
|
|
136
|
+
"gpt-5.6-terra": ["low", "medium", "high", "xhigh", "max"],
|
|
137
|
+
"gpt-5.6-luna": ["low", "medium", "high", "xhigh", "max"]
|
|
138
|
+
},
|
|
133
139
|
"agents": {
|
|
134
140
|
"gsd-planner": { "golden": "opus", "balanced": "opus", "budget": "sonnet", "phaseType": "planning", "routingTier": "heavy" },
|
|
135
141
|
"gsd-roadmapper": { "golden": "opus", "balanced": "sonnet", "budget": "sonnet", "phaseType": "planning", "routingTier": "heavy" },
|
|
@@ -149,6 +155,7 @@
|
|
|
149
155
|
"gsd-ui-auditor": { "golden": "sonnet", "balanced": "sonnet", "budget": "haiku", "phaseType": "verification", "routingTier": "light" },
|
|
150
156
|
"gsd-doc-writer": { "golden": "opus", "balanced": "sonnet", "budget": "haiku", "phaseType": "execution", "routingTier": "standard" },
|
|
151
157
|
"gsd-doc-verifier": { "golden": "sonnet", "balanced": "sonnet", "budget": "haiku", "phaseType": "verification", "routingTier": "light" },
|
|
158
|
+
"gsd-dom-verifier": { "golden": "sonnet", "balanced": "sonnet", "budget": "haiku", "phaseType": "verification", "routingTier": "light" },
|
|
152
159
|
|
|
153
160
|
"gsd-advisor-researcher": { "golden": "opus", "balanced": "sonnet", "budget": "haiku", "phaseType": "research", "routingTier": "standard" },
|
|
154
161
|
"gsd-ai-researcher": { "golden": "opus", "balanced": "sonnet", "budget": "haiku", "phaseType": "research", "routingTier": "standard" },
|
|
@@ -19,8 +19,9 @@ This doc describes what IS, not what should be. Casing inconsistencies are docum
|
|
|
19
19
|
| gsd-research-synthesizer | Multi-research synthesis | `## SYNTHESIS COMPLETE`, `## SYNTHESIS BLOCKED` (unconsumed: blocked-research return — spawners detect failure via the #222 SUMMARY.md-on-disk check, no dispatch branch keys on the marker) | `gsd-core/workflows/new-milestone.md`, `gsd-core/workflows/new-project.md` | sentinel-match |
|
|
20
20
|
| gsd-debugger | Debug investigation | `## DEBUG COMPLETE`, `## ROOT CAUSE FOUND`, `## CHECKPOINT REACHED`, `## INVESTIGATION INCONCLUSIVE`, `## TDD CHECKPOINT`, `## FIX REJECTED BY GUARDRAIL` | `agents/gsd-debug-session-manager.md`, `gsd-core/workflows/diagnose-issues.md`, `gsd-core/workflows/plan-phase.md`, `agents/gsd-executor.md` | sentinel-match |
|
|
21
21
|
| gsd-debug-session-manager | Debug checkpoint loop | `## DEBUG SESSION COMPLETE`, `## CONTINUE_REQUIRED` | `gsd-core/workflows/debug.md` | sentinel-match |
|
|
22
|
-
| gsd-roadmapper | Roadmap creation/revision | `## ROADMAP CREATED`, `## ROADMAP REVISED`, `## ROADMAP BLOCKED
|
|
22
|
+
| gsd-roadmapper | Roadmap creation/revision | `## ROADMAP CREATED`, `## ROADMAP REVISED`, `## ROADMAP BLOCKED` | `gsd-core/workflows/new-milestone.md`, `gsd-core/workflows/new-project.md` | sentinel-match |
|
|
23
23
|
| gsd-ui-auditor | UI review | `## UI REVIEW COMPLETE` | `gsd-core/workflows/ui-review.md` | sentinel-match |
|
|
24
|
+
| gsd-dom-verifier | Live-DOM UAT verification | No marker (writes `{phase}-DOM-VERIFY.md` directly; the frontmatter `outcome` / `reason` scalars carry the verdict, and `could_not_look` is never conflated with `nothing_to_report`) | `{phase}-DOM-VERIFY.md` artifact, written by the `live-dom-uat` capability's `execute:wave:post` step dispatched from `gsd-core/workflows/execute-phase.md` | artifact+query |
|
|
24
25
|
| gsd-ui-checker | UI validation | `## ISSUES FOUND`, `## UI-SPEC VERIFIED` | `gsd-core/workflows/plan-phase.md`, `gsd-core/workflows/quick/steps/plan-checker-loop.md`, `gsd-core/workflows/ui-phase.md`, `gsd-core/workflows/verify-work.md`, `agents/gsd-plan-checker.md` | sentinel-match |
|
|
25
26
|
| gsd-ui-researcher | UI spec creation | `## UI-SPEC COMPLETE`, `## UI-SPEC BLOCKED` | `gsd-core/workflows/ui-phase.md` | sentinel-match |
|
|
26
27
|
| gsd-verifier | Post-execution verification | `## Verification Complete` (unconsumed: Marker Rule 2 recorded decision — intentional title-case marker; completion is detected via the artifact route, nothing matches the marker) | `*-VERIFICATION.md` artifact + `gsd_run query verification.status` in `gsd-core/workflows/verify-work.md` | artifact+query |
|
|
@@ -56,7 +57,7 @@ This doc describes what IS, not what should be. Casing inconsistencies are docum
|
|
|
56
57
|
- `structured-return` -- the agent has no way to write files (no `Write` tool) or simply doesn't; it returns parseable sections, a table, or JSON inline, and the caller reads that return text directly
|
|
57
58
|
5. Markers must appear as H2 headings (`## `) at the start of a line in the agent's final output
|
|
58
59
|
6. The `Consumed by` / `Kind` columns are machine-enforced by `check:contract-drift` (`scripts/check-contract-drift.cjs`), which cross-checks this table against what each `agents/*.md` file actually emits in-fence and what every `gsd-core/workflows/**`, `commands/**`, and `agents/**` file actually consumes. Update this table whenever an agent's return contract changes -- a stale row is a violation the check will report, not something to leave for later.
|
|
59
|
-
7. A marker entry annotated `(unconsumed: <reason>)` is emitted deliberately but matched by no workflow, command, or agent —
|
|
60
|
+
7. A marker entry annotated `(unconsumed: <reason>)` is emitted deliberately but matched by no workflow, command, or agent — a display/presentation format no orchestrator branch consumes (the `## ROADMAP DRAFT` header was the canonical case until #3797 folded its content into `## ROADMAP CREATED`). The check still verifies the marker is declared **and** emitted, and still counts it for case-collision purposes; only the consumer requirement is waived. Use it for display formats, never to silence a real orphan.
|
|
60
61
|
|
|
61
62
|
## Key Handoff Contracts
|
|
62
63
|
|
|
@@ -53,7 +53,26 @@ compound modifiers ("Resolver-only API"), and first-party-qualified services
|
|
|
53
53
|
`capabilities/ai-integration/fragments/api-coverage-plan-pre.md`.
|
|
54
54
|
2. **Seal time (`verify:pre`).** The blocking `api-coverage.verify-pre` gate
|
|
55
55
|
runs `check api-coverage.verify-pre <phase-dir>` and blocks unless a valid
|
|
56
|
-
matrix exists (or no integration is detected
|
|
56
|
+
matrix exists (or no integration is detected in a scope it could actually
|
|
57
|
+
read).
|
|
58
|
+
|
|
59
|
+
### Seal-time outcomes
|
|
60
|
+
|
|
61
|
+
| Condition | Verdict |
|
|
62
|
+
|---|---|
|
|
63
|
+
| Valid `COVERAGE.md` matrix | pass |
|
|
64
|
+
| `No external API integration: <reason>` declaration | pass (the reasoned human overrule) |
|
|
65
|
+
| Malformed / partial matrix | **block** |
|
|
66
|
+
| No matrix, integration signal found | **block** |
|
|
67
|
+
| No matrix, no signal, scope was read | pass |
|
|
68
|
+
| No matrix, **scope could not be established** | **block** — `scope_unavailable: true` (#3909) |
|
|
69
|
+
| Phase token unresolvable | **block** |
|
|
70
|
+
| Plan file exists but unreadable | **block** |
|
|
71
|
+
| No `.planning/phases` tree at all | pass — not a GSD project layout |
|
|
72
|
+
|
|
73
|
+
The last four are the fail-closed arms: the gate refuses to certify "no
|
|
74
|
+
external-API integration" from scope it did not read. A phase with real plans
|
|
75
|
+
and no API vocabulary is the fifth row, and is unaffected.
|
|
57
76
|
|
|
58
77
|
## The coverage matrix format
|
|
59
78
|
|
|
@@ -126,7 +145,10 @@ zero — the matrix is the durable subtraction record.
|
|
|
126
145
|
|
|
127
146
|
```bash
|
|
128
147
|
echo "$PHASE_SCOPE" | node gsd-core/bin/lib/api-coverage.cjs --json
|
|
129
|
-
# exit 0 = integration detected, 1 = none,
|
|
148
|
+
# exit 0 = integration detected, 1 = none (real input, examined, no signal)
|
|
149
|
+
# NO_INPUT = stdin was empty or whitespace-only (registry code — ADR-3889 Phase 3, #3907)
|
|
150
|
+
# UNAVAILABLE = stdin read failed (registry code)
|
|
151
|
+
# NO_INPUT/UNAVAILABLE emit {"skipped":true,"reason":"no_input"|"stdin_error"} — no `detected` key
|
|
130
152
|
```
|
|
131
153
|
|
|
132
154
|
The detector is a pure function (`detectApiIntegration` → `{ detected, signals,
|
|
@@ -5,7 +5,7 @@ Smart discuss is the autonomous-optimized variant of `gsd-discuss-phase`. It pro
|
|
|
5
5
|
**Inputs:** `PHASE_NUM` from execute_phase. Run init to get phase paths:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
PHASE_STATE=$(
|
|
8
|
+
PHASE_STATE=$(gsd_run query init.phase-op ${PHASE_NUM})
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Parse from JSON: `phase_dir`, `phase_slug`, `padded_phase`, `phase_name`.
|
|
@@ -94,7 +94,7 @@ Read the 3-5 most relevant files to understand existing patterns.
|
|
|
94
94
|
**Get phase details:**
|
|
95
95
|
|
|
96
96
|
```bash
|
|
97
|
-
DETAIL=$(
|
|
97
|
+
DETAIL=$(gsd_run query roadmap.get-phase ${PHASE_NUM})
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
Extract `goal`, `requirements`, `success_criteria` from the JSON response.
|
|
@@ -266,7 +266,7 @@ Write the file.
|
|
|
266
266
|
**Commit:**
|
|
267
267
|
|
|
268
268
|
```bash
|
|
269
|
-
|
|
269
|
+
gsd_run query commit "docs(${PADDED_PHASE}): smart discuss context" --files "${phase_dir}/${padded_phase}-CONTEXT.md"
|
|
270
270
|
```
|
|
271
271
|
|
|
272
272
|
Display confirmation:
|