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,396 @@
|
|
|
1
|
+
// `qa-run <target>`: run the whole page-QA matrix (planner, deterministic
|
|
2
|
+
// gates, interactions, critique, snapshot) in one command. The agent's loop
|
|
3
|
+
// collapses to: build the job, run this, read page-qa-result.json.
|
|
4
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
import { closeSync, mkdirSync, openSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { join, resolve } from "node:path";
|
|
8
|
+
import { Option } from "commander";
|
|
9
|
+
import { recordQaSignal } from "../core/agents/qa-signal.js";
|
|
10
|
+
import { artifactsRoot } from "../core/artifacts/index.js";
|
|
11
|
+
import { resolveBinName, reviewPackAutoCleanEnabled } from "../core/config.js";
|
|
12
|
+
import { createManagedQaOutParent, resolveQaRepoRoot } from "../core/qa-artifacts.js";
|
|
13
|
+
import { acquireAdmission, admissionBaseDir, admissionStatus } from "../lib/admission.js";
|
|
14
|
+
import { deleteExpiredPacks, PAGE_REVIEW_DEFAULT_RETENTION_MINUTES, } from "../lib/browser/page-review-pack.js";
|
|
15
|
+
import { QA_RUN_JOB_FILENAME, QA_RUN_RESULT_FILENAME, QA_RUN_STATUS_FILENAME, runQaMatrix, } from "../lib/browser/qa-run.js";
|
|
16
|
+
import { QA_RUN_JOB_SCHEMA_VERSION, QA_RUN_STATUS_SCHEMA_VERSION, validateQaRunJob, } from "../lib/browser/qa-run-contracts.js";
|
|
17
|
+
import { coordEnv } from "../lib/env.js";
|
|
18
|
+
/** Machine-wide admission resource that qa-run queues on by default. */
|
|
19
|
+
export const QA_ADMISSION_RESOURCE = "browser-qa";
|
|
20
|
+
/** Default concurrent browser-QA runs per machine. */
|
|
21
|
+
export const QA_ADMISSION_DEFAULT_CAPACITY = 2;
|
|
22
|
+
export function registerQaRunCommand(program, emit, context) {
|
|
23
|
+
program
|
|
24
|
+
.command("qa-run <target>")
|
|
25
|
+
.description("Run the whole page-QA matrix in one command: QA planner, deterministic " +
|
|
26
|
+
"gates per viewport/theme/state through a bounded process pool, serial " +
|
|
27
|
+
"interaction assertions, capture of every context into a page review pack " +
|
|
28
|
+
"(browsers closed), one in-process pool of vision calls over the pack, and the " +
|
|
29
|
+
"QA snapshot. Writes page-qa-result.json with a fail-closed verdict.")
|
|
30
|
+
.option("--job <file>", "QA job document (JSON). Validated before any browser starts — secret-bearing " +
|
|
31
|
+
"fields are refused, and the job may widen but never narrow the planner's coverage. " +
|
|
32
|
+
"Absent: a minimal implicit job for <target> is used.")
|
|
33
|
+
.option("--mode <mode>", "signoff persists a QA snapshot on a passing run; review never does.", "signoff")
|
|
34
|
+
.option("--concurrency <n>", "Concurrent deterministic gates and pack captures (1-8; default 2). Interactions " +
|
|
35
|
+
"always run serially; the judge pool is policy.critique_pool / --pool.")
|
|
36
|
+
.option("--pool <n>", "Vision calls in flight during the judge stage, across every context (1-16; default: " +
|
|
37
|
+
"the provider's own concurrency). Sets policy.critique_pool.")
|
|
38
|
+
.option("--allow-metered", "Permit the critique provider's metered-API fallback. Default: subscription-backed " +
|
|
39
|
+
"headless harnesses only — exhaustion becomes an incomplete blocker, never a metered call.")
|
|
40
|
+
.option("--retain <minutes>", `Minutes the run's page review pack lives after the judge finishes before the whole ` +
|
|
41
|
+
`pack is deleted (1-43200; default ${PAGE_REVIEW_DEFAULT_RETENTION_MINUTES}). Sets ` +
|
|
42
|
+
"policy.review_pack_retention_minutes. The result document keeps every finding inline.")
|
|
43
|
+
.option("--out-dir <dir>", "PARENT output directory (default: a managed .harnery/artifacts workspace). Every " +
|
|
44
|
+
"invocation writes into its own run-<run_id>/ beneath it and updates the parent's " +
|
|
45
|
+
"latest.json pointer — prior runs are never overwritten and never pass as current.")
|
|
46
|
+
.option("--json", "Print the full QaRunResult JSON to stdout.")
|
|
47
|
+
.option("--detach", "Launch the run as a detached background process whose authoritative state " +
|
|
48
|
+
"lives on disk (job.json, run-status.json, runner.log, the result document). " +
|
|
49
|
+
"The command prints the run directory and returns immediately; a client " +
|
|
50
|
+
"disconnect no longer touches the job. Reconnect with qa-status <run-dir> --wait.")
|
|
51
|
+
.option("--no-queue", "Skip machine-wide admission control. Default: the run waits for one of the " +
|
|
52
|
+
"browser-qa slots so simultaneous heavy runs take turns instead of thrashing " +
|
|
53
|
+
"the host; the wait is recorded as wall_time_ms.queue, never in total.")
|
|
54
|
+
.option("--queue-timeout <minutes>", "Maximum admission wait before the run finalizes incomplete with an " +
|
|
55
|
+
'"admission" blocker (default 20).')
|
|
56
|
+
.option("--queue-capacity <n>", "Concurrent browser-qa runs this machine should allow (1-8; default " +
|
|
57
|
+
"HARNERY_QA_ADMISSION_CAPACITY or 2). Advisory — the smallest capacity among " +
|
|
58
|
+
"concurrent waiters effectively governs.")
|
|
59
|
+
.addOption(new Option("--run-id <uuid>", "Internal: pre-minted run ID (detach child plumbing).").hideHelp())
|
|
60
|
+
.addHelpText("after", "\nExit codes: 0 verdict passed · 1 usage or job-validation error · " +
|
|
61
|
+
"2 verdict failed · 4 verdict incomplete.")
|
|
62
|
+
.action(async (target, opts, command) => {
|
|
63
|
+
if (opts.mode !== "signoff" && opts.mode !== "review") {
|
|
64
|
+
emit.error({
|
|
65
|
+
code: "qa_run_invalid_mode",
|
|
66
|
+
message: '--mode must be "signoff" or "review"',
|
|
67
|
+
});
|
|
68
|
+
process.exitCode = 1;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const modeExplicit = command.getOptionValueSource("mode") === "cli";
|
|
72
|
+
let jobDocument;
|
|
73
|
+
if (opts.job) {
|
|
74
|
+
let rawText;
|
|
75
|
+
try {
|
|
76
|
+
rawText = readFileSync(opts.job, "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
emit.error({
|
|
80
|
+
code: "qa_run_job_unreadable",
|
|
81
|
+
message: `cannot read --job file ${opts.job}: ${err instanceof Error ? err.message : String(err)}`,
|
|
82
|
+
});
|
|
83
|
+
process.exitCode = 1;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = JSON.parse(rawText);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
emit.error({
|
|
92
|
+
code: "qa_run_job_invalid_json",
|
|
93
|
+
message: `--job file ${opts.job} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
94
|
+
});
|
|
95
|
+
process.exitCode = 1;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
99
|
+
const raw = parsed;
|
|
100
|
+
// The CLI target argument is authoritative; a job file may omit
|
|
101
|
+
// target and mode. An explicit --mode overrides the job's mode.
|
|
102
|
+
jobDocument = {
|
|
103
|
+
...raw,
|
|
104
|
+
target,
|
|
105
|
+
...(raw.mode === undefined || modeExplicit ? { mode: opts.mode } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
jobDocument = parsed;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
jobDocument = { schema_version: QA_RUN_JOB_SCHEMA_VERSION, target, mode: opts.mode };
|
|
114
|
+
}
|
|
115
|
+
// All validation errors print at once, before any browser starts.
|
|
116
|
+
const validation = validateQaRunJob(jobDocument);
|
|
117
|
+
if (!validation.ok) {
|
|
118
|
+
for (const message of validation.errors)
|
|
119
|
+
emit.log(`job: ${message}`, "error");
|
|
120
|
+
emit.error({
|
|
121
|
+
code: "qa_run_invalid_job",
|
|
122
|
+
message: `job validation failed with ${validation.errors.length} error${validation.errors.length === 1 ? "" : "s"}`,
|
|
123
|
+
});
|
|
124
|
+
process.exitCode = 1;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const policy = { ...validation.job.policy };
|
|
128
|
+
if (opts.concurrency !== undefined) {
|
|
129
|
+
const n = Number.parseInt(opts.concurrency, 10);
|
|
130
|
+
if (!Number.isInteger(n) || n < 1 || n > 8) {
|
|
131
|
+
emit.error({
|
|
132
|
+
code: "qa_run_invalid_concurrency",
|
|
133
|
+
message: "--concurrency must be an integer between 1 and 8",
|
|
134
|
+
});
|
|
135
|
+
process.exitCode = 1;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
policy.command_concurrency = n;
|
|
139
|
+
}
|
|
140
|
+
if (opts.pool !== undefined) {
|
|
141
|
+
const n = Number.parseInt(opts.pool, 10);
|
|
142
|
+
if (!Number.isInteger(n) || n < 1 || n > 16) {
|
|
143
|
+
emit.error({
|
|
144
|
+
code: "qa_run_invalid_pool",
|
|
145
|
+
message: "--pool must be an integer between 1 and 16",
|
|
146
|
+
});
|
|
147
|
+
process.exitCode = 1;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
policy.critique_pool = n;
|
|
151
|
+
}
|
|
152
|
+
if (opts.allowMetered)
|
|
153
|
+
policy.allow_metered_critique = true;
|
|
154
|
+
if (opts.retain !== undefined) {
|
|
155
|
+
const n = Number.parseInt(opts.retain, 10);
|
|
156
|
+
if (!Number.isInteger(n) || n < 1 || n > 43_200) {
|
|
157
|
+
emit.error({
|
|
158
|
+
code: "qa_run_invalid_retain",
|
|
159
|
+
message: "--retain must be an integer between 1 and 43200 (minutes)",
|
|
160
|
+
});
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
policy.review_pack_retention_minutes = n;
|
|
165
|
+
}
|
|
166
|
+
const job = { ...validation.job, policy };
|
|
167
|
+
const repoRoot = resolveQaRepoRoot(context);
|
|
168
|
+
// Expired packs in the store go before this run adds one; opt-in via
|
|
169
|
+
// review_pack.auto_clean. Only managed, expired packs are deleted.
|
|
170
|
+
if (reviewPackAutoCleanEnabled(repoRoot)) {
|
|
171
|
+
try {
|
|
172
|
+
const swept = deleteExpiredPacks({ roots: [artifactsRoot(repoRoot)], dryRun: false });
|
|
173
|
+
if (swept.deleted.length > 0) {
|
|
174
|
+
emit.log(`removed ${swept.deleted.length} expired page review pack${swept.deleted.length === 1 ? "" : "s"}`, "info");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
emit.log(`expired pack sweep skipped: ${err instanceof Error ? err.message : String(err)}`, "warn");
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
let outParent;
|
|
182
|
+
try {
|
|
183
|
+
outParent =
|
|
184
|
+
opts.outDir !== undefined
|
|
185
|
+
? resolve(opts.outDir)
|
|
186
|
+
: createManagedQaOutParent(repoRoot, "qa-run");
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
emit.error({
|
|
190
|
+
code: "qa_run_output_unavailable",
|
|
191
|
+
message: `cannot create managed QA output: ${err instanceof Error ? err.message : String(err)}`,
|
|
192
|
+
});
|
|
193
|
+
process.exitCode = 1;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const cliScript = process.argv[1];
|
|
197
|
+
if (!cliScript) {
|
|
198
|
+
emit.error({
|
|
199
|
+
code: "qa_run_no_cli_script",
|
|
200
|
+
message: "cannot resolve the host CLI script path for child browse invocations",
|
|
201
|
+
});
|
|
202
|
+
process.exitCode = 1;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// Children run the same host CLI, so they inherit the host's browse
|
|
206
|
+
// wiring (critique provider, cookie jar, profiles) unchanged.
|
|
207
|
+
const browseArgv = [process.execPath, cliScript, "browse"];
|
|
208
|
+
// ----------------------------------------------------- queue settings
|
|
209
|
+
let queueCapacity = QA_ADMISSION_DEFAULT_CAPACITY;
|
|
210
|
+
const capacityEnv = coordEnv("QA_ADMISSION_CAPACITY");
|
|
211
|
+
if (capacityEnv !== undefined) {
|
|
212
|
+
const n = Number.parseInt(capacityEnv, 10);
|
|
213
|
+
if (Number.isInteger(n) && n >= 1 && n <= 8)
|
|
214
|
+
queueCapacity = n;
|
|
215
|
+
}
|
|
216
|
+
if (opts.queueCapacity !== undefined) {
|
|
217
|
+
const n = Number.parseInt(opts.queueCapacity, 10);
|
|
218
|
+
if (!Number.isInteger(n) || n < 1 || n > 8) {
|
|
219
|
+
emit.error({
|
|
220
|
+
code: "qa_run_invalid_queue_capacity",
|
|
221
|
+
message: "--queue-capacity must be an integer between 1 and 8",
|
|
222
|
+
});
|
|
223
|
+
process.exitCode = 1;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
queueCapacity = n;
|
|
227
|
+
}
|
|
228
|
+
let queueTimeoutMs = 20 * 60_000;
|
|
229
|
+
if (opts.queueTimeout !== undefined) {
|
|
230
|
+
const n = Number.parseInt(opts.queueTimeout, 10);
|
|
231
|
+
if (!Number.isInteger(n) || n < 1 || n > 240) {
|
|
232
|
+
emit.error({
|
|
233
|
+
code: "qa_run_invalid_queue_timeout",
|
|
234
|
+
message: "--queue-timeout must be an integer between 1 and 240 (minutes)",
|
|
235
|
+
});
|
|
236
|
+
process.exitCode = 1;
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
queueTimeoutMs = n * 60_000;
|
|
240
|
+
}
|
|
241
|
+
// ------------------------------------------------------------- detach
|
|
242
|
+
if (opts.detach) {
|
|
243
|
+
const runId = randomUUID();
|
|
244
|
+
const runDir = join(outParent, `run-${runId}`);
|
|
245
|
+
mkdirSync(runDir, { recursive: true });
|
|
246
|
+
writeFileSync(join(runDir, QA_RUN_JOB_FILENAME), `${JSON.stringify(job, null, 2)}\n`);
|
|
247
|
+
const logPath = join(runDir, "runner.log");
|
|
248
|
+
const logFd = openSync(logPath, "a");
|
|
249
|
+
// The child is this same command minus --detach plus the pre-minted
|
|
250
|
+
// run ID, detached from the terminal with its output on disk: a
|
|
251
|
+
// client disconnect kills nothing and loses nothing.
|
|
252
|
+
const childArgv = [
|
|
253
|
+
cliScript,
|
|
254
|
+
"qa-run",
|
|
255
|
+
target,
|
|
256
|
+
...(opts.job ? ["--job", resolve(opts.job)] : []),
|
|
257
|
+
"--mode",
|
|
258
|
+
job.mode,
|
|
259
|
+
...(opts.concurrency !== undefined ? ["--concurrency", opts.concurrency] : []),
|
|
260
|
+
...(opts.pool !== undefined ? ["--pool", opts.pool] : []),
|
|
261
|
+
...(opts.allowMetered ? ["--allow-metered"] : []),
|
|
262
|
+
...(opts.retain !== undefined ? ["--retain", opts.retain] : []),
|
|
263
|
+
"--out-dir",
|
|
264
|
+
outParent,
|
|
265
|
+
"--run-id",
|
|
266
|
+
runId,
|
|
267
|
+
...(opts.queue === false ? ["--no-queue"] : []),
|
|
268
|
+
...(opts.queueTimeout !== undefined ? ["--queue-timeout", opts.queueTimeout] : []),
|
|
269
|
+
...(opts.queueCapacity !== undefined ? ["--queue-capacity", opts.queueCapacity] : []),
|
|
270
|
+
];
|
|
271
|
+
const child = spawn(process.execPath, childArgv, {
|
|
272
|
+
detached: true,
|
|
273
|
+
stdio: ["ignore", logFd, logFd],
|
|
274
|
+
});
|
|
275
|
+
child.unref();
|
|
276
|
+
closeSync(logFd);
|
|
277
|
+
const launching = {
|
|
278
|
+
schema_version: QA_RUN_STATUS_SCHEMA_VERSION,
|
|
279
|
+
run_id: runId,
|
|
280
|
+
pid: child.pid ?? 0,
|
|
281
|
+
state: "launching",
|
|
282
|
+
stage: null,
|
|
283
|
+
started_at: new Date().toISOString(),
|
|
284
|
+
updated_at: new Date().toISOString(),
|
|
285
|
+
};
|
|
286
|
+
writeFileSync(join(runDir, QA_RUN_STATUS_FILENAME), `${JSON.stringify(launching, null, 2)}\n`);
|
|
287
|
+
const binName = resolveBinName();
|
|
288
|
+
emit.log(`detached run ${runId} (pid ${child.pid ?? "unknown"})`, "info");
|
|
289
|
+
emit.log(`run dir: ${runDir}`, "info");
|
|
290
|
+
emit.log(`log: ${logPath}`, "info");
|
|
291
|
+
emit.log(`reconnect: ${binName} qa-status ${runDir} --wait`, "info");
|
|
292
|
+
if (opts.json) {
|
|
293
|
+
emit.data({
|
|
294
|
+
detached: true,
|
|
295
|
+
run_id: runId,
|
|
296
|
+
pid: child.pid ?? null,
|
|
297
|
+
run_dir: runDir,
|
|
298
|
+
log: logPath,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// ---------------------------------------------------------- admission
|
|
304
|
+
let admission;
|
|
305
|
+
if (opts.queue !== false) {
|
|
306
|
+
const dir = admissionBaseDir();
|
|
307
|
+
admission = {
|
|
308
|
+
resource: QA_ADMISSION_RESOURCE,
|
|
309
|
+
acquire: async (onWait) => {
|
|
310
|
+
let lastMessage = "";
|
|
311
|
+
const handle = await acquireAdmission({ dir, resource: QA_ADMISSION_RESOURCE, capacity: queueCapacity }, {
|
|
312
|
+
label: `qa-run ${target}`,
|
|
313
|
+
timeoutMs: queueTimeoutMs,
|
|
314
|
+
onWait: (info) => {
|
|
315
|
+
const holders = info.holders.map((holder) => holder.label).join(", ") || "none";
|
|
316
|
+
const message = `queued for a ${QA_ADMISSION_RESOURCE} slot: position ${info.position}, ` +
|
|
317
|
+
`capacity ${queueCapacity}, holder(s): ${holders}`;
|
|
318
|
+
if (message !== lastMessage) {
|
|
319
|
+
lastMessage = message;
|
|
320
|
+
onWait(message);
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
return handle.release;
|
|
325
|
+
},
|
|
326
|
+
holders: () => admissionStatus({ dir, resource: QA_ADMISSION_RESOURCE }).holders.map((holder) => ({
|
|
327
|
+
label: holder.label,
|
|
328
|
+
pid: holder.pid,
|
|
329
|
+
})),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
// One git probe for the identity block. Failure is not an error: a
|
|
333
|
+
// target outside any repository legitimately records "unknown".
|
|
334
|
+
let revisionProbe;
|
|
335
|
+
if (job.tested_revision === undefined) {
|
|
336
|
+
try {
|
|
337
|
+
const head = execFileSync("git", ["rev-parse", "HEAD"], {
|
|
338
|
+
encoding: "utf8",
|
|
339
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
340
|
+
}).trim();
|
|
341
|
+
const porcelain = execFileSync("git", ["status", "--porcelain"], {
|
|
342
|
+
encoding: "utf8",
|
|
343
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
344
|
+
});
|
|
345
|
+
revisionProbe = { tested_revision: head, worktree_dirty: porcelain.trim().length > 0 };
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
revisionProbe = undefined;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const binName = resolveBinName();
|
|
352
|
+
const result = await runQaMatrix({
|
|
353
|
+
job,
|
|
354
|
+
outParent,
|
|
355
|
+
browseArgv,
|
|
356
|
+
...(opts.runId !== undefined ? { runId: opts.runId } : {}),
|
|
357
|
+
...(revisionProbe ? { revisionProbe } : {}),
|
|
358
|
+
...(admission ? { admission } : {}),
|
|
359
|
+
// The judge runs in this process: the host's provider is loaded here,
|
|
360
|
+
// after the headless-only policy has been applied to the environment.
|
|
361
|
+
...(context?.critiqueProvider ? { critiqueProvider: context.critiqueProvider } : {}),
|
|
362
|
+
...(context?.critiqueProviderLoader
|
|
363
|
+
? { critiqueProviderLoader: context.critiqueProviderLoader }
|
|
364
|
+
: {}),
|
|
365
|
+
reviewPackJudgeCommand: (packDir) => `${binName} review-pack judge ${packDir}`,
|
|
366
|
+
// A pack in the managed store expires and is deleted; one under an
|
|
367
|
+
// explicit --out-dir is the caller's and is never swept automatically.
|
|
368
|
+
reviewPackManaged: opts.outDir === undefined,
|
|
369
|
+
onLog: (message) => emit.log(message, "info"),
|
|
370
|
+
});
|
|
371
|
+
// Publish the verdict for `agents status`, so an operator reading a
|
|
372
|
+
// session sees the runner clock instead of inferring QA time from
|
|
373
|
+
// session age. Best-effort by contract: never throws.
|
|
374
|
+
recordQaSignal(result);
|
|
375
|
+
if (opts.json)
|
|
376
|
+
emit.data(result);
|
|
377
|
+
const resultPath = join(result.run.out_dir, QA_RUN_RESULT_FILENAME);
|
|
378
|
+
for (const blocker of result.blockers) {
|
|
379
|
+
emit.log(`blocker [${blocker.stage}${blocker.context_id ? ` ${blocker.context_id}` : ""}]: ${blocker.reason}`, "warn");
|
|
380
|
+
}
|
|
381
|
+
if (result.review_pack) {
|
|
382
|
+
emit.log(`review pack: ${result.review_pack.review}` +
|
|
383
|
+
(result.review_pack.expires_at
|
|
384
|
+
? ` (deleted after ${result.review_pack.expires_at})`
|
|
385
|
+
: ""), "info");
|
|
386
|
+
}
|
|
387
|
+
emit.log(`verdict: ${result.verdict} — run ${result.run.run_id}, ` +
|
|
388
|
+
`${result.contexts.length} context${result.contexts.length === 1 ? "" : "s"}, ` +
|
|
389
|
+
`${result.commands.length} command${result.commands.length === 1 ? "" : "s"}, ` +
|
|
390
|
+
`${result.blockers.length} blocker${result.blockers.length === 1 ? "" : "s"}; result: ${resultPath}`, result.verdict === "passed" ? "info" : "warn");
|
|
391
|
+
if (result.verdict === "failed")
|
|
392
|
+
process.exitCode = 2;
|
|
393
|
+
else if (result.verdict === "incomplete")
|
|
394
|
+
process.exitCode = 4;
|
|
395
|
+
});
|
|
396
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { EmitContext, HarneryProgramContext } from "../commander.js";
|
|
3
|
+
import { type QaRunStage, type QaRunVerdict } from "../lib/browser/qa-run-contracts.js";
|
|
4
|
+
/** A running state whose heartbeat is older than this earns a staleness
|
|
5
|
+
* warning, but stays "running" while the PID is alive. */
|
|
6
|
+
export declare const QA_STATUS_HEARTBEAT_STALE_MS = 120000;
|
|
7
|
+
export type RunDirResolution = {
|
|
8
|
+
ok: true;
|
|
9
|
+
runDir: string;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
error: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Resolve `[path]` to a run directory. A file is a result document (its
|
|
16
|
+
* directory is the run directory); a directory carrying a status or result
|
|
17
|
+
* document is the run directory itself; any other directory is treated as a
|
|
18
|
+
* run PARENT: its `run-*` children are scanned and the one with the newest
|
|
19
|
+
* started_at wins, falling back to the `latest.json` pointer when no child
|
|
20
|
+
* carries a status or result. Without a path, the newest managed QA artifact
|
|
21
|
+
* under the repository's `.harnery/artifacts/` store is used.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveRunDir(inputPath?: string, repoRoot?: string): RunDirResolution;
|
|
24
|
+
export type QaStatusState = QaRunVerdict | "launching" | "queued" | "running" | "dead";
|
|
25
|
+
export interface QaStatusReport {
|
|
26
|
+
state: QaStatusState;
|
|
27
|
+
/** The result document exists; state is the run's final verdict. */
|
|
28
|
+
terminal: boolean;
|
|
29
|
+
/** 0 completed-passed · 2 completed-failed · 4 completed-incomplete or
|
|
30
|
+
* dead · 5 still in progress. */
|
|
31
|
+
exit: 0 | 2 | 4 | 5;
|
|
32
|
+
run_id: string | null;
|
|
33
|
+
pid: number | null;
|
|
34
|
+
stage: QaRunStage | null;
|
|
35
|
+
started_at: string | null;
|
|
36
|
+
updated_at: string | null;
|
|
37
|
+
completed_at: string | null;
|
|
38
|
+
/** now minus the status document's updated_at; null without a heartbeat. */
|
|
39
|
+
heartbeat_age_ms: number | null;
|
|
40
|
+
verdict?: QaRunVerdict;
|
|
41
|
+
result_path?: string;
|
|
42
|
+
log_path?: string;
|
|
43
|
+
queue?: {
|
|
44
|
+
resource: string;
|
|
45
|
+
waiting_since: string;
|
|
46
|
+
};
|
|
47
|
+
wall_time_ms?: Record<string, number>;
|
|
48
|
+
warnings: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface QaStatusDeps {
|
|
51
|
+
/** PID liveness probe (injectable for tests). Default: process.kill(pid, 0). */
|
|
52
|
+
pidAlive?: (pid: number) => boolean;
|
|
53
|
+
/** Evaluation instant in epoch milliseconds. Default: Date.now(). */
|
|
54
|
+
now?: () => number;
|
|
55
|
+
}
|
|
56
|
+
export type QaStatusClassification = {
|
|
57
|
+
ok: true;
|
|
58
|
+
report: QaStatusReport;
|
|
59
|
+
} | {
|
|
60
|
+
ok: false;
|
|
61
|
+
error: string;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Classify one run directory, fail-closed. The result document is terminal
|
|
65
|
+
* and authoritative when it exists; otherwise the status document plus a PID
|
|
66
|
+
* liveness probe decides between a live state and "dead". Neither file is a
|
|
67
|
+
* usage error, not a state.
|
|
68
|
+
*/
|
|
69
|
+
export declare function classifyRun(runDir: string, deps?: QaStatusDeps): QaStatusClassification;
|
|
70
|
+
export declare function registerQaStatusCommand(program: Command, emit: EmitContext, context?: HarneryProgramContext): void;
|
|
71
|
+
//# sourceMappingURL=qa-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qa-status.d.ts","sourceRoot":"","sources":["../../src/commands/qa-status.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAc1E,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;AAG5C;0DAC0D;AAC1D,eAAO,MAAM,4BAA4B,SAAU,CAAC;AAsCpD,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA6B3F;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAkErF;AAMD,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;IAClB;qCACiC;IACjC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACpC,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAQjC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,sBAAsB,CAiK3F;AAkHD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAiGN"}
|