harnery 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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 +61 -60
- 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/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 +193 -23
- 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 +4 -4
- package/dist/core/agents/canonical-emit.js +5 -5
- 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-client.d.ts +21 -2
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +122 -27
- 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/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 +175 -151
- 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 +17 -17
- 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 +3 -3
- package/dist/core/hooks/resolve/coord-root.js +4 -4
- 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/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 +71 -64
- 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/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 +237 -34
- 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 +6 -6
- 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-client.ts +119 -28
- package/src/core/agents/events/consume.ts +1 -1
- package/src/core/agents/events/emit.ts +7 -6
- 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 +185 -162
- package/src/core/hooks/effects/image-capture.ts +6 -6
- package/src/core/hooks/effects/index.ts +17 -17
- 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 +4 -4
- 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/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/src/core/hooks/cli.ts
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,7 +15,7 @@
|
|
|
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
|
|
|
21
21
|
import { spawnSync } from "node:child_process";
|
|
@@ -26,6 +26,7 @@ import { replayCodexJsonl } from "../agents/codex-replay.ts";
|
|
|
26
26
|
import { consumeSince, writeCursor } from "../agents/events/consume.ts";
|
|
27
27
|
import { evaluateStopHook } from "../agents/rules/stop-hook.ts";
|
|
28
28
|
import { projectHeartbeats } from "../agents/state/heartbeat-projector.ts";
|
|
29
|
+
import { writePidmapRow } from "../agents/state/pidmap.ts";
|
|
29
30
|
import { shellMutationPaths } from "../agents/state/shell-mutation.ts";
|
|
30
31
|
import {
|
|
31
32
|
checkpointContext,
|
|
@@ -38,32 +39,32 @@ import {
|
|
|
38
39
|
recordContextSample,
|
|
39
40
|
} from "../context/index.ts";
|
|
40
41
|
import { ensureRelayDaemon, fetchPresence, publishPresence } from "../presence/index.ts";
|
|
42
|
+
import { detectAdapter } from "./adapter/detect.ts";
|
|
43
|
+
import {
|
|
44
|
+
extractBashCommand,
|
|
45
|
+
extractToolDescription,
|
|
46
|
+
type NormalizedEventType,
|
|
47
|
+
normalizeEventName,
|
|
48
|
+
type ParsedPayload,
|
|
49
|
+
parsePayload,
|
|
50
|
+
} from "./adapter/parse.ts";
|
|
41
51
|
import {
|
|
42
52
|
captureImages,
|
|
43
53
|
detectPresence,
|
|
44
54
|
imageJanitor,
|
|
55
|
+
journalArchive,
|
|
56
|
+
journalJanitor,
|
|
57
|
+
journalRecoveryCue,
|
|
45
58
|
playSound,
|
|
46
59
|
resetSoundCounters,
|
|
47
60
|
runSessionSyncExtension,
|
|
48
61
|
runTurnSummary,
|
|
49
|
-
scratchArchive,
|
|
50
|
-
scratchJanitor,
|
|
51
|
-
scratchRecoveryCue,
|
|
52
62
|
soundForEvent,
|
|
53
63
|
} from "./effects/index.ts";
|
|
54
64
|
import { emit } from "./events/emit.ts";
|
|
55
|
-
import type {
|
|
65
|
+
import type { Adapter } from "./events/schema.ts";
|
|
56
66
|
import { canonicalize } from "./guard-path.ts";
|
|
57
|
-
import {
|
|
58
|
-
import {
|
|
59
|
-
extractBashCommand,
|
|
60
|
-
extractToolDescription,
|
|
61
|
-
type NormalizedEventType,
|
|
62
|
-
normalizeEventName,
|
|
63
|
-
type ParsedPayload,
|
|
64
|
-
parsePayload,
|
|
65
|
-
} from "./harness/parse.ts";
|
|
66
|
-
import { parsePsChainLine, selectAnchorPid } from "./resolve/anchor.ts";
|
|
67
|
+
import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.ts";
|
|
67
68
|
import { findCoordRoot } from "./resolve/coord-root.ts";
|
|
68
69
|
import { extractIntentComment, resolveIntent } from "./resolve/intent.ts";
|
|
69
70
|
import { resolveOwner } from "./resolve/owner.ts";
|
|
@@ -78,11 +79,11 @@ function parseArgv(argv: string[]): Argv {
|
|
|
78
79
|
const out: Argv = { eventName: null, extra: [] };
|
|
79
80
|
for (let i = 0; i < argv.length; i++) {
|
|
80
81
|
const arg = argv[i]!;
|
|
81
|
-
if (arg === "--
|
|
82
|
-
i++; //
|
|
82
|
+
if (arg === "--adapter") {
|
|
83
|
+
i++; // detectAdapter will re-parse; just consume the value here.
|
|
83
84
|
continue;
|
|
84
85
|
}
|
|
85
|
-
if (arg.startsWith("--
|
|
86
|
+
if (arg.startsWith("--adapter=")) continue;
|
|
86
87
|
if (!out.eventName && !arg.startsWith("--")) {
|
|
87
88
|
out.eventName = arg;
|
|
88
89
|
} else {
|
|
@@ -108,7 +109,7 @@ async function readStdin(): Promise<string> {
|
|
|
108
109
|
/**
|
|
109
110
|
* Env for child agent-coord spawns, with the coord root pinned. The hook
|
|
110
111
|
* process may be running with the session shell's cwd (inside a submodule or
|
|
111
|
-
*
|
|
112
|
+
* journal dir), and agent-coord resolves its root from cwd unless overridden —
|
|
112
113
|
* without the pin a child could write state to a different .harnery than the
|
|
113
114
|
* one this hook resolved.
|
|
114
115
|
*/
|
|
@@ -149,7 +150,7 @@ function logError(coordRoot: string | null, err: unknown, context: Record<string
|
|
|
149
150
|
/**
|
|
150
151
|
* Spawn `agent-coord assign-name <owner> <kind>` to mint or recover the
|
|
151
152
|
* hurricane-style name for this owner. Returns null on any failure so
|
|
152
|
-
* session.start emission never breaks the
|
|
153
|
+
* session.start emission never breaks the adapter flow.
|
|
153
154
|
*
|
|
154
155
|
* Lives at agent-hooks side (not agent-coord) to keep emitter/consumer
|
|
155
156
|
* separation: we spawn rather than import.
|
|
@@ -182,9 +183,15 @@ function assignNameViaAgentCoord(
|
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
/**
|
|
185
|
-
* Direct (in-process) pidmap write,
|
|
186
|
-
* the agent-coord CLI for every session.start / subagent.start. Pid-map
|
|
187
|
-
*
|
|
186
|
+
* Direct (in-process) pidmap write, avoiding the spawn overhead of going via
|
|
187
|
+
* the agent-coord CLI for every session.start / subagent.start. Pid-map rows
|
|
188
|
+
* are essential for `harn agents whoami` ppid resolution.
|
|
189
|
+
*
|
|
190
|
+
* This used to inline its own copy of the write to keep this module's
|
|
191
|
+
* dependencies narrow, which quietly mattered: the shared writer is where row
|
|
192
|
+
* hygiene lives, so the duplicate meant the only hot write path in the system
|
|
193
|
+
* never swept dead rows, and the map grew unbounded. It calls the shared writer
|
|
194
|
+
* now, and this module already imports from that directory anyway.
|
|
188
195
|
*/
|
|
189
196
|
function writePidmapViaAgentCoord(
|
|
190
197
|
coordRoot: string,
|
|
@@ -193,26 +200,9 @@ function writePidmapViaAgentCoord(
|
|
|
193
200
|
platform: string,
|
|
194
201
|
): void {
|
|
195
202
|
try {
|
|
196
|
-
|
|
197
|
-
// agent-coord/src/state/pidmap.ts but skips importing across module
|
|
198
|
-
// boundaries to keep agent-hooks's deps explicit.
|
|
199
|
-
const dir = join(coordRoot, ".harnery", "pid-map");
|
|
200
|
-
const path = join(dir, String(pid));
|
|
201
|
-
const row = `${instanceId}\t${platform}`;
|
|
202
|
-
if (existsSync(path)) {
|
|
203
|
-
try {
|
|
204
|
-
const current = require("node:fs").readFileSync(path, "utf8");
|
|
205
|
-
if (current === row) return;
|
|
206
|
-
} catch {
|
|
207
|
-
/* fall through */
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
mkdirSync(dir, { recursive: true });
|
|
211
|
-
const tmp = `${path}.tmp.${process.pid}`;
|
|
212
|
-
require("node:fs").writeFileSync(tmp, row, "utf8");
|
|
213
|
-
require("node:fs").renameSync(tmp, path);
|
|
203
|
+
writePidmapRow(coordRoot, pid, instanceId, platform);
|
|
214
204
|
} catch {
|
|
215
|
-
/* never break the
|
|
205
|
+
/* never break the adapter flow */
|
|
216
206
|
}
|
|
217
207
|
}
|
|
218
208
|
|
|
@@ -234,7 +224,7 @@ interface BuildContext {
|
|
|
234
224
|
coordRoot: string;
|
|
235
225
|
payload: ParsedPayload | null;
|
|
236
226
|
raw: string;
|
|
237
|
-
|
|
227
|
+
adapter: Adapter;
|
|
238
228
|
instanceId: string;
|
|
239
229
|
}
|
|
240
230
|
|
|
@@ -245,24 +235,24 @@ function buildEventData(
|
|
|
245
235
|
const p = ctx.payload;
|
|
246
236
|
switch (eventType) {
|
|
247
237
|
case "session.start": {
|
|
248
|
-
const
|
|
249
|
-
ctx.
|
|
238
|
+
const adapterPlatform =
|
|
239
|
+
ctx.adapter === "claude-code"
|
|
250
240
|
? "claude_code"
|
|
251
|
-
: ctx.
|
|
241
|
+
: ctx.adapter === "cursor"
|
|
252
242
|
? "cursor"
|
|
253
243
|
: "codex";
|
|
254
244
|
// Assign (or recover) name + kind via agent-coord. Idempotent: resume
|
|
255
245
|
// returns the original name; new owner consumes a counter slot.
|
|
256
246
|
const assigned = assignNameViaAgentCoord(ctx.coordRoot, ctx.instanceId, "session");
|
|
257
|
-
// Write the
|
|
247
|
+
// Write the adapter pid-map row so `harn agents whoami` ppid-walks find
|
|
258
248
|
// this owner. Prefer the payload pid (the actual claude binary), then the
|
|
259
249
|
// anchor walk (the `node` ancestor for Cursor, which has no payload pid),
|
|
260
250
|
// then our own process.ppid. Without the anchor, Cursor anchored on the
|
|
261
251
|
// ephemeral hook bash parent, a PID that dies before the agent's next
|
|
262
252
|
// shell tool call, so the ppid walk found nothing (no_pidmap_entry).
|
|
263
|
-
const
|
|
264
|
-
if (
|
|
265
|
-
writePidmapViaAgentCoord(ctx.coordRoot,
|
|
253
|
+
const adapterPid = p?.pid ?? findAdapterAnchorPid(ctx.adapter) ?? process.ppid;
|
|
254
|
+
if (adapterPid) {
|
|
255
|
+
writePidmapViaAgentCoord(ctx.coordRoot, adapterPid, ctx.instanceId, adapterPlatform);
|
|
266
256
|
}
|
|
267
257
|
return {
|
|
268
258
|
started_at: new Date().toISOString(),
|
|
@@ -271,17 +261,25 @@ function buildEventData(
|
|
|
271
261
|
// supply it). Fall back to the transcript, populated on `resume`, and
|
|
272
262
|
// backfilled later by `turn.stop` for a fresh `startup` session.
|
|
273
263
|
model: p?.model ?? scanTranscriptModel(p?.transcript_path),
|
|
274
|
-
pid:
|
|
264
|
+
pid: adapterPid,
|
|
275
265
|
source: p?.source,
|
|
276
|
-
platform:
|
|
266
|
+
platform: adapterPlatform,
|
|
277
267
|
name: assigned?.name,
|
|
278
268
|
kind: "session",
|
|
279
269
|
agent_id: ctx.instanceId,
|
|
280
270
|
// Workflow-child linkage: `workflow run` children carry the run id in
|
|
281
271
|
// env (spawn adapters set it via buildChildEnv), so their sessions and
|
|
282
|
-
// heartbeats join back to the run
|
|
272
|
+
// heartbeats join back to the run transcript + /workflows web view.
|
|
283
273
|
...(coordEnv("WORKFLOW_CHILD") === "1" && coordEnv("WORKFLOW_RUN_ID")
|
|
284
|
-
? {
|
|
274
|
+
? {
|
|
275
|
+
workflow_run_id: coordEnv("WORKFLOW_RUN_ID"),
|
|
276
|
+
// Which agent row of that run this session is. The orchestrator
|
|
277
|
+
// stamps it on the way in, because the adapter does not report a
|
|
278
|
+
// session id until the agent has already finished.
|
|
279
|
+
...(coordEnv("WORKFLOW_AGENT_ID")
|
|
280
|
+
? { workflow_agent_id: coordEnv("WORKFLOW_AGENT_ID") }
|
|
281
|
+
: {}),
|
|
282
|
+
}
|
|
285
283
|
: {}),
|
|
286
284
|
};
|
|
287
285
|
}
|
|
@@ -300,7 +298,7 @@ function buildEventData(
|
|
|
300
298
|
|
|
301
299
|
case "turn.stop": {
|
|
302
300
|
return {
|
|
303
|
-
// Backfill the model for
|
|
301
|
+
// Backfill the model for adapters that omit it at session.start
|
|
304
302
|
// (Claude Code). The transcript is populated with assistant turns by
|
|
305
303
|
// Stop-hook time, so this resolves even for fresh `startup` sessions.
|
|
306
304
|
model: p?.model ?? scanTranscriptModel(p?.transcript_path),
|
|
@@ -442,14 +440,14 @@ function numberField(value: unknown): number | undefined {
|
|
|
442
440
|
|
|
443
441
|
async function main(): Promise<number> {
|
|
444
442
|
const { eventName, extra } = parseArgv(process.argv.slice(2));
|
|
445
|
-
const
|
|
443
|
+
const adapter = detectAdapter(process.argv.slice(2));
|
|
446
444
|
const raw = await readStdin();
|
|
447
445
|
|
|
448
446
|
// Kill-switch-INDEPENDENT effects: notification sounds fire BEFORE the
|
|
449
447
|
// HARNERY_AGENT_COORD_OFF gate so audible feedback survives incident-triage
|
|
450
448
|
// bypass: sound playback happens before the kill-switch bailout.
|
|
451
449
|
// Claude-Code-only; stop-failure → error, sub-agent-start → subagent-start.
|
|
452
|
-
if (
|
|
450
|
+
if (adapter === "claude-code" && eventName) {
|
|
453
451
|
const s = soundForEvent(eventName);
|
|
454
452
|
if (s) {
|
|
455
453
|
const repoRoot = findCoordRoot(process.cwd());
|
|
@@ -481,7 +479,7 @@ async function main(): Promise<number> {
|
|
|
481
479
|
const debugBase = {
|
|
482
480
|
ts: new Date().toISOString(),
|
|
483
481
|
event_name: eventName,
|
|
484
|
-
|
|
482
|
+
adapter,
|
|
485
483
|
extra_argv: extra,
|
|
486
484
|
payload_bytes: raw.length,
|
|
487
485
|
cwd: process.cwd(),
|
|
@@ -489,8 +487,8 @@ async function main(): Promise<number> {
|
|
|
489
487
|
ppid: process.ppid,
|
|
490
488
|
};
|
|
491
489
|
|
|
492
|
-
if (!eventName || !
|
|
493
|
-
appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-
|
|
490
|
+
if (!eventName || !adapter) {
|
|
491
|
+
appendDebug(coordRoot, { ...debugBase, skipped: "missing-event-or-adapter" });
|
|
494
492
|
return 0;
|
|
495
493
|
}
|
|
496
494
|
|
|
@@ -500,7 +498,7 @@ async function main(): Promise<number> {
|
|
|
500
498
|
return 0;
|
|
501
499
|
}
|
|
502
500
|
|
|
503
|
-
const payload = parsePayload(raw,
|
|
501
|
+
const payload = parsePayload(raw, adapter);
|
|
504
502
|
const owner = resolveOwner({ payload: payload?.raw ?? null, coordRoot });
|
|
505
503
|
if (!owner) {
|
|
506
504
|
appendDebug(coordRoot, {
|
|
@@ -517,7 +515,7 @@ async function main(): Promise<number> {
|
|
|
517
515
|
coordRoot,
|
|
518
516
|
payload,
|
|
519
517
|
raw,
|
|
520
|
-
|
|
518
|
+
adapter,
|
|
521
519
|
instanceId: owner.instance_id,
|
|
522
520
|
});
|
|
523
521
|
|
|
@@ -528,7 +526,7 @@ async function main(): Promise<number> {
|
|
|
528
526
|
parent_session_id: payload?.parent_session_id,
|
|
529
527
|
turn_id: payload?.turn_id,
|
|
530
528
|
parent_turn_id: payload?.parent_turn_id,
|
|
531
|
-
|
|
529
|
+
adapter,
|
|
532
530
|
data,
|
|
533
531
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
534
532
|
} as Parameters<typeof emit>[1]);
|
|
@@ -541,13 +539,13 @@ async function main(): Promise<number> {
|
|
|
541
539
|
});
|
|
542
540
|
|
|
543
541
|
// Context telemetry is opportunistic and truthful: only persist a sample
|
|
544
|
-
// when the
|
|
542
|
+
// when the adapter payload actually exposes usage/window data. Identical
|
|
545
543
|
// measurements are de-duplicated before they reach the canonical stream.
|
|
546
544
|
if (payload?.raw) {
|
|
547
545
|
try {
|
|
548
546
|
const sample = extractContextSample(payload.raw, {
|
|
549
547
|
sessionId,
|
|
550
|
-
|
|
548
|
+
adapter,
|
|
551
549
|
model: payload.model,
|
|
552
550
|
source: "hook",
|
|
553
551
|
confidence: "reported",
|
|
@@ -559,7 +557,7 @@ async function main(): Promise<number> {
|
|
|
559
557
|
event_type: "context.sampled",
|
|
560
558
|
instance_id: owner.instance_id,
|
|
561
559
|
session_id: sessionId,
|
|
562
|
-
|
|
560
|
+
adapter,
|
|
563
561
|
data: {
|
|
564
562
|
model: sample.model,
|
|
565
563
|
used_tokens: sample.used_tokens,
|
|
@@ -578,13 +576,13 @@ async function main(): Promise<number> {
|
|
|
578
576
|
|
|
579
577
|
// A native pre-compaction signal is the safest available point to capture
|
|
580
578
|
// external work state. The operation is idempotent until recovery, so a
|
|
581
|
-
//
|
|
579
|
+
// adapter retry cannot create a storm of near-identical capsules.
|
|
582
580
|
if (norm.event_type === "context.compaction.started") {
|
|
583
581
|
try {
|
|
584
582
|
const checkpoint = checkpointContext(coordRoot, {
|
|
585
583
|
sessionId,
|
|
586
584
|
instanceId: owner.instance_id,
|
|
587
|
-
|
|
585
|
+
adapter,
|
|
588
586
|
cwd: payload?.cwd ?? process.cwd(),
|
|
589
587
|
reason: "pre_compact",
|
|
590
588
|
model: payload?.model,
|
|
@@ -593,7 +591,7 @@ async function main(): Promise<number> {
|
|
|
593
591
|
event_type: "context.checkpoint.created",
|
|
594
592
|
instance_id: owner.instance_id,
|
|
595
593
|
session_id: sessionId,
|
|
596
|
-
|
|
594
|
+
adapter,
|
|
597
595
|
data: {
|
|
598
596
|
capsule_id: checkpoint.capsule.capsule_id,
|
|
599
597
|
generation: checkpoint.capsule.generation,
|
|
@@ -619,17 +617,17 @@ async function main(): Promise<number> {
|
|
|
619
617
|
}
|
|
620
618
|
|
|
621
619
|
// Phase 8: SessionStart post-emit: project the event so the heartbeat
|
|
622
|
-
// lands synchronously, run stale-sweep, and emit the
|
|
620
|
+
// lands synchronously, run stale-sweep, and emit the adapter-shaped
|
|
623
621
|
// systemMessage JSON (peer table + wiring check + council invites).
|
|
624
|
-
//
|
|
625
|
-
// and the equivalent per-
|
|
622
|
+
// Adapter-agnostic since v0.5.0; replaces the previous bash UX layer
|
|
623
|
+
// and the equivalent per-adapter bash session_start handlers.
|
|
626
624
|
if (norm.event_type === "session.start") {
|
|
627
|
-
// Effect (claude-code): prune stale
|
|
625
|
+
// Effect (claude-code): prune stale journal archives + sweep orphans.
|
|
628
626
|
// The recovery-cue is merged into the
|
|
629
627
|
// session-start additionalContext inside emitSessionStartSystemMessage.
|
|
630
|
-
if (
|
|
631
|
-
// Image-feed retention sweep (size + age cap on .harnery/images/).
|
|
632
|
-
// agnostic, cheap (one readdir), fail-soft. Paired with
|
|
628
|
+
if (adapter === "claude-code") journalJanitor(coordRoot);
|
|
629
|
+
// Image-feed retention sweep (size + age cap on .harnery/images/). Adapter-
|
|
630
|
+
// agnostic, cheap (one readdir), fail-soft. Paired with journalJanitor as a
|
|
633
631
|
// session-start "tidy the coord layer" step.
|
|
634
632
|
try {
|
|
635
633
|
imageJanitor(coordRoot);
|
|
@@ -643,7 +641,7 @@ async function main(): Promise<number> {
|
|
|
643
641
|
event_type: "context.compaction.completed",
|
|
644
642
|
instance_id: owner.instance_id,
|
|
645
643
|
session_id: sessionId,
|
|
646
|
-
|
|
644
|
+
adapter,
|
|
647
645
|
data: { trigger: "auto" },
|
|
648
646
|
});
|
|
649
647
|
markContextCompactionCompleted(coordRoot, {
|
|
@@ -665,7 +663,7 @@ async function main(): Promise<number> {
|
|
|
665
663
|
owner.instance_id,
|
|
666
664
|
sessionId,
|
|
667
665
|
data,
|
|
668
|
-
|
|
666
|
+
adapter,
|
|
669
667
|
recovery?.briefing ?? "",
|
|
670
668
|
);
|
|
671
669
|
if (injected && recovery) {
|
|
@@ -673,7 +671,7 @@ async function main(): Promise<number> {
|
|
|
673
671
|
coordRoot,
|
|
674
672
|
owner.instance_id,
|
|
675
673
|
sessionId,
|
|
676
|
-
|
|
674
|
+
adapter,
|
|
677
675
|
recovery,
|
|
678
676
|
"SessionStart",
|
|
679
677
|
);
|
|
@@ -693,7 +691,7 @@ async function main(): Promise<number> {
|
|
|
693
691
|
}
|
|
694
692
|
}
|
|
695
693
|
|
|
696
|
-
// Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows.
|
|
694
|
+
// Phase 8: SessionEnd cleanup: delete heartbeat + pid-map rows. Adapter-
|
|
697
695
|
// agnostic since v0.5.0.
|
|
698
696
|
if (norm.event_type === "session.end") {
|
|
699
697
|
try {
|
|
@@ -701,10 +699,10 @@ async function main(): Promise<number> {
|
|
|
701
699
|
} catch (err) {
|
|
702
700
|
logError(coordRoot, err, { phase: "session-end-cleanup" });
|
|
703
701
|
}
|
|
704
|
-
// Effects (claude-code): archive the ending agent's
|
|
702
|
+
// Effects (claude-code): archive the ending agent's journal + force a
|
|
705
703
|
// session-telemetry sync (via HARNERY_CLAUDE_SESSIONS_FORCE=1).
|
|
706
|
-
if (
|
|
707
|
-
|
|
704
|
+
if (adapter === "claude-code") {
|
|
705
|
+
journalArchive(coordRoot, owner.instance_id);
|
|
708
706
|
runSessionSyncExtension(coordRoot, true);
|
|
709
707
|
}
|
|
710
708
|
// Presence: publish the post-cleanup state so peers see this session gone
|
|
@@ -732,14 +730,14 @@ async function main(): Promise<number> {
|
|
|
732
730
|
agentCoordBin,
|
|
733
731
|
[
|
|
734
732
|
"log",
|
|
735
|
-
`SUBAGENT_START agent_type=${(data.agent_type as string) ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${
|
|
733
|
+
`SUBAGENT_START agent_type=${(data.agent_type as string) ?? "unknown"} agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
|
|
736
734
|
"--instance",
|
|
737
735
|
owner.instance_id,
|
|
738
736
|
],
|
|
739
737
|
{ encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
|
|
740
738
|
);
|
|
741
739
|
}
|
|
742
|
-
emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data,
|
|
740
|
+
emitSubagentStartContext(coordRoot, owner.instance_id, sessionId, data, adapter);
|
|
743
741
|
} catch (err) {
|
|
744
742
|
logError(coordRoot, err, { phase: "subagent-start-project" });
|
|
745
743
|
}
|
|
@@ -755,7 +753,7 @@ async function main(): Promise<number> {
|
|
|
755
753
|
agentCoordBin,
|
|
756
754
|
[
|
|
757
755
|
"log",
|
|
758
|
-
`SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${
|
|
756
|
+
`SUBAGENT_STOP agent_id=${owner.instance_id.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
|
|
759
757
|
"--instance",
|
|
760
758
|
owner.instance_id,
|
|
761
759
|
],
|
|
@@ -768,11 +766,11 @@ async function main(): Promise<number> {
|
|
|
768
766
|
}
|
|
769
767
|
|
|
770
768
|
// Phase 8: UserPromptSubmit: render dedup'd peer table + council pending
|
|
771
|
-
// and emit the
|
|
769
|
+
// and emit the adapter-shaped systemMessage JSON. Adapter-agnostic since v0.5.0.
|
|
772
770
|
if (norm.event_type === "user_prompt.submit") {
|
|
773
771
|
// Effects (claude-code): reset per-turn sound rate-limit counters + run
|
|
774
772
|
// presence detection on the prompt.
|
|
775
|
-
if (
|
|
773
|
+
if (adapter === "claude-code") {
|
|
776
774
|
resetSoundCounters(sessionId);
|
|
777
775
|
const prompt = (payload?.raw?.prompt as string | undefined) ?? "";
|
|
778
776
|
if (prompt) detectPresence(prompt);
|
|
@@ -805,7 +803,7 @@ async function main(): Promise<number> {
|
|
|
805
803
|
coordRoot,
|
|
806
804
|
owner.instance_id,
|
|
807
805
|
sessionId,
|
|
808
|
-
|
|
806
|
+
adapter,
|
|
809
807
|
recovery?.briefing ?? "",
|
|
810
808
|
);
|
|
811
809
|
if (injected && recovery) {
|
|
@@ -813,7 +811,7 @@ async function main(): Promise<number> {
|
|
|
813
811
|
coordRoot,
|
|
814
812
|
owner.instance_id,
|
|
815
813
|
sessionId,
|
|
816
|
-
|
|
814
|
+
adapter,
|
|
817
815
|
recovery,
|
|
818
816
|
"UserPromptSubmit",
|
|
819
817
|
);
|
|
@@ -824,7 +822,7 @@ async function main(): Promise<number> {
|
|
|
824
822
|
}
|
|
825
823
|
|
|
826
824
|
// turn.stop: telemetry + turn-summary effects, then the stop verdict. The
|
|
827
|
-
// verdict + codex-replay previously lived in the per-
|
|
825
|
+
// verdict + codex-replay previously lived in the per-adapter shell adapters;
|
|
828
826
|
// agent-hook owns them now. Runs on the normal "stop" event only;
|
|
829
827
|
// "stop-failure" (API error) gets no gate, matching the previous
|
|
830
828
|
// stop vs stop-failure split.
|
|
@@ -833,7 +831,7 @@ async function main(): Promise<number> {
|
|
|
833
831
|
// the status_checked / task_set / status_box_present evidence (codex
|
|
834
832
|
// doesn't emit those live; this re-emits turn.stop after agent-hook's own,
|
|
835
833
|
// so the verdict reads the replay's box signal as the latest).
|
|
836
|
-
if (
|
|
834
|
+
if (adapter === "codex" && payload?.transcript_path && existsSync(payload.transcript_path)) {
|
|
837
835
|
try {
|
|
838
836
|
replayCodexJsonl({
|
|
839
837
|
coordRoot,
|
|
@@ -849,7 +847,7 @@ async function main(): Promise<number> {
|
|
|
849
847
|
|
|
850
848
|
// CC effects: rate-limited session-telemetry sync + turn-summary Haiku
|
|
851
849
|
// auto-summary.
|
|
852
|
-
if (
|
|
850
|
+
if (adapter === "claude-code") {
|
|
853
851
|
runSessionSyncExtension(coordRoot, false);
|
|
854
852
|
runTurnSummary(coordRoot, owner.instance_id, sessionId, payload?.transcript_path);
|
|
855
853
|
}
|
|
@@ -857,7 +855,7 @@ async function main(): Promise<number> {
|
|
|
857
855
|
// Master-state heartbeat projection. Drains events.ndjson since the last
|
|
858
856
|
// cursor → per-owner heartbeats. Was a SECOND binary (`agent-coord project`)
|
|
859
857
|
// pinned to Claude Code Stop only; folded in here so it (a) is one
|
|
860
|
-
// entry per event like everything else and (b) fires on EVERY
|
|
858
|
+
// entry per event like everything else and (b) fires on EVERY adapter's stop,
|
|
861
859
|
// not just CC. Runs unconditionally before the verdict's possible exit-2 return
|
|
862
860
|
// (the events are real regardless of whether the agent gets nagged), and after
|
|
863
861
|
// codex-replay above so codex's replayed events are included in the drain.
|
|
@@ -888,22 +886,22 @@ async function main(): Promise<number> {
|
|
|
888
886
|
rule: "stop-hook",
|
|
889
887
|
instance_id: owner.instance_id,
|
|
890
888
|
session_id: sessionId,
|
|
891
|
-
|
|
889
|
+
adapter,
|
|
892
890
|
bypass: coordEnv("AGENT_COORD_BYPASS_STOP") === "1",
|
|
893
891
|
workflow_child: coordEnv("WORKFLOW_CHILD") === "1",
|
|
894
892
|
});
|
|
895
893
|
if (!verdict.allow) {
|
|
896
|
-
//
|
|
894
|
+
// Adapter-aware enforcement channel: Claude Code / Codex honor exit-2 +
|
|
897
895
|
// stderr as a turn block; Cursor ignores exit codes (fail-open) and
|
|
898
896
|
// re-prompts only via a `followup_message` it auto-submits. emitStopBlock
|
|
899
897
|
// writes the right shape and returns the exit code to use.
|
|
900
|
-
const { emitStopBlock } = await import("./
|
|
901
|
-
return emitStopBlock(
|
|
898
|
+
const { emitStopBlock } = await import("./adapter/output.ts");
|
|
899
|
+
return emitStopBlock(adapter, verdict);
|
|
902
900
|
}
|
|
903
901
|
}
|
|
904
902
|
|
|
905
903
|
// Phase 7: PreToolUse: heartbeat + pid-map self-heal on every tool call.
|
|
906
|
-
//
|
|
904
|
+
// Adapter-agnostic: both writes have the same shape regardless of who fired.
|
|
907
905
|
// Cursor/Codex bash dispatchers still fire their own G-guard logic, but the
|
|
908
906
|
// heals here keep the agent-coord layer's view of liveness fresh.
|
|
909
907
|
//
|
|
@@ -913,8 +911,8 @@ async function main(): Promise<number> {
|
|
|
913
911
|
// call was restored here afterward.
|
|
914
912
|
if (norm.event_type === "tool.pre_use") {
|
|
915
913
|
try {
|
|
916
|
-
healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId,
|
|
917
|
-
refreshPidmap(coordRoot, owner.instance_id,
|
|
914
|
+
healHeartbeatViaCli(coordRoot, owner.instance_id, sessionId, adapter);
|
|
915
|
+
refreshPidmap(coordRoot, owner.instance_id, adapter, payload?.pid);
|
|
918
916
|
} catch (err) {
|
|
919
917
|
logError(coordRoot, err, { phase: "pre-tool-use-heal" });
|
|
920
918
|
}
|
|
@@ -928,29 +926,29 @@ async function main(): Promise<number> {
|
|
|
928
926
|
payload,
|
|
929
927
|
instanceId: owner.instance_id,
|
|
930
928
|
sessionId,
|
|
931
|
-
|
|
929
|
+
adapter,
|
|
932
930
|
});
|
|
933
931
|
} catch (err) {
|
|
934
932
|
logError(coordRoot, err, { phase: "pre-tool-use-image-capture" });
|
|
935
933
|
}
|
|
936
934
|
|
|
937
|
-
// G-guard for ALL
|
|
935
|
+
// G-guard for ALL adapters. Claude Code previously ran this via a
|
|
938
936
|
// pre-tool-use bash adapter (which called `agent-coord verdict --rule=claim`);
|
|
939
|
-
// that adapter is now deleted, so agent-hook owns the deny for every
|
|
940
|
-
// emitDeny() inside emits the
|
|
937
|
+
// that adapter is now deleted, so agent-hook owns the deny for every adapter.
|
|
938
|
+
// emitDeny() inside emits the adapter-shaped permission JSON (claude-code +
|
|
941
939
|
// codex use hookSpecificOutput.permissionDecision; cursor uses .permission).
|
|
942
940
|
// apply_patch (codex) parses paths from the patch body and runs verdict
|
|
943
941
|
// per-path; Edit/Write/NotebookEdit resolve a single target. Non-write tools
|
|
944
942
|
// (incl. Agent) yield no targets and pass through with no deny.
|
|
945
943
|
try {
|
|
946
|
-
await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data,
|
|
944
|
+
await runPreToolUseGuard(coordRoot, owner.instance_id, sessionId, data, adapter);
|
|
947
945
|
} catch (err) {
|
|
948
946
|
logError(coordRoot, err, { phase: "pre-tool-use-guard" });
|
|
949
947
|
}
|
|
950
948
|
|
|
951
949
|
// Shell-mutation warn (warn-only, never blocks). Was the cursor
|
|
952
950
|
// beforeShellExecution + codex preToolUse-Bash shell-mutation-claim-log in
|
|
953
|
-
// the per-
|
|
951
|
+
// the per-adapter shell adapters. Cursor sends the command at payload.command;
|
|
954
952
|
// codex Bash at tool_input.command. Emits a decision.warn per candidate-mutated
|
|
955
953
|
// path so a peer sees the write in events.ndjson. (CC never did this,
|
|
956
954
|
// preserved; it emits with its own hooks-side emitter per the
|
|
@@ -958,7 +956,7 @@ async function main(): Promise<number> {
|
|
|
958
956
|
const shellCmd =
|
|
959
957
|
eventName === "before-shell-execution"
|
|
960
958
|
? ((payload?.raw.command as string | undefined) ?? "")
|
|
961
|
-
:
|
|
959
|
+
: adapter === "codex" && data.tool_name === "Bash"
|
|
962
960
|
? (((payload?.raw.tool_input as Record<string, unknown> | undefined)?.command as
|
|
963
961
|
| string
|
|
964
962
|
| undefined) ?? "")
|
|
@@ -967,13 +965,13 @@ async function main(): Promise<number> {
|
|
|
967
965
|
try {
|
|
968
966
|
const paths = shellMutationPaths(shellCmd, coordRoot);
|
|
969
967
|
const truncated = shellCmd.length > 80 ? shellCmd.slice(0, 80) : shellCmd;
|
|
970
|
-
const platform =
|
|
968
|
+
const platform = adapterPlatform(adapter);
|
|
971
969
|
for (const p of paths) {
|
|
972
970
|
emit(coordRoot, {
|
|
973
971
|
event_type: "decision.warn",
|
|
974
972
|
instance_id: owner.instance_id,
|
|
975
973
|
session_id: sessionId,
|
|
976
|
-
|
|
974
|
+
adapter,
|
|
977
975
|
data: {
|
|
978
976
|
rule: "shell_mutation_candidate",
|
|
979
977
|
reason: `path=${p} cmd=${truncated} platform=${platform}`,
|
|
@@ -988,7 +986,7 @@ async function main(): Promise<number> {
|
|
|
988
986
|
}
|
|
989
987
|
|
|
990
988
|
// Phase 7: PostToolUse: stamp last_tool + last_tool_target on heartbeat.
|
|
991
|
-
//
|
|
989
|
+
// Adapter-agnostic for the same reason as tool.pre_use above.
|
|
992
990
|
if (norm.event_type === "tool.post_use") {
|
|
993
991
|
try {
|
|
994
992
|
stampToolActivity(coordRoot, owner.instance_id, data);
|
|
@@ -1006,7 +1004,7 @@ async function main(): Promise<number> {
|
|
|
1006
1004
|
payload,
|
|
1007
1005
|
instanceId: owner.instance_id,
|
|
1008
1006
|
sessionId,
|
|
1009
|
-
|
|
1007
|
+
adapter,
|
|
1010
1008
|
});
|
|
1011
1009
|
} catch (err) {
|
|
1012
1010
|
logError(coordRoot, err, { phase: "post-tool-use-image-capture" });
|
|
@@ -1014,7 +1012,7 @@ async function main(): Promise<number> {
|
|
|
1014
1012
|
}
|
|
1015
1013
|
|
|
1016
1014
|
// Phase 7: PostToolUseFailure: release claim on failed Edit (the file
|
|
1017
|
-
// never landed; the claim is stale).
|
|
1015
|
+
// never landed; the claim is stale). Adapter-agnostic.
|
|
1018
1016
|
if (norm.event_type === "tool.post_use_failure") {
|
|
1019
1017
|
try {
|
|
1020
1018
|
releaseClaimOnFailure(coordRoot, owner.instance_id, data, payload?.raw);
|
|
@@ -1031,7 +1029,7 @@ async function runPreToolUseGuard(
|
|
|
1031
1029
|
instanceId: string,
|
|
1032
1030
|
sessionId: string,
|
|
1033
1031
|
data: Record<string, unknown>,
|
|
1034
|
-
|
|
1032
|
+
adapter: Adapter,
|
|
1035
1033
|
): Promise<void> {
|
|
1036
1034
|
const toolName = (data.tool_name as string | undefined) ?? "";
|
|
1037
1035
|
const targets = collectGuardTargets(toolName, data)
|
|
@@ -1075,8 +1073,8 @@ async function runPreToolUseGuard(
|
|
|
1075
1073
|
reason += ` The patch also touched: ${siblings}: pick a different file or wait.`;
|
|
1076
1074
|
}
|
|
1077
1075
|
}
|
|
1078
|
-
const { emitDeny } = await import("./
|
|
1079
|
-
emitDeny(
|
|
1076
|
+
const { emitDeny } = await import("./adapter/output.ts");
|
|
1077
|
+
emitDeny(adapter, reason);
|
|
1080
1078
|
return;
|
|
1081
1079
|
}
|
|
1082
1080
|
}
|
|
@@ -1142,15 +1140,15 @@ function healHeartbeatViaCli(
|
|
|
1142
1140
|
coordRoot: string,
|
|
1143
1141
|
instanceId: string,
|
|
1144
1142
|
sessionId: string,
|
|
1145
|
-
|
|
1143
|
+
adapter: string,
|
|
1146
1144
|
): void {
|
|
1147
1145
|
const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
|
|
1148
1146
|
if (!existsSync(agentCoordBin)) return;
|
|
1149
|
-
// Pass the detected
|
|
1147
|
+
// Pass the detected adapter so a pruned Cursor/Codex heartbeat is recreated
|
|
1150
1148
|
// with the correct platform; without it, healHeartbeat defaults to
|
|
1151
1149
|
// claude_code and the dashboard mislabels the agent. See
|
|
1152
1150
|
// heartbeat-writer.healHeartbeat.
|
|
1153
|
-
spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--
|
|
1151
|
+
spawnSync(agentCoordBin, ["heal-heartbeat", instanceId, sessionId, `--adapter=${adapter}`], {
|
|
1154
1152
|
encoding: "utf8",
|
|
1155
1153
|
timeout: 2000,
|
|
1156
1154
|
env: childEnv(coordRoot),
|
|
@@ -1158,38 +1156,59 @@ function healHeartbeatViaCli(
|
|
|
1158
1156
|
}
|
|
1159
1157
|
|
|
1160
1158
|
/**
|
|
1161
|
-
* Walk up the ppid chain on Linux/WSL looking for the
|
|
1159
|
+
* Walk up the ppid chain on Linux/WSL looking for the adapter anchor PID,
|
|
1162
1160
|
* the PID of the claude / cursor / codex binary. Finds the agent PID. Used by
|
|
1163
|
-
* `tool.pre_use`'s pid-map self-heal so a re-parented
|
|
1161
|
+
* `tool.pre_use`'s pid-map self-heal so a re-parented adapter binary (the
|
|
1164
1162
|
* VS Code 2.1.x sibling-claude spawn case) gets its pid-map row rewritten on
|
|
1165
1163
|
* the next tool call rather than going invisible until SessionStart fires
|
|
1166
1164
|
* again, which it may never do.
|
|
1167
1165
|
*
|
|
1168
1166
|
* Returns undefined only when no anchor is found; callers fall back to
|
|
1169
|
-
* `process.ppid` (the bash wrapper's parent, which is usually the
|
|
1167
|
+
* `process.ppid` (the bash wrapper's parent, which is usually the adapter binary
|
|
1170
1168
|
* itself). `HARNERY_AGENT_COORD_TEST_ANCHOR_PID` overrides everything so the
|
|
1171
1169
|
* test sandbox can pin a deterministic PID.
|
|
1172
1170
|
*/
|
|
1173
|
-
function
|
|
1171
|
+
function findAdapterAnchorPid(adapter?: Adapter): number | undefined {
|
|
1174
1172
|
const override = coordEnv("AGENT_COORD_TEST_ANCHOR_PID");
|
|
1175
1173
|
if (override) {
|
|
1176
1174
|
const n = Number(override);
|
|
1177
1175
|
if (Number.isFinite(n) && n > 0) return n;
|
|
1178
1176
|
}
|
|
1177
|
+
// A adapter that states its own pid ends the search. Nothing inferred from the
|
|
1178
|
+
// process tree beats the adapter naming itself, and the inference is the part
|
|
1179
|
+
// that has been failing: comm matching wants a binary called after its
|
|
1180
|
+
// adapter, and one Claude Code build ships its CLI under a version-numbered
|
|
1181
|
+
// filename, so the walk found nothing and the caller fell back to the hook's
|
|
1182
|
+
// own shell. That row was dead within seconds, leaving every session in this
|
|
1183
|
+
// environment unattributed.
|
|
1184
|
+
const fromEnv = adapterPidFromEnv();
|
|
1185
|
+
if (fromEnv) return fromEnv;
|
|
1179
1186
|
// Build the ppid chain (nearest → root, up to 20 hops), then hand it to the
|
|
1180
1187
|
// pure selector. Linux/WSL reads /proc; macOS/BSD (no /proc) falls back to
|
|
1181
1188
|
// `ps -o ppid=,comm=` parsed by the unit-tested `parsePsChainLine`. Splitting
|
|
1182
|
-
// the walk (untestable off a live box) from the
|
|
1183
|
-
//
|
|
1184
|
-
|
|
1189
|
+
// the walk (untestable off a live box) from the matching keeps the selector
|
|
1190
|
+
// logic verifiable.
|
|
1191
|
+
//
|
|
1192
|
+
// Only the /proc branch carries an executable path for the selector's
|
|
1193
|
+
// path-based pass. Asking `ps` for one means either a second spawn per hop or
|
|
1194
|
+
// splitting `comm` from `args` on a line where comm may itself contain spaces,
|
|
1195
|
+
// and the adapter that needs the path pass states its pid in the env anyway.
|
|
1196
|
+
const chain: Array<{ pid: number; comm: string; exe?: string }> = [];
|
|
1185
1197
|
let pid = process.pid;
|
|
1186
1198
|
for (let hops = 0; hops < 20; hops++) {
|
|
1187
|
-
let hop: { comm: string; ppid: number } | null = null;
|
|
1199
|
+
let hop: { comm: string; ppid: number; exe?: string } | null = null;
|
|
1188
1200
|
try {
|
|
1189
1201
|
const comm = readFileSync(`/proc/${pid}/comm`, "utf8").trim();
|
|
1190
1202
|
const status = readFileSync(`/proc/${pid}/status`, "utf8");
|
|
1191
1203
|
const m = status.match(/^PPid:\s+(\d+)/m);
|
|
1192
|
-
|
|
1204
|
+
// argv[0], for the path-based second pass. cmdline is NUL-separated.
|
|
1205
|
+
let exe: string | undefined;
|
|
1206
|
+
try {
|
|
1207
|
+
exe = readFileSync(`/proc/${pid}/cmdline`, "utf8").split("\0")[0] || undefined;
|
|
1208
|
+
} catch {
|
|
1209
|
+
/* exe is optional */
|
|
1210
|
+
}
|
|
1211
|
+
hop = { comm, ppid: m ? Number(m[1]) : 0, exe };
|
|
1193
1212
|
} catch {
|
|
1194
1213
|
// no /proc (macOS/BSD) — fall through to ps
|
|
1195
1214
|
}
|
|
@@ -1198,11 +1217,11 @@ function findHarnessAnchorPid(harness?: Harness): number | undefined {
|
|
|
1198
1217
|
if (out.status === 0) hop = parsePsChainLine(out.stdout);
|
|
1199
1218
|
}
|
|
1200
1219
|
if (!hop) break;
|
|
1201
|
-
chain.push({ pid, comm: hop.comm });
|
|
1220
|
+
chain.push({ pid, comm: hop.comm, exe: hop.exe });
|
|
1202
1221
|
if (!Number.isFinite(hop.ppid) || hop.ppid === 0 || hop.ppid === 1) break;
|
|
1203
1222
|
pid = hop.ppid;
|
|
1204
1223
|
}
|
|
1205
|
-
return selectAnchorPid(chain,
|
|
1224
|
+
return selectAnchorPid(chain, adapter);
|
|
1206
1225
|
}
|
|
1207
1226
|
|
|
1208
1227
|
/**
|
|
@@ -1212,7 +1231,7 @@ function findHarnessAnchorPid(harness?: Harness): number | undefined {
|
|
|
1212
1231
|
*
|
|
1213
1232
|
* The pid argument prefers the payload's `pid` (CC populates it on
|
|
1214
1233
|
* SessionStart and may also send it on PreToolUse), then
|
|
1215
|
-
* `
|
|
1234
|
+
* `findAdapterAnchorPid`, then `process.ppid`. Writes go through the same
|
|
1216
1235
|
* idempotent `writePidmapViaAgentCoord` helper that SessionStart uses: no
|
|
1217
1236
|
* disk I/O on no-op heals (when the row already points at us).
|
|
1218
1237
|
*
|
|
@@ -1223,12 +1242,12 @@ function findHarnessAnchorPid(harness?: Harness): number | undefined {
|
|
|
1223
1242
|
function refreshPidmap(
|
|
1224
1243
|
coordRoot: string,
|
|
1225
1244
|
instanceId: string,
|
|
1226
|
-
|
|
1245
|
+
adapter: Adapter,
|
|
1227
1246
|
payloadPid?: number,
|
|
1228
1247
|
): void {
|
|
1229
|
-
const pid = payloadPid ??
|
|
1248
|
+
const pid = payloadPid ?? findAdapterAnchorPid(adapter) ?? process.ppid;
|
|
1230
1249
|
if (!Number.isFinite(pid) || pid <= 0) return;
|
|
1231
|
-
writePidmapViaAgentCoord(coordRoot, pid, instanceId,
|
|
1250
|
+
writePidmapViaAgentCoord(coordRoot, pid, instanceId, adapterPlatform(adapter));
|
|
1232
1251
|
}
|
|
1233
1252
|
|
|
1234
1253
|
function stampToolActivity(
|
|
@@ -1363,7 +1382,7 @@ async function emitUserPromptSubmitSystemMessage(
|
|
|
1363
1382
|
coordRoot: string,
|
|
1364
1383
|
instanceId: string,
|
|
1365
1384
|
sessionId: string,
|
|
1366
|
-
|
|
1385
|
+
adapter: Adapter,
|
|
1367
1386
|
recoveryBriefing = "",
|
|
1368
1387
|
): Promise<boolean> {
|
|
1369
1388
|
const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
|
|
@@ -1385,10 +1404,14 @@ async function emitUserPromptSubmitSystemMessage(
|
|
|
1385
1404
|
|
|
1386
1405
|
const args = ["prompt-context", "--instance", instanceId, "--session", sessionId];
|
|
1387
1406
|
if (agentName) args.push("--name", agentName);
|
|
1388
|
-
//
|
|
1389
|
-
//
|
|
1390
|
-
//
|
|
1391
|
-
|
|
1407
|
+
// Every human-facing adapter gets the first-session naming reminder from
|
|
1408
|
+
// the shared hook path. Cursor + Codex additionally get ongoing set-task
|
|
1409
|
+
// staleness nudges; Claude Code enforces those via its Stop transcript.
|
|
1410
|
+
// Codex gets a fresh status-footer reminder on every prompt. Its Stop hook
|
|
1411
|
+
// stays observe-only, so missing the footer never replaces the answer.
|
|
1412
|
+
args.push("--session-name-nudge");
|
|
1413
|
+
if (adapter === "cursor" || adapter === "codex") args.push("--task-nudge");
|
|
1414
|
+
if (adapter === "codex") args.push("--status-footer-nudge");
|
|
1392
1415
|
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1393
1416
|
if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
|
|
1394
1417
|
}
|
|
@@ -1397,8 +1420,8 @@ async function emitUserPromptSubmitSystemMessage(
|
|
|
1397
1420
|
}
|
|
1398
1421
|
if (!additionalContext) return false;
|
|
1399
1422
|
|
|
1400
|
-
const { emitContext } = await import("./
|
|
1401
|
-
emitContext(
|
|
1423
|
+
const { emitContext } = await import("./adapter/output.ts");
|
|
1424
|
+
emitContext(adapter, "UserPromptSubmit", additionalContext);
|
|
1402
1425
|
return true;
|
|
1403
1426
|
}
|
|
1404
1427
|
|
|
@@ -1407,14 +1430,14 @@ function emitSubagentStartContext(
|
|
|
1407
1430
|
instanceId: string,
|
|
1408
1431
|
sessionId: string,
|
|
1409
1432
|
data: Record<string, unknown>,
|
|
1410
|
-
|
|
1433
|
+
adapter: Adapter,
|
|
1411
1434
|
): void {
|
|
1412
1435
|
// Look up the subagent's assigned name (just-written by agent-coord assignName
|
|
1413
1436
|
// in session.start data) + the parent's short id for the "you are a subagent
|
|
1414
1437
|
// of X" framing.
|
|
1415
1438
|
const subagentName = (data.name as string | undefined) ?? "";
|
|
1416
1439
|
if (!subagentName) return;
|
|
1417
|
-
const platformLabel =
|
|
1440
|
+
const platformLabel = adapterPlatform(adapter);
|
|
1418
1441
|
const parentShort =
|
|
1419
1442
|
sessionId && sessionId !== instanceId ? `agent-${sessionId.slice(0, 8)}` : "the parent session";
|
|
1420
1443
|
const message = `You are agent-${subagentName} (${platformLabel} subagent). You're a subagent of ${parentShort}.`;
|
|
@@ -1436,14 +1459,14 @@ function emitSubagentStartContext(
|
|
|
1436
1459
|
|
|
1437
1460
|
// Use SubagentStart event-name in CC's hookSpecificOutput shape; cursor's
|
|
1438
1461
|
// flat `additional_context` works the same way.
|
|
1439
|
-
void import("./
|
|
1440
|
-
emitContext(
|
|
1462
|
+
void import("./adapter/output.ts").then(({ emitContext }) => {
|
|
1463
|
+
emitContext(adapter, "SubagentStart", combined);
|
|
1441
1464
|
});
|
|
1442
1465
|
}
|
|
1443
1466
|
|
|
1444
|
-
function
|
|
1445
|
-
if (
|
|
1446
|
-
return
|
|
1467
|
+
function adapterPlatform(adapter: Adapter): string {
|
|
1468
|
+
if (adapter === "claude-code") return "claude_code";
|
|
1469
|
+
return adapter;
|
|
1447
1470
|
}
|
|
1448
1471
|
|
|
1449
1472
|
async function emitSessionStartSystemMessage(
|
|
@@ -1451,7 +1474,7 @@ async function emitSessionStartSystemMessage(
|
|
|
1451
1474
|
instanceId: string,
|
|
1452
1475
|
sessionId: string,
|
|
1453
1476
|
emittedData: Record<string, unknown>,
|
|
1454
|
-
|
|
1477
|
+
adapter: Adapter,
|
|
1455
1478
|
recoveryBriefing = "",
|
|
1456
1479
|
): Promise<boolean> {
|
|
1457
1480
|
const agentCoordBin = join(coordRoot, "harnery", "bin", "agent-coord");
|
|
@@ -1463,10 +1486,10 @@ async function emitSessionStartSystemMessage(
|
|
|
1463
1486
|
// Stale-sweep dead peers before rendering peer table.
|
|
1464
1487
|
spawnSync(agentCoordBin, ["stale-sweep"], { encoding: "utf8", timeout: 3000 });
|
|
1465
1488
|
|
|
1466
|
-
// SESSION_START activity log line, fired across all
|
|
1489
|
+
// SESSION_START activity log line, fired across all adapters.
|
|
1467
1490
|
const model = (emittedData.model as string | undefined) ?? "unknown";
|
|
1468
1491
|
const source = (emittedData.source as string | undefined) ?? "startup";
|
|
1469
|
-
const platform =
|
|
1492
|
+
const platform = adapterPlatform(adapter);
|
|
1470
1493
|
spawnSync(
|
|
1471
1494
|
agentCoordBin,
|
|
1472
1495
|
[
|
|
@@ -1485,19 +1508,19 @@ async function emitSessionStartSystemMessage(
|
|
|
1485
1508
|
// The "You are agent-X." prefix in session-context renders unqualified by
|
|
1486
1509
|
// default (claude-code-style). For cursor/codex the bash dispatchers add
|
|
1487
1510
|
// a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
|
|
1488
|
-
if (
|
|
1511
|
+
if (adapter !== "claude-code") {
|
|
1489
1512
|
args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
|
|
1490
1513
|
}
|
|
1491
1514
|
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1492
1515
|
if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
|
|
1493
1516
|
}
|
|
1494
1517
|
|
|
1495
|
-
// Effect (claude-code): merge the
|
|
1518
|
+
// Effect (claude-code): merge the journal recovery cue into the session-start
|
|
1496
1519
|
// context. Was a standalone additionalContext emission from the previous
|
|
1497
|
-
//
|
|
1520
|
+
// journal-on-start adapter; now that agent-hook is the single SessionStart
|
|
1498
1521
|
// entry, it folds in here.
|
|
1499
|
-
if (
|
|
1500
|
-
const cue =
|
|
1522
|
+
if (adapter === "claude-code") {
|
|
1523
|
+
const cue = journalRecoveryCue(coordRoot);
|
|
1501
1524
|
if (cue) additionalContext = [additionalContext, cue].filter(Boolean).join("\n\n");
|
|
1502
1525
|
}
|
|
1503
1526
|
if (recoveryBriefing) {
|
|
@@ -1505,8 +1528,8 @@ async function emitSessionStartSystemMessage(
|
|
|
1505
1528
|
}
|
|
1506
1529
|
if (!additionalContext) return false;
|
|
1507
1530
|
|
|
1508
|
-
const { emitContext } = await import("./
|
|
1509
|
-
emitContext(
|
|
1531
|
+
const { emitContext } = await import("./adapter/output.ts");
|
|
1532
|
+
emitContext(adapter, "SessionStart", additionalContext);
|
|
1510
1533
|
return true;
|
|
1511
1534
|
}
|
|
1512
1535
|
|
|
@@ -1514,7 +1537,7 @@ function completeRecoveryInjection(
|
|
|
1514
1537
|
coordRoot: string,
|
|
1515
1538
|
instanceId: string,
|
|
1516
1539
|
sessionId: string,
|
|
1517
|
-
|
|
1540
|
+
adapter: Adapter,
|
|
1518
1541
|
recovery: PreparedContextRecovery,
|
|
1519
1542
|
injectionEvent: "SessionStart" | "UserPromptSubmit",
|
|
1520
1543
|
): void {
|
|
@@ -1523,7 +1546,7 @@ function completeRecoveryInjection(
|
|
|
1523
1546
|
event_type: "context.recovery.injected",
|
|
1524
1547
|
instance_id: instanceId,
|
|
1525
1548
|
session_id: sessionId,
|
|
1526
|
-
|
|
1549
|
+
adapter,
|
|
1527
1550
|
data: {
|
|
1528
1551
|
capsule_id: recovery.capsule.capsule_id,
|
|
1529
1552
|
generation: recovery.capsule.generation,
|