@unotest/protocol 0.6.2 → 0.9.1
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/CHANGELOG.md +38 -0
- package/dist/index.d.ts +726 -64
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@unotest/protocol` are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.9.1] - 2026-06-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Probe protocol.** `DbgCommandProbe` + `ProbeResult` / `ProbeResultEvent` —
|
|
10
|
+
evaluate a DSL locator string against the live page and report what it matches
|
|
11
|
+
(count, the N a trailing `.first()`/`.last()`/`.nth()` collapsed, per-match
|
|
12
|
+
identity). Shared shape so the agent's `check_locator` and the viewer's human
|
|
13
|
+
probe report identically.
|
|
14
|
+
- **Agent tool-call events.** `ToolCallEvent` / `ToolResultEvent` — an attached
|
|
15
|
+
MCP server surfaces each tool call + result into the run's event stream so the
|
|
16
|
+
viewer's System console shows what the agent called and how it ended.
|
|
17
|
+
- **`RuntimeStateFile.breakpoints`.** The run's active breakpoints (`"line:col"`
|
|
18
|
+
keys — `.debugger.json` seed + any `--breakpoints` override), so the viewer can
|
|
19
|
+
paint gutter dots for breakpoints that aren't persisted.
|
|
20
|
+
- **App-server protocol.** `AppServerEvent` + `parseAppServerEvent` and the
|
|
21
|
+
`IRunnerAdapter` / launch-spec contracts for the project dev app-server
|
|
22
|
+
integration.
|
|
23
|
+
- **Env editing helpers** (`env-edit`) and additional path constants/helpers
|
|
24
|
+
(`paths`).
|
|
25
|
+
|
|
26
|
+
## [0.9.0] - 2026-06-11
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **`ScenariosPayload`** — the `GET /api/scenarios` response now carries both
|
|
31
|
+
the scenario list and the folder list (including empty dirs), so the viewer's
|
|
32
|
+
tree can render and manage folders.
|
|
33
|
+
- **`validateSegmentName`** — shared scenario-file-stem / folder-name validation
|
|
34
|
+
(single FS-safe path segment), used by both the viewer-server writer and the
|
|
35
|
+
client form.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **`RUNNER_CONFIG_KEYS`** now includes `UNOTEST_NETWORK` and `UNOTEST_CONSOLE`,
|
|
40
|
+
so the viewer's Variables panel groups them under "Runner config" rather than
|
|
41
|
+
app data.
|
|
42
|
+
|
|
5
43
|
## [0.6.2] - 2026-06-05
|
|
6
44
|
|
|
7
45
|
Maintenance release: version bump to keep the `@unotest` ecosystem in
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
|
|
3
|
+
type AppServerEvent =
|
|
4
|
+
/** The app under test is ready. Web holders carry the dev-server
|
|
5
|
+
* `url`; device holders (mobile) carry a human `detail` line instead
|
|
6
|
+
* («A: UnoTest-A booted, UnoPeak.app installed»). At least one of
|
|
7
|
+
* the two is expected; the panel renders whichever is present. */
|
|
8
|
+
{
|
|
9
|
+
kind: "app-server:ready";
|
|
10
|
+
url?: string;
|
|
11
|
+
detail?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Already provided by someone else — nothing spawned; the holder
|
|
14
|
+
* exits 0 (web: URL already serving). */
|
|
15
|
+
| {
|
|
16
|
+
kind: "app-server:reused";
|
|
17
|
+
url?: string;
|
|
18
|
+
detail?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Configuration / spawn / readiness failure. The holder exits 1. */
|
|
21
|
+
| {
|
|
22
|
+
kind: "app-server:error";
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
25
|
+
/** Parse one stdout line into an `AppServerEvent`, or null when the line
|
|
26
|
+
* is ordinary dev-server output. */
|
|
27
|
+
declare function parseAppServerEvent(line: string): AppServerEvent | null;
|
|
28
|
+
|
|
1
29
|
/** User-facing project directory containing scenarios + helpers + collections. */
|
|
2
30
|
declare const UNOTEST_DIR = "unotest";
|
|
3
31
|
/** Subdir under `unotest/` for `.test.js` scenarios. */
|
|
@@ -10,6 +38,19 @@ declare const COLLECTIONS_SUBDIR = "_collections";
|
|
|
10
38
|
* Dot-prefix so a single `.gitignore` line covers all runtime debris
|
|
11
39
|
* without touching user code in `unotest/e2e/`. */
|
|
12
40
|
declare const RUNS_SUBDIR = ".runs";
|
|
41
|
+
/** Scenario tree under `unotest/`: `e2e` / `e2e-mobile`. */
|
|
42
|
+
declare function testDirFor(suffix: string): string;
|
|
43
|
+
/** Run-artifact root under `unotest/`: `.runs` / `.runs-mobile`. */
|
|
44
|
+
declare function runsDirFor(suffix: string): string;
|
|
45
|
+
/** `UNOTEST_DEBUG` artifact root under `unotest/`: `.debug` /
|
|
46
|
+
* `.debug-mobile`. */
|
|
47
|
+
declare function debugDirFor(suffix: string): string;
|
|
48
|
+
/** Per-target shared breakpoint store, relative to project root:
|
|
49
|
+
* `unotest/.debugger.json` / `unotest/.debugger-mobile.json`. Breakpoint
|
|
50
|
+
* keys are scenario names RELATIVE to the target's testDir, so each
|
|
51
|
+
* target needs its own file (same key ≠ same scenario across targets).
|
|
52
|
+
* Schema: `BreakpointsFile` in `protocol/breakpoints-file.ts`. */
|
|
53
|
+
declare function debuggerFileFor(suffix: string): string;
|
|
13
54
|
/** Lockfile path *relative to* `unotest/`. Project-local (multiple viewers
|
|
14
55
|
* for different projects coexist). */
|
|
15
56
|
declare const LOCK_FILE = ".viewer.lock";
|
|
@@ -37,13 +78,40 @@ declare const COMMANDS_FILE = "commands.jsonl";
|
|
|
37
78
|
* from the page-snapshot (semantic-DOM YAML) which lives in
|
|
38
79
|
* failure-bundles. */
|
|
39
80
|
declare const RUNTIME_FILE = "runtime.json";
|
|
40
|
-
/**
|
|
41
|
-
* (
|
|
42
|
-
* `
|
|
43
|
-
|
|
81
|
+
/** Read-only page-outline snapshot the in-page picker overlay hit-tests
|
|
82
|
+
* against, written by the runner when the picker arms (and on self-heal).
|
|
83
|
+
* Lives at `unotest/.runs/<runId>/picker-snapshot.txt`. The viewer's
|
|
84
|
+
* Snapshot inspector tab fetches it via the run-dir asset endpoint to show
|
|
85
|
+
* "what the picker sees" for diagnosing ref/coverage gaps. */
|
|
86
|
+
declare const PICKER_SNAPSHOT_FILE = "picker-snapshot.txt";
|
|
44
87
|
/** Project env file edited by the viewer's env-variable editor. Relative
|
|
45
88
|
* to project root. Surfaced as `EnvFile` (`protocol/env-file.ts`). */
|
|
46
89
|
declare const ENV_FILE = "unotest/.env";
|
|
90
|
+
/** Secret scenario variables, beside `.env` under `unotest/`. Same KEY=VALUE
|
|
91
|
+
* format; secrecy is a property of THIS file (not a name heuristic). */
|
|
92
|
+
declare const SECRETS_FILE = "unotest/.secrets";
|
|
93
|
+
/** Env/secrets file naming spans TWO axes (M-11):
|
|
94
|
+
*
|
|
95
|
+
* - TARGET (dash, M-10): `.env` is the shared base AND web's file (bare
|
|
96
|
+
* suffix); `.env-mobile` overrides it for the mobile runner.
|
|
97
|
+
* - ENVIRONMENT (dot): `.env.<name>` overrides for a named environment
|
|
98
|
+
* (`staging`, `production`, …), selected at run time via
|
|
99
|
+
* `UNOTEST_ENV` / `--env`.
|
|
100
|
+
*
|
|
101
|
+
* They compose: `unotest/.env-mobile.staging`. Precedence (low→high):
|
|
102
|
+
* base → target → env-overlay → target+env-overlay — an explicit
|
|
103
|
+
* `--env` is a runtime intent and beats a static target default.
|
|
104
|
+
* Ambient process.env still wins over every file. */
|
|
105
|
+
declare function envFileFor(suffix: string, envName?: string): string;
|
|
106
|
+
declare function secretsFileFor(suffix: string, envName?: string): string;
|
|
107
|
+
/** Ordered (low→high precedence) layer list for a target's env files.
|
|
108
|
+
* Bare suffix / unset env collapse to fewer layers — web with no named
|
|
109
|
+
* environment reads just `[unotest/.env]`. */
|
|
110
|
+
declare function envLayerFilesFor(suffix: string, envName?: string): string[];
|
|
111
|
+
declare function secretsLayerFilesFor(suffix: string, envName?: string): string[];
|
|
112
|
+
/** Read an environment name from a process-env-like record (`UNOTEST_ENV`),
|
|
113
|
+
* normalising empty/blank to `undefined` (= base only). */
|
|
114
|
+
declare function activeEnvName(env: Record<string, string | undefined>): string | undefined;
|
|
47
115
|
|
|
48
116
|
interface RegexLiteral {
|
|
49
117
|
readonly kind: "regex";
|
|
@@ -137,8 +205,19 @@ interface CollectionRunRequest {
|
|
|
137
205
|
/** Stop on first failure. Default `false` (continue-on-fail). */
|
|
138
206
|
bail?: boolean;
|
|
139
207
|
}
|
|
208
|
+
/** Open a live AUTHORING-HOLD session (collaborative model, U1/U3): a
|
|
209
|
+
* headed shared browser + draft stay open with NO running test; the human
|
|
210
|
+
* and agent co-author the draft. Runs `unotest-web author <scenario>`. */
|
|
211
|
+
interface AuthoringRunRequest {
|
|
212
|
+
kind: "authoring";
|
|
213
|
+
/** Scenario `name` — file stem relative to `unotest/e2e/`. A stub is
|
|
214
|
+
* created if the file doesn't exist yet. */
|
|
215
|
+
scenario: string;
|
|
216
|
+
/** Authoring is visible by default — the human must see the live browser. */
|
|
217
|
+
headed?: boolean;
|
|
218
|
+
}
|
|
140
219
|
/** Discriminated union of every run-shape the viewer can request. */
|
|
141
|
-
type RunRequest = ScenarioRunRequest | CollectionRunRequest;
|
|
220
|
+
type RunRequest = ScenarioRunRequest | CollectionRunRequest | AuthoringRunRequest;
|
|
142
221
|
/** All `kind` literals — useful for switch-completeness checks and for
|
|
143
222
|
* adapter `supportedKinds` lists. */
|
|
144
223
|
type RunKind = RunRequest["kind"];
|
|
@@ -188,6 +267,21 @@ interface IRunnerAdapter {
|
|
|
188
267
|
* (e.g. `"@unotest/web"`). NOT used for control flow — viewer
|
|
189
268
|
* must not branch on this. */
|
|
190
269
|
readonly name: string;
|
|
270
|
+
/** Per-target artifact suffix — the single axis that scopes EVERY
|
|
271
|
+
* per-target filesystem name (M-10): `""` for web (the first target
|
|
272
|
+
* keeps the bare names), `"-mobile"` for mobile, `"-unity"` for a
|
|
273
|
+
* future unity runner. Derived names (via `paths.ts` helpers):
|
|
274
|
+
* scenario tree `e2e<suffix>`, run artifacts `.runs<suffix>`, debug
|
|
275
|
+
* logs `.debug<suffix>`, breakpoints `.debugger<suffix>.json`, env
|
|
276
|
+
* overlays `.env<suffix>`. The viewer scopes discovery/runs/
|
|
277
|
+
* breakpoints by the active target's suffix so no folder name is
|
|
278
|
+
* ever hardcoded in viewer source (OCP: a new target just declares
|
|
279
|
+
* its suffix). */
|
|
280
|
+
readonly suffix: string;
|
|
281
|
+
/** Debug-toolbar capabilities the viewer gates its controls on (OCP — a
|
|
282
|
+
* new target just declares what it supports; viewer never branches on the
|
|
283
|
+
* runner name). See `DebugCapabilities`. */
|
|
284
|
+
readonly debug: DebugCapabilities;
|
|
191
285
|
/** Which `RunRequest.kind` values this adapter can handle. Viewer
|
|
192
286
|
* rejects unsupported kinds with `UnsupportedRunKindError` before
|
|
193
287
|
* building argv. */
|
|
@@ -206,6 +300,106 @@ interface IRunnerAdapter {
|
|
|
206
300
|
* (`UNOTEST_WORKER_INDEX/COUNT`) is NOT the adapter's
|
|
207
301
|
* responsibility — see `D-C4` in the collections plan. */
|
|
208
302
|
buildEnv(req: RunRequest): NodeJS.ProcessEnv;
|
|
303
|
+
/** Argv (after the bin path) that starts this runner's LONG-LIVED
|
|
304
|
+
* app-under-test holder (M-12/M-16) — the process that prepares the
|
|
305
|
+
* app (web: spawns the dev server; mobile: boots devices + installs
|
|
306
|
+
* the build), emits `AppServerEvent` JSON lines on stdout, and tears
|
|
307
|
+
* down what it owns when terminated. Absent → the runner has no
|
|
308
|
+
* app-launch capability and the viewer hides the feature for this
|
|
309
|
+
* target. Example: `["app-server"]`. */
|
|
310
|
+
appServerArgs?(): string[];
|
|
311
|
+
/** Path inputs the App panel renders for this target (M-17) — each
|
|
312
|
+
* spec becomes an input + file-picker button whose value is saved
|
|
313
|
+
* into the target's env file (`envKey`). The viewer stays
|
|
314
|
+
* platform-blind: extensions/labels are vocab the adapter owns
|
|
315
|
+
* (mobile iOS: `.app`; a future Android entry adds `.apk`). */
|
|
316
|
+
appServerPickers?(): readonly AppPathPickerSpec[];
|
|
317
|
+
/** Host-OS requirement for THIS runner. The viewer resolves it against
|
|
318
|
+
* the server's real `process.platform` and gates the switcher: an
|
|
319
|
+
* unsupported host shows `reason` and blocks activation (e.g. mobile is
|
|
320
|
+
* macOS-only — iOS Simulator is Apple-licensed). Absent → runs on any
|
|
321
|
+
* host (web). OCP: a new platform-bound runner just declares this; the
|
|
322
|
+
* viewer never hardcodes which target needs which OS. */
|
|
323
|
+
readonly host?: HostRequirement;
|
|
324
|
+
/** Structured environment preflight ("doctor") — what must be installed/
|
|
325
|
+
* configured for this runner to actually run here (mobile: Xcode +
|
|
326
|
+
* simulators; web: Node + a system browser). Pure-ish but MAY shell out
|
|
327
|
+
* to probe the host, hence async; the viewer invokes it on demand (a
|
|
328
|
+
* "Check" button), never on every switch. Absent → nothing to verify
|
|
329
|
+
* beyond the package being installed. The viewer renders the returned
|
|
330
|
+
* list verbatim (severity + message + fix `detail`) — it owns no runner
|
|
331
|
+
* vocab. */
|
|
332
|
+
doctor?(ctx: DoctorContext): Promise<DoctorCheck[]>;
|
|
333
|
+
}
|
|
334
|
+
/** Severity of a single {@link DoctorCheck}. `error` = the runner cannot
|
|
335
|
+
* run until fixed; `warning` = may work, review; `ok` = satisfied. */
|
|
336
|
+
type CheckSeverity = "ok" | "warning" | "error";
|
|
337
|
+
/** One environment-preflight result. The single shape both `@unotest/web`
|
|
338
|
+
* and `@unotest/mobile` already produce from their `runEnvironmentChecks`
|
|
339
|
+
* — lifted here so the viewer (and any future surface) consumes one type,
|
|
340
|
+
* not a per-runner copy. */
|
|
341
|
+
interface DoctorCheck {
|
|
342
|
+
/** Short check id, e.g. `"xcode-cli"`, `"Node.js version"`. */
|
|
343
|
+
name: string;
|
|
344
|
+
severity: CheckSeverity;
|
|
345
|
+
/** One-line outcome, e.g. `"Xcode CLI tools at /Applications/…"`. */
|
|
346
|
+
message: string;
|
|
347
|
+
/** Human-readable remediation when not `ok` — a command or concrete
|
|
348
|
+
* next step. Surfaced under the message in the UI. */
|
|
349
|
+
detail?: string;
|
|
350
|
+
}
|
|
351
|
+
/** What an adapter's {@link IRunnerAdapter.doctor} receives. Kept as an
|
|
352
|
+
* object so new context (e.g. a target's env file) can be added without
|
|
353
|
+
* touching every implementor's signature. */
|
|
354
|
+
interface DoctorContext {
|
|
355
|
+
/** Absolute path to the project root (the dir containing `unotest/`) —
|
|
356
|
+
* for project-aware checks (mobile reads `package.json` to hint RN/Expo). */
|
|
357
|
+
projectRoot: string;
|
|
358
|
+
}
|
|
359
|
+
/** A runner's host-OS requirement. The viewer compares `platforms` against
|
|
360
|
+
* `process.platform`; a mismatch shows `reason` and blocks the switch. */
|
|
361
|
+
interface HostRequirement {
|
|
362
|
+
/** `process.platform` values this runner can execute on, e.g. `["darwin"]`
|
|
363
|
+
* for iOS. */
|
|
364
|
+
platforms: ReadonlyArray<NodeJS.Platform>;
|
|
365
|
+
/** Shown when the current host isn't in `platforms` — one sentence the
|
|
366
|
+
* user reads in the switcher / setup panel. */
|
|
367
|
+
reason: string;
|
|
368
|
+
}
|
|
369
|
+
/** What a runner's debug session supports — drives which debug-toolbar
|
|
370
|
+
* controls the viewer shows. A target that lacks a capability gets the
|
|
371
|
+
* control hidden (no dead buttons). */
|
|
372
|
+
interface DebugCapabilities {
|
|
373
|
+
/** In-page locator picker / recorder — click an element in the SHARED,
|
|
374
|
+
* inspectable page to insert its locator/assertion (web). Runners that
|
|
375
|
+
* drive an opaque device without a clickable DOM (mobile via WDA) set this
|
|
376
|
+
* false → the viewer hides the picker cluster (Capture/Execute +
|
|
377
|
+
* target/A/eye). NOTE: distinct from `attach` — the wheel + agent join
|
|
378
|
+
* apply to mobile too. */
|
|
379
|
+
picker: boolean;
|
|
380
|
+
/** Collaborative attach: a second client (the MCP agent) can join the live
|
|
381
|
+
* debug session and co-drive it, coordinated by the control wheel. True for
|
|
382
|
+
* web (shared browser) AND mobile (shared device via WDA). The viewer shows
|
|
383
|
+
* the wheel / "who's driving" badge when set. */
|
|
384
|
+
attach: boolean;
|
|
385
|
+
/** A failure-pause is resumable as a RETRY of the failed step (mobile D-17:
|
|
386
|
+
* the user fixes the device/app state, Continue re-executes the same
|
|
387
|
+
* statement). When false (web: resume past a failure means "skip & pretend
|
|
388
|
+
* it passed"), the viewer hides Continue/Step on a failure-pause so the
|
|
389
|
+
* only action is Stop. */
|
|
390
|
+
resumeFromFailure: boolean;
|
|
391
|
+
}
|
|
392
|
+
/** One path-input row in the viewer's App panel (M-17). */
|
|
393
|
+
interface AppPathPickerSpec {
|
|
394
|
+
/** Env var the picked path is saved to (e.g. `"APP_PATH"`). Routed to
|
|
395
|
+
* the target's env file by the viewer's variables API (M-11). */
|
|
396
|
+
envKey: string;
|
|
397
|
+
/** Selectable leaf extensions (lowercase, with dot). macOS `.app`
|
|
398
|
+
* bundles are directories — the file browser treats a matching dir
|
|
399
|
+
* as a selectable leaf. */
|
|
400
|
+
extensions: readonly string[];
|
|
401
|
+
/** Human label rendered above the input (e.g. `"iOS app bundle"`). */
|
|
402
|
+
label: string;
|
|
209
403
|
}
|
|
210
404
|
/** Thrown by the viewer when a `RunRequest.kind` isn't in the
|
|
211
405
|
* adapter's `supportedKinds`. The exception filter maps to HTTP 400
|
|
@@ -225,6 +419,57 @@ declare class RunnerNotConfiguredError extends Error {
|
|
|
225
419
|
constructor(message: string);
|
|
226
420
|
}
|
|
227
421
|
|
|
422
|
+
/** Parsed scenario metadata from the mandatory header lines
|
|
423
|
+
* (per design-v0/decisions.md, "Test source format"):
|
|
424
|
+
*
|
|
425
|
+
* // id-<kebab-slug>
|
|
426
|
+
* // <human title>
|
|
427
|
+
* // #<6-hex-color>
|
|
428
|
+
* function test_<...>() { ... }
|
|
429
|
+
*
|
|
430
|
+
* All three lines are required; a file without a complete header is
|
|
431
|
+
* rejected by the discovery service as parse-error (no legacy fallback). */
|
|
432
|
+
interface ScenarioMeta {
|
|
433
|
+
/** Slug from `// id-<slug>`. Stable test identity across rename. */
|
|
434
|
+
id: string;
|
|
435
|
+
/** Human-readable title from `// <text>`. */
|
|
436
|
+
title: string;
|
|
437
|
+
/** Color identifier from `// #RRGGBB`. Used only in tab headers as a
|
|
438
|
+
* thin colored strip — NOT a status signal. */
|
|
439
|
+
color: string;
|
|
440
|
+
/** File stem relative to `unotest/e2e/`, dirs as slashes.
|
|
441
|
+
* Examples: `smoke-welcome`, `auth/signin-flow`.
|
|
442
|
+
* Source-of-truth identity for CLI invocations and tab keys. */
|
|
443
|
+
name: string;
|
|
444
|
+
/** Project-relative path to the source file. */
|
|
445
|
+
path: string;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** Response of `GET /api/scenarios`. Folders are listed independently of
|
|
449
|
+
* the scenarios so an EMPTY directory under `unotest/e2e/` still renders
|
|
450
|
+
* in the tree (the folder list isn't inferred from scenario paths). */
|
|
451
|
+
interface ScenariosPayload {
|
|
452
|
+
scenarios: ScenarioMeta[];
|
|
453
|
+
/** Directory paths relative to `unotest/e2e/`, posix-separated, any
|
|
454
|
+
* depth (e.g. `auth`, `auth/signup`, `autopark`). Excludes reserved
|
|
455
|
+
* subtrees (`_helpers`, `_collections`) and any `_`/`.`-prefixed dir. */
|
|
456
|
+
folders: string[];
|
|
457
|
+
}
|
|
458
|
+
/** Filesystem-unsafe characters in a single path segment. Includes the
|
|
459
|
+
* path separators (`\` `/`) so a valid segment is guaranteed to be ONE
|
|
460
|
+
* level — no nesting smuggled through a name. Mirrors the block-list
|
|
461
|
+
* rationale of `validateCollectionName`. */
|
|
462
|
+
declare const SEGMENT_NAME_FORBIDDEN_RE: RegExp;
|
|
463
|
+
/** Validate a single scenario-file stem or folder name. Returns `null` on
|
|
464
|
+
* success, else a human-readable reason. Shared by the viewer-server
|
|
465
|
+
* writer (authoritative) and the client form (pre-flight) so both agree.
|
|
466
|
+
* Pure — safe to bundle in the browser.
|
|
467
|
+
*
|
|
468
|
+
* Rejects: empty, `.`/`..`, `.`-prefix (hidden), `_`-prefix (reserved for
|
|
469
|
+
* `_helpers`/`_collections`/templates), path separators + FS-unsafe
|
|
470
|
+
* punctuation + control chars. */
|
|
471
|
+
declare function validateSegmentName(name: string): string | null;
|
|
472
|
+
|
|
228
473
|
/** Session profile — the kind of process a tab spawns. Mirrored by the
|
|
229
474
|
* viewer's TerminalStore.TermKind. */
|
|
230
475
|
type TerminalKind = "local" | "claude" | "codex";
|
|
@@ -275,6 +520,229 @@ type TerminalServerMessage = TerminalOutputMessage | TerminalExitMessage | Termi
|
|
|
275
520
|
* directions use this single event name on `/ws/terminal`. */
|
|
276
521
|
declare const TERMINAL_WS_EVENT = "terminal";
|
|
277
522
|
|
|
523
|
+
type VariableCategory = "secret" | "app" | "runner";
|
|
524
|
+
/** User-facing runner-config knobs documented in `unotest/.env`. Single source
|
|
525
|
+
* of truth for "is this name our config?" — drives the viewer's "Runner
|
|
526
|
+
* config" group and the add-variable dropdown.
|
|
527
|
+
*
|
|
528
|
+
* NOT listed (so they never surface as user config): launcher-injected
|
|
529
|
+
* run-control vars (UNOTEST_RUN_ID, UNOTEST_PARENT_RUN_ID,
|
|
530
|
+
* UNOTEST_BUSY_SCENARIOS, UNOTEST_WORKER_*), session-log internals
|
|
531
|
+
* (UNOTEST_SESSION_LOG_*), and path bootstrap (UNOTEST_DIR,
|
|
532
|
+
* UNOTEST_PROJECT_ROOT, UNOTEST_CONFIG, UNOTEST_VIEWER_NO_OPEN). A user would
|
|
533
|
+
* never put those in `unotest/.env`. */
|
|
534
|
+
declare const RUNNER_CONFIG_KEYS: ReadonlySet<string>;
|
|
535
|
+
/** True when `name` is a key the runner consumes as its own configuration. */
|
|
536
|
+
declare function isRunnerConfigKey(name: string): boolean;
|
|
537
|
+
/** Group a variable for the viewer. Secrecy from the source file; runner-vs-app
|
|
538
|
+
* from the owned-key set. */
|
|
539
|
+
declare function categorizeVariable(v: {
|
|
540
|
+
name: string;
|
|
541
|
+
source: "env" | "secrets";
|
|
542
|
+
}): VariableCategory;
|
|
543
|
+
/** An external scenario variable is referenced by a bare UPPER_SNAKE
|
|
544
|
+
* identifier (`APP_BASE_URL`). App / secret names must match this to be
|
|
545
|
+
* resolvable from a scenario; runner keys are validated against the set
|
|
546
|
+
* above instead. Convention only — no value inspection. */
|
|
547
|
+
declare function isExternalVarName(name: string): boolean;
|
|
548
|
+
|
|
549
|
+
/** Parse `KEY=VALUE` env-file CONTENT into a plain record. Pure — the
|
|
550
|
+
* caller does the fs read. Blank lines and `#` comments are skipped;
|
|
551
|
+
* balanced surrounding single/double quotes are stripped; keys not
|
|
552
|
+
* matching `[A-Za-z_][A-Za-z0-9_]*` are ignored. Shared by the web and
|
|
553
|
+
* mobile runners' layered env loaders (M-11) so both parse `.env` files
|
|
554
|
+
* identically. */
|
|
555
|
+
declare function parseEnvContent(raw: string): Record<string, string>;
|
|
556
|
+
/** Quote on write only when the value would otherwise be ambiguous (spaces,
|
|
557
|
+
* `#`, quotes, `=`, backslash, leading backtick, or newlines). Plain tokens
|
|
558
|
+
* stay unquoted. Mirrors the viewer env-dotenv serializer. */
|
|
559
|
+
declare function serializeEnvValue(value: string): string;
|
|
560
|
+
/** Active (non-commented) assignment keys present in env-file `content`.
|
|
561
|
+
* Used to detect duplicates / cross-file shadowing before an add. */
|
|
562
|
+
declare function envKeys(content: string): Set<string>;
|
|
563
|
+
/**
|
|
564
|
+
* Insert `KEY=VALUE` into env-file `content`. With `sectionLabel`, the line
|
|
565
|
+
* goes into the first `# --- <label> --- ` divider section — after the last
|
|
566
|
+
* assignment there (or its description comments if it has no vars yet). The
|
|
567
|
+
* label is matched as a whole word against DIVIDER lines only, so prose
|
|
568
|
+
* comments are never mistaken for a section. No such section → it is created
|
|
569
|
+
* at end-of-file. With no label the line is appended. Does NOT dedup — reject
|
|
570
|
+
* duplicates before calling.
|
|
571
|
+
*/
|
|
572
|
+
declare function insertEnvVar(content: string, key: string, value: string, sectionLabel?: string): string;
|
|
573
|
+
/**
|
|
574
|
+
* Remove the assignment line for `key`, leaving every comment and other line
|
|
575
|
+
* untouched (we do not guess which comments "belong" to the key). Returns the
|
|
576
|
+
* new content and whether anything was removed.
|
|
577
|
+
*/
|
|
578
|
+
declare function removeEnvVar(content: string, key: string): {
|
|
579
|
+
content: string;
|
|
580
|
+
removed: boolean;
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
/** Which group the user is adding into. App/runner → `.env`, secret →
|
|
584
|
+
* `.secrets`. Mirrors VariableCategory as an INPUT (the user's choice). */
|
|
585
|
+
type VariableKind = VariableCategory;
|
|
586
|
+
interface AddVariablePlanInput {
|
|
587
|
+
name: string;
|
|
588
|
+
kind: VariableKind;
|
|
589
|
+
/** Current text of `unotest/.env` (`""` if absent). */
|
|
590
|
+
envContent: string;
|
|
591
|
+
/** Current text of `unotest/.secrets` (`""` if absent). */
|
|
592
|
+
secretsContent: string;
|
|
593
|
+
}
|
|
594
|
+
type VariablePlanError = {
|
|
595
|
+
ok: false;
|
|
596
|
+
code: "duplicate" | "invalid-name" | "unknown-runner-key";
|
|
597
|
+
message: string;
|
|
598
|
+
};
|
|
599
|
+
type AddVariablePlan = {
|
|
600
|
+
ok: true;
|
|
601
|
+
target: "env" | "secrets";
|
|
602
|
+
sectionLabel?: string;
|
|
603
|
+
warnings: string[];
|
|
604
|
+
} | VariablePlanError;
|
|
605
|
+
/**
|
|
606
|
+
* Decide where a new variable goes and what to warn about — or reject it.
|
|
607
|
+
* Reject reasons: duplicate key in the target file; a non-UPPER_SNAKE app/
|
|
608
|
+
* secret name (a scenario could never reference it); a runner key not in the
|
|
609
|
+
* owned-config allowlist. Warnings (non-fatal): secret shadowing a same-named
|
|
610
|
+
* `.env` var, or vice-versa.
|
|
611
|
+
*/
|
|
612
|
+
declare function planAddVariable(input: AddVariablePlanInput): AddVariablePlan;
|
|
613
|
+
/**
|
|
614
|
+
* Warning to show after deleting `name` from the file: if the shell
|
|
615
|
+
* environment still defines it with a DIFFERENT value, it will keep
|
|
616
|
+
* resolving from there (set-if-absent means ambient wins). Comparing values
|
|
617
|
+
* avoids a false positive when `.env` was merely flattened into process.env.
|
|
618
|
+
*/
|
|
619
|
+
declare function deleteShadowWarning(name: string, fileValue: string | undefined, ambientValue: string | undefined): string[];
|
|
620
|
+
|
|
621
|
+
/** A single editor diagnostic. Superset of the `@unotest/dsl`
|
|
622
|
+
* validator diagnostic: it unifies parse errors, the vocab validator,
|
|
623
|
+
* and the platform linter behind one shape, tagged by `source`/`rule`
|
|
624
|
+
* so consumers can theme or filter. Positions are 1-based; a parse
|
|
625
|
+
* error with no recoverable position falls back to `1:1`. */
|
|
626
|
+
interface DslDiagnostic {
|
|
627
|
+
severity: "error" | "warning" | "info";
|
|
628
|
+
/** 1-based line. */
|
|
629
|
+
line: number;
|
|
630
|
+
/** 1-based column. */
|
|
631
|
+
column: number;
|
|
632
|
+
/** 1-based end line, when the producer knows the span. */
|
|
633
|
+
endLine?: number;
|
|
634
|
+
/** 1-based end column, when the producer knows the span. */
|
|
635
|
+
endColumn?: number;
|
|
636
|
+
message: string;
|
|
637
|
+
/** Stable rule id, e.g. `"validator:unknown-function"`, `"validator:dsl"`,
|
|
638
|
+
* a linter rule id, or `"parse"`. */
|
|
639
|
+
rule: string;
|
|
640
|
+
/** Which stage produced it — lets the UI group / colour by origin. */
|
|
641
|
+
source: "parse" | "validate" | "lint";
|
|
642
|
+
}
|
|
643
|
+
/** Coarse grouping for a vocab entry — drives completion icons and
|
|
644
|
+
* ordering. `keyword` covers DSL control-flow / block words (`step`,
|
|
645
|
+
* `if`, `for`, …); `helper` covers project-defined `flow_*` / mock
|
|
646
|
+
* helpers surfaced from the workspace. */
|
|
647
|
+
type DslVocabCategory = "action" | "assertion" | "selector" | "chain" | "navigation" | "read" | "wait" | "state" | "storage" | "multi-context" | "sandbox" | "escape-hatch" | "keyword" | "helper";
|
|
648
|
+
/** One declared argument of a vocab entry — feeds signature help and
|
|
649
|
+
* the snippet placeholders in `insertText`. `kind` is the validator's
|
|
650
|
+
* arg-kind string (`"locatorLike"`, `"stringLike"`, `"number"`,
|
|
651
|
+
* `"any"`, …); the editor treats it as an opaque label. */
|
|
652
|
+
interface DslVocabArg {
|
|
653
|
+
label: string;
|
|
654
|
+
kind: string;
|
|
655
|
+
required: boolean;
|
|
656
|
+
}
|
|
657
|
+
/** A single autocomplete-able item: a vocab function, a DSL keyword, or
|
|
658
|
+
* a project helper. Serializable — crosses the REST boundary verbatim
|
|
659
|
+
* and is cached by the browser (the vocab is static per platform). */
|
|
660
|
+
interface DslVocabEntry {
|
|
661
|
+
name: string;
|
|
662
|
+
category: DslVocabCategory;
|
|
663
|
+
args: DslVocabArg[];
|
|
664
|
+
/** Return-kind string (`"void"`, `"string"`, `"locator"`, …). */
|
|
665
|
+
returns: string;
|
|
666
|
+
/** Snippet body with `${n:label}` placeholders, e.g.
|
|
667
|
+
* `click(${1:locator})`. */
|
|
668
|
+
insertText: string;
|
|
669
|
+
/** Human-readable signature for hover / signature-help, e.g.
|
|
670
|
+
* `getByRole(role, { name?, exact? })`. Richer than the bare arg
|
|
671
|
+
* list — includes option-object shape. */
|
|
672
|
+
signature?: string;
|
|
673
|
+
/** Prose description (markdown) for hover and the completion info
|
|
674
|
+
* panel. */
|
|
675
|
+
doc?: string;
|
|
676
|
+
/** Locator capability from the function contract. `"chainableLocator"`
|
|
677
|
+
* entries can be chained off a locator (offered after `.`); any value
|
|
678
|
+
* other than `"none"` produces a locator (so it fits a `locator`
|
|
679
|
+
* argument slot). Absent for keywords / helpers that have no contract. */
|
|
680
|
+
locatorCapability?: "none" | "locator" | "chainableLocator";
|
|
681
|
+
}
|
|
682
|
+
/** Per-request file context for {@link IDslLanguageService.validate}.
|
|
683
|
+
* The viewer owns workspace discovery, so it supplies the things the
|
|
684
|
+
* platform validator can't know on its own. */
|
|
685
|
+
interface DslValidateContext {
|
|
686
|
+
/** Names of project helpers (`flow_*`, mocks) so their calls are not
|
|
687
|
+
* flagged as unknown functions — mirrors how the lint runner
|
|
688
|
+
* registers `unotest/e2e/_helpers/`. */
|
|
689
|
+
helperNames?: readonly string[];
|
|
690
|
+
/** Whether the source is a scenario or a helper definition file. */
|
|
691
|
+
fileKind?: "scenario" | "helper";
|
|
692
|
+
}
|
|
693
|
+
/** The DSL language service a platform exposes to the viewer. Two
|
|
694
|
+
* concerns only: the static vocabulary (for completion / signature
|
|
695
|
+
* help) and full source validation (parse + vocab validator + linter,
|
|
696
|
+
* identical to the platform's own lint gate). */
|
|
697
|
+
interface IDslLanguageService {
|
|
698
|
+
/** Static, serializable vocabulary for autocomplete and signature
|
|
699
|
+
* help. Stable for the lifetime of the process — safe to cache. */
|
|
700
|
+
getVocab(): DslVocabEntry[];
|
|
701
|
+
/** Full diagnostics for one source string. Pure with respect to the
|
|
702
|
+
* filesystem — all workspace knowledge arrives via `ctx`. */
|
|
703
|
+
validate(source: string, ctx?: DslValidateContext): DslDiagnostic[];
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/** A spawned runner process. Structural superset of the bits of a Node
|
|
707
|
+
* `ChildProcess` the viewer actually consumes — pid for the active-run
|
|
708
|
+
* snapshot, stdout/stderr for log capture, exit/error for finalize,
|
|
709
|
+
* kill for abort. Both `child_process` and Electron `utilityProcess`
|
|
710
|
+
* satisfy this via a thin adapter. */
|
|
711
|
+
interface ILaunchedProcess {
|
|
712
|
+
/** OS process id, or -1 if the spawn failed to produce one. */
|
|
713
|
+
readonly pid: number;
|
|
714
|
+
/** Captured stdout stream, or null when not piped. */
|
|
715
|
+
readonly stdout: Readable | null;
|
|
716
|
+
/** Captured stderr stream, or null when not piped. */
|
|
717
|
+
readonly stderr: Readable | null;
|
|
718
|
+
/** Register the exit handler. Called once when the process exits. */
|
|
719
|
+
onExit(cb: (code: number | null, signal: NodeJS.Signals | null) => void): void;
|
|
720
|
+
/** Register the spawn-error handler (e.g. bin not found). */
|
|
721
|
+
onError(cb: (err: Error) => void): void;
|
|
722
|
+
/** Terminate the process. Default signal SIGTERM. */
|
|
723
|
+
kill(signal?: NodeJS.Signals): void;
|
|
724
|
+
}
|
|
725
|
+
/** Everything the launcher needs to spawn one runner process. The caller
|
|
726
|
+
* (RunnerService) has already merged the environment and resolved the bin
|
|
727
|
+
* + argv from the `IRunnerAdapter`; the launcher only decides HOW to run
|
|
728
|
+
* it. Pure data — no behaviour. */
|
|
729
|
+
interface LaunchSpec {
|
|
730
|
+
/** Absolute path to the JS bin entry — `IRunnerAdapter.resolveBin()`. */
|
|
731
|
+
bin: string;
|
|
732
|
+
/** Argv to pass after the bin — `IRunnerAdapter.buildArgs(req)`. */
|
|
733
|
+
args: string[];
|
|
734
|
+
/** Fully-merged environment for the child. */
|
|
735
|
+
env: NodeJS.ProcessEnv;
|
|
736
|
+
/** Working directory — the workspace project root. */
|
|
737
|
+
cwd: string;
|
|
738
|
+
}
|
|
739
|
+
/** Spawns the runner JS under a Node-capable runtime. Injected into the
|
|
740
|
+
* viewer's RunnerService so the spawn mechanism (system Node vs Electron
|
|
741
|
+
* utilityProcess) is a deployment choice, not baked into the service. */
|
|
742
|
+
interface IProcessLauncher {
|
|
743
|
+
launch(spec: LaunchSpec): ILaunchedProcess;
|
|
744
|
+
}
|
|
745
|
+
|
|
278
746
|
/** Contents of `unotest/.viewer.lock`. Written by viewer-server on
|
|
279
747
|
* startup, removed on graceful shutdown. Stale detection: `process.kill(
|
|
280
748
|
* pid, 0)` throws ESRCH if PID is dead → lockfile is stale, safe to
|
|
@@ -289,32 +757,6 @@ interface LockFile {
|
|
|
289
757
|
startedAt: string;
|
|
290
758
|
}
|
|
291
759
|
|
|
292
|
-
/** Parsed scenario metadata from the mandatory header lines
|
|
293
|
-
* (per design-v0/decisions.md, "Test source format"):
|
|
294
|
-
*
|
|
295
|
-
* // id-<kebab-slug>
|
|
296
|
-
* // <human title>
|
|
297
|
-
* // #<6-hex-color>
|
|
298
|
-
* function test_<...>() { ... }
|
|
299
|
-
*
|
|
300
|
-
* All three lines are required; a file without a complete header is
|
|
301
|
-
* rejected by the discovery service as parse-error (no legacy fallback). */
|
|
302
|
-
interface ScenarioMeta {
|
|
303
|
-
/** Slug from `// id-<slug>`. Stable test identity across rename. */
|
|
304
|
-
id: string;
|
|
305
|
-
/** Human-readable title from `// <text>`. */
|
|
306
|
-
title: string;
|
|
307
|
-
/** Color identifier from `// #RRGGBB`. Used only in tab headers as a
|
|
308
|
-
* thin colored strip — NOT a status signal. */
|
|
309
|
-
color: string;
|
|
310
|
-
/** File stem relative to `unotest/e2e/`, dirs as slashes.
|
|
311
|
-
* Examples: `smoke-welcome`, `auth/signin-flow`.
|
|
312
|
-
* Source-of-truth identity for CLI invocations and tab keys. */
|
|
313
|
-
name: string;
|
|
314
|
-
/** Project-relative path to the source file. */
|
|
315
|
-
path: string;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
760
|
/** Helper file metadata. Helpers live in `unotest/e2e/_helpers/**` as
|
|
319
761
|
* `snake_case` functions (`signin_as`, `seed_user`, …). The runner
|
|
320
762
|
* auto-discovers them; no import system in scenarios. */
|
|
@@ -325,6 +767,152 @@ interface HelperMeta {
|
|
|
325
767
|
path: string;
|
|
326
768
|
}
|
|
327
769
|
|
|
770
|
+
/** Which kind of locator the in-page picker overlay should retarget to and
|
|
771
|
+
* what DSL snippet to emit on pick. `locator` → an interactive element →
|
|
772
|
+
* `click(<loc>)`; `text`/`visibility` → any named/interactive element →
|
|
773
|
+
* `assertText`/`assertVisible`. See docs/recoder/plan.md. */
|
|
774
|
+
type PickerMode = "locator" | "text" | "visibility";
|
|
775
|
+
interface DbgCommandStep {
|
|
776
|
+
id: string;
|
|
777
|
+
cmd: "step";
|
|
778
|
+
}
|
|
779
|
+
interface DbgCommandContinue {
|
|
780
|
+
id: string;
|
|
781
|
+
cmd: "continue";
|
|
782
|
+
}
|
|
783
|
+
interface DbgCommandPause {
|
|
784
|
+
id: string;
|
|
785
|
+
cmd: "pause";
|
|
786
|
+
}
|
|
787
|
+
interface DbgCommandSetBp {
|
|
788
|
+
id: string;
|
|
789
|
+
cmd: "set-bp";
|
|
790
|
+
line: number;
|
|
791
|
+
col: number;
|
|
792
|
+
}
|
|
793
|
+
interface DbgCommandClearBp {
|
|
794
|
+
id: string;
|
|
795
|
+
cmd: "clear-bp";
|
|
796
|
+
line: number;
|
|
797
|
+
col: number;
|
|
798
|
+
}
|
|
799
|
+
interface DbgCommandAbort {
|
|
800
|
+
id: string;
|
|
801
|
+
cmd: "abort";
|
|
802
|
+
}
|
|
803
|
+
/** Start (or, if already active, re-mode) the in-page picker on the live
|
|
804
|
+
* paused page. `execute=false` (default) is capture-only: clicks are
|
|
805
|
+
* swallowed, never run — picks just record a locator/assertion.
|
|
806
|
+
* `execute=true` turns the overlay into a Playwright-style recorder: real
|
|
807
|
+
* clicks / typing / selects RUN on the page and are recorded as DSL actions
|
|
808
|
+
* (`click`/`fill`/`press`/`selectOption`/`check`). In execute mode the
|
|
809
|
+
* `text`/`visibility` modes still record an assertion without running the
|
|
810
|
+
* click (swap mode to drop an assertion mid-flow). */
|
|
811
|
+
interface DbgCommandPickerStart {
|
|
812
|
+
id: string;
|
|
813
|
+
cmd: "picker:start";
|
|
814
|
+
mode: PickerMode;
|
|
815
|
+
execute?: boolean;
|
|
816
|
+
}
|
|
817
|
+
/** Tear down the picker overlay. */
|
|
818
|
+
interface DbgCommandPickerStop {
|
|
819
|
+
id: string;
|
|
820
|
+
cmd: "picker:stop";
|
|
821
|
+
}
|
|
822
|
+
/** On-demand: capture the current page outline (what the picker hit-tests
|
|
823
|
+
* against) and write it to `picker-snapshot.txt`. Lets the viewer's Snapshot
|
|
824
|
+
* tab show / refresh the snapshot without arming the picker. Cheap — runs
|
|
825
|
+
* only when the user opens/refreshes the tab (the outline is expensive on
|
|
826
|
+
* huge pages, so it is never captured on every pause). */
|
|
827
|
+
interface DbgCommandSnapshot {
|
|
828
|
+
id: string;
|
|
829
|
+
cmd: "snapshot";
|
|
830
|
+
}
|
|
831
|
+
/** The DSL line a recorded action / pick renders to. Mirrors the in-page
|
|
832
|
+
* recorder's verbs. `locator` → bare locator; `assertText`/`assertVisible`
|
|
833
|
+
* → assertions; the rest → Playwright-style actions. */
|
|
834
|
+
type RecordedActionKind = "locator" | "assertText" | "assertVisible" | "click" | "fill" | "press" | "selectOption" | "check" | "uncheck";
|
|
835
|
+
/** Agent-driven, ref-safe record (collaborative authoring). The agent picks
|
|
836
|
+
* an element by `ref` (from a snapshot of the SHARED page) + an action; the
|
|
837
|
+
* runner resolves `ref→locator` (`RefResolver`) and emits a `locator:picked`
|
|
838
|
+
* event the viewer inserts — so the agent NEVER hand-writes a locator. Same
|
|
839
|
+
* resolution/insertion pipeline as the human's in-page picker. */
|
|
840
|
+
interface DbgCommandRecord {
|
|
841
|
+
id: string;
|
|
842
|
+
cmd: "record";
|
|
843
|
+
ref: string;
|
|
844
|
+
action: RecordedActionKind;
|
|
845
|
+
/** Typed/selected value for `fill` / `selectOption`. */
|
|
846
|
+
value?: string;
|
|
847
|
+
/** Key for `press` (e.g. "Enter", "Control+A"). */
|
|
848
|
+
key?: string;
|
|
849
|
+
/** Expected text for `assertText` (else the element's textContent is used). */
|
|
850
|
+
text?: string;
|
|
851
|
+
/** Where the viewer drops the line. Default `append` (agent records a flow). */
|
|
852
|
+
placement?: "cursor" | "append";
|
|
853
|
+
}
|
|
854
|
+
/** Collaborative control token (Slice 3). Sets who may act on the shared
|
|
855
|
+
* page: `agent` lets the agent record; `human` (default) blocks the agent.
|
|
856
|
+
* Written by the viewer (Take control button) or the agent (take_wheel). */
|
|
857
|
+
interface DbgCommandWheel {
|
|
858
|
+
id: string;
|
|
859
|
+
cmd: "wheel";
|
|
860
|
+
owner: "agent" | "human";
|
|
861
|
+
}
|
|
862
|
+
/** Evaluate a DSL locator STRING against the live (paused or running) page and
|
|
863
|
+
* report what it matches — count, the N a trailing .first()/.last()/.nth()
|
|
864
|
+
* collapses, and per-match identity — via a `probe:result` event. The runner
|
|
865
|
+
* parses `locator` with the SAME DSL parser the agent's `check_locator` uses,
|
|
866
|
+
* so agent and human probe identically. READ-ONLY (never acts on the page),
|
|
867
|
+
* so it is intentionally NOT wheel-gated: any client may probe at any time. */
|
|
868
|
+
interface DbgCommandProbe {
|
|
869
|
+
id: string;
|
|
870
|
+
cmd: "probe";
|
|
871
|
+
/** Locator exactly as written in a test, e.g.
|
|
872
|
+
* getByRole('row').filter({hasText: 'Uma Quinn'}).first(). */
|
|
873
|
+
locator: string;
|
|
874
|
+
/** Cap on the number of match details returned (default 20). */
|
|
875
|
+
limit?: number;
|
|
876
|
+
}
|
|
877
|
+
type DbgCommand = DbgCommandStep | DbgCommandContinue | DbgCommandPause | DbgCommandSetBp | DbgCommandClearBp | DbgCommandAbort | DbgCommandPickerStart | DbgCommandPickerStop | DbgCommandSnapshot | DbgCommandRecord | DbgCommandWheel | DbgCommandProbe;
|
|
878
|
+
type DbgCommandKind = DbgCommand["cmd"];
|
|
879
|
+
|
|
880
|
+
interface ProbeMatch {
|
|
881
|
+
/** 0-based position among the locator's matches. */
|
|
882
|
+
index: number;
|
|
883
|
+
role?: string;
|
|
884
|
+
name?: string;
|
|
885
|
+
/** Trimmed/clipped textContent of the element. */
|
|
886
|
+
text?: string;
|
|
887
|
+
testId?: string;
|
|
888
|
+
href?: string;
|
|
889
|
+
/** Currently visible? Non-waiting check (a match can exist but be off-screen). */
|
|
890
|
+
visible: boolean;
|
|
891
|
+
}
|
|
892
|
+
interface ProbePinned {
|
|
893
|
+
/** The terminal index op that collapsed a multi-match to a single element. */
|
|
894
|
+
op: "first" | "last" | "nth";
|
|
895
|
+
/** How many elements the chain matched BEFORE the terminal op — i.e. how many
|
|
896
|
+
* the .first()/.last()/.nth() silently picked from. `ofCount > 1` flags an
|
|
897
|
+
* index op hiding ambiguity. */
|
|
898
|
+
ofCount: number;
|
|
899
|
+
}
|
|
900
|
+
interface ProbeResult {
|
|
901
|
+
/** Human-readable chain echo. NOT a selector. */
|
|
902
|
+
chain: string;
|
|
903
|
+
/** Elements the full chain matches. */
|
|
904
|
+
count: number;
|
|
905
|
+
/** Present only when the chain ends in first/last/nth. */
|
|
906
|
+
pinned?: ProbePinned;
|
|
907
|
+
/** Details of up to the requested limit of matches. */
|
|
908
|
+
matches: ProbeMatch[];
|
|
909
|
+
/** True count before truncation (equal to `count`). */
|
|
910
|
+
totalCount: number;
|
|
911
|
+
truncated: boolean;
|
|
912
|
+
/** Actionable hints: nothing matched, hidden ambiguity, truncation, stale ref. */
|
|
913
|
+
warnings: string[];
|
|
914
|
+
}
|
|
915
|
+
|
|
328
916
|
/** Terminal outcome reported by the runner via `run:finished`. */
|
|
329
917
|
type RunOutcome = "completed" | "failed" | "aborted" | "interrupted";
|
|
330
918
|
/** Scenario-level run-id. Format opaque to consumers; treat as string. */
|
|
@@ -427,6 +1015,27 @@ interface PausedEvent extends RunArtifactBase {
|
|
|
427
1015
|
}[];
|
|
428
1016
|
};
|
|
429
1017
|
}
|
|
1018
|
+
/** Emitted by the in-page locator picker / action recorder (debug-pause)
|
|
1019
|
+
* when the user picks an element or performs a recorded action. The runner
|
|
1020
|
+
* resolved the picked `ref` to a locator (`RefResolver`) and rendered the
|
|
1021
|
+
* DSL snippet. The viewer inserts `snippet` per `placement`.
|
|
1022
|
+
* See docs/recoder/plan.md. */
|
|
1023
|
+
interface LocatorPickedEvent extends RunArtifactBase {
|
|
1024
|
+
kind: "locator:picked";
|
|
1025
|
+
mode: PickerMode;
|
|
1026
|
+
/** Ready-to-insert DSL line, e.g. a bare locator
|
|
1027
|
+
* `getByRole("button", {name: "Sign in"})` (locator mode), an assertion
|
|
1028
|
+
* (`assertText(…)`), or a recorded action (`click(…)`, `fill(…)`). */
|
|
1029
|
+
snippet: string;
|
|
1030
|
+
/** Where the viewer drops the snippet:
|
|
1031
|
+
* - `cursor` — at the editor's caret (deliberate picks; user-placed).
|
|
1032
|
+
* - `append` — after the previous recorded line (execute-mode action
|
|
1033
|
+
* recorder, preserving order). */
|
|
1034
|
+
placement: "cursor" | "append";
|
|
1035
|
+
/** `stable` (testId / role+name / label / …) or `fragile` (css/nth-only).
|
|
1036
|
+
* Lets the viewer flag brittle picks. */
|
|
1037
|
+
stability: "stable" | "fragile";
|
|
1038
|
+
}
|
|
430
1039
|
/** Emitted when execution resumes after a `paused` event. The `by` field
|
|
431
1040
|
* records which debug command unblocked it — purely informational; the
|
|
432
1041
|
* next `step:started` event carries the actual line/col. */
|
|
@@ -434,8 +1043,55 @@ interface ResumedEvent extends RunArtifactBase {
|
|
|
434
1043
|
kind: "resumed";
|
|
435
1044
|
by: "step" | "continue";
|
|
436
1045
|
}
|
|
1046
|
+
/** Emitted when the collaborative control token changes owner (Slice 3), so
|
|
1047
|
+
* the viewer can live-update the "who's driving" badge over WS. */
|
|
1048
|
+
interface WheelChangedEvent extends RunArtifactBase {
|
|
1049
|
+
kind: "wheel:changed";
|
|
1050
|
+
owner: "agent" | "human";
|
|
1051
|
+
}
|
|
1052
|
+
/** Emitted in response to a `probe` debug command: the result of evaluating a
|
|
1053
|
+
* locator string against the live page. `id` echoes the command's id so the
|
|
1054
|
+
* client that issued the probe can correlate the reply. READ-ONLY — producing
|
|
1055
|
+
* it never changed the page. */
|
|
1056
|
+
interface ProbeResultEvent extends RunArtifactBase {
|
|
1057
|
+
kind: "probe:result";
|
|
1058
|
+
/** Correlates with the issuing `DbgCommandProbe.id`. */
|
|
1059
|
+
id: string;
|
|
1060
|
+
result: ProbeResult;
|
|
1061
|
+
}
|
|
1062
|
+
/** A single MCP tool invocation by the agent, surfaced into the session's
|
|
1063
|
+
* event stream so the human sees — in the viewer's System console — what the
|
|
1064
|
+
* agent called and how it ended. Emitted ONLY while the MCP server is attached
|
|
1065
|
+
* to this run (own-browser calls have no session to attach to). Paired:
|
|
1066
|
+
* `tool:call` at invocation, `tool:result` at completion, correlated by
|
|
1067
|
+
* `callId`. Read-only telemetry — emitting it never touches the page. */
|
|
1068
|
+
interface ToolCallEvent extends RunArtifactBase {
|
|
1069
|
+
kind: "tool:call";
|
|
1070
|
+
/** Correlates with the matching `tool:result` (one MCP call). */
|
|
1071
|
+
callId: string;
|
|
1072
|
+
/** MCP tool name, e.g. "check_locator", "explore_step". */
|
|
1073
|
+
tool: string;
|
|
1074
|
+
/** Arguments as a secret-redacted, length-capped JSON string — NOT the raw
|
|
1075
|
+
* object. Capped upstream so the line stays a single atomic append. */
|
|
1076
|
+
args: string;
|
|
1077
|
+
}
|
|
1078
|
+
interface ToolResultEvent extends RunArtifactBase {
|
|
1079
|
+
kind: "tool:result";
|
|
1080
|
+
/** Correlates with the issuing `ToolCallEvent.callId`. */
|
|
1081
|
+
callId: string;
|
|
1082
|
+
tool: string;
|
|
1083
|
+
ok: boolean;
|
|
1084
|
+
durationMs: number;
|
|
1085
|
+
/** Secret-redacted, length-capped preview of the result text. */
|
|
1086
|
+
preview: string;
|
|
1087
|
+
/** Present only when `ok` is false. */
|
|
1088
|
+
error?: {
|
|
1089
|
+
class: string;
|
|
1090
|
+
message: string;
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
437
1093
|
/** Discriminated union of every JSONL event the scenario runner emits. */
|
|
438
|
-
type RunArtifact = RunStartedEvent | StepStartedEvent | StepOkEvent | StepFailEvent | ScreenshotEvent | FailureBundleWrittenEvent | PausedEvent | ResumedEvent | RunFinishedEvent;
|
|
1094
|
+
type RunArtifact = RunStartedEvent | StepStartedEvent | StepOkEvent | StepFailEvent | ScreenshotEvent | FailureBundleWrittenEvent | PausedEvent | ResumedEvent | LocatorPickedEvent | WheelChangedEvent | ProbeResultEvent | ToolCallEvent | ToolResultEvent | RunFinishedEvent;
|
|
439
1095
|
interface CollectionRunStartedEvent extends RunArtifactBase {
|
|
440
1096
|
kind: "collection-run:started";
|
|
441
1097
|
runId: RunId;
|
|
@@ -584,37 +1240,6 @@ type TabKind = ScenarioTab | HelperTab | CollectionTab | ScenarioRunTab | Collec
|
|
|
584
1240
|
/** All tab `kind` literals — useful for switch-completeness checks. */
|
|
585
1241
|
type TabKindName = TabKind["kind"];
|
|
586
1242
|
|
|
587
|
-
interface DbgCommandStep {
|
|
588
|
-
id: string;
|
|
589
|
-
cmd: "step";
|
|
590
|
-
}
|
|
591
|
-
interface DbgCommandContinue {
|
|
592
|
-
id: string;
|
|
593
|
-
cmd: "continue";
|
|
594
|
-
}
|
|
595
|
-
interface DbgCommandPause {
|
|
596
|
-
id: string;
|
|
597
|
-
cmd: "pause";
|
|
598
|
-
}
|
|
599
|
-
interface DbgCommandSetBp {
|
|
600
|
-
id: string;
|
|
601
|
-
cmd: "set-bp";
|
|
602
|
-
line: number;
|
|
603
|
-
col: number;
|
|
604
|
-
}
|
|
605
|
-
interface DbgCommandClearBp {
|
|
606
|
-
id: string;
|
|
607
|
-
cmd: "clear-bp";
|
|
608
|
-
line: number;
|
|
609
|
-
col: number;
|
|
610
|
-
}
|
|
611
|
-
interface DbgCommandAbort {
|
|
612
|
-
id: string;
|
|
613
|
-
cmd: "abort";
|
|
614
|
-
}
|
|
615
|
-
type DbgCommand = DbgCommandStep | DbgCommandContinue | DbgCommandPause | DbgCommandSetBp | DbgCommandClearBp | DbgCommandAbort;
|
|
616
|
-
type DbgCommandKind = DbgCommand["cmd"];
|
|
617
|
-
|
|
618
1243
|
interface BreakpointEntry {
|
|
619
1244
|
line: number;
|
|
620
1245
|
col: number;
|
|
@@ -646,6 +1271,15 @@ interface EnvUpdate {
|
|
|
646
1271
|
}
|
|
647
1272
|
|
|
648
1273
|
type RuntimeState = "starting" | "running" | "paused-step" | "paused-failure" | "paused-breakpoint" | "completed" | "failed" | "aborted";
|
|
1274
|
+
/** The terminal run states — a runtime in any of these has FINISHED and is no
|
|
1275
|
+
* longer live / attachable. */
|
|
1276
|
+
declare const TERMINAL_RUNTIME_STATES: readonly ["completed", "failed", "aborted"];
|
|
1277
|
+
/** True when `state` is terminal (completed / failed / aborted): the run ended.
|
|
1278
|
+
* The single source of truth — every consumer (attach discovery, list_runtimes,
|
|
1279
|
+
* current-location, terminal handling) calls this instead of re-spelling the
|
|
1280
|
+
* literal set. Accepts a plain string so both `RuntimeState` and the runner's
|
|
1281
|
+
* own exec-state union pass without coupling. */
|
|
1282
|
+
declare function isTerminalRuntimeState(state: string): boolean;
|
|
649
1283
|
interface RuntimeStateFile {
|
|
650
1284
|
runId: string;
|
|
651
1285
|
scenario: string;
|
|
@@ -666,6 +1300,34 @@ interface RuntimeStateFile {
|
|
|
666
1300
|
file: string;
|
|
667
1301
|
line: number;
|
|
668
1302
|
}[];
|
|
1303
|
+
/** Collaborative control token (Slice 3). `human` (default) → the agent may
|
|
1304
|
+
* NOT act (record); `agent` → the agent holds the wheel and may record. The
|
|
1305
|
+
* human (host) is never blocked. Absent ⇒ `human`. */
|
|
1306
|
+
wheel?: "agent" | "human";
|
|
1307
|
+
/** Session mode (U3). `debug` (default) runs a test (executor + pauses);
|
|
1308
|
+
* `authoring` holds a live browser + draft open with NO running test — the
|
|
1309
|
+
* picker/record work on the live page, not a pause. Lets the viewer enable
|
|
1310
|
+
* authoring controls. Absent ⇒ `debug`. */
|
|
1311
|
+
mode?: "debug" | "authoring";
|
|
1312
|
+
/** Playwright `connect()` ws endpoint of the debug run's SHARED browser,
|
|
1313
|
+
* when launched in share mode (`--debug`). Lets a second client (the MCP
|
|
1314
|
+
* server / agent) attach to the SAME live browser the human is debugging.
|
|
1315
|
+
* Absent for non-shared (normal) runs. Localhost only. */
|
|
1316
|
+
wsEndpoint?: string;
|
|
1317
|
+
/** Active device slot of a mobile debug run (`--debug`) — the collaborative
|
|
1318
|
+
* attach handle for runners that drive a shared DEVICE instead of a browser
|
|
1319
|
+
* (the device's WDA is reachable by any client in the project). A second
|
|
1320
|
+
* client (the mobile MCP / agent) joins by targeting this slot + the run's
|
|
1321
|
+
* `commands.jsonl` wheel. Absent for non-debug runs and for browser runners
|
|
1322
|
+
* (which advertise `wsEndpoint` instead). */
|
|
1323
|
+
deviceSlot?: string;
|
|
1324
|
+
/** The run's ACTIVE breakpoints as `"line:col"` keys (0-based col) — the
|
|
1325
|
+
* union of `.debugger.json` for this scenario AND any ephemeral `--debug
|
|
1326
|
+
* --breakpoints` override the runner was started with. Published so the
|
|
1327
|
+
* viewer can paint glyph dots for breakpoints that aren't persisted in
|
|
1328
|
+
* `.debugger.json` (e.g. an agent's `run_test {breakpoints}` override).
|
|
1329
|
+
* Absent ⇒ none / not a debug run. */
|
|
1330
|
+
breakpoints?: string[];
|
|
669
1331
|
lastFailure: {
|
|
670
1332
|
line: number;
|
|
671
1333
|
col: number;
|
|
@@ -679,4 +1341,4 @@ interface RuntimeStateFile {
|
|
|
679
1341
|
updatedAt: number;
|
|
680
1342
|
}
|
|
681
1343
|
|
|
682
|
-
export { type BreakpointEntry, type BreakpointsFile, COLLECTIONS_SUBDIR, COLLECTION_NAME_FORBIDDEN_RE, COMMANDS_FILE, type CollectionMeta, type CollectionRunArtifact, type CollectionRunFinishedEvent, type CollectionRunRequest, type CollectionRunStartedEvent, type CollectionRunTab, type CollectionScenarioFinishedEvent, type CollectionScenarioStartedEvent, type CollectionTab,
|
|
1344
|
+
export { type AddVariablePlan, type AddVariablePlanInput, type AppPathPickerSpec, type AppServerEvent, type AuthoringRunRequest, type BreakpointEntry, type BreakpointsFile, COLLECTIONS_SUBDIR, COLLECTION_NAME_FORBIDDEN_RE, COMMANDS_FILE, type CheckSeverity, type CollectionMeta, type CollectionRunArtifact, type CollectionRunFinishedEvent, type CollectionRunRequest, type CollectionRunStartedEvent, type CollectionRunTab, type CollectionScenarioFinishedEvent, type CollectionScenarioStartedEvent, type CollectionTab, type DbgCommand, type DbgCommandAbort, type DbgCommandClearBp, type DbgCommandContinue, type DbgCommandKind, type DbgCommandPause, type DbgCommandPickerStart, type DbgCommandPickerStop, type DbgCommandProbe, type DbgCommandRecord, type DbgCommandSetBp, type DbgCommandSnapshot, type DbgCommandStep, type DbgCommandWheel, type DebugCapabilities, type DoctorCheck, type DoctorContext, type DslDiagnostic, type DslValidateContext, type DslVocabArg, type DslVocabCategory, type DslVocabEntry, E2E_SUBDIR, ENV_FILE, type EnvFile, type EnvUpdate, type EnvVar, type ErrorMessage, type FailureBundleWrittenEvent, type FsBreakpointsChangedMessage, type FsCollectionRunStepMessage, type FsCollectionsChangedMessage, type FsHelpersChangedMessage, type FsRunFinishedMessage, type FsRunStartedMessage, type FsRunStepMessage, type FsScenariosChangedMessage, HEARTBEAT_FILE, HELPERS_SUBDIR, type HelperMeta, type HelperTab, type HostRequirement, type IDslLanguageService, type ILaunchedProcess, type IProcessLauncher, type IRunnerAdapter, LOCK_FILE, LOG_FILE, type LaunchSpec, type LocatorPickedEvent, type LockFile, type LogLineMessage, type Matcher, PICKER_SNAPSHOT_FILE, type PausedEvent, type PickerMode, type ProbeMatch, type ProbePinned, type ProbeResult, type ProbeResultEvent, RUNNER_CONFIG_KEYS, RUNS_SUBDIR, RUNTIME_FILE, RUN_MANIFEST_FILE, RUN_SOURCES_FILE, type RecordedActionKind, type RegexLiteral, type ResumedEvent, type RunArtifact, type RunFinishedEvent, type RunId, type RunKind, type RunManifest, type RunMeta, type RunOutcome, type RunRequest, type RunSources, type RunStartedEvent, type RunStatus, RunnerAdapterNotFoundError, RunnerNotConfiguredError, type RuntimeState, type RuntimeStateFile, SECRETS_FILE, SEGMENT_NAME_FORBIDDEN_RE, STDERR_FILE, STDOUT_FILE, STEPS_FILE, type ScenarioMeta, type ScenarioRunRequest, type ScenarioRunTab, type ScenarioTab, type ScenariosPayload, type ScreenshotEvent, type StepFailEvent, type StepOkEvent, type StepStartedEvent, TERMINAL_RUNTIME_STATES, TERMINAL_WS_EVENT, type TabKind, type TabKindName, type TerminalClientMessage, type TerminalCloseMessage, type TerminalDataMessage, type TerminalErrorMessage, type TerminalExitMessage, type TerminalKind, type TerminalOutputMessage, type TerminalResizeMessage, type TerminalServerMessage, type TerminalSpawnMessage, type ToolCallEvent, type ToolResultEvent, UNOTEST_DIR, UnsupportedRunKindError, type VariableCategory, type VariableKind, type VariablePlanError, type WheelChangedEvent, type WsMessage, type WsMessageKind, activeEnvName, categorizeVariable, debugDirFor, debuggerFileFor, deleteShadowWarning, envFileFor, envKeys, envLayerFilesFor, insertEnvVar, isExternalVarName, isRegexLiteral, isRunnerConfigKey, isTerminalRuntimeState, makeRunId, parseAppServerEvent, parseEnvContent, planAddVariable, regexLiteral, removeEnvVar, runsDirFor, sanitizeRunIdSegment, secretsFileFor, secretsLayerFilesFor, serializeEnvValue, testDirFor, validateCollectionName, validateSegmentName };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var _0x4f4e3a=_0x3104;(function(_0x1eb34e,_0x3b8ea7){var _0x1068b4={_0x1e67da:0x20d,_0x5695a2:0x209,_0x4493a2:0x1f8},_0x52fa40=_0x3104,_0x3c2fd3=_0x1eb34e();while(!![]){try{var _0x3568d2=parseInt(_0x52fa40(0x1ec))/0x1*(-parseInt(_0x52fa40(0x1f7))/0x2)+-parseInt(_0x52fa40(0x202))/0x3+parseInt(_0x52fa40(_0x1068b4._0x1e67da))/0x4+parseInt(_0x52fa40(0x201))/0x5+parseInt(_0x52fa40(_0x1068b4._0x5695a2))/0x6*(-parseInt(_0x52fa40(_0x1068b4._0x4493a2))/0x7)+-parseInt(_0x52fa40(0x1f9))/0x8+parseInt(_0x52fa40(0x1f2))/0x9;if(_0x3568d2===_0x3b8ea7)break;else _0x3c2fd3['push'](_0x3c2fd3['shift']());}catch(_0x556852){_0x3c2fd3['push'](_0x3c2fd3['shift']());}}}(_0x3e22,0x3e42c));var __defProp=Object[_0x4f4e3a(0x1f5)],__name=(_0x1f300e,_0x2bde85)=>__defProp(_0x1f300e,_0x4f4e3a(0x1f3),{'value':_0x2bde85,'configurable':!![]}),UNOTEST_DIR=_0x4f4e3a(0x204),E2E_SUBDIR='e2e',HELPERS_SUBDIR=_0x4f4e3a(0x20a),COLLECTIONS_SUBDIR='_collections',RUNS_SUBDIR='.runs',LOCK_FILE='.viewer.lock',LOG_FILE='.viewer.log',STEPS_FILE=_0x4f4e3a(0x210),HEARTBEAT_FILE='heartbeat',STDOUT_FILE=_0x4f4e3a(0x1e4),STDERR_FILE=_0x4f4e3a(0x1ee),COMMANDS_FILE=_0x4f4e3a(0x20c),RUNTIME_FILE=_0x4f4e3a(0x1e1),DEBUGGER_FILE=_0x4f4e3a(0x1e5),ENV_FILE=_0x4f4e3a(0x1ef);function isRegexLiteral(_0x5925e4){var _0x6fc145={_0x2d4185:0x207,_0x4ff995:0x1fc,_0x62b82f:0x1e7},_0x536744=_0x4f4e3a;return typeof _0x5925e4===_0x536744(_0x6fc145._0x2d4185)&&_0x5925e4!==null&&_0x5925e4[_0x536744(0x1fa)]===_0x536744(0x208)&&typeof _0x5925e4['source']===_0x536744(_0x6fc145._0x4ff995)&&typeof _0x5925e4[_0x536744(_0x6fc145._0x62b82f)]===_0x536744(0x1fc);}__name(isRegexLiteral,'isRegexLiteral');function regexLiteral(_0x4d5e36,_0x4b70cd=''){return{'kind':'regex','source':_0x4d5e36,'flags':_0x4b70cd};}__name(regexLiteral,_0x4f4e3a(0x205));var RAND_BYTES=0x3;function makeRunId(_0x17406f){var _0x419ccf={_0x20a001:0x20f},_0x3b6caf=_0x4f4e3a;const _0x48b905=sanitizeRunIdSegment(_0x17406f),_0x2743c1=Date['now']()[_0x3b6caf(_0x419ccf._0x20a001)](0x24),_0x491065=new Uint8Array(RAND_BYTES);globalThis[_0x3b6caf(0x1e3)]['getRandomValues'](_0x491065);let _0x590971='';for(let _0x2680ff=0x0;_0x2680ff<_0x491065['length'];_0x2680ff++){_0x590971+=_0x491065[_0x2680ff][_0x3b6caf(_0x419ccf._0x20a001)](0x10)[_0x3b6caf(0x1ed)](0x2,'0');}return _0x48b905+'-'+_0x2743c1+'-'+_0x590971;}function _0x3e22(){var _0x3b86fc=['BwfRzvj1BKLK','DgvYBwLUywW','mZK1ntmYoxbjqwvXza','BMfTzq','iIbKB2vZig5VDcbZDxbWB3j0ihj1BIbRAw5Kici','zgvMAw5LuhjVCgvYDhK','BgvUz3rO','mLD4BMnmza','nZbMsfzcEfm','mteWmZq0mfvov2HJta','A2LUza','DgvZDa','C3rYAw5N','C2fUAxrPEMvsDw5jzfnLz21LBNq','DMfSAwrHDgvdB2XSzwn0Aw9UtMfTzq','BxvZDcbIzsbHihn0CMLUzW','uNvUBMvYtM90q29UzMLNDxjLzevYCM9Y','mJiZmZq3nxDOt2LKwG','odm1mZiWthfYB0fm','CMvWBgfJzq','Dw5VDgvZDa','CMvNzxHmAxrLCMfS','BxvZDcbUB3qGy29UDgfPBIbCic8GoIaQid8GiIa8id4GFcbVCIbJB250CM9SignOyxjHy3rLCNm','B2jQzwn0','CMvNzxG','mZy0mdjoBNbuqMW','x2HLBhbLCNm','C3rHCNrZv2L0Aa','y29TBwfUzhmUANnVBMW','mte4mtC4ohr5yKTzrq','vw5ZDxbWB3j0zwrsDw5lAw5KrxjYB3i','Dg9tDhjPBMC','C3rLChmUANnVBMW','CNvUDgLTzs5QC29U','iI4G','y3j5ChrV','C3rKB3v0lMXVzW','Dw5VDgvZDc8UzgvIDwDNzxiUANnVBG','CNvU','zMXHz3m','C291CMnLCY5QC29U','BxvZDcbUB3qGyMuGzw1WDhK','uNvUBMvYqwrHChrLCK5VDezVDw5KrxjYB3i','BxvZDcbUB3qGyMuGiI4Iig9YiciUlIi','ndq5ntyZz3z2zeTV','CgfKu3rHCNq','C3rKzxjYlMXVzW','Dw5VDgvZDc8Uzw52'];_0x3e22=function(){return _0x3b86fc;};return _0x3e22();}__name(makeRunId,_0x4f4e3a(0x1f0));function _0x3104(_0x32baaa,_0x47d54f){_0x32baaa=_0x32baaa-0x1e1;var _0x3e22b5=_0x3e22();var _0x310442=_0x3e22b5[_0x32baaa];if(_0x3104['VuSBMU']===undefined){var _0x3aa3ac=function(_0x5330f7){var _0xfa99eb='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x1f300e='',_0x2bde85='';for(var _0x5925e4=0x0,_0x4d5e36,_0x4b70cd,_0x17406f=0x0;_0x4b70cd=_0x5330f7['charAt'](_0x17406f++);~_0x4b70cd&&(_0x4d5e36=_0x5925e4%0x4?_0x4d5e36*0x40+_0x4b70cd:_0x4b70cd,_0x5925e4++%0x4)?_0x1f300e+=String['fromCharCode'](0xff&_0x4d5e36>>(-0x2*_0x5925e4&0x6)):0x0){_0x4b70cd=_0xfa99eb['indexOf'](_0x4b70cd);}for(var _0x48b905=0x0,_0x2743c1=_0x1f300e['length'];_0x48b905<_0x2743c1;_0x48b905++){_0x2bde85+='%'+('00'+_0x1f300e['charCodeAt'](_0x48b905)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2bde85);};_0x3104['SVnHrU']=_0x3aa3ac,_0x3104['AaeHBO']={},_0x3104['VuSBMU']=!![];}var _0x7aba37=_0x3e22b5[0x0],_0x43b91a=_0x32baaa+_0x7aba37,_0x56bb48=_0x3104['AaeHBO'][_0x43b91a];return!_0x56bb48?(_0x310442=_0x3104['SVnHrU'](_0x310442),_0x3104['AaeHBO'][_0x43b91a]=_0x310442):_0x310442=_0x56bb48,_0x310442;}function sanitizeRunIdSegment(_0x3b310c){var _0x52fa43={_0x1eae77:0x203},_0x51e659=_0x4f4e3a;const _0x51667b=_0x3b310c['replace'](/[^a-zA-Z0-9_-]+/g,'-')[_0x51e659(_0x52fa43._0x1eae77)](/-+/g,'-')['replace'](/^-|-$/g,'');return _0x51667b['length']>0x0?_0x51667b:_0x51e659(0x1e6);}__name(sanitizeRunIdSegment,_0x4f4e3a(0x1fd));var COLLECTION_NAME_FORBIDDEN_RE=/[\\/:*?"<>|\x00-\x1f]/;function validateCollectionName(_0x9a1d82){var _0x51caec={_0x209a67:0x1e9,_0x46236c:0x1fb},_0x457e19=_0x4f4e3a;if(typeof _0x9a1d82!=='string')return _0x457e19(0x1ff);const _0x3912c4=_0x9a1d82['trim']();if(_0x3912c4[_0x457e19(0x1f6)]===0x0)return _0x457e19(_0x51caec._0x209a67);if(_0x3912c4==='.'||_0x3912c4==='..')return _0x457e19(0x1eb);if(_0x3912c4[_0x457e19(0x20b)]('.'))return'must\x20not\x20start\x20with\x20\x27.\x27';if(COLLECTION_NAME_FORBIDDEN_RE[_0x457e19(_0x51caec._0x46236c)](_0x3912c4))return _0x457e19(0x206);return null;}__name(validateCollectionName,_0x4f4e3a(0x1fe));var RUN_MANIFEST_FILE='manifest.json',RUN_SOURCES_FILE=_0x4f4e3a(0x1e8),UnsupportedRunKindError=class extends Error{static{__name(this,_0x4f4e3a(0x20e));}constructor(_0xf013ac,_0x19b4a5){var _0x35b3dd={_0x29a67a:0x20e},_0x49d706=_0x4f4e3a;super('runner\x20\x22'+_0x19b4a5+_0x49d706(0x1f4)+_0xf013ac+'\x22'),this[_0x49d706(0x1f3)]=_0x49d706(_0x35b3dd._0x29a67a);}},RunnerAdapterNotFoundError=class extends Error{static{__name(this,_0x4f4e3a(0x1ea));}constructor(_0x58d94b,_0x5ecedd){var _0x523fbe={_0x489149:0x1e2},_0x22eb67=_0x4f4e3a;super('cannot\x20load\x20runner\x20adapter\x20\x22'+_0x58d94b+_0x22eb67(_0x523fbe._0x489149)+_0x5ecedd),this['name']=_0x22eb67(0x1ea);}},RunnerNotConfiguredError=class extends Error{static{__name(this,_0x4f4e3a(0x200));}constructor(_0x4ef503){var _0x1ababb={_0x5bc125:0x200},_0x4c4f88=_0x4f4e3a;super(_0x4ef503),this[_0x4c4f88(0x1f3)]=_0x4c4f88(_0x1ababb._0x5bc125);}},TERMINAL_WS_EVENT=_0x4f4e3a(0x1f1);export{COLLECTIONS_SUBDIR,COLLECTION_NAME_FORBIDDEN_RE,COMMANDS_FILE,DEBUGGER_FILE,E2E_SUBDIR,ENV_FILE,HEARTBEAT_FILE,HELPERS_SUBDIR,LOCK_FILE,LOG_FILE,RUNS_SUBDIR,RUNTIME_FILE,RUN_MANIFEST_FILE,RUN_SOURCES_FILE,RunnerAdapterNotFoundError,RunnerNotConfiguredError,STDERR_FILE,STDOUT_FILE,STEPS_FILE,TERMINAL_WS_EVENT,UNOTEST_DIR,UnsupportedRunKindError,isRegexLiteral,makeRunId,regexLiteral,sanitizeRunIdSegment,validateCollectionName};
|
|
1
|
+
const _0x28d146=_0x4e2f;(function(_0xc46330,_0x4286ef){const _0x5df0fc={_0x234001:0x207,_0x4c4d4b:0x1d2,_0x2d6868:0x213,_0x2854f9:0x239,_0x3b467b:0x243},_0x3b0098=_0x4e2f,_0x5af7f9=_0xc46330();while(!![]){try{const _0x34528f=parseInt(_0x3b0098(_0x5df0fc._0x234001))/0x1+-parseInt(_0x3b0098(_0x5df0fc._0x4c4d4b))/0x2+-parseInt(_0x3b0098(_0x5df0fc._0x2d6868))/0x3*(parseInt(_0x3b0098(_0x5df0fc._0x2854f9))/0x4)+parseInt(_0x3b0098(0x22a))/0x5*(-parseInt(_0x3b0098(_0x5df0fc._0x3b467b))/0x6)+parseInt(_0x3b0098(0x1f8))/0x7+parseInt(_0x3b0098(0x219))/0x8*(parseInt(_0x3b0098(0x1ca))/0x9)+parseInt(_0x3b0098(0x1cf))/0xa*(parseInt(_0x3b0098(0x1f6))/0xb);if(_0x34528f===_0x4286ef)break;else _0x5af7f9['push'](_0x5af7f9['shift']());}catch(_0x526f3c){_0x5af7f9['push'](_0x5af7f9['shift']());}}}(_0x21b2,0x7abb4));var __defProp=Object['defineProperty'],__name=(_0x35127a,_0x403ef7)=>__defProp(_0x35127a,_0x28d146(0x1fd),{'value':_0x403ef7,'configurable':!![]});function parseAppServerEvent(_0x1f4ef1){const _0x23a96e={_0x305ae3:0x224,_0x1e3609:0x218,_0x5501e9:0x1cd,_0x26d303:0x22b},_0x1cfb0d=_0x28d146,_0x444b4d=_0x1f4ef1[_0x1cfb0d(_0x23a96e._0x305ae3)]();if(!_0x444b4d[_0x1cfb0d(0x1f5)]('{'))return null;try{const _0x27b771=JSON[_0x1cfb0d(0x1fc)](_0x444b4d);if(_0x27b771['kind']===_0x1cfb0d(_0x23a96e._0x1e3609)||_0x27b771[_0x1cfb0d(0x22b)]===_0x1cfb0d(_0x23a96e._0x5501e9)||_0x27b771[_0x1cfb0d(_0x23a96e._0x26d303)]==='app-server:error')return _0x27b771;return null;}catch{return null;}}__name(parseAppServerEvent,_0x28d146(0x21d));var UNOTEST_DIR='unotest',E2E_SUBDIR=_0x28d146(0x244),HELPERS_SUBDIR=_0x28d146(0x214),COLLECTIONS_SUBDIR=_0x28d146(0x1fa),RUNS_SUBDIR=_0x28d146(0x1d9);function testDirFor(_0x33cb3e){return''+E2E_SUBDIR+_0x33cb3e;}__name(testDirFor,_0x28d146(0x231));function runsDirFor(_0x24f868){return''+RUNS_SUBDIR+_0x24f868;}__name(runsDirFor,_0x28d146(0x1e2));function debugDirFor(_0x502f51){return'.debug'+_0x502f51;}__name(debugDirFor,_0x28d146(0x216));function debuggerFileFor(_0xa05769){return UNOTEST_DIR+'/.debugger'+_0xa05769+'.json';}__name(debuggerFileFor,_0x28d146(0x20a));var LOCK_FILE=_0x28d146(0x235),LOG_FILE=_0x28d146(0x22e),STEPS_FILE=_0x28d146(0x238),HEARTBEAT_FILE=_0x28d146(0x228),STDOUT_FILE='stdout.log',STDERR_FILE='stderr.log',COMMANDS_FILE=_0x28d146(0x1f3),RUNTIME_FILE='runtime.json',PICKER_SNAPSHOT_FILE=_0x28d146(0x20c),ENV_FILE=_0x28d146(0x1ea),SECRETS_FILE=_0x28d146(0x23b);function envFileFor(_0x1d6d12,_0x58e25a){return''+ENV_FILE+_0x1d6d12+(_0x58e25a?'.'+_0x58e25a:'');}__name(envFileFor,_0x28d146(0x1f7));function secretsFileFor(_0x15c0ad,_0x216aef){return''+SECRETS_FILE+_0x15c0ad+(_0x216aef?'.'+_0x216aef:'');}__name(secretsFileFor,'secretsFileFor');function envLayerFilesFor(_0x3b2b67,_0x56cd4d){return layersFor(ENV_FILE,_0x3b2b67,_0x56cd4d);}__name(envLayerFilesFor,_0x28d146(0x23a));function secretsLayerFilesFor(_0x2d225f,_0x3625ae){return layersFor(SECRETS_FILE,_0x2d225f,_0x3625ae);}__name(secretsLayerFilesFor,'secretsLayerFilesFor');function layersFor(_0x274b4f,_0x907ee3,_0xe73cb7){const _0x171b76={_0x2551b1:0x1eb,_0x38c3d3:0x1eb},_0x5992f0=_0x28d146,_0x29b210=[_0x274b4f];if(_0x907ee3)_0x29b210[_0x5992f0(_0x171b76._0x2551b1)](''+_0x274b4f+_0x907ee3);if(_0xe73cb7){_0x29b210[_0x5992f0(_0x171b76._0x38c3d3)](_0x274b4f+'.'+_0xe73cb7);if(_0x907ee3)_0x29b210['push'](''+_0x274b4f+_0x907ee3+'.'+_0xe73cb7);}return _0x29b210;}__name(layersFor,_0x28d146(0x229));function activeEnvName(_0x831153){const _0x268400=_0x28d146,_0x5ece43=_0x831153[_0x268400(0x200)]?.['trim']();return _0x5ece43?_0x5ece43:void 0x0;}__name(activeEnvName,_0x28d146(0x1df));function isRegexLiteral(_0x3c9b0e){const _0x3acd05={_0x1d4a56:0x22b,_0x3d5dcf:0x1f9},_0x43c974=_0x28d146;return typeof _0x3c9b0e==='object'&&_0x3c9b0e!==null&&_0x3c9b0e[_0x43c974(_0x3acd05._0x1d4a56)]===_0x43c974(_0x3acd05._0x3d5dcf)&&typeof _0x3c9b0e[_0x43c974(0x246)]===_0x43c974(0x21c)&&typeof _0x3c9b0e['flags']==='string';}__name(isRegexLiteral,_0x28d146(0x223));function regexLiteral(_0x180b7a,_0x1ba283=''){const _0x40d837=_0x28d146;return{'kind':_0x40d837(0x1f9),'source':_0x180b7a,'flags':_0x1ba283};}__name(regexLiteral,_0x28d146(0x241));var RAND_BYTES=0x3;function makeRunId(_0x1c08d8){const _0x32e198={_0x437e0a:0x23d,_0x5ad211:0x249,_0x57c034:0x242,_0x15b2f0:0x1e9},_0x3e0cbe=_0x28d146,_0x140159=sanitizeRunIdSegment(_0x1c08d8),_0x6c47b7=Date['now']()['toString'](0x24),_0x3fcf79=new Uint8Array(RAND_BYTES);globalThis[_0x3e0cbe(_0x32e198._0x437e0a)][_0x3e0cbe(0x245)](_0x3fcf79);let _0x104af8='';for(let _0x5002ec=0x0;_0x5002ec<_0x3fcf79[_0x3e0cbe(_0x32e198._0x5ad211)];_0x5002ec++){_0x104af8+=_0x3fcf79[_0x5002ec][_0x3e0cbe(_0x32e198._0x57c034)](0x10)[_0x3e0cbe(_0x32e198._0x15b2f0)](0x2,'0');}return _0x140159+'-'+_0x6c47b7+'-'+_0x104af8;}__name(makeRunId,_0x28d146(0x1d3));function sanitizeRunIdSegment(_0x14c01f){const _0xeec5cc={_0x649591:0x217,_0x50c4f9:0x217},_0x30ba74=_0x28d146,_0x4c35e6=_0x14c01f[_0x30ba74(_0xeec5cc._0x649591)](/[^a-zA-Z0-9_-]+/g,'-')[_0x30ba74(0x217)](/-+/g,'-')[_0x30ba74(_0xeec5cc._0x50c4f9)](/^-|-$/g,'');return _0x4c35e6['length']>0x0?_0x4c35e6:'run';}__name(sanitizeRunIdSegment,_0x28d146(0x1e1));var COLLECTION_NAME_FORBIDDEN_RE=/[\\/:*?"<>|\x00-\x1f]/;function validateCollectionName(_0x2e2c35){const _0x66ddc5={_0x1d52c2:0x201,_0x1ad331:0x1d1,_0x3f59f1:0x1f5,_0x41fdbe:0x24a},_0x23d0da=_0x28d146;if(typeof _0x2e2c35!==_0x23d0da(0x21c))return'must\x20be\x20a\x20string';const _0x56967b=_0x2e2c35[_0x23d0da(0x224)]();if(_0x56967b[_0x23d0da(0x249)]===0x0)return _0x23d0da(_0x66ddc5._0x1d52c2);if(_0x56967b==='.'||_0x56967b==='..')return _0x23d0da(_0x66ddc5._0x1ad331);if(_0x56967b[_0x23d0da(_0x66ddc5._0x3f59f1)]('.'))return _0x23d0da(0x220);if(COLLECTION_NAME_FORBIDDEN_RE[_0x23d0da(_0x66ddc5._0x41fdbe)](_0x56967b))return _0x23d0da(0x210);return null;}__name(validateCollectionName,_0x28d146(0x1ee));var RUN_MANIFEST_FILE=_0x28d146(0x1f0),RUN_SOURCES_FILE=_0x28d146(0x227),UnsupportedRunKindError=class extends Error{static{__name(this,_0x28d146(0x1de));}constructor(_0x4b44dd,_0x3c0adf){const _0x28222d={_0x2e7dec:0x1fe,_0x4da540:0x1de},_0x5c4c81=_0x28d146;super(_0x5c4c81(0x1d5)+_0x3c0adf+_0x5c4c81(_0x28222d._0x2e7dec)+_0x4b44dd+'\x22'),this['name']=_0x5c4c81(_0x28222d._0x4da540);}},RunnerAdapterNotFoundError=class extends Error{static{__name(this,'RunnerAdapterNotFoundError');}constructor(_0x2634db,_0x3327ff){const _0xaa3cd9={_0x461e76:0x1da},_0x1d195f=_0x28d146;super(_0x1d195f(0x1e8)+_0x2634db+_0x1d195f(0x222)+_0x3327ff),this['name']=_0x1d195f(_0xaa3cd9._0x461e76);}},RunnerNotConfiguredError=class extends Error{static{__name(this,'RunnerNotConfiguredError');}constructor(_0x6b5c62){const _0x412223={_0x4220ee:0x1d7},_0x3a61e5=_0x28d146;super(_0x6b5c62),this[_0x3a61e5(0x1fd)]=_0x3a61e5(_0x412223._0x4220ee);}},SEGMENT_NAME_FORBIDDEN_RE=/[\\/:*?"<>|\x00-\x1f]/;function validateSegmentName(_0x33d05b){const _0x1886fe={_0x18ada4:0x201,_0x4df6b0:0x1f5,_0xcd131d:0x1f5,_0x1e3b5d:0x215,_0x48fdaf:0x210},_0x5e49fe=_0x28d146;if(typeof _0x33d05b!==_0x5e49fe(0x21c))return _0x5e49fe(0x20f);const _0x3da06b=_0x33d05b['trim']();if(_0x3da06b[_0x5e49fe(0x249)]===0x0)return _0x5e49fe(_0x1886fe._0x18ada4);if(_0x3da06b==='.'||_0x3da06b==='..')return'must\x20not\x20be\x20\x22.\x22\x20or\x20\x22..\x22';if(_0x3da06b[_0x5e49fe(_0x1886fe._0x4df6b0)]('.'))return'must\x20not\x20start\x20with\x20\x27.\x27';if(_0x3da06b[_0x5e49fe(_0x1886fe._0xcd131d)]('_'))return _0x5e49fe(_0x1886fe._0x1e3b5d);if(SEGMENT_NAME_FORBIDDEN_RE['test'](_0x3da06b))return _0x5e49fe(_0x1886fe._0x48fdaf);return null;}__name(validateSegmentName,'validateSegmentName');var TERMINAL_WS_EVENT=_0x28d146(0x1e7),RUNNER_CONFIG_KEYS=new Set([_0x28d146(0x1fb),'UNOTEST_HEADED',_0x28d146(0x205),_0x28d146(0x236),_0x28d146(0x1ed),_0x28d146(0x1db),_0x28d146(0x233),_0x28d146(0x206),'UNOTEST_LOG_LEVEL',_0x28d146(0x247),_0x28d146(0x1e3),'UNOTEST_DEBUG_MAX_BYTES',_0x28d146(0x21b),_0x28d146(0x1dd),_0x28d146(0x1dc),'UNOTEST_NETWORK',_0x28d146(0x20d),_0x28d146(0x203),_0x28d146(0x20e),_0x28d146(0x1ce),_0x28d146(0x226)]);function isRunnerConfigKey(_0x21673b){const _0x481ce5={_0x40b7f6:0x225},_0x5f120d=_0x28d146;return RUNNER_CONFIG_KEYS[_0x5f120d(_0x481ce5._0x40b7f6)](_0x21673b);}__name(isRunnerConfigKey,_0x28d146(0x208));function categorizeVariable(_0x34db5a){const _0x46f944={_0x316c76:0x248},_0x535a58=_0x28d146;if(_0x34db5a[_0x535a58(0x246)]==='secrets')return _0x535a58(0x240);return isRunnerConfigKey(_0x34db5a[_0x535a58(0x1fd)])?_0x535a58(_0x46f944._0x316c76):'app';}__name(categorizeVariable,_0x28d146(0x1ec));function isExternalVarName(_0x448962){const _0x558d34={_0x1cd59a:0x24a},_0x1700fa=_0x28d146;return/^[A-Z][A-Z0-9_]*$/[_0x1700fa(_0x558d34._0x1cd59a)](_0x448962);}__name(isExternalVarName,_0x28d146(0x1e4));function parseEnvContent(_0x1fed3e){const _0x486972={_0x13541d:0x202,_0x2448b0:0x224,_0x8b0a2f:0x24a,_0x4ee773:0x249},_0x4cf0d0=_0x28d146,_0x150d4d={};for(const _0x2407d3 of _0x1fed3e[_0x4cf0d0(0x1e5)](/\r?\n/)){const _0x31382e=_0x2407d3[_0x4cf0d0(0x224)]();if(_0x31382e===''||_0x31382e[_0x4cf0d0(0x1f5)]('#'))continue;const _0x3e2a14=_0x31382e[_0x4cf0d0(0x1f4)]('=');if(_0x3e2a14<=0x0)continue;const _0x51b339=_0x31382e[_0x4cf0d0(_0x486972._0x13541d)](0x0,_0x3e2a14)[_0x4cf0d0(_0x486972._0x2448b0)]();if(!/^[A-Za-z_][A-Za-z0-9_]*$/[_0x4cf0d0(_0x486972._0x8b0a2f)](_0x51b339))continue;let _0x119fec=_0x31382e[_0x4cf0d0(0x202)](_0x3e2a14+0x1)[_0x4cf0d0(_0x486972._0x2448b0)]();if(_0x119fec[_0x4cf0d0(0x249)]>=0x2){const _0x4652aa=_0x119fec[0x0],_0x5dc471=_0x119fec[_0x119fec[_0x4cf0d0(_0x486972._0x4ee773)]-0x1];(_0x4652aa==='\x22'||_0x4652aa==='\x27')&&_0x4652aa===_0x5dc471&&(_0x119fec=_0x119fec[_0x4cf0d0(_0x486972._0x13541d)](0x1,-0x1));}_0x150d4d[_0x51b339]=_0x119fec;}return _0x150d4d;}__name(parseEnvContent,'parseEnvContent');function serializeEnvValue(_0x4b64ec){const _0x56cb9e={_0x3e5bb7:0x217},_0x1f6c5e=_0x28d146;if(_0x4b64ec==='')return'';if(/[\s#"'=\\]|^[`]/[_0x1f6c5e(0x24a)](_0x4b64ec)||/[\n\r]/[_0x1f6c5e(0x24a)](_0x4b64ec)){const _0x314d9b=_0x4b64ec[_0x1f6c5e(_0x56cb9e._0x3e5bb7)](/\\/g,'\x5c\x5c')[_0x1f6c5e(0x217)](/"/g,'\x5c\x22')[_0x1f6c5e(0x217)](/\n/g,'\x5cn')['replace'](/\r/g,'\x5cr');return'\x22'+_0x314d9b+'\x22';}return _0x4b64ec;}__name(serializeEnvValue,_0x28d146(0x1d4));function envKeys(_0x6c6ea8){const _0x178057={_0x21ba39:0x1e5,_0x4c7f40:0x1f5,_0x5f3f05:0x1f4,_0x55720b:0x202},_0x26b538=_0x28d146,_0x43bfee=new Set();for(const _0x56ffa5 of _0x6c6ea8[_0x26b538(_0x178057._0x21ba39)](/\r?\n/)){const _0x26fa46=_0x56ffa5['trim']();if(_0x26fa46===''||_0x26fa46[_0x26b538(_0x178057._0x4c7f40)]('#'))continue;const _0x14b0f2=_0x26fa46[_0x26b538(_0x178057._0x5f3f05)]('=');if(_0x14b0f2<=0x0)continue;const _0x42bb09=_0x26fa46[_0x26b538(_0x178057._0x55720b)](0x0,_0x14b0f2)[_0x26b538(0x224)]();if(/^[A-Za-z_][A-Za-z0-9_]*$/[_0x26b538(0x24a)](_0x42bb09))_0x43bfee[_0x26b538(0x23c)](_0x42bb09);}return _0x43bfee;}__name(envKeys,_0x28d146(0x211));function isSectionDivider(_0x1ef431){const _0xc56479={_0x5d992e:0x1f5},_0x2f1862=_0x28d146,_0x340cd5=_0x1ef431['trim']();return _0x340cd5[_0x2f1862(_0xc56479._0x5d992e)]('#')&&/---/[_0x2f1862(0x24a)](_0x340cd5);}__name(isSectionDivider,_0x28d146(0x23f));function isAssignmentLine(_0x236ff6){const _0x55c1aa={_0x24912f:0x1f4,_0x43b1eb:0x224},_0x2ae097=_0x28d146,_0x536d39=_0x236ff6['trim']();if(_0x536d39===''||_0x536d39[_0x2ae097(0x1f5)]('#'))return![];const _0x56d163=_0x536d39[_0x2ae097(_0x55c1aa._0x24912f)]('=');return _0x56d163>0x0&&/^[A-Za-z_][A-Za-z0-9_]*$/[_0x2ae097(0x24a)](_0x536d39['slice'](0x0,_0x56d163)[_0x2ae097(_0x55c1aa._0x43b1eb)]());}__name(isAssignmentLine,_0x28d146(0x1d8));function isAssignmentOf(_0xe9c4c9,_0x2316d5){const _0x584e07={_0x338708:0x224,_0x4e2dc:0x1f4,_0x156643:0x202},_0x54dd4d=_0x28d146,_0x118202=_0xe9c4c9[_0x54dd4d(_0x584e07._0x338708)]();if(_0x118202===''||_0x118202[_0x54dd4d(0x1f5)]('#'))return![];const _0x4948c9=_0x118202[_0x54dd4d(_0x584e07._0x4e2dc)]('=');if(_0x4948c9<=0x0)return![];return _0x118202[_0x54dd4d(_0x584e07._0x156643)](0x0,_0x4948c9)[_0x54dd4d(0x224)]()===_0x2316d5;}__name(isAssignmentOf,_0x28d146(0x21e));function splitLines(_0x49335b){const _0x2d3419={_0x110574:0x232,_0x21b616:0x1e5},_0x25e9ba=_0x28d146,_0x5a77e5=_0x49335b[_0x25e9ba(_0x2d3419._0x110574)]('\x0a'),_0x55ae79=_0x5a77e5?_0x49335b[_0x25e9ba(0x202)](0x0,-0x1):_0x49335b;return{'lines':_0x55ae79===''?[]:_0x55ae79[_0x25e9ba(_0x2d3419._0x21b616)]('\x0a'),'trailingNewline':_0x5a77e5};}__name(splitLines,_0x28d146(0x237));function joinLines(_0x19b5bb,_0x3b71cc){const _0x2ce829={_0x153d77:0x22c},_0x4f450d=_0x28d146,_0x47e96a=_0x19b5bb[_0x4f450d(_0x2ce829._0x153d77)]('\x0a');return _0x3b71cc||_0x47e96a===''?_0x47e96a+'\x0a':_0x47e96a;}__name(joinLines,_0x28d146(0x1cb));function _0x21b2(){const _0x2b74c9=['Aw52ywXPzc1Uyw1L','uNvUBMvYtM90q29UzMLNDxjLzevYCM9Y','AxnbC3nPz25Tzw50tgLUzq','lNj1BNm','uNvUBMvYqwrHChrLCK5VDezVDw5KrxjYB3i','vu5pvevtvf9qt1bvuf9huKfdrv9nuW','vu5pvevtvf9erujvr19lruvqx0nbteXt','vu5pvevtvf9erujvr19ive1mx01bwf9cwvrfuW','vw5ZDxbWB3j0zwrsDw5lAw5KrxjYB3i','ywn0AxzLrw52tMfTzq','zw52q29UDgvUDa','C2fUAxrPEMvsDw5jzfnLz21LBNq','CNvUC0rPCKzVCG','vu5pvevtvf9erujvr19esvi','AxnfEhrLCM5HBfzHCK5HBwu','C3bSAxq','AxnuzxjTAw5HBfj1BNrPBwvtDgf0zq','DgvYBwLUywW','y2fUBM90igXVywqGCNvUBMvYigfKyxb0zxiGiG','CgfKu3rHCNq','Dw5VDgvZDc8Uzw52','ChvZAa','y2f0zwDVCML6zvzHCMLHyMXL','vu5pvevtvf9eruzbvuXux05bvKLhqvrjt05FveLnru9vvf9nuW','DMfSAwrHDgvdB2XSzwn0Aw9UtMfTzq','igLZigfSC28GC2v0igLUihLVDxiGC2HLBgWGzw52AxjVBM1LBNqG4OcuigL0ihDPBgWGA2vLCcbYzxnVBhzPBMCGzNjVBsb0AgvYzsaODgHLigvUDMLYB25Tzw50ihDPBNmGB3zLCIb0AguGzMLSzsKU','BwfUAwzLC3qUANnVBG','zMLUzeLUzgv4','ic0Tlq','y29TBwfUzhmUANnVBMW','Aw5KzxHpzG','C3rHCNrZv2L0Aa','mJuYntaXn096Bg9jCq','zw52rMLSzuzVCG','mtK3odC2vgrfyMn5','CMvNzxG','x2nVBgXLy3rPB25Z','vu5pvevtvf9cuK9xu0vs','CgfYC2u','BMfTzq','iIbKB2vZig5VDcbZDxbWB3j0ihj1BIbRAw5Kici','zgvSzxrLu2HHzg93v2fYBMLUzW','vu5pvevtvf9ftLy','BxvZDcbUB3qGyMuGzw1WDhK','C2XPy2u','vu5pvevtvf9dqunirv9esvi','iYaTls0G','vu5pvevtvf9tte9xx01p','vu5pvevtvf9usu1fwK9orq','nZG5odfpAg1YBg8','AxnsDw5UzxjdB25MAwDlzxK','Dw5RBM93BI1YDw5UzxiTA2v5','zgvIDwDNzxjgAwXLrM9Y','qxbW','CgLJA2vYlxnUyxbZAg90lNr4Da','vu5pvevtvf9dt05tt0Xf','tK9Fq09mt1i','BxvZDcbIzsbHihn0CMLUzW','BxvZDcbUB3qGy29UDgfPBIbCic8GoIaQid8GiIa8id4GFcbVCIbJB250CM9SignOyxjHy3rLCNm','zw52s2v5CW','Aw5JBhvKzxm','oteWmKfrwMndCW','x2HLBhbLCNm','BxvZDcbUB3qGC3rHCNqGD2L0AcaNxYCGkhjLC2vYDMvKkq','zgvIDwDeAxjgB3i','CMvWBgfJzq','yxbWlxnLCNzLCJPYzwfKEq','mZjJzMDhseG','igLZig5VDcbHigTUB3DUihj1BM5LCIbZzxr0Aw5NiokaLcbJAg9VC2uGB25LigzYB20GDgHLihj1BM5LCI1JB25MAwCGBgLZDc4','vu5pvevtvf9erujvr19quKvwsuvxx0jzvevt','C3rYAw5N','CgfYC2vbChbtzxj2zxjfDMvUDa','AxnbC3nPz25Tzw50t2y','igfSCMvHzhKGzxHPC3rZigLUia','BxvZDcbUB3qGC3rHCNqGD2L0AcaNlIC','C2vJCMv0C0nVBNrLBNq','iI4G','AxnszwDLEeXPDgvYywW','DhjPBq','AgfZ','refuqujbu0vFvvjm','C291CMnLCY5QC29U','AgvHCNrIzwf0','Bgf5zxjZrM9Y','mtvMCg1MDfy','A2LUza','AM9PBG','CgXHBKfKzfzHCMLHyMXL','lNzPzxDLCI5SB2C','C2vJCMv0CW','Dg9mB3DLCKnHC2u','DgvZDerPCKzVCG','zw5KC1DPDgG','vu5pvevtvf9mt0nbteu','C3bSAwnL','lNzPzxDLCI5SB2nR','vu5pvevtvf9eruzbvuXux1rjtuvpvvrFtvm','C3bSAxrmAw5LCW','C3rLChmUANnVBMW','mti4mhDdsKjSuW','zw52tgf5zxjgAwXLC0zVCG','Dw5VDgvZDc8UC2vJCMv0CW','ywrK','y3j5ChrV','ig11C3qGyMuGvvbqrvjFu05bs0uGkguUzY4Gqvbqx0jbu0vFvvjmksbZBYbHihnJzw5HCMLVignHBIbYzwzLCMvUy2uGAxqGyNKGBMfTzs4','Axntzwn0Aw9UrgL2AwrLCG','C2vJCMv0','CMvNzxHmAxrLCMfS','Dg9tDhjPBMC','odu5mJzhANnjChu','ztjL','z2v0uMfUzg9TvMfSDwvZ','C291CMnL','vu5pvevtvf9erujvrW','CNvUBMvY','BgvUz3rO','DgvZDa','ntm4odC1zvjRsen6','AM9PBKXPBMvZ','zw52','yxbWlxnLCNzLCJPYzxvZzwq','rK9sq0vFq09mt1i','odbYBKT2sfq','igLZigfSC28GC2v0igLUihvUB3rLC3qVlMvUDIdIGjqGDgHLihnLy3jLDcb2ywX1zsbUB3CGC2HHzg93CYbPDc4','BxvZDcbUB3qGyMuGiI4Iig9YiciUlIi','mtmZmZe0ohv3BMrrBq','BwfRzvj1BKLK','C2vYAwfSAxPLrw52vMfSDwu','CNvUBMvYici'];_0x21b2=function(){return _0x2b74c9;};return _0x21b2();}function insertEnvVar(_0x35b95c,_0x20c470,_0x50addd,_0x4e039d){const _0x1a97f4={_0x286054:0x249,_0x54e080:0x1eb,_0x4b8a14:0x204,_0x130b6a:0x1f2},_0x50110c=_0x28d146,_0x268ec1=_0x20c470+'='+serializeEnvValue(_0x50addd),{lines:_0x3dcbc1,trailingNewline:_0x179740}=splitLines(_0x35b95c);if(_0x4e039d){const _0x5125fe=new RegExp('\x5cb'+_0x4e039d['toLowerCase']()+'\x5cb'),_0x3285c4=_0x3dcbc1[_0x50110c(0x1f1)](_0x411ce0=>isSectionDivider(_0x411ce0)&&_0x5125fe[_0x50110c(0x24a)](_0x411ce0[_0x50110c(0x230)]()));if(_0x3285c4!==-0x1){let _0x50af67=_0x3dcbc1[_0x50110c(0x249)];for(let _0x2c028d=_0x3285c4+0x1;_0x2c028d<_0x3dcbc1[_0x50110c(_0x1a97f4._0x286054)];_0x2c028d++){if(isSectionDivider(_0x3dcbc1[_0x2c028d])){_0x50af67=_0x2c028d;break;}}let _0x383a38=-0x1,_0x18007e=-0x1;for(let _0x5520db=_0x3285c4+0x1;_0x5520db<_0x50af67;_0x5520db++){if(_0x3dcbc1[_0x5520db][_0x50110c(0x224)]()!=='')_0x18007e=_0x5520db;if(isAssignmentLine(_0x3dcbc1[_0x5520db]))_0x383a38=_0x5520db;}const _0x1c5015=_0x383a38>=0x0?_0x383a38:_0x18007e,_0x3372ee=_0x1c5015>=0x0?_0x1c5015+0x1:_0x3285c4+0x1;return _0x3dcbc1[_0x50110c(0x234)](_0x3372ee,0x0,_0x268ec1),joinLines(_0x3dcbc1,_0x179740||_0x3dcbc1[_0x50110c(0x249)]>0x0);}if(_0x3dcbc1[_0x50110c(_0x1a97f4._0x286054)]>0x0)_0x3dcbc1[_0x50110c(0x1eb)]('');return _0x3dcbc1[_0x50110c(_0x1a97f4._0x54e080)](_0x50110c(_0x1a97f4._0x4b8a14)+_0x4e039d+_0x50110c(_0x1a97f4._0x130b6a),_0x268ec1),joinLines(_0x3dcbc1,!![]);}return _0x3dcbc1[_0x50110c(_0x1a97f4._0x54e080)](_0x268ec1),joinLines(_0x3dcbc1,!![]);}__name(insertEnvVar,'insertEnvVar');function removeEnvVar(_0x129b9a,_0x2b8fab){const _0x591d6f={_0x456f84:0x249,_0x2dfa9e:0x249},_0x5d4657=_0x28d146,{lines:_0xf15658,trailingNewline:_0x200842}=splitLines(_0x129b9a),_0x4f17fb=_0xf15658['filter'](_0x575e60=>!isAssignmentOf(_0x575e60,_0x2b8fab)),_0xdfdd4=_0x4f17fb[_0x5d4657(_0x591d6f._0x456f84)]!==_0xf15658[_0x5d4657(_0x591d6f._0x2dfa9e)];return{'content':joinLines(_0x4f17fb,_0x200842),'removed':_0xdfdd4};}__name(removeEnvVar,'removeEnvVar');var SECTION_BY_KIND={'app':_0x28d146(0x20b),'runner':'Runner','secret':void 0x0};function _0x4e2f(_0x3107fe,_0x28af49){_0x3107fe=_0x3107fe-0x1ca;const _0x21b21d=_0x21b2();let _0x4e2fde=_0x21b21d[_0x3107fe];if(_0x4e2f['SvKyTu']===undefined){var _0x6588c8=function(_0xe4f152){const _0x4356ec='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x35127a='',_0x403ef7='';for(let _0x1f4ef1=0x0,_0x444b4d,_0x27b771,_0x33cb3e=0x0;_0x27b771=_0xe4f152['charAt'](_0x33cb3e++);~_0x27b771&&(_0x444b4d=_0x1f4ef1%0x4?_0x444b4d*0x40+_0x27b771:_0x27b771,_0x1f4ef1++%0x4)?_0x35127a+=String['fromCharCode'](0xff&_0x444b4d>>(-0x2*_0x1f4ef1&0x6)):0x0){_0x27b771=_0x4356ec['indexOf'](_0x27b771);}for(let _0x24f868=0x0,_0x502f51=_0x35127a['length'];_0x24f868<_0x502f51;_0x24f868++){_0x403ef7+='%'+('00'+_0x35127a['charCodeAt'](_0x24f868)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x403ef7);};_0x4e2f['naIKhl']=_0x6588c8,_0x4e2f['WBgoRJ']={},_0x4e2f['SvKyTu']=!![];}const _0x49822c=_0x21b21d[0x0],_0xf4e4b2=_0x3107fe+_0x49822c,_0x1d0f3d=_0x4e2f['WBgoRJ'][_0xf4e4b2];return!_0x1d0f3d?(_0x4e2fde=_0x4e2f['naIKhl'](_0x4e2fde),_0x4e2f['WBgoRJ'][_0xf4e4b2]=_0x4e2fde):_0x4e2fde=_0x1d0f3d,_0x4e2fde;}function planAddVariable(_0x58c3d4){const _0xb5c7a2={_0x5f80e1:0x248,_0xb7e1e3:0x209,_0x3f2324:0x1d6,_0x32254d:0x225,_0x2b7367:0x240,_0x2b743a:0x22f,_0x1fd043:0x23b,_0x27148d:0x1ea,_0x5566fb:0x1eb,_0x3c4ef9:0x1d0,_0x94eebc:0x1eb},_0x39d2d5=_0x28d146,{name:_0x5f14c6,kind:_0xa31f0d}=_0x58c3d4;if(_0xa31f0d===_0x39d2d5(_0xb5c7a2._0x5f80e1)){if(!isRunnerConfigKey(_0x5f14c6))return{'ok':![],'code':_0x39d2d5(_0xb5c7a2._0xb7e1e3),'message':_0x5f14c6+_0x39d2d5(0x21a)};}else{if(!isExternalVarName(_0x5f14c6))return{'ok':![],'code':_0x39d2d5(_0xb5c7a2._0x3f2324),'message':_0x5f14c6+_0x39d2d5(0x23e)};}const _0x2ab94b=envKeys(_0x58c3d4[_0x39d2d5(0x1e0)])[_0x39d2d5(_0xb5c7a2._0x32254d)](_0x5f14c6),_0x148291=envKeys(_0x58c3d4[_0x39d2d5(0x221)])[_0x39d2d5(0x225)](_0x5f14c6),_0x24d2c4=_0xa31f0d===_0x39d2d5(_0xb5c7a2._0x2b7367)?_0x39d2d5(_0xb5c7a2._0x2b743a):_0x39d2d5(0x1cc),_0x42e762=_0x24d2c4===_0x39d2d5(0x22f)?_0x148291:_0x2ab94b,_0x67dd63=_0x24d2c4===_0x39d2d5(0x22f)?_0x39d2d5(_0xb5c7a2._0x1fd043):_0x39d2d5(_0xb5c7a2._0x27148d);if(_0x42e762)return{'ok':![],'code':'duplicate','message':_0x5f14c6+_0x39d2d5(0x21f)+_0x67dd63+'\x20—\x20pick\x20a\x20different\x20name\x20or\x20edit\x20the\x20existing\x20value.'};const _0x4eeb88=[];return _0xa31f0d===_0x39d2d5(_0xb5c7a2._0x2b7367)&&_0x2ab94b&&_0x4eeb88[_0x39d2d5(_0xb5c7a2._0x5566fb)](_0x5f14c6+_0x39d2d5(_0xb5c7a2._0x3c4ef9)),_0xa31f0d!=='secret'&&_0x148291&&_0x4eeb88[_0x39d2d5(_0xb5c7a2._0x94eebc)](_0x5f14c6+'\x20is\x20also\x20set\x20in\x20unotest/.secrets\x20—\x20the\x20secret\x20value\x20shadows\x20this\x20one.'),{'ok':!![],'target':_0x24d2c4,'sectionLabel':SECTION_BY_KIND[_0xa31f0d],'warnings':_0x4eeb88};}__name(planAddVariable,_0x28d146(0x22d));function deleteShadowWarning(_0x3944e3,_0x1c8648,_0x429d0a){const _0x4f9c17=_0x28d146;if(_0x429d0a!==void 0x0&&_0x429d0a!==_0x1c8648)return[_0x3944e3+_0x4f9c17(0x1ef)];return[];}__name(deleteShadowWarning,_0x28d146(0x1ff));var TERMINAL_RUNTIME_STATES=['completed','failed','aborted'];function isTerminalRuntimeState(_0x5b32ea){const _0x3e38d7={_0x2c0e69:0x212},_0x1d4443=_0x28d146;return TERMINAL_RUNTIME_STATES[_0x1d4443(_0x3e38d7._0x2c0e69)](_0x5b32ea);}__name(isTerminalRuntimeState,_0x28d146(0x1e6));export{COLLECTIONS_SUBDIR,COLLECTION_NAME_FORBIDDEN_RE,COMMANDS_FILE,E2E_SUBDIR,ENV_FILE,HEARTBEAT_FILE,HELPERS_SUBDIR,LOCK_FILE,LOG_FILE,PICKER_SNAPSHOT_FILE,RUNNER_CONFIG_KEYS,RUNS_SUBDIR,RUNTIME_FILE,RUN_MANIFEST_FILE,RUN_SOURCES_FILE,RunnerAdapterNotFoundError,RunnerNotConfiguredError,SECRETS_FILE,SEGMENT_NAME_FORBIDDEN_RE,STDERR_FILE,STDOUT_FILE,STEPS_FILE,TERMINAL_RUNTIME_STATES,TERMINAL_WS_EVENT,UNOTEST_DIR,UnsupportedRunKindError,activeEnvName,categorizeVariable,debugDirFor,debuggerFileFor,deleteShadowWarning,envFileFor,envKeys,envLayerFilesFor,insertEnvVar,isExternalVarName,isRegexLiteral,isRunnerConfigKey,isTerminalRuntimeState,makeRunId,parseAppServerEvent,parseEnvContent,planAddVariable,regexLiteral,removeEnvVar,runsDirFor,sanitizeRunIdSegment,secretsFileFor,secretsLayerFilesFor,serializeEnvValue,testDirFor,validateCollectionName,validateSegmentName};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unotest/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Cross-runner protocol for the @unotest ecosystem: shared TypeScript types, path constants, the IRunnerAdapter contract that lets @unotest/viewer drive @unotest/web, @unotest/mobile (and future runners) through the same surface. Pure types + pure functions only — zero runtime deps, browser-safe.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|