tuna-agent 0.1.1 → 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/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/daemon/extension-handlers.d.ts +63 -0
- package/dist/daemon/extension-handlers.js +630 -0
- package/dist/daemon/index.js +78 -19
- package/dist/daemon/ws-client.d.ts +16 -0
- package/dist/daemon/ws-client.js +45 -0
- package/dist/mcp/browser-server.d.ts +11 -0
- package/dist/mcp/browser-server.js +467 -0
- package/dist/mcp/knowledge-server.js +43 -18
- package/dist/mcp/setup.js +10 -0
- package/dist/utils/claude-cli.js +18 -9
- package/package.json +2 -1
package/dist/daemon/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { loadPMState, savePMState, clearPMState } from './pm-state.js';
|
|
|
9
9
|
import { chatWithPM } from '../pm/planner.js';
|
|
10
10
|
import { executePlanAndReport, simplifyMarkdown, waitForInput } from '../utils/execution-helpers.js';
|
|
11
11
|
import { runClaude } from '../utils/claude-cli.js';
|
|
12
|
+
import { handleGetHistory, handleRetryVideo, handleGenerateIdeas, handleGenerateScript, handleGenerateScene, handleGenerateScenes, handleRenderVideo, handleListCharacters, handleCreateCharacter, handleSaveCharacterSelection, } from './extension-handlers.js';
|
|
12
13
|
import { downloadAttachments, cleanupAttachments } from '../utils/image-download.js';
|
|
13
14
|
import { scanSkills } from '../utils/skill-scanner.js';
|
|
14
15
|
import { setupMcpConfig } from '../mcp/setup.js';
|
|
@@ -75,6 +76,10 @@ export async function startDaemon(config) {
|
|
|
75
76
|
console.error('[Daemon] Received task_assigned without task data');
|
|
76
77
|
break;
|
|
77
78
|
}
|
|
79
|
+
// Resolve tilde in repoPath (e.g. ~/agents/co-founder → /Users/admin/agents/co-founder)
|
|
80
|
+
if (task.repoPath?.startsWith('~/')) {
|
|
81
|
+
task.repoPath = path.join(os.homedir(), task.repoPath.slice(2));
|
|
82
|
+
}
|
|
78
83
|
if (activeTasks >= MAX_CONCURRENT) {
|
|
79
84
|
console.log(`[Daemon] Busy — rejecting task ${task.id}`);
|
|
80
85
|
ws.send({ action: 'task_rejected', taskId: task.id, reason: 'agent_busy' });
|
|
@@ -287,7 +292,6 @@ ${skillContent.slice(0, 15000)}`;
|
|
|
287
292
|
break;
|
|
288
293
|
}
|
|
289
294
|
case 'extension_task': {
|
|
290
|
-
// Task sent from Chrome extension — run Claude and stream results back
|
|
291
295
|
const extCode = msg.code;
|
|
292
296
|
const extTaskId = msg.taskId;
|
|
293
297
|
const extTask = msg.task;
|
|
@@ -297,11 +301,70 @@ ${skillContent.slice(0, 15000)}`;
|
|
|
297
301
|
break;
|
|
298
302
|
}
|
|
299
303
|
console.log(`[Daemon] Extension task ${extTaskId}: ${extTask.substring(0, 80)}`);
|
|
300
|
-
//
|
|
304
|
+
// ── Specialized handlers (no Claude needed) ──────────────────────────
|
|
305
|
+
if (extTask === 'get_history') {
|
|
306
|
+
handleGetHistory(ws, extCode, extTaskId);
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
if (extTask === 'generate_ideas') {
|
|
310
|
+
(async () => {
|
|
311
|
+
await handleGenerateIdeas(ws, extCode, extTaskId, msg.topic);
|
|
312
|
+
})();
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
if (extTask === 'generate_script') {
|
|
316
|
+
(async () => {
|
|
317
|
+
await handleGenerateScript(ws, extCode, extTaskId, msg.idea, msg.topic, msg.style);
|
|
318
|
+
})();
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
if (extTask === 'retry_video') {
|
|
322
|
+
const videoId = msg.videoId;
|
|
323
|
+
handleRetryVideo(ws, extCode, extTaskId, videoId);
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
if (extTask === 'generate_scene') {
|
|
327
|
+
(async () => {
|
|
328
|
+
await handleGenerateScene(ws, extCode, extTaskId, msg.sceneIdx, msg.prompt, msg.aspectRatio || 'portrait');
|
|
329
|
+
})();
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
if (extTask === 'generate_scenes') {
|
|
333
|
+
(async () => {
|
|
334
|
+
await handleGenerateScenes(ws, extCode, extTaskId, msg.scenes, msg.aspectRatio || 'portrait');
|
|
335
|
+
})();
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
if (extTask === 'render_video') {
|
|
339
|
+
(async () => {
|
|
340
|
+
await handleRenderVideo(ws, extCode, extTaskId, {
|
|
341
|
+
scenes: msg.scenes,
|
|
342
|
+
script: msg.script,
|
|
343
|
+
title: msg.title,
|
|
344
|
+
aspectRatio: msg.aspectRatio || 'portrait',
|
|
345
|
+
voiceId: msg.voiceId || '',
|
|
346
|
+
subtitleStyle: msg.subtitleStyle || 'karaoke',
|
|
347
|
+
});
|
|
348
|
+
})();
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
if (extTask === 'list_characters') {
|
|
352
|
+
handleListCharacters(ws, extCode, extTaskId);
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
if (extTask === 'create_character') {
|
|
356
|
+
(async () => {
|
|
357
|
+
await handleCreateCharacter(ws, extCode, extTaskId, msg.name, msg.displayName, msg.prompt, msg.outputCount || 2, msg.orientation || 'portrait');
|
|
358
|
+
})();
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
if (extTask === 'save_character_selection') {
|
|
362
|
+
handleSaveCharacterSelection(ws, extCode, extTaskId, msg.characterId, msg.selectedImages || []);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
// ── Claude-powered tasks (ideas, script, etc.) ────────────────────────
|
|
301
366
|
(async () => {
|
|
302
367
|
try {
|
|
303
|
-
let accumulated = '';
|
|
304
|
-
let progress = 0;
|
|
305
368
|
const result = await runClaude({
|
|
306
369
|
prompt: extTask,
|
|
307
370
|
cwd: os.homedir(),
|
|
@@ -315,37 +378,33 @@ ${skillContent.slice(0, 15000)}`;
|
|
|
315
378
|
if (event?.type === 'content_block_delta') {
|
|
316
379
|
const delta = event.delta;
|
|
317
380
|
if (delta?.type === 'text_delta' && delta.text) {
|
|
318
|
-
|
|
319
|
-
accumulated += chunk;
|
|
320
|
-
ws.send({ action: 'extension_task_stream', code: extCode, taskId: extTaskId, text: chunk });
|
|
381
|
+
ws.sendExtensionStream(extCode, extTaskId, delta.text);
|
|
321
382
|
}
|
|
322
383
|
}
|
|
323
384
|
}
|
|
324
385
|
} : undefined,
|
|
325
386
|
});
|
|
326
|
-
ws.
|
|
327
|
-
action: 'extension_task_done',
|
|
328
|
-
code: extCode,
|
|
329
|
-
taskId: extTaskId,
|
|
330
|
-
result: { script: result.result, text: result.result },
|
|
331
|
-
});
|
|
387
|
+
ws.sendExtensionDone(extCode, extTaskId, { script: result.result, text: result.result });
|
|
332
388
|
console.log(`[Daemon] Extension task ${extTaskId} done`);
|
|
333
389
|
}
|
|
334
390
|
catch (err) {
|
|
335
391
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
336
392
|
console.error(`[Daemon] Extension task ${extTaskId} error: ${errMsg}`);
|
|
337
|
-
ws.
|
|
338
|
-
action: 'extension_task_done',
|
|
339
|
-
code: extCode,
|
|
340
|
-
taskId: extTaskId,
|
|
341
|
-
result: { error: errMsg },
|
|
342
|
-
});
|
|
393
|
+
ws.sendExtensionDone(extCode, extTaskId, { error: errMsg });
|
|
343
394
|
}
|
|
344
395
|
})();
|
|
345
396
|
break;
|
|
346
397
|
}
|
|
347
398
|
case 'pong':
|
|
348
399
|
break;
|
|
400
|
+
case 'flow_command_result': {
|
|
401
|
+
const fcId = msg.id;
|
|
402
|
+
const fcResult = msg.result;
|
|
403
|
+
if (fcId) {
|
|
404
|
+
ws.resolveFlowCommand(fcId, fcResult || {});
|
|
405
|
+
}
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
349
408
|
case 'extension_unpaired': {
|
|
350
409
|
// Extension signed out — remove this code from local config so it's not restored on reconnect
|
|
351
410
|
const unpairCode = msg.code;
|
|
@@ -10,6 +10,8 @@ export declare class AgentWebSocketClient {
|
|
|
10
10
|
private running;
|
|
11
11
|
private onMessage;
|
|
12
12
|
private onAuthFailed?;
|
|
13
|
+
/** Pending flow command callbacks keyed by request ID */
|
|
14
|
+
private _flowCallbacks;
|
|
13
15
|
constructor(config: AgentConfig, onMessage: MessageHandler, onAuthFailed?: (code: number, reason: string) => void);
|
|
14
16
|
connect(): void;
|
|
15
17
|
disconnect(): void;
|
|
@@ -103,6 +105,20 @@ export declare class AgentWebSocketClient {
|
|
|
103
105
|
* Send progress update for an extension task.
|
|
104
106
|
*/
|
|
105
107
|
sendExtensionProgress(code: string, taskId: string, progress: number): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Send a custom-typed event to the extension (generic forwarder via extension_event action).
|
|
110
|
+
*/
|
|
111
|
+
sendExtensionEvent(code: string, event: Record<string, unknown>): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Send a flow command to the extension and wait for the result.
|
|
114
|
+
* Returns a Promise that resolves with the command result.
|
|
115
|
+
*/
|
|
116
|
+
sendFlowCommand(code: string, command: Record<string, unknown>, timeout?: number): Promise<Record<string, unknown>>;
|
|
117
|
+
/**
|
|
118
|
+
* Resolve a pending flow command callback (called from message handler).
|
|
119
|
+
* Returns true if the callback was found and resolved.
|
|
120
|
+
*/
|
|
121
|
+
resolveFlowCommand(id: string, result: Record<string, unknown>): boolean;
|
|
106
122
|
get isConnected(): boolean;
|
|
107
123
|
private _connect;
|
|
108
124
|
private _startHeartbeat;
|
package/dist/daemon/ws-client.js
CHANGED
|
@@ -15,6 +15,8 @@ export class AgentWebSocketClient {
|
|
|
15
15
|
running = false;
|
|
16
16
|
onMessage;
|
|
17
17
|
onAuthFailed;
|
|
18
|
+
/** Pending flow command callbacks keyed by request ID */
|
|
19
|
+
_flowCallbacks = new Map();
|
|
18
20
|
constructor(config, onMessage, onAuthFailed) {
|
|
19
21
|
this.config = config;
|
|
20
22
|
this.onMessage = onMessage;
|
|
@@ -170,6 +172,49 @@ export class AgentWebSocketClient {
|
|
|
170
172
|
sendExtensionProgress(code, taskId, progress) {
|
|
171
173
|
return this.send({ action: 'extension_task_progress', code, taskId, progress });
|
|
172
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Send a custom-typed event to the extension (generic forwarder via extension_event action).
|
|
177
|
+
*/
|
|
178
|
+
sendExtensionEvent(code, event) {
|
|
179
|
+
return this.send({ action: 'extension_event', code, event });
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Send a flow command to the extension and wait for the result.
|
|
183
|
+
* Returns a Promise that resolves with the command result.
|
|
184
|
+
*/
|
|
185
|
+
sendFlowCommand(code, command, timeout = 60000) {
|
|
186
|
+
return new Promise((resolve, reject) => {
|
|
187
|
+
const id = `fc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
188
|
+
const timer = setTimeout(() => {
|
|
189
|
+
this._flowCallbacks.delete(id);
|
|
190
|
+
reject(new Error(`Flow command timed out after ${timeout}ms: ${command.type}`));
|
|
191
|
+
}, timeout);
|
|
192
|
+
this._flowCallbacks.set(id, { resolve, reject, timer });
|
|
193
|
+
const sent = this.sendExtensionEvent(code, {
|
|
194
|
+
type: 'flow_command',
|
|
195
|
+
id,
|
|
196
|
+
command,
|
|
197
|
+
});
|
|
198
|
+
if (!sent) {
|
|
199
|
+
clearTimeout(timer);
|
|
200
|
+
this._flowCallbacks.delete(id);
|
|
201
|
+
reject(new Error('WebSocket not connected — cannot send flow command'));
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Resolve a pending flow command callback (called from message handler).
|
|
207
|
+
* Returns true if the callback was found and resolved.
|
|
208
|
+
*/
|
|
209
|
+
resolveFlowCommand(id, result) {
|
|
210
|
+
const cb = this._flowCallbacks.get(id);
|
|
211
|
+
if (!cb)
|
|
212
|
+
return false;
|
|
213
|
+
clearTimeout(cb.timer);
|
|
214
|
+
this._flowCallbacks.delete(id);
|
|
215
|
+
cb.resolve(result);
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
173
218
|
get isConnected() {
|
|
174
219
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
175
220
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Browser MCP Server for Tuna Agent
|
|
4
|
+
*
|
|
5
|
+
* Stdio-based MCP server that exposes browser automation tools to Claude Code.
|
|
6
|
+
* Uses browserclaw (vendored from OpenClaw) for snapshot+ref browser control.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node browser-server.js [--headless] [--user-data-dir /path/to/chrome/profile] [--cdp-port 9222]
|
|
10
|
+
*/
|
|
11
|
+
export {};
|