@jevitate/cli 0.1.0 → 0.3.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/README.md +23 -0
- package/dist/ai-cli.d.ts +31 -11
- package/dist/ai-cli.js +131 -88
- package/dist/ai-cli.js.map +1 -1
- package/dist/author-journey-cli.d.ts +4 -0
- package/dist/author-journey-cli.js +111 -0
- package/dist/author-journey-cli.js.map +1 -0
- package/dist/bin.js +60349 -16477
- package/dist/bin.js.map +1 -1
- package/dist/browser-run-options.d.ts +89 -0
- package/dist/browser-run-options.js +175 -0
- package/dist/browser-run-options.js.map +1 -0
- package/dist/build-info.generated.d.ts +2 -0
- package/dist/build-info.generated.js +10 -0
- package/dist/build-info.generated.js.map +1 -0
- package/dist/campaign-api.d.ts +151 -0
- package/dist/campaign-api.js +446 -0
- package/dist/campaign-api.js.map +1 -0
- package/dist/campaign-cli.d.ts +6 -0
- package/dist/campaign-cli.js +66 -0
- package/dist/campaign-cli.js.map +1 -0
- package/dist/check-api.d.ts +5 -0
- package/dist/check-api.js +234 -0
- package/dist/check-api.js.map +1 -0
- package/dist/check-budget.d.ts +26 -0
- package/dist/check-budget.js +90 -0
- package/dist/check-budget.js.map +1 -0
- package/dist/check-cli.d.ts +31 -0
- package/dist/check-cli.js +109 -0
- package/dist/check-cli.js.map +1 -0
- package/dist/check-execute.d.ts +29 -0
- package/dist/check-execute.js +420 -0
- package/dist/check-execute.js.map +1 -0
- package/dist/check-plan.d.ts +118 -0
- package/dist/check-plan.js +516 -0
- package/dist/check-plan.js.map +1 -0
- package/dist/check-suite.d.ts +184 -0
- package/dist/check-suite.js +540 -0
- package/dist/check-suite.js.map +1 -0
- package/dist/check-types.d.ts +181 -0
- package/dist/check-types.js +35 -0
- package/dist/check-types.js.map +1 -0
- package/dist/cli-args.d.ts +26 -0
- package/dist/cli-args.js +50 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-output.d.ts +106 -0
- package/dist/cli-output.js +563 -0
- package/dist/cli-output.js.map +1 -0
- package/dist/cli-reference.d.ts +3 -0
- package/dist/cli-reference.js +81 -0
- package/dist/cli-reference.js.map +1 -0
- package/dist/cli-refusal.d.ts +12 -0
- package/dist/cli-refusal.js +52 -0
- package/dist/cli-refusal.js.map +1 -0
- package/dist/cli-shared.d.ts +340 -0
- package/dist/cli-shared.js +537 -0
- package/dist/cli-shared.js.map +1 -0
- package/dist/cli-surface.d.ts +33 -0
- package/dist/cli-surface.js +48 -0
- package/dist/cli-surface.js.map +1 -0
- package/dist/conversation-options.d.ts +15 -0
- package/dist/conversation-options.js +10 -0
- package/dist/conversation-options.js.map +1 -0
- package/dist/credentials-file.d.ts +15 -0
- package/dist/credentials-file.js +56 -0
- package/dist/credentials-file.js.map +1 -0
- package/dist/data-dir.d.ts +1 -1
- package/dist/data-dir.js +1 -1
- package/dist/defect-evidence.d.ts +141 -0
- package/dist/defect-evidence.js +505 -0
- package/dist/defect-evidence.js.map +1 -0
- package/dist/demo-aspect-api.d.ts +209 -0
- package/dist/demo-aspect-api.js +398 -0
- package/dist/demo-aspect-api.js.map +1 -0
- package/dist/demo-aspect-cli.d.ts +3 -0
- package/dist/demo-aspect-cli.js +243 -0
- package/dist/demo-aspect-cli.js.map +1 -0
- package/dist/demo-capture.d.ts +142 -0
- package/dist/demo-capture.js +537 -0
- package/dist/demo-capture.js.map +1 -0
- package/dist/engine.d.ts +35 -0
- package/dist/engine.js +25 -0
- package/dist/engine.js.map +1 -0
- package/dist/environments.d.ts +155 -0
- package/dist/environments.js +364 -0
- package/dist/environments.js.map +1 -0
- package/dist/exit-codes.d.ts +46 -0
- package/dist/exit-codes.js +91 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/explore-adversarial.d.ts +144 -0
- package/dist/explore-adversarial.js +227 -0
- package/dist/explore-adversarial.js.map +1 -0
- package/dist/explore-api.d.ts +7 -187
- package/dist/explore-api.js +7 -301
- package/dist/explore-api.js.map +1 -1
- package/dist/explore-author.d.ts +79 -0
- package/dist/explore-author.js +86 -0
- package/dist/explore-author.js.map +1 -0
- package/dist/explore-cli.d.ts +7 -0
- package/dist/explore-cli.js +1199 -0
- package/dist/explore-cli.js.map +1 -0
- package/dist/explore-coverage.d.ts +173 -0
- package/dist/explore-coverage.js +246 -0
- package/dist/explore-coverage.js.map +1 -0
- package/dist/explore-feature.d.ts +125 -0
- package/dist/explore-feature.js +218 -0
- package/dist/explore-feature.js.map +1 -0
- package/dist/explore-goal.d.ts +271 -0
- package/dist/explore-goal.js +417 -0
- package/dist/explore-goal.js.map +1 -0
- package/dist/explore-shared.d.ts +177 -0
- package/dist/explore-shared.js +149 -0
- package/dist/explore-shared.js.map +1 -0
- package/dist/explore-specs.d.ts +53 -0
- package/dist/explore-specs.js +333 -0
- package/dist/explore-specs.js.map +1 -0
- package/dist/findings-filing.d.ts +64 -0
- package/dist/findings-filing.js +108 -0
- package/dist/findings-filing.js.map +1 -0
- package/dist/fixture-auth.d.ts +63 -0
- package/dist/fixture-auth.js +95 -0
- package/dist/fixture-auth.js.map +1 -0
- package/dist/fixture-cli.d.ts +99 -0
- package/dist/fixture-cli.js +292 -0
- package/dist/fixture-cli.js.map +1 -0
- package/dist/github-issue-filer.d.ts +62 -0
- package/dist/github-issue-filer.js +189 -0
- package/dist/github-issue-filer.js.map +1 -0
- package/dist/host-health-run.d.ts +25 -0
- package/dist/host-health-run.js +33 -0
- package/dist/host-health-run.js.map +1 -0
- package/dist/http-5xx-outcome.d.ts +6 -0
- package/dist/http-5xx-outcome.js +39 -0
- package/dist/http-5xx-outcome.js.map +1 -0
- package/dist/inbox-cli.d.ts +7 -0
- package/dist/inbox-cli.js +197 -0
- package/dist/inbox-cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init-cli.d.ts +4 -0
- package/dist/init-cli.js +156 -0
- package/dist/init-cli.js.map +1 -0
- package/dist/init-keys.d.ts +30 -2
- package/dist/init-keys.js +19 -5
- package/dist/init-keys.js.map +1 -1
- package/dist/init-next-steps.d.ts +35 -0
- package/dist/init-next-steps.js +79 -0
- package/dist/init-next-steps.js.map +1 -0
- package/dist/invariants-file.d.ts +34 -0
- package/dist/invariants-file.js +68 -0
- package/dist/invariants-file.js.map +1 -0
- package/dist/invariants-validate.d.ts +30 -0
- package/dist/invariants-validate.js +105 -0
- package/dist/invariants-validate.js.map +1 -0
- package/dist/journey-annotate-api.d.ts +76 -0
- package/dist/journey-annotate-api.js +269 -0
- package/dist/journey-annotate-api.js.map +1 -0
- package/dist/journey-annotate-cli.d.ts +9 -0
- package/dist/journey-annotate-cli.js +181 -0
- package/dist/journey-annotate-cli.js.map +1 -0
- package/dist/journey-api.d.ts +104 -2
- package/dist/journey-api.js +163 -20
- package/dist/journey-api.js.map +1 -1
- package/dist/journey-cli.d.ts +4 -0
- package/dist/journey-cli.js +411 -0
- package/dist/journey-cli.js.map +1 -0
- package/dist/journey-demo-api.d.ts +114 -0
- package/dist/journey-demo-api.js +405 -0
- package/dist/journey-demo-api.js.map +1 -0
- package/dist/journey-demo-cli.d.ts +10 -0
- package/dist/journey-demo-cli.js +158 -0
- package/dist/journey-demo-cli.js.map +1 -0
- package/dist/journey-prefix.d.ts +194 -0
- package/dist/journey-prefix.js +279 -0
- package/dist/journey-prefix.js.map +1 -0
- package/dist/key-report.d.ts +49 -0
- package/dist/key-report.js +101 -0
- package/dist/key-report.js.map +1 -0
- package/dist/kill-signal.d.ts +193 -0
- package/dist/kill-signal.js +283 -0
- package/dist/kill-signal.js.map +1 -0
- package/dist/launch-armed.d.ts +37 -0
- package/dist/launch-armed.js +31 -0
- package/dist/launch-armed.js.map +1 -0
- package/dist/ledger-api.d.ts +106 -0
- package/dist/ledger-api.js +239 -0
- package/dist/ledger-api.js.map +1 -0
- package/dist/ledger-cli.d.ts +18 -0
- package/dist/ledger-cli.js +107 -0
- package/dist/ledger-cli.js.map +1 -0
- package/dist/load-api.d.ts +29 -11
- package/dist/load-api.js +23 -15
- package/dist/load-api.js.map +1 -1
- package/dist/load-cli.d.ts +4 -0
- package/dist/load-cli.js +97 -0
- package/dist/load-cli.js.map +1 -0
- package/dist/log-correlation.d.ts +200 -0
- package/dist/log-correlation.js +394 -0
- package/dist/log-correlation.js.map +1 -0
- package/dist/log-lines.d.ts +131 -0
- package/dist/log-lines.js +389 -0
- package/dist/log-lines.js.map +1 -0
- package/dist/log-sources.d.ts +71 -0
- package/dist/log-sources.js +236 -0
- package/dist/log-sources.js.map +1 -0
- package/dist/log-trace.d.ts +80 -0
- package/dist/log-trace.js +210 -0
- package/dist/log-trace.js.map +1 -0
- package/dist/logs-cli.d.ts +3 -0
- package/dist/logs-cli.js +51 -0
- package/dist/logs-cli.js.map +1 -0
- package/dist/logs-retention.d.ts +28 -0
- package/dist/logs-retention.js +85 -0
- package/dist/logs-retention.js.map +1 -0
- package/dist/masked-input.d.ts +22 -0
- package/dist/masked-input.js +99 -0
- package/dist/masked-input.js.map +1 -0
- package/dist/mcp-api.d.ts +91 -1
- package/dist/mcp-api.js +514 -18
- package/dist/mcp-api.js.map +1 -1
- package/dist/mcp-args.d.ts +50 -0
- package/dist/mcp-args.js +164 -0
- package/dist/mcp-args.js.map +1 -0
- package/dist/mcp-cli-bridge.d.ts +34 -0
- package/dist/mcp-cli-bridge.js +62 -0
- package/dist/mcp-cli-bridge.js.map +1 -0
- package/dist/mcp-cli-runner.d.ts +29 -0
- package/dist/mcp-cli-runner.js +44 -0
- package/dist/mcp-cli-runner.js.map +1 -0
- package/dist/mcp-cli-tools.d.ts +129 -0
- package/dist/mcp-cli-tools.js +737 -0
- package/dist/mcp-cli-tools.js.map +1 -0
- package/dist/mcp-paths.d.ts +28 -0
- package/dist/mcp-paths.js +76 -0
- package/dist/mcp-paths.js.map +1 -0
- package/dist/mission-actors.d.ts +40 -0
- package/dist/mission-actors.js +72 -0
- package/dist/mission-actors.js.map +1 -0
- package/dist/mission-api.d.ts +35 -0
- package/dist/mission-api.js +60 -3
- package/dist/mission-api.js.map +1 -1
- package/dist/mission-cli.d.ts +4 -0
- package/dist/mission-cli.js +248 -0
- package/dist/mission-cli.js.map +1 -0
- package/dist/mission-exit.d.ts +22 -0
- package/dist/mission-exit.js +26 -0
- package/dist/mission-exit.js.map +1 -0
- package/dist/mission-fixtures.d.ts +234 -0
- package/dist/mission-fixtures.js +862 -0
- package/dist/mission-fixtures.js.map +1 -0
- package/dist/mission-journal.d.ts +60 -0
- package/dist/mission-journal.js +115 -0
- package/dist/mission-journal.js.map +1 -0
- package/dist/mission-queue-cli.d.ts +10 -0
- package/dist/mission-queue-cli.js +198 -0
- package/dist/mission-queue-cli.js.map +1 -0
- package/dist/mission-queue-runner.d.ts +126 -0
- package/dist/mission-queue-runner.js +406 -0
- package/dist/mission-queue-runner.js.map +1 -0
- package/dist/multi-run-cli.d.ts +37 -0
- package/dist/multi-run-cli.js +116 -0
- package/dist/multi-run-cli.js.map +1 -0
- package/dist/multi-run.d.ts +339 -0
- package/dist/multi-run.js +619 -0
- package/dist/multi-run.js.map +1 -0
- package/dist/openrouter-call.d.ts +22 -0
- package/dist/openrouter-call.js +64 -0
- package/dist/openrouter-call.js.map +1 -0
- package/dist/profile-cli.d.ts +4 -0
- package/dist/profile-cli.js +57 -0
- package/dist/profile-cli.js.map +1 -0
- package/dist/program.d.ts +3 -75
- package/dist/program.js +123 -1921
- package/dist/program.js.map +1 -1
- package/dist/project-dir.d.ts +96 -0
- package/dist/project-dir.js +221 -0
- package/dist/project-dir.js.map +1 -0
- package/dist/record-api.d.ts +13 -7
- package/dist/record-api.js +44 -30
- package/dist/record-api.js.map +1 -1
- package/dist/record-cli.d.ts +4 -0
- package/dist/record-cli.js +76 -0
- package/dist/record-cli.js.map +1 -0
- package/dist/recording-cli.d.ts +4 -0
- package/dist/recording-cli.js +248 -0
- package/dist/recording-cli.js.map +1 -0
- package/dist/regression-api.d.ts +107 -0
- package/dist/regression-api.js +387 -6
- package/dist/regression-api.js.map +1 -1
- package/dist/regression-cli.d.ts +4 -0
- package/dist/regression-cli.js +284 -0
- package/dist/regression-cli.js.map +1 -0
- package/dist/report-api.d.ts +146 -0
- package/dist/report-api.js +431 -0
- package/dist/report-api.js.map +1 -0
- package/dist/report-cli.d.ts +12 -0
- package/dist/report-cli.js +147 -0
- package/dist/report-cli.js.map +1 -0
- package/dist/resource-preflight.d.ts +87 -0
- package/dist/resource-preflight.js +160 -0
- package/dist/resource-preflight.js.map +1 -0
- package/dist/result-schema.d.ts +22 -0
- package/dist/result-schema.js +28 -0
- package/dist/result-schema.js.map +1 -0
- package/dist/run-index.d.ts +29 -0
- package/dist/run-index.js +70 -0
- package/dist/run-index.js.map +1 -0
- package/dist/run-key-preflight.d.ts +42 -0
- package/dist/run-key-preflight.js +82 -0
- package/dist/run-key-preflight.js.map +1 -0
- package/dist/run-screenshots.d.ts +123 -0
- package/dist/run-screenshots.js +235 -0
- package/dist/run-screenshots.js.map +1 -0
- package/dist/runtime-env.d.ts +8 -0
- package/dist/runtime-env.js +23 -0
- package/dist/runtime-env.js.map +1 -0
- package/dist/secret-args.d.ts +23 -0
- package/dist/secret-args.js +45 -0
- package/dist/secret-args.js.map +1 -0
- package/dist/serve-cli.d.ts +4 -0
- package/dist/serve-cli.js +95 -0
- package/dist/serve-cli.js.map +1 -0
- package/dist/server-log-verify.d.ts +36 -0
- package/dist/server-log-verify.js +120 -0
- package/dist/server-log-verify.js.map +1 -0
- package/dist/session-check.d.ts +14 -0
- package/dist/session-check.js +44 -0
- package/dist/session-check.js.map +1 -0
- package/dist/site-cli.d.ts +4 -0
- package/dist/site-cli.js +127 -0
- package/dist/site-cli.js.map +1 -0
- package/dist/site-gate-cli.d.ts +28 -0
- package/dist/site-gate-cli.js +59 -0
- package/dist/site-gate-cli.js.map +1 -0
- package/dist/source-api.js +20 -4
- package/dist/source-api.js.map +1 -1
- package/dist/source-cli.d.ts +4 -0
- package/dist/source-cli.js +284 -0
- package/dist/source-cli.js.map +1 -0
- package/dist/source-run-api.d.ts +27 -1
- package/dist/source-run-api.js +22 -11
- package/dist/source-run-api.js.map +1 -1
- package/dist/storage-state-snapshot.d.ts +50 -0
- package/dist/storage-state-snapshot.js +87 -0
- package/dist/storage-state-snapshot.js.map +1 -0
- package/dist/suite-explore-options.d.ts +321 -0
- package/dist/suite-explore-options.js +162 -0
- package/dist/suite-explore-options.js.map +1 -0
- package/dist/target-config.d.ts +115 -0
- package/dist/target-config.js +225 -0
- package/dist/target-config.js.map +1 -0
- package/dist/transcript-file.d.ts +12 -0
- package/dist/transcript-file.js +23 -0
- package/dist/transcript-file.js.map +1 -0
- package/dist/type-fixture-file.d.ts +9 -0
- package/dist/type-fixture-file.js +48 -0
- package/dist/type-fixture-file.js.map +1 -0
- package/dist/ui-api.d.ts +3 -0
- package/dist/ui-api.js +11 -4
- package/dist/ui-api.js.map +1 -1
- package/dist/usability-capture.d.ts +43 -0
- package/dist/usability-capture.js +327 -0
- package/dist/usability-capture.js.map +1 -0
- package/dist/usage-config.d.ts +36 -0
- package/dist/usage-config.js +114 -0
- package/dist/usage-config.js.map +1 -0
- package/dist/ux-api.d.ts +3 -75
- package/dist/ux-api.js +3 -220
- package/dist/ux-api.js.map +1 -1
- package/dist/ux-claim-probe.d.ts +45 -0
- package/dist/ux-claim-probe.js +386 -0
- package/dist/ux-claim-probe.js.map +1 -0
- package/dist/ux-cli.d.ts +4 -0
- package/dist/ux-cli.js +109 -0
- package/dist/ux-cli.js.map +1 -0
- package/dist/ux-config.d.ts +29 -0
- package/dist/ux-config.js +103 -0
- package/dist/ux-config.js.map +1 -0
- package/dist/ux-evidence.d.ts +54 -0
- package/dist/ux-evidence.js +197 -0
- package/dist/ux-evidence.js.map +1 -0
- package/dist/ux-product.d.ts +14 -0
- package/dist/ux-product.js +39 -0
- package/dist/ux-product.js.map +1 -0
- package/dist/ux-review.d.ts +116 -0
- package/dist/ux-review.js +171 -0
- package/dist/ux-review.js.map +1 -0
- package/dist/ux-usability.d.ts +263 -0
- package/dist/ux-usability.js +580 -0
- package/dist/ux-usability.js.map +1 -0
- package/dist/verify-fix-api.d.ts +194 -0
- package/dist/verify-fix-api.js +506 -0
- package/dist/verify-fix-api.js.map +1 -0
- package/dist/verify-fix-cli.d.ts +4 -0
- package/dist/verify-fix-cli.js +115 -0
- package/dist/verify-fix-cli.js.map +1 -0
- package/package.json +23 -18
- package/skills/jevitate-ci-check/SKILL.md +77 -0
- package/skills/jevitate-demo/SKILL.md +61 -0
- package/skills/jevitate-explore/SKILL.md +96 -87
- package/skills/jevitate-getting-started/SKILL.md +89 -0
- package/skills/jevitate-load-test/SKILL.md +11 -2
- package/skills/jevitate-mission-scope/SKILL.md +19 -11
- package/skills/jevitate-record/SKILL.md +23 -5
- package/skills/jevitate-run-journey/SKILL.md +61 -17
- package/skills/jevitate-sources/SKILL.md +57 -14
- package/skills/jevitate-test-campaign/SKILL.md +203 -0
- package/skills/jevitate-ux-review/SKILL.md +106 -16
- package/skills/jevitate-verify-fix/SKILL.md +76 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// ux-review.ts — offline UX review of a saved Recording (`jevitate ux`) (#231).
|
|
2
|
+
import { logsDirFor } from "./project-dir.js";
|
|
3
|
+
import { existsSync, statSync } from "node:fs";
|
|
4
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { a11yChecks, analyzeClaims, buildReport, calibrationCaveat, claimsCaveat, detectFriction, detectRepeatedReplies, detectSignals, evidenceFromFile, groundFindings, loadV1Rubric, parseUxEvidenceFile, resolveMinConfidence, resolveMaxFindingsPerRoute, resolveQualityPolicy, withSignalFindings } from "@jevitate/ux";
|
|
7
|
+
import { NO_PRODUCT_FACTS_CAVEAT, loadProductFacts } from "./ux-product.js";
|
|
8
|
+
import { loadUxMaxFindingsPerPage, loadUxMinConfidence, loadUxMinConfidenceByAppClass, loadUxShow } from "./ux-config.js";
|
|
9
|
+
import { writeUsageSidecar } from "./mission-journal.js";
|
|
10
|
+
import { DEFAULT_JUDGMENT_BUDGET, captureFromTranscript, recordingToEvidence } from "./ux-evidence.js";
|
|
11
|
+
import { clock } from "@jevitate/domain";
|
|
12
|
+
const NO_EVIDENCE_CAVEAT = "no usability evidence sidecar (<stamp>.evidence.json, written next to the Recording by live usability runs, #134): this pass sees only the Recording's touched controls and urls — rubric items needing visible text or a11y facts are Skipped, and the run signals that need the live capture (hung request, stuck job, duplicate write/create, failed submit, inert control, internal id, url mismatch) could not be checked; with a transcript, journey friction and repeated replies still are.";
|
|
13
|
+
const NO_PROBES_CAVEAT = "no guard probes (written by live usability runs into the evidence sidecar, #198): destructive controls could not be checked for a confirmation step offline — such claims are reported as unverifiable coverage, never as findings.";
|
|
14
|
+
const NO_TRANSCRIPT_CAVEAT = "blocked/disabled-target evidence not available: this offline pass has no mission transcript, so a dead end like a button that never enables cannot be seen (pass --result <mission-result.json>, as written by `jevitate explore`, to include it — the same evidence a live usability run sees).";
|
|
15
|
+
/**
|
|
16
|
+
* Offline UX review. FAIL-FAST: an analyzer `failed` outcome throws
|
|
17
|
+
* `UxAnalysisFailedError` (the CLI maps it to a non-zero fail envelope) — never
|
|
18
|
+
* a fabricated "clean" report.
|
|
19
|
+
*/
|
|
20
|
+
export async function runUxReview(opts) {
|
|
21
|
+
// #163: this review's own share of a (possibly shared) tracker.
|
|
22
|
+
const runUsage = opts.usage?.scope();
|
|
23
|
+
const minConfidence = resolveMinConfidence(opts.minConfidence, opts.env ?? process.env, loadUxMinConfidence(opts.configPath), loadUxMinConfidenceByAppClass(opts.configPath, opts.appContext.appClass));
|
|
24
|
+
const quality = resolveQualityPolicy(opts.show, opts.env ?? process.env, loadUxShow(opts.configPath), opts.appContext.appClass);
|
|
25
|
+
const maxFindingsPerRoute = resolveMaxFindingsPerRoute(opts.maxFindingsPerRoute, opts.env ?? process.env, loadUxMaxFindingsPerPage(opts.configPath));
|
|
26
|
+
// #198: product facts are validated before any model call (a bad file is a usage error).
|
|
27
|
+
const product = await loadProductFacts(opts.product);
|
|
28
|
+
// #134: a live usability run's evidence sidecar gives offline review the SAME screens and run
|
|
29
|
+
// signals the live analysis had; otherwise the Recording (+ transcript) is all there is.
|
|
30
|
+
let screens;
|
|
31
|
+
let appContext = opts.appContext;
|
|
32
|
+
let signalFindings = [];
|
|
33
|
+
let friction = [];
|
|
34
|
+
let steps = [];
|
|
35
|
+
let probes;
|
|
36
|
+
const evidenceCaveats = [];
|
|
37
|
+
if (opts.evidenceFile !== undefined) {
|
|
38
|
+
({ screens, appContext } = evidenceFromFile(opts.evidenceFile, opts.appContext));
|
|
39
|
+
signalFindings = detectSignals(opts.evidenceFile.signals, opts.signals);
|
|
40
|
+
friction = detectFriction(opts.evidenceFile.signals, opts.evidenceFile.outcome ?? opts.missionOutcome);
|
|
41
|
+
steps = opts.evidenceFile.signals.steps;
|
|
42
|
+
probes = opts.evidenceFile.probes;
|
|
43
|
+
if (probes === undefined)
|
|
44
|
+
evidenceCaveats.push(NO_PROBES_CAVEAT);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
screens = recordingToEvidence(opts.recording, opts.appContext, opts.appContext.job, opts.missionTranscript);
|
|
48
|
+
if (opts.missionTranscript !== undefined) {
|
|
49
|
+
const partial = captureFromTranscript(opts.missionTranscript);
|
|
50
|
+
signalFindings = detectRepeatedReplies(partial, opts.signals);
|
|
51
|
+
friction = detectFriction(partial, opts.missionOutcome);
|
|
52
|
+
steps = partial.steps;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
evidenceCaveats.push(opts.missionTranscriptUnavailable ?? NO_TRANSCRIPT_CAVEAT);
|
|
56
|
+
}
|
|
57
|
+
evidenceCaveats.push(opts.evidenceUnavailable === undefined ? NO_EVIDENCE_CAVEAT : `${opts.evidenceUnavailable} — ${NO_EVIDENCE_CAVEAT}`);
|
|
58
|
+
evidenceCaveats.push(NO_PROBES_CAVEAT);
|
|
59
|
+
}
|
|
60
|
+
if (product.facts === undefined)
|
|
61
|
+
evidenceCaveats.push(NO_PRODUCT_FACTS_CAVEAT);
|
|
62
|
+
// #198: the same claim pipeline as the live run (claims.ts), over the same evidence.
|
|
63
|
+
const outcome = await analyzeClaims({
|
|
64
|
+
screens,
|
|
65
|
+
rubric: loadV1Rubric(),
|
|
66
|
+
appContext,
|
|
67
|
+
...(opts.secrets === undefined ? {} : { secrets: opts.secrets }),
|
|
68
|
+
judgmentBudget: opts.judgmentBudget ?? DEFAULT_JUDGMENT_BUDGET,
|
|
69
|
+
friction,
|
|
70
|
+
steps,
|
|
71
|
+
signalFindings,
|
|
72
|
+
...(probes === undefined ? {} : { probes }),
|
|
73
|
+
...(product.facts === undefined ? {} : { facts: product.facts }),
|
|
74
|
+
}, { judge: opts.judge, gen: opts.gen, a11yChecker: a11yChecks, ...(opts.polish === true ? { polish: true } : {}) });
|
|
75
|
+
if (outcome.kind === "failed") {
|
|
76
|
+
throw new UxAnalysisFailedError(outcome.reason, outcome.screenId, outcome.rubricItemId);
|
|
77
|
+
}
|
|
78
|
+
const calibrationCaveats = [calibrationCaveat(opts.appContext.appClass), claimsCaveat()];
|
|
79
|
+
const report = buildReport(groundFindings(withSignalFindings(outcome, signalFindings), friction), {
|
|
80
|
+
minConfidence,
|
|
81
|
+
quality,
|
|
82
|
+
maxFindingsPerRoute,
|
|
83
|
+
evidenceCaveats,
|
|
84
|
+
calibrationCaveats,
|
|
85
|
+
});
|
|
86
|
+
const outDir = opts.outDir ?? logsDirFor();
|
|
87
|
+
await mkdir(outDir, { recursive: true });
|
|
88
|
+
const iso = (opts.nowIso ?? (() => clock.nowIso()))();
|
|
89
|
+
const reportPath = join(outDir, `ux-${iso.replace(/[:.]/g, "-")}.json`);
|
|
90
|
+
await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
91
|
+
if (runUsage !== undefined)
|
|
92
|
+
writeUsageSidecar(reportPath, runUsage);
|
|
93
|
+
return { report, reportPath, ...(runUsage === undefined ? {} : { usage: runUsage.snapshot() }) };
|
|
94
|
+
}
|
|
95
|
+
/** Finds the sidecars that exist next to `recordingPath` (only `<stem>.recording.json` has a stem). */
|
|
96
|
+
export function discoverRecordingSidecars(recordingPath) {
|
|
97
|
+
if (!recordingPath.endsWith(".recording.json"))
|
|
98
|
+
return {};
|
|
99
|
+
const stem = recordingPath.slice(0, -".recording.json".length);
|
|
100
|
+
const file = (p) => (existsSync(p) && statSync(p).isFile() ? p : undefined);
|
|
101
|
+
const dir = (p) => (existsSync(p) && statSync(p).isDirectory() ? p : undefined);
|
|
102
|
+
const evidencePath = file(`${stem}.evidence.json`);
|
|
103
|
+
const transcriptPath = file(`${stem}.transcript.json`);
|
|
104
|
+
const resultPath = file(`${stem}.result.json`);
|
|
105
|
+
const screenshotDir = dir(`${stem}.screens`);
|
|
106
|
+
return {
|
|
107
|
+
...(evidencePath === undefined ? {} : { evidencePath }),
|
|
108
|
+
...(transcriptPath === undefined ? {} : { transcriptPath }),
|
|
109
|
+
...(resultPath === undefined ? {} : { resultPath }),
|
|
110
|
+
...(screenshotDir === undefined ? {} : { screenshotDir }),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function asOutcome(v) {
|
|
114
|
+
if (v === null || typeof v !== "object")
|
|
115
|
+
return undefined;
|
|
116
|
+
const o = v;
|
|
117
|
+
if (o.status === "completed")
|
|
118
|
+
return { status: "completed" };
|
|
119
|
+
if (o.status === "incomplete")
|
|
120
|
+
return { status: "incomplete", reason: typeof o.reason === "string" ? o.reason : "not completed" };
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Reads the evidence sidecar and the transcript/result (explicit paths win over discovered ones).
|
|
125
|
+
* Never throws: an unreadable file becomes the matching `…Unavailable` caveat.
|
|
126
|
+
*/
|
|
127
|
+
export async function loadRecordingSidecars(paths) {
|
|
128
|
+
const out = {};
|
|
129
|
+
if (paths.evidencePath !== undefined) {
|
|
130
|
+
try {
|
|
131
|
+
out.evidenceFile = parseUxEvidenceFile(JSON.parse(await readFile(paths.evidencePath, "utf8")));
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
out.evidenceUnavailable = `could not read the evidence sidecar ${paths.evidencePath}: ${err instanceof Error ? err.message : String(err)}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
out.evidenceUnavailable = "no evidence sidecar next to the Recording";
|
|
139
|
+
}
|
|
140
|
+
const source = paths.resultPath ?? paths.transcriptPath;
|
|
141
|
+
if (source !== undefined) {
|
|
142
|
+
try {
|
|
143
|
+
const raw = JSON.parse(await readFile(source, "utf8"));
|
|
144
|
+
const obj = (raw ?? {});
|
|
145
|
+
const transcript = Array.isArray(raw) ? raw : (obj.result?.transcript ?? obj.transcript);
|
|
146
|
+
if (Array.isArray(transcript))
|
|
147
|
+
out.missionTranscript = transcript;
|
|
148
|
+
else
|
|
149
|
+
out.missionTranscriptUnavailable = `${source} has no transcript`;
|
|
150
|
+
const outcome = Array.isArray(raw) ? undefined : asOutcome(obj.result?.outcome ?? obj.outcome);
|
|
151
|
+
if (outcome !== undefined)
|
|
152
|
+
out.missionOutcome = outcome;
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
out.missionTranscriptUnavailable = `could not read ${source}: ${err instanceof Error ? err.message : String(err)}`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
export class UxAnalysisFailedError extends Error {
|
|
161
|
+
screenId;
|
|
162
|
+
rubricItemId;
|
|
163
|
+
code = "E_UX_ANALYSIS";
|
|
164
|
+
constructor(reason, screenId, rubricItemId) {
|
|
165
|
+
super(`UX analysis failed: ${reason}${screenId ? ` (screen ${screenId})` : ""}`);
|
|
166
|
+
this.screenId = screenId;
|
|
167
|
+
this.rubricItemId = rubricItemId;
|
|
168
|
+
this.name = "UxAnalysisFailedError";
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=ux-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ux-review.js","sourceRoot":"","sources":["../src/ux-review.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,kBAAkB,EAAmJ,MAAM,cAAc,CAAC;AAC/c,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1H,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAmC,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACxI,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AA4EzC,MAAM,kBAAkB,GACtB,qeAAqe,CAAC;AAExe,MAAM,gBAAgB,GACpB,qOAAqO,CAAC;AAExO,MAAM,oBAAoB,GACxB,kSAAkS,CAAC;AAErS;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAwB;IACxD,gEAAgE;IAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC;IACrC,MAAM,aAAa,GAAG,oBAAoB,CACxC,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EACvB,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,EACpC,6BAA6B,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CACzE,CAAC;IACF,MAAM,OAAO,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAChI,MAAM,mBAAmB,GAAG,0BAA0B,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,wBAAwB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IACrJ,yFAAyF;IACzF,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrD,8FAA8F;IAC9F,yFAAyF;IACzF,IAAI,OAAqB,CAAC;IAC1B,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,IAAI,cAAc,GAAqC,EAAE,CAAC;IAC1D,IAAI,QAAQ,GAAsC,EAAE,CAAC;IACrD,IAAI,KAAK,GAA0B,EAAE,CAAC;IACtC,IAAI,MAAyC,CAAC;IAC9C,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACpC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACjF,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxE,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC;QACvG,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;QACxC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;QAClC,IAAI,MAAM,KAAK,SAAS;YAAE,eAAe,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACnE,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC5G,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC9D,cAAc,GAAG,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9D,QAAQ,GAAG,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;YACxD,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,4BAA4B,IAAI,oBAAoB,CAAC,CAAC;QAClF,CAAC;QACD,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,mBAAmB,MAAM,kBAAkB,EAAE,CAAC,CAAC;QAC1I,eAAe,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,eAAe,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC/E,qFAAqF;IACrF,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC;QACE,OAAO;QACP,MAAM,EAAE,YAAY,EAAE;QACtB,UAAU;QACV,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QAChE,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,uBAAuB;QAC9D,QAAQ;QACR,KAAK;QACL,cAAc;QACd,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3C,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;KACjE,EACD,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CACjH,CAAC;IACF,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,qBAAqB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,kBAAkB,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;IACzF,MAAM,MAAM,GAAG,WAAW,CAAC,cAAc,CAAC,kBAAkB,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,QAAQ,CAAC,EAAE;QAChG,aAAa;QACb,OAAO;QACP,mBAAmB;QACnB,eAAe;QACf,kBAAkB;KACnB,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;IAC3C,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5E,IAAI,QAAQ,KAAK,SAAS;QAAE,iBAAiB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACpE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC;AACnG,CAAC;AAcD,uGAAuG;AACvG,MAAM,UAAU,yBAAyB,CAAC,aAAqB;IAC7D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAAE,OAAO,EAAE,CAAC;IAC1D,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpF,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACxF,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,IAAI,gBAAgB,CAAC,CAAC;IACnD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,IAAI,kBAAkB,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,IAAI,cAAc,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC;IAC7C,OAAO;QACL,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;QACvD,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;QAC3D,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QACnD,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC;KAC1D,CAAC;AACJ,CAAC;AAWD,SAAS,SAAS,CAAC,CAAU;IAC3B,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,CAAC,GAAG,CAA2C,CAAC;IACtD,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC7D,IAAI,CAAC,CAAC,MAAM,KAAK,YAAY;QAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IAClI,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAI3C;IACC,MAAM,GAAG,GAML,EAAE,CAAC;IACP,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,GAAG,CAAC,YAAY,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QACjG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,mBAAmB,GAAG,uCAAuC,KAAK,CAAC,YAAY,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7I,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,mBAAmB,GAAG,2CAA2C,CAAC;IACxE,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,cAAc,CAAC;IACxD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAY,CAAC;YAClE,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,EAAE,CAAsG,CAAC;YAC7H,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;YACzF,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;gBAAE,GAAG,CAAC,iBAAiB,GAAG,UAA0C,CAAC;;gBAC7F,GAAG,CAAC,4BAA4B,GAAG,GAAG,MAAM,oBAAoB,CAAC;YACtE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;YAC/F,IAAI,OAAO,KAAK,SAAS;gBAAE,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC;QAC1D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,4BAA4B,GAAG,kBAAkB,MAAM,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACrH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAET;IAA4B;IADxD,IAAI,GAAG,eAAwB,CAAC;IACzC,YAAY,MAAc,EAAW,QAAiB,EAAW,YAAqB;QACpF,KAAK,CAAC,uBAAuB,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,YAAY,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAD9C,aAAQ,GAAR,QAAQ,CAAS;QAAW,iBAAY,GAAZ,YAAY,CAAS;QAEpF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import type { JudgmentPort, GenerationPort, UsageTracker, UsageCounts } from "@jevitate/ai-core";
|
|
2
|
+
import { type BrowserPort, type EmulationSpec } from "@jevitate/playwright";
|
|
3
|
+
import { type BrowserRunOptions } from "./browser-run-options.js";
|
|
4
|
+
import { type ScreenshotsSpec } from "./run-screenshots.js";
|
|
5
|
+
import type { InvariantSpec } from "@jevitate/recording";
|
|
6
|
+
import { type SuccessCheck, type SuccessCheckResult, type SuccessWhen, type Bounds, type TimingSummary, type RunAnswer, type RunOutcome, type SecretField, type HangFinding, type SideEffect, type BudgetTrajectory, type CrashReport } from "@jevitate/explore";
|
|
7
|
+
import { type AppContext, type SignalOptions, type UxReport } from "@jevitate/ux";
|
|
8
|
+
import { type ConversationOptions } from "./conversation-options.js";
|
|
9
|
+
import { type GoalOutcome, type MissionFailure, type MissionOutcome } from "@jevitate/domain";
|
|
10
|
+
import { MISSION_RESULT_SCHEMA_VERSION, type AdvisoryServerLogDefect } from "./result-schema.js";
|
|
11
|
+
import { type JourneyPrefix } from "./journey-prefix.js";
|
|
12
|
+
import type { JourneyBranchPoint } from "@jevitate/journey";
|
|
13
|
+
import { type ActionDeltaStats, type HostHealthSampler, type Http5xxDefect } from "@jevitate/explore";
|
|
14
|
+
import type { EnvironmentDegraded, HostHealthSummary } from "@jevitate/domain";
|
|
15
|
+
import { type EngineInfo } from "./engine.js";
|
|
16
|
+
import { type ServerLogsSummary } from "./log-correlation.js";
|
|
17
|
+
import { type MissionTarget, type ServerLogOptions } from "./explore-api.js";
|
|
18
|
+
import type { TargetConfig } from "./target-config.js";
|
|
19
|
+
export interface RunUsabilityMissionOptions {
|
|
20
|
+
/** Test seam (#203): the run's host-health sampler (a deterministic fake host). Default: this host's. */
|
|
21
|
+
readonly hostHealth?: HostHealthSampler;
|
|
22
|
+
readonly url: string;
|
|
23
|
+
readonly job: string;
|
|
24
|
+
readonly allowlist: readonly string[];
|
|
25
|
+
readonly appContext: AppContext;
|
|
26
|
+
readonly judge: JudgmentPort;
|
|
27
|
+
readonly gen: GenerationPort;
|
|
28
|
+
/** Usage accounting (#100): see `RunUxReviewOptions.usage`. */
|
|
29
|
+
readonly usage?: UsageTracker;
|
|
30
|
+
/** Report cutoff (see `RunUxReviewOptions.minConfidence`). */
|
|
31
|
+
readonly minConfidence?: number | string;
|
|
32
|
+
/**
|
|
33
|
+
* Quality grades to show, e.g. "actionable,relevant-minor". Precedence: this (CLI `--show`) >
|
|
34
|
+
* `JEVITATE_UX_SHOW` > config `ux.show` > every grade (#133: the uncalibrated grader labels, it does not filter).
|
|
35
|
+
*/
|
|
36
|
+
readonly show?: string;
|
|
37
|
+
/** Cap on findings per route (see `RunUxReviewOptions.maxFindingsPerRoute`). */
|
|
38
|
+
readonly maxFindingsPerRoute?: number | string;
|
|
39
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
40
|
+
/** Path of the config file holding `ux.minConfidence`. Default `~/.jevitate/config.json`. */
|
|
41
|
+
readonly configPath?: string;
|
|
42
|
+
readonly bounds?: Partial<Bounds>;
|
|
43
|
+
readonly secrets?: readonly string[];
|
|
44
|
+
/**
|
|
45
|
+
* Secret field bindings (`--secret-field` / `--totp`, #72): typed by code, never by the model;
|
|
46
|
+
* masked in every screenshot and redacted from the transcript, Recording and report.
|
|
47
|
+
*/
|
|
48
|
+
readonly secretFields?: readonly SecretField[];
|
|
49
|
+
/** Tuning of the run-signal oracles (#96), e.g. the hung-request floor. Defaults suit real apps. */
|
|
50
|
+
readonly signals?: SignalOptions;
|
|
51
|
+
/** Local file the `upload` op attaches (CLI `--fixture`); validated before any browser opens. */
|
|
52
|
+
readonly fixture?: string;
|
|
53
|
+
readonly judgmentBudget?: number;
|
|
54
|
+
/** Conversational pages: the reply wait (ms) and the cap (chars) on each generated message. */
|
|
55
|
+
readonly conversation?: ConversationOptions;
|
|
56
|
+
readonly outDir?: string;
|
|
57
|
+
readonly browserPortFactory?: () => BrowserPort;
|
|
58
|
+
/** How Chromium is launched (executable/channel/extra args) and shown (#245 demo mode). Default: pinned Chromium, headless. */
|
|
59
|
+
readonly browser?: BrowserRunOptions;
|
|
60
|
+
/** #251 `--screenshots`: masked screenshots (one per distinct screen, or per step) + `index.md`. */
|
|
61
|
+
readonly screenshots?: ScreenshotsSpec;
|
|
62
|
+
/**
|
|
63
|
+
* #250 `--evidence-video`: after the result is written, each defect's minimal repro is replayed
|
|
64
|
+
* with captions (the failing step marked) into a masked clip + before/at screenshots, attached as
|
|
65
|
+
* `defects[].evidence` (and to its issue draft).
|
|
66
|
+
*/
|
|
67
|
+
readonly evidenceVideo?: boolean;
|
|
68
|
+
/** Per-mission viewport/device emulation (#149, CLI `--viewport <W>x<H>` / `--device "<name>"`). */
|
|
69
|
+
readonly emulation?: EmulationSpec;
|
|
70
|
+
/**
|
|
71
|
+
* Playwright storageState JSON to seed the session from (CLI `--storage-state`) — the
|
|
72
|
+
* deterministic authenticated pre-step. Holds live session cookies: handed only to the
|
|
73
|
+
* browser, never to a model or a finding.
|
|
74
|
+
*/
|
|
75
|
+
readonly storageState?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Writes the browser context's storageState here when the run ends (CLI `--save-storage-state`) —
|
|
78
|
+
* see `RunExplorationOptions.saveStorageState`'s doc for the full behaviour (written on every exit
|
|
79
|
+
* path including a crash/kill signal, never over a lost/logged-out session, mode 0600).
|
|
80
|
+
*/
|
|
81
|
+
readonly saveStorageState?: string;
|
|
82
|
+
readonly nowIso?: () => string;
|
|
83
|
+
/** The target's settle/hang configuration (`~/.jevitate/targets.json` + flags). */
|
|
84
|
+
readonly target?: TargetConfig;
|
|
85
|
+
/** Test seam: extract a page's visible text. Default reads the live page. */
|
|
86
|
+
readonly extractText?: (session: {
|
|
87
|
+
page: {
|
|
88
|
+
evaluate: (fn: () => string) => Promise<string>;
|
|
89
|
+
};
|
|
90
|
+
}) => Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Backend log sources (`--log-source`/`--log-defect`, #142), already validated. Lines attach to
|
|
93
|
+
* usability steps the same way as every other strategy; a `server-log` defect is reported in the
|
|
94
|
+
* result but — like every UX finding — never gates `missionOutcome`/`exitCode` (advisory-only).
|
|
95
|
+
*/
|
|
96
|
+
readonly serverLog?: ServerLogOptions;
|
|
97
|
+
/**
|
|
98
|
+
* Horizontal-overflow hard signal (#149, CLI `--check-overflow` / `--ignore-overflow`): checked
|
|
99
|
+
* on every observed screen and, when it fires, reported as a `tier: "signal"` UxFinding — pure
|
|
100
|
+
* DOM geometry (`detectOverflow`), never a model judgment. Runs by default only when the emulated
|
|
101
|
+
* viewport is narrower than 1024px, or always when `checkOverflow` is set.
|
|
102
|
+
*/
|
|
103
|
+
readonly overflow?: {
|
|
104
|
+
readonly checkOverflow?: boolean;
|
|
105
|
+
readonly toleranceCss?: number;
|
|
106
|
+
/** `--ignore-overflow <selector>` (repeatable): intentional overflow, never a finding. */
|
|
107
|
+
readonly ignoreSelectors?: readonly string[];
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* `--invariants` (#150 only): usability does not check app-declared invariants (#86) or captures
|
|
111
|
+
* (#147) today — a spec carrying either is refused. Only its `budget` (over its `observe` map) is
|
|
112
|
+
* read: a pre-action guard and a post-settle check, the same as every other mission.
|
|
113
|
+
*/
|
|
114
|
+
readonly invariants?: InvariantSpec;
|
|
115
|
+
/** Resolved `authFrom.secret` refs (#135) a declared budget's probe may use: `env:VAR` → its value. */
|
|
116
|
+
readonly invariantAuthTokens?: ReadonlyMap<string, string>;
|
|
117
|
+
/**
|
|
118
|
+
* #225: independent completion checks on the job (CLI `--success`, a suite mission's `success`) —
|
|
119
|
+
* the SAME semantics as a goal run's: every one must hold (grounding the model's `done` mid-run and
|
|
120
|
+
* judged again on the final page), a vacuous one (#202) fails unless `allowVacuousChecks`, and the
|
|
121
|
+
* verdict folds exactly like a goal run's (`goalOutcome` → `missionOutcome`). Never ignored: with
|
|
122
|
+
* checks, the job's completion is theirs to decide, not the advisory goal judgment's.
|
|
123
|
+
*/
|
|
124
|
+
readonly successChecks?: readonly SuccessCheck[];
|
|
125
|
+
/** When the page checks must hold (`--success-when`): `final` (default) | `held`. */
|
|
126
|
+
readonly successWhen?: SuccessWhen;
|
|
127
|
+
/** #202 `--allow-vacuous-checks`: a check satisfied before the first action warns instead of failing. */
|
|
128
|
+
readonly allowVacuousChecks?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* #198 `--product <file>`: the product facts (plans/prices, key journeys, each page's intended next
|
|
131
|
+
* step). Default: `.jevitate/product.json` in the project, when present. Validated before a browser
|
|
132
|
+
* opens (`ProductFactsError`, E_UX_PRODUCT_INPUT).
|
|
133
|
+
*/
|
|
134
|
+
readonly product?: string;
|
|
135
|
+
/** #198 `--polish`: polish each verified finding's recommendation with one generation call (opt-in). */
|
|
136
|
+
readonly polish?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* #198 `--probe-guards` (opt-in): click each destructive control once, fail-safe (every write and
|
|
139
|
+
* destructive-looking request aborted; refused on a page with an open WebSocket/EventSource or a
|
|
140
|
+
* controlling service worker), to verify whether a confirmation guards it. Off: nothing is clicked,
|
|
141
|
+
* and those guard claims are reported unverifiable.
|
|
142
|
+
*/
|
|
143
|
+
readonly probeGuards?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* #293 `--from-journey`/`--at-step`: replayed into the session before the review, which then starts
|
|
146
|
+
* on the live page it left — never a fresh navigation. `url` is only the expected landing.
|
|
147
|
+
*/
|
|
148
|
+
readonly journeyPrefix?: JourneyPrefix;
|
|
149
|
+
/**
|
|
150
|
+
* #303 `--action-deltas` (opt-in, off by default): record what each action changed on the page
|
|
151
|
+
* (code's verdict per action) — attached to every transcript and Recording step, summarised in the
|
|
152
|
+
* result (`actionDeltas`), told to the model and used by the no-progress check. Off: no capture.
|
|
153
|
+
*/
|
|
154
|
+
readonly actionDeltas?: boolean;
|
|
155
|
+
}
|
|
156
|
+
/** Usability reads only a spec's `budget` (#150) — never its `invariants`/`capture` (#86/#147, not supported here). */
|
|
157
|
+
export declare class UsabilityInvariantsUnsupportedError extends Error {
|
|
158
|
+
readonly code: "E_USABILITY_INVARIANTS";
|
|
159
|
+
constructor();
|
|
160
|
+
}
|
|
161
|
+
export interface RunUsabilityMissionResult {
|
|
162
|
+
/** The host's health over the run (#203): peaks, the slowest render, starved steps. */
|
|
163
|
+
readonly hostHealth: HostHealthSummary;
|
|
164
|
+
/** Findings met while the host was starved (#203) — advisory, never a defect/hang, never failing the run. */
|
|
165
|
+
readonly environmentDegraded: EnvironmentDegraded[];
|
|
166
|
+
/** #293: the Journey step a journey-anchored review branched from (absent on a bare-URL run). */
|
|
167
|
+
readonly branch?: JourneyBranchPoint;
|
|
168
|
+
/** The result schema's version (#195): the common fields are filled the same way by every strategy. */
|
|
169
|
+
readonly schemaVersion: typeof MISSION_RESULT_SCHEMA_VERSION;
|
|
170
|
+
readonly strategy: "usability";
|
|
171
|
+
/** Where the review ran (#195: every strategy states its scope the same way) — a session PATH at most. */
|
|
172
|
+
readonly target: MissionTarget;
|
|
173
|
+
/**
|
|
174
|
+
* EVERY defect the review found (#195) — HTTP 5xx hard-signal defects (#208) and `server-log`
|
|
175
|
+
* defects (#142), each marked `advisory: true`: reported like every other strategy's, never gating
|
|
176
|
+
* a UX review's outcome.
|
|
177
|
+
*/
|
|
178
|
+
readonly defects: Array<AdvisoryServerLogDefect | (Http5xxDefect & {
|
|
179
|
+
readonly advisory: true;
|
|
180
|
+
})>;
|
|
181
|
+
/** Hang findings (0 or 1: the review stops at a hang), as every strategy lists them (#195). */
|
|
182
|
+
readonly hangs: HangFinding[];
|
|
183
|
+
/** Every Recording the review wrote (#195: one list on every strategy) — a review writes one. */
|
|
184
|
+
readonly recordingPaths: string[];
|
|
185
|
+
/** #245: `--record-video` files, finalized before this result was written (absent when not recording). */
|
|
186
|
+
readonly videoPaths?: string[];
|
|
187
|
+
/** The UX report; `null` when the analysis was unavailable (see `analysisUnavailable`). */
|
|
188
|
+
readonly report: UxReport | null;
|
|
189
|
+
readonly reportPath: string | null;
|
|
190
|
+
readonly stop: string;
|
|
191
|
+
/**
|
|
192
|
+
* Did the review's journey complete (`completed`: the job's success condition was observably met),
|
|
193
|
+
* or why not (`incomplete` + reason)? Never a silent early stop.
|
|
194
|
+
*/
|
|
195
|
+
readonly outcome: RunOutcome;
|
|
196
|
+
/** A find-out job's answer (#101), present only when code grounded it on the observed pages. */
|
|
197
|
+
readonly answer?: RunAnswer;
|
|
198
|
+
readonly screensObserved: number;
|
|
199
|
+
/** The explore loop's decision transcript, written next to the report (each step: its screenshot). */
|
|
200
|
+
readonly transcriptPath: string;
|
|
201
|
+
/** Where the per-step screenshots are written (secret fields masked). */
|
|
202
|
+
readonly screenshotDir: string;
|
|
203
|
+
/**
|
|
204
|
+
* #134: the evidence sidecar (`usability-<stamp>.evidence.json`) — every screen as the analyzer
|
|
205
|
+
* saw it after redaction, plus the run-signal capture — so `jevitate ux <recording>` reproduces
|
|
206
|
+
* this run's findings offline. `null` when it could not be written (redaction unavailable).
|
|
207
|
+
*/
|
|
208
|
+
readonly evidencePath: string | null;
|
|
209
|
+
/** Every per-step screenshot written, in order. */
|
|
210
|
+
readonly screenshots: readonly string[];
|
|
211
|
+
/** The writes the run's actions fired (#116), marked when the control was paid / destructive. */
|
|
212
|
+
readonly sideEffects: readonly SideEffect[];
|
|
213
|
+
readonly sideEffectsTruncated?: number;
|
|
214
|
+
/** #303: the run's action deltas (verdict counts, per-action overhead) — only with `--action-deltas`. */
|
|
215
|
+
readonly actionDeltas?: ActionDeltaStats;
|
|
216
|
+
/**
|
|
217
|
+
* The typed verdict. UX findings are advisory, so a completed review is `clean`; a run whose
|
|
218
|
+
* loop broke is `crashed`/`inconclusive`, and so is one whose analysis could not be produced — or
|
|
219
|
+
* (#209) one whose job was never completed (`failure.kind: "job-incomplete"`).
|
|
220
|
+
*/
|
|
221
|
+
readonly missionOutcome: MissionOutcome;
|
|
222
|
+
readonly exitCode: number;
|
|
223
|
+
readonly failure?: MissionFailure;
|
|
224
|
+
/** For a `crashed` review: the evidence and its attribution (jevitate / system under test / uncertain). */
|
|
225
|
+
readonly crash?: CrashReport;
|
|
226
|
+
/** Where the review ended (redacted), and how many decisions/actions it spent — as a goal run reports them. */
|
|
227
|
+
readonly finalUrl: string;
|
|
228
|
+
readonly decisions: number;
|
|
229
|
+
readonly actions: number;
|
|
230
|
+
/** Why the analysis could not be produced (the run's evidence is still kept). */
|
|
231
|
+
readonly analysisUnavailable?: string;
|
|
232
|
+
/** Slowest pages/transitions and endpoints (p50/max), keyed by normalized route/endpoint. */
|
|
233
|
+
readonly timing: TimingSummary;
|
|
234
|
+
/** Which build produced this result (issue #83): `{version, commit, builtAt}`. */
|
|
235
|
+
readonly engine: EngineInfo;
|
|
236
|
+
/** Judgment/generation call counts and tokens for this run (#100); present only when `opts.usage` was supplied. */
|
|
237
|
+
readonly usage?: UsageCounts;
|
|
238
|
+
/** The hang finding (with its reproduction k/N), present when the run stopped on a hang (#126); also in `hangs`. */
|
|
239
|
+
readonly hang?: HangFinding;
|
|
240
|
+
/** The persisted typed result (`usability-<stamp>.recording.result.json`), readable via MCP `get_mission_result`. */
|
|
241
|
+
readonly resultPath: string;
|
|
242
|
+
/** Backend log correlation summary (#142) — present only when `--log-source` was given. */
|
|
243
|
+
readonly serverLogs?: ServerLogsSummary;
|
|
244
|
+
/** Declared mission spend budgets (#150): the observed trajectory, present when any were declared. */
|
|
245
|
+
readonly budget?: BudgetTrajectory[];
|
|
246
|
+
/**
|
|
247
|
+
* #225 — present only when `successChecks` were given: the job's own ending as a goal run names it
|
|
248
|
+
* (`succeeded` / `failed` / `exhausted` / `blocked` / …), folded onto `missionOutcome` the same way.
|
|
249
|
+
*/
|
|
250
|
+
readonly goalOutcome?: GoalOutcome;
|
|
251
|
+
/** #225: each success check's result, when `successChecks` were given. */
|
|
252
|
+
readonly checks?: readonly SuccessCheckResult[];
|
|
253
|
+
/** #225/#202: the success checks' warnings (a vacuous check, `held` notes), when there were any. */
|
|
254
|
+
readonly checkWarnings?: readonly string[];
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Live usability mission. Guardrail #1 authorizes BEFORE opening a browser.
|
|
258
|
+
* Reuses explore()'s loop (goal = the job) and, via the additive onSnapshot
|
|
259
|
+
* hook, collects one screen's evidence per observation — then analyzes ONCE
|
|
260
|
+
* after the run. A UX finding NEVER gates the loop (the hook's result is
|
|
261
|
+
* ignored by explore). The temp profile dir is always removed.
|
|
262
|
+
*/
|
|
263
|
+
export declare function runUsabilityMission(opts: RunUsabilityMissionOptions): Promise<RunUsabilityMissionResult>;
|