harnery 0.36.0 → 0.38.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 +9 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +10 -1
- package/dist/commands/admission.d.ts +21 -0
- package/dist/commands/admission.d.ts.map +1 -0
- package/dist/commands/admission.js +565 -0
- package/dist/commands/agents.d.ts +7 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +148 -47
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +73 -2
- package/dist/commands/browse-ai.d.ts +2 -2
- package/dist/commands/browse-ai.d.ts.map +1 -1
- package/dist/commands/browse-ai.js +6 -4
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +360 -21
- package/dist/commands/diagnostics.d.ts +4 -0
- package/dist/commands/diagnostics.d.ts.map +1 -0
- package/dist/commands/diagnostics.js +229 -0
- package/dist/commands/fetch.js +1 -0
- package/dist/commands/files.d.ts +12 -0
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +54 -1
- package/dist/commands/governor.d.ts.map +1 -1
- package/dist/commands/governor.js +4 -0
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +71 -2
- package/dist/commands/qa-record.d.ts +144 -0
- package/dist/commands/qa-record.d.ts.map +1 -0
- package/dist/commands/qa-record.js +0 -0
- package/dist/commands/qa-run.d.ts +8 -0
- package/dist/commands/qa-run.d.ts.map +1 -0
- package/dist/commands/qa-run.js +396 -0
- package/dist/commands/qa-status.d.ts +71 -0
- package/dist/commands/qa-status.d.ts.map +1 -0
- package/dist/commands/qa-status.js +490 -0
- package/dist/commands/qa-verify.d.ts +40 -0
- package/dist/commands/qa-verify.d.ts.map +1 -0
- package/dist/commands/qa-verify.js +180 -0
- package/dist/commands/resources.d.ts +4 -0
- package/dist/commands/resources.d.ts.map +1 -0
- package/dist/commands/resources.js +29 -0
- package/dist/commands/review-pack.d.ts +4 -0
- package/dist/commands/review-pack.d.ts.map +1 -0
- package/dist/commands/review-pack.js +1001 -0
- package/dist/commands/supervisor.d.ts +4 -0
- package/dist/commands/supervisor.d.ts.map +1 -0
- package/dist/commands/supervisor.js +101 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +17 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +4 -0
- package/dist/core/agents/cli.js +7 -3
- package/dist/core/agents/health.d.ts +17 -0
- package/dist/core/agents/health.d.ts.map +1 -0
- package/dist/core/agents/health.js +109 -0
- package/dist/core/agents/mailbox.d.ts +92 -0
- package/dist/core/agents/mailbox.d.ts.map +1 -0
- package/dist/core/agents/mailbox.js +325 -0
- package/dist/core/agents/qa-signal.d.ts +111 -0
- package/dist/core/agents/qa-signal.d.ts.map +1 -0
- package/dist/core/agents/qa-signal.js +231 -0
- package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
- package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
- package/dist/core/agents/reconcile-coordination-v3.js +58 -0
- package/dist/core/agents/render/prompt-context.d.ts +5 -0
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +34 -13
- package/dist/core/agents/render/session-context.d.ts +8 -0
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +34 -3
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +50 -1
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +6 -10
- package/dist/core/agents/session-finalizer-v3.js +4 -1
- package/dist/core/agents/session-name-display.d.ts +20 -5
- package/dist/core/agents/session-name-display.d.ts.map +1 -1
- package/dist/core/agents/session-name-display.js +67 -7
- package/dist/core/agents/state/heartbeat-reader.d.ts +7 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.d.ts +11 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +17 -0
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +1 -0
- package/dist/core/agents/state/live-coordination-writer.js +5 -0
- package/dist/core/artifacts/constants.d.ts +1 -1
- package/dist/core/artifacts/constants.js +1 -1
- package/dist/core/artifacts/index.d.ts +82 -6
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +410 -15
- package/dist/core/config.d.ts +20 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +59 -0
- package/dist/core/diagnostics/advice.d.ts +9 -0
- package/dist/core/diagnostics/advice.d.ts.map +1 -0
- package/dist/core/diagnostics/advice.js +112 -0
- package/dist/core/diagnostics/bundle.d.ts +51 -0
- package/dist/core/diagnostics/bundle.d.ts.map +1 -0
- package/dist/core/diagnostics/bundle.js +968 -0
- package/dist/core/diagnostics/comparison.d.ts +5 -0
- package/dist/core/diagnostics/comparison.d.ts.map +1 -0
- package/dist/core/diagnostics/comparison.js +444 -0
- package/dist/core/diagnostics/contract.d.ts +245 -0
- package/dist/core/diagnostics/contract.d.ts.map +1 -0
- package/dist/core/diagnostics/contract.js +18 -0
- package/dist/core/diagnostics/identity.d.ts +3 -0
- package/dist/core/diagnostics/identity.d.ts.map +1 -0
- package/dist/core/diagnostics/identity.js +10 -0
- package/dist/core/diagnostics/index.d.ts +8 -0
- package/dist/core/diagnostics/index.d.ts.map +1 -0
- package/dist/core/diagnostics/index.js +7 -0
- package/dist/core/diagnostics/replay.d.ts +8 -0
- package/dist/core/diagnostics/replay.d.ts.map +1 -0
- package/dist/core/diagnostics/replay.js +213 -0
- package/dist/core/diagnostics/sanitize.d.ts +9 -0
- package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
- package/dist/core/diagnostics/sanitize.js +84 -0
- package/dist/core/events/legacy-storage/compression.d.ts +13 -0
- package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/compression.js +107 -0
- package/dist/core/events/legacy-storage/index.d.ts +1 -0
- package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
- package/dist/core/events/legacy-storage/index.js +1 -0
- package/dist/core/events/v3/archive-retention.d.ts +33 -0
- package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
- package/dist/core/events/v3/archive-retention.js +195 -0
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +10 -0
- package/dist/core/events/v3/capabilities.d.ts +1 -1
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +1 -0
- package/dist/core/events/v3/coordination-view.d.ts +3 -0
- package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
- package/dist/core/events/v3/coordination-view.js +69 -8
- package/dist/core/events/v3/index.d.ts +1 -0
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +1 -0
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +1 -0
- package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +13 -2
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +10 -2
- package/dist/core/events/v3/producers/recorder.d.ts +39 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +350 -17
- package/dist/core/hooks/adapter/output.d.ts +8 -0
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +11 -1
- package/dist/core/hooks/cli.js +303 -219
- package/dist/core/hooks/health.d.ts +59 -0
- package/dist/core/hooks/health.d.ts.map +1 -0
- package/dist/core/hooks/health.js +84 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +10 -3
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
- package/dist/core/hooks/session-name-presence.js +4 -1
- package/dist/core/qa-artifacts.d.ts +20 -0
- package/dist/core/qa-artifacts.d.ts.map +1 -0
- package/dist/core/qa-artifacts.js +110 -0
- package/dist/core/resources/contract.d.ts +96 -0
- package/dist/core/resources/contract.d.ts.map +1 -0
- package/dist/core/resources/contract.js +2 -0
- package/dist/core/resources/index.d.ts +6 -0
- package/dist/core/resources/index.d.ts.map +1 -0
- package/dist/core/resources/index.js +5 -0
- package/dist/core/resources/sampler.d.ts +34 -0
- package/dist/core/resources/sampler.d.ts.map +1 -0
- package/dist/core/resources/sampler.js +458 -0
- package/dist/core/resources/service-status.d.ts +3 -0
- package/dist/core/resources/service-status.d.ts.map +1 -0
- package/dist/core/resources/service-status.js +48 -0
- package/dist/core/resources/service.d.ts +26 -0
- package/dist/core/resources/service.d.ts.map +1 -0
- package/dist/core/resources/service.js +292 -0
- package/dist/core/resources/storage.d.ts +13 -0
- package/dist/core/resources/storage.d.ts.map +1 -0
- package/dist/core/resources/storage.js +30 -0
- package/dist/core/storage/atomic-json.d.ts +3 -0
- package/dist/core/storage/atomic-json.d.ts.map +1 -0
- package/dist/core/storage/atomic-json.js +15 -0
- package/dist/core/storage/builtins.d.ts.map +1 -1
- package/dist/core/storage/builtins.js +45 -6
- package/dist/core/storage/logger.d.ts +2 -0
- package/dist/core/storage/logger.d.ts.map +1 -1
- package/dist/core/storage/logger.js +2 -0
- package/dist/core/storage/query.d.ts +14 -0
- package/dist/core/storage/query.d.ts.map +1 -1
- package/dist/core/storage/query.js +51 -0
- package/dist/core/supervisor/activity.d.ts +4 -0
- package/dist/core/supervisor/activity.d.ts.map +1 -0
- package/dist/core/supervisor/activity.js +141 -0
- package/dist/core/supervisor/contract.d.ts +268 -0
- package/dist/core/supervisor/contract.d.ts.map +1 -0
- package/dist/core/supervisor/contract.js +35 -0
- package/dist/core/supervisor/explanations.d.ts +4 -0
- package/dist/core/supervisor/explanations.d.ts.map +1 -0
- package/dist/core/supervisor/explanations.js +71 -0
- package/dist/core/supervisor/findings.d.ts +20 -0
- package/dist/core/supervisor/findings.d.ts.map +1 -0
- package/dist/core/supervisor/findings.js +399 -0
- package/dist/core/supervisor/history.d.ts +9 -0
- package/dist/core/supervisor/history.d.ts.map +1 -0
- package/dist/core/supervisor/history.js +46 -0
- package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
- package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health-alerts.js +70 -0
- package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
- package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health-storage.js +24 -0
- package/dist/core/supervisor/hook-health.d.ts +72 -0
- package/dist/core/supervisor/hook-health.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health.js +203 -0
- package/dist/core/supervisor/hooks.d.ts +10 -0
- package/dist/core/supervisor/hooks.d.ts.map +1 -0
- package/dist/core/supervisor/hooks.js +28 -0
- package/dist/core/supervisor/index.d.ts +15 -0
- package/dist/core/supervisor/index.d.ts.map +1 -0
- package/dist/core/supervisor/index.js +14 -0
- package/dist/core/supervisor/log-feed.d.ts +9 -0
- package/dist/core/supervisor/log-feed.d.ts.map +1 -0
- package/dist/core/supervisor/log-feed.js +103 -0
- package/dist/core/supervisor/service.d.ts +29 -0
- package/dist/core/supervisor/service.d.ts.map +1 -0
- package/dist/core/supervisor/service.js +450 -0
- package/dist/core/supervisor/services.d.ts +11 -0
- package/dist/core/supervisor/services.d.ts.map +1 -0
- package/dist/core/supervisor/services.js +155 -0
- package/dist/core/supervisor/status.d.ts +3 -0
- package/dist/core/supervisor/status.d.ts.map +1 -0
- package/dist/core/supervisor/status.js +48 -0
- package/dist/core/supervisor/storage.d.ts +30 -0
- package/dist/core/supervisor/storage.d.ts.map +1 -0
- package/dist/core/supervisor/storage.js +73 -0
- package/dist/core/supervisor/timeline.d.ts +3 -0
- package/dist/core/supervisor/timeline.d.ts.map +1 -0
- package/dist/core/supervisor/timeline.js +87 -0
- package/dist/core/workflow/admission.d.ts +23 -0
- package/dist/core/workflow/admission.d.ts.map +1 -0
- package/dist/core/workflow/admission.js +136 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +77 -2
- package/dist/core/workflow/index.d.ts +3 -2
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -1
- package/dist/core/workflow/proof.d.ts +2 -1
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +39 -1
- package/dist/core/workflow/run-state.d.ts +3 -2
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +8 -1
- package/dist/core/workflow/types.d.ts +33 -1
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/types.js +2 -1
- package/dist/lib/admission.d.ts +71 -0
- package/dist/lib/admission.d.ts.map +1 -0
- package/dist/lib/admission.js +264 -0
- package/dist/lib/agent-browser/client.d.ts +1 -1
- package/dist/lib/agent-browser/client.d.ts.map +1 -1
- package/dist/lib/agent-browser/client.js +1 -5
- package/dist/lib/browser/capture-fidelity.d.ts +39 -0
- package/dist/lib/browser/capture-fidelity.d.ts.map +1 -0
- package/dist/lib/browser/capture-fidelity.js +84 -0
- package/dist/lib/browser/client.d.ts +46 -1
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +168 -9
- package/dist/lib/browser/critique.d.ts +38 -1
- package/dist/lib/browser/critique.d.ts.map +1 -1
- package/dist/lib/browser/critique.js +34 -6
- package/dist/lib/browser/index.d.ts +5 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +4 -0
- package/dist/lib/browser/page-review-judge.d.ts +64 -0
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -0
- package/dist/lib/browser/page-review-judge.js +270 -0
- package/dist/lib/browser/page-review-pack.d.ts +613 -0
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -0
- package/dist/lib/browser/page-review-pack.js +1751 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +377 -0
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
- package/dist/lib/browser/qa-run-contracts.js +361 -0
- package/dist/lib/browser/qa-run.d.ts +141 -0
- package/dist/lib/browser/qa-run.d.ts.map +1 -0
- package/dist/lib/browser/qa-run.js +1283 -0
- package/dist/lib/browser/request-diagnostics.d.ts +13 -0
- package/dist/lib/browser/request-diagnostics.d.ts.map +1 -0
- package/dist/lib/browser/request-diagnostics.js +18 -0
- package/dist/lib/browser/tiling.d.ts +19 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -1
- package/dist/lib/browser/tiling.js +28 -0
- package/dist/lib/cookies/client.d.ts +9 -0
- package/dist/lib/cookies/client.d.ts.map +1 -1
- package/dist/lib/cookies/client.js +197 -44
- package/dist/lib/cookies/extra.d.ts +18 -0
- package/dist/lib/cookies/extra.d.ts.map +1 -0
- package/dist/lib/cookies/extra.js +14 -0
- package/dist/lib/cookies/index.d.ts +2 -1
- package/dist/lib/cookies/index.d.ts.map +1 -1
- package/dist/lib/cookies/index.js +2 -1
- package/dist/lib/coord-root-id.d.ts +9 -0
- package/dist/lib/coord-root-id.d.ts.map +1 -0
- package/dist/lib/coord-root-id.js +17 -0
- package/dist/lib/durable-job.d.ts +124 -0
- package/dist/lib/durable-job.d.ts.map +1 -0
- package/dist/lib/durable-job.js +296 -0
- package/dist/lib/http/client.d.ts +7 -1
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +2 -0
- package/dist/lib/instructions/apply.d.ts +3 -1
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +74 -3
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +11 -2
- package/package.json +19 -2
- package/src/commander.ts +75 -1
- package/src/commands/admission.ts +699 -0
- package/src/commands/agents.ts +189 -50
- package/src/commands/artifacts.ts +132 -18
- package/src/commands/browse-ai.ts +10 -5
- package/src/commands/browse.ts +496 -20
- package/src/commands/diagnostics.ts +271 -0
- package/src/commands/fetch.ts +1 -0
- package/src/commands/files.ts +102 -2
- package/src/commands/governor.ts +8 -0
- package/src/commands/ledger-v3.ts +82 -0
- package/src/commands/qa-record.ts +682 -0
- package/src/commands/qa-run.ts +503 -0
- package/src/commands/qa-status.ts +608 -0
- package/src/commands/qa-verify.ts +238 -0
- package/src/commands/resources.ts +38 -0
- package/src/commands/review-pack.ts +1281 -0
- package/src/commands/supervisor.ts +141 -0
- package/src/commands/web.ts +19 -0
- package/src/commands/workflow.ts +8 -0
- package/src/core/agents/cli.ts +7 -3
- package/src/core/agents/health.ts +142 -0
- package/src/core/agents/mailbox.ts +373 -0
- package/src/core/agents/qa-signal.ts +261 -0
- package/src/core/agents/reconcile-coordination-v3.ts +77 -0
- package/src/core/agents/render/prompt-context.ts +42 -12
- package/src/core/agents/render/session-context.ts +37 -3
- package/src/core/agents/rules/commit-conflict.ts +58 -1
- package/src/core/agents/rules/stop-hook.ts +6 -12
- package/src/core/agents/session-finalizer-v3.ts +4 -1
- package/src/core/agents/session-name-display.ts +78 -7
- package/src/core/agents/state/heartbeat-reader.ts +7 -0
- package/src/core/agents/state/heartbeat-writer.ts +23 -0
- package/src/core/agents/state/live-coordination-view.ts +1 -0
- package/src/core/agents/state/live-coordination-writer.ts +5 -0
- package/src/core/artifacts/constants.ts +1 -1
- package/src/core/artifacts/index.ts +565 -30
- package/src/core/config.ts +134 -2
- package/src/core/diagnostics/advice.ts +147 -0
- package/src/core/diagnostics/bundle.ts +1250 -0
- package/src/core/diagnostics/comparison.ts +565 -0
- package/src/core/diagnostics/contract.ts +311 -0
- package/src/core/diagnostics/identity.ts +11 -0
- package/src/core/diagnostics/index.ts +7 -0
- package/src/core/diagnostics/replay.ts +314 -0
- package/src/core/diagnostics/sanitize.ts +97 -0
- package/src/core/events/legacy-storage/compression.ts +130 -0
- package/src/core/events/legacy-storage/index.ts +1 -0
- package/src/core/events/v3/archive-retention.ts +251 -0
- package/src/core/events/v3/bootstrap.ts +10 -0
- package/src/core/events/v3/capabilities.ts +2 -0
- package/src/core/events/v3/coordination-view.ts +100 -11
- package/src/core/events/v3/index.ts +9 -0
- package/src/core/events/v3/live-routing.ts +1 -0
- package/src/core/events/v3/producers/hook-base.ts +14 -2
- package/src/core/events/v3/producers/intake.ts +10 -2
- package/src/core/events/v3/producers/recorder.ts +420 -17
- package/src/core/hooks/adapter/output.ts +12 -1
- package/src/core/hooks/cli.ts +332 -247
- package/src/core/hooks/health.ts +146 -0
- package/src/core/hooks/resolve/transcript.ts +10 -3
- package/src/core/hooks/session-name-presence.ts +6 -1
- package/src/core/qa-artifacts.ts +126 -0
- package/src/core/resources/contract.ts +105 -0
- package/src/core/resources/index.ts +5 -0
- package/src/core/resources/sampler.ts +590 -0
- package/src/core/resources/service-status.ts +62 -0
- package/src/core/resources/service.ts +337 -0
- package/src/core/resources/storage.ts +44 -0
- package/src/core/storage/atomic-json.ts +15 -0
- package/src/core/storage/builtins.ts +62 -6
- package/src/core/storage/logger.ts +2 -0
- package/src/core/storage/query.ts +58 -0
- package/src/core/supervisor/activity.ts +193 -0
- package/src/core/supervisor/contract.ts +312 -0
- package/src/core/supervisor/explanations.ts +104 -0
- package/src/core/supervisor/findings.ts +788 -0
- package/src/core/supervisor/history.ts +61 -0
- package/src/core/supervisor/hook-health-alerts.ts +108 -0
- package/src/core/supervisor/hook-health-storage.ts +25 -0
- package/src/core/supervisor/hook-health.ts +301 -0
- package/src/core/supervisor/hooks.ts +35 -0
- package/src/core/supervisor/index.ts +14 -0
- package/src/core/supervisor/log-feed.ts +131 -0
- package/src/core/supervisor/service.ts +511 -0
- package/src/core/supervisor/services.ts +203 -0
- package/src/core/supervisor/status.ts +59 -0
- package/src/core/supervisor/storage.ts +126 -0
- package/src/core/supervisor/timeline.ts +133 -0
- package/src/core/workflow/admission.ts +215 -0
- package/src/core/workflow/engine.ts +93 -1
- package/src/core/workflow/index.ts +10 -0
- package/src/core/workflow/proof.ts +54 -1
- package/src/core/workflow/run-state.ts +13 -1
- package/src/core/workflow/types.ts +39 -1
- package/src/lib/admission.ts +347 -0
- package/src/lib/agent-browser/client.ts +2 -10
- package/src/lib/browser/capture-fidelity.ts +98 -0
- package/src/lib/browser/client.ts +212 -10
- package/src/lib/browser/critique.ts +62 -7
- package/src/lib/browser/index.ts +65 -0
- package/src/lib/browser/page-review-judge.ts +360 -0
- package/src/lib/browser/page-review-pack.ts +2384 -0
- package/src/lib/browser/qa-run-contracts.ts +743 -0
- package/src/lib/browser/qa-run.ts +1462 -0
- package/src/lib/browser/request-diagnostics.ts +27 -0
- package/src/lib/browser/tiling.ts +32 -0
- package/src/lib/cookies/client.ts +228 -42
- package/src/lib/cookies/extra.ts +28 -0
- package/src/lib/cookies/index.ts +2 -0
- package/src/lib/coord-root-id.ts +23 -0
- package/src/lib/durable-job.ts +407 -0
- package/src/lib/http/client.ts +13 -1
- package/src/lib/instructions/apply.ts +81 -2
- package/src/lib/instructions/templates.ts +11 -2
|
@@ -8,13 +8,22 @@
|
|
|
8
8
|
* expired, inactive, untracked managed unit is deletable.
|
|
9
9
|
*/
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
|
-
import { randomUUID } from "node:crypto";
|
|
12
|
-
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
11
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
12
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmdirSync, rmSync, writeFileSync, } from "node:fs";
|
|
13
13
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
14
14
|
import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.js";
|
|
15
|
-
import { artifactAutoCleanEnabled, artifactAutoCleanIntervalHours, artifactDefaultRetentionDays, } from "../config.js";
|
|
15
|
+
import { artifactAutoCleanEnabled, artifactAutoCleanIntervalHours, artifactDefaultRetentionDays, artifactMaxBytes, artifactMaxUnitBytes, } from "../config.js";
|
|
16
16
|
import { ARTIFACT_MANIFEST, ARTIFACT_SCHEMA_VERSION, ARTIFACTS_DIR } from "./constants.js";
|
|
17
17
|
export { ARTIFACT_MANIFEST, ARTIFACT_SCHEMA_VERSION, ARTIFACTS_DIR } from "./constants.js";
|
|
18
|
+
export function artifactCapabilities() {
|
|
19
|
+
return {
|
|
20
|
+
schema_version: ARTIFACT_SCHEMA_VERSION,
|
|
21
|
+
holds: true,
|
|
22
|
+
atomic_create_holds: true,
|
|
23
|
+
owner_scoped_unhold: true,
|
|
24
|
+
explicit_v1_migration: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
18
27
|
export function artifactsRoot(repoRoot) {
|
|
19
28
|
return join(resolve(repoRoot), ARTIFACTS_DIR);
|
|
20
29
|
}
|
|
@@ -23,6 +32,9 @@ export function configuredArtifactRetentionDays(repoRoot) {
|
|
|
23
32
|
return artifactDefaultRetentionDays(repoRoot);
|
|
24
33
|
}
|
|
25
34
|
export function createArtifact(repoRoot, input) {
|
|
35
|
+
return withArtifactLock(repoRoot, () => createArtifactUnlocked(repoRoot, input));
|
|
36
|
+
}
|
|
37
|
+
function createArtifactUnlocked(repoRoot, input) {
|
|
26
38
|
const now = input.now ?? new Date();
|
|
27
39
|
assertValidDate(now, "now");
|
|
28
40
|
const slug = normalizeSlug(input.slug);
|
|
@@ -31,11 +43,17 @@ export function createArtifact(repoRoot, input) {
|
|
|
31
43
|
const purpose = input.purpose.trim();
|
|
32
44
|
if (!purpose)
|
|
33
45
|
throw new Error("purpose must not be empty");
|
|
34
|
-
const
|
|
46
|
+
const expiresAt = input.retentionMinutes !== undefined
|
|
47
|
+
? addMinutes(now, positiveMinutes(input.retentionMinutes))
|
|
48
|
+
: addDays(now, positiveDays(input.retentionDays));
|
|
35
49
|
const artifactId = input.id ?? randomUUID();
|
|
36
50
|
if (!isSafeId(artifactId)) {
|
|
37
51
|
throw new Error("artifact id must use ASCII letters, digits, hyphens, or underscores");
|
|
38
52
|
}
|
|
53
|
+
const holds = (input.holds ?? []).map((hold) => makeHold(hold, input.actor, now));
|
|
54
|
+
if (new Set(holds.map((hold) => hold.id)).size !== holds.length) {
|
|
55
|
+
throw new Error("duplicate hold id");
|
|
56
|
+
}
|
|
39
57
|
const root = artifactsRoot(repoRoot);
|
|
40
58
|
mkdirSync(root, { recursive: true });
|
|
41
59
|
const date = now.toISOString().slice(0, 10);
|
|
@@ -43,14 +61,16 @@ export function createArtifact(repoRoot, input) {
|
|
|
43
61
|
mkdirSync(path);
|
|
44
62
|
const manifest = {
|
|
45
63
|
schema_version: ARTIFACT_SCHEMA_VERSION,
|
|
64
|
+
holds,
|
|
46
65
|
artifact_id: artifactId,
|
|
47
66
|
slug,
|
|
48
67
|
purpose,
|
|
49
68
|
created_at: now.toISOString(),
|
|
50
69
|
created_by: input.actor,
|
|
51
70
|
retention: {
|
|
52
|
-
expires_at:
|
|
71
|
+
expires_at: expiresAt.toISOString(),
|
|
53
72
|
},
|
|
73
|
+
...(input.big ? { oversize_acknowledged: true } : {}),
|
|
54
74
|
};
|
|
55
75
|
atomicWriteManifest(path, manifest);
|
|
56
76
|
return { path, manifest };
|
|
@@ -75,17 +95,22 @@ export function inventoryArtifacts(repoRoot, opts = {}) {
|
|
|
75
95
|
for (const name of names) {
|
|
76
96
|
rows.push(classifyArtifactPath(repoRoot, join(root, name), now, freshnessSeconds));
|
|
77
97
|
}
|
|
78
|
-
return rows;
|
|
98
|
+
return applyArtifactBudgets(repoRoot, rows);
|
|
79
99
|
}
|
|
80
100
|
export function showArtifact(repoRoot, ref, opts = {}) {
|
|
81
101
|
const path = resolveArtifactRef(repoRoot, ref);
|
|
82
|
-
const entry =
|
|
102
|
+
const entry = inventoryArtifacts(repoRoot, opts).find((row) => row.path === path);
|
|
103
|
+
if (!entry)
|
|
104
|
+
throw new Error(`artifact "${ref}" was not found`);
|
|
83
105
|
const parsed = readManifest(path);
|
|
84
106
|
if (!parsed.ok)
|
|
85
107
|
throw new Error(parsed.reason);
|
|
86
108
|
return { entry, manifest: parsed.manifest };
|
|
87
109
|
}
|
|
88
110
|
export function renewArtifact(repoRoot, ref, days, reason, input = {}) {
|
|
111
|
+
return withArtifactLock(repoRoot, () => renewArtifactUnlocked(repoRoot, ref, days, reason, input));
|
|
112
|
+
}
|
|
113
|
+
function renewArtifactUnlocked(repoRoot, ref, days, reason, input) {
|
|
89
114
|
const now = input.now ?? new Date();
|
|
90
115
|
assertValidDate(now, "now");
|
|
91
116
|
const retentionDays = positiveDays(days);
|
|
@@ -108,6 +133,9 @@ export function renewArtifact(repoRoot, ref, days, reason, input = {}) {
|
|
|
108
133
|
return manifest;
|
|
109
134
|
}
|
|
110
135
|
export function releaseArtifact(repoRoot, ref, input = {}) {
|
|
136
|
+
return withArtifactLock(repoRoot, () => releaseArtifactUnlocked(repoRoot, ref, input));
|
|
137
|
+
}
|
|
138
|
+
function releaseArtifactUnlocked(repoRoot, ref, input) {
|
|
111
139
|
const now = input.now ?? new Date();
|
|
112
140
|
assertValidDate(now, "now");
|
|
113
141
|
const path = resolveArtifactRef(repoRoot, ref);
|
|
@@ -122,20 +150,187 @@ export function releaseArtifact(repoRoot, ref, input = {}) {
|
|
|
122
150
|
atomicWriteManifest(path, manifest);
|
|
123
151
|
return manifest;
|
|
124
152
|
}
|
|
153
|
+
export function holdArtifact(repoRoot, ref, input) {
|
|
154
|
+
const hold = makeHold(input, input.actor, input.now ?? new Date());
|
|
155
|
+
return withArtifactLock(repoRoot, () => {
|
|
156
|
+
const path = resolveArtifactRef(repoRoot, ref);
|
|
157
|
+
const parsed = readManifest(path);
|
|
158
|
+
if (!parsed.ok)
|
|
159
|
+
throw new Error(parsed.reason);
|
|
160
|
+
const previous = parsed.manifest.holds.find((item) => item.id === hold.id);
|
|
161
|
+
if (previous) {
|
|
162
|
+
if (previous.set_by.instance_id !== input.actor.instance_id ||
|
|
163
|
+
previous.reason !== hold.reason) {
|
|
164
|
+
throw new Error("hold id already exists with a different owner or reason");
|
|
165
|
+
}
|
|
166
|
+
return parsed.manifest;
|
|
167
|
+
}
|
|
168
|
+
const manifest = { ...parsed.manifest, holds: [...parsed.manifest.holds, hold] };
|
|
169
|
+
atomicWriteManifest(path, manifest);
|
|
170
|
+
return manifest;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
export function unholdArtifact(repoRoot, ref, id, input) {
|
|
174
|
+
if (!validHoldId(id))
|
|
175
|
+
throw new Error("invalid hold id");
|
|
176
|
+
if (!validActor(input.actor))
|
|
177
|
+
throw new Error("a valid hold actor is required");
|
|
178
|
+
return withArtifactLock(repoRoot, () => {
|
|
179
|
+
const path = resolveArtifactRef(repoRoot, ref);
|
|
180
|
+
const parsed = readManifest(path);
|
|
181
|
+
if (!parsed.ok)
|
|
182
|
+
throw new Error(parsed.reason);
|
|
183
|
+
const hold = parsed.manifest.holds.find((item) => item.id === id);
|
|
184
|
+
if (!hold)
|
|
185
|
+
return parsed.manifest;
|
|
186
|
+
if (hold.set_by.instance_id !== input.actor.instance_id) {
|
|
187
|
+
throw new Error("only the hold owner may remove this hold");
|
|
188
|
+
}
|
|
189
|
+
const manifest = {
|
|
190
|
+
...parsed.manifest,
|
|
191
|
+
holds: parsed.manifest.holds.filter((item) => item.id !== id),
|
|
192
|
+
};
|
|
193
|
+
atomicWriteManifest(path, manifest);
|
|
194
|
+
return manifest;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/** Adopt untracked loose files and legacy directories without changing directory paths. */
|
|
198
|
+
export function adoptUnmanagedArtifactFiles(repoRoot, input) {
|
|
199
|
+
if (input.yes)
|
|
200
|
+
return withArtifactLock(repoRoot, () => adoptUnmanagedArtifactFilesUnlocked(repoRoot, input));
|
|
201
|
+
return adoptUnmanagedArtifactFilesUnlocked(repoRoot, input);
|
|
202
|
+
}
|
|
203
|
+
function adoptUnmanagedArtifactFilesUnlocked(repoRoot, input) {
|
|
204
|
+
const now = input.now ?? new Date();
|
|
205
|
+
const candidates = [];
|
|
206
|
+
for (const row of inventoryArtifacts(repoRoot, { now })) {
|
|
207
|
+
if (row.classification !== "unmanaged")
|
|
208
|
+
continue;
|
|
209
|
+
try {
|
|
210
|
+
const stat = lstatSync(row.path);
|
|
211
|
+
if (stat.isSymbolicLink() || containsTrackedPath(repoRoot, row.path))
|
|
212
|
+
continue;
|
|
213
|
+
if (stat.isFile()) {
|
|
214
|
+
candidates.push({ path: row.path, name: row.name, bytes: stat.size, kind: "file" });
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (stat.isDirectory() && !existsSync(join(row.path, ARTIFACT_MANIFEST))) {
|
|
218
|
+
const bytes = safeTreeSize(row.path);
|
|
219
|
+
if (bytes !== null && normalizeSlug(row.name)) {
|
|
220
|
+
candidates.push({ path: row.path, name: row.name, bytes, kind: "directory" });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// A racing or unreadable entry stays unmanaged.
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const candidateBytes = candidates.reduce((sum, row) => sum + row.bytes, 0);
|
|
229
|
+
const fileBytes = candidates.reduce((sum, row) => sum + (row.kind === "file" ? row.bytes : 0), 0);
|
|
230
|
+
const maxUnitBytes = artifactMaxUnitBytes(repoRoot);
|
|
231
|
+
const requiresBig = fileBytes > maxUnitBytes ||
|
|
232
|
+
candidates.some((row) => row.kind === "directory" && row.bytes > maxUnitBytes);
|
|
233
|
+
const preview = {
|
|
234
|
+
candidates,
|
|
235
|
+
candidate_bytes: candidateBytes,
|
|
236
|
+
requires_big: requiresBig,
|
|
237
|
+
adopted_artifact_id: null,
|
|
238
|
+
adopted_path: null,
|
|
239
|
+
adopted_directories: 0,
|
|
240
|
+
};
|
|
241
|
+
if (!input.yes || candidates.length === 0)
|
|
242
|
+
return preview;
|
|
243
|
+
if (requiresBig && !input.big) {
|
|
244
|
+
throw new Error("unmanaged adoption exceeds the per-bundle ceiling; repeat with --big");
|
|
245
|
+
}
|
|
246
|
+
// Revalidate every exact source before creating a destination. A changed,
|
|
247
|
+
// tracked, linked, or non-regular entry aborts the whole adoption.
|
|
248
|
+
for (const candidate of candidates) {
|
|
249
|
+
const stat = lstatSync(candidate.path);
|
|
250
|
+
const bytes = stat.isDirectory() ? safeTreeSize(candidate.path) : stat.size;
|
|
251
|
+
if (stat.isSymbolicLink() ||
|
|
252
|
+
bytes !== candidate.bytes ||
|
|
253
|
+
containsTrackedPath(repoRoot, candidate.path)) {
|
|
254
|
+
throw new Error(`unmanaged entry changed before adoption: ${candidate.name}`);
|
|
255
|
+
}
|
|
256
|
+
if (candidate.kind === "file" ? !stat.isFile() : !stat.isDirectory()) {
|
|
257
|
+
throw new Error(`unmanaged entry changed before adoption: ${candidate.name}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const files = candidates.filter((candidate) => candidate.kind === "file");
|
|
261
|
+
const created = files.length
|
|
262
|
+
? createArtifactUnlocked(repoRoot, {
|
|
263
|
+
slug: "adopted-unmanaged",
|
|
264
|
+
purpose: input.purpose,
|
|
265
|
+
retentionDays: input.retentionDays,
|
|
266
|
+
actor: input.actor,
|
|
267
|
+
now,
|
|
268
|
+
big: input.big,
|
|
269
|
+
})
|
|
270
|
+
: null;
|
|
271
|
+
for (const candidate of files)
|
|
272
|
+
renameSync(candidate.path, join(created.path, candidate.name));
|
|
273
|
+
const retentionDays = positiveDays(input.retentionDays);
|
|
274
|
+
const directories = candidates.filter((candidate) => candidate.kind === "directory");
|
|
275
|
+
for (const candidate of directories) {
|
|
276
|
+
atomicWriteManifest(candidate.path, {
|
|
277
|
+
schema_version: ARTIFACT_SCHEMA_VERSION,
|
|
278
|
+
holds: [],
|
|
279
|
+
artifact_id: randomUUID(),
|
|
280
|
+
slug: normalizeSlug(candidate.name),
|
|
281
|
+
purpose: `${input.purpose}: ${candidate.name}`,
|
|
282
|
+
created_at: now.toISOString(),
|
|
283
|
+
created_by: input.actor,
|
|
284
|
+
retention: { expires_at: addDays(now, retentionDays).toISOString() },
|
|
285
|
+
...(input.big ? { oversize_acknowledged: true } : {}),
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
...preview,
|
|
290
|
+
adopted_artifact_id: created?.manifest.artifact_id ?? null,
|
|
291
|
+
adopted_path: created?.path ?? null,
|
|
292
|
+
adopted_directories: directories.length,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
125
295
|
export function cleanArtifacts(repoRoot, opts = {}) {
|
|
296
|
+
if (!opts.yes)
|
|
297
|
+
return inventoryArtifacts(repoRoot, opts);
|
|
298
|
+
try {
|
|
299
|
+
return withArtifactLock(repoRoot, () => cleanArtifactsUnlocked(repoRoot, opts));
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
return inventoryArtifacts(repoRoot, opts).map((row) => row.action === "would-delete"
|
|
303
|
+
? {
|
|
304
|
+
...row,
|
|
305
|
+
classification: "unknown",
|
|
306
|
+
action: "keep",
|
|
307
|
+
reason: errorMessage("cleanup refused", error),
|
|
308
|
+
}
|
|
309
|
+
: row);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function cleanArtifactsUnlocked(repoRoot, opts) {
|
|
126
313
|
const now = opts.now ?? new Date();
|
|
127
314
|
const freshnessSeconds = opts.freshnessSeconds ?? 600;
|
|
128
315
|
const rows = inventoryArtifacts(repoRoot, { now, freshnessSeconds });
|
|
129
316
|
if (!opts.yes)
|
|
130
317
|
return rows;
|
|
131
318
|
return rows.map((entry) => {
|
|
132
|
-
if (entry.
|
|
319
|
+
if (entry.action !== "would-delete")
|
|
133
320
|
return entry;
|
|
134
321
|
// Reclassify immediately before removal. A renewal, release-state change,
|
|
135
322
|
// heartbeat, symlink swap, or tracked file added since inventory must win.
|
|
136
|
-
const current =
|
|
137
|
-
if (current
|
|
323
|
+
const current = inventoryArtifacts(repoRoot, { now, freshnessSeconds }).find((row) => row.path === entry.path);
|
|
324
|
+
if (!current) {
|
|
325
|
+
return { ...entry, classification: "unknown", reason: "entry disappeared", action: "keep" };
|
|
326
|
+
}
|
|
327
|
+
if (current.action !== "would-delete" ||
|
|
328
|
+
current.artifact_id !== entry.artifact_id ||
|
|
329
|
+
current.bytes !== entry.bytes ||
|
|
330
|
+
current.last_modified_at !== entry.last_modified_at ||
|
|
331
|
+
current.expires_at !== entry.expires_at) {
|
|
138
332
|
return current;
|
|
333
|
+
}
|
|
139
334
|
try {
|
|
140
335
|
const top = lstatSync(current.path);
|
|
141
336
|
if (!top.isDirectory() || top.isSymbolicLink()) {
|
|
@@ -264,7 +459,16 @@ function classifyArtifactPath(repoRoot, path, now, freshnessSeconds) {
|
|
|
264
459
|
last_modified_at: new Date(effectiveLastModifiedMs).toISOString(),
|
|
265
460
|
expires_at: effectiveExpiresAt,
|
|
266
461
|
owner_instance_id: manifest.created_by?.instance_id ?? null,
|
|
462
|
+
oversize_acknowledged: manifest.oversize_acknowledged === true,
|
|
267
463
|
});
|
|
464
|
+
if (manifest.holds.length > 0) {
|
|
465
|
+
return {
|
|
466
|
+
...base,
|
|
467
|
+
classification: "managed-held",
|
|
468
|
+
reason: `held: ${manifest.holds.map((hold) => hold.id).join(", ")}`,
|
|
469
|
+
action: "keep",
|
|
470
|
+
};
|
|
471
|
+
}
|
|
268
472
|
if (base.bytes === null || lastModifiedMs === null) {
|
|
269
473
|
return {
|
|
270
474
|
...base,
|
|
@@ -309,6 +513,38 @@ function classifyArtifactPath(repoRoot, path, now, freshnessSeconds) {
|
|
|
309
513
|
action: "would-delete",
|
|
310
514
|
};
|
|
311
515
|
}
|
|
516
|
+
function applyArtifactBudgets(repoRoot, inputRows) {
|
|
517
|
+
const maxUnitBytes = artifactMaxUnitBytes(repoRoot);
|
|
518
|
+
const maxBytes = artifactMaxBytes(repoRoot);
|
|
519
|
+
const rows = inputRows.map((row) => ({ ...row }));
|
|
520
|
+
for (const row of rows) {
|
|
521
|
+
if (row.classification === "managed-current" &&
|
|
522
|
+
row.bytes !== null &&
|
|
523
|
+
row.bytes > maxUnitBytes &&
|
|
524
|
+
!row.oversize_acknowledged) {
|
|
525
|
+
row.classification = "managed-oversize";
|
|
526
|
+
row.reason = `bundle uses ${row.bytes} bytes, above the ${maxUnitBytes}-byte ceiling without --big`;
|
|
527
|
+
row.action = "would-delete";
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
const managedBytes = rows.reduce((sum, row) => sum + (row.artifact_id && row.bytes !== null ? row.bytes : 0), 0);
|
|
531
|
+
let retainedBytes = managedBytes -
|
|
532
|
+
rows.reduce((sum, row) => sum + (row.action === "would-delete" && row.bytes !== null ? row.bytes : 0), 0);
|
|
533
|
+
if (retainedBytes <= maxBytes)
|
|
534
|
+
return rows;
|
|
535
|
+
const candidates = rows
|
|
536
|
+
.filter((row) => row.classification === "managed-current" && row.action === "keep" && row.bytes !== null)
|
|
537
|
+
.sort((left, right) => `${left.expires_at ?? ""}\0${left.created_at ?? ""}\0${left.name}`.localeCompare(`${right.expires_at ?? ""}\0${right.created_at ?? ""}\0${right.name}`));
|
|
538
|
+
for (const row of candidates) {
|
|
539
|
+
if (retainedBytes <= maxBytes)
|
|
540
|
+
break;
|
|
541
|
+
row.classification = "managed-over-budget";
|
|
542
|
+
row.reason = `repository artifact budget is ${maxBytes} bytes; earliest-expiring inactive bundles are removed first`;
|
|
543
|
+
row.action = "would-delete";
|
|
544
|
+
retainedBytes -= row.bytes ?? 0;
|
|
545
|
+
}
|
|
546
|
+
return rows;
|
|
547
|
+
}
|
|
312
548
|
function readManifest(path) {
|
|
313
549
|
const manifestPath = join(path, ARTIFACT_MANIFEST);
|
|
314
550
|
if (!existsSync(manifestPath)) {
|
|
@@ -316,11 +552,24 @@ function readManifest(path) {
|
|
|
316
552
|
}
|
|
317
553
|
let value;
|
|
318
554
|
try {
|
|
555
|
+
const unit = lstatSync(path);
|
|
556
|
+
const stat = lstatSync(manifestPath);
|
|
557
|
+
if (!unit.isDirectory() ||
|
|
558
|
+
unit.isSymbolicLink() ||
|
|
559
|
+
!stat.isFile() ||
|
|
560
|
+
stat.isSymbolicLink() ||
|
|
561
|
+
stat.size > 1024 * 1024) {
|
|
562
|
+
return { ok: false, reason: "manifest must be a bounded regular file in a direct directory" };
|
|
563
|
+
}
|
|
319
564
|
value = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
320
565
|
}
|
|
321
566
|
catch (error) {
|
|
322
567
|
return { ok: false, reason: errorMessage("manifest is unreadable", error) };
|
|
323
568
|
}
|
|
569
|
+
return parseArtifactManifest(value);
|
|
570
|
+
}
|
|
571
|
+
/** Validate only the current schema. Legacy conversion belongs to migrateArtifacts. */
|
|
572
|
+
export function parseArtifactManifest(value) {
|
|
324
573
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
325
574
|
return { ok: false, reason: "manifest must be a JSON object" };
|
|
326
575
|
}
|
|
@@ -328,6 +577,11 @@ function readManifest(path) {
|
|
|
328
577
|
if (m.schema_version !== ARTIFACT_SCHEMA_VERSION) {
|
|
329
578
|
return { ok: false, reason: `unsupported schema_version ${String(m.schema_version)}` };
|
|
330
579
|
}
|
|
580
|
+
if (!Array.isArray(m.holds) ||
|
|
581
|
+
m.holds.some((hold) => !validHold(hold)) ||
|
|
582
|
+
new Set(m.holds.map((hold) => hold.id)).size !== m.holds.length) {
|
|
583
|
+
return { ok: false, reason: "invalid holds" };
|
|
584
|
+
}
|
|
331
585
|
if (!isSafeId(m.artifact_id))
|
|
332
586
|
return { ok: false, reason: "invalid artifact_id" };
|
|
333
587
|
if (typeof m.slug !== "string" || !m.slug || normalizeSlug(m.slug) !== m.slug) {
|
|
@@ -357,16 +611,147 @@ function readManifest(path) {
|
|
|
357
611
|
if (m.released_by !== undefined && !validActor(m.released_by)) {
|
|
358
612
|
return { ok: false, reason: "invalid released_by" };
|
|
359
613
|
}
|
|
614
|
+
if (m.oversize_acknowledged !== undefined && typeof m.oversize_acknowledged !== "boolean") {
|
|
615
|
+
return { ok: false, reason: "invalid oversize_acknowledged" };
|
|
616
|
+
}
|
|
360
617
|
return { ok: true, manifest: m };
|
|
361
618
|
}
|
|
362
619
|
function atomicWriteManifest(path, manifest) {
|
|
363
620
|
const target = join(path, ARTIFACT_MANIFEST);
|
|
364
621
|
const tmp = `${target}.tmp.${process.pid}.${randomUUID().slice(0, 8)}`;
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
622
|
+
try {
|
|
623
|
+
writeFileSync(tmp, `${JSON.stringify(manifest, null, 2)}\n`, {
|
|
624
|
+
encoding: "utf8",
|
|
625
|
+
mode: 0o600,
|
|
626
|
+
flag: "wx",
|
|
627
|
+
});
|
|
628
|
+
renameSync(tmp, target);
|
|
629
|
+
}
|
|
630
|
+
finally {
|
|
631
|
+
rmSync(tmp, { force: true });
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
/** Explicit, bounded v1 cutover. Preview never writes; every applied unit keeps its exact preimage. */
|
|
635
|
+
export function migrateArtifacts(repoRoot, opts = {}) {
|
|
636
|
+
const migrate = () => {
|
|
637
|
+
const root = artifactsRoot(repoRoot);
|
|
638
|
+
if (!existsSync(root))
|
|
639
|
+
return [];
|
|
640
|
+
return readdirSync(root)
|
|
641
|
+
.sort()
|
|
642
|
+
.map((name) => {
|
|
643
|
+
const path = join(root, name);
|
|
644
|
+
try {
|
|
645
|
+
const stat = lstatSync(path);
|
|
646
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
647
|
+
throw new Error("not a direct directory");
|
|
648
|
+
if (containsTrackedPath(repoRoot, path))
|
|
649
|
+
throw new Error("artifact contains tracked files");
|
|
650
|
+
const target = join(path, ARTIFACT_MANIFEST);
|
|
651
|
+
const manifestStat = lstatSync(target);
|
|
652
|
+
if (!manifestStat.isFile() ||
|
|
653
|
+
manifestStat.isSymbolicLink() ||
|
|
654
|
+
manifestStat.size > 1024 * 1024) {
|
|
655
|
+
throw new Error("manifest is not a bounded regular file");
|
|
656
|
+
}
|
|
657
|
+
const preimage = readFileSync(target, "utf8");
|
|
658
|
+
const legacy = JSON.parse(preimage);
|
|
659
|
+
if (legacy?.schema_version !== 1) {
|
|
660
|
+
return {
|
|
661
|
+
path,
|
|
662
|
+
action: "keep",
|
|
663
|
+
reason: `schema_version ${String(legacy?.schema_version)} is not a migration source`,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
if (Object.hasOwn(legacy, "holds"))
|
|
667
|
+
throw new Error("v1 manifest unexpectedly contains holds");
|
|
668
|
+
const parsed = parseArtifactManifest({
|
|
669
|
+
...legacy,
|
|
670
|
+
schema_version: ARTIFACT_SCHEMA_VERSION,
|
|
671
|
+
holds: [],
|
|
672
|
+
});
|
|
673
|
+
if (!parsed.ok)
|
|
674
|
+
throw new Error(parsed.reason);
|
|
675
|
+
const digest = createHash("sha256").update(preimage).digest("hex");
|
|
676
|
+
const preimagePath = join(resolve(repoRoot), ".harnery/artifact-migrations", `${digest}.v1.json`);
|
|
677
|
+
if (!opts.yes)
|
|
678
|
+
return {
|
|
679
|
+
path,
|
|
680
|
+
action: "would-migrate",
|
|
681
|
+
reason: "valid v1 manifest",
|
|
682
|
+
preimage_path: preimagePath,
|
|
683
|
+
};
|
|
684
|
+
mkdirSync(dirname(preimagePath), { recursive: true });
|
|
685
|
+
try {
|
|
686
|
+
writeFileSync(preimagePath, preimage, { flag: "wx", mode: 0o600 });
|
|
687
|
+
}
|
|
688
|
+
catch (error) {
|
|
689
|
+
if (error.code !== "EEXIST" ||
|
|
690
|
+
lstatSync(preimagePath).isSymbolicLink() ||
|
|
691
|
+
readFileSync(preimagePath, "utf8") !== preimage)
|
|
692
|
+
throw error;
|
|
693
|
+
}
|
|
694
|
+
if (readFileSync(target, "utf8") !== preimage)
|
|
695
|
+
throw new Error("manifest changed before migration");
|
|
696
|
+
atomicWriteManifest(path, parsed.manifest);
|
|
697
|
+
return {
|
|
698
|
+
path,
|
|
699
|
+
action: "migrated",
|
|
700
|
+
reason: "v1 preimage preserved; identity and retention unchanged",
|
|
701
|
+
preimage_path: preimagePath,
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
catch (error) {
|
|
705
|
+
return { path, action: "keep", reason: errorMessage("migration refused", error) };
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
};
|
|
709
|
+
return opts.yes ? withArtifactLock(repoRoot, migrate) : migrate();
|
|
710
|
+
}
|
|
711
|
+
/** A persistent directory lock fails closed on contention or a crashed owner. */
|
|
712
|
+
function withArtifactLock(repoRoot, action) {
|
|
713
|
+
const lock = join(resolve(repoRoot), ".harnery/artifacts-mutation.lock");
|
|
714
|
+
mkdirSync(dirname(lock), { recursive: true });
|
|
715
|
+
try {
|
|
716
|
+
mkdirSync(lock);
|
|
717
|
+
}
|
|
718
|
+
catch (error) {
|
|
719
|
+
throw new Error(errorMessage("artifact store mutation lock unavailable; retry after its owner finishes", error));
|
|
720
|
+
}
|
|
721
|
+
try {
|
|
722
|
+
return action();
|
|
723
|
+
}
|
|
724
|
+
finally {
|
|
725
|
+
rmdirSync(lock);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
function validHoldId(value) {
|
|
729
|
+
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/.test(value);
|
|
730
|
+
}
|
|
731
|
+
function validHold(value) {
|
|
732
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
733
|
+
return false;
|
|
734
|
+
const hold = value;
|
|
735
|
+
return (validHoldId(hold.id) &&
|
|
736
|
+
typeof hold.reason === "string" &&
|
|
737
|
+
!!hold.reason.trim() &&
|
|
738
|
+
validActor(hold.set_by) &&
|
|
739
|
+
validIso(hold.set_at));
|
|
740
|
+
}
|
|
741
|
+
function makeHold(input, actor, now) {
|
|
742
|
+
assertValidDate(now, "now");
|
|
743
|
+
if (!validActor(actor))
|
|
744
|
+
throw new Error("a valid hold actor is required");
|
|
745
|
+
if (!validHoldId(input.id))
|
|
746
|
+
throw new Error("invalid hold id");
|
|
747
|
+
if (typeof input.reason !== "string" || !input.reason.trim())
|
|
748
|
+
throw new Error("hold reason must not be empty");
|
|
749
|
+
return {
|
|
750
|
+
id: input.id,
|
|
751
|
+
reason: input.reason.trim(),
|
|
752
|
+
set_by: { ...actor },
|
|
753
|
+
set_at: now.toISOString(),
|
|
754
|
+
};
|
|
370
755
|
}
|
|
371
756
|
function ownerLiveness(repoRoot, instanceId, now, freshnessSeconds) {
|
|
372
757
|
try {
|
|
@@ -460,6 +845,7 @@ function rowFor(path, name, repoRoot, classification, reason, bytes = safeTreeSi
|
|
|
460
845
|
last_modified_at: null,
|
|
461
846
|
expires_at: null,
|
|
462
847
|
owner_instance_id: null,
|
|
848
|
+
oversize_acknowledged: false,
|
|
463
849
|
};
|
|
464
850
|
}
|
|
465
851
|
function normalizeSlug(value) {
|
|
@@ -481,6 +867,15 @@ function positiveDays(value) {
|
|
|
481
867
|
function addDays(date, days) {
|
|
482
868
|
return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
483
869
|
}
|
|
870
|
+
function positiveMinutes(value) {
|
|
871
|
+
if (!Number.isInteger(value) || value <= 0 || value > 3650 * 24 * 60) {
|
|
872
|
+
throw new Error("retention minutes must be between 1 and 5256000");
|
|
873
|
+
}
|
|
874
|
+
return value;
|
|
875
|
+
}
|
|
876
|
+
function addMinutes(date, minutes) {
|
|
877
|
+
return new Date(date.getTime() + minutes * 60 * 1000);
|
|
878
|
+
}
|
|
484
879
|
function isSafeId(value) {
|
|
485
880
|
return (typeof value === "string" &&
|
|
486
881
|
value.length >= 8 &&
|
package/dist/core/config.d.ts
CHANGED
|
@@ -185,6 +185,14 @@ export declare function coordFreshnessSeconds(coordRoot?: string | null): number
|
|
|
185
185
|
* `0` (or a negative value) disables automatic rotation.
|
|
186
186
|
*/
|
|
187
187
|
export declare function eventLedgerRotateActiveBytes(coordRoot?: string | null): number;
|
|
188
|
+
export interface EventLedgerArchivePolicy {
|
|
189
|
+
maxBytes: number;
|
|
190
|
+
maxAgeDays: number;
|
|
191
|
+
keepMin: number;
|
|
192
|
+
autoClean: boolean;
|
|
193
|
+
}
|
|
194
|
+
/** Bounded retention for closed V3 epochs under `ledgers/v3-archives`. */
|
|
195
|
+
export declare function eventLedgerArchivePolicy(coordRoot?: string | null): EventLedgerArchivePolicy;
|
|
188
196
|
/**
|
|
189
197
|
* Resolve the standalone dashboard port.
|
|
190
198
|
*
|
|
@@ -200,6 +208,10 @@ export declare function sessionFinalizationConfig(coordRoot?: string | null): Se
|
|
|
200
208
|
* `artifacts.default_retention_days` -> 3 days.
|
|
201
209
|
*/
|
|
202
210
|
export declare function artifactDefaultRetentionDays(coordRoot?: string | null): number;
|
|
211
|
+
/** Soft repository budget for managed working artifacts. */
|
|
212
|
+
export declare function artifactMaxBytes(coordRoot?: string | null): number;
|
|
213
|
+
/** Size at which one bundle requires an explicit `artifacts create --big` acknowledgement. */
|
|
214
|
+
export declare function artifactMaxUnitBytes(coordRoot?: string | null): number;
|
|
203
215
|
/**
|
|
204
216
|
* Whether the daily SessionStart sweep of expired artifact workspaces runs.
|
|
205
217
|
* Precedence: `HARNERY_ARTIFACT_AUTO_CLEAN` (0/false disables) ->
|
|
@@ -208,6 +220,14 @@ export declare function artifactDefaultRetentionDays(coordRoot?: string | null):
|
|
|
208
220
|
* `artifacts clean --yes`.
|
|
209
221
|
*/
|
|
210
222
|
export declare function artifactAutoCleanEnabled(coordRoot?: string | null): boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Whether `qa-run` and `review-pack create` sweep expired page review packs
|
|
225
|
+
* out of the artifact store before starting. Precedence:
|
|
226
|
+
* `HARNERY_REVIEW_PACK_AUTO_CLEAN` (1/true enables, 0/false disables) ->
|
|
227
|
+
* `review_pack.auto_clean` -> disabled. The sweep deletes only packs whose
|
|
228
|
+
* manifest says `managed: true` with `retention.expires_at` in the past.
|
|
229
|
+
*/
|
|
230
|
+
export declare function reviewPackAutoCleanEnabled(coordRoot?: string | null): boolean;
|
|
211
231
|
/**
|
|
212
232
|
* Sweep cadence in hours. Env-only (`HARNERY_ARTIFACT_AUTO_CLEAN_INTERVAL_HOURS`,
|
|
213
233
|
* mainly for tests): the cadence is an implementation detail, not policy, and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,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;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAUH,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;AA4HD,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;;;;;;;;;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;;;;;GAKG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CAOvD;AA4BD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CAmBpE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS3C"}
|