tuna-agent 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/claude-code-adapter.d.ts +3 -1
- package/dist/agents/claude-code-adapter.js +28 -4
- package/dist/agents/factory.d.ts +2 -1
- package/dist/agents/factory.js +2 -2
- package/dist/browser/actions/download.d.ts +16 -0
- package/dist/browser/actions/download.js +39 -0
- package/dist/browser/actions/emulation.d.ts +53 -0
- package/dist/browser/actions/emulation.js +103 -0
- package/dist/browser/actions/evaluate.d.ts +29 -0
- package/dist/browser/actions/evaluate.js +92 -0
- package/dist/browser/actions/interaction.d.ts +79 -0
- package/dist/browser/actions/interaction.js +210 -0
- package/dist/browser/actions/keyboard.d.ts +6 -0
- package/dist/browser/actions/keyboard.js +9 -0
- package/dist/browser/actions/navigation.d.ts +40 -0
- package/dist/browser/actions/navigation.js +92 -0
- package/dist/browser/actions/wait.d.ts +12 -0
- package/dist/browser/actions/wait.js +33 -0
- package/dist/browser/browser.d.ts +722 -0
- package/dist/browser/browser.js +1066 -0
- package/dist/browser/capture/activity.d.ts +22 -0
- package/dist/browser/capture/activity.js +39 -0
- package/dist/browser/capture/pdf.d.ts +6 -0
- package/dist/browser/capture/pdf.js +6 -0
- package/dist/browser/capture/response.d.ts +8 -0
- package/dist/browser/capture/response.js +28 -0
- package/dist/browser/capture/screenshot.d.ts +30 -0
- package/dist/browser/capture/screenshot.js +72 -0
- package/dist/browser/capture/trace.d.ts +13 -0
- package/dist/browser/capture/trace.js +19 -0
- package/dist/browser/chrome-launcher.d.ts +8 -0
- package/dist/browser/chrome-launcher.js +543 -0
- package/dist/browser/connection.d.ts +42 -0
- package/dist/browser/connection.js +359 -0
- package/dist/browser/index.d.ts +6 -0
- package/dist/browser/index.js +3 -0
- package/dist/browser/security.d.ts +51 -0
- package/dist/browser/security.js +357 -0
- package/dist/browser/snapshot/ai-snapshot.d.ts +12 -0
- package/dist/browser/snapshot/ai-snapshot.js +47 -0
- package/dist/browser/snapshot/aria-snapshot.d.ts +26 -0
- package/dist/browser/snapshot/aria-snapshot.js +121 -0
- package/dist/browser/snapshot/ref-map.d.ts +31 -0
- package/dist/browser/snapshot/ref-map.js +250 -0
- package/dist/browser/storage/index.d.ts +36 -0
- package/dist/browser/storage/index.js +65 -0
- package/dist/browser/types.d.ts +429 -0
- package/dist/browser/types.js +2 -0
- package/dist/cli/commands/extension.d.ts +10 -0
- package/dist/cli/commands/extension.js +86 -0
- package/dist/cli/index.js +12 -0
- package/dist/daemon/extension-handlers.d.ts +63 -0
- package/dist/daemon/extension-handlers.js +630 -0
- package/dist/daemon/index.js +173 -44
- package/dist/daemon/ws-client.d.ts +28 -8
- package/dist/daemon/ws-client.js +68 -62
- package/dist/mcp/browser-server.d.ts +11 -0
- package/dist/mcp/browser-server.js +467 -0
- package/dist/mcp/knowledge-server.d.ts +11 -0
- package/dist/mcp/knowledge-server.js +263 -0
- package/dist/mcp/setup.d.ts +20 -0
- package/dist/mcp/setup.js +94 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/utils/claude-cli.d.ts +2 -0
- package/dist/utils/claude-cli.js +29 -9
- package/dist/utils/message-schemas.d.ts +4 -1
- package/dist/utils/message-schemas.js +6 -1
- package/package.json +2 -1
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy for controlling which URLs browser navigation is allowed to reach.
|
|
3
|
+
* Defaults to trusted-network mode (private/internal addresses allowed).
|
|
4
|
+
* Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
|
|
5
|
+
*/
|
|
6
|
+
export interface SsrfPolicy {
|
|
7
|
+
/**
|
|
8
|
+
* Allow navigation to private/internal network addresses.
|
|
9
|
+
* Default: `true` (trusted-network mode). Set to `false` for strict public-only enforcement.
|
|
10
|
+
*/
|
|
11
|
+
dangerouslyAllowPrivateNetwork?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Allow navigation to private/internal network addresses.
|
|
14
|
+
* @deprecated Use `dangerouslyAllowPrivateNetwork` instead.
|
|
15
|
+
*/
|
|
16
|
+
allowPrivateNetwork?: boolean;
|
|
17
|
+
/** Hostnames explicitly allowed even if they resolve to private addresses */
|
|
18
|
+
allowedHostnames?: string[];
|
|
19
|
+
/** Alias for allowedHostnames */
|
|
20
|
+
hostnameAllowlist?: string[];
|
|
21
|
+
}
|
|
22
|
+
/** Supported browser types that can be detected and launched. */
|
|
23
|
+
export type ChromeKind = 'chrome' | 'brave' | 'edge' | 'chromium' | 'canary' | 'custom';
|
|
24
|
+
/** A detected browser executable on the system. */
|
|
25
|
+
export interface ChromeExecutable {
|
|
26
|
+
/** The type of browser (chrome, brave, edge, etc.) */
|
|
27
|
+
kind: ChromeKind;
|
|
28
|
+
/** Absolute path to the browser executable */
|
|
29
|
+
path: string;
|
|
30
|
+
}
|
|
31
|
+
/** A running Chrome instance managed by browserclaw. */
|
|
32
|
+
export interface RunningChrome {
|
|
33
|
+
/** Process ID of the Chrome process */
|
|
34
|
+
pid: number;
|
|
35
|
+
/** The browser executable that was launched */
|
|
36
|
+
exe: ChromeExecutable;
|
|
37
|
+
/** Path to the Chrome user data directory */
|
|
38
|
+
userDataDir: string;
|
|
39
|
+
/** CDP (Chrome DevTools Protocol) port number */
|
|
40
|
+
cdpPort: number;
|
|
41
|
+
/** Unix timestamp (ms) when the browser was started */
|
|
42
|
+
startedAt: number;
|
|
43
|
+
/** The child process handle */
|
|
44
|
+
proc: import('node:child_process').ChildProcess;
|
|
45
|
+
}
|
|
46
|
+
/** Options for launching a new browser instance. */
|
|
47
|
+
export interface LaunchOptions {
|
|
48
|
+
/** Run in headless mode (no visible window). Default: `false` */
|
|
49
|
+
headless?: boolean;
|
|
50
|
+
/** Path to a specific browser executable. Auto-detected if omitted. */
|
|
51
|
+
executablePath?: string;
|
|
52
|
+
/** CDP port to use. Default: `9222` */
|
|
53
|
+
cdpPort?: number;
|
|
54
|
+
/** Disable Chrome's sandbox (needed in some Docker/CI environments). Default: `false` */
|
|
55
|
+
noSandbox?: boolean;
|
|
56
|
+
/** Custom user data directory. Auto-generated if omitted. */
|
|
57
|
+
userDataDir?: string;
|
|
58
|
+
/** Chrome profile directory name (e.g. 'Profile 74'). Uses 'Default' if omitted. */
|
|
59
|
+
profileDirectory?: string;
|
|
60
|
+
/** Profile name shown in the Chrome title bar. Default: `'browserclaw'` */
|
|
61
|
+
profileName?: string;
|
|
62
|
+
/** Profile accent color as a hex string (e.g. `'#FF4500'`). Default: `'#FF4500'` */
|
|
63
|
+
profileColor?: string;
|
|
64
|
+
/** Additional Chrome command-line arguments (e.g. `['--start-maximized']`). */
|
|
65
|
+
chromeArgs?: string[];
|
|
66
|
+
/**
|
|
67
|
+
* SSRF policy controlling which URLs navigation is allowed to reach.
|
|
68
|
+
* Defaults to trusted-network mode (private/internal addresses allowed).
|
|
69
|
+
* Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
|
|
70
|
+
*/
|
|
71
|
+
ssrfPolicy?: SsrfPolicy;
|
|
72
|
+
/**
|
|
73
|
+
* Allow navigation to internal/loopback addresses (localhost, 127.x, private IPs).
|
|
74
|
+
* @deprecated Use `ssrfPolicy: { dangerouslyAllowPrivateNetwork: true }` instead.
|
|
75
|
+
*/
|
|
76
|
+
allowInternal?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/** Options for connecting to an existing browser instance. */
|
|
79
|
+
export interface ConnectOptions {
|
|
80
|
+
/**
|
|
81
|
+
* SSRF policy controlling which URLs navigation is allowed to reach.
|
|
82
|
+
* Defaults to trusted-network mode (private/internal addresses allowed).
|
|
83
|
+
* Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
|
|
84
|
+
*/
|
|
85
|
+
ssrfPolicy?: SsrfPolicy;
|
|
86
|
+
/**
|
|
87
|
+
* Allow navigation to internal/loopback addresses (localhost, 127.x, private IPs).
|
|
88
|
+
* @deprecated Use `ssrfPolicy: { dangerouslyAllowPrivateNetwork: true }` instead.
|
|
89
|
+
*/
|
|
90
|
+
allowInternal?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Bearer token for authenticating with the CDP endpoint.
|
|
93
|
+
* Required when connecting to a browser instance that has auth enabled
|
|
94
|
+
* (e.g. OpenClaw browser control with gateway.auth.token).
|
|
95
|
+
*/
|
|
96
|
+
authToken?: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Describes a single interactive element found during a snapshot.
|
|
100
|
+
* Used to resolve refs (e.g. `e1`) back to Playwright locators.
|
|
101
|
+
*/
|
|
102
|
+
export interface RoleRefInfo {
|
|
103
|
+
/** ARIA role of the element (e.g. `'button'`, `'textbox'`, `'link'`) */
|
|
104
|
+
role: string;
|
|
105
|
+
/** Accessible name of the element */
|
|
106
|
+
name?: string;
|
|
107
|
+
/** Disambiguation index when multiple elements share the same role + name */
|
|
108
|
+
nth?: number;
|
|
109
|
+
}
|
|
110
|
+
/** Map of ref IDs (e.g. `'e1'`, `'e2'`) to their element information. */
|
|
111
|
+
export type RoleRefs = Record<string, RoleRefInfo>;
|
|
112
|
+
/**
|
|
113
|
+
* Metadata about the source of untrusted external content.
|
|
114
|
+
* Used by consumers (e.g. OpenClaw) to wrap browser outputs with
|
|
115
|
+
* structured external-content markers for prompt-injection mitigation.
|
|
116
|
+
*/
|
|
117
|
+
export interface UntrustedContentMeta {
|
|
118
|
+
/** The source URL of the content at the time of capture */
|
|
119
|
+
sourceUrl?: string;
|
|
120
|
+
/** Content type identifier (e.g. `'browser-snapshot'`, `'browser-aria-tree'`) */
|
|
121
|
+
contentType: string;
|
|
122
|
+
/** ISO 8601 timestamp of when the content was captured */
|
|
123
|
+
capturedAt: string;
|
|
124
|
+
}
|
|
125
|
+
/** Result of taking a page snapshot. */
|
|
126
|
+
export interface SnapshotResult {
|
|
127
|
+
/** AI-readable text representation of the page with numbered refs */
|
|
128
|
+
snapshot: string;
|
|
129
|
+
/** Map of ref IDs to element information for targeting actions */
|
|
130
|
+
refs: RoleRefs;
|
|
131
|
+
/** Statistics about the snapshot */
|
|
132
|
+
stats?: SnapshotStats;
|
|
133
|
+
/**
|
|
134
|
+
* Indicates this content originates from an untrusted external source (the web page).
|
|
135
|
+
* AI agents should treat snapshot content as potentially adversarial
|
|
136
|
+
* (e.g. prompt injection via page text). Always `true` for browser snapshots.
|
|
137
|
+
*/
|
|
138
|
+
untrusted?: true;
|
|
139
|
+
/** Structured metadata about the untrusted content source */
|
|
140
|
+
contentMeta?: UntrustedContentMeta;
|
|
141
|
+
}
|
|
142
|
+
/** Statistics about a snapshot's content. */
|
|
143
|
+
export interface SnapshotStats {
|
|
144
|
+
/** Number of lines in the snapshot text */
|
|
145
|
+
lines: number;
|
|
146
|
+
/** Number of characters in the snapshot text */
|
|
147
|
+
chars: number;
|
|
148
|
+
/** Total number of refs assigned */
|
|
149
|
+
refs: number;
|
|
150
|
+
/** Number of interactive element refs (buttons, links, inputs, etc.) */
|
|
151
|
+
interactive: number;
|
|
152
|
+
}
|
|
153
|
+
/** Options for controlling snapshot output. */
|
|
154
|
+
export interface SnapshotOptions {
|
|
155
|
+
/** Only include interactive elements (buttons, links, inputs, etc.) */
|
|
156
|
+
interactive?: boolean;
|
|
157
|
+
/** Remove structural containers that don't contain interactive elements */
|
|
158
|
+
compact?: boolean;
|
|
159
|
+
/** Maximum tree depth to include */
|
|
160
|
+
maxDepth?: number;
|
|
161
|
+
/** Maximum character count before truncation (aria mode only) */
|
|
162
|
+
maxChars?: number;
|
|
163
|
+
/** CSS selector to scope the snapshot to a specific element (role mode only — throws in aria mode) */
|
|
164
|
+
selector?: string;
|
|
165
|
+
/** Frame selector for snapshotting inside iframes (role mode only — throws in aria mode) */
|
|
166
|
+
frameSelector?: string;
|
|
167
|
+
/**
|
|
168
|
+
* Snapshot strategy:
|
|
169
|
+
* - `'aria'` (default) — uses Playwright's `_snapshotForAI()`, produces refs like `e1`
|
|
170
|
+
* - `'role'` — uses Playwright's `ariaSnapshot()` + `getByRole()` resolution
|
|
171
|
+
*/
|
|
172
|
+
mode?: 'role' | 'aria';
|
|
173
|
+
/** Timeout in milliseconds for the snapshot operation (role mode only, default: 5000) */
|
|
174
|
+
timeoutMs?: number;
|
|
175
|
+
/**
|
|
176
|
+
* How refs are stored for role-mode snapshots.
|
|
177
|
+
* - `'role'` (default) — refs resolved via `getByRole()`
|
|
178
|
+
* - `'aria'` — refs resolved via aria snapshot index
|
|
179
|
+
* Only applies when `mode: 'role'`.
|
|
180
|
+
*/
|
|
181
|
+
refsMode?: 'role' | 'aria';
|
|
182
|
+
}
|
|
183
|
+
/** A node in the raw ARIA accessibility tree. */
|
|
184
|
+
export interface AriaNode {
|
|
185
|
+
/** Ref ID for this node (e.g. `'ax1'`) */
|
|
186
|
+
ref: string;
|
|
187
|
+
/** ARIA role (e.g. `'button'`, `'heading'`, `'generic'`) */
|
|
188
|
+
role: string;
|
|
189
|
+
/** Accessible name */
|
|
190
|
+
name: string;
|
|
191
|
+
/** Current value (for inputs, sliders, etc.) */
|
|
192
|
+
value?: string;
|
|
193
|
+
/** Accessible description */
|
|
194
|
+
description?: string;
|
|
195
|
+
/** Backend DOM node ID (for CDP operations) */
|
|
196
|
+
backendDOMNodeId?: number;
|
|
197
|
+
/** Depth in the accessibility tree (0 = root) */
|
|
198
|
+
depth: number;
|
|
199
|
+
}
|
|
200
|
+
/** Result of a raw ARIA tree snapshot. */
|
|
201
|
+
export interface AriaSnapshotResult {
|
|
202
|
+
/** Flat list of accessibility tree nodes */
|
|
203
|
+
nodes: AriaNode[];
|
|
204
|
+
/**
|
|
205
|
+
* Indicates this content originates from an untrusted external source (the web page).
|
|
206
|
+
* AI agents should treat snapshot content as potentially adversarial. Always `true`.
|
|
207
|
+
*/
|
|
208
|
+
untrusted?: true;
|
|
209
|
+
/** Structured metadata about the untrusted content source */
|
|
210
|
+
contentMeta?: UntrustedContentMeta;
|
|
211
|
+
}
|
|
212
|
+
/** A form field to fill as part of a batch `fill()` operation. */
|
|
213
|
+
export interface FormField {
|
|
214
|
+
/** Ref ID of the form field (e.g. `'e3'`) */
|
|
215
|
+
ref: string;
|
|
216
|
+
/** Field type: `'text'`, `'checkbox'`, `'radio'`, etc. */
|
|
217
|
+
type?: string;
|
|
218
|
+
/** Value to set. Booleans for checkboxes, strings for text fields. */
|
|
219
|
+
value?: string | number | boolean;
|
|
220
|
+
}
|
|
221
|
+
/** Options for click actions. */
|
|
222
|
+
export interface ClickOptions {
|
|
223
|
+
/** Double-click instead of single click */
|
|
224
|
+
doubleClick?: boolean;
|
|
225
|
+
/** Mouse button to use */
|
|
226
|
+
button?: 'left' | 'right' | 'middle';
|
|
227
|
+
/** Modifier keys to hold during click */
|
|
228
|
+
modifiers?: ('Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift')[];
|
|
229
|
+
/** Timeout in milliseconds. Default: `8000` */
|
|
230
|
+
timeoutMs?: number;
|
|
231
|
+
}
|
|
232
|
+
/** Options for type actions. */
|
|
233
|
+
export interface TypeOptions {
|
|
234
|
+
/** Press Enter after typing */
|
|
235
|
+
submit?: boolean;
|
|
236
|
+
/** Type character-by-character with delay (75ms per key) instead of instant fill */
|
|
237
|
+
slowly?: boolean;
|
|
238
|
+
/** Timeout in milliseconds. Default: `8000` */
|
|
239
|
+
timeoutMs?: number;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Options for waiting on various conditions.
|
|
243
|
+
* Multiple conditions can be combined — they are checked in order.
|
|
244
|
+
*/
|
|
245
|
+
export interface WaitOptions {
|
|
246
|
+
/** Wait for a fixed duration (milliseconds) */
|
|
247
|
+
timeMs?: number;
|
|
248
|
+
/** Wait until text appears on the page */
|
|
249
|
+
text?: string;
|
|
250
|
+
/** Wait until text disappears from the page */
|
|
251
|
+
textGone?: string;
|
|
252
|
+
/** Wait until a CSS selector matches a visible element */
|
|
253
|
+
selector?: string;
|
|
254
|
+
/** Wait until the URL matches a pattern (supports `**` wildcards) */
|
|
255
|
+
url?: string;
|
|
256
|
+
/** Wait for a specific page load state */
|
|
257
|
+
loadState?: 'load' | 'domcontentloaded' | 'networkidle';
|
|
258
|
+
/** Wait until a JavaScript function returns truthy (evaluated in browser context) */
|
|
259
|
+
fn?: string;
|
|
260
|
+
/** Timeout for each condition in milliseconds. Default: `20000` */
|
|
261
|
+
timeoutMs?: number;
|
|
262
|
+
}
|
|
263
|
+
/** Options for screenshot capture. */
|
|
264
|
+
export interface ScreenshotOptions {
|
|
265
|
+
/** Capture the full scrollable page instead of just the viewport */
|
|
266
|
+
fullPage?: boolean;
|
|
267
|
+
/** Capture a specific element by ref ID */
|
|
268
|
+
ref?: string;
|
|
269
|
+
/** Capture a specific element by CSS selector */
|
|
270
|
+
element?: string;
|
|
271
|
+
/** Image format. Default: `'png'` */
|
|
272
|
+
type?: 'png' | 'jpeg';
|
|
273
|
+
/** Enable labeled screenshot mode (used internally by screenshotWithLabels) */
|
|
274
|
+
labels?: boolean;
|
|
275
|
+
}
|
|
276
|
+
/** A console message captured from the browser page. */
|
|
277
|
+
export interface ConsoleMessage {
|
|
278
|
+
/** Message type: `'log'`, `'info'`, `'warning'`, `'error'`, `'debug'` */
|
|
279
|
+
type: string;
|
|
280
|
+
/** The message text */
|
|
281
|
+
text: string;
|
|
282
|
+
/** ISO 8601 timestamp */
|
|
283
|
+
timestamp: string;
|
|
284
|
+
/** Source location where the message was logged */
|
|
285
|
+
location?: {
|
|
286
|
+
url?: string;
|
|
287
|
+
lineNumber?: number;
|
|
288
|
+
columnNumber?: number;
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/** An uncaught error from the browser page. */
|
|
292
|
+
export interface PageError {
|
|
293
|
+
/** Error message */
|
|
294
|
+
message: string;
|
|
295
|
+
/** Error name (e.g. `'TypeError'`) */
|
|
296
|
+
name?: string;
|
|
297
|
+
/** Stack trace */
|
|
298
|
+
stack?: string;
|
|
299
|
+
/** ISO 8601 timestamp */
|
|
300
|
+
timestamp: string;
|
|
301
|
+
}
|
|
302
|
+
/** A network request captured from the browser page. */
|
|
303
|
+
export interface NetworkRequest {
|
|
304
|
+
/** Internal request ID (e.g. `'r1'`, `'r2'`) */
|
|
305
|
+
id: string;
|
|
306
|
+
/** ISO 8601 timestamp */
|
|
307
|
+
timestamp: string;
|
|
308
|
+
/** HTTP method (e.g. `'GET'`, `'POST'`) */
|
|
309
|
+
method: string;
|
|
310
|
+
/** Request URL */
|
|
311
|
+
url: string;
|
|
312
|
+
/** Resource type (e.g. `'document'`, `'xhr'`, `'fetch'`, `'image'`) */
|
|
313
|
+
resourceType: string;
|
|
314
|
+
/** HTTP status code (set when response is received) */
|
|
315
|
+
status?: number;
|
|
316
|
+
/** Whether the response status was 2xx */
|
|
317
|
+
ok?: boolean;
|
|
318
|
+
/** Error text if the request failed */
|
|
319
|
+
failureText?: string;
|
|
320
|
+
}
|
|
321
|
+
/** Web storage type. */
|
|
322
|
+
export type StorageKind = 'local' | 'session';
|
|
323
|
+
/** Cookie data for setting a browser cookie. */
|
|
324
|
+
export interface CookieData {
|
|
325
|
+
/** Cookie name */
|
|
326
|
+
name: string;
|
|
327
|
+
/** Cookie value */
|
|
328
|
+
value: string;
|
|
329
|
+
/** URL to associate the cookie with (alternative to domain+path) */
|
|
330
|
+
url?: string;
|
|
331
|
+
/** Cookie domain */
|
|
332
|
+
domain?: string;
|
|
333
|
+
/** Cookie path */
|
|
334
|
+
path?: string;
|
|
335
|
+
/** Expiration as Unix timestamp in seconds */
|
|
336
|
+
expires?: number;
|
|
337
|
+
/** HTTP-only flag */
|
|
338
|
+
httpOnly?: boolean;
|
|
339
|
+
/** Secure flag */
|
|
340
|
+
secure?: boolean;
|
|
341
|
+
/** SameSite attribute */
|
|
342
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
343
|
+
}
|
|
344
|
+
/** Information about an open browser tab. */
|
|
345
|
+
export interface BrowserTab {
|
|
346
|
+
/** CDP target ID (used to identify this tab in API calls) */
|
|
347
|
+
targetId: string;
|
|
348
|
+
/** Page title */
|
|
349
|
+
title: string;
|
|
350
|
+
/** Current URL */
|
|
351
|
+
url: string;
|
|
352
|
+
/** Target type (usually `'page'`) */
|
|
353
|
+
type: string;
|
|
354
|
+
}
|
|
355
|
+
/** Result of a download operation. */
|
|
356
|
+
export interface DownloadResult {
|
|
357
|
+
/** The URL that initiated the download */
|
|
358
|
+
url: string;
|
|
359
|
+
/** Filename suggested by the server */
|
|
360
|
+
suggestedFilename: string;
|
|
361
|
+
/** Local path where the file was saved */
|
|
362
|
+
path: string;
|
|
363
|
+
}
|
|
364
|
+
/** Options for arming a dialog handler. */
|
|
365
|
+
export interface DialogOptions {
|
|
366
|
+
/** Whether to accept or dismiss the dialog */
|
|
367
|
+
accept: boolean;
|
|
368
|
+
/** Text to enter in a prompt dialog */
|
|
369
|
+
promptText?: string;
|
|
370
|
+
/** Timeout for waiting for the dialog. Default: `30000` */
|
|
371
|
+
timeoutMs?: number;
|
|
372
|
+
}
|
|
373
|
+
/** Result of intercepting a response body. */
|
|
374
|
+
export interface ResponseBodyResult {
|
|
375
|
+
/** The response URL */
|
|
376
|
+
url: string;
|
|
377
|
+
/** HTTP status code */
|
|
378
|
+
status?: number;
|
|
379
|
+
/** Response headers */
|
|
380
|
+
headers?: Record<string, string>;
|
|
381
|
+
/** Response body text */
|
|
382
|
+
body: string;
|
|
383
|
+
/** Whether the body was truncated due to maxChars */
|
|
384
|
+
truncated?: boolean;
|
|
385
|
+
}
|
|
386
|
+
/** Options for starting a Playwright trace. */
|
|
387
|
+
export interface TraceStartOptions {
|
|
388
|
+
/** Capture screenshots during tracing */
|
|
389
|
+
screenshots?: boolean;
|
|
390
|
+
/** Capture DOM snapshots during tracing */
|
|
391
|
+
snapshots?: boolean;
|
|
392
|
+
/** Include source files in the trace */
|
|
393
|
+
sources?: boolean;
|
|
394
|
+
}
|
|
395
|
+
/** Color scheme for media emulation. */
|
|
396
|
+
export type ColorScheme = 'dark' | 'light' | 'no-preference' | null;
|
|
397
|
+
/** Options for geolocation emulation. */
|
|
398
|
+
export interface GeolocationOptions {
|
|
399
|
+
/** Latitude in degrees */
|
|
400
|
+
latitude?: number;
|
|
401
|
+
/** Longitude in degrees */
|
|
402
|
+
longitude?: number;
|
|
403
|
+
/** Accuracy in meters */
|
|
404
|
+
accuracy?: number;
|
|
405
|
+
/** Origin to grant geolocation permission for (e.g. `'https://example.com'`) */
|
|
406
|
+
origin?: string;
|
|
407
|
+
/** Clear geolocation override */
|
|
408
|
+
clear?: boolean;
|
|
409
|
+
}
|
|
410
|
+
/** HTTP credentials for authentication. */
|
|
411
|
+
export interface HttpCredentials {
|
|
412
|
+
/** Username for HTTP authentication */
|
|
413
|
+
username?: string;
|
|
414
|
+
/** Password for HTTP authentication */
|
|
415
|
+
password?: string;
|
|
416
|
+
/** Clear HTTP credentials */
|
|
417
|
+
clear?: boolean;
|
|
418
|
+
}
|
|
419
|
+
/** @internal */
|
|
420
|
+
export interface PageState {
|
|
421
|
+
console: ConsoleMessage[];
|
|
422
|
+
errors: PageError[];
|
|
423
|
+
requests: NetworkRequest[];
|
|
424
|
+
requestIds: WeakMap<object, string>;
|
|
425
|
+
nextRequestId: number;
|
|
426
|
+
roleRefs?: RoleRefs;
|
|
427
|
+
roleRefsFrameSelector?: string;
|
|
428
|
+
roleRefsMode?: 'role' | 'aria';
|
|
429
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List all Chrome extensions paired with this machine.
|
|
3
|
+
* Usage: tuna-agent extension list
|
|
4
|
+
*/
|
|
5
|
+
export declare function extensionList(): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Pair this machine with a Chrome extension using its pairing code.
|
|
8
|
+
* Usage: tuna-agent extension connect TUNA-XXXX-XXXX
|
|
9
|
+
*/
|
|
10
|
+
export declare function extensionConnect(code: string): Promise<void>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { loadConfig, saveConfig } from '../../config/store.js';
|
|
3
|
+
/**
|
|
4
|
+
* List all Chrome extensions paired with this machine.
|
|
5
|
+
* Usage: tuna-agent extension list
|
|
6
|
+
*/
|
|
7
|
+
export async function extensionList() {
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
if (!config) {
|
|
10
|
+
console.error(chalk.red('Not connected. Run tuna-agent connect <CODE> first.'));
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const res = await fetch(`${config.apiUrl}/extension/list`, {
|
|
15
|
+
headers: { 'Authorization': `Bearer ${config.agentToken}` },
|
|
16
|
+
});
|
|
17
|
+
const body = await res.json();
|
|
18
|
+
if (!res.ok || !body.data) {
|
|
19
|
+
console.error(chalk.red(`Failed: ${body.message || 'Unknown error'}`));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const { extensions, total } = body.data;
|
|
23
|
+
console.log(chalk.cyan(`\nPaired Extensions (${total})\n`));
|
|
24
|
+
if (total === 0) {
|
|
25
|
+
console.log(chalk.gray(' No extensions paired yet.'));
|
|
26
|
+
console.log(`\n Run ${chalk.bold('tuna-agent extension connect <CODE>')} to pair one.`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const ext of extensions) {
|
|
30
|
+
const status = ext.connected ? chalk.green('● connected') : chalk.gray('○ offline');
|
|
31
|
+
console.log(` ${status} ${chalk.bold(ext.code)}`);
|
|
32
|
+
}
|
|
33
|
+
console.log('');
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
37
|
+
console.error(chalk.red(`\nFailed: ${msg}`));
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Pair this machine with a Chrome extension using its pairing code.
|
|
43
|
+
* Usage: tuna-agent extension connect TUNA-XXXX-XXXX
|
|
44
|
+
*/
|
|
45
|
+
export async function extensionConnect(code) {
|
|
46
|
+
const config = loadConfig();
|
|
47
|
+
if (!config) {
|
|
48
|
+
console.error(chalk.red('Not connected. Run tuna-agent connect <CODE> first.'));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
const normalizedCode = code.trim().toUpperCase();
|
|
52
|
+
if (!normalizedCode.startsWith('TUNA-')) {
|
|
53
|
+
console.error(chalk.red('Invalid pair code. Expected format: TUNA-XXXX-XXXX'));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
console.log(chalk.cyan('Pairing with Chrome extension...'));
|
|
57
|
+
console.log(` Code: ${chalk.bold(normalizedCode)}`);
|
|
58
|
+
try {
|
|
59
|
+
const res = await fetch(`${config.apiUrl}/extension/pair`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
'Authorization': `Bearer ${config.agentToken}`,
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({ code: normalizedCode }),
|
|
66
|
+
});
|
|
67
|
+
const body = await res.json();
|
|
68
|
+
if (!res.ok || !body.data) {
|
|
69
|
+
console.error(chalk.red(`\nFailed: ${body.message || 'Unknown error'}`));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
console.log(chalk.green('\nExtension paired successfully!'));
|
|
73
|
+
console.log(` Machine: ${body.data.machineName}`);
|
|
74
|
+
console.log('\nThe Content Creator extension should now show your agent as connected.');
|
|
75
|
+
// Save code locally so agent can restore the pairing after server restart
|
|
76
|
+
const codes = new Set(config.extensionCodes || []);
|
|
77
|
+
codes.add(normalizedCode);
|
|
78
|
+
saveConfig({ ...config, extensionCodes: [...codes] });
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
82
|
+
console.error(chalk.red(`\nPairing failed: ${msg}`));
|
|
83
|
+
console.error(`Make sure tuna-agent daemon is configured (run tuna-agent connect first)`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { connect } from './commands/connect.js';
|
|
|
4
4
|
import { start } from './commands/start.js';
|
|
5
5
|
import { stop } from './commands/stop.js';
|
|
6
6
|
import { status } from './commands/status.js';
|
|
7
|
+
import { extensionConnect, extensionList } from './commands/extension.js';
|
|
7
8
|
const program = new Command()
|
|
8
9
|
.name('tuna-agent')
|
|
9
10
|
.description('Tuna Agent - Run AI coding tasks on your machine')
|
|
@@ -29,4 +30,15 @@ program
|
|
|
29
30
|
.command('status')
|
|
30
31
|
.description('Show agent connection status')
|
|
31
32
|
.action(status);
|
|
33
|
+
const extensionCmd = program
|
|
34
|
+
.command('extension')
|
|
35
|
+
.description('Manage Chrome extension pairing');
|
|
36
|
+
extensionCmd
|
|
37
|
+
.command('connect <code>')
|
|
38
|
+
.description('Pair this agent with the Content Creator Chrome extension')
|
|
39
|
+
.action(extensionConnect);
|
|
40
|
+
extensionCmd
|
|
41
|
+
.command('list')
|
|
42
|
+
.description('List all Chrome extensions paired with this machine')
|
|
43
|
+
.action(extensionList);
|
|
32
44
|
program.parse();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension Task Handlers
|
|
3
|
+
* Handles specialized tasks from the Chrome extension that don't need Claude:
|
|
4
|
+
* - get_history — return local video history
|
|
5
|
+
* - retry_video — re-queue a video for rendering
|
|
6
|
+
* - generate_scene(s) — call Veo3 to create clips
|
|
7
|
+
* - render_video — compose final video via Remotion
|
|
8
|
+
* - list_characters — return character profiles with thumbnails
|
|
9
|
+
* - create_character — create new character profile directory
|
|
10
|
+
*/
|
|
11
|
+
import { AgentWebSocketClient } from './ws-client.js';
|
|
12
|
+
export interface VideoRecord {
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
niche: string;
|
|
16
|
+
status: 'processing' | 'rendered' | 'failed';
|
|
17
|
+
progress: number;
|
|
18
|
+
error?: string;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
outputPath?: string;
|
|
21
|
+
scenes?: Array<{
|
|
22
|
+
idx: number;
|
|
23
|
+
videoUrl?: string;
|
|
24
|
+
prompt: string;
|
|
25
|
+
}>;
|
|
26
|
+
aspectRatio?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function handleGetHistory(ws: AgentWebSocketClient, code: string, taskId: string): void;
|
|
29
|
+
export declare function handleGenerateIdeas(ws: AgentWebSocketClient, code: string, taskId: string, topic: string): Promise<void>;
|
|
30
|
+
export declare function handleGenerateScript(ws: AgentWebSocketClient, code: string, taskId: string, idea: string, topic: string, style?: string): Promise<void>;
|
|
31
|
+
export declare function handleRetryVideo(ws: AgentWebSocketClient, code: string, taskId: string, videoId: string): void;
|
|
32
|
+
export declare function handleGenerateScene(ws: AgentWebSocketClient, code: string, taskId: string, sceneIdx: number, prompt: string, aspectRatio: string): Promise<void>;
|
|
33
|
+
export declare function handleGenerateScenes(ws: AgentWebSocketClient, code: string, taskId: string, scenes: Array<{
|
|
34
|
+
idx: number;
|
|
35
|
+
prompt: string;
|
|
36
|
+
}>, aspectRatio: string): Promise<void>;
|
|
37
|
+
export declare function handleRenderVideo(ws: AgentWebSocketClient, code: string, taskId: string, payload: {
|
|
38
|
+
scenes: Array<{
|
|
39
|
+
idx: number;
|
|
40
|
+
videoUrl?: string;
|
|
41
|
+
prompt: string;
|
|
42
|
+
}>;
|
|
43
|
+
script: string;
|
|
44
|
+
title: string;
|
|
45
|
+
aspectRatio: string;
|
|
46
|
+
voiceId: string;
|
|
47
|
+
subtitleStyle: string;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
export interface CharProfile {
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
thumbnail: string;
|
|
53
|
+
gender: string;
|
|
54
|
+
age: string;
|
|
55
|
+
ethnicity: string;
|
|
56
|
+
vibe: string;
|
|
57
|
+
suitableFor: string;
|
|
58
|
+
poseCount: number;
|
|
59
|
+
images?: string[];
|
|
60
|
+
}
|
|
61
|
+
export declare function handleListCharacters(ws: AgentWebSocketClient, code: string, taskId: string): void;
|
|
62
|
+
export declare function handleCreateCharacter(ws: AgentWebSocketClient, code: string, taskId: string, name: string, displayName: string, prompt: string, outputCount?: number, orientation?: string): Promise<void>;
|
|
63
|
+
export declare function handleSaveCharacterSelection(ws: AgentWebSocketClient, code: string, taskId: string, characterId: string, selectedImages: string[]): void;
|