mandrel 2.59.0 → 2.61.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 +21 -19
- package/.agents/agents/acceptance-critic.md +24 -43
- package/.agents/agents/story-worker.md +20 -21
- package/.agents/docs/agentrc-reference.json +5 -84
- package/.agents/docs/configuration.md +48 -132
- package/.agents/docs/workflows.md +2 -2
- package/.agents/instructions.md +5 -8
- package/.agents/rules/ci-remediation.md +41 -8
- package/.agents/rules/gherkin-standards.md +4 -0
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +16 -496
- package/.agents/schemas/story-deliver-terminal.schema.json +13 -3
- package/.agents/schemas/validation-evidence.schema.json +2 -1
- package/.agents/scripts/README.md +23 -13
- package/.agents/scripts/acceptance-eval.js +35 -169
- 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 +10 -41
- package/.agents/scripts/check-arch-cycles.js +14 -64
- package/.agents/scripts/check-baselines.js +8 -48
- package/.agents/scripts/check-context-budget.js +105 -311
- 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 +34 -98
- package/.agents/scripts/deliver-light.js +25 -171
- package/.agents/scripts/deliver-recover.js +6 -42
- package/.agents/scripts/deliver-run.js +534 -0
- 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 +57 -49
- 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 +7 -19
- 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 +39 -121
- 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 -34
- package/.agents/scripts/lib/config/explain.js +10 -83
- package/.agents/scripts/lib/config/gates/coverage.schema.js +0 -12
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +3 -31
- 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 +11 -52
- package/.agents/scripts/lib/config-schema-shared.js +1 -4
- package/.agents/scripts/lib/config-settings-schema-delivery.js +16 -291
- 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 +18 -35
- package/.agents/scripts/lib/coverage-capture-incremental.js +15 -45
- package/.agents/scripts/lib/coverage-capture-usage.js +8 -25
- 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 -124
- 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 +94 -419
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +20 -98
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +27 -149
- 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 +123 -191
- 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 +22 -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 +28 -156
- 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 +121 -157
- 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 +118 -462
- 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 +37 -307
- 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/pinned-identifier-lint.js +17 -57
- package/.agents/scripts/lib/orchestration/plan-context.js +55 -318
- 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 +16 -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 +71 -289
- package/.agents/scripts/lib/orchestration/plan-persist/soft-findings.js +2 -12
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +96 -362
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +9 -39
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +60 -186
- 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 -91
- 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 +245 -326
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +55 -159
- 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 +83 -239
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +20 -82
- 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 +136 -486
- 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 +96 -0
- 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 +180 -273
- 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 -200
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +167 -252
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +52 -0
- 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 -135
- 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 +63 -344
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +51 -244
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +39 -261
- 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 +51 -66
- package/.agents/scripts/lib/story-body/footer-block.js +11 -44
- package/.agents/scripts/lib/story-body/story-body.js +123 -344
- package/.agents/scripts/lib/temp-retention.js +42 -143
- package/.agents/scripts/lib/templates/decomposer-prompts.js +18 -80
- 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 +67 -209
- 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 -105
- package/.agents/scripts/nav-registry-diff.js +22 -108
- package/.agents/scripts/notify.js +12 -69
- package/.agents/scripts/plan-context.js +97 -92
- package/.agents/scripts/plan-critics.js +12 -66
- package/.agents/scripts/plan-persist.js +71 -137
- package/.agents/scripts/plan-run-epilogue.js +20 -43
- package/.agents/scripts/pr-watch-with-update.js +79 -263
- 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 -259
- package/.agents/scripts/stories-wave-tick.js +179 -415
- 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/skills/core/gates-and-baselines/reference.md +0 -1
- package/.agents/skills/skills.index.json +2 -2
- package/.agents/skills/stack/qa/playwright/SKILL.md +26 -0
- 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/acceptance-self-eval.md +84 -157
- package/.agents/workflows/helpers/audit-lens-core.md +1 -1
- package/.agents/workflows/helpers/code-quality-guardrails.md +12 -15
- package/.agents/workflows/helpers/code-review.md +4 -2
- package/.agents/workflows/helpers/deliver-digest.md +37 -28
- package/.agents/workflows/helpers/deliver-light.md +92 -101
- package/.agents/workflows/helpers/deliver-reference.md +162 -220
- package/.agents/workflows/helpers/deliver-story-reference.md +197 -607
- package/.agents/workflows/helpers/deliver-story.md +17 -18
- package/.agents/workflows/helpers/plan-reference.md +125 -167
- package/.agents/workflows/helpers/qa-core.md +12 -0
- package/.agents/workflows/mandrel-deliver.md +47 -31
- package/.agents/workflows/mandrel-plan.md +22 -21
- package/.agents/workflows/mandrel-update.md +36 -21
- 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 +60 -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 +326 -523
- 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 +17 -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 +21 -0
- package/lib/migrations/steps/strip-removed-agentrc-keys.js +333 -0
- package/package.json +17 -14
- package/.agents/docs/SDLC.md +0 -590
- package/.agents/docs/quality-gates.md +0 -1179
- package/.agents/rules/known-tooling-behavior.md +0 -150
- 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/schemas/model-attribution.schema.json +0 -53
- 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 -366
- package/.agents/scripts/check-test-portability.js +0 -512
- package/.agents/scripts/check-workflow-citations.js +0 -332
- 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/orchestration/model-attribution.js +0 -418
- package/.agents/scripts/lib/orchestration/story-plan-state.js +0 -33
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +0 -67
- 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 -118
- package/.agents/scripts/test-isolate.js +0 -55
- package/.agents/scripts/update-dead-exports-baseline.js +0 -321
|
@@ -1,44 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* single-story-sweep/sweep-lock.js
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* out of `git worktree list`" pattern observed during Story #2007's
|
|
10
|
-
* session.
|
|
11
|
-
*
|
|
12
|
-
* The lock primitive is a single-file rendezvous:
|
|
13
|
-
*
|
|
14
|
-
* - `acquireSweepLock({ lockPath, timeoutMs })` opens the file with
|
|
15
|
-
* `wx` so concurrent attempts fail at the syscall layer (atomic
|
|
16
|
-
* create-or-error).
|
|
17
|
-
* - A stale lockfile (mtime older than `timeoutMs`) is treated as
|
|
18
|
-
* expired and replaced — protects against operators who Ctrl-C
|
|
19
|
-
* mid-init.
|
|
20
|
-
* - The returned `release` callback unlinks the file. A process
|
|
21
|
-
* `'exit'` listener also unlinks as a belt-and-braces guard.
|
|
22
|
-
*
|
|
23
|
-
* The lock is never load-bearing: the caller (`single-story-init.js`)
|
|
24
|
-
* skips the sweep when the lock is contended and continues with init.
|
|
25
|
-
* That matches the existing "sweep never blocks init" contract.
|
|
26
|
-
*
|
|
27
|
-
* **Story #5112 — a live holder is never mistaken for a crashed one.**
|
|
28
|
-
* The critical section this guards (per-candidate `gh pr view`, `getTicket`,
|
|
29
|
-
* `push --delete`) is unbounded, so a healthy sweep can easily outlive the
|
|
30
|
-
* 60 s staleness threshold. Three changes close that:
|
|
31
|
-
*
|
|
32
|
-
* 1. **Heartbeat.** The holder refreshes the lockfile mtime on an
|
|
33
|
-
* unref'd interval below `timeoutMs`, so an alive holder never reads
|
|
34
|
-
* stale no matter how long its critical section runs.
|
|
35
|
-
* 2. **Identity-checked steal.** A stale-breaker re-stats before it
|
|
36
|
-
* unlinks and only removes the *exact* file it observed (same
|
|
37
|
-
* dev/ino/mtime). Two concurrent breakers therefore yield exactly one
|
|
38
|
-
* acquisition — the loser cannot unlink the winner's fresh lockfile.
|
|
39
|
-
* 3. **Owner-checked release.** `release()` unlinks only a lockfile whose
|
|
40
|
-
* owner line still matches this holder, so a late release never drops
|
|
41
|
-
* someone else's lock.
|
|
4
|
+
* Best-effort cross-process lockfile (atomic `wx` create) for the merged-branch
|
|
5
|
+
* sweep. Never load-bearing: a contended caller skips or proceeds. A live
|
|
6
|
+
* holder is never mistaken for a crashed one: it heartbeats its mtime, a
|
|
7
|
+
* stale-breaker removes only the exact file it observed (dev/ino/mtime), and
|
|
8
|
+
* release unlinks only a lockfile still stamped with its owner.
|
|
42
9
|
*/
|
|
43
10
|
|
|
44
11
|
import fs from 'node:fs';
|
|
@@ -46,38 +13,17 @@ import path from 'node:path';
|
|
|
46
13
|
|
|
47
14
|
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
48
15
|
|
|
49
|
-
/**
|
|
50
|
-
* Floor for the heartbeat interval. Below this the refresh cost starts to
|
|
51
|
-
* matter for a short critical section, and no `timeoutMs` this framework
|
|
52
|
-
* configures is small enough to need it.
|
|
53
|
-
*/
|
|
54
16
|
const MIN_HEARTBEAT_MS = 1_000;
|
|
55
17
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* Three refreshes per staleness window means two consecutive missed refreshes
|
|
59
|
-
* (a stalled event loop, a slow disk) still do not make a live holder look
|
|
60
|
-
* dead.
|
|
61
|
-
*/
|
|
18
|
+
// Three refreshes per staleness window: two missed refreshes (stalled loop,
|
|
19
|
+
// slow disk) still do not make a live holder look dead.
|
|
62
20
|
const HEARTBEAT_DIVISOR = 3;
|
|
63
21
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
* (`sweepMergedBranches` over `story-*`) reached by two entry points —
|
|
67
|
-
* `single-story-init.js` and `boot-sweep.js` — so it gets one lockfile.
|
|
68
|
-
* Before Story #5112 they used `single-story-sweep.lock` and
|
|
69
|
-
* `boot-sweep.lock` respectively and could therefore run the same reap
|
|
70
|
-
* concurrently, each acting on branches the other was mid-delete on. Callers
|
|
71
|
-
* resolve it through {@link resolveSweepLockPath} rather than by name.
|
|
72
|
-
*/
|
|
22
|
+
// One critical section reached from single-story-init and boot-sweep, so one
|
|
23
|
+
// lockfile; both MUST resolve it through resolveSweepLockPath.
|
|
73
24
|
const MERGED_BRANCH_SWEEP_LOCK_FILENAME = 'merged-branch-sweep.lock';
|
|
74
25
|
|
|
75
26
|
/**
|
|
76
|
-
* Resolve the one merged-branch sweep lock path. Both sweep entry points
|
|
77
|
-
* MUST route through this helper — that is what makes "one critical section,
|
|
78
|
-
* one lock" checkable rather than a convention two files can silently drift
|
|
79
|
-
* apart on.
|
|
80
|
-
*
|
|
81
27
|
* @param {{ cwd: string, tempRoot?: string }} args
|
|
82
28
|
* @returns {string} absolute path to the shared lockfile.
|
|
83
29
|
*/
|
|
@@ -86,13 +32,8 @@ export function resolveSweepLockPath({ cwd, tempRoot = 'temp' } = {}) {
|
|
|
86
32
|
}
|
|
87
33
|
|
|
88
34
|
/**
|
|
89
|
-
* Derive the heartbeat interval for a given staleness threshold. Module-
|
|
90
|
-
* private: the contract that matters ("strictly below `timeoutMs`") is
|
|
91
|
-
* observable at the `setIntervalFn` seam {@link acquireSweepLock} accepts, so
|
|
92
|
-
* a test pins it there rather than reaching past the public surface.
|
|
93
|
-
*
|
|
94
35
|
* @param {number} timeoutMs
|
|
95
|
-
* @returns {number}
|
|
36
|
+
* @returns {number} an interval strictly below `timeoutMs`.
|
|
96
37
|
*/
|
|
97
38
|
function heartbeatIntervalFor(timeoutMs) {
|
|
98
39
|
const derived = Math.floor(
|
|
@@ -102,35 +43,19 @@ function heartbeatIntervalFor(timeoutMs) {
|
|
|
102
43
|
return Math.max(MIN_HEARTBEAT_MS, derived);
|
|
103
44
|
}
|
|
104
45
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
* one MUST drop its lockfile before it dies: the `'exit'` guard in
|
|
108
|
-
* {@link buildAcquired} never runs for a signal Node has not been asked to
|
|
109
|
-
* handle, so before Story #5278 a Ctrl-C during a full suite left a lockfile
|
|
110
|
-
* behind that every sibling then had to wait `timeoutMs` to break.
|
|
111
|
-
*/
|
|
46
|
+
// Node runs no 'exit' handler for an unhandled fatal signal, so the holder
|
|
47
|
+
// must drop its lockfile on these itself.
|
|
112
48
|
const RELEASE_ON_SIGNALS = Object.freeze(['SIGINT', 'SIGTERM']);
|
|
113
49
|
|
|
114
50
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* `kill(pid, 0)` performs the permission and existence checks without
|
|
118
|
-
* delivering a signal. Three outcomes matter:
|
|
119
|
-
*
|
|
120
|
-
* - it returns → the process exists and is ours: **alive**;
|
|
121
|
-
* - `EPERM` → the process exists but belongs to another user: **alive**
|
|
122
|
-
* (an existence check that we are not allowed to complete is not
|
|
123
|
-
* evidence of death);
|
|
124
|
-
* - `ESRCH` → no such process: **dead**.
|
|
125
|
-
*
|
|
126
|
-
* A pid that cannot be read at all resolves to `null` — "unknown", which
|
|
127
|
-
* leaves the mtime heuristic in charge exactly as before.
|
|
51
|
+
* `kill(pid, 0)`: returns → alive; `EPERM` → alive (exists, not ours);
|
|
52
|
+
* `ESRCH` → dead. Also used by the full-suite waiter queue.
|
|
128
53
|
*
|
|
129
54
|
* @param {number|null} pid
|
|
130
55
|
* @param {(pid: number, signal: number) => void} [killFn]
|
|
131
56
|
* @returns {boolean|null} `null` when the pid is unknown.
|
|
132
57
|
*/
|
|
133
|
-
function isHolderAlive(pid, killFn = process.kill.bind(process)) {
|
|
58
|
+
export function isHolderAlive(pid, killFn = process.kill.bind(process)) {
|
|
134
59
|
if (!Number.isInteger(pid) || pid <= 0) return null;
|
|
135
60
|
try {
|
|
136
61
|
killFn(pid, 0);
|
|
@@ -141,20 +66,12 @@ function isHolderAlive(pid, killFn = process.kill.bind(process)) {
|
|
|
141
66
|
}
|
|
142
67
|
|
|
143
68
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* changes on every heartbeat, so a steal that re-checks all three cannot
|
|
148
|
-
* remove a lock some other process created (or refreshed) in the interim.
|
|
149
|
-
*
|
|
150
|
-
* Returns `null` when the file is absent or stat fails ("no holder").
|
|
69
|
+
* `dev`+`ino` change on re-create and `mtimeMs` on every heartbeat, so a
|
|
70
|
+
* steal that re-checks all three cannot remove a lock created or refreshed in
|
|
71
|
+
* the interim.
|
|
151
72
|
*
|
|
152
73
|
* @param {string} lockPath
|
|
153
74
|
* @param {object} [fsImpl]
|
|
154
|
-
* Module-private: the two readers that need it (the stale takeover and the
|
|
155
|
-
* `readLockMtime` projection below) both live here, and nothing outside this
|
|
156
|
-
* primitive should be reasoning about a lockfile's inode.
|
|
157
|
-
*
|
|
158
75
|
* @returns {{ mtimeMs: number, ino: number|null, dev: number|null }|null}
|
|
159
76
|
*/
|
|
160
77
|
function readLockIdentity(lockPath, fsImpl = fs) {
|
|
@@ -170,21 +87,12 @@ function readLockIdentity(lockPath, fsImpl = fs) {
|
|
|
170
87
|
}
|
|
171
88
|
}
|
|
172
89
|
|
|
173
|
-
/**
|
|
174
|
-
* Pure: read the lockfile mtime. Returns `null` when the file is absent or
|
|
175
|
-
* stat fails (treat as "no holder"). The mtime projection of
|
|
176
|
-
* {@link readLockIdentity}. Exported for tests.
|
|
177
|
-
*/
|
|
90
|
+
/** Lockfile mtime, or `null` when absent (no holder). */
|
|
178
91
|
export function readLockMtime(lockPath, fsImpl = fs) {
|
|
179
92
|
return readLockIdentity(lockPath, fsImpl)?.mtimeMs ?? null;
|
|
180
93
|
}
|
|
181
94
|
|
|
182
95
|
/**
|
|
183
|
-
* Read the owner id a lockfile was created with (its first line). Returns
|
|
184
|
-
* `null` when the file is absent, unreadable, or empty. Module-private — the
|
|
185
|
-
* owner line is an implementation detail of this primitive; callers observe
|
|
186
|
-
* ownership through which acquire wins and which `release()` is a no-op.
|
|
187
|
-
*
|
|
188
96
|
* @param {string} lockPath
|
|
189
97
|
* @param {object} [fsImpl]
|
|
190
98
|
* @returns {string|null}
|
|
@@ -200,14 +108,8 @@ function readLockOwner(lockPath, fsImpl = fs) {
|
|
|
200
108
|
}
|
|
201
109
|
|
|
202
110
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* absent, unreadable, or its pid line is not a positive integer.
|
|
206
|
-
*
|
|
207
|
-
* Exists so a *waiting* caller can name the holder in its wait line: a bounded
|
|
208
|
-
* wait with no attribution is indistinguishable from a hang, and the pid is
|
|
209
|
-
* the one field an operator can act on (`ps`, `kill`). Reading it is
|
|
210
|
-
* advisory — a `null` just means the wait line says less.
|
|
111
|
+
* The holder pid (third line), so a waiter can name who it waits on.
|
|
112
|
+
* Advisory: `null` just means the wait line says less.
|
|
211
113
|
*
|
|
212
114
|
* @param {string} lockPath
|
|
213
115
|
* @param {object} [fsImpl]
|
|
@@ -224,10 +126,7 @@ export function readLockHolderPid(lockPath, fsImpl = fs) {
|
|
|
224
126
|
}
|
|
225
127
|
|
|
226
128
|
/**
|
|
227
|
-
*
|
|
228
|
-
* on either side is "not the same" — an absent file is never the file we
|
|
229
|
-
* observed. Module-private, like {@link readLockIdentity} it compares:
|
|
230
|
-
* nothing outside this primitive should reason about a lockfile's inode.
|
|
129
|
+
* A `null` on either side is never "the same".
|
|
231
130
|
*
|
|
232
131
|
* @param {ReturnType<typeof readLockIdentity>} a
|
|
233
132
|
* @param {ReturnType<typeof readLockIdentity>} b
|
|
@@ -238,23 +137,14 @@ function sameLockIdentity(a, b) {
|
|
|
238
137
|
return a.mtimeMs === b.mtimeMs && a.ino === b.ino && a.dev === b.dev;
|
|
239
138
|
}
|
|
240
139
|
|
|
241
|
-
/**
|
|
242
|
-
* Pure: is the lockfile mtime older than `timeoutMs`? A `null` mtime
|
|
243
|
-
* (no file) returns `false` — the lock isn't held, there's nothing to
|
|
244
|
-
* be stale. Exported for tests.
|
|
245
|
-
*/
|
|
140
|
+
/** A `null` mtime (no file) is never stale. */
|
|
246
141
|
export function isLockStale(mtime, nowMs, timeoutMs) {
|
|
247
142
|
if (mtime === null) return false;
|
|
248
143
|
return nowMs - mtime > timeoutMs;
|
|
249
144
|
}
|
|
250
145
|
|
|
251
146
|
/**
|
|
252
|
-
*
|
|
253
|
-
* `false` when another process holds it. Any other I/O error throws.
|
|
254
|
-
*
|
|
255
|
-
* Uses `fs.openSync(path, 'wx')` — the `'wx'` flag combination is
|
|
256
|
-
* `O_CREAT | O_EXCL | O_WRONLY` which fails with `EEXIST` if the file
|
|
257
|
-
* already exists. Atomic on POSIX and on Windows ReFS/NTFS.
|
|
147
|
+
* `wx` = O_CREAT|O_EXCL: `false` on EEXIST, any other error throws.
|
|
258
148
|
*/
|
|
259
149
|
function tryCreateLock(lockPath, ownerId, fsImpl = fs) {
|
|
260
150
|
fsImpl.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
@@ -277,37 +167,20 @@ function tryCreateLock(lockPath, ownerId, fsImpl = fs) {
|
|
|
277
167
|
}
|
|
278
168
|
|
|
279
169
|
/**
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
* - `{ acquired: true, release: () => void, ownerId }`
|
|
283
|
-
* - `{ acquired: false, reason: 'contended' | 'error', detail?: string }`
|
|
284
|
-
*
|
|
285
|
-
* When a stale lockfile is found (mtime older than `timeoutMs`), it is
|
|
286
|
-
* unlinked and a fresh acquire is retried once. If the retry also
|
|
287
|
-
* loses the race (another caller acquired between the unlink and the
|
|
288
|
-
* retry), the caller gets `acquired: false, reason: 'contended'` and
|
|
289
|
-
* may decide to skip the sweep — same as a fresh contention.
|
|
170
|
+
* Single attempt, with one stale-takeover retry.
|
|
290
171
|
*
|
|
291
172
|
* @param {object} opts
|
|
292
|
-
* @param {string} opts.lockPath
|
|
173
|
+
* @param {string} opts.lockPath
|
|
293
174
|
* @param {number} [opts.timeoutMs=60000] Stale-lock threshold.
|
|
294
|
-
* @param {string} [opts.ownerId]
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
* @param {
|
|
299
|
-
*
|
|
300
|
-
* @param {
|
|
301
|
-
* @param {
|
|
302
|
-
*
|
|
303
|
-
* `timeoutMs`. `0` disables it.
|
|
304
|
-
* @param {Function} [opts.setIntervalFn] Timer seam for tests.
|
|
305
|
-
* @param {Function} [opts.clearIntervalFn] Timer seam for tests.
|
|
306
|
-
* @param {Function} [opts.killFn] `process.kill` seam for the holder
|
|
307
|
-
* liveness probe (Story #5278).
|
|
308
|
-
* @param {object} [opts.processImpl] `process` seam for the
|
|
309
|
-
* release-on-signal handlers.
|
|
310
|
-
* @returns {{ acquired: true, release: () => void, refresh: () => boolean, ownerId: string }
|
|
175
|
+
* @param {string} [opts.ownerId] Persisted for postmortem.
|
|
176
|
+
* @param {object} [opts.nowFn]
|
|
177
|
+
* @param {object} [opts.fsImpl]
|
|
178
|
+
* @param {number} [opts.heartbeatMs] Defaults to `timeoutMs / 3`; `0` disables.
|
|
179
|
+
* @param {Function} [opts.setIntervalFn]
|
|
180
|
+
* @param {Function} [opts.clearIntervalFn]
|
|
181
|
+
* @param {Function} [opts.killFn] Holder liveness probe seam.
|
|
182
|
+
* @param {object} [opts.processImpl] Seam for release-on-signal.
|
|
183
|
+
* @returns {{ acquired: true, release: () => void, ownerId: string }
|
|
311
184
|
* | { acquired: false, reason: 'contended' | 'error', detail?: string }}
|
|
312
185
|
*/
|
|
313
186
|
export function acquireSweepLock({
|
|
@@ -359,9 +232,8 @@ export function acquireSweepLock({
|
|
|
359
232
|
}
|
|
360
233
|
|
|
361
234
|
/**
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* so two concurrent breakers yield exactly one acquisition.
|
|
235
|
+
* `true` only when this call removed the exact stale file it observed and won
|
|
236
|
+
* the re-create, so concurrent breakers yield one acquisition.
|
|
365
237
|
*
|
|
366
238
|
* @param {{ lockPath: string, ownerId: string, fsImpl: object, nowFn: () => number }} holder
|
|
367
239
|
* @param {number} timeoutMs
|
|
@@ -385,20 +257,9 @@ function tryStaleTakeover(
|
|
|
385
257
|
}
|
|
386
258
|
|
|
387
259
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
* - pid **dead** (`ESRCH`) → stale immediately, whatever the mtime says. A
|
|
393
|
-
* crashed or Ctrl-C'd holder no longer costs every sibling a full
|
|
394
|
-
* `timeoutMs` wait for a lockfile nobody is behind.
|
|
395
|
-
* - anything else (alive, or an unreadable pid) → the mtime heuristic
|
|
396
|
-
* decides, byte-for-byte the pre-#5278 rule.
|
|
397
|
-
*
|
|
398
|
-
* Deliberately one-directional. Letting a live pid *veto* the mtime rule
|
|
399
|
-
* would make a hung holder immortal and would break the reclaim contract the
|
|
400
|
-
* full-suite lock depends on; keeping the holder's mtime advancing while it
|
|
401
|
-
* works is the heartbeat's job (`refreshLockSync`), not this predicate's.
|
|
260
|
+
* A dead pid makes the holder stale immediately; otherwise mtime decides.
|
|
261
|
+
* One-directional on purpose: a live pid never vetoes the mtime rule, or a
|
|
262
|
+
* hung holder would be immortal.
|
|
402
263
|
*
|
|
403
264
|
* @param {{ lockPath: string, fsImpl: object, nowFn: () => number, killFn?: Function, observed: {mtimeMs: number}, timeoutMs: number }} args
|
|
404
265
|
* @returns {boolean}
|
|
@@ -418,12 +279,8 @@ function isHolderStale({
|
|
|
418
279
|
}
|
|
419
280
|
|
|
420
281
|
/**
|
|
421
|
-
* Unlink
|
|
422
|
-
*
|
|
423
|
-
* exact file, `false` when the file changed underneath us (a heartbeat, or
|
|
424
|
-
* another breaker's replacement) or the unlink failed. A `false` return means
|
|
425
|
-
* "someone else owns this now": the caller reports contended rather than
|
|
426
|
-
* racing on.
|
|
282
|
+
* Unlink only if the file is still the observed instance; `false` means
|
|
283
|
+
* someone else owns it now.
|
|
427
284
|
*
|
|
428
285
|
* @param {string} lockPath
|
|
429
286
|
* @param {ReturnType<typeof readLockIdentity>} observed
|
|
@@ -443,28 +300,13 @@ function breakStaleLock(lockPath, observed, fsImpl) {
|
|
|
443
300
|
}
|
|
444
301
|
|
|
445
302
|
/**
|
|
446
|
-
*
|
|
447
|
-
* stale to a concurrent acquirer. Refuses to touch a lockfile whose owner
|
|
448
|
-
* line is no longer ours — after a steal the file belongs to someone else and
|
|
449
|
-
* bumping its mtime would keep *their* lock alive on our behalf.
|
|
450
|
-
*
|
|
451
|
-
* **The synchronous refresh entry point (Story #5278).** The interval-driven
|
|
452
|
-
* heartbeat below only fires when the holder's event loop gets a turn, which
|
|
453
|
-
* a `spawnSync` critical section never gives it. A caller on such a stack
|
|
454
|
-
* calls this directly — immediately before it blocks — so the lock it is
|
|
455
|
-
* about to sit on carries a current mtime rather than the one it was created
|
|
456
|
-
* with minutes earlier.
|
|
303
|
+
* Refuses a lockfile no longer ours, or we would keep a thief's lock alive.
|
|
457
304
|
*
|
|
458
305
|
* @param {{ lockPath: string, ownerId: string, fsImpl?: object, nowFn?: () => number }} holder
|
|
459
306
|
* @returns {boolean} `true` when the refresh landed; `false` when the lock is
|
|
460
307
|
* no longer ours (the caller stops heartbeating).
|
|
461
308
|
*/
|
|
462
|
-
|
|
463
|
-
lockPath,
|
|
464
|
-
ownerId,
|
|
465
|
-
fsImpl = fs,
|
|
466
|
-
nowFn = Date.now,
|
|
467
|
-
}) {
|
|
309
|
+
function refreshLockSync({ lockPath, ownerId, fsImpl = fs, nowFn = Date.now }) {
|
|
468
310
|
if (readLockOwner(lockPath, fsImpl) !== ownerId) return false;
|
|
469
311
|
try {
|
|
470
312
|
const stamp = new Date(nowFn());
|
|
@@ -475,11 +317,7 @@ export function refreshLockSync({
|
|
|
475
317
|
}
|
|
476
318
|
}
|
|
477
319
|
|
|
478
|
-
/**
|
|
479
|
-
* Start the holder's mtime heartbeat. Returns a `stop()` that is safe to call
|
|
480
|
-
* repeatedly. The timer is unref'd where the platform supports it, so a
|
|
481
|
-
* forgotten release can never hold the process open.
|
|
482
|
-
*/
|
|
320
|
+
/** Unref'd so a forgotten release never holds the process open. */
|
|
483
321
|
function startHeartbeat(holder) {
|
|
484
322
|
const { heartbeatMs, setIntervalFn, clearIntervalFn } = holder;
|
|
485
323
|
if (!(heartbeatMs > 0) || typeof setIntervalFn !== 'function') {
|
|
@@ -493,7 +331,7 @@ function startHeartbeat(holder) {
|
|
|
493
331
|
try {
|
|
494
332
|
clearIntervalFn(handle);
|
|
495
333
|
} catch {
|
|
496
|
-
//
|
|
334
|
+
// A fake timer seam may not implement clear.
|
|
497
335
|
}
|
|
498
336
|
};
|
|
499
337
|
timer = setIntervalFn(() => {
|
|
@@ -504,11 +342,6 @@ function startHeartbeat(holder) {
|
|
|
504
342
|
}
|
|
505
343
|
|
|
506
344
|
/**
|
|
507
|
-
* Drop a lockfile, but only when it is still stamped with `ownerId`. A
|
|
508
|
-
* lockfile another holder created after ours was stolen (or stale-broken) is
|
|
509
|
-
* theirs — dropping it would hand a third caller a lock the current holder
|
|
510
|
-
* still believes it owns.
|
|
511
|
-
*
|
|
512
345
|
* @param {string} lockPath
|
|
513
346
|
* @param {string} ownerId
|
|
514
347
|
* @param {object} fsImpl
|
|
@@ -518,7 +351,7 @@ function unlinkIfOwned(lockPath, ownerId, fsImpl) {
|
|
|
518
351
|
try {
|
|
519
352
|
fsImpl.unlinkSync(lockPath);
|
|
520
353
|
} catch {
|
|
521
|
-
// Already gone
|
|
354
|
+
// Already gone.
|
|
522
355
|
}
|
|
523
356
|
}
|
|
524
357
|
|
|
@@ -534,8 +367,6 @@ function buildAcquired(holder) {
|
|
|
534
367
|
detachSignals();
|
|
535
368
|
unlinkIfOwned(lockPath, ownerId, fsImpl);
|
|
536
369
|
};
|
|
537
|
-
// Belt-and-braces: process exit also clears the lockfile so a
|
|
538
|
-
// crashed run doesn't leave a stale-but-not-yet-old artifact behind.
|
|
539
370
|
const exitCleanup = () => release();
|
|
540
371
|
if (typeof processImpl?.once === 'function') {
|
|
541
372
|
processImpl.once('exit', exitCleanup);
|
|
@@ -544,25 +375,13 @@ function buildAcquired(holder) {
|
|
|
544
375
|
return {
|
|
545
376
|
acquired: true,
|
|
546
377
|
release,
|
|
547
|
-
refresh: () => refreshLockSync(holder),
|
|
548
378
|
ownerId,
|
|
549
379
|
};
|
|
550
380
|
}
|
|
551
381
|
|
|
552
382
|
/**
|
|
553
|
-
* Drop the lock on SIGINT
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
* The `'exit'` guard above does not cover this: Node only runs `'exit'`
|
|
557
|
-
* handlers for a signal it has been asked to handle, so an unhandled Ctrl-C
|
|
558
|
-
* terminates the process with the lockfile still on disk. Registering here
|
|
559
|
-
* changes only *cleanup*, never the outcome — the handler removes itself and
|
|
560
|
-
* re-sends the same signal, so with no other listener the process dies under
|
|
561
|
-
* the default disposition and exits 128 + signum (130 for SIGINT), exactly as
|
|
562
|
-
* it did before.
|
|
563
|
-
*
|
|
564
|
-
* Returns a detach callback so a released holder stops intercepting signals
|
|
565
|
-
* it no longer has anything to clean up for.
|
|
383
|
+
* Drop the lock on SIGINT/SIGTERM, then re-raise: only cleanup changes, the
|
|
384
|
+
* process still dies under the default disposition (exit 128 + signum).
|
|
566
385
|
*
|
|
567
386
|
* @param {object} processImpl
|
|
568
387
|
* @param {() => void} release
|
|
@@ -578,10 +397,8 @@ function attachSignalRelease(processImpl, release) {
|
|
|
578
397
|
}
|
|
579
398
|
const handlers = RELEASE_ON_SIGNALS.map((signal) => {
|
|
580
399
|
const handler = () => {
|
|
400
|
+
// release() already detached us, so the re-raise cannot loop back.
|
|
581
401
|
release();
|
|
582
|
-
// `release()` has already detached every handler, so this re-raise
|
|
583
|
-
// reaches the default disposition (or another listener) rather than
|
|
584
|
-
// looping back into us.
|
|
585
402
|
try {
|
|
586
403
|
processImpl.kill(processImpl.pid, signal);
|
|
587
404
|
} catch {
|
|
@@ -596,7 +413,7 @@ function attachSignalRelease(processImpl, release) {
|
|
|
596
413
|
try {
|
|
597
414
|
processImpl.off(signal, handler);
|
|
598
415
|
} catch {
|
|
599
|
-
//
|
|
416
|
+
// A seam may not implement removal.
|
|
600
417
|
}
|
|
601
418
|
}
|
|
602
419
|
};
|
|
@@ -606,9 +423,6 @@ const DEFAULT_WAIT_MS = 8_000;
|
|
|
606
423
|
const DEFAULT_POLL_MS = 150;
|
|
607
424
|
|
|
608
425
|
/**
|
|
609
|
-
* Promise-based delay. Injectable so tests can drive the wait loop on a fake
|
|
610
|
-
* clock without a real timer.
|
|
611
|
-
*
|
|
612
426
|
* @param {number} ms
|
|
613
427
|
* @returns {Promise<void>}
|
|
614
428
|
*/
|
|
@@ -619,33 +433,22 @@ function defaultSleep(ms) {
|
|
|
619
433
|
}
|
|
620
434
|
|
|
621
435
|
/**
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
* harmless, so the sweep caller proceeds immediately on contention. The
|
|
626
|
-
* post-land tail is the opposite case — proceeding immediately IS the race
|
|
627
|
-
* two concurrent closes hit on a shared main checkout — so this wrapper
|
|
628
|
-
* polls the primitive with short backoff up to `waitMs` before giving up.
|
|
629
|
-
*
|
|
630
|
-
* It is still **never load-bearing**: on `waitMs` exhaustion it returns
|
|
631
|
-
* `{ acquired: false, reason: 'contended-after-wait' }` and the caller is
|
|
632
|
-
* expected to proceed anyway. The bounded wait is a best-effort collision
|
|
633
|
-
* damper, not a mutual-exclusion guarantee. A hard I/O error short-circuits
|
|
634
|
-
* the loop (spinning would just re-hit it).
|
|
436
|
+
* Polls {@link acquireSweepLock} up to `waitMs` — a collision damper for the
|
|
437
|
+
* post-land tail, not mutual exclusion: on exhaustion the caller proceeds
|
|
438
|
+
* anyway. A hard I/O error returns immediately.
|
|
635
439
|
*
|
|
636
440
|
* @param {object} opts
|
|
637
441
|
* @param {string} opts.lockPath
|
|
638
|
-
* @param {number} [opts.waitMs]
|
|
639
|
-
* @param {number} [opts.pollMs]
|
|
640
|
-
* @param {number} [opts.timeoutMs] Stale-lock expiry
|
|
641
|
-
* underlying acquire.
|
|
442
|
+
* @param {number} [opts.waitMs]
|
|
443
|
+
* @param {number} [opts.pollMs]
|
|
444
|
+
* @param {number} [opts.timeoutMs] Stale-lock expiry.
|
|
642
445
|
* @param {string} [opts.ownerId]
|
|
643
446
|
* @param {() => number} [opts.nowFn]
|
|
644
447
|
* @param {(ms: number) => Promise<void>} [opts.sleepFn]
|
|
645
448
|
* @param {object} [opts.fsImpl]
|
|
646
|
-
* @param {number} [opts.heartbeatMs]
|
|
647
|
-
* @param {Function} [opts.setIntervalFn]
|
|
648
|
-
* @param {Function} [opts.clearIntervalFn]
|
|
449
|
+
* @param {number} [opts.heartbeatMs]
|
|
450
|
+
* @param {Function} [opts.setIntervalFn]
|
|
451
|
+
* @param {Function} [opts.clearIntervalFn]
|
|
649
452
|
* @returns {Promise<{ acquired: true, release: () => void, ownerId: string }
|
|
650
453
|
* | { acquired: false, reason: 'contended-after-wait' | 'error', detail?: string }>}
|
|
651
454
|
*/
|
|
@@ -679,7 +482,6 @@ export async function acquireLockWithWait({
|
|
|
679
482
|
processImpl,
|
|
680
483
|
});
|
|
681
484
|
if (res.acquired) return res;
|
|
682
|
-
// A hard error will not resolve by retrying — surface it immediately.
|
|
683
485
|
if (res.reason === 'error') return res;
|
|
684
486
|
if (nowFn() >= deadline) {
|
|
685
487
|
return { acquired: false, reason: 'contended-after-wait' };
|