harnery 0.34.1 → 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 -94
- package/dist/commands/agents.d.ts +37 -6
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +466 -371
- 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 +31 -6
- 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/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +2 -2
- 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/events.d.ts.map +1 -1
- package/dist/commands/events.js +18 -1
- 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/presence.d.ts.map +1 -1
- package/dist/commands/presence.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 +4 -0
- package/dist/commands/semantic.d.ts.map +1 -0
- package/dist/commands/semantic.js +199 -0
- 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 +84 -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/canonical-emit.d.ts +3 -0
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +12 -0
- package/dist/core/agents/claim-path.d.ts +11 -0
- package/dist/core/agents/claim-path.d.ts.map +1 -0
- package/dist/core/agents/claim-path.js +22 -0
- package/dist/core/agents/cli.js +209 -39
- package/dist/core/agents/coord-client.d.ts +29 -3
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +88 -9
- 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 +245 -13
- package/dist/core/agents/live-lifecycle-v3.js +9 -4
- package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
- package/dist/core/agents/live-observation-v3.js +8 -3
- 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 +36 -17
- 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 +115 -22
- 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/session-name-display.d.ts +1 -0
- package/dist/core/agents/session-name-display.d.ts.map +1 -1
- package/dist/core/agents/session-name-display.js +8 -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-reader.d.ts +46 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
- package/dist/core/agents/state/heartbeat-reader.js +25 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts +9 -48
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +34 -34
- package/dist/core/agents/state/live-coordination-view.d.ts +6 -8
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +16 -67
- 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/agents/state/names.d.ts +9 -1
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +190 -182
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +23 -5
- package/dist/core/artifacts/constants.d.ts +5 -0
- package/dist/core/artifacts/constants.d.ts.map +1 -0
- package/dist/core/artifacts/constants.js +4 -0
- package/dist/core/artifacts/index.d.ts +24 -3
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +96 -8
- 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 +851 -16
- package/dist/core/events/v3/base-contract.d.ts.map +1 -1
- package/dist/core/events/v3/base-contract.js +50 -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.d.ts +11 -0
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +26 -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 +8 -5
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +7 -4
- package/dist/core/events/v3/latency.d.ts +31 -1
- package/dist/core/events/v3/latency.d.ts.map +1 -1
- package/dist/core/events/v3/latency.js +127 -3
- 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 +42 -20
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +153 -41
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/command-recorder.js +10 -1
- 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 +90 -13
- 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.d.ts +17 -1
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +83 -2
- package/dist/core/events/v3/producers/intake.d.ts +13 -0
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +36 -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 +117 -1
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +992 -27
- 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 +52 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
- 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 +21 -6
- 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/parse.d.ts +3 -0
- package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.js +14 -0
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts +142 -0
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
- package/dist/core/hooks/adapter/runtime-telemetry.js +869 -0
- package/dist/core/hooks/cli.js +318 -61
- 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 +39 -0
- package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
- package/dist/core/hooks/remediation-cap.js +63 -0
- 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 +33 -9
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +33 -10
- 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 +37 -0
- package/dist/core/semantic/adapters.d.ts.map +1 -0
- package/dist/core/semantic/adapters.js +360 -0
- package/dist/core/semantic/contract.d.ts +1072 -0
- package/dist/core/semantic/contract.d.ts.map +1 -0
- package/dist/core/semantic/contract.js +331 -0
- package/dist/core/semantic/evidence.d.ts +11 -0
- package/dist/core/semantic/evidence.d.ts.map +1 -0
- package/dist/core/semantic/evidence.js +262 -0
- package/dist/core/semantic/index.d.ts +14 -0
- package/dist/core/semantic/index.d.ts.map +1 -0
- package/dist/core/semantic/index.js +13 -0
- package/dist/core/semantic/once.d.ts +38 -0
- package/dist/core/semantic/once.d.ts.map +1 -0
- package/dist/core/semantic/once.js +364 -0
- package/dist/core/semantic/prompt.d.ts +12 -0
- package/dist/core/semantic/prompt.d.ts.map +1 -0
- package/dist/core/semantic/prompt.js +83 -0
- 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 +27 -0
- package/dist/core/semantic/scheduler.d.ts.map +1 -0
- package/dist/core/semantic/scheduler.js +91 -0
- package/dist/core/semantic/service-status.d.ts +51 -0
- package/dist/core/semantic/service-status.d.ts.map +1 -0
- package/dist/core/semantic/service-status.js +140 -0
- package/dist/core/semantic/service.d.ts +52 -0
- package/dist/core/semantic/service.d.ts.map +1 -0
- package/dist/core/semantic/service.js +559 -0
- 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 +81 -0
- package/dist/core/semantic/storage.d.ts.map +1 -0
- package/dist/core/semantic/storage.js +180 -0
- 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 +18 -0
- package/dist/core/semantic/validate.d.ts.map +1 -0
- package/dist/core/semantic/validate.js +207 -0
- 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/browser/client.d.ts +11 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +13 -0
- package/dist/lib/browser/index.d.ts +1 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/standalone-html.d.ts +25 -0
- package/dist/lib/browser/standalone-html.d.ts.map +1 -0
- package/dist/lib/browser/standalone-html.js +284 -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/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +1 -0
- package/dist/lib/instructions/templates.d.ts +2 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +149 -4
- 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 +34 -2
- package/schemas/config.schema.json +58 -0
- package/schemas/event-v3.schema.json +3073 -581
- package/src/commander.ts +462 -93
- package/src/commands/agents.ts +617 -355
- package/src/commands/backup.ts +18 -14
- package/src/commands/browse-session.ts +12 -0
- package/src/commands/browse.ts +31 -9
- package/src/commands/conversations.ts +279 -0
- package/src/commands/decision.ts +8 -2
- package/src/commands/deinit.ts +6 -0
- package/src/commands/docs.ts +25 -6
- package/src/commands/doctor.ts +75 -9
- package/src/commands/events.ts +21 -1
- 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/presence.ts +7 -2
- package/src/commands/read.ts +6 -2
- package/src/commands/semantic.ts +244 -0
- package/src/commands/storage.ts +310 -0
- package/src/commands/tunnel.ts +66 -52
- package/src/commands/web.ts +92 -7
- package/src/commands/work.ts +3 -3
- package/src/commands/workflow.ts +13 -13
- package/src/core/agents/canonical-emit.ts +15 -0
- package/src/core/agents/claim-path.ts +23 -0
- package/src/core/agents/cli.ts +259 -53
- package/src/core/agents/coord-client.ts +92 -8
- package/src/core/agents/live-authority-v3.ts +342 -14
- package/src/core/agents/live-lifecycle-v3.ts +14 -4
- package/src/core/agents/live-observation-v3.ts +13 -3
- package/src/core/agents/render/prompt-context.ts +40 -16
- package/src/core/agents/rules/stop-hook.ts +129 -25
- 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/session-name-display.ts +9 -1
- package/src/core/agents/state/activity-log.ts +7 -2
- package/src/core/agents/state/heartbeat-reader.ts +69 -0
- package/src/core/agents/state/heartbeat-writer.ts +47 -84
- package/src/core/agents/state/live-coordination-view.ts +17 -81
- package/src/core/agents/state/live-coordination-writer.ts +141 -0
- package/src/core/agents/state/names.ts +190 -182
- package/src/core/agents/state/stale-sweep.ts +25 -5
- package/src/core/artifacts/constants.ts +4 -0
- package/src/core/artifacts/index.ts +113 -8
- 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 +56 -7
- package/src/core/events/v3/bootstrap.ts +195 -2
- package/src/core/events/v3/capabilities.ts +37 -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 +26 -2
- package/src/core/events/v3/latency.ts +213 -2
- package/src/core/events/v3/live-route-observer.ts +80 -0
- package/src/core/events/v3/live-routing.ts +182 -45
- package/src/core/events/v3/producers/command-recorder.ts +10 -1
- package/src/core/events/v3/producers/coordination-recorder.ts +112 -15
- package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
- package/src/core/events/v3/producers/hook-base.ts +116 -2
- package/src/core/events/v3/producers/intake.ts +48 -2
- package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
- package/src/core/events/v3/producers/recorder.ts +1403 -30
- 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 +143 -0
- 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 +66 -5
- 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/parse.ts +16 -0
- package/src/core/hooks/adapter/runtime-telemetry.ts +1200 -0
- package/src/core/hooks/cli.ts +342 -64
- package/src/core/hooks/effects/image-capture.ts +4 -1
- package/src/core/hooks/remediation-cap.ts +83 -0
- 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 +55 -11
- 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 +452 -0
- package/src/core/semantic/contract.ts +430 -0
- package/src/core/semantic/evidence.ts +336 -0
- package/src/core/semantic/index.ts +201 -0
- package/src/core/semantic/once.ts +496 -0
- package/src/core/semantic/prompt.ts +96 -0
- package/src/core/semantic/review.ts +803 -0
- package/src/core/semantic/routes.ts +30 -0
- package/src/core/semantic/scheduler.ts +151 -0
- package/src/core/semantic/service-status.ts +212 -0
- package/src/core/semantic/service.ts +681 -0
- package/src/core/semantic/soak.ts +638 -0
- package/src/core/semantic/storage.ts +300 -0
- package/src/core/semantic/usage.ts +272 -0
- package/src/core/semantic/validate.ts +243 -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/browser/client.ts +21 -0
- package/src/lib/browser/index.ts +4 -0
- package/src/lib/browser/standalone-html.ts +312 -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/apply.ts +1 -0
- package/src/lib/instructions/templates.ts +154 -4
- package/src/lib/local-file-url.ts +31 -0
- package/src/lib/web-performance.ts +335 -0
package/dist/commands/agents.js
CHANGED
|
@@ -13,15 +13,16 @@
|
|
|
13
13
|
* harn agents health --since 7d --json
|
|
14
14
|
*/
|
|
15
15
|
import { spawnSync } from "node:child_process";
|
|
16
|
-
import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync,
|
|
17
|
-
import {
|
|
16
|
+
import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
17
|
+
import { tmpdir } from "node:os";
|
|
18
18
|
import { basename, join, resolve } from "node:path";
|
|
19
19
|
import { coordBinPath } from "../core/agents/coord-bin.js";
|
|
20
20
|
import { checkGitFinalization, formatGitFinalizationFailure, readSessionWriteClaims, } from "../core/agents/finalization.js";
|
|
21
|
-
import { emitEventV3, monorepoRoot, normalizeAdapter, resolveOwner, resolveOwnerBySessionEnv, resolveOwnerWithSource, sessionIdentityFromEnv, } from "../core/agents/index.js";
|
|
22
|
-
import { reopenLiveCoordinationGenerationV3 } from "../core/agents/live-authority-v3.js";
|
|
21
|
+
import { emitEventV3, monorepoRoot, nativeSessionIdentity, normalizeAdapter, resolveOwner, resolveOwnerBySessionEnv, resolveOwnerWithSource, sessionIdentityFromEnv, } from "../core/agents/index.js";
|
|
22
|
+
import { bootstrapLiveCoordinationAuthorityV3, LiveCoordinationAuthorityV3Error, reopenLiveCoordinationGenerationV3, } from "../core/agents/live-authority-v3.js";
|
|
23
23
|
import { listSessionFinalizationRequestsV3, observeHostDisappearedV3, reconcileSessionFinalizationV3, requestSessionEndExplicitV3, } from "../core/agents/session-finalizer-v3.js";
|
|
24
|
-
import { SESSION_NAME_DISPLAY_NOTE } from "../core/agents/session-name-display.js";
|
|
24
|
+
import { SESSION_NAME_DISPLAY_NOTE, sessionNameDisplayPending, } from "../core/agents/session-name-display.js";
|
|
25
|
+
import { agentDisplayName } from "../core/agents/state/activity-log.js";
|
|
25
26
|
import { buildLifecycleSuggestedName, buildSuggestedName, readHeartbeat as readHeartbeatCache, } from "../core/agents/state/heartbeat-writer.js";
|
|
26
27
|
import { readLiveCoordinationRow, readLiveCoordinationRows, } from "../core/agents/state/live-coordination-view.js";
|
|
27
28
|
import { foldSessionState, } from "../core/agents/state/session-state.js";
|
|
@@ -29,11 +30,13 @@ import { coordFreshnessSeconds, resolveBinName, sessionFinalizationConfig, } fro
|
|
|
29
30
|
import { readEventV3ControlState } from "../core/events/v3/control.js";
|
|
30
31
|
import { projectCoordinationViewV3 } from "../core/events/v3/coordination-view.js";
|
|
31
32
|
import { liveInstanceIdV3 } from "../core/events/v3/live-routing.js";
|
|
33
|
+
import { countSummarizedSinceV3, listDiagnosticSummariesV3, } from "../core/events/v3/producers/diagnostic-summaries.js";
|
|
32
34
|
import { listHookIntakeGroupsV3, listHookIntakeRecordsV3, } from "../core/events/v3/producers/intake.js";
|
|
33
35
|
import { listHookProducerStateRecordsV3, readHookProducerStateV3, } from "../core/events/v3/producers/recorder.js";
|
|
34
36
|
import { readLedgerV3 } from "../core/events/v3/reader.js";
|
|
35
37
|
import { EVENT_V3_LEDGER_RELATIVE_ROOT } from "../core/events/v3/writer.js";
|
|
36
38
|
import { evaluateRunQualityIfDue } from "../core/guard/index.js";
|
|
39
|
+
import { readRuntimeContextTelemetry, readRuntimeContextUsage, } from "../core/hooks/adapter/runtime-telemetry.js";
|
|
37
40
|
import { readRemoteMachines } from "../core/presence/index.js";
|
|
38
41
|
import { registerContextCommand } from "./context.js";
|
|
39
42
|
function readCurrentCoordinationRow(instanceId) {
|
|
@@ -57,9 +60,8 @@ import { displayName as displayAgentName, ensureIdentity, listIdentities, lookup
|
|
|
57
60
|
function freshnessCutoffSecs() {
|
|
58
61
|
return coordFreshnessSeconds();
|
|
59
62
|
}
|
|
60
|
-
const SUBAGENT_NOTE = "
|
|
61
|
-
"
|
|
62
|
-
"bridge (per-shell marker file at .harnery/shells/<pid>) is out of scope.";
|
|
63
|
+
const SUBAGENT_NOTE = "Native adapter subagents resolve to their own child generation after the hook bridge " +
|
|
64
|
+
"observes delegation. An unbridged subprocess shell still resolves through its parent.";
|
|
63
65
|
/**
|
|
64
66
|
* Spawn options for agent-coord child processes: pin the coord root the
|
|
65
67
|
* command already resolved (git-superproject-aware via `monorepoRoot()`), so
|
|
@@ -122,24 +124,13 @@ function activityOf(hb) {
|
|
|
122
124
|
function taskStateOf(hb) {
|
|
123
125
|
return hb.task_state ?? "active";
|
|
124
126
|
}
|
|
125
|
-
|
|
126
|
-
export function nativeSessionIdentity(row, fallback) {
|
|
127
|
-
if (row?.native_session_id)
|
|
128
|
-
return row.native_session_id;
|
|
129
|
-
// A projection-only row carries the privacy-safe canonical session
|
|
130
|
-
// fingerprint, not the adapter's native session ID needed to join the hook
|
|
131
|
-
// producer. Until a disposable cache exists, the resolved owner is the only
|
|
132
|
-
// native identity available to command surfaces such as `agents status`.
|
|
133
|
-
if (row?.session_id && !/^sid_[a-f0-9]{64}$/.test(row.session_id))
|
|
134
|
-
return row.session_id;
|
|
135
|
-
return fallback;
|
|
136
|
-
}
|
|
127
|
+
export { nativeSessionIdentity };
|
|
137
128
|
function lifecycleLabel(hb) {
|
|
138
129
|
const state = taskStateOf(hb);
|
|
139
130
|
return state === "blocked" && hb.task_state_reason ? `${state}: ${hb.task_state_reason}` : state;
|
|
140
131
|
}
|
|
141
132
|
let emit;
|
|
142
|
-
export function registerAgentsCommand(program, emitParam, programContext) {
|
|
133
|
+
export function registerAgentsCommand(program, emitParam, programContext, binName = resolveBinName()) {
|
|
143
134
|
emit = emitParam;
|
|
144
135
|
const cmd = program
|
|
145
136
|
.command("agents")
|
|
@@ -176,9 +167,9 @@ export function registerAgentsCommand(program, emitParam, programContext) {
|
|
|
176
167
|
cmd
|
|
177
168
|
.command("suggest-name [description...]")
|
|
178
169
|
.description('Reprint a session name ("Agent <you> - <description>") for the operator to set as their ' +
|
|
179
|
-
"adapter tab title. With no arg, derives
|
|
170
|
+
"adapter tab title. With no arg, prefers the exact pending name, then derives from your current task. The primary naming path " +
|
|
180
171
|
"is set-task (it suggests a name on the first focus declaration); reach for this to reprint " +
|
|
181
|
-
"or
|
|
172
|
+
"or to create an explicit pending-display retry with --json. Read-only.")
|
|
182
173
|
.option("--json", "JSON output instead of the bare name")
|
|
183
174
|
.option("--session-id <id>", "Lookup the V3 generation by session_id directly, bypassing the ppid walk.")
|
|
184
175
|
.action((description, opts) => {
|
|
@@ -218,7 +209,7 @@ export function registerAgentsCommand(program, emitParam, programContext) {
|
|
|
218
209
|
.command("set-task <text...>")
|
|
219
210
|
.description("Declare what this agent is currently working on. Visible to peers in the " +
|
|
220
211
|
"per-prompt snapshot. Pass an empty string ('') to clear.")
|
|
221
|
-
.option("--session-id <id>", `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 \`${
|
|
212
|
+
.option("--session-id <id>", `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\`.`)
|
|
222
213
|
.action((text, opts) => {
|
|
223
214
|
runSetTask(text.join(" "), opts);
|
|
224
215
|
});
|
|
@@ -285,7 +276,7 @@ export function registerAgentsCommand(program, emitParam, programContext) {
|
|
|
285
276
|
});
|
|
286
277
|
cmd
|
|
287
278
|
.command("wait <name>")
|
|
288
|
-
.description(`Block until a peer agent releases files (their \`files_touched\` becomes empty, OR they exit). Pair with \`${
|
|
279
|
+
.description(`Block until a peer agent releases files (their \`files_touched\` becomes empty, OR they exit). Pair with \`${binName} agents ping\` to coordinate hand-offs.`)
|
|
289
280
|
.option("--file <path>", "Wait only for these specific paths (repeatable)", collectPath, [])
|
|
290
281
|
.option("--timeout <dur>", "Give up after this duration; suffix s/m/h/d is required (e.g. 30s, 5m, 1h). Default 60m.", "60m")
|
|
291
282
|
.option("--poll-secs <n>", "Poll interval in seconds (default 5)", "5")
|
|
@@ -330,11 +321,10 @@ export function registerAgentsCommand(program, emitParam, programContext) {
|
|
|
330
321
|
});
|
|
331
322
|
cmd
|
|
332
323
|
.command("heal")
|
|
333
|
-
.description("
|
|
334
|
-
"
|
|
335
|
-
"
|
|
336
|
-
.
|
|
337
|
-
.requiredOption("--kind <kind>", "pidmap | cache")
|
|
324
|
+
.description("Repair the current session's disposable coordination cache from V3. " +
|
|
325
|
+
"Use explicit options to target another generation or repair process attribution.")
|
|
326
|
+
.option("--owner <id>", "Target agent's instance_id. Defaults to the current session.")
|
|
327
|
+
.option("--kind <kind>", "pidmap | cache. Defaults to cache.")
|
|
338
328
|
.option("--session-id <id>", "(--kind cache) native session id used to join the authoritative V3 generation.")
|
|
339
329
|
.option("--adapter <id>", "(--kind cache) adapter used to validate the authoritative V3 generation: " +
|
|
340
330
|
"claude-code | cursor | codex.")
|
|
@@ -342,6 +332,9 @@ export function registerAgentsCommand(program, emitParam, programContext) {
|
|
|
342
332
|
"this shell's ppid chain for a claude process. Pass explicitly " +
|
|
343
333
|
"when calling from outside Claude Code's Bash tool tree (e.g. " +
|
|
344
334
|
"from cron or an external script).")
|
|
335
|
+
.option("--quarantine-transaction <id>", "Quarantine one irreconcilable prepared authority transaction after proving its event was never committed.")
|
|
336
|
+
.option("--approval-record-id <id>", "Durable identifier for the operator approval authorizing transaction quarantine.")
|
|
337
|
+
.option("--yes", "Confirm the exact prepared transaction may be quarantined.")
|
|
345
338
|
.option("--json", "JSON envelope output")
|
|
346
339
|
.action((opts) => {
|
|
347
340
|
runHeal(opts);
|
|
@@ -616,13 +609,10 @@ function runIdentityAssume(target, opts) {
|
|
|
616
609
|
process.exit(1);
|
|
617
610
|
}
|
|
618
611
|
if (!opts.sessionId)
|
|
619
|
-
|
|
612
|
+
ensureAdapterSession(root);
|
|
620
613
|
const owner = opts.sessionId ?? resolveOwner();
|
|
621
614
|
if (!owner) {
|
|
622
|
-
emit.error(
|
|
623
|
-
code: "no_pidmap_entry",
|
|
624
|
-
message: "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
625
|
-
});
|
|
615
|
+
emit.error(sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)"));
|
|
626
616
|
process.exit(1);
|
|
627
617
|
}
|
|
628
618
|
try {
|
|
@@ -802,14 +792,11 @@ function runWhoami(opts) {
|
|
|
802
792
|
});
|
|
803
793
|
process.exit(1);
|
|
804
794
|
}
|
|
805
|
-
|
|
795
|
+
ensureAdapterSession(root);
|
|
806
796
|
const resolved = resolveOwnerWithSource();
|
|
807
797
|
const myOwner = resolved.owner;
|
|
808
798
|
if (!myOwner) {
|
|
809
|
-
emit.error(
|
|
810
|
-
code: "no_pidmap_entry",
|
|
811
|
-
message: "not in an agent session; ppid walk found no pid-map entry",
|
|
812
|
-
});
|
|
799
|
+
emit.error(sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"));
|
|
813
800
|
process.exit(1);
|
|
814
801
|
}
|
|
815
802
|
const hb = readLiveCoordinationRow(root, myOwner);
|
|
@@ -1242,49 +1229,88 @@ function cursorEnvSessionId() {
|
|
|
1242
1229
|
return null;
|
|
1243
1230
|
return raw.startsWith("bc-") && raw.length > 3 ? raw.slice(3) : raw;
|
|
1244
1231
|
}
|
|
1245
|
-
function
|
|
1246
|
-
|
|
1232
|
+
function commandSessionBootstrap() {
|
|
1233
|
+
const cursorSessionId = cursorEnvSessionId();
|
|
1234
|
+
if (process.env.CURSOR_AGENT === "1" && cursorSessionId) {
|
|
1235
|
+
return { adapter: "cursor", sessionId: cursorSessionId };
|
|
1236
|
+
}
|
|
1237
|
+
if (process.env.HARNERY_AGENT_COORD_BRIDGE?.trim() === "codex-wsl") {
|
|
1238
|
+
const sessionId = sessionIdentityFromEnv();
|
|
1239
|
+
if (sessionId)
|
|
1240
|
+
return { adapter: "codex", sessionId };
|
|
1241
|
+
}
|
|
1242
|
+
const claudeSessionId = process.env.CLAUDE_CODE_SESSION_ID?.trim();
|
|
1243
|
+
if (claudeSessionId) {
|
|
1244
|
+
return { adapter: "claude-code", sessionId: claudeSessionId };
|
|
1245
|
+
}
|
|
1246
|
+
return null;
|
|
1247
1247
|
}
|
|
1248
|
-
function
|
|
1249
|
-
|
|
1248
|
+
function ensureAdapterSession(root) {
|
|
1249
|
+
const bootstrap = commandSessionBootstrap();
|
|
1250
|
+
if (!bootstrap)
|
|
1251
|
+
return;
|
|
1252
|
+
// Claude Code owns a reliable native SessionStart hook. Its environment is
|
|
1253
|
+
// accepted by the explicit `agents heal` recovery path, but ordinary
|
|
1254
|
+
// identity and status commands must not impersonate that hook. The heal
|
|
1255
|
+
// bootstrap records derived provenance instead.
|
|
1256
|
+
if (bootstrap.adapter === "claude-code")
|
|
1250
1257
|
return;
|
|
1251
1258
|
// Explicit owner override means the caller already knows who they are.
|
|
1252
1259
|
// Bootstrapping sessionStart inherits that env into the child hook, which
|
|
1253
1260
|
// re-projects a fresh heartbeat onto the override owner and can wipe an
|
|
1254
1261
|
// assumed persona agent_id (seen under Cursor integration fixtures).
|
|
1255
|
-
if (process.env.HARNERY_AGENT_COORD_OWNER?.trim())
|
|
1262
|
+
if (bootstrap.adapter === "cursor" && process.env.HARNERY_AGENT_COORD_OWNER?.trim())
|
|
1256
1263
|
return;
|
|
1257
1264
|
if (resolveOwnerBySessionEnv(root))
|
|
1258
1265
|
return;
|
|
1259
|
-
const sessionId = cursorEnvSessionId();
|
|
1260
|
-
if (!sessionId)
|
|
1261
|
-
return;
|
|
1262
1266
|
const agentHook = coordBinPath("agent-hook", root);
|
|
1263
1267
|
if (!agentHook)
|
|
1264
1268
|
return;
|
|
1265
1269
|
const payload = JSON.stringify({
|
|
1266
|
-
conversation_id: sessionId,
|
|
1267
|
-
session_id: sessionId,
|
|
1270
|
+
...(bootstrap.adapter === "cursor" ? { conversation_id: bootstrap.sessionId } : {}),
|
|
1271
|
+
session_id: bootstrap.sessionId,
|
|
1268
1272
|
hook_event_name: "sessionStart",
|
|
1269
1273
|
workspace_roots: [root],
|
|
1270
1274
|
cwd: root,
|
|
1271
|
-
|
|
1272
|
-
|
|
1275
|
+
...(bootstrap.adapter === "cursor"
|
|
1276
|
+
? { composer_mode: "agent", is_background_agent: false }
|
|
1277
|
+
: { source: "resume" }),
|
|
1273
1278
|
});
|
|
1274
|
-
spawnSync("bash", [agentHook, "session-start", "--adapter",
|
|
1279
|
+
spawnSync("bash", [agentHook, "session-start", "--adapter", bootstrap.adapter], {
|
|
1275
1280
|
input: payload,
|
|
1276
1281
|
cwd: root,
|
|
1277
1282
|
encoding: "utf8",
|
|
1278
1283
|
timeout: 3000,
|
|
1279
1284
|
env: {
|
|
1280
1285
|
...process.env,
|
|
1281
|
-
HARNERY_AGENT_COORD_PLATFORM:
|
|
1286
|
+
HARNERY_AGENT_COORD_PLATFORM: bootstrap.adapter,
|
|
1282
1287
|
HARNERY_COORD_ROOT_OVERRIDE: root,
|
|
1283
|
-
|
|
1284
|
-
|
|
1288
|
+
HARNERY_AGENT_COORD_SESSION_ID: bootstrap.sessionId,
|
|
1289
|
+
...(bootstrap.adapter === "cursor"
|
|
1290
|
+
? {
|
|
1291
|
+
CURSOR_SESSION_ID: bootstrap.sessionId,
|
|
1292
|
+
CURSOR_CONVERSATION_ID: bootstrap.sessionId,
|
|
1293
|
+
}
|
|
1294
|
+
: { CODEX_THREAD_ID: bootstrap.sessionId }),
|
|
1285
1295
|
},
|
|
1286
1296
|
});
|
|
1287
1297
|
}
|
|
1298
|
+
function sessionResolutionFailure(root, fallbackMessage) {
|
|
1299
|
+
if (!sessionIdentityFromEnv())
|
|
1300
|
+
return { code: "no_pidmap_entry", message: fallbackMessage };
|
|
1301
|
+
const control = readEventV3ControlState(root);
|
|
1302
|
+
if (control.state !== "candidate" && control.state !== "active") {
|
|
1303
|
+
const detail = `${control.state}:${control.reason}`;
|
|
1304
|
+
return {
|
|
1305
|
+
code: "event_v3_control_unavailable",
|
|
1306
|
+
message: `the adapter session identity is present, but the V3 control state cannot accept session onboarding (${detail})`,
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
return {
|
|
1310
|
+
code: "session_generation_unavailable",
|
|
1311
|
+
message: "the adapter session identity is present, but no current V3 session generation was available after onboarding",
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1288
1314
|
function runReleaseClaim(path) {
|
|
1289
1315
|
const root = monorepoRoot();
|
|
1290
1316
|
if (!root) {
|
|
@@ -1296,10 +1322,7 @@ function runReleaseClaim(path) {
|
|
|
1296
1322
|
}
|
|
1297
1323
|
const myOwner = resolveOwner();
|
|
1298
1324
|
if (!myOwner) {
|
|
1299
|
-
emit.error(
|
|
1300
|
-
code: "no_pidmap_entry",
|
|
1301
|
-
message: "not in an agent session; ppid walk found no pid-map entry",
|
|
1302
|
-
});
|
|
1325
|
+
emit.error(sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"));
|
|
1303
1326
|
process.exit(1);
|
|
1304
1327
|
}
|
|
1305
1328
|
// Canonicalize: absolute paths under coordRoot get the prefix stripped;
|
|
@@ -1340,13 +1363,10 @@ function runSetTask(task, opts) {
|
|
|
1340
1363
|
// ritual command. The env id carries the same trust as an explicit
|
|
1341
1364
|
// --session-id, and set-task mints the heartbeat exactly as that path does.
|
|
1342
1365
|
if (!opts?.sessionId)
|
|
1343
|
-
|
|
1366
|
+
ensureAdapterSession(root);
|
|
1344
1367
|
const myOwner = opts?.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
|
|
1345
1368
|
if (!myOwner) {
|
|
1346
|
-
emit.error(
|
|
1347
|
-
code: "no_pidmap_entry",
|
|
1348
|
-
message: "not in an agent session; no session-id environment identity and the ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
1349
|
-
});
|
|
1369
|
+
emit.error(sessionResolutionFailure(root, "not in an agent session; no session-id environment identity and the ppid walk found no pid-map entry (pass --session-id to bypass)"));
|
|
1350
1370
|
process.exit(1);
|
|
1351
1371
|
}
|
|
1352
1372
|
// Snapshot BEFORE the mutation: the writer stamps `suggested_session_name`
|
|
@@ -1378,24 +1398,17 @@ function runSetTask(task, opts) {
|
|
|
1378
1398
|
// the first time. `first_of_session: true` means exactly "this call produced
|
|
1379
1399
|
// the session name" — it is never true with a null name (an empty first
|
|
1380
1400
|
// declaration or a `--session-id` relay both keep the window open instead).
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
//
|
|
1387
|
-
//
|
|
1388
|
-
//
|
|
1389
|
-
|
|
1390
|
-
const retriedSuggestedName = !firstSuggestedName &&
|
|
1391
|
-
priorHb?.suggested_session_name &&
|
|
1392
|
-
priorHb.session_name_seen_for !== priorHb.suggested_session_name &&
|
|
1393
|
-
hb?.suggested_session_name === priorHb.suggested_session_name
|
|
1394
|
-
? hb.suggested_session_name
|
|
1395
|
-
: null;
|
|
1396
|
-
const suggestedName = firstSuggestedName ?? retriedSuggestedName;
|
|
1401
|
+
// A native generation restart may rebuild the current cache during the
|
|
1402
|
+
// mutation and carry an already-seen suggestion from the prior generation.
|
|
1403
|
+
// That title is continuity evidence, not a new display request.
|
|
1404
|
+
const pendingName = sessionNameDisplayPending(hb);
|
|
1405
|
+
const firstSuggestedName = !priorHb?.suggested_session_name && pendingName ? pendingName : null;
|
|
1406
|
+
// Routine focus declarations stay title-silent. A pending display no longer
|
|
1407
|
+
// turns every repeated set-task into a fresh name instruction; explicit
|
|
1408
|
+
// recovery belongs to `agents suggest-name --json`.
|
|
1409
|
+
const suggestedName = firstSuggestedName;
|
|
1397
1410
|
const firstOfSession = firstSuggestedName !== null;
|
|
1398
|
-
const sessionNameRetry =
|
|
1411
|
+
const sessionNameRetry = false;
|
|
1399
1412
|
emit.data({
|
|
1400
1413
|
instance_id: myOwner,
|
|
1401
1414
|
name: hb?.name ?? null,
|
|
@@ -1434,13 +1447,10 @@ function runLifecycle(rawState, opts) {
|
|
|
1434
1447
|
return;
|
|
1435
1448
|
}
|
|
1436
1449
|
if (!opts.sessionId)
|
|
1437
|
-
|
|
1450
|
+
ensureAdapterSession(root);
|
|
1438
1451
|
const myOwner = opts.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
|
|
1439
1452
|
if (!myOwner) {
|
|
1440
|
-
emit.error(
|
|
1441
|
-
code: "no_pidmap_entry",
|
|
1442
|
-
message: "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
1443
|
-
});
|
|
1453
|
+
emit.error(sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)"));
|
|
1444
1454
|
process.exitCode = 1;
|
|
1445
1455
|
return;
|
|
1446
1456
|
}
|
|
@@ -1599,23 +1609,23 @@ function runSuggestName(descriptionParts, opts) {
|
|
|
1599
1609
|
// Identity: prefer explicit --session-id (ppid-walk-free escape hatch, mirrors
|
|
1600
1610
|
// `status`/`set-task`), fall back to the ppid walk for interactive shell use.
|
|
1601
1611
|
if (!opts.sessionId)
|
|
1602
|
-
|
|
1612
|
+
ensureAdapterSession(root);
|
|
1603
1613
|
const myOwner = opts.sessionId ?? resolveOwner();
|
|
1604
1614
|
if (!myOwner) {
|
|
1605
|
-
emit.error(
|
|
1606
|
-
code: "no_pidmap_entry",
|
|
1607
|
-
message: "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
|
|
1608
|
-
});
|
|
1615
|
+
emit.error(sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)"));
|
|
1609
1616
|
process.exit(1);
|
|
1610
1617
|
}
|
|
1611
1618
|
const hb = readCurrentCoordinationRow(myOwner);
|
|
1612
1619
|
const agentName = hb?.name || "unknown";
|
|
1613
|
-
//
|
|
1614
|
-
//
|
|
1615
|
-
//
|
|
1616
|
-
//
|
|
1620
|
+
// A bare suggest-name must prefer the exact pending suggestion over rebuilding
|
|
1621
|
+
// from the current task. The task may have changed since the title was minted;
|
|
1622
|
+
// reconstructing it would produce a block the display latch can never accept.
|
|
1623
|
+
// An explicit description keeps the read-only re-suggest behavior.
|
|
1624
|
+
const pendingName = sessionNameDisplayPending(hb);
|
|
1617
1625
|
const parts = descriptionParts.length > 0 ? descriptionParts : hb?.task ? [hb.task] : [];
|
|
1618
|
-
const built =
|
|
1626
|
+
const built = descriptionParts.length === 0 && pendingName
|
|
1627
|
+
? { suggestedName: pendingName, description: hb?.task ?? pendingName }
|
|
1628
|
+
: buildSuggestedName(agentName, parts);
|
|
1619
1629
|
if (!built) {
|
|
1620
1630
|
emit.error({
|
|
1621
1631
|
code: "no_description",
|
|
@@ -1630,6 +1640,7 @@ function runSuggestName(descriptionParts, opts) {
|
|
|
1630
1640
|
emit.data({
|
|
1631
1641
|
name: displayName,
|
|
1632
1642
|
suggested_session_name: suggestedName,
|
|
1643
|
+
session_name_retry: pendingName === suggestedName,
|
|
1633
1644
|
agent_name: agentName,
|
|
1634
1645
|
description,
|
|
1635
1646
|
});
|
|
@@ -1662,13 +1673,10 @@ function runStatus(opts) {
|
|
|
1662
1673
|
// Identity resolution: prefer explicit --session-id (hook-friendly), fall
|
|
1663
1674
|
// back to ppid walk for interactive shell usage.
|
|
1664
1675
|
if (!opts.sessionId)
|
|
1665
|
-
|
|
1676
|
+
ensureAdapterSession(root);
|
|
1666
1677
|
const myOwner = opts.sessionId ?? resolveOwner();
|
|
1667
1678
|
if (!myOwner) {
|
|
1668
|
-
emit.error(
|
|
1669
|
-
code: "no_pidmap_entry",
|
|
1670
|
-
message: "not in an agent session; ppid walk found no pid-map entry (pass --session-id from a hook payload)",
|
|
1671
|
-
});
|
|
1679
|
+
emit.error(sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry (pass --session-id from a hook payload)"));
|
|
1672
1680
|
process.exit(1);
|
|
1673
1681
|
}
|
|
1674
1682
|
const hb = readCurrentCoordinationRow(myOwner);
|
|
@@ -1699,7 +1707,7 @@ function runStatus(opts) {
|
|
|
1699
1707
|
return;
|
|
1700
1708
|
}
|
|
1701
1709
|
}
|
|
1702
|
-
emitEventV3({
|
|
1710
|
+
const statusEmitted = emitEventV3({
|
|
1703
1711
|
owner: myOwner,
|
|
1704
1712
|
session: nativeSessionIdentity(hb, myOwner),
|
|
1705
1713
|
adapter: normalizeAdapter(hb.platform),
|
|
@@ -1708,6 +1716,16 @@ function runStatus(opts) {
|
|
|
1708
1716
|
status: opts.endTurn ? "end_turn_checked" : opts.json ? "json_checked" : "box_checked",
|
|
1709
1717
|
},
|
|
1710
1718
|
});
|
|
1719
|
+
// The closing box is a success artifact. Never print it when the exact
|
|
1720
|
+
// evidence enforced by the Stop hook did not reach the ledger.
|
|
1721
|
+
if (opts.endTurn && !statusEmitted) {
|
|
1722
|
+
emit.error({
|
|
1723
|
+
code: "status_event_failed",
|
|
1724
|
+
message: `the end-of-turn status event could not be recorded; no status box was issued; rerun \`${resolveBinName(root)} agents status --end-turn\``,
|
|
1725
|
+
});
|
|
1726
|
+
process.exitCode = 1;
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1711
1729
|
let sessionEnd;
|
|
1712
1730
|
if (opts.endSession) {
|
|
1713
1731
|
const canonicalInstanceId = liveInstanceIdV3(hb.instance_id);
|
|
@@ -1767,16 +1785,13 @@ function runStatus(opts) {
|
|
|
1767
1785
|
ctxStr = "unavailable";
|
|
1768
1786
|
}
|
|
1769
1787
|
else if (ctxUsage.percentOnly) {
|
|
1770
|
-
|
|
1771
|
-
// window. Show the percent + window estimate, marked as estimated.
|
|
1772
|
-
const pct = Math.round((ctxUsage.used / ctxUsage.window) * 100);
|
|
1773
|
-
ctxStr = `~${pct}% (Cursor; ${fmtTokens(ctxUsage.window)} window est.)`;
|
|
1788
|
+
ctxStr = `${Math.round(ctxUsage.usedPercent)}% (Cursor first-party)`;
|
|
1774
1789
|
}
|
|
1775
1790
|
else {
|
|
1776
1791
|
ctxStr = `${fmtTokens(ctxUsage.used)} / ${fmtTokens(ctxUsage.window)} (${Math.round((ctxUsage.used / ctxUsage.window) * 100)}%)`;
|
|
1777
1792
|
}
|
|
1778
1793
|
const timeStr = formatLocalTime(new Date());
|
|
1779
|
-
const displayName =
|
|
1794
|
+
const displayName = agentDisplayName(hb.instance_id, hb.name);
|
|
1780
1795
|
// Council pending: list of council IDs where this agent is a member of an
|
|
1781
1796
|
// active council in `open` round_status without a contribution to that round.
|
|
1782
1797
|
// Best-effort: fails silently if .harnery/councils/ doesn't exist.
|
|
@@ -1819,8 +1834,8 @@ function runStatus(opts) {
|
|
|
1819
1834
|
})),
|
|
1820
1835
|
})),
|
|
1821
1836
|
pending_councils: pendingCouncils,
|
|
1822
|
-
context_used: ctxUsage
|
|
1823
|
-
context_window: ctxUsage
|
|
1837
|
+
context_used: ctxUsage && "used" in ctxUsage ? ctxUsage.used : null,
|
|
1838
|
+
context_window: ctxUsage && "window" in ctxUsage ? ctxUsage.window : null,
|
|
1824
1839
|
timestamp_iso: new Date().toISOString(),
|
|
1825
1840
|
timestamp_local: timeStr,
|
|
1826
1841
|
...(quality ? { quality } : {}),
|
|
@@ -1938,15 +1953,15 @@ function formatPeers(peers, cap, staleCount, remoteMachines = []) {
|
|
|
1938
1953
|
}
|
|
1939
1954
|
return main;
|
|
1940
1955
|
}
|
|
1941
|
-
export function collectStatusPeerHealth(root, myOwner, nowMs = Date.now()) {
|
|
1956
|
+
export function collectStatusPeerHealth(root, myOwner, nowMs = Date.now(), readRows = readLiveCoordinationRows, freshnessSeconds = freshnessCutoffSecs()) {
|
|
1942
1957
|
let rows = [];
|
|
1943
1958
|
try {
|
|
1944
|
-
rows =
|
|
1959
|
+
rows = readRows(root);
|
|
1945
1960
|
}
|
|
1946
1961
|
catch {
|
|
1947
1962
|
// V3 authority failures must not resurrect disposable cache rows.
|
|
1948
1963
|
}
|
|
1949
|
-
const cutoffMs = nowMs -
|
|
1964
|
+
const cutoffMs = nowMs - freshnessSeconds * 1000;
|
|
1950
1965
|
const livePeers = [];
|
|
1951
1966
|
let stale = 0;
|
|
1952
1967
|
for (const peer of rows) {
|
|
@@ -1974,216 +1989,21 @@ function readContextUsage(sessionId, platform) {
|
|
|
1974
1989
|
// Dispatch by platform: Codex's JSONL shape is different from Claude Code's
|
|
1975
1990
|
// (event_msg/response_item vs user/assistant), and Codex transcripts live
|
|
1976
1991
|
// under ~/.codex/sessions/YYYY/MM/DD/ rather than ~/.claude/projects/.
|
|
1977
|
-
// Cursor
|
|
1978
|
-
//
|
|
1979
|
-
// readCursorContextUsage reads that via bun:sqlite (percent-only).
|
|
1992
|
+
// Cursor stores a first-party percentage in workspaceStorage. The shared
|
|
1993
|
+
// runtime reader returns it without fabricating a token denominator.
|
|
1980
1994
|
if (platform === "codex")
|
|
1981
|
-
return
|
|
1982
|
-
if (platform === "cursor")
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
// for parent chats).
|
|
1992
|
-
//
|
|
1993
|
-
// Roots searched: ~/.config/Cursor/User/workspaceStorage (Linux native install)
|
|
1994
|
-
// and /mnt/c/Users/*/AppData/Roaming/Cursor/User/workspaceStorage (WSL).
|
|
1995
|
-
// We don't filter by workspace path; we scan every workspace's state.vscdb
|
|
1996
|
-
// looking for a composerId match. Cheap enough at status time (~60K per file,
|
|
1997
|
-
// <10ms typical). When a match is found, returns synthetic { used, window }
|
|
1998
|
-
// pair where the percent is what's real; absolutes are derived as
|
|
1999
|
-
// (window * percent / 100). Window hard-coded to a Cursor-typical 200K.
|
|
2000
|
-
const roots = [];
|
|
2001
|
-
const linuxRoot = resolve(homedir(), ".config", "Cursor", "User", "workspaceStorage");
|
|
2002
|
-
if (existsSync(linuxRoot))
|
|
2003
|
-
roots.push(linuxRoot);
|
|
2004
|
-
try {
|
|
2005
|
-
if (existsSync("/mnt/c/Users")) {
|
|
2006
|
-
for (const u of readdirSync("/mnt/c/Users")) {
|
|
2007
|
-
const p = `/mnt/c/Users/${u}/AppData/Roaming/Cursor/User/workspaceStorage`;
|
|
2008
|
-
if (existsSync(p))
|
|
2009
|
-
roots.push(p);
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
catch {
|
|
2014
|
-
// ignore
|
|
2015
|
-
}
|
|
2016
|
-
for (const root of roots) {
|
|
2017
|
-
let workspaces;
|
|
2018
|
-
try {
|
|
2019
|
-
workspaces = readdirSync(root);
|
|
2020
|
-
}
|
|
2021
|
-
catch {
|
|
2022
|
-
continue;
|
|
2023
|
-
}
|
|
2024
|
-
for (const ws of workspaces) {
|
|
2025
|
-
const dbPath = `${root}/${ws}/state.vscdb`;
|
|
2026
|
-
if (!existsSync(dbPath))
|
|
2027
|
-
continue;
|
|
2028
|
-
try {
|
|
2029
|
-
// Lazy-import bun:sqlite so non-Bun runtimes (if any) don't choke at load.
|
|
2030
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
2031
|
-
const { Database } = require("bun:sqlite");
|
|
2032
|
-
const db = new Database(dbPath, { readonly: true });
|
|
2033
|
-
const row = db
|
|
2034
|
-
.query("SELECT value FROM ItemTable WHERE key = 'composer.composerData'")
|
|
2035
|
-
.get();
|
|
2036
|
-
db.close();
|
|
2037
|
-
if (!row?.value)
|
|
2038
|
-
continue;
|
|
2039
|
-
const text = typeof row.value === "string" ? row.value : Buffer.from(row.value).toString("utf8");
|
|
2040
|
-
const parsed = JSON.parse(text);
|
|
2041
|
-
const composers = Array.isArray(parsed?.allComposers) ? parsed.allComposers : [];
|
|
2042
|
-
for (const c of composers) {
|
|
2043
|
-
if (c?.composerId === sessionId && typeof c?.contextUsagePercent === "number") {
|
|
2044
|
-
const window = 200000; // hard-coded Cursor-typical window; refine when Cursor exposes the actual ceiling
|
|
2045
|
-
const used = Math.round((window * c.contextUsagePercent) / 100);
|
|
2046
|
-
return { used, window, percentOnly: true };
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
}
|
|
2050
|
-
catch {
|
|
2051
|
-
// ignore: DB locked, schema drift, etc. Move on to the next workspace.
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
return null;
|
|
2056
|
-
}
|
|
2057
|
-
function readClaudeContextUsage(sessionId) {
|
|
2058
|
-
const root = monorepoRoot();
|
|
2059
|
-
if (!root)
|
|
2060
|
-
return null;
|
|
2061
|
-
// Claude Code's project dir scheme: prepend "-", replace "/" → "-".
|
|
2062
|
-
const encoded = `-${root.replace(/^\//, "").replace(/\//g, "-")}`;
|
|
2063
|
-
const transcriptPath = resolve(homedir(), ".claude", "projects", encoded, `${sessionId}.jsonl`);
|
|
2064
|
-
if (!existsSync(transcriptPath))
|
|
2065
|
-
return null;
|
|
2066
|
-
let raw;
|
|
2067
|
-
try {
|
|
2068
|
-
raw = readFileSync(transcriptPath, "utf8");
|
|
2069
|
-
}
|
|
2070
|
-
catch {
|
|
2071
|
-
return null;
|
|
2072
|
-
}
|
|
2073
|
-
const lines = raw.split("\n");
|
|
2074
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2075
|
-
const line = lines[i].trim();
|
|
2076
|
-
if (!line)
|
|
2077
|
-
continue;
|
|
2078
|
-
try {
|
|
2079
|
-
const entry = JSON.parse(line);
|
|
2080
|
-
const usage = entry?.message?.usage;
|
|
2081
|
-
if (entry?.type === "assistant" && usage) {
|
|
2082
|
-
const used = (usage.input_tokens ?? 0) +
|
|
2083
|
-
(usage.cache_creation_input_tokens ?? 0) +
|
|
2084
|
-
(usage.cache_read_input_tokens ?? 0);
|
|
2085
|
-
// Window: hardcode 1M for Opus 4.7 1M (current default). Refine to
|
|
2086
|
-
// model-aware lookup when other models become routine.
|
|
2087
|
-
return { used, window: 1000000 };
|
|
2088
|
-
}
|
|
2089
|
-
}
|
|
2090
|
-
catch {
|
|
2091
|
-
// skip malformed line
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
return null;
|
|
2095
|
-
}
|
|
2096
|
-
function readCodexContextUsage(sessionId) {
|
|
2097
|
-
// Codex transcripts: ~/.codex/sessions/YYYY/MM/DD/rollout-<TS>-<sessionId>.jsonl
|
|
2098
|
-
// On WSL the active install often lives on the Windows side under
|
|
2099
|
-
// /mnt/c/Users/<user>/.codex/sessions/; both are searched.
|
|
2100
|
-
const path = findCodexTranscript(sessionId);
|
|
2101
|
-
if (!path)
|
|
2102
|
-
return null;
|
|
2103
|
-
let raw;
|
|
2104
|
-
try {
|
|
2105
|
-
raw = readFileSync(path, "utf8");
|
|
2106
|
-
}
|
|
2107
|
-
catch {
|
|
2108
|
-
return null;
|
|
2109
|
-
}
|
|
2110
|
-
const lines = raw.split("\n");
|
|
2111
|
-
// Walk backwards: most recent token_count event wins.
|
|
2112
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2113
|
-
const line = lines[i].trim();
|
|
2114
|
-
if (!line)
|
|
2115
|
-
continue;
|
|
2116
|
-
try {
|
|
2117
|
-
const entry = JSON.parse(line);
|
|
2118
|
-
if (entry?.type === "event_msg" && entry?.payload?.type === "token_count") {
|
|
2119
|
-
const info = entry.payload.info;
|
|
2120
|
-
const used = info?.last_token_usage?.input_tokens;
|
|
2121
|
-
const window = info?.model_context_window;
|
|
2122
|
-
if (typeof used === "number" && typeof window === "number" && window > 0) {
|
|
2123
|
-
return { used, window };
|
|
2124
|
-
}
|
|
2125
|
-
}
|
|
2126
|
-
}
|
|
2127
|
-
catch {
|
|
2128
|
-
// skip malformed line
|
|
2129
|
-
}
|
|
2130
|
-
}
|
|
2131
|
-
return null;
|
|
2132
|
-
}
|
|
2133
|
-
function findCodexTranscript(sessionId) {
|
|
2134
|
-
// Candidate roots in priority order.
|
|
2135
|
-
const homeRoot = resolve(homedir(), ".codex", "sessions");
|
|
2136
|
-
const wslRoots = [];
|
|
2137
|
-
try {
|
|
2138
|
-
if (existsSync("/mnt/c/Users")) {
|
|
2139
|
-
for (const entry of readdirSync("/mnt/c/Users")) {
|
|
2140
|
-
wslRoots.push(`/mnt/c/Users/${entry}/.codex/sessions`);
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
catch {
|
|
2145
|
-
// ignore
|
|
2146
|
-
}
|
|
2147
|
-
const roots = [homeRoot, ...wslRoots];
|
|
2148
|
-
const suffix = `-${sessionId}.jsonl`;
|
|
2149
|
-
for (const root of roots) {
|
|
2150
|
-
if (!existsSync(root))
|
|
2151
|
-
continue;
|
|
2152
|
-
try {
|
|
2153
|
-
// Recursive scan: sessions are partitioned by YYYY/MM/DD/, so depth
|
|
2154
|
-
// is bounded at 3 + one file per session. Cheap enough at status time.
|
|
2155
|
-
const stack = [root];
|
|
2156
|
-
while (stack.length) {
|
|
2157
|
-
const dir = stack.pop();
|
|
2158
|
-
let entries;
|
|
2159
|
-
try {
|
|
2160
|
-
entries = readdirSync(dir);
|
|
2161
|
-
}
|
|
2162
|
-
catch {
|
|
2163
|
-
continue;
|
|
2164
|
-
}
|
|
2165
|
-
for (const name of entries) {
|
|
2166
|
-
const full = `${dir}/${name}`;
|
|
2167
|
-
try {
|
|
2168
|
-
const stat = statSync(full);
|
|
2169
|
-
if (stat.isDirectory()) {
|
|
2170
|
-
stack.push(full);
|
|
2171
|
-
}
|
|
2172
|
-
else if (name.endsWith(suffix)) {
|
|
2173
|
-
return full;
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
catch {
|
|
2177
|
-
// ignore
|
|
2178
|
-
}
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
}
|
|
2182
|
-
catch {
|
|
2183
|
-
// ignore root scan failures
|
|
2184
|
-
}
|
|
1995
|
+
return readRuntimeContextUsage("codex", sessionId);
|
|
1996
|
+
if (platform === "cursor") {
|
|
1997
|
+
const telemetry = readRuntimeContextTelemetry({
|
|
1998
|
+
adapter: "cursor",
|
|
1999
|
+
session_id: sessionId,
|
|
2000
|
+
mode: "status",
|
|
2001
|
+
});
|
|
2002
|
+
return telemetry.state === "observed" && "used_percent" in telemetry
|
|
2003
|
+
? { usedPercent: telemetry.used_percent, percentOnly: true }
|
|
2004
|
+
: null;
|
|
2185
2005
|
}
|
|
2186
|
-
return
|
|
2006
|
+
return readRuntimeContextUsage("claude-code", sessionId);
|
|
2187
2007
|
}
|
|
2188
2008
|
function formatLocalTime(d) {
|
|
2189
2009
|
// "Sat, May 9, 2026, 3:48 AM CDT", rendered in the Chicago timezone.
|
|
@@ -2620,6 +2440,47 @@ export function collectEventLedgerHealthV3(root, nowMs = Date.now()) {
|
|
|
2620
2440
|
catch (error) {
|
|
2621
2441
|
collectionErrors.push(`diagnostics spool unreadable: ${errorText(error)}`);
|
|
2622
2442
|
}
|
|
2443
|
+
// 4b) Coalesced diagnostic summaries: occurrences the producer bounded into
|
|
2444
|
+
// `diagnostic-summaries/` instead of loose files. Counted into the logical
|
|
2445
|
+
// totals so mitigation can never make an active fault look healthy; the
|
|
2446
|
+
// physical loose file count stays visible separately.
|
|
2447
|
+
let summarizedTotal = 0;
|
|
2448
|
+
let summaryFiles = 0;
|
|
2449
|
+
let mitigationFailOpen = 0;
|
|
2450
|
+
try {
|
|
2451
|
+
const listing = listDiagnosticSummariesV3(root);
|
|
2452
|
+
summaryFiles = listing.file_count;
|
|
2453
|
+
mitigationFailOpen = listing.mitigation_health?.fail_open_count ?? 0;
|
|
2454
|
+
if (listing.unreadable_count > 0) {
|
|
2455
|
+
collectionErrors.push(`${listing.unreadable_count} diagnostic summary file(s) unreadable`);
|
|
2456
|
+
}
|
|
2457
|
+
const dayAgoMs = nowMs - 24 * 60 * 60 * 1000;
|
|
2458
|
+
const hourAgoMs = nowMs - 60 * 60 * 1000;
|
|
2459
|
+
for (const summary of listing.summaries) {
|
|
2460
|
+
summarizedTotal += summary.summarized_count;
|
|
2461
|
+
const entry = byCategory[summary.category] ?? { total: 0, last_24h: 0 };
|
|
2462
|
+
const recent = recentByCategory[summary.category] ?? { last_1h: 0, latest_at: null };
|
|
2463
|
+
byCategory[summary.category] = entry;
|
|
2464
|
+
recentByCategory[summary.category] = recent;
|
|
2465
|
+
entry.total += summary.summarized_count;
|
|
2466
|
+
const day = countSummarizedSinceV3([summary], dayAgoMs, undefined, nowMs);
|
|
2467
|
+
const hour = countSummarizedSinceV3([summary], hourAgoMs, undefined, nowMs);
|
|
2468
|
+
entry.last_24h += day;
|
|
2469
|
+
diagnostics24h += day;
|
|
2470
|
+
recent.last_1h += hour;
|
|
2471
|
+
diagnostics1h += hour;
|
|
2472
|
+
const lastMs = summary.last_summarized_at ? Date.parse(summary.last_summarized_at) : NaN;
|
|
2473
|
+
if (Number.isFinite(lastMs)) {
|
|
2474
|
+
latestDiagnosticMs = Math.max(latestDiagnosticMs, lastMs);
|
|
2475
|
+
if (!recent.latest_at || lastMs > Date.parse(recent.latest_at)) {
|
|
2476
|
+
recent.latest_at = new Date(lastMs).toISOString();
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
catch (error) {
|
|
2482
|
+
collectionErrors.push(`diagnostic summaries unreadable: ${errorText(error)}`);
|
|
2483
|
+
}
|
|
2623
2484
|
return {
|
|
2624
2485
|
state: "live",
|
|
2625
2486
|
mode: control.state,
|
|
@@ -2630,7 +2491,10 @@ export function collectEventLedgerHealthV3(root, nowMs = Date.now()) {
|
|
|
2630
2491
|
pending_finalizations: pending,
|
|
2631
2492
|
intake_spool: { total: intakeTotal, groups: intakeGroups },
|
|
2632
2493
|
diagnostics_spool: {
|
|
2633
|
-
total: diagnosticsTotal,
|
|
2494
|
+
total: diagnosticsTotal + summarizedTotal,
|
|
2495
|
+
loose_total: diagnosticsTotal,
|
|
2496
|
+
summarized_total: summarizedTotal,
|
|
2497
|
+
summary_files: summaryFiles,
|
|
2634
2498
|
last_24h: diagnostics24h,
|
|
2635
2499
|
last_1h: diagnostics1h,
|
|
2636
2500
|
latest_at: Number.isFinite(latestDiagnosticMs)
|
|
@@ -2638,11 +2502,59 @@ export function collectEventLedgerHealthV3(root, nowMs = Date.now()) {
|
|
|
2638
2502
|
: null,
|
|
2639
2503
|
by_category: byCategory,
|
|
2640
2504
|
recent_by_category: recentByCategory,
|
|
2505
|
+
mitigation_fail_open: mitigationFailOpen,
|
|
2641
2506
|
},
|
|
2642
2507
|
span_pressure: spanPressure,
|
|
2643
2508
|
collection_errors: collectionErrors,
|
|
2644
2509
|
};
|
|
2645
2510
|
}
|
|
2511
|
+
/**
|
|
2512
|
+
* Tally stop-hook remediation-cap exhaustions in the window from
|
|
2513
|
+
* `.harnery/debug/agent-hook.ndjson` (rows with
|
|
2514
|
+
* `skipped: "stop-remediation-cap-exhausted"`). Each one is a session whose
|
|
2515
|
+
* end-of-turn evidence never landed, so the Stop hook gave up bouncing it and
|
|
2516
|
+
* let the turn end unenforced — a compliance gap an operator should see
|
|
2517
|
+
* without grepping the debug ledger.
|
|
2518
|
+
*/
|
|
2519
|
+
export function readStopRemediationExhaustions(root, cutoffMs) {
|
|
2520
|
+
const p = resolve(root, ".harnery", "debug", "agent-hook.ndjson");
|
|
2521
|
+
if (!existsSync(p))
|
|
2522
|
+
return { total: 0, latestAt: null, sessions: [] };
|
|
2523
|
+
let raw;
|
|
2524
|
+
try {
|
|
2525
|
+
raw = readFileSync(p, "utf8");
|
|
2526
|
+
}
|
|
2527
|
+
catch {
|
|
2528
|
+
return { total: 0, latestAt: null, sessions: [] };
|
|
2529
|
+
}
|
|
2530
|
+
let total = 0;
|
|
2531
|
+
let latestMs = Number.NEGATIVE_INFINITY;
|
|
2532
|
+
const sessions = new Set();
|
|
2533
|
+
for (const line of raw.split("\n")) {
|
|
2534
|
+
if (!line.includes("stop-remediation-cap-exhausted"))
|
|
2535
|
+
continue;
|
|
2536
|
+
try {
|
|
2537
|
+
const e = JSON.parse(line);
|
|
2538
|
+
if (e.skipped !== "stop-remediation-cap-exhausted")
|
|
2539
|
+
continue;
|
|
2540
|
+
const tsMs = e.ts ? Date.parse(e.ts) : Number.NaN;
|
|
2541
|
+
if (!Number.isFinite(tsMs) || tsMs < cutoffMs)
|
|
2542
|
+
continue;
|
|
2543
|
+
total++;
|
|
2544
|
+
latestMs = Math.max(latestMs, tsMs);
|
|
2545
|
+
if (e.session_id && sessions.size < 5)
|
|
2546
|
+
sessions.add(e.session_id);
|
|
2547
|
+
}
|
|
2548
|
+
catch {
|
|
2549
|
+
/* skip malformed */
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
return {
|
|
2553
|
+
total,
|
|
2554
|
+
latestAt: Number.isFinite(latestMs) ? new Date(latestMs).toISOString() : null,
|
|
2555
|
+
sessions: [...sessions],
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2646
2558
|
/** Tally agent-hook failures (.harnery/debug/agent-hook.errors.ndjson) in the
|
|
2647
2559
|
* window by exact error and phase, while separating current-hour failures from
|
|
2648
2560
|
* historical rows. Each line is {ts, error, phase, ...}. */
|
|
@@ -3041,13 +2953,13 @@ function runTrace(name, opts) {
|
|
|
3041
2953
|
/**
|
|
3042
2954
|
* V3 generations, not disposable heartbeat caches, are the active-agent authority.
|
|
3043
2955
|
*/
|
|
3044
|
-
export function collectActiveAgentHealth(root, nowMs = Date.now()) {
|
|
2956
|
+
export function collectActiveAgentHealth(root, nowMs = Date.now(), readRows = readLiveCoordinationRows, freshnessSeconds = freshnessCutoffSecs()) {
|
|
3045
2957
|
const source = "event-ledger-v3";
|
|
3046
2958
|
let heartbeats = [];
|
|
3047
2959
|
try {
|
|
3048
2960
|
const control = readEventV3ControlState(root);
|
|
3049
2961
|
if (control.state === "candidate" || control.state === "active") {
|
|
3050
|
-
heartbeats =
|
|
2962
|
+
heartbeats = readRows(root);
|
|
3051
2963
|
}
|
|
3052
2964
|
}
|
|
3053
2965
|
catch {
|
|
@@ -3073,7 +2985,7 @@ export function collectActiveAgentHealth(root, nowMs = Date.now()) {
|
|
|
3073
2985
|
const ageMs = Number.isFinite(lastObservedMs)
|
|
3074
2986
|
? nowMs - lastObservedMs
|
|
3075
2987
|
: Number.POSITIVE_INFINITY;
|
|
3076
|
-
if (ageMs >
|
|
2988
|
+
if (ageMs > freshnessSeconds * 1000)
|
|
3077
2989
|
stale += 1;
|
|
3078
2990
|
}
|
|
3079
2991
|
return {
|
|
@@ -3085,6 +2997,17 @@ export function collectActiveAgentHealth(root, nowMs = Date.now()) {
|
|
|
3085
2997
|
stale,
|
|
3086
2998
|
};
|
|
3087
2999
|
}
|
|
3000
|
+
/** Classify a parseable heartbeat cache file without conflating age with corruption. */
|
|
3001
|
+
export function classifyHeartbeatCacheIssue(heartbeat, nowMs, staleAgeMs) {
|
|
3002
|
+
if (!heartbeat.name || heartbeat.name === "unknown")
|
|
3003
|
+
return "no-name";
|
|
3004
|
+
const lastHeartbeatMs = heartbeat.last_heartbeat
|
|
3005
|
+
? Date.parse(heartbeat.last_heartbeat)
|
|
3006
|
+
: Number.NaN;
|
|
3007
|
+
if (!Number.isFinite(lastHeartbeatMs))
|
|
3008
|
+
return "invalid-heartbeat";
|
|
3009
|
+
return nowMs - lastHeartbeatMs > staleAgeMs ? "stale-age" : null;
|
|
3010
|
+
}
|
|
3088
3011
|
function runHealth(opts) {
|
|
3089
3012
|
if (opts.json)
|
|
3090
3013
|
emit.config({ format: "json" });
|
|
@@ -3144,6 +3067,7 @@ function runHealth(opts) {
|
|
|
3144
3067
|
}
|
|
3145
3068
|
}
|
|
3146
3069
|
const hookErrors = readHookErrors(root, cutoffMs, nowMs);
|
|
3070
|
+
const stopRemediation = readStopRemediationExhaustions(root, cutoffMs);
|
|
3147
3071
|
const stream = readStreamStats(root);
|
|
3148
3072
|
const eventLedger = collectEventLedgerHealthV3(root);
|
|
3149
3073
|
// Canonical health.* events carry the full instance_id, already resolved to
|
|
@@ -3164,12 +3088,12 @@ function runHealth(opts) {
|
|
|
3164
3088
|
.slice(0, 5)
|
|
3165
3089
|
.map(([agent, count]) => ({ agent, count }));
|
|
3166
3090
|
const activeAgents = collectActiveAgentHealth(root, nowMs);
|
|
3167
|
-
//
|
|
3168
|
-
//
|
|
3169
|
-
//
|
|
3091
|
+
// Heartbeat cache issues: files in active/ that are unparseable, nameless,
|
|
3092
|
+
// invalidly timestamped, or stale. Old parseable timestamps are ordinary
|
|
3093
|
+
// staleness, not evidence of epoch-like timestamp corruption.
|
|
3170
3094
|
let zombieCount = 0;
|
|
3171
3095
|
const zombieSamples = [];
|
|
3172
|
-
const
|
|
3096
|
+
const STALE_HEARTBEAT_AGE_MS = 24 * 60 * 60 * 1000;
|
|
3173
3097
|
if (existsSync(activeDir)) {
|
|
3174
3098
|
for (const file of readdirSync(activeDir)) {
|
|
3175
3099
|
if (!file.endsWith(".json"))
|
|
@@ -3188,15 +3112,11 @@ function runHealth(opts) {
|
|
|
3188
3112
|
zombieSamples.push(`${idFromFile.slice(0, 12)} (unparseable/no-id)`);
|
|
3189
3113
|
continue;
|
|
3190
3114
|
}
|
|
3191
|
-
const
|
|
3192
|
-
|
|
3193
|
-
// Zombie heuristics on a parseable heartbeat: no name, or an age so large
|
|
3194
|
-
// it can only be a broken/epoch timestamp (a real agent would have healed).
|
|
3195
|
-
if (!hb.name || hb.name === "unknown" || ageMs > ABSURD_AGE_MS) {
|
|
3115
|
+
const cacheIssue = classifyHeartbeatCacheIssue(hb, nowMs, STALE_HEARTBEAT_AGE_MS);
|
|
3116
|
+
if (cacheIssue) {
|
|
3196
3117
|
zombieCount++;
|
|
3197
3118
|
if (zombieSamples.length < 5) {
|
|
3198
|
-
|
|
3199
|
-
zombieSamples.push(`${idFromFile.slice(0, 12)} (${why})`);
|
|
3119
|
+
zombieSamples.push(`${idFromFile.slice(0, 12)} (${cacheIssue})`);
|
|
3200
3120
|
}
|
|
3201
3121
|
}
|
|
3202
3122
|
}
|
|
@@ -3246,7 +3166,13 @@ function runHealth(opts) {
|
|
|
3246
3166
|
anomalies.push(`${sweptByReason.unparseable} heartbeat(s) swept as unparseable in ${opts.since}; possible corruption or a non-atomic writer`);
|
|
3247
3167
|
}
|
|
3248
3168
|
if (zombieCount > 0) {
|
|
3249
|
-
anomalies.push(`${zombieCount}
|
|
3169
|
+
anomalies.push(`${zombieCount} heartbeat cache issue(s) in active/ (${zombieSamples.join(", ")}); stale or malformed files the sweep isn't reaping`);
|
|
3170
|
+
}
|
|
3171
|
+
if (stopRemediation.total > 0) {
|
|
3172
|
+
const who = stopRemediation.sessions.length > 0
|
|
3173
|
+
? ` (sessions: ${stopRemediation.sessions.map((s) => s.slice(0, 8)).join(", ")})`
|
|
3174
|
+
: "";
|
|
3175
|
+
anomalies.push(`stop-hook remediation cap exhausted ${stopRemediation.total}x in ${opts.since}${who}; these sessions ended turns without the end-of-turn ritual — check why their evidence never lands`);
|
|
3250
3176
|
}
|
|
3251
3177
|
if (eventLedger.state === "live") {
|
|
3252
3178
|
// Open spans whose generation has no open turn: the turn ended without its
|
|
@@ -3306,6 +3232,11 @@ function runHealth(opts) {
|
|
|
3306
3232
|
stream,
|
|
3307
3233
|
zombies: { count: zombieCount, samples: zombieSamples },
|
|
3308
3234
|
event_ledger: eventLedger,
|
|
3235
|
+
stop_remediation: {
|
|
3236
|
+
total: stopRemediation.total,
|
|
3237
|
+
latest_at: stopRemediation.latestAt,
|
|
3238
|
+
sessions: stopRemediation.sessions,
|
|
3239
|
+
},
|
|
3309
3240
|
anomalies,
|
|
3310
3241
|
};
|
|
3311
3242
|
if (opts.json) {
|
|
@@ -3364,7 +3295,7 @@ function renderHealthBox(report) {
|
|
|
3364
3295
|
`open spans ${ledger.open_spans.total}${orphanGenerations > 0 ? ` (${orphanGenerations} gen turn-closed)` : ""}`,
|
|
3365
3296
|
`pending ends ${ledger.pending_finalizations.length}${pendingAges ? ` (${pendingAges})` : ""}`,
|
|
3366
3297
|
`intake ${ledger.intake_spool.total}`,
|
|
3367
|
-
`diagnostics ${ledger.diagnostics_spool.total} (${ledger.diagnostics_spool.last_1h} in 1h / ${ledger.diagnostics_spool.last_24h} in 24h)`,
|
|
3298
|
+
`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)`,
|
|
3368
3299
|
].join(" · ");
|
|
3369
3300
|
}
|
|
3370
3301
|
const rows = [
|
|
@@ -3384,7 +3315,7 @@ function renderHealthBox(report) {
|
|
|
3384
3315
|
["stream", streamStr],
|
|
3385
3316
|
["event ledger", ledgerStr],
|
|
3386
3317
|
[
|
|
3387
|
-
"
|
|
3318
|
+
"cache issues",
|
|
3388
3319
|
report.zombies.count === 0
|
|
3389
3320
|
? "0"
|
|
3390
3321
|
: `${report.zombies.count} (${report.zombies.samples.join(", ")})`,
|
|
@@ -3768,10 +3699,13 @@ function runPing(name, message, opts) {
|
|
|
3768
3699
|
}
|
|
3769
3700
|
const myOwner = resolveOwner();
|
|
3770
3701
|
if (!myOwner) {
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3702
|
+
const root = monorepoRoot();
|
|
3703
|
+
emit.error(root
|
|
3704
|
+
? sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry")
|
|
3705
|
+
: {
|
|
3706
|
+
code: "no_pidmap_entry",
|
|
3707
|
+
message: "not in an agent session; ppid walk found no pid-map entry",
|
|
3708
|
+
});
|
|
3775
3709
|
process.exit(1);
|
|
3776
3710
|
}
|
|
3777
3711
|
const peerOwner = resolveOwnerByName(name);
|
|
@@ -3913,12 +3847,10 @@ function emitWaitResult(data, opts) {
|
|
|
3913
3847
|
function runHeal(opts) {
|
|
3914
3848
|
if (opts.json)
|
|
3915
3849
|
emit.config({ format: "json" });
|
|
3916
|
-
const
|
|
3917
|
-
const
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
process.exit(1);
|
|
3921
|
-
}
|
|
3850
|
+
const requestedOwner = opts.owner?.trim() ?? "";
|
|
3851
|
+
const quarantineTransaction = opts.quarantineTransaction?.trim() ?? "";
|
|
3852
|
+
const approvalRecordId = opts.approvalRecordId?.trim() ?? "";
|
|
3853
|
+
const kind = opts.kind?.trim() || "cache";
|
|
3922
3854
|
if (kind !== "pidmap" && kind !== "cache") {
|
|
3923
3855
|
emit.error({
|
|
3924
3856
|
code: "bad_kind",
|
|
@@ -3926,6 +3858,30 @@ function runHeal(opts) {
|
|
|
3926
3858
|
});
|
|
3927
3859
|
process.exit(1);
|
|
3928
3860
|
}
|
|
3861
|
+
if (quarantineTransaction) {
|
|
3862
|
+
if (opts.kind || opts.pid) {
|
|
3863
|
+
emit.error({
|
|
3864
|
+
code: "conflicting_recovery_options",
|
|
3865
|
+
message: "--quarantine-transaction cannot be combined with --kind or --pid",
|
|
3866
|
+
});
|
|
3867
|
+
process.exit(1);
|
|
3868
|
+
}
|
|
3869
|
+
if (!opts.yes || !approvalRecordId) {
|
|
3870
|
+
emit.error({
|
|
3871
|
+
code: "transaction_quarantine_confirmation_required",
|
|
3872
|
+
message: "--quarantine-transaction requires --approval-record-id <id> and --yes; " +
|
|
3873
|
+
"the command abandons one uncommitted authority mutation while preserving its record",
|
|
3874
|
+
});
|
|
3875
|
+
process.exit(1);
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
else if (approvalRecordId || opts.yes) {
|
|
3879
|
+
emit.error({
|
|
3880
|
+
code: "transaction_quarantine_target_required",
|
|
3881
|
+
message: "--approval-record-id and --yes require --quarantine-transaction <id>",
|
|
3882
|
+
});
|
|
3883
|
+
process.exit(1);
|
|
3884
|
+
}
|
|
3929
3885
|
if (opts.adapter &&
|
|
3930
3886
|
opts.adapter !== "claude-code" &&
|
|
3931
3887
|
opts.adapter !== "cursor" &&
|
|
@@ -3944,7 +3900,42 @@ function runHeal(opts) {
|
|
|
3944
3900
|
});
|
|
3945
3901
|
process.exit(1);
|
|
3946
3902
|
}
|
|
3947
|
-
const
|
|
3903
|
+
const currentSessionRepair = kind === "cache" &&
|
|
3904
|
+
opts.owner === undefined &&
|
|
3905
|
+
opts.sessionId === undefined &&
|
|
3906
|
+
opts.adapter === undefined &&
|
|
3907
|
+
!quarantineTransaction;
|
|
3908
|
+
const ownerResolution = resolveOwnerWithSource();
|
|
3909
|
+
const bootstrapIdentity = currentSessionRepair ? commandSessionBootstrap() : null;
|
|
3910
|
+
const resolvedCurrentOwner = bootstrapIdentity &&
|
|
3911
|
+
(ownerResolution.source === "none" || ownerResolution.source === "active_singleton")
|
|
3912
|
+
? bootstrapIdentity.sessionId
|
|
3913
|
+
: ownerResolution.owner;
|
|
3914
|
+
const owner = requestedOwner || resolvedCurrentOwner || sessionIdentityFromEnv() || "";
|
|
3915
|
+
if (!owner) {
|
|
3916
|
+
emit.error({
|
|
3917
|
+
code: "session_identity_missing",
|
|
3918
|
+
message: `could not resolve the current session; run ${resolveBinName()} doctor, or pass ` +
|
|
3919
|
+
"--owner <instance-id> --session-id <native-session-id> --adapter <adapter>",
|
|
3920
|
+
});
|
|
3921
|
+
process.exit(1);
|
|
3922
|
+
}
|
|
3923
|
+
const currentRow = readLiveCoordinationRow(root, owner);
|
|
3924
|
+
const inferredAdapter = normalizeAdapter(opts.adapter?.trim() || currentRow?.platform || commandSessionBootstrap()?.adapter);
|
|
3925
|
+
const sessionId = opts.sessionId?.trim() ||
|
|
3926
|
+
(currentSessionRepair ? sessionIdentityFromEnv() : null) ||
|
|
3927
|
+
nativeSessionIdentity(currentRow, owner);
|
|
3928
|
+
if (kind === "cache") {
|
|
3929
|
+
const refusal = cacheHealAuthorityRefusal(root, owner, sessionId, inferredAdapter, currentRow);
|
|
3930
|
+
if (refusal) {
|
|
3931
|
+
emitHealFailure(refusal.reason, refusal.message);
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
const action = quarantineTransaction
|
|
3935
|
+
? "quarantine-authority-transaction"
|
|
3936
|
+
: kind === "pidmap"
|
|
3937
|
+
? "heal-pidmap"
|
|
3938
|
+
: "repair-coordination-cache";
|
|
3948
3939
|
// Refuse to materialize a V3 cache at a truncated owner id.
|
|
3949
3940
|
//
|
|
3950
3941
|
// Heartbeats are keyed by the whole instance_id, so healing at an
|
|
@@ -3983,24 +3974,54 @@ function runHeal(opts) {
|
|
|
3983
3974
|
// heal-pidmap <instance_id> [<pid>]
|
|
3984
3975
|
// repair-coordination-cache <instance_id> [<session_id>]
|
|
3985
3976
|
const helperArgs = [action, owner];
|
|
3986
|
-
if (
|
|
3987
|
-
helperArgs.push(
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3977
|
+
if (quarantineTransaction) {
|
|
3978
|
+
helperArgs.push(quarantineTransaction, approvalRecordId, sessionId, `--adapter=${inferredAdapter}`);
|
|
3979
|
+
}
|
|
3980
|
+
else {
|
|
3981
|
+
if (kind === "pidmap" && opts.pid)
|
|
3982
|
+
helperArgs.push(opts.pid);
|
|
3983
|
+
if (kind === "cache")
|
|
3984
|
+
helperArgs.push(sessionId, `--adapter=${inferredAdapter}`);
|
|
3985
|
+
}
|
|
3992
3986
|
// Both recovery actions are handled by the bundled agent-coord binary.
|
|
3993
3987
|
const helper = agentCoordOrExit(root);
|
|
3994
|
-
|
|
3988
|
+
let proc = spawnSync(helper, helperArgs, {
|
|
3995
3989
|
encoding: "utf8",
|
|
3996
3990
|
...coordHelperOpts(root),
|
|
3997
3991
|
});
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
3992
|
+
let bootstrapState;
|
|
3993
|
+
if (proc.status !== 0 &&
|
|
3994
|
+
currentSessionRepair &&
|
|
3995
|
+
missingAuthorityForCurrentSessionBootstrap(root, owner, sessionId)) {
|
|
3996
|
+
const bootstrap = commandSessionBootstrap();
|
|
3997
|
+
if (!bootstrap ||
|
|
3998
|
+
bootstrap.sessionId !== sessionId ||
|
|
3999
|
+
bootstrap.sessionId !== owner ||
|
|
4000
|
+
bootstrap.adapter !== inferredAdapter) {
|
|
4001
|
+
emitHealFailure("native_identity_unverified", "the current adapter did not provide one matching native session id and adapter");
|
|
4002
|
+
}
|
|
4003
|
+
try {
|
|
4004
|
+
const bootstrapped = bootstrapLiveCoordinationAuthorityV3({
|
|
4005
|
+
coordRoot: root,
|
|
4006
|
+
owner,
|
|
4007
|
+
nativeSessionId: bootstrap.sessionId,
|
|
4008
|
+
adapter: bootstrap.adapter,
|
|
4009
|
+
});
|
|
4010
|
+
bootstrapState = bootstrapped.state;
|
|
4011
|
+
}
|
|
4012
|
+
catch (error) {
|
|
4013
|
+
const reason = error instanceof LiveCoordinationAuthorityV3Error
|
|
4014
|
+
? error.reason
|
|
4015
|
+
: "authority_bootstrap_failed";
|
|
4016
|
+
emitHealFailure(reason, "the current native session could not establish authority; no fallback cache was accepted");
|
|
4017
|
+
}
|
|
4018
|
+
proc = spawnSync(helper, helperArgs, {
|
|
4019
|
+
encoding: "utf8",
|
|
4020
|
+
...coordHelperOpts(root),
|
|
4002
4021
|
});
|
|
4003
|
-
|
|
4022
|
+
}
|
|
4023
|
+
if (proc.status !== 0) {
|
|
4024
|
+
emitHealFailure(healFailureReason(root, owner, sessionId, inferredAdapter), spawnFailureMessage(proc, `agent-coord ${action}`));
|
|
4004
4025
|
}
|
|
4005
4026
|
// Read the derived cache to surface post-action state.
|
|
4006
4027
|
let after = null;
|
|
@@ -4010,13 +4031,15 @@ function runHeal(opts) {
|
|
|
4010
4031
|
catch {
|
|
4011
4032
|
after = null;
|
|
4012
4033
|
}
|
|
4013
|
-
const outcome =
|
|
4014
|
-
?
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
:
|
|
4034
|
+
const outcome = quarantineTransaction
|
|
4035
|
+
? "transaction_quarantined"
|
|
4036
|
+
: kind === "pidmap"
|
|
4037
|
+
? proc.status === 0
|
|
4038
|
+
? "ok"
|
|
4039
|
+
: "failed"
|
|
4040
|
+
: after
|
|
4041
|
+
? "cache_present"
|
|
4042
|
+
: "cache_absent";
|
|
4020
4043
|
emit.data({
|
|
4021
4044
|
rows: [
|
|
4022
4045
|
{
|
|
@@ -4024,10 +4047,15 @@ function runHeal(opts) {
|
|
|
4024
4047
|
action,
|
|
4025
4048
|
outcome,
|
|
4026
4049
|
after,
|
|
4050
|
+
...(quarantineTransaction ? { recovery: JSON.parse(proc.stdout.trim()) } : {}),
|
|
4027
4051
|
},
|
|
4028
4052
|
],
|
|
4029
4053
|
meta: {
|
|
4030
4054
|
kind,
|
|
4055
|
+
automatic: currentSessionRepair && !quarantineTransaction,
|
|
4056
|
+
authority: "event-ledger-v3",
|
|
4057
|
+
adapter: kind === "cache" ? inferredAdapter : undefined,
|
|
4058
|
+
bootstrap: bootstrapState,
|
|
4031
4059
|
// The path actually spawned, not a guess at the layout: the helper is
|
|
4032
4060
|
// resolved from harnery's own package location, which differs between a
|
|
4033
4061
|
// submodule, an installed dependency, and a standalone checkout.
|
|
@@ -4035,11 +4063,16 @@ function runHeal(opts) {
|
|
|
4035
4063
|
},
|
|
4036
4064
|
});
|
|
4037
4065
|
if (!opts.json) {
|
|
4038
|
-
if (
|
|
4066
|
+
if (quarantineTransaction) {
|
|
4067
|
+
emit.text(`coordination recovered: ${quarantineTransaction} quarantined with approval ${approvalRecordId}; ` +
|
|
4068
|
+
`cache ${after ? "present" : "absent"} (${inferredAdapter})\n`);
|
|
4069
|
+
}
|
|
4070
|
+
else if (kind === "pidmap") {
|
|
4039
4071
|
emit.text(`agent-coord ${action} ok\n`);
|
|
4040
4072
|
}
|
|
4041
4073
|
else {
|
|
4042
|
-
emit.text(`
|
|
4074
|
+
emit.text(`coordination repaired: V3 authority live; ${currentSessionRepair ? "current-session " : ""}` +
|
|
4075
|
+
`cache ${after ? "present" : "absent"} (${inferredAdapter})\n`);
|
|
4043
4076
|
}
|
|
4044
4077
|
}
|
|
4045
4078
|
// Canonical health.* emission is owned by the cache writer, so it fires
|
|
@@ -4048,6 +4081,68 @@ function runHeal(opts) {
|
|
|
4048
4081
|
// event when an already-correct heal no-ops. (Previously emitted here
|
|
4049
4082
|
// unconditionally on every `harn agents heal`, which over-counted no-op heals.)
|
|
4050
4083
|
}
|
|
4084
|
+
function cacheHealAuthorityRefusal(root, owner, sessionId, adapter, currentRow) {
|
|
4085
|
+
if (currentRow && normalizeAdapter(currentRow.platform) !== adapter) {
|
|
4086
|
+
return {
|
|
4087
|
+
reason: "adapter_mismatch",
|
|
4088
|
+
message: `the live generation belongs to adapter ${normalizeAdapter(currentRow.platform)}, not ${adapter}`,
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4091
|
+
let producer;
|
|
4092
|
+
try {
|
|
4093
|
+
producer = readHookProducerStateV3(root, adapter, sessionId);
|
|
4094
|
+
}
|
|
4095
|
+
catch {
|
|
4096
|
+
return {
|
|
4097
|
+
reason: "session_mismatch",
|
|
4098
|
+
message: "the native session producer state could not be read safely",
|
|
4099
|
+
};
|
|
4100
|
+
}
|
|
4101
|
+
if (producer?.terminal) {
|
|
4102
|
+
return {
|
|
4103
|
+
reason: "terminal_generation",
|
|
4104
|
+
message: "the matching generation is terminal and cannot be repaired or reopened by heal",
|
|
4105
|
+
};
|
|
4106
|
+
}
|
|
4107
|
+
if (producer && producer.instance_id !== liveInstanceIdV3(owner)) {
|
|
4108
|
+
return {
|
|
4109
|
+
reason: "owner_mismatch",
|
|
4110
|
+
message: "the native session is bound to a different instance owner",
|
|
4111
|
+
};
|
|
4112
|
+
}
|
|
4113
|
+
if (currentRow && (!producer || producer.generation_id !== currentRow.v3_generation_id)) {
|
|
4114
|
+
return {
|
|
4115
|
+
reason: "session_mismatch",
|
|
4116
|
+
message: "the native session does not bind to the requested live generation",
|
|
4117
|
+
};
|
|
4118
|
+
}
|
|
4119
|
+
return null;
|
|
4120
|
+
}
|
|
4121
|
+
function missingAuthorityForCurrentSessionBootstrap(root, owner, sessionId) {
|
|
4122
|
+
if (readLiveCoordinationRow(root, owner))
|
|
4123
|
+
return false;
|
|
4124
|
+
try {
|
|
4125
|
+
const nativeSessionHasProducer = ["claude-code", "codex", "cursor"].some((adapter) => readHookProducerStateV3(root, adapter, sessionId) !== undefined);
|
|
4126
|
+
if (nativeSessionHasProducer)
|
|
4127
|
+
return false;
|
|
4128
|
+
const instanceId = liveInstanceIdV3(owner);
|
|
4129
|
+
return !listHookProducerStateRecordsV3(root, { includeTerminal: true }).some(({ state }) => state.instance_id === instanceId);
|
|
4130
|
+
}
|
|
4131
|
+
catch {
|
|
4132
|
+
return false;
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4135
|
+
function healFailureReason(root, owner, sessionId, adapter) {
|
|
4136
|
+
const refusal = cacheHealAuthorityRefusal(root, owner, sessionId, adapter, readLiveCoordinationRow(root, owner));
|
|
4137
|
+
return refusal?.reason ?? "authority_missing";
|
|
4138
|
+
}
|
|
4139
|
+
function emitHealFailure(reason, message) {
|
|
4140
|
+
emit.error({
|
|
4141
|
+
code: "heal_failed",
|
|
4142
|
+
message: `coordination heal refused (reason=${reason}): ${message}`,
|
|
4143
|
+
});
|
|
4144
|
+
process.exit(1);
|
|
4145
|
+
}
|
|
4051
4146
|
/**
|
|
4052
4147
|
* Emit one V3 council audit transition keyed to the exact durable manifest.
|
|
4053
4148
|
* Falls through silently when no live session can attest the observation.
|