@opengsd/gsd-core 1.14.0 → 1.16.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 +85 -5
- package/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- package/agents/gsd-code-fixer.compact.md +7 -6
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +17 -2
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +3 -3
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -12
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +15 -9
- package/agents/gsd-planner.md +15 -11
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +166 -37
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +37 -14
- package/bin/install.js +764 -287
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +7 -2
- package/commands/gsd/capture.md +9 -5
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +12 -4
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +11 -7
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +7 -2
- package/commands/gsd/quick-batch.md +21 -9
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +7 -4
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +477 -78
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/adr-parser.cjs +3 -1
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +144 -42
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +197 -222
- package/gsd-core/bin/lib/capability-validator.cjs +16 -1
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1625
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +32 -33
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +343 -207
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config-loader.cjs +65 -4
- package/gsd-core/bin/lib/config.cjs +76 -19
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/decisions.cjs +30 -14
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +426 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +364 -132
- package/gsd-core/bin/lib/install-engine.cjs +30 -33
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/installer-migrations.cjs +8 -1
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +37 -6
- package/gsd-core/bin/lib/model-resolver.cjs +171 -62
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +20 -5
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +110 -8
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +489 -88
- package/gsd-core/bin/lib/plan-document.cjs +142 -20
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +692 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +60 -9
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +83 -55
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/roadmap-command-router.cjs +25 -19
- package/gsd-core/bin/lib/roadmap-parser.cjs +242 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1653 -65
- package/gsd-core/bin/lib/roadmap.cjs +405 -88
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +373 -187
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +5 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +14 -7
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +522 -624
- package/gsd-core/bin/lib/runtime-name-policy.cjs +246 -21
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +47 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state-transition.cjs +39 -2
- package/gsd-core/bin/lib/state.cjs +256 -105
- package/gsd-core/bin/lib/surface.cjs +19 -2
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -79
- package/gsd-core/bin/lib/uat-predicate.cjs +359 -38
- package/gsd-core/bin/lib/uat.cjs +432 -7
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +167 -40
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1378 -274
- package/gsd-core/bin/lib/verify-command-grounding.cjs +46 -2
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +357 -531
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +784 -51
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +10 -6
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +12 -3
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +37 -8
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/references/worktree-path-safety.md +321 -0
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +8 -7
- package/gsd-core/workflows/add-tests.md +4 -3
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +13 -4
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +43 -23
- package/gsd-core/workflows/check-todos.md +7 -6
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +112 -25
- package/gsd-core/workflows/code-review.md +146 -135
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +13 -8
- package/gsd-core/workflows/debug.md +32 -7
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +14 -5
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1019 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +37 -3
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- 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 +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +96 -178
- package/gsd-core/workflows/execute-plan.md +18 -23
- package/gsd-core/workflows/explore.md +4 -4
- package/gsd-core/workflows/extract-learnings.md +4 -2
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +3 -2
- package/gsd-core/workflows/help/modes/full.compact.md +3 -3
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/import.md +4 -3
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +6 -4
- package/gsd-core/workflows/map-codebase.md +5 -4
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +11 -11
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +7 -7
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +50 -24
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +113 -13
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +27 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +62 -39
- package/gsd-core/workflows/reapply-patches.md +9 -3
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +33 -17
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +13 -13
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +4 -4
- package/gsd-core/workflows/ship.md +14 -13
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +5 -5
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +48 -11
- package/gsd-core/workflows/ui-review.md +21 -6
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +7 -7
- package/gsd-core/workflows/validate-phase.md +12 -13
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +129 -55
- package/hooks/dist/gsd-agent-isolation-guard.js +32 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +161 -4
- package/hooks/dist/gsd-statusline.js +85 -20
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-validate-commit.sh +63 -4
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +32 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +161 -4
- package/hooks/gsd-statusline.js +85 -20
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-validate-commit.sh +63 -4
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +22 -4
- package/scripts/build-hooks.js +15 -6
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/check-contract-drift.cjs +127 -11
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +15 -8
- package/scripts/docs-guard-registry.cjs +34 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +79 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +34 -2
- package/scripts/lib/ndjson-reporter.cjs +31 -5
- package/scripts/lib/platform-conformance-tier.generated.cjs +45 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- 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-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +38 -1
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +319 -5
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +38 -9
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +25 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/prompt-injection-scan.sh +4 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +7 -2
- package/skills/gsd-capture/SKILL.md +9 -5
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +12 -4
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +10 -6
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +7 -2
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +21 -9
- package/skills/gsd-review/SKILL.md +7 -4
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
|
@@ -11,6 +11,14 @@
|
|
|
11
11
|
"path": "src/vendor/js-yaml.d.cts",
|
|
12
12
|
"reason": "Vendored third-party type declaration (ADR-3473 §8.1, #3881): a .d.cts carries no executable code, so no ESLint rule is meaningful; the vendored js-yaml .cjs it describes is globally ignored as verbatim upstream output (gsd-core/bin/lib/vendor/**). Freshness is enforced by scripts/lint-vendored-deps.cjs, not by lint rules — same precedent as src/vendor/re2js.d.cts above."
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
"path": "src/vendor/saxes.d.cts",
|
|
16
|
+
"reason": "Upstream type forwarding for the vendored saxes bundle (#4692): declaration-only export with no executable code. scripts/lint-vendored-deps.cjs enforces the exact forwarding declaration; TypeScript checks consumers against upstream types."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "src/vendor/tap-parser.d.cts",
|
|
20
|
+
"reason": "Upstream type forwarding for the vendored tap-parser bundle (#4692): declaration-only export with no executable code. scripts/lint-vendored-deps.cjs enforces the exact forwarding declaration; TypeScript checks consumers against upstream types."
|
|
21
|
+
},
|
|
14
22
|
{
|
|
15
23
|
"path": "tests/fixtures/brand-typing/bad-calibrated-as-sample-basis.cts",
|
|
16
24
|
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#3059): type-aware linting would fail by design; it exists to prove the compiler rejects it."
|
|
@@ -34,5 +42,17 @@
|
|
|
34
42
|
{
|
|
35
43
|
"path": "tests/fixtures/brand-typing/ok-correct-composition.cts",
|
|
36
44
|
"reason": "Positive-control counterpart to the bad-* must-not-compile fixtures (#3059); kept in the same exemption so the pair stays together."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"path": "tests/fixtures/gate-evidence-typing/bad-pass-from-unreadable.cts",
|
|
48
|
+
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#5170): the unreadable-evidence branding makes a passing outcome from unreadable evidence a compile error, and tests/gate-evidence.test.cjs asserts tsc rejects it; type-aware linting would fail by design."
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"path": "tests/fixtures/gate-evidence-typing/bad-unbranded-unreadable.cts",
|
|
52
|
+
"reason": "Deliberate MUST-NOT-COMPILE type-error fixture (#5170): the unreadable-evidence branding makes a passing outcome from unreadable evidence a compile error, and tests/gate-evidence.test.cjs asserts tsc rejects it; type-aware linting would fail by design."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"path": "tests/fixtures/gate-evidence-typing/ok-unreadable-arm.cts",
|
|
56
|
+
"reason": "Positive-control counterpart to the gate-evidence-typing bad-* must-not-compile fixtures (#5170): tsc compiles it clean; kept in the same exemption so the pair stays together."
|
|
37
57
|
}
|
|
38
58
|
]
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Anti-divergence drift guard for the FRONTMATTER FENCE seam (found while
|
|
6
|
+
* implementing #5105; ADR-5057 one-owner rule).
|
|
7
|
+
*
|
|
8
|
+
* `src/frontmatter-fence.cts`'s `locateFrontmatterFence` is the SINGLE owner of
|
|
9
|
+
* "where does a document's frontmatter block start and stop" — the BOM, the
|
|
10
|
+
* byte-0 opening fence, the whole-line closing fence, an adjacent empty block,
|
|
11
|
+
* the lenient `----` closer. Before it existed that answer was re-derived in
|
|
12
|
+
* some thirty places across `src/` (regexes like `/^---\r?\n([\s\S]*?)\r?\n---/`,
|
|
13
|
+
* `indexOf('\n---', 4)`, `lines[0].trim() === '---'`), and the copies disagreed
|
|
14
|
+
* on a BOM, CRLF, an adjacent empty block, `----`, `--- x`, a `---` inside a
|
|
15
|
+
* value and leading whitespace. This guard keeps a new copy from appearing.
|
|
16
|
+
*
|
|
17
|
+
* Mechanism: the shared `scripts/lib/drift-scan.cjs` tree walk and regex-literal
|
|
18
|
+
* tokenizer (ADR-3180 Decision 4), scanning the WHOLE `src/` and `hooks/` trees
|
|
19
|
+
* (the hooks load the built `bin/lib` behind `ensureRuntimeBuild`), the dev-time
|
|
20
|
+
* `scripts/` and `eslint-rules/` trees (every one of them that runs after
|
|
21
|
+
* `build:lib` requires the owner from `gsd-core/bin/lib/frontmatter-fence.cjs`),
|
|
22
|
+
* the two hand-written entry points that load `bin/lib` (`bin/install.js`,
|
|
23
|
+
* `gsd-core/bin/gsd-tools.cjs`), and the two native plugin adapters
|
|
24
|
+
* (`.opencode/plugins/gsd-core.js`, `.kilo/plugins/gsd-core.js`), with
|
|
25
|
+
* FUNCTION-SCOPED exemptions carrying a written reason — never a bare file
|
|
26
|
+
* allowlist — exactly as `lint-milestone-window-drift.cjs` does.
|
|
27
|
+
*
|
|
28
|
+
* KEPT COPIES (found while implementing #5105). A file that must run where the
|
|
29
|
+
* built owner may not exist keeps a self-contained copy of `locateFrontmatterFence`,
|
|
30
|
+
* and only that one function is allowlisted: `scripts/changeset/parse.cjs` (the
|
|
31
|
+
* `changeset-lint` CI job runs it with no `npm ci` and no build) and the two plugin
|
|
32
|
+
* adapters (a package/git-spec tree may carry no built `bin/lib`). Each copy is
|
|
33
|
+
* pinned to the owner by tests/frontmatter-fence.test.cjs ("kept frontmatter fence
|
|
34
|
+
* copies agree with the owner") over a fixture corpus and a property test.
|
|
35
|
+
*
|
|
36
|
+
* DETECTORS. Three files carry a regex that recognizes a fence idiom in OTHER
|
|
37
|
+
* text — this guard itself, `lint-frontmatter-scalar-broad-grep.cjs` (workflow
|
|
38
|
+
* shell snippets) and the `no-crlf-fragile-split` ESLint rule (regex literals in
|
|
39
|
+
* source). None of them locates a frontmatter block; each is exempt only for its
|
|
40
|
+
* exact fragment (`DETECTOR_EXEMPTIONS`), so any other fence code in the same
|
|
41
|
+
* file is still flagged.
|
|
42
|
+
*
|
|
43
|
+
* A line (comment text stripped) is a fence re-derivation when it carries:
|
|
44
|
+
* (a) a regex literal whose text contains `---` (`/^---/`, `/\n---/`,
|
|
45
|
+
* `/(\r?\n)---$/`), or
|
|
46
|
+
* (b) `new RegExp(` together with a string/template literal containing `---`, or
|
|
47
|
+
* (c) a fence-shaped string literal — `'---'`, `'\n---'`, `'---\n'`,
|
|
48
|
+
* `'---\r\n'`, `'\r\n---'` — that is the direct argument of
|
|
49
|
+
* `.startsWith(`/`.endsWith(`/`.indexOf(`/`.lastIndexOf(`/`.split(`, or an
|
|
50
|
+
* operand of `===`/`!==`/`==`/`!=`, or (only when it carries a line
|
|
51
|
+
* ending) the argument of `.includes(`.
|
|
52
|
+
* A template literal that BUILDS a block (`` `---\n${yaml}\n---` ``) or an array
|
|
53
|
+
* of fence lines to join is a writer emitting a fence, not a reader locating
|
|
54
|
+
* one, and is not flagged.
|
|
55
|
+
*
|
|
56
|
+
* KNOWN, ACCEPTED limits of a per-line textual scan (the sibling guards'
|
|
57
|
+
* tradeoff): a derivation split across lines, or routed through a variable
|
|
58
|
+
* holding the `---` literal, is left to code review and to the consumer-parity
|
|
59
|
+
* tests in `tests/frontmatter-fence.test.cjs`.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
const fs = require('node:fs');
|
|
63
|
+
const path = require('node:path');
|
|
64
|
+
const driftScan = require('./lib/drift-scan.cjs');
|
|
65
|
+
const { readRegexLiteralAt, MAX_REGEX_LITERAL_LEN, sanitizeForReport, scanTree } = driftScan;
|
|
66
|
+
|
|
67
|
+
// Authored TypeScript source (the generated bin/lib/*.cjs mirror it) and the runtime hooks
|
|
68
|
+
// (`hooks/dist`, their build output, is skipped by the shared walker), plus the two hand-written
|
|
69
|
+
// entry points that load bin/lib and so can — and must — read the owner too.
|
|
70
|
+
const SCAN_TREES = [
|
|
71
|
+
{ dirs: ['src'], ext: new Set(['.cts', '.ts', '.mts']) },
|
|
72
|
+
{ dirs: ['hooks'], ext: new Set(['.js', '.cjs']) },
|
|
73
|
+
{ dirs: ['scripts', 'eslint-rules'], ext: new Set(['.js', '.cjs', '.mjs']) },
|
|
74
|
+
];
|
|
75
|
+
const SCAN_FILES = [
|
|
76
|
+
path.join('bin', 'install.js'),
|
|
77
|
+
path.join('gsd-core', 'bin', 'gsd-tools.cjs'),
|
|
78
|
+
path.join('.opencode', 'plugins', 'gsd-core.js'),
|
|
79
|
+
path.join('.kilo', 'plugins', 'gsd-core.js'),
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const OWNER_FILE = path.join('src', 'frontmatter-fence.cts');
|
|
83
|
+
|
|
84
|
+
// Code outside any top-level function (a module-scope constant) is keyed as this.
|
|
85
|
+
const TOP_LEVEL = '<top-level>';
|
|
86
|
+
|
|
87
|
+
// FUNCTION-SCOPED exemptions, each with its reason:
|
|
88
|
+
// - frontmatter-fence.cts `locateFrontmatterFence`: this IS the owner. Its
|
|
89
|
+
// module-scope fence constants (`CLOSING_FENCE_LINE`, `LENIENT_CLOSING_FENCE_LINE`)
|
|
90
|
+
// sit OUTSIDE this function, at TOP_LEVEL, and are exempted by exact fragment
|
|
91
|
+
// in DETECTOR_EXEMPTIONS below instead — a blanket TOP_LEVEL pass here would
|
|
92
|
+
// let any new top-level helper in this file go unscanned (#5105 fix).
|
|
93
|
+
// - phase.cts `phaseEntryInsertOffset`: its `lastIndexOf('\n---')` finds the
|
|
94
|
+
// ROADMAP's trailing section SEPARATOR (a thematic break closing the phase
|
|
95
|
+
// list) so a new phase entry is appended before it — it never asks where a
|
|
96
|
+
// frontmatter block is.
|
|
97
|
+
// - shell-command-projection.cts `_normalizeMd`: `prevTrimmed !== '---'` is
|
|
98
|
+
// the Markdown normalizer's "no blank line after a thematic break" rule,
|
|
99
|
+
// applied line by line to BODY text; that normalizer's frontmatter skip
|
|
100
|
+
// (`leadingFrontmatterLineCount`) reads the owner.
|
|
101
|
+
// - scripts/changeset/parse.cjs `locateFrontmatterFence`: a kept copy of the
|
|
102
|
+
// owner (#5105) — the `changeset-lint` job in changeset-required.yml runs it
|
|
103
|
+
// with no `npm ci` and no `build:lib`. Pinned to the owner by the parity test
|
|
104
|
+
// tests/frontmatter-fence.test.cjs "kept frontmatter fence copies agree with the owner".
|
|
105
|
+
// - .opencode/plugins/gsd-core.js and .kilo/plugins/gsd-core.js
|
|
106
|
+
// `locateFrontmatterFence`: kept copies of the owner (#5105) — the plugin loads
|
|
107
|
+
// from a package/git-spec tree that may carry no built bin/lib. Pinned to the
|
|
108
|
+
// owner by the same parity test.
|
|
109
|
+
const FUNCTION_SCOPED_EXEMPTIONS = new Map([
|
|
110
|
+
[OWNER_FILE, new Set(['locateFrontmatterFence'])],
|
|
111
|
+
[path.join('src', 'phase.cts'), new Set(['phaseEntryInsertOffset'])],
|
|
112
|
+
[path.join('src', 'shell-command-projection.cts'), new Set(['_normalizeMd'])],
|
|
113
|
+
[path.join('scripts', 'changeset', 'parse.cjs'), new Set(['locateFrontmatterFence'])],
|
|
114
|
+
[path.join('.opencode', 'plugins', 'gsd-core.js'), new Set(['locateFrontmatterFence'])],
|
|
115
|
+
[path.join('.kilo', 'plugins', 'gsd-core.js'), new Set(['locateFrontmatterFence'])],
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
// FRAGMENT-SCOPED exemptions for DETECTORS (#5105), each pinned to the exact
|
|
119
|
+
// reported fragment (the literal's source text) — a regex that recognizes a fence
|
|
120
|
+
// idiom in other text, never one that locates a frontmatter block:
|
|
121
|
+
// - this guard's own fence-literal matcher (`FENCE_LITERAL_CONTENT_RE`);
|
|
122
|
+
// - lint-frontmatter-scalar-broad-grep.cjs `FRONTMATTER_SCOPE_RE`, which finds a
|
|
123
|
+
// `^---`-scoped extraction in a workflow's shell snippet;
|
|
124
|
+
// - the no-crlf-fragile-split ESLint rule's `^---` probe, which classifies a
|
|
125
|
+
// regex literal in linted source as frontmatter-shaped.
|
|
126
|
+
const DETECTOR_EXEMPTIONS = new Map([
|
|
127
|
+
[path.join('scripts', 'lint-frontmatter-fence-drift.cjs'), new Set(['/^(?:\\\\r)?(?:\\\\n)?---(?:\\\\r)?(?:\\\\n)?$/'])],
|
|
128
|
+
[path.join('scripts', 'lint-frontmatter-scalar-broad-grep.cjs'), new Set(['/\\^---[\\s\\S]{0,300}?---/'])],
|
|
129
|
+
[path.join('eslint-rules', 'no-crlf-fragile-split.cjs'), new Set(['/\\^---/'])],
|
|
130
|
+
// The owner's own module-scope fence-literal constants (#5105 fix): these ARE
|
|
131
|
+
// the canonical closing-fence patterns, not a re-derivation — exempted by their
|
|
132
|
+
// exact fragment rather than by a blanket TOP_LEVEL pass, so a NEW top-level
|
|
133
|
+
// helper in this file (one that merely happens to sit outside a function) is
|
|
134
|
+
// still caught.
|
|
135
|
+
[OWNER_FILE, new Set(['/^---[ \\t]*$/', '/^-{4,}[ \\t]*$/'])],
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
// Only a column-0 top-level `function` declaration updates the current-function
|
|
139
|
+
// tracker (mirrors lint-milestone-window-drift.cjs); ANY OTHER non-blank,
|
|
140
|
+
// non-`}` column-0 line — a `const`, a `module.exports =`, an `export const`
|
|
141
|
+
// arrow, anything — resets it to TOP_LEVEL. (#5105 fix: the previous version
|
|
142
|
+
// only reset on a fixed keyword list, so a top-level statement it didn't
|
|
143
|
+
// recognize — e.g. `module.exports = { ... }` — silently inherited the LAST
|
|
144
|
+
// exempted function's name and went unscanned.)
|
|
145
|
+
const TOP_LEVEL_FUNCTION_RE = /^(?:export\s+)?(?:async\s+)?function\s+([A-Za-z0-9_$]+)\s*\(/;
|
|
146
|
+
const COLUMN_ZERO_RESET_RE = /^[^\s}]/;
|
|
147
|
+
|
|
148
|
+
const NEW_REGEXP_RE = /new\s+RegExp\s*\(/;
|
|
149
|
+
|
|
150
|
+
// A fence-shaped string literal's CONTENT (source text between the quotes):
|
|
151
|
+
// `---`, optionally preceded by `\n`/`\r\n` and optionally followed by `\n`/`\r\n`.
|
|
152
|
+
const FENCE_LITERAL_CONTENT_RE = /^(?:\\r)?(?:\\n)?---(?:\\r)?(?:\\n)?$/;
|
|
153
|
+
|
|
154
|
+
const SEARCH_CALL_BEFORE_RE = /\.(startsWith|endsWith|indexOf|lastIndexOf|split|includes)\(\s*$/;
|
|
155
|
+
const COMPARE_BEFORE_RE = /[!=]==?\s*$/;
|
|
156
|
+
const COMPARE_AFTER_RE = /^\s*[!=]==?/;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Read the quoted or backtick-delimited string literal starting at `line[start]`.
|
|
160
|
+
* Returns `{ text, end }` (delimiters included) or null. Same single-pass,
|
|
161
|
+
* escape-aware, bounded style as the shared `readRegexLiteralAt`.
|
|
162
|
+
*/
|
|
163
|
+
function readStringLiteralAt(line, start) {
|
|
164
|
+
const quote = line[start];
|
|
165
|
+
if (quote !== "'" && quote !== '"' && quote !== '`') return null;
|
|
166
|
+
const limit = Math.min(line.length, start + MAX_REGEX_LITERAL_LEN);
|
|
167
|
+
for (let i = start + 1; i < limit; i++) {
|
|
168
|
+
const ch = line[i];
|
|
169
|
+
if (ch === '\\') {
|
|
170
|
+
i++;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (ch === '\r' || ch === '\n') return null;
|
|
174
|
+
if (ch === quote) return { text: line.slice(start, i + 1), end: i + 1 };
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Strip comment text from a line (whole-line `*`, `/*`, `//`, and a trailing
|
|
181
|
+
* `//`), as the sibling guards do — prose about a fence is not a fence.
|
|
182
|
+
*/
|
|
183
|
+
function stripComments(line) {
|
|
184
|
+
const trimmed = line.trim();
|
|
185
|
+
if (trimmed.startsWith('*') || trimmed.startsWith('/*') || trimmed.startsWith('//')) return '';
|
|
186
|
+
const idx = line.indexOf('//');
|
|
187
|
+
return idx === -1 ? line : line.slice(0, idx);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Every regex and string literal on `code`, in order, with its kind and span. */
|
|
191
|
+
function literalsOf(code) {
|
|
192
|
+
const out = [];
|
|
193
|
+
for (let i = 0; i < code.length; i++) {
|
|
194
|
+
const ch = code[i];
|
|
195
|
+
let literal = null;
|
|
196
|
+
let kind = null;
|
|
197
|
+
if (ch === '/' && code[i + 1] !== '/' && code[i + 1] !== '*') {
|
|
198
|
+
literal = readRegexLiteralAt(code, i);
|
|
199
|
+
kind = 'regex';
|
|
200
|
+
} else if (ch === "'" || ch === '"' || ch === '`') {
|
|
201
|
+
literal = readStringLiteralAt(code, i);
|
|
202
|
+
kind = 'string';
|
|
203
|
+
}
|
|
204
|
+
if (!literal) continue;
|
|
205
|
+
out.push({ kind, text: literal.text, start: i, end: literal.end });
|
|
206
|
+
i = literal.end - 1;
|
|
207
|
+
}
|
|
208
|
+
return out;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** The fence re-derivation fragment on a comment-stripped line, or null. */
|
|
212
|
+
function fenceFragment(code) {
|
|
213
|
+
const literals = literalsOf(code);
|
|
214
|
+
const hasNewRegExp = NEW_REGEXP_RE.test(code);
|
|
215
|
+
for (const lit of literals) {
|
|
216
|
+
if (lit.kind === 'regex') {
|
|
217
|
+
if (lit.text.includes('---')) return lit.text;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const content = lit.text.slice(1, -1);
|
|
221
|
+
if (hasNewRegExp && content.includes('---')) return lit.text;
|
|
222
|
+
if (!FENCE_LITERAL_CONTENT_RE.test(content)) continue;
|
|
223
|
+
const before = code.slice(0, lit.start);
|
|
224
|
+
const after = code.slice(lit.end);
|
|
225
|
+
const call = SEARCH_CALL_BEFORE_RE.exec(before);
|
|
226
|
+
if (call && (call[1] !== 'includes' || content.includes('\\n'))) return lit.text;
|
|
227
|
+
if (COMPARE_BEFORE_RE.test(before) || COMPARE_AFTER_RE.test(after)) return lit.text;
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Pure: every unsanctioned frontmatter-fence re-derivation in `text`.
|
|
234
|
+
* `relPath` is the repo-relative path, for reporting and the exemptions.
|
|
235
|
+
* Returns [{ line, fn, found }].
|
|
236
|
+
*/
|
|
237
|
+
function findFrontmatterFenceDrift(text, relPath) {
|
|
238
|
+
const out = [];
|
|
239
|
+
const lines = text.split('\n');
|
|
240
|
+
const exemptFunctions = FUNCTION_SCOPED_EXEMPTIONS.get(relPath) || null;
|
|
241
|
+
const exemptFragments = DETECTOR_EXEMPTIONS.get(relPath) || null;
|
|
242
|
+
let currentFunction = TOP_LEVEL;
|
|
243
|
+
for (let i = 0; i < lines.length; i++) {
|
|
244
|
+
const line = lines[i];
|
|
245
|
+
const fnMatch = TOP_LEVEL_FUNCTION_RE.exec(line);
|
|
246
|
+
if (fnMatch) currentFunction = fnMatch[1];
|
|
247
|
+
else if (COLUMN_ZERO_RESET_RE.test(line)) currentFunction = TOP_LEVEL;
|
|
248
|
+
|
|
249
|
+
const code = stripComments(line);
|
|
250
|
+
if (!code.includes('---')) continue;
|
|
251
|
+
const found = fenceFragment(code);
|
|
252
|
+
if (found === null) continue;
|
|
253
|
+
if (exemptFunctions && exemptFunctions.has(currentFunction)) continue;
|
|
254
|
+
if (exemptFragments && exemptFragments.has(found)) continue;
|
|
255
|
+
out.push({ line: i + 1, fn: currentFunction, found });
|
|
256
|
+
}
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Scan the authored source tree and entry points; every violation carries its repo-relative file. */
|
|
261
|
+
function scanRepo(root) {
|
|
262
|
+
const violations = [];
|
|
263
|
+
for (const { dirs, ext } of SCAN_TREES) {
|
|
264
|
+
violations.push(...scanTree({
|
|
265
|
+
root,
|
|
266
|
+
scanDirs: dirs,
|
|
267
|
+
scanExt: ext,
|
|
268
|
+
onFile(rel, text) {
|
|
269
|
+
return findFrontmatterFenceDrift(text, rel).map((d) => ({ file: rel, ...d }));
|
|
270
|
+
},
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
for (const rel of SCAN_FILES) {
|
|
274
|
+
let text;
|
|
275
|
+
try {
|
|
276
|
+
text = fs.readFileSync(path.join(root, rel), 'utf8');
|
|
277
|
+
} catch {
|
|
278
|
+
continue; // absent in a fixture tree
|
|
279
|
+
}
|
|
280
|
+
violations.push(...findFrontmatterFenceDrift(text, rel).map((d) => ({ file: rel, ...d })));
|
|
281
|
+
}
|
|
282
|
+
return violations;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function main() {
|
|
286
|
+
const root = path.join(__dirname, '..');
|
|
287
|
+
const violations = scanRepo(root);
|
|
288
|
+
if (violations.length === 0) {
|
|
289
|
+
process.stdout.write('ok frontmatter-fence-drift: no frontmatter fence re-derivations outside frontmatter-fence.cts\n');
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
process.stderr.write('frontmatter-fence-drift: independent re-derivation(s) of the frontmatter fence found.\n');
|
|
293
|
+
process.stderr.write('Use `locateFrontmatterFence` (src/frontmatter-fence.cts) for offsets, or `frontmatterBlock` /\n');
|
|
294
|
+
process.stderr.write('`frontmatterRegion` / `extractFrontmatter` / `stripFrontmatter` (src/frontmatter.cts) for content:\n');
|
|
295
|
+
for (const d of violations) {
|
|
296
|
+
process.stderr.write(` ${sanitizeForReport(d.file)}:${d.line} (${sanitizeForReport(d.fn)}) ${sanitizeForReport(d.found)}\n`);
|
|
297
|
+
}
|
|
298
|
+
process.exitCode = 1;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (require.main === module) main();
|
|
302
|
+
|
|
303
|
+
module.exports = {
|
|
304
|
+
findFrontmatterFenceDrift,
|
|
305
|
+
scanRepo,
|
|
306
|
+
fenceFragment,
|
|
307
|
+
stripComments,
|
|
308
|
+
readStringLiteralAt,
|
|
309
|
+
OWNER_FILE,
|
|
310
|
+
TOP_LEVEL,
|
|
311
|
+
FUNCTION_SCOPED_EXEMPTIONS,
|
|
312
|
+
DETECTOR_EXEMPTIONS,
|
|
313
|
+
};
|
|
@@ -17,10 +17,22 @@
|
|
|
17
17
|
* `passed+gaps_found+human_needed` instead of `passed` and blocking a
|
|
18
18
|
* passed phase).
|
|
19
19
|
*
|
|
20
|
-
* The fix-forward is to scope the grep to
|
|
21
|
-
* take only the first match:
|
|
20
|
+
* The fix-forward for a scalar with no owning query is to scope the grep to
|
|
21
|
+
* the leading frontmatter block and take only the first match:
|
|
22
22
|
* sed -n '/^---$/,/^---$/p' "$f" | grep -m1 "^<key>:" | cut -d: -f2 | tr -d ' '
|
|
23
23
|
*
|
|
24
|
+
* ## Rule `verification-status-raw-read` (#5118, ADR-5057 Phase 4)
|
|
25
|
+
*
|
|
26
|
+
* A VERIFICATION report's `status` HAS an owning query — its closed enum,
|
|
27
|
+
* staleness check and routing live in src/verification.cts. Reading that
|
|
28
|
+
* scalar with awk / sed / grep `^status:` (scoped to the frontmatter or not)
|
|
29
|
+
* bypasses all three (transition.md's awk read was W15 in the #5118 census),
|
|
30
|
+
* so it is red even when frontmatter-scoped. The fix-forward is the owner:
|
|
31
|
+
* gsd_run query verification.status "$PHASE_DIR" --pick status
|
|
32
|
+
* `findRawVerificationStatusReadsInBlock` flags a logical line (backslash
|
|
33
|
+
* continuations joined) that names a `*VERIFICATION*` path or variable and
|
|
34
|
+
* reads `^status` with awk, sed or grep.
|
|
35
|
+
*
|
|
24
36
|
* ## What this scans
|
|
25
37
|
*
|
|
26
38
|
* Every fenced ```bash / ```sh code block in `gsd-core/workflows/*.md`,
|
|
@@ -68,6 +80,17 @@ const FRONTMATTER_SCOPE_RE = /\^---[\s\S]{0,300}?---/;
|
|
|
68
80
|
|
|
69
81
|
const ALLOW_RE = /#\s*lint-allow:\s*frontmatter-scalar-broad-grep/;
|
|
70
82
|
|
|
83
|
+
const RULE_BROAD_GREP = 'frontmatter-scalar-broad-grep';
|
|
84
|
+
const RULE_VERIFICATION_RAW_READ = 'verification-status-raw-read';
|
|
85
|
+
|
|
86
|
+
// #5118: a VERIFICATION report path or variable (`*-VERIFICATION.md`,
|
|
87
|
+
// `$VERIFICATION_FILE`, `${VERIFICATION_PATH}`), a raw `^status` pattern, and
|
|
88
|
+
// the text tool doing the read. Case-INsensitive (#5118 review): a lower-case
|
|
89
|
+
// `$verification_file` / `*-verification.md` read is the same bypass.
|
|
90
|
+
const VERIFICATION_PATH_RE = /verification/i;
|
|
91
|
+
const RAW_STATUS_PATTERN_RE = /\^status\b/;
|
|
92
|
+
const RAW_READ_TOOL_RE = /(^|[\s|;&(`$])(awk|gawk|sed|grep|egrep)\s/;
|
|
93
|
+
|
|
71
94
|
// `| head -1` / `| head -n 1` immediately after the grep is functionally
|
|
72
95
|
// equivalent to `-m1` for this check: frontmatter always precedes the body
|
|
73
96
|
// in these generated reports, so the first grep match is always the
|
|
@@ -163,12 +186,63 @@ function findBroadGrepsInBlock(lines) {
|
|
|
163
186
|
}
|
|
164
187
|
|
|
165
188
|
if (pipedToTokenTool || comparedLater) {
|
|
166
|
-
findings.push({ lineIndex: i, key, snippet: line.trim() });
|
|
189
|
+
findings.push({ lineIndex: i, key, snippet: line.trim(), rule: RULE_BROAD_GREP });
|
|
167
190
|
}
|
|
168
191
|
}
|
|
169
192
|
return findings;
|
|
170
193
|
}
|
|
171
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Join backslash-continued physical lines into logical lines, remembering the
|
|
197
|
+
* index of each logical line's FIRST physical line.
|
|
198
|
+
* @param {string[]} lines
|
|
199
|
+
* @returns {{ lineIndex: number, text: string }[]}
|
|
200
|
+
*/
|
|
201
|
+
function logicalLines(lines) {
|
|
202
|
+
const out = [];
|
|
203
|
+
let current = null;
|
|
204
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
205
|
+
const line = lines[i];
|
|
206
|
+
const continued = /\\\s*$/.test(line);
|
|
207
|
+
const piece = continued ? line.replace(/\\\s*$/, ' ') : line;
|
|
208
|
+
if (current === null) current = { lineIndex: i, text: piece };
|
|
209
|
+
else current.text += piece;
|
|
210
|
+
if (!continued) {
|
|
211
|
+
out.push(current);
|
|
212
|
+
current = null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (current !== null) out.push(current);
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Pure (#5118): find every raw read of a VERIFICATION report's `status` in a
|
|
221
|
+
* single fenced bash/sh block — awk / sed / grep over a `*VERIFICATION*`
|
|
222
|
+
* path with a `^status` pattern, whether or not it is frontmatter-scoped.
|
|
223
|
+
* The owner query (`gsd_run query verification.status …`) carries no
|
|
224
|
+
* `^status` pattern and is never flagged. Returns
|
|
225
|
+
* `{ lineIndex, key, snippet, rule }[]` (lineIndex = the logical line's first
|
|
226
|
+
* physical line).
|
|
227
|
+
* @param {string[]} lines
|
|
228
|
+
* @returns {{ lineIndex: number, key: string, snippet: string, rule: string }[]}
|
|
229
|
+
*/
|
|
230
|
+
function findRawVerificationStatusReadsInBlock(lines) {
|
|
231
|
+
const findings = [];
|
|
232
|
+
for (const { lineIndex, text } of logicalLines(lines)) {
|
|
233
|
+
if (!VERIFICATION_PATH_RE.test(text)) continue;
|
|
234
|
+
if (!RAW_STATUS_PATTERN_RE.test(text)) continue;
|
|
235
|
+
if (!RAW_READ_TOOL_RE.test(text)) continue;
|
|
236
|
+
findings.push({
|
|
237
|
+
lineIndex,
|
|
238
|
+
key: 'status',
|
|
239
|
+
snippet: text.replace(/\s+/g, ' ').trim(),
|
|
240
|
+
rule: RULE_VERIFICATION_RAW_READ,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return findings;
|
|
244
|
+
}
|
|
245
|
+
|
|
172
246
|
function walkMarkdown(dir) {
|
|
173
247
|
const out = [];
|
|
174
248
|
let entries;
|
|
@@ -198,12 +272,18 @@ function scan(roots = DEFAULT_ROOTS) {
|
|
|
198
272
|
for (const file of walkMarkdown(abs)) {
|
|
199
273
|
const blocks = extractBashBlocks(fs.readFileSync(file, 'utf8'));
|
|
200
274
|
for (const block of blocks) {
|
|
201
|
-
|
|
275
|
+
const rawReads = findRawVerificationStatusReadsInBlock(block.lines);
|
|
276
|
+
const rawReadLines = new Set(rawReads.map((f) => f.lineIndex));
|
|
277
|
+
// A raw VERIFICATION `status` read is reported once, under its own
|
|
278
|
+
// rule, not a second time as a broad grep.
|
|
279
|
+
const broad = findBroadGrepsInBlock(block.lines).filter((f) => !rawReadLines.has(f.lineIndex));
|
|
280
|
+
for (const finding of [...rawReads, ...broad]) {
|
|
202
281
|
offenders.push({
|
|
203
282
|
file: path.relative(ROOT, file),
|
|
204
283
|
line: block.startLine + finding.lineIndex,
|
|
205
284
|
key: finding.key,
|
|
206
285
|
snippet: finding.snippet,
|
|
286
|
+
rule: finding.rule,
|
|
207
287
|
});
|
|
208
288
|
}
|
|
209
289
|
}
|
|
@@ -217,21 +297,47 @@ function main() {
|
|
|
217
297
|
const roots = rootsEnv ? rootsEnv.split(path.delimiter).filter(Boolean) : DEFAULT_ROOTS;
|
|
218
298
|
const offenders = scan(roots);
|
|
219
299
|
if (offenders.length > 0) {
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
'
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
300
|
+
const detailFor = (rule) => offenders
|
|
301
|
+
.filter((o) => o.rule === rule)
|
|
302
|
+
.map((o) => ` ${o.file}:${o.line} ${o.snippet}`)
|
|
303
|
+
.join('\n');
|
|
304
|
+
const sections = [];
|
|
305
|
+
const rawReads = detailFor(RULE_VERIFICATION_RAW_READ);
|
|
306
|
+
if (rawReads) {
|
|
307
|
+
sections.push(
|
|
308
|
+
`[${RULE_VERIFICATION_RAW_READ}] a VERIFICATION report's \`status\` read with awk/sed/grep\n`
|
|
309
|
+
+ '(DEFECT.FRONTMATTER-SCALAR-BROAD-GREP, #5118). It bypasses the closed VerificationStatus\n'
|
|
310
|
+
+ 'enum, the staleness check and the routing table. Read it through its owner:\n'
|
|
311
|
+
+ ' gsd_run query verification.status "$PHASE_DIR" --pick status\n'
|
|
312
|
+
+ rawReads,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
const broad = detailFor(RULE_BROAD_GREP);
|
|
316
|
+
if (broad) {
|
|
317
|
+
sections.push(
|
|
318
|
+
`[${RULE_BROAD_GREP}] \`grep "^key:"\` over the whole file, compared to an exact token,\n`
|
|
319
|
+
+ 'with no frontmatter scoping and no -m1 (DEFECT.FRONTMATTER-SCALAR-BROAD-GREP).\n'
|
|
320
|
+
+ 'A body line beginning `key:` is enough to break this. Scope a scalar that has no owning\n'
|
|
321
|
+
+ 'query to the frontmatter block (a VERIFICATION `status` always goes through its owner):\n'
|
|
322
|
+
+ ' sed -n \'/^---$/,/^---$/p\' "$f" | grep -m1 "^<key>:" | cut -d: -f2 | tr -d \' \'\n'
|
|
323
|
+
+ 'or add `# lint-allow: frontmatter-scalar-broad-grep — <reason>` if this is a genuine\n'
|
|
324
|
+
+ 'whole-body scan:\n'
|
|
325
|
+
+ broad,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
throw new ExitError(1, `lint-frontmatter-scalar-broad-grep:\n${sections.join('\n')}`);
|
|
231
329
|
}
|
|
232
330
|
console.log(`ok lint-frontmatter-scalar-broad-grep: no un-scoped frontmatter-scalar greps in ${roots.length} root(s)`);
|
|
233
331
|
}
|
|
234
332
|
|
|
235
|
-
module.exports = {
|
|
333
|
+
module.exports = {
|
|
334
|
+
findBroadGrepsInBlock,
|
|
335
|
+
findRawVerificationStatusReadsInBlock,
|
|
336
|
+
extractBashBlocks,
|
|
337
|
+
scan,
|
|
338
|
+
DEFAULT_ROOTS,
|
|
339
|
+
RULE_BROAD_GREP,
|
|
340
|
+
RULE_VERIFICATION_RAW_READ,
|
|
341
|
+
};
|
|
236
342
|
|
|
237
343
|
if (require.main === module) runMain(main);
|