@unotest/protocol 0.6.2 → 0.9.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/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  All notable changes to `@unotest/protocol` are documented in this file.
4
4
 
5
+ ## [0.9.0] - 2026-06-11
6
+
7
+ ### Added
8
+
9
+ - **`ScenariosPayload`** — the `GET /api/scenarios` response now carries both
10
+ the scenario list and the folder list (including empty dirs), so the viewer's
11
+ tree can render and manage folders.
12
+ - **`validateSegmentName`** — shared scenario-file-stem / folder-name validation
13
+ (single FS-safe path segment), used by both the viewer-server writer and the
14
+ client form.
15
+
16
+ ### Changed
17
+
18
+ - **`RUNNER_CONFIG_KEYS`** now includes `UNOTEST_NETWORK` and `UNOTEST_CONSOLE`,
19
+ so the viewer's Variables panel groups them under "Runner config" rather than
20
+ app data.
21
+
5
22
  ## [0.6.2] - 2026-06-05
6
23
 
7
24
  Maintenance release: version bump to keep the `@unotest` ecosystem in
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Readable } from 'node:stream';
2
+
1
3
  /** User-facing project directory containing scenarios + helpers + collections. */
2
4
  declare const UNOTEST_DIR = "unotest";
3
5
  /** Subdir under `unotest/` for `.test.js` scenarios. */
@@ -37,6 +39,12 @@ declare const COMMANDS_FILE = "commands.jsonl";
37
39
  * from the page-snapshot (semantic-DOM YAML) which lives in
38
40
  * failure-bundles. */
39
41
  declare const RUNTIME_FILE = "runtime.json";
42
+ /** Read-only page-outline snapshot the in-page picker overlay hit-tests
43
+ * against, written by the runner when the picker arms (and on self-heal).
44
+ * Lives at `unotest/.runs/<runId>/picker-snapshot.txt`. The viewer's
45
+ * Snapshot inspector tab fetches it via the run-dir asset endpoint to show
46
+ * "what the picker sees" for diagnosing ref/coverage gaps. */
47
+ declare const PICKER_SNAPSHOT_FILE = "picker-snapshot.txt";
40
48
  /** Per-project shared breakpoint store. Path is relative to project root
41
49
  * (NOT under `unotest/.runs/`). Schema: `BreakpointsFile` in
42
50
  * `protocol/breakpoints-file.ts`. */
@@ -44,6 +52,19 @@ declare const DEBUGGER_FILE = "unotest/.debugger.json";
44
52
  /** Project env file edited by the viewer's env-variable editor. Relative
45
53
  * to project root. Surfaced as `EnvFile` (`protocol/env-file.ts`). */
46
54
  declare const ENV_FILE = "unotest/.env";
55
+ /** Secret scenario variables, beside `.env` under `unotest/`. Same KEY=VALUE
56
+ * format; secrecy is a property of THIS file (not a name heuristic). */
57
+ declare const SECRETS_FILE = "unotest/.secrets";
58
+ /** Per-environment overlay file for `.env` / `.secrets`. `unotest/.env`
59
+ * (+ `.secrets`) hold shared defaults; `unotest/.env.<name>` overrides them
60
+ * for a named environment (`staging`, `production`, …), selected at run time
61
+ * via `UNOTEST_ENV` / `--env`. Overlay wins over base; ambient process.env
62
+ * still wins over both. No env name → base file only. */
63
+ declare function envFileFor(envName?: string): string;
64
+ declare function secretsFileFor(envName?: string): string;
65
+ /** Read an environment name from a process-env-like record (`UNOTEST_ENV`),
66
+ * normalising empty/blank to `undefined` (= base only). */
67
+ declare function activeEnvName(env: Record<string, string | undefined>): string | undefined;
47
68
 
