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
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import {
|
|
4
|
+
closeSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
openSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
unlinkSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
} from "node:fs";
|
|
13
|
+
import { hostname, platform } from "node:os";
|
|
14
|
+
import { resolve } from "node:path";
|
|
15
|
+
import { checkPidToken, processStartToken } from "../agents/state/proc-start.ts";
|
|
16
|
+
import { closeProcessLoggers, legacyLogFields, processLogger } from "../storage/logger.ts";
|
|
17
|
+
import {
|
|
18
|
+
RESOURCE_SERVICE_STATUS_SCHEMA_VERSION,
|
|
19
|
+
type ResourceSamplerState,
|
|
20
|
+
type ResourceServiceStatus,
|
|
21
|
+
type ResourceServiceStatusRecord,
|
|
22
|
+
} from "./contract.ts";
|
|
23
|
+
import { sampleResources } from "./sampler.ts";
|
|
24
|
+
import { readResourceServiceStatus } from "./service-status.ts";
|
|
25
|
+
import { resourcePaths, writePrivateJsonAtomic } from "./storage.ts";
|
|
26
|
+
|
|
27
|
+
export const RESOURCE_SERVICE_DEFAULT_INTERVAL_MS = 2_000;
|
|
28
|
+
const RESOURCE_SERVICE_MIN_INTERVAL_MS = 500;
|
|
29
|
+
const RESOURCE_SERVICE_MAX_INTERVAL_MS = 60_000;
|
|
30
|
+
|
|
31
|
+
interface ResourceServiceLease {
|
|
32
|
+
pid: number;
|
|
33
|
+
start_token?: string;
|
|
34
|
+
host: string;
|
|
35
|
+
nonce: string;
|
|
36
|
+
created_at: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface RunResourceServiceInput {
|
|
40
|
+
coordRoot: string;
|
|
41
|
+
intervalMs?: number;
|
|
42
|
+
maxSamples?: number;
|
|
43
|
+
now?: () => Date;
|
|
44
|
+
sample?: typeof sampleResources;
|
|
45
|
+
wait?: (milliseconds: number) => Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type EnsureResourceServiceResult =
|
|
49
|
+
| { state: "running" | "started"; status: ResourceServiceStatus }
|
|
50
|
+
| { state: "unsupported" | "unavailable"; status: ResourceServiceStatus; error: string };
|
|
51
|
+
|
|
52
|
+
export async function spawnResourceService(
|
|
53
|
+
coordRootRaw: string,
|
|
54
|
+
options: { intervalMs?: number } = {},
|
|
55
|
+
): Promise<ResourceServiceStatus> {
|
|
56
|
+
const coordRoot = resolve(coordRootRaw);
|
|
57
|
+
const current = readResourceServiceStatus(coordRoot);
|
|
58
|
+
if (current.running) {
|
|
59
|
+
throw new Error(`resource observer is already running under pid ${current.record?.pid}`);
|
|
60
|
+
}
|
|
61
|
+
const intervalMs = normalizeInterval(options.intervalMs);
|
|
62
|
+
const paths = resourcePaths(coordRoot);
|
|
63
|
+
mkdirSync(paths.root, { recursive: true, mode: 0o700 });
|
|
64
|
+
rmSync(paths.stop, { force: true });
|
|
65
|
+
const harnBin = new URL("../../../bin/harn", import.meta.url).pathname;
|
|
66
|
+
if (!existsSync(harnBin)) throw new Error(`cannot find harn executable at ${harnBin}`);
|
|
67
|
+
let spawnError: Error | undefined;
|
|
68
|
+
const child = spawn(
|
|
69
|
+
harnBin,
|
|
70
|
+
["resources", "service", "daemon", "--root", coordRoot, "--interval-ms", String(intervalMs)],
|
|
71
|
+
{
|
|
72
|
+
cwd: coordRoot,
|
|
73
|
+
detached: true,
|
|
74
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
75
|
+
env: {
|
|
76
|
+
...process.env,
|
|
77
|
+
HARNERY_COORD_ROOT_OVERRIDE: coordRoot,
|
|
78
|
+
HARNERY_OUTPUT_SESSION_TEE: "0",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
child.once("error", (error) => {
|
|
83
|
+
spawnError = error;
|
|
84
|
+
});
|
|
85
|
+
child.unref();
|
|
86
|
+
const deadline = Date.now() + 5_000;
|
|
87
|
+
while (Date.now() < deadline) {
|
|
88
|
+
await delay(50);
|
|
89
|
+
if (spawnError) throw spawnError;
|
|
90
|
+
const status = readResourceServiceStatus(coordRoot);
|
|
91
|
+
if (status.running && status.record?.pid === child.pid) return status;
|
|
92
|
+
if (child.exitCode !== null) break;
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`resource observer failed to start; inspect ${paths.service}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function ensureResourceServiceRunning(
|
|
98
|
+
coordRoot: string,
|
|
99
|
+
): Promise<EnsureResourceServiceResult> {
|
|
100
|
+
const status = readResourceServiceStatus(coordRoot);
|
|
101
|
+
if (status.running) return { state: "running", status };
|
|
102
|
+
if (platform() !== "linux") {
|
|
103
|
+
return {
|
|
104
|
+
state: "unsupported",
|
|
105
|
+
status,
|
|
106
|
+
error: `resource observer does not yet support ${platform()}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const started = await spawnResourceService(coordRoot);
|
|
111
|
+
return { state: "started", status: started };
|
|
112
|
+
} catch (error) {
|
|
113
|
+
return {
|
|
114
|
+
state: "unavailable",
|
|
115
|
+
status: readResourceServiceStatus(coordRoot),
|
|
116
|
+
error: error instanceof Error ? error.message : String(error),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function requestResourceServiceStop(coordRootRaw: string): ResourceServiceStatus {
|
|
122
|
+
const coordRoot = resolve(coordRootRaw);
|
|
123
|
+
const paths = resourcePaths(coordRoot);
|
|
124
|
+
const status = readResourceServiceStatus(coordRoot);
|
|
125
|
+
mkdirSync(paths.root, { recursive: true, mode: 0o700 });
|
|
126
|
+
writePrivateJsonAtomic(paths.stop, {
|
|
127
|
+
requested_at: new Date().toISOString(),
|
|
128
|
+
requested_by_pid: process.pid,
|
|
129
|
+
});
|
|
130
|
+
if (status.running && status.record?.host === hostname()) {
|
|
131
|
+
try {
|
|
132
|
+
process.kill(status.record.pid, "SIGTERM");
|
|
133
|
+
} catch {
|
|
134
|
+
// The durable stop file handles a racing exit.
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return readResourceServiceStatus(coordRoot);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export async function runResourceService(
|
|
141
|
+
input: RunResourceServiceInput,
|
|
142
|
+
): Promise<ResourceServiceStatusRecord> {
|
|
143
|
+
const coordRoot = resolve(input.coordRoot);
|
|
144
|
+
const paths = resourcePaths(coordRoot);
|
|
145
|
+
const intervalMs = normalizeInterval(input.intervalMs);
|
|
146
|
+
const now = input.now ?? (() => new Date());
|
|
147
|
+
const sample = input.sample ?? sampleResources;
|
|
148
|
+
const wait = input.wait ?? delay;
|
|
149
|
+
const lease = acquireLease(coordRoot, now());
|
|
150
|
+
rmSync(paths.stop, { force: true });
|
|
151
|
+
const startedAt = now().toISOString();
|
|
152
|
+
const daemonStartToken = processStartToken(process.pid);
|
|
153
|
+
const status: ResourceServiceStatusRecord = {
|
|
154
|
+
schema_version: RESOURCE_SERVICE_STATUS_SCHEMA_VERSION,
|
|
155
|
+
pid: process.pid,
|
|
156
|
+
...(daemonStartToken ? { start_token: daemonStartToken } : {}),
|
|
157
|
+
host: hostname(),
|
|
158
|
+
nonce: lease.nonce,
|
|
159
|
+
state: "starting",
|
|
160
|
+
started_at: startedAt,
|
|
161
|
+
heartbeat_at: startedAt,
|
|
162
|
+
interval_ms: intervalMs,
|
|
163
|
+
sample_count: 0,
|
|
164
|
+
};
|
|
165
|
+
let stopping = false;
|
|
166
|
+
let previous: ResourceSamplerState | undefined;
|
|
167
|
+
const writeStatus = () => {
|
|
168
|
+
status.heartbeat_at = now().toISOString();
|
|
169
|
+
writePrivateJsonAtomic(paths.service, status);
|
|
170
|
+
};
|
|
171
|
+
const requestStop = () => {
|
|
172
|
+
stopping = true;
|
|
173
|
+
status.state = "stopping";
|
|
174
|
+
writeStatus();
|
|
175
|
+
};
|
|
176
|
+
process.on("SIGINT", requestStop);
|
|
177
|
+
process.on("SIGTERM", requestStop);
|
|
178
|
+
status.state = "running";
|
|
179
|
+
writeStatus();
|
|
180
|
+
log(coordRoot, "resource_observer.started", { pid: process.pid, interval_ms: intervalMs });
|
|
181
|
+
try {
|
|
182
|
+
while (!stopping && !existsSync(paths.stop)) {
|
|
183
|
+
const cycleStarted = Date.now();
|
|
184
|
+
try {
|
|
185
|
+
const result = sample(coordRoot, previous);
|
|
186
|
+
previous = result.state;
|
|
187
|
+
writePrivateJsonAtomic(paths.snapshot, result.snapshot);
|
|
188
|
+
status.sample_count += 1;
|
|
189
|
+
status.last_sample_at = result.snapshot.sampled_at;
|
|
190
|
+
status.last_error_code = undefined;
|
|
191
|
+
log(coordRoot, "resource_observer.sample", {
|
|
192
|
+
sample_count: status.sample_count,
|
|
193
|
+
cpu_percent: result.snapshot.machine.cpu_percent ?? -1,
|
|
194
|
+
memory_percent: result.snapshot.machine.memory_percent ?? -1,
|
|
195
|
+
visible_processes: result.snapshot.visible_process_count,
|
|
196
|
+
unattributed_processes: result.snapshot.unattributed_process_count,
|
|
197
|
+
duration_ms: result.snapshot.sample_duration_ms,
|
|
198
|
+
collector_cpu_ms: result.snapshot.collector_cpu_ms,
|
|
199
|
+
});
|
|
200
|
+
} catch (error) {
|
|
201
|
+
status.last_error_code = resourceErrorCode(error);
|
|
202
|
+
status.state = "error";
|
|
203
|
+
log(
|
|
204
|
+
coordRoot,
|
|
205
|
+
"resource_observer.sample_error",
|
|
206
|
+
{ reason_code: status.last_error_code },
|
|
207
|
+
error,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (status.state === "error") status.state = "running";
|
|
211
|
+
writeStatus();
|
|
212
|
+
if (input.maxSamples !== undefined && status.sample_count >= input.maxSamples) break;
|
|
213
|
+
const remaining = Math.max(0, intervalMs - (Date.now() - cycleStarted));
|
|
214
|
+
if (!stopping && !existsSync(paths.stop)) await wait(remaining);
|
|
215
|
+
}
|
|
216
|
+
} finally {
|
|
217
|
+
process.off("SIGINT", requestStop);
|
|
218
|
+
process.off("SIGTERM", requestStop);
|
|
219
|
+
status.state = "stopped";
|
|
220
|
+
status.stopped_at = now().toISOString();
|
|
221
|
+
writeStatus();
|
|
222
|
+
log(coordRoot, "resource_observer.stopped", { sample_count: status.sample_count });
|
|
223
|
+
try {
|
|
224
|
+
await closeProcessLoggers();
|
|
225
|
+
} finally {
|
|
226
|
+
releaseLease(paths.lease, lease.nonce);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return status;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function acquireLease(coordRoot: string, now: Date): ResourceServiceLease {
|
|
233
|
+
const paths = resourcePaths(coordRoot);
|
|
234
|
+
mkdirSync(paths.root, { recursive: true, mode: 0o700 });
|
|
235
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
236
|
+
const daemonStartToken = processStartToken(process.pid);
|
|
237
|
+
const lease: ResourceServiceLease = {
|
|
238
|
+
pid: process.pid,
|
|
239
|
+
...(daemonStartToken ? { start_token: daemonStartToken } : {}),
|
|
240
|
+
host: hostname(),
|
|
241
|
+
nonce: randomUUID(),
|
|
242
|
+
created_at: now.toISOString(),
|
|
243
|
+
};
|
|
244
|
+
try {
|
|
245
|
+
const fd = openSync(paths.lease, "wx", 0o600);
|
|
246
|
+
try {
|
|
247
|
+
writeFileSync(fd, `${JSON.stringify(lease)}\n`, "utf8");
|
|
248
|
+
} finally {
|
|
249
|
+
closeSync(fd);
|
|
250
|
+
}
|
|
251
|
+
return lease;
|
|
252
|
+
} catch (error) {
|
|
253
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
254
|
+
const existing = readLease(paths.lease);
|
|
255
|
+
if (existing && leaseIsLive(existing)) {
|
|
256
|
+
throw new Error(`resource observer lease is held by pid ${existing.pid}`);
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
unlinkSync(paths.lease);
|
|
260
|
+
} catch {
|
|
261
|
+
// A concurrent starter may have replaced or removed the stale lease.
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
throw new Error("resource observer could not acquire its singleton lease");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function releaseLease(path: string, nonce: string): void {
|
|
269
|
+
const current = readLease(path);
|
|
270
|
+
if (current?.nonce !== nonce) return;
|
|
271
|
+
try {
|
|
272
|
+
unlinkSync(path);
|
|
273
|
+
} catch {
|
|
274
|
+
// A missing lease is already released.
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function readLease(path: string): ResourceServiceLease | undefined {
|
|
279
|
+
try {
|
|
280
|
+
const value = JSON.parse(readFileSync(path, "utf8")) as ResourceServiceLease;
|
|
281
|
+
return value && Number.isInteger(value.pid) && typeof value.nonce === "string"
|
|
282
|
+
? value
|
|
283
|
+
: undefined;
|
|
284
|
+
} catch {
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function leaseIsLive(lease: ResourceServiceLease): boolean {
|
|
290
|
+
if (lease.host !== hostname()) return true;
|
|
291
|
+
try {
|
|
292
|
+
process.kill(lease.pid, 0);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
if ((error as NodeJS.ErrnoException).code !== "EPERM") return false;
|
|
295
|
+
}
|
|
296
|
+
return checkPidToken(lease.pid, lease.start_token) !== "mismatch";
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function log(
|
|
300
|
+
coordRoot: string,
|
|
301
|
+
event: string,
|
|
302
|
+
fields: Record<string, unknown>,
|
|
303
|
+
error?: unknown,
|
|
304
|
+
): void {
|
|
305
|
+
try {
|
|
306
|
+
const logger = processLogger(coordRoot, "resource-observer");
|
|
307
|
+
if (error) logger.error(event, legacyLogFields(fields), error);
|
|
308
|
+
else logger.info(event, legacyLogFields(fields));
|
|
309
|
+
} catch {
|
|
310
|
+
// Observability must never break the observer loop.
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function resourceErrorCode(error: unknown): string {
|
|
315
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
316
|
+
if (/procfs|\/proc\//i.test(message)) return "procfs_read_failed";
|
|
317
|
+
if (/permission|EACCES|EPERM/i.test(message)) return "permission_denied";
|
|
318
|
+
return "sample_failed";
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function normalizeInterval(value: number | undefined): number {
|
|
322
|
+
const interval = value ?? RESOURCE_SERVICE_DEFAULT_INTERVAL_MS;
|
|
323
|
+
if (
|
|
324
|
+
!Number.isFinite(interval) ||
|
|
325
|
+
interval < RESOURCE_SERVICE_MIN_INTERVAL_MS ||
|
|
326
|
+
interval > RESOURCE_SERVICE_MAX_INTERVAL_MS
|
|
327
|
+
) {
|
|
328
|
+
throw new Error(
|
|
329
|
+
`resource observer interval must be ${RESOURCE_SERVICE_MIN_INTERVAL_MS}-${RESOURCE_SERVICE_MAX_INTERVAL_MS} ms`,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
return Math.round(interval);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function delay(milliseconds: number): Promise<void> {
|
|
336
|
+
return new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds));
|
|
337
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import type { ResourceServiceStatusRecord, ResourceSnapshot } from "./contract.ts";
|
|
4
|
+
|
|
5
|
+
export { writePrivateJsonAtomic } from "../storage/atomic-json.ts";
|
|
6
|
+
|
|
7
|
+
export interface ResourcePaths {
|
|
8
|
+
root: string;
|
|
9
|
+
service: string;
|
|
10
|
+
lease: string;
|
|
11
|
+
stop: string;
|
|
12
|
+
snapshot: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resourcePaths(coordRootRaw: string): ResourcePaths {
|
|
16
|
+
const root = join(resolve(coordRootRaw), ".harnery", "resources");
|
|
17
|
+
return {
|
|
18
|
+
root,
|
|
19
|
+
service: join(root, "service.json"),
|
|
20
|
+
lease: join(root, "service.lease.json"),
|
|
21
|
+
stop: join(root, "stop.json"),
|
|
22
|
+
snapshot: join(root, "snapshot.json"),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function readResourceSnapshot(coordRoot: string): ResourceSnapshot | undefined {
|
|
27
|
+
return readJson<ResourceSnapshot>(resourcePaths(coordRoot).snapshot);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function readResourceServiceRecord(
|
|
31
|
+
coordRoot: string,
|
|
32
|
+
): ResourceServiceStatusRecord | undefined {
|
|
33
|
+
return readJson<ResourceServiceStatusRecord>(resourcePaths(coordRoot).service);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function readJson<T>(path: string): T | undefined {
|
|
37
|
+
if (!existsSync(path)) return undefined;
|
|
38
|
+
try {
|
|
39
|
+
const value = JSON.parse(readFileSync(path, "utf8")) as unknown;
|
|
40
|
+
return value && typeof value === "object" ? (value as T) : undefined;
|
|
41
|
+
} catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
|
|
4
|
+
/** Write one private JSON projection without exposing a partial frame to readers. */
|
|
5
|
+
export function writePrivateJsonAtomic(path: string, value: unknown): void {
|
|
6
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
7
|
+
const temporary = `${path}.tmp.${process.pid}.${Date.now()}`;
|
|
8
|
+
writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
9
|
+
try {
|
|
10
|
+
chmodSync(temporary, 0o600);
|
|
11
|
+
} catch {
|
|
12
|
+
// Windows does not expose POSIX modes. The atomic write still applies.
|
|
13
|
+
}
|
|
14
|
+
renameSync(temporary, path);
|
|
15
|
+
}
|
|
@@ -35,6 +35,8 @@ const LOG_PARTITIONS = [
|
|
|
35
35
|
"agent-operational",
|
|
36
36
|
"web-performance",
|
|
37
37
|
"semantic-service",
|
|
38
|
+
"resource-observer",
|
|
39
|
+
"supervisor",
|
|
38
40
|
"governor-service",
|
|
39
41
|
"presence-relay",
|
|
40
42
|
"tunnel-process",
|
|
@@ -59,8 +61,8 @@ const V3_ARCHIVE_PROVIDER: HarneryStorageProvider = {
|
|
|
59
61
|
provider_id: "event-v3-archive-provider",
|
|
60
62
|
kind: "filesystem",
|
|
61
63
|
inventory: "filesystem",
|
|
62
|
-
maintenance: "
|
|
63
|
-
lifecycle_authority: "Event Ledger V3
|
|
64
|
+
maintenance: "delegated",
|
|
65
|
+
lifecycle_authority: "Event Ledger V3 closed-epoch retention policy",
|
|
64
66
|
partitions: ["canonical", "support"],
|
|
65
67
|
};
|
|
66
68
|
|
|
@@ -81,7 +83,7 @@ function eventFamilies(): HarneryStorageFamily[] {
|
|
|
81
83
|
family({
|
|
82
84
|
id: "event-v3-canonical-active",
|
|
83
85
|
owner: "Event Ledger V3 authority",
|
|
84
|
-
storage_class: "
|
|
86
|
+
storage_class: "durable-object-history",
|
|
85
87
|
roots: (context) => [
|
|
86
88
|
exact(context, ".harnery/ledgers/v3/active.ndjson", "file"),
|
|
87
89
|
exact(context, ".harnery/ledgers/v3/catalog.json", "file"),
|
|
@@ -112,14 +114,14 @@ function eventFamilies(): HarneryStorageFamily[] {
|
|
|
112
114
|
format: "canonical-ndjson",
|
|
113
115
|
durability: "immutable",
|
|
114
116
|
writer_model: "object-owned",
|
|
115
|
-
policy:
|
|
117
|
+
policy: closedEpochPolicy("event-v3-archive-canonical-v2"),
|
|
116
118
|
consumers: ["Event Ledger V3 logical authority reader", "recovery verifier"],
|
|
117
119
|
provider: V3_ARCHIVE_PROVIDER,
|
|
118
120
|
}),
|
|
119
121
|
family({
|
|
120
122
|
id: "event-v3-support-active",
|
|
121
123
|
owner: "Event Ledger V3 producer recovery",
|
|
122
|
-
storage_class: "
|
|
124
|
+
storage_class: "durable-object-history",
|
|
123
125
|
roots: (context) => [
|
|
124
126
|
subtree(context, ".harnery/ledgers/v3/diagnostics", OWNER_PROTOCOL_LINKS),
|
|
125
127
|
subtree(context, ".harnery/ledgers/v3/diagnostic-summaries", OWNER_PROTOCOL_LINKS),
|
|
@@ -167,7 +169,7 @@ function eventFamilies(): HarneryStorageFamily[] {
|
|
|
167
169
|
format: "files",
|
|
168
170
|
durability: "immutable",
|
|
169
171
|
writer_model: "object-owned",
|
|
170
|
-
policy:
|
|
172
|
+
policy: closedEpochPolicy("event-v3-archive-support-v2"),
|
|
171
173
|
consumers: ["Event Ledger V3 support reader", "recovery verifier", "agents health"],
|
|
172
174
|
provider: V3_ARCHIVE_PROVIDER,
|
|
173
175
|
}),
|
|
@@ -304,6 +306,14 @@ function logFamilies(): HarneryStorageFamily[] {
|
|
|
304
306
|
),
|
|
305
307
|
(context) => [exact(context, ".harnery/semantic/v2/service.log", "file")],
|
|
306
308
|
),
|
|
309
|
+
operationalFamily(
|
|
310
|
+
"resource-observer-log",
|
|
311
|
+
"resource observer",
|
|
312
|
+
"resource-observer",
|
|
313
|
+
14,
|
|
314
|
+
64 * MIB,
|
|
315
|
+
),
|
|
316
|
+
operationalFamily("supervisor-log", "local supervisor", "supervisor", 14, 64 * MIB),
|
|
307
317
|
withCurrentRoots(
|
|
308
318
|
operationalFamily(
|
|
309
319
|
"governor-service-log",
|
|
@@ -463,6 +473,39 @@ function cacheFamilies(): HarneryStorageFamily[] {
|
|
|
463
473
|
"canonical events and source documents",
|
|
464
474
|
),
|
|
465
475
|
}),
|
|
476
|
+
family({
|
|
477
|
+
id: "resource-observer-cache",
|
|
478
|
+
owner: "resource observer",
|
|
479
|
+
storage_class: "repairable-cache",
|
|
480
|
+
roots: (context) => [subtree(context, ".harnery/resources")],
|
|
481
|
+
format: "json",
|
|
482
|
+
durability: "reconstructable",
|
|
483
|
+
writer_model: "object-owned",
|
|
484
|
+
policy: cachePolicy("resource-observer-cache-v1", "local process and machine samples"),
|
|
485
|
+
consumers: ["resource observer", "dashboard", "storage inventory", "storage health"],
|
|
486
|
+
provider: filesystemProvider(
|
|
487
|
+
"resource-observer-cache-provider",
|
|
488
|
+
"local process and machine samples",
|
|
489
|
+
),
|
|
490
|
+
}),
|
|
491
|
+
family({
|
|
492
|
+
id: "supervisor-cache",
|
|
493
|
+
owner: "local supervisor",
|
|
494
|
+
storage_class: "repairable-cache",
|
|
495
|
+
roots: (context) => [subtree(context, ".harnery/supervisor")],
|
|
496
|
+
format: "json",
|
|
497
|
+
durability: "reconstructable",
|
|
498
|
+
writer_model: "object-owned",
|
|
499
|
+
policy: cachePolicy(
|
|
500
|
+
"supervisor-cache-v1",
|
|
501
|
+
"local resources, service health, log cursors, and finding projections",
|
|
502
|
+
),
|
|
503
|
+
consumers: ["local supervisor", "dashboard", "storage inventory", "storage health"],
|
|
504
|
+
provider: filesystemProvider(
|
|
505
|
+
"supervisor-cache-provider",
|
|
506
|
+
"bounded local diagnostic observations",
|
|
507
|
+
),
|
|
508
|
+
}),
|
|
466
509
|
family({
|
|
467
510
|
id: "structured-log-metrics",
|
|
468
511
|
owner: "structured log provider",
|
|
@@ -770,6 +813,19 @@ function ownerHistoryPolicy(version: string): HarneryStoragePolicy {
|
|
|
770
813
|
});
|
|
771
814
|
}
|
|
772
815
|
|
|
816
|
+
function closedEpochPolicy(version: string): HarneryStoragePolicy {
|
|
817
|
+
return policy(version, "active", "private", "owner-content", {
|
|
818
|
+
status: "active",
|
|
819
|
+
mode: "delegated",
|
|
820
|
+
maxAge: bounded(7 * DAY_MS, "milliseconds"),
|
|
821
|
+
maxBytes: bounded(1024 * MIB, "bytes"),
|
|
822
|
+
maxFiles: unbounded("files", "complete epoch directories are the deletion unit"),
|
|
823
|
+
maxRecords: unbounded("records", "complete epoch directories are the deletion unit"),
|
|
824
|
+
reason:
|
|
825
|
+
"The Event Ledger owner keeps the newest two complete epochs and revalidates each closed epoch before removal.",
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
|
|
773
829
|
function delegatedHistoryPolicy(version: string): HarneryStoragePolicy {
|
|
774
830
|
const result = ownerHistoryPolicy(version);
|
|
775
831
|
result.retention.mode = "delegated";
|
|
@@ -517,6 +517,8 @@ const PROCESS_LOGGER_BINDINGS = {
|
|
|
517
517
|
"agent-hook": "agent-hook-debug-log",
|
|
518
518
|
"agent-coord": "agent-coord-debug-log",
|
|
519
519
|
"semantic-service": "semantic-service-log",
|
|
520
|
+
"resource-observer": "resource-observer-log",
|
|
521
|
+
supervisor: "supervisor-log",
|
|
520
522
|
"governor-service": "governor-service-log",
|
|
521
523
|
"presence-relay": "presence-relay-log",
|
|
522
524
|
} as const;
|
|
@@ -42,6 +42,12 @@ export interface HarneryLogFollowCursor {
|
|
|
42
42
|
active_offset: number;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export interface HarneryRecentActiveLogResult {
|
|
46
|
+
records: readonly HarneryLogRecordV1[];
|
|
47
|
+
bytes_examined: number;
|
|
48
|
+
truncated: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
45
51
|
const LEVELS: readonly HarneryLogLevel[] = ["trace", "debug", "info", "warn", "error", "fatal"];
|
|
46
52
|
const MAX_UNBOUNDED_RECORD_BYTES = 1024 * 1024;
|
|
47
53
|
const STREAM_CHUNK_BYTES = 64 * 1024;
|
|
@@ -109,6 +115,58 @@ export function rotationFollowCursor(
|
|
|
109
115
|
};
|
|
110
116
|
}
|
|
111
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Read the newest complete records from one family's active segment without
|
|
120
|
+
* walking sealed history. Dashboard-style live views need a cheap bounded
|
|
121
|
+
* snapshot; the full `queryLogs` surface remains the historical query path.
|
|
122
|
+
*/
|
|
123
|
+
export function readRecentActiveLogs(
|
|
124
|
+
family: HarneryRegisteredStorageFamily,
|
|
125
|
+
options: { max_records: number; max_bytes: number },
|
|
126
|
+
): HarneryRecentActiveLogResult {
|
|
127
|
+
if (
|
|
128
|
+
!Number.isSafeInteger(options.max_records) ||
|
|
129
|
+
options.max_records <= 0 ||
|
|
130
|
+
!Number.isSafeInteger(options.max_bytes) ||
|
|
131
|
+
options.max_bytes <= 0
|
|
132
|
+
) {
|
|
133
|
+
throw new Error("recent log read requires positive budgets");
|
|
134
|
+
}
|
|
135
|
+
const active = join(familyLogDirectory(family), "active.jsonl");
|
|
136
|
+
if (!existsSync(active)) return { records: [], bytes_examined: 0, truncated: false };
|
|
137
|
+
|
|
138
|
+
const opened = openRegularNoFollow(active);
|
|
139
|
+
try {
|
|
140
|
+
const size = fstatSync(opened.fd).size;
|
|
141
|
+
const start = Math.max(0, size - options.max_bytes);
|
|
142
|
+
const length = size - start;
|
|
143
|
+
if (length === 0) return { records: [], bytes_examined: 0, truncated: false };
|
|
144
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
145
|
+
let consumed = 0;
|
|
146
|
+
while (consumed < length) {
|
|
147
|
+
const count = readSync(opened.fd, buffer, consumed, length - consumed, start + consumed);
|
|
148
|
+
if (count === 0) break;
|
|
149
|
+
consumed += count;
|
|
150
|
+
}
|
|
151
|
+
assertOpenFileIdentity(active, opened.fd, opened.parent);
|
|
152
|
+
const text = buffer.subarray(0, consumed).toString("utf8");
|
|
153
|
+
let lines = text.split("\n");
|
|
154
|
+
// A bounded tail can begin in the middle of a record. The active writer
|
|
155
|
+
// can also leave a not-yet-complete final record while this snapshot reads.
|
|
156
|
+
if (start > 0) lines = lines.slice(1);
|
|
157
|
+
if (!text.endsWith("\n")) lines = lines.slice(0, -1);
|
|
158
|
+
const records = lines.filter((line) => line.trim()).map(parseLogRecord);
|
|
159
|
+
const truncated = start > 0 || records.length > options.max_records;
|
|
160
|
+
return {
|
|
161
|
+
records: records.slice(-options.max_records),
|
|
162
|
+
bytes_examined: consumed,
|
|
163
|
+
truncated,
|
|
164
|
+
};
|
|
165
|
+
} finally {
|
|
166
|
+
closeSync(opened.fd);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
112
170
|
export async function readLogFollow(
|
|
113
171
|
family: HarneryRegisteredStorageFamily,
|
|
114
172
|
cursor: HarneryLogFollowCursor,
|