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,361 @@
|
|
|
1
|
+
// Contracts for the qa-run matrix runner: one JSON job in, one JSON result
|
|
2
|
+
// out, with the coverage-merge and verdict rules as pure functions.
|
|
3
|
+
//
|
|
4
|
+
// The runner executes a whole page-QA matrix (planner, deterministic gates,
|
|
5
|
+
// interactions, critique, snapshot) in one process so the driving agent stops
|
|
6
|
+
// paying a model turn per browser command. These contracts are frozen first so
|
|
7
|
+
// the orchestrator, its tests, and downstream consumers build against the same
|
|
8
|
+
// shape.
|
|
9
|
+
//
|
|
10
|
+
// Two rules are load-bearing and enforced here, not in prose:
|
|
11
|
+
// - A job may WIDEN coverage beyond the planner's manifest but can never
|
|
12
|
+
// narrow it below the manifest (mergeCoverage is a union that keeps
|
|
13
|
+
// manifest order first).
|
|
14
|
+
// - A job must not carry credentials. Authentication is referenced through
|
|
15
|
+
// existing browser profiles and cookie stores; validation refuses
|
|
16
|
+
// secret-shaped fields before any browser or model work starts.
|
|
17
|
+
//
|
|
18
|
+
// Toolkit tier: this module must not import src/core (layering check).
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
export const QA_RUN_JOB_SCHEMA_VERSION = 1;
|
|
21
|
+
export const QA_RUN_RESULT_SCHEMA_VERSION = 4;
|
|
22
|
+
/** Runner stages in execution order. `last_completed_stage` names the last
|
|
23
|
+
* one that finished without contributing a blocker. */
|
|
24
|
+
export const QA_RUN_STAGES = [
|
|
25
|
+
"plan",
|
|
26
|
+
"gates",
|
|
27
|
+
"interactions",
|
|
28
|
+
"capture",
|
|
29
|
+
"critique",
|
|
30
|
+
"snapshot",
|
|
31
|
+
];
|
|
32
|
+
export const QA_RUN_STATUS_SCHEMA_VERSION = 1;
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Job validation
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/** Field names that indicate an embedded credential. Matched on any object
|
|
37
|
+
* key anywhere in the job, case-insensitively. */
|
|
38
|
+
const SECRET_KEY_PATTERN = /(password|passwd|secret|token|api[-_]?key|authorization|cookie|credential|bearer)/i;
|
|
39
|
+
/** Value shapes that indicate an embedded credential even under an innocent
|
|
40
|
+
* key: explicit auth headers and long unbroken high-entropy-looking blobs. */
|
|
41
|
+
const SECRET_VALUE_PATTERNS = [/\bBearer\s+[\w.~+/=-]{16,}/i, /\bBasic\s+[A-Za-z0-9+/=]{16,}/];
|
|
42
|
+
function scanForSecrets(value, path, errors) {
|
|
43
|
+
if (typeof value === "string") {
|
|
44
|
+
for (const pattern of SECRET_VALUE_PATTERNS) {
|
|
45
|
+
if (pattern.test(value)) {
|
|
46
|
+
errors.push(`${path}: value looks like a credential — reference a browser profile or cookie store instead`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(value)) {
|
|
53
|
+
value.forEach((item, i) => {
|
|
54
|
+
scanForSecrets(item, `${path}[${i}]`, errors);
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (value && typeof value === "object") {
|
|
59
|
+
for (const [key, child] of Object.entries(value)) {
|
|
60
|
+
if (SECRET_KEY_PATTERN.test(key)) {
|
|
61
|
+
errors.push(`${path}.${key}: secret-bearing field names are refused — reference a browser profile or cookie store instead`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
scanForSecrets(child, `${path}.${key}`, errors);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function isStringArray(value) {
|
|
69
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validate an untrusted job document. Structural errors and secret-bearing
|
|
73
|
+
* fields are all reported at once so a caller can fix the job in one pass.
|
|
74
|
+
* Validation is deliberately strict: an underspecified job fails here, before
|
|
75
|
+
* any browser or model process starts.
|
|
76
|
+
*/
|
|
77
|
+
export function validateQaRunJob(value) {
|
|
78
|
+
const errors = [];
|
|
79
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
80
|
+
return { ok: false, errors: ["job must be a JSON object"] };
|
|
81
|
+
}
|
|
82
|
+
const job = value;
|
|
83
|
+
if (job.schema_version !== QA_RUN_JOB_SCHEMA_VERSION) {
|
|
84
|
+
errors.push(`schema_version must be ${QA_RUN_JOB_SCHEMA_VERSION}`);
|
|
85
|
+
}
|
|
86
|
+
if (typeof job.target !== "string" || job.target.length === 0) {
|
|
87
|
+
errors.push("target is required (URL, file path, or route)");
|
|
88
|
+
}
|
|
89
|
+
if (job.mode !== "signoff" && job.mode !== "review") {
|
|
90
|
+
errors.push('mode must be "signoff" or "review"');
|
|
91
|
+
}
|
|
92
|
+
const ids = new Set();
|
|
93
|
+
if (job.contexts !== undefined) {
|
|
94
|
+
if (!Array.isArray(job.contexts)) {
|
|
95
|
+
errors.push("contexts must be an array");
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
job.contexts.forEach((ctx, i) => {
|
|
99
|
+
const c = ctx;
|
|
100
|
+
if (typeof c?.id !== "string" || c.id.length === 0)
|
|
101
|
+
errors.push(`contexts[${i}].id is required`);
|
|
102
|
+
else if (ids.has(c.id))
|
|
103
|
+
errors.push(`contexts[${i}].id duplicates "${c.id}"`);
|
|
104
|
+
else
|
|
105
|
+
ids.add(c.id);
|
|
106
|
+
if (typeof c?.viewport !== "string" || c.viewport.length === 0) {
|
|
107
|
+
errors.push(`contexts[${i}].viewport is required`);
|
|
108
|
+
}
|
|
109
|
+
if (c?.theme !== "light" && c?.theme !== "dark") {
|
|
110
|
+
errors.push(`contexts[${i}].theme must be "light" or "dark"`);
|
|
111
|
+
}
|
|
112
|
+
if (typeof c?.state !== "string" || c.state.length === 0) {
|
|
113
|
+
errors.push(`contexts[${i}].state is required ("default" for the plain page)`);
|
|
114
|
+
}
|
|
115
|
+
if (c?.args !== undefined && !isStringArray(c.args)) {
|
|
116
|
+
errors.push(`contexts[${i}].args must be an argument array (never a shell string)`);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (job.checks !== undefined) {
|
|
122
|
+
if (!Array.isArray(job.checks)) {
|
|
123
|
+
errors.push("checks must be an array");
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const checkIds = new Set();
|
|
127
|
+
job.checks.forEach((check, i) => {
|
|
128
|
+
const c = check;
|
|
129
|
+
if (typeof c?.id !== "string" || c.id.length === 0)
|
|
130
|
+
errors.push(`checks[${i}].id is required`);
|
|
131
|
+
else if (checkIds.has(c.id))
|
|
132
|
+
errors.push(`checks[${i}].id duplicates "${c.id}"`);
|
|
133
|
+
else
|
|
134
|
+
checkIds.add(c.id);
|
|
135
|
+
if (!isStringArray(c?.args) || c.args.length === 0) {
|
|
136
|
+
errors.push(`checks[${i}].args must be a non-empty argument array (never a shell string)`);
|
|
137
|
+
}
|
|
138
|
+
if (c?.contexts !== undefined && !isStringArray(c.contexts)) {
|
|
139
|
+
errors.push(`checks[${i}].contexts must be an array of context IDs`);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (job.interaction_states !== undefined) {
|
|
145
|
+
if (!Array.isArray(job.interaction_states)) {
|
|
146
|
+
errors.push("interaction_states must be an array");
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
job.interaction_states.forEach((state, i) => {
|
|
150
|
+
const s = state;
|
|
151
|
+
if (typeof s?.name !== "string" || s.name.length === 0) {
|
|
152
|
+
errors.push(`interaction_states[${i}].name is required`);
|
|
153
|
+
}
|
|
154
|
+
if (!isStringArray(s?.setup) || s.setup.length === 0) {
|
|
155
|
+
errors.push(`interaction_states[${i}].setup must be a non-empty argument array`);
|
|
156
|
+
}
|
|
157
|
+
if (!isStringArray(s?.assertions) || s.assertions.length === 0) {
|
|
158
|
+
errors.push(`interaction_states[${i}].assertions must name at least one outcome assertion — a click without a proven outcome is not a gate`);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (job.policy !== undefined) {
|
|
164
|
+
const p = job.policy;
|
|
165
|
+
if (p?.command_concurrency !== undefined) {
|
|
166
|
+
const n = p.command_concurrency;
|
|
167
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 1 || n > 8) {
|
|
168
|
+
errors.push("policy.command_concurrency must be an integer between 1 and 8");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (p?.command_timeout_ms !== undefined) {
|
|
172
|
+
const n = p.command_timeout_ms;
|
|
173
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 1000) {
|
|
174
|
+
errors.push("policy.command_timeout_ms must be an integer ≥ 1000");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (p?.run_deadline_ms !== undefined) {
|
|
178
|
+
const n = p.run_deadline_ms;
|
|
179
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 10_000) {
|
|
180
|
+
errors.push("policy.run_deadline_ms must be an integer ≥ 10000");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (p?.critique_max_tiles !== undefined) {
|
|
184
|
+
const n = p.critique_max_tiles;
|
|
185
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 1 || n > 200) {
|
|
186
|
+
errors.push("policy.critique_max_tiles must be an integer between 1 and 200");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (p?.critique_pool !== undefined) {
|
|
190
|
+
const n = p.critique_pool;
|
|
191
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 1 || n > 16) {
|
|
192
|
+
errors.push("policy.critique_pool must be an integer between 1 and 16");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (p?.review_pack_retention_minutes !== undefined) {
|
|
196
|
+
const n = p.review_pack_retention_minutes;
|
|
197
|
+
if (typeof n !== "number" || !Number.isInteger(n) || n < 1 || n > 43_200) {
|
|
198
|
+
errors.push("policy.review_pack_retention_minutes must be an integer between 1 and 43200");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
scanForSecrets(job, "job", errors);
|
|
203
|
+
if (errors.length > 0)
|
|
204
|
+
return { ok: false, errors };
|
|
205
|
+
return { ok: true, job: value };
|
|
206
|
+
}
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
// Coverage merge — widen-only
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
export function contextIdFor(context) {
|
|
211
|
+
return `${context.viewport}-${context.theme}-${context.state}`;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Merge planner-manifest coverage with the job's extra contexts. The manifest
|
|
215
|
+
* is the floor: its contexts always run, in manifest order, and a job can only
|
|
216
|
+
* append. The union construction makes narrowing impossible by design; the
|
|
217
|
+
* returned list is what the runner executes and what the result reports.
|
|
218
|
+
*/
|
|
219
|
+
export function mergeCoverage(manifest, job) {
|
|
220
|
+
const merged = manifest.contexts.map((context) => ({
|
|
221
|
+
id: contextIdFor(context),
|
|
222
|
+
viewport: context.viewport,
|
|
223
|
+
theme: context.theme,
|
|
224
|
+
state: context.state,
|
|
225
|
+
}));
|
|
226
|
+
const seen = new Set(merged.map((context) => context.id));
|
|
227
|
+
for (const context of job.contexts ?? []) {
|
|
228
|
+
const canonical = contextIdFor(context);
|
|
229
|
+
if (seen.has(canonical) || seen.has(context.id))
|
|
230
|
+
continue;
|
|
231
|
+
seen.add(canonical);
|
|
232
|
+
seen.add(context.id);
|
|
233
|
+
merged.push(context);
|
|
234
|
+
}
|
|
235
|
+
return merged;
|
|
236
|
+
}
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
// Verdict — fail-closed
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
/**
|
|
241
|
+
* Compute the terminal verdict from completed evidence. The rules are the
|
|
242
|
+
* existing page-QA signoff contract, fail-closed:
|
|
243
|
+
* - any blocker → incomplete (a blocker is a fact the run could not
|
|
244
|
+
* establish, so a defect cannot be ruled out);
|
|
245
|
+
* - any failed or unknown command/critique outcome → failed when the check
|
|
246
|
+
* completed and found a defect, incomplete when the outcome is unknown;
|
|
247
|
+
* - signoff mode additionally requires the snapshot to have been saved.
|
|
248
|
+
* `passed` is only reachable when every input proves out.
|
|
249
|
+
*/
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
// Run identity: job digest + evidence assessment
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
/** Recursively key-sort plain objects so the digest is stable under key
|
|
254
|
+
* order. Arrays keep their order — it is semantically meaningful (contexts,
|
|
255
|
+
* argv arrays). */
|
|
256
|
+
function canonicalize(value) {
|
|
257
|
+
if (Array.isArray(value))
|
|
258
|
+
return value.map(canonicalize);
|
|
259
|
+
if (value && typeof value === "object") {
|
|
260
|
+
const record = value;
|
|
261
|
+
const sorted = {};
|
|
262
|
+
for (const key of Object.keys(record).sort())
|
|
263
|
+
sorted[key] = canonicalize(record[key]);
|
|
264
|
+
return sorted;
|
|
265
|
+
}
|
|
266
|
+
return value;
|
|
267
|
+
}
|
|
268
|
+
/** SHA-256 hex digest over the effective validated job (after the CLI merges
|
|
269
|
+
* its authoritative `target` and `mode`). `policy` is excluded: concurrency,
|
|
270
|
+
* timeout, and metered-critique knobs change how the run executes, not what
|
|
271
|
+
* it proves, and CLI flags mutate them after the job file is read — including
|
|
272
|
+
* them would make the same job file verify differently across invocations. */
|
|
273
|
+
export function computeJobDigest(job) {
|
|
274
|
+
const { policy: _policy, ...identityBearing } = job;
|
|
275
|
+
return createHash("sha256")
|
|
276
|
+
.update(JSON.stringify(canonicalize(identityBearing)))
|
|
277
|
+
.digest("hex");
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Assess whether a result document is fresh evidence for the invocation the
|
|
281
|
+
* caller has in mind. Fail-closed: a document without a verifiable identity
|
|
282
|
+
* block (schema v1 or foreign JSON) is stale by definition, and every
|
|
283
|
+
* expectation mismatch is reported, not just the first.
|
|
284
|
+
*/
|
|
285
|
+
export function assessQaRunEvidence(document, expectations = {}) {
|
|
286
|
+
const reasons = [];
|
|
287
|
+
if (!document || typeof document !== "object" || Array.isArray(document)) {
|
|
288
|
+
return { fresh: false, reasons: ["document is not a result object"] };
|
|
289
|
+
}
|
|
290
|
+
const result = document;
|
|
291
|
+
if (result.schema_version !== QA_RUN_RESULT_SCHEMA_VERSION) {
|
|
292
|
+
return {
|
|
293
|
+
fresh: false,
|
|
294
|
+
reasons: [
|
|
295
|
+
`schema_version is ${JSON.stringify(result.schema_version)}, not ` +
|
|
296
|
+
`${QA_RUN_RESULT_SCHEMA_VERSION} — pre-identity results carry nothing to verify`,
|
|
297
|
+
],
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
const run = result.run;
|
|
301
|
+
if (!run ||
|
|
302
|
+
typeof run.run_id !== "string" ||
|
|
303
|
+
typeof run.started_at !== "string" ||
|
|
304
|
+
typeof run.completed_at !== "string" ||
|
|
305
|
+
typeof run.job_digest !== "string") {
|
|
306
|
+
return { fresh: false, reasons: ["result carries no complete run-identity block"] };
|
|
307
|
+
}
|
|
308
|
+
if (expectations.run_id !== undefined && run.run_id !== expectations.run_id) {
|
|
309
|
+
reasons.push(`run_id ${run.run_id} is not the expected ${expectations.run_id}`);
|
|
310
|
+
}
|
|
311
|
+
if (expectations.job_digest !== undefined && run.job_digest !== expectations.job_digest) {
|
|
312
|
+
reasons.push("job_digest does not match the expected job definition");
|
|
313
|
+
}
|
|
314
|
+
if (expectations.tested_revision !== undefined) {
|
|
315
|
+
if (run.revision_source === "unknown" || run.tested_revision === undefined) {
|
|
316
|
+
reasons.push(`a revision expectation was given but the run recorded revision_source "unknown"`);
|
|
317
|
+
}
|
|
318
|
+
else if (run.tested_revision !== expectations.tested_revision) {
|
|
319
|
+
reasons.push(`tested_revision ${run.tested_revision} is not the expected ${expectations.tested_revision}`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (expectations.not_started_before !== undefined) {
|
|
323
|
+
if (Date.parse(run.started_at) < Date.parse(expectations.not_started_before)) {
|
|
324
|
+
reasons.push(`run started ${run.started_at}, before the freshness floor ${expectations.not_started_before}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (expectations.max_age_ms !== undefined) {
|
|
328
|
+
const now = expectations.now !== undefined ? Date.parse(expectations.now) : Date.now();
|
|
329
|
+
const age = now - Date.parse(run.completed_at);
|
|
330
|
+
if (Number.isNaN(age) || age > expectations.max_age_ms) {
|
|
331
|
+
reasons.push(`run completed ${run.completed_at}, older than the ${expectations.max_age_ms}ms maximum age`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (expectations.found_in_dir !== undefined && run.out_dir !== expectations.found_in_dir) {
|
|
335
|
+
reasons.push(`result was found in ${expectations.found_in_dir} but records out_dir ${run.out_dir} — ` +
|
|
336
|
+
"a moved or copied result is not evidence for its new location");
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
fresh: reasons.length === 0,
|
|
340
|
+
reasons,
|
|
341
|
+
run: run,
|
|
342
|
+
...(result.verdict !== undefined ? { verdict: result.verdict } : {}),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
export function computeVerdict(input) {
|
|
346
|
+
const failed = input.commands.some((command) => command.outcome === "failed") ||
|
|
347
|
+
input.critique.some((entry) => entry.outcome === "failed");
|
|
348
|
+
if (failed)
|
|
349
|
+
return "failed";
|
|
350
|
+
// Hand-recorded evidence can prove a defect but never its absence: nothing
|
|
351
|
+
// re-executable ran, so a manual result stops at incomplete by contract.
|
|
352
|
+
if (input.evidenceSource === "manual")
|
|
353
|
+
return "incomplete";
|
|
354
|
+
const unknown = input.commands.some((command) => command.outcome === "unknown") ||
|
|
355
|
+
input.critique.some((entry) => entry.outcome === "unknown");
|
|
356
|
+
if (input.blockers.length > 0 || unknown)
|
|
357
|
+
return "incomplete";
|
|
358
|
+
if (input.mode === "signoff" && !input.snapshotSaved)
|
|
359
|
+
return "incomplete";
|
|
360
|
+
return "passed";
|
|
361
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { type CritiqueProvider } from "./critique.js";
|
|
2
|
+
import { type QaRunJob, type QaRunResult } from "./qa-run-contracts.js";
|
|
3
|
+
import { type QaSnapshotStoreOptions } from "./qa-snapshot.js";
|
|
4
|
+
/** Set on the runner's own environment before the host's critique provider is
|
|
5
|
+
* loaded for the judge stage, unless the job permits metered critique: the
|
|
6
|
+
* provider must stay on subscription-backed headless harnesses and surface
|
|
7
|
+
* exhaustion instead of falling back to a metered API. */
|
|
8
|
+
export declare const QA_RUN_HEADLESS_ONLY_ENV = "HARNERY_CRITIQUE_HEADLESS_ONLY";
|
|
9
|
+
/** Result document written into the run's output directory. */
|
|
10
|
+
export declare const QA_RUN_RESULT_FILENAME = "page-qa-result.json";
|
|
11
|
+
/** Pointer document written into the parent output directory after every
|
|
12
|
+
* run, naming the newest run's directory and verdict. Consumers resolve the
|
|
13
|
+
* current result through this pointer instead of guessing at loose files. */
|
|
14
|
+
export declare const QA_RUN_LATEST_FILENAME = "latest.json";
|
|
15
|
+
export interface QaRunLatestPointerInput {
|
|
16
|
+
run_id: string;
|
|
17
|
+
dir: string;
|
|
18
|
+
completed_at: string;
|
|
19
|
+
verdict: QaRunResult["verdict"];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Publish the parent directory's latest-result pointer without allowing an
|
|
23
|
+
* older completion to replace a newer one. Both runner and manual evidence
|
|
24
|
+
* use this writer so every producer preserves the same ordering invariant.
|
|
25
|
+
*/
|
|
26
|
+
export declare function writeLatestPointer(outParent: string, input: QaRunLatestPointerInput): string;
|
|
27
|
+
/** Live status document beside the result (QaRunStatusDocument): written at
|
|
28
|
+
* start, every stage boundary, and on a heartbeat timer, so a disconnected
|
|
29
|
+
* client can tell a running job from a dead one without guessing. */
|
|
30
|
+
export declare const QA_RUN_STATUS_FILENAME = "run-status.json";
|
|
31
|
+
/** The effective validated job, written into the run directory so a
|
|
32
|
+
* reconnecting client can re-derive the job digest (`qa-verify --job`). */
|
|
33
|
+
export declare const QA_RUN_JOB_FILENAME = "job.json";
|
|
34
|
+
export interface QaRunExecOptions {
|
|
35
|
+
/** Hard per-command timeout in milliseconds. */
|
|
36
|
+
timeoutMs: number;
|
|
37
|
+
/** Complete child environment (already layered by the runner). */
|
|
38
|
+
env: NodeJS.ProcessEnv;
|
|
39
|
+
}
|
|
40
|
+
export interface QaRunExecResult {
|
|
41
|
+
/** Process exit code; null when the command never completed normally. */
|
|
42
|
+
exitCode: number | null;
|
|
43
|
+
stdout: string;
|
|
44
|
+
stderr: string;
|
|
45
|
+
/** Spawn failure / timeout / signal description. Presence means the
|
|
46
|
+
* command's outcome cannot be trusted. */
|
|
47
|
+
error?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Injectable child-process executor. `argv[0]` is the executable. */
|
|
50
|
+
export type QaRunExec = (argv: string[], options: QaRunExecOptions) => Promise<QaRunExecResult>;
|
|
51
|
+
/** Grace between the timeout's SIGTERM and the follow-up SIGKILL. A child
|
|
52
|
+
* that catches SIGTERM (Bun installs a handler by default) gets this long to
|
|
53
|
+
* exit before the kill is made non-negotiable. */
|
|
54
|
+
export declare const QA_RUN_KILL_GRACE_MS = 5000;
|
|
55
|
+
/** Default executor: spawn with argv arrays only (never a shell string),
|
|
56
|
+
* closed stdin, bounded output buffers, and the policy timeout.
|
|
57
|
+
*
|
|
58
|
+
* Timeout enforcement is escalated and group-wide, via `spawn` rather than
|
|
59
|
+
* `execFile` for two live-verified reasons. First, a child that catches
|
|
60
|
+
* SIGTERM while awaiting its own grandchildren turns a single polite kill
|
|
61
|
+
* into an unbounded wait (a critique command outlived its 120s cap by 10x).
|
|
62
|
+
* Second, `execFile` resolves only when the child's stdio closes, and an
|
|
63
|
+
* orphaned grandchild inheriting the pipe keeps it open after the child is
|
|
64
|
+
* dead — so even a delivered kill did not settle the call. The child is
|
|
65
|
+
* therefore spawned detached into its own process group; at the deadline the
|
|
66
|
+
* whole group gets SIGTERM, then SIGKILL after a grace, and the result
|
|
67
|
+
* settles on exit with whatever output drained, never waiting on a pipe an
|
|
68
|
+
* orphan still holds. A timed-out command reports an error even if the child
|
|
69
|
+
* then exits 0 — a result produced after the deadline cannot be trusted. */
|
|
70
|
+
export declare const defaultQaRunExec: QaRunExec;
|
|
71
|
+
export interface QaRunMatrixOptions {
|
|
72
|
+
/** A validated job (see validateQaRunJob — the runner trusts its shape). */
|
|
73
|
+
job: QaRunJob;
|
|
74
|
+
/** PARENT directory for run output. Every invocation creates its own
|
|
75
|
+
* `run-<run_id>/` beneath it for artifacts and the result document, and
|
|
76
|
+
* maintains `latest.json` in the parent — a reused parent can therefore
|
|
77
|
+
* never present an older run's result as the current one. */
|
|
78
|
+
outParent: string;
|
|
79
|
+
/** argv prefix that reaches the host CLI's browse command, e.g.
|
|
80
|
+
* `[process.execPath, cliScript, "browse"]`. */
|
|
81
|
+
browseArgv: string[];
|
|
82
|
+
/** Injectable executor (tests). Default: execFile via defaultQaRunExec. */
|
|
83
|
+
exec?: QaRunExec;
|
|
84
|
+
/** Extra child-environment overrides layered over process.env. */
|
|
85
|
+
childEnv?: NodeJS.ProcessEnv;
|
|
86
|
+
/** Progress callback for human-facing per-stage lines. */
|
|
87
|
+
onLog?: (message: string) => void;
|
|
88
|
+
/** Run ID override (tests). Default: crypto.randomUUID(). */
|
|
89
|
+
runId?: string;
|
|
90
|
+
/** Working-tree revision probe supplied by the caller (the CLI probes git
|
|
91
|
+
* once). Ignored when the job itself pins tested_revision. */
|
|
92
|
+
revisionProbe?: {
|
|
93
|
+
tested_revision?: string;
|
|
94
|
+
worktree_dirty?: boolean;
|
|
95
|
+
};
|
|
96
|
+
/** Machine-wide admission gate. When present the runner acquires a slot
|
|
97
|
+
* before any browser work, records the wait as wall_time_ms.queue (never
|
|
98
|
+
* part of total), and finalizes an incomplete result with an "admission"
|
|
99
|
+
* blocker when acquisition fails — the evidence trail survives a full
|
|
100
|
+
* queue. The returned function releases the slot; the runner calls it at
|
|
101
|
+
* finalize, and a crashed runner's slot is reclaimed by dead-PID pruning. */
|
|
102
|
+
admission?: {
|
|
103
|
+
resource: string;
|
|
104
|
+
acquire: (onWait: (message: string) => void) => Promise<() => void>;
|
|
105
|
+
/** Snapshot of the other holders of the resource, sampled alongside host
|
|
106
|
+
* pressure so an incomplete run names what it was competing with. */
|
|
107
|
+
holders?: () => Array<{
|
|
108
|
+
label: string;
|
|
109
|
+
pid: number;
|
|
110
|
+
}>;
|
|
111
|
+
};
|
|
112
|
+
/** Host-injected vision call for the judge stage. The judge runs in this
|
|
113
|
+
* process over the pack on disk, after every capture browser has closed. */
|
|
114
|
+
critiqueProvider?: CritiqueProvider;
|
|
115
|
+
/** Lazy alternative to `critiqueProvider`; called once, after the
|
|
116
|
+
* headless-only environment has been applied. */
|
|
117
|
+
critiqueProviderLoader?: () => Promise<CritiqueProvider | undefined>;
|
|
118
|
+
/** QA snapshot store override (tests, host-managed cache locations). */
|
|
119
|
+
snapshotStore?: QaSnapshotStoreOptions;
|
|
120
|
+
/** Renders the command a reader can run to judge the pack later; shown in
|
|
121
|
+
* the pack's review.md when the judge did not run. */
|
|
122
|
+
reviewPackJudgeCommand?: (packDir: string) => string;
|
|
123
|
+
/** True when the run writes into the managed artifact store: the pack's
|
|
124
|
+
* manifest then says `managed: true` and the expiry sweep may delete it
|
|
125
|
+
* once `policy.review_pack_retention_minutes` (default 90) have passed
|
|
126
|
+
* since the judge finished. A pack under an explicit out dir stays
|
|
127
|
+
* unmanaged and is never deleted automatically. */
|
|
128
|
+
reviewPackManaged?: boolean;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Execute the whole QA matrix for one validated job and return the result
|
|
132
|
+
* (also written to `<outDir>/page-qa-result.json`). Stages: plan →
|
|
133
|
+
* deterministic gates (bounded pool) → interactions (serial) → capture (each
|
|
134
|
+
* context rendered once into the run's page review pack through the same
|
|
135
|
+
* pool, browser closed) → critique (one in-process pool of vision calls over
|
|
136
|
+
* every tile of every context, no browser open) → snapshot (persisted from
|
|
137
|
+
* the pack's files in signoff). The verdict is computeVerdict over
|
|
138
|
+
* everything recorded — fail-closed.
|
|
139
|
+
*/
|
|
140
|
+
export declare function runQaMatrix(options: QaRunMatrixOptions): Promise<QaRunResult>;
|
|
141
|
+
//# sourceMappingURL=qa-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qa-run.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/qa-run.ts"],"names":[],"mappings":"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"}
|