harnery 0.38.0 → 0.40.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/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +32 -8
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +97 -6
- package/dist/commands/backup.d.ts +16 -0
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +239 -33
- package/dist/commands/browse.d.ts +8 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +466 -231
- package/dist/commands/diagnostics.d.ts.map +1 -1
- package/dist/commands/diagnostics.js +6 -3
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +20 -4
- package/dist/commands/qa-run.d.ts.map +1 -1
- package/dist/commands/qa-run.js +26 -3
- package/dist/commands/qa-status.d.ts.map +1 -1
- package/dist/commands/qa-status.js +7 -2
- package/dist/commands/resources.d.ts.map +1 -1
- package/dist/commands/resources.js +23 -3
- package/dist/commands/review-pack.d.ts.map +1 -1
- package/dist/commands/review-pack.js +98 -23
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +2 -2
- package/dist/core/adapters/profiles.d.ts +1 -1
- package/dist/core/agents/canonical-emit.d.ts +3 -2
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +2 -0
- package/dist/core/agents/cli.js +13 -6
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +5 -3
- package/dist/core/agents/live-lifecycle-v3.d.ts +2 -2
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.d.ts +7 -5
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +63 -8
- package/dist/core/agents/session-finalizer-v3.d.ts +2 -2
- package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.d.ts +3 -3
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +2 -1
- package/dist/core/agents/state/names.d.ts +35 -2
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +80 -5
- package/dist/core/agents/state/stale-sweep.d.ts +2 -1
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +23 -6
- package/dist/core/agents/turn-elapsed.d.ts +51 -0
- package/dist/core/agents/turn-elapsed.d.ts.map +1 -0
- package/dist/core/agents/turn-elapsed.js +91 -0
- package/dist/core/artifacts/activity.d.ts +14 -0
- package/dist/core/artifacts/activity.d.ts.map +1 -0
- package/dist/core/artifacts/activity.js +52 -0
- package/dist/core/artifacts/delivery-card.d.ts +39 -0
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -0
- package/dist/core/artifacts/delivery-card.js +282 -0
- package/dist/core/artifacts/index.d.ts +42 -7
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +288 -76
- package/dist/core/artifacts/mutation-lock.d.ts +2 -0
- package/dist/core/artifacts/mutation-lock.d.ts.map +1 -0
- package/dist/core/artifacts/mutation-lock.js +91 -0
- package/dist/core/backup/host-snapshot.d.ts +18 -0
- package/dist/core/backup/host-snapshot.d.ts.map +1 -0
- package/dist/core/backup/host-snapshot.js +64 -0
- package/dist/core/config.d.ts +20 -5
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +44 -10
- package/dist/core/diagnostics/advice.d.ts +38 -3
- package/dist/core/diagnostics/advice.d.ts.map +1 -1
- package/dist/core/diagnostics/advice.js +103 -99
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +111 -47
- package/dist/core/diagnostics/comparison.d.ts.map +1 -1
- package/dist/core/diagnostics/comparison.js +3 -2
- package/dist/core/diagnostics/contract.d.ts +15 -31
- package/dist/core/diagnostics/contract.d.ts.map +1 -1
- package/dist/core/diagnostics/contract.js +2 -5
- package/dist/core/diagnostics/index.d.ts +2 -0
- package/dist/core/diagnostics/index.d.ts.map +1 -1
- package/dist/core/diagnostics/index.js +2 -0
- package/dist/core/diagnostics/pressure-contract.d.ts +260 -0
- package/dist/core/diagnostics/pressure-contract.d.ts.map +1 -0
- package/dist/core/diagnostics/pressure-contract.js +70 -0
- package/dist/core/diagnostics/pressure.d.ts +25 -0
- package/dist/core/diagnostics/pressure.d.ts.map +1 -0
- package/dist/core/diagnostics/pressure.js +1138 -0
- package/dist/core/diagnostics/replay.d.ts.map +1 -1
- package/dist/core/diagnostics/replay.js +90 -10
- package/dist/core/events/v3/adapter-id.d.ts +6 -0
- package/dist/core/events/v3/adapter-id.d.ts.map +1 -0
- package/dist/core/events/v3/adapter-id.js +7 -0
- package/dist/core/events/v3/archive-retention.d.ts.map +1 -1
- package/dist/core/events/v3/archive-retention.js +3 -2
- package/dist/core/events/v3/bootstrap.d.ts +41 -4
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +120 -17
- package/dist/core/events/v3/capabilities.d.ts +16 -9
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +37 -2
- package/dist/core/events/v3/capability-drift.d.ts +2 -2
- package/dist/core/events/v3/capability-drift.d.ts.map +1 -1
- package/dist/core/events/v3/control-witness.d.ts +48 -5
- package/dist/core/events/v3/control-witness.d.ts.map +1 -1
- package/dist/core/events/v3/control-witness.js +91 -36
- package/dist/core/events/v3/control.d.ts.map +1 -1
- package/dist/core/events/v3/control.js +22 -2
- package/dist/core/events/v3/index.d.ts +2 -1
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +2 -1
- package/dist/core/events/v3/live-feed.d.ts +7 -1
- package/dist/core/events/v3/live-feed.d.ts.map +1 -1
- package/dist/core/events/v3/live-feed.js +21 -3
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +10 -2
- package/dist/core/events/v3/producers/command-recorder.d.ts +2 -2
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/command-recorder.js +2 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +2 -2
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +2 -1
- package/dist/core/events/v3/producers/hook-base.d.ts +2 -2
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +15 -5
- package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook.js +17 -4
- package/dist/core/events/v3/producers/intake.d.ts +4 -4
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +3 -2
- package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -1
- package/dist/core/events/v3/producers/producer-state-observer.js +2 -1
- package/dist/core/events/v3/producers/recorder.d.ts +16 -5
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +31 -9
- package/dist/core/events/v3/reader.d.ts.map +1 -1
- package/dist/core/events/v3/reader.js +10 -13
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-build.js +3 -2
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +2 -2
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/turn-telemetry.d.ts +2 -2
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.d.ts +16 -14
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +36 -38
- package/dist/core/hooks/backup-schedule.d.ts +34 -0
- package/dist/core/hooks/backup-schedule.d.ts.map +1 -0
- package/dist/core/hooks/backup-schedule.js +114 -0
- package/dist/core/hooks/cli.js +61 -18
- package/dist/core/hooks/codex-wsl-bridge.d.ts +2 -0
- package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -1
- package/dist/core/hooks/codex-wsl-bridge.js +18 -4
- package/dist/core/hooks/index.d.ts +1 -0
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js +1 -0
- package/dist/core/hooks/prompt-context/contract.d.ts +61 -0
- package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/contract.js +102 -0
- package/dist/core/hooks/prompt-context/index.d.ts +5 -0
- package/dist/core/hooks/prompt-context/index.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/index.js +2 -0
- package/dist/core/hooks/prompt-context/runner.d.ts +24 -0
- package/dist/core/hooks/prompt-context/runner.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/runner.js +249 -0
- package/dist/core/qa-artifacts.d.ts +3 -0
- package/dist/core/qa-artifacts.d.ts.map +1 -1
- package/dist/core/qa-artifacts.js +25 -3
- package/dist/core/resources/contract.d.ts +69 -3
- package/dist/core/resources/contract.d.ts.map +1 -1
- package/dist/core/resources/contract.js +1 -1
- package/dist/core/resources/index.d.ts +1 -0
- package/dist/core/resources/index.d.ts.map +1 -1
- package/dist/core/resources/index.js +1 -0
- package/dist/core/resources/native.d.ts +36 -0
- package/dist/core/resources/native.d.ts.map +1 -0
- package/dist/core/resources/native.js +418 -0
- package/dist/core/resources/sampler.d.ts +2 -0
- package/dist/core/resources/sampler.d.ts.map +1 -1
- package/dist/core/resources/sampler.js +31 -1
- package/dist/core/resources/status.d.ts +61 -0
- package/dist/core/resources/status.d.ts.map +1 -0
- package/dist/core/resources/status.js +536 -0
- package/dist/core/resources/system.d.ts +27 -0
- package/dist/core/resources/system.d.ts.map +1 -0
- package/dist/core/resources/system.js +439 -0
- package/dist/core/semantic/contract.d.ts +13 -13
- package/dist/core/semantic/service.d.ts +2 -0
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +27 -4
- package/dist/core/storage/builtins.js +41 -0
- package/dist/core/supervisor/contract.d.ts +41 -3
- package/dist/core/supervisor/contract.d.ts.map +1 -1
- package/dist/core/supervisor/contract.js +3 -2
- package/dist/core/supervisor/findings.d.ts +3 -0
- package/dist/core/supervisor/findings.d.ts.map +1 -1
- package/dist/core/supervisor/findings.js +88 -0
- package/dist/core/supervisor/history.d.ts.map +1 -1
- package/dist/core/supervisor/history.js +14 -0
- package/dist/core/supervisor/ledger-state.d.ts +55 -0
- package/dist/core/supervisor/ledger-state.d.ts.map +1 -0
- package/dist/core/supervisor/ledger-state.js +0 -0
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +120 -7
- package/dist/core/supervisor/storage.d.ts +3 -1
- package/dist/core/supervisor/storage.d.ts.map +1 -1
- package/dist/core/supervisor/storage.js +4 -0
- package/dist/core/workflow/admission.d.ts +3 -0
- package/dist/core/workflow/admission.d.ts.map +1 -1
- package/dist/core/workflow/admission.js +28 -16
- package/dist/core/workflow/engine.js +2 -2
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +6 -1
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +4 -3
- package/dist/lib/browser/capture-fidelity.d.ts +7 -0
- package/dist/lib/browser/capture-fidelity.d.ts.map +1 -1
- package/dist/lib/browser/capture-fidelity.js +17 -0
- package/dist/lib/browser/client.d.ts +9 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +85 -37
- package/dist/lib/browser/index.d.ts +3 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -1
- package/dist/lib/browser/page-review-budget.d.ts +13 -0
- package/dist/lib/browser/page-review-budget.d.ts.map +1 -0
- package/dist/lib/browser/page-review-budget.js +251 -0
- package/dist/lib/browser/page-review-contracts.d.ts +127 -0
- package/dist/lib/browser/page-review-contracts.d.ts.map +1 -0
- package/dist/lib/browser/page-review-contracts.js +5 -0
- package/dist/lib/browser/page-review-evidence.d.ts +48 -0
- package/dist/lib/browser/page-review-evidence.d.ts.map +1 -0
- package/dist/lib/browser/page-review-evidence.js +340 -0
- package/dist/lib/browser/page-review-judge.d.ts +1 -1
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
- package/dist/lib/browser/page-review-judge.js +46 -38
- package/dist/lib/browser/page-review-pack.d.ts +44 -22
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
- package/dist/lib/browser/page-review-pack.js +116 -36
- package/dist/lib/browser/page-review-source.d.ts +12 -0
- package/dist/lib/browser/page-review-source.d.ts.map +1 -0
- package/dist/lib/browser/page-review-source.js +22 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +35 -9
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
- package/dist/lib/browser/qa-run-contracts.js +48 -14
- package/dist/lib/browser/qa-run.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.js +215 -68
- package/dist/lib/browser/qa-snapshot.d.ts +6 -0
- package/dist/lib/browser/qa-snapshot.d.ts.map +1 -1
- package/dist/lib/browser/qa-snapshot.js +259 -48
- package/dist/lib/browser/review-capture-transaction.d.ts +13 -0
- package/dist/lib/browser/review-capture-transaction.d.ts.map +1 -0
- package/dist/lib/browser/review-capture-transaction.js +79 -0
- package/dist/lib/browser/standalone-html.d.ts.map +1 -1
- package/dist/lib/browser/standalone-html.js +4 -2
- package/dist/lib/browser/thumbnail-association.d.ts +34 -0
- package/dist/lib/browser/thumbnail-association.d.ts.map +1 -0
- package/dist/lib/browser/thumbnail-association.js +158 -0
- package/dist/lib/browser/tiling.d.ts +30 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -1
- package/dist/lib/browser/tiling.js +38 -0
- package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
- package/dist/lib/docs-metadata-managed.js +4 -1
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +7 -1
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +1 -0
- package/dist/lib/local-file-url.d.ts +12 -0
- package/dist/lib/local-file-url.d.ts.map +1 -1
- package/dist/lib/local-file-url.js +16 -2
- package/dist/lib/tunnel/state.d.ts +19 -4
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +53 -13
- package/package.json +7 -4
- package/schemas/config.schema.json +69 -2
- package/src/commands/agents.ts +42 -9
- package/src/commands/artifacts.ts +130 -6
- package/src/commands/backup.ts +287 -34
- package/src/commands/browse.ts +564 -267
- package/src/commands/diagnostics.ts +6 -3
- package/src/commands/ledger-v3.ts +20 -3
- package/src/commands/qa-run.ts +37 -3
- package/src/commands/qa-status.ts +11 -2
- package/src/commands/resources.ts +23 -3
- package/src/commands/review-pack.ts +165 -62
- package/src/commands/tunnel.ts +2 -1
- package/src/core/agents/canonical-emit.ts +4 -2
- package/src/core/agents/cli.ts +14 -6
- package/src/core/agents/live-authority-v3.ts +7 -3
- package/src/core/agents/live-lifecycle-v3.ts +2 -2
- package/src/core/agents/render/prompt-context.ts +68 -14
- package/src/core/agents/session-finalizer-v3.ts +2 -2
- package/src/core/agents/state/live-coordination-view.ts +4 -4
- package/src/core/agents/state/names.ts +92 -7
- package/src/core/agents/state/stale-sweep.ts +22 -8
- package/src/core/agents/turn-elapsed.ts +135 -0
- package/src/core/artifacts/activity.ts +71 -0
- package/src/core/artifacts/delivery-card.ts +375 -0
- package/src/core/artifacts/index.ts +385 -91
- package/src/core/artifacts/mutation-lock.ts +106 -0
- package/src/core/backup/host-snapshot.ts +76 -0
- package/src/core/config.ts +66 -13
- package/src/core/diagnostics/advice.ts +148 -120
- package/src/core/diagnostics/bundle.ts +138 -52
- package/src/core/diagnostics/comparison.ts +6 -2
- package/src/core/diagnostics/contract.ts +39 -42
- package/src/core/diagnostics/index.ts +2 -0
- package/src/core/diagnostics/pressure-contract.ts +294 -0
- package/src/core/diagnostics/pressure.ts +1361 -0
- package/src/core/diagnostics/replay.ts +116 -11
- package/src/core/events/v3/adapter-id.ts +12 -0
- package/src/core/events/v3/archive-retention.ts +3 -6
- package/src/core/events/v3/bootstrap.ts +163 -16
- package/src/core/events/v3/capabilities.ts +75 -25
- package/src/core/events/v3/capability-drift.ts +2 -2
- package/src/core/events/v3/control-witness.ts +172 -41
- package/src/core/events/v3/control.ts +34 -2
- package/src/core/events/v3/index.ts +3 -0
- package/src/core/events/v3/live-feed.ts +23 -5
- package/src/core/events/v3/live-routing.ts +14 -2
- package/src/core/events/v3/producers/command-recorder.ts +4 -4
- package/src/core/events/v3/producers/coordination-recorder.ts +4 -4
- package/src/core/events/v3/producers/hook-base.ts +21 -16
- package/src/core/events/v3/producers/hook.ts +21 -4
- package/src/core/events/v3/producers/intake.ts +6 -6
- package/src/core/events/v3/producers/producer-state-observer.ts +2 -1
- package/src/core/events/v3/producers/recorder.ts +50 -21
- package/src/core/events/v3/reader.ts +14 -13
- package/src/core/events/v3/runtime-build.ts +3 -2
- package/src/core/events/v3/runtime-telemetry-capabilities.ts +3 -3
- package/src/core/events/v3/turn-telemetry.ts +4 -4
- package/src/core/hooks/adapter/output.ts +50 -36
- package/src/core/hooks/backup-schedule.ts +147 -0
- package/src/core/hooks/cli.ts +65 -14
- package/src/core/hooks/codex-wsl-bridge.ts +21 -5
- package/src/core/hooks/index.ts +1 -0
- package/src/core/hooks/prompt-context/contract.ts +177 -0
- package/src/core/hooks/prompt-context/index.ts +22 -0
- package/src/core/hooks/prompt-context/runner.ts +303 -0
- package/src/core/qa-artifacts.ts +29 -3
- package/src/core/resources/contract.ts +76 -3
- package/src/core/resources/index.ts +1 -0
- package/src/core/resources/native.ts +481 -0
- package/src/core/resources/sampler.ts +46 -1
- package/src/core/resources/status.ts +717 -0
- package/src/core/resources/system.ts +530 -0
- package/src/core/semantic/service.ts +37 -3
- package/src/core/storage/builtins.ts +41 -0
- package/src/core/supervisor/contract.ts +45 -3
- package/src/core/supervisor/findings.ts +159 -0
- package/src/core/supervisor/history.ts +15 -0
- package/src/core/supervisor/ledger-state.ts +0 -0
- package/src/core/supervisor/service.ts +133 -5
- package/src/core/supervisor/storage.ts +7 -0
- package/src/core/workflow/admission.ts +33 -17
- package/src/core/workflow/engine.ts +2 -2
- package/src/core/workflow/live-session-v3.ts +6 -8
- package/src/core/workflow/proof.ts +4 -3
- package/src/lib/browser/capture-fidelity.ts +23 -0
- package/src/lib/browser/client.ts +96 -44
- package/src/lib/browser/index.ts +15 -1
- package/src/lib/browser/page-review-budget.ts +309 -0
- package/src/lib/browser/page-review-contracts.ts +129 -0
- package/src/lib/browser/page-review-evidence.ts +465 -0
- package/src/lib/browser/page-review-judge.ts +56 -40
- package/src/lib/browser/page-review-pack.ts +181 -43
- package/src/lib/browser/page-review-source.ts +30 -0
- package/src/lib/browser/qa-run-contracts.ts +62 -18
- package/src/lib/browser/qa-run.ts +259 -71
- package/src/lib/browser/qa-snapshot.ts +289 -48
- package/src/lib/browser/review-capture-transaction.ts +106 -0
- package/src/lib/browser/standalone-html.ts +4 -2
- package/src/lib/browser/thumbnail-association.ts +190 -0
- package/src/lib/browser/tiling.ts +63 -0
- package/src/lib/docs-metadata-managed.ts +4 -1
- package/src/lib/identities/assume.ts +12 -4
- package/src/lib/instructions/templates.ts +1 -0
- package/src/lib/local-file-url.ts +17 -2
- package/src/lib/tunnel/state.ts +70 -13
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Freshness helpers shared by `harn backup snapshot` and the session-start
|
|
3
|
+
* scheduler. The host cache is a local, best-effort record of this machine's
|
|
4
|
+
* newest known snapshot: the scheduler reads it to skip a remote restic round
|
|
5
|
+
* trip when the host is plainly current, and restic stays the authority
|
|
6
|
+
* whenever the cache is missing, stale, or written by another host.
|
|
7
|
+
*/
|
|
8
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { hostname } from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
export function parseBackupDuration(value) {
|
|
12
|
+
const match = /^([1-9][0-9]*)(ms|s|m|h|d)$/.exec(value.trim());
|
|
13
|
+
if (!match)
|
|
14
|
+
return null;
|
|
15
|
+
const scalar = Number(match[1]);
|
|
16
|
+
const factor = { ms: 1, s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 }[match[2]];
|
|
17
|
+
const duration = scalar * factor;
|
|
18
|
+
return Number.isSafeInteger(duration) ? duration : null;
|
|
19
|
+
}
|
|
20
|
+
/** Newest snapshot time (epoch ms) in `restic snapshots --json` output, or null. */
|
|
21
|
+
export function newestSnapshotTime(output) {
|
|
22
|
+
try {
|
|
23
|
+
const rows = JSON.parse(output);
|
|
24
|
+
const newest = rows.reduce((latest, row) => {
|
|
25
|
+
const time = typeof row.time === "string" ? Date.parse(row.time) : Number.NaN;
|
|
26
|
+
return Number.isFinite(time) ? Math.max(latest, time) : latest;
|
|
27
|
+
}, Number.NEGATIVE_INFINITY);
|
|
28
|
+
return Number.isFinite(newest) ? newest : null;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function hostSnapshotCachePath(harneryDir) {
|
|
35
|
+
return path.join(harneryDir, "logs", "backup-host-snapshot.json");
|
|
36
|
+
}
|
|
37
|
+
export function readHostSnapshotCache(harneryDir) {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(readFileSync(hostSnapshotCachePath(harneryDir), "utf8"));
|
|
40
|
+
const snapshotAt = typeof parsed.snapshot_at === "string" ? Date.parse(parsed.snapshot_at) : Number.NaN;
|
|
41
|
+
if (typeof parsed.host !== "string" || !Number.isFinite(snapshotAt))
|
|
42
|
+
return null;
|
|
43
|
+
return { host: parsed.host, snapshotAt };
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function recordHostSnapshot(harneryDir, snapshotAt) {
|
|
50
|
+
try {
|
|
51
|
+
const file = hostSnapshotCachePath(harneryDir);
|
|
52
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
53
|
+
const body = `${JSON.stringify({
|
|
54
|
+
host: hostname(),
|
|
55
|
+
snapshot_at: new Date(snapshotAt).toISOString(),
|
|
56
|
+
recorded_at: new Date().toISOString(),
|
|
57
|
+
})}\n`;
|
|
58
|
+
writeFileSync(`${file}.tmp`, body, "utf8");
|
|
59
|
+
renameSync(`${file}.tmp`, file);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// The cache is an optimisation; a failed write only costs a restic query later.
|
|
63
|
+
}
|
|
64
|
+
}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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`, `instructions`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
10
|
+
* `hooksSetupHint`, `hooks`, `agents`, `instructions`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
11
11
|
* `coord` (heartbeat freshness), `logs` (structured-log storage budgets),
|
|
12
12
|
* `artifacts` (working-file retention),
|
|
13
13
|
* `backup` (restic repo/password/prune policy), `sync` (rclone
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* documents its own precedence). Dependency-free (no jsonc npm dep) so it runs on
|
|
19
19
|
* both Bun and Node, and so the ADR-009 vendored copies stay portable.
|
|
20
20
|
*/
|
|
21
|
+
import { type PromptContextConfig } from "./hooks/prompt-context/contract.js";
|
|
21
22
|
export { DEFAULT_WEB_PORT } from "../lib/local-file-url.js";
|
|
22
23
|
export { DEFAULT_EVENT_LEDGER_ROTATE_ACTIVE_BYTES } from "./events/v3/rotation-config.js";
|
|
23
24
|
/** The standalone CLI's bin name: the resolution floor when nothing else is set. */
|
|
@@ -108,6 +109,13 @@ export declare function resolveHooksSetupHint(coordRoot?: string | null): string
|
|
|
108
109
|
* break the prompt hook.
|
|
109
110
|
*/
|
|
110
111
|
export declare function hostPromptReminder(coordRoot?: string | null): string | null;
|
|
112
|
+
/**
|
|
113
|
+
* Project-owned prompt-context provider settings. The user-global config is
|
|
114
|
+
* ignored because one project's executable and data policy must not become a
|
|
115
|
+
* default for another project. Invalid values fail closed to `null`; callers
|
|
116
|
+
* treat that the same as a disabled provider and keep the prompt hook usable.
|
|
117
|
+
*/
|
|
118
|
+
export declare function hostPromptContextConfig(coordRoot?: string | null): PromptContextConfig | null;
|
|
111
119
|
/**
|
|
112
120
|
* Whether the host requires the guarded Git check at the end of tool-using
|
|
113
121
|
* turns. Default false: Harnery exposes `agents status --end-turn` as a capability
|
|
@@ -213,7 +221,7 @@ export declare function artifactMaxBytes(coordRoot?: string | null): number;
|
|
|
213
221
|
/** Size at which one bundle requires an explicit `artifacts create --big` acknowledgement. */
|
|
214
222
|
export declare function artifactMaxUnitBytes(coordRoot?: string | null): number;
|
|
215
223
|
/**
|
|
216
|
-
* Whether
|
|
224
|
+
* Whether opportunistic cleanup of expired artifact workspaces runs.
|
|
217
225
|
* Precedence: `HARNERY_ARTIFACT_AUTO_CLEAN` (0/false disables) ->
|
|
218
226
|
* `artifacts.auto_clean` -> enabled. The sweep only ever deletes
|
|
219
227
|
* `managed-expired` entries via the same guarded classifier as
|
|
@@ -230,15 +238,21 @@ export declare function artifactAutoCleanEnabled(coordRoot?: string | null): boo
|
|
|
230
238
|
export declare function reviewPackAutoCleanEnabled(coordRoot?: string | null): boolean;
|
|
231
239
|
/**
|
|
232
240
|
* Sweep cadence in hours. Env-only (`HARNERY_ARTIFACT_AUTO_CLEAN_INTERVAL_HOURS`,
|
|
233
|
-
* mainly for tests)
|
|
234
|
-
*
|
|
235
|
-
* config surface.
|
|
241
|
+
* mainly for tests). Session starts and new artifact work share the hourly
|
|
242
|
+
* throttle so minute-scale retention is useful within long sessions.
|
|
236
243
|
*/
|
|
237
244
|
export declare function artifactAutoCleanIntervalHours(): number;
|
|
238
245
|
/** Resolved `harn backup` defaults (restic repo/password + prune policy). */
|
|
239
246
|
export interface BackupConfig {
|
|
240
247
|
repo: string;
|
|
241
248
|
passwordFile: string;
|
|
249
|
+
include: readonly string[];
|
|
250
|
+
exclude: readonly string[];
|
|
251
|
+
maxBytes: number;
|
|
252
|
+
schedule: {
|
|
253
|
+
ifStale: string;
|
|
254
|
+
tags: readonly string[];
|
|
255
|
+
} | null;
|
|
242
256
|
keepDaily: number;
|
|
243
257
|
keepWeekly: number;
|
|
244
258
|
keepMonthly: number;
|
|
@@ -247,6 +261,7 @@ export interface BackupConfig {
|
|
|
247
261
|
* `harn backup` (restic) defaults. Per field, precedence is env → config → built-in:
|
|
248
262
|
* repo: `HARNERY_RESTIC_REPO` → `backup.repo` → `~/.cache/harnery/restic-repo`
|
|
249
263
|
* passwordFile: `HARNERY_RESTIC_PASSWORD_FILE` → `backup.password_file` → `~/.config/harnery/restic-password`
|
|
264
|
+
* include/exclude/maxBytes/schedule: `backup.*` → catalog defaults / 50 MiB / disabled
|
|
250
265
|
* keepDaily/Weekly/Monthly: `backup.keep_*` → 7 / 4 / 6
|
|
251
266
|
* `coordRoot` is resolved via `findCoordRoot()` when not passed.
|
|
252
267
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,wCAAwC,EAAE,MAAM,gCAAgC,CAAC;AAE1F,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,2EAA2E;AAC3E,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,MAAM,WAAW,yBAAyB;IACxC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,eAAO,MAAM,mCAAmC,EAAE,yBAMjD,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,4BAA4B,CAAC;CAC3C;AAsID,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAqCvD;AA0CD,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,SAAS,CAAC,2BAA2B,EAAE,2BAA2B,CAAC,CAAC;CAC7E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CAa3E;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,2BAA2B,CAqBrF;AAmFD;;;;;;;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;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAU3E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,mBAAmB,GAAG,IAAI,CAI7F;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAO/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,EAAE,CAY1F;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIxE;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;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAG9E;AAMD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,0EAA0E;AAC1E,wBAAgB,wBAAwB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,wBAAwB,CA+B5F;AAUD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAcvF;AAED,8EAA8E;AAC9E,wBAAgB,yBAAyB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,yBAAyB,CA0B9F;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAe9E;AAKD,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CASlE;AAED,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAStE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAM3E;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAM7E;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CAOvD;AA4BD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CA0CpE;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
|
@@ -7,7 +7,7 @@
|
|
|
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`, `instructions`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
10
|
+
* `hooksSetupHint`, `hooks`, `agents`, `instructions`, `tools`, `workflow`, `skills`, `presence`, plus the tunable
|
|
11
11
|
* `coord` (heartbeat freshness), `logs` (structured-log storage budgets),
|
|
12
12
|
* `artifacts` (working-file retention),
|
|
13
13
|
* `backup` (restic repo/password/prune policy), `sync` (rclone
|
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { readFileSync, statSync } from "node:fs";
|
|
22
22
|
import { homedir } from "node:os";
|
|
23
|
-
import { join } from "node:path";
|
|
23
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
24
24
|
import { coordEnv } from "../lib/env.js";
|
|
25
25
|
import { DEFAULT_WEB_PORT } from "../lib/local-file-url.js";
|
|
26
26
|
import { resolveEventLedgerRotateActiveBytesV3 } from "./events/v3/rotation-config.js";
|
|
27
|
+
import { parsePromptContextConfig, } from "./hooks/prompt-context/contract.js";
|
|
27
28
|
import { findCoordRoot } from "./hooks/resolve/coord-root.js";
|
|
28
29
|
export { DEFAULT_WEB_PORT } from "../lib/local-file-url.js";
|
|
29
30
|
export { DEFAULT_EVENT_LEDGER_ROTATE_ACTIVE_BYTES } from "./events/v3/rotation-config.js";
|
|
@@ -304,6 +305,18 @@ export function hostPromptReminder(coordRoot) {
|
|
|
304
305
|
}
|
|
305
306
|
return reminder;
|
|
306
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Project-owned prompt-context provider settings. The user-global config is
|
|
310
|
+
* ignored because one project's executable and data policy must not become a
|
|
311
|
+
* default for another project. Invalid values fail closed to `null`; callers
|
|
312
|
+
* treat that the same as a disabled provider and keep the prompt hook usable.
|
|
313
|
+
*/
|
|
314
|
+
export function hostPromptContextConfig(coordRoot) {
|
|
315
|
+
const root = coordRoot ?? findCoordRoot();
|
|
316
|
+
if (!root)
|
|
317
|
+
return null;
|
|
318
|
+
return parsePromptContextConfig(readProjectConfig(root).hooks?.promptContext);
|
|
319
|
+
}
|
|
307
320
|
/**
|
|
308
321
|
* Whether the host requires the guarded Git check at the end of tool-using
|
|
309
322
|
* turns. Default false: Harnery exposes `agents status --end-turn` as a capability
|
|
@@ -567,7 +580,7 @@ export function artifactMaxUnitBytes(coordRoot) {
|
|
|
567
580
|
return integerSetting(coordEnv("ARTIFACT_MAX_UNIT_BYTES"), root ? readConfig(root).artifacts?.max_unit_bytes : undefined, 16 * 1024 * 1024, 1024 * 1024 * 1024 * 1024, DEFAULT_ARTIFACT_MAX_UNIT_BYTES);
|
|
568
581
|
}
|
|
569
582
|
/**
|
|
570
|
-
* Whether
|
|
583
|
+
* Whether opportunistic cleanup of expired artifact workspaces runs.
|
|
571
584
|
* Precedence: `HARNERY_ARTIFACT_AUTO_CLEAN` (0/false disables) ->
|
|
572
585
|
* `artifacts.auto_clean` -> enabled. The sweep only ever deletes
|
|
573
586
|
* `managed-expired` entries via the same guarded classifier as
|
|
@@ -600,9 +613,8 @@ export function reviewPackAutoCleanEnabled(coordRoot) {
|
|
|
600
613
|
}
|
|
601
614
|
/**
|
|
602
615
|
* Sweep cadence in hours. Env-only (`HARNERY_ARTIFACT_AUTO_CLEAN_INTERVAL_HOURS`,
|
|
603
|
-
* mainly for tests)
|
|
604
|
-
*
|
|
605
|
-
* config surface.
|
|
616
|
+
* mainly for tests). Session starts and new artifact work share the hourly
|
|
617
|
+
* throttle so minute-scale retention is useful within long sessions.
|
|
606
618
|
*/
|
|
607
619
|
export function artifactAutoCleanIntervalHours() {
|
|
608
620
|
const env = coordEnv("ARTIFACT_AUTO_CLEAN_INTERVAL_HOURS");
|
|
@@ -611,7 +623,7 @@ export function artifactAutoCleanIntervalHours() {
|
|
|
611
623
|
if (Number.isFinite(n) && n > 0 && n <= 24 * 365)
|
|
612
624
|
return n;
|
|
613
625
|
}
|
|
614
|
-
return
|
|
626
|
+
return 1;
|
|
615
627
|
}
|
|
616
628
|
function integerSetting(envValue, configured, minimum, maximum, fallback) {
|
|
617
629
|
for (const value of [envValue, configured]) {
|
|
@@ -634,6 +646,7 @@ function booleanSetting(envValue, configured, fallback) {
|
|
|
634
646
|
* `harn backup` (restic) defaults. Per field, precedence is env → config → built-in:
|
|
635
647
|
* repo: `HARNERY_RESTIC_REPO` → `backup.repo` → `~/.cache/harnery/restic-repo`
|
|
636
648
|
* passwordFile: `HARNERY_RESTIC_PASSWORD_FILE` → `backup.password_file` → `~/.config/harnery/restic-password`
|
|
649
|
+
* include/exclude/maxBytes/schedule: `backup.*` → catalog defaults / 50 MiB / disabled
|
|
637
650
|
* keepDaily/Weekly/Monthly: `backup.keep_*` → 7 / 4 / 6
|
|
638
651
|
* `coordRoot` is resolved via `findCoordRoot()` when not passed.
|
|
639
652
|
*/
|
|
@@ -643,12 +656,33 @@ export function backupConfig(coordRoot) {
|
|
|
643
656
|
const b = root ? (readConfig(root).backup ?? {}) : {};
|
|
644
657
|
const cfgStr = (v) => typeof v === "string" && v.trim() ? v.trim() : undefined;
|
|
645
658
|
const repo = coordEnv("RESTIC_REPO") ?? cfgStr(b.repo) ?? join(home, ".cache", "harnery", "restic-repo");
|
|
646
|
-
const
|
|
647
|
-
|
|
648
|
-
|
|
659
|
+
const envPasswordFile = coordEnv("RESTIC_PASSWORD_FILE");
|
|
660
|
+
const configuredPasswordFile = cfgStr(b.password_file);
|
|
661
|
+
const passwordFile = envPasswordFile
|
|
662
|
+
? envPasswordFile
|
|
663
|
+
: configuredPasswordFile
|
|
664
|
+
? root && !isAbsolute(configuredPasswordFile)
|
|
665
|
+
? resolve(root, configuredPasswordFile)
|
|
666
|
+
: configuredPasswordFile
|
|
667
|
+
: join(home, ".config", "harnery", "restic-password");
|
|
668
|
+
const stringList = (value) => Array.isArray(value)
|
|
669
|
+
? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0)
|
|
670
|
+
: [];
|
|
671
|
+
const schedule = isPlainObject(b.schedule)
|
|
672
|
+
? (() => {
|
|
673
|
+
const ifStale = cfgStr(b.schedule?.if_stale);
|
|
674
|
+
return ifStale
|
|
675
|
+
? { ifStale, tags: stringList(b.schedule?.tags).map((tag) => tag.trim()) }
|
|
676
|
+
: null;
|
|
677
|
+
})()
|
|
678
|
+
: null;
|
|
649
679
|
return {
|
|
650
680
|
repo,
|
|
651
681
|
passwordFile,
|
|
682
|
+
include: stringList(b.include).map((entry) => entry.trim()),
|
|
683
|
+
exclude: stringList(b.exclude).map((entry) => entry.trim()),
|
|
684
|
+
maxBytes: posIntOr(b.max_bytes, 50 * 1_024 * 1_024),
|
|
685
|
+
schedule,
|
|
652
686
|
keepDaily: posIntOr(b.keep_daily, 7),
|
|
653
687
|
keepWeekly: posIntOr(b.keep_weekly, 4),
|
|
654
688
|
keepMonthly: posIntOr(b.keep_monthly, 6),
|
|
@@ -1,9 +1,44 @@
|
|
|
1
|
-
import type { SupervisorCapability,
|
|
2
|
-
import { type DiagnosticAdvice } from "./contract.js";
|
|
1
|
+
import type { SupervisorCapability, SupervisorHistoryPoint } from "../supervisor/contract.js";
|
|
2
|
+
import { type DiagnosticAdvice, type PressureAssessment, type PressureDimension, type PressureHysteresisState, type PressureReasonCode, type PressureScope } from "./contract.js";
|
|
3
|
+
import type { PressureHistorySample } from "./pressure-contract.js";
|
|
4
|
+
/**
|
|
5
|
+
* Advice is an envelope around one already-computed assessment. It maps
|
|
6
|
+
* nothing: severity does not become pressure here, and no numeric threshold is
|
|
7
|
+
* read. `assessPressure` owns the judgement, the observer publishes it, and
|
|
8
|
+
* every surface renders this envelope so all of them agree.
|
|
9
|
+
*/
|
|
3
10
|
export interface BuildDiagnosticAdviceInput {
|
|
4
|
-
|
|
11
|
+
assessment: PressureAssessment;
|
|
12
|
+
/** The state the previous sample carried forward, so a replay can reproduce a transition. */
|
|
13
|
+
priorHysteresis: PressureHysteresisState | null;
|
|
14
|
+
/** Where the assessment came from, and why it is missing when it is. */
|
|
5
15
|
sourceCapability: SupervisorCapability;
|
|
16
|
+
activeFindingCount: number;
|
|
6
17
|
evaluatedAt: string;
|
|
7
18
|
}
|
|
8
19
|
export declare function buildDiagnosticAdvice(input: BuildDiagnosticAdviceInput): DiagnosticAdvice;
|
|
20
|
+
export declare const PRESSURE_DIMENSIONS: readonly PressureDimension[];
|
|
21
|
+
export interface UnknownPressureAssessmentInput {
|
|
22
|
+
observedAt: string;
|
|
23
|
+
/** A stable code from the frozen union, normally `evidence_unavailable` or `snapshot_stale`. */
|
|
24
|
+
reasonCode: PressureReasonCode;
|
|
25
|
+
/** One plain sentence naming what is missing. Becomes the assessment summary. */
|
|
26
|
+
summary: string;
|
|
27
|
+
scope?: PressureScope;
|
|
28
|
+
sampleAgeMs?: number | null;
|
|
29
|
+
prior?: PressureHysteresisState | null;
|
|
30
|
+
observerGeneration?: string | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The assessment to publish when the source is absent, stale, or malformed.
|
|
34
|
+
* Every dimension reads `unavailable` and no owner is named, because a gap in
|
|
35
|
+
* the evidence is not a measurement of health.
|
|
36
|
+
*/
|
|
37
|
+
export declare function unknownPressureAssessment(input: UnknownPressureAssessmentInput): PressureAssessment;
|
|
38
|
+
/**
|
|
39
|
+
* Project bounded supervisor history into the trend input the assessment reads.
|
|
40
|
+
* The observer and a bundle replay both call this, so the trend they compute
|
|
41
|
+
* from the same stored history is the same trend.
|
|
42
|
+
*/
|
|
43
|
+
export declare function pressureHistoryFromSupervisor(points: readonly SupervisorHistoryPoint[]): PressureHistorySample[];
|
|
9
44
|
//# sourceMappingURL=advice.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advice.d.ts","sourceRoot":"","sources":["../../../src/core/diagnostics/advice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"advice.d.ts","sourceRoot":"","sources":["../../../src/core/diagnostics/advice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAEL,KAAK,gBAAgB,EAGrB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EAEtB,KAAK,uBAAuB,EAE5B,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,6FAA6F;IAC7F,eAAe,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAChD,wEAAwE;IACxE,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,gBAAgB,CAWzF;AAED,eAAO,MAAM,mBAAmB,EAAE,SAAS,iBAAiB,EAU3D,CAAC;AAEF,MAAM,WAAW,8BAA8B;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,UAAU,EAAE,kBAAkB,CAAC;IAC/B,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACvC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,8BAA8B,GACpC,kBAAkB,CAiDpB;AA+BD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,SAAS,sBAAsB,EAAE,GACxC,qBAAqB,EAAE,CAUzB"}
|
|
@@ -1,112 +1,116 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const SEVERITY_RANK = {
|
|
3
|
-
info: 0,
|
|
4
|
-
warning: 1,
|
|
5
|
-
critical: 2,
|
|
6
|
-
};
|
|
1
|
+
import { DIAGNOSTIC_ADVICE_SCHEMA_VERSION, PRESSURE_ASSESSMENT_SCHEMA_VERSION, PRESSURE_POLICY, } from "./contract.js";
|
|
7
2
|
export function buildDiagnosticAdvice(input) {
|
|
8
|
-
const sourceAvailable = input.sourceCapability.state === "supported";
|
|
9
|
-
const active = sourceAvailable
|
|
10
|
-
? input.findings.filter((finding) => finding.state === "opened").sort(compareFindings)
|
|
11
|
-
: [];
|
|
12
|
-
const pressureFindings = active.filter((finding) => finding.severity === "warning" || finding.severity === "critical");
|
|
13
|
-
const critical = pressureFindings.filter((finding) => finding.severity === "critical");
|
|
14
|
-
const warning = pressureFindings.filter((finding) => finding.severity === "warning");
|
|
15
|
-
const pressure = critical.length
|
|
16
|
-
? "critical"
|
|
17
|
-
: warning.length
|
|
18
|
-
? "elevated"
|
|
19
|
-
: sourceAvailable
|
|
20
|
-
? "normal"
|
|
21
|
-
: "unknown";
|
|
22
|
-
const fanOutRecommendation = pressure === "critical"
|
|
23
|
-
? "avoid-new-fan-out"
|
|
24
|
-
: pressure === "elevated"
|
|
25
|
-
? "use-caution"
|
|
26
|
-
: pressure === "normal"
|
|
27
|
-
? "proceed"
|
|
28
|
-
: "unknown";
|
|
29
|
-
const contributing = pressureFindings.slice(0, DIAGNOSTIC_ADVICE_LIMITS.max_contributing_findings);
|
|
30
3
|
return {
|
|
31
4
|
schema_version: DIAGNOSTIC_ADVICE_SCHEMA_VERSION,
|
|
32
5
|
evaluated_at: input.evaluatedAt,
|
|
33
|
-
pressure,
|
|
34
|
-
fan_out_recommendation: fanOutRecommendation,
|
|
35
6
|
observer_only: true,
|
|
36
|
-
|
|
7
|
+
assessment: input.assessment,
|
|
8
|
+
prior_hysteresis: input.priorHysteresis,
|
|
37
9
|
source_capability: input.sourceCapability,
|
|
38
|
-
active_finding_count:
|
|
39
|
-
|
|
40
|
-
omitted_contributing_finding_count: Math.max(0, pressureFindings.length - contributing.length),
|
|
41
|
-
contributing_findings: contributing.map(adviceFinding),
|
|
42
|
-
reasons: reasonsFor(critical, warning, input.sourceCapability),
|
|
10
|
+
active_finding_count: Math.max(0, Math.trunc(input.activeFindingCount)),
|
|
11
|
+
summary: input.assessment.summary,
|
|
43
12
|
};
|
|
44
13
|
}
|
|
45
|
-
|
|
14
|
+
export const PRESSURE_DIMENSIONS = [
|
|
15
|
+
"memory_stall",
|
|
16
|
+
"io_stall",
|
|
17
|
+
"cpu_stall",
|
|
18
|
+
"oom_kills",
|
|
19
|
+
"swap_activity",
|
|
20
|
+
"direct_reclaim",
|
|
21
|
+
"memory_available",
|
|
22
|
+
"disk_available",
|
|
23
|
+
"host_memory",
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* The assessment to publish when the source is absent, stale, or malformed.
|
|
27
|
+
* Every dimension reads `unavailable` and no owner is named, because a gap in
|
|
28
|
+
* the evidence is not a measurement of health.
|
|
29
|
+
*/
|
|
30
|
+
export function unknownPressureAssessment(input) {
|
|
31
|
+
const reason = {
|
|
32
|
+
code: input.reasonCode,
|
|
33
|
+
dimension: null,
|
|
34
|
+
summary: input.summary,
|
|
35
|
+
observed_value: null,
|
|
36
|
+
threshold_value: null,
|
|
37
|
+
unit: null,
|
|
38
|
+
sample_count: 0,
|
|
39
|
+
contributes_to: "unknown",
|
|
40
|
+
};
|
|
46
41
|
return {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
schema_version: PRESSURE_ASSESSMENT_SCHEMA_VERSION,
|
|
43
|
+
observer_only: true,
|
|
44
|
+
state: "unknown",
|
|
45
|
+
scope: input.scope ?? "native",
|
|
46
|
+
limiting_resource: "unknown",
|
|
47
|
+
trend: "unknown",
|
|
48
|
+
observed_at: input.observedAt,
|
|
49
|
+
sample_age_ms: input.sampleAgeMs ?? null,
|
|
50
|
+
evidence_state: "unavailable",
|
|
51
|
+
evidence: PRESSURE_DIMENSIONS.map((dimension) => ({
|
|
52
|
+
dimension,
|
|
53
|
+
state: "unavailable",
|
|
54
|
+
observed_value: null,
|
|
55
|
+
unit: null,
|
|
56
|
+
sample_count: 0,
|
|
57
|
+
reason_code: input.reasonCode,
|
|
58
|
+
})).slice(0, PRESSURE_POLICY.limits.max_evidence),
|
|
59
|
+
reasons: [reason],
|
|
60
|
+
contributors: [],
|
|
61
|
+
omitted_contributor_count: 0,
|
|
62
|
+
unattributed_memory_percent: null,
|
|
63
|
+
recommended_action: "unknown",
|
|
64
|
+
summary: input.summary,
|
|
65
|
+
guidance: unknownGuidance(),
|
|
66
|
+
hysteresis: {
|
|
67
|
+
state: "unknown",
|
|
68
|
+
state_since: input.observedAt,
|
|
69
|
+
consecutive_clear_samples: 0,
|
|
70
|
+
dimension_streaks: {},
|
|
71
|
+
oom_baseline_total_kills: input.prior?.oom_baseline_total_kills ?? null,
|
|
72
|
+
oom_hold_until: null,
|
|
73
|
+
observer_generation: input.observerGeneration ?? input.prior?.observer_generation ?? null,
|
|
74
|
+
},
|
|
75
|
+
policy_version: PRESSURE_POLICY.policy_version,
|
|
57
76
|
};
|
|
58
77
|
}
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
summary:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!critical.length && !warning.length && capability.state === "supported") {
|
|
83
|
-
reasons.push({
|
|
84
|
-
code: "no_active_pressure_findings",
|
|
85
|
-
summary: "No active warning or critical findings were observed.",
|
|
86
|
-
finding_ids: [],
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
return reasons.slice(0, DIAGNOSTIC_ADVICE_LIMITS.max_reasons);
|
|
90
|
-
}
|
|
91
|
-
function boundedIds(findings) {
|
|
92
|
-
return findings
|
|
93
|
-
.slice(0, DIAGNOSTIC_ADVICE_LIMITS.max_contributing_findings)
|
|
94
|
-
.map((finding) => finding.id);
|
|
95
|
-
}
|
|
96
|
-
function summaryFor(pressure) {
|
|
97
|
-
switch (pressure) {
|
|
98
|
-
case "critical":
|
|
99
|
-
return "Critical local pressure is active. Avoid starting additional agent work until the findings change.";
|
|
100
|
-
case "elevated":
|
|
101
|
-
return "Elevated local pressure is active. Limit new fan-out and inspect the contributing findings.";
|
|
102
|
-
case "normal":
|
|
103
|
-
return "No active warning or critical findings were observed. Diagnostics do not restrict new fan-out.";
|
|
104
|
-
case "unknown":
|
|
105
|
-
return "Local pressure cannot be determined because the findings source is unavailable.";
|
|
106
|
-
}
|
|
78
|
+
function unknownGuidance() {
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
workload_class: "lightweight",
|
|
82
|
+
recommendation: "unknown",
|
|
83
|
+
summary: "Reads and small edits cost almost nothing, so continue them while the measurements are missing.",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
workload_class: "cpu-heavy",
|
|
87
|
+
recommendation: "unknown",
|
|
88
|
+
summary: "Builds and test runs cannot be judged from here. Start one only if you already know the machine is idle.",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
workload_class: "memory-heavy",
|
|
92
|
+
recommendation: "unknown",
|
|
93
|
+
summary: "Browser captures and page QA cannot be judged from here. Run one at a time until the measurements return.",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
workload_class: "storage-heavy",
|
|
97
|
+
recommendation: "unknown",
|
|
98
|
+
summary: "Large writes and exports cannot be judged from here. Check free disk space yourself before starting one.",
|
|
99
|
+
},
|
|
100
|
+
];
|
|
107
101
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Project bounded supervisor history into the trend input the assessment reads.
|
|
104
|
+
* The observer and a bundle replay both call this, so the trend they compute
|
|
105
|
+
* from the same stored history is the same trend.
|
|
106
|
+
*/
|
|
107
|
+
export function pressureHistoryFromSupervisor(points) {
|
|
108
|
+
return points.slice(-PRESSURE_POLICY.max_history_samples).map((point) => ({
|
|
109
|
+
sampled_at: point.sampled_at,
|
|
110
|
+
memory_full_avg10: point.pressure.memory_full_avg10,
|
|
111
|
+
io_full_avg10: point.pressure.io_full_avg10,
|
|
112
|
+
cpu_some_avg60: point.pressure.cpu_some_avg60,
|
|
113
|
+
memory_available_percent: point.machine.memory_percent === null ? null : 100 - point.machine.memory_percent,
|
|
114
|
+
swap_out_bytes_per_second: point.pressure.swap_out_bytes_per_second,
|
|
115
|
+
}));
|
|
112
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../../src/core/diagnostics/bundle.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EAEvB,MAAM,uBAAuB,CAAC;AAwB/B,OAAO,
|
|
1
|
+
{"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../../src/core/diagnostics/bundle.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EAEvB,MAAM,uBAAuB,CAAC;AAwB/B,OAAO,EASL,KAAK,wBAAwB,EAG7B,KAAK,sBAAsB,EAE3B,KAAK,iBAAiB,EAItB,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AA2BvB,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,wBAAwB,CAAC;IACnC,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,4BAA4B;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;IACzD,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,4BAAiC,GACvC,wBAAwB,CAwG1B;AAkCD,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GACV,yBAAyB,CAsB3B;AAED,gFAAgF;AAChF,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,yBAAyB,CAK3B;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,yBAAyB,CAE7F;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,uBAAuB,EAAE,CA0BjF;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,4BAA4B,EAAE,CA4C/F;AAqCD,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,OAAa,GACf,sBAAsB,CAgBxB"}
|