harnery 0.29.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 +2 -1
- package/dist/commands/work.d.ts.map +1 -1
- package/dist/commands/work.js +55 -25
- 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 +28 -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 +71 -51
- package/dist/core/governor/plan-types.d.ts +181 -0
- 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 +143 -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 +290 -116
- 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/runner.d.ts.map +1 -1
- package/dist/core/work/runner.js +11 -2
- package/dist/core/work/state.d.ts +28 -3
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +148 -16
- 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 +151 -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 +3 -2
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -1
- package/dist/core/workflow/proof.d.ts +28 -5
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +77 -34
- 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 +28 -8
- 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 +26 -8
- 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 +27 -8
- package/dist/core/workflow/spawn-failure.d.ts +15 -1
- package/dist/core/workflow/spawn-failure.d.ts.map +1 -1
- package/dist/core/workflow/spawn-failure.js +35 -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 +119 -46
- 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/exec.d.ts +7 -0
- package/dist/lib/exec.d.ts.map +1 -1
- package/dist/lib/exec.js +6 -3
- 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 +72 -38
- 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 +28 -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 +120 -96
- package/src/core/{supervisor → governor}/plan-types.ts +64 -50
- package/src/core/{supervisor → governor}/planning.ts +240 -188
- 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 +389 -174
- 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/runner.ts +11 -2
- package/src/core/work/state.ts +185 -21
- 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 +166 -90
- package/src/core/workflow/evidence-preflight.ts +165 -0
- package/src/core/workflow/index.ts +6 -3
- package/src/core/workflow/proof.ts +94 -48
- 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 +34 -12
- package/src/core/workflow/spawn-codex.ts +30 -12
- package/src/core/workflow/spawn-cursor.ts +31 -12
- package/src/core/workflow/spawn-failure.ts +41 -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 +130 -46
- 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/exec.ts +13 -3
- 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 +0 -170
- 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/commands/browse.js
CHANGED
|
@@ -2,7 +2,7 @@ import { mkdirSync, statSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
4
4
|
import { resolveBinName } from "../core/config.js";
|
|
5
|
-
import { Browser, captureDevOverlay, wslHeadedLaunchArgs, } from "../lib/browser/index.js";
|
|
5
|
+
import { Browser, captureDevOverlay, DEFAULT_CRITIQUE_RUBRIC, parseAssertSpec, runCritique, tilesFromFullPage, wslHeadedLaunchArgs, } from "../lib/browser/index.js";
|
|
6
6
|
import { diffAgainstBaseline, saveBaseline, } from "../lib/browser/visual-diff.js";
|
|
7
7
|
import { CookieJar } from "../lib/cookies/index.js";
|
|
8
8
|
/**
|
|
@@ -125,6 +125,60 @@ export function registerBrowseCommand(program, emitParam, context) {
|
|
|
125
125
|
.option("--check-overlap-threshold <px>", "Allowed overlap depth on either axis in CSS pixels (default 0).", "0")
|
|
126
126
|
.option("--check-overlap-fail", "Exit 2 when an overlap target fails or is missing.")
|
|
127
127
|
.option("--no-check-overlap-annotate", "Skip overlap screenshot annotations.")
|
|
128
|
+
.option("--check-crowd <selector>", "Flag adjacent card panels (full border, modest corner radius, or box-shadow) " +
|
|
129
|
+
"that touch or nearly touch. Also treats wrappers that contain panels as " +
|
|
130
|
+
"peers, measuring the nearest face panels inside them so a card-grid " +
|
|
131
|
+
"flush against the next card is caught. Walks the whole subtree under the " +
|
|
132
|
+
"selector, so one --check-crowd .wrap catches nested cases. Fills the gap " +
|
|
133
|
+
"between --check-overlap (needs a 2D intersection) and --check-gap (flags " +
|
|
134
|
+
"uneven spacing, so a uniformly-flush stack passes). Repeatable.", (value, previous = []) => [...previous, value], [])
|
|
135
|
+
.option("--check-crowd-min <px>", "Minimum acceptable edge gap between adjacent panel faces in CSS px (default 6). " +
|
|
136
|
+
"Pairs closer than this are flagged; negative separation (overlap) always flags.", "6")
|
|
137
|
+
.option("--check-crowd-fail", "Exit 2 when a crowd target fails or is missing.")
|
|
138
|
+
.option("--no-check-crowd-annotate", "Skip crowd screenshot annotations.")
|
|
139
|
+
.option("--check-placeholder [selector]", "Scan rendered text for unrendered template tokens and bound-value tells: " +
|
|
140
|
+
"JS template literals, `{{x}}` handlebars, `[object Object]`, `Invalid Date`, " +
|
|
141
|
+
"`NaN`, or an element whose whole text is literally 'undefined' / 'null'. Optional selector " +
|
|
142
|
+
"scopes the sweep (default: whole body). Catches the most common generation " +
|
|
143
|
+
"bug on funnels and reports. Do not point it at a page that documents template " +
|
|
144
|
+
"syntax in prose.")
|
|
145
|
+
.option("--check-placeholder-fail", "Exit 2 if any placeholder tell is found.")
|
|
146
|
+
.option("--no-check-placeholder-annotate", "Skip placeholder screenshot annotations.")
|
|
147
|
+
.option("--check-images [selector]", "Audit <img> elements for load + aspect health: a failed load (naturalWidth 0), " +
|
|
148
|
+
"a still-loading image, or a stretched image (rendered aspect ratio far from the " +
|
|
149
|
+
"intrinsic one, with an object-fit that does not correct it). Optional selector " +
|
|
150
|
+
"scopes the sweep (default: whole body).")
|
|
151
|
+
.option("--check-images-tolerance <ratio>", "Aspect-ratio deviation above which an image counts as stretched (0–1, default 0.1 = 10%).", "0.1")
|
|
152
|
+
.option("--check-images-fail", "Exit 2 if any image failed to load or is stretched.")
|
|
153
|
+
.option("--no-check-images-annotate", "Skip image screenshot annotations.")
|
|
154
|
+
.option("--check-truncation [selector]", "Flag text actively cut off by an ellipsis or -webkit-line-clamp — the author asked " +
|
|
155
|
+
"to truncate AND the content overflows. High precision: it does not flag plain " +
|
|
156
|
+
"overflow:hidden clips. Optional selector scopes the sweep (default: whole body).")
|
|
157
|
+
.option("--check-truncation-tolerance <px>", "Overflow past the clip box, in CSS px, above which truncation counts (default 2).", "2")
|
|
158
|
+
.option("--check-truncation-fail", "Exit 2 if any text is actively truncated.")
|
|
159
|
+
.option("--no-check-truncation-annotate", "Skip truncation screenshot annotations.")
|
|
160
|
+
.option("--check-contrast [selector]", "Flag rendered text below the WCAG AA contrast ratio (4.5:1 normal, 3:1 large) against " +
|
|
161
|
+
"its effective background. Runs at whatever theme the page is in, so toggle the theme " +
|
|
162
|
+
"with --batch to cover light and dark. Text over an image or gradient is reported as " +
|
|
163
|
+
"`unknown`, not failed. Optional selector scopes the sweep (default: whole body).")
|
|
164
|
+
.option("--check-contrast-fail", "Exit 2 if any text fails the contrast ratio.")
|
|
165
|
+
.option("--no-check-contrast-annotate", "Skip contrast screenshot annotations.")
|
|
166
|
+
.option("--check-critique [selector]", "Hand the rendered page to a vision model for a visual-defect review, tile by " +
|
|
167
|
+
"tile. Catches the long tail heuristic checks can't enumerate. Default tiling " +
|
|
168
|
+
"cuts the page into overlapping vertical bands; pass a selector to tile one " +
|
|
169
|
+
"screenshot per matching element (semantic tiling). Requires the host to inject " +
|
|
170
|
+
"a critiqueProvider (harnery ships no model client) — without one the check " +
|
|
171
|
+
"reports `skipped`. Findings land under `critique` in the JSON envelope.")
|
|
172
|
+
.option("--check-critique-band <px>", "Band height for default tiling (default 1400).", "1400")
|
|
173
|
+
.option("--check-critique-overlap <px>", "Vertical overlap between bands so a finding at a seam stays visible (default 120).", "120")
|
|
174
|
+
.option("--check-critique-max-tiles <n>", "Cap on tiles sent to the model, to bound cost (default 24).", "24")
|
|
175
|
+
.option("--check-critique-rubric <text>", "Override the default critique rubric.")
|
|
176
|
+
.option("--check-critique-fail", "Exit 2 if the critique returns any high-severity finding.")
|
|
177
|
+
.option("--assert <expr>", "Assert a page value (repeatable). Grammar: '<op> <selector> => <expected>', where op is " +
|
|
178
|
+
"text (trimmed text equals), contains (text includes), matches (text matches a regex), " +
|
|
179
|
+
"count (match count vs a number or >=/<=/>/< comparator), exists / absent (no => needed). " +
|
|
180
|
+
"e.g. --assert 'text h1 => Welcome' --assert 'count .card => >=3' --assert 'absent .error'.", (value, previous = []) => [...previous, value], [])
|
|
181
|
+
.option("--assert-fail", "Exit 2 if any --assert fails.")
|
|
128
182
|
.option("--check-hit [selector]", "Check pointer-target size and spacing in the document or optional scope (repeatable).", (value, previous = []) => [
|
|
129
183
|
...previous,
|
|
130
184
|
typeof value === "string" ? value : null,
|
|
@@ -163,6 +217,7 @@ async function runBrowse(url, opts, context) {
|
|
|
163
217
|
: parseNonNegativeNumber(opts.checkGapExpected, "--check-gap-expected");
|
|
164
218
|
const clipThreshold = parseNonNegativeNumber(opts.checkClipThreshold ?? "0", "--check-clip-threshold");
|
|
165
219
|
const overlapThreshold = parseNonNegativeNumber(opts.checkOverlapThreshold ?? "0", "--check-overlap-threshold");
|
|
220
|
+
const crowdMin = parseNonNegativeNumber(opts.checkCrowdMin ?? "6", "--check-crowd-min");
|
|
166
221
|
const hitProfile = parseTargetSizeProfile(opts.checkHitProfile ?? "wcag-aa");
|
|
167
222
|
// Commander: `--no-cookies` turns `opts.cookies` into `false`. Default is `true`.
|
|
168
223
|
const jar = opts.cookies === false
|
|
@@ -238,7 +293,8 @@ async function runBrowse(url, opts, context) {
|
|
|
238
293
|
const hasLayoutLint = (opts.checkAlign?.length ?? 0) > 0 ||
|
|
239
294
|
(opts.checkGap?.length ?? 0) > 0 ||
|
|
240
295
|
(opts.checkClip?.length ?? 0) > 0 ||
|
|
241
|
-
(opts.checkOverlap?.length ?? 0) > 0
|
|
296
|
+
(opts.checkOverlap?.length ?? 0) > 0 ||
|
|
297
|
+
(opts.checkCrowd?.length ?? 0) > 0;
|
|
242
298
|
let layoutLint;
|
|
243
299
|
if (hasLayoutLint) {
|
|
244
300
|
layoutLint = await browser.checkLayoutLint({
|
|
@@ -261,12 +317,58 @@ async function runBrowse(url, opts, context) {
|
|
|
261
317
|
selector,
|
|
262
318
|
tolerancePx: overlapThreshold,
|
|
263
319
|
})),
|
|
320
|
+
crowd: (opts.checkCrowd ?? []).map((selector) => ({
|
|
321
|
+
selector,
|
|
322
|
+
minGapPx: crowdMin,
|
|
323
|
+
})),
|
|
264
324
|
});
|
|
265
325
|
}
|
|
266
326
|
let hit;
|
|
267
327
|
if (opts.checkHit && opts.checkHit.length > 0) {
|
|
268
328
|
hit = await browser.checkTargetSize(opts.checkHit, hitProfile);
|
|
269
329
|
}
|
|
330
|
+
const hasContentChecks = opts.checkPlaceholder !== undefined ||
|
|
331
|
+
opts.checkImages !== undefined ||
|
|
332
|
+
opts.checkTruncation !== undefined ||
|
|
333
|
+
opts.checkContrast !== undefined;
|
|
334
|
+
let content;
|
|
335
|
+
if (hasContentChecks) {
|
|
336
|
+
content = await browser.checkContent({
|
|
337
|
+
placeholder: opts.checkPlaceholder !== undefined
|
|
338
|
+
? { scope: contentScope(opts.checkPlaceholder) }
|
|
339
|
+
: null,
|
|
340
|
+
image: opts.checkImages !== undefined
|
|
341
|
+
? {
|
|
342
|
+
scope: contentScope(opts.checkImages),
|
|
343
|
+
tolerance: parseNonNegativeNumber(opts.checkImagesTolerance ?? "0.1", "--check-images-tolerance"),
|
|
344
|
+
}
|
|
345
|
+
: null,
|
|
346
|
+
truncation: opts.checkTruncation !== undefined
|
|
347
|
+
? {
|
|
348
|
+
scope: contentScope(opts.checkTruncation),
|
|
349
|
+
tolerance: parseNonNegativeNumber(opts.checkTruncationTolerance ?? "2", "--check-truncation-tolerance"),
|
|
350
|
+
}
|
|
351
|
+
: null,
|
|
352
|
+
contrast: opts.checkContrast !== undefined ? { scope: contentScope(opts.checkContrast) } : null,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
// Vision critique. Capture tiles BEFORE any annotation overlays are injected
|
|
356
|
+
// so the model sees the real page, not our boxes.
|
|
357
|
+
let critique;
|
|
358
|
+
if (opts.checkCritique !== undefined) {
|
|
359
|
+
const tiles = await captureCritiqueTiles(browser, opts);
|
|
360
|
+
critique = await runCritique({
|
|
361
|
+
url: navResult.url,
|
|
362
|
+
rubric: opts.checkCritiqueRubric ?? DEFAULT_CRITIQUE_RUBRIC,
|
|
363
|
+
tiles,
|
|
364
|
+
provider: context?.critiqueProvider,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
let asserts;
|
|
368
|
+
if (opts.assert && opts.assert.length > 0) {
|
|
369
|
+
const specs = opts.assert.map(parseAssertSpec);
|
|
370
|
+
asserts = await browser.checkAsserts(specs);
|
|
371
|
+
}
|
|
270
372
|
const widthThreshold = Number.parseFloat(opts.checkWidthThreshold ?? "0.9");
|
|
271
373
|
const annotateWidth = widths && opts.checkWidthAnnotate !== false;
|
|
272
374
|
const annotateOverflow = overflow && opts.checkOverflowAnnotate !== false;
|
|
@@ -287,19 +389,25 @@ async function runBrowse(url, opts, context) {
|
|
|
287
389
|
gap: opts.checkGapAnnotate === false ? [] : layoutLint.gap,
|
|
288
390
|
clip: opts.checkClipAnnotate === false ? [] : layoutLint.clip,
|
|
289
391
|
overlap: opts.checkOverlapAnnotate === false ? [] : layoutLint.overlap,
|
|
392
|
+
crowd: opts.checkCrowdAnnotate === false ? [] : layoutLint.crowd,
|
|
290
393
|
}
|
|
291
394
|
: undefined;
|
|
292
395
|
if (annotateLayoutLint &&
|
|
293
396
|
(annotateLayoutLint.align.length > 0 ||
|
|
294
397
|
annotateLayoutLint.gap.length > 0 ||
|
|
295
398
|
annotateLayoutLint.clip.length > 0 ||
|
|
296
|
-
annotateLayoutLint.overlap.length > 0
|
|
399
|
+
annotateLayoutLint.overlap.length > 0 ||
|
|
400
|
+
annotateLayoutLint.crowd.length > 0)) {
|
|
297
401
|
await browser.annotateLayoutLint(annotateLayoutLint);
|
|
298
402
|
}
|
|
299
403
|
const annotateHit = hit && opts.checkHitAnnotate !== false;
|
|
300
404
|
if (annotateHit) {
|
|
301
405
|
await browser.annotateTargetSize(hit);
|
|
302
406
|
}
|
|
407
|
+
const contentBoxes = content ? collectContentBoxes(content, opts) : [];
|
|
408
|
+
if (contentBoxes.length > 0) {
|
|
409
|
+
await browser.annotateContent(contentBoxes);
|
|
410
|
+
}
|
|
303
411
|
if (opts.login) {
|
|
304
412
|
await new Promise((res) => {
|
|
305
413
|
emit.log("[--login] Headed Chromium is open. Walk through your auth flow now. Press Enter here to close + persist cookies into the profile.", "info");
|
|
@@ -319,10 +427,10 @@ async function runBrowse(url, opts, context) {
|
|
|
319
427
|
if (opts.baseline || opts.diff) {
|
|
320
428
|
throw new Error("--baseline / --diff require trio mode (screenshot file). Remove --snapshot/--html/--json or capture the screenshot first.");
|
|
321
429
|
}
|
|
322
|
-
await runPrintMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, devOverlay, batchResult);
|
|
430
|
+
await runPrintMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, content, critique, asserts, devOverlay, batchResult);
|
|
323
431
|
}
|
|
324
432
|
else {
|
|
325
|
-
await runTrioMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, devOverlay, batchResult);
|
|
433
|
+
await runTrioMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, content, critique, asserts, devOverlay, batchResult);
|
|
326
434
|
}
|
|
327
435
|
if (visibility && opts.checkVisibleAnnotate !== false) {
|
|
328
436
|
await browser.clearVisibilityAnnotations();
|
|
@@ -339,6 +447,9 @@ async function runBrowse(url, opts, context) {
|
|
|
339
447
|
if (annotateHit) {
|
|
340
448
|
await browser.clearTargetSizeAnnotations();
|
|
341
449
|
}
|
|
450
|
+
if (contentBoxes.length > 0) {
|
|
451
|
+
await browser.clearContentAnnotations();
|
|
452
|
+
}
|
|
342
453
|
if (opts.checkVisibleFail && visibility) {
|
|
343
454
|
const threshold = Number.parseFloat(opts.checkVisibleThreshold ?? "0.9");
|
|
344
455
|
const failed = visibility.filter((r) => !r.found || !r.cssVisible || r.visibleRatio < threshold);
|
|
@@ -389,6 +500,20 @@ async function runBrowse(url, opts, context) {
|
|
|
389
500
|
process.exitCode = 2;
|
|
390
501
|
}
|
|
391
502
|
applyLayoutLintFailGates(opts, layoutLint, hit);
|
|
503
|
+
applyContentFailGates(opts, content);
|
|
504
|
+
if (opts.checkCritiqueFail && critique && critique.outcome === "fail") {
|
|
505
|
+
const high = critique.findings.filter((f) => f.severity === "high").length;
|
|
506
|
+
emit.log(`check-critique FAIL: ${high} high-severity finding(s)`, "warn");
|
|
507
|
+
process.exitCode = 2;
|
|
508
|
+
}
|
|
509
|
+
if (opts.assertFail && asserts) {
|
|
510
|
+
const failed = asserts.filter((a) => a.outcome === "fail");
|
|
511
|
+
for (const a of failed) {
|
|
512
|
+
emit.log(`assert FAIL: ${a.op} ${a.selector} → "${a.actual}"${a.error ? ` (${a.error})` : ""}`, "warn");
|
|
513
|
+
}
|
|
514
|
+
if (failed.length > 0)
|
|
515
|
+
process.exitCode = 2;
|
|
516
|
+
}
|
|
392
517
|
}
|
|
393
518
|
finally {
|
|
394
519
|
await browser.close();
|
|
@@ -488,7 +613,7 @@ function splitBatchSteps(input) {
|
|
|
488
613
|
// ---------------------------------------------------------------------------
|
|
489
614
|
// Print mode (--snapshot / --html / --json): stdout, no file writes
|
|
490
615
|
// ---------------------------------------------------------------------------
|
|
491
|
-
async function runPrintMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, devOverlay, batchResult) {
|
|
616
|
+
async function runPrintMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, content, critique, asserts, devOverlay, batchResult) {
|
|
492
617
|
let body = null;
|
|
493
618
|
if (opts.html) {
|
|
494
619
|
body = await browser.htmlContent(opts.selector);
|
|
@@ -522,9 +647,16 @@ async function runPrintMode(browser, navResult, opts, evalResult, visibility, wi
|
|
|
522
647
|
result.gap = layoutLint.gap;
|
|
523
648
|
result.clip = layoutLint.clip;
|
|
524
649
|
result.overlap = layoutLint.overlap;
|
|
650
|
+
result.crowd = layoutLint.crowd;
|
|
525
651
|
}
|
|
526
652
|
if (hit)
|
|
527
653
|
result.hit = hit;
|
|
654
|
+
if (content)
|
|
655
|
+
assignContent(result, content);
|
|
656
|
+
if (critique)
|
|
657
|
+
result.critique = critique;
|
|
658
|
+
if (asserts)
|
|
659
|
+
result.asserts = asserts;
|
|
528
660
|
if (devOverlay)
|
|
529
661
|
result.devOverlay = devOverlay;
|
|
530
662
|
if (batchResult && batchResult.clipboardReads.length > 0) {
|
|
@@ -548,7 +680,7 @@ async function runPrintMode(browser, navResult, opts, evalResult, visibility, wi
|
|
|
548
680
|
// ---------------------------------------------------------------------------
|
|
549
681
|
// Trio mode (default): write <prefix>.{png,html,json}
|
|
550
682
|
// ---------------------------------------------------------------------------
|
|
551
|
-
async function runTrioMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, devOverlay, batchResult) {
|
|
683
|
+
async function runTrioMode(browser, navResult, opts, evalResult, visibility, widths, overflow, runts, layoutLint, hit, content, critique, asserts, devOverlay, batchResult) {
|
|
552
684
|
const prefix = resolveOutPrefix(opts.out);
|
|
553
685
|
mkdirSync(dirname(prefix), { recursive: true });
|
|
554
686
|
const written = [];
|
|
@@ -618,9 +750,16 @@ async function runTrioMode(browser, navResult, opts, evalResult, visibility, wid
|
|
|
618
750
|
envelope.gap = layoutLint.gap;
|
|
619
751
|
envelope.clip = layoutLint.clip;
|
|
620
752
|
envelope.overlap = layoutLint.overlap;
|
|
753
|
+
envelope.crowd = layoutLint.crowd;
|
|
621
754
|
}
|
|
622
755
|
if (hit)
|
|
623
756
|
envelope.hit = hit;
|
|
757
|
+
if (content)
|
|
758
|
+
assignContent(envelope, content);
|
|
759
|
+
if (critique)
|
|
760
|
+
envelope.critique = critique;
|
|
761
|
+
if (asserts)
|
|
762
|
+
envelope.asserts = asserts;
|
|
624
763
|
if (devOverlay)
|
|
625
764
|
envelope.devOverlay = devOverlay;
|
|
626
765
|
if (batchResult && batchResult.clipboardReads.length > 0) {
|
|
@@ -719,6 +858,22 @@ async function runTrioMode(browser, navResult, opts, evalResult, visibility, wid
|
|
|
719
858
|
});
|
|
720
859
|
emit.log(`check-hit:\n${lines.join("\n")}`, "info");
|
|
721
860
|
}
|
|
861
|
+
if (content) {
|
|
862
|
+
logContentSummary(content);
|
|
863
|
+
}
|
|
864
|
+
if (critique) {
|
|
865
|
+
logCritiqueSummary(critique);
|
|
866
|
+
}
|
|
867
|
+
if (asserts && asserts.length > 0) {
|
|
868
|
+
const lines = asserts.map((a) => {
|
|
869
|
+
const detail = a.error ??
|
|
870
|
+
(a.op === "count" || a.op === "exists" || a.op === "absent"
|
|
871
|
+
? `${a.selector} → ${a.actual}${a.expected ? ` (want ${a.expected})` : ""}`
|
|
872
|
+
: `${a.selector} → "${a.actual.slice(0, 60)}"${a.expected ? ` (want ${a.op} "${a.expected}")` : ""}`);
|
|
873
|
+
return ` [${a.outcome.toUpperCase()}] ${a.op} ${detail}`;
|
|
874
|
+
});
|
|
875
|
+
emit.log(`asserts:\n${lines.join("\n")}`, "info");
|
|
876
|
+
}
|
|
722
877
|
if (savedBaseline) {
|
|
723
878
|
emit.log(`baseline saved: ${savedBaseline.name} → ${savedBaseline.path} (${savedBaseline.bytes} bytes)`, "info");
|
|
724
879
|
}
|
|
@@ -775,6 +930,12 @@ function logLayoutLintSummary(result) {
|
|
|
775
930
|
const worst = Math.max(0, ...check.issues.map((issue) => issue.areaPx));
|
|
776
931
|
lines.push(` [${check.outcome.toUpperCase()}] overlap ${check.selector}: ${check.issues.length} collisions, worst ${worst.toFixed(0)}px²`);
|
|
777
932
|
}
|
|
933
|
+
for (const check of result.crowd) {
|
|
934
|
+
const tightest = check.issues.length > 0
|
|
935
|
+
? Math.min(...check.issues.map((issue) => issue.separationPx))
|
|
936
|
+
: check.minGapPx;
|
|
937
|
+
lines.push(` [${check.outcome.toUpperCase()}] crowd ${check.selector}: ${check.issues.length} tight pair${check.issues.length === 1 ? "" : "s"} (min gap ${check.minGapPx}px, tightest ${tightest.toFixed(1)}px)`);
|
|
938
|
+
}
|
|
778
939
|
if (lines.length > 0)
|
|
779
940
|
emit.log(`layout-lint:\n${lines.join("\n")}`, "info");
|
|
780
941
|
}
|
|
@@ -793,6 +954,7 @@ function applyLayoutLintFailGates(opts, layoutLint, hit) {
|
|
|
793
954
|
gate(opts.checkGapFail, "gap", layoutLint?.gap);
|
|
794
955
|
gate(opts.checkClipFail, "clip", layoutLint?.clip);
|
|
795
956
|
gate(opts.checkOverlapFail, "overlap", layoutLint?.overlap);
|
|
957
|
+
gate(opts.checkCrowdFail, "crowd", layoutLint?.crowd);
|
|
796
958
|
if (opts.checkHitFail && hit) {
|
|
797
959
|
const failed = hit.filter((result) => !result.found || result.outcome === "fail" || result.outcome === "unknown");
|
|
798
960
|
for (const result of failed) {
|
|
@@ -802,6 +964,147 @@ function applyLayoutLintFailGates(opts, layoutLint, hit) {
|
|
|
802
964
|
process.exitCode = 2;
|
|
803
965
|
}
|
|
804
966
|
}
|
|
967
|
+
// ---------------------------------------------------------------------------
|
|
968
|
+
// Content checks (placeholder / image / truncation / contrast)
|
|
969
|
+
// ---------------------------------------------------------------------------
|
|
970
|
+
const CONTENT_COLORS = {
|
|
971
|
+
placeholder: "#dc2626",
|
|
972
|
+
image: "#f97316",
|
|
973
|
+
truncation: "#a855f7",
|
|
974
|
+
contrast: "#0891b2",
|
|
975
|
+
};
|
|
976
|
+
// Optional-selector flags resolve to a scope: a string selector, or null for
|
|
977
|
+
// the whole body when the flag was passed bare.
|
|
978
|
+
function contentScope(value) {
|
|
979
|
+
return typeof value === "string" ? value : null;
|
|
980
|
+
}
|
|
981
|
+
function assignContent(target, content) {
|
|
982
|
+
if (content.placeholder)
|
|
983
|
+
target.placeholder = content.placeholder;
|
|
984
|
+
if (content.image)
|
|
985
|
+
target.image = content.image;
|
|
986
|
+
if (content.truncation)
|
|
987
|
+
target.truncation = content.truncation;
|
|
988
|
+
if (content.contrast)
|
|
989
|
+
target.contrast = content.contrast;
|
|
990
|
+
}
|
|
991
|
+
function collectContentBoxes(content, opts) {
|
|
992
|
+
const boxes = [];
|
|
993
|
+
if (content.placeholder && opts.checkPlaceholderAnnotate !== false) {
|
|
994
|
+
for (const hit of content.placeholder.hits) {
|
|
995
|
+
boxes.push({
|
|
996
|
+
rect: hit.rect,
|
|
997
|
+
label: `placeholder ${hit.token}`,
|
|
998
|
+
color: CONTENT_COLORS.placeholder,
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (content.image && opts.checkImagesAnnotate !== false) {
|
|
1003
|
+
for (const issue of content.image.issues) {
|
|
1004
|
+
boxes.push({ rect: issue.rect, label: `image ${issue.reason}`, color: CONTENT_COLORS.image });
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
if (content.truncation && opts.checkTruncationAnnotate !== false) {
|
|
1008
|
+
for (const hit of content.truncation.hits) {
|
|
1009
|
+
boxes.push({
|
|
1010
|
+
rect: hit.rect,
|
|
1011
|
+
label: `truncated ${hit.how}`,
|
|
1012
|
+
color: CONTENT_COLORS.truncation,
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
if (content.contrast && opts.checkContrastAnnotate !== false) {
|
|
1017
|
+
for (const hit of content.contrast.hits) {
|
|
1018
|
+
if (hit.outcome !== "fail")
|
|
1019
|
+
continue;
|
|
1020
|
+
boxes.push({
|
|
1021
|
+
rect: hit.rect,
|
|
1022
|
+
label: `contrast ${hit.ratio}:1 < ${hit.required}`,
|
|
1023
|
+
color: CONTENT_COLORS.contrast,
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return boxes;
|
|
1028
|
+
}
|
|
1029
|
+
function logContentSummary(content) {
|
|
1030
|
+
const lines = [];
|
|
1031
|
+
if (content.placeholder) {
|
|
1032
|
+
const c = content.placeholder;
|
|
1033
|
+
lines.push(` [${c.outcome.toUpperCase()}] placeholder: ${c.hits.length} tell(s) in ${c.scanned} node(s)`);
|
|
1034
|
+
}
|
|
1035
|
+
if (content.image) {
|
|
1036
|
+
const c = content.image;
|
|
1037
|
+
const missing = c.issues.filter((i) => i.reason === "missing").length;
|
|
1038
|
+
const stretched = c.issues.filter((i) => i.reason === "stretched").length;
|
|
1039
|
+
lines.push(` [${c.outcome.toUpperCase()}] image: ${missing} missing, ${stretched} stretched of ${c.scanned}`);
|
|
1040
|
+
}
|
|
1041
|
+
if (content.truncation) {
|
|
1042
|
+
const c = content.truncation;
|
|
1043
|
+
lines.push(` [${c.outcome.toUpperCase()}] truncation: ${c.hits.length} clipped of ${c.scanned}`);
|
|
1044
|
+
}
|
|
1045
|
+
if (content.contrast) {
|
|
1046
|
+
const c = content.contrast;
|
|
1047
|
+
const fails = c.hits.filter((h) => h.outcome === "fail").length;
|
|
1048
|
+
const unknown = c.hits.filter((h) => h.outcome === "unknown").length;
|
|
1049
|
+
lines.push(` [${c.outcome.toUpperCase()}] contrast: ${fails} fail, ${unknown} unknown of ${c.scanned}`);
|
|
1050
|
+
}
|
|
1051
|
+
if (lines.length > 0)
|
|
1052
|
+
emit.log(`content-checks:\n${lines.join("\n")}`, "info");
|
|
1053
|
+
}
|
|
1054
|
+
function applyContentFailGates(opts, content) {
|
|
1055
|
+
if (!content)
|
|
1056
|
+
return;
|
|
1057
|
+
const gate = (enabled, rule, result) => {
|
|
1058
|
+
if (!enabled || !result)
|
|
1059
|
+
return;
|
|
1060
|
+
if (!result.found || result.outcome === "fail") {
|
|
1061
|
+
emit.log(`check-${rule} FAIL: ${result.found ? "issues found" : "scope not found"}`, "warn");
|
|
1062
|
+
process.exitCode = 2;
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
gate(opts.checkPlaceholderFail, "placeholder", content.placeholder);
|
|
1066
|
+
gate(opts.checkImagesFail, "images", content.image);
|
|
1067
|
+
gate(opts.checkTruncationFail, "truncation", content.truncation);
|
|
1068
|
+
gate(opts.checkContrastFail, "contrast", content.contrast);
|
|
1069
|
+
}
|
|
1070
|
+
// ---------------------------------------------------------------------------
|
|
1071
|
+
// Vision critique tiling
|
|
1072
|
+
// ---------------------------------------------------------------------------
|
|
1073
|
+
async function captureCritiqueTiles(browser, opts) {
|
|
1074
|
+
const maxTiles = Math.max(1, Number.parseInt(opts.checkCritiqueMaxTiles ?? "24", 10));
|
|
1075
|
+
const band = Math.max(200, Number.parseInt(opts.checkCritiqueBand ?? "1400", 10));
|
|
1076
|
+
const overlap = Math.max(0, Number.parseInt(opts.checkCritiqueOverlap ?? "120", 10));
|
|
1077
|
+
// Capture the whole page ONCE, then crop tiles from the pixels. Playwright's
|
|
1078
|
+
// clip is viewport-relative, so a below-fold band clip throws ("clipped area
|
|
1079
|
+
// outside the resulting image") — cropping the full-page image sidesteps that
|
|
1080
|
+
// and keeps every tile at full resolution.
|
|
1081
|
+
const buffer = await browser.fullPageScreenshotBuffer();
|
|
1082
|
+
const elementRects = typeof opts.checkCritique === "string"
|
|
1083
|
+
? await browser.elementTiles(opts.checkCritique)
|
|
1084
|
+
: undefined;
|
|
1085
|
+
const tiles = tilesFromFullPage(buffer, { elementRects, bandHeight: band, overlap, maxTiles });
|
|
1086
|
+
if (elementRects && elementRects.length > maxTiles) {
|
|
1087
|
+
emit.log(`check-critique: ${elementRects.length} elements matched, capped to ${maxTiles} tiles`, "warn");
|
|
1088
|
+
}
|
|
1089
|
+
else if (!elementRects && tiles.length >= maxTiles) {
|
|
1090
|
+
emit.log(`check-critique: page banded to the ${maxTiles}-tile cap (raise --check-critique-max-tiles for full coverage)`, "warn");
|
|
1091
|
+
}
|
|
1092
|
+
return tiles;
|
|
1093
|
+
}
|
|
1094
|
+
function logCritiqueSummary(critique) {
|
|
1095
|
+
if (critique.outcome === "skipped") {
|
|
1096
|
+
emit.log(`check-critique: SKIPPED (${critique.error ?? "no provider"})`, "warn");
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
const high = critique.findings.filter((f) => f.severity === "high").length;
|
|
1100
|
+
const med = critique.findings.filter((f) => f.severity === "medium").length;
|
|
1101
|
+
const low = critique.findings.filter((f) => f.severity === "low").length;
|
|
1102
|
+
const lines = critique.findings
|
|
1103
|
+
.slice(0, 20)
|
|
1104
|
+
.map((f) => ` [${f.severity}] tile ${f.tile} ${f.category}: ${f.description}`);
|
|
1105
|
+
emit.log(`check-critique [${critique.outcome.toUpperCase()}] ${critique.tiles} tiles → ${high} high / ${med} med / ${low} low` +
|
|
1106
|
+
(lines.length ? `\n${lines.join("\n")}` : ""), critique.outcome === "fail" ? "warn" : "info");
|
|
1107
|
+
}
|
|
805
1108
|
function summarizeDiagnostics(diag) {
|
|
806
1109
|
return {
|
|
807
1110
|
viewport: diag.viewport,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { EmitContext, HarneryProgramContext } from "../commander.js";
|
|
3
|
+
/**
|
|
4
|
+
* `harn checkpoint`: durable context continuity across compaction.
|
|
5
|
+
*
|
|
6
|
+
* A checkpoint captures enough of the current work that a fresh generation of
|
|
7
|
+
* the same session can resume it after the adapter compacts or restarts.
|
|
8
|
+
* `create` writes a capsule, `show` prints the latest one, `status` reports the
|
|
9
|
+
* phase, generation, and whatever context telemetry the adapter supplied.
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerCheckpointCommand(program: Command, emit: EmitContext, context?: HarneryProgramContext): void;
|
|
12
|
+
//# sourceMappingURL=checkpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/commands/checkpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAU1E;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CA2HN"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { monorepoRoot, readHeartbeat, resolveOwner } from "../core/agents/index.js";
|
|
2
|
+
import { checkpointContext, readContextState, readLatestCapsule, } from "../core/context/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* `harn checkpoint`: durable context continuity across compaction.
|
|
5
|
+
*
|
|
6
|
+
* A checkpoint captures enough of the current work that a fresh generation of
|
|
7
|
+
* the same session can resume it after the adapter compacts or restarts.
|
|
8
|
+
* `create` writes a capsule, `show` prints the latest one, `status` reports the
|
|
9
|
+
* phase, generation, and whatever context telemetry the adapter supplied.
|
|
10
|
+
*/
|
|
11
|
+
export function registerCheckpointCommand(program, emit, context) {
|
|
12
|
+
const command = program
|
|
13
|
+
.command("checkpoint")
|
|
14
|
+
.description("Durable context-continuity capsules: create one, show the latest, or report continuity phase.")
|
|
15
|
+
.option("--json", "Structured JSON output");
|
|
16
|
+
command
|
|
17
|
+
.command("status")
|
|
18
|
+
.description("Show context-continuity phase, generation, and latest telemetry")
|
|
19
|
+
.option("--session <id>", "Session id (defaults to the current agent heartbeat)")
|
|
20
|
+
.option("--instance <id>", "Agent instance id (defaults to the current owner)")
|
|
21
|
+
.option("--json", "Structured JSON output")
|
|
22
|
+
.action((opts) => {
|
|
23
|
+
try {
|
|
24
|
+
const json = opts.json || Boolean(command.opts().json);
|
|
25
|
+
const identity = resolveContinuityIdentity(context, opts);
|
|
26
|
+
const state = readContextState(identity.coordRoot, identity.sessionId);
|
|
27
|
+
if (json) {
|
|
28
|
+
emit.config({ format: "json" });
|
|
29
|
+
emit.data({ state, identity });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (!state) {
|
|
33
|
+
emit.text(`No context continuity state for session ${identity.sessionId}.\n`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const sample = state.latest_context;
|
|
37
|
+
const usage = sample
|
|
38
|
+
? `${sample.used_tokens ?? "?"}/${sample.window_tokens ?? "?"} tokens${sample.used_percent === undefined ? "" : ` (${sample.used_percent}%)`}`
|
|
39
|
+
: "not reported by adapter";
|
|
40
|
+
emit.text(`${[
|
|
41
|
+
`Session: ${state.session_id}`,
|
|
42
|
+
`Phase: ${state.phase}`,
|
|
43
|
+
`Generation: ${state.generation}`,
|
|
44
|
+
`Telemetry: ${usage}`,
|
|
45
|
+
`Capsule: ${state.latest_capsule ?? "none"}`,
|
|
46
|
+
state.degraded_reason ? `Degraded: ${state.degraded_reason}` : "",
|
|
47
|
+
]
|
|
48
|
+
.filter(Boolean)
|
|
49
|
+
.join("\n")}\n`);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
emitCommandError(emit, "checkpoint_status_failed", err);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
command
|
|
56
|
+
.command("create")
|
|
57
|
+
.description("Create a durable context-continuity capsule for the current work")
|
|
58
|
+
.option("--session <id>", "Session id (defaults to the current agent heartbeat)")
|
|
59
|
+
.option("--instance <id>", "Agent instance id (defaults to the current owner)")
|
|
60
|
+
.option("--adapter <id>", "claude-code, codex, or cursor (inferred from heartbeat)")
|
|
61
|
+
.option("--reason <reason>", "manual, pressure, pre_compact, or session_end", "manual")
|
|
62
|
+
.option("--note <text>", "Short continuation note for the recovered agent")
|
|
63
|
+
.option("--json", "Structured JSON output")
|
|
64
|
+
.action((opts) => {
|
|
65
|
+
try {
|
|
66
|
+
const json = opts.json || Boolean(command.opts().json);
|
|
67
|
+
const reason = parseCheckpointReason(opts.reason);
|
|
68
|
+
const identity = resolveContinuityIdentity(context, opts);
|
|
69
|
+
if (!identity.adapter) {
|
|
70
|
+
throw new Error("could not infer the adapter; pass --adapter claude-code|codex|cursor");
|
|
71
|
+
}
|
|
72
|
+
const result = checkpointContext(identity.coordRoot, {
|
|
73
|
+
sessionId: identity.sessionId,
|
|
74
|
+
instanceId: identity.instanceId,
|
|
75
|
+
adapter: identity.adapter,
|
|
76
|
+
cwd: context?.repoRoot ?? process.cwd(),
|
|
77
|
+
reason,
|
|
78
|
+
continuationNote: opts.note,
|
|
79
|
+
});
|
|
80
|
+
const output = {
|
|
81
|
+
capsule_id: result.capsule.capsule_id,
|
|
82
|
+
generation: result.capsule.generation,
|
|
83
|
+
path: result.state.latest_capsule,
|
|
84
|
+
phase: result.state.phase,
|
|
85
|
+
reused: result.reused,
|
|
86
|
+
};
|
|
87
|
+
if (json) {
|
|
88
|
+
emit.config({ format: "json" });
|
|
89
|
+
emit.data(output);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
emit.text(`Checkpointed context generation ${output.generation}: ${output.path ?? result.path}\n`);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
emitCommandError(emit, "checkpoint_create_failed", err);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
command
|
|
99
|
+
.command("show")
|
|
100
|
+
.description("Show the latest durable context-continuity capsule")
|
|
101
|
+
.option("--session <id>", "Session id (defaults to the current agent heartbeat)")
|
|
102
|
+
.option("--instance <id>", "Agent instance id (defaults to the current owner)")
|
|
103
|
+
.option("--json", "Structured JSON output")
|
|
104
|
+
.action((opts) => {
|
|
105
|
+
try {
|
|
106
|
+
const json = opts.json || Boolean(command.opts().json);
|
|
107
|
+
const identity = resolveContinuityIdentity(context, opts);
|
|
108
|
+
const capsule = readLatestCapsule(identity.coordRoot, identity.sessionId);
|
|
109
|
+
if (!capsule) {
|
|
110
|
+
throw new Error(`no context capsule exists for session ${identity.sessionId}`);
|
|
111
|
+
}
|
|
112
|
+
if (json)
|
|
113
|
+
emit.config({ format: "json" });
|
|
114
|
+
emit.data(capsule);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
emitCommandError(emit, "checkpoint_show_failed", err);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function resolveContinuityIdentity(context, opts) {
|
|
122
|
+
const coordRoot = context?.resolveCoordRoot?.() ?? context?.repoRoot ?? monorepoRoot();
|
|
123
|
+
if (!coordRoot)
|
|
124
|
+
throw new Error("could not resolve a project containing .harnery/");
|
|
125
|
+
const instanceId = opts.instance ?? resolveOwner();
|
|
126
|
+
if (!instanceId) {
|
|
127
|
+
throw new Error("could not resolve the current agent; pass --instance and --session");
|
|
128
|
+
}
|
|
129
|
+
const heartbeat = readHeartbeat(instanceId);
|
|
130
|
+
const sessionId = opts.session ?? heartbeat?.session_id ?? instanceId;
|
|
131
|
+
const adapter = opts.adapter
|
|
132
|
+
? parseAdapter(opts.adapter)
|
|
133
|
+
: adapterFromPlatform(heartbeat?.platform);
|
|
134
|
+
return { coordRoot, instanceId, sessionId, adapter };
|
|
135
|
+
}
|
|
136
|
+
function adapterFromPlatform(platform) {
|
|
137
|
+
if (platform === "claude_code" || platform === "claude-code")
|
|
138
|
+
return "claude-code";
|
|
139
|
+
if (platform === "cursor")
|
|
140
|
+
return "cursor";
|
|
141
|
+
if (platform === "codex")
|
|
142
|
+
return "codex";
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
function parseAdapter(value) {
|
|
146
|
+
if (value === "claude-code" || value === "codex" || value === "cursor")
|
|
147
|
+
return value;
|
|
148
|
+
throw new Error(`invalid adapter "${value}"; expected claude-code, codex, or cursor`);
|
|
149
|
+
}
|
|
150
|
+
function parseCheckpointReason(value) {
|
|
151
|
+
if (value === "manual" ||
|
|
152
|
+
value === "pressure" ||
|
|
153
|
+
value === "pre_compact" ||
|
|
154
|
+
value === "session_end") {
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
throw new Error(`invalid reason "${value}"; expected manual, pressure, pre_compact, or session_end`);
|
|
158
|
+
}
|
|
159
|
+
function emitCommandError(emit, code, err) {
|
|
160
|
+
emit.error({ code, message: err instanceof Error ? err.message : String(err) });
|
|
161
|
+
emit.setExitCode(1);
|
|
162
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import type { EmitContext, HarneryProgramContext } from "../commander.js";
|
|
3
3
|
/**
|
|
4
|
-
* `harn context`: one-shot orientation snapshot.
|
|
4
|
+
* `harn agents context`: one-shot orientation snapshot.
|
|
5
5
|
*
|
|
6
6
|
* Aggregates self / time / repo / commits / submodules / peers (default) plus
|
|
7
7
|
* opt-in services. Useful at session start, post-compaction, or before
|
|
8
8
|
* dispatching subagents. Fail-open per section.
|
|
9
9
|
*/
|
|
10
|
-
export declare function registerContextCommand(
|
|
10
|
+
export declare function registerContextCommand(parent: Command, emit: EmitContext, context?: HarneryProgramContext): void;
|
|
11
11
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAS1E;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAiDN"}
|