@tangle-network/browser-agent-driver 0.15.0 → 0.16.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.
Files changed (42) hide show
  1. package/dist/brain/index.d.ts +22 -1
  2. package/dist/brain/index.d.ts.map +1 -1
  3. package/dist/brain/index.js +57 -1
  4. package/dist/brain/index.js.map +1 -1
  5. package/dist/cli-view-live.d.ts +60 -0
  6. package/dist/cli-view-live.d.ts.map +1 -0
  7. package/dist/cli-view-live.js +216 -0
  8. package/dist/cli-view-live.js.map +1 -0
  9. package/dist/cli-view.d.ts.map +1 -1
  10. package/dist/cli-view.js +4 -1
  11. package/dist/cli-view.js.map +1 -1
  12. package/dist/cli.js +57 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/extensions/loader.d.ts +40 -0
  15. package/dist/extensions/loader.d.ts.map +1 -0
  16. package/dist/extensions/loader.js +85 -0
  17. package/dist/extensions/loader.js.map +1 -0
  18. package/dist/extensions/types.d.ts +132 -0
  19. package/dist/extensions/types.d.ts.map +1 -0
  20. package/dist/extensions/types.js +161 -0
  21. package/dist/extensions/types.js.map +1 -0
  22. package/dist/runner/decision-cache.d.ts +105 -0
  23. package/dist/runner/decision-cache.d.ts.map +1 -0
  24. package/dist/runner/decision-cache.js +150 -0
  25. package/dist/runner/decision-cache.js.map +1 -0
  26. package/dist/runner/deterministic-patterns.d.ts +41 -0
  27. package/dist/runner/deterministic-patterns.d.ts.map +1 -0
  28. package/dist/runner/deterministic-patterns.js +137 -0
  29. package/dist/runner/deterministic-patterns.js.map +1 -0
  30. package/dist/runner/events.d.ts +224 -0
  31. package/dist/runner/events.d.ts.map +1 -0
  32. package/dist/runner/events.js +147 -0
  33. package/dist/runner/events.js.map +1 -0
  34. package/dist/runner/runner.d.ts +22 -0
  35. package/dist/runner/runner.d.ts.map +1 -1
  36. package/dist/runner/runner.js +259 -8
  37. package/dist/runner/runner.js.map +1 -1
  38. package/dist/test-runner.d.ts +19 -1
  39. package/dist/test-runner.d.ts.map +1 -1
  40. package/dist/test-runner.js +18 -3
  41. package/dist/test-runner.js.map +1 -1
  42. package/package.json +1 -1
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Turn event bus — typed pub/sub for sub-turn agent events.
3
+ *
4
+ * The agent loop emits events at every phase boundary so subscribers can
5
+ * observe (live viewer SSE), persist (events.jsonl sink), and react (user
6
+ * extensions). All three consume the same event stream.
7
+ *
8
+ * Design decisions:
9
+ * - In-process only. Cross-process is the SSE server's job, not the bus.
10
+ * - Bounded retention (last N events buffered for late subscribers).
11
+ * - Synchronous fanout. Listeners that need async work do it themselves.
12
+ * - Listener errors are caught and logged — one bad subscriber must not
13
+ * crash the loop.
14
+ * - Each event is plain JSON-serializable (no class instances, no Buffers).
15
+ * This is so events.jsonl can serialize them without surgery.
16
+ *
17
+ * The Turn type from ../types.ts is the COMPLETED-turn artifact (what
18
+ * `onTurn` callbacks consume). TurnEvent is the live, sub-turn stream.
19
+ */
20
+ import type { Action, PageState, Turn } from '../types.js';
21
+ /** A discriminated union of every event the runner emits. */
22
+ export type TurnEvent = RunStartedEvent | TurnStartedEvent | ObserveStartedEvent | ObserveCompletedEvent | DecideStartedEvent | DecideTokenEvent | DecideCompletedEvent | DecideSkippedCachedEvent | DecideSkippedPatternEvent | ExecuteStartedEvent | ExecuteCompletedEvent | VerifyStartedEvent | VerifyCompletedEvent | RecoveryFiredEvent | OverrideAppliedEvent | TurnCompletedEvent | RunCompletedEvent;
23
+ interface BaseEvent {
24
+ /** Monotonic sequence number, assigned by the bus on emit */
25
+ seq: number;
26
+ /** ISO 8601 timestamp */
27
+ ts: string;
28
+ /** The agent run ID this event belongs to */
29
+ runId: string;
30
+ /** 1-indexed turn number, or 0 for run-level events */
31
+ turn: number;
32
+ }
33
+ export interface RunStartedEvent extends BaseEvent {
34
+ type: 'run-started';
35
+ goal: string;
36
+ startUrl?: string;
37
+ maxTurns: number;
38
+ }
39
+ export interface TurnStartedEvent extends BaseEvent {
40
+ type: 'turn-started';
41
+ }
42
+ export interface ObserveStartedEvent extends BaseEvent {
43
+ type: 'observe-started';
44
+ }
45
+ export interface ObserveCompletedEvent extends BaseEvent {
46
+ type: 'observe-completed';
47
+ url: string;
48
+ title: string;
49
+ /** Snapshot byte length (don't send the snapshot itself — too big for the wire) */
50
+ snapshotBytes: number;
51
+ /** Latest screenshot as a data URL, when vision is on */
52
+ screenshot?: string;
53
+ durationMs: number;
54
+ }
55
+ export interface DecideStartedEvent extends BaseEvent {
56
+ type: 'decide-started';
57
+ }
58
+ /** Emitted while the LLM is streaming tokens, for the live viewer's spinner. */
59
+ export interface DecideTokenEvent extends BaseEvent {
60
+ type: 'decide-token';
61
+ /** Cumulative tokens emitted so far (not the latest token text). */
62
+ tokenCount: number;
63
+ }
64
+ export interface DecideCompletedEvent extends BaseEvent {
65
+ type: 'decide-completed';
66
+ action: Action;
67
+ reasoning?: string;
68
+ expectedEffect?: string;
69
+ inputTokens?: number;
70
+ outputTokens?: number;
71
+ cacheReadInputTokens?: number;
72
+ durationMs: number;
73
+ }
74
+ /** The decision was served from the in-session cache; no LLM call fired. */
75
+ export interface DecideSkippedCachedEvent extends BaseEvent {
76
+ type: 'decide-skipped-cached';
77
+ action: Action;
78
+ /** SHA1 hash of the state key that hit */
79
+ cacheKey: string;
80
+ }
81
+ /** A deterministic UI pattern matched; no LLM call fired. */
82
+ export interface DecideSkippedPatternEvent extends BaseEvent {
83
+ type: 'decide-skipped-pattern';
84
+ action: Action;
85
+ patternId: string;
86
+ }
87
+ export interface ExecuteStartedEvent extends BaseEvent {
88
+ type: 'execute-started';
89
+ action: Action;
90
+ }
91
+ export interface ExecuteCompletedEvent extends BaseEvent {
92
+ type: 'execute-completed';
93
+ action: Action;
94
+ success: boolean;
95
+ error?: string;
96
+ /** Bounding box of the target element, when known (for replay overlays) */
97
+ bounds?: {
98
+ x: number;
99
+ y: number;
100
+ width: number;
101
+ height: number;
102
+ };
103
+ durationMs: number;
104
+ }
105
+ export interface VerifyStartedEvent extends BaseEvent {
106
+ type: 'verify-started';
107
+ expectedEffect: string;
108
+ }
109
+ export interface VerifyCompletedEvent extends BaseEvent {
110
+ type: 'verify-completed';
111
+ verified: boolean;
112
+ reason?: string;
113
+ durationMs: number;
114
+ }
115
+ export interface RecoveryFiredEvent extends BaseEvent {
116
+ type: 'recovery-fired';
117
+ strategy: string;
118
+ feedback: string;
119
+ forcedAction?: string;
120
+ }
121
+ export interface OverrideAppliedEvent extends BaseEvent {
122
+ type: 'override-applied';
123
+ source: 'override-pipeline' | 'extension';
124
+ reasoningTag: string;
125
+ feedback: string;
126
+ }
127
+ export interface TurnCompletedEvent extends BaseEvent {
128
+ type: 'turn-completed';
129
+ /** The full Turn artifact, ready for persistence */
130
+ turnArtifact: Turn;
131
+ }
132
+ export interface RunCompletedEvent extends BaseEvent {
133
+ type: 'run-completed';
134
+ success: boolean;
135
+ totalTurns: number;
136
+ totalMs: number;
137
+ reason?: string;
138
+ }
139
+ export type TurnEventListener = (event: TurnEvent) => void;
140
+ export interface TurnEventBusOptions {
141
+ /** Max events retained for late subscribers. Default 200. */
142
+ retention?: number;
143
+ /** Logger for listener errors. Default console.error. */
144
+ onListenerError?: (err: unknown, listener: TurnEventListener) => void;
145
+ }
146
+ /**
147
+ * In-process typed pub/sub for TurnEvents.
148
+ *
149
+ * Subscribers receive every event after subscription, plus a buffered
150
+ * replay of the last N events (default 200) so a late-attaching SSE
151
+ * client can catch up without missing context.
152
+ */
153
+ export declare class TurnEventBus {
154
+ private listeners;
155
+ private buffer;
156
+ private nextSeq;
157
+ private readonly retention;
158
+ private readonly onListenerError;
159
+ constructor(options?: TurnEventBusOptions);
160
+ /**
161
+ * Emit an event. Synchronously fans out to all listeners. Listener errors
162
+ * are caught — one bad subscriber must not crash the loop.
163
+ *
164
+ * The caller supplies the event without `seq` — the bus assigns it.
165
+ *
166
+ * The generic `E extends TurnEvent` form makes TypeScript distribute the
167
+ * `Omit` across the union so each call site sees the right per-variant
168
+ * shape. Without it, `Omit<TurnEvent, ...>` collapses to the intersection
169
+ * of all variants, which is just the BaseEvent fields.
170
+ */
171
+ emit<E extends TurnEvent>(event: DistributiveOmit<E, 'seq'>): void;
172
+ /**
173
+ * Subscribe to all future events. Returns an unsubscribe function.
174
+ *
175
+ * If `replayBuffered` is true (default), the new listener immediately
176
+ * receives every event currently in the retention buffer in order. This
177
+ * lets late subscribers (e.g., a viewer that connects mid-run) reconstruct
178
+ * recent state without missing anything.
179
+ */
180
+ subscribe(listener: TurnEventListener, replayBuffered?: boolean): () => void;
181
+ /** Snapshot the current buffer (for tests / debugging). */
182
+ getBuffered(): TurnEvent[];
183
+ /** Drop all buffered events. Listeners are NOT removed. */
184
+ clearBuffer(): void;
185
+ /** Number of currently subscribed listeners. */
186
+ get listenerCount(): number;
187
+ /** Helper for the runner: emit with an auto-filled timestamp. */
188
+ emitNow<E extends TurnEvent>(event: DistributiveOmit<E, 'seq' | 'ts'>): void;
189
+ }
190
+ /**
191
+ * Distributive Omit — applies `Omit` across each variant of a union type
192
+ * separately, so per-variant fields survive narrowing. Standard `Omit` on a
193
+ * union would collapse to the intersection of property keys (the common
194
+ * fields only), losing the discriminant.
195
+ */
196
+ type DistributiveOmit<T, K extends keyof TurnEvent> = T extends unknown ? Omit<T, K> : never;
197
+ /**
198
+ * Stable JSON serialization of a TurnEvent for events.jsonl persistence.
199
+ * The event is already plain JSON, but we drop the (potentially large)
200
+ * screenshot data URL when persisting — replay reads it from the per-turn
201
+ * report.json instead.
202
+ */
203
+ export declare function serializeForJsonl(event: TurnEvent): string;
204
+ /**
205
+ * Type guard for narrowing TurnEvent unions in subscribers.
206
+ *
207
+ * bus.subscribe((e) => {
208
+ * if (isEvent(e, 'execute-completed') && !e.success) {
209
+ * // e is now narrowed
210
+ * }
211
+ * })
212
+ */
213
+ export declare function isEvent<T extends TurnEvent['type']>(event: TurnEvent, type: T): event is Extract<TurnEvent, {
214
+ type: T;
215
+ }>;
216
+ /** Build a no-op bus for tests / contexts that don't need eventing. */
217
+ export declare function createNullBus(): TurnEventBus;
218
+ /**
219
+ * Lazy-init helper: returns the provided bus or constructs a no-op bus.
220
+ * Used by the runner so callers can opt out by passing nothing.
221
+ */
222
+ export declare function ensureBus(bus?: TurnEventBus): TurnEventBus;
223
+ export type { PageState };
224
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/runner/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Turn event bus — typed pub/sub for sub-turn agent events.
3
+ *
4
+ * The agent loop emits events at every phase boundary so subscribers can
5
+ * observe (live viewer SSE), persist (events.jsonl sink), and react (user
6
+ * extensions). All three consume the same event stream.
7
+ *
8
+ * Design decisions:
9
+ * - In-process only. Cross-process is the SSE server's job, not the bus.
10
+ * - Bounded retention (last N events buffered for late subscribers).
11
+ * - Synchronous fanout. Listeners that need async work do it themselves.
12
+ * - Listener errors are caught and logged — one bad subscriber must not
13
+ * crash the loop.
14
+ * - Each event is plain JSON-serializable (no class instances, no Buffers).
15
+ * This is so events.jsonl can serialize them without surgery.
16
+ *
17
+ * The Turn type from ../types.ts is the COMPLETED-turn artifact (what
18
+ * `onTurn` callbacks consume). TurnEvent is the live, sub-turn stream.
19
+ */
20
+ /**
21
+ * In-process typed pub/sub for TurnEvents.
22
+ *
23
+ * Subscribers receive every event after subscription, plus a buffered
24
+ * replay of the last N events (default 200) so a late-attaching SSE
25
+ * client can catch up without missing context.
26
+ */
27
+ export class TurnEventBus {
28
+ listeners = new Set();
29
+ buffer = [];
30
+ nextSeq = 1;
31
+ retention;
32
+ onListenerError;
33
+ constructor(options = {}) {
34
+ this.retention = options.retention ?? 200;
35
+ this.onListenerError = options.onListenerError ?? ((err, _) => {
36
+ // eslint-disable-next-line no-console
37
+ console.error('[TurnEventBus] listener threw:', err);
38
+ });
39
+ }
40
+ /**
41
+ * Emit an event. Synchronously fans out to all listeners. Listener errors
42
+ * are caught — one bad subscriber must not crash the loop.
43
+ *
44
+ * The caller supplies the event without `seq` — the bus assigns it.
45
+ *
46
+ * The generic `E extends TurnEvent` form makes TypeScript distribute the
47
+ * `Omit` across the union so each call site sees the right per-variant
48
+ * shape. Without it, `Omit<TurnEvent, ...>` collapses to the intersection
49
+ * of all variants, which is just the BaseEvent fields.
50
+ */
51
+ emit(event) {
52
+ const full = { ...event, seq: this.nextSeq++ };
53
+ this.buffer.push(full);
54
+ if (this.buffer.length > this.retention) {
55
+ this.buffer.shift();
56
+ }
57
+ for (const listener of this.listeners) {
58
+ try {
59
+ listener(full);
60
+ }
61
+ catch (err) {
62
+ this.onListenerError(err, listener);
63
+ }
64
+ }
65
+ }
66
+ /**
67
+ * Subscribe to all future events. Returns an unsubscribe function.
68
+ *
69
+ * If `replayBuffered` is true (default), the new listener immediately
70
+ * receives every event currently in the retention buffer in order. This
71
+ * lets late subscribers (e.g., a viewer that connects mid-run) reconstruct
72
+ * recent state without missing anything.
73
+ */
74
+ subscribe(listener, replayBuffered = true) {
75
+ if (replayBuffered) {
76
+ for (const event of this.buffer) {
77
+ try {
78
+ listener(event);
79
+ }
80
+ catch (err) {
81
+ this.onListenerError(err, listener);
82
+ }
83
+ }
84
+ }
85
+ this.listeners.add(listener);
86
+ return () => {
87
+ this.listeners.delete(listener);
88
+ };
89
+ }
90
+ /** Snapshot the current buffer (for tests / debugging). */
91
+ getBuffered() {
92
+ return [...this.buffer];
93
+ }
94
+ /** Drop all buffered events. Listeners are NOT removed. */
95
+ clearBuffer() {
96
+ this.buffer = [];
97
+ }
98
+ /** Number of currently subscribed listeners. */
99
+ get listenerCount() {
100
+ return this.listeners.size;
101
+ }
102
+ /** Helper for the runner: emit with an auto-filled timestamp. */
103
+ emitNow(event) {
104
+ // The cast is safe: E extends TurnEvent and we're adding the missing
105
+ // ts field. The discriminated union narrowing happens at the call site.
106
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
107
+ this.emit({ ...event, ts: new Date().toISOString() });
108
+ }
109
+ }
110
+ // ── Utilities ───────────────────────────────────────────────────────────
111
+ /**
112
+ * Stable JSON serialization of a TurnEvent for events.jsonl persistence.
113
+ * The event is already plain JSON, but we drop the (potentially large)
114
+ * screenshot data URL when persisting — replay reads it from the per-turn
115
+ * report.json instead.
116
+ */
117
+ export function serializeForJsonl(event) {
118
+ if (event.type === 'observe-completed' && event.screenshot) {
119
+ const { screenshot: _screenshot, ...rest } = event;
120
+ return JSON.stringify(rest);
121
+ }
122
+ return JSON.stringify(event);
123
+ }
124
+ /**
125
+ * Type guard for narrowing TurnEvent unions in subscribers.
126
+ *
127
+ * bus.subscribe((e) => {
128
+ * if (isEvent(e, 'execute-completed') && !e.success) {
129
+ * // e is now narrowed
130
+ * }
131
+ * })
132
+ */
133
+ export function isEvent(event, type) {
134
+ return event.type === type;
135
+ }
136
+ /** Build a no-op bus for tests / contexts that don't need eventing. */
137
+ export function createNullBus() {
138
+ return new TurnEventBus({ retention: 0 });
139
+ }
140
+ /**
141
+ * Lazy-init helper: returns the provided bus or constructs a no-op bus.
142
+ * Used by the runner so callers can opt out by passing nothing.
143
+ */
144
+ export function ensureBus(bus) {
145
+ return bus ?? createNullBus();
146
+ }
147
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/runner/events.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,8 @@ import type { Driver } from '../drivers/types.js';
13
13
  import type { Scenario, AgentConfig, AgentResult, Turn } from '../types.js';
