@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
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
* For every file deleted (`git diff --name-status <base>...HEAD`, status
|
|
22
22
|
* `D`), grep the post-diff tree for the deleted file's basename:
|
|
23
23
|
*
|
|
24
|
-
* - `.github/workflows/`, `gsd-core/`, `docs
|
|
25
|
-
*
|
|
24
|
+
* - `.github/workflows/`, `gsd-core/`, `docs/` (excluding `docs/adr/**` and
|
|
25
|
+
* `docs/research/**` — see "Historical-record exemption" below),
|
|
26
|
+
* `package.json` — ANY surviving reference fails (the original rule).
|
|
26
27
|
* - `tests/` — scanned with a discriminator (#3565): a reference that PINS
|
|
27
28
|
* existence (`fs.existsSync(path)`, `readFileSync`, `require`, or the
|
|
28
29
|
* basename as a quoted object key) fails; a reference that ASSERTS
|
|
@@ -46,6 +47,52 @@
|
|
|
46
47
|
* A common basename (`index.js`, `config.json`) can coincidentally match an
|
|
47
48
|
* unrelated file, and this only catches LITERAL string references — not a
|
|
48
49
|
* variable holding the filename or a glob that happened to match it.
|
|
50
|
+
*
|
|
51
|
+
* ## Basename-collision refinement (#3907)
|
|
52
|
+
*
|
|
53
|
+
* #3907 deleted `bin/lib/ui-safety-gate.cjs` while the SEPARATE, still-live
|
|
54
|
+
* `gsd-core/bin/lib/ui-safety-gate.cjs` survives — every reference to the
|
|
55
|
+
* survivor (including it referencing itself) was misattributed to the
|
|
56
|
+
* deletion, 14 false violations on a correct tree. This epic is about
|
|
57
|
+
* de-duplicating modules, so "delete one of two files sharing a basename"
|
|
58
|
+
* recurs by construction.
|
|
59
|
+
*
|
|
60
|
+
* The fix is precision, not suppression: for each deleted file, if its
|
|
61
|
+
* basename is ALSO the basename of a file that still exists in the
|
|
62
|
+
* post-diff tree — `git ls-files` (tracked files) UNIONED with the
|
|
63
|
+
* already filesystem-walked corpus/testsCorpus file lists, because
|
|
64
|
+
* `git ls-files` alone misses gitignored BUILD ARTIFACTS such as
|
|
65
|
+
* `gsd-core/bin/lib/*.cjs` (compiled from `.cts`, never committed) —
|
|
66
|
+
* matching switches from the bare basename to the deleted file's full
|
|
67
|
+
* repo-relative path. Because the deletion is already committed on this
|
|
68
|
+
* branch, none of these sources can list the deleted file itself, so any
|
|
69
|
+
* hit is necessarily a DIFFERENT file. A genuine
|
|
70
|
+
* full-path reference to the deleted file is still caught (strictly more
|
|
71
|
+
* precise, not weaker); a bare-basename reference becomes correctly
|
|
72
|
+
* unattributable to the deleted file specifically and is no longer
|
|
73
|
+
* blamed on it. When no surviving file shares the basename, nothing
|
|
74
|
+
* changes — the original basename rule still applies exactly as before.
|
|
75
|
+
*
|
|
76
|
+
* Residual known limit: a bare-basename reference to a deleted file whose
|
|
77
|
+
* basename survives elsewhere is now invisible to this guard (it cannot
|
|
78
|
+
* tell whether the bare mention meant the deleted file or its
|
|
79
|
+
* basename-twin). Same trade the docstring already makes for prose
|
|
80
|
+
* mentions above — a false violation reds a correct tree; a missed
|
|
81
|
+
* ambiguous mention only loses one detection channel.
|
|
82
|
+
*
|
|
83
|
+
* ## Historical-record exemption (#3942)
|
|
84
|
+
*
|
|
85
|
+
* `docs/adr/**` and `docs/research/**` are excluded from the `docs/` scan.
|
|
86
|
+
* An ADR's or a post-mortem's entire job is to record what was retired —
|
|
87
|
+
* naming the deleted file IS the point of the document, not a defect — so
|
|
88
|
+
* without this exemption a PR could never write the ADR that explains its
|
|
89
|
+
* own deletion in the same PR that performs it (it would have to land in a
|
|
90
|
+
* follow-up, after the fact, which is backwards for a decision record).
|
|
91
|
+
* The exemption is narrow and applies only to these two directories: every
|
|
92
|
+
* other document under `docs/` (guides, `TESTING-SUITES.md`, generated
|
|
93
|
+
* indexes, etc.) still enforces "ANY surviving reference fails" exactly as
|
|
94
|
+
* before. `.github/workflows/`, `gsd-core/`, and `package.json` are
|
|
95
|
+
* likewise unaffected — none of those are historical-record surfaces.
|
|
49
96
|
*/
|
|
50
97
|
|
|
51
98
|
const fs = require('node:fs');
|
|
@@ -78,6 +125,40 @@ function referencesBasename(content, basename) {
|
|
|
78
125
|
return re.test(content);
|
|
79
126
|
}
|
|
80
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Pure: does `content` contain a literal reference to the FULL
|
|
130
|
+
* repo-relative path `relPath` (used instead of {@link referencesBasename}
|
|
131
|
+
* when the deleted file's basename collides with a surviving file — #3907)?
|
|
132
|
+
*
|
|
133
|
+
* Same delimited-match idea as `referencesBasename`, but the left boundary
|
|
134
|
+
* additionally excludes `/` — a `/` immediately to the left would mean the
|
|
135
|
+
* matched text is really a SUFFIX of a longer path (e.g. content contains
|
|
136
|
+
* `gsd-core/bin/lib/x.cjs` and `relPath` is `bin/lib/x.cjs`: without this,
|
|
137
|
+
* the survivor's own path would be mistaken for a reference to the
|
|
138
|
+
* deleted file it merely shares a basename with).
|
|
139
|
+
* @param {string} content
|
|
140
|
+
* @param {string} relPath - repo-relative path, forward-slash separated
|
|
141
|
+
* @returns {boolean}
|
|
142
|
+
*/
|
|
143
|
+
function referencesPath(content, relPath) {
|
|
144
|
+
const re = new RegExp(`(^|[^\\w./-])${escapeRegex(relPath)}($|[^\\w.-])`);
|
|
145
|
+
return re.test(content);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Pure: given the post-diff tree's file list (repo-relative paths), build
|
|
150
|
+
* the set of basenames that still exist. Used to decide, per deleted file,
|
|
151
|
+
* whether basename matching would be ambiguous (#3907).
|
|
152
|
+
* @param {string[]} survivingFiles - repo-relative paths of files present
|
|
153
|
+
* in the post-diff tree (must NOT include the deleted files themselves)
|
|
154
|
+
* @returns {Set<string>}
|
|
155
|
+
*/
|
|
156
|
+
function buildSurvivingBasenames(survivingFiles) {
|
|
157
|
+
const set = new Set();
|
|
158
|
+
for (const f of survivingFiles) set.add(path.basename(f));
|
|
159
|
+
return set;
|
|
160
|
+
}
|
|
161
|
+
|
|
81
162
|
/**
|
|
82
163
|
* Pure: given the deleted file's basename, does content contain a
|
|
83
164
|
* lockfile-dependent idiom (`npm ci`, `cache: 'npm'` / `cache: "npm"`)?
|
|
@@ -110,15 +191,26 @@ function walk(dir) {
|
|
|
110
191
|
* of the post-diff tree, find every surviving reference.
|
|
111
192
|
* @param {string[]} deletedFiles - repo-relative deleted paths
|
|
112
193
|
* @param {{ file: string, content: string }[]} corpus
|
|
194
|
+
* @param {Set<string>} [survivingBasenames] - basenames still present in the
|
|
195
|
+
* post-diff tree (#3907); when a deleted file's basename is in this set,
|
|
196
|
+
* matching switches from basename to the deleted file's full path
|
|
113
197
|
* @returns {{ deletedFile: string, referencedIn: string, reason: string }[]}
|
|
114
198
|
*/
|
|
115
|
-
function findSurvivingReferences(deletedFiles, corpus) {
|
|
199
|
+
function findSurvivingReferences(deletedFiles, corpus, survivingBasenames = new Set()) {
|
|
116
200
|
const violations = [];
|
|
117
201
|
for (const deletedFile of deletedFiles) {
|
|
118
202
|
const basename = path.basename(deletedFile);
|
|
203
|
+
const collides = survivingBasenames.has(basename);
|
|
119
204
|
for (const { file, content } of corpus) {
|
|
120
|
-
|
|
121
|
-
|
|
205
|
+
const matched = collides ? referencesPath(content, deletedFile) : referencesBasename(content, basename);
|
|
206
|
+
if (matched) {
|
|
207
|
+
violations.push({
|
|
208
|
+
deletedFile,
|
|
209
|
+
referencedIn: file,
|
|
210
|
+
reason: collides
|
|
211
|
+
? `full path '${deletedFile}' still referenced (basename '${basename}' also belongs to a surviving file, so matched by path — #3907)`
|
|
212
|
+
: `basename '${basename}' still referenced`,
|
|
213
|
+
});
|
|
122
214
|
}
|
|
123
215
|
}
|
|
124
216
|
if (basename === 'package-lock.json') {
|
|
@@ -154,9 +246,12 @@ function findSurvivingReferences(deletedFiles, corpus) {
|
|
|
154
246
|
*
|
|
155
247
|
* @param {string} line
|
|
156
248
|
* @param {string} basename
|
|
249
|
+
* @param {string} [matchTarget] - text to look for as a quoted object key
|
|
250
|
+
* (#3907: the deleted file's full path when its basename collides with a
|
|
251
|
+
* surviving file; defaults to `basename`, the original behaviour)
|
|
157
252
|
* @returns {'asserts-absence'|'pins-existence'|null}
|
|
158
253
|
*/
|
|
159
|
-
function classifyTestReference(line, basename) {
|
|
254
|
+
function classifyTestReference(line, basename, matchTarget = basename) {
|
|
160
255
|
const negatedCheck =
|
|
161
256
|
/!\s*[A-Za-z_$][\w.$]*\.(includes|indexOf|search|startsWith|endsWith|match)\s*\(/.test(line) ||
|
|
162
257
|
/!\s*(fs\.)?(existsSync|statSync)\s*\(/.test(line) ||
|
|
@@ -170,7 +265,7 @@ function classifyTestReference(line, basename) {
|
|
|
170
265
|
// Template literal needs \\s so the RegExp constructor receives \s — a
|
|
171
266
|
// bare \s in a template literal collapses to 's' and silently matches a
|
|
172
267
|
// literal 's' instead of whitespace.
|
|
173
|
-
if (new RegExp(`['"\`]${escapeRegex(
|
|
268
|
+
if (new RegExp(`['"\`]${escapeRegex(matchTarget)}['"\`]\\s*:`).test(line)) return 'pins-existence';
|
|
174
269
|
return null;
|
|
175
270
|
}
|
|
176
271
|
|
|
@@ -183,24 +278,38 @@ function classifyTestReference(line, basename) {
|
|
|
183
278
|
*
|
|
184
279
|
* @param {string[]} deletedFiles - repo-relative deleted paths
|
|
185
280
|
* @param {{ file: string, content: string }[]} testsCorpus
|
|
281
|
+
* @param {Set<string>} [survivingBasenames] - basenames still present in the
|
|
282
|
+
* post-diff tree (#3907); when a deleted file's basename is in this set,
|
|
283
|
+
* matching switches from basename to the deleted file's full path, same
|
|
284
|
+
* refinement as {@link findSurvivingReferences} so the two scanners
|
|
285
|
+
* cannot disagree about what "a reference" means
|
|
186
286
|
* @returns {{ deletedFile: string, referencedIn: string, reason: string }[]}
|
|
187
287
|
*/
|
|
188
|
-
function findSurvivingTestReferences(deletedFiles, testsCorpus) {
|
|
288
|
+
function findSurvivingTestReferences(deletedFiles, testsCorpus, survivingBasenames = new Set()) {
|
|
189
289
|
const violations = [];
|
|
190
290
|
for (const deletedFile of deletedFiles) {
|
|
191
291
|
const basename = path.basename(deletedFile);
|
|
192
|
-
const
|
|
292
|
+
const collides = survivingBasenames.has(basename);
|
|
293
|
+
const matchTarget = collides ? deletedFile : basename;
|
|
294
|
+
// The left-boundary class matches referencesPath's when collides
|
|
295
|
+
// (excludes '/' so a survivor's own longer path isn't mistaken for a
|
|
296
|
+
// reference to the deleted file it merely shares a basename with).
|
|
297
|
+
const refRe = collides
|
|
298
|
+
? new RegExp(`(^|[^\\w./-])${escapeRegex(matchTarget)}($|[^\\w.-])`)
|
|
299
|
+
: new RegExp(`(^|[^\\w.-])${escapeRegex(matchTarget)}($|[^\\w.-])`);
|
|
193
300
|
for (const { file, content } of testsCorpus) {
|
|
194
301
|
for (const line of content.split(/\r?\n/)) {
|
|
195
302
|
if (!refRe.test(line)) continue;
|
|
196
|
-
const kind = classifyTestReference(line, basename);
|
|
303
|
+
const kind = classifyTestReference(line, basename, matchTarget);
|
|
197
304
|
if (kind === 'pins-existence') {
|
|
198
305
|
violations.push({
|
|
199
306
|
deletedFile,
|
|
200
307
|
referencedIn: file,
|
|
201
308
|
// control-char-stripped + capped: this text is echoed into lint
|
|
202
309
|
// output that AI agents read as trusted instructions
|
|
203
|
-
reason:
|
|
310
|
+
reason: collides
|
|
311
|
+
? `pins-existence: test depends on deleted path '${matchTarget}' — ${sanitizeEcho(line.trim())}`
|
|
312
|
+
: `pins-existence: test depends on deleted basename '${basename}' — ${sanitizeEcho(line.trim())}`,
|
|
204
313
|
});
|
|
205
314
|
}
|
|
206
315
|
// 'asserts-absence' is correct post-deletion state; null is a
|
|
@@ -215,7 +324,7 @@ function getDeletedFiles(root, baseRef) {
|
|
|
215
324
|
// Deliberately let a git failure (unresolvable ref, no merge base, etc.)
|
|
216
325
|
// propagate as a plain Error — main() treats ANY scan() failure as "cannot
|
|
217
326
|
// resolve this base ref in this environment" and degrades to a skip,
|
|
218
|
-
// matching lint-fix-has-regression-
|
|
327
|
+
// matching lint-fix-has-regression-tests.cjs. There is no failure mode here
|
|
219
328
|
// that should hard-exit non-zero; a real drift is only ever reported once
|
|
220
329
|
// the diff succeeds and findSurvivingReferences finds a violation.
|
|
221
330
|
const out = cp.execFileSync('git', ['diff', '--name-status', `${baseRef}...HEAD`], {
|
|
@@ -231,12 +340,53 @@ function getDeletedFiles(root, baseRef) {
|
|
|
231
340
|
.map((line) => line.slice(2));
|
|
232
341
|
}
|
|
233
342
|
|
|
343
|
+
/**
|
|
344
|
+
* All tracked files at the current tree state (the post-diff tree, since
|
|
345
|
+
* this scan runs against a branch where the deletion is already committed —
|
|
346
|
+
* `git ls-files` therefore CANNOT list a deleted file, so any hit for a
|
|
347
|
+
* deleted file's basename is necessarily a different, surviving file).
|
|
348
|
+
* Used to build `survivingBasenames` for the #3907 collision refinement.
|
|
349
|
+
* @param {string} root
|
|
350
|
+
* @returns {string[]} repo-relative paths, forward-slash separated
|
|
351
|
+
*/
|
|
352
|
+
function getSurvivingFiles(root) {
|
|
353
|
+
const out = cp.execFileSync('git', ['ls-files'], {
|
|
354
|
+
cwd: root,
|
|
355
|
+
encoding: 'utf8',
|
|
356
|
+
timeout: 15000,
|
|
357
|
+
});
|
|
358
|
+
return out
|
|
359
|
+
.trim()
|
|
360
|
+
.split('\n')
|
|
361
|
+
.filter(Boolean)
|
|
362
|
+
.map((f) => f.replace(/\\/g, '/'));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// #3942: docs/adr/** and docs/research/** are historical records — an ADR's
|
|
366
|
+
// or a post-mortem's whole job is to narrate what was retired, so naming a
|
|
367
|
+
// file this same PR deletes is the point, not DEFECT.REMOVED-BUT-NEEDED.
|
|
368
|
+
// Narrow and explicit: only these two `docs/` subtrees are exempt; every
|
|
369
|
+
// other document under `docs/` still enforces the original rule unchanged.
|
|
370
|
+
const DOCS_HISTORICAL_RECORD_PREFIXES = ['docs/adr/', 'docs/research/'];
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Pure: is `relFile` (repo-relative, forward-slash separated) inside one of
|
|
374
|
+
* the exempt historical-record directories (#3942)?
|
|
375
|
+
* @param {string} relFile
|
|
376
|
+
* @returns {boolean}
|
|
377
|
+
*/
|
|
378
|
+
function isDocsHistoricalRecord(relFile) {
|
|
379
|
+
return DOCS_HISTORICAL_RECORD_PREFIXES.some((prefix) => relFile.startsWith(prefix));
|
|
380
|
+
}
|
|
381
|
+
|
|
234
382
|
function buildCorpus(root) {
|
|
235
383
|
const corpus = [];
|
|
236
384
|
for (const rel of SCAN_ROOTS) {
|
|
237
385
|
for (const abs of walk(path.join(root, rel))) {
|
|
386
|
+
const relFile = path.relative(root, abs).replace(/\\/g, '/');
|
|
387
|
+
if (rel === 'docs' && isDocsHistoricalRecord(relFile)) continue;
|
|
238
388
|
try {
|
|
239
|
-
corpus.push({ file:
|
|
389
|
+
corpus.push({ file: relFile, content: fs.readFileSync(abs, 'utf8') });
|
|
240
390
|
} catch {
|
|
241
391
|
// unreadable (broken symlink, binary that slipped past SKIP_EXT) — skip
|
|
242
392
|
}
|
|
@@ -257,7 +407,6 @@ function scan(root, baseRef) {
|
|
|
257
407
|
const deletedFiles = getDeletedFiles(root, baseRef);
|
|
258
408
|
if (deletedFiles.length === 0) return [];
|
|
259
409
|
const corpus = buildCorpus(root);
|
|
260
|
-
const violations = findSurvivingReferences(deletedFiles, corpus);
|
|
261
410
|
// tests/ arm (#3565): same deletions, discriminated references. A bare
|
|
262
411
|
// mention that pins nothing is skipped; an absence assertion is the
|
|
263
412
|
// correct post-deletion state; only a pin on a deleted file fails.
|
|
@@ -272,7 +421,21 @@ function scan(root, baseRef) {
|
|
|
272
421
|
// unreadable (broken symlink, binary that slipped past SKIP_EXT) — skip
|
|
273
422
|
}
|
|
274
423
|
}
|
|
275
|
-
|
|
424
|
+
// #3907: per-deletion basename-collision detection — if a surviving file
|
|
425
|
+
// shares the basename, matching switches from basename to full path (see
|
|
426
|
+
// the header's "Basename-collision refinement" section) for BOTH arms.
|
|
427
|
+
// `git ls-files` alone misses gitignored BUILD ARTIFACTS (e.g.
|
|
428
|
+
// gsd-core/bin/lib/*.cjs, compiled from .cts and never committed) —
|
|
429
|
+
// exactly the #3907 collision partner — so it is unioned with the
|
|
430
|
+
// already filesystem-walked corpus/testsCorpus file lists, which do see
|
|
431
|
+
// them.
|
|
432
|
+
const survivingBasenames = buildSurvivingBasenames([
|
|
433
|
+
...getSurvivingFiles(root),
|
|
434
|
+
...corpus.map((c) => c.file),
|
|
435
|
+
...testsCorpus.map((t) => t.file),
|
|
436
|
+
]);
|
|
437
|
+
const violations = findSurvivingReferences(deletedFiles, corpus, survivingBasenames);
|
|
438
|
+
violations.push(...findSurvivingTestReferences(deletedFiles, testsCorpus, survivingBasenames));
|
|
276
439
|
return violations;
|
|
277
440
|
}
|
|
278
441
|
|
|
@@ -284,7 +447,7 @@ function main() {
|
|
|
284
447
|
} catch (e) {
|
|
285
448
|
// origin/<base> unreachable in this environment (e.g. a shallow local
|
|
286
449
|
// clone with no matching remote-tracking ref) — degrade to a skip rather
|
|
287
|
-
// than a false failure, matching lint-fix-has-regression-
|
|
450
|
+
// than a false failure, matching lint-fix-has-regression-tests.cjs.
|
|
288
451
|
console.log(`lint-removed-but-needed: could not resolve ${baseRef}, skipping (${e.message})`);
|
|
289
452
|
return;
|
|
290
453
|
}
|
|
@@ -305,16 +468,21 @@ function main() {
|
|
|
305
468
|
|
|
306
469
|
module.exports = {
|
|
307
470
|
referencesBasename,
|
|
471
|
+
referencesPath,
|
|
472
|
+
buildSurvivingBasenames,
|
|
308
473
|
referencesNpmLockfileDependency,
|
|
309
474
|
findSurvivingReferences,
|
|
310
475
|
classifyTestReference,
|
|
311
476
|
findSurvivingTestReferences,
|
|
312
477
|
getDeletedFiles,
|
|
478
|
+
getSurvivingFiles,
|
|
313
479
|
buildCorpus,
|
|
480
|
+
isDocsHistoricalRecord,
|
|
314
481
|
scan,
|
|
315
482
|
SCAN_ROOTS,
|
|
316
483
|
EXTRA_FILES,
|
|
317
484
|
TESTS_ROOT,
|
|
485
|
+
DOCS_HISTORICAL_RECORD_PREFIXES,
|
|
318
486
|
};
|
|
319
487
|
|
|
320
488
|
if (require.main === module) runMain(main);
|