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
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository-local working artifacts.
|
|
3
|
+
*
|
|
4
|
+
* Artifacts are file trees that should survive an agent session but should not
|
|
5
|
+
* become project records: screenshots, exports, audit dumps, rollback inputs,
|
|
6
|
+
* and similar material. Each direct child of `.harnery/artifacts/` is one
|
|
7
|
+
* managed unit with a small manifest. Cleanup fails closed: only a valid,
|
|
8
|
+
* expired, inactive, untracked managed unit is deletable.
|
|
9
|
+
*/
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
12
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
13
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
14
|
+
import { artifactDefaultRetentionDays } from "../config.js";
|
|
15
|
+
export const ARTIFACTS_DIR = join(".harnery", "artifacts");
|
|
16
|
+
export const ARTIFACT_MANIFEST = ".harnery-artifact.json";
|
|
17
|
+
export const ARTIFACT_SCHEMA_VERSION = 1;
|
|
18
|
+
export function artifactsRoot(repoRoot) {
|
|
19
|
+
return join(resolve(repoRoot), ARTIFACTS_DIR);
|
|
20
|
+
}
|
|
21
|
+
/** Public config-aware default for embedding hosts that create artifact units. */
|
|
22
|
+
export function configuredArtifactRetentionDays(repoRoot) {
|
|
23
|
+
return artifactDefaultRetentionDays(repoRoot);
|
|
24
|
+
}
|
|
25
|
+
export function createArtifact(repoRoot, input) {
|
|
26
|
+
const now = input.now ?? new Date();
|
|
27
|
+
assertValidDate(now, "now");
|
|
28
|
+
const slug = normalizeSlug(input.slug);
|
|
29
|
+
if (!slug)
|
|
30
|
+
throw new Error("slug must contain at least one ASCII letter or digit");
|
|
31
|
+
const purpose = input.purpose.trim();
|
|
32
|
+
if (!purpose)
|
|
33
|
+
throw new Error("purpose must not be empty");
|
|
34
|
+
const retentionDays = positiveDays(input.retentionDays);
|
|
35
|
+
const artifactId = input.id ?? randomUUID();
|
|
36
|
+
if (!isSafeId(artifactId)) {
|
|
37
|
+
throw new Error("artifact id must use ASCII letters, digits, hyphens, or underscores");
|
|
38
|
+
}
|
|
39
|
+
const root = artifactsRoot(repoRoot);
|
|
40
|
+
mkdirSync(root, { recursive: true });
|
|
41
|
+
const date = now.toISOString().slice(0, 10);
|
|
42
|
+
const path = join(root, `${date}_${slug}_${artifactId.slice(0, 8)}`);
|
|
43
|
+
mkdirSync(path);
|
|
44
|
+
const manifest = {
|
|
45
|
+
schema_version: ARTIFACT_SCHEMA_VERSION,
|
|
46
|
+
artifact_id: artifactId,
|
|
47
|
+
slug,
|
|
48
|
+
purpose,
|
|
49
|
+
created_at: now.toISOString(),
|
|
50
|
+
created_by: input.actor,
|
|
51
|
+
retention: {
|
|
52
|
+
expires_at: addDays(now, retentionDays).toISOString(),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
atomicWriteManifest(path, manifest);
|
|
56
|
+
return { path, manifest };
|
|
57
|
+
}
|
|
58
|
+
export function inventoryArtifacts(repoRoot, opts = {}) {
|
|
59
|
+
const root = artifactsRoot(repoRoot);
|
|
60
|
+
if (!existsSync(root))
|
|
61
|
+
return [];
|
|
62
|
+
const now = opts.now ?? new Date();
|
|
63
|
+
assertValidDate(now, "now");
|
|
64
|
+
const freshnessSeconds = opts.freshnessSeconds ?? 600;
|
|
65
|
+
const rows = [];
|
|
66
|
+
let names;
|
|
67
|
+
try {
|
|
68
|
+
names = readdirSync(root).sort();
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return [
|
|
72
|
+
rowFor(root, basename(root), repoRoot, "unknown", errorMessage("cannot read artifact root", error)),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
for (const name of names) {
|
|
76
|
+
rows.push(classifyArtifactPath(repoRoot, join(root, name), now, freshnessSeconds));
|
|
77
|
+
}
|
|
78
|
+
return rows;
|
|
79
|
+
}
|
|
80
|
+
export function showArtifact(repoRoot, ref, opts = {}) {
|
|
81
|
+
const path = resolveArtifactRef(repoRoot, ref);
|
|
82
|
+
const entry = classifyArtifactPath(repoRoot, path, opts.now ?? new Date(), opts.freshnessSeconds ?? 600);
|
|
83
|
+
const parsed = readManifest(path);
|
|
84
|
+
if (!parsed.ok)
|
|
85
|
+
throw new Error(parsed.reason);
|
|
86
|
+
return { entry, manifest: parsed.manifest };
|
|
87
|
+
}
|
|
88
|
+
export function renewArtifact(repoRoot, ref, days, reason, input = {}) {
|
|
89
|
+
const now = input.now ?? new Date();
|
|
90
|
+
assertValidDate(now, "now");
|
|
91
|
+
const retentionDays = positiveDays(days);
|
|
92
|
+
const why = reason.trim();
|
|
93
|
+
if (!why)
|
|
94
|
+
throw new Error("renewal reason must not be empty");
|
|
95
|
+
const path = resolveArtifactRef(repoRoot, ref);
|
|
96
|
+
const parsed = readManifest(path);
|
|
97
|
+
if (!parsed.ok)
|
|
98
|
+
throw new Error(parsed.reason);
|
|
99
|
+
const manifest = {
|
|
100
|
+
...parsed.manifest,
|
|
101
|
+
retention: {
|
|
102
|
+
expires_at: addDays(now, retentionDays).toISOString(),
|
|
103
|
+
renewed_at: now.toISOString(),
|
|
104
|
+
reason: why,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
atomicWriteManifest(path, manifest);
|
|
108
|
+
return manifest;
|
|
109
|
+
}
|
|
110
|
+
export function releaseArtifact(repoRoot, ref, input = {}) {
|
|
111
|
+
const now = input.now ?? new Date();
|
|
112
|
+
assertValidDate(now, "now");
|
|
113
|
+
const path = resolveArtifactRef(repoRoot, ref);
|
|
114
|
+
const parsed = readManifest(path);
|
|
115
|
+
if (!parsed.ok)
|
|
116
|
+
throw new Error(parsed.reason);
|
|
117
|
+
const manifest = {
|
|
118
|
+
...parsed.manifest,
|
|
119
|
+
released_at: now.toISOString(),
|
|
120
|
+
released_by: input.actor,
|
|
121
|
+
};
|
|
122
|
+
atomicWriteManifest(path, manifest);
|
|
123
|
+
return manifest;
|
|
124
|
+
}
|
|
125
|
+
export function cleanArtifacts(repoRoot, opts = {}) {
|
|
126
|
+
const now = opts.now ?? new Date();
|
|
127
|
+
const freshnessSeconds = opts.freshnessSeconds ?? 600;
|
|
128
|
+
const rows = inventoryArtifacts(repoRoot, { now, freshnessSeconds });
|
|
129
|
+
if (!opts.yes)
|
|
130
|
+
return rows;
|
|
131
|
+
return rows.map((entry) => {
|
|
132
|
+
if (entry.classification !== "managed-expired")
|
|
133
|
+
return entry;
|
|
134
|
+
// Reclassify immediately before removal. A renewal, release-state change,
|
|
135
|
+
// heartbeat, symlink swap, or tracked file added since inventory must win.
|
|
136
|
+
const current = classifyArtifactPath(repoRoot, entry.path, now, freshnessSeconds);
|
|
137
|
+
if (current.classification !== "managed-expired")
|
|
138
|
+
return current;
|
|
139
|
+
try {
|
|
140
|
+
const top = lstatSync(current.path);
|
|
141
|
+
if (!top.isDirectory() || top.isSymbolicLink()) {
|
|
142
|
+
return {
|
|
143
|
+
...current,
|
|
144
|
+
classification: "unknown",
|
|
145
|
+
reason: "entry changed before deletion",
|
|
146
|
+
action: "keep",
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
rmSync(current.path, { recursive: true, force: false });
|
|
150
|
+
return { ...current, action: "deleted" };
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return {
|
|
154
|
+
...current,
|
|
155
|
+
classification: "unknown",
|
|
156
|
+
reason: errorMessage("entry changed or could not be deleted", error),
|
|
157
|
+
action: "keep",
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
export function resolveArtifactRef(repoRoot, ref) {
|
|
163
|
+
const root = artifactsRoot(repoRoot);
|
|
164
|
+
const candidate = isAbsolute(ref) ? resolve(ref) : resolve(root, ref);
|
|
165
|
+
if (candidate === root || !candidate.startsWith(`${root}${sep}`) || dirname(candidate) !== root) {
|
|
166
|
+
// A bare artifact id is the only non-path lookup. It must match exactly,
|
|
167
|
+
// never by prefix, so two UUIDs cannot make a command ambiguous.
|
|
168
|
+
const matches = inventoryArtifacts(repoRoot)
|
|
169
|
+
.filter((entry) => entry.artifact_id === ref)
|
|
170
|
+
.map((entry) => entry.path);
|
|
171
|
+
if (matches.length === 1)
|
|
172
|
+
return matches[0];
|
|
173
|
+
throw new Error(`artifact "${ref}" was not found`);
|
|
174
|
+
}
|
|
175
|
+
if (!existsSync(candidate)) {
|
|
176
|
+
const matches = inventoryArtifacts(repoRoot)
|
|
177
|
+
.filter((entry) => entry.artifact_id === ref)
|
|
178
|
+
.map((entry) => entry.path);
|
|
179
|
+
if (matches.length === 1)
|
|
180
|
+
return matches[0];
|
|
181
|
+
throw new Error(`artifact "${ref}" was not found`);
|
|
182
|
+
}
|
|
183
|
+
return candidate;
|
|
184
|
+
}
|
|
185
|
+
function classifyArtifactPath(repoRoot, path, now, freshnessSeconds) {
|
|
186
|
+
const name = basename(path);
|
|
187
|
+
let st;
|
|
188
|
+
try {
|
|
189
|
+
st = lstatSync(path);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
return rowFor(path, name, repoRoot, "unknown", errorMessage("cannot inspect entry", error));
|
|
193
|
+
}
|
|
194
|
+
if (st.isSymbolicLink()) {
|
|
195
|
+
return rowFor(path, name, repoRoot, "symlink", "symlinks are never traversed or deleted");
|
|
196
|
+
}
|
|
197
|
+
if (!st.isDirectory()) {
|
|
198
|
+
return rowFor(path, name, repoRoot, "unmanaged", "workspace entries must be directories");
|
|
199
|
+
}
|
|
200
|
+
const parsed = readManifest(path);
|
|
201
|
+
if (!parsed.ok) {
|
|
202
|
+
const classification = existsSync(join(path, ARTIFACT_MANIFEST))
|
|
203
|
+
? "invalid-manifest"
|
|
204
|
+
: "unmanaged";
|
|
205
|
+
return rowFor(path, name, repoRoot, classification, parsed.reason);
|
|
206
|
+
}
|
|
207
|
+
const manifest = parsed.manifest;
|
|
208
|
+
const bytes = safeTreeSize(path);
|
|
209
|
+
const base = rowFor(path, name, repoRoot, "managed-current", "retention has not expired", bytes);
|
|
210
|
+
Object.assign(base, {
|
|
211
|
+
artifact_id: manifest.artifact_id,
|
|
212
|
+
slug: manifest.slug,
|
|
213
|
+
created_at: manifest.created_at,
|
|
214
|
+
expires_at: manifest.retention.expires_at,
|
|
215
|
+
owner_instance_id: manifest.created_by?.instance_id ?? null,
|
|
216
|
+
});
|
|
217
|
+
if (base.bytes === null) {
|
|
218
|
+
return {
|
|
219
|
+
...base,
|
|
220
|
+
classification: "unknown",
|
|
221
|
+
reason: "one or more artifact paths are unreadable",
|
|
222
|
+
action: "keep",
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (containsTrackedPath(repoRoot, path)) {
|
|
226
|
+
return {
|
|
227
|
+
...base,
|
|
228
|
+
classification: "managed-tracked",
|
|
229
|
+
reason: "Git tracks one or more paths inside this artifact",
|
|
230
|
+
action: "keep",
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
if (!manifest.released_at && manifest.created_by?.instance_id) {
|
|
234
|
+
const live = ownerLiveness(repoRoot, manifest.created_by.instance_id, now, freshnessSeconds);
|
|
235
|
+
if (live === "live") {
|
|
236
|
+
return {
|
|
237
|
+
...base,
|
|
238
|
+
classification: "managed-active",
|
|
239
|
+
reason: `owner ${manifest.created_by.instance_id} has a fresh heartbeat`,
|
|
240
|
+
action: "keep",
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
if (live === "unknown") {
|
|
244
|
+
return {
|
|
245
|
+
...base,
|
|
246
|
+
classification: "unknown",
|
|
247
|
+
reason: `owner ${manifest.created_by.instance_id} heartbeat is unreadable`,
|
|
248
|
+
action: "keep",
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (Date.parse(manifest.retention.expires_at) > now.getTime())
|
|
253
|
+
return base;
|
|
254
|
+
return {
|
|
255
|
+
...base,
|
|
256
|
+
classification: "managed-expired",
|
|
257
|
+
reason: `retention expired at ${manifest.retention.expires_at}`,
|
|
258
|
+
action: "would-delete",
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function readManifest(path) {
|
|
262
|
+
const manifestPath = join(path, ARTIFACT_MANIFEST);
|
|
263
|
+
if (!existsSync(manifestPath)) {
|
|
264
|
+
return { ok: false, reason: `missing ${ARTIFACT_MANIFEST}` };
|
|
265
|
+
}
|
|
266
|
+
let value;
|
|
267
|
+
try {
|
|
268
|
+
value = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
return { ok: false, reason: errorMessage("manifest is unreadable", error) };
|
|
272
|
+
}
|
|
273
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
274
|
+
return { ok: false, reason: "manifest must be a JSON object" };
|
|
275
|
+
}
|
|
276
|
+
const m = value;
|
|
277
|
+
if (m.schema_version !== ARTIFACT_SCHEMA_VERSION) {
|
|
278
|
+
return { ok: false, reason: `unsupported schema_version ${String(m.schema_version)}` };
|
|
279
|
+
}
|
|
280
|
+
if (!isSafeId(m.artifact_id))
|
|
281
|
+
return { ok: false, reason: "invalid artifact_id" };
|
|
282
|
+
if (typeof m.slug !== "string" || !m.slug || normalizeSlug(m.slug) !== m.slug) {
|
|
283
|
+
return { ok: false, reason: "invalid slug" };
|
|
284
|
+
}
|
|
285
|
+
if (typeof m.purpose !== "string" || !m.purpose.trim()) {
|
|
286
|
+
return { ok: false, reason: "invalid purpose" };
|
|
287
|
+
}
|
|
288
|
+
if (!validIso(m.created_at))
|
|
289
|
+
return { ok: false, reason: "invalid created_at" };
|
|
290
|
+
if (!m.retention || typeof m.retention !== "object" || !validIso(m.retention.expires_at)) {
|
|
291
|
+
return { ok: false, reason: "invalid retention.expires_at" };
|
|
292
|
+
}
|
|
293
|
+
if (m.released_at !== undefined && !validIso(m.released_at)) {
|
|
294
|
+
return { ok: false, reason: "invalid released_at" };
|
|
295
|
+
}
|
|
296
|
+
if (m.created_by !== undefined && !validActor(m.created_by)) {
|
|
297
|
+
return { ok: false, reason: "invalid created_by" };
|
|
298
|
+
}
|
|
299
|
+
if (m.released_by !== undefined && !validActor(m.released_by)) {
|
|
300
|
+
return { ok: false, reason: "invalid released_by" };
|
|
301
|
+
}
|
|
302
|
+
return { ok: true, manifest: m };
|
|
303
|
+
}
|
|
304
|
+
function atomicWriteManifest(path, manifest) {
|
|
305
|
+
const target = join(path, ARTIFACT_MANIFEST);
|
|
306
|
+
const tmp = `${target}.tmp.${process.pid}.${randomUUID().slice(0, 8)}`;
|
|
307
|
+
writeFileSync(tmp, `${JSON.stringify(manifest, null, 2)}\n`, {
|
|
308
|
+
encoding: "utf8",
|
|
309
|
+
mode: 0o600,
|
|
310
|
+
});
|
|
311
|
+
renameSync(tmp, target);
|
|
312
|
+
}
|
|
313
|
+
function ownerLiveness(repoRoot, instanceId, now, freshnessSeconds) {
|
|
314
|
+
const path = join(repoRoot, ".harnery", "active", `${instanceId}.json`);
|
|
315
|
+
if (!existsSync(path))
|
|
316
|
+
return "stale";
|
|
317
|
+
try {
|
|
318
|
+
const hb = JSON.parse(readFileSync(path, "utf8"));
|
|
319
|
+
if (typeof hb.last_heartbeat !== "string")
|
|
320
|
+
return "unknown";
|
|
321
|
+
const ts = Date.parse(hb.last_heartbeat);
|
|
322
|
+
if (!Number.isFinite(ts))
|
|
323
|
+
return "unknown";
|
|
324
|
+
return now.getTime() - ts <= freshnessSeconds * 1000 ? "live" : "stale";
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
return "unknown";
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function containsTrackedPath(repoRoot, path) {
|
|
331
|
+
const rel = relative(repoRoot, path);
|
|
332
|
+
if (rel.startsWith("..") || isAbsolute(rel))
|
|
333
|
+
return true;
|
|
334
|
+
const result = spawnSync("git", ["ls-files", "-z", "--", rel], {
|
|
335
|
+
cwd: repoRoot,
|
|
336
|
+
encoding: "utf8",
|
|
337
|
+
});
|
|
338
|
+
// If Git itself cannot answer, fail closed.
|
|
339
|
+
return result.status !== 0 || result.stdout.length > 0;
|
|
340
|
+
}
|
|
341
|
+
function safeTreeSize(path) {
|
|
342
|
+
try {
|
|
343
|
+
const st = lstatSync(path);
|
|
344
|
+
if (st.isSymbolicLink())
|
|
345
|
+
return st.size;
|
|
346
|
+
if (st.isFile())
|
|
347
|
+
return st.size;
|
|
348
|
+
if (!st.isDirectory())
|
|
349
|
+
return 0;
|
|
350
|
+
let total = st.size;
|
|
351
|
+
for (const child of readdirSync(path)) {
|
|
352
|
+
const size = safeTreeSize(join(path, child));
|
|
353
|
+
if (size === null)
|
|
354
|
+
return null;
|
|
355
|
+
total += size;
|
|
356
|
+
}
|
|
357
|
+
return total;
|
|
358
|
+
}
|
|
359
|
+
catch {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function rowFor(path, name, repoRoot, classification, reason, bytes = safeTreeSize(path)) {
|
|
364
|
+
return {
|
|
365
|
+
name,
|
|
366
|
+
path,
|
|
367
|
+
relative_path: relative(repoRoot, path),
|
|
368
|
+
classification,
|
|
369
|
+
reason,
|
|
370
|
+
action: classification === "managed-expired" ? "would-delete" : "keep",
|
|
371
|
+
bytes,
|
|
372
|
+
artifact_id: null,
|
|
373
|
+
slug: null,
|
|
374
|
+
created_at: null,
|
|
375
|
+
expires_at: null,
|
|
376
|
+
owner_instance_id: null,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function normalizeSlug(value) {
|
|
380
|
+
// Collapsing every non-alphanumeric run to a single "-" leaves no two
|
|
381
|
+
// adjacent dashes, so trimming the edges needs fixed-length patterns rather
|
|
382
|
+
// than "-+", whose backtracking is polynomial on a long run of dashes.
|
|
383
|
+
const collapsed = value
|
|
384
|
+
.trim()
|
|
385
|
+
.toLowerCase()
|
|
386
|
+
.replace(/[^a-z0-9]+/g, "-");
|
|
387
|
+
return collapsed.replace(/^-/, "").replace(/-$/, "").slice(0, 64);
|
|
388
|
+
}
|
|
389
|
+
function positiveDays(value) {
|
|
390
|
+
if (!Number.isInteger(value) || value <= 0 || value > 3650) {
|
|
391
|
+
throw new Error("retention days must be between 1 and 3650");
|
|
392
|
+
}
|
|
393
|
+
return value;
|
|
394
|
+
}
|
|
395
|
+
function addDays(date, days) {
|
|
396
|
+
return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
397
|
+
}
|
|
398
|
+
function isSafeId(value) {
|
|
399
|
+
return (typeof value === "string" &&
|
|
400
|
+
value.length >= 8 &&
|
|
401
|
+
value.length <= 128 &&
|
|
402
|
+
/^[A-Za-z0-9_-]+$/.test(value));
|
|
403
|
+
}
|
|
404
|
+
function validActor(value) {
|
|
405
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
406
|
+
return false;
|
|
407
|
+
const actor = value;
|
|
408
|
+
return (isSafeId(actor.instance_id) &&
|
|
409
|
+
(actor.session_id === undefined || isSafeId(actor.session_id)) &&
|
|
410
|
+
(actor.name === undefined || (typeof actor.name === "string" && actor.name.length <= 128)));
|
|
411
|
+
}
|
|
412
|
+
function validIso(value) {
|
|
413
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
414
|
+
}
|
|
415
|
+
function assertValidDate(value, label) {
|
|
416
|
+
if (!Number.isFinite(value.getTime()))
|
|
417
|
+
throw new Error(`${label} must be a valid date`);
|
|
418
|
+
}
|
|
419
|
+
function errorMessage(prefix, error) {
|
|
420
|
+
return `${prefix}: ${error instanceof Error ? error.message : String(error)}`;
|
|
421
|
+
}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Fields owned here: `binName` (host CLI name for agent-facing strings),
|
|
10
10
|
* `hooksSetupHint`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
11
|
-
* `coord` (heartbeat freshness), `
|
|
12
|
-
*
|
|
11
|
+
* `coord` (heartbeat freshness), `artifacts` (working-file retention),
|
|
12
|
+
* `backup` (restic repo/password/prune policy), and `sync` (rclone
|
|
13
|
+
* remote/prefix) sections. The `files` deny/override section
|
|
13
14
|
* is parsed separately by `web/lib/files.ts`.
|
|
14
15
|
*
|
|
15
16
|
* Env vars and CLI flags override any config value per invocation (each accessor
|
|
@@ -91,6 +92,12 @@ export declare function presenceRelayUrl(coordRoot?: string | null): string | nu
|
|
|
91
92
|
* `coordRoot` is resolved via `findCoordRoot()` when not passed.
|
|
92
93
|
*/
|
|
93
94
|
export declare function coordFreshnessSeconds(coordRoot?: string | null): number;
|
|
95
|
+
/**
|
|
96
|
+
* Default retention for a newly-created working artifact. Precedence:
|
|
97
|
+
* `HARNERY_ARTIFACT_RETENTION_DAYS` -> project/user config
|
|
98
|
+
* `artifacts.default_retention_days` -> 3 days.
|
|
99
|
+
*/
|
|
100
|
+
export declare function artifactDefaultRetentionDays(coordRoot?: string | null): number;
|
|
94
101
|
/** Resolved `harn backup` defaults (restic repo/password + prune policy). */
|
|
95
102
|
export interface BackupConfig {
|
|
96
103
|
repo: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAsE1C,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAqCvD;AAwFD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAShE;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAK9E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAOrE;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAO3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAOlE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAWzE;AAQD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CASvE;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAe9E;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CAmBpE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS3C"}
|
package/dist/core/config.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Fields owned here: `binName` (host CLI name for agent-facing strings),
|
|
10
10
|
* `hooksSetupHint`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
11
|
-
* `coord` (heartbeat freshness), `
|
|
12
|
-
*
|
|
11
|
+
* `coord` (heartbeat freshness), `artifacts` (working-file retention),
|
|
12
|
+
* `backup` (restic repo/password/prune policy), and `sync` (rclone
|
|
13
|
+
* remote/prefix) sections. The `files` deny/override section
|
|
13
14
|
* is parsed separately by `web/lib/files.ts`.
|
|
14
15
|
*
|
|
15
16
|
* Env vars and CLI flags override any config value per invocation (each accessor
|
|
@@ -294,6 +295,29 @@ export function coordFreshnessSeconds(coordRoot) {
|
|
|
294
295
|
return posIntOr(readConfig(root).coord?.freshness_seconds, DEFAULT_FRESHNESS_SECS);
|
|
295
296
|
return DEFAULT_FRESHNESS_SECS;
|
|
296
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* Default retention for a newly-created working artifact. Precedence:
|
|
300
|
+
* `HARNERY_ARTIFACT_RETENTION_DAYS` -> project/user config
|
|
301
|
+
* `artifacts.default_retention_days` -> 3 days.
|
|
302
|
+
*/
|
|
303
|
+
export function artifactDefaultRetentionDays(coordRoot) {
|
|
304
|
+
const env = coordEnv("ARTIFACT_RETENTION_DAYS");
|
|
305
|
+
if (env !== undefined) {
|
|
306
|
+
const n = Number(env);
|
|
307
|
+
if (Number.isFinite(n) && n > 0 && n <= 3650)
|
|
308
|
+
return n;
|
|
309
|
+
}
|
|
310
|
+
const root = coordRoot ?? findCoordRoot();
|
|
311
|
+
if (!root)
|
|
312
|
+
return 3;
|
|
313
|
+
const configured = readConfig(root).artifacts?.default_retention_days;
|
|
314
|
+
return typeof configured === "number" &&
|
|
315
|
+
Number.isFinite(configured) &&
|
|
316
|
+
configured > 0 &&
|
|
317
|
+
configured <= 3650
|
|
318
|
+
? configured
|
|
319
|
+
: 3;
|
|
320
|
+
}
|
|
297
321
|
/**
|
|
298
322
|
* `harn backup` (restic) defaults. Per field, precedence is env → config → built-in:
|
|
299
323
|
* repo: `HARNERY_RESTIC_REPO` → `backup.repo` → `~/.cache/harnery/restic-repo`
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Context continuity: durable, structured state around native
|
|
3
|
-
* compaction. Harnery does not decide when a
|
|
4
|
-
* context telemetry when the
|
|
2
|
+
* Context continuity: durable, structured state around native adapter
|
|
3
|
+
* compaction. Harnery does not decide when a adapter compacts. It records
|
|
4
|
+
* context telemetry when the adapter exposes it, checkpoints external work
|
|
5
5
|
* state before compaction, and renders a verified recovery briefing after it.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { Adapter } from "../hooks/events/schema.js";
|
|
8
8
|
export declare const CONTEXT_SCHEMA_VERSION: 1;
|
|
9
9
|
export declare const MAX_CAPSULE_BYTES: number;
|
|
10
10
|
export type ContextSampleSource = "hook" | "native_event" | "result" | "transcript" | "estimate";
|
|
@@ -13,7 +13,7 @@ export type ContextPhase = "observing" | "checkpointed" | "recovered" | "degrade
|
|
|
13
13
|
export type CheckpointReason = "manual" | "pressure" | "pre_compact" | "session_end";
|
|
14
14
|
export interface ContextSample {
|
|
15
15
|
session_id: string;
|
|
16
|
-
|
|
16
|
+
adapter: Adapter;
|
|
17
17
|
model?: string;
|
|
18
18
|
used_tokens?: number;
|
|
19
19
|
window_tokens?: number;
|
|
@@ -52,7 +52,7 @@ export interface ContinuityCapsule {
|
|
|
52
52
|
session: {
|
|
53
53
|
session_id: string;
|
|
54
54
|
instance_id: string;
|
|
55
|
-
|
|
55
|
+
adapter: Adapter;
|
|
56
56
|
model?: string;
|
|
57
57
|
};
|
|
58
58
|
context?: ContextSample;
|
|
@@ -69,7 +69,7 @@ export interface ContinuityCapsule {
|
|
|
69
69
|
}
|
|
70
70
|
export interface ExtractContextSampleOptions {
|
|
71
71
|
sessionId: string;
|
|
72
|
-
|
|
72
|
+
adapter: Adapter;
|
|
73
73
|
model?: string;
|
|
74
74
|
source?: ContextSampleSource;
|
|
75
75
|
confidence?: ContextSampleConfidence;
|
|
@@ -78,7 +78,7 @@ export interface ExtractContextSampleOptions {
|
|
|
78
78
|
export interface CheckpointContextInput {
|
|
79
79
|
sessionId: string;
|
|
80
80
|
instanceId: string;
|
|
81
|
-
|
|
81
|
+
adapter: Adapter;
|
|
82
82
|
cwd: string;
|
|
83
83
|
reason: CheckpointReason;
|
|
84
84
|
model?: string;
|
|
@@ -101,7 +101,7 @@ export interface PreparedContextRecovery {
|
|
|
101
101
|
capsule: ContinuityCapsule;
|
|
102
102
|
briefing: string;
|
|
103
103
|
}
|
|
104
|
-
/** Parse the context-window shapes exposed by current
|
|
104
|
+
/** Parse the context-window shapes exposed by current adapter hook/status data. */
|
|
105
105
|
export declare function extractContextSample(payload: Record<string, unknown>, options: ExtractContextSampleOptions): ContextSample | null;
|
|
106
106
|
/** Persist a latest context sample. Identical measurements are a no-op. */
|
|
107
107
|
export declare function recordContextSample(coordRoot: string, instanceId: string, sample: ContextSample): {
|
|
@@ -114,18 +114,18 @@ export declare function recordContextSample(coordRoot: string, instanceId: strin
|
|
|
114
114
|
* create a new generation.
|
|
115
115
|
*/
|
|
116
116
|
export declare function checkpointContext(coordRoot: string, input: CheckpointContextInput): CheckpointContextResult;
|
|
117
|
-
/** Prepare a briefing without claiming that a
|
|
117
|
+
/** Prepare a briefing without claiming that a adapter has accepted it yet. */
|
|
118
118
|
export declare function prepareContextRecovery(coordRoot: string, input: {
|
|
119
119
|
sessionId: string;
|
|
120
120
|
instanceId: string;
|
|
121
121
|
cwd: string;
|
|
122
122
|
}): PreparedContextRecovery | null;
|
|
123
|
-
/** Advance continuity only after the
|
|
123
|
+
/** Advance continuity only after the adapter context channel accepted the briefing. */
|
|
124
124
|
export declare function completeContextRecovery(coordRoot: string, input: {
|
|
125
125
|
sessionId: string;
|
|
126
126
|
instanceId: string;
|
|
127
127
|
}): ContextContinuityState;
|
|
128
|
-
/** Record that the
|
|
128
|
+
/** Record that the adapter, rather than Harnery, reported compaction complete. */
|
|
129
129
|
export declare function markContextCompactionCompleted(coordRoot: string, input: {
|
|
130
130
|
sessionId: string;
|
|
131
131
|
instanceId: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Context continuity: durable, structured state around native
|
|
3
|
-
* compaction. Harnery does not decide when a
|
|
4
|
-
* context telemetry when the
|
|
2
|
+
* Context continuity: durable, structured state around native adapter
|
|
3
|
+
* compaction. Harnery does not decide when a adapter compacts. It records
|
|
4
|
+
* context telemetry when the adapter exposes it, checkpoints external work
|
|
5
5
|
* state before compaction, and renders a verified recovery briefing after it.
|
|
6
6
|
*/
|
|
7
7
|
import { spawnSync } from "node:child_process";
|
|
@@ -12,7 +12,7 @@ export const CONTEXT_SCHEMA_VERSION = 1;
|
|
|
12
12
|
export const MAX_CAPSULE_BYTES = 32 * 1024;
|
|
13
13
|
const MAX_SNAPSHOT_PATHS = 15;
|
|
14
14
|
const MAX_SNAPSHOT_PATH_CHARS = 500;
|
|
15
|
-
/** Parse the context-window shapes exposed by current
|
|
15
|
+
/** Parse the context-window shapes exposed by current adapter hook/status data. */
|
|
16
16
|
export function extractContextSample(payload, options) {
|
|
17
17
|
const contextValue = payload.context_window;
|
|
18
18
|
const context = record(contextValue);
|
|
@@ -48,7 +48,7 @@ export function extractContextSample(payload, options) {
|
|
|
48
48
|
string(record(payload.model)?.display_name);
|
|
49
49
|
return {
|
|
50
50
|
session_id: options.sessionId,
|
|
51
|
-
|
|
51
|
+
adapter: options.adapter,
|
|
52
52
|
model,
|
|
53
53
|
used_tokens: usedTokens,
|
|
54
54
|
window_tokens: windowTokens,
|
|
@@ -105,7 +105,7 @@ export function checkpointContext(coordRoot, input) {
|
|
|
105
105
|
session: {
|
|
106
106
|
session_id: input.sessionId,
|
|
107
107
|
instance_id: input.instanceId,
|
|
108
|
-
|
|
108
|
+
adapter: input.adapter,
|
|
109
109
|
model: input.model ?? current.latest_context?.model ?? heartbeat?.model,
|
|
110
110
|
},
|
|
111
111
|
context: current.latest_context,
|
|
@@ -129,7 +129,7 @@ export function checkpointContext(coordRoot, input) {
|
|
|
129
129
|
writeState(coordRoot, next);
|
|
130
130
|
return { capsule, path: absolutePath, state: next, reused: false };
|
|
131
131
|
}
|
|
132
|
-
/** Prepare a briefing without claiming that a
|
|
132
|
+
/** Prepare a briefing without claiming that a adapter has accepted it yet. */
|
|
133
133
|
export function prepareContextRecovery(coordRoot, input) {
|
|
134
134
|
const now = new Date().toISOString();
|
|
135
135
|
const current = readContextState(coordRoot, input.sessionId) ??
|
|
@@ -150,7 +150,7 @@ export function prepareContextRecovery(coordRoot, input) {
|
|
|
150
150
|
const briefing = renderRecoveryBriefing(capsule, liveRepo);
|
|
151
151
|
return { state: current, capsule, briefing };
|
|
152
152
|
}
|
|
153
|
-
/** Advance continuity only after the
|
|
153
|
+
/** Advance continuity only after the adapter context channel accepted the briefing. */
|
|
154
154
|
export function completeContextRecovery(coordRoot, input) {
|
|
155
155
|
const now = new Date().toISOString();
|
|
156
156
|
const current = readContextState(coordRoot, input.sessionId) ??
|
|
@@ -166,7 +166,7 @@ export function completeContextRecovery(coordRoot, input) {
|
|
|
166
166
|
writeState(coordRoot, recovered);
|
|
167
167
|
return recovered;
|
|
168
168
|
}
|
|
169
|
-
/** Record that the
|
|
169
|
+
/** Record that the adapter, rather than Harnery, reported compaction complete. */
|
|
170
170
|
export function markContextCompactionCompleted(coordRoot, input) {
|
|
171
171
|
const now = input.observedAt ?? new Date().toISOString();
|
|
172
172
|
const current = readContextState(coordRoot, input.sessionId) ??
|
|
@@ -344,7 +344,7 @@ function git(cwd, args) {
|
|
|
344
344
|
function sameMeasurement(a, b) {
|
|
345
345
|
if (!a)
|
|
346
346
|
return false;
|
|
347
|
-
return (a.
|
|
347
|
+
return (a.adapter === b.adapter &&
|
|
348
348
|
a.model === b.model &&
|
|
349
349
|
a.used_tokens === b.used_tokens &&
|
|
350
350
|
a.window_tokens === b.window_tokens &&
|