harnery 0.34.1 → 0.36.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/dist/commander.d.ts +30 -5
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +124 -94
- package/dist/commands/agents.d.ts +37 -6
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +466 -371
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +10 -10
- package/dist/commands/browse-session.d.ts.map +1 -1
- package/dist/commands/browse-session.js +12 -0
- package/dist/commands/browse.d.ts +1 -1
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +31 -6
- package/dist/commands/conversations.d.ts +10 -0
- package/dist/commands/conversations.d.ts.map +1 -0
- package/dist/commands/conversations.js +201 -0
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +2 -2
- package/dist/commands/deinit.d.ts.map +1 -1
- package/dist/commands/deinit.js +5 -0
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +13 -2
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +51 -7
- package/dist/commands/events.d.ts.map +1 -1
- package/dist/commands/events.js +18 -1
- package/dist/commands/fetch.js +6 -5
- package/dist/commands/files.d.ts +22 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/files.js +113 -0
- package/dist/commands/governor.js +14 -12
- package/dist/commands/inbox.d.ts +5 -0
- package/dist/commands/inbox.d.ts.map +1 -0
- package/dist/commands/inbox.js +57 -0
- package/dist/commands/init.d.ts +4 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +63 -13
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +347 -1
- package/dist/commands/logs.d.ts +4 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +169 -0
- package/dist/commands/messages.d.ts +5 -0
- package/dist/commands/messages.d.ts.map +1 -0
- package/dist/commands/messages.js +45 -0
- package/dist/commands/outline.d.ts +1 -1
- package/dist/commands/outline.d.ts.map +1 -1
- package/dist/commands/outline.js +2 -2
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +2 -2
- package/dist/commands/read.d.ts +1 -1
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +2 -2
- package/dist/commands/semantic.d.ts +4 -0
- package/dist/commands/semantic.d.ts.map +1 -0
- package/dist/commands/semantic.js +199 -0
- package/dist/commands/storage.d.ts +4 -0
- package/dist/commands/storage.d.ts.map +1 -0
- package/dist/commands/storage.js +238 -0
- package/dist/commands/tunnel.d.ts +5 -1
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +44 -31
- package/dist/commands/web.d.ts +3 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +84 -7
- package/dist/commands/work.js +3 -3
- package/dist/commands/workflow.js +13 -13
- package/dist/core/adapters/profiles.d.ts +1 -1
- package/dist/core/agents/canonical-emit.d.ts +3 -0
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +12 -0
- package/dist/core/agents/claim-path.d.ts +11 -0
- package/dist/core/agents/claim-path.d.ts.map +1 -0
- package/dist/core/agents/claim-path.js +22 -0
- package/dist/core/agents/cli.js +209 -39
- package/dist/core/agents/coord-client.d.ts +29 -3
- package/dist/core/agents/coord-client.d.ts.map +1 -1
- package/dist/core/agents/coord-client.js +88 -9
- package/dist/core/agents/live-authority-v3.d.ts +47 -1
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +245 -13
- package/dist/core/agents/live-lifecycle-v3.js +9 -4
- package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
- package/dist/core/agents/live-observation-v3.js +8 -3
- package/dist/core/agents/render/prompt-context.d.ts +9 -3
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +36 -17
- package/dist/core/agents/rules/stop-hook.d.ts +2 -0
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +115 -22
- package/dist/core/agents/rules/verdict.d.ts +1 -0
- package/dist/core/agents/rules/verdict.d.ts.map +1 -1
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +4 -0
- package/dist/core/agents/session-finalization-state-v3.js +1 -1
- package/dist/core/agents/session-finalizer-v3.js +5 -1
- package/dist/core/agents/session-name-display.d.ts +1 -0
- package/dist/core/agents/session-name-display.d.ts.map +1 -1
- package/dist/core/agents/session-name-display.js +8 -1
- package/dist/core/agents/state/activity-log.d.ts +3 -0
- package/dist/core/agents/state/activity-log.d.ts.map +1 -1
- package/dist/core/agents/state/activity-log.js +6 -3
- package/dist/core/agents/state/heartbeat-reader.d.ts +46 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
- package/dist/core/agents/state/heartbeat-reader.js +25 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts +9 -48
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +34 -34
- package/dist/core/agents/state/live-coordination-view.d.ts +6 -8
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +16 -67
- package/dist/core/agents/state/live-coordination-writer.d.ts +12 -0
- package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -0
- package/dist/core/agents/state/live-coordination-writer.js +92 -0
- package/dist/core/agents/state/names.d.ts +9 -1
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +190 -182
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +23 -5
- package/dist/core/artifacts/constants.d.ts +5 -0
- package/dist/core/artifacts/constants.d.ts.map +1 -0
- package/dist/core/artifacts/constants.js +4 -0
- package/dist/core/artifacts/index.d.ts +24 -3
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +96 -8
- package/dist/core/config.d.ts +62 -4
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +98 -4
- package/dist/core/conversations/archive.d.ts +49 -0
- package/dist/core/conversations/archive.d.ts.map +1 -0
- package/dist/core/conversations/archive.js +136 -0
- package/dist/core/conversations/catalog.d.ts +10 -0
- package/dist/core/conversations/catalog.d.ts.map +1 -0
- package/dist/core/conversations/catalog.js +72 -0
- package/dist/core/conversations/context-pack.d.ts +6 -0
- package/dist/core/conversations/context-pack.d.ts.map +1 -0
- package/dist/core/conversations/context-pack.js +60 -0
- package/dist/core/conversations/contract.d.ts +155 -0
- package/dist/core/conversations/contract.d.ts.map +1 -0
- package/dist/core/conversations/contract.js +1 -0
- package/dist/core/conversations/evaluation.d.ts +16 -0
- package/dist/core/conversations/evaluation.d.ts.map +1 -0
- package/dist/core/conversations/evaluation.js +9 -0
- package/dist/core/conversations/index.d.ts +10 -0
- package/dist/core/conversations/index.d.ts.map +1 -0
- package/dist/core/conversations/index.js +9 -0
- package/dist/core/conversations/lifecycle.d.ts +28 -0
- package/dist/core/conversations/lifecycle.d.ts.map +1 -0
- package/dist/core/conversations/lifecycle.js +29 -0
- package/dist/core/conversations/normalize.d.ts +14 -0
- package/dist/core/conversations/normalize.d.ts.map +1 -0
- package/dist/core/conversations/normalize.js +82 -0
- package/dist/core/conversations/query.d.ts +8 -0
- package/dist/core/conversations/query.d.ts.map +1 -0
- package/dist/core/conversations/query.js +280 -0
- package/dist/core/conversations/search-index.d.ts +9 -0
- package/dist/core/conversations/search-index.d.ts.map +1 -0
- package/dist/core/conversations/search-index.js +29 -0
- package/dist/core/events/legacy-storage/canary.d.ts +18 -0
- package/dist/core/events/legacy-storage/canary.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/canary.js +150 -0
- package/dist/core/events/legacy-storage/fence.d.ts +15 -0
- package/dist/core/events/legacy-storage/fence.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/fence.js +115 -0
- package/dist/core/events/legacy-storage/index.d.ts +6 -0
- package/dist/core/events/legacy-storage/index.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/index.js +5 -0
- package/dist/core/events/legacy-storage/inventory.d.ts +10 -0
- package/dist/core/events/legacy-storage/inventory.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/inventory.js +40 -0
- package/dist/core/events/legacy-storage/manifest.d.ts +23 -0
- package/dist/core/events/legacy-storage/manifest.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/manifest.js +108 -0
- package/dist/core/events/legacy-storage/reader.d.ts +15 -0
- package/dist/core/events/legacy-storage/reader.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/reader.js +154 -0
- package/dist/core/events/v3/authority-outbox.d.ts +7 -2
- package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
- package/dist/core/events/v3/authority-outbox.js +16 -3
- package/dist/core/events/v3/base-contract.d.ts +851 -16
- package/dist/core/events/v3/base-contract.d.ts.map +1 -1
- package/dist/core/events/v3/base-contract.js +50 -7
- package/dist/core/events/v3/bootstrap.d.ts +39 -0
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +167 -3
- package/dist/core/events/v3/capabilities.d.ts +11 -0
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +26 -3
- package/dist/core/events/v3/control-witness.d.ts +44 -0
- package/dist/core/events/v3/control-witness.d.ts.map +1 -0
- package/dist/core/events/v3/control-witness.js +233 -0
- package/dist/core/events/v3/control-writer.d.ts +4 -0
- package/dist/core/events/v3/control-writer.d.ts.map +1 -0
- package/dist/core/events/v3/control-writer.js +16 -0
- package/dist/core/events/v3/control.d.ts +8 -2
- package/dist/core/events/v3/control.d.ts.map +1 -1
- package/dist/core/events/v3/control.js +46 -18
- package/dist/core/events/v3/coordination-transaction-recovery.d.ts +42 -0
- package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -0
- package/dist/core/events/v3/coordination-transaction-recovery.js +342 -0
- package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
- package/dist/core/events/v3/coordination-view.js +16 -1
- package/dist/core/events/v3/generated.d.ts +1 -1
- package/dist/core/events/v3/generated.js +1 -1
- package/dist/core/events/v3/index.d.ts +8 -5
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +7 -4
- package/dist/core/events/v3/latency.d.ts +31 -1
- package/dist/core/events/v3/latency.d.ts.map +1 -1
- package/dist/core/events/v3/latency.js +127 -3
- package/dist/core/events/v3/live-route-observer.d.ts +31 -0
- package/dist/core/events/v3/live-route-observer.d.ts.map +1 -0
- package/dist/core/events/v3/live-route-observer.js +58 -0
- package/dist/core/events/v3/live-routing.d.ts +42 -20
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +153 -41
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/command-recorder.js +10 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +11 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +90 -13
- package/dist/core/events/v3/producers/diagnostic-summaries.d.ts +129 -0
- package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -0
- package/dist/core/events/v3/producers/diagnostic-summaries.js +499 -0
- package/dist/core/events/v3/producers/hook-base.d.ts +17 -1
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +83 -2
- package/dist/core/events/v3/producers/intake.d.ts +13 -0
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +36 -2
- package/dist/core/events/v3/producers/producer-state-observer.d.ts +8 -0
- package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -0
- package/dist/core/events/v3/producers/producer-state-observer.js +45 -0
- package/dist/core/events/v3/producers/recorder.d.ts +117 -1
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +992 -27
- package/dist/core/events/v3/reader.d.ts +51 -0
- package/dist/core/events/v3/reader.d.ts.map +1 -1
- package/dist/core/events/v3/reader.js +181 -1
- package/dist/core/events/v3/rotation-config.d.ts +9 -0
- package/dist/core/events/v3/rotation-config.d.ts.map +1 -0
- package/dist/core/events/v3/rotation-config.js +91 -0
- package/dist/core/events/v3/runtime-build.d.ts +11 -0
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -0
- package/dist/core/events/v3/runtime-build.js +39 -0
- package/dist/core/events/v3/runtime-identity.d.ts +5 -0
- package/dist/core/events/v3/runtime-identity.d.ts.map +1 -0
- package/dist/core/events/v3/runtime-identity.js +18 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +52 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
- package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
- package/dist/core/events/v3/support-storage/classify.d.ts +46 -0
- package/dist/core/events/v3/support-storage/classify.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/classify.js +149 -0
- package/dist/core/events/v3/support-storage/eligibility.d.ts +29 -0
- package/dist/core/events/v3/support-storage/eligibility.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/eligibility.js +35 -0
- package/dist/core/events/v3/support-storage/index.d.ts +10 -0
- package/dist/core/events/v3/support-storage/index.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/index.js +9 -0
- package/dist/core/events/v3/support-storage/inventory.d.ts +30 -0
- package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/inventory.js +94 -0
- package/dist/core/events/v3/support-storage/logical-authority.d.ts +14 -0
- package/dist/core/events/v3/support-storage/logical-authority.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/logical-authority.js +104 -0
- package/dist/core/events/v3/support-storage/maintenance.d.ts +98 -0
- package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/maintenance.js +352 -0
- package/dist/core/events/v3/support-storage/pack-contract.d.ts +59 -0
- package/dist/core/events/v3/support-storage/pack-contract.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/pack-contract.js +249 -0
- package/dist/core/events/v3/support-storage/pack-reader.d.ts +34 -0
- package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/pack-reader.js +258 -0
- package/dist/core/events/v3/support-storage/pack-writer.d.ts +30 -0
- package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/pack-writer.js +268 -0
- package/dist/core/events/v3/support-storage/recovery.d.ts +15 -0
- package/dist/core/events/v3/support-storage/recovery.d.ts.map +1 -0
- package/dist/core/events/v3/support-storage/recovery.js +22 -0
- package/dist/core/events/v3/turn-telemetry.d.ts +21 -6
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
- package/dist/core/events/v3/turn-telemetry.js +32 -2
- package/dist/core/events/v3/writer.d.ts +13 -1
- package/dist/core/events/v3/writer.d.ts.map +1 -1
- package/dist/core/events/v3/writer.js +126 -12
- package/dist/core/governor/plan-read.d.ts.map +1 -1
- package/dist/core/governor/plan-read.js +5 -21
- package/dist/core/governor/planning.js +6 -8
- package/dist/core/governor/service-read.d.ts +12 -0
- package/dist/core/governor/service-read.d.ts.map +1 -1
- package/dist/core/governor/service-read.js +266 -2
- package/dist/core/governor/service.d.ts +1 -0
- package/dist/core/governor/service.d.ts.map +1 -1
- package/dist/core/governor/service.js +53 -18
- package/dist/core/guard/evidence-v3.d.ts.map +1 -1
- package/dist/core/guard/evidence-v3.js +2 -0
- package/dist/core/hooks/adapter/events.d.ts.map +1 -1
- package/dist/core/hooks/adapter/events.js +1 -0
- package/dist/core/hooks/adapter/output.d.ts +4 -2
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +13 -5
- package/dist/core/hooks/adapter/parse.d.ts +3 -0
- package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
- package/dist/core/hooks/adapter/parse.js +14 -0
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts +142 -0
- package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
- package/dist/core/hooks/adapter/runtime-telemetry.js +869 -0
- package/dist/core/hooks/cli.js +318 -61
- package/dist/core/hooks/effects/image-capture.d.ts +1 -1
- package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
- package/dist/core/hooks/effects/image-capture.js +4 -2
- package/dist/core/hooks/remediation-cap.d.ts +39 -0
- package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
- package/dist/core/hooks/remediation-cap.js +63 -0
- package/dist/core/hooks/resolve/coord-root.d.ts +22 -9
- package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
- package/dist/core/hooks/resolve/coord-root.js +92 -11
- package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
- package/dist/core/hooks/resolve/owner.js +5 -0
- package/dist/core/hooks/resolve/transcript.d.ts +33 -9
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +33 -10
- package/dist/core/inbox/contract.d.ts +64 -0
- package/dist/core/inbox/contract.d.ts.map +1 -0
- package/dist/core/inbox/contract.js +13 -0
- package/dist/core/inbox/index.d.ts +5 -0
- package/dist/core/inbox/index.d.ts.map +1 -0
- package/dist/core/inbox/index.js +4 -0
- package/dist/core/inbox/lifecycle.d.ts +22 -0
- package/dist/core/inbox/lifecycle.d.ts.map +1 -0
- package/dist/core/inbox/lifecycle.js +41 -0
- package/dist/core/inbox/service.d.ts +36 -0
- package/dist/core/inbox/service.d.ts.map +1 -0
- package/dist/core/inbox/service.js +210 -0
- package/dist/core/inbox/watcher.d.ts +7 -0
- package/dist/core/inbox/watcher.d.ts.map +1 -0
- package/dist/core/inbox/watcher.js +26 -0
- package/dist/core/presence/codec-digest.d.ts.map +1 -1
- package/dist/core/presence/codec-digest.js +14 -3
- package/dist/core/presence/relay-client.d.ts +1 -0
- package/dist/core/presence/relay-client.d.ts.map +1 -1
- package/dist/core/presence/relay-client.js +52 -8
- package/dist/core/semantic/adapters.d.ts +37 -0
- package/dist/core/semantic/adapters.d.ts.map +1 -0
- package/dist/core/semantic/adapters.js +360 -0
- package/dist/core/semantic/contract.d.ts +1072 -0
- package/dist/core/semantic/contract.d.ts.map +1 -0
- package/dist/core/semantic/contract.js +331 -0
- package/dist/core/semantic/evidence.d.ts +11 -0
- package/dist/core/semantic/evidence.d.ts.map +1 -0
- package/dist/core/semantic/evidence.js +262 -0
- package/dist/core/semantic/index.d.ts +14 -0
- package/dist/core/semantic/index.d.ts.map +1 -0
- package/dist/core/semantic/index.js +13 -0
- package/dist/core/semantic/once.d.ts +38 -0
- package/dist/core/semantic/once.d.ts.map +1 -0
- package/dist/core/semantic/once.js +364 -0
- package/dist/core/semantic/prompt.d.ts +12 -0
- package/dist/core/semantic/prompt.d.ts.map +1 -0
- package/dist/core/semantic/prompt.js +83 -0
- package/dist/core/semantic/review.d.ts +144 -0
- package/dist/core/semantic/review.d.ts.map +1 -0
- package/dist/core/semantic/review.js +544 -0
- package/dist/core/semantic/routes.d.ts +10 -0
- package/dist/core/semantic/routes.d.ts.map +1 -0
- package/dist/core/semantic/routes.js +21 -0
- package/dist/core/semantic/scheduler.d.ts +27 -0
- package/dist/core/semantic/scheduler.d.ts.map +1 -0
- package/dist/core/semantic/scheduler.js +91 -0
- package/dist/core/semantic/service-status.d.ts +51 -0
- package/dist/core/semantic/service-status.d.ts.map +1 -0
- package/dist/core/semantic/service-status.js +140 -0
- package/dist/core/semantic/service.d.ts +52 -0
- package/dist/core/semantic/service.d.ts.map +1 -0
- package/dist/core/semantic/service.js +559 -0
- package/dist/core/semantic/soak.d.ts +75 -0
- package/dist/core/semantic/soak.d.ts.map +1 -0
- package/dist/core/semantic/soak.js +476 -0
- package/dist/core/semantic/storage.d.ts +81 -0
- package/dist/core/semantic/storage.d.ts.map +1 -0
- package/dist/core/semantic/storage.js +180 -0
- package/dist/core/semantic/usage.d.ts +43 -0
- package/dist/core/semantic/usage.d.ts.map +1 -0
- package/dist/core/semantic/usage.js +193 -0
- package/dist/core/semantic/validate.d.ts +18 -0
- package/dist/core/semantic/validate.d.ts.map +1 -0
- package/dist/core/semantic/validate.js +207 -0
- package/dist/core/storage/buffer.d.ts +28 -0
- package/dist/core/storage/buffer.d.ts.map +1 -0
- package/dist/core/storage/buffer.js +101 -0
- package/dist/core/storage/builtins.d.ts +3 -0
- package/dist/core/storage/builtins.d.ts.map +1 -0
- package/dist/core/storage/builtins.js +683 -0
- package/dist/core/storage/catalog.d.ts +19 -0
- package/dist/core/storage/catalog.d.ts.map +1 -0
- package/dist/core/storage/catalog.js +365 -0
- package/dist/core/storage/config.d.ts +16 -0
- package/dist/core/storage/config.d.ts.map +1 -0
- package/dist/core/storage/config.js +311 -0
- package/dist/core/storage/contract.d.ts +275 -0
- package/dist/core/storage/contract.d.ts.map +1 -0
- package/dist/core/storage/contract.js +3 -0
- package/dist/core/storage/durable-history.d.ts +36 -0
- package/dist/core/storage/durable-history.d.ts.map +1 -0
- package/dist/core/storage/durable-history.js +606 -0
- package/dist/core/storage/health.d.ts +4 -0
- package/dist/core/storage/health.d.ts.map +1 -0
- package/dist/core/storage/health.js +65 -0
- package/dist/core/storage/index.d.ts +16 -0
- package/dist/core/storage/index.d.ts.map +1 -0
- package/dist/core/storage/index.js +15 -0
- package/dist/core/storage/inventory.d.ts +25 -0
- package/dist/core/storage/inventory.d.ts.map +1 -0
- package/dist/core/storage/inventory.js +666 -0
- package/dist/core/storage/jsonl.d.ts +52 -0
- package/dist/core/storage/jsonl.d.ts.map +1 -0
- package/dist/core/storage/jsonl.js +156 -0
- package/dist/core/storage/log-retention.d.ts +52 -0
- package/dist/core/storage/log-retention.d.ts.map +1 -0
- package/dist/core/storage/log-retention.js +419 -0
- package/dist/core/storage/logger.d.ts +82 -0
- package/dist/core/storage/logger.d.ts.map +1 -0
- package/dist/core/storage/logger.js +411 -0
- package/dist/core/storage/maintenance-providers.d.ts +26 -0
- package/dist/core/storage/maintenance-providers.d.ts.map +1 -0
- package/dist/core/storage/maintenance-providers.js +141 -0
- package/dist/core/storage/maintenance.d.ts +125 -0
- package/dist/core/storage/maintenance.d.ts.map +1 -0
- package/dist/core/storage/maintenance.js +609 -0
- package/dist/core/storage/metrics.d.ts +60 -0
- package/dist/core/storage/metrics.d.ts.map +1 -0
- package/dist/core/storage/metrics.js +134 -0
- package/dist/core/storage/policy.d.ts +7 -0
- package/dist/core/storage/policy.d.ts.map +1 -0
- package/dist/core/storage/policy.js +110 -0
- package/dist/core/storage/process-log.d.ts +38 -0
- package/dist/core/storage/process-log.d.ts.map +1 -0
- package/dist/core/storage/process-log.js +165 -0
- package/dist/core/storage/query.d.ts +34 -0
- package/dist/core/storage/query.d.ts.map +1 -0
- package/dist/core/storage/query.js +295 -0
- package/dist/core/storage/receipts.d.ts +23 -0
- package/dist/core/storage/receipts.d.ts.map +1 -0
- package/dist/core/storage/receipts.js +117 -0
- package/dist/core/storage/segments.d.ts +84 -0
- package/dist/core/storage/segments.d.ts.map +1 -0
- package/dist/core/storage/segments.js +542 -0
- package/dist/core/storage/sink-graph.d.ts +65 -0
- package/dist/core/storage/sink-graph.d.ts.map +1 -0
- package/dist/core/storage/sink-graph.js +213 -0
- package/dist/core/storage/storm-control.d.ts +23 -0
- package/dist/core/storage/storm-control.d.ts.map +1 -0
- package/dist/core/storage/storm-control.js +59 -0
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +10 -14
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +2 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/lazy-commands.d.ts +26 -0
- package/dist/lazy-commands.d.ts.map +1 -0
- package/dist/lazy-commands.js +210 -0
- package/dist/lib/browser/client.d.ts +11 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +13 -0
- package/dist/lib/browser/index.d.ts +1 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/standalone-html.d.ts +25 -0
- package/dist/lib/browser/standalone-html.d.ts.map +1 -0
- package/dist/lib/browser/standalone-html.js +284 -0
- package/dist/lib/docs-lint.d.ts +2 -0
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +45 -80
- package/dist/lib/docs-metadata-audit.d.ts +3 -0
- package/dist/lib/docs-metadata-audit.d.ts.map +1 -1
- package/dist/lib/docs-metadata-audit.js +13 -23
- package/dist/lib/docs-metadata-sync.d.ts +1 -0
- package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
- package/dist/lib/docs-metadata-sync.js +28 -10
- package/dist/lib/docs-repository-view.d.ts +22 -0
- package/dist/lib/docs-repository-view.d.ts.map +1 -0
- package/dist/lib/docs-repository-view.js +185 -0
- package/dist/lib/http/client.d.ts +11 -5
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +22 -4
- package/dist/lib/http/index.d.ts +1 -1
- package/dist/lib/http/index.d.ts.map +1 -1
- package/dist/lib/http/index.js +1 -1
- package/dist/lib/indexer-exclusions.d.ts +27 -0
- package/dist/lib/indexer-exclusions.d.ts.map +1 -0
- package/dist/lib/indexer-exclusions.js +176 -0
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +1 -0
- package/dist/lib/instructions/templates.d.ts +2 -0
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +149 -4
- package/dist/lib/local-file-url.d.ts +9 -0
- package/dist/lib/local-file-url.d.ts.map +1 -0
- package/dist/lib/local-file-url.js +20 -0
- package/dist/lib/web-performance.d.ts +118 -0
- package/dist/lib/web-performance.d.ts.map +1 -0
- package/dist/lib/web-performance.js +192 -0
- package/package.json +34 -2
- package/schemas/config.schema.json +58 -0
- package/schemas/event-v3.schema.json +3073 -581
- package/src/commander.ts +462 -93
- package/src/commands/agents.ts +617 -355
- package/src/commands/backup.ts +18 -14
- package/src/commands/browse-session.ts +12 -0
- package/src/commands/browse.ts +31 -9
- package/src/commands/conversations.ts +279 -0
- package/src/commands/decision.ts +8 -2
- package/src/commands/deinit.ts +6 -0
- package/src/commands/docs.ts +25 -6
- package/src/commands/doctor.ts +75 -9
- package/src/commands/events.ts +21 -1
- package/src/commands/fetch.ts +7 -6
- package/src/commands/files.ts +143 -0
- package/src/commands/governor.ts +13 -12
- package/src/commands/inbox.ts +61 -0
- package/src/commands/init.ts +78 -16
- package/src/commands/ledger-v3.ts +421 -1
- package/src/commands/logs.ts +224 -0
- package/src/commands/messages.ts +61 -0
- package/src/commands/outline.ts +6 -2
- package/src/commands/presence.ts +7 -2
- package/src/commands/read.ts +6 -2
- package/src/commands/semantic.ts +244 -0
- package/src/commands/storage.ts +310 -0
- package/src/commands/tunnel.ts +66 -52
- package/src/commands/web.ts +92 -7
- package/src/commands/work.ts +3 -3
- package/src/commands/workflow.ts +13 -13
- package/src/core/agents/canonical-emit.ts +15 -0
- package/src/core/agents/claim-path.ts +23 -0
- package/src/core/agents/cli.ts +259 -53
- package/src/core/agents/coord-client.ts +92 -8
- package/src/core/agents/live-authority-v3.ts +342 -14
- package/src/core/agents/live-lifecycle-v3.ts +14 -4
- package/src/core/agents/live-observation-v3.ts +13 -3
- package/src/core/agents/render/prompt-context.ts +40 -16
- package/src/core/agents/rules/stop-hook.ts +129 -25
- package/src/core/agents/rules/verdict.ts +1 -0
- package/src/core/agents/session-events.ts +4 -0
- package/src/core/agents/session-finalization-state-v3.ts +1 -1
- package/src/core/agents/session-finalizer-v3.ts +4 -1
- package/src/core/agents/session-name-display.ts +9 -1
- package/src/core/agents/state/activity-log.ts +7 -2
- package/src/core/agents/state/heartbeat-reader.ts +69 -0
- package/src/core/agents/state/heartbeat-writer.ts +47 -84
- package/src/core/agents/state/live-coordination-view.ts +17 -81
- package/src/core/agents/state/live-coordination-writer.ts +141 -0
- package/src/core/agents/state/names.ts +190 -182
- package/src/core/agents/state/stale-sweep.ts +25 -5
- package/src/core/artifacts/constants.ts +4 -0
- package/src/core/artifacts/index.ts +113 -8
- package/src/core/config.ts +126 -5
- package/src/core/conversations/archive.ts +237 -0
- package/src/core/conversations/catalog.ts +79 -0
- package/src/core/conversations/context-pack.ts +72 -0
- package/src/core/conversations/contract.ts +178 -0
- package/src/core/conversations/evaluation.ts +30 -0
- package/src/core/conversations/index.ts +9 -0
- package/src/core/conversations/lifecycle.ts +63 -0
- package/src/core/conversations/normalize.ts +105 -0
- package/src/core/conversations/query.ts +318 -0
- package/src/core/conversations/search-index.ts +48 -0
- package/src/core/events/legacy-storage/canary.ts +177 -0
- package/src/core/events/legacy-storage/fence.ts +129 -0
- package/src/core/events/legacy-storage/index.ts +5 -0
- package/src/core/events/legacy-storage/inventory.ts +51 -0
- package/src/core/events/legacy-storage/manifest.ts +136 -0
- package/src/core/events/legacy-storage/reader.ts +178 -0
- package/src/core/events/v3/authority-outbox.ts +22 -1
- package/src/core/events/v3/base-contract.ts +56 -7
- package/src/core/events/v3/bootstrap.ts +195 -2
- package/src/core/events/v3/capabilities.ts +37 -3
- package/src/core/events/v3/control-witness.ts +339 -0
- package/src/core/events/v3/control-writer.ts +16 -0
- package/src/core/events/v3/control.ts +54 -18
- package/src/core/events/v3/coordination-transaction-recovery.ts +477 -0
- package/src/core/events/v3/coordination-view.ts +17 -1
- package/src/core/events/v3/generated.ts +1 -1
- package/src/core/events/v3/index.ts +26 -2
- package/src/core/events/v3/latency.ts +213 -2
- package/src/core/events/v3/live-route-observer.ts +80 -0
- package/src/core/events/v3/live-routing.ts +182 -45
- package/src/core/events/v3/producers/command-recorder.ts +10 -1
- package/src/core/events/v3/producers/coordination-recorder.ts +112 -15
- package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
- package/src/core/events/v3/producers/hook-base.ts +116 -2
- package/src/core/events/v3/producers/intake.ts +48 -2
- package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
- package/src/core/events/v3/producers/recorder.ts +1403 -30
- package/src/core/events/v3/reader.ts +243 -2
- package/src/core/events/v3/rotation-config.ts +98 -0
- package/src/core/events/v3/runtime-build.ts +41 -0
- package/src/core/events/v3/runtime-identity.ts +16 -0
- package/src/core/events/v3/runtime-telemetry-capabilities.ts +143 -0
- package/src/core/events/v3/support-storage/classify.ts +209 -0
- package/src/core/events/v3/support-storage/eligibility.ts +58 -0
- package/src/core/events/v3/support-storage/index.ts +9 -0
- package/src/core/events/v3/support-storage/inventory.ts +135 -0
- package/src/core/events/v3/support-storage/logical-authority.ts +117 -0
- package/src/core/events/v3/support-storage/maintenance.ts +501 -0
- package/src/core/events/v3/support-storage/pack-contract.ts +337 -0
- package/src/core/events/v3/support-storage/pack-reader.ts +346 -0
- package/src/core/events/v3/support-storage/pack-writer.ts +352 -0
- package/src/core/events/v3/support-storage/recovery.ts +43 -0
- package/src/core/events/v3/turn-telemetry.ts +66 -5
- package/src/core/events/v3/writer.ts +168 -16
- package/src/core/governor/plan-read.ts +5 -18
- package/src/core/governor/planning.ts +5 -8
- package/src/core/governor/service-read.ts +320 -2
- package/src/core/governor/service.ts +49 -22
- package/src/core/guard/evidence-v3.ts +1 -0
- package/src/core/hooks/adapter/events.ts +1 -0
- package/src/core/hooks/adapter/output.ts +12 -5
- package/src/core/hooks/adapter/parse.ts +16 -0
- package/src/core/hooks/adapter/runtime-telemetry.ts +1200 -0
- package/src/core/hooks/cli.ts +342 -64
- package/src/core/hooks/effects/image-capture.ts +4 -1
- package/src/core/hooks/remediation-cap.ts +83 -0
- package/src/core/hooks/resolve/coord-root.ts +91 -11
- package/src/core/hooks/resolve/owner.ts +4 -0
- package/src/core/hooks/resolve/transcript.ts +55 -11
- package/src/core/inbox/contract.ts +81 -0
- package/src/core/inbox/index.ts +4 -0
- package/src/core/inbox/lifecycle.ts +104 -0
- package/src/core/inbox/service.ts +305 -0
- package/src/core/inbox/watcher.ts +36 -0
- package/src/core/presence/codec-digest.ts +15 -9
- package/src/core/presence/relay-client.ts +55 -7
- package/src/core/semantic/adapters.ts +452 -0
- package/src/core/semantic/contract.ts +430 -0
- package/src/core/semantic/evidence.ts +336 -0
- package/src/core/semantic/index.ts +201 -0
- package/src/core/semantic/once.ts +496 -0
- package/src/core/semantic/prompt.ts +96 -0
- package/src/core/semantic/review.ts +803 -0
- package/src/core/semantic/routes.ts +30 -0
- package/src/core/semantic/scheduler.ts +151 -0
- package/src/core/semantic/service-status.ts +212 -0
- package/src/core/semantic/service.ts +681 -0
- package/src/core/semantic/soak.ts +638 -0
- package/src/core/semantic/storage.ts +300 -0
- package/src/core/semantic/usage.ts +272 -0
- package/src/core/semantic/validate.ts +243 -0
- package/src/core/storage/buffer.ts +124 -0
- package/src/core/storage/builtins.ts +916 -0
- package/src/core/storage/catalog.ts +467 -0
- package/src/core/storage/config.ts +423 -0
- package/src/core/storage/contract.ts +342 -0
- package/src/core/storage/durable-history.ts +738 -0
- package/src/core/storage/health.ts +76 -0
- package/src/core/storage/index.ts +15 -0
- package/src/core/storage/inventory.ts +859 -0
- package/src/core/storage/jsonl.ts +213 -0
- package/src/core/storage/log-retention.ts +555 -0
- package/src/core/storage/logger.ts +546 -0
- package/src/core/storage/maintenance-providers.ts +200 -0
- package/src/core/storage/maintenance.ts +929 -0
- package/src/core/storage/metrics.ts +199 -0
- package/src/core/storage/policy.ts +141 -0
- package/src/core/storage/process-log.ts +203 -0
- package/src/core/storage/query.ts +360 -0
- package/src/core/storage/receipts.ts +162 -0
- package/src/core/storage/segments.ts +721 -0
- package/src/core/storage/sink-graph.ts +343 -0
- package/src/core/storage/storm-control.ts +91 -0
- package/src/core/work/state.ts +12 -21
- package/src/core/workflow/live-session-v3.ts +2 -4
- package/src/index.ts +2 -0
- package/src/lazy-commands.ts +294 -0
- package/src/lib/browser/client.ts +21 -0
- package/src/lib/browser/index.ts +4 -0
- package/src/lib/browser/standalone-html.ts +312 -0
- package/src/lib/docs-lint.ts +58 -77
- package/src/lib/docs-metadata-audit.ts +26 -21
- package/src/lib/docs-metadata-sync.ts +32 -9
- package/src/lib/docs-repository-view.ts +220 -0
- package/src/lib/http/client.ts +44 -8
- package/src/lib/http/index.ts +6 -1
- package/src/lib/indexer-exclusions.ts +173 -0
- package/src/lib/instructions/apply.ts +1 -0
- package/src/lib/instructions/templates.ts +154 -4
- package/src/lib/local-file-url.ts +31 -0
- package/src/lib/web-performance.ts +335 -0
|
@@ -23,11 +23,14 @@ import {
|
|
|
23
23
|
} from "node:fs";
|
|
24
24
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
25
25
|
import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.ts";
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
artifactAutoCleanEnabled,
|
|
28
|
+
artifactAutoCleanIntervalHours,
|
|
29
|
+
artifactDefaultRetentionDays,
|
|
30
|
+
} from "../config.ts";
|
|
31
|
+
import { ARTIFACT_MANIFEST, ARTIFACT_SCHEMA_VERSION, ARTIFACTS_DIR } from "./constants.ts";
|
|
27
32
|
|
|
28
|
-
export
|
|
29
|
-
export const ARTIFACT_MANIFEST = ".harnery-artifact.json";
|
|
30
|
-
export const ARTIFACT_SCHEMA_VERSION = 1 as const;
|
|
33
|
+
export { ARTIFACT_MANIFEST, ARTIFACT_SCHEMA_VERSION, ARTIFACTS_DIR } from "./constants.ts";
|
|
31
34
|
|
|
32
35
|
export interface ArtifactActor {
|
|
33
36
|
instance_id: string;
|
|
@@ -72,6 +75,7 @@ export interface ArtifactInventoryEntry {
|
|
|
72
75
|
artifact_id: string | null;
|
|
73
76
|
slug: string | null;
|
|
74
77
|
created_at: string | null;
|
|
78
|
+
last_modified_at: string | null;
|
|
75
79
|
expires_at: string | null;
|
|
76
80
|
owner_instance_id: string | null;
|
|
77
81
|
}
|
|
@@ -277,6 +281,65 @@ export function cleanArtifacts(
|
|
|
277
281
|
});
|
|
278
282
|
}
|
|
279
283
|
|
|
284
|
+
/** Sibling of the artifacts root so the stamp never appears in the inventory scan. */
|
|
285
|
+
const AUTO_CLEAN_STAMP = ".harnery/artifacts-auto-clean.json";
|
|
286
|
+
|
|
287
|
+
export interface ArtifactAutoCleanResult {
|
|
288
|
+
ran: boolean;
|
|
289
|
+
reason: "swept" | "disabled" | "fresh" | "no-root";
|
|
290
|
+
deleted: number;
|
|
291
|
+
bytes: number;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Throttled expired-artifact sweep, fired as a SessionStart effect.
|
|
296
|
+
*
|
|
297
|
+
* Retention was previously enforced only when someone remembered to run
|
|
298
|
+
* `artifacts clean --yes`, so expired workspaces accumulated indefinitely on
|
|
299
|
+
* busy hosts. This runs the exact same guarded deletion (only
|
|
300
|
+
* `managed-expired` entries, each re-classified immediately before removal;
|
|
301
|
+
* unmanaged and legacy directories are never touched) at most once per
|
|
302
|
+
* interval (default 24h), claim-first via a stamp file so concurrent session
|
|
303
|
+
* starts do not double-sweep. Disable with `artifacts.auto_clean: false` or
|
|
304
|
+
* `HARNERY_ARTIFACT_AUTO_CLEAN=0`.
|
|
305
|
+
*/
|
|
306
|
+
export function autoCleanArtifacts(
|
|
307
|
+
repoRoot: string,
|
|
308
|
+
opts: { now?: Date } = {},
|
|
309
|
+
): ArtifactAutoCleanResult {
|
|
310
|
+
const now = opts.now ?? new Date();
|
|
311
|
+
assertValidDate(now, "now");
|
|
312
|
+
if (!existsSync(artifactsRoot(repoRoot))) {
|
|
313
|
+
return { ran: false, reason: "no-root", deleted: 0, bytes: 0 };
|
|
314
|
+
}
|
|
315
|
+
if (!artifactAutoCleanEnabled(repoRoot)) {
|
|
316
|
+
return { ran: false, reason: "disabled", deleted: 0, bytes: 0 };
|
|
317
|
+
}
|
|
318
|
+
const stampPath = join(resolve(repoRoot), AUTO_CLEAN_STAMP);
|
|
319
|
+
const intervalMs = artifactAutoCleanIntervalHours() * 60 * 60 * 1000;
|
|
320
|
+
try {
|
|
321
|
+
const stamp = JSON.parse(readFileSync(stampPath, "utf8")) as { last_run_at?: string };
|
|
322
|
+
const last = Date.parse(stamp.last_run_at ?? "");
|
|
323
|
+
if (Number.isFinite(last) && now.getTime() - last < intervalMs) {
|
|
324
|
+
return { ran: false, reason: "fresh", deleted: 0, bytes: 0 };
|
|
325
|
+
}
|
|
326
|
+
} catch {
|
|
327
|
+
// Missing or unreadable stamp: sweep now and write a fresh one.
|
|
328
|
+
}
|
|
329
|
+
// Claim first: a crash mid-sweep costs one skipped interval, while claiming
|
|
330
|
+
// after would let two concurrent session starts both walk the store.
|
|
331
|
+
writeFileSync(stampPath, `${JSON.stringify({ last_run_at: now.toISOString() }, null, 2)}\n`);
|
|
332
|
+
const rows = cleanArtifacts(repoRoot, { yes: true, now });
|
|
333
|
+
const deletedRows = rows.filter((row) => row.action === "deleted");
|
|
334
|
+
const deleted = deletedRows.length;
|
|
335
|
+
const bytes = deletedRows.reduce((sum, row) => sum + (row.bytes ?? 0), 0);
|
|
336
|
+
writeFileSync(
|
|
337
|
+
stampPath,
|
|
338
|
+
`${JSON.stringify({ last_run_at: now.toISOString(), deleted, bytes }, null, 2)}\n`,
|
|
339
|
+
);
|
|
340
|
+
return { ran: true, reason: "swept", deleted, bytes };
|
|
341
|
+
}
|
|
342
|
+
|
|
280
343
|
export function resolveArtifactRef(repoRoot: string, ref: string): string {
|
|
281
344
|
const root = artifactsRoot(repoRoot);
|
|
282
345
|
const candidate = isAbsolute(ref) ? resolve(ref) : resolve(root, ref);
|
|
@@ -328,16 +391,22 @@ function classifyArtifactPath(
|
|
|
328
391
|
}
|
|
329
392
|
const manifest = parsed.manifest;
|
|
330
393
|
const bytes = safeTreeSize(path);
|
|
394
|
+
const lastModifiedMs = safeTreeLastModified(path, now);
|
|
395
|
+
const retentionAnchorMs = Date.parse(manifest.retention.renewed_at ?? manifest.created_at);
|
|
396
|
+
const retentionWindowMs = Date.parse(manifest.retention.expires_at) - retentionAnchorMs;
|
|
397
|
+
const effectiveLastModifiedMs = Math.max(retentionAnchorMs, lastModifiedMs ?? 0);
|
|
398
|
+
const effectiveExpiresAt = new Date(effectiveLastModifiedMs + retentionWindowMs).toISOString();
|
|
331
399
|
const base = rowFor(path, name, repoRoot, "managed-current", "retention has not expired", bytes);
|
|
332
400
|
Object.assign(base, {
|
|
333
401
|
artifact_id: manifest.artifact_id,
|
|
334
402
|
slug: manifest.slug,
|
|
335
403
|
created_at: manifest.created_at,
|
|
336
|
-
|
|
404
|
+
last_modified_at: new Date(effectiveLastModifiedMs).toISOString(),
|
|
405
|
+
expires_at: effectiveExpiresAt,
|
|
337
406
|
owner_instance_id: manifest.created_by?.instance_id ?? null,
|
|
338
407
|
});
|
|
339
408
|
|
|
340
|
-
if (base.bytes === null) {
|
|
409
|
+
if (base.bytes === null || lastModifiedMs === null) {
|
|
341
410
|
return {
|
|
342
411
|
...base,
|
|
343
412
|
classification: "unknown",
|
|
@@ -372,11 +441,11 @@ function classifyArtifactPath(
|
|
|
372
441
|
};
|
|
373
442
|
}
|
|
374
443
|
}
|
|
375
|
-
if (Date.parse(
|
|
444
|
+
if (Date.parse(effectiveExpiresAt) > now.getTime()) return base;
|
|
376
445
|
return {
|
|
377
446
|
...base,
|
|
378
447
|
classification: "managed-expired",
|
|
379
|
-
reason: `retention expired at ${
|
|
448
|
+
reason: `retention expired at ${effectiveExpiresAt}`,
|
|
380
449
|
action: "would-delete",
|
|
381
450
|
};
|
|
382
451
|
}
|
|
@@ -410,6 +479,13 @@ function readManifest(path: string): ParsedManifest | ManifestError {
|
|
|
410
479
|
if (!m.retention || typeof m.retention !== "object" || !validIso(m.retention.expires_at)) {
|
|
411
480
|
return { ok: false, reason: "invalid retention.expires_at" };
|
|
412
481
|
}
|
|
482
|
+
if (m.retention.renewed_at !== undefined && !validIso(m.retention.renewed_at)) {
|
|
483
|
+
return { ok: false, reason: "invalid retention.renewed_at" };
|
|
484
|
+
}
|
|
485
|
+
const retentionAnchor = Date.parse(m.retention.renewed_at ?? m.created_at);
|
|
486
|
+
if (Date.parse(m.retention.expires_at) <= retentionAnchor) {
|
|
487
|
+
return { ok: false, reason: "retention.expires_at must follow its retention anchor" };
|
|
488
|
+
}
|
|
413
489
|
if (m.released_at !== undefined && !validIso(m.released_at)) {
|
|
414
490
|
return { ok: false, reason: "invalid released_at" };
|
|
415
491
|
}
|
|
@@ -478,6 +554,34 @@ function safeTreeSize(path: string): number | null {
|
|
|
478
554
|
}
|
|
479
555
|
}
|
|
480
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Return the newest filesystem change in a managed tree without following
|
|
559
|
+
* symlinks. A small future tolerance protects a write racing the inventory
|
|
560
|
+
* scan; timestamps farther ahead are ignored as clock-skewed metadata.
|
|
561
|
+
*/
|
|
562
|
+
function safeTreeLastModified(path: string, now: Date): number | null {
|
|
563
|
+
const nowMs = now.getTime();
|
|
564
|
+
const futureToleranceMs = 5 * 60 * 1000;
|
|
565
|
+
try {
|
|
566
|
+
const st = lstatSync(path);
|
|
567
|
+
let latest = 0;
|
|
568
|
+
for (const timestamp of [st.mtimeMs, st.ctimeMs]) {
|
|
569
|
+
if (Number.isFinite(timestamp) && timestamp <= nowMs + futureToleranceMs) {
|
|
570
|
+
latest = Math.max(latest, Math.min(timestamp, nowMs));
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if (st.isSymbolicLink() || !st.isDirectory()) return latest;
|
|
574
|
+
for (const child of readdirSync(path)) {
|
|
575
|
+
const childLatest = safeTreeLastModified(join(path, child), now);
|
|
576
|
+
if (childLatest === null) return null;
|
|
577
|
+
latest = Math.max(latest, childLatest);
|
|
578
|
+
}
|
|
579
|
+
return latest;
|
|
580
|
+
} catch {
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
481
585
|
function rowFor(
|
|
482
586
|
path: string,
|
|
483
587
|
name: string,
|
|
@@ -497,6 +601,7 @@ function rowFor(
|
|
|
497
601
|
artifact_id: null,
|
|
498
602
|
slug: null,
|
|
499
603
|
created_at: null,
|
|
604
|
+
last_modified_at: null,
|
|
500
605
|
expires_at: null,
|
|
501
606
|
owner_instance_id: null,
|
|
502
607
|
};
|
package/src/core/config.ts
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
* 2. `<project-root>/.harnery/config.jsonc` — project override (authoritative)
|
|
8
8
|
*
|
|
9
9
|
* Fields owned here: `binName` (host CLI name for agent-facing strings),
|
|
10
|
-
* `hooksSetupHint`, `agents`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
11
|
-
* `coord` (heartbeat freshness), `
|
|
10
|
+
* `hooksSetupHint`, `agents`, `instructions`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
11
|
+
* `coord` (heartbeat freshness), `logs` (structured-log storage budgets),
|
|
12
|
+
* `artifacts` (working-file retention),
|
|
12
13
|
* `backup` (restic repo/password/prune policy), `sync` (rclone
|
|
13
14
|
* remote/prefix), and `web` (dashboard port) sections. The `files` deny/override section
|
|
14
15
|
* is parsed separately by `web/lib/files.ts`.
|
|
@@ -22,16 +23,21 @@ import { readFileSync, statSync } from "node:fs";
|
|
|
22
23
|
import { homedir } from "node:os";
|
|
23
24
|
import { join } from "node:path";
|
|
24
25
|
import { coordEnv } from "../lib/env.ts";
|
|
26
|
+
import { DEFAULT_WEB_PORT } from "../lib/local-file-url.ts";
|
|
27
|
+
import { resolveEventLedgerRotateActiveBytesV3 } from "./events/v3/rotation-config.ts";
|
|
25
28
|
import { findCoordRoot } from "./hooks/resolve/coord-root.ts";
|
|
26
29
|
|
|
30
|
+
export { DEFAULT_WEB_PORT } from "../lib/local-file-url.ts";
|
|
31
|
+
export { DEFAULT_EVENT_LEDGER_ROTATE_ACTIVE_BYTES } from "./events/v3/rotation-config.ts";
|
|
32
|
+
|
|
27
33
|
/** The standalone CLI's bin name: the resolution floor when nothing else is set. */
|
|
28
34
|
export const DEFAULT_BIN_NAME = "harn";
|
|
29
35
|
|
|
30
36
|
/** Heartbeat-freshness default (seconds): the sweep window when nothing overrides it. */
|
|
31
37
|
export const DEFAULT_FRESHNESS_SECS = 600;
|
|
32
38
|
|
|
33
|
-
/**
|
|
34
|
-
export const
|
|
39
|
+
/** Keep a fresh host reminder bounded to one short prompt-context line. */
|
|
40
|
+
export const MAX_HOST_PROMPT_REMINDER_CHARS = 500;
|
|
35
41
|
|
|
36
42
|
export interface SessionFinalizationConfig {
|
|
37
43
|
archiveGraceSeconds: number;
|
|
@@ -76,6 +82,11 @@ interface HarneryConfig {
|
|
|
76
82
|
requireGitFinalization?: boolean;
|
|
77
83
|
finalizationRoots?: AgentFinalizationRoot[];
|
|
78
84
|
};
|
|
85
|
+
/** Host-owned agent instruction settings. */
|
|
86
|
+
instructions?: {
|
|
87
|
+
hostAddendumFile?: unknown;
|
|
88
|
+
promptReminder?: unknown;
|
|
89
|
+
};
|
|
79
90
|
/**
|
|
80
91
|
* Managed-tool provisioning consent. `{ ripgrep: { autoInstall: true } }`
|
|
81
92
|
* lets `grep` download the pinned, checksum-verified ripgrep into the
|
|
@@ -118,11 +129,20 @@ interface HarneryConfig {
|
|
|
118
129
|
reconcile_interval_seconds?: number;
|
|
119
130
|
};
|
|
120
131
|
};
|
|
132
|
+
/** Strictly validated structured-log storage overrides. */
|
|
133
|
+
logs?: { storage?: unknown };
|
|
134
|
+
/**
|
|
135
|
+
* Universal event-ledger V3 tunables. `rotate_active_bytes` is the active
|
|
136
|
+
* segment size at which the epoch is archived and replaced automatically
|
|
137
|
+
* (default 32 MiB; `0` disables rotation). Read via
|
|
138
|
+
* `eventLedgerRotateActiveBytes()`.
|
|
139
|
+
*/
|
|
140
|
+
events?: { rotate_active_bytes?: number };
|
|
121
141
|
/**
|
|
122
142
|
* Managed working-artifact defaults. `default_retention_days` is the
|
|
123
143
|
* create-time TTL when the caller does not pass `artifacts create --days`.
|
|
124
144
|
*/
|
|
125
|
-
artifacts?: { default_retention_days?: number };
|
|
145
|
+
artifacts?: { default_retention_days?: number; auto_clean?: boolean };
|
|
126
146
|
/**
|
|
127
147
|
* `harn backup` (restic) defaults: `repo` path/URL, `password_file`, and the
|
|
128
148
|
* `keep_daily`/`keep_weekly`/`keep_monthly` prune policy. Read via `backupConfig()`.
|
|
@@ -232,6 +252,40 @@ export interface CoordRunQualityConfigSource {
|
|
|
232
252
|
digest_seed: unknown;
|
|
233
253
|
}
|
|
234
254
|
|
|
255
|
+
export interface LogStorageConfigLayerSource {
|
|
256
|
+
layer: "user" | "project";
|
|
257
|
+
value: unknown;
|
|
258
|
+
invalid: boolean;
|
|
259
|
+
/** Stable file signature for bounded diagnostics without retaining values. */
|
|
260
|
+
signature: string | null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface LogStorageConfigSource {
|
|
264
|
+
layers: readonly [LogStorageConfigLayerSource, LogStorageConfigLayerSource];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Raw user and project `logs.storage` layers with their origin intact.
|
|
269
|
+
*
|
|
270
|
+
* Storage retention validates these as one fail-closed unit. It cannot use the
|
|
271
|
+
* ordinary merged reader because commands must explain whether each effective
|
|
272
|
+
* scalar came from a user class, user family, project class, or project family.
|
|
273
|
+
*/
|
|
274
|
+
export function logStorageConfigSource(root: string): LogStorageConfigSource {
|
|
275
|
+
const projectPath = join(root, ".harnery", "config.jsonc");
|
|
276
|
+
const user = parseConfigLayer(userConfigPath());
|
|
277
|
+
const project = parseConfigLayer(projectPath);
|
|
278
|
+
const layer = (source: ReturnType<typeof parseConfigLayer>): LogStorageConfigLayerSource => ({
|
|
279
|
+
layer: source.path_kind,
|
|
280
|
+
value: source.config.logs?.storage,
|
|
281
|
+
invalid: source.invalid,
|
|
282
|
+
signature: source.signature,
|
|
283
|
+
});
|
|
284
|
+
return {
|
|
285
|
+
layers: [layer(user), layer(project)],
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
235
289
|
/**
|
|
236
290
|
* Effective user-plus-project `coord.run_quality` value with parse diagnostics.
|
|
237
291
|
* The ordinary config reader stays fail-soft; this one lets the guard visibly
|
|
@@ -387,6 +441,28 @@ export function resolveHooksSetupHint(coordRoot?: string | null): string | null
|
|
|
387
441
|
return typeof hint === "string" && hint.trim() ? hint.trim() : null;
|
|
388
442
|
}
|
|
389
443
|
|
|
444
|
+
/**
|
|
445
|
+
* One project-owned reminder that a supported prompt hook can place immediately
|
|
446
|
+
* before a model response. The value is deliberately project-only: host policy
|
|
447
|
+
* must not follow the user-global config into unrelated repositories. It is
|
|
448
|
+
* emitted directly from config and never copied into coordination state.
|
|
449
|
+
*
|
|
450
|
+
* The reminder must be one non-empty line of at most 500 characters. Invalid
|
|
451
|
+
* values fail closed to no reminder so a malformed optional setting cannot
|
|
452
|
+
* break the prompt hook.
|
|
453
|
+
*/
|
|
454
|
+
export function hostPromptReminder(coordRoot?: string | null): string | null {
|
|
455
|
+
const root = coordRoot ?? findCoordRoot();
|
|
456
|
+
if (!root) return null;
|
|
457
|
+
const value = readProjectConfig(root).instructions?.promptReminder;
|
|
458
|
+
if (typeof value !== "string") return null;
|
|
459
|
+
const reminder = value.trim();
|
|
460
|
+
if (!reminder || reminder.length > MAX_HOST_PROMPT_REMINDER_CHARS || /[\r\n]/.test(reminder)) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
return reminder;
|
|
464
|
+
}
|
|
465
|
+
|
|
390
466
|
/**
|
|
391
467
|
* Whether the host requires the guarded Git check at the end of tool-using
|
|
392
468
|
* turns. Default false: Harnery exposes `agents status --end-turn` as a capability
|
|
@@ -531,6 +607,21 @@ export function coordFreshnessSeconds(coordRoot?: string | null): number {
|
|
|
531
607
|
return DEFAULT_FRESHNESS_SECS;
|
|
532
608
|
}
|
|
533
609
|
|
|
610
|
+
/**
|
|
611
|
+
* Active-segment byte size at which the V3 event ledger rotates to a fresh
|
|
612
|
+
* epoch. Every reader validates the complete epoch, so an unbounded active
|
|
613
|
+
* segment makes each cold read (one per hook process) scale with all history.
|
|
614
|
+
* Precedence:
|
|
615
|
+
* 1. `HARNERY_EVENT_V3_ROTATE_ACTIVE_BYTES` env
|
|
616
|
+
* 2. `.harnery/config.jsonc` `events.rotate_active_bytes`
|
|
617
|
+
* 3. 33554432 (32 MiB)
|
|
618
|
+
* `0` (or a negative value) disables automatic rotation.
|
|
619
|
+
*/
|
|
620
|
+
export function eventLedgerRotateActiveBytes(coordRoot?: string | null): number {
|
|
621
|
+
const root = coordRoot ?? findCoordRoot();
|
|
622
|
+
return resolveEventLedgerRotateActiveBytesV3(root);
|
|
623
|
+
}
|
|
624
|
+
|
|
534
625
|
function parseWebPort(value: unknown, source: string): number {
|
|
535
626
|
const port = typeof value === "number" ? value : Number(value);
|
|
536
627
|
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
|
|
@@ -612,6 +703,36 @@ export function artifactDefaultRetentionDays(coordRoot?: string | null): number
|
|
|
612
703
|
: 3;
|
|
613
704
|
}
|
|
614
705
|
|
|
706
|
+
/**
|
|
707
|
+
* Whether the daily SessionStart sweep of expired artifact workspaces runs.
|
|
708
|
+
* Precedence: `HARNERY_ARTIFACT_AUTO_CLEAN` (0/false disables) ->
|
|
709
|
+
* `artifacts.auto_clean` -> enabled. The sweep only ever deletes
|
|
710
|
+
* `managed-expired` entries via the same guarded classifier as
|
|
711
|
+
* `artifacts clean --yes`.
|
|
712
|
+
*/
|
|
713
|
+
export function artifactAutoCleanEnabled(coordRoot?: string | null): boolean {
|
|
714
|
+
const env = coordEnv("ARTIFACT_AUTO_CLEAN");
|
|
715
|
+
if (env !== undefined) return !(env === "0" || env.toLowerCase() === "false");
|
|
716
|
+
const root = coordRoot ?? findCoordRoot();
|
|
717
|
+
if (!root) return true;
|
|
718
|
+
return readConfig(root).artifacts?.auto_clean !== false;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Sweep cadence in hours. Env-only (`HARNERY_ARTIFACT_AUTO_CLEAN_INTERVAL_HOURS`,
|
|
723
|
+
* mainly for tests): the cadence is an implementation detail, not policy, and
|
|
724
|
+
* retention itself is quantized in whole days, so the 24h default is not a
|
|
725
|
+
* config surface.
|
|
726
|
+
*/
|
|
727
|
+
export function artifactAutoCleanIntervalHours(): number {
|
|
728
|
+
const env = coordEnv("ARTIFACT_AUTO_CLEAN_INTERVAL_HOURS");
|
|
729
|
+
if (env !== undefined) {
|
|
730
|
+
const n = Number(env);
|
|
731
|
+
if (Number.isFinite(n) && n > 0 && n <= 24 * 365) return n;
|
|
732
|
+
}
|
|
733
|
+
return 24;
|
|
734
|
+
}
|
|
735
|
+
|
|
615
736
|
/** Resolved `harn backup` defaults (restic repo/password + prune policy). */
|
|
616
737
|
export interface BackupConfig {
|
|
617
738
|
repo: string;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
appendDurableHistoryRecord,
|
|
5
|
+
type DurableHistoryFaultBoundary,
|
|
6
|
+
readDurableHistorySync,
|
|
7
|
+
} from "../storage/durable-history.ts";
|
|
8
|
+
import type {
|
|
9
|
+
HarneryConversationAccessMode,
|
|
10
|
+
HarneryConversationArchiveAuthorityMode,
|
|
11
|
+
HarneryConversationProvider,
|
|
12
|
+
HarneryConversationRecordV1,
|
|
13
|
+
HarneryConversationSourceSnapshot,
|
|
14
|
+
} from "./contract.ts";
|
|
15
|
+
import { digest, normalizeConversationRecord } from "./normalize.ts";
|
|
16
|
+
|
|
17
|
+
export const HARNERY_CONVERSATION_MANIFEST_SCHEMA = "harnery.conversation-manifest/v1" as const;
|
|
18
|
+
|
|
19
|
+
export interface HarneryConversationArchiveManifest {
|
|
20
|
+
schema: typeof HARNERY_CONVERSATION_MANIFEST_SCHEMA;
|
|
21
|
+
policy_version: "conversation-archive-v1";
|
|
22
|
+
provider_id: string;
|
|
23
|
+
project_scope_id: string;
|
|
24
|
+
conversation_id: string;
|
|
25
|
+
source_snapshot_id: string;
|
|
26
|
+
completeness: HarneryConversationSourceSnapshot["completeness"];
|
|
27
|
+
omissions: readonly string[];
|
|
28
|
+
record_count: number;
|
|
29
|
+
logical_bytes: number;
|
|
30
|
+
first_occurred_at?: string;
|
|
31
|
+
last_occurred_at?: string;
|
|
32
|
+
record_set_digest: `sha256:${string}`;
|
|
33
|
+
authority_mode: HarneryConversationArchiveAuthorityMode;
|
|
34
|
+
updated_at: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface CaptureConversationOptions {
|
|
38
|
+
coord_root: string;
|
|
39
|
+
project_scope_id: string;
|
|
40
|
+
conversation_id: string;
|
|
41
|
+
access_mode: HarneryConversationAccessMode;
|
|
42
|
+
authority_mode: HarneryConversationArchiveAuthorityMode;
|
|
43
|
+
now?: () => Date;
|
|
44
|
+
fault?: (
|
|
45
|
+
boundary:
|
|
46
|
+
| DurableHistoryFaultBoundary
|
|
47
|
+
| "after_record_append"
|
|
48
|
+
| "before_manifest_publish"
|
|
49
|
+
| "after_manifest_publish",
|
|
50
|
+
) => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface CaptureConversationResult {
|
|
54
|
+
state: "disabled" | "source-only" | "captured";
|
|
55
|
+
accepted: number;
|
|
56
|
+
duplicates: number;
|
|
57
|
+
omissions: readonly string[];
|
|
58
|
+
manifest?: HarneryConversationArchiveManifest;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function captureProviderConversation(
|
|
62
|
+
provider: HarneryConversationProvider,
|
|
63
|
+
options: CaptureConversationOptions,
|
|
64
|
+
): Promise<CaptureConversationResult> {
|
|
65
|
+
if (options.access_mode === "off") return result("disabled");
|
|
66
|
+
if (options.access_mode === "source") return result("source-only");
|
|
67
|
+
const objectDir = conversationArchiveDir(
|
|
68
|
+
options.coord_root,
|
|
69
|
+
provider.capabilities.provider_id,
|
|
70
|
+
options.conversation_id,
|
|
71
|
+
);
|
|
72
|
+
mkdirSync(objectDir, { recursive: true, mode: 0o700 });
|
|
73
|
+
const lease = join(objectDir, ".capture.lease");
|
|
74
|
+
try {
|
|
75
|
+
mkdirSync(lease, { mode: 0o700 });
|
|
76
|
+
} catch {
|
|
77
|
+
throw new Error(`conversation capture lease busy: ${options.conversation_id}`);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const snapshot = await provider.snapshot(options.project_scope_id, options.conversation_id);
|
|
81
|
+
const existing = readConversationArchive(objectDir);
|
|
82
|
+
const seen = new Map(existing.map((record) => [record.record_id, record.content_digest]));
|
|
83
|
+
let accepted = 0;
|
|
84
|
+
let duplicates = 0;
|
|
85
|
+
const omissions = new Set(snapshot.omissions);
|
|
86
|
+
let sequence = existing.at(-1)?.sequence ?? 0;
|
|
87
|
+
for await (const native of provider.stream(options.project_scope_id, options.conversation_id)) {
|
|
88
|
+
const normalized = normalizeConversationRecord({
|
|
89
|
+
capabilities: provider.capabilities,
|
|
90
|
+
snapshot,
|
|
91
|
+
native,
|
|
92
|
+
captured_at: (options.now?.() ?? new Date()).toISOString(),
|
|
93
|
+
sequence: sequence + 1,
|
|
94
|
+
});
|
|
95
|
+
if (!normalized.record) {
|
|
96
|
+
omissions.add(normalized.omission ?? "record_excluded");
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const prior = seen.get(normalized.record.record_id);
|
|
100
|
+
if (prior) {
|
|
101
|
+
if (prior !== normalized.record.content_digest) {
|
|
102
|
+
throw new Error(`conversation record collision: ${normalized.record.record_id}`);
|
|
103
|
+
}
|
|
104
|
+
duplicates += 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
sequence += 1;
|
|
108
|
+
normalized.record.sequence = sequence;
|
|
109
|
+
appendDurableHistoryRecord(objectDir, normalized.record, {
|
|
110
|
+
max_record_bytes: 1_048_576,
|
|
111
|
+
max_segment_bytes: 8_388_608,
|
|
112
|
+
fault: options.fault,
|
|
113
|
+
});
|
|
114
|
+
options.fault?.("after_record_append");
|
|
115
|
+
seen.set(normalized.record.record_id, normalized.record.content_digest);
|
|
116
|
+
accepted += 1;
|
|
117
|
+
}
|
|
118
|
+
const records = readConversationArchive(objectDir);
|
|
119
|
+
const manifest = manifestFor(
|
|
120
|
+
records,
|
|
121
|
+
{ ...snapshot, omissions: [...omissions].sort() },
|
|
122
|
+
options.authority_mode,
|
|
123
|
+
options.now?.() ?? new Date(),
|
|
124
|
+
);
|
|
125
|
+
options.fault?.("before_manifest_publish");
|
|
126
|
+
publishManifest(objectDir, manifest);
|
|
127
|
+
options.fault?.("after_manifest_publish");
|
|
128
|
+
return { state: "captured", accepted, duplicates, omissions: [...omissions].sort(), manifest };
|
|
129
|
+
} finally {
|
|
130
|
+
rmSync(lease, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function readConversationArchive(
|
|
135
|
+
objectDirOrCoordRoot: string,
|
|
136
|
+
providerId?: string,
|
|
137
|
+
conversationId?: string,
|
|
138
|
+
): HarneryConversationRecordV1[] {
|
|
139
|
+
const objectDir =
|
|
140
|
+
providerId && conversationId
|
|
141
|
+
? conversationArchiveDir(objectDirOrCoordRoot, providerId, conversationId)
|
|
142
|
+
: objectDirOrCoordRoot;
|
|
143
|
+
return readDurableHistorySync<HarneryConversationRecordV1>(objectDir, {
|
|
144
|
+
max_record_bytes: 1_048_576,
|
|
145
|
+
max_records: 1_000_000,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function reconcileConversationArchive(input: {
|
|
150
|
+
coord_root: string;
|
|
151
|
+
provider_id: string;
|
|
152
|
+
conversation_id: string;
|
|
153
|
+
snapshot: HarneryConversationSourceSnapshot;
|
|
154
|
+
authority_mode: HarneryConversationArchiveAuthorityMode;
|
|
155
|
+
now: Date;
|
|
156
|
+
}): HarneryConversationArchiveManifest {
|
|
157
|
+
const objectDir = conversationArchiveDir(
|
|
158
|
+
input.coord_root,
|
|
159
|
+
input.provider_id,
|
|
160
|
+
input.conversation_id,
|
|
161
|
+
);
|
|
162
|
+
const manifest = manifestFor(
|
|
163
|
+
readConversationArchive(objectDir),
|
|
164
|
+
input.snapshot,
|
|
165
|
+
input.authority_mode,
|
|
166
|
+
input.now,
|
|
167
|
+
);
|
|
168
|
+
publishManifest(objectDir, manifest);
|
|
169
|
+
return manifest;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function loadConversationManifest(
|
|
173
|
+
coordRoot: string,
|
|
174
|
+
providerId: string,
|
|
175
|
+
conversationId: string,
|
|
176
|
+
): HarneryConversationArchiveManifest | undefined {
|
|
177
|
+
const path = join(conversationArchiveDir(coordRoot, providerId, conversationId), "manifest.json");
|
|
178
|
+
try {
|
|
179
|
+
const parsed = JSON.parse(readFileSync(path, "utf8")) as HarneryConversationArchiveManifest;
|
|
180
|
+
if (parsed.schema !== HARNERY_CONVERSATION_MANIFEST_SCHEMA) throw new Error("unknown schema");
|
|
181
|
+
return parsed;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined;
|
|
184
|
+
throw new Error(`conversation manifest invalid: ${(error as Error).message}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function conversationArchiveDir(
|
|
189
|
+
coordRoot: string,
|
|
190
|
+
providerId: string,
|
|
191
|
+
conversationId: string,
|
|
192
|
+
): string {
|
|
193
|
+
const provider = opaque(providerId);
|
|
194
|
+
const conversation = digest(`${providerId}\0${conversationId}`).slice("sha256:".length, 38);
|
|
195
|
+
return join(resolve(coordRoot), ".harnery", "conversations", provider, conversation);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function manifestFor(
|
|
199
|
+
records: readonly HarneryConversationRecordV1[],
|
|
200
|
+
snapshot: HarneryConversationSourceSnapshot,
|
|
201
|
+
authorityMode: HarneryConversationArchiveAuthorityMode,
|
|
202
|
+
now: Date,
|
|
203
|
+
): HarneryConversationArchiveManifest {
|
|
204
|
+
return {
|
|
205
|
+
schema: HARNERY_CONVERSATION_MANIFEST_SCHEMA,
|
|
206
|
+
policy_version: "conversation-archive-v1",
|
|
207
|
+
provider_id: snapshot.provider_id,
|
|
208
|
+
project_scope_id: snapshot.project_scope_id,
|
|
209
|
+
conversation_id: snapshot.conversation_id,
|
|
210
|
+
source_snapshot_id: snapshot.snapshot_id,
|
|
211
|
+
completeness: snapshot.completeness,
|
|
212
|
+
omissions: [...snapshot.omissions],
|
|
213
|
+
record_count: records.length,
|
|
214
|
+
logical_bytes: records.reduce((sum, record) => sum + record.content_bytes, 0),
|
|
215
|
+
...(records[0] ? { first_occurred_at: records[0].occurred_at } : {}),
|
|
216
|
+
...(records.at(-1) ? { last_occurred_at: records.at(-1)!.occurred_at } : {}),
|
|
217
|
+
record_set_digest: digest(records.map((record) => record.record_id).join("\n")),
|
|
218
|
+
authority_mode: authorityMode,
|
|
219
|
+
updated_at: now.toISOString(),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function publishManifest(objectDir: string, manifest: HarneryConversationArchiveManifest): void {
|
|
224
|
+
const path = join(objectDir, "manifest.json");
|
|
225
|
+
const temp = `${path}.tmp-${process.pid}`;
|
|
226
|
+
writeFileSync(temp, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o600 });
|
|
227
|
+
renameSync(temp, path);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function opaque(value: string): string {
|
|
231
|
+
if (!/^[a-z][a-z0-9-]{1,63}$/.test(value)) throw new Error(`invalid provider id: ${value}`);
|
|
232
|
+
return value;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function result(state: "disabled" | "source-only"): CaptureConversationResult {
|
|
236
|
+
return { state, accepted: 0, duplicates: 0, omissions: [] };
|
|
237
|
+
}
|