48
69
  interface RegexLiteral {
49
70
  readonly kind: "regex";
@@ -137,8 +158,19 @@ interface CollectionRunRequest {
137
158
  /** Stop on first failure. Default `false` (continue-on-fail). */
138
159
  bail?: boolean;
139
160
  }
161
+ /** Open a live AUTHORING-HOLD session (collaborative model, U1/U3): a
162
+ * headed shared browser + draft stay open with NO running test; the human
163
+ * and agent co-author the draft. Runs `unotest-web author <scenario>`. */
164
+ interface AuthoringRunRequest {
165
+ kind: "authoring";
166
+ /** Scenario `name` — file stem relative to `unotest/e2e/`. A stub is
167
+ * created if the file doesn't exist yet. */
168
+ scenario: string;
169
+ /** Authoring is visible by default — the human must see the live browser. */
170
+ headed?: boolean;
171
+ }
140
172
  /** Discriminated union of every run-shape the viewer can request. */
141
- type RunRequest = ScenarioRunRequest | CollectionRunRequest;
173
+ type RunRequest = ScenarioRunRequest | CollectionRunRequest | AuthoringRunRequest;
142
174
  /** All `kind` literals — useful for switch-completeness checks and for
143
175
  * adapter `supportedKinds` lists. */
144
176
  type RunKind = RunRequest["kind"];
@@ -225,6 +257,57 @@ declare class RunnerNotConfiguredError extends Error {
225
257
  constructor(message: string);
226
258
  }
227
259
 
260
+ /** Parsed scenario metadata from the mandatory header lines
261
+ * (per design-v0/decisions.md, "Test source format"):
262
+ *
263
+ * // id-<kebab-slug>
264
+ * // <human title>
265
+ * // #<6-hex-color>
266
+ * function test_<...>() { ... }
267
+ *
268
+ * All three lines are required; a file without a complete header is
269
+ * rejected by the discovery service as parse-error (no legacy fallback). */
270
+ interface ScenarioMeta {
271
+ /** Slug from `// id-<slug>`. Stable test identity across rename. */
272
+ id: string;
273
+ /** Human-readable title from `// <text>`. */
274
+ title: string;
275
+ /** Color identifier from `// #RRGGBB`. Used only in tab headers as a
276
+ * thin colored strip — NOT a status signal. */
277
+ color: string;
278
+ /** File stem relative to `unotest/e2e/`, dirs as slashes.
279
+ * Examples: `smoke-welcome`, `auth/signin-flow`.
280
+ * Source-of-truth identity for CLI invocations and tab keys. */
281
+ name: string;
282
+ /** Project-relative path to the source file. */
283
+ path: string;
284
+ }
285
+
286
+ /** Response of `GET /api/scenarios`. Folders are listed independently of
287
+ * the scenarios so an EMPTY directory under `unotest/e2e/` still renders
288
+ * in the tree (the folder list isn't inferred from scenario paths). */
289
+ interface ScenariosPayload {
290
+ scenarios: ScenarioMeta[];
291
+ /** Directory paths relative to `unotest/e2e/`, posix-separated, any
292
+ * depth (e.g. `auth`, `auth/signup`, `autopark`). Excludes reserved
293
+ * subtrees (`_helpers`, `_collections`) and any `_`/`.`-prefixed dir. */
294
+ folders: string[];
295
+ }
296
+ /** Filesystem-unsafe characters in a single path segment. Includes the
297
+ * path separators (`\` `/`) so a valid segment is guaranteed to be ONE
298
+ * level — no nesting smuggled through a name. Mirrors the block-list
299
+ * rationale of `validateCollectionName`. */
300
+ declare const SEGMENT_NAME_FORBIDDEN_RE: RegExp;
301
+ /** Validate a single scenario-file stem or folder name. Returns `null` on
302
+ * success, else a human-readable reason. Shared by the viewer-server
303
+ * writer (authoritative) and the client form (pre-flight) so both agree.
304
+ * Pure — safe to bundle in the browser.
305
+ *
306
+ * Rejects: empty, `.`/`..`, `.`-prefix (hidden), `_`-prefix (reserved for
307
+ * `_helpers`/`_collections`/templates), path separators + FS-unsafe
308
+ * punctuation + control chars. */
309
+ declare function validateSegmentName(name: string): string | null;
310
+
228
311
  /** Session profile — the kind of process a tab spawns. Mirrored by the
229
312
  * viewer's TerminalStore.TermKind. */
230
313
  type TerminalKind = "local" | "claude" | "codex";
@@ -275,6 +358,222 @@ type TerminalServerMessage = TerminalOutputMessage | TerminalExitMessage | Termi
275
358
  * directions use this single event name on `/ws/terminal`. */
276
359
  declare const TERMINAL_WS_EVENT = "terminal";
277
360
 
361
+ type VariableCategory = "secret" | "app" | "runner";
362
+ /** User-facing runner-config knobs documented in `unotest/.env`. Single source
363
+ * of truth for "is this name our config?" — drives the viewer's "Runner
364
+ * config" group and the add-variable dropdown.
365
+ *
366
+ * NOT listed (so they never surface as user config): launcher-injected
367
+ * run-control vars (UNOTEST_RUN_ID, UNOTEST_PARENT_RUN_ID,
368
+ * UNOTEST_BUSY_SCENARIOS, UNOTEST_WORKER_*), session-log internals
369
+ * (UNOTEST_SESSION_LOG_*), and path bootstrap (UNOTEST_DIR,
370
+ * UNOTEST_PROJECT_ROOT, UNOTEST_CONFIG, UNOTEST_VIEWER_NO_OPEN). A user would
371
+ * never put those in `unotest/.env`. */
372
+ declare const RUNNER_CONFIG_KEYS: ReadonlySet<string>;
373
+ /** True when `name` is a key the runner consumes as its own configuration. */
374
+ declare function isRunnerConfigKey(name: string): boolean;
375
+ /** Group a variable for the viewer. Secrecy from the source file; runner-vs-app
376
+ * from the owned-key set. */
377
+ declare function categorizeVariable(v: {
378
+ name: string;
379
+ source: "env" | "secrets";
380
+ }): VariableCategory;
381
+ /** An external scenario variable is referenced by a bare UPPER_SNAKE
382
+ * identifier (`APP_BASE_URL`). App / secret names must match this to be
383
+ * resolvable from a scenario; runner keys are validated against the set
384
+ * above instead. Convention only — no value inspection. */
385
+ declare function isExternalVarName(name: string): boolean;
386
+
387
+ /** Quote on write only when the value would otherwise be ambiguous (spaces,
388
+ * `#`, quotes, `=`, backslash, leading backtick, or newlines). Plain tokens
389
+ * stay unquoted. Mirrors the viewer env-dotenv serializer. */
390
+ declare function serializeEnvValue(value: string): string;
391
+ /** Active (non-commented) assignment keys present in env-file `content`.
392
+ * Used to detect duplicates / cross-file shadowing before an add. */
393
+ declare function envKeys(content: string): Set<string>;
394
+ /**
395
+ * Insert `KEY=VALUE` into env-file `content`. With `sectionLabel`, the line
396
+ * goes into the first `# --- <label> --- ` divider section — after the last
397
+ * assignment there (or its description comments if it has no vars yet). The
398
+ * label is matched as a whole word against DIVIDER lines only, so prose
399
+ * comments are never mistaken for a section. No such section → it is created
400
+ * at end-of-file. With no label the line is appended. Does NOT dedup — reject
401
+ * duplicates before calling.
402
+ */
403
+ declare function insertEnvVar(content: string, key: string, value: string, sectionLabel?: string): string;
404
+ /**
405
+ * Remove the assignment line for `key`, leaving every comment and other line
406
+ * untouched (we do not guess which comments "belong" to the key). Returns the
407
+ * new content and whether anything was removed.
408
+ */
409
+ declare function removeEnvVar(content: string, key: string): {
410
+ content: string;
411
+ removed: boolean;
412
+ };
413
+
414
+ /** Which group the user is adding into. App/runner → `.env`, secret →
415
+ * `.secrets`. Mirrors VariableCategory as an INPUT (the user's choice). */
416
+ type VariableKind = VariableCategory;
417
+ interface AddVariablePlanInput {
418
+ name: string;
419
+ kind: VariableKind;
420
+ /** Current text of `unotest/.env` (`""` if absent). */
421
+ envContent: string;
422
+ /** Current text of `unotest/.secrets` (`""` if absent). */
423
+ secretsContent: string;
424
+ }
425
+ type VariablePlanError = {
426
+ ok: false;
427
+ code: "duplicate" | "invalid-name" | "unknown-runner-key";
428
+ message: string;
429
+ };
430
+ type AddVariablePlan = {
431
+ ok: true;
432
+ target: "env" | "secrets";
433
+ sectionLabel?: string;
434
+ warnings: string[];
435
+ } | VariablePlanError;
436
+ /**
437
+ * Decide where a new variable goes and what to warn about — or reject it.
438
+ * Reject reasons: duplicate key in the target file; a non-UPPER_SNAKE app/
439
+ * secret name (a scenario could never reference it); a runner key not in the
440
+ * owned-config allowlist. Warnings (non-fatal): secret shadowing a same-named
441
+ * `.env` var, or vice-versa.
442
+ */
443
+ declare function planAddVariable(input: AddVariablePlanInput): AddVariablePlan;
444
+ /**
445
+ * Warning to show after deleting `name` from the file: if the shell
446
+ * environment still defines it with a DIFFERENT value, it will keep
447
+ * resolving from there (set-if-absent means ambient wins). Comparing values
448
+ * avoids a false positive when `.env` was merely flattened into process.env.
449
+ */
450
+ declare function deleteShadowWarning(name: string, fileValue: string | undefined, ambientValue: string | undefined): string[];
451
+
452
+ /** A single editor diagnostic. Superset of the `@unotest/dsl`
453
+ * validator diagnostic: it unifies parse errors, the vocab validator,
454
+ * and the platform linter behind one shape, tagged by `source`/`rule`
455
+ * so consumers can theme or filter. Positions are 1-based; a parse
456
+ * error with no recoverable position falls back to `1:1`. */
457
+ interface DslDiagnostic {
458
+ severity: "error" | "warning" | "info";
459
+ /** 1-based line. */
460
+ line: number;
461
+ /** 1-based column. */
462
+ column: number;
463
+ /** 1-based end line, when the producer knows the span. */
464
+ endLine?: number;
465
+ /** 1-based end column, when the producer knows the span. */
466
+ endColumn?: number;
467
+ message: string;
468
+ /** Stable rule id, e.g. `"validator:unknown-function"`, `"validator:dsl"`,
469
+ * a linter rule id, or `"parse"`. */
470
+ rule: string;
471
+ /** Which stage produced it — lets the UI group / colour by origin. */
472
+ source: "parse" | "validate" | "lint";
473
+ }
474
+ /** Coarse grouping for a vocab entry — drives completion icons and
475
+ * ordering. `keyword` covers DSL control-flow / block words (`step`,
476
+ * `if`, `for`, …); `helper` covers project-defined `flow_*` / mock
477
+ * helpers surfaced from the workspace. */
478
+ type DslVocabCategory = "action" | "assertion" | "selector" | "chain" | "navigation" | "read" | "wait" | "state" | "storage" | "multi-context" | "sandbox" | "escape-hatch" | "keyword" | "helper";
479
+ /** One declared argument of a vocab entry — feeds signature help and
480
+ * the snippet placeholders in `insertText`. `kind` is the validator's
481
+ * arg-kind string (`"locatorLike"`, `"stringLike"`, `"number"`,
482
+ * `"any"`, …); the editor treats it as an opaque label. */
483
+ interface DslVocabArg {
484
+ label: string;
485
+ kind: string;
486
+ required: boolean;
487
+ }
488
+ /** A single autocomplete-able item: a vocab function, a DSL keyword, or
489
+ * a project helper. Serializable — crosses the REST boundary verbatim
490
+ * and is cached by the browser (the vocab is static per platform). */
491
+ interface DslVocabEntry {
492
+ name: string;
493
+ category: DslVocabCategory;
494
+ args: DslVocabArg[];
495
+ /** Return-kind string (`"void"`, `"string"`, `"locator"`, …). */
496
+ returns: string;
497
+ /** Snippet body with `${n:label}` placeholders, e.g.
498
+ * `click(${1:locator})`. */
499
+ insertText: string;
500
+ /** Human-readable signature for hover / signature-help, e.g.
501
+ * `getByRole(role, { name?, exact? })`. Richer than the bare arg
502
+ * list — includes option-object shape. */
503
+ signature?: string;
504
+ /** Prose description (markdown) for hover and the completion info
505
+ * panel. */
506
+ doc?: string;
507
+ /** Locator capability from the function contract. `"chainableLocator"`
508
+ * entries can be chained off a locator (offered after `.`); any value
509
+ * other than `"none"` produces a locator (so it fits a `locator`
510
+ * argument slot). Absent for keywords / helpers that have no contract. */
511
+ locatorCapability?: "none" | "locator" | "chainableLocator";
512
+ }
513
+ /** Per-request file context for {@link IDslLanguageService.validate}.
514
+ * The viewer owns workspace discovery, so it supplies the things the
515
+ * platform validator can't know on its own. */
516
+ interface DslValidateContext {
517
+ /** Names of project helpers (`flow_*`, mocks) so their calls are not
518
+ * flagged as unknown functions — mirrors how the lint runner
519
+ * registers `unotest/e2e/_helpers/`. */
520
+ helperNames?: readonly string[];
521
+ /** Whether the source is a scenario or a helper definition file. */
522
+ fileKind?: "scenario" | "helper";
523
+ }
524
+ /** The DSL language service a platform exposes to the viewer. Two
525
+ * concerns only: the static vocabulary (for completion / signature
526
+ * help) and full source validation (parse + vocab validator + linter,
527
+ * identical to the platform's own lint gate). */
528
+ interface IDslLanguageService {
529
+ /** Static, serializable vocabulary for autocomplete and signature
530
+ * help. Stable for the lifetime of the process — safe to cache. */
531
+ getVocab(): DslVocabEntry[];
532
+ /** Full diagnostics for one source string. Pure with respect to the
533
+ * filesystem — all workspace knowledge arrives via `ctx`. */
534
+ validate(source: string, ctx?: DslValidateContext): DslDiagnostic[];
535
+ }
536
+
537
+ /** A spawned runner process. Structural superset of the bits of a Node
538
+ * `ChildProcess` the viewer actually consumes — pid for the active-run
539
+ * snapshot, stdout/stderr for log capture, exit/error for finalize,
540
+ * kill for abort. Both `child_process` and Electron `utilityProcess`
541
+ * satisfy this via a thin adapter. */
542
+ interface ILaunchedProcess {
543
+ /** OS process id, or -1 if the spawn failed to produce one. */
544
+ readonly pid: number;
545
+ /** Captured stdout stream, or null when not piped. */
546
+ readonly stdout: Readable | null;
547
+ /** Captured stderr stream, or null when not piped. */
548
+ readonly stderr: Readable | null;
549
+ /** Register the exit handler. Called once when the process exits. */
550
+ onExit(cb: (code: number | null, signal: NodeJS.Signals | null) => void): void;
551
+ /** Register the spawn-error handler (e.g. bin not found). */
552
+ onError(cb: (err: Error) => void): void;
553
+ /** Terminate the process. Default signal SIGTERM. */
554
+ kill(signal?: NodeJS.Signals): void;
555
+ }
556
+ /** Everything the launcher needs to spawn one runner process. The caller
557
+ * (RunnerService) has already merged the environment and resolved the bin
558
+ * + argv from the `IRunnerAdapter`; the launcher only decides HOW to run
559
+ * it. Pure data — no behaviour. */
560
+ interface LaunchSpec {
561
+ /** Absolute path to the JS bin entry — `IRunnerAdapter.resolveBin()`. */
562
+ bin: string;
563
+ /** Argv to pass after the bin — `IRunnerAdapter.buildArgs(req)`. */
564
+ args: string[];
565
+ /** Fully-merged environment for the child. */
566
+ env: NodeJS.ProcessEnv;
567
+ /** Working directory — the workspace project root. */
568
+ cwd: string;
569
+ }
570
+ /** Spawns the runner JS under a Node-capable runtime. Injected into the
571
+ * viewer's RunnerService so the spawn mechanism (system Node vs Electron
572
+ * utilityProcess) is a deployment choice, not baked into the service. */
573
+ interface IProcessLauncher {
574
+ launch(spec: LaunchSpec): ILaunchedProcess;
575
+ }
576
+
278
577
  /** Contents of `unotest/.viewer.lock`. Written by viewer-server on
279
578
  * startup, removed on graceful shutdown. Stale detection: `process.kill(
280
579
  * pid, 0)` throws ESRCH if PID is dead → lockfile is stale, safe to
@@ -289,32 +588,6 @@ interface LockFile {
289
588
  startedAt: string;
290
589
  }
291
590
 
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
591
  /** Helper file metadata. Helpers live in `unotest/e2e/_helpers/**` as
319
592
  * `snake_case` functions (`signin_as`, `seed_user`, …). The runner
320
593
  * auto-discovers them; no import system in scenarios. */
@@ -325,6 +598,101 @@ interface HelperMeta {
325
598
  path: string;
326
599
  }
327
600
 
601
+ /** Which kind of locator the in-page picker overlay should retarget to and
602
+ * what DSL snippet to emit on pick. `locator` → an interactive element →
603
+ * `click(<loc>)`; `text`/`visibility` → any named/interactive element →
604
+ * `assertText`/`assertVisible`. See docs/recoder/plan.md. */
605
+ type PickerMode = "locator" | "text" | "visibility";
606
+ interface DbgCommandStep {
607
+ id: string;
608
+ cmd: "step";
609
+ }
610
+ interface DbgCommandContinue {
611
+ id: string;
612
+ cmd: "continue";
613
+ }
614
+ interface DbgCommandPause {
615
+ id: string;
616
+ cmd: "pause";
617
+ }
618
+ interface DbgCommandSetBp {
619
+ id: string;
620
+ cmd: "set-bp";
621
+ line: number;
622
+ col: number;
623
+ }
624
+ interface DbgCommandClearBp {
625
+ id: string;
626
+ cmd: "clear-bp";
627
+ line: number;
628
+ col: number;
629
+ }
630
+ interface DbgCommandAbort {
631
+ id: string;
632
+ cmd: "abort";
633
+ }
634
+ /** Start (or, if already active, re-mode) the in-page picker on the live
635
+ * paused page. `execute=false` (default) is capture-only: clicks are
636
+ * swallowed, never run — picks just record a locator/assertion.
637
+ * `execute=true` turns the overlay into a Playwright-style recorder: real
638
+ * clicks / typing / selects RUN on the page and are recorded as DSL actions
639
+ * (`click`/`fill`/`press`/`selectOption`/`check`). In execute mode the
640
+ * `text`/`visibility` modes still record an assertion without running the
641
+ * click (swap mode to drop an assertion mid-flow). */
642
+ interface DbgCommandPickerStart {
643
+ id: string;
644
+ cmd: "picker:start";
645
+ mode: PickerMode;
646
+ execute?: boolean;
647
+ }
648
+ /** Tear down the picker overlay. */
649
+ interface DbgCommandPickerStop {
650
+ id: string;
651
+ cmd: "picker:stop";
652
+ }
653
+ /** On-demand: capture the current page outline (what the picker hit-tests
654
+ * against) and write it to `picker-snapshot.txt`. Lets the viewer's Snapshot
655
+ * tab show / refresh the snapshot without arming the picker. Cheap — runs
656
+ * only when the user opens/refreshes the tab (the outline is expensive on
657
+ * huge pages, so it is never captured on every pause). */
658
+ interface DbgCommandSnapshot {
659
+ id: string;
660
+ cmd: "snapshot";
661
+ }
662
+ /** The DSL line a recorded action / pick renders to. Mirrors the in-page
663
+ * recorder's verbs. `locator` → bare locator; `assertText`/`assertVisible`
664
+ * → assertions; the rest → Playwright-style actions. */
665
+ type RecordedActionKind = "locator" | "assertText" | "assertVisible" | "click" | "fill" | "press" | "selectOption" | "check" | "uncheck";
666
+ /** Agent-driven, ref-safe record (collaborative authoring). The agent picks
667
+ * an element by `ref` (from a snapshot of the SHARED page) + an action; the
668
+ * runner resolves `ref→locator` (`RefResolver`) and emits a `locator:picked`
669
+ * event the viewer inserts — so the agent NEVER hand-writes a locator. Same
670
+ * resolution/insertion pipeline as the human's in-page picker. */
671
+ interface DbgCommandRecord {
672
+ id: string;
673
+ cmd: "record";
674
+ ref: string;
675
+ action: RecordedActionKind;
676
+ /** Typed/selected value for `fill` / `selectOption`. */
677
+ value?: string;
678
+ /** Key for `press` (e.g. "Enter", "Control+A"). */
679
+ key?: string;
680
+ /** Expected text for `assertText` (else the element's textContent is used). */
681
+ text?: string;
682
+ /** Where the viewer drops the line. Default `append` (agent records a flow). */
683
+ placement?: "cursor" | "append";
684
+ }
685
+ /** Collaborative control token (Slice 3). Sets who may act on the shared
686
+ * page: `agent` lets the agent record; `human` (default) blocks the agent.
687
+ * Written by the viewer (Take control button) or the agent (take_wheel). */
688
+ interface DbgCommandWheel {
689
+ id: string;
690
+ cmd: "wheel";
691
+ owner: "agent" | "human";
692
+ }
693
+ type DbgCommand = DbgCommandStep | DbgCommandContinue | DbgCommandPause | DbgCommandSetBp | DbgCommandClearBp | DbgCommandAbort | DbgCommandPickerStart | DbgCommandPickerStop | DbgCommandSnapshot | DbgCommandRecord | DbgCommandWheel;
694
+ type DbgCommandKind = DbgCommand["cmd"];
695
+
328
696
  /** Terminal outcome reported by the runner via `run:finished`. */
329
697
  type RunOutcome = "completed" | "failed" | "aborted" | "interrupted";
330
698
  /** Scenario-level run-id. Format opaque to consumers; treat as string. */
@@ -427,6 +795,27 @@ interface PausedEvent extends RunArtifactBase {
427
795
  }[];
428
796
  };
