mandrel 2.60.0 → 2.62.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/.agents/README.md +10 -10
- package/.agents/agents/story-worker.md +1 -1
- package/.agents/docs/agentrc-reference.json +4 -82
- package/.agents/docs/configuration.md +20 -87
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +1 -3
- package/.agents/rules/gherkin-standards.md +4 -0
- package/.agents/schemas/agentrc.schema.json +11 -486
- package/.agents/schemas/story-deliver-terminal.schema.json +10 -0
- package/.agents/schemas/validation-evidence.schema.json +2 -1
- package/.agents/scripts/README.md +14 -14
- package/.agents/scripts/acceptance-eval.js +32 -164
- package/.agents/scripts/agents-bootstrap-github.js +27 -129
- package/.agents/scripts/apply-quality-bootstrap.js +4 -40
- package/.agents/scripts/audit-baselines.js +6 -27
- package/.agents/scripts/audit-labels-bootstrap.js +5 -29
- package/.agents/scripts/audit-to-stories.js +91 -361
- package/.agents/scripts/boot-sweep.js +19 -72
- package/.agents/scripts/bootstrap.js +74 -395
- package/.agents/scripts/ceremony-derive.js +9 -45
- package/.agents/scripts/check-arch-cycles.js +14 -64
- package/.agents/scripts/check-baselines.js +8 -48
- package/.agents/scripts/check-context-budget.js +46 -172
- package/.agents/scripts/check-cyclomatic.js +12 -44
- package/.agents/scripts/check-dead-exports.js +13 -64
- package/.agents/scripts/check-doc-links.js +38 -186
- package/.agents/scripts/check-gherkin-corpus.js +24 -127
- package/.agents/scripts/check-test-temp-hygiene.js +28 -169
- package/.agents/scripts/coverage-capture.js +32 -99
- package/.agents/scripts/deliver-light.js +14 -101
- package/.agents/scripts/deliver-recover.js +6 -42
- package/.agents/scripts/deliver-run.js +36 -133
- package/.agents/scripts/diagnose-friction.js +24 -116
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +23 -85
- package/.agents/scripts/file-ci-gap.js +10 -50
- package/.agents/scripts/generate-config-docs.js +30 -170
- package/.agents/scripts/generate-lens-checklists.js +8 -52
- package/.agents/scripts/generate-skills-index.js +14 -112
- package/.agents/scripts/generate-workflows-doc.js +10 -70
- package/.agents/scripts/git-cleanup.js +2 -34
- package/.agents/scripts/lib/Graph.js +24 -81
- package/.agents/scripts/lib/ITicketingProvider.js +47 -143
- package/.agents/scripts/lib/Logger.js +14 -76
- package/.agents/scripts/lib/audit-baselines/engine.js +11 -31
- package/.agents/scripts/lib/audit-baselines/gate-surface.js +3 -17
- package/.agents/scripts/lib/audit-baselines/headroom.js +4 -20
- package/.agents/scripts/lib/audit-baselines/hotspots.js +3 -15
- package/.agents/scripts/lib/audit-baselines/kinds.js +23 -89
- package/.agents/scripts/lib/audit-baselines/outliers.js +6 -23
- package/.agents/scripts/lib/audit-baselines/read.js +3 -16
- package/.agents/scripts/lib/audit-baselines/staleness.js +7 -26
- package/.agents/scripts/lib/audit-baselines/surface-entry.js +7 -28
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -20
- package/.agents/scripts/lib/audit-baselines/weights.js +9 -37
- package/.agents/scripts/lib/audit-suite/audit-rules-reader.js +3 -18
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +26 -124
- package/.agents/scripts/lib/audit-suite/dispatch-checklist.js +14 -45
- package/.agents/scripts/lib/audit-suite/findings.js +12 -52
- package/.agents/scripts/lib/audit-suite/frontmatter.js +5 -29
- package/.agents/scripts/lib/audit-suite/index.js +1 -15
- package/.agents/scripts/lib/audit-suite/lens-checklist.js +10 -45
- package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +11 -76
- package/.agents/scripts/lib/audit-suite/runner.js +13 -43
- package/.agents/scripts/lib/audit-suite/selector.js +49 -349
- package/.agents/scripts/lib/audit-suite/substitutions.js +12 -40
- package/.agents/scripts/lib/audit-suite/workflow-loader.js +3 -15
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +11 -73
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +8 -37
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +25 -143
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +14 -80
- package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +4 -18
- package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +7 -40
- package/.agents/scripts/lib/audit-to-stories/group-findings.js +9 -39
- package/.agents/scripts/lib/audit-to-stories/issue-corpus.js +10 -66
- package/.agents/scripts/lib/audit-to-stories/issue-index.js +6 -30
- package/.agents/scripts/lib/audit-to-stories/issues-file.js +6 -36
- package/.agents/scripts/lib/audit-to-stories/ledger-commit.js +17 -69
- package/.agents/scripts/lib/audit-to-stories/ledger-pr.js +17 -85
- package/.agents/scripts/lib/audit-to-stories/ledger-record.js +10 -48
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +38 -146
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +7 -42
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +10 -57
- package/.agents/scripts/lib/baseline-loader.js +12 -51
- package/.agents/scripts/lib/baseline-schema-registry.js +5 -22
- package/.agents/scripts/lib/baselines/component-matcher.js +3 -12
- package/.agents/scripts/lib/baselines/components.js +10 -61
- package/.agents/scripts/lib/baselines/coverage-updater-cli.js +7 -36
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +5 -21
- package/.agents/scripts/lib/baselines/crap-preview-scan.js +19 -45
- package/.agents/scripts/lib/baselines/crap-updater-cli.js +16 -65
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +5 -33
- package/.agents/scripts/lib/baselines/duplication-scanner.js +11 -60
- package/.agents/scripts/lib/baselines/env-overrides.js +12 -67
- package/.agents/scripts/lib/baselines/envelope.js +13 -129
- package/.agents/scripts/lib/baselines/exit-codes.js +6 -49
- package/.agents/scripts/lib/baselines/git-base.js +23 -142
- package/.agents/scripts/lib/baselines/kernel.js +11 -111
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +9 -47
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +8 -51
- package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +7 -62
- package/.agents/scripts/lib/baselines/kinds/bundle-size.js +8 -29
- package/.agents/scripts/lib/baselines/kinds/coverage.js +3 -15
- package/.agents/scripts/lib/baselines/kinds/crap.js +94 -415
- package/.agents/scripts/lib/baselines/kinds/duplication.js +4 -30
- package/.agents/scripts/lib/baselines/kinds/kind-factory.js +7 -53
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +15 -80
- package/.agents/scripts/lib/baselines/kinds/mutation.js +12 -72
- package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +4 -11
- package/.agents/scripts/lib/baselines/merge-envelopes.js +30 -146
- package/.agents/scripts/lib/baselines/path-canon.js +19 -128
- package/.agents/scripts/lib/baselines/preview-gates.js +8 -37
- package/.agents/scripts/lib/baselines/reader.js +14 -107
- package/.agents/scripts/lib/baselines/refresh-service.js +35 -252
- package/.agents/scripts/lib/baselines/scope.js +11 -135
- package/.agents/scripts/lib/baselines/writer.js +16 -149
- package/.agents/scripts/lib/bdd-runner-detect.js +18 -113
- package/.agents/scripts/lib/bdd-scenario-budget.js +9 -36
- package/.agents/scripts/lib/bdd-scenario-scanner.js +11 -73
- package/.agents/scripts/lib/bdd-step-index.js +26 -100
- package/.agents/scripts/lib/bootstrap/baseline-merge-driver.js +23 -103
- package/.agents/scripts/lib/bootstrap/branch-protection.js +2 -5
- package/.agents/scripts/lib/bootstrap/commit-push.js +12 -50
- package/.agents/scripts/lib/bootstrap/gh-preflight.js +14 -101
- package/.agents/scripts/lib/bootstrap/hitl-confirm.js +5 -30
- package/.agents/scripts/lib/bootstrap/install-ledger.js +17 -73
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +17 -121
- package/.agents/scripts/lib/bootstrap/manifest.js +15 -86
- package/.agents/scripts/lib/bootstrap/merge-methods.js +4 -33
- package/.agents/scripts/lib/bootstrap/preflight.js +12 -61
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +34 -235
- package/.agents/scripts/lib/bootstrap/prompt.js +21 -129
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +27 -141
- package/.agents/scripts/lib/bootstrap/summary.js +1 -8
- package/.agents/scripts/lib/bootstrap/workflow-audit.js +11 -84
- package/.agents/scripts/lib/branch-name-guard.js +4 -23
- package/.agents/scripts/lib/changed-files.js +31 -143
- package/.agents/scripts/lib/checks/core-bare-clean.js +4 -24
- package/.agents/scripts/lib/checks/index.js +18 -101
- package/.agents/scripts/lib/checks/loop-health.js +11 -53
- package/.agents/scripts/lib/checks/state.js +16 -91
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +10 -61
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +14 -83
- package/.agents/scripts/lib/child-exec.js +39 -108
- package/.agents/scripts/lib/cli/standard-args.js +9 -116
- package/.agents/scripts/lib/cli-args.js +31 -146
- package/.agents/scripts/lib/cli-usage.js +5 -27
- package/.agents/scripts/lib/cli-utils.js +2 -12
- package/.agents/scripts/lib/close-validation/commands.js +13 -76
- package/.agents/scripts/lib/close-validation/gates.js +92 -331
- package/.agents/scripts/lib/close-validation/process.js +121 -151
- package/.agents/scripts/lib/close-validation/projections/advisories.js +5 -31
- package/.agents/scripts/lib/close-validation/projections/crap.js +19 -67
- package/.agents/scripts/lib/close-validation/projections/head-sha.js +1 -17
- package/.agents/scripts/lib/close-validation/projections/inputs.js +4 -34
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +11 -58
- package/.agents/scripts/lib/close-validation/runner.js +53 -110
- package/.agents/scripts/lib/command-header.js +6 -28
- package/.agents/scripts/lib/config/acceptance-eval.js +4 -30
- package/.agents/scripts/lib/config/baselines.js +3 -14
- package/.agents/scripts/lib/config/ci.js +8 -38
- package/.agents/scripts/lib/config/commands.js +1 -15
- package/.agents/scripts/lib/config/defaults.js +4 -33
- package/.agents/scripts/lib/config/delivery-routing.js +6 -35
- package/.agents/scripts/lib/config/explain.js +9 -80
- package/.agents/scripts/lib/config/gates/coverage.schema.js +0 -12
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +2 -30
- package/.agents/scripts/lib/config/gates/crap.schema.js +1 -34
- package/.agents/scripts/lib/config/gates/duplication.schema.js +1 -8
- package/.agents/scripts/lib/config/gates/index.js +2 -17
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +1 -20
- package/.agents/scripts/lib/config/gates/mutation.schema.js +1 -7
- package/.agents/scripts/lib/config/gates/shared.js +4 -64
- package/.agents/scripts/lib/config/github.js +4 -22
- package/.agents/scripts/lib/config/limits.js +4 -57
- package/.agents/scripts/lib/config/paths.js +2 -21
- package/.agents/scripts/lib/config/qa.js +4 -38
- package/.agents/scripts/lib/config/quality.js +76 -432
- package/.agents/scripts/lib/config/runners.js +12 -56
- package/.agents/scripts/lib/config/runtime.js +13 -57
- package/.agents/scripts/lib/config/shared.js +2 -16
- package/.agents/scripts/lib/config/sync-agentrc.js +9 -50
- package/.agents/scripts/lib/config/temp-paths.js +40 -280
- package/.agents/scripts/lib/config/validate-orchestration.js +5 -17
- package/.agents/scripts/lib/config/worktree-isolation.js +9 -28
- package/.agents/scripts/lib/config-resolver.js +10 -52
- package/.agents/scripts/lib/config-schema-shared.js +1 -4
- package/.agents/scripts/lib/config-settings-schema-delivery.js +12 -294
- package/.agents/scripts/lib/config-settings-schema-quality.js +7 -219
- package/.agents/scripts/lib/config-settings-schema.js +37 -274
- package/.agents/scripts/lib/coverage-baseline.js +20 -110
- package/.agents/scripts/lib/coverage-capture-fullscope.js +12 -37
- package/.agents/scripts/lib/coverage-capture-incremental.js +12 -43
- package/.agents/scripts/lib/coverage-capture-usage.js +4 -24
- package/.agents/scripts/lib/coverage-capture.js +99 -224
- package/.agents/scripts/lib/coverage-utils.js +14 -79
- package/.agents/scripts/lib/cpu-pool.js +17 -123
- package/.agents/scripts/lib/crap-baseline-join.js +16 -88
- package/.agents/scripts/lib/crap-coordinates.js +6 -25
- package/.agents/scripts/lib/crap-engine.js +40 -153
- package/.agents/scripts/lib/crap-method-identity.js +16 -78
- package/.agents/scripts/lib/crap-utils.js +31 -155
- package/.agents/scripts/lib/cyclomatic-ceiling.js +14 -87
- package/.agents/scripts/lib/cyclomatic-scope.js +10 -50
- package/.agents/scripts/lib/dead-exports-knip.js +18 -56
- package/.agents/scripts/lib/dead-exports-mode.js +5 -24
- package/.agents/scripts/lib/degraded-mode.js +3 -26
- package/.agents/scripts/lib/dependency-parser.js +8 -40
- package/.agents/scripts/lib/dependency-version.js +13 -35
- package/.agents/scripts/lib/detect-package-manager.js +6 -36
- package/.agents/scripts/lib/doc-tiers.js +22 -126
- package/.agents/scripts/lib/duplicate-search.js +8 -72
- package/.agents/scripts/lib/env-loader.js +5 -27
- package/.agents/scripts/lib/error-redactor.js +6 -31
- package/.agents/scripts/lib/errors/index.js +2 -22
- package/.agents/scripts/lib/escomplex-ast-compat.js +22 -163
- package/.agents/scripts/lib/escomplex-kernel.js +21 -123
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +93 -419
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +20 -98
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +27 -151
- package/.agents/scripts/lib/findings/audit-ledger.js +23 -97
- package/.agents/scripts/lib/findings/classify-finding.js +14 -69
- package/.agents/scripts/lib/findings/promote-finding.js +14 -112
- package/.agents/scripts/lib/findings/provenance-field.js +11 -52
- package/.agents/scripts/lib/findings/route-finding.js +37 -255
- package/.agents/scripts/lib/findings/semantic-issue-search.js +14 -59
- package/.agents/scripts/lib/findings/severity.js +18 -104
- package/.agents/scripts/lib/format-generated-json.js +12 -44
- package/.agents/scripts/lib/full-suite-lock.js +160 -429
- package/.agents/scripts/lib/full-suite-queue.js +213 -0
- package/.agents/scripts/lib/gates/baseline-store.js +5 -9
- package/.agents/scripts/lib/gates/friction.js +1 -3
- package/.agents/scripts/lib/generated/agentrc-validator.js +2 -2
- package/.agents/scripts/lib/gh-exec.js +31 -259
- package/.agents/scripts/lib/git/cached-fetch.js +9 -52
- package/.agents/scripts/lib/git/sync-from-base.js +15 -107
- package/.agents/scripts/lib/git-branch-cleanup.js +14 -61
- package/.agents/scripts/lib/git-branch-lifecycle.js +16 -87
- package/.agents/scripts/lib/git-utils.js +37 -161
- package/.agents/scripts/lib/github/framework-repo.js +8 -71
- package/.agents/scripts/lib/github-url.js +2 -17
- package/.agents/scripts/lib/import-graph.js +11 -38
- package/.agents/scripts/lib/install-cmd-parser.js +4 -13
- package/.agents/scripts/lib/json-utils.js +3 -18
- package/.agents/scripts/lib/label-constants.js +16 -111
- package/.agents/scripts/lib/label-taxonomy.js +4 -30
- package/.agents/scripts/lib/maintainability-engine.js +12 -80
- package/.agents/scripts/lib/maintainability-unscorable.js +5 -25
- package/.agents/scripts/lib/maintainability-utils.js +16 -92
- package/.agents/scripts/lib/mandrel-catalog.js +12 -70
- package/.agents/scripts/lib/notifications/notifier.js +13 -38
- package/.agents/scripts/lib/npm-scripts.js +4 -23
- package/.agents/scripts/lib/observability/metrics-ledger.js +16 -76
- package/.agents/scripts/lib/observability/runtime-friction.js +44 -286
- package/.agents/scripts/lib/observability/signal-validator.js +5 -37
- package/.agents/scripts/lib/observability/signals-writer.js +11 -121
- package/.agents/scripts/lib/observability/source-classifier.js +21 -203
- package/.agents/scripts/lib/observability/terse-result.js +14 -47
- package/.agents/scripts/lib/onboard/init-tail.js +13 -74
- package/.agents/scripts/lib/onboard/scaffold-docs.js +11 -34
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +25 -139
- package/.agents/scripts/lib/orchestration/auto-merge-cwd.js +11 -66
- package/.agents/scripts/lib/orchestration/behind-recovery.js +10 -55
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +5 -75
- package/.agents/scripts/lib/orchestration/change-set.js +7 -36
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +9 -46
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +11 -44
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +5 -24
- package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +3 -12
- package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +5 -38
- package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +3 -8
- package/.agents/scripts/lib/orchestration/check-baselines/phases/refresh-ack.js +28 -136
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +3 -13
- package/.agents/scripts/lib/orchestration/check-state.js +92 -0
- package/.agents/scripts/lib/orchestration/ci-gap-intake.js +37 -144
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +42 -189
- package/.agents/scripts/lib/orchestration/code-review.js +24 -128
- package/.agents/scripts/lib/orchestration/column-sync.js +23 -111
- package/.agents/scripts/lib/orchestration/complexity-gate.js +42 -214
- package/.agents/scripts/lib/orchestration/deliver-recover.js +36 -168
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +4 -35
- package/.agents/scripts/lib/orchestration/dependency-candidates.js +9 -41
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +25 -115
- package/.agents/scripts/lib/orchestration/doc-reader.js +2 -6
- package/.agents/scripts/lib/orchestration/docs-digest.js +13 -51
- package/.agents/scripts/lib/orchestration/epic-candidates.js +13 -53
- package/.agents/scripts/lib/orchestration/epic-checklist.js +9 -33
- package/.agents/scripts/lib/orchestration/epic-container.js +41 -167
- package/.agents/scripts/lib/orchestration/epic-expansion.js +10 -40
- package/.agents/scripts/lib/orchestration/epic-rollup.js +55 -207
- package/.agents/scripts/lib/orchestration/file-assumption-enum.js +2 -22
- package/.agents/scripts/lib/orchestration/file-assumptions.js +45 -253
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-detect.js +9 -46
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +7 -57
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +21 -126
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +2 -6
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +9 -34
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +41 -190
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/merged-tip.js +9 -45
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +19 -85
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +3 -17
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +16 -100
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +1 -4
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +16 -67
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +9 -33
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +8 -29
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +15 -68
- package/.agents/scripts/lib/orchestration/light-backstop.js +11 -49
- package/.agents/scripts/lib/orchestration/light-escalation.js +21 -89
- package/.agents/scripts/lib/orchestration/light-suitability.js +26 -231
- package/.agents/scripts/lib/orchestration/merge-block-class.js +39 -216
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -377
- package/.agents/scripts/lib/orchestration/merge-queue.js +158 -0
- package/.agents/scripts/lib/orchestration/pinned-identifier-lint.js +17 -57
- package/.agents/scripts/lib/orchestration/plan-context.js +52 -303
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +22 -79
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +5 -31
- package/.agents/scripts/lib/orchestration/plan-metrics.js +29 -108
- package/.agents/scripts/lib/orchestration/plan-navigation.js +8 -27
- package/.agents/scripts/lib/orchestration/plan-persist/acceptance-handle-repair.js +12 -49
- package/.agents/scripts/lib/orchestration/plan-persist/audit-provenance.js +18 -73
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +14 -78
- package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +6 -30
- package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +14 -65
- package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +21 -76
- package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +6 -43
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +14 -68
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +9 -41
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +49 -248
- package/.agents/scripts/lib/orchestration/plan-persist/soft-findings.js +2 -12
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +85 -368
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +8 -38
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +30 -190
- package/.agents/scripts/lib/orchestration/plan-persist/wave-collision-gate.js +9 -49
- package/.agents/scripts/lib/orchestration/plan-persist/wave-serialisation.js +7 -28
- package/.agents/scripts/lib/orchestration/plan-reachability.js +13 -42
- package/.agents/scripts/lib/orchestration/plan-run-labels/reap.js +16 -91
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +16 -54
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +10 -52
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +14 -109
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +11 -83
- package/.agents/scripts/lib/orchestration/pr-watch.js +48 -306
- package/.agents/scripts/lib/orchestration/project-meta-cache.js +15 -80
- package/.agents/scripts/lib/orchestration/project-meta-resolver.js +10 -51
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +12 -76
- package/.agents/scripts/lib/orchestration/remote-verifier.js +12 -36
- package/.agents/scripts/lib/orchestration/resolve-stories.js +33 -164
- package/.agents/scripts/lib/orchestration/retro-proposals.js +66 -361
- package/.agents/scripts/lib/orchestration/review-base-ref.js +9 -43
- package/.agents/scripts/lib/orchestration/review-depth.js +12 -94
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +10 -111
- package/.agents/scripts/lib/orchestration/review-providers/degraded-gates.js +13 -71
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +7 -51
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +8 -53
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -214
- package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +7 -52
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +4 -33
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +11 -71
- package/.agents/scripts/lib/orchestration/review-providers/scoped-lint.js +19 -131
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +6 -89
- package/.agents/scripts/lib/orchestration/review-providers/types.js +26 -56
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +3 -46
- package/.agents/scripts/lib/orchestration/run-epilogue.js +40 -199
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +13 -81
- package/.agents/scripts/lib/orchestration/single-story-close/close-note.js +7 -34
- package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +16 -89
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +18 -109
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +190 -280
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +18 -80
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +103 -97
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +8 -64
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +183 -485
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +30 -134
- package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +9 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/lock-wait-pending.js +49 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +13 -86
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +20 -95
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +46 -203
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pre-gate-steps.js +8 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +12 -83
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -39
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +1 -6
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-outcome.js +4 -28
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +6 -51
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +6 -34
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +23 -121
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +110 -290
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +15 -69
- package/.agents/scripts/lib/orchestration/story-body-gate.js +4 -23
- package/.agents/scripts/lib/orchestration/story-close/baseline-upward-writeback.js +50 -179
- package/.agents/scripts/lib/orchestration/story-close/context-budget-writeback.js +11 -41
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +23 -311
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +22 -147
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +16 -67
- package/.agents/scripts/lib/orchestration/story-deliver-terminal-schema.js +12 -68
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +42 -201
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +43 -245
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +4 -23
- package/.agents/scripts/lib/orchestration/story-init-remote.js +2 -6
- package/.agents/scripts/lib/orchestration/story-reachability.js +3 -23
- package/.agents/scripts/lib/orchestration/task-body-validator.js +12 -126
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -131
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +15 -149
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +5 -33
- package/.agents/scripts/lib/orchestration/ticket-validator.js +39 -181
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +51 -244
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +39 -250
- package/.agents/scripts/lib/orchestration/ticketing/state.js +14 -68
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +46 -263
- package/.agents/scripts/lib/orchestration/ticketing.js +2 -26
- package/.agents/scripts/lib/orchestration/verify-credit.js +18 -79
- package/.agents/scripts/lib/orchestration/worktree-dirty.js +5 -30
- package/.agents/scripts/lib/path-security.js +3 -6
- package/.agents/scripts/lib/plan-phase-cleanup.js +9 -49
- package/.agents/scripts/lib/preflight-runner.js +13 -69
- package/.agents/scripts/lib/process-group.js +143 -0
- package/.agents/scripts/lib/project-root.js +2 -8
- package/.agents/scripts/lib/provider-factory.js +2 -25
- package/.agents/scripts/lib/qa/console-allowlist.js +10 -59
- package/.agents/scripts/lib/qa/qa-session.js +15 -69
- package/.agents/scripts/lib/qa/redact-evidence.js +18 -129
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +26 -135
- package/.agents/scripts/lib/qa/resolve-selection.js +16 -84
- package/.agents/scripts/lib/reserved-test-ids.js +9 -47
- package/.agents/scripts/lib/runtime-deps/dep-resolution.js +13 -53
- package/.agents/scripts/lib/runtime-deps/ensure-installed.js +10 -44
- package/.agents/scripts/lib/runtime-deps/manifest.js +10 -30
- package/.agents/scripts/lib/runtime-deps/parser-major.js +15 -51
- package/.agents/scripts/lib/runtime-deps/preflight.js +4 -22
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +11 -55
- package/.agents/scripts/lib/signals/detectors/common.js +12 -38
- package/.agents/scripts/lib/signals/index.js +2 -19
- package/.agents/scripts/lib/signals/schema.js +14 -109
- package/.agents/scripts/lib/signals/write.js +2 -11
- package/.agents/scripts/lib/single-story/confirm-merge.js +31 -72
- package/.agents/scripts/lib/single-story/story-merged-notify.js +8 -49
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +4 -26
- package/.agents/scripts/lib/single-story-sweep/protection.js +13 -100
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +60 -258
- package/.agents/scripts/lib/single-story-sweep.js +14 -97
- package/.agents/scripts/lib/skills/parse-skill.js +13 -59
- package/.agents/scripts/lib/skills/skills-index.js +8 -29
- package/.agents/scripts/lib/skills/walk-skill-files.js +17 -78
- package/.agents/scripts/lib/source-extensions.js +11 -42
- package/.agents/scripts/lib/source-text/strip-js-comments.js +8 -41
- package/.agents/scripts/lib/stdio-flush.js +9 -36
- package/.agents/scripts/lib/story-adjacency.js +8 -40
- package/.agents/scripts/lib/story-body/body-format-lints.js +22 -83
- package/.agents/scripts/lib/story-body/footer-block.js +11 -44
- package/.agents/scripts/lib/story-body/story-body.js +83 -358
- package/.agents/scripts/lib/temp-retention.js +42 -143
- package/.agents/scripts/lib/templates/decomposer-prompts.js +11 -65
- package/.agents/scripts/lib/test-env.js +12 -65
- package/.agents/scripts/lib/test-run-credit.js +10 -65
- package/.agents/scripts/lib/test-runner-contract.js +19 -74
- package/.agents/scripts/lib/test-temp.js +38 -184
- package/.agents/scripts/lib/test-tiers.js +12 -96
- package/.agents/scripts/lib/ticket-body-sections.js +21 -96
- package/.agents/scripts/lib/transpile.js +15 -74
- package/.agents/scripts/lib/util/concurrent-map.js +6 -25
- package/.agents/scripts/lib/util/parse-id-list.js +8 -34
- package/.agents/scripts/lib/util/poll-loop.js +8 -28
- package/.agents/scripts/lib/util/with-timeout.js +2 -11
- package/.agents/scripts/lib/validation-evidence.js +21 -96
- package/.agents/scripts/lib/wave-runner/footprint.js +17 -70
- package/.agents/scripts/lib/wave-runner/live-probe.js +53 -221
- package/.agents/scripts/lib/wave-runner/ready-set.js +72 -301
- package/.agents/scripts/lib/workers/crap-worker.js +11 -64
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +8 -45
- package/.agents/scripts/lib/workers/maintainability-worker.js +5 -21
- package/.agents/scripts/lib/workers/serve-worker-messages.js +2 -18
- package/.agents/scripts/lib/workflow-closure.js +22 -105
- package/.agents/scripts/lib/workspace-provisioner.js +16 -54
- package/.agents/scripts/lib/worktree/git-hooks.js +15 -60
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +20 -60
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +10 -62
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +22 -86
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +24 -126
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +2 -20
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +46 -180
- package/.agents/scripts/lib/worktree-manager.js +15 -40
- package/.agents/scripts/lint-issue-body.js +12 -68
- package/.agents/scripts/mandrel-update-preflight.js +10 -70
- package/.agents/scripts/merge-baseline.js +30 -104
- package/.agents/scripts/nav-registry-diff.js +22 -108
- package/.agents/scripts/notify.js +12 -69
- package/.agents/scripts/plan-context.js +27 -111
- package/.agents/scripts/plan-critics.js +12 -66
- package/.agents/scripts/plan-persist.js +31 -148
- package/.agents/scripts/plan-run-epilogue.js +11 -37
- package/.agents/scripts/pr-watch-with-update.js +76 -267
- package/.agents/scripts/providers/github/auth.js +3 -8
- package/.agents/scripts/providers/github/blocked-by-add.js +14 -61
- package/.agents/scripts/providers/github/board-add.js +5 -21
- package/.agents/scripts/providers/github/branch-protection.js +11 -43
- package/.agents/scripts/providers/github/cache.js +2 -14
- package/.agents/scripts/providers/github/comments.js +7 -40
- package/.agents/scripts/providers/github/compose.js +3 -19
- package/.agents/scripts/providers/github/errors.js +22 -125
- package/.agents/scripts/providers/github/issues.js +31 -123
- package/.agents/scripts/providers/github/labels.js +24 -124
- package/.agents/scripts/providers/github/mappers.js +5 -27
- package/.agents/scripts/providers/github/merge-methods.js +3 -22
- package/.agents/scripts/providers/github/project-board.js +2 -17
- package/.agents/scripts/providers/github/projects-v2-graphql.js +3 -6
- package/.agents/scripts/providers/github/request-helpers.js +5 -32
- package/.agents/scripts/providers/github/search-budget.js +9 -39
- package/.agents/scripts/providers/github/search-query.js +5 -26
- package/.agents/scripts/providers/github/sub-issue-add.js +15 -65
- package/.agents/scripts/providers/github/sub-issues.js +7 -36
- package/.agents/scripts/providers/github/tickets.js +32 -134
- package/.agents/scripts/providers/github.js +18 -59
- package/.agents/scripts/prune-plan-run-labels.js +12 -46
- package/.agents/scripts/quality-preview.js +35 -220
- package/.agents/scripts/resolve-doc-tiers.js +3 -26
- package/.agents/scripts/resolve-stories.js +16 -67
- package/.agents/scripts/resync-status-column.js +6 -25
- package/.agents/scripts/run-tests.js +29 -104
- package/.agents/scripts/single-story-close.js +23 -135
- package/.agents/scripts/single-story-confirm-merge.js +32 -139
- package/.agents/scripts/single-story-init.js +47 -209
- package/.agents/scripts/stories-wave-tick.js +102 -472
- package/.agents/scripts/sync-agentrc.js +3 -21
- package/.agents/scripts/sync-claude-agents.js +9 -55
- package/.agents/scripts/sync-claude-commands.js +20 -110
- package/.agents/scripts/test-wrapper.js +6 -43
- package/.agents/scripts/update-coverage-baseline.js +5 -22
- package/.agents/scripts/update-crap-baseline.js +7 -30
- package/.agents/scripts/update-duplication-baseline.js +16 -92
- package/.agents/scripts/update-maintainability-baseline.js +8 -62
- package/.agents/scripts/update-ticket-state.js +1 -7
- package/.agents/scripts/validate-skills.js +6 -26
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/templates/docs/audit-sweep-runbook.md +3 -4
- package/.agents/workflows/audit-accessibility.md +4 -7
- package/.agents/workflows/audit-adrs.md +3 -6
- package/.agents/workflows/audit-architecture.md +3 -11
- package/.agents/workflows/audit-baselines.md +6 -9
- package/.agents/workflows/audit-clean-code.md +8 -12
- package/.agents/workflows/audit-data-model.md +3 -7
- package/.agents/workflows/audit-dependencies.md +4 -7
- package/.agents/workflows/audit-devops.md +4 -8
- package/.agents/workflows/audit-documentation.md +1 -4
- package/.agents/workflows/audit-mobile.md +4 -7
- package/.agents/workflows/audit-navigability.md +3 -6
- package/.agents/workflows/audit-performance.md +2 -4
- package/.agents/workflows/audit-privacy.md +4 -7
- package/.agents/workflows/audit-quality.md +4 -7
- package/.agents/workflows/audit-security.md +4 -7
- package/.agents/workflows/audit-seo.md +4 -7
- package/.agents/workflows/audit-sre.md +4 -7
- package/.agents/workflows/audit-to-stories.md +17 -30
- package/.agents/workflows/audit-ux-ui.md +4 -7
- package/.agents/workflows/helpers/audit-lens-core.md +1 -1
- package/.agents/workflows/helpers/code-quality-guardrails.md +12 -15
- package/.agents/workflows/helpers/deliver-digest.md +6 -4
- package/.agents/workflows/helpers/deliver-reference.md +114 -188
- package/.agents/workflows/helpers/deliver-story-reference.md +189 -533
- package/.agents/workflows/helpers/plan-reference.md +86 -139
- package/.agents/workflows/helpers/qa-core.md +12 -0
- package/.agents/workflows/memory-consolidate.md +1 -1
- package/.agents/workflows/qa-assist.md +27 -71
- package/.agents/workflows/qa-explore.md +19 -59
- package/.agents/workflows/qa-run.md +11 -33
- package/README.md +1 -1
- package/bin/mandrel.js +5 -46
- package/bin/postinstall.js +18 -107
- package/docs/CHANGELOG.md +32 -0
- package/lib/cli/doctor.js +11 -71
- package/lib/cli/init.js +26 -165
- package/lib/cli/migrate.js +5 -64
- package/lib/cli/registry.js +84 -467
- package/lib/cli/sync-agents.js +4 -64
- package/lib/cli/sync-commands.js +11 -64
- package/lib/cli/sync.js +34 -213
- package/lib/cli/uninstall.js +40 -219
- package/lib/cli/update.js +105 -661
- package/lib/cli/version-check.js +8 -72
- package/lib/cli/version-helpers.js +14 -87
- package/lib/migrations/helpers/retire-agentrc-key.js +11 -52
- package/lib/migrations/index.js +15 -92
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +2 -15
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +1 -13
- package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +2 -15
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +9 -38
- package/lib/migrations/steps/2.20.0-retire-codebase-snapshot.js +1 -13
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +2 -27
- package/lib/migrations/steps/2.57.0-retire-delivery-limit-knobs.js +2 -23
- package/lib/migrations/steps/2.57.0-retire-planning-limit-knobs.js +2 -27
- package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +2 -21
- package/lib/migrations/steps/strip-removed-agentrc-keys.js +333 -0
- package/package.json +16 -14
- package/.agents/docs/SDLC.md +0 -590
- package/.agents/docs/quality-gates.md +0 -1183
- package/.agents/rules/known-tooling-behavior.md +0 -200
- package/.agents/rules/orchestration-error-handling.md +0 -61
- package/.agents/rules/test-seams.md +0 -59
- package/.agents/schemas/baselines/lighthouse.schema.json +0 -59
- package/.agents/schemas/baselines/lint.schema.json +0 -47
- package/.agents/scripts/check-action-pinning.js +0 -260
- package/.agents/scripts/check-audit-attribution.js +0 -302
- package/.agents/scripts/check-baseline-drift.js +0 -211
- package/.agents/scripts/check-baseline-scope.js +0 -362
- package/.agents/scripts/check-generated-validator.js +0 -202
- package/.agents/scripts/check-knip-entries.js +0 -159
- package/.agents/scripts/check-lifecycle-lint.js +0 -294
- package/.agents/scripts/check-pinned-override-notes.js +0 -102
- package/.agents/scripts/check-schema-references.js +0 -368
- package/.agents/scripts/check-test-portability.js +0 -512
- package/.agents/scripts/check-workflow-citations.js +0 -218
- package/.agents/scripts/check-workflow-cli-lint.js +0 -299
- package/.agents/scripts/check-workflow-timeouts.js +0 -291
- package/.agents/scripts/install-matrix-assert.js +0 -326
- package/.agents/scripts/lib/audit-advisories.js +0 -195
- package/.agents/scripts/lib/audit-attribution.js +0 -134
- package/.agents/scripts/lib/baselines/drift-detector.js +0 -351
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +0 -87
- package/.agents/scripts/lib/baselines/kinds/lint.js +0 -184
- package/.agents/scripts/lib/baselines/orphan-pruner.js +0 -233
- package/.agents/scripts/lib/baselines/scope-assert.js +0 -223
- package/.agents/scripts/lib/baselines/scope-inventory.js +0 -314
- package/.agents/scripts/lib/c8-cli-path.js +0 -21
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +0 -51
- package/.agents/scripts/lib/config/gates/lint.schema.js +0 -18
- package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +0 -70
- package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +0 -284
- package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +0 -80
- package/.agents/scripts/lib/dynamic-workflow/degraded-coverage.js +0 -81
- package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +0 -87
- package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +0 -74
- package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +0 -90
- package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +0 -43
- package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +0 -83
- package/.agents/scripts/lib/fs-walk.js +0 -52
- package/.agents/scripts/lib/knip-config-resolver.js +0 -181
- package/.agents/scripts/lib/knip-entry-sync.js +0 -452
- package/.agents/scripts/lib/pinned-override-notes.js +0 -88
- package/.agents/scripts/lib/pinned-override-resolve.js +0 -212
- package/.agents/scripts/lib/test-isolate/cli-options.js +0 -93
- package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +0 -52
- package/.agents/scripts/lib/test-isolate/list-files.js +0 -90
- package/.agents/scripts/lib/test-isolate/parse-tap.js +0 -75
- package/.agents/scripts/lib/test-isolate/progress-log.js +0 -45
- package/.agents/scripts/lib/test-isolate/render-report.js +0 -97
- package/.agents/scripts/lib/test-isolate/run-isolate.js +0 -87
- package/.agents/scripts/lib/test-isolate/runner.js +0 -483
- package/.agents/scripts/lib/test-profile/parse-tap.js +0 -136
- package/.agents/scripts/lib/test-profile/render-report.js +0 -45
- package/.agents/scripts/lint-label-vocabulary.js +0 -214
- package/.agents/scripts/post-structured-comment.js +0 -127
- package/.agents/scripts/provision-git-hooks.js +0 -85
- package/.agents/scripts/prune-baseline-orphans.js +0 -181
- package/.agents/scripts/run-coverage.js +0 -197
- package/.agents/scripts/run-lint.js +0 -133
- package/.agents/scripts/run-test-profile.js +0 -129
- package/.agents/scripts/run-verify.js +0 -125
- package/.agents/scripts/test-isolate.js +0 -55
- package/.agents/scripts/update-dead-exports-baseline.js +0 -321
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/test-isolate/run-isolate.js — the `test-isolate` orchestration.
|
|
3
|
-
*
|
|
4
|
-
* Story #5316: moved out of `.agents/scripts/test-isolate.js` (CRAP 56 at
|
|
5
|
-
* cyclomatic 7, 0% coverage) so it can be driven from a test. The CLI shell
|
|
6
|
-
* that remains does nothing but call this and translate the exit code.
|
|
7
|
-
*
|
|
8
|
-
* `resolveFiles` and `diagnose` are named seams defaulting to the real
|
|
9
|
-
* implementations, per [`rules/test-seams.md`](../../../rules/test-seams.md):
|
|
10
|
-
* a unit test substitutes them rather than running real suites in child
|
|
11
|
-
* processes, and the production caller passes neither.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { parseIsolateArgv } from './cli-options.js';
|
|
15
|
-
import { resolveTestFiles as defaultResolveTestFiles } from './list-files.js';
|
|
16
|
-
import { createProgressLogger } from './progress-log.js';
|
|
17
|
-
import { renderReport } from './render-report.js';
|
|
18
|
-
import { diagnoseIsolation as defaultDiagnoseIsolation } from './runner.js';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* The report shape returned when no file matched the pattern — a real report
|
|
22
|
-
* with nothing in it, so callers never branch on null.
|
|
23
|
-
*
|
|
24
|
-
* @returns {import('./runner.js').IsolateReport}
|
|
25
|
-
*/
|
|
26
|
-
function emptyReport() {
|
|
27
|
-
return {
|
|
28
|
-
pattern: null,
|
|
29
|
-
files: [],
|
|
30
|
-
isolated: [],
|
|
31
|
-
suite: [],
|
|
32
|
-
flippers: [],
|
|
33
|
-
bisections: [],
|
|
34
|
-
envMutators: [],
|
|
35
|
-
durationMs: 0,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Run the isolation diagnosis end to end.
|
|
41
|
-
*
|
|
42
|
-
* Exit code is 1 when the run found anything worth an operator's attention —
|
|
43
|
-
* a flipper OR an env mutator — and 0 otherwise. An empty match set is not a
|
|
44
|
-
* failure: nothing was asked of the suite, so nothing can be wrong with it.
|
|
45
|
-
*
|
|
46
|
-
* @param {object} [opts]
|
|
47
|
-
* @param {string[]} [opts.argv]
|
|
48
|
-
* @param {string} [opts.repoRoot]
|
|
49
|
-
* @param {(line: string) => void} [opts.onLog]
|
|
50
|
-
* @param {(args: {pattern: string|undefined, repoRoot: string}) => string[]} [opts.resolveFiles]
|
|
51
|
-
* @param {(args: object) => Promise<import('./runner.js').IsolateReport>} [opts.diagnose]
|
|
52
|
-
* @returns {Promise<{ exitCode: number, report: import('./runner.js').IsolateReport }>}
|
|
53
|
-
*/
|
|
54
|
-
export async function runTestIsolate({
|
|
55
|
-
argv = [],
|
|
56
|
-
repoRoot,
|
|
57
|
-
onLog = (s) => process.stdout.write(`${s}\n`),
|
|
58
|
-
resolveFiles = defaultResolveTestFiles,
|
|
59
|
-
diagnose = defaultDiagnoseIsolation,
|
|
60
|
-
} = {}) {
|
|
61
|
-
const options = parseIsolateArgv(argv);
|
|
62
|
-
const files = resolveFiles({ pattern: options.pattern, repoRoot });
|
|
63
|
-
if (files.length === 0) {
|
|
64
|
-
onLog(
|
|
65
|
-
`[test-isolate] no test files matched pattern: ${options.pattern ?? '<default>'}`,
|
|
66
|
-
);
|
|
67
|
-
return { exitCode: 0, report: emptyReport() };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (!options.quiet) {
|
|
71
|
-
onLog(`[test-isolate] scanning ${files.length} file(s)...`);
|
|
72
|
-
}
|
|
73
|
-
const report = await diagnose({
|
|
74
|
-
repoRoot,
|
|
75
|
-
files,
|
|
76
|
-
workers: options.workers,
|
|
77
|
-
suiteConcurrency: options.suiteConcurrency,
|
|
78
|
-
maxBisectDepth: options.maxBisectDepth,
|
|
79
|
-
maxBisectTargets: options.maxBisectTargets,
|
|
80
|
-
onProgress: options.quiet ? undefined : createProgressLogger(onLog),
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
onLog(options.json ? JSON.stringify(report, null, 2) : renderReport(report));
|
|
84
|
-
|
|
85
|
-
const clean = report.flippers.length === 0 && report.envMutators.length === 0;
|
|
86
|
-
return { exitCode: clean ? 0 : 1, report };
|
|
87
|
-
}
|
|
@@ -1,483 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
-
import { parseSingleFileTap, parseSuiteTap } from './parse-tap.js';
|
|
7
|
-
|
|
8
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const ENV_LOADER = path.resolve(__dirname, 'env-snapshot-loader.js');
|
|
10
|
-
|
|
11
|
-
const NODE_TEST_BASE = [
|
|
12
|
-
'--experimental-test-module-mocks',
|
|
13
|
-
'--test',
|
|
14
|
-
'--test-reporter=tap',
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {{ added: string[], removed: string[], changed: string[] }} EnvDiff
|
|
19
|
-
*
|
|
20
|
-
* @typedef {{
|
|
21
|
-
* file: string,
|
|
22
|
-
* status: 'pass' | 'fail',
|
|
23
|
-
* failingTests: string[],
|
|
24
|
-
* envDiff: EnvDiff | null,
|
|
25
|
-
* durationMs: number,
|
|
26
|
-
* }} IsolatedResult
|
|
27
|
-
*
|
|
28
|
-
* @typedef {{
|
|
29
|
-
* file: string,
|
|
30
|
-
* status: 'pass' | 'fail' | 'missing',
|
|
31
|
-
* failingTests: string[],
|
|
32
|
-
* }} SuiteResult
|
|
33
|
-
*
|
|
34
|
-
* @typedef {{
|
|
35
|
-
* file: string,
|
|
36
|
-
* suspects: string[],
|
|
37
|
-
* inconclusive: boolean,
|
|
38
|
-
* }} BisectionResult
|
|
39
|
-
*
|
|
40
|
-
* @typedef {{
|
|
41
|
-
* pattern: string,
|
|
42
|
-
* files: string[],
|
|
43
|
-
* isolated: IsolatedResult[],
|
|
44
|
-
* suite: SuiteResult[],
|
|
45
|
-
* flippers: string[],
|
|
46
|
-
* bisections: BisectionResult[],
|
|
47
|
-
* envMutators: { file: string, envDiff: EnvDiff }[],
|
|
48
|
-
* durationMs: number,
|
|
49
|
-
* }} IsolateReport
|
|
50
|
-
*/
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @param {object} opts
|
|
54
|
-
* @param {string} opts.repoRoot
|
|
55
|
-
* @param {string} opts.file
|
|
56
|
-
* @param {string} [opts.envOutDir] Directory for env-diff output files.
|
|
57
|
-
* @param {number} [opts.timeoutMs]
|
|
58
|
-
* @param {typeof spawn} [opts.spawnFn]
|
|
59
|
-
* @returns {Promise<IsolatedResult>}
|
|
60
|
-
*/
|
|
61
|
-
function runFileIsolated({
|
|
62
|
-
repoRoot,
|
|
63
|
-
file,
|
|
64
|
-
envOutDir,
|
|
65
|
-
timeoutMs = 120_000,
|
|
66
|
-
spawnFn = spawn,
|
|
67
|
-
}) {
|
|
68
|
-
return new Promise((resolve) => {
|
|
69
|
-
const started = Date.now();
|
|
70
|
-
const envOutPath = envOutDir
|
|
71
|
-
? path.join(envOutDir, `${file.replace(/[\\/]/g, '__')}.env-diff`)
|
|
72
|
-
: null;
|
|
73
|
-
if (envOutPath) {
|
|
74
|
-
cleanupEnvSidecars(envOutPath);
|
|
75
|
-
}
|
|
76
|
-
const args = [...NODE_TEST_BASE, '--test-concurrency=1', file];
|
|
77
|
-
const nodeOptions = envOutPath
|
|
78
|
-
? `--import ${pathToFileUrl(ENV_LOADER)}`
|
|
79
|
-
: '';
|
|
80
|
-
const child = spawnFn(process.execPath, args, {
|
|
81
|
-
cwd: repoRoot,
|
|
82
|
-
env: {
|
|
83
|
-
...sanitizeEnv(process.env),
|
|
84
|
-
NODE_OPTIONS: nodeOptions,
|
|
85
|
-
TEST_ISOLATE_ENV_OUT: envOutPath ?? '',
|
|
86
|
-
FORCE_COLOR: '0',
|
|
87
|
-
NO_COLOR: '1',
|
|
88
|
-
SKIP_PREFLIGHT: '1',
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
let stdout = '';
|
|
92
|
-
let stderr = '';
|
|
93
|
-
child.stdout.on('data', (d) => {
|
|
94
|
-
stdout += d.toString('utf8');
|
|
95
|
-
});
|
|
96
|
-
child.stderr.on('data', (d) => {
|
|
97
|
-
stderr += d.toString('utf8');
|
|
98
|
-
});
|
|
99
|
-
const timer = setTimeout(() => {
|
|
100
|
-
child.kill('SIGKILL');
|
|
101
|
-
}, timeoutMs);
|
|
102
|
-
child.on('close', (code) => {
|
|
103
|
-
clearTimeout(timer);
|
|
104
|
-
const parsed = parseSingleFileTap(stdout + stderr, code ?? 1);
|
|
105
|
-
const envDiff = readEnvDiff(envOutPath);
|
|
106
|
-
resolve({
|
|
107
|
-
file,
|
|
108
|
-
status: parsed.status,
|
|
109
|
-
failingTests: parsed.failingTests,
|
|
110
|
-
envDiff,
|
|
111
|
-
durationMs: Date.now() - started,
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function readEnvDiff(envOutPath) {
|
|
118
|
-
if (!envOutPath) return null;
|
|
119
|
-
const dir = path.dirname(envOutPath);
|
|
120
|
-
const base = path.basename(envOutPath);
|
|
121
|
-
let merged = null;
|
|
122
|
-
try {
|
|
123
|
-
if (!fs.existsSync(dir)) return null;
|
|
124
|
-
for (const entry of fs.readdirSync(dir)) {
|
|
125
|
-
if (!entry.startsWith(`${base}.`) || !entry.endsWith('.json')) continue;
|
|
126
|
-
try {
|
|
127
|
-
/** @type {EnvDiff} */
|
|
128
|
-
const parsed = JSON.parse(
|
|
129
|
-
fs.readFileSync(path.join(dir, entry), 'utf8'),
|
|
130
|
-
);
|
|
131
|
-
merged = mergeEnvDiffs(merged, parsed);
|
|
132
|
-
} catch {
|
|
133
|
-
// skip unreadable sidecar
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
} catch {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
return merged;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function mergeEnvDiffs(a, b) {
|
|
143
|
-
if (!a) return b;
|
|
144
|
-
const dedupe = (arr) => Array.from(new Set(arr));
|
|
145
|
-
return {
|
|
146
|
-
added: dedupe([...(a.added ?? []), ...(b.added ?? [])]),
|
|
147
|
-
removed: dedupe([...(a.removed ?? []), ...(b.removed ?? [])]),
|
|
148
|
-
changed: dedupe([...(a.changed ?? []), ...(b.changed ?? [])]),
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function cleanupEnvSidecars(envOutPath) {
|
|
153
|
-
const dir = path.dirname(envOutPath);
|
|
154
|
-
const base = path.basename(envOutPath);
|
|
155
|
-
if (!fs.existsSync(dir)) return;
|
|
156
|
-
for (const entry of fs.readdirSync(dir)) {
|
|
157
|
-
if (entry.startsWith(`${base}.`) && entry.endsWith('.json')) {
|
|
158
|
-
try {
|
|
159
|
-
fs.rmSync(path.join(dir, entry), { force: true });
|
|
160
|
-
} catch {
|
|
161
|
-
// ignore
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function pathToFileUrl(p) {
|
|
168
|
-
return pathToFileURL(p).href;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Strip env vars that signal "I am a node:test worker" so spawned child
|
|
173
|
-
* `node --test` processes don't refuse to run with "node:test run() is
|
|
174
|
-
* being called recursively". This lets `test-isolate` itself be exercised
|
|
175
|
-
* from inside the project's own test suite.
|
|
176
|
-
*/
|
|
177
|
-
function sanitizeEnv(source) {
|
|
178
|
-
const out = { ...source };
|
|
179
|
-
for (const key of Object.keys(out)) {
|
|
180
|
-
if (key.startsWith('NODE_TEST_CONTEXT')) delete out[key];
|
|
181
|
-
}
|
|
182
|
-
delete out.NODE_TEST_CONTEXT;
|
|
183
|
-
return out;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Run a list of test files inside a single `node --test` invocation at the
|
|
188
|
-
* given concurrency. Returns per-file pass/fail parsed from TAP.
|
|
189
|
-
*
|
|
190
|
-
* @param {object} opts
|
|
191
|
-
* @param {string} opts.repoRoot
|
|
192
|
-
* @param {string[]} opts.files
|
|
193
|
-
* @param {number} [opts.concurrency]
|
|
194
|
-
* @param {number} [opts.timeoutMs]
|
|
195
|
-
* @param {typeof spawn} [opts.spawnFn]
|
|
196
|
-
* @returns {Promise<{ results: SuiteResult[], exitCode: number, stdout: string, stderr: string }>}
|
|
197
|
-
*/
|
|
198
|
-
function runSuite({
|
|
199
|
-
repoRoot,
|
|
200
|
-
files,
|
|
201
|
-
concurrency = 8,
|
|
202
|
-
timeoutMs = 5 * 60 * 1000,
|
|
203
|
-
spawnFn = spawn,
|
|
204
|
-
}) {
|
|
205
|
-
return new Promise((resolve) => {
|
|
206
|
-
if (files.length === 0) {
|
|
207
|
-
resolve({ results: [], exitCode: 0, stdout: '', stderr: '' });
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
const args = [
|
|
211
|
-
...NODE_TEST_BASE,
|
|
212
|
-
`--test-concurrency=${concurrency}`,
|
|
213
|
-
...files,
|
|
214
|
-
];
|
|
215
|
-
const child = spawnFn(process.execPath, args, {
|
|
216
|
-
cwd: repoRoot,
|
|
217
|
-
env: {
|
|
218
|
-
...sanitizeEnv(process.env),
|
|
219
|
-
FORCE_COLOR: '0',
|
|
220
|
-
NO_COLOR: '1',
|
|
221
|
-
SKIP_PREFLIGHT: '1',
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
let stdout = '';
|
|
225
|
-
let stderr = '';
|
|
226
|
-
child.stdout.on('data', (d) => {
|
|
227
|
-
stdout += d.toString('utf8');
|
|
228
|
-
});
|
|
229
|
-
child.stderr.on('data', (d) => {
|
|
230
|
-
stderr += d.toString('utf8');
|
|
231
|
-
});
|
|
232
|
-
const timer = setTimeout(() => {
|
|
233
|
-
child.kill('SIGKILL');
|
|
234
|
-
}, timeoutMs);
|
|
235
|
-
child.on('close', (code) => {
|
|
236
|
-
clearTimeout(timer);
|
|
237
|
-
const parsed = parseSuiteTap(stdout + stderr);
|
|
238
|
-
// Node's TAP reporter prints subtest names using the host path
|
|
239
|
-
// separator (backslashes on Windows). Look up both forms.
|
|
240
|
-
const results = files.map((file) => {
|
|
241
|
-
const winForm = file.replace(/\//g, '\\');
|
|
242
|
-
const entry = parsed.get(file) ?? parsed.get(winForm);
|
|
243
|
-
if (!entry) {
|
|
244
|
-
return { file, status: 'missing', failingTests: [] };
|
|
245
|
-
}
|
|
246
|
-
return {
|
|
247
|
-
file,
|
|
248
|
-
status: entry.status,
|
|
249
|
-
failingTests: entry.failingTests,
|
|
250
|
-
};
|
|
251
|
-
});
|
|
252
|
-
resolve({ results, exitCode: code ?? 1, stdout, stderr });
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Run isolated runs in parallel across a worker pool.
|
|
259
|
-
*
|
|
260
|
-
* @param {object} opts
|
|
261
|
-
* @param {string} opts.repoRoot
|
|
262
|
-
* @param {string[]} opts.files
|
|
263
|
-
* @param {string} [opts.envOutDir]
|
|
264
|
-
* @param {number} [opts.workers]
|
|
265
|
-
* @param {number} [opts.timeoutMs]
|
|
266
|
-
* @param {(r: IsolatedResult) => void} [opts.onResult]
|
|
267
|
-
* @returns {Promise<IsolatedResult[]>}
|
|
268
|
-
*/
|
|
269
|
-
async function runIsolatedPool({
|
|
270
|
-
repoRoot,
|
|
271
|
-
files,
|
|
272
|
-
envOutDir,
|
|
273
|
-
workers = Math.max(2, Math.min(os.cpus().length, 8)),
|
|
274
|
-
timeoutMs = 120_000,
|
|
275
|
-
onResult,
|
|
276
|
-
}) {
|
|
277
|
-
const queue = [...files];
|
|
278
|
-
const results = [];
|
|
279
|
-
const workerCount = Math.min(workers, queue.length);
|
|
280
|
-
await Promise.all(
|
|
281
|
-
Array.from({ length: workerCount }, async () => {
|
|
282
|
-
while (queue.length > 0) {
|
|
283
|
-
const file = queue.shift();
|
|
284
|
-
if (!file) return;
|
|
285
|
-
const r = await runFileIsolated({
|
|
286
|
-
repoRoot,
|
|
287
|
-
file,
|
|
288
|
-
envOutDir,
|
|
289
|
-
timeoutMs,
|
|
290
|
-
});
|
|
291
|
-
results.push(r);
|
|
292
|
-
if (onResult) onResult(r);
|
|
293
|
-
}
|
|
294
|
-
}),
|
|
295
|
-
);
|
|
296
|
-
return results;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Bisect to find the smallest candidate subset (down to a single file) whose
|
|
301
|
-
* presence alongside `target` reproduces `target` failing.
|
|
302
|
-
*
|
|
303
|
-
* Strategy: binary halving. Run `[half, target]` at full concurrency. If
|
|
304
|
-
* `target` fails, recurse into `half`; else recurse into the other half. The
|
|
305
|
-
* search depth is capped — when both halves keep failing or neither
|
|
306
|
-
* reproduces, the bisection is marked inconclusive and the residual
|
|
307
|
-
* candidate set returned as suspects.
|
|
308
|
-
*
|
|
309
|
-
* @param {object} opts
|
|
310
|
-
* @param {string} opts.repoRoot
|
|
311
|
-
* @param {string} opts.target File that flipped (passed alone, failed in suite).
|
|
312
|
-
* @param {string[]} opts.candidates All other files in the suite.
|
|
313
|
-
* @param {number} [opts.concurrency]
|
|
314
|
-
* @param {number} [opts.maxDepth]
|
|
315
|
-
* @param {(stage: string, payload: object) => void} [opts.onProgress]
|
|
316
|
-
* @returns {Promise<BisectionResult>}
|
|
317
|
-
*/
|
|
318
|
-
export async function bisectFlipper({
|
|
319
|
-
repoRoot,
|
|
320
|
-
target,
|
|
321
|
-
candidates,
|
|
322
|
-
concurrency = 8,
|
|
323
|
-
maxDepth = 8,
|
|
324
|
-
onProgress,
|
|
325
|
-
runSuiteFn = runSuite,
|
|
326
|
-
}) {
|
|
327
|
-
let pool = [...candidates];
|
|
328
|
-
let depth = 0;
|
|
329
|
-
let inconclusive = false;
|
|
330
|
-
|
|
331
|
-
while (pool.length > 1 && depth < maxDepth) {
|
|
332
|
-
const mid = Math.ceil(pool.length / 2);
|
|
333
|
-
const half = pool.slice(0, mid);
|
|
334
|
-
const { results } = await runSuiteFn({
|
|
335
|
-
repoRoot,
|
|
336
|
-
files: [...half, target],
|
|
337
|
-
concurrency,
|
|
338
|
-
});
|
|
339
|
-
const targetResult = results.find((r) => r.file === target);
|
|
340
|
-
if (onProgress) {
|
|
341
|
-
onProgress('probe', {
|
|
342
|
-
target,
|
|
343
|
-
depth,
|
|
344
|
-
candidates: half.length,
|
|
345
|
-
targetStatus: targetResult?.status,
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
if (targetResult?.status === 'fail') {
|
|
349
|
-
pool = half;
|
|
350
|
-
} else {
|
|
351
|
-
const other = pool.slice(mid);
|
|
352
|
-
const r2 = await runSuiteFn({
|
|
353
|
-
repoRoot,
|
|
354
|
-
files: [...other, target],
|
|
355
|
-
concurrency,
|
|
356
|
-
});
|
|
357
|
-
const t2 = r2.results.find((r) => r.file === target);
|
|
358
|
-
if (onProgress) {
|
|
359
|
-
onProgress('probe', {
|
|
360
|
-
target,
|
|
361
|
-
depth: depth + 0.5,
|
|
362
|
-
candidates: other.length,
|
|
363
|
-
targetStatus: t2?.status,
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
if (t2?.status === 'fail') {
|
|
367
|
-
pool = other;
|
|
368
|
-
} else {
|
|
369
|
-
inconclusive = true;
|
|
370
|
-
break;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
depth += 1;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return {
|
|
377
|
-
file: target,
|
|
378
|
-
suspects: pool,
|
|
379
|
-
inconclusive: inconclusive || pool.length > 1,
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Drive the full isolation diagnosis.
|
|
385
|
-
*
|
|
386
|
-
* @param {object} opts
|
|
387
|
-
* @param {string} opts.repoRoot
|
|
388
|
-
* @param {string[]} opts.files
|
|
389
|
-
* @param {number} [opts.suiteConcurrency]
|
|
390
|
-
* @param {number} [opts.workers]
|
|
391
|
-
* @param {number} [opts.maxBisectTargets]
|
|
392
|
-
* @param {number} [opts.maxBisectDepth]
|
|
393
|
-
* @param {(stage: string, payload?: object) => void} [opts.onProgress]
|
|
394
|
-
* @returns {Promise<IsolateReport>}
|
|
395
|
-
*/
|
|
396
|
-
export async function diagnoseIsolation({
|
|
397
|
-
repoRoot,
|
|
398
|
-
files,
|
|
399
|
-
suiteConcurrency = 8,
|
|
400
|
-
workers,
|
|
401
|
-
maxBisectTargets = 5,
|
|
402
|
-
maxBisectDepth = 8,
|
|
403
|
-
onProgress = () => {},
|
|
404
|
-
}) {
|
|
405
|
-
const started = Date.now();
|
|
406
|
-
const envOutDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-isolate-env-'));
|
|
407
|
-
|
|
408
|
-
onProgress('isolated:start', { count: files.length });
|
|
409
|
-
const isolated = await runIsolatedPool({
|
|
410
|
-
repoRoot,
|
|
411
|
-
files,
|
|
412
|
-
envOutDir,
|
|
413
|
-
workers,
|
|
414
|
-
onResult: (r) =>
|
|
415
|
-
onProgress('isolated:file', {
|
|
416
|
-
file: r.file,
|
|
417
|
-
status: r.status,
|
|
418
|
-
durationMs: r.durationMs,
|
|
419
|
-
}),
|
|
420
|
-
});
|
|
421
|
-
onProgress('isolated:done', { count: isolated.length });
|
|
422
|
-
|
|
423
|
-
onProgress('suite:start', { count: files.length });
|
|
424
|
-
const { results: suite } = await runSuite({
|
|
425
|
-
repoRoot,
|
|
426
|
-
files,
|
|
427
|
-
concurrency: suiteConcurrency,
|
|
428
|
-
});
|
|
429
|
-
onProgress('suite:done', { count: suite.length });
|
|
430
|
-
|
|
431
|
-
const suiteByFile = new Map(suite.map((s) => [s.file, s]));
|
|
432
|
-
const isolatedByFile = new Map(isolated.map((s) => [s.file, s]));
|
|
433
|
-
|
|
434
|
-
const flippers = files.filter((f) => {
|
|
435
|
-
const iso = isolatedByFile.get(f);
|
|
436
|
-
const ste = suiteByFile.get(f);
|
|
437
|
-
return iso?.status === 'pass' && ste?.status === 'fail';
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
const bisectTargets = flippers.slice(0, maxBisectTargets);
|
|
441
|
-
const bisections = [];
|
|
442
|
-
for (const target of bisectTargets) {
|
|
443
|
-
const candidates = files.filter((f) => f !== target);
|
|
444
|
-
onProgress('bisect:start', { target });
|
|
445
|
-
const result = await bisectFlipper({
|
|
446
|
-
repoRoot,
|
|
447
|
-
target,
|
|
448
|
-
candidates,
|
|
449
|
-
concurrency: suiteConcurrency,
|
|
450
|
-
maxDepth: maxBisectDepth,
|
|
451
|
-
onProgress,
|
|
452
|
-
});
|
|
453
|
-
bisections.push(result);
|
|
454
|
-
onProgress('bisect:done', { target, suspects: result.suspects });
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const envMutators = isolated
|
|
458
|
-
.filter((r) => {
|
|
459
|
-
const d = r.envDiff;
|
|
460
|
-
return (
|
|
461
|
-
d &&
|
|
462
|
-
(d.added.length > 0 || d.removed.length > 0 || d.changed.length > 0)
|
|
463
|
-
);
|
|
464
|
-
})
|
|
465
|
-
.map((r) => ({ file: r.file, envDiff: r.envDiff }));
|
|
466
|
-
|
|
467
|
-
try {
|
|
468
|
-
fs.rmSync(envOutDir, { recursive: true, force: true });
|
|
469
|
-
} catch {
|
|
470
|
-
// ignore
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return {
|
|
474
|
-
pattern: files.length === 1 ? files[0] : null,
|
|
475
|
-
files,
|
|
476
|
-
isolated,
|
|
477
|
-
suite,
|
|
478
|
-
flippers,
|
|
479
|
-
bisections,
|
|
480
|
-
envMutators,
|
|
481
|
-
durationMs: Date.now() - started,
|
|
482
|
-
};
|
|
483
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parse Node.js `node --test --test-reporter tap` output into structured
|
|
3
|
-
* timing rows plus footer aggregates.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const SUBTEST_RE = /^(\s*)# Subtest:\s*(.+)$/;
|
|
7
|
-
const RESULT_RE = /^(\s*)(ok|not ok)\s+\d+\s+-\s+(.+)$/;
|
|
8
|
-
const DURATION_RE = /^\s*duration_ms:\s*([\d.]+)/;
|
|
9
|
-
const FOOTER_TESTS_RE = /^# tests\s+(\d+)/;
|
|
10
|
-
const FOOTER_SUITES_RE = /^# suites\s+(\d+)/;
|
|
11
|
-
const FOOTER_DURATION_RE = /^# duration_ms\s+([\d.]+)/;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {'test' | 'suite'} TapEntryKind
|
|
15
|
-
* @typedef {{
|
|
16
|
-
* kind: TapEntryKind,
|
|
17
|
-
* name: string,
|
|
18
|
-
* path: string,
|
|
19
|
-
* durationMs: number,
|
|
20
|
-
* }} TapTimingEntry
|
|
21
|
-
* @typedef {{
|
|
22
|
-
* totalDurationMs: number | null,
|
|
23
|
-
* testCount: number | null,
|
|
24
|
-
* suiteCount: number | null,
|
|
25
|
-
* entries: TapTimingEntry[],
|
|
26
|
-
* }} TapProfile
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @param {string} tapText
|
|
31
|
-
* @returns {TapProfile}
|
|
32
|
-
*/
|
|
33
|
-
export function parseTapOutput(tapText) {
|
|
34
|
-
const lines = tapText.replace(/\r\n/g, '\n').split('\n');
|
|
35
|
-
const suiteStack = [];
|
|
36
|
-
const entries = [];
|
|
37
|
-
let pending = null;
|
|
38
|
-
let totalDurationMs = null;
|
|
39
|
-
let testCount = null;
|
|
40
|
-
let suiteCount = null;
|
|
41
|
-
|
|
42
|
-
for (const line of lines) {
|
|
43
|
-
const subtest = line.match(SUBTEST_RE);
|
|
44
|
-
if (subtest) {
|
|
45
|
-
const depth = Math.floor(subtest[1].length / 4);
|
|
46
|
-
const name = subtest[2].trim();
|
|
47
|
-
suiteStack.length = depth;
|
|
48
|
-
suiteStack[depth] = name;
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const result = line.match(RESULT_RE);
|
|
53
|
-
if (result) {
|
|
54
|
-
pending = {
|
|
55
|
-
depth: Math.floor(result[1].length / 4),
|
|
56
|
-
name: result[3].trim(),
|
|
57
|
-
kind: null,
|
|
58
|
-
durationMs: null,
|
|
59
|
-
};
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (pending) {
|
|
64
|
-
const duration = line.match(DURATION_RE);
|
|
65
|
-
if (duration) {
|
|
66
|
-
pending.durationMs = Number(duration[1]);
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (line.trim() === "type: 'test'") {
|
|
70
|
-
pending.kind = 'test';
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (line.trim() === "type: 'suite'") {
|
|
74
|
-
pending.kind = 'suite';
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (line.trim() === '---') {
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
if (line.trim() === '...') {
|
|
81
|
-
if (pending.durationMs != null && pending.kind) {
|
|
82
|
-
flushPending();
|
|
83
|
-
}
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const footerTests = line.match(FOOTER_TESTS_RE);
|
|
89
|
-
if (footerTests) {
|
|
90
|
-
testCount = Number(footerTests[1]);
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
const footerSuites = line.match(FOOTER_SUITES_RE);
|
|
94
|
-
if (footerSuites) {
|
|
95
|
-
suiteCount = Number(footerSuites[1]);
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
const footerDuration = line.match(FOOTER_DURATION_RE);
|
|
99
|
-
if (footerDuration) {
|
|
100
|
-
totalDurationMs = Number(footerDuration[1]);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (pending?.durationMs != null && pending.kind) {
|
|
105
|
-
flushPending();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
totalDurationMs,
|
|
110
|
-
testCount,
|
|
111
|
-
suiteCount,
|
|
112
|
-
entries,
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
function flushPending() {
|
|
116
|
-
const pathParts = suiteStack.slice(0, pending.depth).concat(pending.name);
|
|
117
|
-
entries.push({
|
|
118
|
-
kind: pending.kind,
|
|
119
|
-
name: pending.name,
|
|
120
|
-
path: pathParts.join(' › '),
|
|
121
|
-
durationMs: pending.durationMs,
|
|
122
|
-
});
|
|
123
|
-
pending = null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* @param {TapTimingEntry[]} entries
|
|
129
|
-
* @param {number} [topN=20]
|
|
130
|
-
* @returns {TapTimingEntry[]}
|
|
131
|
-
*/
|
|
132
|
-
export function selectSlowestEntries(entries, topN = 20) {
|
|
133
|
-
return [...entries]
|
|
134
|
-
.sort((a, b) => b.durationMs - a.durationMs)
|
|
135
|
-
.slice(0, topN);
|
|
136
|
-
}
|