@jevitate/cli 0.12.0 → 0.13.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/bin.js +48283 -47589
- package/dist/build-info.generated.js +2 -2
- package/dist/explore-cli/adversarial-strategy.d.ts +3 -0
- package/dist/explore-cli/adversarial-strategy.js +99 -0
- package/dist/explore-cli/adversarial-strategy.js.map +1 -0
- package/dist/explore-cli/coverage-strategy.d.ts +3 -0
- package/dist/explore-cli/coverage-strategy.js +95 -0
- package/dist/explore-cli/coverage-strategy.js.map +1 -0
- package/dist/explore-cli/feature-strategy.d.ts +3 -0
- package/dist/explore-cli/feature-strategy.js +59 -0
- package/dist/explore-cli/feature-strategy.js.map +1 -0
- package/dist/explore-cli/goal-strategy.d.ts +3 -0
- package/dist/explore-cli/goal-strategy.js +184 -0
- package/dist/explore-cli/goal-strategy.js.map +1 -0
- package/dist/explore-cli/options.d.ts +3 -0
- package/dist/explore-cli/options.js +155 -0
- package/dist/explore-cli/options.js.map +1 -0
- package/dist/explore-cli/run.d.ts +7 -0
- package/dist/explore-cli/run.js +682 -0
- package/dist/explore-cli/run.js.map +1 -0
- package/dist/explore-cli/shared.d.ts +158 -0
- package/dist/explore-cli/shared.js +20 -0
- package/dist/explore-cli/shared.js.map +1 -0
- package/dist/explore-cli/usability-strategy.d.ts +3 -0
- package/dist/explore-cli/usability-strategy.js +136 -0
- package/dist/explore-cli/usability-strategy.js.map +1 -0
- package/dist/explore-cli.d.ts +2 -2
- package/dist/explore-cli.js +2 -1347
- package/dist/explore-cli.js.map +1 -1
- package/dist/journey-anchor-api.d.ts +10 -9
- package/dist/journey-anchor-api.js +12 -22
- package/dist/journey-anchor-api.js.map +1 -1
- package/dist/journey-anchor-cli.d.ts +1 -1
- package/dist/journey-anchor-cli.js +10 -6
- package/dist/journey-anchor-cli.js.map +1 -1
- package/dist/journey-cli/anchors.d.ts +4 -0
- package/dist/journey-cli/anchors.js +48 -0
- package/dist/journey-cli/anchors.js.map +1 -0
- package/dist/journey-cli/find.d.ts +4 -0
- package/dist/journey-cli/find.js +44 -0
- package/dist/journey-cli/find.js.map +1 -0
- package/dist/journey-cli/lint.d.ts +4 -0
- package/dist/journey-cli/lint.js +76 -0
- package/dist/journey-cli/lint.js.map +1 -0
- package/dist/journey-cli/list.d.ts +4 -0
- package/dist/journey-cli/list.js +48 -0
- package/dist/journey-cli/list.js.map +1 -0
- package/dist/journey-cli/migrate.d.ts +4 -0
- package/dist/journey-cli/migrate.js +101 -0
- package/dist/journey-cli/migrate.js.map +1 -0
- package/dist/journey-cli/promote.d.ts +4 -0
- package/dist/journey-cli/promote.js +181 -0
- package/dist/journey-cli/promote.js.map +1 -0
- package/dist/journey-cli/publish.d.ts +4 -0
- package/dist/journey-cli/publish.js +70 -0
- package/dist/journey-cli/publish.js.map +1 -0
- package/dist/journey-cli/review.d.ts +4 -0
- package/dist/journey-cli/review.js +103 -0
- package/dist/journey-cli/review.js.map +1 -0
- package/dist/journey-cli/run.d.ts +4 -0
- package/dist/journey-cli/run.js +244 -0
- package/dist/journey-cli/run.js.map +1 -0
- package/dist/journey-cli/shared.d.ts +9 -0
- package/dist/journey-cli/shared.js +12 -0
- package/dist/journey-cli/shared.js.map +1 -0
- package/dist/journey-cli/verify.d.ts +4 -0
- package/dist/journey-cli/verify.js +125 -0
- package/dist/journey-cli/verify.js.map +1 -0
- package/dist/journey-cli.d.ts +3 -2
- package/dist/journey-cli.js +21 -949
- package/dist/journey-cli.js.map +1 -1
- package/dist/journey-review/render.d.ts +43 -0
- package/dist/journey-review/render.js +461 -0
- package/dist/journey-review/render.js.map +1 -0
- package/dist/journey-review.d.ts +1 -4
- package/dist/journey-review.js +16 -391
- package/dist/journey-review.js.map +1 -1
- package/dist/log-sources.js +17 -1
- package/dist/log-sources.js.map +1 -1
- package/dist/mcp-api.js +16 -821
- package/dist/mcp-api.js.map +1 -1
- package/dist/mcp-cli-tools.js +12 -4
- package/dist/mcp-cli-tools.js.map +1 -1
- package/dist/mcp-tools/cli.d.ts +3 -0
- package/dist/mcp-tools/cli.js +20 -0
- package/dist/mcp-tools/cli.js.map +1 -0
- package/dist/mcp-tools/explore.d.ts +3 -0
- package/dist/mcp-tools/explore.js +141 -0
- package/dist/mcp-tools/explore.js.map +1 -0
- package/dist/mcp-tools/findings.d.ts +3 -0
- package/dist/mcp-tools/findings.js +277 -0
- package/dist/mcp-tools/findings.js.map +1 -0
- package/dist/mcp-tools/inbox.d.ts +3 -0
- package/dist/mcp-tools/inbox.js +106 -0
- package/dist/mcp-tools/inbox.js.map +1 -0
- package/dist/mcp-tools/journey.d.ts +3 -0
- package/dist/mcp-tools/journey.js +260 -0
- package/dist/mcp-tools/journey.js.map +1 -0
- package/dist/mcp-tools/shared.d.ts +39 -0
- package/dist/mcp-tools/shared.js +69 -0
- package/dist/mcp-tools/shared.js.map +1 -0
- package/dist/sweep-api.d.ts +9 -0
- package/dist/sweep-api.js +70 -2
- package/dist/sweep-api.js.map +1 -1
- package/dist/sweep-cli.d.ts +2 -0
- package/dist/sweep-cli.js +22 -5
- package/dist/sweep-cli.js.map +1 -1
- package/dist/ux-usability/analysis.d.ts +14 -0
- package/dist/ux-usability/analysis.js +106 -0
- package/dist/ux-usability/analysis.js.map +1 -0
- package/dist/ux-usability/done-adjudication.d.ts +15 -0
- package/dist/ux-usability/done-adjudication.js +56 -0
- package/dist/ux-usability/done-adjudication.js.map +1 -0
- package/dist/ux-usability/hang.d.ts +5 -0
- package/dist/ux-usability/hang.js +41 -0
- package/dist/ux-usability/hang.js.map +1 -0
- package/dist/ux-usability/loop.d.ts +15 -0
- package/dist/ux-usability/loop.js +104 -0
- package/dist/ux-usability/loop.js.map +1 -0
- package/dist/ux-usability/observe.d.ts +7 -0
- package/dist/ux-usability/observe.js +89 -0
- package/dist/ux-usability/observe.js.map +1 -0
- package/dist/ux-usability/result.d.ts +11 -0
- package/dist/ux-usability/result.js +113 -0
- package/dist/ux-usability/result.js.map +1 -0
- package/dist/ux-usability/setup.d.ts +75 -0
- package/dist/ux-usability/setup.js +203 -0
- package/dist/ux-usability/setup.js.map +1 -0
- package/dist/ux-usability/teardown.d.ts +3 -0
- package/dist/ux-usability/teardown.js +13 -0
- package/dist/ux-usability/teardown.js.map +1 -0
- package/dist/ux-usability.d.ts +14 -17
- package/dist/ux-usability.js +15 -589
- package/dist/ux-usability.js.map +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type GoalBasedResult, BudgetMonitor } from "@jevitate/explore";
|
|
2
|
+
import type { UsabilitySetup } from "./setup.js";
|
|
3
|
+
/**
|
|
4
|
+
* Phase 2 — the act loop: the Journey prefix (if any), the budget hooks, then the model-driven loop —
|
|
5
|
+
* through the goal mission's independent adjudication when `successChecks` were given, else
|
|
6
|
+
* `explore()` — and the drained server-log transcript, Recording and transcript written.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runUsabilityLoop(ctx: UsabilitySetup): Promise<{
|
|
9
|
+
start: import("../journey-prefix.js").AnchoredStart;
|
|
10
|
+
budget: BudgetMonitor | null;
|
|
11
|
+
adjudication: GoalBasedResult | undefined;
|
|
12
|
+
run: import("@jevitate/explore").ExploreRun;
|
|
13
|
+
serverLogRun: import("../log-correlation.js").ServerLogRuntimeResult | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export type UsabilityLoop = Awaited<ReturnType<typeof runUsabilityLoop>>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// ux-usability/loop.ts — phase 2 of `runUsabilityMission` (#500): the model-driven act loop.
|
|
2
|
+
import { journeyFixtureBaseDir } from "../journey-api.js";
|
|
3
|
+
import { demoOverlayOf } from "../browser-run-options.js";
|
|
4
|
+
import { CastActor, BrowseTheWeb } from "@jevitate/screenplay";
|
|
5
|
+
import { explore, runGoalBasedMission, InvariantMonitor, BudgetMonitor } from "@jevitate/explore";
|
|
6
|
+
import { conversationConfig } from "../conversation-options.js";
|
|
7
|
+
import { startFromJourney } from "../journey-prefix.js";
|
|
8
|
+
import { usabilityOnSnapshot } from "./observe.js";
|
|
9
|
+
/**
|
|
10
|
+
* Phase 2 — the act loop: the Journey prefix (if any), the budget hooks, then the model-driven loop —
|
|
11
|
+
* through the goal mission's independent adjudication when `successChecks` were given, else
|
|
12
|
+
* `explore()` — and the drained server-log transcript, Recording and transcript written.
|
|
13
|
+
*/
|
|
14
|
+
export async function runUsabilityLoop(ctx) {
|
|
15
|
+
const { opts, session, origin, serverLog, journalListener, journal, health, uxSecretCommand, fixture, capture } = ctx;
|
|
16
|
+
// #293: a journey-anchored review first replays its Journey's prefix into this very session.
|
|
17
|
+
const start = await startFromJourney(opts.journeyPrefix, session, opts.url, opts.allowlist, opts.browser);
|
|
18
|
+
const actor = CastActor.named("usability-mission").whoCan(new BrowseTheWeb(session, [...opts.allowlist]));
|
|
19
|
+
// #150 — usability's own budget wiring: a plain `InvariantMonitor` reads a budget's declared
|
|
20
|
+
// observables (the same #86/#135 read/auth/redaction machinery), but this mission folds NO
|
|
21
|
+
// invariant defects — only a budget crossing can end the run early, via the same pre-action
|
|
22
|
+
// guard / post-settle hooks `explore()` offers every mission.
|
|
23
|
+
const budgetDecls = opts.invariants?.budget ?? [];
|
|
24
|
+
const invariantMonitor = opts.invariants === undefined || budgetDecls.length === 0
|
|
25
|
+
? null
|
|
26
|
+
: new InvariantMonitor(opts.invariants, {
|
|
27
|
+
allowlist: opts.allowlist,
|
|
28
|
+
baseUrl: opts.url,
|
|
29
|
+
...(opts.secrets === undefined ? {} : { secrets: opts.secrets }),
|
|
30
|
+
...(opts.invariantAuthTokens === undefined ? {} : { authTokens: opts.invariantAuthTokens }),
|
|
31
|
+
});
|
|
32
|
+
const budget = invariantMonitor === null ? null : new BudgetMonitor(budgetDecls, invariantMonitor);
|
|
33
|
+
let budgetSettledSteps = 0;
|
|
34
|
+
const exploreCfg = {
|
|
35
|
+
...(opts.target?.timing === undefined ? {} : { timingConfig: opts.target.timing }),
|
|
36
|
+
...(opts.target?.settle === undefined ? {} : { settle: opts.target.settle }),
|
|
37
|
+
...(opts.target?.hangs === undefined ? {} : { hangs: opts.target.hangs }),
|
|
38
|
+
...(opts.target?.safety === undefined ? {} : { safety: opts.target.safety }),
|
|
39
|
+
onTranscriptEntry: serverLog?.onTranscriptEntry ?? journalListener,
|
|
40
|
+
onRecording: journal.onRecording,
|
|
41
|
+
// #303 (opt-in): action deltas, with Jev's advisory relevance labels.
|
|
42
|
+
...(opts.actionDeltas === true ? { actionDeltas: { jev: true } } : {}),
|
|
43
|
+
hostHealth: health,
|
|
44
|
+
demoOverlay: demoOverlayOf(opts.browser),
|
|
45
|
+
...(opts.secretFields === undefined ? {} : { secretFields: opts.secretFields }),
|
|
46
|
+
...(uxSecretCommand === undefined ? {} : { secretCommand: uxSecretCommand }),
|
|
47
|
+
...(opts.secretCommandAttempts === undefined ? {} : { secretCommandAttempts: opts.secretCommandAttempts }),
|
|
48
|
+
actor,
|
|
49
|
+
judge: opts.judge,
|
|
50
|
+
gen: opts.gen,
|
|
51
|
+
goal: opts.job,
|
|
52
|
+
allowlist: opts.allowlist,
|
|
53
|
+
startUrl: start.url,
|
|
54
|
+
...(start.branch === undefined ? {} : { startInPlace: true }),
|
|
55
|
+
...(start.restart === undefined ? {} : { restartAtStart: start.restart.restartAtStart }),
|
|
56
|
+
bounds: opts.bounds,
|
|
57
|
+
secrets: opts.secrets,
|
|
58
|
+
site: origin,
|
|
59
|
+
fixture,
|
|
60
|
+
fixtureRoot: journeyFixtureBaseDir(),
|
|
61
|
+
...conversationConfig(opts.conversation),
|
|
62
|
+
onSnapshot: usabilityOnSnapshot(ctx),
|
|
63
|
+
...(budget === null
|
|
64
|
+
? {}
|
|
65
|
+
: {
|
|
66
|
+
onBeforeAction: async (info) => {
|
|
67
|
+
const g = await budget.guard(session.page, info);
|
|
68
|
+
return g.refuse ? { refuse: true, reason: g.reason ?? "budget guard refused the action" } : { refuse: false };
|
|
69
|
+
},
|
|
70
|
+
onSettled: async () => {
|
|
71
|
+
budgetSettledSteps += 1;
|
|
72
|
+
// The FIRST settled snapshot (before any action) is the budget's baseline.
|
|
73
|
+
if (budgetSettledSteps === 1) {
|
|
74
|
+
const b = await budget.baseline(session.page);
|
|
75
|
+
return b.crossed ? { stop: true, reason: b.reason ?? "budget observable unreadable at run start" } : { stop: false };
|
|
76
|
+
}
|
|
77
|
+
const r = await budget.afterSettle(session.page, budgetSettledSteps);
|
|
78
|
+
return r.crossed ? { stop: true, reason: r.reason ?? "mission budget crossed" } : { stop: false };
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
};
|
|
82
|
+
const brief = "usability review: pursue the stated job as a plausible first-time user, using only what is on screen";
|
|
83
|
+
// #225: `--success` is never ignored — with checks the loop runs through the goal mission's
|
|
84
|
+
// independent adjudication (the same oracle, `held`/vacuous rules and verdict as a goal run).
|
|
85
|
+
const checks = opts.successChecks ?? [];
|
|
86
|
+
const adjudication = checks.length === 0
|
|
87
|
+
? undefined
|
|
88
|
+
: await runGoalBasedMission({
|
|
89
|
+
...exploreCfg,
|
|
90
|
+
missionBrief: brief,
|
|
91
|
+
successChecks: checks,
|
|
92
|
+
// #225: a `done` whose check failed on a job judged done ends the run — never the whole budget.
|
|
93
|
+
stopWhenJudgedDone: true,
|
|
94
|
+
...(opts.successWhen === undefined ? {} : { successWhen: opts.successWhen }),
|
|
95
|
+
...(opts.allowVacuousChecks === true ? { allowVacuousChecks: true } : {}),
|
|
96
|
+
});
|
|
97
|
+
const run = adjudication?.run ?? (await explore({ ...exploreCfg, missionContext: brief }));
|
|
98
|
+
// Never blocks the mission itself: the drain wait happens AFTER `explore()` returned.
|
|
99
|
+
const serverLogRun = serverLog === undefined ? undefined : await serverLog.finish(run.transcript);
|
|
100
|
+
journal.writeRecording(run.recording);
|
|
101
|
+
journal.writeTranscript(capture.withScreenshots(serverLogRun?.transcript ?? run.transcript));
|
|
102
|
+
return { start, budget, adjudication, run, serverLogRun };
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/ux-usability/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ExploreConfig } from "@jevitate/explore";
|
|
2
|
+
import type { UsabilitySetup } from "./setup.js";
|
|
3
|
+
/**
|
|
4
|
+
* Phase 2a — the act loop's `onSnapshot` hook: one screen's evidence per observation, its
|
|
5
|
+
* (secret-masked) screenshot and the overflow/clipping hard signals. Never gates the loop.
|
|
6
|
+
*/
|
|
7
|
+
export declare function usabilityOnSnapshot(ctx: UsabilitySetup): NonNullable<ExploreConfig["onSnapshot"]>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// ux-usability/observe.ts — the usability act loop's per-screen observation hook (#500).
|
|
2
|
+
import { clippingSummary, detectClipping, detectOverflow, shouldCheckOverflow } from "@jevitate/explore";
|
|
3
|
+
import { makeSignalFinding } from "@jevitate/ux";
|
|
4
|
+
import { snapshotToEvidence } from "../ux-evidence.js";
|
|
5
|
+
/**
|
|
6
|
+
* Phase 2a — the act loop's `onSnapshot` hook: one screen's evidence per observation, its
|
|
7
|
+
* (secret-masked) screenshot and the overflow/clipping hard signals. Never gates the loop.
|
|
8
|
+
*/
|
|
9
|
+
export function usabilityOnSnapshot(ctx) {
|
|
10
|
+
const { opts, extract, session, collected, history, capture, seenOverflow, overflowFindings, secrets } = ctx;
|
|
11
|
+
return async (snap) => {
|
|
12
|
+
let visibleText = "";
|
|
13
|
+
try {
|
|
14
|
+
visibleText = await extract(session);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
visibleText = ""; // best-effort; the analyzer Skips visibleText items honestly
|
|
18
|
+
}
|
|
19
|
+
const ev = snapshotToEvidence(snap, visibleText, opts.appContext, opts.job, [...history]);
|
|
20
|
+
collected.push(ev);
|
|
21
|
+
history.push({ screenId: ev.screenId, url: ev.url });
|
|
22
|
+
// #98 the step's (secret-masked) screenshot; #96 the screen's facts for the signal oracles.
|
|
23
|
+
await capture.observe(snap, visibleText);
|
|
24
|
+
// #149: horizontal-overflow hard signal — pure DOM geometry, never a model judgment.
|
|
25
|
+
// Best-effort like visibleText extraction above: a detection failure never fails the mission.
|
|
26
|
+
try {
|
|
27
|
+
const vp = session.page.viewportSize();
|
|
28
|
+
if (shouldCheckOverflow(vp?.width, opts.overflow?.checkOverflow ?? false)) {
|
|
29
|
+
const overflow = await detectOverflow(session.page, {
|
|
30
|
+
viewport: vp ?? { width: 1280, height: 720 },
|
|
31
|
+
...(opts.emulation?.device === undefined ? {} : { device: opts.emulation.device }),
|
|
32
|
+
...(opts.overflow?.toleranceCss === undefined ? {} : { toleranceCss: opts.overflow.toleranceCss }),
|
|
33
|
+
...(opts.overflow?.ignoreSelectors === undefined ? {} : { ignoreSelectors: opts.overflow.ignoreSelectors }),
|
|
34
|
+
secrets,
|
|
35
|
+
});
|
|
36
|
+
if (overflow !== null && !seenOverflow.has(overflow.fingerprint)) {
|
|
37
|
+
seenOverflow.add(overflow.fingerprint);
|
|
38
|
+
overflowFindings.push(makeSignalFinding({
|
|
39
|
+
kind: "horizontal-overflow",
|
|
40
|
+
confidence: 0.9,
|
|
41
|
+
url: ev.url,
|
|
42
|
+
screenId: ev.screenId,
|
|
43
|
+
observation: `${overflow.element.descriptor} overflows the ${overflow.viewport.width}px viewport by ${overflow.overflowPx}px on ${overflow.route}.`,
|
|
44
|
+
userImpact: "Content extends past the visible viewport; a user on this device must discover and use horizontal scrolling to see it, and may miss it entirely.",
|
|
45
|
+
recommendation: `Constrain ${overflow.element.descriptor} to the viewport width (e.g. a responsive layout, or an explicit scroll container) at ${overflow.viewport.width}px.`,
|
|
46
|
+
controls: [overflow.element.descriptor],
|
|
47
|
+
evidence: {
|
|
48
|
+
kind: "horizontal-overflow",
|
|
49
|
+
steps: [history.length],
|
|
50
|
+
requests: [],
|
|
51
|
+
detail: `scrollWidth exceeds innerWidth by ${overflow.overflowPx}px at a ${overflow.viewport.width}x${overflow.viewport.height} viewport`,
|
|
52
|
+
},
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
// #302: text cut off vertically (a fixed-height box, or above the page top) — one finding per element.
|
|
56
|
+
const clipped = await detectClipping(session.page, {
|
|
57
|
+
viewport: vp ?? { width: 1280, height: 720 },
|
|
58
|
+
...(opts.emulation?.device === undefined ? {} : { device: opts.emulation.device }),
|
|
59
|
+
...(opts.overflow?.ignoreSelectors === undefined ? {} : { ignoreSelectors: opts.overflow.ignoreSelectors }),
|
|
60
|
+
secrets,
|
|
61
|
+
});
|
|
62
|
+
for (const c of clipped) {
|
|
63
|
+
if (seenOverflow.has(c.fingerprint))
|
|
64
|
+
continue;
|
|
65
|
+
seenOverflow.add(c.fingerprint);
|
|
66
|
+
overflowFindings.push(makeSignalFinding({
|
|
67
|
+
kind: "vertical-clipping",
|
|
68
|
+
confidence: 0.9,
|
|
69
|
+
url: ev.url,
|
|
70
|
+
screenId: ev.screenId,
|
|
71
|
+
observation: c.cause === "overflow-hidden"
|
|
72
|
+
? `${c.element.descriptor} cuts off its text by ${c.clippedPx}px on ${c.route}: the content is taller than the box and overflow is hidden.`
|
|
73
|
+
: `${c.element.descriptor} is cut off ${c.clippedPx}px above the top of the page on ${c.route}.`,
|
|
74
|
+
userImpact: "Part of the text is cut off and no scroll position shows it: a user on this device cannot read it.",
|
|
75
|
+
recommendation: c.cause === "overflow-hidden"
|
|
76
|
+
? `Let ${c.element.descriptor} grow with its content (min-height instead of height), make it scrollable, or truncate on purpose with line-clamp at ${c.viewport.width}px.`
|
|
77
|
+
: `Give the container of ${c.element.descriptor} room for its wrapped content (no fixed height, or no wrapping) at ${c.viewport.width}px.`,
|
|
78
|
+
controls: [c.element.descriptor],
|
|
79
|
+
evidence: { kind: "vertical-clipping", steps: [history.length], requests: [], detail: clippingSummary(c) },
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Best-effort: the run's own explore loop is never held up or failed by this check.
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=observe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe.js","sourceRoot":"","sources":["../../src/ux-usability/observe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HangFinding } from "@jevitate/explore";
|
|
2
|
+
import type { RunUsabilityMissionResult } from "../ux-usability.js";
|
|
3
|
+
import type { UsabilitySetup } from "./setup.js";
|
|
4
|
+
import type { UsabilityLoop } from "./loop.js";
|
|
5
|
+
import type { UsabilityAnalysis } from "./analysis.js";
|
|
6
|
+
import type { UsabilityVerdict } from "./done-adjudication.js";
|
|
7
|
+
/**
|
|
8
|
+
* Phase 6 — result: every context closed (videos finalized), the result's common fields, then the
|
|
9
|
+
* report (or the typed analysis-unavailable result), persisted and returned with its run evidence.
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeUsabilityResult(ctx: UsabilitySetup, loop: UsabilityLoop, analysis: UsabilityAnalysis, hang: HangFinding | undefined, verdict: UsabilityVerdict): Promise<RunUsabilityMissionResult>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// ux-usability/result.ts — phase 6 of `runUsabilityMission` (#500): the report and the typed, persisted result.
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { resolve as resolvePath } from "node:path";
|
|
4
|
+
import { finalizeVideos } from "../browser-run-options.js";
|
|
5
|
+
import { evidenceOf, withRunEvidence } from "../defect-evidence.js";
|
|
6
|
+
import { buildReport, calibrationCaveat, claimsCaveat, groundFindings, withSignalFindings } from "@jevitate/ux";
|
|
7
|
+
import { NO_PRODUCT_FACTS_CAVEAT } from "../ux-product.js";
|
|
8
|
+
import { resultPathFor, writeMissionResult } from "../mission-journal.js";
|
|
9
|
+
import { MISSION_RESULT_SCHEMA_VERSION, advisoryDefects, defectFields } from "../result-schema.js";
|
|
10
|
+
import { missionExitCode } from "../mission-exit.js";
|
|
11
|
+
import { branchFields } from "../journey-prefix.js";
|
|
12
|
+
import { failureWithHostStarved } from "../host-health-run.js";
|
|
13
|
+
import { currentEngineInfo } from "../engine.js";
|
|
14
|
+
import { triageOf } from "../explore-shared.js";
|
|
15
|
+
import { serverLogResult } from "../explore-api.js";
|
|
16
|
+
import { UxAnalysisFailedError } from "../ux-review.js";
|
|
17
|
+
/**
|
|
18
|
+
* Phase 6 — result: every context closed (videos finalized), the result's common fields, then the
|
|
19
|
+
* report (or the typed analysis-unavailable result), persisted and returned with its run evidence.
|
|
20
|
+
*/
|
|
21
|
+
export async function writeUsabilityResult(ctx, loop, analysis, hang, verdict) {
|
|
22
|
+
const { opts, runCapture, videoDir, closeSession, journal, collected, screenshotDir, capture, runUsage, http5xx, secrets, minConfidence, quality, maxFindingsPerRoute, product, reportPath } = ctx;
|
|
23
|
+
const { start, run, serverLogRun, budget, adjudication } = loop;
|
|
24
|
+
const { signalFindings, friction, outcome, evidenceWritten } = analysis;
|
|
25
|
+
const { host, runOutcome, jobFailure } = verdict;
|
|
26
|
+
// #245: every context closed (videos finalized) before the result naming them is written.
|
|
27
|
+
const shotFields = await runCapture.finish();
|
|
28
|
+
const videos = await finalizeVideos(videoDir, closeSession);
|
|
29
|
+
const base = {
|
|
30
|
+
schemaVersion: MISSION_RESULT_SCHEMA_VERSION,
|
|
31
|
+
strategy: "usability",
|
|
32
|
+
target: {
|
|
33
|
+
seedUrl: start.persistUrl,
|
|
34
|
+
allowlist: [...opts.allowlist],
|
|
35
|
+
...(opts.storageState !== undefined ? { storageStatePath: resolvePath(opts.storageState) } : {}),
|
|
36
|
+
},
|
|
37
|
+
...branchFields(start),
|
|
38
|
+
recordingPaths: [journal.recordingPath],
|
|
39
|
+
...videos,
|
|
40
|
+
...shotFields,
|
|
41
|
+
resultPath: resultPathFor(journal.recordingPath),
|
|
42
|
+
hangs: hang === undefined ? [] : [hang],
|
|
43
|
+
timing: run.timing,
|
|
44
|
+
stop: run.stop,
|
|
45
|
+
outcome: run.outcome,
|
|
46
|
+
...(run.answer === undefined ? {} : { answer: run.answer }),
|
|
47
|
+
screensObserved: collected.length,
|
|
48
|
+
transcriptPath: journal.transcriptPath,
|
|
49
|
+
screenshotDir,
|
|
50
|
+
evidencePath: evidenceWritten,
|
|
51
|
+
screenshots: capture.screenshots(),
|
|
52
|
+
sideEffects: run.sideEffects,
|
|
53
|
+
...(run.sideEffectsTruncated === undefined ? {} : { sideEffectsTruncated: run.sideEffectsTruncated }),
|
|
54
|
+
...(run.safetyOverrides === undefined ? {} : { safetyOverrides: run.safetyOverrides }),
|
|
55
|
+
...(run.actionDeltas === undefined ? {} : { actionDeltas: run.actionDeltas }),
|
|
56
|
+
engine: currentEngineInfo(),
|
|
57
|
+
...(() => {
|
|
58
|
+
const f = failureWithHostStarved(host, run.failure ?? host.failure ?? jobFailure);
|
|
59
|
+
return f === undefined ? {} : { failure: f };
|
|
60
|
+
})(),
|
|
61
|
+
...(run.crash === undefined ? {} : { crash: run.crash }),
|
|
62
|
+
finalUrl: run.finalUrl,
|
|
63
|
+
decisions: run.decisions,
|
|
64
|
+
actions: run.actions,
|
|
65
|
+
depth: run.depth,
|
|
66
|
+
...(runUsage === undefined ? {} : { usage: runUsage.snapshot() }),
|
|
67
|
+
...(hang === undefined ? {} : { hang }),
|
|
68
|
+
// #142 follow-up: reported but never gates `missionOutcome`/`exitCode` — a UX finding is
|
|
69
|
+
// always advisory, and a `server-log` defect here is treated the same way. So is an HTTP 5xx
|
|
70
|
+
// hard-signal defect (#208): listed with its fingerprint (verify-fix replays it), advisory here.
|
|
71
|
+
...serverLogResult(serverLogRun),
|
|
72
|
+
...defectFields([
|
|
73
|
+
...http5xx.defects(run.transcript, run.recording.pages.flatMap((p) => p.steps)[0]?.step.kind === "navigate" ? 1 : 0).map((d) => ({ ...d, advisory: true })),
|
|
74
|
+
...advisoryDefects(serverLogRun?.defects),
|
|
75
|
+
]),
|
|
76
|
+
...(budget === null ? {} : { budget: budget.trajectory() }),
|
|
77
|
+
...(adjudication === undefined
|
|
78
|
+
? {}
|
|
79
|
+
: {
|
|
80
|
+
goalOutcome: adjudication.outcome,
|
|
81
|
+
checks: adjudication.checks,
|
|
82
|
+
...(adjudication.warnings === undefined ? {} : { checkWarnings: adjudication.warnings }),
|
|
83
|
+
}),
|
|
84
|
+
...host.fields,
|
|
85
|
+
};
|
|
86
|
+
if (outcome.kind === "failed") {
|
|
87
|
+
// The analysis is the review's product: without it the review is inconclusive (never a
|
|
88
|
+
// fabricated clean report) — but the run's transcript is kept, and this is a typed result.
|
|
89
|
+
const why = new UxAnalysisFailedError(outcome.reason, outcome.screenId, outcome.rubricItemId).message;
|
|
90
|
+
const missionOutcome = runOutcome === "clean" ? "inconclusive" : runOutcome;
|
|
91
|
+
const unavailable = {
|
|
92
|
+
...base,
|
|
93
|
+
report: null,
|
|
94
|
+
reportPath: null,
|
|
95
|
+
missionOutcome,
|
|
96
|
+
exitCode: missionExitCode(missionOutcome),
|
|
97
|
+
analysisUnavailable: why,
|
|
98
|
+
};
|
|
99
|
+
// Persisted like every other mission's typed result, so MCP `get_mission_result` can read it (#117).
|
|
100
|
+
return await withRunEvidence({ ...unavailable, resultPath: writeMissionResult(journal.recordingPath, missionOutcome, unavailable.exitCode, unavailable, runUsage) }, evidenceOf(opts, secrets), triageOf(opts, serverLogRun, secrets));
|
|
101
|
+
}
|
|
102
|
+
const report = buildReport(groundFindings(withSignalFindings(outcome, signalFindings), friction), {
|
|
103
|
+
minConfidence,
|
|
104
|
+
quality,
|
|
105
|
+
maxFindingsPerRoute,
|
|
106
|
+
...(product.facts === undefined ? { evidenceCaveats: [NO_PRODUCT_FACTS_CAVEAT] } : {}),
|
|
107
|
+
calibrationCaveats: [calibrationCaveat(opts.appContext.appClass), claimsCaveat()],
|
|
108
|
+
});
|
|
109
|
+
await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
110
|
+
const reviewed = { ...base, report, reportPath, missionOutcome: runOutcome, exitCode: missionExitCode(runOutcome) };
|
|
111
|
+
return await withRunEvidence({ ...reviewed, resultPath: writeMissionResult(journal.recordingPath, runOutcome, reviewed.exitCode, reviewed, runUsage) }, evidenceOf(opts, secrets), triageOf(opts, serverLogRun, secrets));
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/ux-usability/result.ts"],"names":[],"mappings":"AAAA,gHAAgH;AAChH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEpE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAChH,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,YAAY,EAAgC,MAAM,qBAAqB,CAAC;AACjI,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAOxD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAmB,EACnB,IAAmB,EACnB,QAA2B,EAC3B,IAA6B,EAC7B,OAAyB;IAEzB,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC;IACnM,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAChE,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,QAAQ,CAAC;IACxE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IACjD,0FAA0F;IAC1F,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG;QACX,aAAa,EAAE,6BAA6B;QAC5C,QAAQ,EAAE,WAAoB;QAC9B,MAAM,EAAE;YACN,OAAO,EAAE,KAAK,CAAC,UAAU;YACzB,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;YAC9B,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjG;QACD,GAAG,YAAY,CAAC,KAAK,CAAC;QACtB,cAAc,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;QACvC,GAAG,MAAM;QACT,GAAG,UAAU;QACb,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC;QAChD,KAAK,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;QAC3D,eAAe,EAAE,SAAS,CAAC,MAAM;QACjC,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,aAAa;QACb,YAAY,EAAE,eAAe;QAC7B,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;QAClC,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,GAAG,CAAC,GAAG,CAAC,oBAAoB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACrG,GAAG,CAAC,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,CAAC,eAAe,EAAE,CAAC;QACtF,GAAG,CAAC,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7E,MAAM,EAAE,iBAAiB,EAAE;QAC3B,GAAG,CAAC,GAAiC,EAAE;YACrC,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,UAAU,CAAC,CAAC;YAClF,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAC/C,CAAC,CAAC,EAAE;QACJ,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;QACxD,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;QACjE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,yFAAyF;QACzF,6FAA6F;QAC7F,iGAAiG;QACjG,GAAG,eAAe,CAAC,YAAY,CAAC;QAChC,GAAG,YAAY,CAA0E;YACvF,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAa,EAAE,CAAC,CAAC;YACpK,GAAG,eAAe,CAAC,YAAY,EAAE,OAAO,CAAC;SAC1C,CAAC;QACF,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;QAC3D,GAAG,CAAC,YAAY,KAAK,SAAS;YAC5B,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC;gBACE,WAAW,EAAE,YAAY,CAAC,OAAO;gBACjC,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,GAAG,CAAC,YAAY,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;aACzF,CAAC;QACN,GAAG,IAAI,CAAC,MAAM;KACf,CAAC;IACF,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,uFAAuF;QACvF,2FAA2F;QAC3F,MAAM,GAAG,GAAG,IAAI,qBAAqB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC;QACtG,MAAM,cAAc,GAAmB,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;QAC5F,MAAM,WAAW,GAAG;YAClB,GAAG,IAAI;YACP,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,IAAI;YAChB,cAAc;YACd,QAAQ,EAAE,eAAe,CAAC,cAAc,CAAC;YACzC,mBAAmB,EAAE,GAAG;SACzB,CAAC;QACF,qGAAqG;QACrG,OAAO,MAAM,eAAe,CAAC,EAAE,GAAG,WAAW,EAAE,UAAU,EAAE,kBAAkB,CAAC,OAAO,CAAC,aAAa,EAAE,cAAc,EAAE,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IACzO,CAAC;IACD,MAAM,MAAM,GAAG,WAAW,CAAC,cAAc,CAAC,kBAAkB,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,QAAQ,CAAC,EAAE;QAChG,aAAa;QACb,OAAO;QACP,mBAAmB;QACnB,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,kBAAkB,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;KAClF,CAAC,CAAC;IACH,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;IACpH,OAAO,MAAM,eAAe,CAAC,EAAE,GAAG,QAAQ,EAAE,UAAU,EAAE,kBAAkB,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;AAC5N,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type SecretCommandRunner, type TranscriptEntry } from "@jevitate/explore";
|
|
2
|
+
import { type ScreenRef, type UxEvidence, type UxFinding } from "@jevitate/ux";
|
|
3
|
+
import { MissionJournal } from "../mission-journal.js";
|
|
4
|
+
import { Http5xxOracle } from "@jevitate/explore";
|
|
5
|
+
import { UsabilityCapture } from "../usability-capture.js";
|
|
6
|
+
import type { RunUsabilityMissionOptions } from "../ux-usability.js";
|
|
7
|
+
/** Usability reads only a spec's `budget` (#150) — never its `invariants`/`capture` (#86/#147, not supported here). */
|
|
8
|
+
export declare class UsabilityInvariantsUnsupportedError extends Error {
|
|
9
|
+
readonly code: "E_USABILITY_INVARIANTS";
|
|
10
|
+
constructor();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Phase 1 — set-up: every bad-input refusal BEFORE a browser opens, the run's artifact paths, the
|
|
14
|
+
* armed launch (kill switch, host sampler, browser), the capture/journal/server-log listener chain
|
|
15
|
+
* and the once-only session close. Returns the run's shared state, mutated in place by later phases.
|
|
16
|
+
*/
|
|
17
|
+
export declare function setUpUsabilityMission(opts: RunUsabilityMissionOptions): Promise<{
|
|
18
|
+
opts: RunUsabilityMissionOptions;
|
|
19
|
+
origin: string;
|
|
20
|
+
minConfidence: number;
|
|
21
|
+
quality: import("@jevitate/ux").QualityPolicy;
|
|
22
|
+
maxFindingsPerRoute: number;
|
|
23
|
+
fixture: string | undefined;
|
|
24
|
+
product: import("../ux-product.js").LoadedProductFacts;
|
|
25
|
+
runCapture: import("../run-screenshots.js").RunCapture;
|
|
26
|
+
portFactory: () => import("@jevitate/playwright").BrowserPort;
|
|
27
|
+
port: import("@jevitate/playwright").BrowserPort;
|
|
28
|
+
collected: UxEvidence[];
|
|
29
|
+
history: ScreenRef[];
|
|
30
|
+
overflowFindings: UxFinding[];
|
|
31
|
+
seenOverflow: Set<string>;
|
|
32
|
+
extract: (session: {
|
|
33
|
+
page: {
|
|
34
|
+
evaluate: (fn: () => string) => Promise<string>;
|
|
35
|
+
};
|
|
36
|
+
}) => Promise<string>;
|
|
37
|
+
outDir: string;
|
|
38
|
+
stamp: string;
|
|
39
|
+
reportPath: string;
|
|
40
|
+
journal: MissionJournal;
|
|
41
|
+
screenshotDir: string;
|
|
42
|
+
videoDir: string | undefined;
|
|
43
|
+
launch: {
|
|
44
|
+
storageState?: string | undefined;
|
|
45
|
+
viewport?: import("@jevitate/playwright").ViewportSize;
|
|
46
|
+
device?: string;
|
|
47
|
+
geolocation?: import("@jevitate/playwright").GeolocationSpec;
|
|
48
|
+
allowedOrigins: string[];
|
|
49
|
+
baseUrl: string;
|
|
50
|
+
executablePath?: string;
|
|
51
|
+
channel?: string;
|
|
52
|
+
args?: readonly string[];
|
|
53
|
+
slowMo?: number;
|
|
54
|
+
extensions?: readonly import("@jevitate/playwright").UnpackedExtension[];
|
|
55
|
+
resources?: import("@jevitate/playwright").ResourceLimits;
|
|
56
|
+
recordVideo?: {
|
|
57
|
+
dir: string;
|
|
58
|
+
} | undefined;
|
|
59
|
+
headless: boolean;
|
|
60
|
+
};
|
|
61
|
+
secrets: string[];
|
|
62
|
+
runUsage: import("@jevitate/ai-core").UsageLedger | undefined;
|
|
63
|
+
disarmKillSwitch: () => void;
|
|
64
|
+
health: import("@jevitate/explore").HostHealthSampler;
|
|
65
|
+
session: import("@jevitate/playwright").BrowserSession;
|
|
66
|
+
snapshotter: import("../storage-state-snapshot.js").StorageStateSnapshotter;
|
|
67
|
+
uxSecretCommand: SecretCommandRunner | undefined;
|
|
68
|
+
http5xx: Http5xxOracle;
|
|
69
|
+
capture: UsabilityCapture;
|
|
70
|
+
journalListener: (entry: TranscriptEntry, all: readonly TranscriptEntry[]) => void;
|
|
71
|
+
serverLog: import("../log-correlation.js").ServerLogRuntime | undefined;
|
|
72
|
+
closeSession: () => Promise<void>;
|
|
73
|
+
}>;
|
|
74
|
+
/** The run's shared state: set up once, handed to every later phase (the same objects, never copies). */
|
|
75
|
+
export type UsabilitySetup = Awaited<ReturnType<typeof setUpUsabilityMission>>;
|