harnery 0.33.0 → 0.34.1
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.map +1 -1
- package/dist/commander.js +4 -0
- 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 +1237 -590
- 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 +1 -1
- package/dist/commands/claude-desktop.d.ts.map +1 -1
- package/dist/commands/claude-desktop.js +3 -74
- 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.js +10 -1
- 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 +9 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +223 -51
- 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 +11 -5
- 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 +22 -22
- package/dist/core/agents/cli.js +207 -234
- 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 -81
- 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 +4 -5
- package/dist/core/agents/index.d.ts.map +1 -1
- package/dist/core/agents/index.js +4 -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 +4 -4
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +23 -58
- 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 +8 -32
- 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 +23 -55
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +56 -228
- 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 +4 -3
- package/dist/core/agents/state/session-state.d.ts.map +1 -1
- package/dist/core/agents/state/session-state.js +18 -9
- 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 +12 -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 +63 -25
- 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 +306 -444
- 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 +161 -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 +4 -3
- package/dist/core/presence/blob.d.ts.map +1 -1
- package/dist/core/presence/blob.js +45 -44
- 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/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/claude-desktop.d.ts +0 -47
- package/dist/lib/claude-desktop.d.ts.map +1 -1
- package/dist/lib/claude-desktop.js +1 -169
- 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 +1 -1
- package/dist/lib/instructions/bundle.d.ts.map +1 -1
- package/dist/lib/instructions/bundle.js +1 -1
- 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 +26 -5
- 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 +4 -0
- package/src/commands/adapter.ts +2 -2
- package/src/commands/agents.ts +1530 -593
- 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 +2 -101
- 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 +14 -1
- package/src/commands/events.ts +256 -0
- package/src/commands/governor.ts +18 -4
- package/src/commands/init.ts +253 -57
- package/src/commands/instructions.ts +1 -1
- package/src/commands/journal.ts +4 -13
- package/src/commands/ledger-v3.ts +111 -0
- package/src/commands/presence.ts +11 -10
- 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 +34 -25
- package/src/core/agents/cli.ts +236 -262
- package/src/core/agents/codex-archive-v3.ts +138 -0
- package/src/core/agents/coord-client.ts +75 -188
- package/src/core/agents/finalization.ts +120 -38
- package/src/core/agents/index.ts +4 -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 +29 -60
- package/src/core/agents/render/session-context.ts +10 -31
- 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 +82 -277
- package/src/core/agents/state/live-coordination-view.ts +290 -0
- package/src/core/agents/state/session-state.ts +24 -12
- 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 +14 -6
- package/src/core/hooks/adapter/output.ts +7 -2
- package/src/core/hooks/adapter/parse.ts +80 -38
- package/src/core/hooks/adapter/wiring.ts +119 -13
- package/src/core/hooks/cli.ts +352 -466
- 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 +171 -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 +48 -41
- package/src/core/presence/codec-digest.ts +215 -0
- 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/claude-desktop.ts +1 -232
- 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 +2 -2
- 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 -76
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +0 -1
- package/dist/core/agents/state/heartbeat-projector.js +0 -581
- 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 -341
- 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 -645
- 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 -582
- package/src/core/hooks/events/ulid.ts +0 -51
- package/src/lib/docs-frontmatter-migrate.ts +0 -427
package/dist/core/hooks/cli.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 4. Resolve instance_id (env → payload → pid-map walk).
|
|
9
9
|
* 5. Map event-name → canonical event_type.
|
|
10
10
|
* 6. Build event data from payload + resolvers (intent, transcript scan).
|
|
11
|
-
* 7.
|
|
11
|
+
* 7. Record the normalized observation in the canonical V3 ledger.
|
|
12
12
|
* 8. (Still also writes a debug breadcrumb to .harnery/debug/ for visibility.)
|
|
13
13
|
*
|
|
14
14
|
* Phase 2 ship criterion: confirms parser correctness across thousands of
|
|
@@ -21,29 +21,31 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
|
21
21
|
import { dirname, join } from "node:path";
|
|
22
22
|
import { coordEnv } from "../../lib/env.js";
|
|
23
23
|
import { buildInstructionBundle } from "../../lib/instructions/bundle.js";
|
|
24
|
-
import { replayCodexJsonl } from "../agents/codex-replay.js";
|
|
25
24
|
import { coordBinPath } from "../agents/coord-bin.js";
|
|
26
|
-
import { consumeSince, writeCursor } from "../agents/events/consume.js";
|
|
27
25
|
import { classifyWriteClaimFinalization, formatWriteClaimFinalizationDenial, } from "../agents/finalization.js";
|
|
28
|
-
import { evaluateStopHook } from "../agents/rules/stop-hook.js";
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
26
|
+
import { evaluateStopHook, STOP_REMEDIATION_MARKER } from "../agents/rules/stop-hook.js";
|
|
27
|
+
import { assistantTextStartsWithSessionNameBlock, isSessionNameRemediationCommand, sessionNameDisplayInstruction, sessionNameDisplayPending, toolResponseMintedSessionName, } from "../agents/session-name-display.js";
|
|
28
|
+
import { stampSessionNameSeen } from "../agents/state/heartbeat-writer.js";
|
|
29
|
+
import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.js";
|
|
31
30
|
import { writePidmapRow } from "../agents/state/pidmap.js";
|
|
32
|
-
import { shellMutationPaths } from "../agents/state/shell-mutation.js";
|
|
33
31
|
import { agentsRequireGitFinalization, resolveBinName } from "../config.js";
|
|
34
32
|
import { checkpointContext, completeContextRecovery, extractContextSample, markContextCompactionCompleted, prepareContextRecovery, readContextState, recordContextSample, } from "../context/index.js";
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
33
|
+
import { tryWriteLiveDisplayV3 } from "../events/v3/live-feed.js";
|
|
34
|
+
import { recordLiveHookSignalV3, resolveLiveEventLedgerRouteV3, } from "../events/v3/live-routing.js";
|
|
35
|
+
import { captureSpanClockV3 } from "../events/v3/span-state.js";
|
|
36
|
+
import { fetchPresence } from "../presence/index.js";
|
|
37
|
+
import { stableScopeId } from "../workflow/scope-id.js";
|
|
38
|
+
import { detectAdapter, shouldSkipHookAdapter } from "./adapter/detect.js";
|
|
37
39
|
import { extractBashCommand, extractToolDescription, normalizeEventName, parsePayload, } from "./adapter/parse.js";
|
|
38
40
|
import { codexWslFileLinkTelemetry, inspectCodexWslBridge, isWslUncPath, renderCodexWslFileLinkContext, } from "./codex-wsl-bridge.js";
|
|
39
|
-
import { captureImages, detectPresence, imageJanitor, journalArchive, journalJanitor, journalRecoveryCue, playSound, resetSoundCounters, runSessionSyncExtension,
|
|
40
|
-
import {
|
|
41
|
+
import { captureImages, detectPresence, imageJanitor, journalArchive, journalJanitor, journalRecoveryCue, playSound, recordImageArtifactsV3, resetSoundCounters, runSessionSyncExtension, soundForEvent, } from "./effects/index.js";
|
|
42
|
+
import { toolInputHash, toolTargetHash } from "./events/input-hash.js";
|
|
41
43
|
import { canonicalize } from "./guard-path.js";
|
|
42
44
|
import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.js";
|
|
43
45
|
import { findCoordRoot } from "./resolve/coord-root.js";
|
|
44
46
|
import { extractIntentComment, resolveIntent } from "./resolve/intent.js";
|
|
45
47
|
import { resolveOwner } from "./resolve/owner.js";
|
|
46
|
-
import {
|
|
48
|
+
import { inspectSessionNameDisplayImmediately, scanAssistantTextIncludes, scanSessionNameDisplayedImmediately, scanStatusBoxPresent, scanTranscriptModel, } from "./resolve/transcript.js";
|
|
47
49
|
import { sessionNamePresence } from "./session-name-presence.js";
|
|
48
50
|
import { unsafeCrossShellReason } from "./unsafe-cross-shell.js";
|
|
49
51
|
function parseArgv(argv) {
|
|
@@ -119,7 +121,7 @@ function logError(coordRoot, err, context) {
|
|
|
119
121
|
/**
|
|
120
122
|
* Spawn `agent-coord assign-name <owner> <kind>` to mint or recover the
|
|
121
123
|
* hurricane-style name for this owner. Returns null on any failure so
|
|
122
|
-
* session.
|
|
124
|
+
* session.started emission never breaks the adapter flow.
|
|
123
125
|
*
|
|
124
126
|
* Lives at agent-hooks side (not agent-coord) to keep emitter/consumer
|
|
125
127
|
* separation: we spawn rather than import.
|
|
@@ -151,7 +153,7 @@ function assignNameViaAgentCoord(coordRoot, instanceId, kind, forkedFrom) {
|
|
|
151
153
|
}
|
|
152
154
|
/**
|
|
153
155
|
* Direct (in-process) pidmap write, avoiding the spawn overhead of going via
|
|
154
|
-
* the agent-coord CLI for every session.
|
|
156
|
+
* the agent-coord CLI for every session.started signal. Pid-map rows
|
|
155
157
|
* are essential for `harn agents whoami` ppid resolution.
|
|
156
158
|
*
|
|
157
159
|
* This used to inline its own copy of the write to keep this module's
|
|
@@ -185,18 +187,18 @@ function summarizeOutput(value, headTail = 500) {
|
|
|
185
187
|
function buildEventData(eventType, ctx) {
|
|
186
188
|
const p = ctx.payload;
|
|
187
189
|
switch (eventType) {
|
|
188
|
-
case "session.
|
|
190
|
+
case "session.started": {
|
|
189
191
|
const adapterPlatform = ctx.adapter === "claude-code"
|
|
190
192
|
? "claude-code"
|
|
191
193
|
: ctx.adapter === "cursor"
|
|
192
194
|
? "cursor"
|
|
193
195
|
: "codex";
|
|
194
196
|
// Recorded fork lineage is NOT detected here. On claude-code a fork
|
|
195
|
-
// never fires its own session.
|
|
197
|
+
// never fires its own session.started — SessionStart fires under the
|
|
196
198
|
// PARENT's session id (source=resume) before the fork id is minted
|
|
197
199
|
// (verified 2026-08-05) — so detection at this point can only mislabel
|
|
198
200
|
// the resumed parent. The fork's new instance is caught by the
|
|
199
|
-
// tool.
|
|
201
|
+
// tool.requested heal path instead. The forkedFrom plumbing below stays
|
|
200
202
|
// for adapters that DO report a parent at session start.
|
|
201
203
|
const forkedFrom = undefined;
|
|
202
204
|
// Assign (or recover) name + kind via agent-coord. Idempotent: resume
|
|
@@ -218,7 +220,7 @@ function buildEventData(eventType, ctx) {
|
|
|
218
220
|
cwd: p?.cwd ?? process.cwd(),
|
|
219
221
|
// Claude Code's SessionStart payload omits `model` (Codex + Cursor
|
|
220
222
|
// supply it). Fall back to the transcript, populated on `resume`, and
|
|
221
|
-
// backfilled later by `turn.
|
|
223
|
+
// backfilled later by `turn.completed` for a fresh startup session.
|
|
222
224
|
model: p?.model ?? scanTranscriptModel(p?.transcript_path),
|
|
223
225
|
pid: adapterPid,
|
|
224
226
|
source: p?.source,
|
|
@@ -254,23 +256,30 @@ function buildEventData(eventType, ctx) {
|
|
|
254
256
|
: {}),
|
|
255
257
|
};
|
|
256
258
|
}
|
|
257
|
-
case "session.
|
|
259
|
+
case "session.ended":
|
|
258
260
|
return {
|
|
259
261
|
ended_at: new Date().toISOString(),
|
|
260
262
|
clean_exit: p?.clean_exit ?? true,
|
|
261
263
|
};
|
|
262
|
-
case "
|
|
264
|
+
case "turn.started": {
|
|
265
|
+
// Cursor can deliver beforeSubmitPrompt before sessionStart. Ensure that
|
|
266
|
+
// high-confidence prompt bootstrap also mints durable display identity;
|
|
267
|
+
// a later SessionStart remains idempotent.
|
|
268
|
+
if (ctx.adapter === "cursor" &&
|
|
269
|
+
!readLiveCoordinationRow(ctx.coordRoot, ctx.instanceId)?.name) {
|
|
270
|
+
assignNameViaAgentCoord(ctx.coordRoot, ctx.instanceId, "session");
|
|
271
|
+
}
|
|
263
272
|
const prompt = p?.prompt ?? "";
|
|
264
273
|
const { value, truncated } = clampString(prompt, 4000);
|
|
265
274
|
return { prompt_text: value, ...(truncated ? { truncated: true } : {}) };
|
|
266
275
|
}
|
|
267
|
-
case "turn.
|
|
276
|
+
case "turn.completed": {
|
|
268
277
|
const lastAssistantMessage = p?.raw.last_assistant_message ?? "";
|
|
269
278
|
const fileLinkTelemetry = ctx.adapter === "codex"
|
|
270
279
|
? codexWslFileLinkTelemetry(ctx.coordRoot, p?.cwd, lastAssistantMessage)
|
|
271
280
|
: null;
|
|
272
281
|
return {
|
|
273
|
-
// Backfill the model for adapters that omit it at session.
|
|
282
|
+
// Backfill the model for adapters that omit it at session.started
|
|
274
283
|
// (Claude Code). The transcript is populated with assistant turns by
|
|
275
284
|
// Stop-hook time, so this resolves even for fresh `startup` sessions.
|
|
276
285
|
model: p?.model ?? scanTranscriptModel(p?.transcript_path),
|
|
@@ -284,7 +293,7 @@ function buildEventData(eventType, ctx) {
|
|
|
284
293
|
// Box present if the transcript scan finds it OR the final assistant
|
|
285
294
|
// message carries the `┌─ agent-` prefix. The latter covers codex's
|
|
286
295
|
// text-only stop (box in last_assistant_message, no transcript), which
|
|
287
|
-
// the verdict now sees because agent-hook emits this turn.
|
|
296
|
+
// the verdict now sees because agent-hook emits this turn.completed itself
|
|
288
297
|
// (the previous path passed those via the no-history fail-open).
|
|
289
298
|
status_box_present: scanStatusBoxPresent(p?.transcript_path) || lastAssistantMessage.includes("┌─ agent-"),
|
|
290
299
|
// Shadow measurement for the rule-2/3 detector: the loose scan above
|
|
@@ -302,12 +311,12 @@ function buildEventData(eventType, ctx) {
|
|
|
302
311
|
// and which name that refers to. Reported on every stop while a name
|
|
303
312
|
// exists (the stop-hook.session_name verdict reads it per turn); the
|
|
304
313
|
// transcript scan itself stops once the name has been sighted.
|
|
305
|
-
...sessionNamePresence(ctx.coordRoot, ctx.instanceId,
|
|
314
|
+
...sessionNamePresence(ctx.coordRoot, ctx.instanceId, (name) => scanSessionNameDisplayedImmediately(p?.transcript_path, name, assistantTextStartsWithSessionNameBlock)),
|
|
306
315
|
...(fileLinkTelemetry ?? {}),
|
|
307
316
|
stop_hook_active: p?.stop_hook_active,
|
|
308
317
|
};
|
|
309
318
|
}
|
|
310
|
-
case "
|
|
319
|
+
case "agent.started": {
|
|
311
320
|
const subagentCallId = p?.raw.subagent_id ?? p?.raw.agent_id;
|
|
312
321
|
// Subagents inherit parent's name via the resolve-name session_id path
|
|
313
322
|
// (agent-coord/state/names.ts → kind=transient). Use the call ID as the
|
|
@@ -325,12 +334,12 @@ function buildEventData(eventType, ctx) {
|
|
|
325
334
|
parent_session_id: p?.parent_session_id,
|
|
326
335
|
};
|
|
327
336
|
}
|
|
328
|
-
case "
|
|
337
|
+
case "agent.completed": {
|
|
329
338
|
const status = p?.exit_status;
|
|
330
339
|
const normalized = status === "error" || status === "interrupted" ? status : "ok";
|
|
331
340
|
return { exit_status: normalized, reason: p?.reason };
|
|
332
341
|
}
|
|
333
|
-
case "tool.
|
|
342
|
+
case "tool.requested": {
|
|
334
343
|
const toolName = p?.tool_name ?? "unknown";
|
|
335
344
|
const command = extractBashCommand(toolName, p?.tool_input);
|
|
336
345
|
const description = extractToolDescription(p?.tool_input);
|
|
@@ -345,13 +354,15 @@ function buildEventData(eventType, ctx) {
|
|
|
345
354
|
return {
|
|
346
355
|
tool_name: toolName,
|
|
347
356
|
tool_input: clamped.value,
|
|
357
|
+
input_hash: toolInputHash(toolName, p?.tool_input ?? null),
|
|
358
|
+
target_hash: toolTargetHash(toolName, p?.tool_input ?? null),
|
|
348
359
|
intent,
|
|
349
360
|
intent_source: source,
|
|
350
361
|
tool_use_id: p?.tool_use_id,
|
|
351
362
|
...(clamped.truncated ? { truncated: true } : {}),
|
|
352
363
|
};
|
|
353
364
|
}
|
|
354
|
-
case "
|
|
365
|
+
case "wait.started": {
|
|
355
366
|
const description = extractToolDescription(p?.tool_input);
|
|
356
367
|
const reason = description ? clampString(description, 500).value : undefined;
|
|
357
368
|
return {
|
|
@@ -360,30 +371,27 @@ function buildEventData(eventType, ctx) {
|
|
|
360
371
|
...(reason ? { reason } : {}),
|
|
361
372
|
};
|
|
362
373
|
}
|
|
363
|
-
case "tool.
|
|
364
|
-
const toolName = p?.tool_name ?? "unknown";
|
|
365
|
-
const summary = summarizeOutput(p?.tool_response);
|
|
366
|
-
return {
|
|
367
|
-
tool_name: toolName,
|
|
368
|
-
output_summary: summary.summary,
|
|
369
|
-
exit_status: "ok",
|
|
370
|
-
duration_ms: 0, // Phase 3 pairs pre/post via tool_use_id
|
|
371
|
-
tool_use_id: p?.tool_use_id,
|
|
372
|
-
...(summary.truncated ? { truncated: true } : {}),
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
case "tool.post_use_failure": {
|
|
374
|
+
case "tool.completed": {
|
|
376
375
|
const toolName = p?.tool_name ?? "unknown";
|
|
377
376
|
const summary = summarizeOutput(p?.tool_response);
|
|
378
|
-
return
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
377
|
+
return ctx.eventName === "post-tool-use-failure"
|
|
378
|
+
? {
|
|
379
|
+
tool_name: toolName,
|
|
380
|
+
error: summary.summary,
|
|
381
|
+
duration_ms: 0,
|
|
382
|
+
tool_use_id: p?.tool_use_id,
|
|
383
|
+
...(summary.truncated ? { truncated: true } : {}),
|
|
384
|
+
}
|
|
385
|
+
: {
|
|
386
|
+
tool_name: toolName,
|
|
387
|
+
output_summary: summary.summary,
|
|
388
|
+
exit_status: "ok",
|
|
389
|
+
duration_ms: 0,
|
|
390
|
+
tool_use_id: p?.tool_use_id,
|
|
391
|
+
...(summary.truncated ? { truncated: true } : {}),
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
case "context.compaction_started": {
|
|
387
395
|
const metadata = objectRecord(p?.raw.compact_metadata);
|
|
388
396
|
return {
|
|
389
397
|
trigger: stringField(p?.raw.trigger) ?? stringField(metadata?.trigger),
|
|
@@ -392,7 +400,7 @@ function buildEventData(eventType, ctx) {
|
|
|
392
400
|
numberField(metadata?.pre_compact_tokens),
|
|
393
401
|
};
|
|
394
402
|
}
|
|
395
|
-
case "context.
|
|
403
|
+
case "context.compaction_completed": {
|
|
396
404
|
const metadata = objectRecord(p?.raw.compact_metadata);
|
|
397
405
|
return {
|
|
398
406
|
trigger: stringField(p?.raw.trigger) ?? stringField(metadata?.trigger),
|
|
@@ -427,9 +435,36 @@ function numberField(value) {
|
|
|
427
435
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
428
436
|
}
|
|
429
437
|
async function main() {
|
|
438
|
+
const hookStartedAt = performance.now();
|
|
439
|
+
const hookClock = captureSpanClockV3();
|
|
430
440
|
const { eventName, extra } = parseArgv(process.argv.slice(2));
|
|
431
441
|
const adapter = detectAdapter(process.argv.slice(2));
|
|
432
442
|
const raw = await readStdin();
|
|
443
|
+
// Cursor executes the Claude Code project hooks too on hosts wired for both
|
|
444
|
+
// adapters, piping them its own payload (identifiable by the top-level
|
|
445
|
+
// cursor_version envelope field). That stray `--adapter claude-code`
|
|
446
|
+
// dispatch must not record (twin generation) or play Claude-Code-only
|
|
447
|
+
// sounds, so it bails here, before every effect. Cursor's own
|
|
448
|
+
// `--adapter cursor` dispatch of the same payload carries the session.
|
|
449
|
+
if (shouldSkipHookAdapter(adapter, raw)) {
|
|
450
|
+
if (coordEnv("AGENT_COORD_OFF") !== "1") {
|
|
451
|
+
const coordRoot = findCoordRoot(process.cwd());
|
|
452
|
+
if (coordRoot) {
|
|
453
|
+
appendDebug(coordRoot, {
|
|
454
|
+
ts: new Date().toISOString(),
|
|
455
|
+
event_name: eventName,
|
|
456
|
+
adapter,
|
|
457
|
+
extra_argv: extra,
|
|
458
|
+
payload_bytes: raw.length,
|
|
459
|
+
cwd: process.cwd(),
|
|
460
|
+
pid: process.pid,
|
|
461
|
+
ppid: process.ppid,
|
|
462
|
+
skipped: "cursor-payload-claude-adapter",
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return 0;
|
|
467
|
+
}
|
|
433
468
|
// Kill-switch-INDEPENDENT effects: notification sounds fire BEFORE the
|
|
434
469
|
// HARNERY_AGENT_COORD_OFF gate so audible feedback survives incident-triage
|
|
435
470
|
// bypass: sound playback happens before the kill-switch bailout.
|
|
@@ -460,6 +495,7 @@ async function main() {
|
|
|
460
495
|
const coordRoot = findCoordRoot(process.cwd());
|
|
461
496
|
if (!coordRoot)
|
|
462
497
|
return 0;
|
|
498
|
+
const ledgerRoute = resolveLiveEventLedgerRouteV3(coordRoot);
|
|
463
499
|
// Always log a breadcrumb, useful when an event_type maps to null or owner
|
|
464
500
|
// resolution fails. Stays cheap (one append) and self-prunes via repo log
|
|
465
501
|
// rotation policy.
|
|
@@ -483,7 +519,10 @@ async function main() {
|
|
|
483
519
|
return 0;
|
|
484
520
|
}
|
|
485
521
|
const payload = parsePayload(raw, adapter);
|
|
486
|
-
const owner = resolveOwner({
|
|
522
|
+
const owner = resolveOwner({
|
|
523
|
+
payload: payload?.raw ?? null,
|
|
524
|
+
coordRoot,
|
|
525
|
+
});
|
|
487
526
|
if (!owner) {
|
|
488
527
|
appendDebug(coordRoot, {
|
|
489
528
|
...debugBase,
|
|
@@ -499,37 +538,98 @@ async function main() {
|
|
|
499
538
|
raw,
|
|
500
539
|
adapter,
|
|
501
540
|
instanceId: owner.instance_id,
|
|
541
|
+
eventName,
|
|
502
542
|
});
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
543
|
+
const turnRitual = norm.event_type === "turn.completed"
|
|
544
|
+
? {
|
|
545
|
+
status_box_present: data.status_box_present === true,
|
|
546
|
+
status_box_present_strict: data.status_box_present_strict === true,
|
|
547
|
+
session_name_required: typeof data.session_name_present_for === "string",
|
|
548
|
+
session_name_present: data.session_name_present === true,
|
|
549
|
+
}
|
|
550
|
+
: undefined;
|
|
551
|
+
const stopRemediation = norm.event_type === "turn.started" &&
|
|
552
|
+
typeof data.prompt_text === "string" &&
|
|
553
|
+
data.prompt_text.includes(STOP_REMEDIATION_MARKER);
|
|
554
|
+
if (ledgerRoute.state === "blocked") {
|
|
555
|
+
appendDebug(coordRoot, {
|
|
556
|
+
...debugBase,
|
|
557
|
+
skipped: "v3-control-blocked",
|
|
558
|
+
reason: ledgerRoute.reason,
|
|
559
|
+
event_type: norm.event_type,
|
|
560
|
+
owner_source: owner.source,
|
|
561
|
+
});
|
|
562
|
+
return 0;
|
|
563
|
+
}
|
|
564
|
+
let capturedImages = [];
|
|
565
|
+
if (norm.event_type === "tool.requested" ||
|
|
566
|
+
(norm.event_type === "tool.completed" && eventName === "post-tool-use")) {
|
|
567
|
+
try {
|
|
568
|
+
capturedImages = captureImages(coordRoot, norm.event_type, payload);
|
|
569
|
+
}
|
|
570
|
+
catch (err) {
|
|
571
|
+
logError(coordRoot, err, { phase: "image-capture" });
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
const v3Result = recordLiveHookSignalV3({
|
|
575
|
+
coordRoot,
|
|
576
|
+
route: ledgerRoute,
|
|
577
|
+
eventName,
|
|
578
|
+
payload,
|
|
510
579
|
adapter,
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
580
|
+
instanceId: owner.instance_id,
|
|
581
|
+
...(coordEnv("WORKFLOW_CHILD") === "1" && coordEnv("WORKFLOW_RUN_ID")
|
|
582
|
+
? {
|
|
583
|
+
run_id: stableScopeId("run", coordEnv("WORKFLOW_RUN_ID")),
|
|
584
|
+
workflow_id: stableScopeId("wf", coordEnv("WORKFLOW_RUN_ID")),
|
|
585
|
+
...(coordEnv("WORKFLOW_AGENT_ID")
|
|
586
|
+
? { workflow_agent_id: coordEnv("WORKFLOW_AGENT_ID") }
|
|
587
|
+
: {}),
|
|
588
|
+
}
|
|
589
|
+
: {}),
|
|
590
|
+
...(adapter === "codex" && isWslUncPath(payload?.cwd) ? { bridge: "codex-wsl" } : {}),
|
|
591
|
+
hook_name: eventName,
|
|
592
|
+
hook_duration_ms: Math.max(0, Math.floor(performance.now() - hookStartedAt)),
|
|
593
|
+
monotonic_ns: hookClock.monotonic_ns,
|
|
594
|
+
...(stopRemediation ? { stop_remediation: true } : {}),
|
|
595
|
+
...(turnRitual ? { turn_ritual: turnRitual } : {}),
|
|
596
|
+
...(coordEnv("EXPERIMENT_DEFER_V3_DRAIN") === "1" ? { defer_drain: true } : {}),
|
|
519
597
|
});
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
598
|
+
const v3EventId = v3Result && "event" in v3Result
|
|
599
|
+
? v3Result.event.event_id
|
|
600
|
+
: v3Result && "event_id" in v3Result
|
|
601
|
+
? v3Result.event_id
|
|
602
|
+
: undefined;
|
|
603
|
+
if (v3Result?.state === "recorded" && capturedImages.length > 0) {
|
|
526
604
|
try {
|
|
527
|
-
|
|
605
|
+
recordImageArtifactsV3(coordRoot, v3Result.event, capturedImages);
|
|
528
606
|
}
|
|
529
607
|
catch (err) {
|
|
530
|
-
logError(coordRoot, err, { phase: "
|
|
608
|
+
logError(coordRoot, err, { phase: "image-artifact-observation" });
|
|
531
609
|
}
|
|
532
610
|
}
|
|
611
|
+
if (norm.event_type === "tool.requested" &&
|
|
612
|
+
v3Result &&
|
|
613
|
+
v3Result.state === "recorded" &&
|
|
614
|
+
"generation_id" in v3Result.event.scope) {
|
|
615
|
+
const intent = typeof data.intent === "string" ? data.intent : undefined;
|
|
616
|
+
if (intent && intent !== "(no intent)") {
|
|
617
|
+
tryWriteLiveDisplayV3(coordRoot, {
|
|
618
|
+
generation_id: v3Result.event.scope.generation_id,
|
|
619
|
+
event_id: v3Result.event.event_id,
|
|
620
|
+
...(typeof data.tool_name === "string" ? { executable: data.tool_name } : {}),
|
|
621
|
+
intent_display: intent,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
appendDebug(coordRoot, {
|
|
626
|
+
...debugBase,
|
|
627
|
+
event_type: norm.event_type,
|
|
628
|
+
owner_source: owner.source,
|
|
629
|
+
...(v3EventId ? { event_v3_id: v3EventId } : {}),
|
|
630
|
+
...(v3Result ? { event_v3_state: v3Result.state } : {}),
|
|
631
|
+
...(v3Result && "reason" in v3Result ? { event_v3_reason: v3Result.reason } : {}),
|
|
632
|
+
});
|
|
533
633
|
// Context telemetry is opportunistic and truthful: only persist a sample
|
|
534
634
|
// when the adapter payload actually exposes usage/window data. Identical
|
|
535
635
|
// measurements are de-duplicated before they reach the canonical stream.
|
|
@@ -544,22 +644,7 @@ async function main() {
|
|
|
544
644
|
});
|
|
545
645
|
if (sample) {
|
|
546
646
|
const recorded = recordContextSample(coordRoot, owner.instance_id, sample);
|
|
547
|
-
|
|
548
|
-
emit(coordRoot, {
|
|
549
|
-
event_type: "context.sampled",
|
|
550
|
-
instance_id: owner.instance_id,
|
|
551
|
-
session_id: sessionId,
|
|
552
|
-
adapter,
|
|
553
|
-
data: {
|
|
554
|
-
model: sample.model,
|
|
555
|
-
used_tokens: sample.used_tokens,
|
|
556
|
-
window_tokens: sample.window_tokens,
|
|
557
|
-
used_percent: sample.used_percent,
|
|
558
|
-
telemetry_source: sample.source,
|
|
559
|
-
confidence: sample.confidence,
|
|
560
|
-
},
|
|
561
|
-
});
|
|
562
|
-
}
|
|
647
|
+
void recorded;
|
|
563
648
|
}
|
|
564
649
|
}
|
|
565
650
|
catch (err) {
|
|
@@ -569,7 +654,7 @@ async function main() {
|
|
|
569
654
|
// A native pre-compaction signal is the safest available point to capture
|
|
570
655
|
// external work state. The operation is idempotent until recovery, so a
|
|
571
656
|
// adapter retry cannot create a storm of near-identical capsules.
|
|
572
|
-
if (norm.event_type === "context.
|
|
657
|
+
if (norm.event_type === "context.compaction_started") {
|
|
573
658
|
try {
|
|
574
659
|
const checkpoint = checkpointContext(coordRoot, {
|
|
575
660
|
sessionId,
|
|
@@ -579,25 +664,13 @@ async function main() {
|
|
|
579
664
|
reason: "pre_compact",
|
|
580
665
|
model: payload?.model,
|
|
581
666
|
});
|
|
582
|
-
|
|
583
|
-
event_type: "context.checkpoint.created",
|
|
584
|
-
instance_id: owner.instance_id,
|
|
585
|
-
session_id: sessionId,
|
|
586
|
-
adapter,
|
|
587
|
-
data: {
|
|
588
|
-
capsule_id: checkpoint.capsule.capsule_id,
|
|
589
|
-
generation: checkpoint.capsule.generation,
|
|
590
|
-
path: checkpoint.state.latest_capsule ?? "",
|
|
591
|
-
reason: checkpoint.capsule.reason,
|
|
592
|
-
reused: checkpoint.reused,
|
|
593
|
-
},
|
|
594
|
-
});
|
|
667
|
+
void checkpoint;
|
|
595
668
|
}
|
|
596
669
|
catch (err) {
|
|
597
670
|
logError(coordRoot, err, { phase: "context-checkpoint" });
|
|
598
671
|
}
|
|
599
672
|
}
|
|
600
|
-
if (norm.event_type === "context.
|
|
673
|
+
if (norm.event_type === "context.compaction_completed") {
|
|
601
674
|
try {
|
|
602
675
|
markContextCompactionCompleted(coordRoot, {
|
|
603
676
|
sessionId,
|
|
@@ -613,31 +686,16 @@ async function main() {
|
|
|
613
686
|
// systemMessage JSON (peer table + wiring check + council invites).
|
|
614
687
|
// Adapter-agnostic since v0.5.0; replaces the previous bash UX layer
|
|
615
688
|
// and the equivalent per-adapter bash session_start handlers.
|
|
616
|
-
if (norm.event_type === "session.
|
|
689
|
+
if (norm.event_type === "session.started") {
|
|
617
690
|
// Effect (claude-code): prune stale journal archives + sweep orphans.
|
|
618
691
|
// The recovery-cue is merged into the
|
|
619
692
|
// session-start additionalContext inside emitSessionStartSystemMessage.
|
|
620
693
|
if (adapter === "claude-code")
|
|
621
694
|
journalJanitor(coordRoot);
|
|
622
|
-
|
|
623
|
-
// agnostic, cheap (one readdir), fail-soft. Paired with journalJanitor as a
|
|
624
|
-
// session-start "tidy the coord layer" step.
|
|
625
|
-
try {
|
|
626
|
-
imageJanitor(coordRoot);
|
|
627
|
-
}
|
|
628
|
-
catch (err) {
|
|
629
|
-
logError(coordRoot, err, { phase: "session-start-image-janitor" });
|
|
630
|
-
}
|
|
695
|
+
imageJanitor(coordRoot);
|
|
631
696
|
let recovery = null;
|
|
632
697
|
if (payload?.source === "compact") {
|
|
633
698
|
try {
|
|
634
|
-
emit(coordRoot, {
|
|
635
|
-
event_type: "context.compaction.completed",
|
|
636
|
-
instance_id: owner.instance_id,
|
|
637
|
-
session_id: sessionId,
|
|
638
|
-
adapter,
|
|
639
|
-
data: { trigger: "auto" },
|
|
640
|
-
});
|
|
641
699
|
markContextCompactionCompleted(coordRoot, {
|
|
642
700
|
sessionId,
|
|
643
701
|
instanceId: owner.instance_id,
|
|
@@ -655,19 +713,16 @@ async function main() {
|
|
|
655
713
|
try {
|
|
656
714
|
const injected = await emitSessionStartSystemMessage(coordRoot, owner.instance_id, sessionId, data, adapter, recovery?.briefing ?? "");
|
|
657
715
|
if (injected && recovery) {
|
|
658
|
-
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId,
|
|
716
|
+
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, recovery);
|
|
659
717
|
}
|
|
660
718
|
}
|
|
661
719
|
catch (err) {
|
|
662
720
|
logError(coordRoot, err, { phase: "session-start-systemMessage" });
|
|
663
721
|
}
|
|
664
|
-
//
|
|
665
|
-
//
|
|
666
|
-
// When a relay is configured, also make sure the live-socket daemon runs.
|
|
722
|
+
// Pull advisory cross-machine presence. V3 never publishes from the
|
|
723
|
+
// disposable heartbeat cache.
|
|
667
724
|
try {
|
|
668
|
-
publishPresence(coordRoot);
|
|
669
725
|
fetchPresence(coordRoot);
|
|
670
|
-
ensureRelayDaemon(coordRoot);
|
|
671
726
|
}
|
|
672
727
|
catch (err) {
|
|
673
728
|
logError(coordRoot, err, { phase: "session-start-presence" });
|
|
@@ -675,7 +730,7 @@ async function main() {
|
|
|
675
730
|
}
|
|
676
731
|
// Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Adapter-
|
|
677
732
|
// agnostic since v0.5.0.
|
|
678
|
-
if (norm.event_type === "session.
|
|
733
|
+
if (norm.event_type === "session.ended") {
|
|
679
734
|
try {
|
|
680
735
|
cleanupSessionEnd(coordRoot, owner.instance_id, data.reason ?? "unknown");
|
|
681
736
|
}
|
|
@@ -688,19 +743,11 @@ async function main() {
|
|
|
688
743
|
journalArchive(coordRoot, owner.instance_id);
|
|
689
744
|
runSessionSyncExtension(coordRoot, true);
|
|
690
745
|
}
|
|
691
|
-
// Presence: publish the post-cleanup state so peers see this session gone
|
|
692
|
-
// promptly rather than waiting out the remote-stale window.
|
|
693
|
-
try {
|
|
694
|
-
publishPresence(coordRoot);
|
|
695
|
-
}
|
|
696
|
-
catch (err) {
|
|
697
|
-
logError(coordRoot, err, { phase: "session-end-presence" });
|
|
698
|
-
}
|
|
699
746
|
}
|
|
700
747
|
// Phase 8: SubagentStart: sync-project to create the subagent heartbeat,
|
|
701
748
|
// log the lifecycle event, and emit a context message announcing the
|
|
702
749
|
// subagent (claude-code + cursor; codex doesn't fan out subagents today).
|
|
703
|
-
if (norm.event_type === "
|
|
750
|
+
if (norm.event_type === "agent.started") {
|
|
704
751
|
try {
|
|
705
752
|
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
706
753
|
if (existsSync(agentCoordBin)) {
|
|
@@ -723,7 +770,7 @@ async function main() {
|
|
|
723
770
|
}
|
|
724
771
|
}
|
|
725
772
|
// Phase 8: SubagentStop: delete subagent heartbeat + log.
|
|
726
|
-
if (norm.event_type === "
|
|
773
|
+
if (norm.event_type === "agent.completed") {
|
|
727
774
|
try {
|
|
728
775
|
cleanupSessionEnd(coordRoot, owner.instance_id, data.reason ?? "unknown");
|
|
729
776
|
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
@@ -742,7 +789,7 @@ async function main() {
|
|
|
742
789
|
}
|
|
743
790
|
// Phase 8: UserPromptSubmit: render dedup'd peer table + council pending
|
|
744
791
|
// and emit the adapter-shaped systemMessage JSON. Adapter-agnostic since v0.5.0.
|
|
745
|
-
if (norm.event_type === "
|
|
792
|
+
if (norm.event_type === "turn.started") {
|
|
746
793
|
// Effects (claude-code): reset per-turn sound rate-limit counters + run
|
|
747
794
|
// presence detection on the prompt.
|
|
748
795
|
if (adapter === "claude-code") {
|
|
@@ -777,74 +824,26 @@ async function main() {
|
|
|
777
824
|
try {
|
|
778
825
|
const injected = await emitUserPromptSubmitSystemMessage(coordRoot, owner.instance_id, sessionId, adapter, payload?.cwd, recovery?.briefing ?? "");
|
|
779
826
|
if (injected && recovery) {
|
|
780
|
-
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId,
|
|
827
|
+
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, recovery);
|
|
781
828
|
}
|
|
782
829
|
}
|
|
783
830
|
catch (err) {
|
|
784
831
|
logError(coordRoot, err, { phase: "user-prompt-submit-systemMessage" });
|
|
785
832
|
}
|
|
786
833
|
}
|
|
787
|
-
// turn.
|
|
834
|
+
// turn.completed: telemetry, then the stop verdict. The
|
|
788
835
|
// verdict + codex-replay previously lived in the per-adapter shell adapters;
|
|
789
836
|
// agent-hook owns them now. Runs on the normal "stop" event only;
|
|
790
837
|
// "stop-failure" (API error) gets no gate, matching the previous
|
|
791
838
|
// stop vs stop-failure split.
|
|
792
|
-
if (norm.event_type === "turn.
|
|
793
|
-
//
|
|
794
|
-
// the status_checked / task_set / status_box_present evidence (codex
|
|
795
|
-
// doesn't emit those live; this re-emits turn.stop after agent-hook's own,
|
|
796
|
-
// so the verdict reads the replay's box signal as the latest).
|
|
797
|
-
if (adapter === "codex" && payload?.transcript_path && existsSync(payload.transcript_path)) {
|
|
798
|
-
try {
|
|
799
|
-
replayCodexJsonl({
|
|
800
|
-
coordRoot,
|
|
801
|
-
jsonlPath: payload.transcript_path,
|
|
802
|
-
sessionId,
|
|
803
|
-
instanceId: owner.instance_id,
|
|
804
|
-
lastAssistantMessage: payload.raw.last_assistant_message ?? "",
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
catch (err) {
|
|
808
|
-
logError(coordRoot, err, { phase: "codex-replay" });
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
// CC effects: rate-limited session-telemetry sync + turn-summary Haiku
|
|
812
|
-
// auto-summary.
|
|
839
|
+
if (norm.event_type === "turn.completed" && eventName === "stop") {
|
|
840
|
+
// Claude Code session telemetry sync remains an independent side effect.
|
|
813
841
|
if (adapter === "claude-code") {
|
|
814
842
|
runSessionSyncExtension(coordRoot, false);
|
|
815
|
-
runTurnSummary(coordRoot, owner.instance_id, sessionId, payload?.transcript_path);
|
|
816
|
-
}
|
|
817
|
-
// Master-state heartbeat projection. Drains events.ndjson since the last
|
|
818
|
-
// cursor → per-owner heartbeats. Was a SECOND binary (`agent-coord project`)
|
|
819
|
-
// pinned to Claude Code Stop only; folded in here so it (a) is one
|
|
820
|
-
// entry per event like everything else and (b) fires on EVERY adapter's stop,
|
|
821
|
-
// not just CC. Runs unconditionally before the verdict's possible exit-2 return
|
|
822
|
-
// (the events are real regardless of whether the agent gets nagged), and after
|
|
823
|
-
// codex-replay above so codex's replayed events are included in the drain.
|
|
824
|
-
// Not an emitter (consumes + writes heartbeats), so no emitter/consumer conflict.
|
|
825
|
-
try {
|
|
826
|
-
const result = consumeSince(coordRoot);
|
|
827
|
-
projectHeartbeats(coordRoot, result.events);
|
|
828
|
-
if (result.lastEventId)
|
|
829
|
-
writeCursor(coordRoot, result.lastEventId);
|
|
830
|
-
}
|
|
831
|
-
catch (err) {
|
|
832
|
-
logError(coordRoot, err, { phase: "stop-projection" });
|
|
833
|
-
}
|
|
834
|
-
// Presence: publish AFTER the projection above so the blob carries this
|
|
835
|
-
// turn's fresh task/turn_summary/files. Change-batched + keepalive'd;
|
|
836
|
-
// the push itself runs detached. The relay daemon (when configured) is
|
|
837
|
-
// re-ensured here too — it self-exits on idle, and the next turn revives it.
|
|
838
|
-
try {
|
|
839
|
-
publishPresence(coordRoot);
|
|
840
|
-
ensureRelayDaemon(coordRoot);
|
|
841
843
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
// Stop verdict (status-box + set-task gate). Direct in-process call: the
|
|
846
|
-
// rule lives in harnery. agent-hook already emitted this turn.stop (with
|
|
847
|
-
// status_box_present) above, so the evidence is in the stream.
|
|
844
|
+
// Stop verdict (V3 ritual + task/status gate). Direct in-process call: the
|
|
845
|
+
// rule lives in Harnery. agent-hook already emitted this turn.completed
|
|
846
|
+
// with privacy-safe ritual observations, so the evidence is in the stream.
|
|
848
847
|
const verdict = evaluateStopHook(coordRoot, {
|
|
849
848
|
rule: "stop-hook",
|
|
850
849
|
instance_id: owner.instance_id,
|
|
@@ -853,31 +852,27 @@ async function main() {
|
|
|
853
852
|
bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
|
|
854
853
|
workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
|
|
855
854
|
});
|
|
856
|
-
const enforcementMode = stopEnforcementMode(verdict.rule);
|
|
857
|
-
emit(coordRoot, {
|
|
858
|
-
event_type: "stop.verdict",
|
|
859
|
-
instance_id: owner.instance_id,
|
|
860
|
-
session_id: sessionId,
|
|
861
|
-
turn_id: payload?.turn_id,
|
|
862
|
-
parent_turn_id: payload?.parent_turn_id,
|
|
863
|
-
adapter,
|
|
864
|
-
data: {
|
|
865
|
-
allow: verdict.allow,
|
|
866
|
-
rule: verdict.rule,
|
|
867
|
-
...(verdict.reason ? { reason: verdict.reason } : {}),
|
|
868
|
-
enforcement_mode: enforcementMode,
|
|
869
|
-
eligible: enforcementMode === "enforced",
|
|
870
|
-
nag_delivered: enforcementMode === "enforced" && !verdict.allow,
|
|
871
|
-
},
|
|
872
|
-
});
|
|
873
855
|
if (!verdict.allow) {
|
|
874
|
-
// Adapter-aware enforcement channel: Claude Code
|
|
875
|
-
//
|
|
876
|
-
//
|
|
877
|
-
// writes the right shape and returns the exit code to use.
|
|
856
|
+
// Adapter-aware enforcement channel: Claude Code honors exit-2 + stderr
|
|
857
|
+
// as a turn block; Cursor ignores exit codes and re-prompts only via a
|
|
858
|
+
// `followup_message` it auto-submits. Codex returned observe-only above.
|
|
859
|
+
// emitStopBlock writes the right shape and returns the exit code to use.
|
|
878
860
|
const { emitStopBlock } = await import("./adapter/output.js");
|
|
879
861
|
return emitStopBlock(adapter, verdict, coordRoot);
|
|
880
862
|
}
|
|
863
|
+
// An explicit end requested from inside this turn cannot be authoritative
|
|
864
|
+
// until the adapter has committed turn.completed above. Reconcile only
|
|
865
|
+
// when such a request exists; any later real work cancels it in the
|
|
866
|
+
// finalizer instead of being terminated underneath the agent.
|
|
867
|
+
try {
|
|
868
|
+
const { hasPendingExplicitSessionEndV3, reconcileSessionFinalizationV3 } = await import("../agents/session-finalizer-v3.js");
|
|
869
|
+
if (hasPendingExplicitSessionEndV3(coordRoot)) {
|
|
870
|
+
reconcileSessionFinalizationV3(coordRoot);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
catch (err) {
|
|
874
|
+
logError(coordRoot, err, { phase: "stop-explicit-session-finalization" });
|
|
875
|
+
}
|
|
881
876
|
}
|
|
882
877
|
// Phase 7: PreToolUse: heartbeat + pid-map self-heal on every tool call.
|
|
883
878
|
// Adapter-agnostic: both writes have the same shape regardless of who fired.
|
|
@@ -888,40 +883,32 @@ async function main() {
|
|
|
888
883
|
// side-by-side in the previous pre-tool-use adapter. The Phase 4-6 refactor
|
|
889
884
|
// preserved the heartbeat half but dropped the pid-map half; the pid-map
|
|
890
885
|
// call was restored here afterward.
|
|
891
|
-
if (norm.event_type === "tool.
|
|
886
|
+
if (norm.event_type === "tool.requested") {
|
|
892
887
|
try {
|
|
893
888
|
// Recorded fork lineage, heal-path flavor. A forked CC conversation
|
|
894
|
-
// never fires its own session.
|
|
889
|
+
// never fires its own session.started (SessionStart fires under the
|
|
895
890
|
// PARENT's session id with source=resume, before the fork id is
|
|
896
891
|
// minted; verified 2026-08-05), so the fork's new instance first
|
|
897
892
|
// materializes right here. Gate detection on "no heartbeat yet" so the
|
|
898
893
|
// transcript scan runs once per instance lifetime, not per tool call.
|
|
899
|
-
let forkedFrom;
|
|
900
|
-
if (adapter === "claude-code" &&
|
|
901
|
-
payload?.transcript_path &&
|
|
902
|
-
!existsSync(join(coordRoot, ".harnery", "active", `${owner.instance_id}.json`))) {
|
|
903
|
-
forkedFrom = detectForkParent(payload.transcript_path, owner.instance_id);
|
|
904
|
-
}
|
|
905
|
-
healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId, adapter, forkedFrom);
|
|
906
894
|
refreshPidmap(coordRoot, owner.instance_id, adapter, payload?.pid);
|
|
907
895
|
}
|
|
908
896
|
catch (err) {
|
|
909
897
|
logError(coordRoot, err, { phase: "pre-tool-use-heal" });
|
|
910
898
|
}
|
|
911
|
-
//
|
|
912
|
-
//
|
|
899
|
+
// The suggested name is a pending display latch. The set-task call itself
|
|
900
|
+
// runs before a name exists; every later tool waits until the exact block
|
|
901
|
+
// is the first assistant text after the mint result. Cursor supplies
|
|
902
|
+
// agent_message directly; Claude Code and Codex are resolved from their
|
|
903
|
+
// JSONL transcripts. Later commentary must not erase an already-correct
|
|
904
|
+
// display, and an unreadable transcript must not deadlock every tool.
|
|
913
905
|
try {
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
payload,
|
|
918
|
-
instanceId: owner.instance_id,
|
|
919
|
-
sessionId,
|
|
920
|
-
adapter,
|
|
921
|
-
});
|
|
906
|
+
const displayAllowed = await enforcePendingSessionNameDisplay(coordRoot, owner.instance_id, adapter, payload);
|
|
907
|
+
if (!displayAllowed)
|
|
908
|
+
return 0;
|
|
922
909
|
}
|
|
923
910
|
catch (err) {
|
|
924
|
-
logError(coordRoot, err, { phase: "pre-tool-use-
|
|
911
|
+
logError(coordRoot, err, { phase: "pre-tool-use-session-name" });
|
|
925
912
|
}
|
|
926
913
|
// Windows-native Codex + WSL UNC only: block the one cross-shell shape
|
|
927
914
|
// proven to corrupt argument boundaries. Normal WSL argv calls, literal
|
|
@@ -934,13 +921,6 @@ async function main() {
|
|
|
934
921
|
toolInput: payload?.tool_input,
|
|
935
922
|
});
|
|
936
923
|
if (unsafeShellReason) {
|
|
937
|
-
emit(coordRoot, {
|
|
938
|
-
event_type: "decision.block",
|
|
939
|
-
instance_id: owner.instance_id,
|
|
940
|
-
session_id: sessionId,
|
|
941
|
-
adapter,
|
|
942
|
-
data: { rule: "unsafe_cross_shell", reason: unsafeShellReason },
|
|
943
|
-
});
|
|
944
924
|
const { emitDeny } = await import("./adapter/output.js");
|
|
945
925
|
emitDeny(adapter, unsafeShellReason);
|
|
946
926
|
return 0;
|
|
@@ -960,79 +940,30 @@ async function main() {
|
|
|
960
940
|
catch (err) {
|
|
961
941
|
logError(coordRoot, err, { phase: "pre-tool-use-guard" });
|
|
962
942
|
}
|
|
963
|
-
if (guardAllowed)
|
|
964
|
-
|
|
965
|
-
stampSessionStateEvent(coordRoot, owner.instance_id, envelope);
|
|
966
|
-
}
|
|
967
|
-
catch (err) {
|
|
968
|
-
logError(coordRoot, err, { phase: "activity-projection" });
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
// Shell-mutation warn (warn-only, never blocks). Was the cursor
|
|
972
|
-
// beforeShellExecution + codex preToolUse-Bash shell-mutation-claim-log in
|
|
973
|
-
// the per-adapter shell adapters. Cursor sends the command at payload.command;
|
|
974
|
-
// codex Bash at tool_input.command. Emits a decision.warn per candidate-mutated
|
|
975
|
-
// path so a peer sees the write in events.ndjson. (CC never did this,
|
|
976
|
-
// preserved; it emits with its own hooks-side emitter per the
|
|
977
|
-
// independent-emitter rule.)
|
|
978
|
-
const shellCmd = eventName === "before-shell-execution"
|
|
979
|
-
? (payload?.raw.command ?? "")
|
|
980
|
-
: adapter === "codex" && data.tool_name === "Bash"
|
|
981
|
-
? (payload?.raw.tool_input?.command ?? "")
|
|
982
|
-
: "";
|
|
983
|
-
if (shellCmd) {
|
|
984
|
-
try {
|
|
985
|
-
const paths = shellMutationPaths(shellCmd, coordRoot);
|
|
986
|
-
const truncated = shellCmd.length > 80 ? shellCmd.slice(0, 80) : shellCmd;
|
|
987
|
-
const platform = adapterPlatform(adapter);
|
|
988
|
-
for (const p of paths) {
|
|
989
|
-
emit(coordRoot, {
|
|
990
|
-
event_type: "decision.warn",
|
|
991
|
-
instance_id: owner.instance_id,
|
|
992
|
-
session_id: sessionId,
|
|
993
|
-
adapter,
|
|
994
|
-
data: {
|
|
995
|
-
rule: "shell_mutation_candidate",
|
|
996
|
-
reason: `path=${p} cmd=${truncated} platform=${platform}`,
|
|
997
|
-
},
|
|
998
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
catch (err) {
|
|
1003
|
-
logError(coordRoot, err, { phase: "shell-mutation-warn" });
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
943
|
+
if (!guardAllowed)
|
|
944
|
+
return 0;
|
|
1006
945
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
logError(coordRoot, err, { phase: "post-tool-use-stamp" });
|
|
1015
|
-
}
|
|
1016
|
-
// Image feed: a Bash command that wrote an image (harn browse, harn image,
|
|
1017
|
-
// --diff, …) is the "agent produced this" signal. Scan the command + its
|
|
1018
|
-
// output for freshly-written image paths and capture them.
|
|
946
|
+
if (norm.event_type === "tool.completed" && eventName === "post-tool-use") {
|
|
947
|
+
// Inject only at the successful tool boundary that actually minted or
|
|
948
|
+
// retried a name: the first non-empty set-task, a pending-name set-task
|
|
949
|
+
// retry, or the transition to lifecycle done. The
|
|
950
|
+
// coordination row intentionally remains pending until transcript evidence
|
|
951
|
+
// catches up; reading that latch alone here would re-inject after every
|
|
952
|
+
// later tool and make the agent print the same block repeatedly.
|
|
1019
953
|
try {
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
sessionId,
|
|
1026
|
-
adapter,
|
|
1027
|
-
});
|
|
954
|
+
const name = sessionNameDisplayPending(readLiveCoordinationRow(coordRoot, owner.instance_id));
|
|
955
|
+
if (name && toolResponseMintedSessionName(payload?.tool_response, name)) {
|
|
956
|
+
const { emitContext } = await import("./adapter/output.js");
|
|
957
|
+
emitContext(adapter, "PostToolUse", sessionNameDisplayInstruction(name));
|
|
958
|
+
}
|
|
1028
959
|
}
|
|
1029
960
|
catch (err) {
|
|
1030
|
-
logError(coordRoot, err, { phase: "post-tool-use-
|
|
961
|
+
logError(coordRoot, err, { phase: "post-tool-use-session-name" });
|
|
1031
962
|
}
|
|
1032
963
|
}
|
|
1033
964
|
// Phase 7: PostToolUseFailure: release claim on failed Edit (the file
|
|
1034
965
|
// never landed; the claim is stale). Adapter-agnostic.
|
|
1035
|
-
if (norm.event_type === "tool.
|
|
966
|
+
if (norm.event_type === "tool.completed" && eventName === "post-tool-use-failure") {
|
|
1036
967
|
try {
|
|
1037
968
|
releaseClaimOnFailure(coordRoot, owner.instance_id, data, payload?.raw);
|
|
1038
969
|
}
|
|
@@ -1042,14 +973,32 @@ async function main() {
|
|
|
1042
973
|
}
|
|
1043
974
|
return 0;
|
|
1044
975
|
}
|
|
1045
|
-
function
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
if (
|
|
1051
|
-
return
|
|
1052
|
-
|
|
976
|
+
async function enforcePendingSessionNameDisplay(coordRoot, instanceId, adapter, payload) {
|
|
977
|
+
const name = sessionNameDisplayPending(readLiveCoordinationRow(coordRoot, instanceId));
|
|
978
|
+
if (!name)
|
|
979
|
+
return true;
|
|
980
|
+
const command = extractBashCommand(payload?.tool_name, payload?.tool_input);
|
|
981
|
+
if (isSessionNameRemediationCommand(command, resolveBinName(coordRoot)))
|
|
982
|
+
return true;
|
|
983
|
+
const inspection = payload?.agent_message !== undefined
|
|
984
|
+
? {
|
|
985
|
+
state: assistantTextStartsWithSessionNameBlock(payload.agent_message, name)
|
|
986
|
+
? "present"
|
|
987
|
+
: "absent",
|
|
988
|
+
}
|
|
989
|
+
: inspectSessionNameDisplayImmediately(payload?.transcript_path, name, assistantTextStartsWithSessionNameBlock);
|
|
990
|
+
if (inspection.state === "present") {
|
|
991
|
+
stampSessionNameSeen(coordRoot, instanceId, name);
|
|
992
|
+
return true;
|
|
993
|
+
}
|
|
994
|
+
if (inspection.state === "unavailable") {
|
|
995
|
+
const { emitContext } = await import("./adapter/output.js");
|
|
996
|
+
emitContext(adapter, "PreToolUse", "Harnery could not verify the pending session-name display because the adapter transcript is unavailable or not flushed yet. This tool is allowed so the session cannot deadlock; display the requested block before later work. Verification remains pending.");
|
|
997
|
+
return true;
|
|
998
|
+
}
|
|
999
|
+
const { emitDeny } = await import("./adapter/output.js");
|
|
1000
|
+
emitDeny(adapter, sessionNameDisplayInstruction(name));
|
|
1001
|
+
return false;
|
|
1053
1002
|
}
|
|
1054
1003
|
async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data, adapter) {
|
|
1055
1004
|
const toolName = data.tool_name ?? "";
|
|
@@ -1128,23 +1077,6 @@ async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data, adapte
|
|
|
1128
1077
|
emitDeny(adapter, reason);
|
|
1129
1078
|
return false;
|
|
1130
1079
|
}
|
|
1131
|
-
// The verdict mutates the live heartbeat immediately, but that file is a
|
|
1132
|
-
// projection and can be rebuilt at any later hook. Persist the acquisition
|
|
1133
|
-
// in the canonical stream too. This matters most for Codex apply_patch:
|
|
1134
|
-
// one tool call can claim several files, and tool.pre_use's clamped payload
|
|
1135
|
-
// is not a durable ownership representation for those targets.
|
|
1136
|
-
emit(coordRoot, {
|
|
1137
|
-
event_type: "claim.acquire",
|
|
1138
|
-
instance_id: instanceId,
|
|
1139
|
-
session_id: sessionId,
|
|
1140
|
-
adapter,
|
|
1141
|
-
source: "agent-hooks",
|
|
1142
|
-
data: {
|
|
1143
|
-
path: target.path,
|
|
1144
|
-
mode: "write",
|
|
1145
|
-
...(target.finalization ? { finalization: target.finalization } : {}),
|
|
1146
|
-
},
|
|
1147
|
-
});
|
|
1148
1080
|
}
|
|
1149
1081
|
return true;
|
|
1150
1082
|
}
|
|
@@ -1204,28 +1136,10 @@ function parseApplyPatchPaths(data) {
|
|
|
1204
1136
|
}
|
|
1205
1137
|
return out;
|
|
1206
1138
|
}
|
|
1207
|
-
function healHeartbeatViaCli(coordRoot, instanceId, sessionId, adapter, forkedFrom) {
|
|
1208
|
-
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1209
|
-
if (!existsSync(agentCoordBin))
|
|
1210
|
-
return;
|
|
1211
|
-
// Pass the detected adapter so a pruned Cursor/Codex heartbeat is recreated
|
|
1212
|
-
// with the correct platform; without it, healHeartbeat defaults to
|
|
1213
|
-
// claude-code and the dashboard mislabels the agent. See
|
|
1214
|
-
// heartbeat-writer.healHeartbeat. --forked-from carries detected fork
|
|
1215
|
-
// lineage for an instance that never session.started (the CC fork flow).
|
|
1216
|
-
const args = ["heal-heartbeat", instanceId, sessionId, `--adapter=${adapter}`];
|
|
1217
|
-
if (forkedFrom)
|
|
1218
|
-
args.push(`--forked-from=${forkedFrom}`);
|
|
1219
|
-
spawnSync(agentCoordBin, args, {
|
|
1220
|
-
encoding: "utf8",
|
|
1221
|
-
timeout: 2000,
|
|
1222
|
-
env: childEnv(coordRoot),
|
|
1223
|
-
});
|
|
1224
|
-
}
|
|
1225
1139
|
/**
|
|
1226
1140
|
* Walk up the ppid chain on Linux/WSL looking for the adapter anchor PID,
|
|
1227
1141
|
* the PID of the claude / cursor / codex binary. Finds the agent PID. Used by
|
|
1228
|
-
* `tool.
|
|
1142
|
+
* `tool.requested` pid-map self-heal so a re-parented adapter binary (the
|
|
1229
1143
|
* VS Code 2.1.x sibling-claude spawn case) gets its pid-map row rewritten on
|
|
1230
1144
|
* the next tool call rather than going invisible until SessionStart fires
|
|
1231
1145
|
* again, which it may never do.
|
|
@@ -1298,9 +1212,7 @@ function findAdapterAnchorPid(adapter) {
|
|
|
1298
1212
|
return selectAnchorPid(chain, adapter);
|
|
1299
1213
|
}
|
|
1300
1214
|
/**
|
|
1301
|
-
* Pid-map self-heal for `tool.
|
|
1302
|
-
* `healHeartbeatViaCli`; the two were paired before the Phase 6 refactor split
|
|
1303
|
-
* them apart, then restored together afterward.
|
|
1215
|
+
* Pid-map self-heal for `tool.requested`.
|
|
1304
1216
|
*
|
|
1305
1217
|
* The pid argument prefers the payload's `pid` (CC populates it on
|
|
1306
1218
|
* SessionStart and may also send it on PreToolUse), then
|
|
@@ -1318,38 +1230,6 @@ function refreshPidmap(coordRoot, instanceId, adapter, payloadPid) {
|
|
|
1318
1230
|
return;
|
|
1319
1231
|
writePidmapViaAgentCoord(coordRoot, pid, instanceId, adapterPlatform(adapter));
|
|
1320
1232
|
}
|
|
1321
|
-
function stampToolActivity(coordRoot, instanceId, data) {
|
|
1322
|
-
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1323
|
-
if (!existsSync(agentCoordBin))
|
|
1324
|
-
return;
|
|
1325
|
-
const toolName = data.tool_name ?? "";
|
|
1326
|
-
// Extract a 1-line target from the tool_input blob (file path / command head).
|
|
1327
|
-
const toolInputRaw = data.tool_input;
|
|
1328
|
-
let target = "";
|
|
1329
|
-
if (typeof toolInputRaw === "string") {
|
|
1330
|
-
try {
|
|
1331
|
-
const parsed = JSON.parse(toolInputRaw);
|
|
1332
|
-
target =
|
|
1333
|
-
parsed.file_path ??
|
|
1334
|
-
parsed.path ??
|
|
1335
|
-
parsed.notebook_path ??
|
|
1336
|
-
parsed.command ??
|
|
1337
|
-
parsed.url ??
|
|
1338
|
-
parsed.pattern ??
|
|
1339
|
-
"";
|
|
1340
|
-
}
|
|
1341
|
-
catch {
|
|
1342
|
-
/* skip */
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
if (target.length > 200)
|
|
1346
|
-
target = target.slice(0, 200);
|
|
1347
|
-
spawnSync(agentCoordBin, ["stamp-tool-activity", instanceId, toolName, target], {
|
|
1348
|
-
encoding: "utf8",
|
|
1349
|
-
timeout: 2000,
|
|
1350
|
-
env: childEnv(coordRoot),
|
|
1351
|
-
});
|
|
1352
|
-
}
|
|
1353
1233
|
function releaseClaimOnFailure(coordRoot, instanceId, data, rawPayload) {
|
|
1354
1234
|
const toolName = data.tool_name ?? "";
|
|
1355
1235
|
if (toolName !== "Edit" && toolName !== "Write" && toolName !== "NotebookEdit")
|
|
@@ -1389,6 +1269,12 @@ function releaseClaimOnFailure(coordRoot, instanceId, data, rawPayload) {
|
|
|
1389
1269
|
? filePath.slice(coordRoot.length + 1)
|
|
1390
1270
|
: filePath;
|
|
1391
1271
|
}
|
|
1272
|
+
// In V3 the release is an authority event, not a heartbeat mutation. Avoid
|
|
1273
|
+
// creating a disposable cache for a failure that never acquired a claim,
|
|
1274
|
+
// but release the exact path when the validated projection says it is held.
|
|
1275
|
+
const row = readLiveCoordinationRow(coordRoot, instanceId);
|
|
1276
|
+
if (!row?.files_touched?.includes(canonical))
|
|
1277
|
+
return;
|
|
1392
1278
|
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1393
1279
|
if (!existsSync(agentCoordBin))
|
|
1394
1280
|
return;
|
|
@@ -1399,16 +1285,6 @@ function releaseClaimOnFailure(coordRoot, instanceId, data, rawPayload) {
|
|
|
1399
1285
|
});
|
|
1400
1286
|
}
|
|
1401
1287
|
function cleanupSessionEnd(coordRoot, instanceId, reason) {
|
|
1402
|
-
// Remove heartbeat from the canonical .harnery/active/ dir.
|
|
1403
|
-
const path = join(coordRoot, ".harnery", "active", `${instanceId}.json`);
|
|
1404
|
-
try {
|
|
1405
|
-
if (existsSync(path)) {
|
|
1406
|
-
require("node:fs").unlinkSync(path);
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
catch {
|
|
1410
|
-
/* swallow */
|
|
1411
|
-
}
|
|
1412
1288
|
// Sweep pid-map entries pointing to this instance
|
|
1413
1289
|
const pidmapDir = join(coordRoot, ".harnery", "pid-map");
|
|
1414
1290
|
if (existsSync(pidmapDir)) {
|
|
@@ -1442,22 +1318,7 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
|
|
|
1442
1318
|
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1443
1319
|
let additionalContext = "";
|
|
1444
1320
|
if (existsSync(agentCoordBin)) {
|
|
1445
|
-
// Look up the agent's name from its heartbeat (for council pending rendering).
|
|
1446
|
-
let agentName = "";
|
|
1447
|
-
try {
|
|
1448
|
-
const fs = require("node:fs");
|
|
1449
|
-
const hbPath = join(coordRoot, ".harnery", "active", `${instanceId}.json`);
|
|
1450
|
-
if (fs.existsSync(hbPath)) {
|
|
1451
|
-
const hb = JSON.parse(fs.readFileSync(hbPath, "utf8"));
|
|
1452
|
-
agentName = hb.name ?? "";
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
catch {
|
|
1456
|
-
/* fall through with empty name; peer table still renders */
|
|
1457
|
-
}
|
|
1458
1321
|
const args = ["prompt-context", "--instance", instanceId, "--session", sessionId];
|
|
1459
|
-
if (agentName)
|
|
1460
|
-
args.push("--name", agentName);
|
|
1461
1322
|
// Every human-facing adapter gets the first-session naming reminder from
|
|
1462
1323
|
// the shared hook path. Cursor + Codex additionally get ongoing set-task
|
|
1463
1324
|
// staleness nudges; Claude Code enforces those via its Stop transcript.
|
|
@@ -1494,7 +1355,7 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
|
|
|
1494
1355
|
}
|
|
1495
1356
|
function emitSubagentStartContext(coordRoot, instanceId, sessionId, data, adapter) {
|
|
1496
1357
|
// Look up the subagent's assigned name (just-written by agent-coord assignName
|
|
1497
|
-
// in session.
|
|
1358
|
+
// in session.started data) + the parent's short id for the "you are a subagent
|
|
1498
1359
|
// of X" framing.
|
|
1499
1360
|
const subagentName = data.name ?? "";
|
|
1500
1361
|
if (!subagentName)
|
|
@@ -1526,13 +1387,19 @@ function adapterPlatform(adapter) {
|
|
|
1526
1387
|
}
|
|
1527
1388
|
async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, emittedData, adapter, recoveryBriefing = "") {
|
|
1528
1389
|
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1390
|
+
const workflowChild = coordEnv("WORKFLOW_CHILD") === "1";
|
|
1529
1391
|
let additionalContext = "";
|
|
1530
1392
|
if (existsSync(agentCoordBin)) {
|
|
1531
1393
|
// Sync-project so the heartbeat exists for downstream readers (peer table,
|
|
1532
1394
|
// wiring check, council invites).
|
|
1533
1395
|
spawnSync(agentCoordBin, ["project"], { encoding: "utf8", timeout: 3000 });
|
|
1534
|
-
//
|
|
1535
|
-
|
|
1396
|
+
// Opportunistic reconciliation makes normal session starts a failsafe for
|
|
1397
|
+
// archive, idle, cascade, and host lifecycle observations.
|
|
1398
|
+
spawnSync(agentCoordBin, ["reconcile-finalization"], {
|
|
1399
|
+
encoding: "utf8",
|
|
1400
|
+
timeout: 5000,
|
|
1401
|
+
env: { ...process.env, HARNERY_COORD_ROOT_OVERRIDE: coordRoot },
|
|
1402
|
+
});
|
|
1536
1403
|
// SESSION_START activity log line, fired across all adapters.
|
|
1537
1404
|
const model = emittedData.model ?? "unknown";
|
|
1538
1405
|
const source = emittedData.source ?? "startup";
|
|
@@ -1543,34 +1410,39 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
|
|
|
1543
1410
|
"--instance",
|
|
1544
1411
|
instanceId,
|
|
1545
1412
|
], { encoding: "utf8", timeout: 2000 });
|
|
1546
|
-
//
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1413
|
+
// Workflow children retain lifecycle/event capture but do not receive
|
|
1414
|
+
// operator-facing peer, council, or init-remediation context. Injecting
|
|
1415
|
+
// that context can make a bounded child follow housekeeping instructions
|
|
1416
|
+
// instead of its assigned prompt.
|
|
1417
|
+
if (!workflowChild) {
|
|
1418
|
+
const agentName = emittedData.name ?? "";
|
|
1419
|
+
const args = ["session-context", "--instance", instanceId, "--session", sessionId];
|
|
1420
|
+
if (agentName)
|
|
1421
|
+
args.push("--name", agentName);
|
|
1422
|
+
// The "You are agent-X." prefix in session-context renders unqualified by
|
|
1423
|
+
// default (claude-code-style). For cursor/codex the bash dispatchers add
|
|
1424
|
+
// a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
|
|
1425
|
+
if (adapter !== "claude-code") {
|
|
1426
|
+
args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
|
|
1427
|
+
}
|
|
1428
|
+
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1429
|
+
if (result.status === 0 && result.stdout)
|
|
1430
|
+
additionalContext = result.stdout.trim();
|
|
1556
1431
|
}
|
|
1557
|
-
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1558
|
-
if (result.status === 0 && result.stdout)
|
|
1559
|
-
additionalContext = result.stdout.trim();
|
|
1560
1432
|
}
|
|
1561
1433
|
// Effect (claude-code): merge the journal recovery cue into the session-start
|
|
1562
1434
|
// context. Was a standalone additionalContext emission from the previous
|
|
1563
1435
|
// journal-on-start adapter; now that agent-hook is the single SessionStart
|
|
1564
1436
|
// entry, it folds in here.
|
|
1565
|
-
if (adapter === "claude-code") {
|
|
1437
|
+
if (adapter === "claude-code" && !workflowChild) {
|
|
1566
1438
|
const cue = journalRecoveryCue(coordRoot);
|
|
1567
1439
|
if (cue)
|
|
1568
1440
|
additionalContext = [additionalContext, cue].filter(Boolean).join("\n\n");
|
|
1569
1441
|
}
|
|
1570
|
-
if (recoveryBriefing) {
|
|
1442
|
+
if (recoveryBriefing && !workflowChild) {
|
|
1571
1443
|
additionalContext = [additionalContext, recoveryBriefing].filter(Boolean).join("\n\n");
|
|
1572
1444
|
}
|
|
1573
|
-
if (adapter === "codex" && isWslUncPath(emittedData.cwd)) {
|
|
1445
|
+
if (adapter === "codex" && !workflowChild && isWslUncPath(emittedData.cwd)) {
|
|
1574
1446
|
const fileLinkContext = renderCodexWslFileLinkContext(coordRoot, emittedData.cwd);
|
|
1575
1447
|
if (fileLinkContext) {
|
|
1576
1448
|
additionalContext = [additionalContext, fileLinkContext].filter(Boolean).join("\n\n");
|
|
@@ -1591,19 +1463,9 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
|
|
|
1591
1463
|
emitContext(adapter, "SessionStart", additionalContext);
|
|
1592
1464
|
return true;
|
|
1593
1465
|
}
|
|
1594
|
-
function completeRecoveryInjection(coordRoot, instanceId, sessionId,
|
|
1466
|
+
function completeRecoveryInjection(coordRoot, instanceId, sessionId, recovery) {
|
|
1595
1467
|
completeContextRecovery(coordRoot, { sessionId, instanceId });
|
|
1596
|
-
|
|
1597
|
-
event_type: "context.recovery.injected",
|
|
1598
|
-
instance_id: instanceId,
|
|
1599
|
-
session_id: sessionId,
|
|
1600
|
-
adapter,
|
|
1601
|
-
data: {
|
|
1602
|
-
capsule_id: recovery.capsule.capsule_id,
|
|
1603
|
-
generation: recovery.capsule.generation,
|
|
1604
|
-
injection_event: injectionEvent,
|
|
1605
|
-
},
|
|
1606
|
-
});
|
|
1468
|
+
void recovery;
|
|
1607
1469
|
}
|
|
1608
1470
|
main()
|
|
1609
1471
|
.then((code) => process.exit(code))
|