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.
Files changed (55) hide show
  1. package/dist/browser/actions/download.d.ts +16 -0
  2. package/dist/browser/actions/download.js +39 -0
  3. package/dist/browser/actions/emulation.d.ts +53 -0
  4. package/dist/browser/actions/emulation.js +103 -0
  5. package/dist/browser/actions/evaluate.d.ts +29 -0
  6. package/dist/browser/actions/evaluate.js +92 -0
  7. package/dist/browser/actions/interaction.d.ts +79 -0
  8. package/dist/browser/actions/interaction.js +210 -0
  9. package/dist/browser/actions/keyboard.d.ts +6 -0
  10. package/dist/browser/actions/keyboard.js +9 -0
  11. package/dist/browser/actions/navigation.d.ts +40 -0
  12. package/dist/browser/actions/navigation.js +92 -0
  13. package/dist/browser/actions/wait.d.ts +12 -0
  14. package/dist/browser/actions/wait.js +33 -0
  15. package/dist/browser/browser.d.ts +722 -0
  16. package/dist/browser/browser.js +1066 -0
  17. package/dist/browser/capture/activity.d.ts +22 -0
  18. package/dist/browser/capture/activity.js +39 -0
  19. package/dist/browser/capture/pdf.d.ts +6 -0
  20. package/dist/browser/capture/pdf.js +6 -0
  21. package/dist/browser/capture/response.d.ts +8 -0
  22. package/dist/browser/capture/response.js +28 -0
  23. package/dist/browser/capture/screenshot.d.ts +30 -0
  24. package/dist/browser/capture/screenshot.js +72 -0
  25. package/dist/browser/capture/trace.d.ts +13 -0
  26. package/dist/browser/capture/trace.js +19 -0
  27. package/dist/browser/chrome-launcher.d.ts +8 -0
  28. package/dist/browser/chrome-launcher.js +543 -0
  29. package/dist/browser/connection.d.ts +42 -0
  30. package/dist/browser/connection.js +359 -0
  31. package/dist/browser/index.d.ts +6 -0
  32. package/dist/browser/index.js +3 -0
  33. package/dist/browser/security.d.ts +51 -0
  34. package/dist/browser/security.js +357 -0
  35. package/dist/browser/snapshot/ai-snapshot.d.ts +12 -0
  36. package/dist/browser/snapshot/ai-snapshot.js +47 -0
  37. package/dist/browser/snapshot/aria-snapshot.d.ts +26 -0
  38. package/dist/browser/snapshot/aria-snapshot.js +121 -0
  39. package/dist/browser/snapshot/ref-map.d.ts +31 -0
  40. package/dist/browser/snapshot/ref-map.js +250 -0
  41. package/dist/browser/storage/index.d.ts +36 -0
  42. package/dist/browser/storage/index.js +65 -0
  43. package/dist/browser/types.d.ts +429 -0
  44. package/dist/browser/types.js +2 -0
  45. package/dist/daemon/extension-handlers.d.ts +63 -0
  46. package/dist/daemon/extension-handlers.js +630 -0
  47. package/dist/daemon/index.js +78 -19
  48. package/dist/daemon/ws-client.d.ts +16 -0
  49. package/dist/daemon/ws-client.js +45 -0
  50. package/dist/mcp/browser-server.d.ts +11 -0
  51. package/dist/mcp/browser-server.js +467 -0
  52. package/dist/mcp/knowledge-server.js +43 -18
  53. package/dist/mcp/setup.js +10 -0
  54. package/dist/utils/claude-cli.js +18 -9
  55. package/package.json +2 -1
@@ -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
- // Run in background don't block message handling
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
- const chunk = delta.text;
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.send({
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.send({
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;
@@ -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 {};