harnery 0.35.0 → 0.36.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/dist/commander.d.ts +30 -5
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +124 -96
- package/dist/commands/agents.d.ts +23 -3
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +379 -198
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +10 -10
- package/dist/commands/browse-session.d.ts.map +1 -1
- package/dist/commands/browse-session.js +12 -0
- package/dist/commands/browse.d.ts +1 -1
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +5 -4
- package/dist/commands/conversations.d.ts +10 -0
- package/dist/commands/conversations.d.ts.map +1 -0
- package/dist/commands/conversations.js +201 -0
- package/dist/commands/deinit.d.ts.map +1 -1
- package/dist/commands/deinit.js +5 -0
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +13 -2
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +51 -7
- package/dist/commands/fetch.js +6 -5
- package/dist/commands/files.d.ts +22 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/files.js +113 -0
- package/dist/commands/governor.js +14 -12
- package/dist/commands/inbox.d.ts +5 -0
- package/dist/commands/inbox.d.ts.map +1 -0
- package/dist/commands/inbox.js +57 -0
- package/dist/commands/init.d.ts +4 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +63 -13
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +347 -1
- package/dist/commands/logs.d.ts +4 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +169 -0
- package/dist/commands/messages.d.ts +5 -0
- package/dist/commands/messages.d.ts.map +1 -0
- package/dist/commands/messages.js +45 -0
- package/dist/commands/outline.d.ts +1 -1
- package/dist/commands/outline.d.ts.map +1 -1
- package/dist/commands/outline.js +2 -2
- package/dist/commands/read.d.ts +1 -1
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +2 -2
- package/dist/commands/semantic.d.ts.map +1 -1
- package/dist/commands/semantic.js +54 -2
- package/dist/commands/storage.d.ts +4 -0
- package/dist/commands/storage.d.ts.map +1 -0
- package/dist/commands/storage.js +238 -0
- package/dist/commands/tunnel.d.ts +5 -1
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +44 -31
- package/dist/commands/web.d.ts +3 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +67 -7
- package/dist/commands/work.js +3 -3
- package/dist/commands/workflow.js +13 -13
- package/dist/core/adapters/profiles.d.ts +1 -1
- package/dist/core/agents/cli.js +209 -39
- package/dist/core/agents/live-authority-v3.d.ts +47 -1
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +244 -10
- package/dist/core/agents/live-lifecycle-v3.js +6 -1
- package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
- package/dist/core/agents/live-observation-v3.js +6 -1
- package/dist/core/agents/render/prompt-context.d.ts +9 -3
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +24 -7
- package/dist/core/agents/rules/stop-hook.d.ts +2 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +94 -13
- package/dist/core/agents/rules/verdict.d.ts +1 -0
- package/dist/core/agents/rules/verdict.d.ts.map +1 -1
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +4 -0
- package/dist/core/agents/session-finalization-state-v3.js +1 -1
- package/dist/core/agents/session-finalizer-v3.js +5 -1
- package/dist/core/agents/state/activity-log.d.ts +3 -0
- package/dist/core/agents/state/activity-log.d.ts.map +1 -1
- package/dist/core/agents/state/activity-log.js +6 -3
- package/dist/core/agents/state/heartbeat-writer.d.ts +6 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +18 -0
- package/dist/core/agents/state/live-coordination-view.d.ts +5 -7
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +15 -90
- package/dist/core/agents/state/live-coordination-writer.d.ts +12 -0
- package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -0
- package/dist/core/agents/state/live-coordination-writer.js +92 -0
- package/dist/core/artifacts/index.d.ts +21 -0
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +46 -1
- package/dist/core/config.d.ts +62 -4
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +98 -4
- package/dist/core/conversations/archive.d.ts +49 -0
- package/dist/core/conversations/archive.d.ts.map +1 -0
- package/dist/core/conversations/archive.js +136 -0
- package/dist/core/conversations/catalog.d.ts +10 -0
- package/dist/core/conversations/catalog.d.ts.map +1 -0
- package/dist/core/conversations/catalog.js +72 -0
- package/dist/core/conversations/context-pack.d.ts +6 -0
- package/dist/core/conversations/context-pack.d.ts.map +1 -0
- package/dist/core/conversations/context-pack.js +60 -0
- package/dist/core/conversations/contract.d.ts +155 -0
- package/dist/core/conversations/contract.d.ts.map +1 -0
- package/dist/core/conversations/contract.js +1 -0
- package/dist/core/conversations/evaluation.d.ts +16 -0
- package/dist/core/conversations/evaluation.d.ts.map +1 -0
- package/dist/core/conversations/evaluation.js +9 -0
- package/dist/core/conversations/index.d.ts +10 -0
- package/dist/core/conversations/index.d.ts.map +1 -0
- package/dist/core/conversations/index.js +9 -0
- package/dist/core/conversations/lifecycle.d.ts +28 -0
- package/dist/core/conversations/lifecycle.d.ts.map +1 -0
- package/dist/core/conversations/lifecycle.js +29 -0
- package/dist/core/conversations/normalize.d.ts +14 -0
- package/dist/core/conversations/normalize.d.ts.map +1 -0
- package/dist/core/conversations/normalize.js +82 -0
- package/dist/core/conversations/query.d.ts +8 -0
- package/dist/core/conversations/query.d.ts.map +1 -0
- package/dist/core/conversations/query.js +280 -0
- package/dist/core/conversations/search-index.d.ts +9 -0
- package/dist/core/conversations/search-index.d.ts.map +1 -0
- package/dist/core/conversations/search-index.js +29 -0
- package/dist/core/events/legacy-storage/canary.d.ts +18 -0
- package/dist/core/events/legacy-storage/canary.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/canary.js +150 -0
- package/dist/core/events/legacy-storage/fence.d.ts +15 -0
- package/dist/core/events/legacy-storage/fence.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/fence.js +115 -0
- package/dist/core/events/legacy-storage/index.d.ts +6 -0
- package/dist/core/events/legacy-storage/index.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/index.js +5 -0
- package/dist/core/events/legacy-storage/inventory.d.ts +10 -0
- package/dist/core/events/legacy-storage/inventory.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/inventory.js +40 -0
- package/dist/core/events/legacy-storage/manifest.d.ts +23 -0
- package/dist/core/events/legacy-storage/manifest.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/manifest.js +108 -0
- package/dist/core/events/legacy-storage/reader.d.ts +15 -0
- package/dist/core/events/legacy-storage/reader.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/reader.js +154 -0
- package/dist/core/events/v3/authority-outbox.d.ts +7 -2
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +16 -3
- package/dist/core/events/v3/base-contract.d.ts +81 -41
- package/dist/core/events/v3/base-contract.d.ts.map +1 -1
- package/dist/core/events/v3/base-contract.js +17 -7
- package/dist/core/events/v3/bootstrap.d.ts +39 -0
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +167 -3
- package/dist/core/events/v3/capabilities.js +3 -3
- package/dist/core/events/v3/control-witness.d.ts +44 -0
- package/dist/core/events/v3/control-witness.d.ts.map +1 -0
- package/dist/core/events/v3/control-witness.js +233 -0
- package/dist/core/events/v3/control-writer.d.ts +4 -0
- package/dist/core/events/v3/control-writer.d.ts.map +1 -0
- package/dist/core/events/v3/control-writer.js +16 -0
- package/dist/core/events/v3/control.d.ts +8 -2
- package/dist/core/events/v3/control.d.ts.map +1 -1
- package/dist/core/events/v3/control.js +46 -18
- package/dist/core/events/v3/coordination-transaction-recovery.d.ts +42 -0
- package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -0
- package/dist/core/events/v3/coordination-transaction-recovery.js +342 -0
- package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
- package/dist/core/events/v3/coordination-view.js +16 -1
- package/dist/core/events/v3/generated.d.ts +1 -1
- package/dist/core/events/v3/generated.js +1 -1
- package/dist/core/events/v3/index.d.ts +4 -2
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +3 -1
- package/dist/core/events/v3/live-route-observer.d.ts +31 -0
- package/dist/core/events/v3/live-route-observer.d.ts.map +1 -0
- package/dist/core/events/v3/live-route-observer.js +58 -0
- package/dist/core/events/v3/live-routing.d.ts +13 -21
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +45 -41
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +11 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +76 -10
- package/dist/core/events/v3/producers/diagnostic-summaries.d.ts +129 -0
- package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -0
- package/dist/core/events/v3/producers/diagnostic-summaries.js +499 -0
- package/dist/core/events/v3/producers/hook-base.js +1 -1
- package/dist/core/events/v3/producers/intake.d.ts +7 -0
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +25 -2
- package/dist/core/events/v3/producers/producer-state-observer.d.ts +8 -0
- package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -0
- package/dist/core/events/v3/producers/producer-state-observer.js +45 -0
- package/dist/core/events/v3/producers/recorder.d.ts +55 -1
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +353 -24
- package/dist/core/events/v3/reader.d.ts +51 -0
- package/dist/core/events/v3/reader.d.ts.map +1 -1
- package/dist/core/events/v3/reader.js +181 -1
- package/dist/core/events/v3/rotation-config.d.ts +9 -0
- package/dist/core/events/v3/rotation-config.d.ts.map +1 -0
- package/dist/core/events/v3/rotation-config.js +91 -0
- package/dist/core/events/v3/runtime-build.d.ts +11 -0
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -0
- package/dist/core/events/v3/runtime-build.js +39 -0
- package/dist/core/events/v3/runtime-identity.d.ts +5 -0
- package/dist/core/events/v3/runtime-identity.d.ts.map +1 -0
- package/dist/core/events/v3/runtime-identity.js +18 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +6 -5
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-telemetry-capabilities.js +1 -1
- package/dist/core/events/v3/support-storage/classify.d.ts +46 -0
- package/dist/core/events/v3/support-storage/classify.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/classify.js +149 -0
- package/dist/core/events/v3/support-storage/eligibility.d.ts +29 -0
- package/dist/core/events/v3/support-storage/eligibility.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/eligibility.js +35 -0
- package/dist/core/events/v3/support-storage/index.d.ts +10 -0
- package/dist/core/events/v3/support-storage/index.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/index.js +9 -0
- package/dist/core/events/v3/support-storage/inventory.d.ts +30 -0
- package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/inventory.js +94 -0
- package/dist/core/events/v3/support-storage/logical-authority.d.ts +14 -0
- package/dist/core/events/v3/support-storage/logical-authority.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/logical-authority.js +104 -0
- package/dist/core/events/v3/support-storage/maintenance.d.ts +98 -0
- package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/maintenance.js +352 -0
- package/dist/core/events/v3/support-storage/pack-contract.d.ts +59 -0
- package/dist/core/events/v3/support-storage/pack-contract.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/pack-contract.js +249 -0
- package/dist/core/events/v3/support-storage/pack-reader.d.ts +34 -0
- package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/pack-reader.js +258 -0
- package/dist/core/events/v3/support-storage/pack-writer.d.ts +30 -0
- package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/pack-writer.js +268 -0
- package/dist/core/events/v3/support-storage/recovery.d.ts +15 -0
- package/dist/core/events/v3/support-storage/recovery.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/recovery.js +22 -0
- package/dist/core/events/v3/turn-telemetry.d.ts +14 -8
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
- package/dist/core/events/v3/turn-telemetry.js +32 -2
- package/dist/core/events/v3/writer.d.ts +13 -1
- package/dist/core/events/v3/writer.d.ts.map +1 -1
- package/dist/core/events/v3/writer.js +126 -12
- package/dist/core/governor/plan-read.d.ts.map +1 -1
- package/dist/core/governor/plan-read.js +5 -21
- package/dist/core/governor/planning.js +6 -8
- package/dist/core/governor/service-read.d.ts +12 -0
- package/dist/core/governor/service-read.d.ts.map +1 -1
- package/dist/core/governor/service-read.js +266 -2
- package/dist/core/governor/service.d.ts +1 -0
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +53 -18
- package/dist/core/guard/evidence-v3.d.ts.map +1 -1
- package/dist/core/guard/evidence-v3.js +2 -0
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +1 -0
- package/dist/core/hooks/adapter/output.d.ts +4 -2
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +13 -5
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts +27 -4
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -1
- package/dist/core/hooks/adapter/runtime-telemetry.js +307 -6
- package/dist/core/hooks/cli.js +212 -30
- package/dist/core/hooks/effects/image-capture.d.ts +1 -1
- package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
- package/dist/core/hooks/effects/image-capture.js +4 -2
- package/dist/core/hooks/remediation-cap.d.ts +8 -3
- package/dist/core/hooks/remediation-cap.d.ts.map +1 -1
- package/dist/core/hooks/remediation-cap.js +3 -11
- package/dist/core/hooks/resolve/coord-root.d.ts +22 -9
- package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
- package/dist/core/hooks/resolve/coord-root.js +92 -11
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +5 -0
- package/dist/core/hooks/resolve/transcript.d.ts +8 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +11 -0
- package/dist/core/inbox/contract.d.ts +64 -0
- package/dist/core/inbox/contract.d.ts.map +1 -0
- package/dist/core/inbox/contract.js +13 -0
- package/dist/core/inbox/index.d.ts +5 -0
- package/dist/core/inbox/index.d.ts.map +1 -0
- package/dist/core/inbox/index.js +4 -0
- package/dist/core/inbox/lifecycle.d.ts +22 -0
- package/dist/core/inbox/lifecycle.d.ts.map +1 -0
- package/dist/core/inbox/lifecycle.js +41 -0
- package/dist/core/inbox/service.d.ts +36 -0
- package/dist/core/inbox/service.d.ts.map +1 -0
- package/dist/core/inbox/service.js +210 -0
- package/dist/core/inbox/watcher.d.ts +7 -0
- package/dist/core/inbox/watcher.d.ts.map +1 -0
- package/dist/core/inbox/watcher.js +26 -0
- package/dist/core/presence/codec-digest.d.ts.map +1 -1
- package/dist/core/presence/codec-digest.js +14 -3
- package/dist/core/presence/relay-client.d.ts +1 -0
- package/dist/core/presence/relay-client.d.ts.map +1 -1
- package/dist/core/presence/relay-client.js +52 -8
- package/dist/core/semantic/adapters.d.ts +11 -8
- package/dist/core/semantic/adapters.d.ts.map +1 -1
- package/dist/core/semantic/adapters.js +169 -31
- package/dist/core/semantic/contract.d.ts +532 -48
- package/dist/core/semantic/contract.d.ts.map +1 -1
- package/dist/core/semantic/contract.js +104 -3
- package/dist/core/semantic/index.d.ts +7 -3
- package/dist/core/semantic/index.d.ts.map +1 -1
- package/dist/core/semantic/index.js +7 -3
- package/dist/core/semantic/once.d.ts +6 -1
- package/dist/core/semantic/once.d.ts.map +1 -1
- package/dist/core/semantic/once.js +80 -9
- package/dist/core/semantic/prompt.d.ts.map +1 -1
- package/dist/core/semantic/prompt.js +14 -1
- package/dist/core/semantic/review.d.ts +144 -0
- package/dist/core/semantic/review.d.ts.map +1 -0
- package/dist/core/semantic/review.js +544 -0
- package/dist/core/semantic/routes.d.ts +10 -0
- package/dist/core/semantic/routes.d.ts.map +1 -0
- package/dist/core/semantic/routes.js +21 -0
- package/dist/core/semantic/scheduler.d.ts +14 -3
- package/dist/core/semantic/scheduler.d.ts.map +1 -1
- package/dist/core/semantic/scheduler.js +30 -6
- package/dist/core/semantic/service-status.d.ts +20 -0
- package/dist/core/semantic/service-status.d.ts.map +1 -1
- package/dist/core/semantic/service-status.js +60 -4
- package/dist/core/semantic/service.d.ts +1 -0
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +104 -15
- package/dist/core/semantic/soak.d.ts +75 -0
- package/dist/core/semantic/soak.d.ts.map +1 -0
- package/dist/core/semantic/soak.js +476 -0
- package/dist/core/semantic/storage.d.ts +11 -1
- package/dist/core/semantic/storage.d.ts.map +1 -1
- package/dist/core/semantic/storage.js +4 -3
- package/dist/core/semantic/usage.d.ts +43 -0
- package/dist/core/semantic/usage.d.ts.map +1 -0
- package/dist/core/semantic/usage.js +193 -0
- package/dist/core/semantic/validate.d.ts +3 -1
- package/dist/core/semantic/validate.d.ts.map +1 -1
- package/dist/core/semantic/validate.js +34 -1
- package/dist/core/storage/buffer.d.ts +28 -0
- package/dist/core/storage/buffer.d.ts.map +1 -0
- package/dist/core/storage/buffer.js +101 -0
- package/dist/core/storage/builtins.d.ts +3 -0
- package/dist/core/storage/builtins.d.ts.map +1 -0
- package/dist/core/storage/builtins.js +683 -0
- package/dist/core/storage/catalog.d.ts +19 -0
- package/dist/core/storage/catalog.d.ts.map +1 -0
- package/dist/core/storage/catalog.js +365 -0
- package/dist/core/storage/config.d.ts +16 -0
- package/dist/core/storage/config.d.ts.map +1 -0
- package/dist/core/storage/config.js +311 -0
- package/dist/core/storage/contract.d.ts +275 -0
- package/dist/core/storage/contract.d.ts.map +1 -0
- package/dist/core/storage/contract.js +3 -0
- package/dist/core/storage/durable-history.d.ts +36 -0
- package/dist/core/storage/durable-history.d.ts.map +1 -0
- package/dist/core/storage/durable-history.js +606 -0
- package/dist/core/storage/health.d.ts +4 -0
- package/dist/core/storage/health.d.ts.map +1 -0
- package/dist/core/storage/health.js +65 -0
- package/dist/core/storage/index.d.ts +16 -0
- package/dist/core/storage/index.d.ts.map +1 -0
- package/dist/core/storage/index.js +15 -0
- package/dist/core/storage/inventory.d.ts +25 -0
- package/dist/core/storage/inventory.d.ts.map +1 -0
- package/dist/core/storage/inventory.js +666 -0
- package/dist/core/storage/jsonl.d.ts +52 -0
- package/dist/core/storage/jsonl.d.ts.map +1 -0
- package/dist/core/storage/jsonl.js +156 -0
- package/dist/core/storage/log-retention.d.ts +52 -0
- package/dist/core/storage/log-retention.d.ts.map +1 -0
- package/dist/core/storage/log-retention.js +419 -0
- package/dist/core/storage/logger.d.ts +82 -0
- package/dist/core/storage/logger.d.ts.map +1 -0
- package/dist/core/storage/logger.js +411 -0
- package/dist/core/storage/maintenance-providers.d.ts +26 -0
- package/dist/core/storage/maintenance-providers.d.ts.map +1 -0
- package/dist/core/storage/maintenance-providers.js +141 -0
- package/dist/core/storage/maintenance.d.ts +125 -0
- package/dist/core/storage/maintenance.d.ts.map +1 -0
- package/dist/core/storage/maintenance.js +609 -0
- package/dist/core/storage/metrics.d.ts +60 -0
- package/dist/core/storage/metrics.d.ts.map +1 -0
- package/dist/core/storage/metrics.js +134 -0
- package/dist/core/storage/policy.d.ts +7 -0
- package/dist/core/storage/policy.d.ts.map +1 -0
- package/dist/core/storage/policy.js +110 -0
- package/dist/core/storage/process-log.d.ts +38 -0
- package/dist/core/storage/process-log.d.ts.map +1 -0
- package/dist/core/storage/process-log.js +165 -0
- package/dist/core/storage/query.d.ts +34 -0
- package/dist/core/storage/query.d.ts.map +1 -0
- package/dist/core/storage/query.js +295 -0
- package/dist/core/storage/receipts.d.ts +23 -0
- package/dist/core/storage/receipts.d.ts.map +1 -0
- package/dist/core/storage/receipts.js +117 -0
- package/dist/core/storage/segments.d.ts +84 -0
- package/dist/core/storage/segments.d.ts.map +1 -0
- package/dist/core/storage/segments.js +542 -0
- package/dist/core/storage/sink-graph.d.ts +65 -0
- package/dist/core/storage/sink-graph.d.ts.map +1 -0
- package/dist/core/storage/sink-graph.js +213 -0
- package/dist/core/storage/storm-control.d.ts +23 -0
- package/dist/core/storage/storm-control.d.ts.map +1 -0
- package/dist/core/storage/storm-control.js +59 -0
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +10 -14
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +2 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/lazy-commands.d.ts +26 -0
- package/dist/lazy-commands.d.ts.map +1 -0
- package/dist/lazy-commands.js +210 -0
- package/dist/lib/docs-lint.d.ts +2 -0
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +45 -80
- package/dist/lib/docs-metadata-audit.d.ts +3 -0
- package/dist/lib/docs-metadata-audit.d.ts.map +1 -1
- package/dist/lib/docs-metadata-audit.js +13 -23
- package/dist/lib/docs-metadata-sync.d.ts +1 -0
- package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
- package/dist/lib/docs-metadata-sync.js +28 -10
- package/dist/lib/docs-repository-view.d.ts +22 -0
- package/dist/lib/docs-repository-view.d.ts.map +1 -0
- package/dist/lib/docs-repository-view.js +185 -0
- package/dist/lib/http/client.d.ts +11 -5
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +22 -4
- package/dist/lib/http/index.d.ts +1 -1
- package/dist/lib/http/index.d.ts.map +1 -1
- package/dist/lib/http/index.js +1 -1
- package/dist/lib/indexer-exclusions.d.ts +27 -0
- package/dist/lib/indexer-exclusions.d.ts.map +1 -0
- package/dist/lib/indexer-exclusions.js +176 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +5 -0
- package/dist/lib/local-file-url.d.ts +9 -0
- package/dist/lib/local-file-url.d.ts.map +1 -0
- package/dist/lib/local-file-url.js +20 -0
- package/dist/lib/web-performance.d.ts +118 -0
- package/dist/lib/web-performance.d.ts.map +1 -0
- package/dist/lib/web-performance.js +192 -0
- package/package.json +29 -2
- package/schemas/config.schema.json +58 -0
- package/schemas/event-v3.schema.json +324 -112
- package/src/commander.ts +462 -95
- package/src/commands/agents.ts +517 -190
- package/src/commands/backup.ts +18 -14
- package/src/commands/browse-session.ts +12 -0
- package/src/commands/browse.ts +6 -7
- package/src/commands/conversations.ts +279 -0
- package/src/commands/deinit.ts +6 -0
- package/src/commands/docs.ts +25 -6
- package/src/commands/doctor.ts +75 -9
- package/src/commands/fetch.ts +7 -6
- package/src/commands/files.ts +143 -0
- package/src/commands/governor.ts +13 -12
- package/src/commands/inbox.ts +61 -0
- package/src/commands/init.ts +78 -16
- package/src/commands/ledger-v3.ts +421 -1
- package/src/commands/logs.ts +224 -0
- package/src/commands/messages.ts +61 -0
- package/src/commands/outline.ts +6 -2
- package/src/commands/read.ts +6 -2
- package/src/commands/semantic.ts +66 -1
- package/src/commands/storage.ts +310 -0
- package/src/commands/tunnel.ts +66 -52
- package/src/commands/web.ts +77 -7
- package/src/commands/work.ts +3 -3
- package/src/commands/workflow.ts +13 -13
- package/src/core/agents/cli.ts +259 -53
- package/src/core/agents/live-authority-v3.ts +341 -10
- package/src/core/agents/live-lifecycle-v3.ts +6 -1
- package/src/core/agents/live-observation-v3.ts +6 -1
- package/src/core/agents/render/prompt-context.ts +27 -6
- package/src/core/agents/rules/stop-hook.ts +107 -16
- package/src/core/agents/rules/verdict.ts +1 -0
- package/src/core/agents/session-events.ts +4 -0
- package/src/core/agents/session-finalization-state-v3.ts +1 -1
- package/src/core/agents/session-finalizer-v3.ts +4 -1
- package/src/core/agents/state/activity-log.ts +7 -2
- package/src/core/agents/state/heartbeat-writer.ts +27 -0
- package/src/core/agents/state/live-coordination-view.ts +16 -105
- package/src/core/agents/state/live-coordination-writer.ts +141 -0
- package/src/core/artifacts/index.ts +64 -1
- package/src/core/config.ts +126 -5
- package/src/core/conversations/archive.ts +237 -0
- package/src/core/conversations/catalog.ts +79 -0
- package/src/core/conversations/context-pack.ts +72 -0
- package/src/core/conversations/contract.ts +178 -0
- package/src/core/conversations/evaluation.ts +30 -0
- package/src/core/conversations/index.ts +9 -0
- package/src/core/conversations/lifecycle.ts +63 -0
- package/src/core/conversations/normalize.ts +105 -0
- package/src/core/conversations/query.ts +318 -0
- package/src/core/conversations/search-index.ts +48 -0
- package/src/core/events/legacy-storage/canary.ts +177 -0
- package/src/core/events/legacy-storage/fence.ts +129 -0
- package/src/core/events/legacy-storage/index.ts +5 -0
- package/src/core/events/legacy-storage/inventory.ts +51 -0
- package/src/core/events/legacy-storage/manifest.ts +136 -0
- package/src/core/events/legacy-storage/reader.ts +178 -0
- package/src/core/events/v3/authority-outbox.ts +22 -1
- package/src/core/events/v3/base-contract.ts +17 -7
- package/src/core/events/v3/bootstrap.ts +195 -2
- package/src/core/events/v3/capabilities.ts +3 -3
- package/src/core/events/v3/control-witness.ts +339 -0
- package/src/core/events/v3/control-writer.ts +16 -0
- package/src/core/events/v3/control.ts +54 -18
- package/src/core/events/v3/coordination-transaction-recovery.ts +477 -0
- package/src/core/events/v3/coordination-view.ts +17 -1
- package/src/core/events/v3/generated.ts +1 -1
- package/src/core/events/v3/index.ts +5 -2
- package/src/core/events/v3/live-route-observer.ts +80 -0
- package/src/core/events/v3/live-routing.ts +64 -46
- package/src/core/events/v3/producers/coordination-recorder.ts +95 -10
- package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
- package/src/core/events/v3/producers/hook-base.ts +1 -1
- package/src/core/events/v3/producers/intake.ts +30 -2
- package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
- package/src/core/events/v3/producers/recorder.ts +571 -33
- package/src/core/events/v3/reader.ts +243 -2
- package/src/core/events/v3/rotation-config.ts +98 -0
- package/src/core/events/v3/runtime-build.ts +41 -0
- package/src/core/events/v3/runtime-identity.ts +16 -0
- package/src/core/events/v3/runtime-telemetry-capabilities.ts +14 -8
- package/src/core/events/v3/support-storage/classify.ts +209 -0
- package/src/core/events/v3/support-storage/eligibility.ts +58 -0
- package/src/core/events/v3/support-storage/index.ts +9 -0
- package/src/core/events/v3/support-storage/inventory.ts +135 -0
- package/src/core/events/v3/support-storage/logical-authority.ts +117 -0
- package/src/core/events/v3/support-storage/maintenance.ts +501 -0
- package/src/core/events/v3/support-storage/pack-contract.ts +337 -0
- package/src/core/events/v3/support-storage/pack-reader.ts +346 -0
- package/src/core/events/v3/support-storage/pack-writer.ts +352 -0
- package/src/core/events/v3/support-storage/recovery.ts +43 -0
- package/src/core/events/v3/turn-telemetry.ts +58 -7
- package/src/core/events/v3/writer.ts +168 -16
- package/src/core/governor/plan-read.ts +5 -18
- package/src/core/governor/planning.ts +5 -8
- package/src/core/governor/service-read.ts +320 -2
- package/src/core/governor/service.ts +49 -22
- package/src/core/guard/evidence-v3.ts +1 -0
- package/src/core/hooks/adapter/events.ts +1 -0
- package/src/core/hooks/adapter/output.ts +12 -5
- package/src/core/hooks/adapter/runtime-telemetry.ts +408 -13
- package/src/core/hooks/cli.ts +226 -32
- package/src/core/hooks/effects/image-capture.ts +4 -1
- package/src/core/hooks/remediation-cap.ts +12 -6
- package/src/core/hooks/resolve/coord-root.ts +91 -11
- package/src/core/hooks/resolve/owner.ts +4 -0
- package/src/core/hooks/resolve/transcript.ts +18 -0
- package/src/core/inbox/contract.ts +81 -0
- package/src/core/inbox/index.ts +4 -0
- package/src/core/inbox/lifecycle.ts +104 -0
- package/src/core/inbox/service.ts +305 -0
- package/src/core/inbox/watcher.ts +36 -0
- package/src/core/presence/codec-digest.ts +15 -9
- package/src/core/presence/relay-client.ts +55 -7
- package/src/core/semantic/adapters.ts +200 -41
- package/src/core/semantic/contract.ts +135 -3
- package/src/core/semantic/index.ts +76 -2
- package/src/core/semantic/once.ts +93 -7
- package/src/core/semantic/prompt.ts +13 -1
- package/src/core/semantic/review.ts +803 -0
- package/src/core/semantic/routes.ts +30 -0
- package/src/core/semantic/scheduler.ts +49 -5
- package/src/core/semantic/service-status.ts +99 -5
- package/src/core/semantic/service.ts +116 -15
- package/src/core/semantic/soak.ts +638 -0
- package/src/core/semantic/storage.ts +20 -6
- package/src/core/semantic/usage.ts +272 -0
- package/src/core/semantic/validate.ts +31 -0
- package/src/core/storage/buffer.ts +124 -0
- package/src/core/storage/builtins.ts +916 -0
- package/src/core/storage/catalog.ts +467 -0
- package/src/core/storage/config.ts +423 -0
- package/src/core/storage/contract.ts +342 -0
- package/src/core/storage/durable-history.ts +738 -0
- package/src/core/storage/health.ts +76 -0
- package/src/core/storage/index.ts +15 -0
- package/src/core/storage/inventory.ts +859 -0
- package/src/core/storage/jsonl.ts +213 -0
- package/src/core/storage/log-retention.ts +555 -0
- package/src/core/storage/logger.ts +546 -0
- package/src/core/storage/maintenance-providers.ts +200 -0
- package/src/core/storage/maintenance.ts +929 -0
- package/src/core/storage/metrics.ts +199 -0
- package/src/core/storage/policy.ts +141 -0
- package/src/core/storage/process-log.ts +203 -0
- package/src/core/storage/query.ts +360 -0
- package/src/core/storage/receipts.ts +162 -0
- package/src/core/storage/segments.ts +721 -0
- package/src/core/storage/sink-graph.ts +343 -0
- package/src/core/storage/storm-control.ts +91 -0
- package/src/core/work/state.ts +12 -21
- package/src/core/workflow/live-session-v3.ts +2 -4
- package/src/index.ts +2 -0
- package/src/lazy-commands.ts +294 -0
- package/src/lib/docs-lint.ts +58 -77
- package/src/lib/docs-metadata-audit.ts +26 -21
- package/src/lib/docs-metadata-sync.ts +32 -9
- package/src/lib/docs-repository-view.ts +220 -0
- package/src/lib/http/client.ts +44 -8
- package/src/lib/http/index.ts +6 -1
- package/src/lib/indexer-exclusions.ts +173 -0
- package/src/lib/instructions/templates.ts +5 -0
- package/src/lib/local-file-url.ts +31 -0
- package/src/lib/web-performance.ts +335 -0
package/src/commands/agents.ts
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
rmSync,
|
|
24
24
|
writeFileSync,
|
|
25
25
|
} from "node:fs";
|
|
26
|
-
import {
|
|
26
|
+
import { tmpdir } from "node:os";
|
|
27
27
|
import { basename, join, resolve } from "node:path";
|
|
28
28
|
import type { Command } from "commander";
|
|
29
29
|
import type { EmitContext, HarneryProgramContext } from "../commander.ts";
|
|
@@ -44,7 +44,11 @@ import {
|
|
|
44
44
|
resolveOwnerWithSource,
|
|
45
45
|
sessionIdentityFromEnv,
|
|
46
46
|
} from "../core/agents/index.ts";
|
|
47
|
-
import {
|
|
47
|
+
import {
|
|
48
|
+
bootstrapLiveCoordinationAuthorityV3,
|
|
49
|
+
LiveCoordinationAuthorityV3Error,
|
|
50
|
+
reopenLiveCoordinationGenerationV3,
|
|
51
|
+
} from "../core/agents/live-authority-v3.ts";
|
|
48
52
|
import {
|
|
49
53
|
listSessionFinalizationRequestsV3,
|
|
50
54
|
observeHostDisappearedV3,
|
|
@@ -56,6 +60,7 @@ import {
|
|
|
56
60
|
SESSION_NAME_DISPLAY_NOTE,
|
|
57
61
|
sessionNameDisplayPending,
|
|
58
62
|
} from "../core/agents/session-name-display.ts";
|
|
63
|
+
import { agentDisplayName } from "../core/agents/state/activity-log.ts";
|
|
59
64
|
import {
|
|
60
65
|
buildLifecycleSuggestedName,
|
|
61
66
|
buildSuggestedName,
|
|
@@ -80,6 +85,10 @@ import type { EventTypeV3 } from "../core/events/v3/contract.ts";
|
|
|
80
85
|
import { readEventV3ControlState } from "../core/events/v3/control.ts";
|
|
81
86
|
import { projectCoordinationViewV3 } from "../core/events/v3/coordination-view.ts";
|
|
82
87
|
import { liveInstanceIdV3 } from "../core/events/v3/live-routing.ts";
|
|
88
|
+
import {
|
|
89
|
+
countSummarizedSinceV3,
|
|
90
|
+
listDiagnosticSummariesV3,
|
|
91
|
+
} from "../core/events/v3/producers/diagnostic-summaries.ts";
|
|
83
92
|
import {
|
|
84
93
|
listHookIntakeGroupsV3,
|
|
85
94
|
listHookIntakeRecordsV3,
|
|
@@ -92,7 +101,10 @@ import { readLedgerV3 } from "../core/events/v3/reader.ts";
|
|
|
92
101
|
import { EVENT_V3_LEDGER_RELATIVE_ROOT } from "../core/events/v3/writer.ts";
|
|
93
102
|
import type { RunQualitySnapshot, RunQualityStatus } from "../core/guard/index.ts";
|
|
94
103
|
import { evaluateRunQualityIfDue } from "../core/guard/index.ts";
|
|
95
|
-
import {
|
|
104
|
+
import {
|
|
105
|
+
readRuntimeContextTelemetry,
|
|
106
|
+
readRuntimeContextUsage,
|
|
107
|
+
} from "../core/hooks/adapter/runtime-telemetry.ts";
|
|
96
108
|
import { type RemoteMachine, readRemoteMachines } from "../core/presence/index.ts";
|
|
97
109
|
import { registerContextCommand } from "./context.ts";
|
|
98
110
|
|
|
@@ -264,6 +276,7 @@ export function registerAgentsCommand(
|
|
|
264
276
|
program: Command,
|
|
265
277
|
emitParam: EmitContext,
|
|
266
278
|
programContext?: HarneryProgramContext,
|
|
279
|
+
binName = resolveBinName(),
|
|
267
280
|
): void {
|
|
268
281
|
emit = emitParam;
|
|
269
282
|
const cmd = program
|
|
@@ -385,7 +398,7 @@ export function registerAgentsCommand(
|
|
|
385
398
|
)
|
|
386
399
|
.option(
|
|
387
400
|
"--session-id <id>",
|
|
388
|
-
`Set the task on the heartbeat with this session_id directly, bypassing the ppid walk. Mirror of \`status --session-id\`: use it when the ppid walk can't resolve self (e.g. Cursor, whose shell tool calls don't descend from a pid-map-registered anchor). Discover the id via \`${
|
|
401
|
+
`Set the task on the heartbeat with this session_id directly, bypassing the ppid walk. Mirror of \`status --session-id\`: use it when the ppid walk can't resolve self (e.g. Cursor, whose shell tool calls don't descend from a pid-map-registered anchor). Discover the id via \`${binName} agents list --json\`.`,
|
|
389
402
|
)
|
|
390
403
|
.action((text: string[], opts: { sessionId?: string }) => {
|
|
391
404
|
runSetTask(text.join(" "), opts);
|
|
@@ -484,7 +497,7 @@ export function registerAgentsCommand(
|
|
|
484
497
|
cmd
|
|
485
498
|
.command("wait <name>")
|
|
486
499
|
.description(
|
|
487
|
-
`Block until a peer agent releases files (their \`files_touched\` becomes empty, OR they exit). Pair with \`${
|
|
500
|
+
`Block until a peer agent releases files (their \`files_touched\` becomes empty, OR they exit). Pair with \`${binName} agents ping\` to coordinate hand-offs.`,
|
|
488
501
|
)
|
|
489
502
|
.option(
|
|
490
503
|
"--file <path>",
|
|
@@ -567,12 +580,11 @@ export function registerAgentsCommand(
|
|
|
567
580
|
cmd
|
|
568
581
|
.command("heal")
|
|
569
582
|
.description(
|
|
570
|
-
"
|
|
571
|
-
"
|
|
572
|
-
"disposable V3 coordination cache from the authoritative ledger).",
|
|
583
|
+
"Repair the current session's disposable coordination cache from V3. " +
|
|
584
|
+
"Use explicit options to target another generation or repair process attribution.",
|
|
573
585
|
)
|
|
574
|
-
.
|
|
575
|
-
.
|
|
586
|
+
.option("--owner <id>", "Target agent's instance_id. Defaults to the current session.")
|
|
587
|
+
.option("--kind <kind>", "pidmap | cache. Defaults to cache.")
|
|
576
588
|
.option(
|
|
577
589
|
"--session-id <id>",
|
|
578
590
|
"(--kind cache) native session id used to join the authoritative V3 generation.",
|
|
@@ -589,14 +601,26 @@ export function registerAgentsCommand(
|
|
|
589
601
|
"when calling from outside Claude Code's Bash tool tree (e.g. " +
|
|
590
602
|
"from cron or an external script).",
|
|
591
603
|
)
|
|
604
|
+
.option(
|
|
605
|
+
"--quarantine-transaction <id>",
|
|
606
|
+
"Quarantine one irreconcilable prepared authority transaction after proving its event was never committed.",
|
|
607
|
+
)
|
|
608
|
+
.option(
|
|
609
|
+
"--approval-record-id <id>",
|
|
610
|
+
"Durable identifier for the operator approval authorizing transaction quarantine.",
|
|
611
|
+
)
|
|
612
|
+
.option("--yes", "Confirm the exact prepared transaction may be quarantined.")
|
|
592
613
|
.option("--json", "JSON envelope output")
|
|
593
614
|
.action(
|
|
594
615
|
(opts: {
|
|
595
|
-
owner
|
|
596
|
-
kind
|
|
616
|
+
owner?: string;
|
|
617
|
+
kind?: string;
|
|
597
618
|
sessionId?: string;
|
|
598
619
|
adapter?: string;
|
|
599
620
|
pid?: string;
|
|
621
|
+
quarantineTransaction?: string;
|
|
622
|
+
approvalRecordId?: string;
|
|
623
|
+
yes?: boolean;
|
|
600
624
|
json?: boolean;
|
|
601
625
|
}) => {
|
|
602
626
|
runHeal(opts);
|
|
@@ -935,14 +959,15 @@ function runIdentityAssume(
|
|
|
935
959
|
});
|
|
936
960
|
process.exit(1);
|
|
937
961
|
}
|
|
938
|
-
if (!opts.sessionId)
|
|
962
|
+
if (!opts.sessionId) ensureAdapterSession(root);
|
|
939
963
|
const owner = opts.sessionId ?? resolveOwner();
|
|
940
964
|
if (!owner) {
|
|
941
|
-
emit.error(
|
|
942
|
-
|
|
943
|
-
|
|
965
|
+
emit.error(
|
|
966
|
+
sessionResolutionFailure(
|
|
967
|
+
root,
|
|
944
968
|
"not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
945
|
-
|
|
969
|
+
),
|
|
970
|
+
);
|
|
946
971
|
process.exit(1);
|
|
947
972
|
}
|
|
948
973
|
try {
|
|
@@ -1214,14 +1239,13 @@ function runWhoami(opts: { json?: boolean }): void {
|
|
|
1214
1239
|
process.exit(1);
|
|
1215
1240
|
}
|
|
1216
1241
|
|
|
1217
|
-
|
|
1242
|
+
ensureAdapterSession(root);
|
|
1218
1243
|
const resolved = resolveOwnerWithSource();
|
|
1219
1244
|
const myOwner = resolved.owner;
|
|
1220
1245
|
if (!myOwner) {
|
|
1221
|
-
emit.error(
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
});
|
|
1246
|
+
emit.error(
|
|
1247
|
+
sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"),
|
|
1248
|
+
);
|
|
1225
1249
|
process.exit(1);
|
|
1226
1250
|
}
|
|
1227
1251
|
|
|
@@ -1703,49 +1727,96 @@ function cursorEnvSessionId(): string | null {
|
|
|
1703
1727
|
return raw.startsWith("bc-") && raw.length > 3 ? raw.slice(3) : raw;
|
|
1704
1728
|
}
|
|
1705
1729
|
|
|
1706
|
-
|
|
1707
|
-
|
|
1730
|
+
interface CommandSessionBootstrap {
|
|
1731
|
+
adapter: "claude-code" | "cursor" | "codex";
|
|
1732
|
+
sessionId: string;
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
function commandSessionBootstrap(): CommandSessionBootstrap | null {
|
|
1736
|
+
const cursorSessionId = cursorEnvSessionId();
|
|
1737
|
+
if (process.env.CURSOR_AGENT === "1" && cursorSessionId) {
|
|
1738
|
+
return { adapter: "cursor", sessionId: cursorSessionId };
|
|
1739
|
+
}
|
|
1740
|
+
if (process.env.HARNERY_AGENT_COORD_BRIDGE?.trim() === "codex-wsl") {
|
|
1741
|
+
const sessionId = sessionIdentityFromEnv();
|
|
1742
|
+
if (sessionId) return { adapter: "codex", sessionId };
|
|
1743
|
+
}
|
|
1744
|
+
const claudeSessionId = process.env.CLAUDE_CODE_SESSION_ID?.trim();
|
|
1745
|
+
if (claudeSessionId) {
|
|
1746
|
+
return { adapter: "claude-code", sessionId: claudeSessionId };
|
|
1747
|
+
}
|
|
1748
|
+
return null;
|
|
1708
1749
|
}
|
|
1709
1750
|
|
|
1710
|
-
function
|
|
1711
|
-
|
|
1751
|
+
function ensureAdapterSession(root: string): void {
|
|
1752
|
+
const bootstrap = commandSessionBootstrap();
|
|
1753
|
+
if (!bootstrap) return;
|
|
1754
|
+
// Claude Code owns a reliable native SessionStart hook. Its environment is
|
|
1755
|
+
// accepted by the explicit `agents heal` recovery path, but ordinary
|
|
1756
|
+
// identity and status commands must not impersonate that hook. The heal
|
|
1757
|
+
// bootstrap records derived provenance instead.
|
|
1758
|
+
if (bootstrap.adapter === "claude-code") return;
|
|
1712
1759
|
// Explicit owner override means the caller already knows who they are.
|
|
1713
1760
|
// Bootstrapping sessionStart inherits that env into the child hook, which
|
|
1714
1761
|
// re-projects a fresh heartbeat onto the override owner and can wipe an
|
|
1715
1762
|
// assumed persona agent_id (seen under Cursor integration fixtures).
|
|
1716
|
-
if (process.env.HARNERY_AGENT_COORD_OWNER?.trim()) return;
|
|
1763
|
+
if (bootstrap.adapter === "cursor" && process.env.HARNERY_AGENT_COORD_OWNER?.trim()) return;
|
|
1717
1764
|
if (resolveOwnerBySessionEnv(root)) return;
|
|
1718
1765
|
|
|
1719
|
-
const sessionId = cursorEnvSessionId();
|
|
1720
|
-
if (!sessionId) return;
|
|
1721
1766
|
const agentHook = coordBinPath("agent-hook", root);
|
|
1722
1767
|
if (!agentHook) return;
|
|
1723
1768
|
|
|
1724
1769
|
const payload = JSON.stringify({
|
|
1725
|
-
conversation_id: sessionId,
|
|
1726
|
-
session_id: sessionId,
|
|
1770
|
+
...(bootstrap.adapter === "cursor" ? { conversation_id: bootstrap.sessionId } : {}),
|
|
1771
|
+
session_id: bootstrap.sessionId,
|
|
1727
1772
|
hook_event_name: "sessionStart",
|
|
1728
1773
|
workspace_roots: [root],
|
|
1729
1774
|
cwd: root,
|
|
1730
|
-
|
|
1731
|
-
|
|
1775
|
+
...(bootstrap.adapter === "cursor"
|
|
1776
|
+
? { composer_mode: "agent", is_background_agent: false }
|
|
1777
|
+
: { source: "resume" }),
|
|
1732
1778
|
});
|
|
1733
1779
|
|
|
1734
|
-
spawnSync("bash", [agentHook, "session-start", "--adapter",
|
|
1780
|
+
spawnSync("bash", [agentHook, "session-start", "--adapter", bootstrap.adapter], {
|
|
1735
1781
|
input: payload,
|
|
1736
1782
|
cwd: root,
|
|
1737
1783
|
encoding: "utf8",
|
|
1738
1784
|
timeout: 3000,
|
|
1739
1785
|
env: {
|
|
1740
1786
|
...process.env,
|
|
1741
|
-
HARNERY_AGENT_COORD_PLATFORM:
|
|
1787
|
+
HARNERY_AGENT_COORD_PLATFORM: bootstrap.adapter,
|
|
1742
1788
|
HARNERY_COORD_ROOT_OVERRIDE: root,
|
|
1743
|
-
|
|
1744
|
-
|
|
1789
|
+
HARNERY_AGENT_COORD_SESSION_ID: bootstrap.sessionId,
|
|
1790
|
+
...(bootstrap.adapter === "cursor"
|
|
1791
|
+
? {
|
|
1792
|
+
CURSOR_SESSION_ID: bootstrap.sessionId,
|
|
1793
|
+
CURSOR_CONVERSATION_ID: bootstrap.sessionId,
|
|
1794
|
+
}
|
|
1795
|
+
: { CODEX_THREAD_ID: bootstrap.sessionId }),
|
|
1745
1796
|
},
|
|
1746
1797
|
});
|
|
1747
1798
|
}
|
|
1748
1799
|
|
|
1800
|
+
function sessionResolutionFailure(
|
|
1801
|
+
root: string,
|
|
1802
|
+
fallbackMessage: string,
|
|
1803
|
+
): { code: string; message: string } {
|
|
1804
|
+
if (!sessionIdentityFromEnv()) return { code: "no_pidmap_entry", message: fallbackMessage };
|
|
1805
|
+
const control = readEventV3ControlState(root);
|
|
1806
|
+
if (control.state !== "candidate" && control.state !== "active") {
|
|
1807
|
+
const detail = `${control.state}:${control.reason}`;
|
|
1808
|
+
return {
|
|
1809
|
+
code: "event_v3_control_unavailable",
|
|
1810
|
+
message: `the adapter session identity is present, but the V3 control state cannot accept session onboarding (${detail})`,
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1813
|
+
return {
|
|
1814
|
+
code: "session_generation_unavailable",
|
|
1815
|
+
message:
|
|
1816
|
+
"the adapter session identity is present, but no current V3 session generation was available after onboarding",
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1749
1820
|
function runReleaseClaim(path: string): void {
|
|
1750
1821
|
const root = monorepoRoot();
|
|
1751
1822
|
if (!root) {
|
|
@@ -1757,10 +1828,9 @@ function runReleaseClaim(path: string): void {
|
|
|
1757
1828
|
}
|
|
1758
1829
|
const myOwner = resolveOwner();
|
|
1759
1830
|
if (!myOwner) {
|
|
1760
|
-
emit.error(
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
});
|
|
1831
|
+
emit.error(
|
|
1832
|
+
sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"),
|
|
1833
|
+
);
|
|
1764
1834
|
process.exit(1);
|
|
1765
1835
|
}
|
|
1766
1836
|
// Canonicalize: absolute paths under coordRoot get the prefix stripped;
|
|
@@ -1801,14 +1871,15 @@ function runSetTask(task: string, opts?: { sessionId?: string }): void {
|
|
|
1801
1871
|
// returns null by design, and erroring here orphans the session's first
|
|
1802
1872
|
// ritual command. The env id carries the same trust as an explicit
|
|
1803
1873
|
// --session-id, and set-task mints the heartbeat exactly as that path does.
|
|
1804
|
-
if (!opts?.sessionId)
|
|
1874
|
+
if (!opts?.sessionId) ensureAdapterSession(root);
|
|
1805
1875
|
const myOwner = opts?.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
|
|
1806
1876
|
if (!myOwner) {
|
|
1807
|
-
emit.error(
|
|
1808
|
-
|
|
1809
|
-
|
|
1877
|
+
emit.error(
|
|
1878
|
+
sessionResolutionFailure(
|
|
1879
|
+
root,
|
|
1810
1880
|
"not in an agent session; no session-id environment identity and the ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
1811
|
-
|
|
1881
|
+
),
|
|
1882
|
+
);
|
|
1812
1883
|
process.exit(1);
|
|
1813
1884
|
}
|
|
1814
1885
|
|
|
@@ -1897,14 +1968,15 @@ function runLifecycle(rawState: string, opts: { reason?: string; sessionId?: str
|
|
|
1897
1968
|
process.exitCode = 1;
|
|
1898
1969
|
return;
|
|
1899
1970
|
}
|
|
1900
|
-
if (!opts.sessionId)
|
|
1971
|
+
if (!opts.sessionId) ensureAdapterSession(root);
|
|
1901
1972
|
const myOwner = opts.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
|
|
1902
1973
|
if (!myOwner) {
|
|
1903
|
-
emit.error(
|
|
1904
|
-
|
|
1905
|
-
|
|
1974
|
+
emit.error(
|
|
1975
|
+
sessionResolutionFailure(
|
|
1976
|
+
root,
|
|
1906
1977
|
"not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
1907
|
-
|
|
1978
|
+
),
|
|
1979
|
+
);
|
|
1908
1980
|
process.exitCode = 1;
|
|
1909
1981
|
return;
|
|
1910
1982
|
}
|
|
@@ -2079,14 +2151,15 @@ function runSuggestName(
|
|
|
2079
2151
|
|
|
2080
2152
|
// Identity: prefer explicit --session-id (ppid-walk-free escape hatch, mirrors
|
|
2081
2153
|
// `status`/`set-task`), fall back to the ppid walk for interactive shell use.
|
|
2082
|
-
if (!opts.sessionId)
|
|
2154
|
+
if (!opts.sessionId) ensureAdapterSession(root);
|
|
2083
2155
|
const myOwner = opts.sessionId ?? resolveOwner();
|
|
2084
2156
|
if (!myOwner) {
|
|
2085
|
-
emit.error(
|
|
2086
|
-
|
|
2087
|
-
|
|
2157
|
+
emit.error(
|
|
2158
|
+
sessionResolutionFailure(
|
|
2159
|
+
root,
|
|
2088
2160
|
"not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
2089
|
-
|
|
2161
|
+
),
|
|
2162
|
+
);
|
|
2090
2163
|
process.exit(1);
|
|
2091
2164
|
}
|
|
2092
2165
|
|
|
@@ -2158,14 +2231,15 @@ function runStatus(opts: {
|
|
|
2158
2231
|
|
|
2159
2232
|
// Identity resolution: prefer explicit --session-id (hook-friendly), fall
|
|
2160
2233
|
// back to ppid walk for interactive shell usage.
|
|
2161
|
-
if (!opts.sessionId)
|
|
2234
|
+
if (!opts.sessionId) ensureAdapterSession(root);
|
|
2162
2235
|
const myOwner = opts.sessionId ?? resolveOwner();
|
|
2163
2236
|
if (!myOwner) {
|
|
2164
|
-
emit.error(
|
|
2165
|
-
|
|
2166
|
-
|
|
2237
|
+
emit.error(
|
|
2238
|
+
sessionResolutionFailure(
|
|
2239
|
+
root,
|
|
2167
2240
|
"not in an agent session; ppid walk found no pid-map entry (pass --session-id from a hook payload)",
|
|
2168
|
-
|
|
2241
|
+
),
|
|
2242
|
+
);
|
|
2169
2243
|
process.exit(1);
|
|
2170
2244
|
}
|
|
2171
2245
|
|
|
@@ -2207,7 +2281,7 @@ function runStatus(opts: {
|
|
|
2207
2281
|
}
|
|
2208
2282
|
}
|
|
2209
2283
|
|
|
2210
|
-
emitEventV3({
|
|
2284
|
+
const statusEmitted = emitEventV3({
|
|
2211
2285
|
owner: myOwner,
|
|
2212
2286
|
session: nativeSessionIdentity(hb, myOwner),
|
|
2213
2287
|
adapter: normalizeAdapter(hb.platform),
|
|
@@ -2216,6 +2290,16 @@ function runStatus(opts: {
|
|
|
2216
2290
|
status: opts.endTurn ? "end_turn_checked" : opts.json ? "json_checked" : "box_checked",
|
|
2217
2291
|
},
|
|
2218
2292
|
});
|
|
2293
|
+
// The closing box is a success artifact. Never print it when the exact
|
|
2294
|
+
// evidence enforced by the Stop hook did not reach the ledger.
|
|
2295
|
+
if (opts.endTurn && !statusEmitted) {
|
|
2296
|
+
emit.error({
|
|
2297
|
+
code: "status_event_failed",
|
|
2298
|
+
message: `the end-of-turn status event could not be recorded; no status box was issued; rerun \`${resolveBinName(root)} agents status --end-turn\``,
|
|
2299
|
+
});
|
|
2300
|
+
process.exitCode = 1;
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2219
2303
|
|
|
2220
2304
|
let sessionEnd:
|
|
2221
2305
|
| { state: "queued" | "already_requested"; request_id: string }
|
|
@@ -2285,10 +2369,7 @@ function runStatus(opts: {
|
|
|
2285
2369
|
if (!ctxUsage) {
|
|
2286
2370
|
ctxStr = "unavailable";
|
|
2287
2371
|
} else if (ctxUsage.percentOnly) {
|
|
2288
|
-
|
|
2289
|
-
// window. Show the percent + window estimate, marked as estimated.
|
|
2290
|
-
const pct = Math.round((ctxUsage.used / ctxUsage.window) * 100);
|
|
2291
|
-
ctxStr = `~${pct}% (Cursor; ${fmtTokens(ctxUsage.window)} window est.)`;
|
|
2372
|
+
ctxStr = `${Math.round(ctxUsage.usedPercent)}% (Cursor first-party)`;
|
|
2292
2373
|
} else {
|
|
2293
2374
|
ctxStr = `${fmtTokens(ctxUsage.used)} / ${fmtTokens(ctxUsage.window)} (${Math.round(
|
|
2294
2375
|
(ctxUsage.used / ctxUsage.window) * 100,
|
|
@@ -2296,7 +2377,7 @@ function runStatus(opts: {
|
|
|
2296
2377
|
}
|
|
2297
2378
|
|
|
2298
2379
|
const timeStr = formatLocalTime(new Date());
|
|
2299
|
-
const displayName =
|
|
2380
|
+
const displayName = agentDisplayName(hb.instance_id, hb.name);
|
|
2300
2381
|
|
|
2301
2382
|
// Council pending: list of council IDs where this agent is a member of an
|
|
2302
2383
|
// active council in `open` round_status without a contribution to that round.
|
|
@@ -2340,8 +2421,8 @@ function runStatus(opts: {
|
|
|
2340
2421
|
})),
|
|
2341
2422
|
})),
|
|
2342
2423
|
pending_councils: pendingCouncils,
|
|
2343
|
-
context_used: ctxUsage
|
|
2344
|
-
context_window: ctxUsage
|
|
2424
|
+
context_used: ctxUsage && "used" in ctxUsage ? ctxUsage.used : null,
|
|
2425
|
+
context_window: ctxUsage && "window" in ctxUsage ? ctxUsage.window : null,
|
|
2345
2426
|
timestamp_iso: new Date().toISOString(),
|
|
2346
2427
|
timestamp_local: timeStr,
|
|
2347
2428
|
...(quality ? { quality } : {}),
|
|
@@ -2485,15 +2566,17 @@ export function collectStatusPeerHealth(
|
|
|
2485
2566
|
root: string,
|
|
2486
2567
|
myOwner: string,
|
|
2487
2568
|
nowMs = Date.now(),
|
|
2569
|
+
readRows: (root: string) => StatusPeerHeartbeat[] = readLiveCoordinationRows,
|
|
2570
|
+
freshnessSeconds = freshnessCutoffSecs(),
|
|
2488
2571
|
): { livePeers: StatusPeerHeartbeat[]; stale: number } {
|
|
2489
2572
|
let rows: StatusPeerHeartbeat[] = [];
|
|
2490
2573
|
try {
|
|
2491
|
-
rows =
|
|
2574
|
+
rows = readRows(root);
|
|
2492
2575
|
} catch {
|
|
2493
2576
|
// V3 authority failures must not resurrect disposable cache rows.
|
|
2494
2577
|
}
|
|
2495
2578
|
|
|
2496
|
-
const cutoffMs = nowMs -
|
|
2579
|
+
const cutoffMs = nowMs - freshnessSeconds * 1000;
|
|
2497
2580
|
const livePeers: StatusPeerHeartbeat[] = [];
|
|
2498
2581
|
let stale = 0;
|
|
2499
2582
|
for (const peer of rows) {
|
|
@@ -2515,85 +2598,28 @@ function fmtTokens(n: number): string {
|
|
|
2515
2598
|
function readContextUsage(
|
|
2516
2599
|
sessionId: string,
|
|
2517
2600
|
platform?: string | null,
|
|
2518
|
-
):
|
|
2601
|
+
):
|
|
2602
|
+
| { used: number; window: number; percentOnly?: false }
|
|
2603
|
+
| { usedPercent: number; percentOnly: true }
|
|
2604
|
+
| null {
|
|
2519
2605
|
if (!sessionId) return null;
|
|
2520
2606
|
// Dispatch by platform: Codex's JSONL shape is different from Claude Code's
|
|
2521
2607
|
// (event_msg/response_item vs user/assistant), and Codex transcripts live
|
|
2522
2608
|
// under ~/.codex/sessions/YYYY/MM/DD/ rather than ~/.claude/projects/.
|
|
2523
|
-
// Cursor
|
|
2524
|
-
//
|
|
2525
|
-
// readCursorContextUsage reads that via bun:sqlite (percent-only).
|
|
2609
|
+
// Cursor stores a first-party percentage in workspaceStorage. The shared
|
|
2610
|
+
// runtime reader returns it without fabricating a token denominator.
|
|
2526
2611
|
if (platform === "codex") return readRuntimeContextUsage("codex", sessionId);
|
|
2527
|
-
if (platform === "cursor")
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
// is a JSON blob with .allComposers[].contextUsagePercent. We find the
|
|
2537
|
-
// composer matching the agent's session_id (Cursor uses session_id == composerId
|
|
2538
|
-
// for parent chats).
|
|
2539
|
-
//
|
|
2540
|
-
// Roots searched: ~/.config/Cursor/User/workspaceStorage (Linux native install)
|
|
2541
|
-
// and /mnt/c/Users/*/AppData/Roaming/Cursor/User/workspaceStorage (WSL).
|
|
2542
|
-
// We don't filter by workspace path; we scan every workspace's state.vscdb
|
|
2543
|
-
// looking for a composerId match. Cheap enough at status time (~60K per file,
|
|
2544
|
-
// <10ms typical). When a match is found, returns synthetic { used, window }
|
|
2545
|
-
// pair where the percent is what's real; absolutes are derived as
|
|
2546
|
-
// (window * percent / 100). Window hard-coded to a Cursor-typical 200K.
|
|
2547
|
-
const roots: string[] = [];
|
|
2548
|
-
const linuxRoot = resolve(homedir(), ".config", "Cursor", "User", "workspaceStorage");
|
|
2549
|
-
if (existsSync(linuxRoot)) roots.push(linuxRoot);
|
|
2550
|
-
try {
|
|
2551
|
-
if (existsSync("/mnt/c/Users")) {
|
|
2552
|
-
for (const u of readdirSync("/mnt/c/Users")) {
|
|
2553
|
-
const p = `/mnt/c/Users/${u}/AppData/Roaming/Cursor/User/workspaceStorage`;
|
|
2554
|
-
if (existsSync(p)) roots.push(p);
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
} catch {
|
|
2558
|
-
// ignore
|
|
2559
|
-
}
|
|
2560
|
-
for (const root of roots) {
|
|
2561
|
-
let workspaces: string[];
|
|
2562
|
-
try {
|
|
2563
|
-
workspaces = readdirSync(root);
|
|
2564
|
-
} catch {
|
|
2565
|
-
continue;
|
|
2566
|
-
}
|
|
2567
|
-
for (const ws of workspaces) {
|
|
2568
|
-
const dbPath = `${root}/${ws}/state.vscdb`;
|
|
2569
|
-
if (!existsSync(dbPath)) continue;
|
|
2570
|
-
try {
|
|
2571
|
-
// Lazy-import bun:sqlite so non-Bun runtimes (if any) don't choke at load.
|
|
2572
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2573
|
-
const { Database } = require("bun:sqlite");
|
|
2574
|
-
const db = new Database(dbPath, { readonly: true });
|
|
2575
|
-
const row = db
|
|
2576
|
-
.query("SELECT value FROM ItemTable WHERE key = 'composer.composerData'")
|
|
2577
|
-
.get() as { value: string | Uint8Array } | null;
|
|
2578
|
-
db.close();
|
|
2579
|
-
if (!row?.value) continue;
|
|
2580
|
-
const text =
|
|
2581
|
-
typeof row.value === "string" ? row.value : Buffer.from(row.value).toString("utf8");
|
|
2582
|
-
const parsed = JSON.parse(text);
|
|
2583
|
-
const composers = Array.isArray(parsed?.allComposers) ? parsed.allComposers : [];
|
|
2584
|
-
for (const c of composers) {
|
|
2585
|
-
if (c?.composerId === sessionId && typeof c?.contextUsagePercent === "number") {
|
|
2586
|
-
const window = 200000; // hard-coded Cursor-typical window; refine when Cursor exposes the actual ceiling
|
|
2587
|
-
const used = Math.round((window * c.contextUsagePercent) / 100);
|
|
2588
|
-
return { used, window, percentOnly: true };
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
|
-
} catch {
|
|
2592
|
-
// ignore: DB locked, schema drift, etc. Move on to the next workspace.
|
|
2593
|
-
}
|
|
2594
|
-
}
|
|
2612
|
+
if (platform === "cursor") {
|
|
2613
|
+
const telemetry = readRuntimeContextTelemetry({
|
|
2614
|
+
adapter: "cursor",
|
|
2615
|
+
session_id: sessionId,
|
|
2616
|
+
mode: "status",
|
|
2617
|
+
});
|
|
2618
|
+
return telemetry.state === "observed" && "used_percent" in telemetry
|
|
2619
|
+
? { usedPercent: telemetry.used_percent, percentOnly: true }
|
|
2620
|
+
: null;
|
|
2595
2621
|
}
|
|
2596
|
-
return
|
|
2622
|
+
return readRuntimeContextUsage("claude-code", sessionId);
|
|
2597
2623
|
}
|
|
2598
2624
|
|
|
2599
2625
|
function formatLocalTime(d: Date): string {
|
|
@@ -2993,9 +3019,9 @@ interface HealthReport {
|
|
|
2993
3019
|
lines: number;
|
|
2994
3020
|
cursor_backlog: number;
|
|
2995
3021
|
};
|
|
2996
|
-
//
|
|
2997
|
-
//
|
|
2998
|
-
//
|
|
3022
|
+
// Heartbeat cache files present in active/ but stale or malformed. These are
|
|
3023
|
+
// files the sweep is not catching; a parseable old heartbeat is stale, not
|
|
3024
|
+
// evidence of an epoch-like or corrupt timestamp.
|
|
2999
3025
|
zombies: {
|
|
3000
3026
|
count: number;
|
|
3001
3027
|
samples: string[];
|
|
@@ -3049,12 +3075,21 @@ export type EventLedgerHealthV3 =
|
|
|
3049
3075
|
groups: Array<{ adapter: string; session_hash: string; count: number }>;
|
|
3050
3076
|
};
|
|
3051
3077
|
diagnostics_spool: {
|
|
3078
|
+
/** Logical occurrences: loose files plus coalesced summary counts. */
|
|
3052
3079
|
total: number;
|
|
3080
|
+
/** Physical loose diagnostic files. */
|
|
3081
|
+
loose_total: number;
|
|
3082
|
+
/** Occurrences coalesced into summaries instead of loose files. */
|
|
3083
|
+
summarized_total: number;
|
|
3084
|
+
/** Physical summary files in `diagnostic-summaries/`. */
|
|
3085
|
+
summary_files: number;
|
|
3053
3086
|
last_24h: number;
|
|
3054
3087
|
last_1h: number;
|
|
3055
3088
|
latest_at: string | null;
|
|
3056
3089
|
by_category: Record<string, { total: number; last_24h: number }>;
|
|
3057
3090
|
recent_by_category: Record<string, { last_1h: number; latest_at: string | null }>;
|
|
3091
|
+
/** Times the summary gate failed open (loose write proceeded). */
|
|
3092
|
+
mitigation_fail_open: number;
|
|
3058
3093
|
};
|
|
3059
3094
|
span_pressure: Array<{ instance_id: string; generation_id: string; span_count: number }>;
|
|
3060
3095
|
collection_errors: string[];
|
|
@@ -3194,6 +3229,47 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
|
|
|
3194
3229
|
collectionErrors.push(`diagnostics spool unreadable: ${errorText(error)}`);
|
|
3195
3230
|
}
|
|
3196
3231
|
|
|
3232
|
+
// 4b) Coalesced diagnostic summaries: occurrences the producer bounded into
|
|
3233
|
+
// `diagnostic-summaries/` instead of loose files. Counted into the logical
|
|
3234
|
+
// totals so mitigation can never make an active fault look healthy; the
|
|
3235
|
+
// physical loose file count stays visible separately.
|
|
3236
|
+
let summarizedTotal = 0;
|
|
3237
|
+
let summaryFiles = 0;
|
|
3238
|
+
let mitigationFailOpen = 0;
|
|
3239
|
+
try {
|
|
3240
|
+
const listing = listDiagnosticSummariesV3(root);
|
|
3241
|
+
summaryFiles = listing.file_count;
|
|
3242
|
+
mitigationFailOpen = listing.mitigation_health?.fail_open_count ?? 0;
|
|
3243
|
+
if (listing.unreadable_count > 0) {
|
|
3244
|
+
collectionErrors.push(`${listing.unreadable_count} diagnostic summary file(s) unreadable`);
|
|
3245
|
+
}
|
|
3246
|
+
const dayAgoMs = nowMs - 24 * 60 * 60 * 1000;
|
|
3247
|
+
const hourAgoMs = nowMs - 60 * 60 * 1000;
|
|
3248
|
+
for (const summary of listing.summaries) {
|
|
3249
|
+
summarizedTotal += summary.summarized_count;
|
|
3250
|
+
const entry = byCategory[summary.category] ?? { total: 0, last_24h: 0 };
|
|
3251
|
+
const recent = recentByCategory[summary.category] ?? { last_1h: 0, latest_at: null };
|
|
3252
|
+
byCategory[summary.category] = entry;
|
|
3253
|
+
recentByCategory[summary.category] = recent;
|
|
3254
|
+
entry.total += summary.summarized_count;
|
|
3255
|
+
const day = countSummarizedSinceV3([summary], dayAgoMs, undefined, nowMs);
|
|
3256
|
+
const hour = countSummarizedSinceV3([summary], hourAgoMs, undefined, nowMs);
|
|
3257
|
+
entry.last_24h += day;
|
|
3258
|
+
diagnostics24h += day;
|
|
3259
|
+
recent.last_1h += hour;
|
|
3260
|
+
diagnostics1h += hour;
|
|
3261
|
+
const lastMs = summary.last_summarized_at ? Date.parse(summary.last_summarized_at) : NaN;
|
|
3262
|
+
if (Number.isFinite(lastMs)) {
|
|
3263
|
+
latestDiagnosticMs = Math.max(latestDiagnosticMs, lastMs);
|
|
3264
|
+
if (!recent.latest_at || lastMs > Date.parse(recent.latest_at)) {
|
|
3265
|
+
recent.latest_at = new Date(lastMs).toISOString();
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
} catch (error) {
|
|
3270
|
+
collectionErrors.push(`diagnostic summaries unreadable: ${errorText(error)}`);
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3197
3273
|
return {
|
|
3198
3274
|
state: "live",
|
|
3199
3275
|
mode: control.state,
|
|
@@ -3204,7 +3280,10 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
|
|
|
3204
3280
|
pending_finalizations: pending,
|
|
3205
3281
|
intake_spool: { total: intakeTotal, groups: intakeGroups },
|
|
3206
3282
|
diagnostics_spool: {
|
|
3207
|
-
total: diagnosticsTotal,
|
|
3283
|
+
total: diagnosticsTotal + summarizedTotal,
|
|
3284
|
+
loose_total: diagnosticsTotal,
|
|
3285
|
+
summarized_total: summarizedTotal,
|
|
3286
|
+
summary_files: summaryFiles,
|
|
3208
3287
|
last_24h: diagnostics24h,
|
|
3209
3288
|
last_1h: diagnostics1h,
|
|
3210
3289
|
latest_at: Number.isFinite(latestDiagnosticMs)
|
|
@@ -3212,6 +3291,7 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
|
|
|
3212
3291
|
: null,
|
|
3213
3292
|
by_category: byCategory,
|
|
3214
3293
|
recent_by_category: recentByCategory,
|
|
3294
|
+
mitigation_fail_open: mitigationFailOpen,
|
|
3215
3295
|
},
|
|
3216
3296
|
span_pressure: spanPressure,
|
|
3217
3297
|
collection_errors: collectionErrors,
|
|
@@ -3717,13 +3797,15 @@ type ActiveHealthHeartbeat = {
|
|
|
3717
3797
|
export function collectActiveAgentHealth(
|
|
3718
3798
|
root: string,
|
|
3719
3799
|
nowMs = Date.now(),
|
|
3800
|
+
readRows: (root: string) => ActiveHealthHeartbeat[] = readLiveCoordinationRows,
|
|
3801
|
+
freshnessSeconds = freshnessCutoffSecs(),
|
|
3720
3802
|
): ActiveAgentHealthSummary {
|
|
3721
3803
|
const source: ActiveAgentHealthSummary["source"] = "event-ledger-v3";
|
|
3722
3804
|
let heartbeats: ActiveHealthHeartbeat[] = [];
|
|
3723
3805
|
try {
|
|
3724
3806
|
const control = readEventV3ControlState(root);
|
|
3725
3807
|
if (control.state === "candidate" || control.state === "active") {
|
|
3726
|
-
heartbeats =
|
|
3808
|
+
heartbeats = readRows(root);
|
|
3727
3809
|
}
|
|
3728
3810
|
} catch {
|
|
3729
3811
|
// The event-ledger section reports the authority read failure. Do not
|
|
@@ -3749,7 +3831,7 @@ export function collectActiveAgentHealth(
|
|
|
3749
3831
|
const ageMs = Number.isFinite(lastObservedMs)
|
|
3750
3832
|
? nowMs - lastObservedMs
|
|
3751
3833
|
: Number.POSITIVE_INFINITY;
|
|
3752
|
-
if (ageMs >
|
|
3834
|
+
if (ageMs > freshnessSeconds * 1000) stale += 1;
|
|
3753
3835
|
}
|
|
3754
3836
|
return {
|
|
3755
3837
|
source,
|
|
@@ -3761,6 +3843,22 @@ export function collectActiveAgentHealth(
|
|
|
3761
3843
|
};
|
|
3762
3844
|
}
|
|
3763
3845
|
|
|
3846
|
+
export type HeartbeatCacheIssue = "no-name" | "invalid-heartbeat" | "stale-age";
|
|
3847
|
+
|
|
3848
|
+
/** Classify a parseable heartbeat cache file without conflating age with corruption. */
|
|
3849
|
+
export function classifyHeartbeatCacheIssue(
|
|
3850
|
+
heartbeat: Pick<Heartbeat, "name" | "last_heartbeat">,
|
|
3851
|
+
nowMs: number,
|
|
3852
|
+
staleAgeMs: number,
|
|
3853
|
+
): HeartbeatCacheIssue | null {
|
|
3854
|
+
if (!heartbeat.name || heartbeat.name === "unknown") return "no-name";
|
|
3855
|
+
const lastHeartbeatMs = heartbeat.last_heartbeat
|
|
3856
|
+
? Date.parse(heartbeat.last_heartbeat)
|
|
3857
|
+
: Number.NaN;
|
|
3858
|
+
if (!Number.isFinite(lastHeartbeatMs)) return "invalid-heartbeat";
|
|
3859
|
+
return nowMs - lastHeartbeatMs > staleAgeMs ? "stale-age" : null;
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3764
3862
|
function runHealth(opts: { since: string; json?: boolean }): void {
|
|
3765
3863
|
if (opts.json) emit.config({ format: "json" });
|
|
3766
3864
|
|
|
@@ -3845,12 +3943,12 @@ function runHealth(opts: { since: string; json?: boolean }): void {
|
|
|
3845
3943
|
.map(([agent, count]) => ({ agent, count }));
|
|
3846
3944
|
|
|
3847
3945
|
const activeAgents = collectActiveAgentHealth(root, nowMs);
|
|
3848
|
-
//
|
|
3849
|
-
//
|
|
3850
|
-
//
|
|
3946
|
+
// Heartbeat cache issues: files in active/ that are unparseable, nameless,
|
|
3947
|
+
// invalidly timestamped, or stale. Old parseable timestamps are ordinary
|
|
3948
|
+
// staleness, not evidence of epoch-like timestamp corruption.
|
|
3851
3949
|
let zombieCount = 0;
|
|
3852
3950
|
const zombieSamples: string[] = [];
|
|
3853
|
-
const
|
|
3951
|
+
const STALE_HEARTBEAT_AGE_MS = 24 * 60 * 60 * 1000;
|
|
3854
3952
|
if (existsSync(activeDir)) {
|
|
3855
3953
|
for (const file of readdirSync(activeDir)) {
|
|
3856
3954
|
if (!file.endsWith(".json")) continue;
|
|
@@ -3867,15 +3965,11 @@ function runHealth(opts: { since: string; json?: boolean }): void {
|
|
|
3867
3965
|
zombieSamples.push(`${idFromFile.slice(0, 12)} (unparseable/no-id)`);
|
|
3868
3966
|
continue;
|
|
3869
3967
|
}
|
|
3870
|
-
const
|
|
3871
|
-
|
|
3872
|
-
// Zombie heuristics on a parseable heartbeat: no name, or an age so large
|
|
3873
|
-
// it can only be a broken/epoch timestamp (a real agent would have healed).
|
|
3874
|
-
if (!hb.name || hb.name === "unknown" || ageMs > ABSURD_AGE_MS) {
|
|
3968
|
+
const cacheIssue = classifyHeartbeatCacheIssue(hb, nowMs, STALE_HEARTBEAT_AGE_MS);
|
|
3969
|
+
if (cacheIssue) {
|
|
3875
3970
|
zombieCount++;
|
|
3876
3971
|
if (zombieSamples.length < 5) {
|
|
3877
|
-
|
|
3878
|
-
zombieSamples.push(`${idFromFile.slice(0, 12)} (${why})`);
|
|
3972
|
+
zombieSamples.push(`${idFromFile.slice(0, 12)} (${cacheIssue})`);
|
|
3879
3973
|
}
|
|
3880
3974
|
}
|
|
3881
3975
|
}
|
|
@@ -3939,7 +4033,7 @@ function runHealth(opts: { since: string; json?: boolean }): void {
|
|
|
3939
4033
|
}
|
|
3940
4034
|
if (zombieCount > 0) {
|
|
3941
4035
|
anomalies.push(
|
|
3942
|
-
`${zombieCount}
|
|
4036
|
+
`${zombieCount} heartbeat cache issue(s) in active/ (${zombieSamples.join(", ")}); stale or malformed files the sweep isn't reaping`,
|
|
3943
4037
|
);
|
|
3944
4038
|
}
|
|
3945
4039
|
if (stopRemediation.total > 0) {
|
|
@@ -4095,7 +4189,7 @@ function renderHealthBox(report: HealthReport): void {
|
|
|
4095
4189
|
`open spans ${ledger.open_spans.total}${orphanGenerations > 0 ? ` (${orphanGenerations} gen turn-closed)` : ""}`,
|
|
4096
4190
|
`pending ends ${ledger.pending_finalizations.length}${pendingAges ? ` (${pendingAges})` : ""}`,
|
|
4097
4191
|
`intake ${ledger.intake_spool.total}`,
|
|
4098
|
-
`diagnostics ${ledger.diagnostics_spool.total} (${ledger.diagnostics_spool.last_1h} in 1h / ${ledger.diagnostics_spool.last_24h} in 24h)`,
|
|
4192
|
+
`diagnostics ${ledger.diagnostics_spool.total}${ledger.diagnostics_spool.summarized_total > 0 ? ` (${ledger.diagnostics_spool.loose_total} loose + ${ledger.diagnostics_spool.summarized_total} summarized)` : ""} (${ledger.diagnostics_spool.last_1h} in 1h / ${ledger.diagnostics_spool.last_24h} in 24h)`,
|
|
4099
4193
|
].join(" · ");
|
|
4100
4194
|
}
|
|
4101
4195
|
|
|
@@ -4116,7 +4210,7 @@ function renderHealthBox(report: HealthReport): void {
|
|
|
4116
4210
|
["stream", streamStr],
|
|
4117
4211
|
["event ledger", ledgerStr],
|
|
4118
4212
|
[
|
|
4119
|
-
"
|
|
4213
|
+
"cache issues",
|
|
4120
4214
|
report.zombies.count === 0
|
|
4121
4215
|
? "0"
|
|
4122
4216
|
: `${report.zombies.count} (${report.zombies.samples.join(", ")})`,
|
|
@@ -4552,10 +4646,18 @@ function runPing(name: string, message: string, opts: { json?: boolean }): void
|
|
|
4552
4646
|
}
|
|
4553
4647
|
const myOwner = resolveOwner();
|
|
4554
4648
|
if (!myOwner) {
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4649
|
+
const root = monorepoRoot();
|
|
4650
|
+
emit.error(
|
|
4651
|
+
root
|
|
4652
|
+
? sessionResolutionFailure(
|
|
4653
|
+
root,
|
|
4654
|
+
"not in an agent session; ppid walk found no pid-map entry",
|
|
4655
|
+
)
|
|
4656
|
+
: {
|
|
4657
|
+
code: "no_pidmap_entry",
|
|
4658
|
+
message: "not in an agent session; ppid walk found no pid-map entry",
|
|
4659
|
+
},
|
|
4660
|
+
);
|
|
4559
4661
|
process.exit(1);
|
|
4560
4662
|
}
|
|
4561
4663
|
const peerOwner = resolveOwnerByName(name);
|
|
@@ -4722,21 +4824,22 @@ function emitWaitResult(
|
|
|
4722
4824
|
}
|
|
4723
4825
|
|
|
4724
4826
|
function runHeal(opts: {
|
|
4725
|
-
owner
|
|
4726
|
-
kind
|
|
4827
|
+
owner?: string;
|
|
4828
|
+
kind?: string;
|
|
4727
4829
|
sessionId?: string;
|
|
4728
4830
|
adapter?: string;
|
|
4729
4831
|
pid?: string;
|
|
4832
|
+
quarantineTransaction?: string;
|
|
4833
|
+
approvalRecordId?: string;
|
|
4834
|
+
yes?: boolean;
|
|
4730
4835
|
json?: boolean;
|
|
4731
4836
|
}): void {
|
|
4732
4837
|
if (opts.json) emit.config({ format: "json" });
|
|
4733
4838
|
|
|
4734
|
-
const
|
|
4735
|
-
const
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
process.exit(1);
|
|
4739
|
-
}
|
|
4839
|
+
const requestedOwner = opts.owner?.trim() ?? "";
|
|
4840
|
+
const quarantineTransaction = opts.quarantineTransaction?.trim() ?? "";
|
|
4841
|
+
const approvalRecordId = opts.approvalRecordId?.trim() ?? "";
|
|
4842
|
+
const kind = opts.kind?.trim() || "cache";
|
|
4740
4843
|
if (kind !== "pidmap" && kind !== "cache") {
|
|
4741
4844
|
emit.error({
|
|
4742
4845
|
code: "bad_kind",
|
|
@@ -4744,6 +4847,30 @@ function runHeal(opts: {
|
|
|
4744
4847
|
});
|
|
4745
4848
|
process.exit(1);
|
|
4746
4849
|
}
|
|
4850
|
+
if (quarantineTransaction) {
|
|
4851
|
+
if (opts.kind || opts.pid) {
|
|
4852
|
+
emit.error({
|
|
4853
|
+
code: "conflicting_recovery_options",
|
|
4854
|
+
message: "--quarantine-transaction cannot be combined with --kind or --pid",
|
|
4855
|
+
});
|
|
4856
|
+
process.exit(1);
|
|
4857
|
+
}
|
|
4858
|
+
if (!opts.yes || !approvalRecordId) {
|
|
4859
|
+
emit.error({
|
|
4860
|
+
code: "transaction_quarantine_confirmation_required",
|
|
4861
|
+
message:
|
|
4862
|
+
"--quarantine-transaction requires --approval-record-id <id> and --yes; " +
|
|
4863
|
+
"the command abandons one uncommitted authority mutation while preserving its record",
|
|
4864
|
+
});
|
|
4865
|
+
process.exit(1);
|
|
4866
|
+
}
|
|
4867
|
+
} else if (approvalRecordId || opts.yes) {
|
|
4868
|
+
emit.error({
|
|
4869
|
+
code: "transaction_quarantine_target_required",
|
|
4870
|
+
message: "--approval-record-id and --yes require --quarantine-transaction <id>",
|
|
4871
|
+
});
|
|
4872
|
+
process.exit(1);
|
|
4873
|
+
}
|
|
4747
4874
|
if (
|
|
4748
4875
|
opts.adapter &&
|
|
4749
4876
|
opts.adapter !== "claude-code" &&
|
|
@@ -4766,7 +4893,52 @@ function runHeal(opts: {
|
|
|
4766
4893
|
process.exit(1);
|
|
4767
4894
|
}
|
|
4768
4895
|
|
|
4769
|
-
const
|
|
4896
|
+
const currentSessionRepair =
|
|
4897
|
+
kind === "cache" &&
|
|
4898
|
+
opts.owner === undefined &&
|
|
4899
|
+
opts.sessionId === undefined &&
|
|
4900
|
+
opts.adapter === undefined &&
|
|
4901
|
+
!quarantineTransaction;
|
|
4902
|
+
|
|
4903
|
+
const ownerResolution = resolveOwnerWithSource();
|
|
4904
|
+
const bootstrapIdentity = currentSessionRepair ? commandSessionBootstrap() : null;
|
|
4905
|
+
const resolvedCurrentOwner =
|
|
4906
|
+
bootstrapIdentity &&
|
|
4907
|
+
(ownerResolution.source === "none" || ownerResolution.source === "active_singleton")
|
|
4908
|
+
? bootstrapIdentity.sessionId
|
|
4909
|
+
: ownerResolution.owner;
|
|
4910
|
+
const owner = requestedOwner || resolvedCurrentOwner || sessionIdentityFromEnv() || "";
|
|
4911
|
+
if (!owner) {
|
|
4912
|
+
emit.error({
|
|
4913
|
+
code: "session_identity_missing",
|
|
4914
|
+
message:
|
|
4915
|
+
`could not resolve the current session; run ${resolveBinName()} doctor, or pass ` +
|
|
4916
|
+
"--owner <instance-id> --session-id <native-session-id> --adapter <adapter>",
|
|
4917
|
+
});
|
|
4918
|
+
process.exit(1);
|
|
4919
|
+
}
|
|
4920
|
+
|
|
4921
|
+
const currentRow = readLiveCoordinationRow(root, owner);
|
|
4922
|
+
const inferredAdapter = normalizeAdapter(
|
|
4923
|
+
opts.adapter?.trim() || currentRow?.platform || commandSessionBootstrap()?.adapter,
|
|
4924
|
+
);
|
|
4925
|
+
const sessionId =
|
|
4926
|
+
opts.sessionId?.trim() ||
|
|
4927
|
+
(currentSessionRepair ? sessionIdentityFromEnv() : null) ||
|
|
4928
|
+
nativeSessionIdentity(currentRow, owner);
|
|
4929
|
+
|
|
4930
|
+
if (kind === "cache") {
|
|
4931
|
+
const refusal = cacheHealAuthorityRefusal(root, owner, sessionId, inferredAdapter, currentRow);
|
|
4932
|
+
if (refusal) {
|
|
4933
|
+
emitHealFailure(refusal.reason, refusal.message);
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4936
|
+
|
|
4937
|
+
const action = quarantineTransaction
|
|
4938
|
+
? "quarantine-authority-transaction"
|
|
4939
|
+
: kind === "pidmap"
|
|
4940
|
+
? "heal-pidmap"
|
|
4941
|
+
: "repair-coordination-cache";
|
|
4770
4942
|
|
|
4771
4943
|
// Refuse to materialize a V3 cache at a truncated owner id.
|
|
4772
4944
|
//
|
|
@@ -4809,23 +4981,72 @@ function runHeal(opts: {
|
|
|
4809
4981
|
// heal-pidmap <instance_id> [<pid>]
|
|
4810
4982
|
// repair-coordination-cache <instance_id> [<session_id>]
|
|
4811
4983
|
const helperArgs: string[] = [action, owner];
|
|
4812
|
-
if (
|
|
4813
|
-
|
|
4814
|
-
|
|
4984
|
+
if (quarantineTransaction) {
|
|
4985
|
+
helperArgs.push(
|
|
4986
|
+
quarantineTransaction,
|
|
4987
|
+
approvalRecordId,
|
|
4988
|
+
sessionId,
|
|
4989
|
+
`--adapter=${inferredAdapter}`,
|
|
4990
|
+
);
|
|
4991
|
+
} else {
|
|
4992
|
+
if (kind === "pidmap" && opts.pid) helperArgs.push(opts.pid);
|
|
4993
|
+
if (kind === "cache") helperArgs.push(sessionId, `--adapter=${inferredAdapter}`);
|
|
4994
|
+
}
|
|
4815
4995
|
|
|
4816
4996
|
// Both recovery actions are handled by the bundled agent-coord binary.
|
|
4817
4997
|
const helper = agentCoordOrExit(root);
|
|
4818
|
-
|
|
4998
|
+
let proc = spawnSync(helper, helperArgs, {
|
|
4819
4999
|
encoding: "utf8",
|
|
4820
5000
|
...coordHelperOpts(root),
|
|
4821
5001
|
});
|
|
4822
5002
|
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
5003
|
+
let bootstrapState: "created" | "reused" | undefined;
|
|
5004
|
+
if (
|
|
5005
|
+
proc.status !== 0 &&
|
|
5006
|
+
currentSessionRepair &&
|
|
5007
|
+
missingAuthorityForCurrentSessionBootstrap(root, owner, sessionId)
|
|
5008
|
+
) {
|
|
5009
|
+
const bootstrap = commandSessionBootstrap();
|
|
5010
|
+
if (
|
|
5011
|
+
!bootstrap ||
|
|
5012
|
+
bootstrap.sessionId !== sessionId ||
|
|
5013
|
+
bootstrap.sessionId !== owner ||
|
|
5014
|
+
bootstrap.adapter !== inferredAdapter
|
|
5015
|
+
) {
|
|
5016
|
+
emitHealFailure(
|
|
5017
|
+
"native_identity_unverified",
|
|
5018
|
+
"the current adapter did not provide one matching native session id and adapter",
|
|
5019
|
+
);
|
|
5020
|
+
}
|
|
5021
|
+
try {
|
|
5022
|
+
const bootstrapped = bootstrapLiveCoordinationAuthorityV3({
|
|
5023
|
+
coordRoot: root,
|
|
5024
|
+
owner,
|
|
5025
|
+
nativeSessionId: bootstrap.sessionId,
|
|
5026
|
+
adapter: bootstrap.adapter,
|
|
5027
|
+
});
|
|
5028
|
+
bootstrapState = bootstrapped.state;
|
|
5029
|
+
} catch (error) {
|
|
5030
|
+
const reason =
|
|
5031
|
+
error instanceof LiveCoordinationAuthorityV3Error
|
|
5032
|
+
? error.reason
|
|
5033
|
+
: "authority_bootstrap_failed";
|
|
5034
|
+
emitHealFailure(
|
|
5035
|
+
reason,
|
|
5036
|
+
"the current native session could not establish authority; no fallback cache was accepted",
|
|
5037
|
+
);
|
|
5038
|
+
}
|
|
5039
|
+
proc = spawnSync(helper, helperArgs, {
|
|
5040
|
+
encoding: "utf8",
|
|
5041
|
+
...coordHelperOpts(root),
|
|
4827
5042
|
});
|
|
4828
|
-
|
|
5043
|
+
}
|
|
5044
|
+
|
|
5045
|
+
if (proc.status !== 0) {
|
|
5046
|
+
emitHealFailure(
|
|
5047
|
+
healFailureReason(root, owner, sessionId, inferredAdapter),
|
|
5048
|
+
spawnFailureMessage(proc, `agent-coord ${action}`),
|
|
5049
|
+
);
|
|
4829
5050
|
}
|
|
4830
5051
|
|
|
4831
5052
|
// Read the derived cache to surface post-action state.
|
|
@@ -4836,8 +5057,9 @@ function runHeal(opts: {
|
|
|
4836
5057
|
after = null;
|
|
4837
5058
|
}
|
|
4838
5059
|
|
|
4839
|
-
const outcome =
|
|
4840
|
-
|
|
5060
|
+
const outcome = quarantineTransaction
|
|
5061
|
+
? "transaction_quarantined"
|
|
5062
|
+
: kind === "pidmap"
|
|
4841
5063
|
? proc.status === 0
|
|
4842
5064
|
? "ok"
|
|
4843
5065
|
: "failed"
|
|
@@ -4852,10 +5074,15 @@ function runHeal(opts: {
|
|
|
4852
5074
|
action,
|
|
4853
5075
|
outcome,
|
|
4854
5076
|
after,
|
|
5077
|
+
...(quarantineTransaction ? { recovery: JSON.parse(proc.stdout.trim()) as unknown } : {}),
|
|
4855
5078
|
},
|
|
4856
5079
|
],
|
|
4857
5080
|
meta: {
|
|
4858
5081
|
kind,
|
|
5082
|
+
automatic: currentSessionRepair && !quarantineTransaction,
|
|
5083
|
+
authority: "event-ledger-v3",
|
|
5084
|
+
adapter: kind === "cache" ? inferredAdapter : undefined,
|
|
5085
|
+
bootstrap: bootstrapState,
|
|
4859
5086
|
// The path actually spawned, not a guess at the layout: the helper is
|
|
4860
5087
|
// resolved from harnery's own package location, which differs between a
|
|
4861
5088
|
// submodule, an installed dependency, and a standalone checkout.
|
|
@@ -4863,10 +5090,18 @@ function runHeal(opts: {
|
|
|
4863
5090
|
},
|
|
4864
5091
|
});
|
|
4865
5092
|
if (!opts.json) {
|
|
4866
|
-
if (
|
|
5093
|
+
if (quarantineTransaction) {
|
|
5094
|
+
emit.text(
|
|
5095
|
+
`coordination recovered: ${quarantineTransaction} quarantined with approval ${approvalRecordId}; ` +
|
|
5096
|
+
`cache ${after ? "present" : "absent"} (${inferredAdapter})\n`,
|
|
5097
|
+
);
|
|
5098
|
+
} else if (kind === "pidmap") {
|
|
4867
5099
|
emit.text(`agent-coord ${action} ok\n`);
|
|
4868
5100
|
} else {
|
|
4869
|
-
emit.text(
|
|
5101
|
+
emit.text(
|
|
5102
|
+
`coordination repaired: V3 authority live; ${currentSessionRepair ? "current-session " : ""}` +
|
|
5103
|
+
`cache ${after ? "present" : "absent"} (${inferredAdapter})\n`,
|
|
5104
|
+
);
|
|
4870
5105
|
}
|
|
4871
5106
|
}
|
|
4872
5107
|
|
|
@@ -4877,6 +5112,98 @@ function runHeal(opts: {
|
|
|
4877
5112
|
// unconditionally on every `harn agents heal`, which over-counted no-op heals.)
|
|
4878
5113
|
}
|
|
4879
5114
|
|
|
5115
|
+
type HealAuthorityRefusal = {
|
|
5116
|
+
reason: "adapter_mismatch" | "owner_mismatch" | "session_mismatch" | "terminal_generation";
|
|
5117
|
+
message: string;
|
|
5118
|
+
};
|
|
5119
|
+
|
|
5120
|
+
function cacheHealAuthorityRefusal(
|
|
5121
|
+
root: string,
|
|
5122
|
+
owner: string,
|
|
5123
|
+
sessionId: string,
|
|
5124
|
+
adapter: "claude-code" | "cursor" | "codex",
|
|
5125
|
+
currentRow: LiveCoordinationRow | null,
|
|
5126
|
+
): HealAuthorityRefusal | null {
|
|
5127
|
+
if (currentRow && normalizeAdapter(currentRow.platform) !== adapter) {
|
|
5128
|
+
return {
|
|
5129
|
+
reason: "adapter_mismatch",
|
|
5130
|
+
message: `the live generation belongs to adapter ${normalizeAdapter(currentRow.platform)}, not ${adapter}`,
|
|
5131
|
+
};
|
|
5132
|
+
}
|
|
5133
|
+
let producer: ReturnType<typeof readHookProducerStateV3>;
|
|
5134
|
+
try {
|
|
5135
|
+
producer = readHookProducerStateV3(root, adapter, sessionId);
|
|
5136
|
+
} catch {
|
|
5137
|
+
return {
|
|
5138
|
+
reason: "session_mismatch",
|
|
5139
|
+
message: "the native session producer state could not be read safely",
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
5142
|
+
if (producer?.terminal) {
|
|
5143
|
+
return {
|
|
5144
|
+
reason: "terminal_generation",
|
|
5145
|
+
message: "the matching generation is terminal and cannot be repaired or reopened by heal",
|
|
5146
|
+
};
|
|
5147
|
+
}
|
|
5148
|
+
if (producer && producer.instance_id !== liveInstanceIdV3(owner)) {
|
|
5149
|
+
return {
|
|
5150
|
+
reason: "owner_mismatch",
|
|
5151
|
+
message: "the native session is bound to a different instance owner",
|
|
5152
|
+
};
|
|
5153
|
+
}
|
|
5154
|
+
if (currentRow && (!producer || producer.generation_id !== currentRow.v3_generation_id)) {
|
|
5155
|
+
return {
|
|
5156
|
+
reason: "session_mismatch",
|
|
5157
|
+
message: "the native session does not bind to the requested live generation",
|
|
5158
|
+
};
|
|
5159
|
+
}
|
|
5160
|
+
return null;
|
|
5161
|
+
}
|
|
5162
|
+
|
|
5163
|
+
function missingAuthorityForCurrentSessionBootstrap(
|
|
5164
|
+
root: string,
|
|
5165
|
+
owner: string,
|
|
5166
|
+
sessionId: string,
|
|
5167
|
+
): boolean {
|
|
5168
|
+
if (readLiveCoordinationRow(root, owner)) return false;
|
|
5169
|
+
try {
|
|
5170
|
+
const nativeSessionHasProducer = (["claude-code", "codex", "cursor"] as const).some(
|
|
5171
|
+
(adapter) => readHookProducerStateV3(root, adapter, sessionId) !== undefined,
|
|
5172
|
+
);
|
|
5173
|
+
if (nativeSessionHasProducer) return false;
|
|
5174
|
+
const instanceId = liveInstanceIdV3(owner);
|
|
5175
|
+
return !listHookProducerStateRecordsV3(root, { includeTerminal: true }).some(
|
|
5176
|
+
({ state }) => state.instance_id === instanceId,
|
|
5177
|
+
);
|
|
5178
|
+
} catch {
|
|
5179
|
+
return false;
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
|
|
5183
|
+
function healFailureReason(
|
|
5184
|
+
root: string,
|
|
5185
|
+
owner: string,
|
|
5186
|
+
sessionId: string,
|
|
5187
|
+
adapter: "claude-code" | "cursor" | "codex",
|
|
5188
|
+
): string {
|
|
5189
|
+
const refusal = cacheHealAuthorityRefusal(
|
|
5190
|
+
root,
|
|
5191
|
+
owner,
|
|
5192
|
+
sessionId,
|
|
5193
|
+
adapter,
|
|
5194
|
+
readLiveCoordinationRow(root, owner),
|
|
5195
|
+
);
|
|
5196
|
+
return refusal?.reason ?? "authority_missing";
|
|
5197
|
+
}
|
|
5198
|
+
|
|
5199
|
+
function emitHealFailure(reason: string, message: string): never {
|
|
5200
|
+
emit.error({
|
|
5201
|
+
code: "heal_failed",
|
|
5202
|
+
message: `coordination heal refused (reason=${reason}): ${message}`,
|
|
5203
|
+
});
|
|
5204
|
+
process.exit(1);
|
|
5205
|
+
}
|
|
5206
|
+
|
|
4880
5207
|
/**
|
|
4881
5208
|
* Emit one V3 council audit transition keyed to the exact durable manifest.
|
|
4882
5209
|
* Falls through silently when no live session can attest the observation.
|