@opengsd/gsd-core 1.14.0 → 1.16.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/.opencode/plugins/gsd-core.js +85 -5
- package/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- package/agents/gsd-code-fixer.compact.md +7 -6
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +17 -2
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +3 -3
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -12
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +15 -9
- package/agents/gsd-planner.md +15 -11
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +166 -37
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +37 -14
- package/bin/install.js +764 -287
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +7 -2
- package/commands/gsd/capture.md +9 -5
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +12 -4
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +11 -7
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +7 -2
- package/commands/gsd/quick-batch.md +21 -9
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +7 -4
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +477 -78
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/adr-parser.cjs +3 -1
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +144 -42
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +197 -222
- package/gsd-core/bin/lib/capability-validator.cjs +16 -1
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +343 -207
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config-loader.cjs +65 -4
- package/gsd-core/bin/lib/config.cjs +76 -19
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/decisions.cjs +30 -14
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +426 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +364 -132
- package/gsd-core/bin/lib/install-engine.cjs +30 -33
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +37 -6
- package/gsd-core/bin/lib/model-resolver.cjs +171 -62
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +110 -8
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +489 -88
- package/gsd-core/bin/lib/plan-document.cjs +142 -20
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +692 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
- package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
- package/gsd-core/bin/lib/roadmap.cjs +405 -88
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
- package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state-transition.cjs +39 -2
- package/gsd-core/bin/lib/state.cjs +256 -105
- package/gsd-core/bin/lib/surface.cjs +19 -2
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
- package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
- package/gsd-core/bin/lib/uat.cjs +432 -7
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1378 -274
- package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +357 -531
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +12 -3
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +37 -8
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/references/worktree-path-safety.md +321 -0
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- package/gsd-core/templates/verification-report.md +1 -1
- 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 +8 -7
- package/gsd-core/workflows/add-tests.md +4 -3
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +13 -4
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +43 -23
- package/gsd-core/workflows/check-todos.md +7 -6
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +112 -25
- package/gsd-core/workflows/code-review.md +146 -135
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +13 -8
- package/gsd-core/workflows/debug.md +32 -7
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +14 -5
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- 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 +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +96 -178
- package/gsd-core/workflows/execute-plan.md +18 -23
- package/gsd-core/workflows/explore.md +4 -4
- package/gsd-core/workflows/extract-learnings.md +4 -2
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +3 -2
- package/gsd-core/workflows/help/modes/full.compact.md +3 -3
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/import.md +4 -3
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +6 -4
- package/gsd-core/workflows/map-codebase.md +5 -4
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +11 -11
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +7 -7
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +50 -24
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +113 -13
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +62 -39
- package/gsd-core/workflows/reapply-patches.md +9 -3
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +33 -17
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +13 -13
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +4 -4
- package/gsd-core/workflows/ship.md +14 -13
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +5 -5
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +48 -11
- package/gsd-core/workflows/ui-review.md +21 -6
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +7 -7
- package/gsd-core/workflows/validate-phase.md +12 -13
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +129 -55
- package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +161 -4
- package/hooks/dist/gsd-statusline.js +85 -20
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-validate-commit.sh +63 -4
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +32 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +161 -4
- package/hooks/gsd-statusline.js +85 -20
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-validate-commit.sh +63 -4
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +22 -4
- package/scripts/build-hooks.js +15 -6
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/check-contract-drift.cjs +127 -11
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +15 -8
- package/scripts/docs-guard-registry.cjs +34 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +79 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
- package/scripts/lib/ndjson-reporter.cjs +31 -5
- package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +319 -5
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +38 -9
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/prompt-injection-scan.sh +4 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +7 -2
- package/skills/gsd-capture/SKILL.md +9 -5
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +12 -4
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +7 -2
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +21 -9
- package/skills/gsd-review/SKILL.md +7 -4
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
|
@@ -38,7 +38,7 @@ const stateContract = require("./state-contract.cjs");
|
|
|
38
38
|
const { publishStateContract } = stateContract;
|
|
39
39
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
40
40
|
const phaseIdMod = require("./phase-id.cjs");
|
|
41
|
-
const { normalizePhaseName, matchPhaseDirs,
|
|
41
|
+
const { normalizePhaseName, matchPhaseDirs, isSentinelPhaseId, isSentinelPhaseDir, buildPhaseHeadingScanRegex, PHASE_HEADING_BASELINE } = phaseIdMod;
|
|
42
42
|
const pattern_cjs_1 = require("./pattern.cjs");
|
|
43
43
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
44
44
|
const roadmapParserMod = require("./roadmap-parser.cjs");
|
|
@@ -63,7 +63,7 @@ const { extractFrontmatter } = frontmatterMod;
|
|
|
63
63
|
// divergence signal). Routed through the single write-seam composition
|
|
64
64
|
// (`syncAndPreserveStateMd`) instead, under `withStateLock` — see
|
|
65
65
|
// `cmdMilestoneComplete`'s own STATE.md-update block for the full rationale.
|
|
66
|
-
const { syncAndPreserveStateMd, withStateLock, readModifyWriteStateMd } = stateMod;
|
|
66
|
+
const { syncAndPreserveStateMd, withStateLock, readModifyWriteStateMd, assertVerificationReportsReadable } = stateMod;
|
|
67
67
|
// #2288 security: a milestone version label becomes a filesystem directory
|
|
68
68
|
// component (`milestones/<label>-phases/`) into which phase directories are
|
|
69
69
|
// MOVED. Any label used as a path segment must be a safe version token —
|
|
@@ -642,8 +642,21 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
|
|
642
642
|
// windows converge to the same value regardless of which version drove
|
|
643
643
|
// the lookup.
|
|
644
644
|
const scopedContent = sliceMilestoneWindow(roadmapContent, version) ?? extractCurrentMilestone(roadmapContent, cwd);
|
|
645
|
-
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag
|
|
646
|
-
|
|
645
|
+
// #1729: `(?:\s*\([^)\n]{0,200}\))?` tolerates a pre-colon ( ) tag, owned
|
|
646
|
+
// by buildPhaseHeadingScanRegex (phase-id.cts) so this guard also
|
|
647
|
+
// recognizes bracket-convention headings instead of hand-rolling a
|
|
648
|
+
// literal `Phase\s+`.
|
|
649
|
+
// #4984 fix: resolved ONCE and threaded into BOTH the heading scan and
|
|
650
|
+
// the disk-side matchPhaseDirs check below — the heading scan alone
|
|
651
|
+
// recognizing `[GSD.02] 01:` and extracting the bare phase-number token
|
|
652
|
+
// "01" is only half the fix. Without also passing this convention to
|
|
653
|
+
// matchPhaseDirs, its bracket-qualified match arm never fires, "01"
|
|
654
|
+
// matches no bracket directory name ("GSD.02-01-setup"), and every
|
|
655
|
+
// properly-scaffolded bracket phase reads as disk_status: 'no_directory'
|
|
656
|
+
// — turning a real bracket project's own phases into false "ROADMAP
|
|
657
|
+
// lists N unstarted phase(s)" failures on `milestone complete`.
|
|
658
|
+
const convention = resolvePhaseIdConvention(cwd);
|
|
659
|
+
const { regex: phasePattern, phaseNumGroup } = buildPhaseHeadingScanRegex(PHASE_HEADING_BASELINE.ANY_BRACKET, convention);
|
|
647
660
|
const noDirectoryPhases = [];
|
|
648
661
|
let pm;
|
|
649
662
|
const phaseDirEntries = (() => {
|
|
@@ -658,7 +671,7 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
|
|
658
671
|
}
|
|
659
672
|
})();
|
|
660
673
|
while ((pm = phasePattern.exec(scopedContent)) !== null) {
|
|
661
|
-
const phaseNum = pm[
|
|
674
|
+
const phaseNum = pm[phaseNumGroup];
|
|
662
675
|
// Phase 0 (pre-milestone) and Phase 999 (backlog) are sentinels, not
|
|
663
676
|
// real phases — they legitimately have no directory and must not block
|
|
664
677
|
// milestone completion. Mirrors the engine-wide sentinel convention
|
|
@@ -672,7 +685,7 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
|
|
672
685
|
// with a matching token exists on disk. Use the same matchPhaseDirs
|
|
673
686
|
// owner that roadmap.analyze uses to avoid false positives on decimal
|
|
674
687
|
// (2.1) and letter-suffix (12A) phase IDs. (#2528)
|
|
675
|
-
const hasDirectory = matchPhaseDirs(phaseDirEntries, normalized).matches.length > 0;
|
|
688
|
+
const hasDirectory = matchPhaseDirs(phaseDirEntries, normalized, convention).matches.length > 0;
|
|
676
689
|
if (!hasDirectory) {
|
|
677
690
|
noDirectoryPhases.push(phaseNum);
|
|
678
691
|
}
|
|
@@ -856,6 +869,15 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
|
|
856
869
|
output(dryRunResult, raw);
|
|
857
870
|
return;
|
|
858
871
|
}
|
|
872
|
+
// #5118 (no write before the error): the STATE.md update further down
|
|
873
|
+
// rebuilds the frontmatter from every phase's report and throws on a
|
|
874
|
+
// `status` outside the closed set — AFTER the archive directory, the
|
|
875
|
+
// archived ROADMAP/REQUIREMENTS copies, MILESTONES.md and the moved audit
|
|
876
|
+
// and quick-task files. Validate first, so the refusal leaves the tree
|
|
877
|
+
// untouched.
|
|
878
|
+
if (node_fs_1.default.existsSync(statePath)) {
|
|
879
|
+
assertVerificationReportsReadable((0, shell_command_projection_cjs_1.platformReadSync)(statePath) || '', cwd);
|
|
880
|
+
}
|
|
859
881
|
// Ensure archive directory exists. Deliberately placed AFTER the dry-run
|
|
860
882
|
// early return and every refusal/guard above (missingExplicitVersion, the
|
|
861
883
|
// scope refusal, the unstarted-phase guard) — #3184 review finding: this
|
|
@@ -1689,6 +1711,15 @@ function cmdQuickArchive(cwd, version, options, raw) {
|
|
|
1689
1711
|
}, raw);
|
|
1690
1712
|
return;
|
|
1691
1713
|
}
|
|
1714
|
+
// #5118 (no write before the error): the STATE.md reset below goes through
|
|
1715
|
+
// `readModifyWriteStateMd`, whose frontmatter rebuild reads every phase's
|
|
1716
|
+
// report and throws on a `status` outside the closed set — AFTER the quick
|
|
1717
|
+
// task directories have been MOVED. Validate first, so the refusal leaves the
|
|
1718
|
+
// tree untouched. Gated on there being anything to archive: a run that would
|
|
1719
|
+
// move nothing never reaches that rebuild.
|
|
1720
|
+
if (node_fs_1.default.existsSync(statePath) && listQuickTaskDirsForArchive(cwd).length > 0) {
|
|
1721
|
+
assertVerificationReportsReadable(node_fs_1.default.readFileSync(statePath, 'utf-8'), cwd);
|
|
1722
|
+
}
|
|
1692
1723
|
const quickArchiveResult = archiveQuickTaskDirectories(cwd, version);
|
|
1693
1724
|
const warnings = [];
|
|
1694
1725
|
let stateUpdated = false;
|
|
@@ -55,24 +55,24 @@ const { planningDir } = planningWorkspaceMod;
|
|
|
55
55
|
// <install>/gsd-core/bin/lib). Precedence for the gate: project config.runtime →
|
|
56
56
|
// GSD_RUNTIME env (manual/CI override + test seam) → install marker → 'claude'.
|
|
57
57
|
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
58
|
+
// Whether a runtime resolves tier aliases natively is a runtime-descriptor fact
|
|
59
|
+
// (`hostBehaviors.nativeModelAliases`, #5169) — `claude` is currently the ONLY
|
|
60
|
+
// runtime that declares it — not a hand-kept set in this module. A label that is
|
|
61
|
+
// not a registered runtime (a future runtime named by env/config) has none.
|
|
62
|
+
function hasNativeModelAliases(runtime) {
|
|
63
|
+
return (0, runtime_name_policy_cjs_1.hostBehaviorsFor)(runtime).nativeModelAliases === true;
|
|
64
|
+
}
|
|
62
65
|
// #3897 rung 2: the marker reader + its cache and test seams were promoted to
|
|
63
66
|
// the canonical owner, `runtime-slash.cts` (imported above) — this module now
|
|
64
67
|
// consumes that single implementation instead of holding its own copy. N5:
|
|
65
68
|
// behaviour and the seam contract are unchanged by the move; the re-exports
|
|
66
69
|
// below (`export =` at the bottom of this file) preserve every existing
|
|
67
70
|
// caller's `require('./model-resolver.cjs')` surface byte-for-behaviour.
|
|
68
|
-
// The runtime whose install is actually resolving
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
function resolveActiveRuntime(config) {
|
|
74
|
-
return (0, runtime_name_policy_cjs_1.resolveRuntimeNameFromCandidates)(process.env['GSD_RUNTIME'], config['runtime'], (0, runtime_slash_cjs_1.readInstallRuntimeMarker)()) || 'claude';
|
|
75
|
-
}
|
|
71
|
+
// The runtime whose install is actually resolving — one chain, owned by
|
|
72
|
+
// runtime-slash.cts's `resolveActiveRuntime` (#5169): GSD_RUNTIME env → project
|
|
73
|
+
// config.runtime → per-install .gsd-runtime marker → 'claude', canonicalized so
|
|
74
|
+
// an alias or case variant (e.g. "claude-code"/"Claude") cannot defeat the
|
|
75
|
+
// native-alias check below (#2297 review).
|
|
76
76
|
// Did the PROJECT's own config (root `.planning/config.json` or the active
|
|
77
77
|
// workstream/project override) explicitly set resolve_model_ids to "omit"?
|
|
78
78
|
// Project config takes precedence over the shared ~/.gsd/defaults.json (#2297
|
|
@@ -123,7 +123,13 @@ function resolveTierEntry({ runtime, tier, overrides }) {
|
|
|
123
123
|
*/
|
|
124
124
|
function _resolveRuntimeTier(config, tier) {
|
|
125
125
|
return resolveTierEntry({
|
|
126
|
-
|
|
126
|
+
// #4505/#4495: TIER SELECTION follows the runtime that is actually
|
|
127
|
+
// resolving, not whatever the config file happens to say. `config.runtime`
|
|
128
|
+
// is frequently absent (the runtime is normally known from GSD_RUNTIME or
|
|
129
|
+
// the per-install marker), and reading it raw made
|
|
130
|
+
// `model_profile_overrides.<runtime>.<tier>` silently inert for every
|
|
131
|
+
// install that did not also write the key by hand.
|
|
132
|
+
runtime: (0, runtime_slash_cjs_1.resolveActiveRuntime)(config),
|
|
127
133
|
tier,
|
|
128
134
|
overrides: config['model_profile_overrides'],
|
|
129
135
|
});
|
|
@@ -142,10 +148,19 @@ function _resolveRuntimeTier(config, tier) {
|
|
|
142
148
|
*
|
|
143
149
|
* This helper reads ONLY the user's override entry for the effective claude
|
|
144
150
|
* runtime and tier — never the builtin claude tier map — so an install with no
|
|
145
|
-
* override is byte-identical to before the fix.
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
151
|
+
* override is byte-identical to before the fix.
|
|
152
|
+
*
|
|
153
|
+
* #4505 CHANGED how the runtime reaches here. #4192 originally passed
|
|
154
|
+
* `config['runtime']` and recorded that the value policy "must key off the
|
|
155
|
+
* config the operator wrote, NOT resolveActiveRuntime". That reading turned out
|
|
156
|
+
* to defeat #4192's own stated principle — that an explicit pin must not be
|
|
157
|
+
* silently UNPINNED. With `config.runtime` absent and GSD_RUNTIME=opencode, the
|
|
158
|
+
* config-keyed read treated the session as claude and collapsed an explicit
|
|
159
|
+
* `claude-opus-4-8` pin to the bare alias `opus`, which is a Claude-only token
|
|
160
|
+
* the actual runtime cannot spawn. The runtime is now the ACTIVE one, so the
|
|
161
|
+
* claude value policy applies exactly when claude is what is running. No test
|
|
162
|
+
* pinned the previous behaviour; the ones covering #4192's pins and the
|
|
163
|
+
* alias-native posture all still pass.
|
|
149
164
|
*
|
|
150
165
|
* Value policy mirrors the model_overrides path (#2041/#4192): an override
|
|
151
166
|
* value that maps to a current tier alias collapses to that alias
|
|
@@ -155,10 +170,12 @@ function _resolveRuntimeTier(config, tier) {
|
|
|
155
170
|
* Malformed entries (no usable `model` string) return null so the caller falls
|
|
156
171
|
* through to normal alias resolution (ADR-443 D1: invalid values fall through).
|
|
157
172
|
*/
|
|
158
|
-
function resolveClaudeTierOverrideModel(
|
|
173
|
+
function resolveClaudeTierOverrideModel(
|
|
174
|
+
// The ACTIVE runtime (#4505), not the raw config key — see docblock.
|
|
175
|
+
activeRuntime, tier, overrides) {
|
|
159
176
|
if (!tier || tier === 'inherit')
|
|
160
177
|
return null;
|
|
161
|
-
const effectiveRuntime =
|
|
178
|
+
const effectiveRuntime = activeRuntime || 'claude';
|
|
162
179
|
if (effectiveRuntime !== 'claude')
|
|
163
180
|
return null; // non-claude runtimes resolve at step 3
|
|
164
181
|
const overridesMap = overrides;
|
|
@@ -264,13 +281,18 @@ function _resetModelOverrideWarningCacheForTests() {
|
|
|
264
281
|
* `Object.hasOwn` lookup defeats `__proto__`/`constructor` lookups on the plain
|
|
265
282
|
* object literal so those reserved keys cannot return a truthy non-string.
|
|
266
283
|
*/
|
|
267
|
-
function mapClaudeOverrideForRuntime(override,
|
|
284
|
+
function mapClaudeOverrideForRuntime(override,
|
|
285
|
+
// The ACTIVE runtime (#4505). Previously the raw `config['runtime']`, which
|
|
286
|
+
// made an explicit claude pin collapse to a bare alias whenever the runtime
|
|
287
|
+
// was declared via GSD_RUNTIME or the install marker rather than the config —
|
|
288
|
+
// handing a Claude-only token to a runtime that cannot spawn it.
|
|
289
|
+
activeRuntime, agentType) {
|
|
268
290
|
// Defensive: model_overrides is typed Record<string,string> but a malformed
|
|
269
291
|
// config could surface a non-string; pass through verbatim (preserving the
|
|
270
292
|
// pre-fix no-crash behaviour) and let the downstream Agent tool reject it.
|
|
271
293
|
if (typeof override !== 'string')
|
|
272
294
|
return override;
|
|
273
|
-
const onClaude = !
|
|
295
|
+
const onClaude = !activeRuntime || activeRuntime === 'claude';
|
|
274
296
|
if (!onClaude)
|
|
275
297
|
return override;
|
|
276
298
|
// Object.hasOwn guards against __proto__/constructor returning a truthy
|
|
@@ -480,7 +502,7 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
480
502
|
? modelOverrides[agentType]
|
|
481
503
|
: undefined;
|
|
482
504
|
if (override) {
|
|
483
|
-
const mapped = mapClaudeOverrideForRuntime(override, config
|
|
505
|
+
const mapped = mapClaudeOverrideForRuntime(override, (0, runtime_slash_cjs_1.resolveActiveRuntime)(config), agentType);
|
|
484
506
|
if (mapped !== null)
|
|
485
507
|
return mapped;
|
|
486
508
|
// Unmappable Claude ID — fall through to tier resolution (matches model_policy).
|
|
@@ -497,10 +519,19 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
497
519
|
const agentModels = Object.hasOwn(modelProfilesMapForModel, agentType) ? modelProfilesMapForModel[agentType] : undefined;
|
|
498
520
|
const tier = computeProfileTier(config, agentType);
|
|
499
521
|
// 2.5. model_policy preset (#49, #1133)
|
|
522
|
+
// `configRuntime` is retained ONLY as the EXPLICIT-OPT-IN signal for step 3's
|
|
523
|
+
// precedence over the omit gate (see the note there). Every actual runtime
|
|
524
|
+
// question — which tier map to read, which value policy applies — now uses
|
|
525
|
+
// the active runtime (#4505).
|
|
500
526
|
const configRuntime = config['runtime'];
|
|
527
|
+
// #4505/#4495: GSD_RUNTIME -> config.runtime -> per-install marker -> 'claude'.
|
|
528
|
+
// Never undefined, so the "no runtime declared anywhere" case still resolves
|
|
529
|
+
// 'claude' and step 3's deliberate claude skip (#1156/#2297/#4192) is
|
|
530
|
+
// unchanged for every existing install.
|
|
531
|
+
const activeRuntime = (0, runtime_slash_cjs_1.resolveActiveRuntime)(config);
|
|
501
532
|
if (tier && tier !== 'inherit') {
|
|
502
|
-
const onClaude =
|
|
503
|
-
const effectiveRuntime =
|
|
533
|
+
const onClaude = activeRuntime === 'claude';
|
|
534
|
+
const effectiveRuntime = activeRuntime;
|
|
504
535
|
const mergedPolicy = config['model_policy']
|
|
505
536
|
? { ...config['model_policy'], runtime: effectiveRuntime }
|
|
506
537
|
: null;
|
|
@@ -525,8 +556,49 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
525
556
|
warnModelPolicyUnmappable(agentType, policyModel, tier);
|
|
526
557
|
}
|
|
527
558
|
}
|
|
528
|
-
// 3
|
|
529
|
-
|
|
559
|
+
// #4505: the omit DECISION is computed here, ahead of step 3, though the
|
|
560
|
+
// return still happens at step 4 below.
|
|
561
|
+
//
|
|
562
|
+
// Step 3 was previously unreachable unless the operator had written `runtime`
|
|
563
|
+
// into the config. Keying it off the ACTIVE runtime — the #4495 fix — makes it
|
|
564
|
+
// reachable for env- and marker-declared runtimes too, which newly exposes an
|
|
565
|
+
// ordering the corpus already decided, in two places that only coexisted
|
|
566
|
+
// because step 3 could not fire:
|
|
567
|
+
//
|
|
568
|
+
// #2517 `runtime:"codex"` + resolve_model_ids:"omit" -> the codex tier
|
|
569
|
+
// model. "Explicit non-Claude opt-in wins" — the operator naming a
|
|
570
|
+
// runtime in the project config outranks an omit.
|
|
571
|
+
// #4717 (user-sanctioned decision a — supersedes #2297 acceptance #4):
|
|
572
|
+
// a DETECTED runtime now constitutes that opt-in too. The identity
|
|
573
|
+
// fill in config-loader materializes GSD_RUNTIME / the per-install
|
|
574
|
+
// marker into `config.runtime` when it is empty, so a genuinely
|
|
575
|
+
// installed non-Claude runtime resolves its own tier map instead of
|
|
576
|
+
// the omit's "". The shared "omit" remains a Claude protection:
|
|
577
|
+
// marker/env = claude still ignores it (native aliases), and
|
|
578
|
+
// garbage runtime values still fail safe to "" (guard below).
|
|
579
|
+
//
|
|
580
|
+
// So the opt-in signal is the `runtime` KEY — written by the operator or
|
|
581
|
+
// materialized by the #4717 fill: step 3 reads the active runtime's tier
|
|
582
|
+
// map, but only outranks the omit gate when that key canonicalizes to a
|
|
583
|
+
// recognised non-Claude runtime.
|
|
584
|
+
const omitApplies = config['resolve_model_ids'] === 'omit'
|
|
585
|
+
&& (projectExplicitlySetsOmit(cwd) || !hasNativeModelAliases(activeRuntime));
|
|
586
|
+
// CANONICALIZED, not the raw field. Comparing the raw value against the literal
|
|
587
|
+
// 'claude' made every spelling that is not exactly that string count as a
|
|
588
|
+
// non-Claude opt-in and outrank the omit gate: `runtime:"Claude"`,
|
|
589
|
+
// `runtime:"claude-code"` and even `runtime:5` each emitted a model id where
|
|
590
|
+
// origin/next returned "". That is the #2297 acceptance-#4 case this very
|
|
591
|
+
// block claims to preserve, failing OPEN. (Security review of #4505.)
|
|
592
|
+
//
|
|
593
|
+
// null covers both "not a string" and "not a runtime we recognise", and both
|
|
594
|
+
// must read as NOT an opt-in: an unrecognised value is not evidence the
|
|
595
|
+
// operator deliberately chose a non-Claude runtime, so it must not buy an
|
|
596
|
+
// escalation past an explicit omit.
|
|
597
|
+
const configRuntimeCanonical = (0, runtime_name_policy_cjs_1.canonicalizeRuntimeName)(configRuntime);
|
|
598
|
+
const explicitNonClaudeOptIn = configRuntimeCanonical !== null && configRuntimeCanonical !== 'claude';
|
|
599
|
+
// 3. Runtime-aware resolution (#2517), keyed off the ACTIVE runtime (#4505).
|
|
600
|
+
if (activeRuntime !== 'claude' && tier && tier !== 'inherit'
|
|
601
|
+
&& (explicitNonClaudeOptIn || !omitApplies)) {
|
|
530
602
|
const entry = _resolveRuntimeTier(config, tier);
|
|
531
603
|
if (entry?.model)
|
|
532
604
|
return entry.model;
|
|
@@ -541,8 +613,7 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
541
613
|
// NOTE: a non-Claude runtime that HAS a populated runtime-tier map already
|
|
542
614
|
// returned its own model id at step 3 above, before this gate — for those the
|
|
543
615
|
// explicit-project-omit honoring here is moot (step 3 wins, by #2517 design).
|
|
544
|
-
if (
|
|
545
|
-
&& (projectExplicitlySetsOmit(cwd) || !RUNTIMES_WITH_NATIVE_ALIASES.has(resolveActiveRuntime(config)))) {
|
|
616
|
+
if (omitApplies) {
|
|
546
617
|
return '';
|
|
547
618
|
}
|
|
548
619
|
// 4.5. Claude-runtime tier override (#4192 Finding 1). Sits AFTER the omit
|
|
@@ -554,10 +625,30 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
554
625
|
// `model_profile_overrides.claude.<tier>` entry for this tier — see
|
|
555
626
|
// resolveClaudeTierOverrideModel for why the builtin map stays out.
|
|
556
627
|
if (tier && tier !== 'inherit') {
|
|
557
|
-
const claudeOverrideModel = resolveClaudeTierOverrideModel(
|
|
628
|
+
const claudeOverrideModel = resolveClaudeTierOverrideModel(activeRuntime, tier, config['model_profile_overrides']);
|
|
558
629
|
if (claudeOverrideModel !== null)
|
|
559
630
|
return claudeOverrideModel;
|
|
560
631
|
}
|
|
632
|
+
// 4.75 dynamic_routing.tier_models (#4505 / #3024).
|
|
633
|
+
//
|
|
634
|
+
// Position is the documented composition, not a convenience:
|
|
635
|
+
// docs/features/dynamic-routing-with-failure-tier-escalation.md —
|
|
636
|
+
// "model_overrides always wins; dynamic_routing.tier_models[<tier>] resolves
|
|
637
|
+
// above models.<phase_type> and model_profile."
|
|
638
|
+
// So it sits BELOW model_overrides (step 1), the model_policy preset (2.5),
|
|
639
|
+
// the runtime tier map (3), the resolve_model_ids:"omit" gate (4) and the
|
|
640
|
+
// claude tier override (4.5) — and ABOVE the profile lookup (5).
|
|
641
|
+
//
|
|
642
|
+
// An earlier cut of this fix routed every call site through resolveModelForTier
|
|
643
|
+
// instead, which returns the tier model directly and therefore skipped steps 3,
|
|
644
|
+
// 4 and 4.5 entirely: with `resolve_model_ids:"omit"` and a non-Claude runtime
|
|
645
|
+
// it handed out a model id where the gate had returned "". Putting the step
|
|
646
|
+
// here keeps every higher-precedence layer reachable.
|
|
647
|
+
if (tier !== 'inherit') {
|
|
648
|
+
const routed = dynamicRoutingModel(config, agentType, 0);
|
|
649
|
+
if (routed !== null)
|
|
650
|
+
return routed;
|
|
651
|
+
}
|
|
561
652
|
// 5. Profile lookup (Claude-native default).
|
|
562
653
|
if (!agentModels) {
|
|
563
654
|
return profile === 'quality' ? 'opus'
|
|
@@ -614,6 +705,50 @@ function assertValidGranularityOverride(override, fail) {
|
|
|
614
705
|
fail(`invalid granularity '${override}' (valid: ${[...VALID_GRANULARITIES].join(', ')})`);
|
|
615
706
|
}
|
|
616
707
|
}
|
|
708
|
+
/**
|
|
709
|
+
* #4505 — the ONE implementation of `dynamic_routing.tier_models` lookup.
|
|
710
|
+
*
|
|
711
|
+
* Returns the configured model for this agent's routing tier at `attempt`, or
|
|
712
|
+
* null when dynamic routing does not apply (disabled, absent, no tier table, an
|
|
713
|
+
* agent with no default routing tier, or no entry for the tier). Both entry
|
|
714
|
+
* points call it, so the first-spawn value and the escalated value can never
|
|
715
|
+
* drift apart — the "Generative Fix Divergence" this repo names by name.
|
|
716
|
+
*
|
|
717
|
+
* `attempt` 0 means "no escalation yet", which is the documented FIRST-SPAWN
|
|
718
|
+
* case, NOT "skip dynamic routing":
|
|
719
|
+
* docs/features/dynamic-routing-with-failure-tier-escalation.md —
|
|
720
|
+
* "enabled: true — the resolver picks tier_models[default_tier] for the first
|
|
721
|
+
* spawn and escalates one tier up on orchestrator-detected soft failure."
|
|
722
|
+
*/
|
|
723
|
+
function dynamicRoutingModel(config, agentType, attempt) {
|
|
724
|
+
const dr = config['dynamic_routing'];
|
|
725
|
+
if (!dr || typeof dr !== 'object' || dr['enabled'] !== true)
|
|
726
|
+
return null;
|
|
727
|
+
const tierModels = dr['tier_models'];
|
|
728
|
+
if (!tierModels || typeof tierModels !== 'object')
|
|
729
|
+
return null;
|
|
730
|
+
const defaultTier = (AGENT_DEFAULT_TIERS)[agentType];
|
|
731
|
+
if (!defaultTier || !(VALID_AGENT_TIERS).has(defaultTier))
|
|
732
|
+
return null;
|
|
733
|
+
const maxEscalations = Number.isInteger(dr['max_escalations']) && dr['max_escalations'] >= 0
|
|
734
|
+
? dr['max_escalations']
|
|
735
|
+
: 1;
|
|
736
|
+
const escalationEnabled = dr['escalate_on_failure'] !== false;
|
|
737
|
+
const effectiveAttempt = escalationEnabled ? Math.min(attempt, maxEscalations) : 0;
|
|
738
|
+
let tier = defaultTier;
|
|
739
|
+
for (let i = 0; i < effectiveAttempt; i += 1) {
|
|
740
|
+
const next = (nextTier)(tier);
|
|
741
|
+
if (!next || next === tier)
|
|
742
|
+
break;
|
|
743
|
+
tier = next;
|
|
744
|
+
}
|
|
745
|
+
// Own-property guard: `tier_models` is a config-supplied plain object, so a
|
|
746
|
+
// prototype-chain key must not resolve an inherited member.
|
|
747
|
+
const alias = Object.hasOwn(tierModels, tier) ? tierModels[tier] : undefined;
|
|
748
|
+
if (typeof alias !== 'string' || alias.length === 0)
|
|
749
|
+
return null;
|
|
750
|
+
return alias;
|
|
751
|
+
}
|
|
617
752
|
/**
|
|
618
753
|
* #3024 — Resolve a model for a specific dynamic-routing attempt.
|
|
619
754
|
*/
|
|
@@ -629,45 +764,19 @@ function resolveModelForTier(cwd, agentType, attempt) {
|
|
|
629
764
|
? modelOverrides[agentType]
|
|
630
765
|
: undefined;
|
|
631
766
|
if (override) {
|
|
632
|
-
const mapped = mapClaudeOverrideForRuntime(override, config
|
|
767
|
+
const mapped = mapClaudeOverrideForRuntime(override, (0, runtime_slash_cjs_1.resolveActiveRuntime)(config), agentType);
|
|
633
768
|
if (mapped !== null)
|
|
634
769
|
return mapped;
|
|
635
770
|
// Unmappable Claude ID — fall through to dynamic_routing / model_policy resolution.
|
|
636
771
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
}
|
|
640
|
-
const dr = config['dynamic_routing'];
|
|
641
|
-
if (!dr || typeof dr !== 'object' || dr['enabled'] !== true) {
|
|
642
|
-
return resolveModelInternal(cwd, agentType);
|
|
643
|
-
}
|
|
644
|
-
const tierModels = dr['tier_models'];
|
|
645
|
-
if (!tierModels || typeof tierModels !== 'object') {
|
|
646
|
-
return resolveModelInternal(cwd, agentType);
|
|
647
|
-
}
|
|
648
|
-
const defaultTier = (AGENT_DEFAULT_TIERS)[agentType];
|
|
649
|
-
if (!defaultTier || !(VALID_AGENT_TIERS).has(defaultTier)) {
|
|
650
|
-
return resolveModelInternal(cwd, agentType);
|
|
651
|
-
}
|
|
652
|
-
const maxEscalations = Number.isInteger(dr['max_escalations']) && dr['max_escalations'] >= 0
|
|
653
|
-
? dr['max_escalations']
|
|
654
|
-
: 1;
|
|
655
|
-
const escalationEnabled = dr['escalate_on_failure'] !== false;
|
|
656
|
-
const effectiveAttempt = escalationEnabled
|
|
657
|
-
? Math.min(attemptN, maxEscalations)
|
|
658
|
-
: 0;
|
|
659
|
-
let tier = defaultTier;
|
|
660
|
-
for (let i = 0; i < effectiveAttempt; i += 1) {
|
|
661
|
-
const next = (nextTier)(tier);
|
|
662
|
-
if (!next || next === tier)
|
|
663
|
-
break;
|
|
664
|
-
tier = next;
|
|
665
|
-
}
|
|
666
|
-
const alias = tierModels[tier];
|
|
667
|
-
if (typeof alias !== 'string' || alias.length === 0) {
|
|
772
|
+
// #4505: same active-runtime rule as resolveModelInternal step 3.
|
|
773
|
+
if (config['model_policy'] && (0, runtime_slash_cjs_1.resolveActiveRuntime)(config) !== 'claude') {
|
|
668
774
|
return resolveModelInternal(cwd, agentType);
|
|
669
775
|
}
|
|
670
|
-
|
|
776
|
+
const alias = dynamicRoutingModel(config, agentType, attemptN);
|
|
777
|
+
if (alias !== null)
|
|
778
|
+
return alias;
|
|
779
|
+
return resolveModelInternal(cwd, agentType);
|
|
671
780
|
}
|
|
672
781
|
/**
|
|
673
782
|
* Keep only usable model ids: non-empty strings. A malformed config can put
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* (RFC 4122); invalid values are silently coerced to undefined.
|
|
17
17
|
* command: string — the dispatched verb
|
|
18
18
|
* args?: unknown — only present when includeArgs === true
|
|
19
|
-
* result: { kind: 'ok' | 'UnknownCommand' | 'InvalidArgs' | 'HandlerRefusal' | 'HandlerFailure', ...payload }
|
|
19
|
+
* result: { kind: 'ok' | 'UnknownCommand' | 'InvalidArgs' | 'HandlerRefusal' | 'HandlerFailure' | 'VerificationStatusInvalid', ...payload }
|
|
20
20
|
* timestamp: string — ISO 8601
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
* No-op logger (createNoOpLogger):
|
|
17
17
|
* Silent on all events. Used as the Hub default when no logger is injected.
|
|
18
18
|
*
|
|
19
|
+
* Live-seam gate (resolveDispatchLogger, #4975):
|
|
20
|
+
* The one opt-in decision both live createHub() seams share. Resolves
|
|
21
|
+
* `audit.enabled` for the seam's cwd and returns the default logger, or
|
|
22
|
+
* undefined (inject nothing) when observability is off.
|
|
23
|
+
*
|
|
19
24
|
* ADR-457 build-at-publish: the hand-written bin/lib/observability/logger.cjs
|
|
20
25
|
* collapsed to a TypeScript source of truth. Behaviour is preserved
|
|
21
26
|
* byte-for-behaviour from the prior hand-written .cjs; only types are added.
|
|
@@ -26,6 +31,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
31
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
27
32
|
const node_path_1 = __importDefault(require("node:path"));
|
|
28
33
|
const redaction_cjs_1 = require("./redaction.cjs");
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
35
|
+
const planningWorkspace = require("../planning-workspace.cjs");
|
|
36
|
+
const { readScopedConfigValue } = planningWorkspace;
|
|
29
37
|
const AUDIT_FILE_NAME = '.gsd-trace.jsonl';
|
|
30
38
|
const PLANNING_DIR = '.planning';
|
|
31
39
|
// ─── helpers ─────────────────────────────────────────────────────────────────
|
|
@@ -47,6 +55,8 @@ function _safeStringify(value) {
|
|
|
47
55
|
* inject nothing (the Hub stays byte-for-byte silent, preserving the default
|
|
48
56
|
* dispatch output contract, incl. --json-errors); when on, the caller injects
|
|
49
57
|
* createDefaultLogger and gets the stderr-on-error line + opt-in file audit.
|
|
58
|
+
* The live seams reach it through resolveDispatchLogger, which supplies the
|
|
59
|
+
* project config — called bare, only the env var is seen (#4975).
|
|
50
60
|
*/
|
|
51
61
|
function _isAuditEnabled(config) {
|
|
52
62
|
if (process.env['GSD_AUDIT'] === '1')
|
|
@@ -148,4 +158,39 @@ function createDefaultLogger({ cwd = process.cwd(), config } = {}) {
|
|
|
148
158
|
},
|
|
149
159
|
};
|
|
150
160
|
}
|
|
151
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Resolve `audit.enabled` for `cwd` as the value `config-get audit.enabled`
|
|
163
|
+
* reports, through planning-workspace's readScopedConfigValue — the one
|
|
164
|
+
* scope-aware ladder worktreesOptedOut (#3972) reads too, so the two gates
|
|
165
|
+
* can never resolve the same config differently. Strict `=== true`, never
|
|
166
|
+
* coerced.
|
|
167
|
+
*
|
|
168
|
+
* Direct file reads, deliberately NOT loadConfig: this runs on every live
|
|
169
|
+
* dispatch, and loadConfig can rewrite config.json, spawn git, scan the
|
|
170
|
+
* capability registry, and print warnings — none of which a dispatch that
|
|
171
|
+
* never opted in may do (the default dispatch output is a stable contract,
|
|
172
|
+
* ADR-2619). Never throws. An unreadable or unparseable config file sets
|
|
173
|
+
* nothing, so the ladder moves on: under GSD_WORKSTREAM a broken workstream
|
|
174
|
+
* config inherits the root's `audit.enabled` (where config-get fails with
|
|
175
|
+
* CONFIG_PARSE_FAILED); otherwise the GSD_AUDIT env var alone decides.
|
|
176
|
+
*/
|
|
177
|
+
function _readAuditConfig(cwd) {
|
|
178
|
+
const { present, value } = readScopedConfigValue(cwd, ['audit', 'enabled']);
|
|
179
|
+
return { audit: { enabled: present && value === true } };
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The DispatchLogger a live createHub() seam injects (#4975). Either
|
|
183
|
+
* GSD_AUDIT=1 or `audit.enabled: true` in the project config turns the opt-in
|
|
184
|
+
* audit trail (and the structured stderr line on error) on; neither turns the
|
|
185
|
+
* other off. When observability is off this returns undefined so the Hub keeps
|
|
186
|
+
* its no-op fallback and the default dispatch output — including the
|
|
187
|
+
* --json-errors envelope — stays byte-for-byte unchanged (#2620).
|
|
188
|
+
*
|
|
189
|
+
* `cwd` defaults exactly as createDefaultLogger's does, so the config that
|
|
190
|
+
* decides and the directory that receives the trail are always the same.
|
|
191
|
+
*/
|
|
192
|
+
function resolveDispatchLogger(cwd = process.cwd()) {
|
|
193
|
+
const config = _readAuditConfig(cwd);
|
|
194
|
+
return _isAuditEnabled(config) ? createDefaultLogger({ cwd, config }) : undefined;
|
|
195
|
+
}
|
|
196
|
+
module.exports = { createDefaultLogger, createNoOpLogger, isAuditEnabled: _isAuditEnabled, resolveDispatchLogger };
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.MAX_USER_PATTERN_LEN = void 0;
|
|
46
46
|
exports.escapeRegex = escapeRegex;
|
|
47
|
+
exports.escapeEre = escapeEre;
|
|
47
48
|
exports.literalPattern = literalPattern;
|
|
48
49
|
exports.compileUserPattern = compileUserPattern;
|
|
49
50
|
// re2js is vendored, not an npm dependency at runtime: gsd-core/bin/** is
|
|
@@ -66,6 +67,15 @@ const escapeMetachars = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
|
66
67
|
function escapeRegex(value) {
|
|
67
68
|
return (escapeBuiltin ?? escapeMetachars)(value);
|
|
68
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Escape `value` for a POSIX extended regular expression (e.g. `git log --extended-regexp
|
|
72
|
+
* --grep=…`). Always the plain backslash-escape of every ERE metacharacter, never
|
|
73
|
+
* `RegExp.escape`: that built-in writes a leading digit as `\x31`, which ERE does not read as a
|
|
74
|
+
* digit. #5139 (a plan id interpolated into a git `--grep` pattern).
|
|
75
|
+
*/
|
|
76
|
+
function escapeEre(value) {
|
|
77
|
+
return escapeMetachars(value);
|
|
78
|
+
}
|
|
69
79
|
function literalPattern(value, flags) {
|
|
70
80
|
return new RegExp(escapeRegex(value), flags);
|
|
71
81
|
}
|
|
@@ -22,10 +22,12 @@ const commandRoutingHub = require("./command-routing-hub.cjs");
|
|
|
22
22
|
const { createHub, ERROR_KINDS, makeInvalidArgs } = commandRoutingHub;
|
|
23
23
|
// #2620 (ADR-0174 §6): inject the reference DispatchLogger on the live phase
|
|
24
24
|
// dispatch path, but only when observability is opt-in enabled; otherwise the
|
|
25
|
-
// Hub stays byte-for-byte silent via its no-op fallback.
|
|
25
|
+
// Hub stays byte-for-byte silent via its no-op fallback. #4975: the opt-in is
|
|
26
|
+
// GSD_AUDIT=1 or `audit.enabled` in the project config — resolveDispatchLogger
|
|
27
|
+
// owns that whole decision for every live seam.
|
|
26
28
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
27
29
|
const observabilityLogger = require("./observability/logger.cjs");
|
|
28
|
-
const {
|
|
30
|
+
const { resolveDispatchLogger } = observabilityLogger;
|
|
29
31
|
// ─── Implementation ───────────────────────────────────────────────────────────
|
|
30
32
|
function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
31
33
|
// ── Unsupported subcommands ─────────────────────────────────────────────────
|
|
@@ -186,11 +188,16 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
186
188
|
},
|
|
187
189
|
'uat-passed': (_ctx) => {
|
|
188
190
|
let requireVerification = false;
|
|
191
|
+
let uatOnly = false;
|
|
189
192
|
const positional = [];
|
|
190
193
|
for (const token of args.slice(2)) {
|
|
191
194
|
if (token === '--require-verification') {
|
|
192
195
|
requireVerification = true;
|
|
193
196
|
}
|
|
197
|
+
else if (token === '--uat-only') {
|
|
198
|
+
// #4663: evaluate UAT rows only (verification-status blockers skipped).
|
|
199
|
+
uatOnly = true;
|
|
200
|
+
}
|
|
194
201
|
else if (token === '--raw') {
|
|
195
202
|
// --raw is handled by the outer CLI layer; accepted here silently
|
|
196
203
|
}
|
|
@@ -201,7 +208,10 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
201
208
|
positional.push(token);
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
|
-
|
|
211
|
+
if (requireVerification && uatOnly) {
|
|
212
|
+
return makeInvalidArgs('--uat-only', '--uat-only and --require-verification are mutually exclusive');
|
|
213
|
+
}
|
|
214
|
+
phase.cmdPhaseUatPassed(cwd, positional[0], raw, { policy: { requireVerification, uatOnly } });
|
|
205
215
|
return { ok: true, data: null };
|
|
206
216
|
},
|
|
207
217
|
// #1437 — list plan files for a phase
|
|
@@ -250,8 +260,8 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
250
260
|
// #175: Hub is CJS-only — no mode param, no sdkLoader.
|
|
251
261
|
// #2620: wire the reference logger (ADR-0174 §6) only when observability is
|
|
252
262
|
// opt-in enabled; otherwise leave it unset so the Hub stays byte-for-byte
|
|
253
|
-
// silent via its no-op fallback.
|
|
254
|
-
const hub = createHub({ cjsRegistry, manifest, logger:
|
|
263
|
+
// silent via its no-op fallback. #4975: GSD_AUDIT=1 or `audit.enabled`.
|
|
264
|
+
const hub = createHub({ cjsRegistry, manifest, logger: resolveDispatchLogger(cwd) });
|
|
255
265
|
// ── Dispatch ────────────────────────────────────────────────────────────────
|
|
256
266
|
const result = hub.dispatch({
|
|
257
267
|
family: 'phase',
|
|
@@ -274,6 +284,11 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
274
284
|
error(result.reason);
|
|
275
285
|
return;
|
|
276
286
|
}
|
|
287
|
+
if (result.kind === ERROR_KINDS.VerificationStatusInvalid) {
|
|
288
|
+
// #5118: typed reason survives to the CLI surface
|
|
289
|
+
error(result.message, result.reason);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
277
292
|
// HandlerFailure: message field
|
|
278
293
|
error(result.message);
|
|
279
294
|
return;
|
|
@@ -47,6 +47,7 @@ exports.parseCalibrationDocument = parseCalibrationDocument;
|
|
|
47
47
|
exports.renderCalibrationDocument = renderCalibrationDocument;
|
|
48
48
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- prompt-budget.cjs is an export= CommonJS module
|
|
49
49
|
const promptBudget = require("./prompt-budget.cjs");
|
|
50
|
+
const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
|
|
50
51
|
const { estimateTokens } = promptBudget;
|
|
51
52
|
/**
|
|
52
53
|
* Assert that a bare number is an UNCORRECTED projection.
|
|
@@ -239,11 +240,11 @@ function applyCalibration(rawTokens, factor) {
|
|
|
239
240
|
function extractFrontmatterBlock(text, key) {
|
|
240
241
|
if (typeof text !== 'string')
|
|
241
242
|
return null;
|
|
242
|
-
//
|
|
243
|
-
const
|
|
244
|
-
if (
|
|
243
|
+
// The block is the one the one fence owner finds (`locateFrontmatterFence`).
|
|
244
|
+
const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(text);
|
|
245
|
+
if (!fence?.closed)
|
|
245
246
|
return null;
|
|
246
|
-
const lines =
|
|
247
|
+
const lines = text.slice(fence.openEnd, fence.bodyEnd).split(/\r?\n/);
|
|
247
248
|
const startIdx = lines.findIndex((l) => l === `${key}:` || l.startsWith(`${key}:`));
|
|
248
249
|
if (startIdx === -1)
|
|
249
250
|
return null;
|