@cleocode/core 2026.9.26 → 2026.10.2
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/dist/build-provenance.json +2 -2
- package/dist/cloud/journal.d.ts +9 -5
- package/dist/cloud/journal.d.ts.map +1 -1
- package/dist/cloud/journal.js +29 -8
- package/dist/cloud/journal.js.map +1 -1
- package/dist/cloud/manifest-check.d.ts +140 -4
- package/dist/cloud/manifest-check.d.ts.map +1 -1
- package/dist/cloud/manifest-check.js +309 -10
- package/dist/cloud/manifest-check.js.map +1 -1
- package/dist/cloud/nexus-attach.d.ts +119 -0
- package/dist/cloud/nexus-attach.d.ts.map +1 -0
- package/dist/cloud/nexus-attach.js +267 -0
- package/dist/cloud/nexus-attach.js.map +1 -0
- package/dist/cloud/nexus-auth.d.ts +15 -3
- package/dist/cloud/nexus-auth.d.ts.map +1 -1
- package/dist/cloud/nexus-auth.js +90 -6
- package/dist/cloud/nexus-auth.js.map +1 -1
- package/dist/cloud/nexus-cloud-activity.d.ts +37 -0
- package/dist/cloud/nexus-cloud-activity.d.ts.map +1 -0
- package/dist/cloud/nexus-cloud-activity.js +79 -0
- package/dist/cloud/nexus-cloud-activity.js.map +1 -0
- package/dist/cloud/nexus-cloud-status.d.ts +132 -0
- package/dist/cloud/nexus-cloud-status.d.ts.map +1 -0
- package/dist/cloud/nexus-cloud-status.js +476 -0
- package/dist/cloud/nexus-cloud-status.js.map +1 -0
- package/dist/cloud/nexus-cloud.d.ts +179 -0
- package/dist/cloud/nexus-cloud.d.ts.map +1 -0
- package/dist/cloud/nexus-cloud.js +296 -0
- package/dist/cloud/nexus-cloud.js.map +1 -0
- package/dist/cloud/nexus-device.d.ts +32 -7
- package/dist/cloud/nexus-device.d.ts.map +1 -1
- package/dist/cloud/nexus-device.js +54 -7
- package/dist/cloud/nexus-device.js.map +1 -1
- package/dist/cloud/nexus-enrol.d.ts +35 -4
- package/dist/cloud/nexus-enrol.d.ts.map +1 -1
- package/dist/cloud/nexus-enrol.js +192 -47
- package/dist/cloud/nexus-enrol.js.map +1 -1
- package/dist/cloud/nexus-home.d.ts +74 -0
- package/dist/cloud/nexus-home.d.ts.map +1 -0
- package/dist/cloud/nexus-home.js +97 -0
- package/dist/cloud/nexus-home.js.map +1 -0
- package/dist/cloud/nexus-link.d.ts +8 -1
- package/dist/cloud/nexus-link.d.ts.map +1 -1
- package/dist/cloud/nexus-link.js +138 -11
- package/dist/cloud/nexus-link.js.map +1 -1
- package/dist/cloud/nexus-logout.d.ts +114 -0
- package/dist/cloud/nexus-logout.d.ts.map +1 -0
- package/dist/cloud/nexus-logout.js +429 -0
- package/dist/cloud/nexus-logout.js.map +1 -0
- package/dist/cloud/nexus-vault-keys.d.ts +129 -0
- package/dist/cloud/nexus-vault-keys.d.ts.map +1 -0
- package/dist/cloud/nexus-vault-keys.js +277 -0
- package/dist/cloud/nexus-vault-keys.js.map +1 -0
- package/dist/cloud/nexus-vault-state.d.ts +121 -0
- package/dist/cloud/nexus-vault-state.d.ts.map +1 -0
- package/dist/cloud/nexus-vault-state.js +274 -0
- package/dist/cloud/nexus-vault-state.js.map +1 -0
- package/dist/cloud/nexus-vault.d.ts +160 -0
- package/dist/cloud/nexus-vault.d.ts.map +1 -0
- package/dist/cloud/nexus-vault.js +1733 -0
- package/dist/cloud/nexus-vault.js.map +1 -0
- package/dist/cloud/signing.d.ts +24 -8
- package/dist/cloud/signing.d.ts.map +1 -1
- package/dist/cloud/signing.js +61 -15
- package/dist/cloud/signing.js.map +1 -1
- package/dist/docs/export-document.js +8341 -3317
- package/dist/docs/export-document.js.map +3 -3
- package/dist/doctor/migrations.d.ts +75 -0
- package/dist/doctor/migrations.d.ts.map +1 -0
- package/dist/doctor/migrations.js +136 -0
- package/dist/doctor/migrations.js.map +1 -0
- package/dist/doctor/sync-sealer.d.ts +48 -0
- package/dist/doctor/sync-sealer.d.ts.map +1 -0
- package/dist/doctor/sync-sealer.js +109 -0
- package/dist/doctor/sync-sealer.js.map +1 -0
- package/dist/doctor/sync-triggers.d.ts +53 -0
- package/dist/doctor/sync-triggers.d.ts.map +1 -0
- package/dist/doctor/sync-triggers.js +157 -0
- package/dist/doctor/sync-triggers.js.map +1 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +5 -1
- package/dist/init.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/llm/plugin-facade.js +8668 -3644
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/nexus/projects-clean.d.ts +3 -0
- package/dist/nexus/projects-clean.d.ts.map +1 -1
- package/dist/nexus/projects-clean.js +9 -3
- package/dist/nexus/projects-clean.js.map +1 -1
- package/dist/nexus/registry-roots.d.ts +3 -1
- package/dist/nexus/registry-roots.d.ts.map +1 -1
- package/dist/nexus/registry-roots.js +5 -2
- package/dist/nexus/registry-roots.js.map +1 -1
- package/dist/nexus/registry.d.ts +8 -1
- package/dist/nexus/registry.d.ts.map +1 -1
- package/dist/nexus/registry.js +24 -10
- package/dist/nexus/registry.js.map +1 -1
- package/dist/nexus/workspace.d.ts +4 -1
- package/dist/nexus/workspace.d.ts.map +1 -1
- package/dist/nexus/workspace.js +10 -4
- package/dist/nexus/workspace.js.map +1 -1
- package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
- package/dist/orchestrate/spawn-ops.js +7 -2
- package/dist/orchestrate/spawn-ops.js.map +1 -1
- package/dist/orchestrate/worker-verify.d.ts +121 -12
- package/dist/orchestrate/worker-verify.d.ts.map +1 -1
- package/dist/orchestrate/worker-verify.js +172 -21
- package/dist/orchestrate/worker-verify.js.map +1 -1
- package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
- package/dist/orchestration/spawn-prompt.js +15 -9
- package/dist/orchestration/spawn-prompt.js.map +1 -1
- package/dist/release/ci-evidence.d.ts +9 -0
- package/dist/release/ci-evidence.d.ts.map +1 -1
- package/dist/release/ci-evidence.js +9 -2
- package/dist/release/ci-evidence.js.map +1 -1
- package/dist/resources/backend.d.ts +15 -3
- package/dist/resources/backend.d.ts.map +1 -1
- package/dist/resources/backend.js +7 -3
- package/dist/resources/backend.js.map +1 -1
- package/dist/resources/darwin-backend.d.ts +142 -0
- package/dist/resources/darwin-backend.d.ts.map +1 -0
- package/dist/resources/darwin-backend.js +288 -0
- package/dist/resources/darwin-backend.js.map +1 -0
- package/dist/resources/governor.d.ts +44 -1
- package/dist/resources/governor.d.ts.map +1 -1
- package/dist/resources/governor.js +100 -36
- package/dist/resources/governor.js.map +1 -1
- package/dist/resources/heavy-command.d.ts +132 -0
- package/dist/resources/heavy-command.d.ts.map +1 -0
- package/dist/resources/heavy-command.js +768 -0
- package/dist/resources/heavy-command.js.map +1 -0
- package/dist/resources/monitor.d.ts +50 -1
- package/dist/resources/monitor.d.ts.map +1 -1
- package/dist/resources/monitor.js +83 -1
- package/dist/resources/monitor.js.map +1 -1
- package/dist/resources/run-admission.d.ts +303 -0
- package/dist/resources/run-admission.d.ts.map +1 -0
- package/dist/resources/run-admission.js +648 -0
- package/dist/resources/run-admission.js.map +1 -0
- package/dist/resources/run-class.d.ts +111 -0
- package/dist/resources/run-class.d.ts.map +1 -0
- package/dist/resources/run-class.js +658 -0
- package/dist/resources/run-class.js.map +1 -0
- package/dist/resources/run-governed.d.ts +158 -0
- package/dist/resources/run-governed.d.ts.map +1 -0
- package/dist/resources/run-governed.js +406 -0
- package/dist/resources/run-governed.js.map +1 -0
- package/dist/resources/slot-holder.d.ts +267 -0
- package/dist/resources/slot-holder.d.ts.map +1 -0
- package/dist/resources/slot-holder.js +505 -0
- package/dist/resources/slot-holder.js.map +1 -0
- package/dist/resources/tool-groups.d.ts +74 -0
- package/dist/resources/tool-groups.d.ts.map +1 -0
- package/dist/resources/tool-groups.js +118 -0
- package/dist/resources/tool-groups.js.map +1 -0
- package/dist/routing/build-command-groups.d.ts.map +1 -1
- package/dist/routing/build-command-groups.js +1 -0
- package/dist/routing/build-command-groups.js.map +1 -1
- package/dist/selfimprove/fix-gen.js +8676 -3652
- package/dist/selfimprove/fix-gen.js.map +3 -3
- package/dist/sentient/cross-project-hygiene.d.ts +3 -2
- package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
- package/dist/sentient/cross-project-hygiene.js +5 -2
- package/dist/sentient/cross-project-hygiene.js.map +1 -1
- package/dist/sentient/state.d.ts +7 -0
- package/dist/sentient/state.d.ts.map +1 -1
- package/dist/sentient/state.js.map +1 -1
- package/dist/sentient/tick.d.ts +14 -2
- package/dist/sentient/tick.d.ts.map +1 -1
- package/dist/sentient/tick.js +63 -4
- package/dist/sentient/tick.js.map +1 -1
- package/dist/setup/sections/nexus-account.d.ts +8 -6
- package/dist/setup/sections/nexus-account.d.ts.map +1 -1
- package/dist/setup/sections/nexus-account.js +53 -9
- package/dist/setup/sections/nexus-account.js.map +1 -1
- package/dist/store/backup-recover.d.ts.map +1 -1
- package/dist/store/backup-recover.js +5 -0
- package/dist/store/backup-recover.js.map +1 -1
- package/dist/store/data-accessor.d.ts +1 -0
- package/dist/store/data-accessor.d.ts.map +1 -1
- package/dist/store/data-accessor.js +7 -0
- package/dist/store/data-accessor.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts +23 -1
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +126 -36
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/exodus/recovery.d.ts.map +1 -1
- package/dist/store/exodus/recovery.js +15 -0
- package/dist/store/exodus/recovery.js.map +1 -1
- package/dist/store/legacy-tasks-lineage.d.ts.map +1 -1
- package/dist/store/legacy-tasks-lineage.js +5 -0
- package/dist/store/legacy-tasks-lineage.js.map +1 -1
- package/dist/store/lock.d.ts +8 -1
- package/dist/store/lock.d.ts.map +1 -1
- package/dist/store/lock.js +10 -2
- package/dist/store/lock.js.map +1 -1
- package/dist/store/migration-manager.d.ts +5 -0
- package/dist/store/migration-manager.d.ts.map +1 -1
- package/dist/store/migration-manager.js +11 -0
- package/dist/store/migration-manager.js.map +1 -1
- package/dist/store/migration-runner.d.ts +158 -0
- package/dist/store/migration-runner.d.ts.map +1 -0
- package/dist/store/migration-runner.js +493 -0
- package/dist/store/migration-runner.js.map +1 -0
- package/dist/store/portable-bundle-import.d.ts +15 -1
- package/dist/store/portable-bundle-import.d.ts.map +1 -1
- package/dist/store/portable-bundle-import.js +24 -4
- package/dist/store/portable-bundle-import.js.map +1 -1
- package/dist/store/portable-bundle-relocate.d.ts +43 -0
- package/dist/store/portable-bundle-relocate.d.ts.map +1 -1
- package/dist/store/portable-bundle-relocate.js +79 -5
- package/dist/store/portable-bundle-relocate.js.map +1 -1
- package/dist/store/portable-bundle-scan.d.ts +20 -0
- package/dist/store/portable-bundle-scan.d.ts.map +1 -1
- package/dist/store/portable-bundle-scan.js +38 -3
- package/dist/store/portable-bundle-scan.js.map +1 -1
- package/dist/store/portable-bundle.d.ts +33 -0
- package/dist/store/portable-bundle.d.ts.map +1 -1
- package/dist/store/portable-bundle.js +34 -7
- package/dist/store/portable-bundle.js.map +1 -1
- package/dist/store/row-identity-registry.d.ts +137 -7
- package/dist/store/row-identity-registry.d.ts.map +1 -1
- package/dist/store/row-identity-registry.js +364 -9
- package/dist/store/row-identity-registry.js.map +1 -1
- package/dist/store/row-identity.d.ts.map +1 -1
- package/dist/store/row-identity.js +9 -10
- package/dist/store/row-identity.js.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.js +10 -0
- package/dist/store/sqlite-data-accessor.js.map +1 -1
- package/dist/store/sqlite.d.ts +31 -0
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +5 -1
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/sync/capture.d.ts +203 -0
- package/dist/store/sync/capture.d.ts.map +1 -0
- package/dist/store/sync/capture.js +562 -0
- package/dist/store/sync/capture.js.map +1 -0
- package/dist/store/sync/clock-store.d.ts.map +1 -1
- package/dist/store/sync/clock-store.js +2 -0
- package/dist/store/sync/clock-store.js.map +1 -1
- package/dist/store/sync/fk-orphans.d.ts +133 -0
- package/dist/store/sync/fk-orphans.d.ts.map +1 -0
- package/dist/store/sync/fk-orphans.js +265 -0
- package/dist/store/sync/fk-orphans.js.map +1 -0
- package/dist/store/sync/flags.d.ts +7 -0
- package/dist/store/sync/flags.d.ts.map +1 -1
- package/dist/store/sync/flags.js +16 -0
- package/dist/store/sync/flags.js.map +1 -1
- package/dist/store/sync/hlc.d.ts.map +1 -1
- package/dist/store/sync/hlc.js +4 -0
- package/dist/store/sync/hlc.js.map +1 -1
- package/dist/store/sync/identity-fill.d.ts +45 -0
- package/dist/store/sync/identity-fill.d.ts.map +1 -0
- package/dist/store/sync/identity-fill.js +85 -0
- package/dist/store/sync/identity-fill.js.map +1 -0
- package/dist/store/sync/machinery.d.ts +27 -0
- package/dist/store/sync/machinery.d.ts.map +1 -0
- package/dist/store/sync/machinery.js +44 -0
- package/dist/store/sync/machinery.js.map +1 -0
- package/dist/store/sync/netting.d.ts +120 -0
- package/dist/store/sync/netting.d.ts.map +1 -0
- package/dist/store/sync/netting.js +336 -0
- package/dist/store/sync/netting.js.map +1 -0
- package/dist/store/sync/replica.d.ts +59 -3
- package/dist/store/sync/replica.d.ts.map +1 -1
- package/dist/store/sync/replica.js +84 -3
- package/dist/store/sync/replica.js.map +1 -1
- package/dist/store/sync/schema.d.ts +18 -3
- package/dist/store/sync/schema.d.ts.map +1 -1
- package/dist/store/sync/schema.js +27 -3
- package/dist/store/sync/schema.js.map +1 -1
- package/dist/store/sync/seal-backlog.d.ts +21 -0
- package/dist/store/sync/seal-backlog.d.ts.map +1 -0
- package/dist/store/sync/seal-backlog.js +24 -0
- package/dist/store/sync/seal-backlog.js.map +1 -0
- package/dist/store/sync/sealer-values.d.ts +34 -0
- package/dist/store/sync/sealer-values.d.ts.map +1 -0
- package/dist/store/sync/sealer-values.js +53 -0
- package/dist/store/sync/sealer-values.js.map +1 -0
- package/dist/store/sync/sealer.d.ts +145 -0
- package/dist/store/sync/sealer.d.ts.map +1 -0
- package/dist/store/sync/sealer.js +906 -0
- package/dist/store/sync/sealer.js.map +1 -0
- package/dist/store/sync/structural.d.ts +63 -0
- package/dist/store/sync/structural.d.ts.map +1 -0
- package/dist/store/sync/structural.js +180 -0
- package/dist/store/sync/structural.js.map +1 -0
- package/dist/store/sync/timestamps.d.ts +92 -0
- package/dist/store/sync/timestamps.d.ts.map +1 -0
- package/dist/store/sync/timestamps.js +228 -0
- package/dist/store/sync/timestamps.js.map +1 -0
- package/dist/store/sync/tombstones.d.ts +75 -0
- package/dist/store/sync/tombstones.d.ts.map +1 -0
- package/dist/store/sync/tombstones.js +103 -0
- package/dist/store/sync/tombstones.js.map +1 -0
- package/dist/store/sync/trigger-classes.d.ts +221 -0
- package/dist/store/sync/trigger-classes.d.ts.map +1 -0
- package/dist/store/sync/trigger-classes.js +441 -0
- package/dist/store/sync/trigger-classes.js.map +1 -0
- package/dist/store/sync/trigger-suspend-at-path.d.ts +23 -0
- package/dist/store/sync/trigger-suspend-at-path.d.ts.map +1 -0
- package/dist/store/sync/trigger-suspend-at-path.js +44 -0
- package/dist/store/sync/trigger-suspend-at-path.js.map +1 -0
- package/dist/store/sync/writer-version.d.ts +43 -0
- package/dist/store/sync/writer-version.d.ts.map +1 -0
- package/dist/store/sync/writer-version.js +90 -0
- package/dist/store/sync/writer-version.js.map +1 -0
- package/dist/store/table-classification.d.ts.map +1 -1
- package/dist/store/table-classification.js +102 -0
- package/dist/store/table-classification.js.map +1 -1
- package/dist/store/trigger-suspend-schema.d.ts +44 -0
- package/dist/store/trigger-suspend-schema.d.ts.map +1 -0
- package/dist/store/trigger-suspend-schema.js +25 -0
- package/dist/store/trigger-suspend-schema.js.map +1 -0
- package/dist/store/vault-manifest.d.ts +365 -0
- package/dist/store/vault-manifest.d.ts.map +1 -0
- package/dist/store/vault-manifest.js +812 -0
- package/dist/store/vault-manifest.js.map +1 -0
- package/dist/store/writer-lease.d.ts +31 -0
- package/dist/store/writer-lease.d.ts.map +1 -1
- package/dist/store/writer-lease.js +65 -2
- package/dist/store/writer-lease.js.map +1 -1
- package/dist/system/health.d.ts.map +1 -1
- package/dist/system/health.js +21 -0
- package/dist/system/health.js.map +1 -1
- package/dist/system/project-health.d.ts.map +1 -1
- package/dist/system/project-health.js +3 -1
- package/dist/system/project-health.js.map +1 -1
- package/dist/tasks/affected-packages.d.ts +58 -0
- package/dist/tasks/affected-packages.d.ts.map +1 -1
- package/dist/tasks/affected-packages.js +75 -6
- package/dist/tasks/affected-packages.js.map +1 -1
- package/dist/tasks/affected-scope.d.ts +150 -23
- package/dist/tasks/affected-scope.d.ts.map +1 -1
- package/dist/tasks/affected-scope.js +320 -32
- package/dist/tasks/affected-scope.js.map +1 -1
- package/dist/tasks/change-set.d.ts +96 -0
- package/dist/tasks/change-set.d.ts.map +1 -1
- package/dist/tasks/change-set.js +169 -4
- package/dist/tasks/change-set.js.map +1 -1
- package/dist/tasks/complete-ci.d.ts +115 -0
- package/dist/tasks/complete-ci.d.ts.map +1 -0
- package/dist/tasks/complete-ci.js +171 -0
- package/dist/tasks/complete-ci.js.map +1 -0
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +50 -17
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/compute-task-view.d.ts.map +1 -1
- package/dist/tasks/compute-task-view.js +7 -0
- package/dist/tasks/compute-task-view.js.map +1 -1
- package/dist/tasks/done-plan.d.ts.map +1 -1
- package/dist/tasks/done-plan.js +51 -30
- package/dist/tasks/done-plan.js.map +1 -1
- package/dist/tasks/done-record.d.ts +6 -0
- package/dist/tasks/done-record.d.ts.map +1 -1
- package/dist/tasks/done-record.js +9 -3
- package/dist/tasks/done-record.js.map +1 -1
- package/dist/tasks/evidence.d.ts +3 -2
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +143 -12
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/gate-notes.d.ts +22 -0
- package/dist/tasks/gate-notes.d.ts.map +1 -0
- package/dist/tasks/gate-notes.js +33 -0
- package/dist/tasks/gate-notes.js.map +1 -0
- package/dist/tasks/index.d.ts +2 -1
- package/dist/tasks/index.d.ts.map +1 -1
- package/dist/tasks/index.js +2 -1
- package/dist/tasks/index.js.map +1 -1
- package/dist/tasks/test-run-binding.d.ts +117 -0
- package/dist/tasks/test-run-binding.d.ts.map +1 -0
- package/dist/tasks/test-run-binding.js +365 -0
- package/dist/tasks/test-run-binding.js.map +1 -0
- package/dist/tasks/tool-cache-env.d.ts +123 -0
- package/dist/tasks/tool-cache-env.d.ts.map +1 -0
- package/dist/tasks/tool-cache-env.js +287 -0
- package/dist/tasks/tool-cache-env.js.map +1 -0
- package/dist/tasks/tool-cache-failed-first.d.ts +155 -0
- package/dist/tasks/tool-cache-failed-first.d.ts.map +1 -0
- package/dist/tasks/tool-cache-failed-first.js +285 -0
- package/dist/tasks/tool-cache-failed-first.js.map +1 -0
- package/dist/tasks/tool-cache.d.ts +375 -55
- package/dist/tasks/tool-cache.d.ts.map +1 -1
- package/dist/tasks/tool-cache.js +912 -303
- package/dist/tasks/tool-cache.js.map +1 -1
- package/dist/tasks/tool-resolver.d.ts +4 -3
- package/dist/tasks/tool-resolver.d.ts.map +1 -1
- package/dist/tasks/tool-resolver.js +15 -4
- package/dist/tasks/tool-resolver.js.map +1 -1
- package/dist/tasks/tool-semaphore.d.ts +67 -7
- package/dist/tasks/tool-semaphore.d.ts.map +1 -1
- package/dist/tasks/tool-semaphore.js +134 -56
- package/dist/tasks/tool-semaphore.js.map +1 -1
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +4 -0
- package/dist/upgrade.js.map +1 -1
- package/dist/validation/engine-ops.d.ts +6 -0
- package/dist/validation/engine-ops.d.ts.map +1 -1
- package/dist/validation/engine-ops.js +8 -0
- package/dist/validation/engine-ops.js.map +1 -1
- package/migrations/drizzle-cleo-project/20260930170000_t12819-trigger-suspend-clause/migration.sql +367 -0
- package/migrations/sync-journal/20260930120000_t12343-capture/migration.sql +47 -0
- package/migrations/sync-journal/20261001170000_t12984-sealer/migration.sql +101 -0
- package/package.json +13 -13
- package/templates/CLEO-INJECTION.md +5 -5
- package/templates/CLEO-REFERENCE.md +8 -4
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holder records for local lock slots: the governor's class slots and the
|
|
3
|
+
* tool semaphore's per-tool slots (T12963, gh#1222).
|
|
4
|
+
*
|
|
5
|
+
* `proper-lockfile` frees a slot whose holder died only after
|
|
6
|
+
* {@link SLOT_LOCK_STALE_MS} (10 min) of mtime staleness. With a one-slot
|
|
7
|
+
* `test-run` budget, a SIGKILLed `cleo verify tool:test` blocked every later
|
|
8
|
+
* heavy run for ten minutes, and the deferral named no one. Each slot carries
|
|
9
|
+
* a `<slot>.holder.json` record: the holder's pid and process start time, the
|
|
10
|
+
* lock directory it describes, and the process groups of the tools it started.
|
|
11
|
+
* A slot is reaped only when the holder pid is provably gone (or recycled) AND
|
|
12
|
+
* every one of those tool groups is gone too: a tool started detached outlives
|
|
13
|
+
* a SIGKILLed cleo, and it is the tool that uses the machine.
|
|
14
|
+
*
|
|
15
|
+
* Start times are `ps -o lstart=` strings rendered under `PS_STABLE_ENV` (UTC,
|
|
16
|
+
* C locale), so a string written by one process compares equal to the same
|
|
17
|
+
* process's start time read by another, whatever either one's `TZ` or locale.
|
|
18
|
+
*
|
|
19
|
+
* @task T12963
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
22
|
+
import { hostname } from 'node:os';
|
|
23
|
+
import { basename } from 'node:path';
|
|
24
|
+
import lockfile from 'proper-lockfile';
|
|
25
|
+
import { getLogger } from '../logger.js';
|
|
26
|
+
import { readProcessEntry } from '../sessions/terminal-identity.js';
|
|
27
|
+
import { followToolGroups, isProbeableId, probeProcessGroup } from './tool-groups.js';
|
|
28
|
+
let _log = null;
|
|
29
|
+
function log() {
|
|
30
|
+
if (_log === null)
|
|
31
|
+
_log = getLogger('resource-governor');
|
|
32
|
+
return _log;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A slot lock older than this may be stolen (its holder presumed dead): the
|
|
36
|
+
* `proper-lockfile` stale window of every governor slot, and the default of
|
|
37
|
+
* every tool-semaphore slot.
|
|
38
|
+
*/
|
|
39
|
+
export const SLOT_LOCK_STALE_MS = 600_000;
|
|
40
|
+
/**
|
|
41
|
+
* How often a governor slot holder refreshes its lock. Short, so a holder
|
|
42
|
+
* frozen by a job pause keeps its slot for nearly the whole stale window
|
|
43
|
+
* (#1777 round 6).
|
|
44
|
+
*/
|
|
45
|
+
export const SLOT_LOCK_UPDATE_MS = 15_000;
|
|
46
|
+
/** `proper-lockfile`'s "someone else holds this lock" code: the only failure that means busy. */
|
|
47
|
+
const LOCK_HELD = 'ELOCKED';
|
|
48
|
+
/** Whether a `proper-lockfile` error means the lock is held by someone else. */
|
|
49
|
+
function isLockHeld(err) {
|
|
50
|
+
return err?.code === LOCK_HELD;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A lock mtime younger than this was refreshed by a live holder, which is
|
|
54
|
+
* then taken as the holder without spawning `ps`. It must cover the slowest
|
|
55
|
+
* refresher among the slots judged here: governor slots refresh every
|
|
56
|
+
* {@link SLOT_LOCK_UPDATE_MS} (15 s), tool-semaphore slots at
|
|
57
|
+
* `proper-lockfile`'s default of half their stale window (5 min); plus slack
|
|
58
|
+
* for a busy event loop. A holder frozen by a paused `cleo run` job stops
|
|
59
|
+
* refreshing but keeps its pid and start time, so it stays alive after the
|
|
60
|
+
* window too.
|
|
61
|
+
*/
|
|
62
|
+
const LOCK_REFRESH_WINDOW_MS = SLOT_LOCK_STALE_MS / 2 + 30_000;
|
|
63
|
+
/**
|
|
64
|
+
* A lock this close to `proper-lockfile`'s own stale threshold is left to
|
|
65
|
+
* `proper-lockfile`: its stale takeover runs outside the reap guard and could
|
|
66
|
+
* replace the lock between our check and our `rm` (T12963 re-review F2).
|
|
67
|
+
*/
|
|
68
|
+
const STALE_TAKEOVER_MARGIN_MS = 60_000;
|
|
69
|
+
/** How long a pid's start time is reused before `ps` is asked again. */
|
|
70
|
+
const START_CACHE_TTL_MS = 10_000;
|
|
71
|
+
/** Stale threshold of the per-slot reap guard; a reap holds it for milliseconds. */
|
|
72
|
+
const REAP_GUARD_STALE_MS = 10_000;
|
|
73
|
+
const _startCache = new Map();
|
|
74
|
+
/** This process's own start time, read once (`undefined` until then). */
|
|
75
|
+
let _ownStartedAt;
|
|
76
|
+
/**
|
|
77
|
+
* Start time of `pid`, or `null` when `ps` cannot say. Cached for
|
|
78
|
+
* {@link START_CACHE_TTL_MS}: a blocked acquire polls every 200 ms, and a `ps`
|
|
79
|
+
* spawn per poll is load an overloaded machine does not need.
|
|
80
|
+
*/
|
|
81
|
+
function processStartedAt(pid) {
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
const hit = _startCache.get(pid);
|
|
84
|
+
if (hit && now - hit.readAtMs < START_CACHE_TTL_MS)
|
|
85
|
+
return hit.startedAt;
|
|
86
|
+
const startedAt = readProcessEntry(pid)?.startedAt ?? null;
|
|
87
|
+
_startCache.set(pid, { readAtMs: now, startedAt });
|
|
88
|
+
return startedAt;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* This process's start time (`ps -o lstart=` under `PS_STABLE_ENV`), read once
|
|
92
|
+
* per process, or `null` when `ps` could not say.
|
|
93
|
+
*
|
|
94
|
+
* @returns The start time, or `null`.
|
|
95
|
+
*
|
|
96
|
+
* @task T12963
|
|
97
|
+
*/
|
|
98
|
+
export function ownProcessStartedAt() {
|
|
99
|
+
if (_ownStartedAt === undefined)
|
|
100
|
+
_ownStartedAt = processStartedAt(process.pid);
|
|
101
|
+
return _ownStartedAt;
|
|
102
|
+
}
|
|
103
|
+
/** Default probe: `kill(pid, 0)`, `kill(-pgid, 0)` and a cached `ps` start time. */
|
|
104
|
+
const defaultPidProbe = {
|
|
105
|
+
liveness(pid) {
|
|
106
|
+
if (!isProbeableId(pid))
|
|
107
|
+
return 'unknown';
|
|
108
|
+
try {
|
|
109
|
+
process.kill(pid, 0); // signal 0 = existence check, sends nothing
|
|
110
|
+
return 'alive';
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
const code = err.code;
|
|
114
|
+
if (code === 'ESRCH')
|
|
115
|
+
return 'gone';
|
|
116
|
+
// EPERM: it exists but belongs to another user. Anything else: we cannot tell.
|
|
117
|
+
return code === 'EPERM' ? 'alive' : 'unknown';
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
startedAt: processStartedAt,
|
|
121
|
+
groupLiveness: probeProcessGroup,
|
|
122
|
+
};
|
|
123
|
+
function holderPathOf(slotPath) {
|
|
124
|
+
return `${slotPath}.holder.json`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A lock directory's identity: `<ino>:<birthtimeMs>`, or `null` when the
|
|
128
|
+
* filesystem reports no birth time (NFS, FUSE, older kernels report 0). An
|
|
129
|
+
* inode alone can be reused by the next lock, so such a lock has no identity
|
|
130
|
+
* and is never reaped (T12963 re-review F3).
|
|
131
|
+
*
|
|
132
|
+
* @param ino - The lock directory's inode.
|
|
133
|
+
* @param birthtimeMs - Its birth time, as `fs.Stats.birthtimeMs`.
|
|
134
|
+
* @returns The identity, or `null`.
|
|
135
|
+
*
|
|
136
|
+
* @internal Exported for tests.
|
|
137
|
+
* @task T12963
|
|
138
|
+
*/
|
|
139
|
+
export function lockIdentity(ino, birthtimeMs) {
|
|
140
|
+
const birth = Math.trunc(birthtimeMs);
|
|
141
|
+
return Number.isFinite(birth) && birth > 0 ? `${ino}:${birth}` : null;
|
|
142
|
+
}
|
|
143
|
+
/** The slot's current lock directory (identity and mtime), or `null` when there is none. */
|
|
144
|
+
function lockStatOf(slotPath) {
|
|
145
|
+
try {
|
|
146
|
+
const st = statSync(`${slotPath}.lock`);
|
|
147
|
+
return { id: lockIdentity(st.ino, st.birthtimeMs), mtimeMs: st.mtimeMs };
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The identity of a slot's current lock directory, for a holder record's
|
|
155
|
+
* `lockId`, or `null` when there is no lock or it has no usable identity.
|
|
156
|
+
*
|
|
157
|
+
* @param slotPath - Slot lock file path.
|
|
158
|
+
* @returns The lock identity, or `null`.
|
|
159
|
+
*
|
|
160
|
+
* @task T12963
|
|
161
|
+
*/
|
|
162
|
+
export function currentLockId(slotPath) {
|
|
163
|
+
return lockStatOf(slotPath)?.id ?? null;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Write a slot's holder record. Best-effort: a failed write leaves the slot
|
|
167
|
+
* unreapable (it waits out the stale timeout), never unheld.
|
|
168
|
+
*
|
|
169
|
+
* @param slotPath - Slot lock file path.
|
|
170
|
+
* @param record - The record to write.
|
|
171
|
+
*
|
|
172
|
+
* @task T12963
|
|
173
|
+
*/
|
|
174
|
+
export function writeHolderRecord(slotPath, record) {
|
|
175
|
+
try {
|
|
176
|
+
writeFileSync(holderPathOf(slotPath), JSON.stringify(record), 'utf-8');
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
/* best-effort — never fail an acquire that succeeded */
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Keep a held slot's record listing every tool group this process starts
|
|
184
|
+
* while it holds the slot. Rewrites only while the slot's lock is still the
|
|
185
|
+
* one the record describes.
|
|
186
|
+
*
|
|
187
|
+
* @param slotPath - Slot lock file path.
|
|
188
|
+
* @param record - The record as first written (its `toolGroups` are replaced).
|
|
189
|
+
* @returns The groups already running (put them in the first record) and `stop`.
|
|
190
|
+
*
|
|
191
|
+
* @task T12963
|
|
192
|
+
*/
|
|
193
|
+
export function recordToolGroupsWhileHeld(slotPath, record) {
|
|
194
|
+
return followToolGroups((groups) => {
|
|
195
|
+
const current = record();
|
|
196
|
+
if (current.lockId == null || currentLockId(slotPath) !== current.lockId)
|
|
197
|
+
return;
|
|
198
|
+
writeHolderRecord(slotPath, { ...current, toolGroups: [...groups] });
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Write the holder record for a governor slot whose lock is held, stamping it
|
|
203
|
+
* with the current lock's identity.
|
|
204
|
+
*
|
|
205
|
+
* @param slotPath - Slot lock file path.
|
|
206
|
+
* @param holder - Who holds it.
|
|
207
|
+
* @returns The record as written.
|
|
208
|
+
*
|
|
209
|
+
* @internal Exported so tests can plant a foreign holder.
|
|
210
|
+
* @task T12963
|
|
211
|
+
*/
|
|
212
|
+
export function writeGovernorHolder(slotPath, holder) {
|
|
213
|
+
const record = { ...holder, lockId: currentLockId(slotPath) };
|
|
214
|
+
writeHolderRecord(slotPath, record);
|
|
215
|
+
return record;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Read a governor slot's holder record, or `null` when absent or malformed.
|
|
219
|
+
*
|
|
220
|
+
* @param slotPath - Slot lock file path.
|
|
221
|
+
* @returns The record, or `null`.
|
|
222
|
+
*
|
|
223
|
+
* @task T12963
|
|
224
|
+
*/
|
|
225
|
+
export function readGovernorHolder(slotPath) {
|
|
226
|
+
try {
|
|
227
|
+
const parsed = JSON.parse(readFileSync(holderPathOf(slotPath), 'utf-8'));
|
|
228
|
+
if (!isProbeableId(parsed.pid) ||
|
|
229
|
+
typeof parsed.host !== 'string' ||
|
|
230
|
+
typeof parsed.acquiredAtMs !== 'number' ||
|
|
231
|
+
(parsed.startedAt !== null && typeof parsed.startedAt !== 'string')) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
return parsed;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/** The holder pid alone: gone, recycled, alive or unknown. */
|
|
241
|
+
function assessHolderPid(holder, lockMtimeMs, probe) {
|
|
242
|
+
const liveness = probe.liveness(holder.pid);
|
|
243
|
+
if (liveness !== 'alive')
|
|
244
|
+
return liveness === 'gone' ? 'dead' : 'unknown';
|
|
245
|
+
// Without the lock's mtime, or while it is being refreshed, a live pid is the holder.
|
|
246
|
+
if (lockMtimeMs === null || Date.now() - lockMtimeMs < LOCK_REFRESH_WINDOW_MS)
|
|
247
|
+
return 'alive';
|
|
248
|
+
if (holder.startedAt == null)
|
|
249
|
+
return 'alive';
|
|
250
|
+
const startedAt = probe.startedAt(holder.pid);
|
|
251
|
+
if (startedAt === null)
|
|
252
|
+
return 'unknown'; // ps failed: never proof of death
|
|
253
|
+
return startedAt === holder.startedAt ? 'alive' : 'dead';
|
|
254
|
+
}
|
|
255
|
+
/** The holder's tool groups: `dead` only when every one is provably gone. */
|
|
256
|
+
function assessToolGroups(groups, probe) {
|
|
257
|
+
if (groups === undefined)
|
|
258
|
+
return 'dead';
|
|
259
|
+
if (!Array.isArray(groups))
|
|
260
|
+
return 'unknown';
|
|
261
|
+
let unknown = false;
|
|
262
|
+
for (const pgid of groups) {
|
|
263
|
+
if (!isProbeableId(pgid))
|
|
264
|
+
return 'unknown';
|
|
265
|
+
const state = probe.groupLiveness(pgid);
|
|
266
|
+
if (state === 'alive')
|
|
267
|
+
return 'alive';
|
|
268
|
+
if (state === 'unknown')
|
|
269
|
+
unknown = true;
|
|
270
|
+
}
|
|
271
|
+
return unknown ? 'unknown' : 'dead';
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Decide whether a slot's recorded holder still holds it.
|
|
275
|
+
*
|
|
276
|
+
* - `dead`: the holder pid is gone, or alive with a different start time
|
|
277
|
+
* than the record's (a recycled pid), AND every tool group it started is
|
|
278
|
+
* gone.
|
|
279
|
+
* - `unknown`: no record, another host's pid, a pid of 1 or below, a record
|
|
280
|
+
* that does not describe the current lock (or a lock with no identity), or
|
|
281
|
+
* a probe that failed. Never treated as dead.
|
|
282
|
+
* - `alive`: otherwise, including a live pid whose start time was never
|
|
283
|
+
* recorded, and a dead holder whose tool is still running.
|
|
284
|
+
*
|
|
285
|
+
* A live holder's `proper-lockfile` timer refreshes the lock mtime (governor
|
|
286
|
+
* slots every 15 s, tool slots every 5 min). While the mtime is within
|
|
287
|
+
* {@link LOCK_REFRESH_WINDOW_MS} a live pid is taken as the holder without
|
|
288
|
+
* asking `ps`, so a contended acquire spawns nothing. A pid recycled inside that window therefore reads as alive until
|
|
289
|
+
* the refresh lapses; that is the safe direction.
|
|
290
|
+
*
|
|
291
|
+
* @param holder - The slot's record, or `null`.
|
|
292
|
+
* @param slotPath - Slot lock file path. Without it the lock identity and
|
|
293
|
+
* mtime are not consulted, so a live pid is always `alive` (report-only).
|
|
294
|
+
* @param probe - Pid probe; tests inject one.
|
|
295
|
+
* @returns The verdict.
|
|
296
|
+
*
|
|
297
|
+
* @task T12963
|
|
298
|
+
*/
|
|
299
|
+
export function assessSlotHolder(holder, slotPath, probe = defaultPidProbe) {
|
|
300
|
+
if (holder === null || holder.host !== hostname() || !isProbeableId(holder.pid)) {
|
|
301
|
+
return 'unknown';
|
|
302
|
+
}
|
|
303
|
+
let lockMtimeMs = null;
|
|
304
|
+
if (slotPath !== undefined) {
|
|
305
|
+
const lock = lockStatOf(slotPath);
|
|
306
|
+
if (lock === null || lock.id === null || holder.lockId !== lock.id)
|
|
307
|
+
return 'unknown';
|
|
308
|
+
lockMtimeMs = lock.mtimeMs;
|
|
309
|
+
}
|
|
310
|
+
const pid = assessHolderPid(holder, lockMtimeMs, probe);
|
|
311
|
+
return pid === 'dead' ? assessToolGroups(holder.toolGroups, probe) : pid;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* {@link assessSlotHolder} for a governor slot's record.
|
|
315
|
+
*
|
|
316
|
+
* @param holder - The slot's record, or `null`.
|
|
317
|
+
* @param slotPath - Slot lock file path.
|
|
318
|
+
* @param probe - Pid probe; tests inject one.
|
|
319
|
+
* @returns The verdict.
|
|
320
|
+
*
|
|
321
|
+
* @task T12963
|
|
322
|
+
*/
|
|
323
|
+
export function assessGovernorHolder(holder, slotPath, probe = defaultPidProbe) {
|
|
324
|
+
return assessSlotHolder(holder, slotPath, probe);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Free a held slot whose holder is provably dead: its pid gone or recycled
|
|
328
|
+
* and every tool group it started gone.
|
|
329
|
+
*
|
|
330
|
+
* Runs under a per-slot guard and re-checks the holder inside it. The holder
|
|
331
|
+
* record is removed with the lock, so a second reaper that takes the guard
|
|
332
|
+
* afterwards finds no record (or the next holder's) and stands down. A lock
|
|
333
|
+
* within {@link STALE_TAKEOVER_MARGIN_MS} of `staleMs` is left to
|
|
334
|
+
* `proper-lockfile`, and the lock identity is re-read immediately before the
|
|
335
|
+
* `rm`, so a concurrent stale takeover's fresh lock is never removed.
|
|
336
|
+
*
|
|
337
|
+
* @param slotPath - Slot lock file path.
|
|
338
|
+
* @param readHolder - Reads the slot's record (the governor's or the tool semaphore's).
|
|
339
|
+
* @param opts - The slot's `proper-lockfile` stale threshold, and a probe (tests).
|
|
340
|
+
* @returns `true` when the slot was reaped; the caller then takes it.
|
|
341
|
+
*
|
|
342
|
+
* @task T12963
|
|
343
|
+
*/
|
|
344
|
+
export function reapSlotIfHolderDead(slotPath, readHolder, opts = {}) {
|
|
345
|
+
const staleMs = opts.staleMs ?? SLOT_LOCK_STALE_MS;
|
|
346
|
+
const probe = opts.probe ?? defaultPidProbe;
|
|
347
|
+
if (assessSlotHolder(readHolder(slotPath), slotPath, probe) !== 'dead')
|
|
348
|
+
return false;
|
|
349
|
+
let releaseGuard;
|
|
350
|
+
try {
|
|
351
|
+
releaseGuard = lockfile.lockSync(`${slotPath}.reap`, {
|
|
352
|
+
lockfilePath: `${slotPath}.reaping`,
|
|
353
|
+
stale: REAP_GUARD_STALE_MS,
|
|
354
|
+
realpath: false,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
return false; // another waiter is reaping this slot
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
const holder = readHolder(slotPath);
|
|
362
|
+
if (holder === null || assessSlotHolder(holder, slotPath, probe) !== 'dead')
|
|
363
|
+
return false;
|
|
364
|
+
const lock = lockStatOf(slotPath);
|
|
365
|
+
if (lock === null || Date.now() - lock.mtimeMs > staleMs - STALE_TAKEOVER_MARGIN_MS) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
// Re-read the identity last: a lock replaced since the check, and the
|
|
369
|
+
// record its new holder wrote, are left alone.
|
|
370
|
+
if (currentLockId(slotPath) !== holder.lockId)
|
|
371
|
+
return false;
|
|
372
|
+
rmSync(holderPathOf(slotPath), { force: true });
|
|
373
|
+
rmSync(`${slotPath}.lock`, { recursive: true, force: true });
|
|
374
|
+
log().warn({ slot: slotPath, holderPid: holder.pid, toolGroups: holder.toolGroups ?? [] }, 'reaped a slot whose holder process and tool groups are gone');
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
try {
|
|
382
|
+
releaseGuard();
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
/* the guard was already released */
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Name every held governor slot and its holder, for a deferral reason.
|
|
391
|
+
*
|
|
392
|
+
* @param slots - Slot lock file paths of one class.
|
|
393
|
+
* @returns `; held by …`, or `''` when no slot is held.
|
|
394
|
+
*
|
|
395
|
+
* @task T12963
|
|
396
|
+
*/
|
|
397
|
+
export function describeSlotHolders(slots) {
|
|
398
|
+
const held = [];
|
|
399
|
+
for (const path of slots) {
|
|
400
|
+
if (!existsSync(`${path}.lock`))
|
|
401
|
+
continue;
|
|
402
|
+
const h = readGovernorHolder(path);
|
|
403
|
+
const groups = h?.toolGroups?.length ? ` with tool group(s) ${h.toolGroups.join(',')}` : '';
|
|
404
|
+
held.push(h
|
|
405
|
+
? `${basename(path)}: pid ${h.pid} on ${h.host}${groups} since ` +
|
|
406
|
+
`${new Date(h.acquiredAtMs).toISOString()} (${assessGovernorHolder(h, path)})`
|
|
407
|
+
: `${basename(path)}: holder unknown`);
|
|
408
|
+
}
|
|
409
|
+
return held.length > 0 ? `; held by ${held.join(', ')}` : '';
|
|
410
|
+
}
|
|
411
|
+
/** A grant's release: stops recording tool groups, drops our record, then the lock. Idempotent. */
|
|
412
|
+
function holderRelease(slotPath, holder, stopRecording, unlock) {
|
|
413
|
+
let released = false;
|
|
414
|
+
return async () => {
|
|
415
|
+
if (released)
|
|
416
|
+
return;
|
|
417
|
+
released = true;
|
|
418
|
+
stopRecording();
|
|
419
|
+
// Record first, lock second: the record must never outlive our lock and
|
|
420
|
+
// end up describing the next holder's.
|
|
421
|
+
const mine = holder();
|
|
422
|
+
const current = readGovernorHolder(slotPath);
|
|
423
|
+
if (current?.pid === mine.pid && current.acquiredAtMs === mine.acquiredAtMs) {
|
|
424
|
+
try {
|
|
425
|
+
rmSync(holderPathOf(slotPath), { force: true });
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
/* best-effort — a stale record is only ever advisory */
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
await unlock();
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
// Already released (e.g. stale recovery) — post-condition holds.
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Take a free slot without waiting; record the holder. `null` when the lock
|
|
441
|
+
* is held (`ELOCKED`). Any other lock error (EACCES from a sandbox, EROFS,
|
|
442
|
+
* ENOSPC…) is thrown, never read as busy: the governor surfaces it so its
|
|
443
|
+
* caller can fail open (#1777 round 8, R8-1).
|
|
444
|
+
*/
|
|
445
|
+
async function tryLockSlot(slotPath, cls) {
|
|
446
|
+
let unlock;
|
|
447
|
+
try {
|
|
448
|
+
unlock = await lockfile.lock(slotPath, {
|
|
449
|
+
retries: 0,
|
|
450
|
+
stale: SLOT_LOCK_STALE_MS,
|
|
451
|
+
update: SLOT_LOCK_UPDATE_MS,
|
|
452
|
+
realpath: false,
|
|
453
|
+
// A long grant (cleo run) can outlive a lid-closed sleep; another
|
|
454
|
+
// process may then reclaim the "stale" slot. proper-lockfile's
|
|
455
|
+
// default throws from a timer and crashes the holder; log instead
|
|
456
|
+
// and keep running (#1777 round 3, L-7).
|
|
457
|
+
onCompromised: (err) => {
|
|
458
|
+
log().warn({ cls, slot: basename(slotPath), err: err.message }, 'governor slot lock compromised (likely sleep or a stale reclaim); continuing');
|
|
459
|
+
},
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
catch (err) {
|
|
463
|
+
if (isLockHeld(err))
|
|
464
|
+
return null;
|
|
465
|
+
throw err;
|
|
466
|
+
}
|
|
467
|
+
let holder;
|
|
468
|
+
const recording = recordToolGroupsWhileHeld(slotPath, () => holder);
|
|
469
|
+
holder = writeGovernorHolder(slotPath, {
|
|
470
|
+
pid: process.pid,
|
|
471
|
+
startedAt: ownProcessStartedAt(),
|
|
472
|
+
host: hostname(),
|
|
473
|
+
cls,
|
|
474
|
+
acquiredAtMs: Date.now(),
|
|
475
|
+
toolGroups: [...recording.groups],
|
|
476
|
+
});
|
|
477
|
+
return holderRelease(slotPath, () => holder, recording.stop, unlock);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Take a slot without waiting: free, or freed by reaping a dead holder.
|
|
481
|
+
*
|
|
482
|
+
* @param slotPath - Slot lock file path.
|
|
483
|
+
* @param cls - Class the slot belongs to.
|
|
484
|
+
* @returns The grant's release (drops the holder record, then the lock), or
|
|
485
|
+
* `null` when the slot is held.
|
|
486
|
+
* @throws Any lock error other than `ELOCKED` (an unwritable slot directory),
|
|
487
|
+
* for the governor's fail-open path.
|
|
488
|
+
*
|
|
489
|
+
* @task T12963
|
|
490
|
+
*/
|
|
491
|
+
export async function lockSlot(slotPath, cls) {
|
|
492
|
+
const free = await tryLockSlot(slotPath, cls);
|
|
493
|
+
if (free !== null)
|
|
494
|
+
return free;
|
|
495
|
+
return reapSlotIfHolderDead(slotPath, readGovernorHolder) ? tryLockSlot(slotPath, cls) : null;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Forget cached start times, this process's included. Tests only.
|
|
499
|
+
* @internal
|
|
500
|
+
*/
|
|
501
|
+
export function _resetSlotHolderStateForTest() {
|
|
502
|
+
_startCache.clear();
|
|
503
|
+
_ownStartedAt = undefined;
|
|
504
|
+
}
|
|
505
|
+
//# sourceMappingURL=slot-holder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-holder.js","sourceRoot":"","sources":["../../src/resources/slot-holder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process groups of the tools this process started (T12963).
|
|
3
|
+
*
|
|
4
|
+
* The tool cache starts every tool detached, in its own process group, so a
|
|
5
|
+
* deadline can signal the whole tree. The flip side: when cleo itself dies,
|
|
6
|
+
* nothing reaches that group. A SIGKILLed `cleo verify tool:test` can leave
|
|
7
|
+
* its test runner running with PPID 1, so a slot is not free just because its
|
|
8
|
+
* holder pid is gone. Every slot this process holds therefore records the
|
|
9
|
+
* groups started while it is held, and a slot is reaped only once both its
|
|
10
|
+
* holder pid and those groups are gone.
|
|
11
|
+
*
|
|
12
|
+
* @task T12963
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Whether `id` may ever be probed as a pid or process group: an integer above
|
|
16
|
+
* 1. Never 0 (our own group), 1 (init) or a negative number (`kill(-1)`
|
|
17
|
+
* reaches every process we own).
|
|
18
|
+
*
|
|
19
|
+
* @param id - Candidate pid or pgid.
|
|
20
|
+
* @returns `true` when it is safe to probe.
|
|
21
|
+
*
|
|
22
|
+
* @task T12963
|
|
23
|
+
*/
|
|
24
|
+
export declare function isProbeableId(id: unknown): id is number;
|
|
25
|
+
/**
|
|
26
|
+
* Register a tool's process group as running. Every slot this process holds
|
|
27
|
+
* is told, so its holder record lists the group. A no-op on Windows (no POSIX
|
|
28
|
+
* process groups) and for an id that is not probeable.
|
|
29
|
+
*
|
|
30
|
+
* @param pgid - The group id: the pid of a child spawned with `detached: true`.
|
|
31
|
+
* @returns Marks the group as no longer running (idempotent).
|
|
32
|
+
*
|
|
33
|
+
* @task T12963
|
|
34
|
+
*/
|
|
35
|
+
export declare function trackToolGroup(pgid: number | undefined): () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Process groups this process started that have not finished yet.
|
|
38
|
+
*
|
|
39
|
+
* @returns Group ids, oldest first.
|
|
40
|
+
*
|
|
41
|
+
* @task T12963
|
|
42
|
+
*/
|
|
43
|
+
export declare function activeToolGroups(): number[];
|
|
44
|
+
/**
|
|
45
|
+
* Follow the tool groups started while a slot is held: seeded with the groups
|
|
46
|
+
* already running, then `onNew` is called with the full list each time
|
|
47
|
+
* another one starts.
|
|
48
|
+
*
|
|
49
|
+
* @param onNew - Called with every group recorded so far, after each new one.
|
|
50
|
+
* @returns The groups recorded so far (kept up to date) and `stop`.
|
|
51
|
+
*
|
|
52
|
+
* @task T12963
|
|
53
|
+
*/
|
|
54
|
+
export declare function followToolGroups(onNew: (groups: readonly number[]) => void): {
|
|
55
|
+
groups: readonly number[];
|
|
56
|
+
stop: () => void;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Whether a process group still has a member, by `kill(-pgid, 0)` (signal 0
|
|
60
|
+
* sends nothing).
|
|
61
|
+
*
|
|
62
|
+
* @param pgid - Group id.
|
|
63
|
+
* @returns `gone` (ESRCH), `alive` (exists, EPERM included), or `unknown`
|
|
64
|
+
* when the id is not probeable or the probe failed some other way.
|
|
65
|
+
*
|
|
66
|
+
* @task T12963
|
|
67
|
+
*/
|
|
68
|
+
export declare function probeProcessGroup(pgid: number): 'gone' | 'alive' | 'unknown';
|
|
69
|
+
/**
|
|
70
|
+
* Forget every tracked group and listener. Tests only.
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
export declare function _resetToolGroupsForTest(): void;
|
|
74
|
+
//# sourceMappingURL=tool-groups.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-groups.d.ts","sourceRoot":"","sources":["../../src/resources/tool-groups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,MAAM,CAEvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,IAAI,CASnE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,GAAG;IAC5E,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAcA;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAU5E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C"}
|