@tangle-network/browser-agent-driver 0.24.1 → 0.25.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 (84) hide show
  1. package/dist/brain/index.d.ts +5 -0
  2. package/dist/brain/index.d.ts.map +1 -1
  3. package/dist/brain/index.js +80 -32
  4. package/dist/brain/index.js.map +1 -1
  5. package/dist/cli-attach.d.ts +128 -0
  6. package/dist/cli-attach.d.ts.map +1 -0
  7. package/dist/cli-attach.js +254 -0
  8. package/dist/cli-attach.js.map +1 -0
  9. package/dist/cli-preview.d.ts +59 -0
  10. package/dist/cli-preview.d.ts.map +1 -0
  11. package/dist/cli-preview.js +144 -0
  12. package/dist/cli-preview.js.map +1 -0
  13. package/dist/cli-share.d.ts +77 -0
  14. package/dist/cli-share.d.ts.map +1 -0
  15. package/dist/cli-share.js +141 -0
  16. package/dist/cli-share.js.map +1 -0
  17. package/dist/cli-ui.d.ts.map +1 -1
  18. package/dist/cli-ui.js +15 -1
  19. package/dist/cli-ui.js.map +1 -1
  20. package/dist/cli.js +262 -14
  21. package/dist/cli.js.map +1 -1
  22. package/dist/drivers/cursor-overlay.d.ts +18 -10
  23. package/dist/drivers/cursor-overlay.d.ts.map +1 -1
  24. package/dist/drivers/cursor-overlay.js +221 -30
  25. package/dist/drivers/cursor-overlay.js.map +1 -1
  26. package/dist/drivers/overlay-label.d.ts +33 -0
  27. package/dist/drivers/overlay-label.d.ts.map +1 -0
  28. package/dist/drivers/overlay-label.js +92 -0
  29. package/dist/drivers/overlay-label.js.map +1 -0
  30. package/dist/drivers/playwright.d.ts +30 -0
  31. package/dist/drivers/playwright.d.ts.map +1 -1
  32. package/dist/drivers/playwright.js +204 -16
  33. package/dist/drivers/playwright.js.map +1 -1
  34. package/dist/drivers/snapshot.d.ts +12 -0
  35. package/dist/drivers/snapshot.d.ts.map +1 -1
  36. package/dist/drivers/snapshot.js +17 -0
  37. package/dist/drivers/snapshot.js.map +1 -1
  38. package/dist/drivers/types.d.ts +13 -0
  39. package/dist/drivers/types.d.ts.map +1 -1
  40. package/dist/multi-actor.d.ts.map +1 -1
  41. package/dist/multi-actor.js +4 -0
  42. package/dist/multi-actor.js.map +1 -1
  43. package/dist/run-state.d.ts.map +1 -1
  44. package/dist/run-state.js +12 -2
  45. package/dist/run-state.js.map +1 -1
  46. package/dist/runner/interrupt-controller.d.ts +67 -0
  47. package/dist/runner/interrupt-controller.d.ts.map +1 -0
  48. package/dist/runner/interrupt-controller.js +142 -0
  49. package/dist/runner/interrupt-controller.js.map +1 -0
  50. package/dist/runner/overlay-narration.d.ts +83 -0
  51. package/dist/runner/overlay-narration.d.ts.map +1 -0
  52. package/dist/runner/overlay-narration.js +172 -0
  53. package/dist/runner/overlay-narration.js.map +1 -0
  54. package/dist/runner/parallel-runner.d.ts +4 -0
  55. package/dist/runner/parallel-runner.d.ts.map +1 -1
  56. package/dist/runner/parallel-runner.js +1 -0
  57. package/dist/runner/parallel-runner.js.map +1 -1
  58. package/dist/runner/runner.d.ts +17 -0
  59. package/dist/runner/runner.d.ts.map +1 -1
  60. package/dist/runner/runner.js +72 -50
  61. package/dist/runner/runner.js.map +1 -1
  62. package/dist/runner/stream-webhook.d.ts +70 -0
  63. package/dist/runner/stream-webhook.d.ts.map +1 -0
  64. package/dist/runner/stream-webhook.js +132 -0
  65. package/dist/runner/stream-webhook.js.map +1 -0
  66. package/dist/skills/domain-loader.d.ts +78 -0
  67. package/dist/skills/domain-loader.d.ts.map +1 -0
  68. package/dist/skills/domain-loader.js +201 -0
  69. package/dist/skills/domain-loader.js.map +1 -0
  70. package/dist/skills/macro-loader.d.ts +95 -0
  71. package/dist/skills/macro-loader.d.ts.map +1 -0
  72. package/dist/skills/macro-loader.js +237 -0
  73. package/dist/skills/macro-loader.js.map +1 -0
  74. package/dist/supervisor/critic.js +1 -1
  75. package/dist/supervisor/policy.js +7 -0
  76. package/dist/supervisor/policy.js.map +1 -1
  77. package/dist/test-runner.d.ts +13 -0
  78. package/dist/test-runner.d.ts.map +1 -1
  79. package/dist/test-runner.js +6 -0
  80. package/dist/test-runner.js.map +1 -1
  81. package/dist/types.d.ts +19 -1
  82. package/dist/types.d.ts.map +1 -1
  83. package/dist/viewer/viewer.html +122 -8
  84. package/package.json +3 -2
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Attach mode — connect to the user's already-running Chrome via CDP.
3
+ *
4
+ * Inspired by browser-use/browser-harness. The agent drives the user's
5
+ * real browser instead of launching a fresh Chromium, which preserves
6
+ * login state, cookies, SSO — the workflows that "automate anything
7
+ * I'm already logged into" need.
8
+ *
9
+ * Two entrypoints:
10
+ * - `bad --attach` probes 127.0.0.1:9222 (or `--attach-port`),
11
+ * populates the existing cdpUrl path at cli.ts:916.
12
+ * - `bad chrome-debug` launches the user's system Chrome with
13
+ * `--remote-debugging-port=<port>` pointed at their default profile
14
+ * so attach has something to connect to.
15
+ *
16
+ * Attach is fundamentally incompatible with wallet mode and extension
17
+ * loading — both require launchPersistentContext. Those combinations
18
+ * error out with a clear message rather than silently ignoring flags.
19
+ */
20
+ import { spawn } from 'node:child_process';
21
+ export declare const DEFAULT_ATTACH_PORT = 9222;
22
+ export interface ChromeDebugInfo {
23
+ /** WebSocket URL for CDP (passable to playwright.chromium.connectOverCDP) */
24
+ webSocketDebuggerUrl: string;
25
+ /** Human-readable browser label (e.g. "Chrome/131.0.6778.86") */
26
+ browser?: string;
27
+ /** Raw probe payload for diagnostics */
28
+ raw: unknown;
29
+ }
30
+ export interface ProbeOptions {
31
+ host?: string;
32
+ port?: number;
33
+ /** Abort probe after this many ms. Default 1500. */
34
+ timeoutMs?: number;
35
+ /** Injected fetch for tests */
36
+ fetchImpl?: typeof fetch;
37
+ }
38
+ /**
39
+ * Probe the Chrome DevTools JSON endpoint at host:port/json/version.
40
+ * Returns connection info if Chrome is listening, null if the probe
41
+ * fails (no listener, non-JSON body, missing field, timeout).
42
+ *
43
+ * Never throws — attach UX hinges on a probe that reports "not running"
44
+ * rather than crashing when the user hasn't started Chrome yet.
45
+ */
46
+ export declare function probeChromeDebug(opts?: ProbeOptions): Promise<ChromeDebugInfo | null>;
47
+ export interface ResolveAttachOptions {
48
+ /** Host (default 127.0.0.1) */
49
+ host?: string;
50
+ /** Port (default 9222). */
51
+ port?: number;
52
+ /** Max probe attempts; ms between attempts comes from `retryDelayMs`. */
53
+ attempts?: number;
54
+ retryDelayMs?: number;
55
+ /** Injected for tests */
56
+ probeImpl?: (o: ProbeOptions) => Promise<ChromeDebugInfo | null>;
57
+ /** Injected for tests */
58
+ sleepImpl?: (ms: number) => Promise<void>;
59
+ }
60
+ /**
61
+ * Probe up to `attempts` times with `retryDelayMs` between tries.
62
+ * Returns the resolved info or throws a user-facing error explaining
63
+ * how to start Chrome with debugging enabled.
64
+ */
65
+ export declare function resolveAttachEndpoint(opts?: ResolveAttachOptions): Promise<ChromeDebugInfo>;
66
+ /** Find the user's system Chrome binary. Returns null if none found. */
67
+ export declare function findChromeBinary(platform?: NodeJS.Platform): string | null;
68
+ /**
69
+ * Return the user's default Chrome profile directory for this platform,
70
+ * or null if we can't locate it. Used by `chrome-debug` to launch against
71
+ * the real profile (so login state is preserved).
72
+ */
73
+ export declare function findChromeUserDataDir(platform?: NodeJS.Platform, homeDir?: string): string | null;
74
+ export interface ChromeDebugOptions {
75
+ port?: number;
76
+ /** Override the user-data-dir. Default: the system profile. */
77
+ userDataDir?: string;
78
+ /** Override Chrome binary path. Default: auto-detected. */
79
+ binary?: string;
80
+ /** Injected for tests */
81
+ spawnImpl?: typeof spawn;
82
+ /** Injected for tests */
83
+ probeImpl?: (o: ProbeOptions) => Promise<ChromeDebugInfo | null>;
84
+ /** Injected for tests */
85
+ platform?: NodeJS.Platform;
86
+ /** Injected for tests */
87
+ homeDir?: string;
88
+ /** Total wait time for the port to open before giving up. Default 10s. */
89
+ readyTimeoutMs?: number;
90
+ }
91
+ /**
92
+ * Launch the user's system Chrome with `--remote-debugging-port=<port>`
93
+ * against their default profile. Waits up to readyTimeoutMs for the
94
+ * port to respond, then returns the probe info.
95
+ *
96
+ * This is intentionally ergonomic over "correct for all edge cases" —
97
+ * advanced users with non-default Chrome installs or custom profiles
98
+ * should still use `--cdp-url` directly. This handles the 90% case.
99
+ */
100
+ export declare function handleChromeDebug(opts?: ChromeDebugOptions): Promise<ChromeDebugInfo>;
101
+ /**
102
+ * CLI subcommand entrypoint. Wraps handleChromeDebug with help-text
103
+ * output. Exits with the probe info printed so the user (or a shell
104
+ * script) can copy the WS URL.
105
+ */
106
+ export declare function runChromeDebugCommand(opts: {
107
+ port?: number;
108
+ userDataDir?: string;
109
+ quiet?: boolean;
110
+ }): Promise<number>;
111
+ /**
112
+ * Assert-helper used by the main run path. Hard-errors when a caller
113
+ * passed flags that attach mode cannot honor — no silent fallback, no
114
+ * "warn and do the wrong thing." If the user said --profile-dir AND
115
+ * --attach, they meant something, and we shouldn't guess.
116
+ */
117
+ export declare function validateAttachConflicts(opts: {
118
+ walletEnabled: boolean;
119
+ profileDir?: string;
120
+ extensionPaths?: string[];
121
+ userDataDir?: string;
122
+ }): {
123
+ ok: true;
124
+ } | {
125
+ ok: false;
126
+ errors: string[];
127
+ };
128
+ //# sourceMappingURL=cli-attach.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-attach.d.ts","sourceRoot":"","sources":["../src/cli-attach.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Attach mode — connect to the user's already-running Chrome via CDP.
3
+ *
4
+ * Inspired by browser-use/browser-harness. The agent drives the user's
5
+ * real browser instead of launching a fresh Chromium, which preserves
6
+ * login state, cookies, SSO — the workflows that "automate anything
7
+ * I'm already logged into" need.
8
+ *
9
+ * Two entrypoints:
10
+ * - `bad --attach` probes 127.0.0.1:9222 (or `--attach-port`),
11
+ * populates the existing cdpUrl path at cli.ts:916.
12
+ * - `bad chrome-debug` launches the user's system Chrome with
13
+ * `--remote-debugging-port=<port>` pointed at their default profile
14
+ * so attach has something to connect to.
15
+ *
16
+ * Attach is fundamentally incompatible with wallet mode and extension
17
+ * loading — both require launchPersistentContext. Those combinations
18
+ * error out with a clear message rather than silently ignoring flags.
19
+ */
20
+ import * as fs from 'node:fs';
21
+ import * as os from 'node:os';
22
+ import * as path from 'node:path';
23
+ import { spawn } from 'node:child_process';
24
+ import chalk from 'chalk';
25
+ import { cliError, cliLog } from './cli-ui.js';
26
+ export const DEFAULT_ATTACH_PORT = 9222;
27
+ /**
28
+ * Probe the Chrome DevTools JSON endpoint at host:port/json/version.
29
+ * Returns connection info if Chrome is listening, null if the probe
30
+ * fails (no listener, non-JSON body, missing field, timeout).
31
+ *
32
+ * Never throws — attach UX hinges on a probe that reports "not running"
33
+ * rather than crashing when the user hasn't started Chrome yet.
34
+ */
35
+ export async function probeChromeDebug(opts = {}) {
36
+ const host = opts.host ?? '127.0.0.1';
37
+ const port = opts.port ?? DEFAULT_ATTACH_PORT;
38
+ const timeoutMs = opts.timeoutMs ?? 1500;
39
+ const fetchImpl = opts.fetchImpl ?? fetch;
40
+ const url = `http://${host}:${port}/json/version`;
41
+ // Single AbortController spans the whole request: connect + headers +
42
+ // body read. Per the fetch spec, aborting mid-stream propagates into
43
+ // body.text()/json(), so a server that sends headers then stalls the
44
+ // body gets cut off at the same timeout as a dead-port connection.
45
+ const controller = new AbortController();
46
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
47
+ try {
48
+ const res = await fetchImpl(url, { signal: controller.signal });
49
+ if (!res.ok)
50
+ return null;
51
+ const body = await res.json();
52
+ const ws = body?.webSocketDebuggerUrl;
53
+ if (typeof ws !== 'string' || ws.length === 0)
54
+ return null;
55
+ const browserLabel = typeof body?.Browser === 'string' ? body.Browser : undefined;
56
+ return { webSocketDebuggerUrl: ws, browser: browserLabel, raw: body };
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ finally {
62
+ clearTimeout(timer);
63
+ }
64
+ }
65
+ /**
66
+ * Probe up to `attempts` times with `retryDelayMs` between tries.
67
+ * Returns the resolved info or throws a user-facing error explaining
68
+ * how to start Chrome with debugging enabled.
69
+ */
70
+ export async function resolveAttachEndpoint(opts = {}) {
71
+ const host = opts.host ?? '127.0.0.1';
72
+ const port = opts.port ?? DEFAULT_ATTACH_PORT;
73
+ const attempts = Math.max(1, opts.attempts ?? 1);
74
+ const delay = Math.max(0, opts.retryDelayMs ?? 500);
75
+ const probe = opts.probeImpl ?? probeChromeDebug;
76
+ const sleep = opts.sleepImpl ?? ((ms) => new Promise(res => setTimeout(res, ms)));
77
+ for (let i = 0; i < attempts; i++) {
78
+ const info = await probe({ host, port });
79
+ if (info)
80
+ return info;
81
+ if (i < attempts - 1)
82
+ await sleep(delay);
83
+ }
84
+ throw new Error(`No Chrome DevTools listener on ${host}:${port}. ` +
85
+ `Start your Chrome with remote debugging first:\n` +
86
+ ` bad chrome-debug\n` +
87
+ `…or pass --cdp-url <ws://...> to target a different endpoint.`);
88
+ }
89
+ /** Find the user's system Chrome binary. Returns null if none found. */
90
+ export function findChromeBinary(platform = process.platform) {
91
+ const candidates = [];
92
+ if (platform === 'darwin') {
93
+ candidates.push('/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta', '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary', '/Applications/Chromium.app/Contents/MacOS/Chromium');
94
+ }
95
+ else if (platform === 'linux') {
96
+ candidates.push('/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium', '/usr/bin/chromium-browser', '/snap/bin/chromium');
97
+ }
98
+ else if (platform === 'win32') {
99
+ candidates.push('C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe');
100
+ }
101
+ for (const candidate of candidates) {
102
+ if (fs.existsSync(candidate))
103
+ return candidate;
104
+ }
105
+ return null;
106
+ }
107
+ /**
108
+ * Return the user's default Chrome profile directory for this platform,
109
+ * or null if we can't locate it. Used by `chrome-debug` to launch against
110
+ * the real profile (so login state is preserved).
111
+ */
112
+ export function findChromeUserDataDir(platform = process.platform, homeDir = os.homedir()) {
113
+ let candidate = null;
114
+ if (platform === 'darwin') {
115
+ candidate = path.join(homeDir, 'Library', 'Application Support', 'Google', 'Chrome');
116
+ }
117
+ else if (platform === 'linux') {
118
+ candidate = path.join(homeDir, '.config', 'google-chrome');
119
+ }
120
+ else if (platform === 'win32') {
121
+ candidate = path.join(homeDir, 'AppData', 'Local', 'Google', 'Chrome', 'User Data');
122
+ }
123
+ if (candidate && fs.existsSync(candidate))
124
+ return candidate;
125
+ return null;
126
+ }
127
+ /**
128
+ * Launch the user's system Chrome with `--remote-debugging-port=<port>`
129
+ * against their default profile. Waits up to readyTimeoutMs for the
130
+ * port to respond, then returns the probe info.
131
+ *
132
+ * This is intentionally ergonomic over "correct for all edge cases" —
133
+ * advanced users with non-default Chrome installs or custom profiles
134
+ * should still use `--cdp-url` directly. This handles the 90% case.
135
+ */
136
+ export async function handleChromeDebug(opts = {}) {
137
+ const platform = opts.platform ?? process.platform;
138
+ const homeDir = opts.homeDir ?? os.homedir();
139
+ const port = opts.port ?? DEFAULT_ATTACH_PORT;
140
+ const probe = opts.probeImpl ?? probeChromeDebug;
141
+ const spawnFn = opts.spawnImpl ?? spawn;
142
+ // If Chrome is already listening on the port, just return it.
143
+ const existing = await probe({ port });
144
+ if (existing) {
145
+ cliLog('attach', `Chrome already listening on :${port} (${existing.browser ?? 'unknown'})`);
146
+ return existing;
147
+ }
148
+ const binary = opts.binary ?? findChromeBinary(platform);
149
+ if (!binary) {
150
+ throw new Error(`Could not locate a system Chrome binary on ${platform}. ` +
151
+ `Install Chrome, or start it manually with --remote-debugging-port=${port} and pass --cdp-url.`);
152
+ }
153
+ const userDataDir = opts.userDataDir ?? findChromeUserDataDir(platform, homeDir) ?? undefined;
154
+ const args = [
155
+ `--remote-debugging-port=${port}`,
156
+ '--no-first-run',
157
+ '--no-default-browser-check',
158
+ ];
159
+ if (userDataDir)
160
+ args.push(`--user-data-dir=${userDataDir}`);
161
+ cliLog('attach', `launching ${binary}`);
162
+ if (userDataDir)
163
+ cliLog('attach', `using profile ${userDataDir}`);
164
+ const child = spawnFn(binary, args, {
165
+ detached: true,
166
+ stdio: 'ignore',
167
+ });
168
+ // Capture early exit so the thrown error at deadline can name the exit
169
+ // code instead of generically saying "timed out". `detached:true` means
170
+ // we deliberately don't block on the child, but we still want to know if
171
+ // it died before our probe succeeded.
172
+ let childExitCode = null;
173
+ let childExitSignal = null;
174
+ child.on?.('exit', (code, signal) => {
175
+ childExitCode = code;
176
+ childExitSignal = signal;
177
+ });
178
+ child.unref?.();
179
+ const deadline = Date.now() + (opts.readyTimeoutMs ?? 10_000);
180
+ while (Date.now() < deadline) {
181
+ if (childExitCode !== null || childExitSignal !== null) {
182
+ throw new Error(`Chrome exited before the DevTools endpoint came up ` +
183
+ `(code=${childExitCode ?? 'null'} signal=${childExitSignal ?? 'null'}). ` +
184
+ `Another Chrome instance may be holding the profile lock — quit it and retry.`);
185
+ }
186
+ const info = await probe({ port });
187
+ if (info) {
188
+ cliLog('attach', `connected (${info.browser ?? 'chrome'})`);
189
+ return info;
190
+ }
191
+ await new Promise(res => setTimeout(res, 250));
192
+ }
193
+ // Deadline hit without a successful probe. Kill the child we spawned so
194
+ // the user doesn't accumulate zombie Chrome processes on repeated tries.
195
+ if (child.pid && !child.killed) {
196
+ try {
197
+ child.kill('SIGTERM');
198
+ }
199
+ catch { /* best-effort */ }
200
+ }
201
+ throw new Error(`Chrome launched but the DevTools endpoint didn't come up within ${opts.readyTimeoutMs ?? 10_000}ms. ` +
202
+ `Try starting Chrome manually:\n "${binary}" --remote-debugging-port=${port}`);
203
+ }
204
+ /**
205
+ * CLI subcommand entrypoint. Wraps handleChromeDebug with help-text
206
+ * output. Exits with the probe info printed so the user (or a shell
207
+ * script) can copy the WS URL.
208
+ */
209
+ export async function runChromeDebugCommand(opts) {
210
+ try {
211
+ const info = await handleChromeDebug({
212
+ port: opts.port,
213
+ userDataDir: opts.userDataDir,
214
+ });
215
+ if (!opts.quiet) {
216
+ console.log('');
217
+ console.log(` ${chalk.green('✓')} Chrome debugging: ${info.webSocketDebuggerUrl}`);
218
+ console.log(` ${chalk.dim('run:')} bad --attach ${opts.port && opts.port !== DEFAULT_ATTACH_PORT ? `--attach-port ${opts.port} ` : ''}--goal "..."`);
219
+ console.log('');
220
+ }
221
+ return 0;
222
+ }
223
+ catch (err) {
224
+ cliError(err instanceof Error ? err.message : String(err));
225
+ return 1;
226
+ }
227
+ }
228
+ /**
229
+ * Assert-helper used by the main run path. Hard-errors when a caller
230
+ * passed flags that attach mode cannot honor — no silent fallback, no
231
+ * "warn and do the wrong thing." If the user said --profile-dir AND
232
+ * --attach, they meant something, and we shouldn't guess.
233
+ */
234
+ export function validateAttachConflicts(opts) {
235
+ const errors = [];
236
+ if (opts.walletEnabled) {
237
+ errors.push('Attach mode connects to your real Chrome and cannot load the wallet extension. ' +
238
+ 'Use `bad --wallet` (without --attach) for wallet flows.');
239
+ }
240
+ if (opts.extensionPaths && opts.extensionPaths.length > 0) {
241
+ errors.push('Attach mode cannot load extensions (they must be installed in the running Chrome already). ' +
242
+ 'Drop --extension, or use `bad --wallet` for wallet extensions.');
243
+ }
244
+ if (opts.profileDir) {
245
+ errors.push('--profile-dir is incompatible with --attach. ' +
246
+ 'The attached Chrome uses its own profile — drop --profile-dir or run without --attach.');
247
+ }
248
+ if (opts.userDataDir) {
249
+ errors.push('--user-data-dir is incompatible with --attach. ' +
250
+ 'The attached Chrome uses its own data dir — drop --user-data-dir or run without --attach.');
251
+ }
252
+ return errors.length > 0 ? { ok: false, errors } : { ok: true };
253
+ }
254
+ //# sourceMappingURL=cli-attach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-attach.js","sourceRoot":"","sources":["../src/cli-attach.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * `bad preview` — plan-only mode, no execution.
3
+ *
4
+ * `terraform plan` for browser agents. Given a goal + URL, launch a
5
+ * browser, observe the page once, ask the Brain's planner to emit a
6
+ * full structured plan, render it as a dry-run tree, then EXIT without
7
+ * executing a single action.
8
+ *
9
+ * Use cases:
10
+ * - Regulated workflows where BSA / compliance needs to review the
11
+ * agent's intent before execution
12
+ * - Pre-flight for expensive long runs ("will this agent do the
13
+ * right thing? let me see the plan first")
14
+ * - Debugging — which approach is the agent taking?
15
+ *
16
+ * Library-friendly: throws `PreviewError`; CLI dispatcher catches.
17
+ *
18
+ * Implementation: reuses BrowserAgent.brain.plan() — the planner is
19
+ * already a first-class concept in the runner. We just never hand the
20
+ * plan to the executor.
21
+ */
22
+ import type { Plan } from './types.js';
23
+ export declare class PreviewError extends Error {
24
+ constructor(message: string);
25
+ }
26
+ export interface PreviewOptions {
27
+ goal: string;
28
+ url: string;
29
+ model?: string;
30
+ provider?: string;
31
+ apiKey?: string;
32
+ baseUrl?: string;
33
+ /** Write the plan as JSON to this path in addition to printing it. */
34
+ output?: string;
35
+ /** Emit JSON on stdout (pipe-friendly). */
36
+ json?: boolean;
37
+ /** Cap on plan steps. Default 12. */
38
+ maxSteps?: number;
39
+ /** Headed browser (default: headless). Useful when you want to see the page the plan is built against. */
40
+ headed?: boolean;
41
+ }
42
+ export interface PreviewResult {
43
+ goal: string;
44
+ url: string;
45
+ plan: Plan | null;
46
+ raw: string;
47
+ parseError?: string;
48
+ tokensUsed?: number;
49
+ durationMs: number;
50
+ }
51
+ /**
52
+ * Run the planner against a single observation of the URL. Never
53
+ * executes an action. Returns the structured plan + raw model output.
54
+ */
55
+ export declare function runPreview(opts: PreviewOptions): Promise<PreviewResult>;
56
+ /** Print a plan as a tree to stdout (human-readable). */
57
+ export declare function renderPreview(result: PreviewResult): void;
58
+ export declare function handlePreviewCommand(opts: PreviewOptions): Promise<PreviewResult>;
59
+ //# sourceMappingURL=cli-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-preview.d.ts","sourceRoot":"","sources":["../src/cli-preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2CAA2C;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0GAA0G;IAC1G,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAyC7E;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAkDzD;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAWvF"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * `bad preview` — plan-only mode, no execution.
3
+ *
4
+ * `terraform plan` for browser agents. Given a goal + URL, launch a
5
+ * browser, observe the page once, ask the Brain's planner to emit a
6
+ * full structured plan, render it as a dry-run tree, then EXIT without
7
+ * executing a single action.
8
+ *
9
+ * Use cases:
10
+ * - Regulated workflows where BSA / compliance needs to review the
11
+ * agent's intent before execution
12
+ * - Pre-flight for expensive long runs ("will this agent do the
13
+ * right thing? let me see the plan first")
14
+ * - Debugging — which approach is the agent taking?
15
+ *
16
+ * Library-friendly: throws `PreviewError`; CLI dispatcher catches.
17
+ *
18
+ * Implementation: reuses BrowserAgent.brain.plan() — the planner is
19
+ * already a first-class concept in the runner. We just never hand the
20
+ * plan to the executor.
21
+ */
22
+ import * as fs from 'node:fs';
23
+ import chalk from 'chalk';
24
+ export class PreviewError extends Error {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = 'PreviewError';
28
+ }
29
+ }
30
+ /**
31
+ * Run the planner against a single observation of the URL. Never
32
+ * executes an action. Returns the structured plan + raw model output.
33
+ */
34
+ export async function runPreview(opts) {
35
+ if (!opts.goal)
36
+ throw new PreviewError('preview requires --goal "..."');
37
+ if (!opts.url)
38
+ throw new PreviewError('preview requires --url "..."');
39
+ // Lazy-load the heavy surface — browser, brain, driver. Keeps
40
+ // `bad --help` snappy for users who never run preview.
41
+ const { chromium } = await import('playwright');
42
+ const { Brain } = await import('./brain/index.js');
43
+ const { PlaywrightDriver } = await import('./drivers/playwright.js');
44
+ const startedAt = Date.now();
45
+ const browser = await chromium.launch({ headless: !opts.headed });
46
+ let result;
47
+ try {
48
+ const ctx = await browser.newContext();
49
+ const page = await ctx.newPage();
50
+ await page.goto(opts.url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
51
+ const driver = new PlaywrightDriver(page, { captureScreenshots: false });
52
+ const state = await driver.observe();
53
+ const brain = new Brain({
54
+ provider: opts.provider ?? undefined,
55
+ model: opts.model,
56
+ apiKey: opts.apiKey,
57
+ baseUrl: opts.baseUrl,
58
+ });
59
+ const planResult = await brain.plan(opts.goal, state, { maxSteps: opts.maxSteps ?? 12 });
60
+ result = {
61
+ goal: opts.goal,
62
+ url: opts.url,
63
+ plan: planResult.plan,
64
+ raw: planResult.raw,
65
+ parseError: planResult.parseError,
66
+ tokensUsed: planResult.tokensUsed,
67
+ durationMs: Date.now() - startedAt,
68
+ };
69
+ }
70
+ finally {
71
+ await browser.close().catch(() => { });
72
+ }
73
+ return result;
74
+ }
75
+ /** Print a plan as a tree to stdout (human-readable). */
76
+ export function renderPreview(result) {
77
+ const G = chalk.green;
78
+ const D = chalk.dim;
79
+ const C = chalk.cyan;
80
+ const Y = chalk.yellow;
81
+ const R = chalk.red;
82
+ console.log('');
83
+ console.log(` ${chalk.bold('Goal:')} ${result.goal}`);
84
+ console.log(` ${chalk.bold('URL:')} ${result.url}`);
85
+ console.log(` ${D(`planned in ${result.durationMs}ms${result.tokensUsed ? ` · ${result.tokensUsed} tokens` : ''}`)}`);
86
+ console.log('');
87
+ if (!result.plan) {
88
+ console.log(` ${R('✗ No structured plan returned.')}`);
89
+ if (result.parseError)
90
+ console.log(` ${D('parse error:')} ${result.parseError}`);
91
+ console.log('');
92
+ console.log(` ${D('Raw model output:')}`);
93
+ console.log(indent(result.raw, ' '));
94
+ return;
95
+ }
96
+ const plan = result.plan;
97
+ const n = plan.steps.length;
98
+ console.log(` ${G(`✓ Plan: ${n} step${n === 1 ? '' : 's'}`)}`);
99
+ if (plan.reasoning)
100
+ console.log(` ${D('strategy:')} ${plan.reasoning}`);
101
+ console.log('');
102
+ for (let i = 0; i < plan.steps.length; i++) {
103
+ const s = plan.steps[i];
104
+ const action = s.action;
105
+ const verb = action.action;
106
+ const target = (() => {
107
+ switch (verb) {
108
+ case 'click': return action.selector;
109
+ case 'type': return `${action.selector} ← ${C(`"${action.text}"`)}`;
110
+ case 'press': return `${action.selector} ← ${Y(action.key)}`;
111
+ case 'navigate': return action.url;
112
+ default: return '';
113
+ }
114
+ })();
115
+ const num = String(i + 1).padStart(String(n).length, ' ');
116
+ console.log(` ${D(num + '.')} ${C(verb)}${target ? ' ' + target : ''}`);
117
+ if (s.rationale)
118
+ console.log(` ${D(s.rationale)}`);
119
+ if (s.expectedEffect)
120
+ console.log(` ${D('→ verify:')} ${s.expectedEffect}`);
121
+ }
122
+ if (plan.finalResult) {
123
+ console.log('');
124
+ console.log(` ${G('complete:')} ${plan.finalResult}`);
125
+ }
126
+ console.log('');
127
+ }
128
+ export async function handlePreviewCommand(opts) {
129
+ const result = await runPreview(opts);
130
+ if (opts.output) {
131
+ fs.writeFileSync(opts.output, JSON.stringify(result, null, 2));
132
+ }
133
+ if (opts.json) {
134
+ console.log(JSON.stringify(result, null, 2));
135
+ }
136
+ else {
137
+ renderPreview(result);
138
+ }
139
+ return result;
140
+ }
141
+ function indent(text, prefix) {
142
+ return text.split('\n').map((l) => prefix + l).join('\n');
143
+ }
144
+ //# sourceMappingURL=cli-preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-preview.js","sourceRoot":"","sources":["../src/cli-preview.ts"],"names":[],"mappings":"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"}