@opengsd/gsd-core 1.11.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 +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 +17 -9
- 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 +15 -55
- package/agents/gsd-planner.md +6 -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 +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +609 -134
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/quick.md +8 -4
- package/gsd-core/bin/gsd-tools.cjs +567 -51
- 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-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +336 -95
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-validator.cjs +205 -18
- package/gsd-core/bin/lib/check-command-router.cjs +145 -5
- 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 +410 -4
- 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 +543 -44
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +118 -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 +84 -7
- 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/frontmatter.cjs +840 -305
- package/gsd-core/bin/lib/gap-checker.cjs +27 -3
- package/gsd-core/bin/lib/git-base-branch.cjs +174 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +6 -3
- 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 +39 -6
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +120 -41
- package/gsd-core/bin/lib/install-engine.cjs +68 -3
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +33 -1
- package/gsd-core/bin/lib/install-profiles.cjs +78 -4
- 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 +10 -7
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +160 -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-table.cjs +52 -4
- package/gsd-core/bin/lib/milestone.cjs +90 -5
- 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-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +70 -4
- 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 +405 -84
- package/gsd-core/bin/lib/plan-document.cjs +263 -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 +18 -14
- package/gsd-core/bin/lib/planning-workspace.cjs +56 -0
- 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/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 +9 -9
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +79 -16
- package/gsd-core/bin/lib/roadmap.cjs +74 -19
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +96 -8
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +34 -1
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +287 -55
- 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 +71 -8
- package/gsd-core/bin/lib/smart-entry.cjs +12 -22
- 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 +186 -0
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +517 -101
- package/gsd-core/bin/lib/state.cjs +946 -163
- package/gsd-core/bin/lib/surface.cjs +10 -2
- 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/uat-predicate.cjs +58 -20
- package/gsd-core/bin/lib/uat.cjs +1376 -125
- 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/validate-command-router.cjs +2 -2
- 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.cjs +14 -1
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +95 -40
- 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 +177 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -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/references/agent-contracts.md +3 -2
- 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 +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +1 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- 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 +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/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-human-verify-mode.md +15 -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 +37 -8
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/runtime-aware-dispatch.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 +2 -2
- 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 +3 -0
- package/gsd-core/templates/state.md +7 -0
- 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 +4 -9
- 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 +10 -26
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +1 -1
- package/gsd-core/workflows/code-review.md +121 -40
- package/gsd-core/workflows/complete-milestone.md +15 -10
- package/gsd-core/workflows/debug.md +5 -3
- package/gsd-core/workflows/diagnose-issues.md +12 -6
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +3 -7
- 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 +2 -2
- 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 +1 -1
- package/gsd-core/workflows/eval-review.md +4 -9
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +113 -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 +22 -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 +38 -54
- package/gsd-core/workflows/execute-plan.md +17 -12
- package/gsd-core/workflows/explore.md +1 -1
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +2 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +3 -6
- package/gsd-core/workflows/import.md +14 -11
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +44 -11
- 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 +2 -2
- package/gsd-core/workflows/new-milestone.md +9 -21
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +12 -26
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -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 +121 -42
- package/gsd-core/workflows/plan-review-convergence.md +46 -9
- 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 +27 -12
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -3
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +2 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +20 -29
- 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 +193 -15
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +2 -2
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +3 -5
- package/gsd-core/workflows/ship.md +12 -6
- 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 +23 -1
- 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 +1 -1
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +5 -5
- package/gsd-core/workflows/ui-phase.md +10 -16
- package/gsd-core/workflows/ui-review.md +6 -10
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +6 -10
- package/gsd-core/workflows/validate-phase.md +2 -2
- 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 +57 -18
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- 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 +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 +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +16 -7
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +17 -8
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +215 -26
- 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 +34 -16
- 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-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- 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 +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 +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +16 -7
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +17 -8
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +215 -26
- 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 +34 -16
- 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-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +12 -7
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +5 -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 +45 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +396 -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 +134 -1
- 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/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 +193 -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 +21 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-removed-but-needed.cjs +184 -16
- 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 +122 -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/mutation-matrix.cjs +599 -50
- package/scripts/prompt-injection-scan.sh +75 -14
- 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-import/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- 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, ...)` —
|
|
@@ -409,6 +410,15 @@ function _resolveDevPreferencesSkillTarget(targetDir, runtime, scope = 'global')
|
|
|
409
410
|
// must confine against installRoot, not targetDir, or it would flag the
|
|
410
411
|
// legitimate override destination as an escape.
|
|
411
412
|
let installRoot = targetDir;
|
|
413
|
+
// Reported in Codex review of #3725: `installRoot !== targetDir` was used as the
|
|
414
|
+
// stand-in for "the skills kind declared a `home` override", and the two are NOT
|
|
415
|
+
// equivalent — a resolved `home` that happens to EQUAL targetDir (a configDir of
|
|
416
|
+
// `$HOME/.agents`, which is exactly where codex's override points) makes the
|
|
417
|
+
// inequality false while the override is very much declared, skipping the guard
|
|
418
|
+
// and writing SKILL.md into the real home. Report the declaration itself instead
|
|
419
|
+
// of inferring it from two paths, read off the SAME layout resolution the
|
|
420
|
+
// destination came from so the guard cannot vouch for a path this does not write.
|
|
421
|
+
let hasHomeOverride = false;
|
|
412
422
|
if (runtime) {
|
|
413
423
|
const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, targetDir, scope);
|
|
414
424
|
const skillsKindEntry = layout.kinds.find((k) => k.kind === 'skills');
|
|
@@ -420,6 +430,7 @@ function _resolveDevPreferencesSkillTarget(targetDir, runtime, scope = 'global')
|
|
|
420
430
|
// -> $HOME/.agents) instead of always resolving against targetDir, so a
|
|
421
431
|
// legacy dev-preferences migration lands in the SAME tree the installer
|
|
422
432
|
// and surface-apply use. Runtimes with no `home` override are unaffected.
|
|
433
|
+
hasHomeOverride = skillsKindEntry.home != null;
|
|
423
434
|
installRoot = skillsKindEntry.home ?? targetDir;
|
|
424
435
|
skillDir = node_path_1.default.join(runtimeArtifactInstallPlan.assertDestWithinConfigHome(installRoot, skillsKindEntry.destSubpath), stemName);
|
|
425
436
|
}
|
|
@@ -427,14 +438,42 @@ function _resolveDevPreferencesSkillTarget(targetDir, runtime, scope = 'global')
|
|
|
427
438
|
// Legacy fallback for callers that have not yet been updated to pass runtime
|
|
428
439
|
skillDir = node_path_1.default.join(runtimeArtifactInstallPlan.assertDestWithinConfigHome(targetDir, 'skills'), 'gsd-dev-preferences');
|
|
429
440
|
}
|
|
430
|
-
return { skillFile: node_path_1.default.join(skillDir, 'SKILL.md'), installRoot };
|
|
441
|
+
return { skillFile: node_path_1.default.join(skillDir, 'SKILL.md'), installRoot, hasHomeOverride };
|
|
431
442
|
}
|
|
432
|
-
|
|
443
|
+
/**
|
|
444
|
+
* @param deps - #3712 test seam, mirroring the one on `installRuntimeArtifacts`
|
|
445
|
+
* and `uninstallRuntimeArtifacts`. This is the SIXTH writer that resolves a
|
|
446
|
+
* skills-kind `home`, and its guard's trigger condition — "HOME equals the
|
|
447
|
+
* passwd home" — cannot be reproduced without pointing at the developer's real
|
|
448
|
+
* home, so it is injected rather than simulated. Production callers pass
|
|
449
|
+
* nothing and bind real `os`/`process.env`.
|
|
450
|
+
*/
|
|
451
|
+
function migrateLegacyDevPreferencesToSkill(targetDir, saved, runtime, scope = 'global', deps = {}) {
|
|
433
452
|
if (!saved || !saved.has('dev-preferences.md'))
|
|
434
453
|
return false;
|
|
435
454
|
const target = _resolveDevPreferencesSkillTarget(targetDir, runtime, scope);
|
|
436
455
|
if (!target)
|
|
437
456
|
return false; // runtime has no skills layout at this scope (e.g. cline local)
|
|
457
|
+
// #3712 — the SIXTH writer that resolves a skills-kind `home` override.
|
|
458
|
+
// Exported and directly callable, and `_runLegacyInstallMigrations` runs it
|
|
459
|
+
// BEFORE installRuntimeArtifacts' own assertion, so a future runtime pairing a
|
|
460
|
+
// home override with this migration would write to the real home ahead of any
|
|
461
|
+
// guard. It creates rather than prunes, which is why it was missed.
|
|
462
|
+
//
|
|
463
|
+
// Guards the destination ALREADY RESOLVED above, never a second resolution of
|
|
464
|
+
// its own. An earlier revision re-ran resolveRuntimeArtifactLayout() here —
|
|
465
|
+
// and without `capabilityRegistry`, so a registry-dependent descriptor could
|
|
466
|
+
// make the two disagree and leave the guard vouching for a path the migration
|
|
467
|
+
// does not write. That is the generative-fix-divergence shape; reported in
|
|
468
|
+
// review of #3725. `target.hasHomeOverride` is that same resolution's own answer
|
|
469
|
+
// to "did the skills kind declare a `home`?" — not re-derived, and not inferred
|
|
470
|
+
// from `installRoot !== targetDir`, which is false whenever the override happens
|
|
471
|
+
// to resolve onto targetDir itself (Codex review of #3725).
|
|
472
|
+
if (runtime && target.hasHomeOverride) {
|
|
473
|
+
testHomeGuard.assertTestHomeSandboxed('migrateLegacyDevPreferencesToSkill', runtime, [
|
|
474
|
+
{ kind: 'skills', home: node_path_1.default.dirname(target.skillFile) },
|
|
475
|
+
], { os: deps.os, env: deps.env });
|
|
476
|
+
}
|
|
438
477
|
const { skillFile, installRoot } = target;
|
|
439
478
|
const skillDir = node_path_1.default.dirname(skillFile);
|
|
440
479
|
// Security fix: `existsSync` FOLLOWS symlinks and reports `false` for a
|
|
@@ -960,6 +999,11 @@ function installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile, res
|
|
|
960
999
|
// Legacy cleanup before layout-driven writes
|
|
961
1000
|
_runLegacyInstallMigrations(runtime, configDir, scope);
|
|
962
1001
|
const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, configDir, scope, capabilityRegistry);
|
|
1002
|
+
// #3712: a global `home` override escapes the sandboxed configDir. Refuse to
|
|
1003
|
+
// execute when a test run would land that escape in the developer's real home.
|
|
1004
|
+
testHomeGuard.assertTestHomeSandboxed('installRuntimeArtifacts', runtime, layout?.kinds, {
|
|
1005
|
+
os: deps.os, env: deps.env,
|
|
1006
|
+
});
|
|
963
1007
|
const planResult = runtimeArtifactInstallPlan.createRuntimeArtifactInstallPlan({
|
|
964
1008
|
// `Layout` is structurally identical across the layout/install-plan .cjs
|
|
965
1009
|
// modules but nominally distinct to tsc (untyped .cjs boundary) — bridge it.
|
|
@@ -1183,6 +1227,13 @@ function installOpencodeFamilySkills(runtime, targetDir, rawCommandsDir, pathPre
|
|
|
1183
1227
|
const skillsKindEntry = layout.kinds.find((k) => k.kind === 'skills');
|
|
1184
1228
|
if (!skillsKindEntry)
|
|
1185
1229
|
return 0;
|
|
1230
|
+
// #3712: combined-family runtimes take installRuntimeArtifacts' early return
|
|
1231
|
+
// BEFORE its guard runs, and this writer honors `skillsKindEntry.home` below and
|
|
1232
|
+
// then prunes that destination. opencode/kilo declare no `home` today, so there
|
|
1233
|
+
// is no live escape — but that makes this a bypass waiting on a descriptor
|
|
1234
|
+
// change rather than a safe omission, so it is guarded at the writer instead.
|
|
1235
|
+
// Scoped to the SKILLS kind alone, for the same reason as the agents writer.
|
|
1236
|
+
testHomeGuard.assertTestHomeSandboxed('installOpencodeFamilySkills', runtime, [skillsKindEntry]);
|
|
1186
1237
|
const rawDir = rawCommandsDir;
|
|
1187
1238
|
if (!rawDir || !installFs().existsSync(rawDir))
|
|
1188
1239
|
return 0;
|
|
@@ -1345,6 +1396,14 @@ function installAgentsKindStandalone(runtime, targetDir, scope, resolvedProfile,
|
|
|
1345
1396
|
const agentsKindEntry = layout.kinds.find((k) => k.kind === 'agents');
|
|
1346
1397
|
if (!agentsKindEntry)
|
|
1347
1398
|
return null;
|
|
1399
|
+
// #3712: this writer selects `agentsKindEntry.home` over targetDir below and then
|
|
1400
|
+
// prunes that destination via _removeGsdEntries, so it is a fifth route into the
|
|
1401
|
+
// developer's real home. No agents kind declares a `home` override today, so like
|
|
1402
|
+
// installOpencodeFamilySkills it is guarded against a descriptor change rather
|
|
1403
|
+
// than a present escape. Scoped to the AGENTS kind alone: passing the whole
|
|
1404
|
+
// layout made codex's unrelated skills-kind override trip a writer that never
|
|
1405
|
+
// touches it, which is a false refusal, not a tighter guard.
|
|
1406
|
+
testHomeGuard.assertTestHomeSandboxed('installAgentsKindStandalone', runtime, [agentsKindEntry]);
|
|
1348
1407
|
// ADR-1235 §1: same agentCtx shape createRuntimeArtifactInstallPlan builds
|
|
1349
1408
|
// for the generic layout-driven loop (runtime-artifact-install-plan.cts) —
|
|
1350
1409
|
// targetDir IS the install root the inline agent loop called `targetDir`.
|
|
@@ -1683,7 +1742,7 @@ function installOpencodeFamilyArtifacts(runtime, configDir, scope, resolvedProfi
|
|
|
1683
1742
|
* @param configDir resolved runtime config directory
|
|
1684
1743
|
* @param scope
|
|
1685
1744
|
*/
|
|
1686
|
-
function uninstallRuntimeArtifacts(runtime, configDir, scope) {
|
|
1745
|
+
function uninstallRuntimeArtifacts(runtime, configDir, scope, deps = {}) {
|
|
1687
1746
|
// A retired descriptor kind is absent from the current uninstall plan, just
|
|
1688
1747
|
// as it is absent from the install plan. Sweep manifest-proven output from
|
|
1689
1748
|
// retired kinds before removing the current layout so a direct uninstall
|
|
@@ -1695,6 +1754,12 @@ function uninstallRuntimeArtifacts(runtime, configDir, scope) {
|
|
|
1695
1754
|
// (the layout's gsd-* prefix pass would wipe a skill dir created here).
|
|
1696
1755
|
const stagedLegacyArtifacts = _runLegacyUninstallCleanup(runtime, configDir, scope);
|
|
1697
1756
|
const layout = runtimeArtifactLayout.resolveRuntimeArtifactLayout(runtime, configDir, scope);
|
|
1757
|
+
// #3712: uninstall resolves the SAME `kind.home` override as install and then
|
|
1758
|
+
// prunes it via _removeGsdEntries below, so it is a second escape route into
|
|
1759
|
+
// the developer's real home, not a read-only path. Guard it identically.
|
|
1760
|
+
testHomeGuard.assertTestHomeSandboxed('uninstallRuntimeArtifacts', runtime, layout?.kinds, {
|
|
1761
|
+
os: deps.os, env: deps.env,
|
|
1762
|
+
});
|
|
1698
1763
|
const plan = runtimeArtifactInstallPlan.createRuntimeArtifactUninstallPlan(layout);
|
|
1699
1764
|
const kindsByName = new Map(layout.kinds.map((kind) => [kind.kind, kind]));
|
|
1700
1765
|
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
|
|
@@ -145,6 +145,10 @@ function readGsdRuntimeProfileResolver(targetDir = null) {
|
|
|
145
145
|
model_profile_overrides: (projectConfig && projectConfig.model_profile_overrides) ||
|
|
146
146
|
(homeDefaults && homeDefaults.model_profile_overrides) ||
|
|
147
147
|
null,
|
|
148
|
+
// #3705: same project-wins-over-home precedence as every other key here.
|
|
149
|
+
model_policy: (projectConfig && projectConfig.model_policy) ||
|
|
150
|
+
(homeDefaults && homeDefaults.model_policy) ||
|
|
151
|
+
null,
|
|
148
152
|
};
|
|
149
153
|
if (!merged.runtime)
|
|
150
154
|
return null;
|
|
@@ -164,6 +168,34 @@ function readGsdRuntimeProfileResolver(targetDir = null) {
|
|
|
164
168
|
const tier = agentModels[profile] || agentModels.balanced;
|
|
165
169
|
if (!tier)
|
|
166
170
|
return null;
|
|
171
|
+
// #3705: policy sits between the per-agent override and the tier table —
|
|
172
|
+
// the position dispatch uses. Measured against `query resolve-model` on the
|
|
173
|
+
// same config: policy-only -> the policy model; tier-overrides-only -> the
|
|
174
|
+
// override; BOTH -> the policy model. So policy outranks
|
|
175
|
+
// `model_profile_overrides`, and an explicit `model_overrides[agent]`
|
|
176
|
+
// (applied by resolveAgentModelOverride below) outranks policy.
|
|
177
|
+
//
|
|
178
|
+
// Calls the exported owner (#49) rather than re-deriving tier -> model here:
|
|
179
|
+
// a second implementation of that mapping is the very divergence this issue
|
|
180
|
+
// is, one layer down. A null from it (unknown provider, missing tier key, a
|
|
181
|
+
// `runtime_tiers` miss) falls through to the tier table — never to null,
|
|
182
|
+
// which would omit a frontmatter key that used to be written.
|
|
183
|
+
// The policy object must carry the effective runtime before it is resolved.
|
|
184
|
+
// `resolveModelPolicy`'s `runtime_tiers` branch reads `policy['runtime']`, but
|
|
185
|
+
// the documented config shape (docs/CONFIGURATION.md) puts `runtime` at the
|
|
186
|
+
// TOP level and keeps only `provider`/`runtime_tiers` inside `model_policy`.
|
|
187
|
+
// Dispatch injects it — `{ ...config.model_policy, runtime: effectiveRuntime }`
|
|
188
|
+
// (model-resolver.cts) — and passing the policy unmodified here silently
|
|
189
|
+
// skipped `runtime_tiers` entirely, falling through to the flat hi/med/lo keys
|
|
190
|
+
// or the catalog tier. That is the same "catalog Anthropic ID baked over a
|
|
191
|
+
// configured provider" defect this fix exists to close, so the injection is
|
|
192
|
+
// mirrored rather than assumed.
|
|
193
|
+
const policyForRuntime = merged.model_policy
|
|
194
|
+
? { ...merged.model_policy, runtime }
|
|
195
|
+
: null;
|
|
196
|
+
const policyModel = gsdResolveModelPolicy(policyForRuntime, tier);
|
|
197
|
+
if (policyModel)
|
|
198
|
+
return { model: policyModel };
|
|
167
199
|
return gsdResolveTierEntry({
|
|
168
200
|
runtime,
|
|
169
201
|
tier,
|
|
@@ -137,9 +137,79 @@ function parseCallsAgents(content) {
|
|
|
137
137
|
* Also derives calls_agents for each skill by scanning the body text for
|
|
138
138
|
* `gsd-*` agent name references. Agent stems are stored under the special
|
|
139
139
|
* key `_calls_agents_<stem>` so they don't conflict with skill stems.
|
|
140
|
+
*
|
|
141
|
+
* #3798: command bodies are thin delegators — the actual `subagent_type=`
|
|
142
|
+
* spawns live in the workflow files each command references
|
|
143
|
+
* (`@…/workflows/<name>.md`). The agent derivation therefore ALSO reads every
|
|
144
|
+
* workflow file the command references (plus the workflow's steps/ fragments
|
|
145
|
+
* when it is split per the progressive-disclosure pattern) and unions their
|
|
146
|
+
* `gsd-*` tokens into the same `_calls_agents_<stem>` set. Without this,
|
|
147
|
+
* tiered profiles omitted agents their own installed skills spawn
|
|
148
|
+
* (gsd-verifier at execute-phase's verify_phase_goal was the filed repro).
|
|
149
|
+
* Over-inclusion fails safe: a tiered profile installing one extra agent
|
|
150
|
+
* costs bytes, never a broken spawn.
|
|
140
151
|
*/
|
|
141
152
|
const DEFAULT_COMMANDS_DIR = node_path_1.default.resolve(__dirname, '..', '..', '..', 'commands', 'gsd');
|
|
142
|
-
|
|
153
|
+
const DEFAULT_WORKFLOWS_DIR = node_path_1.default.resolve(__dirname, '..', '..', 'workflows');
|
|
154
|
+
/**
|
|
155
|
+
* Collect the `gsd-*` agent tokens from every workflow file a command body
|
|
156
|
+
* references. References are the `workflows/<name>.md` path suffixes the
|
|
157
|
+
* delegating commands embed (`@…/gsd-core/workflows/<name>.md`). A
|
|
158
|
+
* split workflow (workflows/<name>/steps/*.md) contributes its fragments as
|
|
159
|
+
* well, because the parent dispatches into them and the spawns live there.
|
|
160
|
+
*/
|
|
161
|
+
function workflowAgentRefs(content, workflowsDir) {
|
|
162
|
+
const refs = content.match(/workflows\/([a-z0-9][a-z0-9-]*)\.md/g) || [];
|
|
163
|
+
const names = [...new Set(refs.map((r) => r.slice('workflows/'.length)))];
|
|
164
|
+
const tokens = new Set();
|
|
165
|
+
for (const name of names) {
|
|
166
|
+
const direct = node_path_1.default.join(workflowsDir, name);
|
|
167
|
+
let body = null;
|
|
168
|
+
try {
|
|
169
|
+
body = node_fs_1.default.readFileSync(direct, 'utf8');
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
body = null;
|
|
173
|
+
}
|
|
174
|
+
if (body === null)
|
|
175
|
+
continue;
|
|
176
|
+
for (const tok of parseCallsAgents(body))
|
|
177
|
+
tokens.add(tok);
|
|
178
|
+
// Split workflow: union EVERY fragment under the workflow's directory
|
|
179
|
+
// (steps/, modes/, templates/…) — the parent dispatches into these per
|
|
180
|
+
// the progressive-disclosure pattern, and spawns live in all of them
|
|
181
|
+
// (#3798 review: modes/ carried gsd-advisor-researcher's spawn while the
|
|
182
|
+
// parent only named it incidentally in prose).
|
|
183
|
+
const fragDir = node_path_1.default.join(workflowsDir, name.slice(0, -3));
|
|
184
|
+
const walk = (dir) => {
|
|
185
|
+
let frags;
|
|
186
|
+
try {
|
|
187
|
+
frags = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
for (const frag of frags) {
|
|
193
|
+
const full = node_path_1.default.join(dir, frag.name);
|
|
194
|
+
if (frag.isDirectory()) {
|
|
195
|
+
walk(full);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (!frag.isFile() || !frag.name.endsWith('.md'))
|
|
199
|
+
continue;
|
|
200
|
+
try {
|
|
201
|
+
const fragBody = node_fs_1.default.readFileSync(full, 'utf8');
|
|
202
|
+
for (const tok of parseCallsAgents(fragBody))
|
|
203
|
+
tokens.add(tok);
|
|
204
|
+
}
|
|
205
|
+
catch { /* unreadable fragment — skip */ }
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
walk(fragDir);
|
|
209
|
+
}
|
|
210
|
+
return [...tokens];
|
|
211
|
+
}
|
|
212
|
+
function loadSkillsManifest(commandsDir = DEFAULT_COMMANDS_DIR, workflowsDir = DEFAULT_WORKFLOWS_DIR) {
|
|
143
213
|
const manifest = new Map();
|
|
144
214
|
if (!node_fs_1.default.existsSync(commandsDir))
|
|
145
215
|
return manifest;
|
|
@@ -153,9 +223,12 @@ function loadSkillsManifest(commandsDir = DEFAULT_COMMANDS_DIR) {
|
|
|
153
223
|
try {
|
|
154
224
|
const content = node_fs_1.default.readFileSync(node_path_1.default.join(commandsDir, entry.name), 'utf8');
|
|
155
225
|
manifest.set(stem, parseRequires(content));
|
|
156
|
-
// Derive agent references from body text
|
|
157
|
-
const agentRefs =
|
|
158
|
-
|
|
226
|
+
// Derive agent references from body text + the workflows it delegates to
|
|
227
|
+
const agentRefs = [
|
|
228
|
+
...parseCallsAgents(content),
|
|
229
|
+
...workflowAgentRefs(content, workflowsDir),
|
|
230
|
+
];
|
|
231
|
+
manifest.set(`_calls_agents_${stem}`, [...new Set(agentRefs)]);
|
|
159
232
|
}
|
|
160
233
|
catch {
|
|
161
234
|
manifest.set(stem, []);
|
|
@@ -1156,6 +1229,7 @@ module.exports = {
|
|
|
1156
1229
|
// Shared internals
|
|
1157
1230
|
parseRequires,
|
|
1158
1231
|
parseCallsAgents,
|
|
1232
|
+
workflowAgentRefs,
|
|
1159
1233
|
cleanupStagedSkills,
|
|
1160
1234
|
// #2322: capability-skill security seams — exported for direct unit-testing
|
|
1161
1235
|
// and for surface.cts's prune pass (CAPABILITY_SKILL_MARKER parity).
|
|
@@ -48,6 +48,9 @@ exports.BUNDLED_GSD_HOOK_FILES = Object.freeze(new Set([
|
|
|
48
48
|
'hooks/gsd-windsurf-pre-command.js',
|
|
49
49
|
'hooks/gsd-ensure-canonical-path.js',
|
|
50
50
|
'hooks/gsd-graphify-update.sh',
|
|
51
|
+
// #3662: portable node resolver staged into hooks/ (not itself a lifecycle
|
|
52
|
+
// hook — managed JS hook commands route through it under --portable-hooks).
|
|
53
|
+
'hooks/gsd-node-runner.sh',
|
|
51
54
|
'hooks/gsd-phase-boundary.sh',
|
|
52
55
|
'hooks/gsd-prompt-guard.js',
|
|
53
56
|
'hooks/gsd-read-guard.js',
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Installer migration: retire Antigravity's configHome skills/agents surfaces (#3738).
|
|
4
|
+
*
|
|
5
|
+
* Antigravity's machine-local discovery scans ~/.gemini/config/{skills,agents}
|
|
6
|
+
* (antigravity.google/docs/skills, /docs/subagents); the configHome
|
|
7
|
+
* (~/.gemini/antigravity{,-ide,-cli}) is not scanned for global artifacts, so
|
|
8
|
+
* skills installed there are silently ignored. Since #3738 the global layout
|
|
9
|
+
* declares a `home: ".gemini/config"` override for both kinds, and new
|
|
10
|
+
* installs land in the scanned dir. This migration converges an existing
|
|
11
|
+
* installation: manifest-managed files under the configHome's skills/ and
|
|
12
|
+
* agents/ subtrees are removed (modified ones backed up first), unmanifested
|
|
13
|
+
* files are preserved, and now-empty container directories are retired.
|
|
14
|
+
*
|
|
15
|
+
* Scope is GLOBAL only: the local workspace layout (.agents/skills,
|
|
16
|
+
* .agents/agents) is the documented, still-live surface and is never touched.
|
|
17
|
+
*
|
|
18
|
+
* Is the action safe in non-interactive install?
|
|
19
|
+
* Yes. Every emitted action type (`remove-managed`, `backup-and-remove`,
|
|
20
|
+
* `remove-empty-dir`) is non-interactive and journaled; none requires a
|
|
21
|
+
* user choice, and unknown files never produce an action.
|
|
22
|
+
*
|
|
23
|
+
* See docs/installer-migrations.md#shipped-migrations and the antigravity row
|
|
24
|
+
* of docs/installer-migrations.md#runtime-configuration-contract-registry.
|
|
25
|
+
*/
|
|
26
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
27
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
28
|
+
};
|
|
29
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
30
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
31
|
+
/** The two retired configHome-relative artifact subpaths. */
|
|
32
|
+
const RETIRED_SUBPATHS = ['skills', 'agents'];
|
|
33
|
+
/** Only GSD-owned top-level entries are retirement candidates. */
|
|
34
|
+
const GSD_PREFIX = 'gsd-';
|
|
35
|
+
const FILE_REASON = 'Antigravity scans ~/.gemini/config/{skills,agents} for global discovery and does not scan the ' +
|
|
36
|
+
'configHome, so these artifacts are invisible to the runtime (#3738); the same artifacts reinstall ' +
|
|
37
|
+
"under the global layout's .gemini/config home override";
|
|
38
|
+
const FILE_OWNERSHIP_EVIDENCE = 'pre-#3738 antigravity installs record skills/gsd-*/** and agents/gsd-*.md keys in ' +
|
|
39
|
+
'gsd-file-manifest.json at the configHome root; the migration only walks gsd--prefixed entries ' +
|
|
40
|
+
'under the two retired subpaths';
|
|
41
|
+
const DIR_REASON = 'the retired container directory is removed only once every GSD-owned entry inside it is gone; a ' +
|
|
42
|
+
'directory that still holds an unmanifested user file — or any file-level action that failed to ' +
|
|
43
|
+
'apply — is left in place by the emptiness re-check';
|
|
44
|
+
const DIR_OWNERSHIP_EVIDENCE = 'skills/ and agents/ at the antigravity configHome root are GSD-installed container directories ' +
|
|
45
|
+
'from the pre-#3738 layout; removal is gated on emptiness by the shared remove-empty-dir action';
|
|
46
|
+
/**
|
|
47
|
+
* Recursively collect files and directories under `root/relDir`, never
|
|
48
|
+
* following a symlink (whether it names a file or a directory) and never
|
|
49
|
+
* emitting a path that resolves outside `baseResolved`. Mirrors the traversal
|
|
50
|
+
* guard in migration 009 (`walkPiHooksTree`).
|
|
51
|
+
*/
|
|
52
|
+
function walkTree(root, relDir, baseResolved, files, dirs) {
|
|
53
|
+
const dir = node_path_1.default.join(root, relDir);
|
|
54
|
+
const entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
// Never follow a symlink into or through: it must not be traversed,
|
|
57
|
+
// hashed, or removed, regardless of what it points at.
|
|
58
|
+
if (entry.isSymbolicLink())
|
|
59
|
+
continue;
|
|
60
|
+
const relPath = node_path_1.default.posix.join(relDir, entry.name);
|
|
61
|
+
const resolved = node_path_1.default.resolve(root, relPath);
|
|
62
|
+
if (resolved !== baseResolved && !resolved.startsWith(baseResolved + node_path_1.default.sep))
|
|
63
|
+
continue;
|
|
64
|
+
if (entry.isDirectory()) {
|
|
65
|
+
dirs.push(relPath);
|
|
66
|
+
walkTree(root, relPath, baseResolved, files, dirs);
|
|
67
|
+
}
|
|
68
|
+
else if (entry.isFile()) {
|
|
69
|
+
files.push(relPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const migration = {
|
|
74
|
+
id: '2026-08-26-antigravity-retire-confighome-artifacts',
|
|
75
|
+
title: "Retire Antigravity's configHome skills/agents surfaces",
|
|
76
|
+
description: 'Remove manifest-managed skills/gsd-*/ and agents/gsd-*.md under the Antigravity configHome ' +
|
|
77
|
+
'(~/.gemini/antigravity{,-ide,-cli}) — a location Antigravity does not scan for global discovery — ' +
|
|
78
|
+
'and retire the now-empty container directories, now that the global layout installs both kinds ' +
|
|
79
|
+
'under the ~/.gemini/config home override (#3738). Global scope only; the local .agents workspace ' +
|
|
80
|
+
'surface is untouched.',
|
|
81
|
+
introducedIn: '1.11.0',
|
|
82
|
+
runtimes: ['antigravity'],
|
|
83
|
+
scopes: ['global'],
|
|
84
|
+
destructive: true,
|
|
85
|
+
plan: (ctx) => {
|
|
86
|
+
// Defense in depth ahead of the framework's own runtimes/scope filters:
|
|
87
|
+
// a claude/kimi/etc. skills/ or agents/ directory is a live install
|
|
88
|
+
// surface, never a retirement target, and so is antigravity's LOCAL
|
|
89
|
+
// .agents/skills layout.
|
|
90
|
+
if (ctx.runtime !== 'antigravity')
|
|
91
|
+
return [];
|
|
92
|
+
if (ctx.scope !== 'global')
|
|
93
|
+
return [];
|
|
94
|
+
const actions = [];
|
|
95
|
+
for (const subpath of RETIRED_SUBPATHS) {
|
|
96
|
+
const surfaceRoot = node_path_1.default.join(ctx.configDir, subpath);
|
|
97
|
+
let rootLstat;
|
|
98
|
+
try {
|
|
99
|
+
rootLstat = node_fs_1.default.lstatSync(surfaceRoot);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
continue; // absent -> nothing to retire for this surface, idempotent
|
|
103
|
+
}
|
|
104
|
+
// Never follow a symlinked surface root: walking through it could plan
|
|
105
|
+
// actions against paths outside the config directory entirely.
|
|
106
|
+
if (rootLstat.isSymbolicLink() || !rootLstat.isDirectory())
|
|
107
|
+
continue;
|
|
108
|
+
const baseResolved = node_path_1.default.resolve(ctx.configDir);
|
|
109
|
+
const files = [];
|
|
110
|
+
const dirs = [];
|
|
111
|
+
try {
|
|
112
|
+
const entries = node_fs_1.default.readdirSync(surfaceRoot, { withFileTypes: true });
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
if (entry.isSymbolicLink() || !entry.name.startsWith(GSD_PREFIX))
|
|
115
|
+
continue;
|
|
116
|
+
const relPath = node_path_1.default.posix.join(subpath, entry.name);
|
|
117
|
+
if (entry.isDirectory()) {
|
|
118
|
+
dirs.push(relPath);
|
|
119
|
+
walkTree(ctx.configDir, relPath, baseResolved, files, dirs);
|
|
120
|
+
}
|
|
121
|
+
else if (entry.isFile()) {
|
|
122
|
+
files.push(relPath);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Unreadable directory: nothing safe to plan for this surface.
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
for (const relPath of files) {
|
|
131
|
+
const { classification } = ctx.classifyArtifact(relPath);
|
|
132
|
+
if (classification === 'managed-pristine') {
|
|
133
|
+
actions.push({ type: 'remove-managed', relPath, reason: FILE_REASON, ownershipEvidence: FILE_OWNERSHIP_EVIDENCE });
|
|
134
|
+
}
|
|
135
|
+
else if (classification === 'managed-modified') {
|
|
136
|
+
actions.push({ type: 'backup-and-remove', relPath, reason: FILE_REASON, ownershipEvidence: FILE_OWNERSHIP_EVIDENCE });
|
|
137
|
+
}
|
|
138
|
+
// 'unknown' (user-added, not manifest-recorded): no action, preserved.
|
|
139
|
+
// 'missing' / 'managed-missing': impossible here — relPath was just
|
|
140
|
+
// discovered by walking the live filesystem, so it currently exists.
|
|
141
|
+
}
|
|
142
|
+
// Deepest directories first, so a child has already been evaluated
|
|
143
|
+
// (and possibly removed) before its parent's own emptiness is
|
|
144
|
+
// re-checked by the executor. The surface root itself is appended
|
|
145
|
+
// last, unconditionally: the executor's own emptiness re-check is what
|
|
146
|
+
// actually decides whether it goes, not this ordering.
|
|
147
|
+
const orderedDirs = [...dirs].sort((a, b) => b.split('/').length - a.split('/').length);
|
|
148
|
+
orderedDirs.push(subpath);
|
|
149
|
+
for (const relPath of orderedDirs) {
|
|
150
|
+
actions.push({
|
|
151
|
+
type: 'remove-empty-dir',
|
|
152
|
+
relPath,
|
|
153
|
+
reason: DIR_REASON,
|
|
154
|
+
ownershipEvidence: DIR_OWNERSHIP_EVIDENCE,
|
|
155
|
+
// Declared, not derived: classifyArtifact() hashes file contents
|
|
156
|
+
// via sha256File(), which throws EISDIR against a directory path.
|
|
157
|
+
// These relPaths name directories, so classification is stated
|
|
158
|
+
// directly (never 'unknown', so the planner's
|
|
159
|
+
// unknown-classification block never fires for them).
|
|
160
|
+
classification: 'managed-pristine',
|
|
161
|
+
originalHash: null,
|
|
162
|
+
currentHash: null,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return actions;
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
module.exports = migration;
|
|
@@ -505,17 +505,20 @@ function acquireInstallMigrationLock(configDir, { timeoutMs = DEFAULT_LOCK_TIMEO
|
|
|
505
505
|
let lockCreatedByUs = false;
|
|
506
506
|
try {
|
|
507
507
|
fd = node_fs_1.default.openSync(lockPath, 'wx');
|
|
508
|
-
// Close the open descriptor before writing so the file handle is
|
|
509
|
-
// released on Windows before the release closure unlinks it.
|
|
510
|
-
// Write payload via writeFileSync with the path (not the fd) so we
|
|
511
|
-
// don't hold an open fd across the lifetime of the lock.
|
|
512
|
-
node_fs_1.default.closeSync(fd);
|
|
513
|
-
fd = null;
|
|
514
508
|
lockCreatedByUs = true; // we own the file; clean it up on any subsequent error
|
|
515
|
-
|
|
509
|
+
// Write the payload through the exclusively-created descriptor: a
|
|
510
|
+
// second open-by-path here would be a TOCTOU window (CWE-367) where a
|
|
511
|
+
// co-writer of the directory could symlink-swap the just-created empty
|
|
512
|
+
// lock file before the payload lands.
|
|
513
|
+
node_fs_1.default.writeFileSync(fd, JSON.stringify({
|
|
516
514
|
pid: process.pid,
|
|
517
515
|
acquiredAt: new Date().toISOString(),
|
|
518
516
|
}) + '\n');
|
|
517
|
+
// Close before returning so no handle stays open across the lock's
|
|
518
|
+
// lifetime — Windows cannot unlink a file with an open handle when the
|
|
519
|
+
// release closure runs.
|
|
520
|
+
node_fs_1.default.closeSync(fd);
|
|
521
|
+
fd = null;
|
|
519
522
|
lockCreatedByUs = false; // release closure owns cleanup from here
|
|
520
523
|
return () => {
|
|
521
524
|
const failures = [];
|