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