429
797
  }
798
+ /** Emitted by the in-page locator picker / action recorder (debug-pause)
799
+ * when the user picks an element or performs a recorded action. The runner
800
+ * resolved the picked `ref` to a locator (`RefResolver`) and rendered the
801
+ * DSL snippet. The viewer inserts `snippet` per `placement`.
802
+ * See docs/recoder/plan.md. */
803
+ interface LocatorPickedEvent extends RunArtifactBase {
804
+ kind: "locator:picked";
805
+ mode: PickerMode;
806
+ /** Ready-to-insert DSL line, e.g. a bare locator
807
+ * `getByRole("button", {name: "Sign in"})` (locator mode), an assertion
808
+ * (`assertText(…)`), or a recorded action (`click(…)`, `fill(…)`). */
809
+ snippet: string;
810
+ /** Where the viewer drops the snippet:
811
+ * - `cursor` — at the editor's caret (deliberate picks; user-placed).
812
+ * - `append` — after the previous recorded line (execute-mode action
813
+ * recorder, preserving order). */
814
+ placement: "cursor" | "append";
815
+ /** `stable` (testId / role+name / label / …) or `fragile` (css/nth-only).
816
+ * Lets the viewer flag brittle picks. */
817
+ stability: "stable" | "fragile";
818
+ }
430
819
  /** Emitted when execution resumes after a `paused` event. The `by` field
431
820
  * records which debug command unblocked it — purely informational; the
432
821
  * next `step:started` event carries the actual line/col. */
