@opengsd/gsd-core 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +78 -42
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +0 -1
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +3 -1
- package/agents/gsd-plan-checker.md +91 -112
- package/agents/gsd-planner.md +20 -4
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +82 -7
- package/agents/gsd-ui-researcher.md +70 -3
- package/agents/gsd-verifier.md +24 -2
- package/bin/install.js +847 -200
- 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/ns-workflow.md +2 -1
- package/commands/gsd/phase.md +1 -1
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/quick.md +8 -4
- package/commands/gsd/surface.md +18 -8
- package/gsd-core/bin/gsd-tools.cjs +761 -100
- package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
- package/gsd-core/bin/lib/api-coverage.cjs +30 -9
- package/gsd-core/bin/lib/artifacts.cjs +2 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
- package/gsd-core/bin/lib/audit.cjs +163 -41
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +785 -144
- package/gsd-core/bin/lib/capability-state.cjs +25 -4
- package/gsd-core/bin/lib/capability-validator.cjs +321 -18
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +229 -6
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
- package/gsd-core/bin/lib/command-aliases.cjs +16 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +877 -54
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +121 -29
- package/gsd-core/bin/lib/config.cjs +92 -2
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +118 -14
- package/gsd-core/bin/lib/decisions.cjs +213 -1
- package/gsd-core/bin/lib/edge-probe.cjs +23 -2
- 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/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +975 -326
- package/gsd-core/bin/lib/gap-checker.cjs +41 -8
- package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
- package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
- package/gsd-core/bin/lib/host-integration.cjs +96 -11
- package/gsd-core/bin/lib/init-command-router.cjs +132 -21
- package/gsd-core/bin/lib/init.cjs +252 -56
- package/gsd-core/bin/lib/install-engine.cjs +252 -15
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
- package/gsd-core/bin/lib/install-profiles.cjs +100 -18
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +195 -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/loop-resolver.cjs +14 -8
- package/gsd-core/bin/lib/markdown-table.cjs +175 -4
- package/gsd-core/bin/lib/milestone.cjs +112 -7
- package/gsd-core/bin/lib/model-catalog.cjs +177 -19
- package/gsd-core/bin/lib/model-resolver.cjs +10 -28
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/phase-command-router.cjs +13 -6
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +321 -13
- package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
- package/gsd-core/bin/lib/phase-locator.cjs +138 -17
- package/gsd-core/bin/lib/phase.cjs +1175 -115
- package/gsd-core/bin/lib/plan-document.cjs +273 -0
- package/gsd-core/bin/lib/plan-scan.cjs +13 -2
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +165 -34
- package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
- package/gsd-core/bin/lib/probe-core.cjs +4 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +62 -14
- package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
- package/gsd-core/bin/lib/roadmap.cjs +248 -64
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +75 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -31
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +47 -18
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +216 -5
- package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
- package/gsd-core/bin/lib/state-transition.cjs +850 -145
- package/gsd-core/bin/lib/state.cjs +1629 -287
- package/gsd-core/bin/lib/surface.cjs +33 -10
- 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/tdd-red-evidence.cjs +133 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
- package/gsd-core/bin/lib/uat.cjs +2542 -387
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
- package/gsd-core/bin/lib/unusable-input.cjs +13 -0
- package/gsd-core/bin/lib/update-context.cjs +6 -2
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +230 -12
- package/gsd-core/bin/lib/vendor/README.md +43 -5
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +287 -13
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +441 -56
- package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +185 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/bin/verify-reapply-patches.cjs +70 -3
- package/gsd-core/references/agent-contracts.md +6 -5
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +37 -19
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/edge-probe.md +17 -5
- package/gsd-core/references/execute-mvp-tdd.md +18 -18
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +3 -3
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +22 -0
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/mvp-concepts.md +2 -2
- 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/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +76 -3
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +39 -9
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/tdd.md +15 -12
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +2 -2
- package/gsd-core/references/verifier-evidence-gate.md +160 -0
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +11 -11
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/phase-prompt.md +7 -0
- package/gsd-core/templates/state.md +7 -0
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +3 -1
- package/gsd-core/workflows/add-phase.md +5 -3
- package/gsd-core/workflows/add-tests.md +4 -9
- package/gsd-core/workflows/add-todo.md +2 -2
- package/gsd-core/workflows/ai-integration-phase.md +5 -10
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +14 -3
- package/gsd-core/workflows/audit-milestone.md +11 -9
- package/gsd-core/workflows/audit-uat.md +19 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +12 -26
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/cleanup.md +3 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
- package/gsd-core/workflows/code-review-fix.md +3 -1
- package/gsd-core/workflows/code-review.md +192 -69
- package/gsd-core/workflows/complete-milestone.md +28 -14
- package/gsd-core/workflows/debug.md +6 -4
- package/gsd-core/workflows/diagnose-issues.md +17 -7
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/do.md +46 -19
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +3 -1
- package/gsd-core/workflows/eval-review.md +5 -10
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -11
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +29 -5
- 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 +4 -2
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +68 -66
- package/gsd-core/workflows/execute-plan.md +25 -20
- package/gsd-core/workflows/explore.md +3 -1
- package/gsd-core/workflows/extract-learnings.md +3 -1
- package/gsd-core/workflows/fast.md +8 -2
- package/gsd-core/workflows/forensics.md +3 -1
- package/gsd-core/workflows/graduation.md +6 -6
- package/gsd-core/workflows/health.md +4 -7
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +2 -0
- package/gsd-core/workflows/import.md +17 -14
- package/gsd-core/workflows/inbox.md +5 -6
- package/gsd-core/workflows/ingest-docs.md +45 -12
- package/gsd-core/workflows/insert-phase.md +7 -5
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +7 -3
- package/gsd-core/workflows/list-workspaces.md +3 -1
- package/gsd-core/workflows/manager.md +15 -26
- package/gsd-core/workflows/map-codebase.md +3 -1
- package/gsd-core/workflows/milestone-summary.md +3 -1
- package/gsd-core/workflows/mvp-phase.md +3 -3
- package/gsd-core/workflows/new-milestone.md +10 -22
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +17 -29
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +4 -2
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +20 -5
- 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 +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
- package/gsd-core/workflows/plan-phase.md +251 -54
- package/gsd-core/workflows/plan-review-convergence.md +148 -19
- package/gsd-core/workflows/plant-seed.md +3 -3
- package/gsd-core/workflows/pr-branch.md +195 -51
- package/gsd-core/workflows/profile-user.md +17 -15
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +52 -15
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +33 -32
- package/gsd-core/workflows/reapply-patches.md +2 -0
- package/gsd-core/workflows/remove-phase.md +6 -4
- package/gsd-core/workflows/remove-workspace.md +3 -3
- package/gsd-core/workflows/resume-project.md +14 -14
- package/gsd-core/workflows/review.md +404 -21
- package/gsd-core/workflows/scan.md +3 -1
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +9 -9
- package/gsd-core/workflows/settings-integrations.md +66 -32
- package/gsd-core/workflows/settings.md +4 -6
- package/gsd-core/workflows/ship.md +22 -16
- package/gsd-core/workflows/sketch-wrap-up.md +13 -17
- package/gsd-core/workflows/sketch.md +13 -19
- package/gsd-core/workflows/smart-entry.md +4 -6
- package/gsd-core/workflows/spec-phase.md +31 -4
- package/gsd-core/workflows/spike-wrap-up.md +9 -11
- package/gsd-core/workflows/spike.md +21 -32
- package/gsd-core/workflows/stats.md +4 -2
- package/gsd-core/workflows/sync-skills.md +13 -5
- package/gsd-core/workflows/thread.md +13 -7
- package/gsd-core/workflows/transition.md +7 -5
- package/gsd-core/workflows/ui-phase.md +36 -21
- package/gsd-core/workflows/ui-review.md +7 -11
- package/gsd-core/workflows/ultraplan-phase.md +7 -13
- package/gsd-core/workflows/undo.md +9 -17
- package/gsd-core/workflows/update.md +47 -48
- 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 +106 -21
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +302 -22
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +77 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +46 -12
- package/hooks/dist/gsd-read-guard.js +18 -7
- package/hooks/dist/gsd-read-injection-scanner.js +22 -13
- package/hooks/dist/gsd-secret-read-guard.js +1079 -0
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +222 -29
- package/hooks/dist/gsd-validate-commit.sh +523 -12
- 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 +36 -17
- 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 +210 -1
- 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 +36 -6
- package/hooks/dist/managed-hooks-registry.cjs +4 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +302 -22
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +3 -1
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +28 -23
- package/hooks/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +77 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +46 -12
- package/hooks/gsd-read-guard.js +18 -7
- package/hooks/gsd-read-injection-scanner.js +22 -13
- package/hooks/gsd-secret-read-guard.js +1079 -0
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +222 -29
- package/hooks/gsd-validate-commit.sh +523 -12
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +36 -17
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/hooks.json +6 -0
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/managed-hooks-registry.cjs +4 -0
- package/package.json +14 -9
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +12 -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 +52 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +406 -0
- package/scripts/gen-capability-registry.cjs +8 -6
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-loop-host-contract.cjs +189 -4
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +32 -2
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +45 -14
- package/scripts/lint-phase-id-drift.cjs +133 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-removed-but-needed.cjs +184 -16
- package/scripts/lint-response-language-coverage.cjs +524 -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-write-path-drift.cjs +337 -432
- package/scripts/lint-test-file-count.allowlist.json +124 -4
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +51 -64
- package/scripts/lint-vendored-deps.cjs +208 -35
- package/scripts/lint-workflow-shellcheck-baseline.json +1027 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +83 -14
- package/scripts/require-issue-link-policy.cjs +16 -1
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +22 -3
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -109
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/state-write-path-drift-baseline.json +0 -19
|
@@ -32,6 +32,7 @@ const retiredArtifactCleanup = require("./retired-artifact-cleanup.cjs");
|
|
|
32
32
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
33
33
|
const external_descriptor_trust_cjs_1 = require("./external-descriptor-trust.cjs");
|
|
34
34
|
const commonjs_marker_cjs_1 = require("./commonjs-marker.cjs");
|
|
35
|
+
const testHomeGuard = require("./real-home-guard.cjs");
|
|
35
36
|
// #2874 (ADR-58 cleanup phase): the injectable fs seam for the
|
|
36
37
|
// installRuntimeArtifacts call tree. `installFs()` resolves to real
|
|
37
38
|
// `node:fs` unless a call is wrapped in `withInstallFs(deps.fs, ...)` —
|
|
@@ -54,6 +55,148 @@ const { processAttribution } = runtimeArtifactConversion;
|
|
|
54
55
|
// resolveRuntimeArtifactLayout: accessed via module ref (not destructured) so
|
|
55
56
|
// test stubs that monkeypatch the module's exports are seen at call time.
|
|
56
57
|
const { getDirName } = runtimeNamePolicy;
|
|
58
|
+
function withInstallerPackageSource(configDir, fn) {
|
|
59
|
+
// Reuse the existing compatibility-marker contract through the existing fs
|
|
60
|
+
// seam. The marker exists only in this synchronous call tree: no disk state,
|
|
61
|
+
// layout export, stage argument, or caller-settable authority flag is added.
|
|
62
|
+
const markerPath = node_path_1.default.resolve(configDir, '.gsd-source');
|
|
63
|
+
const packageCommandsRoot = runtimeArtifactLayout.findInstallSourceRoot();
|
|
64
|
+
const markerBytes = Buffer.from(packageCommandsRoot + '\n');
|
|
65
|
+
const base = installFs();
|
|
66
|
+
const overlay = {
|
|
67
|
+
...base,
|
|
68
|
+
existsSync: (candidate) => node_path_1.default.resolve(candidate) === markerPath || base.existsSync(candidate),
|
|
69
|
+
lstatSync: (candidate) => node_path_1.default.resolve(candidate) === markerPath
|
|
70
|
+
? { isFile: () => true, isDirectory: () => false, isSymbolicLink: () => false }
|
|
71
|
+
: base.lstatSync(candidate),
|
|
72
|
+
readFileSync: ((candidate, encoding) => {
|
|
73
|
+
if (node_path_1.default.resolve(candidate) !== markerPath) {
|
|
74
|
+
return encoding ? base.readFileSync(candidate, encoding) : base.readFileSync(candidate);
|
|
75
|
+
}
|
|
76
|
+
return encoding ? markerBytes.toString(encoding) : Buffer.from(markerBytes);
|
|
77
|
+
}),
|
|
78
|
+
};
|
|
79
|
+
return withInstallFs(overlay, fn);
|
|
80
|
+
}
|
|
81
|
+
function isRuntimeSurfaceSourceUnavailable(message) {
|
|
82
|
+
return message.startsWith('Runtime Surface source is unavailable or incomplete for ') &&
|
|
83
|
+
message.endsWith('install or upgrade gsd-core before materializing this surface.');
|
|
84
|
+
}
|
|
85
|
+
function assertCorpusTreeHasNoSymlinks(root) {
|
|
86
|
+
if (!installFs().existsSync(root))
|
|
87
|
+
return;
|
|
88
|
+
const stat = installFs().lstatSync(root);
|
|
89
|
+
if (stat.isSymbolicLink()) {
|
|
90
|
+
throw new Error(`Runtime Surface corpus path is a symlink: ${root}`);
|
|
91
|
+
}
|
|
92
|
+
if (!stat.isDirectory())
|
|
93
|
+
return;
|
|
94
|
+
for (const name of installFs().readdirSync(root)) {
|
|
95
|
+
assertCorpusTreeHasNoSymlinks(node_path_1.default.join(root, name));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function previousOwnedCorpusFiles(configDir, prefix) {
|
|
99
|
+
try {
|
|
100
|
+
const files = installerMigrations.readInstallManifest(configDir).files;
|
|
101
|
+
return Object.keys(files)
|
|
102
|
+
.filter((entry) => entry.startsWith(prefix))
|
|
103
|
+
.map((entry) => entry.slice(prefix.length))
|
|
104
|
+
.filter((entry) => entry !== '' && !node_path_1.default.posix.isAbsolute(entry) && !entry.split('/').some((part) => part === '' || part === '.' || part === '..'));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// An absent or unreadable prior manifest provides no ownership evidence.
|
|
108
|
+
// Preserve existing entries rather than guessing that they are stale.
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function pruneEmptyCorpusParents(start, stop) {
|
|
113
|
+
let current = node_path_1.default.dirname(start);
|
|
114
|
+
while (current !== stop && current.startsWith(stop + node_path_1.default.sep)) {
|
|
115
|
+
if (installFs().readdirSync(current).length > 0)
|
|
116
|
+
return;
|
|
117
|
+
installFs().rmdirSync(current);
|
|
118
|
+
current = node_path_1.default.dirname(current);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function syncRuntimeSurfaceCorpus(source, destination, configDir, manifestPrefix) {
|
|
122
|
+
if (hasExistingSymlinkBetween(node_path_1.default.resolve(configDir), destination, { allowOptInFollow: isSymlinkedDestOptIn() })) {
|
|
123
|
+
throw new Error(`syncRuntimeSurfaceCorpus: destination "${destination}" contains a symlink the install root "${configDir}" does not trust — refusing to write.`);
|
|
124
|
+
}
|
|
125
|
+
assertCorpusTreeHasNoSymlinks(destination);
|
|
126
|
+
// Remove only paths the previous manifest proves GSD owned and which the
|
|
127
|
+
// executing package no longer ships. Unknown neighbouring files survive.
|
|
128
|
+
for (const relative of previousOwnedCorpusFiles(configDir, manifestPrefix)) {
|
|
129
|
+
const sourceEntry = node_path_1.default.join(source, ...relative.split('/'));
|
|
130
|
+
let sourceIsFile = false;
|
|
131
|
+
try {
|
|
132
|
+
sourceIsFile = installFs().lstatSync(sourceEntry).isFile();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
sourceIsFile = false;
|
|
136
|
+
}
|
|
137
|
+
if (sourceIsFile)
|
|
138
|
+
continue;
|
|
139
|
+
const target = node_path_1.default.join(destination, ...relative.split('/'));
|
|
140
|
+
if (!installFs().existsSync(target))
|
|
141
|
+
continue;
|
|
142
|
+
const targetStat = installFs().lstatSync(target);
|
|
143
|
+
if (!targetStat.isFile()) {
|
|
144
|
+
throw new Error(`Runtime Surface corpus ownership conflict at ${target}`);
|
|
145
|
+
}
|
|
146
|
+
installFs().rmSync(target, { force: true });
|
|
147
|
+
pruneEmptyCorpusParents(target, destination);
|
|
148
|
+
}
|
|
149
|
+
installFs().mkdirSync(node_path_1.default.dirname(destination), { recursive: true });
|
|
150
|
+
installFs().cpSync(source, destination, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Provision the raw, installation-owned input needed to re-materialize a
|
|
154
|
+
* global Runtime Surface after the executing package tree disappears.
|
|
155
|
+
*
|
|
156
|
+
* The corpus deliberately lives below the already-installed `gsd-core/`
|
|
157
|
+
* tree and is accepted only after its manifest ownership and hashes verify.
|
|
158
|
+
* The compatibility marker does not replace that installed-corpus authority.
|
|
159
|
+
*/
|
|
160
|
+
function provisionRuntimeSurfaceCorpus(layout, configDir, scope) {
|
|
161
|
+
const required = new Set();
|
|
162
|
+
if ((0, install_scope_cjs_1.isGlobalScope)(scope)) {
|
|
163
|
+
for (const kind of layout.kinds) {
|
|
164
|
+
if (kind.kind === 'commands' || kind.kind === 'skills')
|
|
165
|
+
required.add('commands');
|
|
166
|
+
if (kind.kind === 'agents' || kind.kind === 'kimi-agents')
|
|
167
|
+
required.add('agents');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (required.size === 0)
|
|
171
|
+
return;
|
|
172
|
+
const corpusRoot = node_path_1.default.join(configDir, 'gsd-core');
|
|
173
|
+
if (required.has('commands')) {
|
|
174
|
+
const source = runtimeArtifactLayout.findInstallSourceRoot();
|
|
175
|
+
const destination = node_path_1.default.join(corpusRoot, 'commands', 'gsd');
|
|
176
|
+
syncRuntimeSurfaceCorpus(source, destination, configDir, 'gsd-core/commands/gsd/');
|
|
177
|
+
}
|
|
178
|
+
if (required.has('agents')) {
|
|
179
|
+
const source = node_path_1.default.join(executingPackageRoot(), 'agents');
|
|
180
|
+
const destination = node_path_1.default.join(corpusRoot, 'agents');
|
|
181
|
+
syncRuntimeSurfaceCorpus(source, destination, configDir, 'gsd-core/agents/');
|
|
182
|
+
}
|
|
183
|
+
const markerFile = _hostBehaviors(layout.runtime).sourceMarkerFile;
|
|
184
|
+
if (typeof markerFile === 'string' && markerFile !== '' && required.has('commands')) {
|
|
185
|
+
try {
|
|
186
|
+
const markerPath = runtimeArtifactInstallPlan.assertDestWithinConfigHome(configDir, markerFile);
|
|
187
|
+
if (hasExistingSymlinkBetween(node_path_1.default.resolve(configDir), markerPath, { allowOptInFollow: isSymlinkedDestOptIn() })) {
|
|
188
|
+
throw new Error(`compatibility marker "${markerPath}" contains an untrusted symlink`);
|
|
189
|
+
}
|
|
190
|
+
installFs().writeFileSync(markerPath, node_path_1.default.join(corpusRoot, 'commands', 'gsd') + '\n', 'utf8');
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// The existing installer marker writer owns the user-facing warning and
|
|
194
|
+
// keeps marker failure non-fatal. The installed corpus remains usable
|
|
195
|
+
// without the compatibility marker.
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function executingPackageRoot() { return node_path_1.default.dirname(node_path_1.default.dirname(runtimeArtifactLayout.findInstallSourceRoot())); }
|
|
57
200
|
// ---------------------------------------------------------------------------
|
|
58
201
|
// USER_OWNED_ARTIFACTS
|
|
59
202
|
// ---------------------------------------------------------------------------
|
|
@@ -409,6 +552,15 @@ function _resolveDevPreferencesSkillTarget(targetDir, runtime, scope = 'global')
|
|
|
409
552
|
// must confine against installRoot, not targetDir, or it would flag the
|
|
410
553
|
// legitimate override destination as an escape.
|
|
411
554
|
let installRoot = targetDir;
|
|
555
|
+
// Reported in Codex review of #3725: `installRoot !== targetDir` was used as the
|
|
556
|
+
// stand-in for "the skills kind declared a `home` override", and the two are NOT
|
|
557
|
+
// equivalent — a resolved `home` that happens to EQUAL targetDir (a configDir of
|
|
558
|
+
// `$HOME/.agents`, which is exactly where codex's override points) makes the
|
|
559
|
+
// inequality false while the override is very much declared, skipping the guard
|
|
560
|
+
// and writing SKILL.md into the real home. Report the declaration itself instead
|
|
561
|
+
// of inferring it from two paths, read off the SAME layout resolution the
|
|
562
|
+
// destination came from so the guard cannot vouch for a path this does not write.
|
|
563
|
+
let hasHomeOverride = false;
|
|
412
564
|
if (runtime) {
|
|
413
565
|
const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, targetDir, scope);
|
|
414
566
|
const skillsKindEntry = layout.kinds.find((k) => k.kind === 'skills');
|
|
@@ -420,6 +572,7 @@ function _resolveDevPreferencesSkillTarget(targetDir, runtime, scope = 'global')
|
|
|
420
572
|
// -> $HOME/.agents) instead of always resolving against targetDir, so a
|
|
421
573
|
// legacy dev-preferences migration lands in the SAME tree the installer
|
|
422
574
|
// and surface-apply use. Runtimes with no `home` override are unaffected.
|
|
575
|
+
hasHomeOverride = skillsKindEntry.home != null;
|
|
423
576
|
installRoot = skillsKindEntry.home ?? targetDir;
|
|
424
577
|
skillDir = node_path_1.default.join(runtimeArtifactInstallPlan.assertDestWithinConfigHome(installRoot, skillsKindEntry.destSubpath), stemName);
|
|
425
578
|
}
|
|
@@ -427,14 +580,42 @@ function _resolveDevPreferencesSkillTarget(targetDir, runtime, scope = 'global')
|
|
|
427
580
|
// Legacy fallback for callers that have not yet been updated to pass runtime
|
|
428
581
|
skillDir = node_path_1.default.join(runtimeArtifactInstallPlan.assertDestWithinConfigHome(targetDir, 'skills'), 'gsd-dev-preferences');
|
|
429
582
|
}
|
|
430
|
-
return { skillFile: node_path_1.default.join(skillDir, 'SKILL.md'), installRoot };
|
|
583
|
+
return { skillFile: node_path_1.default.join(skillDir, 'SKILL.md'), installRoot, hasHomeOverride };
|
|
431
584
|
}
|
|
432
|
-
|
|
585
|
+
/**
|
|
586
|
+
* @param deps - #3712 test seam, mirroring the one on `installRuntimeArtifacts`
|
|
587
|
+
* and `uninstallRuntimeArtifacts`. This is the SIXTH writer that resolves a
|
|
588
|
+
* skills-kind `home`, and its guard's trigger condition — "HOME equals the
|
|
589
|
+
* passwd home" — cannot be reproduced without pointing at the developer's real
|
|
590
|
+
* home, so it is injected rather than simulated. Production callers pass
|
|
591
|
+
* nothing and bind real `os`/`process.env`.
|
|
592
|
+
*/
|
|
593
|
+
function migrateLegacyDevPreferencesToSkill(targetDir, saved, runtime, scope = 'global', deps = {}) {
|
|
433
594
|
if (!saved || !saved.has('dev-preferences.md'))
|
|
434
595
|
return false;
|
|
435
596
|
const target = _resolveDevPreferencesSkillTarget(targetDir, runtime, scope);
|
|
436
597
|
if (!target)
|
|
437
598
|
return false; // runtime has no skills layout at this scope (e.g. cline local)
|
|
599
|
+
// #3712 — the SIXTH writer that resolves a skills-kind `home` override.
|
|
600
|
+
// Exported and directly callable, and `_runLegacyInstallMigrations` runs it
|
|
601
|
+
// BEFORE installRuntimeArtifacts' own assertion, so a future runtime pairing a
|
|
602
|
+
// home override with this migration would write to the real home ahead of any
|
|
603
|
+
// guard. It creates rather than prunes, which is why it was missed.
|
|
604
|
+
//
|
|
605
|
+
// Guards the destination ALREADY RESOLVED above, never a second resolution of
|
|
606
|
+
// its own. An earlier revision re-ran resolveRuntimeArtifactLayout() here —
|
|
607
|
+
// and without `capabilityRegistry`, so a registry-dependent descriptor could
|
|
608
|
+
// make the two disagree and leave the guard vouching for a path the migration
|
|
609
|
+
// does not write. That is the generative-fix-divergence shape; reported in
|
|
610
|
+
// review of #3725. `target.hasHomeOverride` is that same resolution's own answer
|
|
611
|
+
// to "did the skills kind declare a `home`?" — not re-derived, and not inferred
|
|
612
|
+
// from `installRoot !== targetDir`, which is false whenever the override happens
|
|
613
|
+
// to resolve onto targetDir itself (Codex review of #3725).
|
|
614
|
+
if (runtime && target.hasHomeOverride) {
|
|
615
|
+
testHomeGuard.assertTestHomeSandboxed('migrateLegacyDevPreferencesToSkill', runtime, [
|
|
616
|
+
{ kind: 'skills', home: node_path_1.default.dirname(target.skillFile) },
|
|
617
|
+
], { os: deps.os, env: deps.env });
|
|
618
|
+
}
|
|
438
619
|
const { skillFile, installRoot } = target;
|
|
439
620
|
const skillDir = node_path_1.default.dirname(skillFile);
|
|
440
621
|
// Security fix: `existsSync` FOLLOWS symlinks and reports `false` for a
|
|
@@ -938,6 +1119,7 @@ function _runLegacyUninstallCleanup(runtime, configDir, scope = 'global') {
|
|
|
938
1119
|
*/
|
|
939
1120
|
function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, resolveAttribution = () => undefined, capabilityRegistry, deps = {}) {
|
|
940
1121
|
return withInstallFs(deps.fs, () => {
|
|
1122
|
+
const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, configDir, scope, capabilityRegistry);
|
|
941
1123
|
// A removed descriptor kind is no longer visited by the layout loop, so it
|
|
942
1124
|
// cannot prune its own previous output. Clean manifest-proven retired files
|
|
943
1125
|
// before materializing the current layout (#2644).
|
|
@@ -947,6 +1129,7 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
|
|
|
947
1129
|
// generic layout-driven loop below, mirroring the bespoke install path that
|
|
948
1130
|
// previously lived inline in bin/install.js.
|
|
949
1131
|
const behaviors = _hostBehaviors(runtime);
|
|
1132
|
+
const projectDir = scope === 'global' ? process.cwd() : configDir;
|
|
950
1133
|
if (behaviors.combinedFamilyInstall) {
|
|
951
1134
|
// #2329: combined-family runtimes (OpenCode/Kilo) bypass
|
|
952
1135
|
// _runLegacyInstallMigrations below entirely (early return), so their
|
|
@@ -955,12 +1138,24 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
|
|
|
955
1138
|
// #2874 design row 2: this early return must ALSO return an executed
|
|
956
1139
|
// plan — installOpencodeFamilyArtifacts reports what it wrote, so a
|
|
957
1140
|
// whole runtime family returning undefined is no longer a hole.
|
|
958
|
-
|
|
1141
|
+
// An injected filesystem supplies its own hermetic corpus fixture. The
|
|
1142
|
+
// real installer is the authority that refreshes package bytes into the
|
|
1143
|
+
// durable installed corpus; attempting that cross-filesystem copy through
|
|
1144
|
+
// an in-memory destination adapter would read from the wrong filesystem.
|
|
1145
|
+
if (!deps.fs)
|
|
1146
|
+
provisionRuntimeSurfaceCorpus(layout, configDir, scope);
|
|
1147
|
+
return installOpencodeFamilyArtifacts(runtime, configDir, scope, resolvedProfile, resolveAttribution, behaviors, capabilityRegistry, deps.packageRoot, projectDir);
|
|
959
1148
|
}
|
|
960
1149
|
// Legacy cleanup before layout-driven writes
|
|
961
1150
|
_runLegacyInstallMigrations(runtime, configDir, scope);
|
|
962
|
-
|
|
963
|
-
|
|
1151
|
+
if (!deps.fs)
|
|
1152
|
+
provisionRuntimeSurfaceCorpus(layout, configDir, scope);
|
|
1153
|
+
// #3712: a global `home` override escapes the sandboxed configDir. Refuse to
|
|
1154
|
+
// execute when a test run would land that escape in the developer's real home.
|
|
1155
|
+
testHomeGuard.assertTestHomeSandboxed('installRuntimeArtifacts', runtime, layout?.kinds, {
|
|
1156
|
+
os: deps.os, env: deps.env,
|
|
1157
|
+
});
|
|
1158
|
+
const createPlan = () => runtimeArtifactInstallPlan.createRuntimeArtifactInstallPlan({
|
|
964
1159
|
// `Layout` is structurally identical across the layout/install-plan .cjs
|
|
965
1160
|
// modules but nominally distinct to tsc (untyped .cjs boundary) — bridge it.
|
|
966
1161
|
layout: layout,
|
|
@@ -968,7 +1163,16 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
|
|
|
968
1163
|
homedir: () => node_os_1.default.homedir(),
|
|
969
1164
|
platform: process.platform,
|
|
970
1165
|
resolveAttribution,
|
|
1166
|
+
projectDir,
|
|
971
1167
|
});
|
|
1168
|
+
let planResult = createPlan();
|
|
1169
|
+
if (scope === 'global' &&
|
|
1170
|
+
!planResult.ok &&
|
|
1171
|
+
planResult.kind === 'stage_failed' &&
|
|
1172
|
+
planResult.cleanupDirs.length === 0 &&
|
|
1173
|
+
isRuntimeSurfaceSourceUnavailable(planResult.message)) {
|
|
1174
|
+
planResult = withInstallerPackageSource(configDir, createPlan);
|
|
1175
|
+
}
|
|
972
1176
|
const cleanupDirs = planResult.ok ? planResult.plan.cleanupDirs : planResult.cleanupDirs;
|
|
973
1177
|
// #2874 row 1/4/5: per-kind executed-plan entries, appended only as the
|
|
974
1178
|
// loop below actually finishes writing each kind — a kind that throws
|
|
@@ -1132,8 +1336,10 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
|
|
|
1132
1336
|
// is safe even when configDir has no .gsd-source marker (artifactLayout: []).
|
|
1133
1337
|
let nativePluginInstalled = false;
|
|
1134
1338
|
if (behaviors.nativePlugin) {
|
|
1135
|
-
|
|
1136
|
-
|
|
1339
|
+
// Native plugin sources live only in the executing package, never in the
|
|
1340
|
+
// durable Runtime Surface corpus. Do not derive this package root from a
|
|
1341
|
+
// config-scoped provider that may now correctly resolve installed input.
|
|
1342
|
+
const src = deps.packageRoot ?? executingPackageRoot();
|
|
1137
1343
|
_installNativePluginIfDeclared(runtime, configDir, behaviors, src);
|
|
1138
1344
|
nativePluginInstalled = true;
|
|
1139
1345
|
}
|
|
@@ -1183,6 +1389,13 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
|
|
|
1183
1389
|
const skillsKindEntry = layout.kinds.find((k) => k.kind === 'skills');
|
|
1184
1390
|
if (!skillsKindEntry)
|
|
1185
1391
|
return 0;
|
|
1392
|
+
// #3712: combined-family runtimes take installRuntimeArtifacts' early return
|
|
1393
|
+
// BEFORE its guard runs, and this writer honors `skillsKindEntry.home` below and
|
|
1394
|
+
// then prunes that destination. opencode/kilo declare no `home` today, so there
|
|
1395
|
+
// is no live escape — but that makes this a bypass waiting on a descriptor
|
|
1396
|
+
// change rather than a safe omission, so it is guarded at the writer instead.
|
|
1397
|
+
// Scoped to the SKILLS kind alone, for the same reason as the agents writer.
|
|
1398
|
+
testHomeGuard.assertTestHomeSandboxed('installOpencodeFamilySkills', runtime, [skillsKindEntry]);
|
|
1186
1399
|
const rawDir = rawCommandsDir;
|
|
1187
1400
|
if (!rawDir || !installFs().existsSync(rawDir))
|
|
1188
1401
|
return 0;
|
|
@@ -1337,20 +1550,37 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
|
|
|
1337
1550
|
* @param capabilityRegistry - #2362: optional composed capability registry, threaded
|
|
1338
1551
|
* straight through to resolveRuntimeArtifactLayout (unused by the agents kind today,
|
|
1339
1552
|
* but kept for signature parity with the skills/commands siblings on this call tree)
|
|
1553
|
+
* @param projectDir - project/config discovery root, distinct from the artifact destination
|
|
1340
1554
|
* @returns `{ sourceDir, destDir }` describing what was written, or `null` when the
|
|
1341
1555
|
* runtime's layout declares no `agents` kind.
|
|
1342
1556
|
*/
|
|
1343
|
-
function installAgentsKindStandalone(runtime, targetDir, scope, resolvedProfile, pathPrefix, resolveAttribution = () => undefined, capabilityRegistry) {
|
|
1557
|
+
function installAgentsKindStandalone(runtime, targetDir, scope, resolvedProfile, pathPrefix, resolveAttribution = () => undefined, capabilityRegistry, projectDir) {
|
|
1344
1558
|
const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, targetDir, scope, capabilityRegistry);
|
|
1345
|
-
const agentsKindEntry = layout.kinds.find((
|
|
1559
|
+
const agentsKindEntry = layout.kinds.find((kind) => kind.kind === 'agents');
|
|
1346
1560
|
if (!agentsKindEntry)
|
|
1347
1561
|
return null;
|
|
1562
|
+
// #3712: this writer selects `agentsKindEntry.home` over targetDir below and then
|
|
1563
|
+
// prunes that destination via _removeGsdEntries, so it is a fifth route into the
|
|
1564
|
+
// developer's real home. No agents kind declares a `home` override today, so like
|
|
1565
|
+
// installOpencodeFamilySkills it is guarded against a descriptor change rather
|
|
1566
|
+
// than a present escape. Scoped to the AGENTS kind alone: passing the whole
|
|
1567
|
+
// layout made codex's unrelated skills-kind override trip a writer that never
|
|
1568
|
+
// touches it, which is a false refusal, not a tighter guard.
|
|
1569
|
+
testHomeGuard.assertTestHomeSandboxed('installAgentsKindStandalone', runtime, [agentsKindEntry]);
|
|
1348
1570
|
// ADR-1235 §1: same agentCtx shape createRuntimeArtifactInstallPlan builds
|
|
1349
1571
|
// for the generic layout-driven loop (runtime-artifact-install-plan.cts) —
|
|
1350
1572
|
// targetDir IS the install root the inline agent loop called `targetDir`.
|
|
1351
1573
|
const attribution = resolveAttribution ? resolveAttribution(runtime) : undefined;
|
|
1352
|
-
const agentCtx = { runtime, pathPrefix, attribution, targetDir };
|
|
1353
|
-
|
|
1574
|
+
const agentCtx = { runtime, pathPrefix, attribution, targetDir, projectDir: projectDir ?? targetDir };
|
|
1575
|
+
let stagedDir;
|
|
1576
|
+
try {
|
|
1577
|
+
stagedDir = agentsKindEntry.stage(resolvedProfile, agentCtx);
|
|
1578
|
+
}
|
|
1579
|
+
catch (err) {
|
|
1580
|
+
if (scope !== 'global' || !isRuntimeSurfaceSourceUnavailable(err.message))
|
|
1581
|
+
throw err;
|
|
1582
|
+
stagedDir = withInstallerPackageSource(targetDir, () => agentsKindEntry.stage(resolvedProfile, agentCtx));
|
|
1583
|
+
}
|
|
1354
1584
|
const stagedAgentFiles = installFs().existsSync(stagedDir)
|
|
1355
1585
|
? installFs().readdirSync(stagedDir).filter((f) => f.endsWith('.md'))
|
|
1356
1586
|
: [];
|
|
@@ -1611,12 +1841,13 @@ function _migrateLegacyOpencodeCommandDir(runtime, configDir, behaviors) {
|
|
|
1611
1841
|
* installOpencodeFamilySkills so an installed third-party capability skill
|
|
1612
1842
|
* materializes for this combined-family (OpenCode/Kilo) install path too.
|
|
1613
1843
|
* Absent -> no third-party skills staged (fail closed).
|
|
1844
|
+
* @param projectDir - project/config discovery root, distinct from configDir for global installs
|
|
1614
1845
|
* @returns #2874 design row 2: an executed-plan value, same top-level shape
|
|
1615
1846
|
* (`runtime`/`scope`/`kinds`/`cleanup`/`postSteps`) as the generic
|
|
1616
1847
|
* `installRuntimeArtifacts` branch — this was the one early return a
|
|
1617
1848
|
* `void`-shaped hole survived unnoticed in.
|
|
1618
1849
|
*/
|
|
1619
|
-
function installOpencodeFamilyArtifacts(runtime, configDir, scope, resolvedProfile, resolveAttribution = () => undefined, behaviors = {}, capabilityRegistry) {
|
|
1850
|
+
function installOpencodeFamilyArtifacts(runtime, configDir, scope, resolvedProfile, resolveAttribution = () => undefined, behaviors = {}, capabilityRegistry, packageRoot, projectDir) {
|
|
1620
1851
|
// #2870: `scope` keeps its exported required `string` signature (no
|
|
1621
1852
|
// signature change). It is always the `installRuntimeArtifacts`-forwarded
|
|
1622
1853
|
// 'global' | 'local' literal produced by bin/install.js's scope-resolution
|
|
@@ -1629,7 +1860,7 @@ function installOpencodeFamilyArtifacts(runtime, configDir, scope, resolvedProfi
|
|
|
1629
1860
|
// into stageSkillsForProfile/stageSkillsForRuntimeAsSkills. The repo/package
|
|
1630
1861
|
// root (needed below for the native plugin source) is two levels up.
|
|
1631
1862
|
const commandsGsdDir = runtimeArtifactLayout.findInstallSourceRoot(configDir);
|
|
1632
|
-
const src =
|
|
1863
|
+
const src = packageRoot ?? executingPackageRoot();
|
|
1633
1864
|
const rawCommandsDir = installProfiles.stageSkillsForProfile(commandsGsdDir, resolvedProfile);
|
|
1634
1865
|
const pathPrefix = runtimeArtifactConversion._computePathPrefix({
|
|
1635
1866
|
isGlobal,
|
|
@@ -1652,7 +1883,7 @@ function installOpencodeFamilyArtifacts(runtime, configDir, scope, resolvedProfi
|
|
|
1652
1883
|
// generic layout-driven loop uses (see installAgentsKindStandalone's own
|
|
1653
1884
|
// doc). A `null` result means this runtime's layout declares no `agents`
|
|
1654
1885
|
// kind — nothing written, nothing reported (no #1879-F15 inert claim).
|
|
1655
|
-
const agentsResult = installAgentsKindStandalone(runtime, configDir, scope, resolvedProfile, pathPrefix, resolveAttribution, capabilityRegistry);
|
|
1886
|
+
const agentsResult = installAgentsKindStandalone(runtime, configDir, scope, resolvedProfile, pathPrefix, resolveAttribution, capabilityRegistry, projectDir);
|
|
1656
1887
|
_installNativePluginIfDeclared(runtime, configDir, behaviors, src);
|
|
1657
1888
|
// #2874 design row 2: report what this combined-family install wrote,
|
|
1658
1889
|
// mirroring the generic branch's top-level shape. `cleanup` is `[]` — this
|
|
@@ -1683,7 +1914,7 @@ function installOpencodeFamilyArtifacts(runtime, configDir, scope, resolvedProfi
|
|
|
1683
1914
|
* @param configDir resolved runtime config directory
|
|
1684
1915
|
* @param scope
|
|
1685
1916
|
*/
|
|
1686
|
-
function uninstallRuntimeArtifacts(runtime, configDir, scope) {
|
|
1917
|
+
function uninstallRuntimeArtifacts(runtime, configDir, scope, deps = {}) {
|
|
1687
1918
|
// A retired descriptor kind is absent from the current uninstall plan, just
|
|
1688
1919
|
// as it is absent from the install plan. Sweep manifest-proven output from
|
|
1689
1920
|
// retired kinds before removing the current layout so a direct uninstall
|
|
@@ -1695,6 +1926,12 @@ function uninstallRuntimeArtifacts(runtime, configDir, scope) {
|
|
|
1695
1926
|
// (the layout's gsd-* prefix pass would wipe a skill dir created here).
|
|
1696
1927
|
const stagedLegacyArtifacts = _runLegacyUninstallCleanup(runtime, configDir, scope);
|
|
1697
1928
|
const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, configDir, scope);
|
|
1929
|
+
// #3712: uninstall resolves the SAME `kind.home` override as install and then
|
|
1930
|
+
// prunes it via _removeGsdEntries below, so it is a second escape route into
|
|
1931
|
+
// the developer's real home, not a read-only path. Guard it identically.
|
|
1932
|
+
testHomeGuard.assertTestHomeSandboxed('uninstallRuntimeArtifacts', runtime, layout?.kinds, {
|
|
1933
|
+
os: deps.os, env: deps.env,
|
|
1934
|
+
});
|
|
1698
1935
|
const plan = runtimeArtifactInstallPlan.createRuntimeArtifactUninstallPlan(layout);
|
|
1699
1936
|
const kindsByName = new Map(layout.kinds.map((kind) => [kind.kind, kind]));
|
|
1700
1937
|
for (const item of plan.items) {
|
|
@@ -45,7 +45,7 @@ const modelCatalog = require("./model-catalog.cjs");
|
|
|
45
45
|
const { MODEL_PROFILES: GSD_MODEL_PROFILES } = modelCatalog;
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- model-resolver.cjs is an export= CommonJS module
|
|
47
47
|
const modelResolverModule = require("./model-resolver.cjs");
|
|
48
|
-
const { resolveTierEntry: gsdResolveTierEntry } = modelResolverModule;
|
|
48
|
+
const { resolveTierEntry: gsdResolveTierEntry, resolveModelPolicy: gsdResolveModelPolicy } = modelResolverModule;
|
|
49
49
|
/**
|
|
50
50
|
* Read `model_overrides` from `~/.gsd/defaults.json` at install time.
|
|
51
51
|
* Returns an object mapping agent names to model IDs, or null if the file
|
|
@@ -114,6 +114,50 @@ function readGsdEffectiveModelOverrides(targetDir = null, options = {}) {
|
|
|
114
114
|
// Per-project wins on conflict; preserve non-conflicting global keys.
|
|
115
115
|
return { ...(global || {}), ...(projectOverrides || {}) };
|
|
116
116
|
}
|
|
117
|
+
function readGsdAgentTools(config) {
|
|
118
|
+
const raw = config?.agent_tools;
|
|
119
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
120
|
+
return null;
|
|
121
|
+
const result = {};
|
|
122
|
+
for (const [selector, value] of Object.entries(raw)) {
|
|
123
|
+
// An explicitly present selector always has a verdict. Invalid values are
|
|
124
|
+
// empty so a project config cannot accidentally restore a global grant.
|
|
125
|
+
result[selector] = Array.isArray(value)
|
|
126
|
+
? value.filter((entry) => typeof entry === 'string')
|
|
127
|
+
.map((entry) => entry.trim())
|
|
128
|
+
.filter((entry) => entry.length > 0
|
|
129
|
+
&& !entry.endsWith(':')
|
|
130
|
+
&& !/[\s\u0000-\u001F\u007F-\u009F,#"'\u2028\u2029]/.test(entry))
|
|
131
|
+
: [];
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Resolve valid install-time `agent_tools` grants from global defaults and
|
|
137
|
+
* the nearest project config. Project selectors replace only matching global
|
|
138
|
+
* selectors; malformed whole files remain harmless absence like the existing
|
|
139
|
+
* model override resolver.
|
|
140
|
+
*/
|
|
141
|
+
function readGsdEffectiveAgentTools(targetDir = null, options = {}) {
|
|
142
|
+
const home = options.homedir ? options.homedir() : node_os_1.default.homedir();
|
|
143
|
+
const globalConfig = _readGsdConfigFile(node_path_1.default.join(home, '.gsd', 'defaults.json'), 'global defaults');
|
|
144
|
+
let projectConfig = null;
|
|
145
|
+
if (targetDir) {
|
|
146
|
+
const candidate = _findAncestorGsdConfigPath(targetDir);
|
|
147
|
+
if (candidate) {
|
|
148
|
+
projectConfig = _readGsdConfigFile(candidate, 'project config');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const global = readGsdAgentTools(globalConfig);
|
|
152
|
+
const project = readGsdAgentTools(projectConfig);
|
|
153
|
+
if (projectConfig
|
|
154
|
+
&& Object.prototype.hasOwnProperty.call(projectConfig, 'agent_tools')
|
|
155
|
+
&& project === null)
|
|
156
|
+
return {};
|
|
157
|
+
if (!global && !project)
|
|
158
|
+
return null;
|
|
159
|
+
return { ...(global || {}), ...(project || {}) };
|
|
160
|
+
}
|
|
117
161
|
/**
|
|
118
162
|
* Build a runtime-aware tier resolver for the install path (#2517).
|
|
119
163
|
*
|
|
@@ -145,6 +189,10 @@ function readGsdRuntimeProfileResolver(targetDir = null) {
|
|
|
145
189
|
model_profile_overrides: (projectConfig && projectConfig.model_profile_overrides) ||
|
|
146
190
|
(homeDefaults && homeDefaults.model_profile_overrides) ||
|
|
147
191
|
null,
|
|
192
|
+
// #3705: same project-wins-over-home precedence as every other key here.
|
|
193
|
+
model_policy: (projectConfig && projectConfig.model_policy) ||
|
|
194
|
+
(homeDefaults && homeDefaults.model_policy) ||
|
|
195
|
+
null,
|
|
148
196
|
};
|
|
149
197
|
if (!merged.runtime)
|
|
150
198
|
return null;
|
|
@@ -164,6 +212,34 @@ function readGsdRuntimeProfileResolver(targetDir = null) {
|
|
|
164
212
|
const tier = agentModels[profile] || agentModels.balanced;
|
|
165
213
|
if (!tier)
|
|
166
214
|
return null;
|
|
215
|
+
// #3705: policy sits between the per-agent override and the tier table —
|
|
216
|
+
// the position dispatch uses. Measured against `query resolve-model` on the
|
|
217
|
+
// same config: policy-only -> the policy model; tier-overrides-only -> the
|
|
218
|
+
// override; BOTH -> the policy model. So policy outranks
|
|
219
|
+
// `model_profile_overrides`, and an explicit `model_overrides[agent]`
|
|
220
|
+
// (applied by resolveAgentModelOverride below) outranks policy.
|
|
221
|
+
//
|
|
222
|
+
// Calls the exported owner (#49) rather than re-deriving tier -> model here:
|
|
223
|
+
// a second implementation of that mapping is the very divergence this issue
|
|
224
|
+
// is, one layer down. A null from it (unknown provider, missing tier key, a
|
|
225
|
+
// `runtime_tiers` miss) falls through to the tier table — never to null,
|
|
226
|
+
// which would omit a frontmatter key that used to be written.
|
|
227
|
+
// The policy object must carry the effective runtime before it is resolved.
|
|
228
|
+
// `resolveModelPolicy`'s `runtime_tiers` branch reads `policy['runtime']`, but
|
|
229
|
+
// the documented config shape (docs/CONFIGURATION.md) puts `runtime` at the
|
|
230
|
+
// TOP level and keeps only `provider`/`runtime_tiers` inside `model_policy`.
|
|
231
|
+
// Dispatch injects it — `{ ...config.model_policy, runtime: effectiveRuntime }`
|
|
232
|
+
// (model-resolver.cts) — and passing the policy unmodified here silently
|
|
233
|
+
// skipped `runtime_tiers` entirely, falling through to the flat hi/med/lo keys
|
|
234
|
+
// or the catalog tier. That is the same "catalog Anthropic ID baked over a
|
|
235
|
+
// configured provider" defect this fix exists to close, so the injection is
|
|
236
|
+
// mirrored rather than assumed.
|
|
237
|
+
const policyForRuntime = merged.model_policy
|
|
238
|
+
? { ...merged.model_policy, runtime }
|
|
239
|
+
: null;
|
|
240
|
+
const policyModel = gsdResolveModelPolicy(policyForRuntime, tier);
|
|
241
|
+
if (policyModel)
|
|
242
|
+
return { model: policyModel };
|
|
167
243
|
return gsdResolveTierEntry({
|
|
168
244
|
runtime,
|
|
169
245
|
tier,
|
|
@@ -198,6 +274,7 @@ function resolveAgentModelOverride(agentName, modelOverrides, runtimeResolver) {
|
|
|
198
274
|
module.exports = {
|
|
199
275
|
readGsdGlobalModelOverrides,
|
|
200
276
|
readGsdEffectiveModelOverrides,
|
|
277
|
+
readGsdEffectiveAgentTools,
|
|
201
278
|
readGsdRuntimeProfileResolver,
|
|
202
279
|
resolveAgentModelOverride,
|
|
203
280
|
};
|