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
|
@@ -1,182 +1,189 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* from the canonical event stream alone (no transcript scan).
|
|
2
|
+
* End-of-turn ritual verdict derived from the authoritative V3 event ledger.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Rule 2/3: latest `turn.stop` event has `status_box_present: true` (or the
|
|
11
|
-
* stop currently firing carries that field via the in-flight event
|
|
12
|
-
* agent-hook emits before the stop hook runs).
|
|
13
|
-
* Rule 3/3: `state.task_set` event with matching turn boundary exists.
|
|
14
|
-
* Session-naming rule (at most once per session, CC semantics only): the turn
|
|
15
|
-
* whose set-task produced `suggested_session_name` must carry an
|
|
16
|
-
* in-window `turn.stop` with `session_name_present: true`.
|
|
17
|
-
*
|
|
18
|
-
* Pure-prose-turn exemption: when zero `tool.pre_use` events fire in
|
|
19
|
-
* the current turn, rules 1/3 and 3/3 do not apply. Rule 2/3 still applies
|
|
20
|
-
* as a user-visible mobile cue.
|
|
21
|
-
*
|
|
22
|
-
* Remediation continuity: an adapter whose Stop channel re-prompts by
|
|
23
|
-
* submitting a new user message (Cursor's `followup_message`) opens a fresh
|
|
24
|
-
* turn to repair the previous one. Such a turn inherits the window of the turn
|
|
25
|
-
* it repairs, so ritual events accumulate instead of alternating. See
|
|
26
|
-
* `resolveTurnStartMs`.
|
|
4
|
+
* V3 keeps prompt and reply bodies private. The hook producer records only the
|
|
5
|
+
* structural observations needed here: whether the reply showed the status box
|
|
6
|
+
* and current session name, and whether a prompt was emitted by Harnery's own
|
|
7
|
+
* Cursor remediation channel. Task and status evidence comes from the existing
|
|
8
|
+
* `coord.task_changed` and `coord.status_observed` events.
|
|
27
9
|
*/
|
|
28
10
|
|
|
29
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
30
|
-
import { join } from "node:path";
|
|
31
11
|
import {
|
|
32
12
|
agentsRequireGitFinalization,
|
|
33
13
|
endOfTurnStatusCommand,
|
|
34
14
|
resolveBinName,
|
|
35
15
|
} from "../../config.ts";
|
|
16
|
+
import type { EventV3 } from "../../events/v3/contract.ts";
|
|
17
|
+
import { readEventV3ControlState } from "../../events/v3/control.ts";
|
|
18
|
+
import { liveInstanceIdV3 } from "../../events/v3/live-routing.ts";
|
|
19
|
+
import { readLedgerV3 } from "../../events/v3/reader.ts";
|
|
20
|
+
import { readLiveCoordinationRow } from "../state/live-coordination-view.ts";
|
|
36
21
|
|
|
37
22
|
export type { VerdictResult } from "./verdict.ts";
|
|
38
23
|
|
|
39
24
|
import type { VerdictResult } from "./verdict.ts";
|
|
40
25
|
|
|
41
|
-
interface CanonicalEvent {
|
|
42
|
-
event_id: string;
|
|
43
|
-
event_type: string;
|
|
44
|
-
ts: string;
|
|
45
|
-
instance_id: string;
|
|
46
|
-
session_id: string;
|
|
47
|
-
turn_id?: string;
|
|
48
|
-
adapter: string;
|
|
49
|
-
source: string;
|
|
50
|
-
data: Record<string, unknown>;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
26
|
export interface StopHookRequest {
|
|
54
27
|
rule: "stop-hook";
|
|
55
28
|
instance_id: string;
|
|
56
29
|
session_id?: string;
|
|
57
|
-
/** Firing adapter. Selects the end-of-turn ack signal (see `ackSignalFor`).
|
|
58
|
-
* Undefined → Claude Code semantics (transcript-scanned status box). */
|
|
59
30
|
adapter?: string;
|
|
60
|
-
/** Wall-clock cutoff for the current turn; events strictly after this are not yet relevant. */
|
|
61
31
|
now_ms?: number;
|
|
62
|
-
/** Override the turn-window discovery (used by tests). */
|
|
63
32
|
turn_window?: { start_ms: number; end_ms: number };
|
|
64
|
-
/** Bypass switch: operator escape hatch identical to HARNERY_AGENT_COORD_BYPASS_STOP. */
|
|
65
33
|
bypass?: boolean;
|
|
66
|
-
/** Headless child spawned by `harn workflow` (HARNERY_WORKFLOW_CHILD=1).
|
|
67
|
-
* The end-of-turn ritual exists to surface status to a HUMAN reader; a
|
|
68
|
-
* workflow child reports to the engine's transcript instead, so the ritual is
|
|
69
|
-
* meaningless there — worse, blocking burns the child's turn budget on
|
|
70
|
-
* re-prompts (observed as error_max_turns in the Phase 1 spike). Exempting
|
|
71
|
-
* here, rather than disabling the child's hooks wholesale, keeps heartbeat +
|
|
72
|
-
* event capture on: the child stays visible to peers and the coord layer. */
|
|
73
34
|
workflow_child?: boolean;
|
|
74
35
|
}
|
|
75
36
|
|
|
76
|
-
/**
|
|
77
|
-
* The end-of-turn "I surfaced my status" signal, detected differently per
|
|
78
|
-
* adapter because the ritual's *goal* (status visible to the human) is reached
|
|
79
|
-
* by different means:
|
|
80
|
-
*
|
|
81
|
-
* - **Claude Code / Codex** collapse tool calls in the UI, so the human-visible
|
|
82
|
-
* signal is the verbatim status-box paste in the reply (rule 2/3, detected
|
|
83
|
-
* by scanning the transcript for the `┌─ agent-` prefix, `status_box_present`
|
|
84
|
-
* on `turn.stop`).
|
|
85
|
-
* - **Cursor** renders Shell output inline, so simply *running* `harn agents
|
|
86
|
-
* status` (which emits `state.status_checked`) already puts the box on
|
|
87
|
-
* screen. The separate paste is redundant, and undetectable anyway, since
|
|
88
|
-
* Cursor's stop payload carries neither a transcript path nor the assistant
|
|
89
|
-
* message. So rule 1/3 *is* the ack signal on Cursor; rule 2/3 collapses into
|
|
90
|
-
* it rather than being a second requirement.
|
|
91
|
-
*
|
|
92
|
-
* This is why the fix is not "relax 2/3 because we can't see it": it's "2/3
|
|
93
|
-
* and 1/3 are two detections of the same thing, and Cursor's inline UI makes
|
|
94
|
-
* 1/3 the right one." The enforcement *channel* (exit-2+stderr vs Cursor's
|
|
95
|
-
* `followup_message`) is handled separately in hooks/adapter/output.ts.
|
|
96
|
-
*/
|
|
97
|
-
type AckSignal = "status_box_present" | "status_checked";
|
|
98
|
-
|
|
99
|
-
function ackSignalFor(adapter?: string): AckSignal {
|
|
100
|
-
return adapter === "cursor" ? "status_checked" : "status_box_present";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const RECENT_EVENT_WINDOW_LINES = 5_000;
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Machine marker that opens a Stop-remediation message. Written by
|
|
107
|
-
* `hooks/adapter/output.ts` on the adapters whose Stop channel is a new user
|
|
108
|
-
* message, and read back here off `user_prompt.submit.data.prompt_text` to
|
|
109
|
-
* recognize a turn Harnery itself opened.
|
|
110
|
-
*
|
|
111
|
-
* Leading position is deliberate: `prompt_text` is clamped when recorded, so a
|
|
112
|
-
* trailing marker could be truncated away on a long reason.
|
|
113
|
-
*/
|
|
114
37
|
export const STOP_REMEDIATION_MARKER = "[harnery:stop-remediation";
|
|
115
38
|
|
|
116
|
-
/** How far back the remediation walk may travel. Adapters cap their own
|
|
117
|
-
* followup chains (Cursor's `loop_limit`), and each prompt can appear once per
|
|
118
|
-
* observing adapter, so this only guards a pathological stream. */
|
|
119
39
|
const MAX_REMEDIATION_WALK_BACK = 16;
|
|
120
40
|
|
|
121
|
-
function
|
|
122
|
-
const
|
|
123
|
-
if (
|
|
124
|
-
|
|
41
|
+
export function evaluateStopHook(coordRoot: string, req: StopHookRequest): VerdictResult {
|
|
42
|
+
const unconditional = unconditionalVerdict(req);
|
|
43
|
+
if (unconditional) return unconditional;
|
|
44
|
+
|
|
45
|
+
const control = readEventV3ControlState(coordRoot);
|
|
46
|
+
if (control.state !== "candidate" && control.state !== "active") {
|
|
47
|
+
return evidenceUnavailable(
|
|
48
|
+
`V3 control state is ${control.state}; authoritative Stop evidence is unavailable`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const ledger =
|
|
54
|
+
control.state === "candidate"
|
|
55
|
+
? readLedgerV3(coordRoot, { authority: "candidate" })
|
|
56
|
+
: readLedgerV3(coordRoot);
|
|
57
|
+
if (!ledger.complete || ledger.diagnostics.length > 0) {
|
|
58
|
+
return evidenceUnavailable(
|
|
59
|
+
"V3 ledger integrity is not authority-safe; Stop remains fail-open",
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return evaluateStopHookV3Events(
|
|
63
|
+
coordRoot,
|
|
64
|
+
req,
|
|
65
|
+
ledger.events.map(({ event }) => event),
|
|
66
|
+
);
|
|
67
|
+
} catch {
|
|
68
|
+
return evidenceUnavailable("V3 ledger is not readable; Stop remains fail-open");
|
|
69
|
+
}
|
|
125
70
|
}
|
|
126
71
|
|
|
127
|
-
/**
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return
|
|
72
|
+
/** Pure V3 evaluator used by replay and regression tests after authority checks. */
|
|
73
|
+
export function evaluateStopHookV3Events(
|
|
74
|
+
coordRoot: string,
|
|
75
|
+
req: StopHookRequest,
|
|
76
|
+
events: readonly EventV3[],
|
|
77
|
+
): VerdictResult {
|
|
78
|
+
const unconditional = unconditionalVerdict(req);
|
|
79
|
+
if (unconditional) return unconditional;
|
|
80
|
+
|
|
81
|
+
const owner = liveInstanceIdV3(req.instance_id);
|
|
82
|
+
const endMs = req.turn_window?.end_ms ?? req.now_ms ?? Date.now();
|
|
83
|
+
const currentTerminal = [...events]
|
|
84
|
+
.reverse()
|
|
85
|
+
.find(
|
|
86
|
+
(event) =>
|
|
87
|
+
event.event_type === "turn.completed" &&
|
|
88
|
+
event.scope.instance_id === owner &&
|
|
89
|
+
eventTimeMs(event) <= endMs,
|
|
90
|
+
);
|
|
91
|
+
if (currentTerminal?.event_type !== "turn.completed") {
|
|
92
|
+
return {
|
|
93
|
+
allow: true,
|
|
94
|
+
exit_code: 0,
|
|
95
|
+
rule: "stop-hook.no_history",
|
|
96
|
+
reason: "no authoritative V3 turn terminal for this owner; nothing to evaluate",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!("generation_id" in currentTerminal.scope)) {
|
|
101
|
+
return evidenceUnavailable("turn.completed has no V3 generation scope; Stop remains fail-open");
|
|
102
|
+
}
|
|
103
|
+
const generationId = currentTerminal.scope.generation_id;
|
|
104
|
+
const ownerEvents = events.filter(
|
|
105
|
+
(event) =>
|
|
106
|
+
event.scope.instance_id === owner &&
|
|
107
|
+
"generation_id" in event.scope &&
|
|
108
|
+
event.scope.generation_id === generationId,
|
|
109
|
+
);
|
|
110
|
+
const startMs =
|
|
111
|
+
req.turn_window?.start_ms ??
|
|
112
|
+
resolveTurnStartMs(ownerEvents, endMs, Math.max(0, endMs - 5 * 60 * 1000));
|
|
113
|
+
const inTurn = ownerEvents.filter((event) => {
|
|
114
|
+
const time = eventTimeMs(event);
|
|
115
|
+
return Number.isFinite(time) && time >= startMs && time <= endMs;
|
|
157
116
|
});
|
|
158
|
-
if (prompts.length === 0) return fallbackMs;
|
|
159
117
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
118
|
+
const usedTool = inTurn.some((event) => event.event_type === "tool.requested");
|
|
119
|
+
const statusEvents = inTurn.filter(
|
|
120
|
+
(event) =>
|
|
121
|
+
event.event_type === "coord.status_observed" && event.payload.subject_instance_id === owner,
|
|
122
|
+
);
|
|
123
|
+
const statusChecked = statusEvents.length > 0;
|
|
124
|
+
const requiredStatusChecked = agentsRequireGitFinalization(coordRoot)
|
|
125
|
+
? statusEvents.some(
|
|
126
|
+
(event) =>
|
|
127
|
+
event.event_type === "coord.status_observed" &&
|
|
128
|
+
event.payload.status === "end_turn_checked",
|
|
129
|
+
)
|
|
130
|
+
: statusChecked;
|
|
131
|
+
const taskSet = inTurn.some(
|
|
132
|
+
(event) =>
|
|
133
|
+
event.event_type === "coord.task_changed" && event.payload.subject_instance_id === owner,
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const turnTerminals = inTurn.filter(
|
|
137
|
+
(event): event is Extract<EventV3, { event_type: "turn.completed" }> =>
|
|
138
|
+
event.event_type === "turn.completed",
|
|
139
|
+
);
|
|
140
|
+
const latestTerminal = turnTerminals.at(-1);
|
|
141
|
+
const latestBox = observedBoolean(latestTerminal?.payload.ritual?.status_box_present);
|
|
142
|
+
if (req.adapter !== "cursor" && latestBox === undefined) {
|
|
143
|
+
return evidenceUnavailable(
|
|
144
|
+
"turn.completed has no observed V3 status-box result; Stop remains fail-open",
|
|
145
|
+
);
|
|
167
146
|
}
|
|
168
147
|
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
|
|
148
|
+
const ackPresent = req.adapter === "cursor" ? requiredStatusChecked : latestBox === true;
|
|
149
|
+
const ackBlock =
|
|
150
|
+
req.adapter === "cursor" ? () => rule13Block(coordRoot) : () => rule23Block(coordRoot);
|
|
151
|
+
|
|
152
|
+
// Pure prose turns keep the human-visible acknowledgement but do not require
|
|
153
|
+
// task or final-status mutations. This preserves the pre-V3 policy exactly.
|
|
154
|
+
if (!usedTool) {
|
|
155
|
+
if (!ackPresent) return ackBlock();
|
|
156
|
+
return {
|
|
157
|
+
allow: true,
|
|
158
|
+
exit_code: 0,
|
|
159
|
+
rule: "stop-hook.pure_prose_pass",
|
|
160
|
+
reason: "no tool calls this turn; task and final-status mutations were not required",
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!requiredStatusChecked) return rule13Block(coordRoot);
|
|
165
|
+
if (!ackPresent) return ackBlock();
|
|
166
|
+
if (!taskSet) return rule33Block(coordRoot);
|
|
167
|
+
|
|
168
|
+
// Claude Code can prove session-name presentation from assistant-only text.
|
|
169
|
+
// Cursor cannot expose that text and Codex returned observe-only above.
|
|
170
|
+
if (req.adapter !== "cursor") {
|
|
171
|
+
const naming = turnTerminals
|
|
172
|
+
.map((event) => observedNaming(event.payload.ritual?.session_name))
|
|
173
|
+
.filter((value): value is { required: boolean; present: boolean } => value !== undefined);
|
|
174
|
+
if (
|
|
175
|
+
naming.some(({ required }) => required) &&
|
|
176
|
+
!naming.some(({ present }) => present) &&
|
|
177
|
+
!sessionNameSeenStamped(coordRoot, req.instance_id)
|
|
178
|
+
) {
|
|
179
|
+
return sessionNameBlock(coordRoot, req.instance_id);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return { allow: true, exit_code: 0, rule: "stop-hook.pass" };
|
|
172
184
|
}
|
|
173
185
|
|
|
174
|
-
|
|
175
|
-
* Evaluate the Stop-hook verdict. Returns the first failing rule (or allow
|
|
176
|
-
* when all three pass). Soft-fails open when the event stream isn't
|
|
177
|
-
* readable, fail-open posture on a verdict failure.
|
|
178
|
-
*/
|
|
179
|
-
export function evaluateStopHook(coordRoot: string, req: StopHookRequest): VerdictResult {
|
|
186
|
+
function unconditionalVerdict(req: StopHookRequest): VerdictResult | undefined {
|
|
180
187
|
if (req.bypass) {
|
|
181
188
|
return {
|
|
182
189
|
allow: true,
|
|
@@ -185,7 +192,6 @@ export function evaluateStopHook(coordRoot: string, req: StopHookRequest): Verdi
|
|
|
185
192
|
reason: "HARNERY_AGENT_COORD_BYPASS_STOP=1",
|
|
186
193
|
};
|
|
187
194
|
}
|
|
188
|
-
|
|
189
195
|
if (req.workflow_child) {
|
|
190
196
|
return {
|
|
191
197
|
allow: true,
|
|
@@ -194,13 +200,6 @@ export function evaluateStopHook(coordRoot: string, req: StopHookRequest): Verdi
|
|
|
194
200
|
reason: "HARNERY_WORKFLOW_CHILD=1: headless workflow child; ritual not applicable",
|
|
195
201
|
};
|
|
196
202
|
}
|
|
197
|
-
|
|
198
|
-
// A blocked Codex Stop does not reject the turn. Codex creates a continuation
|
|
199
|
-
// prompt and asks the model to answer again. Some clients retain only that
|
|
200
|
-
// final continuation response, so a coordination reminder can replace a
|
|
201
|
-
// correct user-facing answer with status output. The Stop path has already
|
|
202
|
-
// emitted turn.stop and projected the coordination state before this verdict
|
|
203
|
-
// runs. Keep that telemetry, but never continue a Codex turn for this ritual.
|
|
204
203
|
if (req.adapter === "codex") {
|
|
205
204
|
return {
|
|
206
205
|
allow: true,
|
|
@@ -209,137 +208,73 @@ export function evaluateStopHook(coordRoot: string, req: StopHookRequest): Verdi
|
|
|
209
208
|
reason: "Codex Stop continuations must not replace the user-facing answer",
|
|
210
209
|
};
|
|
211
210
|
}
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
212
213
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
214
|
+
function resolveTurnStartMs(
|
|
215
|
+
ownerEvents: readonly EventV3[],
|
|
216
|
+
nowMs: number,
|
|
217
|
+
fallbackMs: number,
|
|
218
|
+
): number {
|
|
219
|
+
const turns = ownerEvents.filter(
|
|
220
|
+
(event): event is Extract<EventV3, { event_type: "turn.started" }> =>
|
|
221
|
+
event.event_type === "turn.started" && eventTimeMs(event) <= nowMs,
|
|
222
|
+
);
|
|
223
|
+
if (turns.length === 0) return fallbackMs;
|
|
224
224
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
};
|
|
225
|
+
let index = turns.length - 1;
|
|
226
|
+
let hops = 0;
|
|
227
|
+
while (index > 0 && hops < MAX_REMEDIATION_WALK_BACK) {
|
|
228
|
+
const turn = turns[index];
|
|
229
|
+
if (!turn?.payload.stop_remediation) break;
|
|
230
|
+
index -= 1;
|
|
231
|
+
hops += 1;
|
|
233
232
|
}
|
|
233
|
+
return eventTimeMs(turns[index]!);
|
|
234
|
+
}
|
|
234
235
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// together with the turn it repairs (see `resolveTurnStartMs`). Fall back to a
|
|
239
|
-
// 5-minute window when no user_prompt.submit is in scope (fresh wiring,
|
|
240
|
-
// out-of-window prompt, etc.) so a stale stream doesn't silently pass.
|
|
241
|
-
const nowMs = req.now_ms ?? Date.now();
|
|
242
|
-
const startMs = req.turn_window
|
|
243
|
-
? req.turn_window.start_ms
|
|
244
|
-
: resolveTurnStartMs(ownerEvents, nowMs, nowMs - 5 * 60 * 1000);
|
|
245
|
-
const endMs = req.turn_window ? req.turn_window.end_ms : nowMs;
|
|
246
|
-
|
|
247
|
-
const inTurn = ownerEvents.filter((e) => {
|
|
248
|
-
const t = Date.parse(e.ts);
|
|
249
|
-
return Number.isFinite(t) && t >= startMs && t <= endMs;
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
const toolPreUseInTurn = inTurn.some((e) => e.event_type === "tool.pre_use");
|
|
253
|
-
const statusEvents = inTurn.filter((e) => e.event_type === "state.status_checked");
|
|
254
|
-
const statusChecked = statusEvents.length > 0;
|
|
255
|
-
const requiredStatusChecked = agentsRequireGitFinalization(coordRoot)
|
|
256
|
-
? statusEvents.some((e) => e.data.git_finalization_checked === true)
|
|
257
|
-
: statusChecked;
|
|
258
|
-
const taskSet = inTurn.some((e) => e.event_type === "state.task_set");
|
|
259
|
-
|
|
260
|
-
// Rule 2/3: status_box_present on the most recent turn.stop for this owner.
|
|
261
|
-
// The turn.stop event fires from agent-hook stop, which is wired BEFORE
|
|
262
|
-
// the stop-hook verdict, so by the time we evaluate, the just-
|
|
263
|
-
// fired turn.stop is already in the stream.
|
|
264
|
-
const latestTurnStop = [...inTurn].reverse().find((e) => e.event_type === "turn.stop");
|
|
265
|
-
const boxPresent = latestTurnStop ? Boolean(latestTurnStop.data.status_box_present) : false;
|
|
266
|
-
|
|
267
|
-
// Adapter-aware end-of-turn ack signal (see `ackSignalFor`). On Cursor the
|
|
268
|
-
// ack is `status_checked` (running `harn agents status` shows the box inline);
|
|
269
|
-
// on Claude Code / Codex it's the transcript-scanned `status_box_present`.
|
|
270
|
-
// The matching block helper carries the right "how to fix" message.
|
|
271
|
-
const ackSignal = ackSignalFor(req.adapter);
|
|
272
|
-
const ackPresent =
|
|
273
|
-
ackSignal === "status_checked"
|
|
274
|
-
? toolPreUseInTurn
|
|
275
|
-
? requiredStatusChecked
|
|
276
|
-
: statusChecked
|
|
277
|
-
: boxPresent;
|
|
278
|
-
const ackBlock =
|
|
279
|
-
ackSignal === "status_checked" ? () => rule13Block(coordRoot) : () => rule23Block(coordRoot);
|
|
280
|
-
|
|
281
|
-
// Pure-prose-turn exemption: only the ack signal applies. Parity
|
|
282
|
-
// across adapters: CC requires the box; Cursor requires status_checked.
|
|
283
|
-
if (!toolPreUseInTurn) {
|
|
284
|
-
if (!ackPresent) {
|
|
285
|
-
return ackBlock();
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
allow: true,
|
|
289
|
-
exit_code: 0,
|
|
290
|
-
rule: "stop-hook.pure_prose_pass",
|
|
291
|
-
reason: "no tool calls this turn; rules 1/3 + 3/3 skipped",
|
|
292
|
-
};
|
|
293
|
-
}
|
|
236
|
+
function eventTimeMs(event: EventV3): number {
|
|
237
|
+
return Date.parse(event.time.observed_at);
|
|
238
|
+
}
|
|
294
239
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
240
|
+
function observedBoolean(value: unknown): boolean | undefined {
|
|
241
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
242
|
+
const observation = value as { state?: unknown; value?: unknown };
|
|
243
|
+
return observation.state === "observed" && typeof observation.value === "boolean"
|
|
244
|
+
? observation.value
|
|
245
|
+
: undefined;
|
|
246
|
+
}
|
|
300
247
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const namingEvent = inTurn.find(
|
|
312
|
-
(e) =>
|
|
313
|
-
((e.event_type === "state.task_set" && e.data.first_of_session === true) ||
|
|
314
|
-
(e.event_type === "state.task_state" && e.data.name_reminted === true)) &&
|
|
315
|
-
typeof e.data.suggested_session_name === "string" &&
|
|
316
|
-
e.data.suggested_session_name.length > 0,
|
|
317
|
-
);
|
|
318
|
-
if (namingEvent) {
|
|
319
|
-
// ANY in-window turn.stop with the flag satisfies the rule, not just the
|
|
320
|
-
// latest: once seen, `session_name_seen_at` is stamped and later
|
|
321
|
-
// turn.stops OMIT the field, so a later block on a different rule (whose
|
|
322
|
-
// repair fires a fresh turn.stop) must not un-satisfy this one.
|
|
323
|
-
const namePresent = inTurn.some(
|
|
324
|
-
(e) => e.event_type === "turn.stop" && e.data.session_name_present === true,
|
|
325
|
-
);
|
|
326
|
-
if (!namePresent) {
|
|
327
|
-
return sessionNameBlock(String(namingEvent.data.suggested_session_name));
|
|
328
|
-
}
|
|
329
|
-
}
|
|
248
|
+
function observedNaming(value: unknown): { required: boolean; present: boolean } | undefined {
|
|
249
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
250
|
+
const observation = value as { state?: unknown; value?: unknown };
|
|
251
|
+
if (
|
|
252
|
+
observation.state !== "observed" ||
|
|
253
|
+
!observation.value ||
|
|
254
|
+
typeof observation.value !== "object" ||
|
|
255
|
+
Array.isArray(observation.value)
|
|
256
|
+
) {
|
|
257
|
+
return undefined;
|
|
330
258
|
}
|
|
259
|
+
const naming = observation.value as { required?: unknown; present?: unknown };
|
|
260
|
+
return typeof naming.required === "boolean" && typeof naming.present === "boolean"
|
|
261
|
+
? { required: naming.required, present: naming.present }
|
|
262
|
+
: undefined;
|
|
263
|
+
}
|
|
331
264
|
|
|
265
|
+
function evidenceUnavailable(reason: string): VerdictResult {
|
|
332
266
|
return {
|
|
333
267
|
allow: true,
|
|
334
268
|
exit_code: 0,
|
|
335
|
-
rule: "stop-hook.
|
|
269
|
+
rule: "stop-hook.v3_evidence_unavailable",
|
|
270
|
+
reason,
|
|
336
271
|
};
|
|
337
272
|
}
|
|
338
273
|
|
|
339
274
|
function rule13Block(coordRoot?: string): VerdictResult {
|
|
340
275
|
const missingEvidence = agentsRequireGitFinalization(coordRoot)
|
|
341
|
-
? "no
|
|
342
|
-
: "no
|
|
276
|
+
? "no end_turn_checked coord.status_observed event found in this turn"
|
|
277
|
+
: "no coord.status_observed event found in this turn";
|
|
343
278
|
return {
|
|
344
279
|
allow: false,
|
|
345
280
|
exit_code: 2,
|
|
@@ -353,47 +288,58 @@ function rule23Block(coordRoot?: string): VerdictResult {
|
|
|
353
288
|
allow: false,
|
|
354
289
|
exit_code: 2,
|
|
355
290
|
rule: "stop-hook.rule_2_3",
|
|
356
|
-
reason: `End-of-turn rule (2/3): turn.
|
|
291
|
+
reason: `End-of-turn rule (2/3): turn.completed did not observe the agent-status box in your reply text. Paste the \`${endOfTurnStatusCommand(coordRoot)}\` output verbatim as a fenced code block (the \`┌─ agent-\` prefix is the detection signal).`,
|
|
357
292
|
};
|
|
358
293
|
}
|
|
359
294
|
|
|
360
|
-
|
|
295
|
+
/**
|
|
296
|
+
* A remediation stop cannot land a fresh `turn.completed`: the turn's first
|
|
297
|
+
* stop closed the turn span, continuations open no new one, so the recorder
|
|
298
|
+
* ignores their terminals. When that first terminal lost the transcript flush
|
|
299
|
+
* race and recorded `present: false`, in-window ledger evidence can never
|
|
300
|
+
* change, and the naming rule blocked every retry forever. The sighting stamp
|
|
301
|
+
* on the live coordination row is the durable record that the current
|
|
302
|
+
* suggested name WAS shown in an assistant reply (session-name-presence.ts
|
|
303
|
+
* writes it on the first sighting), so honor it before blocking. Ledger
|
|
304
|
+
* evidence stays primary; the stamp is consulted only after in-window
|
|
305
|
+
* terminals said absent.
|
|
306
|
+
*/
|
|
307
|
+
function sessionNameSeenStamped(coordRoot: string, instanceId: string): boolean {
|
|
308
|
+
try {
|
|
309
|
+
const row = readLiveCoordinationRow(coordRoot, instanceId);
|
|
310
|
+
return (
|
|
311
|
+
typeof row?.suggested_session_name === "string" &&
|
|
312
|
+
row.suggested_session_name.length > 0 &&
|
|
313
|
+
row.session_name_seen_for === row.suggested_session_name
|
|
314
|
+
);
|
|
315
|
+
} catch {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function sessionNameBlock(coordRoot: string, instanceId: string): VerdictResult {
|
|
321
|
+
let name: string | undefined;
|
|
322
|
+
try {
|
|
323
|
+
name = readLiveCoordinationRow(coordRoot, instanceId)?.suggested_session_name;
|
|
324
|
+
} catch {
|
|
325
|
+
// The ledger evidence still authorizes the block; the cache is UX only.
|
|
326
|
+
}
|
|
327
|
+
const instruction = name
|
|
328
|
+
? `Reproduce it by itself in a fenced code block: ${name}`
|
|
329
|
+
: `Run \`${resolveBinName(coordRoot)} agents suggest-name\`, then reproduce its output by itself in a fenced code block.`;
|
|
361
330
|
return {
|
|
362
331
|
allow: false,
|
|
363
332
|
exit_code: 2,
|
|
364
333
|
rule: "stop-hook.session_name",
|
|
365
|
-
reason: `Session-naming rule:
|
|
334
|
+
reason: `Session-naming rule: V3 observed that the current session name was required but absent. ${instruction}`,
|
|
366
335
|
};
|
|
367
336
|
}
|
|
368
337
|
|
|
369
|
-
function rule33Block(): VerdictResult {
|
|
338
|
+
function rule33Block(coordRoot?: string): VerdictResult {
|
|
370
339
|
return {
|
|
371
340
|
allow: false,
|
|
372
341
|
exit_code: 2,
|
|
373
342
|
rule: "stop-hook.rule_3_3",
|
|
374
|
-
reason: `End-of-turn rule (3/3): no
|
|
343
|
+
reason: `End-of-turn rule (3/3): no coord.task_changed event found in this turn; run \`${resolveBinName(coordRoot)} agents set-task "<short focus>"\` to declare what you're working on. Pass an empty string if the turn was purely conversational.`,
|
|
375
344
|
};
|
|
376
345
|
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Read the last N JSON lines from events.ndjson. The Stop-hook verdict needs
|
|
380
|
-
* just the most recent turn so we tail-read aggressively.
|
|
381
|
-
*/
|
|
382
|
-
function readRecentEvents(coordRoot: string, maxLines: number): CanonicalEvent[] {
|
|
383
|
-
const path = join(coordRoot, ".harnery", "events.ndjson");
|
|
384
|
-
if (!existsSync(path)) return [];
|
|
385
|
-
const raw = readFileSync(path, "utf8");
|
|
386
|
-
const lines = raw.split("\n");
|
|
387
|
-
const start = Math.max(0, lines.length - maxLines);
|
|
388
|
-
const out: CanonicalEvent[] = [];
|
|
389
|
-
for (let i = start; i < lines.length; i++) {
|
|
390
|
-
const line = lines[i];
|
|
391
|
-
if (!line?.trim()) continue;
|
|
392
|
-
try {
|
|
393
|
-
out.push(JSON.parse(line) as CanonicalEvent);
|
|
394
|
-
} catch {
|
|
395
|
-
/* skip malformed */
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
return out;
|
|
399
|
-
}
|