14
14
  import type { ProjectStore } from '../memory/project-store.js';
15
15
  import { RunRegistry } from '../memory/run-registry.js';
16
+ import { TurnEventBus } from './events.js';
17
+ import type { ResolvedExtensions } from '../extensions/types.js';
16
18
  export interface BrowserAgentOptions {
17
19
  driver: Driver;
18
20
  config?: AgentConfig;
@@ -26,6 +28,22 @@ export interface BrowserAgentOptions {
26
28
  projectStore?: ProjectStore;
27
29
  /** Run registry for orchestration-facing manifests */
28
30
  runRegistry?: RunRegistry;
31
+ /**
32
+ * Optional TurnEventBus for sub-turn observability. The runner emits events
33
+ * at every phase boundary (observe-start/end, decide-start/end, execute,
34
+ * verify, recovery, override, turn-start/end). When omitted, a no-op bus is
35
+ * used so existing call sites are unchanged.
36
+ *
37
+ * Subscribers: live SSE viewer, events.jsonl persistence, user extensions.
38
+ */
39
+ eventBus?: TurnEventBus;
40
+ /**
41
+ * Pre-resolved user extensions (loaded from bad.config.{js,mjs,ts} or via
42
+ * --extension flags). The runner subscribes them to the event bus, applies
43
+ * mutateDecision after the LLM decide step, and forwards rule additions to
44
+ * the brain's system prompt composer.
45
+ */
46
+ extensions?: ResolvedExtensions;
29
47
  }
30
48
  export declare class BrowserAgent {
31
49
  private driver;
@@ -39,6 +57,10 @@ export declare class BrowserAgent {
39
57
  private knowledge?;
40
58
  private selectorCache?;
41
59
  private cachedPostState;
60
+ private bus;
61
+ private currentRunId;
62
+ private decisionCache?;
63
+ private extensions?;
42
64
  constructor(options: BrowserAgentOptions);
43
65
  run(scenario: Scenario): Promise<AgentResult>;
44
66
  private selectFollowUpActions;
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/runner/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAuC,MAAM,aAAa,CAAC;AAKjH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAsB/D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AA0CxD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9B,wDAAwD;IACxD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACnG,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sEAAsE;IACtE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,sDAAsD;IACtD,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAC,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAqF;IAC3G,OAAO,CAAC,mBAAmB,CAAC,CAAS;IACrC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,SAAS,CAAC,CAAe;IACjC,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,eAAe,CAAwB;gBAEnC,OAAO,EAAE,mBAAmB;IAWlC,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC;IAmuCnD,OAAO,CAAC,qBAAqB;IA2B7B,qEAAqE;IACrE,OAAO,CAAC,UAAU;IAclB;;;;;;;;;;;;OAYG;YACW,YAAY;YAkCZ,+BAA+B;YAgE/B,mCAAmC;YAwCnC,6BAA6B;YA4C7B,qCAAqC;YAqBrC,4BAA4B;YA4B5B,4BAA4B;YAkC5B,wBAAwB;CASvC;AAED,2BAA2B;AAC3B,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,GAC5C,OAAO,CAAC,WAAW,CAAC,CAGtB"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/runner/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAuC,MAAM,aAAa,CAAC;AAKjH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAsB/D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAa,MAAM,aAAa,CAAC;AAGtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AA0CjE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC9B,wDAAwD;IACxD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACnG,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sEAAsE;IACtE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,sDAAsD;IACtD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAC,CAAuB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAqF;IAC3G,OAAO,CAAC,mBAAmB,CAAC,CAAS;IACrC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,SAAS,CAAC,CAAe;IACjC,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,YAAY,CAAM;IAK1B,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,UAAU,CAAC,CAAqB;gBAE5B,OAAO,EAAE,mBAAmB;IAyBlC,GAAG,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC;IAm9CnD,OAAO,CAAC,qBAAqB;IA2B7B,qEAAqE;IACrE,OAAO,CAAC,UAAU;IAclB;;;;;;;;;;;;OAYG;YACW,YAAY;YAkCZ,+BAA+B;YAgE/B,mCAAmC;YAwCnC,6BAA6B;YA4C7B,qCAAqC;YAqBrC,4BAA4B;YA4B5B,4BAA4B;YAkC5B,wBAAwB;CASvC;AAED,2BAA2B;AAC3B,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAC,GAC5C,OAAO,CAAC,WAAW,CAAC,CAGtB"}