@opengsd/gsd-core 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-debug-session-manager.md +11 -0
- package/agents/gsd-doc-synthesizer.md +2 -4
- package/agents/gsd-executor.md +5 -5
- package/agents/gsd-mempalace-curator.md +5 -2
- package/agents/gsd-phase-researcher.md +20 -1
- package/agents/gsd-plan-checker.md +37 -0
- package/agents/gsd-planner.md +44 -46
- package/agents/gsd-user-profiler.md +3 -0
- package/agents/gsd-verifier.md +12 -3
- package/bin/install.js +841 -971
- package/bin/lib/ui-safety-gate.cjs +2 -0
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/mempalace-recall.md +1 -1
- package/commands/gsd/new-milestone.md +1 -1
- package/commands/gsd/quick.md +1 -1
- package/commands/gsd/review-backlog.md +2 -1
- package/commands/gsd/verify-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +469 -88
- package/gsd-core/bin/lib/active-workstream-store.cjs +138 -22
- package/gsd-core/bin/lib/agent-install-check.cjs +230 -32
- package/gsd-core/bin/lib/api-coverage.cjs +3 -5
- package/gsd-core/bin/lib/artifacts.cjs +3 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
- package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
- package/gsd-core/bin/lib/audit.cjs +876 -240
- package/gsd-core/bin/lib/broken-windows.cjs +1 -1
- package/gsd-core/bin/lib/capability-consent.cjs +149 -15
- package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
- package/gsd-core/bin/lib/capability-registry.cjs +575 -101
- package/gsd-core/bin/lib/capability-source.cjs +92 -0
- package/gsd-core/bin/lib/capability-trust.cjs +444 -25
- package/gsd-core/bin/lib/capability-validator.cjs +495 -22
- package/gsd-core/bin/lib/capability-writer.cjs +3 -2
- package/gsd-core/bin/lib/check-command-router.cjs +71 -37
- package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
- package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
- package/gsd-core/bin/lib/command-aliases.cjs +22 -0
- package/gsd-core/bin/lib/command-roster.cjs +44 -1
- package/gsd-core/bin/lib/commands.cjs +651 -86
- package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
- package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
- package/gsd-core/bin/lib/config-loader.cjs +75 -0
- package/gsd-core/bin/lib/config.cjs +10 -1
- package/gsd-core/bin/lib/core-utils.cjs +127 -29
- package/gsd-core/bin/lib/decisions.cjs +23 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
- package/gsd-core/bin/lib/frontmatter.cjs +155 -20
- package/gsd-core/bin/lib/gap-checker.cjs +68 -7
- package/gsd-core/bin/lib/git-base-branch.cjs +102 -0
- package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
- package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
- package/gsd-core/bin/lib/init.cjs +321 -129
- package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
- package/gsd-core/bin/lib/install-engine.cjs +745 -258
- package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
- package/gsd-core/bin/lib/install-profiles.cjs +134 -57
- package/gsd-core/bin/lib/install-scope.cjs +270 -0
- package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
- package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +138 -31
- package/gsd-core/bin/lib/io.cjs +10 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
- package/gsd-core/bin/lib/markdown-table.cjs +133 -20
- package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
- package/gsd-core/bin/lib/milestone.cjs +754 -70
- package/gsd-core/bin/lib/model-catalog.cjs +59 -1
- package/gsd-core/bin/lib/model-resolver.cjs +183 -40
- package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
- package/gsd-core/bin/lib/pattern.cjs +122 -0
- package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
- package/gsd-core/bin/lib/phase-id.cjs +444 -36
- package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
- package/gsd-core/bin/lib/phase-locator.cjs +125 -18
- package/gsd-core/bin/lib/phase.cjs +646 -143
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
- package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
- package/gsd-core/bin/lib/plan-scan.cjs +86 -2
- package/gsd-core/bin/lib/planning-scope.cjs +31 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +56 -6
- package/gsd-core/bin/lib/probe-core.cjs +1 -1
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +13 -4
- package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
- package/gsd-core/bin/lib/roadmap-command-router.cjs +34 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +943 -184
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
- package/gsd-core/bin/lib/roadmap.cjs +385 -94
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +608 -46
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +426 -55
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
- package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +115 -3
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
- package/gsd-core/bin/lib/security.cjs +104 -5
- package/gsd-core/bin/lib/shell-command-projection.cjs +275 -3
- package/gsd-core/bin/lib/smart-entry.cjs +142 -22
- package/gsd-core/bin/lib/state-command-router.cjs +5 -1
- package/gsd-core/bin/lib/state-document.cjs +152 -8
- package/gsd-core/bin/lib/state-transition.cjs +371 -117
- package/gsd-core/bin/lib/state.cjs +1794 -357
- package/gsd-core/bin/lib/surface.cjs +23 -9
- package/gsd-core/bin/lib/text-lines.cjs +80 -0
- package/gsd-core/bin/lib/token-scanner.cjs +76 -0
- package/gsd-core/bin/lib/uat-predicate.cjs +9 -3
- package/gsd-core/bin/lib/uat.cjs +399 -56
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
- package/gsd-core/bin/lib/unusable-input.cjs +24 -0
- package/gsd-core/bin/lib/update-context.cjs +8 -2
- package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
- package/gsd-core/bin/lib/validate.cjs +20 -6
- package/gsd-core/bin/lib/vendor/README.md +37 -0
- package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
- package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +258 -8
- package/gsd-core/bin/lib/verify.cjs +368 -888
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
- package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
- package/gsd-core/bin/lib/workstream.cjs +2 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +176 -9
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +7 -1
- package/gsd-core/references/agent-contracts.md +43 -26
- package/gsd-core/references/checkpoints.md +2 -2
- package/gsd-core/references/context-budget.md +1 -1
- package/gsd-core/references/dispatch-isolation-gate.md +138 -0
- package/gsd-core/references/doc-conflict-engine.md +1 -1
- package/gsd-core/references/execute-mvp-tdd.md +3 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
- package/gsd-core/references/execute-phase-context-guard.md +1 -1
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +6 -2
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-planning-commit.md +2 -1
- package/gsd-core/references/loop-hook-dispatch.md +39 -2
- package/gsd-core/references/model-profiles.md +12 -4
- package/gsd-core/references/mvp-concepts.md +9 -9
- package/gsd-core/references/planner-guidance.md +3 -9
- package/gsd-core/references/planner-preconditions.md +1 -1
- package/gsd-core/references/planner-reviews.md +1 -1
- package/gsd-core/references/planning-config.md +8 -6
- package/gsd-core/references/revision-loop.md +1 -1
- package/gsd-core/references/specless-probe-fallback.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +3 -3
- package/gsd-core/references/verifier-phase-gates.md +192 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +22 -6
- package/gsd-core/templates/discussion-log.md +1 -1
- package/gsd-core/templates/phase-prompt.md +2 -4
- package/gsd-core/templates/state.md +4 -4
- package/gsd-core/templates/verification-report.md +9 -1
- package/gsd-core/workflows/ai-integration-phase.md +9 -11
- package/gsd-core/workflows/autonomous.md +1 -1
- package/gsd-core/workflows/cleanup.md +62 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +13 -3
- package/gsd-core/workflows/code-review-fix.md +37 -10
- package/gsd-core/workflows/code-review.md +38 -12
- package/gsd-core/workflows/complete-milestone.md +141 -18
- package/gsd-core/workflows/debug.md +7 -5
- package/gsd-core/workflows/diagnose-issues.md +35 -9
- package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
- package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +2 -1
- package/gsd-core/workflows/edit-phase.md +26 -1
- package/gsd-core/workflows/eval-review.md +3 -5
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +31 -6
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +2 -0
- package/gsd-core/workflows/execute-phase.md +38 -50
- package/gsd-core/workflows/execute-plan.md +36 -4
- package/gsd-core/workflows/explore.md +131 -4
- package/gsd-core/workflows/fast.md +10 -2
- package/gsd-core/workflows/health.md +73 -4
- package/gsd-core/workflows/import.md +4 -4
- package/gsd-core/workflows/ingest-docs.md +5 -5
- package/gsd-core/workflows/mvp-phase.md +6 -3
- package/gsd-core/workflows/new-milestone.md +14 -9
- package/gsd-core/workflows/new-project.md +14 -14
- package/gsd-core/workflows/next.md +12 -0
- package/gsd-core/workflows/plan-phase.md +41 -17
- package/gsd-core/workflows/plan-review-convergence.md +50 -2
- package/gsd-core/workflows/progress.md +34 -6
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -4
- package/gsd-core/workflows/quick/steps/quick-verification.md +27 -6
- package/gsd-core/workflows/quick/steps/research-phase.md +2 -2
- package/gsd-core/workflows/quick.md +35 -15
- package/gsd-core/workflows/review.md +26 -5
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -1
- package/gsd-core/workflows/settings.md +66 -2
- package/gsd-core/workflows/ship.md +104 -44
- package/gsd-core/workflows/spec-phase.md +30 -12
- package/gsd-core/workflows/sync-skills.md +63 -8
- package/gsd-core/workflows/transition.md +46 -11
- package/gsd-core/workflows/ui-phase.md +5 -5
- package/gsd-core/workflows/ui-review.md +2 -2
- package/gsd-core/workflows/update.md +1 -1
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work.md +9 -7
- package/hooks/dist/gsd-agent-isolation-guard.js +103 -14
- package/hooks/dist/gsd-check-update-worker.js +56 -13
- package/hooks/dist/gsd-check-update.js +19 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
- package/hooks/dist/gsd-cursor-subagent-start.js +77 -2
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
- package/hooks/dist/gsd-prompt-guard.js +21 -20
- package/hooks/dist/gsd-read-injection-scanner.js +38 -24
- package/hooks/dist/gsd-statusline.js +18 -0
- package/hooks/dist/gsd-update-banner.js +22 -1
- package/hooks/dist/gsd-workflow-guard.js +134 -36
- package/hooks/dist/lib/git-cmd.js +92 -59
- package/hooks/dist/lib/injection-patterns.js +45 -0
- package/hooks/dist/lib/isolation-deny-reason.js +39 -0
- package/hooks/dist/lib/isolation-sentinel.js +9 -0
- package/hooks/gsd-agent-isolation-guard.js +103 -14
- package/hooks/gsd-check-update-worker.js +56 -13
- package/hooks/gsd-check-update.js +19 -1
- package/hooks/gsd-cursor-pre-tool.js +0 -3
- package/hooks/gsd-cursor-subagent-start.js +77 -2
- package/hooks/gsd-cursor-subagent-stop.js +3 -2
- package/hooks/gsd-prompt-guard.js +21 -20
- package/hooks/gsd-read-injection-scanner.js +38 -24
- package/hooks/gsd-statusline.js +18 -0
- package/hooks/gsd-update-banner.js +22 -1
- package/hooks/gsd-workflow-guard.js +134 -36
- package/hooks/lib/git-cmd.js +92 -59
- package/hooks/lib/injection-patterns.js +45 -0
- package/hooks/lib/isolation-deny-reason.js +39 -0
- package/hooks/lib/isolation-sentinel.js +9 -0
- package/package.json +21 -9
- package/pi/gsd.cjs +19 -5
- package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
- package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
- package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
- package/scripts/changeset/lint.cjs +60 -5
- package/scripts/check-alias-drift.cjs +7 -43
- package/scripts/check-contract-drift.cjs +297 -0
- package/scripts/ci-test-scope.cjs +19 -2
- package/scripts/command-contract-helpers.cjs +903 -1
- package/scripts/gen-adr-index.cjs +728 -38
- package/scripts/gen-capability-registry.cjs +3 -15
- package/scripts/gen-context-index.cjs +2 -11
- package/scripts/gen-health-docs.cjs +390 -0
- package/scripts/gen-inventory-manifest.cjs +50 -4
- package/scripts/gen-loop-host-contract.cjs +4 -24
- package/scripts/gen-registry.cjs +3 -14
- package/scripts/lib/alias-drift-families.cjs +46 -0
- package/scripts/lib/drift-scan.cjs +278 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
- package/scripts/lint-canary-version-leak.cjs +73 -0
- package/scripts/lint-command-contract.cjs +96 -13
- package/scripts/lint-completion-predicate-drift.cjs +933 -0
- package/scripts/lint-completion-ratio-drift.cjs +214 -0
- package/scripts/lint-default-flip-documentation.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
- package/scripts/lint-eslint-glob-coverage.cjs +340 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
- package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
- package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
- package/scripts/lint-milestone-window-drift.cjs +468 -0
- package/scripts/lint-phase-enumeration-drift.cjs +479 -0
- package/scripts/lint-plan-count-drift.cjs +318 -0
- package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
- package/scripts/lint-planning-prompt-drift.cjs +434 -0
- package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
- package/scripts/lint-regression-test-names.cjs +15 -13
- package/scripts/lint-removed-but-needed.cjs +320 -0
- package/scripts/lint-state-field-drift.cjs +805 -0
- package/scripts/lint-state-write-path-drift.cjs +1045 -0
- package/scripts/lint-test-file-count.allowlist.json +21 -10
- package/scripts/lint-unreachable-guard-drift.cjs +843 -0
- package/scripts/lint-vendored-deps.cjs +124 -0
- package/scripts/pr-changed-files.cjs +63 -0
- package/scripts/pr-template-policy.cjs +14 -4
- package/scripts/prompt-injection-scan.sh +25 -0
- package/scripts/require-issue-link-policy.cjs +192 -0
- package/scripts/state-write-path-drift-baseline.json +19 -0
- package/scripts/sync-runtime-launcher.cjs +2 -4
- package/skills/gsd-autonomous/SKILL.md +0 -1
- package/skills/gsd-code-review/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -2
- package/skills/gsd-map-codebase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-recall/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-next/SKILL.md +0 -1
- package/skills/gsd-plan-phase/SKILL.md +0 -1
- package/skills/gsd-progress/SKILL.md +0 -1
- package/skills/gsd-quick/SKILL.md +1 -1
- package/skills/gsd-review-backlog/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +0 -1
- package/skills/gsd-verify-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/discovery-phase.md +0 -298
- package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
- package/gsd-core/workflows/verify-phase.md +0 -574
- package/scripts/affected-tests-lib.cjs +0 -554
- package/scripts/lint-allow-test-rule-refs.cjs +0 -162
- package/scripts/run-affected-tests.cjs +0 -7
- package/scripts/run-tests.cjs +0 -1051
|
@@ -10,12 +10,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
10
10
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.RUNTIMES_WITH_FAST_MODE = exports.EFFORT_ARGV = exports.EFFORT_RENDERING = exports.KNOWN_PROVIDERS = exports.PROVIDER_PRESETS = exports.RUNTIMES_WITH_REASONING_EFFORT = exports.KNOWN_RUNTIMES = exports.RUNTIME_PROFILE_MAP = exports.MODEL_ALIAS_MAP = exports.AGENT_DEFAULT_TIERS = exports.AGENT_TO_PHASE_TYPE = exports.MODEL_PROFILES = exports.ADAPTIVE_TIER_VALUES = exports.VALID_TIERS = exports.VALID_AGENT_TIERS = exports.VALID_PHASE_TYPES = exports.VALID_PROFILES = exports.catalog = void 0;
|
|
13
|
+
exports.RUNTIMES_WITH_FAST_MODE = exports.EFFORT_ARGV = exports.EFFORT_RENDERING = exports.CLAUDE_AGENT_ALIASES = exports.KNOWN_PROVIDERS = exports.PROVIDER_PRESETS = exports.RUNTIMES_WITH_REASONING_EFFORT = exports.KNOWN_RUNTIMES = exports.RUNTIME_PROFILE_MAP = exports.MODEL_ALIAS_MAP = exports.AGENT_DEFAULT_TIERS = exports.AGENT_TO_PHASE_TYPE = exports.MODEL_PROFILES = exports.ADAPTIVE_TIER_VALUES = exports.VALID_TIERS = exports.VALID_AGENT_TIERS = exports.VALID_PHASE_TYPES = exports.VALID_PROFILES = exports.catalog = void 0;
|
|
14
|
+
exports.isAnthropicFlavoredModel = isAnthropicFlavoredModel;
|
|
14
15
|
exports.nextTier = nextTier;
|
|
15
16
|
exports.formatAgentToModelMapAsTable = formatAgentToModelMapAsTable;
|
|
16
17
|
exports.getAgentToModelMapForProfile = getAgentToModelMapForProfile;
|
|
17
18
|
exports.renderEffortArgv = renderEffortArgv;
|
|
18
19
|
exports.renderEffortForRuntime = renderEffortForRuntime;
|
|
20
|
+
exports.mergeEffortTierDefaults = mergeEffortTierDefaults;
|
|
19
21
|
const node_path_1 = __importDefault(require("node:path"));
|
|
20
22
|
// In .cts (CommonJS output) files, `require` is available as a global;
|
|
21
23
|
// we use it directly to load JSON candidates.
|
|
@@ -103,6 +105,27 @@ exports.PROVIDER_PRESETS = _catalog.providerPresets ?? {};
|
|
|
103
105
|
exports.KNOWN_PROVIDERS = new Set(Object.entries(exports.PROVIDER_PRESETS)
|
|
104
106
|
.filter(([, tiers]) => Object.values(tiers).some((budgets) => budgets && Object.values(budgets).some((entry) => entry && entry.model)))
|
|
105
107
|
.map(([name]) => name));
|
|
108
|
+
// ─── #3241 — Anthropic-flavored model detection ──────────────────────────────
|
|
109
|
+
//
|
|
110
|
+
// Moved here from src/model-resolver.cts (the "seam decision" in
|
|
111
|
+
// .gsd/phase/feat-3241-codex-omit-model-by-default/40-design.md): this leaf
|
|
112
|
+
// module is the one common dependency both model-resolver and the (layering-
|
|
113
|
+
// restricted) install-time Codex-posture checks can share without pulling
|
|
114
|
+
// model-resolver's config-loader dependency chain into a "pure read/verify"
|
|
115
|
+
// caller. model-resolver re-exports both names for back-compat.
|
|
116
|
+
//
|
|
117
|
+
// #2310 — True if `model` is an Anthropic-flavored value that must never appear as a
|
|
118
|
+
// Codex agent `.toml` `model`. Two forms: (a) a bare Claude Agent-tool tier alias
|
|
119
|
+
// (opus/sonnet/haiku/fable — CLAUDE_AGENT_ALIASES below); (b) any Claude model id in
|
|
120
|
+
// any provider namespacing — `claude-*`, `anthropic/claude-*`, `us.anthropic.claude-*`
|
|
121
|
+
// (the forms the catalog assigns to opencode/hermes/kilo, reachable on a Codex .toml
|
|
122
|
+
// via the runtime-resolver path). No OpenAI/Codex model id contains "claude", so a
|
|
123
|
+
// case-insensitive substring test is a safe, exhaustive guard for (b). Codex/ChatGPT
|
|
124
|
+
// rejects all of these.
|
|
125
|
+
exports.CLAUDE_AGENT_ALIASES = new Set(['opus', 'sonnet', 'haiku', 'fable']);
|
|
126
|
+
function isAnthropicFlavoredModel(model) {
|
|
127
|
+
return typeof model === 'string' && (exports.CLAUDE_AGENT_ALIASES.has(model) || model.toLowerCase().includes('claude'));
|
|
128
|
+
}
|
|
106
129
|
function nextTier(currentTier) {
|
|
107
130
|
const order = ['light', 'standard', 'heavy'];
|
|
108
131
|
const idx = order.indexOf(String(currentTier));
|
|
@@ -205,6 +228,13 @@ function renderEffortArgv(host, universalEffort, effortSurface) {
|
|
|
205
228
|
* Render a universal effort string for a specific runtime.
|
|
206
229
|
*/
|
|
207
230
|
function renderEffortForRuntime(runtime, universalEffort) {
|
|
231
|
+
// #3533 (10d): 'inherit' is not a wire level on ANY runtime — it means
|
|
232
|
+
// "omit the key / pass no argument and follow the session/host default".
|
|
233
|
+
// Renderers must never emit it as a literal; null param/channel tells
|
|
234
|
+
// resolve-execution consumers there is no propagation.
|
|
235
|
+
if (universalEffort === 'inherit') {
|
|
236
|
+
return { value: 'inherit', param: null, channel: null };
|
|
237
|
+
}
|
|
208
238
|
const spec = exports.EFFORT_RENDERING[runtime];
|
|
209
239
|
if (!spec) {
|
|
210
240
|
return { value: universalEffort, param: null, channel: null };
|
|
@@ -215,5 +245,33 @@ function renderEffortForRuntime(runtime, universalEffort) {
|
|
|
215
245
|
channel: spec.channel,
|
|
216
246
|
};
|
|
217
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* #3531 (10c) — Merge a config `effort.routing_tier_defaults` block over the
|
|
250
|
+
* manifest tier defaults instead of replacing them. A partial config must not
|
|
251
|
+
* discard built-ins: per tier, a valid override value wins and an invalid one
|
|
252
|
+
* is ignored so the manifest value for that tier surfaces (ADR-443 D1's
|
|
253
|
+
* "invalid values fall through" holds within the merged layer).
|
|
254
|
+
*
|
|
255
|
+
* Pure: returns a new object and never mutates either input — the manifest
|
|
256
|
+
* constants (`CANONICAL_CONFIG_DEFAULTS`, the catalog cache) stay frozen. The
|
|
257
|
+
* validator is injected because `EFFORT_SET` lives in model-resolver, which
|
|
258
|
+
* imports this leaf (a reverse import would be a cycle); both effort
|
|
259
|
+
* resolvers pass their own `(v) => typeof v === 'string' && EFFORT_SET.has(v)`.
|
|
260
|
+
*/
|
|
261
|
+
function mergeEffortTierDefaults(manifest, override, isValid) {
|
|
262
|
+
const merged = { ...(manifest || {}) };
|
|
263
|
+
if (override && typeof override === 'object' && !Array.isArray(override)) {
|
|
264
|
+
for (const [tier, value] of Object.entries(override)) {
|
|
265
|
+
// House pollution guard (mirrors _deepMergeConfig in config-loader): the
|
|
266
|
+
// string-only validator already makes these inert, but an explicit skip
|
|
267
|
+
// keeps this merge safe even if a caller's validator is ever relaxed.
|
|
268
|
+
if (tier === '__proto__' || tier === 'constructor' || tier === 'prototype')
|
|
269
|
+
continue;
|
|
270
|
+
if (isValid(value))
|
|
271
|
+
merged[tier] = value;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return merged;
|
|
275
|
+
}
|
|
218
276
|
// ─── Fast mode propagation ───────────────────────────────────────────────────
|
|
219
277
|
exports.RUNTIMES_WITH_FAST_MODE = new Set(['api']);
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* - ./config-loader.cjs (loadConfig)
|
|
18
18
|
* - ./configuration.cjs (CONFIG_DEFAULTS as CANONICAL_CONFIG_DEFAULTS)
|
|
19
19
|
* - ./model-profiles.cjs (MODEL_PROFILES, AGENT_TO_PHASE_TYPE, AGENT_DEFAULT_TIERS, VALID_AGENT_TIERS, nextTier)
|
|
20
|
-
* - ./model-catalog.cjs (MODEL_ALIAS_MAP, RUNTIME_PROFILE_MAP, PROVIDER_PRESETS, VALID_TIERS
|
|
20
|
+
* - ./model-catalog.cjs (MODEL_ALIAS_MAP, RUNTIME_PROFILE_MAP, PROVIDER_PRESETS, VALID_TIERS,
|
|
21
|
+
* CLAUDE_AGENT_ALIASES — re-exported below for back-compat, #3241)
|
|
21
22
|
*/
|
|
22
23
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
24
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -153,7 +154,9 @@ const CLAUDE_POLICY_ID_TO_ALIAS = {
|
|
|
153
154
|
.map(([aliasName, id]) => [id, aliasName])),
|
|
154
155
|
'claude-fable-5': 'fable',
|
|
155
156
|
};
|
|
156
|
-
|
|
157
|
+
// CLAUDE_AGENT_ALIASES moved to ./model-catalog.cts (#3241) — imported above
|
|
158
|
+
// and re-exported below for back-compat (bin/install.js:474,
|
|
159
|
+
// tests/codex-config.test.cjs:24 depend on the name being on this module).
|
|
157
160
|
// Dedupe stderr warnings so repeated agent resolutions don't spam (#1133).
|
|
158
161
|
const _modelPolicyUnmappableWarned = new Set();
|
|
159
162
|
function warnModelPolicyUnmappable(agentType, policyModel, tier) {
|
|
@@ -216,7 +219,7 @@ function mapClaudeOverrideForRuntime(override, configRuntime, agentType) {
|
|
|
216
219
|
if (Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, override)) {
|
|
217
220
|
return CLAUDE_POLICY_ID_TO_ALIAS[override];
|
|
218
221
|
}
|
|
219
|
-
if (CLAUDE_AGENT_ALIASES.has(override))
|
|
222
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(override))
|
|
220
223
|
return override;
|
|
221
224
|
if (override.startsWith('claude-')) {
|
|
222
225
|
warnModelOverrideUnmappable(agentType, override);
|
|
@@ -278,33 +281,161 @@ function resolveModelPolicy(policy, tier) {
|
|
|
278
281
|
return null;
|
|
279
282
|
return budgetEntry.model;
|
|
280
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* #2229 — the profile/phase-type tier for (config, agentType).
|
|
286
|
+
*
|
|
287
|
+
* Extracted verbatim from resolveModelInternal's step 2 so the same expression can
|
|
288
|
+
* answer "which tier did GSD resolve?" without also resolving a model id. The
|
|
289
|
+
* extraction is behaviour-preserving by construction: resolveModelInternal calls
|
|
290
|
+
* straight back into it.
|
|
291
|
+
*
|
|
292
|
+
* Returns null when the agent has no catalog entry and the profile is not `inherit`.
|
|
293
|
+
*/
|
|
294
|
+
function computeProfileTier(config, agentType) {
|
|
295
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
296
|
+
const profile = String(config['model_profile'] || 'balanced').toLowerCase();
|
|
297
|
+
// Own-property guard: agentType is an unvalidated CLI positional (the
|
|
298
|
+
// `resolve-model <agent-type>` argument is never checked against a known
|
|
299
|
+
// agent list), so a prototype-chain agentType ("toString", "constructor")
|
|
300
|
+
// would otherwise return an inherited member from this plain object
|
|
301
|
+
// instead of undefined — verified reachable purely via the CLI.
|
|
302
|
+
const modelProfilesMap = MODEL_PROFILES;
|
|
303
|
+
const agentModels = Object.hasOwn(modelProfilesMap, agentType) ? modelProfilesMap[agentType] : undefined;
|
|
304
|
+
const phaseType = (AGENT_TO_PHASE_TYPE)[agentType];
|
|
305
|
+
const configModels = config['models'];
|
|
306
|
+
const phaseTypeTier = (phaseType && configModels && typeof configModels === 'object')
|
|
307
|
+
? configModels[phaseType]
|
|
308
|
+
: undefined;
|
|
309
|
+
return (phaseTypeTier && model_catalog_cjs_1.VALID_TIERS.has(phaseTypeTier))
|
|
310
|
+
? phaseTypeTier
|
|
311
|
+
: (profile === 'inherit'
|
|
312
|
+
? 'inherit'
|
|
313
|
+
: (agentModels
|
|
314
|
+
// Own-property guard: `profile` is a config-supplied string
|
|
315
|
+
// (config['model_profile'], lower-cased); an already-lowercase
|
|
316
|
+
// prototype-chain key ("constructor", "__proto__") would otherwise
|
|
317
|
+
// return an inherited non-string member instead of falling back to
|
|
318
|
+
// 'balanced' (verified: profile:"constructor"/"__proto__" leaked a
|
|
319
|
+
// function/object through both the tier and model resolution paths).
|
|
320
|
+
? ((Object.hasOwn(agentModels, profile) ? agentModels[profile] : undefined) || agentModels['balanced'])
|
|
321
|
+
: null));
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* #2229 — the effective model TIER for (config, agentType), as a signal a workflow can
|
|
325
|
+
* read: `gsd_run query resolve-model <agent> --pick tier`.
|
|
326
|
+
*
|
|
327
|
+
* Why this is not just "look at the resolved model": on every runtime the installer
|
|
328
|
+
* configures with `resolve_model_ids: "omit"` — which is every non-Claude runtime, see
|
|
329
|
+
* docs/CONFIGURATION.md — resolveModelInternal deliberately returns '' below. A guard
|
|
330
|
+
* keyed on the model id therefore cannot tell a budget-tier run from a top-tier one
|
|
331
|
+
* there, while the tier itself is computed ABOVE that early-return and stays knowable.
|
|
332
|
+
*
|
|
333
|
+
* Honesty contract — this never guesses, because a guard that reports a wrong tier is
|
|
334
|
+
* worse than one that reports none:
|
|
335
|
+
* - a per-agent `model_overrides` pin naming a known alias (or a full Claude id that
|
|
336
|
+
* maps to one) reports that alias;
|
|
337
|
+
* - a pin that maps to nothing reports 'unknown' — a raw model id carries no tier;
|
|
338
|
+
* - `model_profile: inherit` reports 'inherit' — the session model is not ours to name;
|
|
339
|
+
* - an agent with no catalog entry reports 'unknown'.
|
|
340
|
+
*
|
|
341
|
+
* Callers must treat 'unknown' and 'inherit' as "cannot tell", never as "adequate".
|
|
342
|
+
*/
|
|
343
|
+
function resolveTierFromConfig(config, agentType) {
|
|
344
|
+
const rawOverrides = config['model_overrides'];
|
|
345
|
+
const modelOverrides = (rawOverrides && typeof rawOverrides === 'object' && !Array.isArray(rawOverrides))
|
|
346
|
+
? rawOverrides
|
|
347
|
+
: null;
|
|
348
|
+
// Own-property guard: agentType is a caller-supplied string (the
|
|
349
|
+
// `resolve-model <agent-type>` CLI positional is not validated against a
|
|
350
|
+
// known agent list); a prototype-chain agentType ("toString",
|
|
351
|
+
// "constructor") against ANY model_overrides object — even `{}` — would
|
|
352
|
+
// otherwise return an inherited member instead of undefined.
|
|
353
|
+
const override = (modelOverrides && Object.hasOwn(modelOverrides, agentType))
|
|
354
|
+
? modelOverrides[agentType]
|
|
355
|
+
: undefined;
|
|
356
|
+
if (override && typeof override === 'string') {
|
|
357
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(override))
|
|
358
|
+
return override;
|
|
359
|
+
// Own-property guard: this indexes a plain object with a config-supplied
|
|
360
|
+
// string, so a prototype-chain key ("toString", "constructor", "valueOf")
|
|
361
|
+
// would otherwise return an inherited member instead of undefined — and a
|
|
362
|
+
// function-valued tier is dropped entirely by JSON.stringify, silently
|
|
363
|
+
// removing the key a guard depends on.
|
|
364
|
+
const alias = Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, override)
|
|
365
|
+
? CLAUDE_POLICY_ID_TO_ALIAS[override]
|
|
366
|
+
: undefined;
|
|
367
|
+
if (typeof alias === 'string' && alias)
|
|
368
|
+
return alias;
|
|
369
|
+
return 'unknown';
|
|
370
|
+
}
|
|
371
|
+
const profileTier = computeProfileTier(config, agentType);
|
|
372
|
+
// #3282 — mirror resolveModelInternal's step 2.5 (model_policy preset). The
|
|
373
|
+
// profile tier alone under-reports: model_policy can dispatch a DIFFERENT
|
|
374
|
+
// tier than the profile implies (e.g. a `balanced` profile's "sonnet" tier
|
|
375
|
+
// combined with `model_policy: {budget: 'low'}` actually spawns "haiku"),
|
|
376
|
+
// and reporting the profile tier there is exactly the under-report this
|
|
377
|
+
// fixes — a haiku-tier run must never be reported as "sonnet". Skipped
|
|
378
|
+
// under the same condition resolveModelInternal skips it (no tier, or
|
|
379
|
+
// "inherit" — the session model is not ours to name).
|
|
380
|
+
if (profileTier && profileTier !== 'inherit') {
|
|
381
|
+
const mergedPolicy = config['model_policy']
|
|
382
|
+
? { ...config['model_policy'], runtime: config['runtime'] || 'claude' }
|
|
383
|
+
: null;
|
|
384
|
+
const policyModel = resolveModelPolicy(mergedPolicy, profileTier);
|
|
385
|
+
if (policyModel) {
|
|
386
|
+
// Map the policy-resolved id back to a tier alias with the same
|
|
387
|
+
// own-property-guarded lookups used above. If it maps, that alias IS
|
|
388
|
+
// the tier that actually runs — report it (the fix). If it does not
|
|
389
|
+
// map — including every non-Claude runtime, where resolveModelInternal
|
|
390
|
+
// returns the policy model verbatim with no tier meaning — the model
|
|
391
|
+
// carries no tier we can name; report 'unknown' rather than falling
|
|
392
|
+
// back to the profile tier, which would silently reintroduce the
|
|
393
|
+
// under-report this block exists to close.
|
|
394
|
+
const aliasForId = Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, policyModel)
|
|
395
|
+
? CLAUDE_POLICY_ID_TO_ALIAS[policyModel]
|
|
396
|
+
: undefined;
|
|
397
|
+
if (typeof aliasForId === 'string' && aliasForId)
|
|
398
|
+
return aliasForId;
|
|
399
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(policyModel))
|
|
400
|
+
return policyModel;
|
|
401
|
+
return 'unknown';
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return profileTier || 'unknown';
|
|
405
|
+
}
|
|
406
|
+
function resolveTierInternal(cwd, agentType) {
|
|
407
|
+
return resolveTierFromConfig(loadConfig(cwd), agentType);
|
|
408
|
+
}
|
|
281
409
|
function resolveModelInternal(cwd, agentType) {
|
|
282
410
|
const config = loadConfig(cwd);
|
|
283
411
|
// 1. Per-agent override (#2041: map Claude full IDs → Agent-tool aliases on
|
|
284
412
|
// the claude runtime, mirroring the model_policy path #1144; non-Claude
|
|
285
413
|
// runtimes and non-Claude values pass through verbatim).
|
|
286
414
|
const modelOverrides = config['model_overrides'];
|
|
287
|
-
|
|
415
|
+
// Own-property guard (see resolveTierFromConfig above): without it, an
|
|
416
|
+
// agentType of "toString" against `model_overrides: {}` returned the
|
|
417
|
+
// inherited Function.prototype.toString as the resolved "model" — verified
|
|
418
|
+
// reachable purely via the CLI, no override value needed.
|
|
419
|
+
const override = (modelOverrides && Object.hasOwn(modelOverrides, agentType))
|
|
420
|
+
? modelOverrides[agentType]
|
|
421
|
+
: undefined;
|
|
288
422
|
if (override) {
|
|
289
423
|
const mapped = mapClaudeOverrideForRuntime(override, config['runtime'], agentType);
|
|
290
424
|
if (mapped !== null)
|
|
291
425
|
return mapped;
|
|
292
426
|
// Unmappable Claude ID — fall through to tier resolution (matches model_policy).
|
|
293
427
|
}
|
|
294
|
-
// 2. Compute the tier
|
|
428
|
+
// 2. Compute the tier (#2229: shared with resolveTierFromConfig so the tier a
|
|
429
|
+
// workflow reads and the tier a model is resolved from can never diverge).
|
|
295
430
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
296
431
|
const profile = String(config['model_profile'] || 'balanced').toLowerCase();
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const tier = (
|
|
304
|
-
? phaseTypeTier
|
|
305
|
-
: (profile === 'inherit'
|
|
306
|
-
? 'inherit'
|
|
307
|
-
: (agentModels ? (agentModels[profile] || agentModels['balanced']) : null));
|
|
432
|
+
// Own-property guard (see computeProfileTier above): without it, agentType
|
|
433
|
+
// "toString" returned Function.prototype.toString as `agentModels`
|
|
434
|
+
// (truthy), which skipped the "unknown agent" fallback below and made
|
|
435
|
+
// resolveModelInternal return undefined instead of a tier-derived string.
|
|
436
|
+
const modelProfilesMapForModel = MODEL_PROFILES;
|
|
437
|
+
const agentModels = Object.hasOwn(modelProfilesMapForModel, agentType) ? modelProfilesMapForModel[agentType] : undefined;
|
|
438
|
+
const tier = computeProfileTier(config, agentType);
|
|
308
439
|
// 2.5. model_policy preset (#49, #1133)
|
|
309
440
|
const configRuntime = config['runtime'];
|
|
310
441
|
if (tier && tier !== 'inherit') {
|
|
@@ -320,11 +451,13 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
320
451
|
return policyModel;
|
|
321
452
|
// Claude Code's Agent tool takes tier aliases (opus/sonnet/haiku/fable),
|
|
322
453
|
// not full model IDs — map the policy-resolved ID back to an alias (#1133).
|
|
323
|
-
const aliasForId = CLAUDE_POLICY_ID_TO_ALIAS
|
|
324
|
-
|
|
454
|
+
const aliasForId = Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, policyModel)
|
|
455
|
+
? CLAUDE_POLICY_ID_TO_ALIAS[policyModel]
|
|
456
|
+
: undefined;
|
|
457
|
+
if (typeof aliasForId === 'string' && aliasForId)
|
|
325
458
|
return aliasForId;
|
|
326
459
|
// The policy value may already be a bare Claude agent alias (e.g. "fable").
|
|
327
|
-
if (CLAUDE_AGENT_ALIASES.has(policyModel))
|
|
460
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(policyModel))
|
|
328
461
|
return policyModel;
|
|
329
462
|
// No Claude alias for this ID (e.g. a pinned minor version like
|
|
330
463
|
// claude-opus-4-5). Warn once and fall through to the tier alias rather
|
|
@@ -415,7 +548,13 @@ function resolveModelForTier(cwd, agentType, attempt) {
|
|
|
415
548
|
const config = loadConfig(cwd);
|
|
416
549
|
const attemptN = Number.isInteger(attempt) && attempt > 0 ? attempt : 0;
|
|
417
550
|
const modelOverrides = config['model_overrides'];
|
|
418
|
-
|
|
551
|
+
// Own-property guard (see resolveTierFromConfig above): without it, an
|
|
552
|
+
// agentType of "toString" against `model_overrides: {}` returned the
|
|
553
|
+
// inherited Function.prototype.toString as the resolved "model" — verified
|
|
554
|
+
// reachable purely via the CLI, no override value needed.
|
|
555
|
+
const override = (modelOverrides && Object.hasOwn(modelOverrides, agentType))
|
|
556
|
+
? modelOverrides[agentType]
|
|
557
|
+
: undefined;
|
|
419
558
|
if (override) {
|
|
420
559
|
const mapped = mapClaudeOverrideForRuntime(override, config['runtime'], agentType);
|
|
421
560
|
if (mapped !== null)
|
|
@@ -533,7 +672,12 @@ function resolveProviderEscalation(cwd, agentType, attempt, applicable) {
|
|
|
533
672
|
}
|
|
534
673
|
// ─── #443 — Unified effort + fast_mode resolvers ─────────────────────────────
|
|
535
674
|
const VALID_EFFORTS = ['minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
536
|
-
|
|
675
|
+
// #3533 (10d): the VOCABULARY carries one more member than the LADDER —
|
|
676
|
+
// 'inherit' is a declarable effort choice ("follow the session", expressed by
|
|
677
|
+
// OMITTING the effort key at the writer) but not a level nextEffort may step
|
|
678
|
+
// into. Keeping it out of VALID_EFFORTS means escalation (resolveEffortForTier)
|
|
679
|
+
// never walks past an explicit inherit: nextEffort('inherit') is null.
|
|
680
|
+
const EFFORT_SET = new Set([...VALID_EFFORTS, 'inherit']);
|
|
537
681
|
/**
|
|
538
682
|
* Walk one step up the effort ladder from `e`.
|
|
539
683
|
*/
|
|
@@ -576,26 +720,23 @@ function resolveEffortInternal(cwd, agentType, opts) {
|
|
|
576
720
|
}
|
|
577
721
|
}
|
|
578
722
|
// Step 3: routing_tier_defaults by agent's default tier.
|
|
723
|
+
// #3531 (10c): the config block merges OVER the manifest tier defaults
|
|
724
|
+
// rather than replacing them — an effort block without
|
|
725
|
+
// routing_tier_defaults (or missing this agent's tier) falls back to the
|
|
726
|
+
// manifest built-in for that tier instead of skipping to effort.default.
|
|
727
|
+
// Invalid config values are dropped by the merge, so the manifest value for
|
|
728
|
+
// the tier surfaces (the same "invalid falls through" rule every layer has).
|
|
579
729
|
const agentTier = (AGENT_DEFAULT_TIERS)[agentType];
|
|
580
730
|
if (agentTier) {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
const manifestDefaults = canonicalEffort && typeof canonicalEffort === 'object'
|
|
591
|
-
? canonicalEffort['routing_tier_defaults']
|
|
592
|
-
: undefined;
|
|
593
|
-
if (manifestDefaults && typeof manifestDefaults === 'object') {
|
|
594
|
-
const v = manifestDefaults[agentTier];
|
|
595
|
-
if (typeof v === 'string' && EFFORT_SET.has(v))
|
|
596
|
-
return v;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
731
|
+
const canonicalEffort = (configuration_cjs_1.CONFIG_DEFAULTS)['effort'];
|
|
732
|
+
const manifestDefaults = canonicalEffort && typeof canonicalEffort === 'object'
|
|
733
|
+
? canonicalEffort['routing_tier_defaults']
|
|
734
|
+
: undefined;
|
|
735
|
+
const isValidEffort = (v) => typeof v === 'string' && EFFORT_SET.has(v);
|
|
736
|
+
const merged = (0, model_catalog_cjs_1.mergeEffortTierDefaults)(manifestDefaults, effortCfg ? effortCfg['routing_tier_defaults'] : undefined, isValidEffort);
|
|
737
|
+
const v = merged[agentTier];
|
|
738
|
+
if (isValidEffort(v))
|
|
739
|
+
return v;
|
|
599
740
|
}
|
|
600
741
|
// Step 4: effort.default
|
|
601
742
|
if (effortCfg) {
|
|
@@ -693,9 +834,11 @@ function resolveEffortForTier(cwd, agentType, attempt) {
|
|
|
693
834
|
}
|
|
694
835
|
module.exports = {
|
|
695
836
|
resolveTierEntry,
|
|
696
|
-
CLAUDE_AGENT_ALIASES,
|
|
837
|
+
CLAUDE_AGENT_ALIASES: model_catalog_cjs_1.CLAUDE_AGENT_ALIASES,
|
|
697
838
|
resolveModelPolicy,
|
|
698
839
|
resolveModelInternal,
|
|
840
|
+
resolveTierInternal,
|
|
841
|
+
resolveTierFromConfig,
|
|
699
842
|
_resetModelPolicyWarningCacheForTests,
|
|
700
843
|
_resetModelOverrideWarningCacheForTests,
|
|
701
844
|
_setInstallRuntimeMarkerForTests,
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* hang or take super-linear time on an adversarial `workflow.test_command`.
|
|
24
24
|
*
|
|
25
25
|
* Single source of truth: all four test-command gates (regression, post-merge,
|
|
26
|
-
* audit-fix
|
|
26
|
+
* audit-fix) route their resolved command through this helper so
|
|
27
27
|
* the paths cannot drift.
|
|
28
28
|
*
|
|
29
29
|
* Leaf module — depends only on node:fs / node:path.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* pattern.cts — the pattern-construction seam (ADR-3212 §1, epic #3212 Phase 1,
|
|
4
|
+
* #3412).
|
|
5
|
+
*
|
|
6
|
+
* Source in src/pattern.cts, compiled to gsd-core/bin/lib/pattern.cjs
|
|
7
|
+
* (gitignored), per the repo's ADR-457 build-at-publish convention.
|
|
8
|
+
*
|
|
9
|
+
* Sole owner of building a `RegExp` from a runtime value. `escapeRegex`
|
|
10
|
+
* delegates to the built-in `RegExp.escape` (ES2026 / Node 24+) when present,
|
|
11
|
+
* falling back to an in-file metacharacter escape below Node 24 (#3498) —
|
|
12
|
+
* still the one owner: no module outside this seam escapes a value for regex
|
|
13
|
+
* use (ADR §1).
|
|
14
|
+
*
|
|
15
|
+
* Counts, corrected during implementation (design doc "Ground truth" #1;
|
|
16
|
+
* .gsd/phase/chore-3412-pattern-seam/40-design.md): the ADR's census counted
|
|
17
|
+
* ~12 *named* helper functions. The shape-based lint guard
|
|
18
|
+
* (eslint-rules/no-adhoc-regex-escape.cjs), which matches the escape-class
|
|
19
|
+
* SHAPE wherever it appears rather than named-function bodies, found 27
|
|
20
|
+
* additional inline copies that census-by-name could not see — **~39 escape
|
|
21
|
+
* sites total**. Call sites follow the same pattern: 17 were surveyed
|
|
22
|
+
* directly, but `src/phase-id.cts`'s `escapeRegex` turned out to have 8
|
|
23
|
+
* external production importers the pre-implementation survey missed, plus
|
|
24
|
+
* the 27 guard-found inline sites also call into the seam — **~44 call
|
|
25
|
+
* sites total**. The lesson worth keeping: a named-function census
|
|
26
|
+
* structurally cannot see an inline `.replace(...)` copy or an
|
|
27
|
+
* externally-imported symbol; only a shape-based guard (or a direct
|
|
28
|
+
* importer graph query) does.
|
|
29
|
+
*
|
|
30
|
+
* `escapeRegex` is the PRIMARY export: the large majority of call sites
|
|
31
|
+
* build a *source string* (alternation via `.map(escapeRegex).join('|')`, or
|
|
32
|
+
* template/concat interpolation into a larger pattern) rather than a
|
|
33
|
+
* standalone literal match. `literalPattern` is the minority convenience
|
|
34
|
+
* wrapper for the remaining "match this value literally" shape — not the
|
|
35
|
+
* dominant one (design doc "Ground truth" #2).
|
|
36
|
+
*
|
|
37
|
+
* Behavior-preserving for MATCH RESULTS, not for pattern TEXT: `RegExp.escape`
|
|
38
|
+
* hex-escapes the leading character of nearly every non-empty input (and `-`,
|
|
39
|
+
* space, and control characters throughout), so the escaped source string
|
|
40
|
+
* differs from the twelve deleted copies' output for almost every value.
|
|
41
|
+
* Match behavior against that source is unaffected — verified by the
|
|
42
|
+
* migration-equivalence property sweep in tests/pattern.test.cjs (rows 15-17).
|
|
43
|
+
*/
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.MAX_USER_PATTERN_LEN = void 0;
|
|
46
|
+
exports.escapeRegex = escapeRegex;
|
|
47
|
+
exports.literalPattern = literalPattern;
|
|
48
|
+
exports.compileUserPattern = compileUserPattern;
|
|
49
|
+
// re2js is vendored, not an npm dependency at runtime: gsd-core/bin/** is
|
|
50
|
+
// copied into installed trees that have no node_modules, so this module must
|
|
51
|
+
// carry zero external requires (eslint-rules/no-external-require-in-bin.cjs
|
|
52
|
+
// enforces it). See gsd-core/bin/lib/vendor/README.md.
|
|
53
|
+
const re2js_cjs_1 = require("./vendor/re2js.cjs");
|
|
54
|
+
// #3498: RegExp.escape is ES2026 (first shipped in Node 24). The gsd-test
|
|
55
|
+
// matrix still runs a linux-node22 lane, and the build itself consumes this
|
|
56
|
+
// module (scripts/gen-loop-host-contract.cjs), so a hard dependency breaks
|
|
57
|
+
// `npm run build` on Node 22. Prefer the built-in when present; otherwise use
|
|
58
|
+
// the local metachar escape — still inside this file, so the #3212 sole-owner
|
|
59
|
+
// invariant (and lint-no-adhoc-regex-escape's scope) is preserved. Captured at
|
|
60
|
+
// module load so a runtime mutation of RegExp.escape cannot flip the path
|
|
61
|
+
// mid-process.
|
|
62
|
+
const escapeBuiltin = typeof RegExp.escape === 'function'
|
|
63
|
+
? RegExp.escape.bind(RegExp)
|
|
64
|
+
: undefined;
|
|
65
|
+
const escapeMetachars = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
66
|
+
function escapeRegex(value) {
|
|
67
|
+
return (escapeBuiltin ?? escapeMetachars)(value);
|
|
68
|
+
}
|
|
69
|
+
function literalPattern(value, flags) {
|
|
70
|
+
return new RegExp(escapeRegex(value), flags);
|
|
71
|
+
}
|
|
72
|
+
/** Max length for a user-supplied regex pattern before it is refused (ReDoS/compile-cost mitigation). */
|
|
73
|
+
exports.MAX_USER_PATTERN_LEN = 512;
|
|
74
|
+
/** Always-false matcher shared by every neutralization path — a refused pattern must never be able to report a match. */
|
|
75
|
+
const NEVER_MATCH = () => false;
|
|
76
|
+
/**
|
|
77
|
+
* Compile an UNTRUSTED, user-supplied pattern (e.g. plan frontmatter) via RE2
|
|
78
|
+
* (re2js), whose matching is linear-time in input length by construction —
|
|
79
|
+
* there is no backtracking engine here to exploit, so the vulnerability class
|
|
80
|
+
* (catastrophic/exponential backtracking) is closed by the engine rather than
|
|
81
|
+
* detected by a heuristic scan of the pattern text.
|
|
82
|
+
*
|
|
83
|
+
* Never throws. A pattern that is empty, too long, or not valid RE2 syntax
|
|
84
|
+
* (backreferences and look-around are unsupported by RE2 — those are exactly
|
|
85
|
+
* the constructs that require backtracking) is REFUSED: `test()` always
|
|
86
|
+
* returns `false`, and `neutralized` reports why so callers can surface the
|
|
87
|
+
* refusal (#3477 follow-up: a neutralized pattern must not look like a plain
|
|
88
|
+
* "not found"). Restores the guards lost with
|
|
89
|
+
* `sdk/src/query/validate.ts:regexForKeyLinkPattern` (#3477); this revision
|
|
90
|
+
* (post-#3477-follow-up) replaces the hand-rolled backtracking-shape scanner
|
|
91
|
+
* with RE2's linear-time guarantee — a refused pattern is never re-attempted
|
|
92
|
+
* as a literal-escaped match, since guessing at a pattern we could not
|
|
93
|
+
* compile is what produced the prior false-pass regression.
|
|
94
|
+
*
|
|
95
|
+
* `pattern` is `unknown`, not `string`, because callers pull this straight off
|
|
96
|
+
* parsed plan frontmatter (untrusted YAML) — a non-string value must reach the
|
|
97
|
+
* `'empty'`/never-match branch rather than being force-cast by the caller.
|
|
98
|
+
*/
|
|
99
|
+
function compileUserPattern(pattern) {
|
|
100
|
+
if (typeof pattern !== 'string' || pattern.length === 0) {
|
|
101
|
+
return { test: NEVER_MATCH, neutralized: 'empty' };
|
|
102
|
+
}
|
|
103
|
+
if (pattern.length > exports.MAX_USER_PATTERN_LEN) {
|
|
104
|
+
// The cap now bounds compile cost/memory, not backtracking (RE2 has none) —
|
|
105
|
+
// an over-long pattern is refused outright rather than truncated-and-compiled.
|
|
106
|
+
return { test: NEVER_MATCH, neutralized: 'too-long' };
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
// translateRegExp accepts JS-flavored syntax (named groups, `/`-escaping,
|
|
110
|
+
// etc.) that RE2's own grammar doesn't, reducing spurious refusals of
|
|
111
|
+
// otherwise-safe, JS-authored patterns before compiling under RE2's
|
|
112
|
+
// linear-time engine.
|
|
113
|
+
const compiled = re2js_cjs_1.RE2JS.compile(re2js_cjs_1.RE2JS.translateRegExp(pattern));
|
|
114
|
+
return { test: (input) => compiled.test(input), neutralized: null };
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Backreferences, look-around, or any other RE2-unsupported/malformed
|
|
118
|
+
// syntax. No literal-escape fallback: a pattern we could not compile is
|
|
119
|
+
// never guessed at — guessing produced the #3477 false-pass regression.
|
|
120
|
+
return { test: NEVER_MATCH, neutralized: 'unsupported' };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -231,7 +231,7 @@ function extractFrontmatterBlock(text, key) {
|
|
|
231
231
|
if (typeof text !== 'string')
|
|
232
232
|
return null;
|
|
233
233
|
// Anchor at byte 0 — CRLF-tolerant.
|
|
234
|
-
const fm = /^---\r?\n([\s\S]*?)\r?\n
|
|
234
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|\r?$)/.exec(text);
|
|
235
235
|
if (fm === null)
|
|
236
236
|
return null;
|
|
237
237
|
const lines = fm[1].split(/\r?\n/);
|