harnery 0.32.0 → 0.34.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/README.md +2 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +7 -1
- package/dist/commands/adapter.js +2 -2
- package/dist/commands/agents.d.ts +144 -1
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +1408 -565
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +7 -6
- package/dist/commands/backup.d.ts +1 -1
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +29 -16
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +234 -12
- package/dist/commands/checkpoint.d.ts.map +1 -1
- package/dist/commands/checkpoint.js +3 -2
- package/dist/commands/claude-desktop.d.ts +2 -2
- package/dist/commands/claude-desktop.d.ts.map +1 -1
- package/dist/commands/claude-desktop.js +2 -2
- package/dist/commands/context.js +1 -6
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +22 -38
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +91 -28
- package/dist/commands/doctor.d.ts +4 -2
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +55 -7
- package/dist/commands/events.d.ts +5 -0
- package/dist/commands/events.d.ts.map +1 -0
- package/dist/commands/events.js +189 -0
- package/dist/commands/governor.d.ts.map +1 -1
- package/dist/commands/governor.js +13 -4
- package/dist/commands/init.d.ts +10 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +233 -51
- package/dist/commands/instructions.d.ts +4 -0
- package/dist/commands/instructions.d.ts.map +1 -0
- package/dist/commands/instructions.js +100 -0
- package/dist/commands/journal.d.ts.map +1 -1
- package/dist/commands/journal.js +4 -13
- package/dist/commands/ledger-v3.d.ts +5 -0
- package/dist/commands/ledger-v3.d.ts.map +1 -0
- package/dist/commands/ledger-v3.js +91 -0
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +15 -6
- package/dist/commands/sync.d.ts +1 -1
- package/dist/commands/sync.js +1 -1
- package/dist/commands/web.d.ts +6 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +67 -7
- package/dist/commands/work.d.ts.map +1 -1
- package/dist/commands/work.js +22 -5
- package/dist/core/adapter.d.ts +5 -0
- package/dist/core/adapter.d.ts.map +1 -0
- package/dist/core/adapter.js +1 -0
- package/dist/core/adapters/attest.d.ts +5 -2
- package/dist/core/adapters/attest.d.ts.map +1 -1
- package/dist/core/adapters/attest.js +8 -3
- package/dist/core/adapters/profiles.d.ts +6 -6
- package/dist/core/adapters/profiles.d.ts.map +1 -1
- package/dist/core/adapters/profiles.js +4 -4
- package/dist/core/agents/canonical-emit.d.ts +17 -15
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +27 -25
- package/dist/core/agents/cli.js +212 -235
- package/dist/core/agents/codex-archive-v3.d.ts +14 -0
- package/dist/core/agents/codex-archive-v3.d.ts.map +1 -0
- package/dist/core/agents/codex-archive-v3.js +110 -0
- package/dist/core/agents/coord-client.d.ts +19 -70
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +65 -155
- package/dist/core/agents/finalization.d.ts +4 -1
- package/dist/core/agents/finalization.d.ts.map +1 -1
- package/dist/core/agents/finalization.js +89 -32
- package/dist/core/agents/index.d.ts +5 -5
- package/dist/core/agents/index.d.ts.map +1 -1
- package/dist/core/agents/index.js +5 -5
- package/dist/core/agents/live-authority-v3.d.ts +59 -0
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -0
- package/dist/core/agents/live-authority-v3.js +233 -0
- package/dist/core/agents/live-lifecycle-v3.d.ts +20 -0
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -0
- package/dist/core/agents/live-lifecycle-v3.js +91 -0
- package/dist/core/agents/live-observation-v3.d.ts +25 -0
- package/dist/core/agents/live-observation-v3.d.ts.map +1 -0
- package/dist/core/agents/live-observation-v3.js +157 -0
- package/dist/core/agents/render/prompt-context.d.ts +10 -4
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +61 -55
- package/dist/core/agents/render/session-context.d.ts +1 -1
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +15 -33
- package/dist/core/agents/rules/claim-conflict.d.ts +3 -3
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +79 -127
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +3 -18
- package/dist/core/agents/rules/stop-hook.d.ts +9 -50
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +193 -236
- package/dist/core/agents/session-events.d.ts +5 -7
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +127 -95
- package/dist/core/agents/session-finalization-state-v3.d.ts +30 -0
- package/dist/core/agents/session-finalization-state-v3.d.ts.map +1 -0
- package/dist/core/agents/session-finalization-state-v3.js +40 -0
- package/dist/core/agents/session-finalizer-v3.d.ts +107 -0
- package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -0
- package/dist/core/agents/session-finalizer-v3.js +734 -0
- package/dist/core/agents/session-name-display.d.ts +40 -0
- package/dist/core/agents/session-name-display.d.ts.map +1 -0
- package/dist/core/agents/session-name-display.js +119 -0
- package/dist/core/agents/state/activity-log.d.ts +3 -3
- package/dist/core/agents/state/activity-log.d.ts.map +1 -1
- package/dist/core/agents/state/activity-log.js +7 -16
- package/dist/core/agents/state/heartbeat-writer.d.ts +29 -46
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +59 -199
- package/dist/core/agents/state/live-coordination-view.d.ts +31 -0
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -0
- package/dist/core/agents/state/live-coordination-view.js +209 -0
- package/dist/core/agents/state/session-state.d.ts +45 -0
- package/dist/core/agents/state/session-state.d.ts.map +1 -0
- package/dist/core/agents/state/session-state.js +90 -0
- package/dist/core/agents/state/stale-sweep.d.ts +1 -1
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +26 -15
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +5 -7
- package/dist/core/config.d.ts +33 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +98 -2
- package/dist/core/context/index.d.ts +1 -4
- package/dist/core/context/index.d.ts.map +1 -1
- package/dist/core/context/index.js +9 -9
- package/dist/core/events/span-parent.d.ts +15 -0
- package/dist/core/events/span-parent.d.ts.map +1 -0
- package/dist/core/events/span-parent.js +34 -0
- package/dist/core/events/v3/advance.d.ts +14 -0
- package/dist/core/events/v3/advance.d.ts.map +1 -0
- package/dist/core/events/v3/advance.js +134 -0
- package/dist/core/events/v3/authority-outbox.d.ts +78 -0
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -0
- package/dist/core/events/v3/authority-outbox.js +399 -0
- package/dist/core/events/v3/base-builder.d.ts +20 -0
- package/dist/core/events/v3/base-builder.d.ts.map +1 -0
- package/dist/core/events/v3/base-builder.js +29 -0
- package/dist/core/events/v3/base-contract.d.ts +7576 -0
- package/dist/core/events/v3/base-contract.d.ts.map +1 -0
- package/dist/core/events/v3/base-contract.js +647 -0
- package/dist/core/events/v3/bootstrap.d.ts +34 -0
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -0
- package/dist/core/events/v3/bootstrap.js +175 -0
- package/dist/core/events/v3/builder.d.ts +20 -0
- package/dist/core/events/v3/builder.d.ts.map +1 -0
- package/dist/core/events/v3/builder.js +28 -0
- package/dist/core/events/v3/canonical.d.ts +31 -0
- package/dist/core/events/v3/canonical.d.ts.map +1 -0
- package/dist/core/events/v3/canonical.js +100 -0
- package/dist/core/events/v3/capabilities.d.ts +31 -0
- package/dist/core/events/v3/capabilities.d.ts.map +1 -0
- package/dist/core/events/v3/capabilities.js +107 -0
- package/dist/core/events/v3/capability-drift.d.ts +22 -0
- package/dist/core/events/v3/capability-drift.d.ts.map +1 -0
- package/dist/core/events/v3/capability-drift.js +134 -0
- package/dist/core/events/v3/catalog.d.ts +38 -0
- package/dist/core/events/v3/catalog.d.ts.map +1 -0
- package/dist/core/events/v3/catalog.js +135 -0
- package/dist/core/events/v3/clock-order.d.ts +34 -0
- package/dist/core/events/v3/clock-order.d.ts.map +1 -0
- package/dist/core/events/v3/clock-order.js +35 -0
- package/dist/core/events/v3/contract.d.ts +171 -0
- package/dist/core/events/v3/contract.d.ts.map +1 -0
- package/dist/core/events/v3/contract.js +180 -0
- package/dist/core/events/v3/control.d.ts +111 -0
- package/dist/core/events/v3/control.d.ts.map +1 -0
- package/dist/core/events/v3/control.js +419 -0
- package/dist/core/events/v3/coordination-view.d.ts +69 -0
- package/dist/core/events/v3/coordination-view.d.ts.map +1 -0
- package/dist/core/events/v3/coordination-view.js +119 -0
- package/dist/core/events/v3/economics.d.ts +77 -0
- package/dist/core/events/v3/economics.d.ts.map +1 -0
- package/dist/core/events/v3/economics.js +274 -0
- package/dist/core/events/v3/finalization-view.d.ts +26 -0
- package/dist/core/events/v3/finalization-view.d.ts.map +1 -0
- package/dist/core/events/v3/finalization-view.js +37 -0
- package/dist/core/events/v3/fingerprint-keys.d.ts +25 -0
- package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -0
- package/dist/core/events/v3/fingerprint-keys.js +217 -0
- package/dist/core/events/v3/generated.d.ts +4 -0
- package/dist/core/events/v3/generated.d.ts.map +1 -0
- package/dist/core/events/v3/generated.js +47 -0
- package/dist/core/events/v3/ids.d.ts +9 -0
- package/dist/core/events/v3/ids.d.ts.map +1 -0
- package/dist/core/events/v3/ids.js +25 -0
- package/dist/core/events/v3/index.d.ts +35 -0
- package/dist/core/events/v3/index.d.ts.map +1 -0
- package/dist/core/events/v3/index.js +33 -0
- package/dist/core/events/v3/latency.d.ts +63 -0
- package/dist/core/events/v3/latency.d.ts.map +1 -0
- package/dist/core/events/v3/latency.js +412 -0
- package/dist/core/events/v3/live-feed.d.ts +45 -0
- package/dist/core/events/v3/live-feed.d.ts.map +1 -0
- package/dist/core/events/v3/live-feed.js +246 -0
- package/dist/core/events/v3/live-observation.d.ts +35 -0
- package/dist/core/events/v3/live-observation.d.ts.map +1 -0
- package/dist/core/events/v3/live-observation.js +1 -0
- package/dist/core/events/v3/live-routing.d.ts +57 -0
- package/dist/core/events/v3/live-routing.d.ts.map +1 -0
- package/dist/core/events/v3/live-routing.js +107 -0
- package/dist/core/events/v3/producers/command-recorder.d.ts +67 -0
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -0
- package/dist/core/events/v3/producers/command-recorder.js +477 -0
- package/dist/core/events/v3/producers/command.d.ts +50 -0
- package/dist/core/events/v3/producers/command.d.ts.map +1 -0
- package/dist/core/events/v3/producers/command.js +135 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +53 -0
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -0
- package/dist/core/events/v3/producers/coordination-recorder.js +376 -0
- package/dist/core/events/v3/producers/coordination.d.ts +90 -0
- package/dist/core/events/v3/producers/coordination.d.ts.map +1 -0
- package/dist/core/events/v3/producers/coordination.js +229 -0
- package/dist/core/events/v3/producers/hook-base.d.ts +54 -0
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -0
- package/dist/core/events/v3/producers/hook-base.js +424 -0
- package/dist/core/events/v3/producers/hook.d.ts +29 -0
- package/dist/core/events/v3/producers/hook.d.ts.map +1 -0
- package/dist/core/events/v3/producers/hook.js +71 -0
- package/dist/core/events/v3/producers/intake.d.ts +65 -0
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -0
- package/dist/core/events/v3/producers/intake.js +244 -0
- package/dist/core/events/v3/producers/recorder.d.ts +240 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -0
- package/dist/core/events/v3/producers/recorder.js +2176 -0
- package/dist/core/events/v3/projection.d.ts +101 -0
- package/dist/core/events/v3/projection.d.ts.map +1 -0
- package/dist/core/events/v3/projection.js +479 -0
- package/dist/core/events/v3/reader.d.ts +75 -0
- package/dist/core/events/v3/reader.d.ts.map +1 -0
- package/dist/core/events/v3/reader.js +778 -0
- package/dist/core/events/v3/recovery-record.d.ts +47 -0
- package/dist/core/events/v3/recovery-record.d.ts.map +1 -0
- package/dist/core/events/v3/recovery-record.js +167 -0
- package/dist/core/events/v3/recovery.d.ts +22 -0
- package/dist/core/events/v3/recovery.d.ts.map +1 -0
- package/dist/core/events/v3/recovery.js +227 -0
- package/dist/core/events/v3/span-state.d.ts +52 -0
- package/dist/core/events/v3/span-state.d.ts.map +1 -0
- package/dist/core/events/v3/span-state.js +142 -0
- package/dist/core/events/v3/targets.d.ts +23 -0
- package/dist/core/events/v3/targets.d.ts.map +1 -0
- package/dist/core/events/v3/targets.js +134 -0
- package/dist/core/events/v3/turn-telemetry.d.ts +41 -0
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -0
- package/dist/core/events/v3/turn-telemetry.js +168 -0
- package/dist/core/events/v3/validate.d.ts +9 -0
- package/dist/core/events/v3/validate.d.ts.map +1 -0
- package/dist/core/events/v3/validate.js +281 -0
- package/dist/core/events/v3/writer.d.ts +56 -0
- package/dist/core/events/v3/writer.d.ts.map +1 -0
- package/dist/core/events/v3/writer.js +335 -0
- package/dist/core/governor/index.d.ts +1 -1
- package/dist/core/governor/index.d.ts.map +1 -1
- package/dist/core/governor/index.js +1 -1
- package/dist/core/governor/plan-api.d.ts +2 -1
- package/dist/core/governor/plan-api.d.ts.map +1 -1
- package/dist/core/governor/plan-api.js +6 -3
- package/dist/core/governor/read.d.ts +1 -1
- package/dist/core/governor/read.d.ts.map +1 -1
- package/dist/core/governor/read.js +1 -1
- package/dist/core/governor/state.d.ts +9 -0
- package/dist/core/governor/state.d.ts.map +1 -1
- package/dist/core/governor/state.js +40 -3
- package/dist/core/guard/config.d.ts +5 -0
- package/dist/core/guard/config.d.ts.map +1 -0
- package/dist/core/guard/config.js +157 -0
- package/dist/core/guard/coordinator.d.ts +14 -0
- package/dist/core/guard/coordinator.d.ts.map +1 -0
- package/dist/core/guard/coordinator.js +173 -0
- package/dist/core/guard/evaluator.d.ts +4 -0
- package/dist/core/guard/evaluator.d.ts.map +1 -0
- package/dist/core/guard/evaluator.js +242 -0
- package/dist/core/guard/evidence-v3.d.ts +15 -0
- package/dist/core/guard/evidence-v3.d.ts.map +1 -0
- package/dist/core/guard/evidence-v3.js +171 -0
- package/dist/core/guard/index.d.ts +10 -0
- package/dist/core/guard/index.d.ts.map +1 -0
- package/dist/core/guard/index.js +6 -0
- package/dist/core/guard/live-source-v3.d.ts +40 -0
- package/dist/core/guard/live-source-v3.d.ts.map +1 -0
- package/dist/core/guard/live-source-v3.js +128 -0
- package/dist/core/guard/storage.d.ts +27 -0
- package/dist/core/guard/storage.d.ts.map +1 -0
- package/dist/core/guard/storage.js +140 -0
- package/dist/core/guard/types.d.ts +119 -0
- package/dist/core/guard/types.d.ts.map +1 -0
- package/dist/core/guard/types.js +1 -0
- package/dist/core/hooks/adapter/detect.d.ts +18 -1
- package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
- package/dist/core/hooks/adapter/detect.js +29 -0
- package/dist/core/hooks/adapter/events.d.ts +7 -4
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +13 -4
- package/dist/core/hooks/adapter/output.d.ts +2 -2
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.d.ts +7 -4
- package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.js +64 -24
- package/dist/core/hooks/adapter/wiring.d.ts +30 -4
- package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
- package/dist/core/hooks/adapter/wiring.js +89 -11
- package/dist/core/hooks/cli.d.ts +1 -1
- package/dist/core/hooks/cli.js +345 -400
- package/dist/core/hooks/codex-authorization.d.ts +30 -0
- package/dist/core/hooks/codex-authorization.d.ts.map +1 -0
- package/dist/core/hooks/codex-authorization.js +199 -0
- package/dist/core/hooks/effects/image-capture.d.ts +20 -34
- package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
- package/dist/core/hooks/effects/image-capture.js +212 -221
- package/dist/core/hooks/effects/index.d.ts +1 -9
- package/dist/core/hooks/effects/index.d.ts.map +1 -1
- package/dist/core/hooks/effects/index.js +1 -24
- package/dist/core/hooks/events/input-hash.d.ts +7 -0
- package/dist/core/hooks/events/input-hash.d.ts.map +1 -0
- package/dist/core/hooks/events/input-hash.js +43 -0
- package/dist/core/hooks/index.d.ts +4 -3
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js +2 -3
- package/dist/core/hooks/resolve/coord-root.d.ts +1 -1
- package/dist/core/hooks/resolve/coord-root.js +1 -1
- package/dist/core/hooks/resolve/owner.d.ts +16 -15
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +51 -42
- package/dist/core/hooks/resolve/transcript.d.ts +33 -3
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +155 -14
- package/dist/core/hooks/session-name-presence.d.ts +9 -10
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
- package/dist/core/hooks/session-name-presence.js +15 -15
- package/dist/core/hooks/unsafe-cross-shell.d.ts +1 -1
- package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -1
- package/dist/core/journal/index.d.ts +2 -2
- package/dist/core/journal/index.d.ts.map +1 -1
- package/dist/core/journal/index.js +9 -22
- package/dist/core/presence/blob.d.ts +8 -3
- package/dist/core/presence/blob.d.ts.map +1 -1
- package/dist/core/presence/blob.js +54 -41
- package/dist/core/presence/codec-digest.d.ts +29 -0
- package/dist/core/presence/codec-digest.d.ts.map +1 -0
- package/dist/core/presence/codec-digest.js +170 -0
- package/dist/core/presence/index.js +15 -1
- package/dist/core/presence/relay-client.d.ts +1 -1
- package/dist/core/presence/relay-client.d.ts.map +1 -1
- package/dist/core/presence/relay-client.js +5 -5
- package/dist/core/work/index.d.ts +1 -1
- package/dist/core/work/index.d.ts.map +1 -1
- package/dist/core/work/index.js +1 -1
- package/dist/core/work/read.d.ts +1 -1
- package/dist/core/work/read.d.ts.map +1 -1
- package/dist/core/work/read.js +1 -1
- package/dist/core/work/runner.d.ts.map +1 -1
- package/dist/core/work/runner.js +6 -0
- package/dist/core/work/state.d.ts +9 -0
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +17 -3
- package/dist/core/workflow/engine.js +24 -25
- package/dist/core/workflow/live-session-v3.d.ts +19 -0
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -0
- package/dist/core/workflow/live-session-v3.js +86 -0
- package/dist/core/workflow/scope-id.d.ts +3 -0
- package/dist/core/workflow/scope-id.d.ts.map +1 -0
- package/dist/core/workflow/scope-id.js +5 -0
- package/dist/core/workflow/workspaces/leases.d.ts +4 -0
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/leases.js +53 -19
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/browser/client.d.ts +41 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +203 -0
- package/dist/lib/browser/critique.d.ts +28 -2
- package/dist/lib/browser/critique.d.ts.map +1 -1
- package/dist/lib/browser/critique.js +74 -18
- package/dist/lib/browser/geometry.d.ts +1 -1
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +130 -6
- package/dist/lib/browser/index.d.ts +3 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +3 -0
- package/dist/lib/browser/qa-plan.d.ts +174 -0
- package/dist/lib/browser/qa-plan.d.ts.map +1 -0
- package/dist/lib/browser/qa-plan.js +321 -0
- package/dist/lib/browser/qa-reuse.d.ts +99 -0
- package/dist/lib/browser/qa-reuse.d.ts.map +1 -0
- package/dist/lib/browser/qa-reuse.js +222 -0
- package/dist/lib/browser/qa-snapshot.d.ts +64 -0
- package/dist/lib/browser/qa-snapshot.d.ts.map +1 -0
- package/dist/lib/browser/qa-snapshot.js +171 -0
- package/dist/lib/browser/runts.d.ts.map +1 -1
- package/dist/lib/browser/runts.js +22 -1
- package/dist/lib/browser/tiling.d.ts +71 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -0
- package/dist/lib/browser/tiling.js +118 -0
- package/dist/lib/context/index.d.ts +0 -3
- package/dist/lib/context/index.d.ts.map +1 -1
- package/dist/lib/context/index.js +20 -42
- package/dist/lib/council/index.d.ts +2 -2
- package/dist/lib/council/index.d.ts.map +1 -1
- package/dist/lib/council/index.js +9 -20
- package/dist/lib/docs-frontmatter.d.ts +1 -6
- package/dist/lib/docs-frontmatter.d.ts.map +1 -1
- package/dist/lib/docs-frontmatter.js +12 -78
- package/dist/lib/docs-index.d.ts +9 -0
- package/dist/lib/docs-index.d.ts.map +1 -1
- package/dist/lib/docs-index.js +32 -3
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +14 -30
- package/dist/lib/docs-metadata-audit.d.ts +19 -0
- package/dist/lib/docs-metadata-audit.d.ts.map +1 -0
- package/dist/lib/docs-metadata-audit.js +132 -0
- package/dist/lib/docs-metadata-managed.d.ts +23 -0
- package/dist/lib/docs-metadata-managed.d.ts.map +1 -0
- package/dist/lib/docs-metadata-managed.js +78 -0
- package/dist/lib/docs-metadata-sync.d.ts +20 -0
- package/dist/lib/docs-metadata-sync.d.ts.map +1 -0
- package/dist/lib/docs-metadata-sync.js +222 -0
- package/dist/lib/docs-metadata-v2-schema.d.ts +273 -0
- package/dist/lib/docs-metadata-v2-schema.d.ts.map +1 -0
- package/dist/lib/docs-metadata-v2-schema.js +134 -0
- package/dist/lib/docs-metadata-v2.d.ts +21 -0
- package/dist/lib/docs-metadata-v2.d.ts.map +1 -0
- package/dist/lib/docs-metadata-v2.js +424 -0
- package/dist/lib/docs-new.d.ts +11 -0
- package/dist/lib/docs-new.d.ts.map +1 -0
- package/dist/lib/docs-new.js +52 -0
- package/dist/lib/docs-sweep.d.ts.map +1 -1
- package/dist/lib/docs-sweep.js +45 -29
- package/dist/lib/headless/index.d.ts +98 -0
- package/dist/lib/headless/index.d.ts.map +1 -0
- package/dist/lib/headless/index.js +211 -0
- package/dist/lib/identities/assume.d.ts +4 -4
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +52 -68
- package/dist/lib/instructions/apply.d.ts +5 -4
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +32 -20
- package/dist/lib/instructions/bundle.d.ts +33 -0
- package/dist/lib/instructions/bundle.d.ts.map +1 -0
- package/dist/lib/instructions/bundle.js +149 -0
- package/dist/lib/instructions/splice.d.ts +0 -1
- package/dist/lib/instructions/splice.d.ts.map +1 -1
- package/dist/lib/instructions/splice.js +22 -6
- package/dist/lib/instructions/templates.d.ts +7 -5
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +79 -9
- package/package.json +27 -6
- package/schemas/config.schema.json +120 -2
- package/schemas/docs-metadata-v2.schema.json +441 -0
- package/schemas/event-v3.schema.json +24472 -0
- package/src/commander.ts +7 -1
- package/src/commands/adapter.ts +2 -2
- package/src/commands/agents.ts +1737 -570
- package/src/commands/artifacts.ts +7 -6
- package/src/commands/backup.ts +29 -21
- package/src/commands/browse.ts +349 -8
- package/src/commands/checkpoint.ts +4 -3
- package/src/commands/claude-desktop.ts +7 -5
- package/src/commands/context.ts +1 -6
- package/src/commands/decision.ts +27 -44
- package/src/commands/docs.ts +100 -33
- package/src/commands/doctor.ts +73 -8
- package/src/commands/events.ts +256 -0
- package/src/commands/governor.ts +18 -4
- package/src/commands/init.ts +264 -57
- package/src/commands/instructions.ts +129 -0
- package/src/commands/journal.ts +4 -13
- package/src/commands/ledger-v3.ts +111 -0
- package/src/commands/presence.ts +18 -11
- package/src/commands/sync.ts +1 -1
- package/src/commands/web.ts +67 -8
- package/src/commands/work.ts +28 -5
- package/src/core/adapter.ts +5 -0
- package/src/core/adapters/attest.ts +8 -3
- package/src/core/adapters/profiles.ts +4 -6
- package/src/core/agents/canonical-emit.ts +39 -28
- package/src/core/agents/cli.ts +242 -263
- package/src/core/agents/codex-archive-v3.ts +138 -0
- package/src/core/agents/coord-client.ts +75 -177
- package/src/core/agents/finalization.ts +120 -38
- package/src/core/agents/index.ts +5 -5
- package/src/core/agents/live-authority-v3.ts +375 -0
- package/src/core/agents/live-lifecycle-v3.ts +140 -0
- package/src/core/agents/live-observation-v3.ts +216 -0
- package/src/core/agents/render/prompt-context.ts +89 -55
- package/src/core/agents/render/session-context.ts +23 -32
- package/src/core/agents/rules/claim-conflict.ts +85 -126
- package/src/core/agents/rules/commit-conflict.ts +3 -14
- package/src/core/agents/rules/stop-hook.ts +239 -293
- package/src/core/agents/session-events.ts +137 -104
- package/src/core/agents/session-finalization-state-v3.ts +90 -0
- package/src/core/agents/session-finalizer-v3.ts +953 -0
- package/src/core/agents/session-name-display.ts +149 -0
- package/src/core/agents/state/activity-log.ts +6 -14
- package/src/core/agents/state/heartbeat-writer.ts +98 -242
- package/src/core/agents/state/live-coordination-view.ts +290 -0
- package/src/core/agents/state/session-state.ts +143 -0
- package/src/core/agents/state/stale-sweep.ts +40 -17
- package/src/core/artifacts/index.ts +4 -5
- package/src/core/config.ts +148 -3
- package/src/core/context/index.ts +9 -17
- package/src/core/events/span-parent.ts +46 -0
- package/src/core/events/v3/advance.ts +168 -0
- package/src/core/events/v3/authority-outbox.ts +548 -0
- package/src/core/events/v3/base-builder.ts +60 -0
- package/src/core/events/v3/base-contract.ts +882 -0
- package/src/core/events/v3/bootstrap.ts +226 -0
- package/src/core/events/v3/builder.ts +59 -0
- package/src/core/events/v3/canonical.ts +153 -0
- package/src/core/events/v3/capabilities.ts +171 -0
- package/src/core/events/v3/capability-drift.ts +177 -0
- package/src/core/events/v3/catalog.ts +202 -0
- package/src/core/events/v3/clock-order.ts +41 -0
- package/src/core/events/v3/contract.ts +365 -0
- package/src/core/events/v3/control.ts +576 -0
- package/src/core/events/v3/coordination-view.ts +193 -0
- package/src/core/events/v3/economics.ts +384 -0
- package/src/core/events/v3/finalization-view.ts +67 -0
- package/src/core/events/v3/fingerprint-keys.ts +260 -0
- package/src/core/events/v3/generated.ts +48 -0
- package/src/core/events/v3/ids.ts +33 -0
- package/src/core/events/v3/index.ts +322 -0
- package/src/core/events/v3/latency.ts +551 -0
- package/src/core/events/v3/live-feed.ts +319 -0
- package/src/core/events/v3/live-observation.ts +39 -0
- package/src/core/events/v3/live-routing.ts +135 -0
- package/src/core/events/v3/producers/command-recorder.ts +631 -0
- package/src/core/events/v3/producers/command.ts +201 -0
- package/src/core/events/v3/producers/coordination-recorder.ts +538 -0
- package/src/core/events/v3/producers/coordination.ts +355 -0
- package/src/core/events/v3/producers/hook-base.ts +578 -0
- package/src/core/events/v3/producers/hook.ts +119 -0
- package/src/core/events/v3/producers/intake.ts +319 -0
- package/src/core/events/v3/producers/recorder.ts +2805 -0
- package/src/core/events/v3/projection.ts +653 -0
- package/src/core/events/v3/reader.ts +1127 -0
- package/src/core/events/v3/recovery-record.ts +244 -0
- package/src/core/events/v3/recovery.ts +271 -0
- package/src/core/events/v3/span-state.ts +187 -0
- package/src/core/events/v3/targets.ts +182 -0
- package/src/core/events/v3/turn-telemetry.ts +259 -0
- package/src/core/events/v3/validate.ts +361 -0
- package/src/core/events/v3/writer.ts +419 -0
- package/src/core/governor/index.ts +3 -0
- package/src/core/governor/plan-api.ts +10 -2
- package/src/core/governor/read.ts +3 -0
- package/src/core/governor/state.ts +52 -5
- package/src/core/guard/config.ts +206 -0
- package/src/core/guard/coordinator.ts +227 -0
- package/src/core/guard/evaluator.ts +343 -0
- package/src/core/guard/evidence-v3.ts +227 -0
- package/src/core/guard/index.ts +35 -0
- package/src/core/guard/live-source-v3.ts +204 -0
- package/src/core/guard/storage.ts +188 -0
- package/src/core/guard/types.ts +152 -0
- package/src/core/hooks/adapter/detect.ts +28 -1
- package/src/core/hooks/adapter/events.ts +15 -6
- package/src/core/hooks/adapter/output.ts +7 -2
- package/src/core/hooks/adapter/parse.ts +81 -36
- package/src/core/hooks/adapter/wiring.ts +119 -13
- package/src/core/hooks/cli.ts +398 -422
- package/src/core/hooks/codex-authorization.ts +253 -0
- package/src/core/hooks/effects/image-capture.ts +228 -238
- package/src/core/hooks/effects/index.ts +1 -36
- package/src/core/hooks/events/input-hash.ts +47 -0
- package/src/core/hooks/index.ts +4 -11
- package/src/core/hooks/resolve/coord-root.ts +1 -1
- package/src/core/hooks/resolve/owner.ts +52 -45
- package/src/core/hooks/resolve/transcript.ts +165 -14
- package/src/core/hooks/session-name-presence.ts +14 -15
- package/src/core/hooks/unsafe-cross-shell.ts +1 -1
- package/src/core/journal/index.ts +15 -22
- package/src/core/presence/blob.ts +63 -38
- package/src/core/presence/codec-digest.ts +215 -0
- package/src/core/presence/index.ts +18 -1
- package/src/core/presence/relay-client.ts +5 -5
- package/src/core/work/index.ts +3 -0
- package/src/core/work/read.ts +3 -0
- package/src/core/work/runner.ts +6 -0
- package/src/core/work/state.ts +27 -3
- package/src/core/workflow/engine.ts +24 -24
- package/src/core/workflow/live-session-v3.ts +126 -0
- package/src/core/workflow/scope-id.ts +6 -0
- package/src/core/workflow/workspaces/leases.ts +56 -19
- package/src/index.ts +1 -1
- package/src/lib/browser/client.ts +230 -0
- package/src/lib/browser/critique.ts +104 -27
- package/src/lib/browser/geometry.ts +143 -14
- package/src/lib/browser/index.ts +34 -0
- package/src/lib/browser/qa-plan.ts +501 -0
- package/src/lib/browser/qa-reuse.ts +306 -0
- package/src/lib/browser/qa-snapshot.ts +223 -0
- package/src/lib/browser/runts.ts +27 -2
- package/src/lib/browser/tiling.ts +164 -0
- package/src/lib/context/index.ts +22 -46
- package/src/lib/council/index.ts +9 -21
- package/src/lib/docs-frontmatter.ts +8 -79
- package/src/lib/docs-index.ts +33 -3
- package/src/lib/docs-lint.ts +15 -29
- package/src/lib/docs-metadata-audit.ts +166 -0
- package/src/lib/docs-metadata-managed.ts +83 -0
- package/src/lib/docs-metadata-sync.ts +262 -0
- package/src/lib/docs-metadata-v2-schema.ts +138 -0
- package/src/lib/docs-metadata-v2.ts +646 -0
- package/src/lib/docs-new.ts +63 -0
- package/src/lib/docs-sweep.ts +42 -28
- package/src/lib/headless/index.ts +287 -0
- package/src/lib/identities/assume.ts +67 -86
- package/src/lib/instructions/apply.ts +33 -20
- package/src/lib/instructions/bundle.ts +199 -0
- package/src/lib/instructions/splice.ts +21 -7
- package/src/lib/instructions/templates.ts +85 -13
- package/dist/core/agents/cli-emit.d.ts +0 -27
- package/dist/core/agents/cli-emit.d.ts.map +0 -1
- package/dist/core/agents/cli-emit.js +0 -57
- package/dist/core/agents/codex-replay.d.ts +0 -29
- package/dist/core/agents/codex-replay.d.ts.map +0 -1
- package/dist/core/agents/codex-replay.js +0 -138
- package/dist/core/agents/events/consume.d.ts +0 -82
- package/dist/core/agents/events/consume.d.ts.map +0 -1
- package/dist/core/agents/events/consume.js +0 -195
- package/dist/core/agents/events/emit.d.ts +0 -42
- package/dist/core/agents/events/emit.d.ts.map +0 -1
- package/dist/core/agents/events/emit.js +0 -75
- package/dist/core/agents/events/ulid.d.ts +0 -11
- package/dist/core/agents/events/ulid.d.ts.map +0 -1
- package/dist/core/agents/events/ulid.js +0 -47
- package/dist/core/agents/state/heartbeat-projector.d.ts +0 -65
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +0 -1
- package/dist/core/agents/state/heartbeat-projector.js +0 -527
- package/dist/core/hooks/events/emit.d.ts +0 -31
- package/dist/core/hooks/events/emit.d.ts.map +0 -1
- package/dist/core/hooks/events/emit.js +0 -93
- package/dist/core/hooks/events/rotate.d.ts +0 -43
- package/dist/core/hooks/events/rotate.d.ts.map +0 -1
- package/dist/core/hooks/events/rotate.js +0 -142
- package/dist/core/hooks/events/schema.d.ts +0 -312
- package/dist/core/hooks/events/schema.d.ts.map +0 -1
- package/dist/core/hooks/events/schema.js +0 -12
- package/dist/core/hooks/events/ulid.d.ts +0 -10
- package/dist/core/hooks/events/ulid.d.ts.map +0 -1
- package/dist/core/hooks/events/ulid.js +0 -47
- package/dist/lib/docs-frontmatter-migrate.d.ts +0 -33
- package/dist/lib/docs-frontmatter-migrate.d.ts.map +0 -1
- package/dist/lib/docs-frontmatter-migrate.js +0 -364
- package/src/core/agents/cli-emit.ts +0 -64
- package/src/core/agents/codex-replay.ts +0 -163
- package/src/core/agents/events/consume.ts +0 -254
- package/src/core/agents/events/emit.ts +0 -115
- package/src/core/agents/events/ulid.ts +0 -51
- package/src/core/agents/state/heartbeat-projector.ts +0 -582
- package/src/core/hooks/events/emit.ts +0 -125
- package/src/core/hooks/events/rotate.ts +0 -151
- package/src/core/hooks/events/schema.ts +0 -538
- package/src/core/hooks/events/ulid.ts +0 -51
- package/src/lib/docs-frontmatter-migrate.ts +0 -427
package/src/lib/docs-sweep.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync as __existsSyncForDocs } from "node:fs";
|
|
2
2
|
import { resolve as __resolveForDocs } from "node:path";
|
|
3
|
-
import { readDocStatus } from "./docs-frontmatter.ts";
|
|
3
|
+
import { parseFrontmatter, readDocStatus } from "./docs-frontmatter.ts";
|
|
4
4
|
import { sh } from "./exec.ts";
|
|
5
5
|
|
|
6
6
|
// Module-level docs context, initialized by initDocsContext() before any
|
|
@@ -22,7 +22,7 @@ function isSubmoduleInitialized(name: string): boolean {
|
|
|
22
22
|
return __existsSyncForDocs(__resolveForDocs(REPO_ROOT, name, ".git"));
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
25
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
26
26
|
import { join, relative } from "node:path";
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -141,7 +141,18 @@ function walkMdFiles(dir: string, skipReadme = false): string[] {
|
|
|
141
141
|
return out;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
function
|
|
144
|
+
function metadataAgeDays(file: string, field: string, nowMs = Date.now()): number | null {
|
|
145
|
+
try {
|
|
146
|
+
const value = parseFrontmatter(readFileSync(file, "utf8")).data[field];
|
|
147
|
+
if (typeof value !== "string") return null;
|
|
148
|
+
const parsed = Date.parse(value);
|
|
149
|
+
return Number.isNaN(parsed) ? null : Math.floor((nowMs - parsed) / (1000 * 60 * 60 * 24));
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function sweepPlans(repoName: string, repoPath: string, items: SweepItem[]): void {
|
|
145
156
|
const plansDir = join(repoPath, "docs", "plans");
|
|
146
157
|
if (!existsSync(plansDir)) return;
|
|
147
158
|
|
|
@@ -150,7 +161,7 @@ function sweepPlans(repoName: string, repoPath: string, ages: AgeMap, items: Swe
|
|
|
150
161
|
const displayPath = join(repoName === "(root)" ? "" : repoName, rel);
|
|
151
162
|
const isArchived = rel.includes("/archive/");
|
|
152
163
|
const status = readDocStatus(full, "plan");
|
|
153
|
-
const age =
|
|
164
|
+
const age = metadataAgeDays(full, "status_changed_at");
|
|
154
165
|
if (age == null) continue;
|
|
155
166
|
|
|
156
167
|
if (!isArchived && status === "in-progress" && age > STALLED_PLAN_DAYS) {
|
|
@@ -159,7 +170,7 @@ function sweepPlans(repoName: string, repoPath: string, ages: AgeMap, items: Swe
|
|
|
159
170
|
repo: repoName,
|
|
160
171
|
path: displayPath,
|
|
161
172
|
ageDays: age,
|
|
162
|
-
message: `plan
|
|
173
|
+
message: `plan has remained in-progress for ${age}d; confirm it is still active or change status`,
|
|
163
174
|
});
|
|
164
175
|
}
|
|
165
176
|
if (!isArchived && status === "shipped" && age > UNARCHIVED_SHIPPED_DAYS) {
|
|
@@ -174,7 +185,7 @@ function sweepPlans(repoName: string, repoPath: string, ages: AgeMap, items: Swe
|
|
|
174
185
|
}
|
|
175
186
|
}
|
|
176
187
|
|
|
177
|
-
function sweepIssues(repoName: string, repoPath: string,
|
|
188
|
+
function sweepIssues(repoName: string, repoPath: string, items: SweepItem[]): void {
|
|
178
189
|
const issuesDir = join(repoPath, "docs", "issues");
|
|
179
190
|
if (!existsSync(issuesDir)) return;
|
|
180
191
|
|
|
@@ -185,7 +196,7 @@ function sweepIssues(repoName: string, repoPath: string, ages: AgeMap, items: Sw
|
|
|
185
196
|
const displayPath = join(repoName === "(root)" ? "" : repoName, rel);
|
|
186
197
|
const status = readDocStatus(full, "issue");
|
|
187
198
|
if (status !== "open") continue;
|
|
188
|
-
const age =
|
|
199
|
+
const age = metadataAgeDays(full, "status_changed_at");
|
|
189
200
|
if (age == null || age <= OPEN_ISSUE_DAYS) continue;
|
|
190
201
|
items.push({
|
|
191
202
|
kind: "open-issue-cold",
|
|
@@ -197,7 +208,7 @@ function sweepIssues(repoName: string, repoPath: string, ages: AgeMap, items: Sw
|
|
|
197
208
|
}
|
|
198
209
|
}
|
|
199
210
|
|
|
200
|
-
function sweepHandoffs(repoName: string, repoPath: string,
|
|
211
|
+
function sweepHandoffs(repoName: string, repoPath: string, items: SweepItem[]): void {
|
|
201
212
|
const handoffsDir = join(repoPath, "docs", "handoffs");
|
|
202
213
|
if (!existsSync(handoffsDir)) return;
|
|
203
214
|
|
|
@@ -205,7 +216,7 @@ function sweepHandoffs(repoName: string, repoPath: string, ages: AgeMap, items:
|
|
|
205
216
|
const rel = relative(repoPath, full);
|
|
206
217
|
const status = readDocStatus(full, "handoff");
|
|
207
218
|
if (status !== "open") continue;
|
|
208
|
-
const age =
|
|
219
|
+
const age = metadataAgeDays(full, "status_changed_at");
|
|
209
220
|
if (age == null || age <= COLD_HANDOFF_DAYS) continue;
|
|
210
221
|
const displayPath = join(repoName === "(root)" ? "" : repoName, rel);
|
|
211
222
|
items.push({
|
|
@@ -218,19 +229,23 @@ function sweepHandoffs(repoName: string, repoPath: string, ages: AgeMap, items:
|
|
|
218
229
|
}
|
|
219
230
|
}
|
|
220
231
|
|
|
221
|
-
function
|
|
222
|
-
const
|
|
223
|
-
if (!existsSync(
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
function sweepRunbooks(repoName: string, repoPath: string, items: SweepItem[]): void {
|
|
233
|
+
const docs = join(repoPath, "docs");
|
|
234
|
+
if (!existsSync(docs)) return;
|
|
235
|
+
for (const runbook of walkMdFiles(docs)) {
|
|
236
|
+
const metadata = parseFrontmatter(readFileSync(runbook, "utf8")).data;
|
|
237
|
+
if (metadata.schema !== "harnery-doc/v2" || metadata.type !== "runbook") continue;
|
|
238
|
+
const age = metadataAgeDays(runbook, "reviewed_at");
|
|
239
|
+
if (age == null || age <= RUNBOOK_DAYS) continue;
|
|
240
|
+
const rel = relative(repoPath, runbook);
|
|
241
|
+
items.push({
|
|
242
|
+
kind: "runbook-unverified",
|
|
243
|
+
repo: repoName,
|
|
244
|
+
path: join(repoName === "(root)" ? "" : repoName, rel),
|
|
245
|
+
ageDays: age,
|
|
246
|
+
message: `runbook has not been reviewed for ${age}d; verify it with docs metadata sync --reviewed`,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
234
249
|
}
|
|
235
250
|
|
|
236
251
|
function sweepTopicDocs(
|
|
@@ -324,10 +339,10 @@ export async function runSweep(opts: SweepOpts): Promise<SweepItem[]> {
|
|
|
324
339
|
for (let i = 0; i < filtered.length; i++) {
|
|
325
340
|
const { name, path } = filtered[i]!;
|
|
326
341
|
const ages = ageMaps[i]!;
|
|
327
|
-
sweepPlans(name, path,
|
|
328
|
-
sweepIssues(name, path,
|
|
329
|
-
sweepHandoffs(name, path,
|
|
330
|
-
|
|
342
|
+
sweepPlans(name, path, items);
|
|
343
|
+
sweepIssues(name, path, items);
|
|
344
|
+
sweepHandoffs(name, path, items);
|
|
345
|
+
sweepRunbooks(name, path, items);
|
|
331
346
|
sweepTopicDocs(name, path, ages, items);
|
|
332
347
|
await sweepDecisions(name, path, ages, items);
|
|
333
348
|
}
|
|
@@ -344,7 +359,6 @@ export async function runSweep(opts: SweepOpts): Promise<SweepItem[]> {
|
|
|
344
359
|
*/
|
|
345
360
|
export async function countColdHandoffs(): Promise<number> {
|
|
346
361
|
const items: SweepItem[] = [];
|
|
347
|
-
|
|
348
|
-
sweepHandoffs("(root)", REPO_ROOT, ages, items);
|
|
362
|
+
sweepHandoffs("(root)", REPO_ROOT, items);
|
|
349
363
|
return items.length;
|
|
350
364
|
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless harness calling — run a one-shot prompt (optionally with images)
|
|
3
|
+
* through a locally installed AI coding harness CLI and return its reply.
|
|
4
|
+
*
|
|
5
|
+
* Backends, in default preference order (subscription seats an embedding
|
|
6
|
+
* host already pays for, before any metered API a host might add on top):
|
|
7
|
+
*
|
|
8
|
+
* 1. claude-code `claude -p` JSON envelope on stdout
|
|
9
|
+
* 2. codex `codex exec` last message written to a file
|
|
10
|
+
* 3. cursor `cursor-agent -p` plain text on stdout
|
|
11
|
+
*
|
|
12
|
+
* Design rules, each learned from a live failure:
|
|
13
|
+
*
|
|
14
|
+
* - Every call runs from a NEUTRAL temp cwd holding only the staged images,
|
|
15
|
+
* so the nested session loads no repo instructions, hooks, or coordination
|
|
16
|
+
* rituals from the caller's checkout.
|
|
17
|
+
* - The child's stdin is CLOSED immediately. execFile leaves it open as a
|
|
18
|
+
* pipe, and codex interprets that as "more prompt coming" and blocks on
|
|
19
|
+
* it, then exits with no output.
|
|
20
|
+
* - An empty reply THROWS instead of returning "": a one-shot call that
|
|
21
|
+
* produced nothing was inconclusive, and callers gating on the result must
|
|
22
|
+
* fail closed rather than read silence as success.
|
|
23
|
+
* - `runHeadless` walks the backend chain PER CALL: a backend that is
|
|
24
|
+
* installed but errors (rate limit, timeout, transient exec failure) hands
|
|
25
|
+
* the same request to the next backend instead of failing the call. "On
|
|
26
|
+
* PATH" is not "working", and under parallel load the first backend can
|
|
27
|
+
* flake on a fraction of calls while the second runs clean.
|
|
28
|
+
*
|
|
29
|
+
* Env knobs (read through coordEnv, so the HARNERY_ prefix stays in one
|
|
30
|
+
* place): HARNERY_HEADLESS_BACKEND forces one backend and disables the
|
|
31
|
+
* fallback walk; HARNERY_HEADLESS_MODEL overrides the model passed to
|
|
32
|
+
* whichever backend runs.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { execFile } from "node:child_process";
|
|
36
|
+
import {
|
|
37
|
+
accessSync,
|
|
38
|
+
constants,
|
|
39
|
+
existsSync,
|
|
40
|
+
mkdtempSync,
|
|
41
|
+
readFileSync,
|
|
42
|
+
rmSync,
|
|
43
|
+
statSync,
|
|
44
|
+
writeFileSync,
|
|
45
|
+
} from "node:fs";
|
|
46
|
+
import { tmpdir } from "node:os";
|
|
47
|
+
import { delimiter, isAbsolute, join } from "node:path";
|
|
48
|
+
import { promisify } from "node:util";
|
|
49
|
+
import { coordEnv } from "../env.ts";
|
|
50
|
+
|
|
51
|
+
const execFileAsync = promisify(execFile);
|
|
52
|
+
|
|
53
|
+
/** Names accepted by `runHeadlessOn`, `runHeadless({backends})`, and the
|
|
54
|
+
* HARNERY_HEADLESS_BACKEND env knob. */
|
|
55
|
+
export type HeadlessBackendName = "claude-code" | "codex" | "cursor";
|
|
56
|
+
|
|
57
|
+
/** An image to stage into the call's neutral cwd. `data` is the PNG bytes
|
|
58
|
+
* (Buffer) or their base64 encoding (string). */
|
|
59
|
+
export interface HeadlessImage {
|
|
60
|
+
data: Buffer | string;
|
|
61
|
+
/** Staged filename inside the neutral dir (default `image-<n>.png`). */
|
|
62
|
+
name?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface HeadlessRequest {
|
|
66
|
+
/**
|
|
67
|
+
* The prompt, or a builder receiving the staged image paths. Backends that
|
|
68
|
+
* cannot attach an image natively (claude-code, cursor) rely on the prompt
|
|
69
|
+
* naming the staged paths so the harness reads them with its own tools;
|
|
70
|
+
* codex additionally attaches every image via `-i`.
|
|
71
|
+
*/
|
|
72
|
+
prompt: string | ((ctx: { imagePaths: string[] }) => string);
|
|
73
|
+
images?: HeadlessImage[];
|
|
74
|
+
/** Model override for this call; HARNERY_HEADLESS_MODEL wins over it. */
|
|
75
|
+
model?: string;
|
|
76
|
+
/** Kill the child after this long (default 240_000 ms). */
|
|
77
|
+
timeoutMs?: number;
|
|
78
|
+
/** Agentic turn budget where the backend supports one (default 4). */
|
|
79
|
+
maxTurns?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface HeadlessResult {
|
|
83
|
+
/** The harness's final reply text, never empty (empty replies throw). */
|
|
84
|
+
text: string;
|
|
85
|
+
/** Which backend produced it. */
|
|
86
|
+
backend: HeadlessBackendName;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface RunHeadlessOptions {
|
|
90
|
+
/** Preference order (default: HEADLESS_BACKENDS order). */
|
|
91
|
+
backends?: HeadlessBackendName[];
|
|
92
|
+
/** Walk the chain past a failing backend (default true). Forcing a backend
|
|
93
|
+
* via HARNERY_HEADLESS_BACKEND implies false. */
|
|
94
|
+
fallback?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const MAX_BUFFER = 32 * 1024 * 1024;
|
|
98
|
+
const DEFAULT_TIMEOUT_MS = 240_000;
|
|
99
|
+
const DEFAULT_MAX_TURNS = 4;
|
|
100
|
+
|
|
101
|
+
/** Cross-runtime `which`: walk PATH (and PATHEXT on Windows) for an
|
|
102
|
+
* executable. Node has no built-in and Bun.which only exists under Bun. */
|
|
103
|
+
export function whichBin(bin: string): string | undefined {
|
|
104
|
+
if (isAbsolute(bin)) return isExecutable(bin) ? bin : undefined;
|
|
105
|
+
const paths = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
106
|
+
const exts =
|
|
107
|
+
process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";") : [""];
|
|
108
|
+
for (const dir of paths) {
|
|
109
|
+
for (const ext of exts) {
|
|
110
|
+
const candidate = join(dir, bin + ext.toLowerCase());
|
|
111
|
+
if (isExecutable(candidate)) return candidate;
|
|
112
|
+
if (ext) {
|
|
113
|
+
const upper = join(dir, bin + ext);
|
|
114
|
+
if (isExecutable(upper)) return upper;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isExecutable(path: string): boolean {
|
|
122
|
+
try {
|
|
123
|
+
if (!statSync(path).isFile()) return false;
|
|
124
|
+
accessSync(path, constants.X_OK);
|
|
125
|
+
return true;
|
|
126
|
+
} catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface StagedCall {
|
|
132
|
+
dir: string;
|
|
133
|
+
imagePaths: string[];
|
|
134
|
+
prompt: string;
|
|
135
|
+
model?: string;
|
|
136
|
+
timeoutMs: number;
|
|
137
|
+
maxTurns: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Write the request's images into a fresh neutral dir and resolve the
|
|
141
|
+
* prompt against their staged paths. Caller must clean the dir up. */
|
|
142
|
+
function stageCall(req: HeadlessRequest): StagedCall {
|
|
143
|
+
const dir = mkdtempSync(join(tmpdir(), "harnery-headless-"));
|
|
144
|
+
const imagePaths = (req.images ?? []).map((img, i) => {
|
|
145
|
+
const path = join(dir, img.name ?? `image-${i + 1}.png`);
|
|
146
|
+
writeFileSync(path, typeof img.data === "string" ? Buffer.from(img.data, "base64") : img.data);
|
|
147
|
+
return path;
|
|
148
|
+
});
|
|
149
|
+
const prompt = typeof req.prompt === "function" ? req.prompt({ imagePaths }) : req.prompt;
|
|
150
|
+
return {
|
|
151
|
+
dir,
|
|
152
|
+
imagePaths,
|
|
153
|
+
prompt,
|
|
154
|
+
model: coordEnv("HEADLESS_MODEL") ?? req.model,
|
|
155
|
+
timeoutMs: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
156
|
+
maxTurns: req.maxTurns ?? DEFAULT_MAX_TURNS,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Run a harness CLI from the neutral dir with stdin CLOSED (see module
|
|
161
|
+
* comment: an open stdin pipe deadlocks codex). */
|
|
162
|
+
function execHarness(bin: string, args: string[], call: StagedCall) {
|
|
163
|
+
const pending = execFileAsync(bin, args, {
|
|
164
|
+
cwd: call.dir,
|
|
165
|
+
timeout: call.timeoutMs,
|
|
166
|
+
maxBuffer: MAX_BUFFER,
|
|
167
|
+
});
|
|
168
|
+
pending.child.stdin?.end();
|
|
169
|
+
return pending;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function assertReply(text: string, backend: HeadlessBackendName): HeadlessResult {
|
|
173
|
+
if (!text.trim()) throw new Error(`${backend}: empty reply (inconclusive; failing closed)`);
|
|
174
|
+
return { text, backend };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function runClaudeCode(bin: string, call: StagedCall): Promise<HeadlessResult> {
|
|
178
|
+
const args = ["-p", call.prompt, "--output-format", "json", "--max-turns", String(call.maxTurns)];
|
|
179
|
+
if (call.imagePaths.length) args.push("--allowedTools", "Read");
|
|
180
|
+
if (call.model) args.push("--model", call.model);
|
|
181
|
+
const { stdout } = await execHarness(bin, args, call);
|
|
182
|
+
const envelope = JSON.parse(stdout) as { is_error?: boolean; result?: unknown };
|
|
183
|
+
if (envelope.is_error) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
typeof envelope.result === "string" ? envelope.result : "claude-code: headless error",
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return assertReply(typeof envelope.result === "string" ? envelope.result : "", "claude-code");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function runCodex(bin: string, call: StagedCall): Promise<HeadlessResult> {
|
|
192
|
+
const outPath = join(call.dir, "last-message.txt");
|
|
193
|
+
const args = ["exec", "--skip-git-repo-check"];
|
|
194
|
+
for (const png of call.imagePaths) args.push("-i", png);
|
|
195
|
+
args.push("--output-last-message", outPath);
|
|
196
|
+
if (call.model) args.push("-m", call.model);
|
|
197
|
+
args.push(call.prompt);
|
|
198
|
+
await execHarness(bin, args, call);
|
|
199
|
+
return assertReply(existsSync(outPath) ? readFileSync(outPath, "utf-8") : "", "codex");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** `-f` trusts the neutral dir so cursor's read tool runs without a prompt. */
|
|
203
|
+
async function runCursor(bin: string, call: StagedCall): Promise<HeadlessResult> {
|
|
204
|
+
const args = ["-p", call.prompt, "--output-format", "text", "-f"];
|
|
205
|
+
if (call.model) args.push("--model", call.model);
|
|
206
|
+
const { stdout } = await execHarness(bin, args, call);
|
|
207
|
+
return assertReply(stdout, "cursor");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
type BackendRunner = (bin: string, call: StagedCall) => Promise<HeadlessResult>;
|
|
211
|
+
|
|
212
|
+
/** The backend registry in default preference order. */
|
|
213
|
+
export const HEADLESS_BACKENDS: ReadonlyArray<{ name: HeadlessBackendName; bin: string }> = [
|
|
214
|
+
{ name: "claude-code", bin: "claude" },
|
|
215
|
+
{ name: "codex", bin: "codex" },
|
|
216
|
+
{ name: "cursor", bin: "cursor-agent" },
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
const RUNNERS: Record<HeadlessBackendName, BackendRunner> = {
|
|
220
|
+
"claude-code": runClaudeCode,
|
|
221
|
+
codex: runCodex,
|
|
222
|
+
cursor: runCursor,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
function backendBin(name: HeadlessBackendName): string | undefined {
|
|
226
|
+
const entry = HEADLESS_BACKENDS.find((b) => b.name === name);
|
|
227
|
+
return entry ? whichBin(entry.bin) : undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Backends whose binary is on PATH right now, in preference order. Being
|
|
231
|
+
* listed means installed, not proven working — that is what the per-call
|
|
232
|
+
* fallback in `runHeadless` is for. */
|
|
233
|
+
export function availableHeadlessBackends(): HeadlessBackendName[] {
|
|
234
|
+
return HEADLESS_BACKENDS.filter((b) => whichBin(b.bin)).map((b) => b.name);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Run the request on exactly one named backend. Throws when the backend is
|
|
238
|
+
* not installed or the call fails. */
|
|
239
|
+
export async function runHeadlessOn(
|
|
240
|
+
name: HeadlessBackendName,
|
|
241
|
+
req: HeadlessRequest,
|
|
242
|
+
): Promise<HeadlessResult> {
|
|
243
|
+
const bin = backendBin(name);
|
|
244
|
+
if (!bin) throw new Error(`headless backend not installed: ${name}`);
|
|
245
|
+
const call = stageCall(req);
|
|
246
|
+
try {
|
|
247
|
+
return await RUNNERS[name](bin, call);
|
|
248
|
+
} finally {
|
|
249
|
+
rmSync(call.dir, { recursive: true, force: true });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Run the request on the first backend that succeeds, walking the preference
|
|
255
|
+
* order past installed-but-failing backends (unless fallback is disabled or a
|
|
256
|
+
* backend is forced via HARNERY_HEADLESS_BACKEND). Throws when no backend is
|
|
257
|
+
* installed, or every attempted backend failed — the error message carries
|
|
258
|
+
* each backend's failure so a flaky chain is diagnosable.
|
|
259
|
+
*/
|
|
260
|
+
export async function runHeadless(
|
|
261
|
+
req: HeadlessRequest,
|
|
262
|
+
opts: RunHeadlessOptions = {},
|
|
263
|
+
): Promise<HeadlessResult> {
|
|
264
|
+
const forced = coordEnv("HEADLESS_BACKEND") as HeadlessBackendName | undefined;
|
|
265
|
+
if (forced && !opts.backends) {
|
|
266
|
+
if (!HEADLESS_BACKENDS.some((b) => b.name === forced)) {
|
|
267
|
+
throw new Error(`unknown HARNERY_HEADLESS_BACKEND: ${forced}`);
|
|
268
|
+
}
|
|
269
|
+
return runHeadlessOn(forced, req);
|
|
270
|
+
}
|
|
271
|
+
const order = opts.backends ?? HEADLESS_BACKENDS.map((b) => b.name);
|
|
272
|
+
const installed = order.filter((name) => backendBin(name));
|
|
273
|
+
if (!installed.length) {
|
|
274
|
+
throw new Error(`no headless backend installed (looked for: ${order.join(", ")})`);
|
|
275
|
+
}
|
|
276
|
+
const fallback = opts.fallback ?? true;
|
|
277
|
+
const attempts = fallback ? installed : installed.slice(0, 1);
|
|
278
|
+
const failures: string[] = [];
|
|
279
|
+
for (const name of attempts) {
|
|
280
|
+
try {
|
|
281
|
+
return await runHeadlessOn(name, req);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
failures.push(`${name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
throw new Error(`every headless backend failed:\n ${failures.join("\n ")}`);
|
|
287
|
+
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The operation is serialized because "is this name live?" and "claim it"
|
|
5
5
|
* must be one critical section. Authoritative state is written twice on
|
|
6
|
-
* purpose: `.name-history`
|
|
7
|
-
* `
|
|
6
|
+
* purpose: `.name-history` supplies display metadata, while the canonical
|
|
7
|
+
* `coord.identity_attested` event makes replay and derived readers converge.
|
|
8
8
|
*
|
|
9
9
|
* Local collision policy: a fresh heartbeat alone is not enough to block.
|
|
10
10
|
* If the namesake has no live pid-map process (crashed session, healed
|
|
@@ -14,21 +14,17 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { randomUUID } from "node:crypto";
|
|
17
|
-
import {
|
|
18
|
-
existsSync,
|
|
19
|
-
mkdirSync,
|
|
20
|
-
readdirSync,
|
|
21
|
-
readFileSync,
|
|
22
|
-
statSync,
|
|
23
|
-
unlinkSync,
|
|
24
|
-
writeFileSync,
|
|
25
|
-
} from "node:fs";
|
|
17
|
+
import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
26
18
|
import { join } from "node:path";
|
|
27
19
|
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
20
|
+
import { recordLiveIdentityChangeV3 } from "../../core/agents/live-authority-v3.ts";
|
|
21
|
+
import { recordLiveSweepObservationV3 } from "../../core/agents/live-lifecycle-v3.ts";
|
|
22
|
+
import type { Heartbeat } from "../../core/agents/state/heartbeat-writer.ts";
|
|
23
|
+
import {
|
|
24
|
+
readLiveCoordinationRow,
|
|
25
|
+
readLiveCoordinationRows,
|
|
26
|
+
} from "../../core/agents/state/live-coordination-view.ts";
|
|
27
|
+
import { resolveForkAncestry } from "../../core/agents/state/names.ts";
|
|
32
28
|
import { instanceHasLivePid, removePidmapRowsForInstance } from "../../core/agents/state/pidmap.ts";
|
|
33
29
|
import { coordFreshnessSeconds } from "../../core/config.ts";
|
|
34
30
|
import { readRemoteMachines } from "../../core/presence/index.ts";
|
|
@@ -44,7 +40,7 @@ export type IdentityAssumeErrorCode =
|
|
|
44
40
|
| "identity_is_ancestor"
|
|
45
41
|
| "identity_not_found"
|
|
46
42
|
| "invalid_identity"
|
|
47
|
-
| "
|
|
43
|
+
| "no_live_generation"
|
|
48
44
|
| "not_session"
|
|
49
45
|
| "projection_failed";
|
|
50
46
|
|
|
@@ -91,22 +87,19 @@ export function findIdentityConflict(
|
|
|
91
87
|
instanceId: string,
|
|
92
88
|
name: string,
|
|
93
89
|
nowMs = Date.now(),
|
|
90
|
+
excludedInstanceIds: ReadonlySet<string> = new Set(),
|
|
94
91
|
): IdentityConflict | null {
|
|
95
92
|
const wanted = name.toLowerCase();
|
|
96
93
|
const cutoffMs = nowMs - coordFreshnessSeconds(coordRoot) * 1000;
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
// Malformed heartbeats are handled by stale sweep, not this command.
|
|
109
|
-
}
|
|
94
|
+
for (const row of readLiveCoordinationRows(coordRoot)) {
|
|
95
|
+
if (
|
|
96
|
+
row.instance_id === instanceId ||
|
|
97
|
+
excludedInstanceIds.has(row.instance_id) ||
|
|
98
|
+
!heartbeatIsFresh(row, cutoffMs)
|
|
99
|
+
)
|
|
100
|
+
continue;
|
|
101
|
+
if ((row.name ?? "").toLowerCase() === wanted) {
|
|
102
|
+
return { instance_id: row.instance_id, name: row.name ?? name, scope: "local" };
|
|
110
103
|
}
|
|
111
104
|
}
|
|
112
105
|
|
|
@@ -143,13 +136,20 @@ export function reclaimAbandonedLocalConflict(
|
|
|
143
136
|
let adapter: "claude-code" | "cursor" | "codex" = "claude-code";
|
|
144
137
|
let sessionId = conflict.instance_id;
|
|
145
138
|
let ageSecs: number | undefined;
|
|
139
|
+
const liveRow = readLiveCoordinationRow(coordRoot, conflict.instance_id);
|
|
140
|
+
if (liveRow) {
|
|
141
|
+
adapter = adapterOf(liveRow.platform);
|
|
142
|
+
sessionId = liveRow.session_id || conflict.instance_id;
|
|
143
|
+
const ts = Date.parse(liveRow.last_heartbeat);
|
|
144
|
+
if (Number.isFinite(ts)) ageSecs = Math.max(0, Math.floor((Date.now() - ts) / 1000));
|
|
145
|
+
}
|
|
146
146
|
if (existsSync(hbPath)) {
|
|
147
147
|
try {
|
|
148
148
|
const hb = JSON.parse(readFileSync(hbPath, "utf8")) as Heartbeat;
|
|
149
|
+
// Native producer identity is private cache metadata, not ledger authority.
|
|
150
|
+
// It is required to join the exact producer state when recording the sweep.
|
|
149
151
|
adapter = adapterOf(hb.platform);
|
|
150
152
|
sessionId = hb.session_id || conflict.instance_id;
|
|
151
|
-
const ts = Date.parse(hb.last_heartbeat);
|
|
152
|
-
if (Number.isFinite(ts)) ageSecs = Math.max(0, Math.floor((Date.now() - ts) / 1000));
|
|
153
153
|
} catch {
|
|
154
154
|
/* content unreadable — still reclaim the file */
|
|
155
155
|
}
|
|
@@ -160,23 +160,14 @@ export function reclaimAbandonedLocalConflict(
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
removePidmapRowsForInstance(coordRoot, conflict.instance_id);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
reason: "stale",
|
|
172
|
-
...(ageSecs !== undefined ? { age_secs: ageSecs } : {}),
|
|
173
|
-
reclaimed_by: "identity.assume",
|
|
174
|
-
},
|
|
175
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
176
|
-
} as Parameters<typeof emit>[1]);
|
|
177
|
-
} catch {
|
|
178
|
-
/* telemetry only */
|
|
179
|
-
}
|
|
163
|
+
recordLiveSweepObservationV3({
|
|
164
|
+
coordRoot,
|
|
165
|
+
owner: conflict.instance_id,
|
|
166
|
+
nativeSessionId: sessionId,
|
|
167
|
+
adapter,
|
|
168
|
+
observation: "stale_heartbeat",
|
|
169
|
+
ageMs: Math.max(0, (ageSecs ?? 0) * 1_000),
|
|
170
|
+
});
|
|
180
171
|
return true;
|
|
181
172
|
}
|
|
182
173
|
|
|
@@ -260,11 +251,11 @@ export function assumeIdentity(
|
|
|
260
251
|
): IdentityAssumeResult {
|
|
261
252
|
const release = acquireLock(coordRoot);
|
|
262
253
|
try {
|
|
263
|
-
const hb =
|
|
254
|
+
const hb = readLiveCoordinationRow(coordRoot, instanceId);
|
|
264
255
|
if (!hb) {
|
|
265
256
|
throw new IdentityAssumeError(
|
|
266
|
-
"
|
|
267
|
-
`no live
|
|
257
|
+
"no_live_generation",
|
|
258
|
+
`no authority-safe live V3 generation for instance '${instanceId}'`,
|
|
268
259
|
);
|
|
269
260
|
}
|
|
270
261
|
if (hb.kind && hb.kind !== "session") {
|
|
@@ -298,7 +289,16 @@ export function assumeIdentity(
|
|
|
298
289
|
let conflict = findIdentityConflict(coordRoot, instanceId, targetIdentity.name);
|
|
299
290
|
if (conflict && reclaimAbandonedLocalConflict(coordRoot, conflict)) {
|
|
300
291
|
reclaimedInstanceId = conflict.instance_id;
|
|
301
|
-
|
|
292
|
+
// The V3 sweep is intentionally provisional, so the generation remains
|
|
293
|
+
// replay-visible after its disposable cache is removed. Ignore that one
|
|
294
|
+
// reclaimed holder while still checking for any additional namesake.
|
|
295
|
+
conflict = findIdentityConflict(
|
|
296
|
+
coordRoot,
|
|
297
|
+
instanceId,
|
|
298
|
+
targetIdentity.name,
|
|
299
|
+
Date.now(),
|
|
300
|
+
new Set([reclaimedInstanceId]),
|
|
301
|
+
);
|
|
302
302
|
}
|
|
303
303
|
if (conflict) {
|
|
304
304
|
const where = conflict.scope === "remote" ? ` on ${conflict.machine}` : "";
|
|
@@ -312,15 +312,7 @@ export function assumeIdentity(
|
|
|
312
312
|
|
|
313
313
|
const previousName = hb.name || null;
|
|
314
314
|
const previousAgentId = hb.agent_id || null;
|
|
315
|
-
const
|
|
316
|
-
coordRoot,
|
|
317
|
-
instanceId,
|
|
318
|
-
identity.name,
|
|
319
|
-
identity.agent_id,
|
|
320
|
-
"session",
|
|
321
|
-
);
|
|
322
|
-
const changed =
|
|
323
|
-
history.changed || previousName !== identity.name || previousAgentId !== identity.agent_id;
|
|
315
|
+
const changed = previousName !== identity.name || previousAgentId !== identity.agent_id;
|
|
324
316
|
if (!changed) {
|
|
325
317
|
return {
|
|
326
318
|
changed: false,
|
|
@@ -336,34 +328,20 @@ export function assumeIdentity(
|
|
|
336
328
|
};
|
|
337
329
|
}
|
|
338
330
|
|
|
339
|
-
const emitted =
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
agent_id: identity.agent_id,
|
|
348
|
-
...(previousName ? { previous_name: previousName } : {}),
|
|
349
|
-
...(previousAgentId ? { previous_agent_id: previousAgentId } : {}),
|
|
350
|
-
...(reclaimedInstanceId ? { reclaimed_instance_id: reclaimedInstanceId } : {}),
|
|
351
|
-
},
|
|
352
|
-
},
|
|
353
|
-
{ coordRoot },
|
|
354
|
-
);
|
|
355
|
-
if (!emitted?.projected) {
|
|
356
|
-
throw new IdentityAssumeError(
|
|
357
|
-
"projection_failed",
|
|
358
|
-
"the durable name binding was recorded but event projection failed; rerun the command to heal it",
|
|
359
|
-
);
|
|
360
|
-
}
|
|
331
|
+
const emitted = recordLiveIdentityChangeV3({
|
|
332
|
+
coordRoot,
|
|
333
|
+
owner: instanceId,
|
|
334
|
+
nativeSessionId: hb.native_session_id ?? hb.session_id,
|
|
335
|
+
adapter: adapterOf(hb.platform),
|
|
336
|
+
name: identity.name,
|
|
337
|
+
identityId: identity.agent_id,
|
|
338
|
+
});
|
|
361
339
|
|
|
362
|
-
const projected =
|
|
340
|
+
const projected = readLiveCoordinationRow(coordRoot, instanceId);
|
|
363
341
|
if (projected?.name !== identity.name || projected.agent_id !== identity.agent_id) {
|
|
364
342
|
throw new IdentityAssumeError(
|
|
365
343
|
"projection_failed",
|
|
366
|
-
"
|
|
344
|
+
"coord.identity_attested was emitted but the V3 projection did not converge; rerun the command",
|
|
367
345
|
);
|
|
368
346
|
}
|
|
369
347
|
return {
|
|
@@ -375,7 +353,10 @@ export function assumeIdentity(
|
|
|
375
353
|
name: identity.name,
|
|
376
354
|
agent_id: identity.agent_id,
|
|
377
355
|
identity_created: created,
|
|
378
|
-
event_id:
|
|
356
|
+
event_id:
|
|
357
|
+
emitted.state === "recorded" && emitted.result.state === "recorded"
|
|
358
|
+
? emitted.result.event.event_id
|
|
359
|
+
: null,
|
|
379
360
|
reclaimed_instance_id: reclaimedInstanceId,
|
|
380
361
|
};
|
|
381
362
|
} finally {
|