@@ -434,8 +823,14 @@ interface ResumedEvent extends RunArtifactBase {
434
823
  kind: "resumed";
435
824
  by: "step" | "continue";
436
825
  }
826
+ /** Emitted when the collaborative control token changes owner (Slice 3), so
827
+ * the viewer can live-update the "who's driving" badge over WS. */
828
+ interface WheelChangedEvent extends RunArtifactBase {
829
+ kind: "wheel:changed";
830
+ owner: "agent" | "human";
831
+ }
437
832
  /** Discriminated union of every JSONL event the scenario runner emits. */
438
- type RunArtifact = RunStartedEvent | StepStartedEvent | StepOkEvent | StepFailEvent | ScreenshotEvent | FailureBundleWrittenEvent | PausedEvent | ResumedEvent | RunFinishedEvent;
833
+ type RunArtifact = RunStartedEvent | StepStartedEvent | StepOkEvent | StepFailEvent | ScreenshotEvent | FailureBundleWrittenEvent | PausedEvent | ResumedEvent | LocatorPickedEvent | WheelChangedEvent | RunFinishedEvent;
439
834
  interface CollectionRunStartedEvent extends RunArtifactBase {
440
835
  kind: "collection-run:started";
441
836
  runId: RunId;
@@ -584,37 +979,6 @@ type TabKind = ScenarioTab | HelperTab | CollectionTab | ScenarioRunTab | Collec
584
979
  /** All tab `kind` literals — useful for switch-completeness checks. */
585
980
  type TabKindName = TabKind["kind"];
586
981
 
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
982
  interface BreakpointEntry {
619
983
  line: number;
620
984
  col: number;
@@ -666,6 +1030,20 @@ interface RuntimeStateFile {
666
1030
  file: string;
667
1031
  line: number;
668
1032
  }[];
1033
+ /** Collaborative control token (Slice 3). `human` (default) → the agent may
1034
+ * NOT act (record); `agent` → the agent holds the wheel and may record. The
1035
+ * human (host) is never blocked. Absent ⇒ `human`. */
1036
+ wheel?: "agent" | "human";
1037
+ /** Session mode (U3). `debug` (default) runs a test (executor + pauses);
1038
+ * `authoring` holds a live browser + draft open with NO running test — the
1039
+ * picker/record work on the live page, not a pause. Lets the viewer enable
1040
+ * authoring controls. Absent ⇒ `debug`. */
1041
+ mode?: "debug" | "authoring";
1042
+ /** Playwright `connect()` ws endpoint of the debug run's SHARED browser,
1043
+ * when launched in share mode (`--debug`). Lets a second client (the MCP
1044
+ * server / agent) attach to the SAME live browser the human is debugging.
1045
+ * Absent for non-shared (normal) runs. Localhost only. */
1046
+ wsEndpoint?: string;
669
1047
  lastFailure: {
670
1048
  line: number;
671
1049
  col: number;
@@ -679,4 +1057,4 @@ interface RuntimeStateFile {
679
1057
  updatedAt: number;
680
1058
  }
681
1059
 
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, DEBUGGER_FILE, type DbgCommand, type DbgCommandAbort, type DbgCommandClearBp, type DbgCommandContinue, type DbgCommandKind, type DbgCommandPause, type DbgCommandSetBp, type DbgCommandStep, 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 IRunnerAdapter, LOCK_FILE, LOG_FILE, type LockFile, type LogLineMessage, type Matcher, type PausedEvent, RUNS_SUBDIR, RUNTIME_FILE, RUN_MANIFEST_FILE, RUN_SOURCES_FILE, 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, STDERR_FILE, STDOUT_FILE, STEPS_FILE, type ScenarioMeta, type ScenarioRunRequest, type ScenarioRunTab, type ScenarioTab, type ScreenshotEvent, type StepFailEvent, type StepOkEvent, type StepStartedEvent, 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, UNOTEST_DIR, UnsupportedRunKindError, type WsMessage, type WsMessageKind, isRegexLiteral, makeRunId, regexLiteral, sanitizeRunIdSegment, validateCollectionName };
1060
+ export { type AddVariablePlan, type AddVariablePlanInput, type AuthoringRunRequest, 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, DEBUGGER_FILE, type DbgCommand, type DbgCommandAbort, type DbgCommandClearBp, type DbgCommandContinue, type DbgCommandKind, type DbgCommandPause, type DbgCommandPickerStart, type DbgCommandPickerStop, type DbgCommandRecord, type DbgCommandSetBp, type DbgCommandSnapshot, type DbgCommandStep, type DbgCommandWheel, 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 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, 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_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, UNOTEST_DIR, UnsupportedRunKindError, type VariableCategory, type VariableKind, type VariablePlanError, type WheelChangedEvent, type WsMessage, type WsMessageKind, activeEnvName, categorizeVariable, deleteShadowWarning, envFileFor, envKeys, insertEnvVar, isExternalVarName, isRegexLiteral, isRunnerConfigKey, makeRunId, planAddVariable, regexLiteral, removeEnvVar, sanitizeRunIdSegment, secretsFileFor, serializeEnvValue, 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 _0x1f0e61=_0x33f9;(function(_0x38cb05,_0x1ead2a){const _0x13d8d8={_0x4a53ac:0x25d,_0x17e566:0x234,_0x10c109:0x24b,_0x39c227:0x20d,_0x385608:0x200,_0x232f49:0x201},_0x39243a=_0x33f9,_0xc8ec76=_0x38cb05();while(!![]){try{const _0x36e89c=parseInt(_0x39243a(_0x13d8d8._0x4a53ac))/0x1*(-parseInt(_0x39243a(_0x13d8d8._0x17e566))/0x2)+-parseInt(_0x39243a(_0x13d8d8._0x10c109))/0x3+parseInt(_0x39243a(_0x13d8d8._0x39c227))/0x4*(-parseInt(_0x39243a(0x252))/0x5)+parseInt(_0x39243a(_0x13d8d8._0x385608))/0x6+parseInt(_0x39243a(0x205))/0x7+parseInt(_0x39243a(0x224))/0x8+-parseInt(_0x39243a(0x207))/0x9*(-parseInt(_0x39243a(_0x13d8d8._0x232f49))/0xa);if(_0x36e89c===_0x1ead2a)break;else _0xc8ec76['push'](_0xc8ec76['shift']());}catch(_0x21d4af){_0xc8ec76['push'](_0xc8ec76['shift']());}}}(_0x51ae,0x69c7c));var __defProp=Object['defineProperty'],__name=(_0x55616a,_0x2ea849)=>__defProp(_0x55616a,_0x1f0e61(0x211),{'value':_0x2ea849,'configurable':!![]}),UNOTEST_DIR=_0x1f0e61(0x1ee),E2E_SUBDIR=_0x1f0e61(0x258),HELPERS_SUBDIR=_0x1f0e61(0x22c),COLLECTIONS_SUBDIR='_collections',RUNS_SUBDIR=_0x1f0e61(0x21b),LOCK_FILE=_0x1f0e61(0x259),LOG_FILE=_0x1f0e61(0x22e),STEPS_FILE=_0x1f0e61(0x21c),HEARTBEAT_FILE='heartbeat',STDOUT_FILE=_0x1f0e61(0x254),STDERR_FILE=_0x1f0e61(0x220),COMMANDS_FILE=_0x1f0e61(0x1ed),RUNTIME_FILE=_0x1f0e61(0x250),PICKER_SNAPSHOT_FILE=_0x1f0e61(0x1ff),DEBUGGER_FILE=_0x1f0e61(0x20f),ENV_FILE=_0x1f0e61(0x221),SECRETS_FILE='unotest/.secrets';function _0x51ae(){const _0x2131f0=['AxnfEhrLCM5HBfzHCK5HBwu','iIbKB2vZig5VDcbZDxbWB3j0ihj1BIbRAw5Kici','vu5pvevtvf9ftLy','vw5ZDxbWB3j0zwrsDw5lAw5KrxjYB3i','vu5pvevtvf9mt0nbteu','vu5pvevtvf9dt05tt0Xf','zw52s2v5CW','A2LUza','C2vJCMv0','y2fUBM90igXVywqGCNvUBMvYigfKyxb0zxiGiG','CgLJA2vYlxnUyxbZAg90lNr4Da','ndi5nZy0ngPpvwDxCG','ody5otbMse50DgS','CMvNzxHmAxrLCMfS','C291CMnL','C3bSAxrmAw5LCW','mJeWodyXn3rywgPuvG','vu5pvevtvf9erujvr19ive1mx01bwf9cwvrfuW','ntq5re9iueDY','uNvUBMvYqwrHChrLCK5VDezVDw5KrxjYB3i','BxvZDcbUB3qGC3rHCNqGD2L0AcaNlIC','Aw52ywXPzc1Uyw1L','refuqujbu0vFvvjm','vu5pvevtvf9erujvr19lruvqx0nbteXt','mZmWotK2s3bYvKn3','vu5pvevtvf9erujvrW','Dw5VDgvZDc8UzgvIDwDNzxiUANnVBG','Dg9mB3DLCKnHC2u','BMfTzq','igLZigfSC28GC2v0igLUihvUB3rLC3qVlMvUDIdIGjqGDgHLihnLy3jLDcb2ywX1zsbUB3CGC2HHzg93CYbPDc4','Dw5VDgvZDc8UC2vJCMv0CW','C3rYAw5N','CNvU','vu5pvevtvf9erujvr19esvi','vu5pvevtvf9dqunirv9esvi','CgfKu3rHCNq','BxvZDcbUB3qGy29UDgfPBIbCic8GoIaQid8GiIa8id4GFcbVCIbJB250CM9SignOyxjHy3rLCNm','AgfZ','lNj1BNm','C3rLChmUANnVBMW','zw5KC1DPDgG','BgvUz3rO','AxnszwDLEeXPDgvYywW','C3rKzxjYlMXVzW','Dw5VDgvZDc8Uzw52','Dw5RBM93BI1YDw5UzxiTA2v5','vu5pvevtvf9mt0DFtevwruW','otu1nZzmu1HisMy','vu5pvevtvf9orvrxt1jl','C3rHCNrZv2L0Aa','ywrK','B2jQzwn0','DhjPBq','igLZigfSC28GC2v0igLUihvUB3rLC3qVlNnLy3jLDhmG4OcuihrOzsbZzwnYzxqGDMfSDwuGC2HHzg93CYb0AgLZig9Uzs4','vu5pvevtvf9qt1bvuf9huKfdrv9nuW','x2HLBhbLCNm','zw52q29UDgvUDa','lNzPzxDLCI5SB2C','CMvWBgfJzq','iI4G','C2XPy2u','C2fUAxrPEMvsDw5jzfnLz21LBNq','CMvNzxG','mtrMAhPIDMu','zhvWBgLJyxrL','Dg9tDhjPBMC','Aw5KzxHpzG','yxbW','AxnbC3nPz25Tzw50t2y','Aw5Zzxj0rw52vMfY','C2vJCMv0C0zPBgvgB3i','AM9PBG','uNvUBMvYtM90q29UzMLNDxjLzevYCM9Y','C291CMnLCY5QC29U','y3j5ChrV','DgvZDa','vu5pvevtvf9eruzbvuXux1rjtuvpvvrFtvm','C2vJCMv0CW','ChvZAa','zMLUzeLUzgv4','zgvSzxrLu2HHzg93v2fYBMLUzW','igLZig5VDcbHigTUB3DUihj1BM5LCIbZzxr0Aw5NiokaLcbJAg9VC2uGB25LigzYB20GDgHLihj1BM5LCI1JB25MAwCGBgLZDc4','BxvZDcbUB3qGC3rHCNqGD2L0AcaNxYCGkhjLC2vYDMvKkq','Axntzwn0Aw9UrgL2AwrLCG','ig11C3qGyMuGvvbqrvjFu05bs0uGkguUzY4Gqvbqx0jbu0vFvvjmksbZBYbHihnJzw5HCMLVignHBIbYzwzLCMvUy2uGAxqGyNKGBMfTzs4','y2f0zwDVCML6zvzHCMLHyMXL','mZq2odK5B01ouhby','iokaLcbWAwnRigeGzgLMzMvYzw50ig5HBwuGB3iGzwrPDcb0AguGzxHPC3rPBMCGDMfSDwuU','C2vYAwfSAxPLrw52vMfSDwu','iYaTls0G','BxvZDcbUB3qGyMuGzw1WDhK','CNvUDgLTzs5QC29U','igfSCMvHzhKGzxHPC3rZigLUia','ndvArK55CfK','zw52','C3rKB3v0lMXVzW','CMvTB3zLrw52vMfY','CNvUBMvY','vu5pvevtvf9cuK9xu0vs','ztjL','lNzPzxDLCI5SB2nR','vu5pvevtvf9erujvr19quKvwsuvxx0jzvevt','zMLSDgvY','C2vJCMv0C0nVBNrLBNq','mZGWnJnfCgf1D2C','C3bSAxq','qxbW','y29TBwfUzhmUANnVBMW','Dw5VDgvZDa','CgXHBKfKzfzHCMLHyMXL','vu5pvevtvf9iruferuq','DMfSAwrHDgvtzwDTzw50tMfTzq','C3bSAwnL','BxvZDcbUB3qGyMuGiI4Iig9YiciUlIi','BwfUAwzLC3qUANnVBG'];_0x51ae=function(){return _0x2131f0;};return _0x51ae();}function envFileFor(_0xc63703){return _0xc63703?ENV_FILE+'.'+_0xc63703:ENV_FILE;}__name(envFileFor,'envFileFor');function secretsFileFor(_0x45ac5d){return _0x45ac5d?SECRETS_FILE+'.'+_0x45ac5d:SECRETS_FILE;}__name(secretsFileFor,_0x1f0e61(0x23b));function activeEnvName(_0x27e8e9){const _0x268161=_0x1f0e61,_0x250b3b=_0x27e8e9[_0x268161(0x1f7)]?.['trim']();return _0x250b3b?_0x250b3b:void 0x0;}function _0x33f9(_0x2e96f1,_0x5b0908){_0x2e96f1=_0x2e96f1-0x1ec;const _0x51aebd=_0x51ae();let _0x33f91d=_0x51aebd[_0x2e96f1];if(_0x33f9['mirZHF']===undefined){var _0x56bae3=function(_0x51aad6){const _0x11a841='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x55616a='',_0x2ea849='';for(let _0xc63703=0x0,_0x45ac5d,_0x27e8e9,_0x250b3b=0x0;_0x27e8e9=_0x51aad6['charAt'](_0x250b3b++);~_0x27e8e9&&(_0x45ac5d=_0xc63703%0x4?_0x45ac5d*0x40+_0x27e8e9:_0x27e8e9,_0xc63703++%0x4)?_0x55616a+=String['fromCharCode'](0xff&_0x45ac5d>>(-0x2*_0xc63703&0x6)):0x0){_0x27e8e9=_0x11a841['indexOf'](_0x27e8e9);}for(let _0x53a502=0x0,_0x2a672f=_0x55616a['length'];_0x53a502<_0x2a672f;_0x53a502++){_0x2ea849+='%'+('00'+_0x55616a['charCodeAt'](_0x53a502)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2ea849);};_0x33f9['KPQEhF']=_0x56bae3,_0x33f9['FSigyn']={},_0x33f9['mirZHF']=!![];}const _0x273467=_0x51aebd[0x0],_0x5a525f=_0x2e96f1+_0x273467,_0x551b20=_0x33f9['FSigyn'][_0x5a525f];return!_0x551b20?(_0x33f91d=_0x33f9['KPQEhF'](_0x33f91d),_0x33f9['FSigyn'][_0x5a525f]=_0x33f91d):_0x33f91d=_0x551b20,_0x33f91d;}__name(activeEnvName,'activeEnvName');function isRegexLiteral(_0x53a502){const _0x9e11bf={_0x359d3b:0x228},_0x3b88e3=_0x1f0e61;return typeof _0x53a502===_0x3b88e3(_0x9e11bf._0x359d3b)&&_0x53a502!==null&&_0x53a502[_0x3b88e3(0x1fc)]==='regex'&&typeof _0x53a502[_0x3b88e3(0x203)]===_0x3b88e3(0x214)&&typeof _0x53a502['flags']==='string';}__name(isRegexLiteral,_0x1f0e61(0x21f));function regexLiteral(_0x2a672f,_0x50f6e0=''){const _0x35d2d4={_0x3b5303:0x233},_0x741b72=_0x1f0e61;return{'kind':_0x741b72(_0x35d2d4._0x3b5303),'source':_0x2a672f,'flags':_0x50f6e0};}__name(regexLiteral,_0x1f0e61(0x202));var RAND_BYTES=0x3;function makeRunId(_0x36f805){const _0x947e41={_0x58b3cc:0x236,_0x562653:0x23f},_0x2ad894=_0x1f0e61,_0x3d2060=sanitizeRunIdSegment(_0x36f805),_0x5160e2=Date['now']()[_0x2ad894(_0x947e41._0x58b3cc)](0x24),_0x2b69d4=new Uint8Array(RAND_BYTES);globalThis[_0x2ad894(_0x947e41._0x562653)]['getRandomValues'](_0x2b69d4);let _0x57fdcc='';for(let _0x4083cc=0x0;_0x4083cc<_0x2b69d4[_0x2ad894(0x21e)];_0x4083cc++){_0x57fdcc+=_0x2b69d4[_0x4083cc][_0x2ad894(_0x947e41._0x58b3cc)](0x10)[_0x2ad894(0x218)](0x2,'0');}return _0x3d2060+'-'+_0x5160e2+'-'+_0x57fdcc;}__name(makeRunId,'makeRunId');function sanitizeRunIdSegment(_0xe3bd1d){const _0x467364={_0x24e5be:0x21e},_0x4a8dee=_0x1f0e61,_0xe79735=_0xe3bd1d[_0x4a8dee(0x22f)](/[^a-zA-Z0-9_-]+/g,'-')['replace'](/-+/g,'-')[_0x4a8dee(0x22f)](/^-|-$/g,'');return _0xe79735[_0x4a8dee(_0x467364._0x24e5be)]>0x0?_0xe79735:_0x4a8dee(0x215);}__name(sanitizeRunIdSegment,_0x1f0e61(0x232));var COLLECTION_NAME_FORBIDDEN_RE=/[\\/:*?"<>|\x00-\x1f]/;function validateCollectionName(_0xbc4dce){const _0x479df4={_0x5351f5:0x229,_0x39eee9:0x21e,_0x5ab7b3:0x24f,_0x45ef4f:0x226,_0x4e9515:0x240,_0x3887ad:0x219},_0x268c8b=_0x1f0e61;if(typeof _0xbc4dce!=='string')return'must\x20be\x20a\x20string';const _0x3550bc=_0xbc4dce[_0x268c8b(_0x479df4._0x5351f5)]();if(_0x3550bc[_0x268c8b(_0x479df4._0x39eee9)]===0x0)return _0x268c8b(_0x479df4._0x5ab7b3);if(_0x3550bc==='.'||_0x3550bc==='..')return _0x268c8b(0x1f3);if(_0x3550bc[_0x268c8b(_0x479df4._0x45ef4f)]('.'))return _0x268c8b(0x209);if(COLLECTION_NAME_FORBIDDEN_RE[_0x268c8b(_0x479df4._0x4e9515)](_0x3550bc))return _0x268c8b(_0x479df4._0x3887ad);return null;}__name(validateCollectionName,'validateCollectionName');var RUN_MANIFEST_FILE=_0x1f0e61(0x1f4),RUN_SOURCES_FILE=_0x1f0e61(0x23e),UnsupportedRunKindError=class extends Error{static{__name(this,_0x1f0e61(0x1f8));}constructor(_0x9ee938,_0x2b19b5){const _0x1bf2d3=_0x1f0e61;super('runner\x20\x22'+_0x2b19b5+_0x1bf2d3(0x1f6)+_0x9ee938+'\x22'),this['name']=_0x1bf2d3(0x1f8);}},RunnerAdapterNotFoundError=class extends Error{static{__name(this,_0x1f0e61(0x208));}constructor(_0xcb36ad,_0x5d07d3){const _0x2818de={_0x529a02:0x1fe,_0x2cbf13:0x208},_0x2ecb25=_0x1f0e61;super(_0x2ecb25(_0x2818de._0x529a02)+_0xcb36ad+_0x2ecb25(0x230)+_0x5d07d3),this['name']=_0x2ecb25(_0x2818de._0x2cbf13);}},RunnerNotConfiguredError=class extends Error{static{__name(this,'RunnerNotConfiguredError');}constructor(_0x4570c2){const _0x59a39c={_0x3825bb:0x211},_0x3da234=_0x1f0e61;super(_0x4570c2),this[_0x3da234(_0x59a39c._0x3825bb)]=_0x3da234(0x23d);}},SEGMENT_NAME_FORBIDDEN_RE=/[\\/:*?"<>|\x00-\x1f]/;function validateSegmentName(_0x5c3b0e){const _0x5a3c1e={_0xa8ba3e:0x24f,_0x12b4c2:0x1f3,_0x5b4a98:0x226,_0x2bb7db:0x247,_0x30c8cd:0x240},_0x45da77=_0x1f0e61;if(typeof _0x5c3b0e!=='string')return'must\x20be\x20a\x20string';const _0xa31cd7=_0x5c3b0e['trim']();if(_0xa31cd7[_0x45da77(0x21e)]===0x0)return _0x45da77(_0x5a3c1e._0xa8ba3e);if(_0xa31cd7==='.'||_0xa31cd7==='..')return _0x45da77(_0x5a3c1e._0x12b4c2);if(_0xa31cd7[_0x45da77(_0x5a3c1e._0x5b4a98)]('.'))return _0x45da77(0x209);if(_0xa31cd7[_0x45da77(_0x5a3c1e._0x5b4a98)]('_'))return _0x45da77(_0x5a3c1e._0x2bb7db);if(SEGMENT_NAME_FORBIDDEN_RE[_0x45da77(_0x5a3c1e._0x30c8cd)](_0xa31cd7))return'must\x20not\x20contain\x20\x5c\x20/\x20:\x20*\x20?\x20\x22\x20<\x20>\x20|\x20or\x20control\x20characters';return null;}__name(validateSegmentName,_0x1f0e61(0x1f1));var TERMINAL_WS_EVENT='terminal',RUNNER_CONFIG_KEYS=new Set([_0x1f0e61(0x257),_0x1f0e61(0x1f0),'UNOTEST_SLOW_MO',_0x1f0e61(0x241),'UNOTEST_DEFAULT_NAVIGATION_TIMEOUT_MS',_0x1f0e61(0x22b),_0x1f0e61(0x1f9),'UNOTEST_TIMEZONE',_0x1f0e61(0x223),_0x1f0e61(0x20e),_0x1f0e61(0x216),'UNOTEST_DEBUG_MAX_BYTES',_0x1f0e61(0x25a),_0x1f0e61(0x206),_0x1f0e61(0x20c),_0x1f0e61(0x225),_0x1f0e61(0x1fa),_0x1f0e61(0x217),'NO_COLOR','FORCE_COLOR',_0x1f0e61(0x20b)]);function isRunnerConfigKey(_0x38536f){const _0x3a6264=_0x1f0e61;return RUNNER_CONFIG_KEYS[_0x3a6264(0x21a)](_0x38536f);}__name(isRunnerConfigKey,'isRunnerConfigKey');function categorizeVariable(_0x2b874){const _0x4c935b={_0x168734:0x203,_0x350445:0x242,_0x55f45b:0x1fd},_0x368e97=_0x1f0e61;if(_0x2b874[_0x368e97(_0x4c935b._0x168734)]===_0x368e97(_0x4c935b._0x350445))return _0x368e97(_0x4c935b._0x55f45b);return isRunnerConfigKey(_0x2b874['name'])?_0x368e97(0x256):_0x368e97(0x238);}__name(categorizeVariable,_0x1f0e61(0x24a));function isExternalVarName(_0xac84a0){const _0x4cc968={_0x3bbd51:0x240},_0x5b803e=_0x1f0e61;return/^[A-Z][A-Z0-9_]*$/[_0x5b803e(_0x4cc968._0x3bbd51)](_0xac84a0);}__name(isExternalVarName,_0x1f0e61(0x1f5));function serializeEnvValue(_0x58f93f){const _0xa7ee4f={_0x1e58da:0x240,_0x1e72ab:0x22f},_0x479ca7=_0x1f0e61;if(_0x58f93f==='')return'';if(/[\s#"'=\\]|^[`]/['test'](_0x58f93f)||/[\n\r]/[_0x479ca7(_0xa7ee4f._0x1e58da)](_0x58f93f)){const _0x397997=_0x58f93f[_0x479ca7(_0xa7ee4f._0x1e72ab)](/\\/g,'\x5c\x5c')[_0x479ca7(0x22f)](/"/g,'\x5c\x22')[_0x479ca7(_0xa7ee4f._0x1e72ab)](/\n/g,'\x5cn')[_0x479ca7(_0xa7ee4f._0x1e72ab)](/\r/g,'\x5cr');return'\x22'+_0x397997+'\x22';}return _0x58f93f;}__name(serializeEnvValue,_0x1f0e61(0x24d));function envKeys(_0x534855){const _0x25e112={_0x37da95:0x25e,_0x4b476b:0x229,_0x51891e:0x240,_0x24be55:0x227},_0x56be10=_0x1f0e61,_0x23cfac=new Set();for(const _0x2ba23f of _0x534855[_0x56be10(_0x25e112._0x37da95)](/\r?\n/)){const _0x6e3c9=_0x2ba23f[_0x56be10(_0x25e112._0x4b476b)]();if(_0x6e3c9===''||_0x6e3c9[_0x56be10(0x226)]('#'))continue;const _0x111485=_0x6e3c9['indexOf']('=');if(_0x111485<=0x0)continue;const _0x36d4cc=_0x6e3c9['slice'](0x0,_0x111485)[_0x56be10(0x229)]();if(/^[A-Za-z_][A-Za-z0-9_]*$/[_0x56be10(_0x25e112._0x51891e)](_0x36d4cc))_0x23cfac[_0x56be10(_0x25e112._0x24be55)](_0x36d4cc);}return _0x23cfac;}__name(envKeys,_0x1f0e61(0x1fb));function isSectionDivider(_0x59aa3b){const _0x4c6a02={_0x41c6a4:0x226},_0x46402d=_0x1f0e61,_0x537627=_0x59aa3b[_0x46402d(0x229)]();return _0x537627[_0x46402d(_0x4c6a02._0x41c6a4)]('#')&&/---/[_0x46402d(0x240)](_0x537627);}__name(isSectionDivider,_0x1f0e61(0x248));function isAssignmentLine(_0x8ece7d){const _0x1a0f81={_0x1d0949:0x237,_0x527170:0x231},_0x2814aa=_0x1f0e61,_0x25dd6b=_0x8ece7d[_0x2814aa(0x229)]();if(_0x25dd6b===''||_0x25dd6b[_0x2814aa(0x226)]('#'))return![];const _0x318078=_0x25dd6b[_0x2814aa(_0x1a0f81._0x1d0949)]('=');return _0x318078>0x0&&/^[A-Za-z_][A-Za-z0-9_]*$/[_0x2814aa(0x240)](_0x25dd6b[_0x2814aa(_0x1a0f81._0x527170)](0x0,_0x318078)[_0x2814aa(0x229)]());}__name(isAssignmentLine,'isAssignmentLine');function isAssignmentOf(_0x2d8764,_0x3b91d7){const _0x1b74e2=_0x1f0e61,_0x24bfb6=_0x2d8764[_0x1b74e2(0x229)]();if(_0x24bfb6===''||_0x24bfb6[_0x1b74e2(0x226)]('#'))return![];const _0xa82690=_0x24bfb6['indexOf']('=');if(_0xa82690<=0x0)return![];return _0x24bfb6[_0x1b74e2(0x231)](0x0,_0xa82690)[_0x1b74e2(0x229)]()===_0x3b91d7;}__name(isAssignmentOf,_0x1f0e61(0x239));function splitLines(_0x20d72d){const _0x45a3eb={_0x2de1f2:0x21d,_0xe1cf45:0x231,_0x281fc2:0x25e},_0x5c4cb8=_0x1f0e61,_0x2c281a=_0x20d72d[_0x5c4cb8(_0x45a3eb._0x2de1f2)]('\x0a'),_0x3355ad=_0x2c281a?_0x20d72d[_0x5c4cb8(_0x45a3eb._0xe1cf45)](0x0,-0x1):_0x20d72d;return{'lines':_0x3355ad===''?[]:_0x3355ad[_0x5c4cb8(_0x45a3eb._0x281fc2)]('\x0a'),'trailingNewline':_0x2c281a};}__name(splitLines,_0x1f0e61(0x204));function joinLines(_0x50f552,_0x14d8b8){const _0x2117fc=_0x1f0e61,_0x93be1b=_0x50f552[_0x2117fc(0x23c)]('\x0a');return _0x14d8b8||_0x93be1b===''?_0x93be1b+'\x0a':_0x93be1b;}__name(joinLines,'joinLines');function insertEnvVar(_0x188c04,_0x3e47bc,_0x2940c5,_0xed420d){const _0x2b7248={_0xd59b30:0x210,_0x288b8b:0x229,_0x5eab7d:0x243},_0x4859a1=_0x1f0e61,_0x37c865=_0x3e47bc+'='+serializeEnvValue(_0x2940c5),{lines:_0x5d31ae,trailingNewline:_0x134cb9}=splitLines(_0x188c04);if(_0xed420d){const _0x4bf986=new RegExp('\x5cb'+_0xed420d[_0x4859a1(_0x2b7248._0xd59b30)]()+'\x5cb'),_0x374d59=_0x5d31ae[_0x4859a1(0x244)](_0x3bc857=>isSectionDivider(_0x3bc857)&&_0x4bf986[_0x4859a1(0x240)](_0x3bc857[_0x4859a1(0x210)]()));if(_0x374d59!==-0x1){let _0x5f0b95=_0x5d31ae['length'];for(let _0x1466cf=_0x374d59+0x1;_0x1466cf<_0x5d31ae[_0x4859a1(0x21e)];_0x1466cf++){if(isSectionDivider(_0x5d31ae[_0x1466cf])){_0x5f0b95=_0x1466cf;break;}}let _0x49654c=-0x1,_0x1879bb=-0x1;for(let _0x55e7d2=_0x374d59+0x1;_0x55e7d2<_0x5f0b95;_0x55e7d2++){if(_0x5d31ae[_0x55e7d2][_0x4859a1(_0x2b7248._0x288b8b)]()!=='')_0x1879bb=_0x55e7d2;if(isAssignmentLine(_0x5d31ae[_0x55e7d2]))_0x49654c=_0x55e7d2;}const _0x3333f6=_0x49654c>=0x0?_0x49654c:_0x1879bb,_0x322b38=_0x3333f6>=0x0?_0x3333f6+0x1:_0x374d59+0x1;return _0x5d31ae[_0x4859a1(0x1f2)](_0x322b38,0x0,_0x37c865),joinLines(_0x5d31ae,_0x134cb9||_0x5d31ae['length']>0x0);}if(_0x5d31ae['length']>0x0)_0x5d31ae['push']('');return _0x5d31ae[_0x4859a1(_0x2b7248._0x5eab7d)](_0x4859a1(0x24e)+_0xed420d+'\x20---',_0x37c865),joinLines(_0x5d31ae,!![]);}return _0x5d31ae[_0x4859a1(0x243)](_0x37c865),joinLines(_0x5d31ae,!![]);}__name(insertEnvVar,_0x1f0e61(0x23a));function removeEnvVar(_0x52edbb,_0x248430){const _0x2d1812={_0x2bc4bc:0x25b},_0x202974=_0x1f0e61,{lines:_0x206f2b,trailingNewline:_0x45a27c}=splitLines(_0x52edbb),_0x4f6dfe=_0x206f2b[_0x202974(_0x2d1812._0x2bc4bc)](_0x42693d=>!isAssignmentOf(_0x42693d,_0x248430)),_0x23c17d=_0x4f6dfe[_0x202974(0x21e)]!==_0x206f2b[_0x202974(0x21e)];return{'content':joinLines(_0x4f6dfe,_0x45a27c),'removed':_0x23c17d};}__name(removeEnvVar,_0x1f0e61(0x255));var SECTION_BY_KIND={'app':_0x1f0e61(0x1ec),'runner':'Runner','secret':void 0x0};function planAddVariable(_0x1699f1){const _0x39dd5f={_0x4ec17c:0x222,_0x3dee5e:0x25c,_0x5f393b:0x21a,_0x71ccda:0x1fd,_0x3bc962:0x242,_0x5bf886:0x213,_0x1c05ff:0x221,_0xa68ea5:0x235,_0x5da33b:0x251,_0x1f2001:0x24c},_0x1156a9=_0x1f0e61,{name:_0x10c3e7,kind:_0x4f2b4f}=_0x1699f1;if(_0x4f2b4f===_0x1156a9(0x256)){if(!isRunnerConfigKey(_0x10c3e7))return{'ok':![],'code':_0x1156a9(_0x39dd5f._0x4ec17c),'message':_0x10c3e7+_0x1156a9(0x246)};}else{if(!isExternalVarName(_0x10c3e7))return{'ok':![],'code':_0x1156a9(0x20a),'message':_0x10c3e7+_0x1156a9(0x249)};}const _0x3bc757=envKeys(_0x1699f1[_0x1156a9(0x22d)])['has'](_0x10c3e7),_0xcd7eb7=envKeys(_0x1699f1[_0x1156a9(_0x39dd5f._0x3dee5e)])[_0x1156a9(_0x39dd5f._0x5f393b)](_0x10c3e7),_0x58d91e=_0x4f2b4f===_0x1156a9(_0x39dd5f._0x71ccda)?_0x1156a9(_0x39dd5f._0x3bc962):_0x1156a9(0x253),_0x579a83=_0x58d91e==='secrets'?_0xcd7eb7:_0x3bc757,_0xf67b1e=_0x58d91e==='secrets'?_0x1156a9(_0x39dd5f._0x5bf886):_0x1156a9(_0x39dd5f._0x1c05ff);if(_0x579a83)return{'ok':![],'code':_0x1156a9(_0x39dd5f._0xa68ea5),'message':_0x10c3e7+_0x1156a9(_0x39dd5f._0x5da33b)+_0xf67b1e+_0x1156a9(_0x39dd5f._0x1f2001)};const _0x849263=[];return _0x4f2b4f===_0x1156a9(_0x39dd5f._0x71ccda)&&_0x3bc757&&_0x849263[_0x1156a9(0x243)](_0x10c3e7+_0x1156a9(0x212)),_0x4f2b4f!==_0x1156a9(0x1fd)&&_0xcd7eb7&&_0x849263['push'](_0x10c3e7+_0x1156a9(0x22a)),{'ok':!![],'target':_0x58d91e,'sectionLabel':SECTION_BY_KIND[_0x4f2b4f],'warnings':_0x849263};}__name(planAddVariable,_0x1f0e61(0x1ef));function deleteShadowWarning(_0xf8edb1,_0x4962ce,_0x4e53ce){if(_0x4e53ce!==void 0x0&&_0x4e53ce!==_0x4962ce)return[_0xf8edb1+'\x20is\x20also\x20set\x20in\x20your\x20shell\x20environment\x20—\x20it\x20will\x20keep\x20resolving\x20from\x20there\x20(the\x20environment\x20wins\x20over\x20the\x20file).'];return[];}__name(deleteShadowWarning,_0x1f0e61(0x245));export{COLLECTIONS_SUBDIR,COLLECTION_NAME_FORBIDDEN_RE,COMMANDS_FILE,DEBUGGER_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_WS_EVENT,UNOTEST_DIR,UnsupportedRunKindError,activeEnvName,categorizeVariable,deleteShadowWarning,envFileFor,envKeys,insertEnvVar,isExternalVarName,isRegexLiteral,isRunnerConfigKey,makeRunId,planAddVariable,regexLiteral,removeEnvVar,sanitizeRunIdSegment,secretsFileFor,serializeEnvValue,validateCollectionName,validateSegmentName};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unotest/protocol",
3
- "version": "0.6.2",
3
+ "version": "0.9.0",
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": {