@opengsd/gsd-core 1.13.0 → 1.15.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/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-advisor-researcher.compact.md +85 -0
- package/agents/gsd-ai-researcher.compact.md +96 -0
- package/agents/gsd-assumptions-analyzer.compact.md +81 -0
- package/agents/gsd-code-fixer.compact.md +459 -0
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +269 -0
- package/agents/gsd-code-reviewer.md +15 -3
- package/agents/gsd-codebase-mapper.compact.md +760 -0
- package/agents/gsd-debug-session-manager.compact.md +360 -0
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-doc-classifier.compact.md +192 -0
- package/agents/gsd-doc-synthesizer.compact.md +200 -0
- package/agents/gsd-doc-verifier.compact.md +143 -0
- package/agents/gsd-doc-writer.compact.md +440 -0
- package/agents/gsd-dom-verifier.compact.md +138 -0
- package/agents/gsd-domain-researcher.compact.md +141 -0
- package/agents/gsd-eval-auditor.compact.md +160 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-executor.md +13 -8
- package/agents/gsd-framework-selector.compact.md +82 -0
- package/agents/gsd-integration-checker.compact.md +245 -0
- package/agents/gsd-intel-updater.compact.md +226 -0
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.compact.md +45 -0
- package/agents/gsd-nyquist-auditor.compact.md +179 -0
- package/agents/gsd-pattern-mapper.compact.md +275 -0
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +8 -7
- package/agents/gsd-planner.md +12 -8
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-roadmapper.compact.md +454 -0
- package/agents/gsd-roadmapper.md +13 -0
- package/agents/gsd-security-auditor.compact.md +162 -0
- package/agents/gsd-ui-auditor.compact.md +404 -0
- package/agents/gsd-ui-auditor.md +155 -17
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +848 -163
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- package/commands/gsd/cleanup.md +1 -0
- package/commands/gsd/code-review.md +2 -1
- package/commands/gsd/complete-milestone.md +1 -0
- package/commands/gsd/config.md +1 -0
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +8 -3
- package/commands/gsd/mempalace-recall.md +1 -0
- package/commands/gsd/new-milestone.md +1 -0
- package/commands/gsd/new-project.md +1 -0
- package/commands/gsd/next.md +1 -0
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +1 -0
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/review.md +2 -3
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/thread.md +1 -0
- package/commands/gsd/workspace.md +1 -0
- package/commands/gsd/workstreams.md +1 -0
- package/gsd-core/bin/check-latest-version.cjs +8 -3
- package/gsd-core/bin/gsd-tools.cjs +672 -146
- package/gsd-core/bin/lib/adr-parser.cjs +4 -2
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +119 -34
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
- package/gsd-core/bin/lib/capability-loader.cjs +135 -1
- package/gsd-core/bin/lib/capability-registry.cjs +96 -189
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-validator.cjs +14 -2
- package/gsd-core/bin/lib/check-command-router.cjs +213 -49
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +823 -112
- package/gsd-core/bin/lib/config-loader.cjs +66 -4
- package/gsd-core/bin/lib/config.cjs +186 -45
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +164 -45
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +614 -86
- package/gsd-core/bin/lib/install-engine.cjs +29 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
- package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +37 -13
- package/gsd-core/bin/lib/model-resolver.cjs +253 -53
- package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
- 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 +268 -27
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +393 -88
- package/gsd-core/bin/lib/plan-document.cjs +49 -1
- package/gsd-core/bin/lib/planning-document.cjs +459 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
- package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
- package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
- package/gsd-core/bin/lib/research-store.cjs +11 -12
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +356 -42
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-document.cjs +130 -28
- package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
- package/gsd-core/bin/lib/state-transition.cjs +181 -30
- package/gsd-core/bin/lib/state.cjs +265 -27
- package/gsd-core/bin/lib/surface.cjs +77 -3
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
- package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
- package/gsd-core/bin/lib/uat.cjs +9 -1
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/update-context.cjs +30 -24
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification.cjs +315 -30
- package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
- package/gsd-core/bin/lib/verify.cjs +320 -48
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
- package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- 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-phase-between-wave-reset.md +7 -6
- 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 +18 -0
- package/gsd-core/references/model-profiles.md +13 -4
- 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 +14 -2
- package/gsd-core/references/tdd.md +30 -4
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +433 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/state.md +6 -3
- package/gsd-core/templates/summary.compact.md +212 -0
- package/gsd-core/templates/user-setup.compact.md +199 -0
- package/gsd-core/templates/user-setup.md +0 -9
- 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 +1 -1
- package/gsd-core/workflows/add-tests.md +2 -2
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +11 -3
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- 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 +29 -16
- package/gsd-core/workflows/check-todos.md +6 -4
- package/gsd-core/workflows/cleanup.md +5 -3
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +216 -73
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +41 -264
- package/gsd-core/workflows/debug.md +3 -3
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- 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 +1 -1
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +17 -158
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +10 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- 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 +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/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -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/wave-post-gate-hooks.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +83 -172
- package/gsd-core/workflows/execute-plan.md +24 -10
- package/gsd-core/workflows/explore.md +3 -3
- package/gsd-core/workflows/extract-learnings.md +2 -1
- 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 +2 -2
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/help.md +1 -1
- package/gsd-core/workflows/import.md +2 -2
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +2 -2
- package/gsd-core/workflows/map-codebase.md +52 -5
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +56 -14
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- 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 +39 -209
- 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 +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- 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 +45 -187
- 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 +132 -20
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
- 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 +1 -1
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +1 -1
- package/gsd-core/workflows/quick.md +29 -10
- package/gsd-core/workflows/reapply-patches.md +86 -6
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +31 -16
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -2
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +22 -9
- package/gsd-core/workflows/ship.md +3 -2
- 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 +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +44 -8
- package/gsd-core/workflows/ui-review.md +18 -4
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +14 -12
- package/gsd-core/workflows/validate-phase.md +3 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +101 -196
- package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
- package/hooks/dist/gsd-context-monitor.js +88 -15
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-secret-read-guard.js +71 -19
- package/hooks/dist/gsd-statusline.js +81 -20
- package/hooks/dist/gsd-validate-commit.sh +97 -8
- package/hooks/dist/gsd-worktree-path-guard.js +25 -14
- package/hooks/dist/gsd-write-guard.js +46 -1
- package/hooks/dist/lib/dispatch-identity.js +187 -0
- package/hooks/dist/lib/filename-classification.js +64 -0
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/gsd-agent-isolation-guard.js +66 -16
- package/hooks/gsd-context-monitor.js +88 -15
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-secret-read-guard.js +71 -19
- package/hooks/gsd-statusline.js +81 -20
- package/hooks/gsd-validate-commit.sh +97 -8
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/package.json +11 -6
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +131 -12
- package/scripts/check-env.cjs +36 -8
- package/scripts/check-glossary-refs.cjs +25 -21
- package/scripts/ci-next-health.cjs +271 -0
- package/scripts/ci-prepare-test-scope.cjs +7 -7
- package/scripts/ci-test-scope.cjs +126 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +35 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- package/scripts/gen-platform-conformance-tier.cjs +557 -0
- package/scripts/lib/drift-scan.cjs +1 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +623 -13
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +9 -3
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +29 -9
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
- package/scripts/prompt-injection-scan.sh +18 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- package/skills/gsd-cleanup/SKILL.md +1 -0
- package/skills/gsd-code-review/SKILL.md +2 -1
- package/skills/gsd-complete-milestone/SKILL.md +1 -0
- package/skills/gsd-config/SKILL.md +1 -0
- package/skills/gsd-debug/SKILL.md +1 -0
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +8 -3
- package/skills/gsd-mempalace-recall/SKILL.md +1 -0
- package/skills/gsd-new-milestone/SKILL.md +1 -0
- package/skills/gsd-new-project/SKILL.md +1 -0
- package/skills/gsd-next/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -0
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review/SKILL.md +2 -3
- package/skills/gsd-review-backlog/SKILL.md +1 -0
- package/skills/gsd-settings/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +1 -0
- package/skills/gsd-thread/SKILL.md +1 -0
- package/skills/gsd-workspace/SKILL.md +1 -0
- package/skills/gsd-workstreams/SKILL.md +1 -0
- package/vscode/package.json +1 -1
- package/gsd-core/templates/claude-md.md +0 -145
- package/gsd-core/templates/codebase/concerns.md +0 -310
- package/gsd-core/templates/codebase/conventions.md +0 -307
- package/gsd-core/templates/codebase/integrations.md +0 -280
- package/gsd-core/templates/codebase/structure.md +0 -285
- package/gsd-core/templates/codebase/testing.md +0 -480
- package/gsd-core/templates/debug-subagent-prompt.md +0 -91
- package/gsd-core/templates/discovery.md +0 -146
|
@@ -123,11 +123,89 @@ 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: resolveActiveRuntime(config),
|
|
127
133
|
tier,
|
|
128
134
|
overrides: config['model_profile_overrides'],
|
|
129
135
|
});
|
|
130
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* #4192 — Resolve the claude-runtime TIER OVERRIDE model for (config, tier).
|
|
139
|
+
*
|
|
140
|
+
* Step 3's runtime-aware resolution deliberately skips the claude runtime to
|
|
141
|
+
* preserve the alias-native posture (#1156/#2297): with no user override, the
|
|
142
|
+
* resolver must keep returning bare tier aliases, and the builtin claude tier
|
|
143
|
+
* map (`opus → claude-opus-4-8`, …) must never force full-ID emission on every
|
|
144
|
+
* default install. But `model_profile_overrides.<runtime>.<tier>` is a
|
|
145
|
+
* documented override point (docs/CONFIGURATION.md § Runtime-Aware Profiles)
|
|
146
|
+
* that `workflows/settings-advanced.md` actively writes for claude-runtime
|
|
147
|
+
* users — and #4192 Finding 1 measured the key inert on this runtime.
|
|
148
|
+
*
|
|
149
|
+
* This helper reads ONLY the user's override entry for the effective claude
|
|
150
|
+
* runtime and tier — never the builtin claude tier map — so an install with no
|
|
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.
|
|
164
|
+
*
|
|
165
|
+
* Value policy mirrors the model_overrides path (#2041/#4192): an override
|
|
166
|
+
* value that maps to a current tier alias collapses to that alias
|
|
167
|
+
* (byte-equivalent resolution, alias-form emission); anything else — a pinned
|
|
168
|
+
* older generation (`claude-opus-4-7`), a bare alias/tier repoint (`sonnet`),
|
|
169
|
+
* or a non-Claude vendor id (`openai/o3`) — is emitted verbatim as pinned.
|
|
170
|
+
* Malformed entries (no usable `model` string) return null so the caller falls
|
|
171
|
+
* through to normal alias resolution (ADR-443 D1: invalid values fall through).
|
|
172
|
+
*/
|
|
173
|
+
function resolveClaudeTierOverrideModel(
|
|
174
|
+
// The ACTIVE runtime (#4505), not the raw config key — see docblock.
|
|
175
|
+
activeRuntime, tier, overrides) {
|
|
176
|
+
if (!tier || tier === 'inherit')
|
|
177
|
+
return null;
|
|
178
|
+
const effectiveRuntime = activeRuntime || 'claude';
|
|
179
|
+
if (effectiveRuntime !== 'claude')
|
|
180
|
+
return null; // non-claude runtimes resolve at step 3
|
|
181
|
+
const overridesMap = overrides;
|
|
182
|
+
if (!overridesMap || typeof overridesMap !== 'object')
|
|
183
|
+
return null;
|
|
184
|
+
// Own-property guards throughout: both levels are config-supplied plain
|
|
185
|
+
// objects, so a prototype-chain key ("constructor", "toString") must not
|
|
186
|
+
// resolve an inherited member instead of falling through (same hardening as
|
|
187
|
+
// every other config-keyed lookup in this module).
|
|
188
|
+
const runtimeEntry = Object.hasOwn(overridesMap, effectiveRuntime)
|
|
189
|
+
? overridesMap[effectiveRuntime]
|
|
190
|
+
: undefined;
|
|
191
|
+
if (!runtimeEntry || typeof runtimeEntry !== 'object')
|
|
192
|
+
return null;
|
|
193
|
+
const userRaw = Object.hasOwn(runtimeEntry, tier) ? runtimeEntry[tier] : undefined;
|
|
194
|
+
if (userRaw === undefined || userRaw === null)
|
|
195
|
+
return null;
|
|
196
|
+
const entry = typeof userRaw === 'string'
|
|
197
|
+
? { model: userRaw }
|
|
198
|
+
: userRaw;
|
|
199
|
+
if (!entry || typeof entry !== 'object')
|
|
200
|
+
return null;
|
|
201
|
+
const model = entry['model'];
|
|
202
|
+
if (typeof model !== 'string' || model.length === 0)
|
|
203
|
+
return null;
|
|
204
|
+
if (Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, model)) {
|
|
205
|
+
return CLAUDE_POLICY_ID_TO_ALIAS[model];
|
|
206
|
+
}
|
|
207
|
+
return model;
|
|
208
|
+
}
|
|
131
209
|
// Reverse of the Claude tier-default IDs, plus the Fable alias which Claude
|
|
132
210
|
// Code's Agent tool accepts but which is not a GSD model-profile tier (#1133).
|
|
133
211
|
const CLAUDE_POLICY_ID_TO_ALIAS = {
|
|
@@ -154,7 +232,10 @@ function warnModelPolicyUnmappable(agentType, policyModel, tier) {
|
|
|
154
232
|
function _resetModelPolicyWarningCacheForTests() {
|
|
155
233
|
_modelPolicyUnmappableWarned.clear();
|
|
156
234
|
}
|
|
157
|
-
// Dedupe stderr warnings for unmappable model_overrides Claude IDs (#2041
|
|
235
|
+
// Dedupe stderr warnings for unmappable model_overrides Claude IDs (#2041 /
|
|
236
|
+
// #4192). #2041 originally warned that such a value was being DROPPED to tier
|
|
237
|
+
// resolution; #4192 keeps the warn-once breadcrumb but changes the behavior to
|
|
238
|
+
// a verbatim pass-through, so the text now describes the pass-through.
|
|
158
239
|
const _modelOverrideUnmappableWarned = new Set();
|
|
159
240
|
function warnModelOverrideUnmappable(agentType, overrideValue) {
|
|
160
241
|
const key = `${agentType}::${overrideValue}`;
|
|
@@ -165,8 +246,9 @@ function warnModelOverrideUnmappable(agentType, overrideValue) {
|
|
|
165
246
|
// full to stderr/logs (#2041 security review). MUST go to stderr — resolve-
|
|
166
247
|
// model's JSON result is parsed from stdout.
|
|
167
248
|
const safe = overrideValue.length > 64 ? overrideValue.slice(0, 64) + '…' : overrideValue;
|
|
168
|
-
process.stderr.write(`gsd: warning — model_overrides value "${safe}" for ${agentType} ` +
|
|
169
|
-
`
|
|
249
|
+
process.stderr.write(`gsd: warning — model_overrides value "${safe}" for ${agentType} is a fully-qualified ` +
|
|
250
|
+
`Claude model ID with no tier alias; passing it through verbatim. Claude Code setups ` +
|
|
251
|
+
`whose Agent tool accepts only tier aliases will not honor it. (#4192)\n`);
|
|
170
252
|
}
|
|
171
253
|
// Test-only: reset the model_overrides warn-dedupe cache between cases (#2041).
|
|
172
254
|
function _resetModelOverrideWarningCacheForTests() {
|
|
@@ -175,25 +257,42 @@ function _resetModelOverrideWarningCacheForTests() {
|
|
|
175
257
|
/**
|
|
176
258
|
* #2041 — Map a `model_overrides` value to its Claude Agent-tool alias on the
|
|
177
259
|
* claude runtime, mirroring the `model_policy` path (#1144). Claude Code's
|
|
178
|
-
* Agent tool `model` parameter documents
|
|
179
|
-
* fable)
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
260
|
+
* Agent tool `model` parameter documents tier aliases (opus/sonnet/haiku/
|
|
261
|
+
* fable) as the always-accepted form. Returns the value to emit verbatim, or
|
|
262
|
+
* null to signal "fall through to normal tier/dynamic-routing resolution".
|
|
263
|
+
* Non-Claude runtimes and non-Claude values always pass through verbatim.
|
|
264
|
+
*
|
|
265
|
+
* #4192 — an unmappable `claude-*` value (a pinned generation that is not the
|
|
266
|
+
* current catalog default, e.g. `claude-opus-4-7`) is now PASSED THROUGH
|
|
267
|
+
* VERBATIM with a warn-once stderr breadcrumb, instead of being dropped to
|
|
268
|
+
* tier resolution. #2041's drop was correct when the value was plausibly a
|
|
269
|
+
* mis-typed current default, but for an explicit pin it silently UNPINNED the
|
|
270
|
+
* operator's choice — the resolver would report a tier the config never asked
|
|
271
|
+
* for, the exact "profile can misrepresent what actually runs" defect #4192
|
|
272
|
+
* files. The documented contract ("any fully-qualified model ID",
|
|
273
|
+
* docs/CONFIGURATION.md § Per-Agent Overrides,
|
|
274
|
+
* gsd-core/references/model-profiles.md § Per-Agent Overrides) is restored:
|
|
275
|
+
* the pin is resolved as configured. Values that DO map to a current tier
|
|
276
|
+
* alias still collapse to that alias — byte-equivalent resolution, the #2041
|
|
277
|
+
* protection preserved — and a mappable pin never warns.
|
|
184
278
|
*
|
|
185
279
|
* Hardening (code+security review): a `typeof` guard preserves the pre-fix
|
|
186
280
|
* no-crash behavior if a malformed config surfaces a non-string value, and an
|
|
187
281
|
* `Object.hasOwn` lookup defeats `__proto__`/`constructor` lookups on the plain
|
|
188
282
|
* object literal so those reserved keys cannot return a truthy non-string.
|
|
189
283
|
*/
|
|
190
|
-
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) {
|
|
191
290
|
// Defensive: model_overrides is typed Record<string,string> but a malformed
|
|
192
291
|
// config could surface a non-string; pass through verbatim (preserving the
|
|
193
292
|
// pre-fix no-crash behaviour) and let the downstream Agent tool reject it.
|
|
194
293
|
if (typeof override !== 'string')
|
|
195
294
|
return override;
|
|
196
|
-
const onClaude = !
|
|
295
|
+
const onClaude = !activeRuntime || activeRuntime === 'claude';
|
|
197
296
|
if (!onClaude)
|
|
198
297
|
return override;
|
|
199
298
|
// Object.hasOwn guards against __proto__/constructor returning a truthy
|
|
@@ -204,8 +303,9 @@ function mapClaudeOverrideForRuntime(override, configRuntime, agentType) {
|
|
|
204
303
|
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(override))
|
|
205
304
|
return override;
|
|
206
305
|
if (override.startsWith('claude-')) {
|
|
306
|
+
// #4192: explicit generation pin — resolve as configured (see docblock).
|
|
207
307
|
warnModelOverrideUnmappable(agentType, override);
|
|
208
|
-
return
|
|
308
|
+
return override;
|
|
209
309
|
}
|
|
210
310
|
return override;
|
|
211
311
|
}
|
|
@@ -402,7 +502,7 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
402
502
|
? modelOverrides[agentType]
|
|
403
503
|
: undefined;
|
|
404
504
|
if (override) {
|
|
405
|
-
const mapped = mapClaudeOverrideForRuntime(override, config
|
|
505
|
+
const mapped = mapClaudeOverrideForRuntime(override, resolveActiveRuntime(config), agentType);
|
|
406
506
|
if (mapped !== null)
|
|
407
507
|
return mapped;
|
|
408
508
|
// Unmappable Claude ID — fall through to tier resolution (matches model_policy).
|
|
@@ -419,10 +519,19 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
419
519
|
const agentModels = Object.hasOwn(modelProfilesMapForModel, agentType) ? modelProfilesMapForModel[agentType] : undefined;
|
|
420
520
|
const tier = computeProfileTier(config, agentType);
|
|
421
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).
|
|
422
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 = resolveActiveRuntime(config);
|
|
423
532
|
if (tier && tier !== 'inherit') {
|
|
424
|
-
const onClaude =
|
|
425
|
-
const effectiveRuntime =
|
|
533
|
+
const onClaude = activeRuntime === 'claude';
|
|
534
|
+
const effectiveRuntime = activeRuntime;
|
|
426
535
|
const mergedPolicy = config['model_policy']
|
|
427
536
|
? { ...config['model_policy'], runtime: effectiveRuntime }
|
|
428
537
|
: null;
|
|
@@ -447,8 +556,49 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
447
556
|
warnModelPolicyUnmappable(agentType, policyModel, tier);
|
|
448
557
|
}
|
|
449
558
|
}
|
|
450
|
-
// 3
|
|
451
|
-
|
|
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) || !RUNTIMES_WITH_NATIVE_ALIASES.has(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)) {
|
|
452
602
|
const entry = _resolveRuntimeTier(config, tier);
|
|
453
603
|
if (entry?.model)
|
|
454
604
|
return entry.model;
|
|
@@ -463,10 +613,42 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
463
613
|
// NOTE: a non-Claude runtime that HAS a populated runtime-tier map already
|
|
464
614
|
// returned its own model id at step 3 above, before this gate — for those the
|
|
465
615
|
// explicit-project-omit honoring here is moot (step 3 wins, by #2517 design).
|
|
466
|
-
if (
|
|
467
|
-
&& (projectExplicitlySetsOmit(cwd) || !RUNTIMES_WITH_NATIVE_ALIASES.has(resolveActiveRuntime(config)))) {
|
|
616
|
+
if (omitApplies) {
|
|
468
617
|
return '';
|
|
469
618
|
}
|
|
619
|
+
// 4.5. Claude-runtime tier override (#4192 Finding 1). Sits AFTER the omit
|
|
620
|
+
// gate so an explicit project `resolve_model_ids:"omit"` still wins (#2297:
|
|
621
|
+
// explicit project omit is honored regardless of runtime), and BEFORE the
|
|
622
|
+
// alias return so a pinned generation is not re-collapsed to a tier alias or
|
|
623
|
+
// re-materialized to the LATEST catalog id by step 5's
|
|
624
|
+
// `resolve_model_ids:true` path. Fires ONLY when the user wrote a
|
|
625
|
+
// `model_profile_overrides.claude.<tier>` entry for this tier — see
|
|
626
|
+
// resolveClaudeTierOverrideModel for why the builtin map stays out.
|
|
627
|
+
if (tier && tier !== 'inherit') {
|
|
628
|
+
const claudeOverrideModel = resolveClaudeTierOverrideModel(activeRuntime, tier, config['model_profile_overrides']);
|
|
629
|
+
if (claudeOverrideModel !== null)
|
|
630
|
+
return claudeOverrideModel;
|
|
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
|
+
}
|
|
470
652
|
// 5. Profile lookup (Claude-native default).
|
|
471
653
|
if (!agentModels) {
|
|
472
654
|
return profile === 'quality' ? 'opus'
|
|
@@ -523,6 +705,50 @@ function assertValidGranularityOverride(override, fail) {
|
|
|
523
705
|
fail(`invalid granularity '${override}' (valid: ${[...VALID_GRANULARITIES].join(', ')})`);
|
|
524
706
|
}
|
|
525
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
|
+
}
|
|
526
752
|
/**
|
|
527
753
|
* #3024 — Resolve a model for a specific dynamic-routing attempt.
|
|
528
754
|
*/
|
|
@@ -538,45 +764,19 @@ function resolveModelForTier(cwd, agentType, attempt) {
|
|
|
538
764
|
? modelOverrides[agentType]
|
|
539
765
|
: undefined;
|
|
540
766
|
if (override) {
|
|
541
|
-
const mapped = mapClaudeOverrideForRuntime(override, config
|
|
767
|
+
const mapped = mapClaudeOverrideForRuntime(override, resolveActiveRuntime(config), agentType);
|
|
542
768
|
if (mapped !== null)
|
|
543
769
|
return mapped;
|
|
544
770
|
// Unmappable Claude ID — fall through to dynamic_routing / model_policy resolution.
|
|
545
771
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
const dr = config['dynamic_routing'];
|
|
550
|
-
if (!dr || typeof dr !== 'object' || dr['enabled'] !== true) {
|
|
551
|
-
return resolveModelInternal(cwd, agentType);
|
|
552
|
-
}
|
|
553
|
-
const tierModels = dr['tier_models'];
|
|
554
|
-
if (!tierModels || typeof tierModels !== 'object') {
|
|
772
|
+
// #4505: same active-runtime rule as resolveModelInternal step 3.
|
|
773
|
+
if (config['model_policy'] && resolveActiveRuntime(config) !== 'claude') {
|
|
555
774
|
return resolveModelInternal(cwd, agentType);
|
|
556
775
|
}
|
|
557
|
-
const
|
|
558
|
-
if (
|
|
559
|
-
return
|
|
560
|
-
|
|
561
|
-
const maxEscalations = Number.isInteger(dr['max_escalations']) && dr['max_escalations'] >= 0
|
|
562
|
-
? dr['max_escalations']
|
|
563
|
-
: 1;
|
|
564
|
-
const escalationEnabled = dr['escalate_on_failure'] !== false;
|
|
565
|
-
const effectiveAttempt = escalationEnabled
|
|
566
|
-
? Math.min(attemptN, maxEscalations)
|
|
567
|
-
: 0;
|
|
568
|
-
let tier = defaultTier;
|
|
569
|
-
for (let i = 0; i < effectiveAttempt; i += 1) {
|
|
570
|
-
const next = (nextTier)(tier);
|
|
571
|
-
if (!next || next === tier)
|
|
572
|
-
break;
|
|
573
|
-
tier = next;
|
|
574
|
-
}
|
|
575
|
-
const alias = tierModels[tier];
|
|
576
|
-
if (typeof alias !== 'string' || alias.length === 0) {
|
|
577
|
-
return resolveModelInternal(cwd, agentType);
|
|
578
|
-
}
|
|
579
|
-
return alias;
|
|
776
|
+
const alias = dynamicRoutingModel(config, agentType, attemptN);
|
|
777
|
+
if (alias !== null)
|
|
778
|
+
return alias;
|
|
779
|
+
return resolveModelInternal(cwd, agentType);
|
|
580
780
|
}
|
|
581
781
|
/**
|
|
582
782
|
* Keep only usable model ids: non-empty strings. A malformed config can put
|
|
@@ -126,7 +126,13 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
126
126
|
if (args.includes('--dry-run')) {
|
|
127
127
|
return makeInvalidArgs('--dry-run', 'phase insert does not support --dry-run');
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
// #4569: --sibling opts into joining afterPhase's parent decimal level
|
|
130
|
+
// instead of nesting one level deeper. Filtered out like other
|
|
131
|
+
// boolean flags (see `remove`'s --force handling above) so it never
|
|
132
|
+
// leaks into the free-text description.
|
|
133
|
+
const sibling = args.includes('--sibling');
|
|
134
|
+
const insertArgs = args.slice(2).filter(token => token !== '--sibling');
|
|
135
|
+
phase.cmdPhaseInsert(cwd, insertArgs[0], insertArgs.slice(1).join(' '), raw, sibling ? 'sibling' : 'nested');
|
|
130
136
|
return { ok: true, data: null };
|
|
131
137
|
},
|
|
132
138
|
remove: (_ctx) => {
|
|
@@ -180,11 +186,16 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
180
186
|
},
|
|
181
187
|
'uat-passed': (_ctx) => {
|
|
182
188
|
let requireVerification = false;
|
|
189
|
+
let uatOnly = false;
|
|
183
190
|
const positional = [];
|
|
184
191
|
for (const token of args.slice(2)) {
|
|
185
192
|
if (token === '--require-verification') {
|
|
186
193
|
requireVerification = true;
|
|
187
194
|
}
|
|
195
|
+
else if (token === '--uat-only') {
|
|
196
|
+
// #4663: evaluate UAT rows only (verification-status blockers skipped).
|
|
197
|
+
uatOnly = true;
|
|
198
|
+
}
|
|
188
199
|
else if (token === '--raw') {
|
|
189
200
|
// --raw is handled by the outer CLI layer; accepted here silently
|
|
190
201
|
}
|
|
@@ -195,7 +206,10 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
195
206
|
positional.push(token);
|
|
196
207
|
}
|
|
197
208
|
}
|
|
198
|
-
|
|
209
|
+
if (requireVerification && uatOnly) {
|
|
210
|
+
return makeInvalidArgs('--uat-only', '--uat-only and --require-verification are mutually exclusive');
|
|
211
|
+
}
|
|
212
|
+
phase.cmdPhaseUatPassed(cwd, positional[0], raw, { policy: { requireVerification, uatOnly } });
|
|
199
213
|
return { ok: true, data: null };
|
|
200
214
|
},
|
|
201
215
|
// #1437 — list plan files for a phase
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical bracket convention card (#3638 / ADR-612 PR-5).
|
|
4
|
+
*
|
|
5
|
+
* This module is the sole editable source of the compact grammar diagram.
|
|
6
|
+
* Render sites import phaseIdCard(); generated documentation is held to the
|
|
7
|
+
* same bytes by tests/phase-id-card.test.cjs. PR-6 can therefore inject the
|
|
8
|
+
* card broadly without inventing another copy.
|
|
9
|
+
*/
|
|
10
|
+
const PHASE_ID_CARD = [
|
|
11
|
+
'[GSD.02] 05.03-01',
|
|
12
|
+
' │ │ │ │ │',
|
|
13
|
+
' │ │ │ │ └── plan 01',
|
|
14
|
+
' │ │ │ └────── subphase 03',
|
|
15
|
+
' │ │ └───────── phase 05',
|
|
16
|
+
' │ └───────────── milestone 02',
|
|
17
|
+
' └───────────────── project GSD',
|
|
18
|
+
].join('\n');
|
|
19
|
+
const PHASE_ID_LEGEND = "milestone = bracket integer; dots = phase-levels; one hyphen = plan; "
|
|
20
|
+
+ "no 'Phase' word, no vX.Y";
|
|
21
|
+
function phaseIdCard(options = {}) {
|
|
22
|
+
const parts = [];
|
|
23
|
+
if (options.title)
|
|
24
|
+
parts.push(options.title, '');
|
|
25
|
+
parts.push(PHASE_ID_CARD, '', PHASE_ID_LEGEND);
|
|
26
|
+
return parts.join('\n');
|
|
27
|
+
}
|
|
28
|
+
module.exports = {
|
|
29
|
+
phaseIdCard,
|
|
30
|
+
PHASE_ID_CARD,
|
|
31
|
+
PHASE_ID_LEGEND,
|
|
32
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase-ID display adapters (#3638 / ADR-612 PR-5).
|
|
4
|
+
*
|
|
5
|
+
* STATE.md and milestone metadata still expose the legacy `vN.0` marker on
|
|
6
|
+
* this stacked base. Display surfaces need to translate that metadata into a
|
|
7
|
+
* bracket identity without growing another renderer. These pure adapters do
|
|
8
|
+
* only the boundary normalization, then delegate identity parsing/rendering to
|
|
9
|
+
* phase-id.cts's canonical pair.
|
|
10
|
+
*/
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
12
|
+
const phaseId = require("./phase-id.cjs");
|
|
13
|
+
const { parsePhaseId, renderMilestoneId, renderPhaseId } = phaseId;
|
|
14
|
+
function canonicalNumeric(value) {
|
|
15
|
+
let offset = 0;
|
|
16
|
+
while (offset < value.length - 1 && value[offset] === '0')
|
|
17
|
+
offset++;
|
|
18
|
+
const stripped = value.slice(offset);
|
|
19
|
+
return stripped.length < 2 ? stripped.padStart(2, '0') : stripped;
|
|
20
|
+
}
|
|
21
|
+
function isDigits(value) {
|
|
22
|
+
return value.length > 0
|
|
23
|
+
&& [...value].every(char => char >= '0' && char <= '9');
|
|
24
|
+
}
|
|
25
|
+
function milestoneToken(value) {
|
|
26
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
27
|
+
return null;
|
|
28
|
+
const raw = String(value).replace(/^v/i, '');
|
|
29
|
+
const parts = raw.split('.');
|
|
30
|
+
if (parts.length > 2 || parts.some(part => !isDigits(part)))
|
|
31
|
+
return null;
|
|
32
|
+
return canonicalNumeric(parts[0]);
|
|
33
|
+
}
|
|
34
|
+
function phaseToken(value) {
|
|
35
|
+
if (typeof value !== 'string' && typeof value !== 'number')
|
|
36
|
+
return null;
|
|
37
|
+
const raw = String(value);
|
|
38
|
+
const parts = raw.split('.');
|
|
39
|
+
if (parts.length > 2 || parts.some(part => !isDigits(part)))
|
|
40
|
+
return null;
|
|
41
|
+
return parts.map(canonicalNumeric).join('.');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Render a bracket phase display from legacy milestone metadata.
|
|
45
|
+
* Returns null for incomplete or invalid metadata so cosmetic callers can
|
|
46
|
+
* degrade without breaking a command/statusline render.
|
|
47
|
+
*/
|
|
48
|
+
function renderBracketPhaseDisplay(milestone, phase, projectCode) {
|
|
49
|
+
const project = typeof projectCode === 'string' ? projectCode : '';
|
|
50
|
+
const mm = milestoneToken(milestone);
|
|
51
|
+
const pp = phaseToken(phase);
|
|
52
|
+
if (!project || mm === null || pp === null)
|
|
53
|
+
return null;
|
|
54
|
+
try {
|
|
55
|
+
return renderPhaseId(parsePhaseId(`${project}.${mm}-${pp}`));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Render only the bracket milestone label, still through canonical parsing. */
|
|
62
|
+
function renderBracketMilestoneDisplay(milestone, projectCode) {
|
|
63
|
+
const project = typeof projectCode === 'string' ? projectCode : '';
|
|
64
|
+
const mm = milestoneToken(milestone);
|
|
65
|
+
if (!project || mm === null)
|
|
66
|
+
return null;
|
|
67
|
+
try {
|
|
68
|
+
// The sentinel phase is a validation vehicle, not a rendering artifact.
|
|
69
|
+
return renderMilestoneId(parsePhaseId(`${project}.${mm}-00`));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
module.exports = {
|
|
76
|
+
renderBracketPhaseDisplay,
|
|
77
|
+
renderBracketMilestoneDisplay,
|
|
78
|
+
};
|