harnery 0.30.0 → 0.31.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/README.md +4 -4
- package/dist/commander.d.ts +8 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +14 -13
- package/dist/commands/adapter.d.ts +12 -0
- package/dist/commands/adapter.d.ts.map +1 -0
- package/dist/commands/{harness.js → adapter.js} +35 -35
- package/dist/commands/agents.d.ts +3 -2
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +185 -74
- package/dist/commands/artifacts.d.ts +4 -0
- package/dist/commands/artifacts.d.ts.map +1 -0
- package/dist/commands/artifacts.js +143 -0
- package/dist/commands/backup.d.ts +1 -1
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +5 -2
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +310 -7
- package/dist/commands/checkpoint.d.ts +12 -0
- package/dist/commands/checkpoint.d.ts.map +1 -0
- package/dist/commands/checkpoint.js +162 -0
- package/dist/commands/context.d.ts +2 -2
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +3 -151
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +31 -7
- package/dist/commands/deinit.d.ts +2 -2
- package/dist/commands/deinit.js +15 -15
- package/dist/commands/doctor.js +23 -23
- package/dist/commands/governor.d.ts +4 -0
- package/dist/commands/governor.d.ts.map +1 -0
- package/dist/commands/{supervisor.js → governor.js} +133 -108
- package/dist/commands/grep.d.ts +1 -1
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +19 -2
- package/dist/commands/init.d.ts +12 -12
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +44 -30
- package/dist/commands/{session.d.ts → journal.d.ts} +2 -2
- package/dist/commands/journal.d.ts.map +1 -0
- package/dist/commands/{scratch.js → journal.js} +47 -47
- package/dist/commands/policy.js +1 -1
- package/dist/commands/presence.js +2 -2
- package/dist/commands/sync.d.ts +1 -1
- package/dist/commands/sync.js +3 -3
- package/dist/commands/tunnel.d.ts +16 -0
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +213 -27
- package/dist/commands/web-fetch.js +1 -1
- package/dist/commands/web.d.ts +19 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +51 -0
- package/dist/commands/work.d.ts.map +1 -1
- package/dist/commands/work.js +38 -22
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +35 -28
- package/dist/core/{harnesses → adapters}/attest-projection.d.ts +2 -2
- package/dist/core/adapters/attest-projection.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/attest.d.ts +16 -16
- package/dist/core/adapters/attest.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/attest.js +9 -9
- package/dist/core/{harnesses → adapters}/attestation.d.ts +16 -16
- package/dist/core/adapters/attestation.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/attestation.js +20 -20
- package/dist/core/{harnesses → adapters}/bench.d.ts +12 -12
- package/dist/core/adapters/bench.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/bench.js +12 -12
- package/dist/core/adapters/index.d.ts +13 -0
- package/dist/core/adapters/index.d.ts.map +1 -0
- package/dist/core/adapters/index.js +6 -0
- package/dist/core/{harnesses → adapters}/profiles.d.ts +11 -11
- package/dist/core/adapters/profiles.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/profiles.js +11 -11
- package/dist/core/adapters/registry.d.ts +15 -0
- package/dist/core/adapters/registry.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/registry.js +11 -11
- package/dist/core/{harnesses → adapters}/types.d.ts +23 -23
- package/dist/core/adapters/types.d.ts.map +1 -0
- package/dist/core/{harnesses → adapters}/types.js +1 -1
- package/dist/core/agents/canonical-emit.d.ts +9 -14
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +15 -44
- package/dist/core/agents/cli-emit.js +1 -1
- package/dist/core/agents/cli.js +30 -26
- package/dist/core/agents/codex-replay.d.ts +1 -1
- package/dist/core/agents/codex-replay.js +6 -6
- package/dist/core/agents/coord-bin.d.ts +33 -0
- package/dist/core/agents/coord-bin.d.ts.map +1 -0
- package/dist/core/agents/coord-bin.js +89 -0
- package/dist/core/agents/coord-client.d.ts +78 -8
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +303 -75
- package/dist/core/agents/events/consume.d.ts +1 -1
- package/dist/core/agents/events/emit.d.ts +5 -6
- package/dist/core/agents/events/emit.d.ts.map +1 -1
- package/dist/core/agents/events/emit.js +2 -2
- package/dist/core/agents/paths.d.ts +5 -2
- package/dist/core/agents/paths.d.ts.map +1 -1
- package/dist/core/agents/paths.js +7 -13
- package/dist/core/agents/render/prompt-context.d.ts +21 -9
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +82 -30
- package/dist/core/agents/render/session-context.d.ts +1 -1
- package/dist/core/agents/render/session-context.js +5 -5
- package/dist/core/agents/rules/claim-conflict.d.ts +2 -6
- package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/claim-conflict.js +1 -1
- package/dist/core/agents/rules/commit-conflict.js +98 -22
- package/dist/core/agents/rules/stop-hook.d.ts +9 -9
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +23 -5
- package/dist/core/agents/rules/verdict.d.ts +14 -0
- package/dist/core/agents/rules/verdict.d.ts.map +1 -0
- package/dist/core/agents/rules/verdict.js +1 -0
- package/dist/core/agents/session-events.js +3 -3
- package/dist/core/agents/state/council.d.ts +1 -1
- package/dist/core/agents/state/council.js +1 -1
- package/dist/core/agents/state/heartbeat-projector.d.ts +3 -2
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-projector.js +14 -10
- package/dist/core/agents/state/heartbeat-writer.d.ts +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +12 -12
- package/dist/core/agents/state/{scratch.d.ts → journal.d.ts} +7 -7
- package/dist/core/agents/state/{scratch.d.ts.map → journal.d.ts.map} +1 -1
- package/dist/core/agents/state/{scratch.js → journal.js} +12 -12
- package/dist/core/agents/state/pidmap.d.ts +28 -4
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +130 -15
- package/dist/core/agents/state/proc-start.d.ts +95 -0
- package/dist/core/agents/state/proc-start.d.ts.map +1 -0
- package/dist/core/agents/state/proc-start.js +199 -0
- package/dist/core/agents/state/shell-mutation.d.ts +1 -1
- package/dist/core/agents/state/shell-mutation.js +1 -1
- package/dist/core/agents/state/stale-sweep.js +7 -7
- package/dist/core/artifacts/index.d.ts +86 -0
- package/dist/core/artifacts/index.d.ts.map +1 -0
- package/dist/core/artifacts/index.js +421 -0
- package/dist/core/config.d.ts +9 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +26 -2
- package/dist/core/context/index.d.ts +12 -12
- package/dist/core/context/index.js +10 -10
- package/dist/core/governor/adapter-spread.d.ts +52 -0
- package/dist/core/governor/adapter-spread.d.ts.map +1 -0
- package/dist/core/governor/adapter-spread.js +52 -0
- package/dist/core/governor/index.d.ts +7 -0
- package/dist/core/governor/index.d.ts.map +1 -0
- package/dist/core/governor/index.js +6 -0
- package/dist/core/governor/plan-api.d.ts +38 -0
- package/dist/core/governor/plan-api.d.ts.map +1 -0
- package/dist/core/governor/plan-api.js +83 -0
- package/dist/core/governor/plan-read.d.ts +5 -0
- package/dist/core/governor/plan-read.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/plan-read.js +66 -52
- package/dist/core/{supervisor → governor}/plan-types.d.ts +57 -56
- package/dist/core/governor/plan-types.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/plan-types.js +4 -4
- package/dist/core/governor/planning.d.ts +48 -0
- package/dist/core/governor/planning.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/planning.js +125 -94
- package/dist/core/governor/read.d.ts +6 -0
- package/dist/core/governor/read.d.ts.map +1 -0
- package/dist/core/governor/read.js +4 -0
- package/dist/core/governor/runner.d.ts +37 -0
- package/dist/core/governor/runner.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/runner.js +15 -15
- package/dist/core/governor/service-read.d.ts +6 -0
- package/dist/core/governor/service-read.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/service-read.js +12 -12
- package/dist/core/governor/service.d.ts +114 -0
- package/dist/core/governor/service.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/service.js +57 -57
- package/dist/core/governor/state.d.ts +116 -0
- package/dist/core/governor/state.d.ts.map +1 -0
- package/dist/core/{supervisor → governor}/state.js +228 -108
- package/dist/core/hooks/adapter/detect.d.ts +9 -0
- package/dist/core/hooks/{harness → adapter}/detect.d.ts.map +1 -1
- package/dist/core/hooks/{harness → adapter}/detect.js +8 -8
- package/dist/core/hooks/{harness → adapter}/events.d.ts +15 -14
- package/dist/core/hooks/adapter/events.d.ts.map +1 -0
- package/dist/core/hooks/{harness → adapter}/events.js +5 -5
- package/dist/core/hooks/{harness → adapter}/output.d.ts +20 -14
- package/dist/core/hooks/adapter/output.d.ts.map +1 -0
- package/dist/core/hooks/{harness → adapter}/output.js +30 -22
- package/dist/core/hooks/{harness → adapter}/parse.d.ts +5 -5
- package/dist/core/hooks/{harness → adapter}/parse.d.ts.map +1 -1
- package/dist/core/hooks/{harness → adapter}/parse.js +4 -4
- package/dist/core/hooks/{harness → adapter}/wiring.d.ts +15 -15
- package/dist/core/hooks/{harness → adapter}/wiring.d.ts.map +1 -1
- package/dist/core/hooks/{harness → adapter}/wiring.js +13 -13
- package/dist/core/hooks/cli.d.ts +3 -3
- package/dist/core/hooks/cli.js +187 -162
- package/dist/core/hooks/effects/image-capture.d.ts +5 -5
- package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
- package/dist/core/hooks/effects/image-capture.js +3 -3
- package/dist/core/hooks/effects/index.d.ts +12 -12
- package/dist/core/hooks/effects/index.d.ts.map +1 -1
- package/dist/core/hooks/effects/index.js +19 -19
- package/dist/core/hooks/events/emit.d.ts +2 -2
- package/dist/core/hooks/events/emit.d.ts.map +1 -1
- package/dist/core/hooks/events/emit.js +1 -1
- package/dist/core/hooks/events/rotate.js +1 -1
- package/dist/core/hooks/events/schema.d.ts +13 -5
- package/dist/core/hooks/events/schema.d.ts.map +1 -1
- package/dist/core/hooks/guard-path.d.ts +2 -2
- package/dist/core/hooks/guard-path.js +2 -2
- package/dist/core/hooks/index.d.ts +1 -1
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/resolve/anchor.d.ts +14 -5
- package/dist/core/hooks/resolve/anchor.d.ts.map +1 -1
- package/dist/core/hooks/resolve/anchor.js +64 -7
- package/dist/core/hooks/resolve/coord-root.d.ts +16 -11
- package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
- package/dist/core/hooks/resolve/coord-root.js +18 -43
- package/dist/core/hooks/resolve/intent.js +1 -1
- package/dist/core/hooks/resolve/owner.d.ts +1 -1
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +11 -5
- package/dist/core/{scratch → journal}/index.d.ts +25 -25
- package/dist/core/{scratch → journal}/index.d.ts.map +1 -1
- package/dist/core/{scratch → journal}/index.js +38 -38
- package/dist/core/policy/evaluate.d.ts +1 -1
- package/dist/core/policy/evaluate.d.ts.map +1 -1
- package/dist/core/policy/evaluate.js +7 -7
- package/dist/core/policy/types.d.ts +3 -3
- package/dist/core/policy/types.d.ts.map +1 -1
- package/dist/core/work/state.d.ts +12 -4
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +50 -17
- package/dist/core/workflow/adapters.d.ts +17 -0
- package/dist/core/workflow/adapters.d.ts.map +1 -0
- package/dist/core/workflow/adapters.js +21 -0
- package/dist/core/workflow/approvals.js +6 -6
- package/dist/core/workflow/billing.d.ts +9 -9
- package/dist/core/workflow/billing.js +9 -9
- package/dist/core/workflow/child-env.d.ts +10 -2
- package/dist/core/workflow/child-env.d.ts.map +1 -1
- package/dist/core/workflow/child-env.js +12 -4
- package/dist/core/workflow/engine.d.ts +15 -5
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +138 -83
- package/dist/core/workflow/evidence-preflight.d.ts +24 -0
- package/dist/core/workflow/evidence-preflight.d.ts.map +1 -0
- package/dist/core/workflow/evidence-preflight.js +134 -0
- package/dist/core/workflow/index.d.ts +1 -1
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/proof.d.ts +11 -5
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +45 -36
- package/dist/core/workflow/run-state.d.ts +1 -1
- package/dist/core/workflow/run-state.js +7 -7
- package/dist/core/workflow/sandbox-projection.d.ts +6 -6
- package/dist/core/workflow/sandbox-projection.d.ts.map +1 -1
- package/dist/core/workflow/sandbox-projection.js +11 -11
- package/dist/core/workflow/spawn-claude.d.ts +3 -3
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +9 -6
- package/dist/core/workflow/spawn-codex.d.ts +4 -4
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +9 -6
- package/dist/core/workflow/spawn-cursor.d.ts +4 -4
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +9 -6
- package/dist/core/workflow/spawn-failure.d.ts +1 -1
- package/dist/core/workflow/spawn-failure.js +1 -1
- package/dist/core/workflow/specialists.js +2 -2
- package/dist/core/workflow/{journal.d.ts → transcript.d.ts} +8 -8
- package/dist/core/workflow/transcript.d.ts.map +1 -0
- package/dist/core/workflow/{journal.js → transcript.js} +14 -14
- package/dist/core/workflow/types.d.ts +98 -51
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/types.js +11 -1
- package/dist/core/workflow/validate.d.ts +1 -1
- package/dist/core/workflow/validate.js +1 -1
- package/dist/core/workflow/workspaces/cancellation.js +2 -2
- package/dist/core/workflow/workspaces/cleanup.js +2 -2
- package/dist/core/workflow/workspaces/execution.js +6 -6
- package/dist/core/workflow/workspaces/inspect.js +9 -9
- package/dist/core/workflow/workspaces/integration.js +14 -14
- package/dist/core/workflow/workspaces/lifecycle.d.ts +1 -1
- package/dist/core/workflow/workspaces/lifecycle.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/lifecycle.js +9 -9
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/local-git.js +39 -5
- package/dist/core/workflow/workspaces/recovery.js +3 -3
- package/dist/core/workflow/workspaces/state.d.ts +1 -1
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/state.js +3 -3
- package/dist/core/workflow/workspaces/types.d.ts +1 -1
- package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
- package/dist/lib/browser/asserts.d.ts +28 -0
- package/dist/lib/browser/asserts.d.ts.map +1 -0
- package/dist/lib/browser/asserts.js +152 -0
- package/dist/lib/browser/client.d.ts +49 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +155 -14
- package/dist/lib/browser/content-checks.d.ts +108 -0
- package/dist/lib/browser/content-checks.d.ts.map +1 -0
- package/dist/lib/browser/content-checks.js +474 -0
- package/dist/lib/browser/critique.d.ts +91 -0
- package/dist/lib/browser/critique.d.ts.map +1 -0
- package/dist/lib/browser/critique.js +167 -0
- package/dist/lib/browser/geometry.d.ts +32 -0
- package/dist/lib/browser/geometry.d.ts.map +1 -1
- package/dist/lib/browser/geometry.js +244 -1
- package/dist/lib/browser/index.d.ts +4 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -0
- package/dist/lib/claude-desktop.d.ts.map +1 -1
- package/dist/lib/claude-desktop.js +4 -1
- package/dist/lib/context/index.js +9 -2
- package/dist/lib/council/index.d.ts +6 -6
- package/dist/lib/council/index.d.ts.map +1 -1
- package/dist/lib/council/index.js +8 -8
- package/dist/lib/identities/assume.d.ts +2 -2
- package/dist/lib/identities/assume.js +7 -7
- package/dist/lib/instructions/apply.d.ts +3 -3
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +75 -27
- package/dist/lib/instructions/host-addendum.d.ts +54 -0
- package/dist/lib/instructions/host-addendum.d.ts.map +1 -0
- package/dist/lib/instructions/host-addendum.js +107 -0
- package/dist/lib/instructions/templates.d.ts +10 -3
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +41 -12
- package/dist/lib/machine.d.ts +2 -2
- package/dist/lib/machine.js +2 -2
- package/package.json +26 -21
- package/schemas/config.schema.json +26 -1
- package/src/commander.ts +22 -13
- package/src/commands/{harness.ts → adapter.ts} +46 -46
- package/src/commands/agents.ts +200 -78
- package/src/commands/artifacts.ts +168 -0
- package/src/commands/backup.ts +47 -33
- package/src/commands/browse.ts +438 -2
- package/src/commands/checkpoint.ts +196 -0
- package/src/commands/context.ts +3 -176
- package/src/commands/decision.ts +41 -7
- package/src/commands/deinit.ts +16 -16
- package/src/commands/doctor.ts +28 -28
- package/src/commands/{supervisor.ts → governor.ts} +184 -154
- package/src/commands/grep.ts +19 -2
- package/src/commands/init.ts +50 -34
- package/src/commands/{scratch.ts → journal.ts} +60 -60
- package/src/commands/policy.ts +1 -1
- package/src/commands/presence.ts +2 -2
- package/src/commands/sync.ts +3 -3
- package/src/commands/tunnel.ts +256 -38
- package/src/commands/web-fetch.ts +1 -1
- package/src/commands/web.ts +56 -1
- package/src/commands/work.ts +50 -35
- package/src/commands/workflow.ts +43 -34
- package/src/core/{harnesses → adapters}/attest-projection.ts +2 -2
- package/src/core/{harnesses → adapters}/attest.ts +27 -27
- package/src/core/{harnesses → adapters}/attestation.ts +41 -41
- package/src/core/{harnesses → adapters}/bench.ts +34 -43
- package/src/core/adapters/index.ts +56 -0
- package/src/core/{harnesses → adapters}/profiles.ts +16 -16
- package/src/core/{harnesses → adapters}/registry.ts +23 -23
- package/src/core/{harnesses → adapters}/types.ts +23 -23
- package/src/core/agents/canonical-emit.ts +16 -43
- package/src/core/agents/cli-emit.ts +1 -1
- package/src/core/agents/cli.ts +30 -28
- package/src/core/agents/codex-replay.ts +6 -6
- package/src/core/agents/coord-bin.ts +92 -0
- package/src/core/agents/coord-client.ts +302 -78
- package/src/core/agents/events/consume.ts +1 -1
- package/src/core/agents/events/emit.ts +7 -6
- package/src/core/agents/paths.ts +7 -11
- package/src/core/agents/render/prompt-context.ts +107 -31
- package/src/core/agents/render/session-context.ts +6 -6
- package/src/core/agents/rules/claim-conflict.ts +4 -7
- package/src/core/agents/rules/commit-conflict.ts +103 -22
- package/src/core/agents/rules/stop-hook.ts +33 -17
- package/src/core/agents/rules/verdict.ts +13 -0
- package/src/core/agents/session-events.ts +4 -4
- package/src/core/agents/state/council.ts +1 -1
- package/src/core/agents/state/heartbeat-projector.ts +16 -12
- package/src/core/agents/state/heartbeat-writer.ts +12 -12
- package/src/core/agents/state/{scratch.ts → journal.ts} +12 -12
- package/src/core/agents/state/pidmap.ts +130 -15
- package/src/core/agents/state/proc-start.ts +208 -0
- package/src/core/agents/state/shell-mutation.ts +1 -1
- package/src/core/agents/state/stale-sweep.ts +7 -7
- package/src/core/artifacts/index.ts +557 -0
- package/src/core/config.ts +30 -2
- package/src/core/context/index.ts +15 -15
- package/src/core/governor/adapter-spread.ts +82 -0
- package/src/core/governor/index.ts +91 -0
- package/src/core/governor/plan-api.ts +115 -0
- package/src/core/{supervisor → governor}/plan-read.ts +112 -97
- package/src/core/{supervisor → governor}/plan-types.ts +59 -56
- package/src/core/{supervisor → governor}/planning.ts +223 -192
- package/src/core/governor/read.ts +59 -0
- package/src/core/{supervisor → governor}/runner.ts +39 -39
- package/src/core/{supervisor → governor}/service-read.ts +22 -22
- package/src/core/{supervisor → governor}/service.ts +117 -119
- package/src/core/{supervisor → governor}/state.ts +325 -167
- package/src/core/hooks/adapter/detect.ts +30 -0
- package/src/core/hooks/{harness → adapter}/events.ts +16 -14
- package/src/core/hooks/{harness → adapter}/output.ts +31 -23
- package/src/core/hooks/{harness → adapter}/parse.ts +5 -5
- package/src/core/hooks/{harness → adapter}/wiring.ts +21 -21
- package/src/core/hooks/cli.ts +197 -173
- package/src/core/hooks/effects/image-capture.ts +6 -6
- package/src/core/hooks/effects/index.ts +19 -19
- package/src/core/hooks/events/emit.ts +3 -3
- package/src/core/hooks/events/rotate.ts +1 -1
- package/src/core/hooks/events/schema.ts +15 -7
- package/src/core/hooks/guard-path.ts +2 -2
- package/src/core/hooks/index.ts +1 -1
- package/src/core/hooks/resolve/anchor.ts +63 -8
- package/src/core/hooks/resolve/coord-root.ts +18 -40
- package/src/core/hooks/resolve/intent.ts +1 -1
- package/src/core/hooks/resolve/owner.ts +11 -5
- package/src/core/{scratch → journal}/index.ts +53 -53
- package/src/core/policy/evaluate.ts +8 -8
- package/src/core/policy/types.ts +3 -3
- package/src/core/work/state.ts +65 -23
- package/src/core/workflow/adapters.ts +33 -0
- package/src/core/workflow/approvals.ts +7 -7
- package/src/core/workflow/billing.ts +12 -12
- package/src/core/workflow/child-env.ts +13 -4
- package/src/core/workflow/engine.ts +155 -90
- package/src/core/workflow/evidence-preflight.ts +165 -0
- package/src/core/workflow/index.ts +3 -3
- package/src/core/workflow/proof.ts +60 -50
- package/src/core/workflow/run-state.ts +7 -7
- package/src/core/workflow/sandbox-projection.ts +16 -16
- package/src/core/workflow/spawn-claude.ts +13 -10
- package/src/core/workflow/spawn-codex.ts +13 -10
- package/src/core/workflow/spawn-cursor.ts +13 -10
- package/src/core/workflow/spawn-failure.ts +1 -1
- package/src/core/workflow/specialists.ts +2 -2
- package/src/core/workflow/{journal.ts → transcript.ts} +16 -16
- package/src/core/workflow/types.ts +108 -51
- package/src/core/workflow/validate.ts +1 -1
- package/src/core/workflow/workspaces/cancellation.ts +2 -2
- package/src/core/workflow/workspaces/cleanup.ts +2 -2
- package/src/core/workflow/workspaces/execution.ts +6 -6
- package/src/core/workflow/workspaces/inspect.ts +14 -11
- package/src/core/workflow/workspaces/integration.ts +18 -14
- package/src/core/workflow/workspaces/lifecycle.ts +10 -10
- package/src/core/workflow/workspaces/local-git.ts +47 -5
- package/src/core/workflow/workspaces/recovery.ts +3 -3
- package/src/core/workflow/workspaces/state.ts +4 -3
- package/src/core/workflow/workspaces/types.ts +1 -1
- package/src/lib/browser/asserts.ts +177 -0
- package/src/lib/browser/client.ts +189 -14
- package/src/lib/browser/content-checks.ts +571 -0
- package/src/lib/browser/critique.ts +231 -0
- package/src/lib/browser/geometry.ts +297 -1
- package/src/lib/browser/index.ts +34 -0
- package/src/lib/claude-desktop.ts +4 -1
- package/src/lib/context/index.ts +11 -1
- package/src/lib/council/index.ts +9 -9
- package/src/lib/identities/assume.ts +7 -7
- package/src/lib/instructions/apply.ts +87 -25
- package/src/lib/instructions/host-addendum.ts +126 -0
- package/src/lib/instructions/templates.ts +44 -15
- package/src/lib/machine.ts +2 -2
- package/dist/commands/harness.d.ts +0 -12
- package/dist/commands/harness.d.ts.map +0 -1
- package/dist/commands/scratch.d.ts +0 -4
- package/dist/commands/scratch.d.ts.map +0 -1
- package/dist/commands/session.d.ts.map +0 -1
- package/dist/commands/session.js +0 -162
- package/dist/commands/supervisor.d.ts +0 -4
- package/dist/commands/supervisor.d.ts.map +0 -1
- package/dist/core/harnesses/attest-projection.d.ts.map +0 -1
- package/dist/core/harnesses/attest.d.ts.map +0 -1
- package/dist/core/harnesses/attestation.d.ts.map +0 -1
- package/dist/core/harnesses/bench.d.ts.map +0 -1
- package/dist/core/harnesses/index.d.ts +0 -13
- package/dist/core/harnesses/index.d.ts.map +0 -1
- package/dist/core/harnesses/index.js +0 -6
- package/dist/core/harnesses/profiles.d.ts.map +0 -1
- package/dist/core/harnesses/registry.d.ts +0 -15
- package/dist/core/harnesses/registry.d.ts.map +0 -1
- package/dist/core/harnesses/types.d.ts.map +0 -1
- package/dist/core/hooks/harness/detect.d.ts +0 -9
- package/dist/core/hooks/harness/events.d.ts.map +0 -1
- package/dist/core/hooks/harness/output.d.ts.map +0 -1
- package/dist/core/supervisor/index.d.ts +0 -7
- package/dist/core/supervisor/index.d.ts.map +0 -1
- package/dist/core/supervisor/index.js +0 -6
- package/dist/core/supervisor/plan-api.d.ts +0 -23
- package/dist/core/supervisor/plan-api.d.ts.map +0 -1
- package/dist/core/supervisor/plan-api.js +0 -50
- package/dist/core/supervisor/plan-read.d.ts +0 -5
- package/dist/core/supervisor/plan-read.d.ts.map +0 -1
- package/dist/core/supervisor/plan-types.d.ts.map +0 -1
- package/dist/core/supervisor/planning.d.ts +0 -33
- package/dist/core/supervisor/planning.d.ts.map +0 -1
- package/dist/core/supervisor/read.d.ts +0 -6
- package/dist/core/supervisor/read.d.ts.map +0 -1
- package/dist/core/supervisor/read.js +0 -4
- package/dist/core/supervisor/runner.d.ts +0 -37
- package/dist/core/supervisor/runner.d.ts.map +0 -1
- package/dist/core/supervisor/service-read.d.ts +0 -6
- package/dist/core/supervisor/service-read.d.ts.map +0 -1
- package/dist/core/supervisor/service.d.ts +0 -114
- package/dist/core/supervisor/service.d.ts.map +0 -1
- package/dist/core/supervisor/state.d.ts +0 -95
- package/dist/core/supervisor/state.d.ts.map +0 -1
- package/dist/core/workflow/harnesses.d.ts +0 -17
- package/dist/core/workflow/harnesses.d.ts.map +0 -1
- package/dist/core/workflow/harnesses.js +0 -21
- package/dist/core/workflow/journal.d.ts.map +0 -1
- package/src/commands/session.ts +0 -187
- package/src/core/harnesses/index.ts +0 -56
- package/src/core/hooks/harness/detect.ts +0 -30
- package/src/core/supervisor/index.ts +0 -89
- package/src/core/supervisor/plan-api.ts +0 -73
- package/src/core/supervisor/read.ts +0 -59
- package/src/core/workflow/harnesses.ts +0 -33
- /package/dist/core/{harnesses → adapters}/attest-projection.js +0 -0
package/dist/core/hooks/cli.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* alongside the legacy stream.
|
|
4
4
|
*
|
|
5
5
|
* Flow:
|
|
6
|
-
* 1. Parse argv → event-name +
|
|
7
|
-
* 2. Read stdin →
|
|
6
|
+
* 1. Parse argv → event-name + adapter.
|
|
7
|
+
* 2. Read stdin → adapter payload (JSON or empty).
|
|
8
8
|
* 3. Find coord root (walk up for .harnery/).
|
|
9
9
|
* 4. Resolve instance_id (env → payload → pid-map walk).
|
|
10
10
|
* 5. Map event-name → canonical event_type.
|
|
@@ -15,25 +15,27 @@
|
|
|
15
15
|
* Phase 2 ship criterion: confirms parser correctness across thousands of
|
|
16
16
|
* real events without affecting behavior. Always exits 0. Failures land in
|
|
17
17
|
* `.harnery/debug/agent-hook.errors.ndjson` for audit but never break the
|
|
18
|
-
*
|
|
18
|
+
* adapter flow.
|
|
19
19
|
*/
|
|
20
20
|
import { spawnSync } from "node:child_process";
|
|
21
21
|
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
22
22
|
import { dirname, join } from "node:path";
|
|
23
23
|
import { coordEnv } from "../../lib/env.js";
|
|
24
24
|
import { replayCodexJsonl } from "../agents/codex-replay.js";
|
|
25
|
+
import { coordBinPath } from "../agents/coord-bin.js";
|
|
25
26
|
import { consumeSince, writeCursor } from "../agents/events/consume.js";
|
|
26
27
|
import { evaluateStopHook } from "../agents/rules/stop-hook.js";
|
|
27
28
|
import { projectHeartbeats } from "../agents/state/heartbeat-projector.js";
|
|
29
|
+
import { writePidmapRow } from "../agents/state/pidmap.js";
|
|
28
30
|
import { shellMutationPaths } from "../agents/state/shell-mutation.js";
|
|
29
31
|
import { checkpointContext, completeContextRecovery, extractContextSample, markContextCompactionCompleted, prepareContextRecovery, readContextState, recordContextSample, } from "../context/index.js";
|
|
30
32
|
import { ensureRelayDaemon, fetchPresence, publishPresence } from "../presence/index.js";
|
|
31
|
-
import {
|
|
33
|
+
import { detectAdapter } from "./adapter/detect.js";
|
|
34
|
+
import { extractBashCommand, extractToolDescription, normalizeEventName, parsePayload, } from "./adapter/parse.js";
|
|
35
|
+
import { captureImages, detectPresence, imageJanitor, journalArchive, journalJanitor, journalRecoveryCue, playSound, resetSoundCounters, runSessionSyncExtension, runTurnSummary, soundForEvent, } from "./effects/index.js";
|
|
32
36
|
import { emit } from "./events/emit.js";
|
|
33
37
|
import { canonicalize } from "./guard-path.js";
|
|
34
|
-
import {
|
|
35
|
-
import { extractBashCommand, extractToolDescription, normalizeEventName, parsePayload, } from "./harness/parse.js";
|
|
36
|
-
import { parsePsChainLine, selectAnchorPid } from "./resolve/anchor.js";
|
|
38
|
+
import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.js";
|
|
37
39
|
import { findCoordRoot } from "./resolve/coord-root.js";
|
|
38
40
|
import { extractIntentComment, resolveIntent } from "./resolve/intent.js";
|
|
39
41
|
import { resolveOwner } from "./resolve/owner.js";
|
|
@@ -42,11 +44,11 @@ function parseArgv(argv) {
|
|
|
42
44
|
const out = { eventName: null, extra: [] };
|
|
43
45
|
for (let i = 0; i < argv.length; i++) {
|
|
44
46
|
const arg = argv[i];
|
|
45
|
-
if (arg === "--
|
|
46
|
-
i++; //
|
|
47
|
+
if (arg === "--adapter") {
|
|
48
|
+
i++; // detectAdapter will re-parse; just consume the value here.
|
|
47
49
|
continue;
|
|
48
50
|
}
|
|
49
|
-
if (arg.startsWith("--
|
|
51
|
+
if (arg.startsWith("--adapter="))
|
|
50
52
|
continue;
|
|
51
53
|
if (!out.eventName && !arg.startsWith("--")) {
|
|
52
54
|
out.eventName = arg;
|
|
@@ -74,7 +76,7 @@ async function readStdin() {
|
|
|
74
76
|
/**
|
|
75
77
|
* Env for child agent-coord spawns, with the coord root pinned. The hook
|
|
76
78
|
* process may be running with the session shell's cwd (inside a submodule or
|
|
77
|
-
*
|
|
79
|
+
* journal dir), and agent-coord resolves its root from cwd unless overridden —
|
|
78
80
|
* without the pin a child could write state to a different .harnery than the
|
|
79
81
|
* one this hook resolved.
|
|
80
82
|
*/
|
|
@@ -111,13 +113,13 @@ function logError(coordRoot, err, context) {
|
|
|
111
113
|
/**
|
|
112
114
|
* Spawn `agent-coord assign-name <owner> <kind>` to mint or recover the
|
|
113
115
|
* hurricane-style name for this owner. Returns null on any failure so
|
|
114
|
-
* session.start emission never breaks the
|
|
116
|
+
* session.start emission never breaks the adapter flow.
|
|
115
117
|
*
|
|
116
118
|
* Lives at agent-hooks side (not agent-coord) to keep emitter/consumer
|
|
117
119
|
* separation: we spawn rather than import.
|
|
118
120
|
*/
|
|
119
121
|
function assignNameViaAgentCoord(coordRoot, instanceId, kind) {
|
|
120
|
-
const binary =
|
|
122
|
+
const binary = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
121
123
|
if (!existsSync(binary))
|
|
122
124
|
return null;
|
|
123
125
|
try {
|
|
@@ -139,35 +141,22 @@ function assignNameViaAgentCoord(coordRoot, instanceId, kind) {
|
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
143
|
/**
|
|
142
|
-
* Direct (in-process) pidmap write,
|
|
143
|
-
* the agent-coord CLI for every session.start / subagent.start. Pid-map
|
|
144
|
-
*
|
|
144
|
+
* Direct (in-process) pidmap write, avoiding the spawn overhead of going via
|
|
145
|
+
* the agent-coord CLI for every session.start / subagent.start. Pid-map rows
|
|
146
|
+
* are essential for `harn agents whoami` ppid resolution.
|
|
147
|
+
*
|
|
148
|
+
* This used to inline its own copy of the write to keep this module's
|
|
149
|
+
* dependencies narrow, which quietly mattered: the shared writer is where row
|
|
150
|
+
* hygiene lives, so the duplicate meant the only hot write path in the system
|
|
151
|
+
* never swept dead rows, and the map grew unbounded. It calls the shared writer
|
|
152
|
+
* now, and this module already imports from that directory anyway.
|
|
145
153
|
*/
|
|
146
154
|
function writePidmapViaAgentCoord(coordRoot, pid, instanceId, platform) {
|
|
147
155
|
try {
|
|
148
|
-
|
|
149
|
-
// agent-coord/src/state/pidmap.ts but skips importing across module
|
|
150
|
-
// boundaries to keep agent-hooks's deps explicit.
|
|
151
|
-
const dir = join(coordRoot, ".harnery", "pid-map");
|
|
152
|
-
const path = join(dir, String(pid));
|
|
153
|
-
const row = `${instanceId}\t${platform}`;
|
|
154
|
-
if (existsSync(path)) {
|
|
155
|
-
try {
|
|
156
|
-
const current = require("node:fs").readFileSync(path, "utf8");
|
|
157
|
-
if (current === row)
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
/* fall through */
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
mkdirSync(dir, { recursive: true });
|
|
165
|
-
const tmp = `${path}.tmp.${process.pid}`;
|
|
166
|
-
require("node:fs").writeFileSync(tmp, row, "utf8");
|
|
167
|
-
require("node:fs").renameSync(tmp, path);
|
|
156
|
+
writePidmapRow(coordRoot, pid, instanceId, platform);
|
|
168
157
|
}
|
|
169
158
|
catch {
|
|
170
|
-
/* never break the
|
|
159
|
+
/* never break the adapter flow */
|
|
171
160
|
}
|
|
172
161
|
}
|
|
173
162
|
function clampString(s, max) {
|
|
@@ -188,23 +177,23 @@ function buildEventData(eventType, ctx) {
|
|
|
188
177
|
const p = ctx.payload;
|
|
189
178
|
switch (eventType) {
|
|
190
179
|
case "session.start": {
|
|
191
|
-
const
|
|
180
|
+
const adapterPlatform = ctx.adapter === "claude-code"
|
|
192
181
|
? "claude_code"
|
|
193
|
-
: ctx.
|
|
182
|
+
: ctx.adapter === "cursor"
|
|
194
183
|
? "cursor"
|
|
195
184
|
: "codex";
|
|
196
185
|
// Assign (or recover) name + kind via agent-coord. Idempotent: resume
|
|
197
186
|
// returns the original name; new owner consumes a counter slot.
|
|
198
187
|
const assigned = assignNameViaAgentCoord(ctx.coordRoot, ctx.instanceId, "session");
|
|
199
|
-
// Write the
|
|
188
|
+
// Write the adapter pid-map row so `harn agents whoami` ppid-walks find
|
|
200
189
|
// this owner. Prefer the payload pid (the actual claude binary), then the
|
|
201
190
|
// anchor walk (the `node` ancestor for Cursor, which has no payload pid),
|
|
202
191
|
// then our own process.ppid. Without the anchor, Cursor anchored on the
|
|
203
192
|
// ephemeral hook bash parent, a PID that dies before the agent's next
|
|
204
193
|
// shell tool call, so the ppid walk found nothing (no_pidmap_entry).
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
207
|
-
writePidmapViaAgentCoord(ctx.coordRoot,
|
|
194
|
+
const adapterPid = p?.pid ?? findAdapterAnchorPid(ctx.adapter) ?? process.ppid;
|
|
195
|
+
if (adapterPid) {
|
|
196
|
+
writePidmapViaAgentCoord(ctx.coordRoot, adapterPid, ctx.instanceId, adapterPlatform);
|
|
208
197
|
}
|
|
209
198
|
return {
|
|
210
199
|
started_at: new Date().toISOString(),
|
|
@@ -213,17 +202,25 @@ function buildEventData(eventType, ctx) {
|
|
|
213
202
|
// supply it). Fall back to the transcript, populated on `resume`, and
|
|
214
203
|
// backfilled later by `turn.stop` for a fresh `startup` session.
|
|
215
204
|
model: p?.model ?? scanTranscriptModel(p?.transcript_path),
|
|
216
|
-
pid:
|
|
205
|
+
pid: adapterPid,
|
|
217
206
|
source: p?.source,
|
|
218
|
-
platform:
|
|
207
|
+
platform: adapterPlatform,
|
|
219
208
|
name: assigned?.name,
|
|
220
209
|
kind: "session",
|
|
221
210
|
agent_id: ctx.instanceId,
|
|
222
211
|
// Workflow-child linkage: `workflow run` children carry the run id in
|
|
223
212
|
// env (spawn adapters set it via buildChildEnv), so their sessions and
|
|
224
|
-
// heartbeats join back to the run
|
|
213
|
+
// heartbeats join back to the run transcript + /workflows web view.
|
|
225
214
|
...(coordEnv("WORKFLOW_CHILD") === "1" && coordEnv("WORKFLOW_RUN_ID")
|
|
226
|
-
? {
|
|
215
|
+
? {
|
|
216
|
+
workflow_run_id: coordEnv("WORKFLOW_RUN_ID"),
|
|
217
|
+
// Which agent row of that run this session is. The orchestrator
|
|
218
|
+
// stamps it on the way in, because the adapter does not report a
|
|
219
|
+
// session id until the agent has already finished.
|
|
220
|
+
...(coordEnv("WORKFLOW_AGENT_ID")
|
|
221
|
+
? { workflow_agent_id: coordEnv("WORKFLOW_AGENT_ID") }
|
|
222
|
+
: {}),
|
|
223
|
+
}
|
|
227
224
|
: {}),
|
|
228
225
|
};
|
|
229
226
|
}
|
|
@@ -239,7 +236,7 @@ function buildEventData(eventType, ctx) {
|
|
|
239
236
|
}
|
|
240
237
|
case "turn.stop": {
|
|
241
238
|
return {
|
|
242
|
-
// Backfill the model for
|
|
239
|
+
// Backfill the model for adapters that omit it at session.start
|
|
243
240
|
// (Claude Code). The transcript is populated with assistant turns by
|
|
244
241
|
// Stop-hook time, so this resolves even for fresh `startup` sessions.
|
|
245
242
|
model: p?.model ?? scanTranscriptModel(p?.transcript_path),
|
|
@@ -363,13 +360,13 @@ function numberField(value) {
|
|
|
363
360
|
}
|
|
364
361
|
async function main() {
|
|
365
362
|
const { eventName, extra } = parseArgv(process.argv.slice(2));
|
|
366
|
-
const
|
|
363
|
+
const adapter = detectAdapter(process.argv.slice(2));
|
|
367
364
|
const raw = await readStdin();
|
|
368
365
|
// Kill-switch-INDEPENDENT effects: notification sounds fire BEFORE the
|
|
369
366
|
// HARNERY_AGENT_COORD_OFF gate so audible feedback survives incident-triage
|
|
370
367
|
// bypass: sound playback happens before the kill-switch bailout.
|
|
371
368
|
// Claude-Code-only; stop-failure → error, sub-agent-start → subagent-start.
|
|
372
|
-
if (
|
|
369
|
+
if (adapter === "claude-code" && eventName) {
|
|
373
370
|
const s = soundForEvent(eventName);
|
|
374
371
|
if (s) {
|
|
375
372
|
const repoRoot = findCoordRoot(process.cwd());
|
|
@@ -401,15 +398,15 @@ async function main() {
|
|
|
401
398
|
const debugBase = {
|
|
402
399
|
ts: new Date().toISOString(),
|
|
403
400
|
event_name: eventName,
|
|
404
|
-
|
|
401
|
+
adapter,
|
|
405
402
|
extra_argv: extra,
|
|
406
403
|
payload_bytes: raw.length,
|
|
407
404
|
cwd: process.cwd(),
|
|
408
405
|
pid: process.pid,
|
|
409
406
|
ppid: process.ppid,
|
|
410
407
|
};
|
|
411
|
-
if (!eventName || !
|
|
412
|
-
appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-
|
|
408
|
+
if (!eventName || !adapter) {
|
|
409
|
+
appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-adapter" });
|
|
413
410
|
return 0;
|
|
414
411
|
}
|
|
415
412
|
const norm = normalizeEventName(eventName);
|
|
@@ -417,7 +414,7 @@ async function main() {
|
|
|
417
414
|
appendDebug(coordRoot, { ...debugBase, skipped: "non-canonical-event" });
|
|
418
415
|
return 0;
|
|
419
416
|
}
|
|
420
|
-
const payload = parsePayload(raw,
|
|
417
|
+
const payload = parsePayload(raw, adapter);
|
|
421
418
|
const owner = resolveOwner({ payload: payload?.raw ?? null, coordRoot });
|
|
422
419
|
if (!owner) {
|
|
423
420
|
appendDebug(coordRoot, {
|
|
@@ -432,7 +429,7 @@ async function main() {
|
|
|
432
429
|
coordRoot,
|
|
433
430
|
payload,
|
|
434
431
|
raw,
|
|
435
|
-
|
|
432
|
+
adapter,
|
|
436
433
|
instanceId: owner.instance_id,
|
|
437
434
|
});
|
|
438
435
|
const envelope = emit(coordRoot, {
|
|
@@ -442,7 +439,7 @@ async function main() {
|
|
|
442
439
|
parent_session_id: payload?.parent_session_id,
|
|
443
440
|
turn_id: payload?.turn_id,
|
|
444
441
|
parent_turn_id: payload?.parent_turn_id,
|
|
445
|
-
|
|
442
|
+
adapter,
|
|
446
443
|
data,
|
|
447
444
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
448
445
|
});
|
|
@@ -453,13 +450,13 @@ async function main() {
|
|
|
453
450
|
event_id: envelope.event_id,
|
|
454
451
|
});
|
|
455
452
|
// Context telemetry is opportunistic and truthful: only persist a sample
|
|
456
|
-
// when the
|
|
453
|
+
// when the adapter payload actually exposes usage/window data. Identical
|
|
457
454
|
// measurements are de-duplicated before they reach the canonical stream.
|
|
458
455
|
if (payload?.raw) {
|
|
459
456
|
try {
|
|
460
457
|
const sample = extractContextSample(payload.raw, {
|
|
461
458
|
sessionId,
|
|
462
|
-
|
|
459
|
+
adapter,
|
|
463
460
|
model: payload.model,
|
|
464
461
|
source: "hook",
|
|
465
462
|
confidence: "reported",
|
|
@@ -471,7 +468,7 @@ async function main() {
|
|
|
471
468
|
event_type: "context.sampled",
|
|
472
469
|
instance_id: owner.instance_id,
|
|
473
470
|
session_id: sessionId,
|
|
474
|
-
|
|
471
|
+
adapter,
|
|
475
472
|
data: {
|
|
476
473
|
model: sample.model,
|
|
477
474
|
used_tokens: sample.used_tokens,
|
|
@@ -490,13 +487,13 @@ async function main() {
|
|
|
490
487
|
}
|
|
491
488
|
// A native pre-compaction signal is the safest available point to capture
|
|
492
489
|
// external work state. The operation is idempotent until recovery, so a
|
|
493
|
-
//
|
|
490
|
+
// adapter retry cannot create a storm of near-identical capsules.
|
|
494
491
|
if (norm.event_type === "context.compaction.started") {
|
|
495
492
|
try {
|
|
496
493
|
const checkpoint = checkpointContext(coordRoot, {
|
|
497
494
|
sessionId,
|
|
498
495
|
instanceId: owner.instance_id,
|
|
499
|
-
|
|
496
|
+
adapter,
|
|
500
497
|
cwd: payload?.cwd ?? process.cwd(),
|
|
501
498
|
reason: "pre_compact",
|
|
502
499
|
model: payload?.model,
|
|
@@ -505,7 +502,7 @@ async function main() {
|
|
|
505
502
|
event_type: "context.checkpoint.created",
|
|
506
503
|
instance_id: owner.instance_id,
|
|
507
504
|
session_id: sessionId,
|
|
508
|
-
|
|
505
|
+
adapter,
|
|
509
506
|
data: {
|
|
510
507
|
capsule_id: checkpoint.capsule.capsule_id,
|
|
511
508
|
generation: checkpoint.capsule.generation,
|
|
@@ -531,18 +528,18 @@ async function main() {
|
|
|
531
528
|
}
|
|
532
529
|
}
|
|
533
530
|
// Phase 8: SessionStart post-emit: project the event so the heartbeat
|
|
534
|
-
// lands synchronously, run stale-sweep, and emit the
|
|
531
|
+
// lands synchronously, run stale-sweep, and emit the adapter-shaped
|
|
535
532
|
// systemMessage JSON (peer table + wiring check + council invites).
|
|
536
|
-
//
|
|
537
|
-
// and the equivalent per-
|
|
533
|
+
// Adapter-agnostic since v0.5.0; replaces the previous bash UX layer
|
|
534
|
+
// and the equivalent per-adapter bash session_start handlers.
|
|
538
535
|
if (norm.event_type === "session.start") {
|
|
539
|
-
// Effect (claude-code): prune stale
|
|
536
|
+
// Effect (claude-code): prune stale journal archives + sweep orphans.
|
|
540
537
|
// The recovery-cue is merged into the
|
|
541
538
|
// session-start additionalContext inside emitSessionStartSystemMessage.
|
|
542
|
-
if (
|
|
543
|
-
|
|
544
|
-
// Image-feed retention sweep (size + age cap on .harnery/images/).
|
|
545
|
-
// agnostic, cheap (one readdir), fail-soft. Paired with
|
|
539
|
+
if (adapter === "claude-code")
|
|
540
|
+
journalJanitor(coordRoot);
|
|
541
|
+
// Image-feed retention sweep (size + age cap on .harnery/images/). Adapter-
|
|
542
|
+
// agnostic, cheap (one readdir), fail-soft. Paired with journalJanitor as a
|
|
546
543
|
// session-start "tidy the coord layer" step.
|
|
547
544
|
try {
|
|
548
545
|
imageJanitor(coordRoot);
|
|
@@ -557,7 +554,7 @@ async function main() {
|
|
|
557
554
|
event_type: "context.compaction.completed",
|
|
558
555
|
instance_id: owner.instance_id,
|
|
559
556
|
session_id: sessionId,
|
|
560
|
-
|
|
557
|
+
adapter,
|
|
561
558
|
data: { trigger: "auto" },
|
|
562
559
|
});
|
|
563
560
|
markContextCompactionCompleted(coordRoot, {
|
|
@@ -575,9 +572,9 @@ async function main() {
|
|
|
575
572
|
}
|
|
576
573
|
}
|
|
577
574
|
try {
|
|
578
|
-
const injected = await emitSessionStartSystemMessage(coordRoot, owner.instance_id, sessionId, data,
|
|
575
|
+
const injected = await emitSessionStartSystemMessage(coordRoot, owner.instance_id, sessionId, data, adapter, recovery?.briefing ?? "");
|
|
579
576
|
if (injected && recovery) {
|
|
580
|
-
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId,
|
|
577
|
+
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, adapter, recovery, "SessionStart");
|
|
581
578
|
}
|
|
582
579
|
}
|
|
583
580
|
catch (err) {
|
|
@@ -595,7 +592,7 @@ async function main() {
|
|
|
595
592
|
logError(coordRoot, err, { phase: "session-start-presence" });
|
|
596
593
|
}
|
|
597
594
|
}
|
|
598
|
-
// Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows.
|
|
595
|
+
// Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Adapter-
|
|
599
596
|
// agnostic since v0.5.0.
|
|
600
597
|
if (norm.event_type === "session.end") {
|
|
601
598
|
try {
|
|
@@ -604,10 +601,10 @@ async function main() {
|
|
|
604
601
|
catch (err) {
|
|
605
602
|
logError(coordRoot, err, { phase: "session-end-cleanup" });
|
|
606
603
|
}
|
|
607
|
-
// Effects (claude-code): archive the ending agent's
|
|
604
|
+
// Effects (claude-code): archive the ending agent's journal + force a
|
|
608
605
|
// session-telemetry sync (via HARNERY_CLAUDE_SESSIONS_FORCE=1).
|
|
609
|
-
if (
|
|
610
|
-
|
|
606
|
+
if (adapter === "claude-code") {
|
|
607
|
+
journalArchive(coordRoot, owner.instance_id);
|
|
611
608
|
runSessionSyncExtension(coordRoot, true);
|
|
612
609
|
}
|
|
613
610
|
// Presence: publish the post-cleanup state so peers see this session gone
|
|
@@ -624,7 +621,7 @@ async function main() {
|
|
|
624
621
|
// subagent (claude-code + cursor; codex doesn't fan out subagents today).
|
|
625
622
|
if (norm.event_type === "subagent.start") {
|
|
626
623
|
try {
|
|
627
|
-
const agentCoordBin =
|
|
624
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
628
625
|
if (existsSync(agentCoordBin)) {
|
|
629
626
|
spawnSync(agentCoordBin, ["project"], {
|
|
630
627
|
encoding: "utf8",
|
|
@@ -633,12 +630,12 @@ async function main() {
|
|
|
633
630
|
});
|
|
634
631
|
spawnSync(agentCoordBin, [
|
|
635
632
|
"log",
|
|
636
|
-
`SUBAGENT_START agent_type=${data.agent_type ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${
|
|
633
|
+
`SUBAGENT_START agent_type=${data.agent_type ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
|
|
637
634
|
"--instance",
|
|
638
635
|
owner.instance_id,
|
|
639
636
|
], { encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) });
|
|
640
637
|
}
|
|
641
|
-
emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data,
|
|
638
|
+
emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data, adapter);
|
|
642
639
|
}
|
|
643
640
|
catch (err) {
|
|
644
641
|
logError(coordRoot, err, { phase: "subagent-start-project" });
|
|
@@ -648,11 +645,11 @@ async function main() {
|
|
|
648
645
|
if (norm.event_type === "subagent.stop") {
|
|
649
646
|
try {
|
|
650
647
|
cleanupSessionEnd(coordRoot, owner.instance_id, data.reason ?? "unknown");
|
|
651
|
-
const agentCoordBin =
|
|
648
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
652
649
|
if (existsSync(agentCoordBin)) {
|
|
653
650
|
spawnSync(agentCoordBin, [
|
|
654
651
|
"log",
|
|
655
|
-
`SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${
|
|
652
|
+
`SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
|
|
656
653
|
"--instance",
|
|
657
654
|
owner.instance_id,
|
|
658
655
|
], { encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) });
|
|
@@ -663,11 +660,11 @@ async function main() {
|
|
|
663
660
|
}
|
|
664
661
|
}
|
|
665
662
|
// Phase 8: UserPromptSubmit: render dedup'd peer table + council pending
|
|
666
|
-
// and emit the
|
|
663
|
+
// and emit the adapter-shaped systemMessage JSON. Adapter-agnostic since v0.5.0.
|
|
667
664
|
if (norm.event_type === "user_prompt.submit") {
|
|
668
665
|
// Effects (claude-code): reset per-turn sound rate-limit counters + run
|
|
669
666
|
// presence detection on the prompt.
|
|
670
|
-
if (
|
|
667
|
+
if (adapter === "claude-code") {
|
|
671
668
|
resetSoundCounters(sessionId);
|
|
672
669
|
const prompt = payload?.raw?.prompt ?? "";
|
|
673
670
|
if (prompt)
|
|
@@ -697,9 +694,9 @@ async function main() {
|
|
|
697
694
|
}
|
|
698
695
|
}
|
|
699
696
|
try {
|
|
700
|
-
const injected = await emitUserPromptSubmitSystemMessage(coordRoot, owner.instance_id, sessionId,
|
|
697
|
+
const injected = await emitUserPromptSubmitSystemMessage(coordRoot, owner.instance_id, sessionId, adapter, recovery?.briefing ?? "");
|
|
701
698
|
if (injected && recovery) {
|
|
702
|
-
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId,
|
|
699
|
+
completeRecoveryInjection(coordRoot, owner.instance_id, sessionId, adapter, recovery, "UserPromptSubmit");
|
|
703
700
|
}
|
|
704
701
|
}
|
|
705
702
|
catch (err) {
|
|
@@ -707,7 +704,7 @@ async function main() {
|
|
|
707
704
|
}
|
|
708
705
|
}
|
|
709
706
|
// turn.stop: telemetry + turn-summary effects, then the stop verdict. The
|
|
710
|
-
// verdict + codex-replay previously lived in the per-
|
|
707
|
+
// verdict + codex-replay previously lived in the per-adapter shell adapters;
|
|
711
708
|
// agent-hook owns them now. Runs on the normal "stop" event only;
|
|
712
709
|
// "stop-failure" (API error) gets no gate, matching the previous
|
|
713
710
|
// stop vs stop-failure split.
|
|
@@ -716,7 +713,7 @@ async function main() {
|
|
|
716
713
|
// the status_checked / task_set / status_box_present evidence (codex
|
|
717
714
|
// doesn't emit those live; this re-emits turn.stop after agent-hook's own,
|
|
718
715
|
// so the verdict reads the replay's box signal as the latest).
|
|
719
|
-
if (
|
|
716
|
+
if (adapter === "codex" && payload?.transcript_path && existsSync(payload.transcript_path)) {
|
|
720
717
|
try {
|
|
721
718
|
replayCodexJsonl({
|
|
722
719
|
coordRoot,
|
|
@@ -732,14 +729,14 @@ async function main() {
|
|
|
732
729
|
}
|
|
733
730
|
// CC effects: rate-limited session-telemetry sync + turn-summary Haiku
|
|
734
731
|
// auto-summary.
|
|
735
|
-
if (
|
|
732
|
+
if (adapter === "claude-code") {
|
|
736
733
|
runSessionSyncExtension(coordRoot, false);
|
|
737
734
|
runTurnSummary(coordRoot, owner.instance_id, sessionId, payload?.transcript_path);
|
|
738
735
|
}
|
|
739
736
|
// Master-state heartbeat projection. Drains events.ndjson since the last
|
|
740
737
|
// cursor → per-owner heartbeats. Was a SECOND binary (`agent-coord project`)
|
|
741
738
|
// pinned to Claude Code Stop only; folded in here so it (a) is one
|
|
742
|
-
// entry per event like everything else and (b) fires on EVERY
|
|
739
|
+
// entry per event like everything else and (b) fires on EVERY adapter's stop,
|
|
743
740
|
// not just CC. Runs unconditionally before the verdict's possible exit-2 return
|
|
744
741
|
// (the events are real regardless of whether the agent gets nagged), and after
|
|
745
742
|
// codex-replay above so codex's replayed events are included in the drain.
|
|
@@ -771,21 +768,21 @@ async function main() {
|
|
|
771
768
|
rule: "stop-hook",
|
|
772
769
|
instance_id: owner.instance_id,
|
|
773
770
|
session_id: sessionId,
|
|
774
|
-
|
|
771
|
+
adapter,
|
|
775
772
|
bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
|
|
776
773
|
workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
|
|
777
774
|
});
|
|
778
775
|
if (!verdict.allow) {
|
|
779
|
-
//
|
|
776
|
+
// Adapter-aware enforcement channel: Claude Code / Codex honor exit-2 +
|
|
780
777
|
// stderr as a turn block; Cursor ignores exit codes (fail-open) and
|
|
781
778
|
// re-prompts only via a `followup_message` it auto-submits. emitStopBlock
|
|
782
779
|
// writes the right shape and returns the exit code to use.
|
|
783
|
-
const { emitStopBlock } = await import("./
|
|
784
|
-
return emitStopBlock(
|
|
780
|
+
const { emitStopBlock } = await import("./adapter/output.js");
|
|
781
|
+
return emitStopBlock(adapter, verdict);
|
|
785
782
|
}
|
|
786
783
|
}
|
|
787
784
|
// Phase 7: PreToolUse: heartbeat + pid-map self-heal on every tool call.
|
|
788
|
-
//
|
|
785
|
+
// Adapter-agnostic: both writes have the same shape regardless of who fired.
|
|
789
786
|
// Cursor/Codex bash dispatchers still fire their own G-guard logic, but the
|
|
790
787
|
// heals here keep the agent-coord layer's view of liveness fresh.
|
|
791
788
|
//
|
|
@@ -795,8 +792,8 @@ async function main() {
|
|
|
795
792
|
// call was restored here afterward.
|
|
796
793
|
if (norm.event_type === "tool.pre_use") {
|
|
797
794
|
try {
|
|
798
|
-
healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId,
|
|
799
|
-
refreshPidmap(coordRoot, owner.instance_id,
|
|
795
|
+
healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId, adapter);
|
|
796
|
+
refreshPidmap(coordRoot, owner.instance_id, adapter, payload?.pid);
|
|
800
797
|
}
|
|
801
798
|
catch (err) {
|
|
802
799
|
logError(coordRoot, err, { phase: "pre-tool-use-heal" });
|
|
@@ -810,49 +807,49 @@ async function main() {
|
|
|
810
807
|
payload,
|
|
811
808
|
instanceId: owner.instance_id,
|
|
812
809
|
sessionId,
|
|
813
|
-
|
|
810
|
+
adapter,
|
|
814
811
|
});
|
|
815
812
|
}
|
|
816
813
|
catch (err) {
|
|
817
814
|
logError(coordRoot, err, { phase: "pre-tool-use-image-capture" });
|
|
818
815
|
}
|
|
819
|
-
// G-guard for ALL
|
|
816
|
+
// G-guard for ALL adapters. Claude Code previously ran this via a
|
|
820
817
|
// pre-tool-use bash adapter (which called `agent-coord verdict --rule=claim`);
|
|
821
|
-
// that adapter is now deleted, so agent-hook owns the deny for every
|
|
822
|
-
// emitDeny() inside emits the
|
|
818
|
+
// that adapter is now deleted, so agent-hook owns the deny for every adapter.
|
|
819
|
+
// emitDeny() inside emits the adapter-shaped permission JSON (claude-code +
|
|
823
820
|
// codex use hookSpecificOutput.permissionDecision; cursor uses .permission).
|
|
824
821
|
// apply_patch (codex) parses paths from the patch body and runs verdict
|
|
825
822
|
// per-path; Edit/Write/NotebookEdit resolve a single target. Non-write tools
|
|
826
823
|
// (incl. Agent) yield no targets and pass through with no deny.
|
|
827
824
|
try {
|
|
828
|
-
await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data,
|
|
825
|
+
await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data, adapter);
|
|
829
826
|
}
|
|
830
827
|
catch (err) {
|
|
831
828
|
logError(coordRoot, err, { phase: "pre-tool-use-guard" });
|
|
832
829
|
}
|
|
833
830
|
// Shell-mutation warn (warn-only, never blocks). Was the cursor
|
|
834
831
|
// beforeShellExecution + codex preToolUse-Bash shell-mutation-claim-log in
|
|
835
|
-
// the per-
|
|
832
|
+
// the per-adapter shell adapters. Cursor sends the command at payload.command;
|
|
836
833
|
// codex Bash at tool_input.command. Emits a decision.warn per candidate-mutated
|
|
837
834
|
// path so a peer sees the write in events.ndjson. (CC never did this,
|
|
838
835
|
// preserved; it emits with its own hooks-side emitter per the
|
|
839
836
|
// independent-emitter rule.)
|
|
840
837
|
const shellCmd = eventName === "before-shell-execution"
|
|
841
838
|
? (payload?.raw.command ?? "")
|
|
842
|
-
:
|
|
839
|
+
: adapter === "codex" && data.tool_name === "Bash"
|
|
843
840
|
? (payload?.raw.tool_input?.command ?? "")
|
|
844
841
|
: "";
|
|
845
842
|
if (shellCmd) {
|
|
846
843
|
try {
|
|
847
844
|
const paths = shellMutationPaths(shellCmd, coordRoot);
|
|
848
845
|
const truncated = shellCmd.length > 80 ? shellCmd.slice(0, 80) : shellCmd;
|
|
849
|
-
const platform =
|
|
846
|
+
const platform = adapterPlatform(adapter);
|
|
850
847
|
for (const p of paths) {
|
|
851
848
|
emit(coordRoot, {
|
|
852
849
|
event_type: "decision.warn",
|
|
853
850
|
instance_id: owner.instance_id,
|
|
854
851
|
session_id: sessionId,
|
|
855
|
-
|
|
852
|
+
adapter,
|
|
856
853
|
data: {
|
|
857
854
|
rule: "shell_mutation_candidate",
|
|
858
855
|
reason: `path=${p} cmd=${truncated} platform=${platform}`,
|
|
@@ -867,7 +864,7 @@ async function main() {
|
|
|
867
864
|
}
|
|
868
865
|
}
|
|
869
866
|
// Phase 7: PostToolUse: stamp last_tool + last_tool_target on heartbeat.
|
|
870
|
-
//
|
|
867
|
+
// Adapter-agnostic for the same reason as tool.pre_use above.
|
|
871
868
|
if (norm.event_type === "tool.post_use") {
|
|
872
869
|
try {
|
|
873
870
|
stampToolActivity(coordRoot, owner.instance_id, data);
|
|
@@ -885,7 +882,7 @@ async function main() {
|
|
|
885
882
|
payload,
|
|
886
883
|
instanceId: owner.instance_id,
|
|
887
884
|
sessionId,
|
|
888
|
-
|
|
885
|
+
adapter,
|
|
889
886
|
});
|
|
890
887
|
}
|
|
891
888
|
catch (err) {
|
|
@@ -893,7 +890,7 @@ async function main() {
|
|
|
893
890
|
}
|
|
894
891
|
}
|
|
895
892
|
// Phase 7: PostToolUseFailure: release claim on failed Edit (the file
|
|
896
|
-
// never landed; the claim is stale).
|
|
893
|
+
// never landed; the claim is stale). Adapter-agnostic.
|
|
897
894
|
if (norm.event_type === "tool.post_use_failure") {
|
|
898
895
|
try {
|
|
899
896
|
releaseClaimOnFailure(coordRoot, owner.instance_id, data, payload?.raw);
|
|
@@ -904,14 +901,14 @@ async function main() {
|
|
|
904
901
|
}
|
|
905
902
|
return 0;
|
|
906
903
|
}
|
|
907
|
-
async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data,
|
|
904
|
+
async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data, adapter) {
|
|
908
905
|
const toolName = data.tool_name ?? "";
|
|
909
906
|
const targets = collectGuardTargets(toolName, data)
|
|
910
907
|
.map((p) => canonicalize(coordRoot, p))
|
|
911
908
|
.filter((p) => p !== null);
|
|
912
909
|
if (targets.length === 0)
|
|
913
910
|
return;
|
|
914
|
-
const agentCoordBin =
|
|
911
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
915
912
|
if (!existsSync(agentCoordBin))
|
|
916
913
|
return;
|
|
917
914
|
// For apply_patch (multi-file), collect siblings so the deny reason names
|
|
@@ -949,8 +946,8 @@ async function runPreToolUseGuard(coordRoot, instanceId, sessionId, data, harnes
|
|
|
949
946
|
reason += ` The patch also touched: ${siblings}: pick a different file or wait.`;
|
|
950
947
|
}
|
|
951
948
|
}
|
|
952
|
-
const { emitDeny } = await import("./
|
|
953
|
-
emitDeny(
|
|
949
|
+
const { emitDeny } = await import("./adapter/output.js");
|
|
950
|
+
emitDeny(adapter, reason);
|
|
954
951
|
return;
|
|
955
952
|
}
|
|
956
953
|
}
|
|
@@ -1011,45 +1008,60 @@ function parseApplyPatchPaths(data) {
|
|
|
1011
1008
|
}
|
|
1012
1009
|
return out;
|
|
1013
1010
|
}
|
|
1014
|
-
function healHeartbeatViaCli(coordRoot, instanceId, sessionId,
|
|
1015
|
-
const agentCoordBin =
|
|
1011
|
+
function healHeartbeatViaCli(coordRoot, instanceId, sessionId, adapter) {
|
|
1012
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1016
1013
|
if (!existsSync(agentCoordBin))
|
|
1017
1014
|
return;
|
|
1018
|
-
// Pass the detected
|
|
1015
|
+
// Pass the detected adapter so a pruned Cursor/Codex heartbeat is recreated
|
|
1019
1016
|
// with the correct platform; without it, healHeartbeat defaults to
|
|
1020
1017
|
// claude_code and the dashboard mislabels the agent. See
|
|
1021
1018
|
// heartbeat-writer.healHeartbeat.
|
|
1022
|
-
spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--
|
|
1019
|
+
spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--adapter=${adapter}`], {
|
|
1023
1020
|
encoding: "utf8",
|
|
1024
1021
|
timeout: 2000,
|
|
1025
1022
|
env: childEnv(coordRoot),
|
|
1026
1023
|
});
|
|
1027
1024
|
}
|
|
1028
1025
|
/**
|
|
1029
|
-
* Walk up the ppid chain on Linux/WSL looking for the
|
|
1026
|
+
* Walk up the ppid chain on Linux/WSL looking for the adapter anchor PID,
|
|
1030
1027
|
* the PID of the claude / cursor / codex binary. Finds the agent PID. Used by
|
|
1031
|
-
* `tool.pre_use`'s pid-map self-heal so a re-parented
|
|
1028
|
+
* `tool.pre_use`'s pid-map self-heal so a re-parented adapter binary (the
|
|
1032
1029
|
* VS Code 2.1.x sibling-claude spawn case) gets its pid-map row rewritten on
|
|
1033
1030
|
* the next tool call rather than going invisible until SessionStart fires
|
|
1034
1031
|
* again, which it may never do.
|
|
1035
1032
|
*
|
|
1036
1033
|
* Returns undefined only when no anchor is found; callers fall back to
|
|
1037
|
-
* `process.ppid` (the bash wrapper's parent, which is usually the
|
|
1034
|
+
* `process.ppid` (the bash wrapper's parent, which is usually the adapter binary
|
|
1038
1035
|
* itself). `HARNERY_AGENT_COORD_TEST_ANCHOR_PID` overrides everything so the
|
|
1039
1036
|
* test sandbox can pin a deterministic PID.
|
|
1040
1037
|
*/
|
|
1041
|
-
function
|
|
1038
|
+
function findAdapterAnchorPid(adapter) {
|
|
1042
1039
|
const override = coordEnv("AGENT_COORD_TEST_ANCHOR_PID");
|
|
1043
1040
|
if (override) {
|
|
1044
1041
|
const n = Number(override);
|
|
1045
1042
|
if (Number.isFinite(n) && n > 0)
|
|
1046
1043
|
return n;
|
|
1047
1044
|
}
|
|
1045
|
+
// A adapter that states its own pid ends the search. Nothing inferred from the
|
|
1046
|
+
// process tree beats the adapter naming itself, and the inference is the part
|
|
1047
|
+
// that has been failing: comm matching wants a binary called after its
|
|
1048
|
+
// adapter, and one Claude Code build ships its CLI under a version-numbered
|
|
1049
|
+
// filename, so the walk found nothing and the caller fell back to the hook's
|
|
1050
|
+
// own shell. That row was dead within seconds, leaving every session in this
|
|
1051
|
+
// environment unattributed.
|
|
1052
|
+
const fromEnv = adapterPidFromEnv();
|
|
1053
|
+
if (fromEnv)
|
|
1054
|
+
return fromEnv;
|
|
1048
1055
|
// Build the ppid chain (nearest → root, up to 20 hops), then hand it to the
|
|
1049
1056
|
// pure selector. Linux/WSL reads /proc; macOS/BSD (no /proc) falls back to
|
|
1050
1057
|
// `ps -o ppid=,comm=` parsed by the unit-tested `parsePsChainLine`. Splitting
|
|
1051
|
-
// the walk (untestable off a live box) from the
|
|
1052
|
-
//
|
|
1058
|
+
// the walk (untestable off a live box) from the matching keeps the selector
|
|
1059
|
+
// logic verifiable.
|
|
1060
|
+
//
|
|
1061
|
+
// Only the /proc branch carries an executable path for the selector's
|
|
1062
|
+
// path-based pass. Asking `ps` for one means either a second spawn per hop or
|
|
1063
|
+
// splitting `comm` from `args` on a line where comm may itself contain spaces,
|
|
1064
|
+
// and the adapter that needs the path pass states its pid in the env anyway.
|
|
1053
1065
|
const chain = [];
|
|
1054
1066
|
let pid = process.pid;
|
|
1055
1067
|
for (let hops = 0; hops < 20; hops++) {
|
|
@@ -1058,7 +1070,15 @@ function findHarnessAnchorPid(harness) {
|
|
|
1058
1070
|
const comm = readFileSync(`/proc/${pid}/comm`, "utf8").trim();
|
|
1059
1071
|
const status = readFileSync(`/proc/${pid}/status`, "utf8");
|
|
1060
1072
|
const m = status.match(/^PPid:\s+(\d+)/m);
|
|
1061
|
-
|
|
1073
|
+
// argv[0], for the path-based second pass. cmdline is NUL-separated.
|
|
1074
|
+
let exe;
|
|
1075
|
+
try {
|
|
1076
|
+
exe = readFileSync(`/proc/${pid}/cmdline`, "utf8").split("\0")[0] || undefined;
|
|
1077
|
+
}
|
|
1078
|
+
catch {
|
|
1079
|
+
/* exe is optional */
|
|
1080
|
+
}
|
|
1081
|
+
hop = { comm, ppid: m ? Number(m[1]) : 0, exe };
|
|
1062
1082
|
}
|
|
1063
1083
|
catch {
|
|
1064
1084
|
// no /proc (macOS/BSD) — fall through to ps
|
|
@@ -1070,12 +1090,12 @@ function findHarnessAnchorPid(harness) {
|
|
|
1070
1090
|
}
|
|
1071
1091
|
if (!hop)
|
|
1072
1092
|
break;
|
|
1073
|
-
chain.push({ pid, comm: hop.comm });
|
|
1093
|
+
chain.push({ pid, comm: hop.comm, exe: hop.exe });
|
|
1074
1094
|
if (!Number.isFinite(hop.ppid) || hop.ppid === 0 || hop.ppid === 1)
|
|
1075
1095
|
break;
|
|
1076
1096
|
pid = hop.ppid;
|
|
1077
1097
|
}
|
|
1078
|
-
return selectAnchorPid(chain,
|
|
1098
|
+
return selectAnchorPid(chain, adapter);
|
|
1079
1099
|
}
|
|
1080
1100
|
/**
|
|
1081
1101
|
* Pid-map self-heal for `tool.pre_use`. Symmetric counterpart to
|
|
@@ -1084,7 +1104,7 @@ function findHarnessAnchorPid(harness) {
|
|
|
1084
1104
|
*
|
|
1085
1105
|
* The pid argument prefers the payload's `pid` (CC populates it on
|
|
1086
1106
|
* SessionStart and may also send it on PreToolUse), then
|
|
1087
|
-
* `
|
|
1107
|
+
* `findAdapterAnchorPid`, then `process.ppid`. Writes go through the same
|
|
1088
1108
|
* idempotent `writePidmapViaAgentCoord` helper that SessionStart uses: no
|
|
1089
1109
|
* disk I/O on no-op heals (when the row already points at us).
|
|
1090
1110
|
*
|
|
@@ -1092,14 +1112,14 @@ function findHarnessAnchorPid(harness) {
|
|
|
1092
1112
|
* `harn agents heal-events` pidmap counts meaningful. The inline helper does
|
|
1093
1113
|
* not yet.
|
|
1094
1114
|
*/
|
|
1095
|
-
function refreshPidmap(coordRoot, instanceId,
|
|
1096
|
-
const pid = payloadPid ??
|
|
1115
|
+
function refreshPidmap(coordRoot, instanceId, adapter, payloadPid) {
|
|
1116
|
+
const pid = payloadPid ?? findAdapterAnchorPid(adapter) ?? process.ppid;
|
|
1097
1117
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
1098
1118
|
return;
|
|
1099
|
-
writePidmapViaAgentCoord(coordRoot, pid, instanceId,
|
|
1119
|
+
writePidmapViaAgentCoord(coordRoot, pid, instanceId, adapterPlatform(adapter));
|
|
1100
1120
|
}
|
|
1101
1121
|
function stampToolActivity(coordRoot, instanceId, data) {
|
|
1102
|
-
const agentCoordBin =
|
|
1122
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1103
1123
|
if (!existsSync(agentCoordBin))
|
|
1104
1124
|
return;
|
|
1105
1125
|
const toolName = data.tool_name ?? "";
|
|
@@ -1169,7 +1189,7 @@ function releaseClaimOnFailure(coordRoot, instanceId, data, rawPayload) {
|
|
|
1169
1189
|
? filePath.slice(coordRoot.length + 1)
|
|
1170
1190
|
: filePath;
|
|
1171
1191
|
}
|
|
1172
|
-
const agentCoordBin =
|
|
1192
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1173
1193
|
if (!existsSync(agentCoordBin))
|
|
1174
1194
|
return;
|
|
1175
1195
|
spawnSync(agentCoordBin, ["release-claim", instanceId, canonical], {
|
|
@@ -1213,13 +1233,13 @@ function cleanupSessionEnd(coordRoot, instanceId, reason) {
|
|
|
1213
1233
|
}
|
|
1214
1234
|
}
|
|
1215
1235
|
// Activity log
|
|
1216
|
-
const agentCoordBin =
|
|
1236
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1217
1237
|
if (existsSync(agentCoordBin)) {
|
|
1218
1238
|
spawnSync(agentCoordBin, ["log", `SESSION_END reason=${reason}`, "--instance", instanceId], { encoding: "utf8", timeout: 2000 });
|
|
1219
1239
|
}
|
|
1220
1240
|
}
|
|
1221
|
-
async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId,
|
|
1222
|
-
const agentCoordBin =
|
|
1241
|
+
async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionId, adapter, recoveryBriefing = "") {
|
|
1242
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1223
1243
|
let additionalContext = "";
|
|
1224
1244
|
if (existsSync(agentCoordBin)) {
|
|
1225
1245
|
// Look up the agent's name from its heartbeat (for council pending rendering).
|
|
@@ -1238,11 +1258,16 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
|
|
|
1238
1258
|
const args = ["prompt-context", "--instance", instanceId, "--session", sessionId];
|
|
1239
1259
|
if (agentName)
|
|
1240
1260
|
args.push("--name", agentName);
|
|
1241
|
-
//
|
|
1242
|
-
//
|
|
1243
|
-
//
|
|
1244
|
-
|
|
1261
|
+
// Every human-facing adapter gets the first-session naming reminder from
|
|
1262
|
+
// the shared hook path. Cursor + Codex additionally get ongoing set-task
|
|
1263
|
+
// staleness nudges; Claude Code enforces those via its Stop transcript.
|
|
1264
|
+
// Codex gets a fresh status-footer reminder on every prompt. Its Stop hook
|
|
1265
|
+
// stays observe-only, so missing the footer never replaces the answer.
|
|
1266
|
+
args.push("--session-name-nudge");
|
|
1267
|
+
if (adapter === "cursor" || adapter === "codex")
|
|
1245
1268
|
args.push("--task-nudge");
|
|
1269
|
+
if (adapter === "codex")
|
|
1270
|
+
args.push("--status-footer-nudge");
|
|
1246
1271
|
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1247
1272
|
if (result.status === 0 && result.stdout)
|
|
1248
1273
|
additionalContext = result.stdout.trim();
|
|
@@ -1252,24 +1277,24 @@ async function emitUserPromptSubmitSystemMessage(coordRoot, instanceId, sessionI
|
|
|
1252
1277
|
}
|
|
1253
1278
|
if (!additionalContext)
|
|
1254
1279
|
return false;
|
|
1255
|
-
const { emitContext } = await import("./
|
|
1256
|
-
emitContext(
|
|
1280
|
+
const { emitContext } = await import("./adapter/output.js");
|
|
1281
|
+
emitContext(adapter, "UserPromptSubmit", additionalContext);
|
|
1257
1282
|
return true;
|
|
1258
1283
|
}
|
|
1259
|
-
function emitSubagentStartContext(coordRoot, instanceId, sessionId, data,
|
|
1284
|
+
function emitSubagentStartContext(coordRoot, instanceId, sessionId, data, adapter) {
|
|
1260
1285
|
// Look up the subagent's assigned name (just-written by agent-coord assignName
|
|
1261
1286
|
// in session.start data) + the parent's short id for the "you are a subagent
|
|
1262
1287
|
// of X" framing.
|
|
1263
1288
|
const subagentName = data.name ?? "";
|
|
1264
1289
|
if (!subagentName)
|
|
1265
1290
|
return;
|
|
1266
|
-
const platformLabel =
|
|
1291
|
+
const platformLabel = adapterPlatform(adapter);
|
|
1267
1292
|
const parentShort = sessionId && sessionId !== instanceId ? `agent-${sessionId.slice(0, 8)}` : "the parent session";
|
|
1268
1293
|
const message = `You are agent-${subagentName} (${platformLabel} subagent). You're a subagent of ${parentShort}.`;
|
|
1269
1294
|
// Render peer table inline since the subagent might want to know who else
|
|
1270
1295
|
// is around. Reuse prompt-context (which dedups against the per-owner hash);
|
|
1271
1296
|
// first call will always emit.
|
|
1272
|
-
const agentCoordBin =
|
|
1297
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1273
1298
|
let combined = message;
|
|
1274
1299
|
if (existsSync(agentCoordBin)) {
|
|
1275
1300
|
const result = spawnSync(agentCoordBin, ["prompt-context", "--instance", instanceId, "--session", sessionId, "--name", subagentName], { encoding: "utf8", timeout: 3000 });
|
|
@@ -1279,17 +1304,17 @@ function emitSubagentStartContext(coordRoot, instanceId, sessionId, data, harnes
|
|
|
1279
1304
|
}
|
|
1280
1305
|
// Use SubagentStart event-name in CC's hookSpecificOutput shape; cursor's
|
|
1281
1306
|
// flat `additional_context` works the same way.
|
|
1282
|
-
void import("./
|
|
1283
|
-
emitContext(
|
|
1307
|
+
void import("./adapter/output.js").then(({ emitContext }) => {
|
|
1308
|
+
emitContext(adapter, "SubagentStart", combined);
|
|
1284
1309
|
});
|
|
1285
1310
|
}
|
|
1286
|
-
function
|
|
1287
|
-
if (
|
|
1311
|
+
function adapterPlatform(adapter) {
|
|
1312
|
+
if (adapter === "claude-code")
|
|
1288
1313
|
return "claude_code";
|
|
1289
|
-
return
|
|
1314
|
+
return adapter;
|
|
1290
1315
|
}
|
|
1291
|
-
async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, emittedData,
|
|
1292
|
-
const agentCoordBin =
|
|
1316
|
+
async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, emittedData, adapter, recoveryBriefing = "") {
|
|
1317
|
+
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1293
1318
|
let additionalContext = "";
|
|
1294
1319
|
if (existsSync(agentCoordBin)) {
|
|
1295
1320
|
// Sync-project so the heartbeat exists for downstream readers (peer table,
|
|
@@ -1297,10 +1322,10 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
|
|
|
1297
1322
|
spawnSync(agentCoordBin, ["project"], { encoding: "utf8", timeout: 3000 });
|
|
1298
1323
|
// Stale-sweep dead peers before rendering peer table.
|
|
1299
1324
|
spawnSync(agentCoordBin, ["stale-sweep"], { encoding: "utf8", timeout: 3000 });
|
|
1300
|
-
// SESSION_START activity log line, fired across all
|
|
1325
|
+
// SESSION_START activity log line, fired across all adapters.
|
|
1301
1326
|
const model = emittedData.model ?? "unknown";
|
|
1302
1327
|
const source = emittedData.source ?? "startup";
|
|
1303
|
-
const platform =
|
|
1328
|
+
const platform = adapterPlatform(adapter);
|
|
1304
1329
|
spawnSync(agentCoordBin, [
|
|
1305
1330
|
"log",
|
|
1306
1331
|
`SESSION_START model=${model} source=${source} platform=${platform}`,
|
|
@@ -1315,19 +1340,19 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
|
|
|
1315
1340
|
// The "You are agent-X." prefix in session-context renders unqualified by
|
|
1316
1341
|
// default (claude-code-style). For cursor/codex the bash dispatchers add
|
|
1317
1342
|
// a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
|
|
1318
|
-
if (
|
|
1343
|
+
if (adapter !== "claude-code") {
|
|
1319
1344
|
args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
|
|
1320
1345
|
}
|
|
1321
1346
|
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1322
1347
|
if (result.status === 0 && result.stdout)
|
|
1323
1348
|
additionalContext = result.stdout.trim();
|
|
1324
1349
|
}
|
|
1325
|
-
// Effect (claude-code): merge the
|
|
1350
|
+
// Effect (claude-code): merge the journal recovery cue into the session-start
|
|
1326
1351
|
// context. Was a standalone additionalContext emission from the previous
|
|
1327
|
-
//
|
|
1352
|
+
// journal-on-start adapter; now that agent-hook is the single SessionStart
|
|
1328
1353
|
// entry, it folds in here.
|
|
1329
|
-
if (
|
|
1330
|
-
const cue =
|
|
1354
|
+
if (adapter === "claude-code") {
|
|
1355
|
+
const cue = journalRecoveryCue(coordRoot);
|
|
1331
1356
|
if (cue)
|
|
1332
1357
|
additionalContext = [additionalContext, cue].filter(Boolean).join("\n\n");
|
|
1333
1358
|
}
|
|
@@ -1336,17 +1361,17 @@ async function emitSessionStartSystemMessage(coordRoot, instanceId, sessionId, e
|
|
|
1336
1361
|
}
|
|
1337
1362
|
if (!additionalContext)
|
|
1338
1363
|
return false;
|
|
1339
|
-
const { emitContext } = await import("./
|
|
1340
|
-
emitContext(
|
|
1364
|
+
const { emitContext } = await import("./adapter/output.js");
|
|
1365
|
+
emitContext(adapter, "SessionStart", additionalContext);
|
|
1341
1366
|
return true;
|
|
1342
1367
|
}
|
|
1343
|
-
function completeRecoveryInjection(coordRoot, instanceId, sessionId,
|
|
1368
|
+
function completeRecoveryInjection(coordRoot, instanceId, sessionId, adapter, recovery, injectionEvent) {
|
|
1344
1369
|
completeContextRecovery(coordRoot, { sessionId, instanceId });
|
|
1345
1370
|
emit(coordRoot, {
|
|
1346
1371
|
event_type: "context.recovery.injected",
|
|
1347
1372
|
instance_id: instanceId,
|
|
1348
1373
|
session_id: sessionId,
|
|
1349
|
-
|
|
1374
|
+
adapter,
|
|
1350
1375
|
data: {
|
|
1351
1376
|
capsule_id: recovery.capsule.capsule_id,
|
|
1352
1377
|
generation: recovery.capsule.generation,
|