@opengsd/gsd-core 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +12 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-synthesizer.md +2 -4
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +22 -14
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +5 -3
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +23 -2
- package/agents/gsd-plan-checker.md +50 -53
- package/agents/gsd-planner.md +50 -50
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-user-profiler.md +3 -0
- package/agents/gsd-verifier.md +13 -4
- package/bin/install.js +1448 -1103
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/import.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 +9 -5
- package/commands/gsd/review-backlog.md +2 -1
- package/commands/gsd/verify-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +1035 -138
- package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
- package/gsd-core/bin/lib/api-coverage.cjs +33 -14
- package/gsd-core/bin/lib/artifacts.cjs +5 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
- package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
- package/gsd-core/bin/lib/audit.cjs +1026 -268
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- 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-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +845 -130
- package/gsd-core/bin/lib/capability-source.cjs +92 -0
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-trust.cjs +444 -25
- package/gsd-core/bin/lib/capability-validator.cjs +700 -40
- package/gsd-core/bin/lib/capability-writer.cjs +3 -2
- package/gsd-core/bin/lib/check-command-router.cjs +216 -42
- package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
- package/gsd-core/bin/lib/command-aliases.cjs +22 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-roster.cjs +44 -1
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +1172 -108
- package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
- package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
- package/gsd-core/bin/lib/config-loader.cjs +187 -23
- package/gsd-core/bin/lib/config.cjs +102 -3
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +208 -33
- package/gsd-core/bin/lib/decisions.cjs +23 -0
- package/gsd-core/bin/lib/edge-probe.cjs +9 -1
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
- package/gsd-core/bin/lib/frontmatter.cjs +899 -229
- package/gsd-core/bin/lib/gap-checker.cjs +95 -10
- package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
- 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 +149 -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 +268 -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 +187 -0
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +439 -168
- package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
- package/gsd-core/bin/lib/install-engine.cjs +811 -259
- package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
- package/gsd-core/bin/lib/install-profiles.cjs +212 -61
- package/gsd-core/bin/lib/install-scope.cjs +270 -0
- package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
- package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +170 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
- package/gsd-core/bin/lib/markdown-table.cjs +183 -22
- package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
- package/gsd-core/bin/lib/milestone.cjs +842 -73
- package/gsd-core/bin/lib/model-catalog.cjs +232 -16
- package/gsd-core/bin/lib/model-resolver.cjs +193 -68
- package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/pattern.cjs +122 -0
- package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
- package/gsd-core/bin/lib/phase-id.cjs +514 -40
- package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
- package/gsd-core/bin/lib/phase-locator.cjs +262 -34
- package/gsd-core/bin/lib/phase.cjs +1038 -214
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
- package/gsd-core/bin/lib/plan-scan.cjs +98 -3
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-scope.cjs +31 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
- package/gsd-core/bin/lib/probe-core.cjs +5 -2
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
- 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 +59 -11
- package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
- package/gsd-core/bin/lib/roadmap.cjs +442 -96
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -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 +402 -58
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
- package/gsd-core/bin/lib/security.cjs +104 -5
- package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
- package/gsd-core/bin/lib/smart-entry.cjs +133 -23
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +52 -19
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +338 -8
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +846 -176
- package/gsd-core/bin/lib/state.cjs +2589 -369
- package/gsd-core/bin/lib/surface.cjs +33 -11
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/text-lines.cjs +80 -0
- package/gsd-core/bin/lib/token-scanner.cjs +76 -0
- package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
- package/gsd-core/bin/lib/uat.cjs +1761 -167
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
- package/gsd-core/bin/lib/unusable-input.cjs +37 -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-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +20 -6
- package/gsd-core/bin/lib/vendor/README.md +75 -0
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -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 +272 -9
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +453 -918
- 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-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/workstream.cjs +2 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/references/agent-contracts.md +44 -26
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +39 -21
- package/gsd-core/references/context-budget.md +1 -1
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/dispatch-isolation-gate.md +138 -0
- package/gsd-core/references/doc-conflict-engine.md +1 -1
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +4 -6
- package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
- 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 +17 -11
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +5 -4
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +61 -2
- package/gsd-core/references/model-profiles.md +12 -4
- package/gsd-core/references/mvp-concepts.md +9 -9
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-guidance.md +3 -9
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-preconditions.md +1 -1
- package/gsd-core/references/planner-reviews.md +1 -1
- package/gsd-core/references/planner-revision.md +1 -1
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +44 -13
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +1 -1
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/specless-probe-fallback.md +1 -1
- package/gsd-core/references/tdd.md +1 -3
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +5 -5
- package/gsd-core/references/verifier-phase-gates.md +192 -0
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -17
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/discussion-log.md +1 -1
- package/gsd-core/templates/phase-prompt.md +5 -4
- package/gsd-core/templates/state.md +11 -4
- package/gsd-core/templates/verification-report.md +9 -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 +3 -3
- package/gsd-core/workflows/add-tests.md +3 -8
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +13 -20
- package/gsd-core/workflows/audit-fix.md +12 -3
- package/gsd-core/workflows/audit-milestone.md +9 -9
- package/gsd-core/workflows/audit-uat.md +17 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +11 -27
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +64 -5
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
- package/gsd-core/workflows/code-review-fix.md +38 -11
- package/gsd-core/workflows/code-review.md +159 -52
- package/gsd-core/workflows/complete-milestone.md +151 -23
- package/gsd-core/workflows/debug.md +12 -8
- package/gsd-core/workflows/diagnose-issues.md +47 -15
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
- package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +3 -6
- package/gsd-core/workflows/docs-update.md +5 -4
- package/gsd-core/workflows/edit-phase.md +27 -2
- package/gsd-core/workflows/eval-review.md +7 -14
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
- 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 +77 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase.md +72 -100
- package/gsd-core/workflows/execute-plan.md +52 -15
- package/gsd-core/workflows/explore.md +131 -4
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +10 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +76 -10
- package/gsd-core/workflows/import.md +18 -15
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +49 -16
- package/gsd-core/workflows/insert-phase.md +5 -5
- package/gsd-core/workflows/list-seeds.md +5 -3
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +12 -23
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +8 -5
- package/gsd-core/workflows/new-milestone.md +22 -29
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +26 -40
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +14 -2
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
- package/gsd-core/workflows/plan-phase.md +162 -59
- package/gsd-core/workflows/plan-review-convergence.md +96 -11
- package/gsd-core/workflows/plant-seed.md +2 -2
- package/gsd-core/workflows/pr-branch.md +187 -51
- package/gsd-core/workflows/profile-user.md +16 -14
- package/gsd-core/workflows/progress.md +61 -18
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
- package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
- package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +55 -44
- package/gsd-core/workflows/remove-phase.md +4 -4
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +8 -12
- package/gsd-core/workflows/review.md +219 -20
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -1
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +69 -7
- package/gsd-core/workflows/ship.md +116 -50
- package/gsd-core/workflows/sketch-wrap-up.md +11 -17
- package/gsd-core/workflows/sketch.md +12 -18
- package/gsd-core/workflows/smart-entry.md +3 -5
- package/gsd-core/workflows/spec-phase.md +53 -13
- package/gsd-core/workflows/spike-wrap-up.md +7 -11
- package/gsd-core/workflows/spike.md +20 -31
- package/gsd-core/workflows/stats.md +2 -2
- package/gsd-core/workflows/sync-skills.md +64 -9
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +49 -14
- package/gsd-core/workflows/ui-phase.md +15 -21
- package/gsd-core/workflows/ui-review.md +8 -12
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +7 -11
- package/gsd-core/workflows/validate-phase.md +3 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +66 -25
- package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
- package/hooks/dist/gsd-check-update-worker.js +56 -13
- package/hooks/dist/gsd-check-update.js +19 -1
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +19 -10
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
- package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +37 -27
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +55 -32
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +231 -24
- package/hooks/dist/gsd-update-banner.js +22 -1
- package/hooks/dist/gsd-validate-commit.sh +80 -6
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +162 -46
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-cmd.js +92 -59
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- 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/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +158 -30
- package/hooks/gsd-check-update-worker.js +56 -13
- package/hooks/gsd-check-update.js +19 -1
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +19 -10
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +2 -3
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +83 -3
- package/hooks/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +37 -27
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +55 -32
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +231 -24
- package/hooks/gsd-update-banner.js +22 -1
- package/hooks/gsd-validate-commit.sh +80 -6
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +162 -46
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +92 -59
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- 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/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +28 -11
- package/pi/gsd.cjs +19 -5
- package/scripts/base64-scan.sh +74 -12
- package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
- package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
- package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
- package/scripts/build-hooks.js +5 -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/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +64 -14
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/command-contract-helpers.cjs +903 -1
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-adr-index.cjs +728 -38
- package/scripts/gen-capability-registry.cjs +11 -21
- package/scripts/gen-context-index.cjs +2 -11
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-health-docs.cjs +390 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-inventory-manifest.cjs +50 -4
- package/scripts/gen-loop-host-contract.cjs +138 -25
- package/scripts/gen-registry.cjs +3 -14
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/alias-drift-families.cjs +46 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +308 -0
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -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-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
- package/scripts/lint-eslint-glob-coverage.cjs +340 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
- package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
- package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
- package/scripts/lint-milestone-window-drift.cjs +468 -0
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +492 -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 +471 -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 +488 -0
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-field-drift.cjs +805 -0
- package/scripts/lint-state-write-path-drift.cjs +950 -0
- package/scripts/lint-test-file-count.allowlist.json +137 -8
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +830 -0
- package/scripts/lint-vendored-deps.cjs +297 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/pr-changed-files.cjs +63 -0
- package/scripts/pr-template-policy.cjs +14 -4
- package/scripts/prompt-injection-scan.sh +100 -14
- package/scripts/require-issue-link-policy.cjs +192 -0
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +24 -7
- package/skills/gsd-autonomous/SKILL.md +0 -1
- package/skills/gsd-code-review/SKILL.md +1 -1
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -2
- package/skills/gsd-import/SKILL.md +1 -1
- 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 +9 -5
- 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/bin/lib/ui-safety-gate.cjs +0 -107
- 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/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/run-affected-tests.cjs +0 -7
- package/scripts/run-tests.cjs +0 -1051
|
@@ -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 };
|
|
@@ -34,6 +35,7 @@ const model_catalog_cjs_1 = require("./model-catalog.cjs");
|
|
|
34
35
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
35
36
|
const node_path_1 = __importDefault(require("node:path"));
|
|
36
37
|
const runtime_name_policy_cjs_1 = require("./runtime-name-policy.cjs");
|
|
38
|
+
const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
|
|
37
39
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
38
40
|
const planningWorkspaceMod = require("./planning-workspace.cjs");
|
|
39
41
|
const { planningDir } = planningWorkspaceMod;
|
|
@@ -57,38 +59,19 @@ const { planningDir } = planningWorkspaceMod;
|
|
|
57
59
|
// registry-parity test guards this set so a future alias-capable runtime fails
|
|
58
60
|
// loudly here instead of silently omitting.
|
|
59
61
|
const RUNTIMES_WITH_NATIVE_ALIASES = new Set(['claude']);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const raw = node_fs_1.default.readFileSync(markerPath, 'utf8').trim();
|
|
67
|
-
_installMarkerCache = raw || null;
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
// No marker: dev/source tree, or an install predating #2297. Fall through to
|
|
71
|
-
// the 'claude' default (keeps tier aliases — never worse than the bug).
|
|
72
|
-
_installMarkerCache = null;
|
|
73
|
-
}
|
|
74
|
-
return _installMarkerCache;
|
|
75
|
-
}
|
|
76
|
-
// Test seams for the install-marker rung (the dev/source tree has no marker, so
|
|
77
|
-
// the file read always bottoms out at 'claude' — these let tests exercise the
|
|
78
|
-
// third precedence rung and reset the module-level cache between cases).
|
|
79
|
-
function _setInstallRuntimeMarkerForTests(value) {
|
|
80
|
-
_installMarkerCache = value;
|
|
81
|
-
}
|
|
82
|
-
function _resetInstallRuntimeMarkerCacheForTests() {
|
|
83
|
-
_installMarkerCache = undefined;
|
|
84
|
-
}
|
|
62
|
+
// #3897 rung 2: the marker reader + its cache and test seams were promoted to
|
|
63
|
+
// the canonical owner, `runtime-slash.cts` (imported above) — this module now
|
|
64
|
+
// consumes that single implementation instead of holding its own copy. N5:
|
|
65
|
+
// behaviour and the seam contract are unchanged by the move; the re-exports
|
|
66
|
+
// below (`export =` at the bottom of this file) preserve every existing
|
|
67
|
+
// caller's `require('./model-resolver.cjs')` surface byte-for-behaviour.
|
|
85
68
|
// The runtime whose install is actually resolving, canonicalized so an alias or
|
|
86
69
|
// case variant (e.g. "claude-code"/"Claude") cannot defeat the native-alias
|
|
87
70
|
// check below (#2297 review). Precedence mirrors resolveRuntime()
|
|
88
71
|
// (runtime-slash.cts): GSD_RUNTIME env → project config.runtime → per-install
|
|
89
72
|
// .gsd-runtime marker → 'claude'.
|
|
90
73
|
function resolveActiveRuntime(config) {
|
|
91
|
-
return (0, runtime_name_policy_cjs_1.resolveRuntimeNameFromCandidates)(process.env['GSD_RUNTIME'], config['runtime'], readInstallRuntimeMarker()) || 'claude';
|
|
74
|
+
return (0, runtime_name_policy_cjs_1.resolveRuntimeNameFromCandidates)(process.env['GSD_RUNTIME'], config['runtime'], (0, runtime_slash_cjs_1.readInstallRuntimeMarker)()) || 'claude';
|
|
92
75
|
}
|
|
93
76
|
// Did the PROJECT's own config (root `.planning/config.json` or the active
|
|
94
77
|
// workstream/project override) explicitly set resolve_model_ids to "omit"?
|
|
@@ -153,7 +136,9 @@ const CLAUDE_POLICY_ID_TO_ALIAS = {
|
|
|
153
136
|
.map(([aliasName, id]) => [id, aliasName])),
|
|
154
137
|
'claude-fable-5': 'fable',
|
|
155
138
|
};
|
|
156
|
-
|
|
139
|
+
// CLAUDE_AGENT_ALIASES moved to ./model-catalog.cts (#3241) — imported above
|
|
140
|
+
// and re-exported below for back-compat (bin/install.js:474,
|
|
141
|
+
// tests/codex-config.test.cjs:24 depend on the name being on this module).
|
|
157
142
|
// Dedupe stderr warnings so repeated agent resolutions don't spam (#1133).
|
|
158
143
|
const _modelPolicyUnmappableWarned = new Set();
|
|
159
144
|
function warnModelPolicyUnmappable(agentType, policyModel, tier) {
|
|
@@ -216,7 +201,7 @@ function mapClaudeOverrideForRuntime(override, configRuntime, agentType) {
|
|
|
216
201
|
if (Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, override)) {
|
|
217
202
|
return CLAUDE_POLICY_ID_TO_ALIAS[override];
|
|
218
203
|
}
|
|
219
|
-
if (CLAUDE_AGENT_ALIASES.has(override))
|
|
204
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(override))
|
|
220
205
|
return override;
|
|
221
206
|
if (override.startsWith('claude-')) {
|
|
222
207
|
warnModelOverrideUnmappable(agentType, override);
|
|
@@ -278,33 +263,161 @@ function resolveModelPolicy(policy, tier) {
|
|
|
278
263
|
return null;
|
|
279
264
|
return budgetEntry.model;
|
|
280
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* #2229 — the profile/phase-type tier for (config, agentType).
|
|
268
|
+
*
|
|
269
|
+
* Extracted verbatim from resolveModelInternal's step 2 so the same expression can
|
|
270
|
+
* answer "which tier did GSD resolve?" without also resolving a model id. The
|
|
271
|
+
* extraction is behaviour-preserving by construction: resolveModelInternal calls
|
|
272
|
+
* straight back into it.
|
|
273
|
+
*
|
|
274
|
+
* Returns null when the agent has no catalog entry and the profile is not `inherit`.
|
|
275
|
+
*/
|
|
276
|
+
function computeProfileTier(config, agentType) {
|
|
277
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
278
|
+
const profile = String(config['model_profile'] || 'balanced').toLowerCase();
|
|
279
|
+
// Own-property guard: agentType is an unvalidated CLI positional (the
|
|
280
|
+
// `resolve-model <agent-type>` argument is never checked against a known
|
|
281
|
+
// agent list), so a prototype-chain agentType ("toString", "constructor")
|
|
282
|
+
// would otherwise return an inherited member from this plain object
|
|
283
|
+
// instead of undefined — verified reachable purely via the CLI.
|
|
284
|
+
const modelProfilesMap = MODEL_PROFILES;
|
|
285
|
+
const agentModels = Object.hasOwn(modelProfilesMap, agentType) ? modelProfilesMap[agentType] : undefined;
|
|
286
|
+
const phaseType = (AGENT_TO_PHASE_TYPE)[agentType];
|
|
287
|
+
const configModels = config['models'];
|
|
288
|
+
const phaseTypeTier = (phaseType && configModels && typeof configModels === 'object')
|
|
289
|
+
? configModels[phaseType]
|
|
290
|
+
: undefined;
|
|
291
|
+
return (phaseTypeTier && model_catalog_cjs_1.VALID_TIERS.has(phaseTypeTier))
|
|
292
|
+
? phaseTypeTier
|
|
293
|
+
: (profile === 'inherit'
|
|
294
|
+
? 'inherit'
|
|
295
|
+
: (agentModels
|
|
296
|
+
// Own-property guard: `profile` is a config-supplied string
|
|
297
|
+
// (config['model_profile'], lower-cased); an already-lowercase
|
|
298
|
+
// prototype-chain key ("constructor", "__proto__") would otherwise
|
|
299
|
+
// return an inherited non-string member instead of falling back to
|
|
300
|
+
// 'balanced' (verified: profile:"constructor"/"__proto__" leaked a
|
|
301
|
+
// function/object through both the tier and model resolution paths).
|
|
302
|
+
? ((Object.hasOwn(agentModels, profile) ? agentModels[profile] : undefined) || agentModels['balanced'])
|
|
303
|
+
: null));
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* #2229 — the effective model TIER for (config, agentType), as a signal a workflow can
|
|
307
|
+
* read: `gsd_run query resolve-model <agent> --pick tier`.
|
|
308
|
+
*
|
|
309
|
+
* Why this is not just "look at the resolved model": on every runtime the installer
|
|
310
|
+
* configures with `resolve_model_ids: "omit"` — which is every non-Claude runtime, see
|
|
311
|
+
* docs/CONFIGURATION.md — resolveModelInternal deliberately returns '' below. A guard
|
|
312
|
+
* keyed on the model id therefore cannot tell a budget-tier run from a top-tier one
|
|
313
|
+
* there, while the tier itself is computed ABOVE that early-return and stays knowable.
|
|
314
|
+
*
|
|
315
|
+
* Honesty contract — this never guesses, because a guard that reports a wrong tier is
|
|
316
|
+
* worse than one that reports none:
|
|
317
|
+
* - a per-agent `model_overrides` pin naming a known alias (or a full Claude id that
|
|
318
|
+
* maps to one) reports that alias;
|
|
319
|
+
* - a pin that maps to nothing reports 'unknown' — a raw model id carries no tier;
|
|
320
|
+
* - `model_profile: inherit` reports 'inherit' — the session model is not ours to name;
|
|
321
|
+
* - an agent with no catalog entry reports 'unknown'.
|
|
322
|
+
*
|
|
323
|
+
* Callers must treat 'unknown' and 'inherit' as "cannot tell", never as "adequate".
|
|
324
|
+
*/
|
|
325
|
+
function resolveTierFromConfig(config, agentType) {
|
|
326
|
+
const rawOverrides = config['model_overrides'];
|
|
327
|
+
const modelOverrides = (rawOverrides && typeof rawOverrides === 'object' && !Array.isArray(rawOverrides))
|
|
328
|
+
? rawOverrides
|
|
329
|
+
: null;
|
|
330
|
+
// Own-property guard: agentType is a caller-supplied string (the
|
|
331
|
+
// `resolve-model <agent-type>` CLI positional is not validated against a
|
|
332
|
+
// known agent list); a prototype-chain agentType ("toString",
|
|
333
|
+
// "constructor") against ANY model_overrides object — even `{}` — would
|
|
334
|
+
// otherwise return an inherited member instead of undefined.
|
|
335
|
+
const override = (modelOverrides && Object.hasOwn(modelOverrides, agentType))
|
|
336
|
+
? modelOverrides[agentType]
|
|
337
|
+
: undefined;
|
|
338
|
+
if (override && typeof override === 'string') {
|
|
339
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(override))
|
|
340
|
+
return override;
|
|
341
|
+
// Own-property guard: this indexes a plain object with a config-supplied
|
|
342
|
+
// string, so a prototype-chain key ("toString", "constructor", "valueOf")
|
|
343
|
+
// would otherwise return an inherited member instead of undefined — and a
|
|
344
|
+
// function-valued tier is dropped entirely by JSON.stringify, silently
|
|
345
|
+
// removing the key a guard depends on.
|
|
346
|
+
const alias = Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, override)
|
|
347
|
+
? CLAUDE_POLICY_ID_TO_ALIAS[override]
|
|
348
|
+
: undefined;
|
|
349
|
+
if (typeof alias === 'string' && alias)
|
|
350
|
+
return alias;
|
|
351
|
+
return 'unknown';
|
|
352
|
+
}
|
|
353
|
+
const profileTier = computeProfileTier(config, agentType);
|
|
354
|
+
// #3282 — mirror resolveModelInternal's step 2.5 (model_policy preset). The
|
|
355
|
+
// profile tier alone under-reports: model_policy can dispatch a DIFFERENT
|
|
356
|
+
// tier than the profile implies (e.g. a `balanced` profile's "sonnet" tier
|
|
357
|
+
// combined with `model_policy: {budget: 'low'}` actually spawns "haiku"),
|
|
358
|
+
// and reporting the profile tier there is exactly the under-report this
|
|
359
|
+
// fixes — a haiku-tier run must never be reported as "sonnet". Skipped
|
|
360
|
+
// under the same condition resolveModelInternal skips it (no tier, or
|
|
361
|
+
// "inherit" — the session model is not ours to name).
|
|
362
|
+
if (profileTier && profileTier !== 'inherit') {
|
|
363
|
+
const mergedPolicy = config['model_policy']
|
|
364
|
+
? { ...config['model_policy'], runtime: config['runtime'] || 'claude' }
|
|
365
|
+
: null;
|
|
366
|
+
const policyModel = resolveModelPolicy(mergedPolicy, profileTier);
|
|
367
|
+
if (policyModel) {
|
|
368
|
+
// Map the policy-resolved id back to a tier alias with the same
|
|
369
|
+
// own-property-guarded lookups used above. If it maps, that alias IS
|
|
370
|
+
// the tier that actually runs — report it (the fix). If it does not
|
|
371
|
+
// map — including every non-Claude runtime, where resolveModelInternal
|
|
372
|
+
// returns the policy model verbatim with no tier meaning — the model
|
|
373
|
+
// carries no tier we can name; report 'unknown' rather than falling
|
|
374
|
+
// back to the profile tier, which would silently reintroduce the
|
|
375
|
+
// under-report this block exists to close.
|
|
376
|
+
const aliasForId = Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, policyModel)
|
|
377
|
+
? CLAUDE_POLICY_ID_TO_ALIAS[policyModel]
|
|
378
|
+
: undefined;
|
|
379
|
+
if (typeof aliasForId === 'string' && aliasForId)
|
|
380
|
+
return aliasForId;
|
|
381
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(policyModel))
|
|
382
|
+
return policyModel;
|
|
383
|
+
return 'unknown';
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return profileTier || 'unknown';
|
|
387
|
+
}
|
|
388
|
+
function resolveTierInternal(cwd, agentType) {
|
|
389
|
+
return resolveTierFromConfig(loadConfig(cwd), agentType);
|
|
390
|
+
}
|
|
281
391
|
function resolveModelInternal(cwd, agentType) {
|
|
282
392
|
const config = loadConfig(cwd);
|
|
283
393
|
// 1. Per-agent override (#2041: map Claude full IDs → Agent-tool aliases on
|
|
284
394
|
// the claude runtime, mirroring the model_policy path #1144; non-Claude
|
|
285
395
|
// runtimes and non-Claude values pass through verbatim).
|
|
286
396
|
const modelOverrides = config['model_overrides'];
|
|
287
|
-
|
|
397
|
+
// Own-property guard (see resolveTierFromConfig above): without it, an
|
|
398
|
+
// agentType of "toString" against `model_overrides: {}` returned the
|
|
399
|
+
// inherited Function.prototype.toString as the resolved "model" — verified
|
|
400
|
+
// reachable purely via the CLI, no override value needed.
|
|
401
|
+
const override = (modelOverrides && Object.hasOwn(modelOverrides, agentType))
|
|
402
|
+
? modelOverrides[agentType]
|
|
403
|
+
: undefined;
|
|
288
404
|
if (override) {
|
|
289
405
|
const mapped = mapClaudeOverrideForRuntime(override, config['runtime'], agentType);
|
|
290
406
|
if (mapped !== null)
|
|
291
407
|
return mapped;
|
|
292
408
|
// Unmappable Claude ID — fall through to tier resolution (matches model_policy).
|
|
293
409
|
}
|
|
294
|
-
// 2. Compute the tier
|
|
410
|
+
// 2. Compute the tier (#2229: shared with resolveTierFromConfig so the tier a
|
|
411
|
+
// workflow reads and the tier a model is resolved from can never diverge).
|
|
295
412
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
296
413
|
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));
|
|
414
|
+
// Own-property guard (see computeProfileTier above): without it, agentType
|
|
415
|
+
// "toString" returned Function.prototype.toString as `agentModels`
|
|
416
|
+
// (truthy), which skipped the "unknown agent" fallback below and made
|
|
417
|
+
// resolveModelInternal return undefined instead of a tier-derived string.
|
|
418
|
+
const modelProfilesMapForModel = MODEL_PROFILES;
|
|
419
|
+
const agentModels = Object.hasOwn(modelProfilesMapForModel, agentType) ? modelProfilesMapForModel[agentType] : undefined;
|
|
420
|
+
const tier = computeProfileTier(config, agentType);
|
|
308
421
|
// 2.5. model_policy preset (#49, #1133)
|
|
309
422
|
const configRuntime = config['runtime'];
|
|
310
423
|
if (tier && tier !== 'inherit') {
|
|
@@ -320,11 +433,13 @@ function resolveModelInternal(cwd, agentType) {
|
|
|
320
433
|
return policyModel;
|
|
321
434
|
// Claude Code's Agent tool takes tier aliases (opus/sonnet/haiku/fable),
|
|
322
435
|
// not full model IDs — map the policy-resolved ID back to an alias (#1133).
|
|
323
|
-
const aliasForId = CLAUDE_POLICY_ID_TO_ALIAS
|
|
324
|
-
|
|
436
|
+
const aliasForId = Object.hasOwn(CLAUDE_POLICY_ID_TO_ALIAS, policyModel)
|
|
437
|
+
? CLAUDE_POLICY_ID_TO_ALIAS[policyModel]
|
|
438
|
+
: undefined;
|
|
439
|
+
if (typeof aliasForId === 'string' && aliasForId)
|
|
325
440
|
return aliasForId;
|
|
326
441
|
// The policy value may already be a bare Claude agent alias (e.g. "fable").
|
|
327
|
-
if (CLAUDE_AGENT_ALIASES.has(policyModel))
|
|
442
|
+
if (model_catalog_cjs_1.CLAUDE_AGENT_ALIASES.has(policyModel))
|
|
328
443
|
return policyModel;
|
|
329
444
|
// No Claude alias for this ID (e.g. a pinned minor version like
|
|
330
445
|
// claude-opus-4-5). Warn once and fall through to the tier alias rather
|
|
@@ -415,7 +530,13 @@ function resolveModelForTier(cwd, agentType, attempt) {
|
|
|
415
530
|
const config = loadConfig(cwd);
|
|
416
531
|
const attemptN = Number.isInteger(attempt) && attempt > 0 ? attempt : 0;
|
|
417
532
|
const modelOverrides = config['model_overrides'];
|
|
418
|
-
|
|
533
|
+
// Own-property guard (see resolveTierFromConfig above): without it, an
|
|
534
|
+
// agentType of "toString" against `model_overrides: {}` returned the
|
|
535
|
+
// inherited Function.prototype.toString as the resolved "model" — verified
|
|
536
|
+
// reachable purely via the CLI, no override value needed.
|
|
537
|
+
const override = (modelOverrides && Object.hasOwn(modelOverrides, agentType))
|
|
538
|
+
? modelOverrides[agentType]
|
|
539
|
+
: undefined;
|
|
419
540
|
if (override) {
|
|
420
541
|
const mapped = mapClaudeOverrideForRuntime(override, config['runtime'], agentType);
|
|
421
542
|
if (mapped !== null)
|
|
@@ -533,7 +654,12 @@ function resolveProviderEscalation(cwd, agentType, attempt, applicable) {
|
|
|
533
654
|
}
|
|
534
655
|
// ─── #443 — Unified effort + fast_mode resolvers ─────────────────────────────
|
|
535
656
|
const VALID_EFFORTS = ['minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
536
|
-
|
|
657
|
+
// #3533 (10d): the VOCABULARY carries one more member than the LADDER —
|
|
658
|
+
// 'inherit' is a declarable effort choice ("follow the session", expressed by
|
|
659
|
+
// OMITTING the effort key at the writer) but not a level nextEffort may step
|
|
660
|
+
// into. Keeping it out of VALID_EFFORTS means escalation (resolveEffortForTier)
|
|
661
|
+
// never walks past an explicit inherit: nextEffort('inherit') is null.
|
|
662
|
+
const EFFORT_SET = new Set([...VALID_EFFORTS, 'inherit']);
|
|
537
663
|
/**
|
|
538
664
|
* Walk one step up the effort ladder from `e`.
|
|
539
665
|
*/
|
|
@@ -576,26 +702,23 @@ function resolveEffortInternal(cwd, agentType, opts) {
|
|
|
576
702
|
}
|
|
577
703
|
}
|
|
578
704
|
// Step 3: routing_tier_defaults by agent's default tier.
|
|
705
|
+
// #3531 (10c): the config block merges OVER the manifest tier defaults
|
|
706
|
+
// rather than replacing them — an effort block without
|
|
707
|
+
// routing_tier_defaults (or missing this agent's tier) falls back to the
|
|
708
|
+
// manifest built-in for that tier instead of skipping to effort.default.
|
|
709
|
+
// Invalid config values are dropped by the merge, so the manifest value for
|
|
710
|
+
// the tier surfaces (the same "invalid falls through" rule every layer has).
|
|
579
711
|
const agentTier = (AGENT_DEFAULT_TIERS)[agentType];
|
|
580
712
|
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
|
-
}
|
|
713
|
+
const canonicalEffort = (configuration_cjs_1.CONFIG_DEFAULTS)['effort'];
|
|
714
|
+
const manifestDefaults = canonicalEffort && typeof canonicalEffort === 'object'
|
|
715
|
+
? canonicalEffort['routing_tier_defaults']
|
|
716
|
+
: undefined;
|
|
717
|
+
const isValidEffort = (v) => typeof v === 'string' && EFFORT_SET.has(v);
|
|
718
|
+
const merged = (0, model_catalog_cjs_1.mergeEffortTierDefaults)(manifestDefaults, effortCfg ? effortCfg['routing_tier_defaults'] : undefined, isValidEffort);
|
|
719
|
+
const v = merged[agentTier];
|
|
720
|
+
if (isValidEffort(v))
|
|
721
|
+
return v;
|
|
599
722
|
}
|
|
600
723
|
// Step 4: effort.default
|
|
601
724
|
if (effortCfg) {
|
|
@@ -693,13 +816,15 @@ function resolveEffortForTier(cwd, agentType, attempt) {
|
|
|
693
816
|
}
|
|
694
817
|
module.exports = {
|
|
695
818
|
resolveTierEntry,
|
|
696
|
-
CLAUDE_AGENT_ALIASES,
|
|
819
|
+
CLAUDE_AGENT_ALIASES: model_catalog_cjs_1.CLAUDE_AGENT_ALIASES,
|
|
697
820
|
resolveModelPolicy,
|
|
698
821
|
resolveModelInternal,
|
|
822
|
+
resolveTierInternal,
|
|
823
|
+
resolveTierFromConfig,
|
|
699
824
|
_resetModelPolicyWarningCacheForTests,
|
|
700
825
|
_resetModelOverrideWarningCacheForTests,
|
|
701
|
-
_setInstallRuntimeMarkerForTests,
|
|
702
|
-
_resetInstallRuntimeMarkerCacheForTests,
|
|
826
|
+
_setInstallRuntimeMarkerForTests: runtime_slash_cjs_1._setInstallRuntimeMarkerForTests,
|
|
827
|
+
_resetInstallRuntimeMarkerCacheForTests: runtime_slash_cjs_1._resetInstallRuntimeMarkerCacheForTests,
|
|
703
828
|
VALID_GRANULARITIES,
|
|
704
829
|
resolveGranularityInternal,
|
|
705
830
|
assertValidGranularityOverride,
|
|
@@ -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.
|
|
@@ -117,7 +117,11 @@ function listPlanningDocCandidates(cwd) {
|
|
|
117
117
|
return [...candidates].sort();
|
|
118
118
|
}
|
|
119
119
|
function listCodebaseMapFiles(cwd) {
|
|
120
|
-
|
|
120
|
+
// #3964: project-scoped, agreeing with init's map-codebase surface and
|
|
121
|
+
// verify.cts's codebase drift check — a flat-root read made
|
|
122
|
+
// has_codebase_map/needs_codebase_map answer for the wrong project under
|
|
123
|
+
// GSD_PROJECT.
|
|
124
|
+
const codebaseDir = node_path_1.default.join(planningDir(cwd), 'codebase');
|
|
121
125
|
if (!node_fs_1.default.existsSync(codebaseDir))
|
|
122
126
|
return [];
|
|
123
127
|
return REQUIRED_CODEBASE_MAP_FILES.filter((file) => node_fs_1.default.existsSync(node_path_1.default.join(codebaseDir, file)));
|
|
@@ -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
|
+
}
|
|
@@ -218,20 +218,29 @@ function applyCalibration(rawTokens, factor) {
|
|
|
218
218
|
* Extract a two-space-indented scalar block (`estimate:` / `actuals:`) out of a
|
|
219
219
|
* document's leading YAML frontmatter.
|
|
220
220
|
*
|
|
221
|
-
* Hand-rolled
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
221
|
+
* Hand-rolled for its TYPE CONTRACT, not for dependency availability — js-yaml
|
|
222
|
+
* is vendored and available at runtime as of ADR-3473 §8.1 (#3881), which
|
|
223
|
+
* migrated `src/frontmatter.cts`'s `extractFrontmatter` onto it. That parser
|
|
224
|
+
* runs under js-yaml's FAILSAFE_SCHEMA, which resolves every scalar as a
|
|
225
|
+
* string, whereas this function deliberately returns numbers for
|
|
226
|
+
* numeric-looking values (`out[m[1]] = asNumber : rawValue`) so
|
|
227
|
+
* `parseEstimate`/`parseActuals` see the types they validate. A naive swap
|
|
228
|
+
* onto `extractFrontmatter` would turn `tokens: 5000` into `"5000"` and make
|
|
229
|
+
* `isPositiveInt` reject every estimate. Scope is deliberately narrow: the
|
|
230
|
+
* leading `---` block only, so an `estimate:` line inside a fenced code
|
|
231
|
+
* block in the body cannot be mistaken for frontmatter (the
|
|
232
|
+
* DEFECT.FRONTMATTER-SCALAR-BROAD-GREP class). Migrating this function onto
|
|
233
|
+
* the shared parser (with a typed coercion layer over its string-only
|
|
234
|
+
* output) is tracked as follow-on work under ADR-3473 §8.1, not done here —
|
|
235
|
+
* this module is calibration-critical and has a history of subtle numeric
|
|
236
|
+
* defects shipping past a large green suite (#2631 factor², #2632
|
|
237
|
+
* self-defeating loop).
|
|
229
238
|
*/
|
|
230
239
|
function extractFrontmatterBlock(text, key) {
|
|
231
240
|
if (typeof text !== 'string')
|
|
232
241
|
return null;
|
|
233
242
|
// Anchor at byte 0 — CRLF-tolerant.
|
|
234
|
-
const fm = /^---\r?\n([\s\S]*?)\r?\n
|
|
243
|
+
const fm = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|\r?$)/.exec(text);
|
|
235
244
|
if (fm === null)
|
|
236
245
|
return null;
|
|
237
246
|
const lines = fm[1].split(/\r?\n/);
|