@hasna/connectors 0.0.6 → 0.2.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 (118) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +67 -41
  3. package/bin/index.js +1390 -745
  4. package/bin/mcp.js +184 -19
  5. package/bin/serve.js +1118 -0
  6. package/connectors/connect-anthropic/package.json +4 -4
  7. package/connectors/connect-aws/package.json +4 -4
  8. package/connectors/connect-brandsight/package.json +4 -4
  9. package/connectors/connect-cloudflare/.env.example +0 -5
  10. package/connectors/connect-cloudflare/package.json +4 -4
  11. package/connectors/connect-discord/package.json +4 -4
  12. package/connectors/connect-docker/package.json +4 -4
  13. package/connectors/connect-e2b/package.json +4 -4
  14. package/connectors/connect-elevenlabs/package.json +4 -4
  15. package/connectors/connect-exa/package.json +4 -4
  16. package/connectors/connect-figma/package.json +4 -4
  17. package/connectors/connect-firecrawl/package.json +4 -4
  18. package/connectors/connect-github/package.json +4 -4
  19. package/connectors/connect-gmail/package.json +4 -4
  20. package/connectors/connect-google/package.json +4 -4
  21. package/connectors/connect-googlecalendar/package.json +4 -4
  22. package/connectors/connect-googlecloud/package.json +4 -4
  23. package/connectors/connect-googlecontacts/package.json +4 -4
  24. package/connectors/connect-googledocs/package.json +4 -4
  25. package/connectors/connect-googledrive/package.json +4 -4
  26. package/connectors/connect-googlegemini/package.json +4 -4
  27. package/connectors/connect-googlemaps/package.json +2 -2
  28. package/connectors/connect-googlesheets/package.json +4 -4
  29. package/connectors/connect-googletasks/package.json +2 -2
  30. package/connectors/connect-hedra/package.json +4 -4
  31. package/connectors/connect-heygen/package.json +4 -4
  32. package/connectors/connect-huggingface/package.json +4 -4
  33. package/connectors/connect-icons8/package.json +4 -4
  34. package/connectors/connect-maropost/package.json +4 -4
  35. package/connectors/connect-mercury/package.json +4 -4
  36. package/connectors/connect-meta/package.json +4 -4
  37. package/connectors/connect-midjourney/package.json +4 -4
  38. package/connectors/connect-mistral/package.json +4 -4
  39. package/connectors/connect-mixpanel/package.json +4 -4
  40. package/connectors/connect-notion/.env.example +0 -5
  41. package/connectors/connect-notion/package.json +2 -2
  42. package/connectors/connect-openai/package.json +4 -4
  43. package/connectors/connect-openweathermap/package.json +4 -4
  44. package/connectors/connect-pandadoc/package.json +4 -4
  45. package/connectors/connect-quo/package.json +4 -4
  46. package/connectors/connect-reddit/package.json +4 -4
  47. package/connectors/connect-reducto/package.json +1 -1
  48. package/connectors/connect-resend/package.json +4 -4
  49. package/connectors/connect-revolut/package.json +4 -4
  50. package/connectors/connect-sedo/package.json +4 -4
  51. package/connectors/connect-sentry/package.json +4 -4
  52. package/connectors/connect-shadcn/package.json +4 -4
  53. package/connectors/connect-shopify/package.json +2 -2
  54. package/connectors/connect-snap/package.json +4 -4
  55. package/connectors/connect-stabilityai/package.json +4 -4
  56. package/connectors/connect-stripe/package.json +4 -4
  57. package/connectors/connect-stripeatlas/package.json +4 -4
  58. package/connectors/connect-substack/package.json +4 -4
  59. package/connectors/connect-tiktok/package.json +4 -4
  60. package/connectors/connect-tinker/package.json +4 -4
  61. package/connectors/connect-twilio/package.json +6 -6
  62. package/connectors/connect-uspto/package.json +4 -4
  63. package/connectors/connect-webflow/package.json +2 -2
  64. package/connectors/connect-wix/package.json +2 -2
  65. package/connectors/connect-x/package.json +4 -4
  66. package/connectors/connect-xads/package.json +4 -4
  67. package/connectors/connect-xai/package.json +4 -4
  68. package/connectors/connect-youtube/package.json +4 -4
  69. package/connectors/connect-zoom/package.json +4 -4
  70. package/dashboard/dist/assets/index-BZZ_709y.css +1 -0
  71. package/dashboard/dist/assets/index-CBroKWCD.js +234 -0
  72. package/dashboard/dist/index.html +13 -0
  73. package/dashboard/dist/logo.jpg +0 -0
  74. package/dist/cli/cli.test.d.ts +1 -0
  75. package/dist/cli/components/App.d.ts +6 -0
  76. package/dist/cli/components/CategorySelect.d.ts +6 -0
  77. package/dist/cli/components/ConnectorSelect.d.ts +10 -0
  78. package/dist/cli/components/Header.d.ts +6 -0
  79. package/dist/cli/components/InstallProgress.d.ts +8 -0
  80. package/dist/cli/components/SearchView.d.ts +8 -0
  81. package/dist/cli/components/components.test.d.ts +1 -0
  82. package/dist/cli/index.d.ts +2 -0
  83. package/dist/index.d.ts +11 -0
  84. package/dist/index.js +11 -16
  85. package/dist/lib/installer.d.ts +55 -0
  86. package/dist/lib/installer.test.d.ts +1 -0
  87. package/dist/lib/registry.d.ts +18 -0
  88. package/dist/lib/registry.test.d.ts +1 -0
  89. package/dist/mcp/index.d.ts +2 -0
  90. package/dist/mcp/mcp.test.d.ts +1 -0
  91. package/dist/server/auth.d.ts +70 -0
  92. package/dist/server/dashboard.d.ts +5 -0
  93. package/dist/server/index.d.ts +6 -0
  94. package/dist/server/serve.d.ts +12 -0
  95. package/dist/server/server.test.d.ts +1 -0
  96. package/package.json +11 -6
  97. package/connectors/connect-browseruse/.env.example +0 -7
  98. package/connectors/connect-browseruse/.npmrc.example +0 -2
  99. package/connectors/connect-browseruse/AGENTS.md +0 -172
  100. package/connectors/connect-browseruse/CLAUDE.md +0 -172
  101. package/connectors/connect-browseruse/GEMINI.md +0 -172
  102. package/connectors/connect-browseruse/README.md +0 -153
  103. package/connectors/connect-browseruse/package.json +0 -52
  104. package/connectors/connect-browseruse/src/api/billing.ts +0 -32
  105. package/connectors/connect-browseruse/src/api/browsers.ts +0 -50
  106. package/connectors/connect-browseruse/src/api/client.ts +0 -168
  107. package/connectors/connect-browseruse/src/api/files.ts +0 -70
  108. package/connectors/connect-browseruse/src/api/index.ts +0 -95
  109. package/connectors/connect-browseruse/src/api/profiles.ts +0 -59
  110. package/connectors/connect-browseruse/src/api/sessions.ts +0 -88
  111. package/connectors/connect-browseruse/src/api/skills.ts +0 -194
  112. package/connectors/connect-browseruse/src/api/tasks.ts +0 -127
  113. package/connectors/connect-browseruse/src/cli/index.ts +0 -888
  114. package/connectors/connect-browseruse/src/index.ts +0 -35
  115. package/connectors/connect-browseruse/src/types/index.ts +0 -312
  116. package/connectors/connect-browseruse/src/utils/config.ts +0 -212
  117. package/connectors/connect-browseruse/src/utils/output.ts +0 -119
  118. package/connectors/connect-browseruse/tsconfig.json +0 -16
@@ -1,888 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { Command } from 'commander';
3
- import chalk from 'chalk';
4
- import { BrowserUse } from '../api';
5
- import {
6
- getApiKey,
7
- setApiKey,
8
- getBaseUrl,
9
- setBaseUrl,
10
- clearConfig,
11
- getConfigDir,
12
- setProfileOverride,
13
- getCurrentProfile,
14
- setCurrentProfile,
15
- listProfiles,
16
- createProfile,
17
- deleteProfile,
18
- profileExists,
19
- loadProfile,
20
- hasApiKey,
21
- } from '../utils/config';
22
- import type { OutputFormat } from '../utils/output';
23
- import { success, error, info, print, warn } from '../utils/output';
24
-
25
- const CONNECTOR_NAME = 'connect-browseruse';
26
- const VERSION = '0.0.2';
27
-
28
- const program = new Command();
29
-
30
- program
31
- .name(CONNECTOR_NAME)
32
- .description('Browser Use Cloud API connector CLI - AI-powered browser automation')
33
- .version(VERSION)
34
- .option('-f, --format <format>', 'Output format (json, pretty)', 'pretty')
35
- .option('-p, --profile <profile>', 'Use a specific profile')
36
- .hook('preAction', (thisCommand) => {
37
- const opts = thisCommand.opts();
38
- if (opts.profile) {
39
- if (!profileExists(opts.profile)) {
40
- error(`Profile "${opts.profile}" does not exist. Create it with "${CONNECTOR_NAME} profile create ${opts.profile}"`);
41
- process.exit(1);
42
- }
43
- setProfileOverride(opts.profile);
44
- }
45
- });
46
-
47
- // Helper to get output format
48
- function getFormat(cmd: Command): OutputFormat {
49
- const parent = cmd.parent;
50
- return (parent?.opts().format || 'pretty') as OutputFormat;
51
- }
52
-
53
- // Helper to get authenticated client
54
- function getClient(): BrowserUse {
55
- const apiKey = getApiKey();
56
- const baseUrl = getBaseUrl();
57
-
58
- if (!apiKey) {
59
- error(`No API key configured. Run "${CONNECTOR_NAME} config set-key <key>" or set BROWSER_USE_API_KEY environment variable.`);
60
- process.exit(1);
61
- }
62
-
63
- return new BrowserUse({ apiKey, baseUrl });
64
- }
65
-
66
- // ============================================
67
- // Profile Commands
68
- // ============================================
69
- const profileCmd = program
70
- .command('profile')
71
- .description('Manage configuration profiles');
72
-
73
- profileCmd
74
- .command('list')
75
- .description('List all profiles')
76
- .action(() => {
77
- const profiles = listProfiles();
78
- const current = getCurrentProfile();
79
-
80
- if (profiles.length === 0) {
81
- info('No profiles found. Use "profile create <name>" to create one.');
82
- return;
83
- }
84
-
85
- success(`Profiles:`);
86
- profiles.forEach(p => {
87
- const isActive = p === current ? chalk.green(' (active)') : '';
88
- console.log(` ${p}${isActive}`);
89
- });
90
- });
91
-
92
- profileCmd
93
- .command('use <name>')
94
- .description('Switch to a profile')
95
- .action((name: string) => {
96
- if (!profileExists(name)) {
97
- error(`Profile "${name}" does not exist. Create it with "profile create ${name}"`);
98
- process.exit(1);
99
- }
100
- setCurrentProfile(name);
101
- success(`Switched to profile: ${name}`);
102
- });
103
-
104
- profileCmd
105
- .command('create <name>')
106
- .description('Create a new profile')
107
- .option('--api-key <key>', 'Browser Use API key')
108
- .option('--use', 'Switch to this profile after creation')
109
- .action((name: string, opts) => {
110
- if (profileExists(name)) {
111
- error(`Profile "${name}" already exists`);
112
- process.exit(1);
113
- }
114
-
115
- createProfile(name, {
116
- apiKey: opts.apiKey,
117
- });
118
- success(`Profile "${name}" created`);
119
-
120
- if (opts.use) {
121
- setCurrentProfile(name);
122
- info(`Switched to profile: ${name}`);
123
- }
124
- });
125
-
126
- profileCmd
127
- .command('delete <name>')
128
- .description('Delete a profile')
129
- .action((name: string) => {
130
- if (name === 'default') {
131
- error('Cannot delete the default profile');
132
- process.exit(1);
133
- }
134
- if (deleteProfile(name)) {
135
- success(`Profile "${name}" deleted`);
136
- } else {
137
- error(`Profile "${name}" not found`);
138
- process.exit(1);
139
- }
140
- });
141
-
142
- profileCmd
143
- .command('show [name]')
144
- .description('Show profile configuration')
145
- .action((name?: string) => {
146
- const profileName = name || getCurrentProfile();
147
- const config = loadProfile(profileName);
148
- const active = getCurrentProfile();
149
-
150
- console.log(chalk.bold(`Profile: ${profileName}${profileName === active ? chalk.green(' (active)') : ''}`));
151
- info(`API Key: ${config.apiKey ? `${config.apiKey.substring(0, 8)}...` : chalk.gray('not set')}`);
152
- info(`Base URL: ${config.baseUrl || chalk.gray('default (https://api.browser-use.com/api/v2)')}`);
153
- });
154
-
155
- // ============================================
156
- // Config Commands
157
- // ============================================
158
- const configCmd = program
159
- .command('config')
160
- .description('Manage CLI configuration');
161
-
162
- configCmd
163
- .command('set-key <apiKey>')
164
- .description('Set Browser Use API key')
165
- .action((apiKey: string) => {
166
- setApiKey(apiKey);
167
- success(`API key saved to profile: ${getCurrentProfile()}`);
168
- });
169
-
170
- configCmd
171
- .command('set-url <baseUrl>')
172
- .description('Set custom base URL')
173
- .action((baseUrl: string) => {
174
- setBaseUrl(baseUrl);
175
- success(`Base URL set to: ${baseUrl}`);
176
- });
177
-
178
- configCmd
179
- .command('show')
180
- .description('Show current configuration')
181
- .action(() => {
182
- const profileName = getCurrentProfile();
183
- const apiKey = getApiKey();
184
- const baseUrl = getBaseUrl();
185
-
186
- console.log(chalk.bold(`Active Profile: ${profileName}`));
187
- info(`Config directory: ${getConfigDir()}`);
188
- info(`API Key: ${apiKey ? `${apiKey.substring(0, 8)}...` : chalk.gray('not set')}`);
189
- info(`Base URL: ${baseUrl}`);
190
- });
191
-
192
- configCmd
193
- .command('clear')
194
- .description('Clear configuration for active profile')
195
- .action(() => {
196
- clearConfig();
197
- success(`Configuration cleared for profile: ${getCurrentProfile()}`);
198
- });
199
-
200
- // ============================================
201
- // Tasks Commands
202
- // ============================================
203
- const tasksCmd = program
204
- .command('tasks')
205
- .alias('task')
206
- .description('Task operations');
207
-
208
- tasksCmd
209
- .command('list')
210
- .description('List all tasks')
211
- .option('-n, --limit <number>', 'Maximum results', '20')
212
- .option('-s, --status <status>', 'Filter by status')
213
- .option('--session <id>', 'Filter by session ID')
214
- .action(async (opts) => {
215
- try {
216
- const client = getClient();
217
- const result = await client.tasks.list({
218
- limit: parseInt(opts.limit),
219
- status: opts.status,
220
- sessionId: opts.session,
221
- });
222
- print(result.data, getFormat(tasksCmd));
223
- if (result.hasMore) {
224
- info('More results available. Use --cursor to paginate.');
225
- }
226
- } catch (err) {
227
- error(String(err));
228
- process.exit(1);
229
- }
230
- });
231
-
232
- tasksCmd
233
- .command('create <task>')
234
- .description('Create a new task')
235
- .option('--session <id>', 'Use existing session')
236
- .option('--save-browser-data', 'Save browser data after task')
237
- .option('--secrets <json>', 'Sensitive data as JSON (e.g., \'{"x_user":"email","x_pass":"password"}\')')
238
- .option('--no-vision', 'Disable vision to prevent LLM from seeing screenshots')
239
- .option('--allowed-domains <domains>', 'Comma-separated list of allowed domains')
240
- .action(async (task: string, opts) => {
241
- try {
242
- const client = getClient();
243
-
244
- // Parse sensitive data if provided
245
- let sensitiveData: Record<string, string> | undefined;
246
- if (opts.secrets) {
247
- try {
248
- sensitiveData = JSON.parse(opts.secrets);
249
- } catch {
250
- error('Invalid JSON for --secrets option');
251
- process.exit(1);
252
- }
253
- }
254
-
255
- const result = await client.tasks.create({
256
- task,
257
- sessionId: opts.session,
258
- save_browser_data: opts.saveBrowserData,
259
- sensitive_data: sensitiveData,
260
- use_vision: opts.vision !== false ? undefined : false,
261
- allowed_domains: opts.allowedDomains?.split(',').map((d: string) => d.trim()),
262
- });
263
- success(`Task created: ${result.id}`);
264
- print(result, getFormat(tasksCmd));
265
- } catch (err) {
266
- error(String(err));
267
- process.exit(1);
268
- }
269
- });
270
-
271
- tasksCmd
272
- .command('get <taskId>')
273
- .description('Get a task by ID')
274
- .action(async (taskId: string) => {
275
- try {
276
- const client = getClient();
277
- const result = await client.tasks.get(taskId);
278
- print(result, getFormat(tasksCmd));
279
- } catch (err) {
280
- error(String(err));
281
- process.exit(1);
282
- }
283
- });
284
-
285
- tasksCmd
286
- .command('run <task>')
287
- .description('Run a task and wait for completion')
288
- .option('--timeout <ms>', 'Timeout in milliseconds', '300000')
289
- .option('--secrets <json>', 'Sensitive data as JSON (e.g., \'{"x_user":"email","x_pass":"password"}\')')
290
- .option('--no-vision', 'Disable vision to prevent LLM from seeing screenshots')
291
- .option('--allowed-domains <domains>', 'Comma-separated list of allowed domains')
292
- .action(async (task: string, opts) => {
293
- try {
294
- const client = getClient();
295
- info('Creating task...');
296
-
297
- // Parse sensitive data if provided
298
- let sensitiveData: Record<string, string> | undefined;
299
- if (opts.secrets) {
300
- try {
301
- sensitiveData = JSON.parse(opts.secrets);
302
- info('Sensitive data configured (values hidden from LLM)');
303
- } catch {
304
- error('Invalid JSON for --secrets option');
305
- process.exit(1);
306
- }
307
- }
308
-
309
- const created = await client.tasks.create({
310
- task,
311
- sensitive_data: sensitiveData,
312
- use_vision: opts.vision !== false ? undefined : false,
313
- allowed_domains: opts.allowedDomains?.split(',').map((d: string) => d.trim()),
314
- });
315
- info(`Task created: ${created.id}`);
316
- if (created.liveUrl) {
317
- info(`Live view: ${created.liveUrl}`);
318
- }
319
-
320
- info('Waiting for completion...');
321
- const result = await client.tasks.waitForCompletion(
322
- created.id,
323
- 2000,
324
- parseInt(opts.timeout)
325
- );
326
-
327
- if (result.status === 'completed') {
328
- success('Task completed successfully');
329
- } else if (result.status === 'failed') {
330
- error(`Task failed: ${result.error}`);
331
- } else {
332
- warn(`Task ended with status: ${result.status}`);
333
- }
334
-
335
- print(result, getFormat(tasksCmd));
336
- } catch (err) {
337
- error(String(err));
338
- process.exit(1);
339
- }
340
- });
341
-
342
- tasksCmd
343
- .command('stop <taskId>')
344
- .description('Stop a running task')
345
- .action(async (taskId: string) => {
346
- try {
347
- const client = getClient();
348
- const result = await client.tasks.stop(taskId);
349
- success(`Task stopped: ${taskId}`);
350
- print(result, getFormat(tasksCmd));
351
- } catch (err) {
352
- error(String(err));
353
- process.exit(1);
354
- }
355
- });
356
-
357
- tasksCmd
358
- .command('pause <taskId>')
359
- .description('Pause a running task')
360
- .action(async (taskId: string) => {
361
- try {
362
- const client = getClient();
363
- const result = await client.tasks.pause(taskId);
364
- success(`Task paused: ${taskId}`);
365
- print(result, getFormat(tasksCmd));
366
- } catch (err) {
367
- error(String(err));
368
- process.exit(1);
369
- }
370
- });
371
-
372
- tasksCmd
373
- .command('resume <taskId>')
374
- .description('Resume a paused task')
375
- .action(async (taskId: string) => {
376
- try {
377
- const client = getClient();
378
- const result = await client.tasks.resume(taskId);
379
- success(`Task resumed: ${taskId}`);
380
- print(result, getFormat(tasksCmd));
381
- } catch (err) {
382
- error(String(err));
383
- process.exit(1);
384
- }
385
- });
386
-
387
- tasksCmd
388
- .command('logs <taskId>')
389
- .description('Get task logs download URL')
390
- .action(async (taskId: string) => {
391
- try {
392
- const client = getClient();
393
- const result = await client.tasks.getLogs(taskId);
394
- print(result, getFormat(tasksCmd));
395
- } catch (err) {
396
- error(String(err));
397
- process.exit(1);
398
- }
399
- });
400
-
401
- // ============================================
402
- // Sessions Commands
403
- // ============================================
404
- const sessionsCmd = program
405
- .command('sessions')
406
- .alias('session')
407
- .description('Session operations');
408
-
409
- sessionsCmd
410
- .command('list')
411
- .description('List all sessions')
412
- .option('-n, --limit <number>', 'Maximum results', '20')
413
- .option('-s, --status <status>', 'Filter by status')
414
- .action(async (opts) => {
415
- try {
416
- const client = getClient();
417
- const result = await client.sessions.list({
418
- limit: parseInt(opts.limit),
419
- status: opts.status,
420
- });
421
- print(result.data, getFormat(sessionsCmd));
422
- } catch (err) {
423
- error(String(err));
424
- process.exit(1);
425
- }
426
- });
427
-
428
- sessionsCmd
429
- .command('create')
430
- .description('Create a new session')
431
- .option('--task <task>', 'Initial task to run')
432
- .option('--profile <id>', 'Browser profile ID')
433
- .option('--proxy <url>', 'Proxy URL')
434
- .option('--keep-alive', 'Keep session alive after task')
435
- .action(async (opts) => {
436
- try {
437
- const client = getClient();
438
- const result = await client.sessions.create({
439
- task: opts.task,
440
- profileId: opts.profile,
441
- proxyUrl: opts.proxy,
442
- keepAlive: opts.keepAlive,
443
- });
444
- success(`Session created: ${result.id}`);
445
- if (result.liveUrl) {
446
- info(`Live view: ${result.liveUrl}`);
447
- }
448
- print(result, getFormat(sessionsCmd));
449
- } catch (err) {
450
- error(String(err));
451
- process.exit(1);
452
- }
453
- });
454
-
455
- sessionsCmd
456
- .command('get <sessionId>')
457
- .description('Get a session by ID')
458
- .action(async (sessionId: string) => {
459
- try {
460
- const client = getClient();
461
- const result = await client.sessions.get(sessionId);
462
- print(result, getFormat(sessionsCmd));
463
- } catch (err) {
464
- error(String(err));
465
- process.exit(1);
466
- }
467
- });
468
-
469
- sessionsCmd
470
- .command('stop <sessionId>')
471
- .description('Stop a session')
472
- .action(async (sessionId: string) => {
473
- try {
474
- const client = getClient();
475
- const result = await client.sessions.stop(sessionId);
476
- success(`Session stopped: ${sessionId}`);
477
- print(result, getFormat(sessionsCmd));
478
- } catch (err) {
479
- error(String(err));
480
- process.exit(1);
481
- }
482
- });
483
-
484
- sessionsCmd
485
- .command('delete <sessionId>')
486
- .description('Delete a session')
487
- .action(async (sessionId: string) => {
488
- try {
489
- const client = getClient();
490
- await client.sessions.delete(sessionId);
491
- success(`Session deleted: ${sessionId}`);
492
- } catch (err) {
493
- error(String(err));
494
- process.exit(1);
495
- }
496
- });
497
-
498
- sessionsCmd
499
- .command('share <sessionId>')
500
- .description('Create public share URL for a session')
501
- .action(async (sessionId: string) => {
502
- try {
503
- const client = getClient();
504
- const result = await client.sessions.createPublicShare(sessionId);
505
- success(`Public share created`);
506
- info(`URL: ${result.publicUrl}`);
507
- info(`Expires: ${result.expiresAt}`);
508
- } catch (err) {
509
- error(String(err));
510
- process.exit(1);
511
- }
512
- });
513
-
514
- // ============================================
515
- // Browser Profiles Commands
516
- // ============================================
517
- const profilesCmd = program
518
- .command('profiles')
519
- .description('Browser profile operations (persistent browser state)');
520
-
521
- profilesCmd
522
- .command('list')
523
- .description('List all browser profiles')
524
- .option('-n, --limit <number>', 'Maximum results', '20')
525
- .action(async (opts) => {
526
- try {
527
- const client = getClient();
528
- const result = await client.profiles.list({
529
- limit: parseInt(opts.limit),
530
- });
531
- print(result.data, getFormat(profilesCmd));
532
- } catch (err) {
533
- error(String(err));
534
- process.exit(1);
535
- }
536
- });
537
-
538
- profilesCmd
539
- .command('create <name>')
540
- .description('Create a new browser profile')
541
- .option('-d, --description <desc>', 'Profile description')
542
- .action(async (name: string, opts) => {
543
- try {
544
- const client = getClient();
545
- const result = await client.profiles.create({
546
- name,
547
- description: opts.description,
548
- });
549
- success(`Browser profile created: ${result.id}`);
550
- print(result, getFormat(profilesCmd));
551
- } catch (err) {
552
- error(String(err));
553
- process.exit(1);
554
- }
555
- });
556
-
557
- profilesCmd
558
- .command('get <profileId>')
559
- .description('Get a browser profile by ID')
560
- .action(async (profileId: string) => {
561
- try {
562
- const client = getClient();
563
- const result = await client.profiles.get(profileId);
564
- print(result, getFormat(profilesCmd));
565
- } catch (err) {
566
- error(String(err));
567
- process.exit(1);
568
- }
569
- });
570
-
571
- profilesCmd
572
- .command('delete <profileId>')
573
- .description('Delete a browser profile')
574
- .action(async (profileId: string) => {
575
- try {
576
- const client = getClient();
577
- await client.profiles.delete(profileId);
578
- success(`Browser profile deleted: ${profileId}`);
579
- } catch (err) {
580
- error(String(err));
581
- process.exit(1);
582
- }
583
- });
584
-
585
- // ============================================
586
- // Skills Commands
587
- // ============================================
588
- const skillsCmd = program
589
- .command('skills')
590
- .alias('skill')
591
- .description('Skill operations');
592
-
593
- skillsCmd
594
- .command('list')
595
- .description('List all skills')
596
- .option('-n, --limit <number>', 'Maximum results', '20')
597
- .option('-s, --status <status>', 'Filter by status')
598
- .action(async (opts) => {
599
- try {
600
- const client = getClient();
601
- const result = await client.skills.list({
602
- limit: parseInt(opts.limit),
603
- status: opts.status,
604
- });
605
- print(result.data, getFormat(skillsCmd));
606
- } catch (err) {
607
- error(String(err));
608
- process.exit(1);
609
- }
610
- });
611
-
612
- skillsCmd
613
- .command('create <name>')
614
- .description('Create a new skill')
615
- .requiredOption('-t, --task <task>', 'Task description for skill generation')
616
- .option('-d, --description <desc>', 'Skill description')
617
- .action(async (name: string, opts) => {
618
- try {
619
- const client = getClient();
620
- info('Creating skill (this may take a while)...');
621
- const result = await client.skills.create({
622
- name,
623
- task: opts.task,
624
- description: opts.description,
625
- });
626
- success(`Skill created: ${result.id}`);
627
- info(`Status: ${result.status}`);
628
- print(result, getFormat(skillsCmd));
629
- } catch (err) {
630
- error(String(err));
631
- process.exit(1);
632
- }
633
- });
634
-
635
- skillsCmd
636
- .command('get <skillId>')
637
- .description('Get a skill by ID')
638
- .action(async (skillId: string) => {
639
- try {
640
- const client = getClient();
641
- const result = await client.skills.get(skillId);
642
- print(result, getFormat(skillsCmd));
643
- } catch (err) {
644
- error(String(err));
645
- process.exit(1);
646
- }
647
- });
648
-
649
- skillsCmd
650
- .command('execute <skillId>')
651
- .description('Execute a skill')
652
- .requiredOption('-p, --params <json>', 'Parameters as JSON')
653
- .option('--session <id>', 'Use existing session')
654
- .action(async (skillId: string, opts) => {
655
- try {
656
- const client = getClient();
657
- const params = JSON.parse(opts.params);
658
- const result = await client.skills.execute(skillId, {
659
- parameters: params,
660
- sessionId: opts.session,
661
- });
662
- success(`Execution started: ${result.id}`);
663
- print(result, getFormat(skillsCmd));
664
- } catch (err) {
665
- error(String(err));
666
- process.exit(1);
667
- }
668
- });
669
-
670
- skillsCmd
671
- .command('run <skillId>')
672
- .description('Execute a skill and wait for completion')
673
- .requiredOption('-p, --params <json>', 'Parameters as JSON')
674
- .option('--timeout <ms>', 'Timeout in milliseconds', '300000')
675
- .action(async (skillId: string, opts) => {
676
- try {
677
- const client = getClient();
678
- const params = JSON.parse(opts.params);
679
- info('Executing skill...');
680
- const result = await client.skills.run(
681
- skillId,
682
- { parameters: params },
683
- 2000,
684
- parseInt(opts.timeout)
685
- );
686
-
687
- if (result.status === 'completed') {
688
- success('Skill execution completed');
689
- } else {
690
- error(`Execution failed: ${result.error}`);
691
- }
692
-
693
- print(result, getFormat(skillsCmd));
694
- } catch (err) {
695
- error(String(err));
696
- process.exit(1);
697
- }
698
- });
699
-
700
- skillsCmd
701
- .command('refine <skillId>')
702
- .description('Refine a skill with feedback')
703
- .requiredOption('-f, --feedback <text>', 'Feedback for improvement')
704
- .action(async (skillId: string, opts) => {
705
- try {
706
- const client = getClient();
707
- const result = await client.skills.refine(skillId, {
708
- feedback: opts.feedback,
709
- });
710
- success(`Skill refinement started`);
711
- print(result, getFormat(skillsCmd));
712
- } catch (err) {
713
- error(String(err));
714
- process.exit(1);
715
- }
716
- });
717
-
718
- skillsCmd
719
- .command('delete <skillId>')
720
- .description('Delete a skill')
721
- .action(async (skillId: string) => {
722
- try {
723
- const client = getClient();
724
- await client.skills.delete(skillId);
725
- success(`Skill deleted: ${skillId}`);
726
- } catch (err) {
727
- error(String(err));
728
- process.exit(1);
729
- }
730
- });
731
-
732
- // ============================================
733
- // Marketplace Commands
734
- // ============================================
735
- const marketplaceCmd = program
736
- .command('marketplace')
737
- .description('Skills marketplace operations');
738
-
739
- marketplaceCmd
740
- .command('list')
741
- .description('List marketplace skills')
742
- .option('-n, --limit <number>', 'Maximum results', '20')
743
- .option('-s, --search <query>', 'Search query')
744
- .action(async (opts) => {
745
- try {
746
- const client = getClient();
747
- const result = await client.marketplace.list({
748
- limit: parseInt(opts.limit),
749
- search: opts.search,
750
- });
751
- print(result.data, getFormat(marketplaceCmd));
752
- } catch (err) {
753
- error(String(err));
754
- process.exit(1);
755
- }
756
- });
757
-
758
- marketplaceCmd
759
- .command('get <skillId>')
760
- .description('Get a marketplace skill by ID')
761
- .action(async (skillId: string) => {
762
- try {
763
- const client = getClient();
764
- const result = await client.marketplace.get(skillId);
765
- print(result, getFormat(marketplaceCmd));
766
- } catch (err) {
767
- error(String(err));
768
- process.exit(1);
769
- }
770
- });
771
-
772
- marketplaceCmd
773
- .command('clone <skillId>')
774
- .description('Clone a marketplace skill to your project')
775
- .option('-n, --name <name>', 'Custom name for cloned skill')
776
- .action(async (skillId: string, opts) => {
777
- try {
778
- const client = getClient();
779
- const result = await client.marketplace.clone(skillId, {
780
- name: opts.name,
781
- });
782
- success(`Skill cloned: ${result.id}`);
783
- print(result, getFormat(marketplaceCmd));
784
- } catch (err) {
785
- error(String(err));
786
- process.exit(1);
787
- }
788
- });
789
-
790
- // ============================================
791
- // Billing Commands
792
- // ============================================
793
- const billingCmd = program
794
- .command('billing')
795
- .description('Billing and account information');
796
-
797
- billingCmd
798
- .command('status')
799
- .description('Show account billing status')
800
- .action(async () => {
801
- try {
802
- const client = getClient();
803
- const result = await client.billing.getAccount();
804
- console.log(chalk.bold(`Account: ${result.email}`));
805
- info(`Plan: ${result.plan}`);
806
- info(`Credits: ${result.credits}`);
807
- print(result, getFormat(billingCmd));
808
- } catch (err) {
809
- error(String(err));
810
- process.exit(1);
811
- }
812
- });
813
-
814
- billingCmd
815
- .command('credits')
816
- .description('Show current credit balance')
817
- .action(async () => {
818
- try {
819
- const client = getClient();
820
- const credits = await client.billing.getCredits();
821
- console.log(chalk.bold(`Credits: ${credits}`));
822
- } catch (err) {
823
- error(String(err));
824
- process.exit(1);
825
- }
826
- });
827
-
828
- // ============================================
829
- // Quick Run Command (shortcut)
830
- // ============================================
831
- program
832
- .command('run <task>')
833
- .description('Run a browser automation task (shortcut)')
834
- .option('--timeout <ms>', 'Timeout in milliseconds', '300000')
835
- .option('--secrets <json>', 'Sensitive data as JSON (e.g., \'{"x_user":"email","x_pass":"password"}\')')
836
- .option('--no-vision', 'Disable vision to prevent LLM from seeing screenshots')
837
- .option('--allowed-domains <domains>', 'Comma-separated list of allowed domains')
838
- .action(async (task: string, opts) => {
839
- try {
840
- const client = getClient();
841
- info('Starting task...');
842
-
843
- // Parse sensitive data if provided
844
- let sensitiveData: Record<string, string> | undefined;
845
- if (opts.secrets) {
846
- try {
847
- sensitiveData = JSON.parse(opts.secrets);
848
- info('Sensitive data configured (values hidden from LLM)');
849
- } catch {
850
- error('Invalid JSON for --secrets option');
851
- process.exit(1);
852
- }
853
- }
854
-
855
- const created = await client.tasks.create({
856
- task,
857
- sensitive_data: sensitiveData,
858
- use_vision: opts.vision !== false ? undefined : false,
859
- allowed_domains: opts.allowedDomains?.split(',').map((d: string) => d.trim()),
860
- });
861
- info(`Task: ${created.id}`);
862
- if (created.liveUrl) {
863
- info(`Live view: ${created.liveUrl}`);
864
- }
865
-
866
- const result = await client.tasks.waitForCompletion(
867
- created.id,
868
- 2000,
869
- parseInt(opts.timeout)
870
- );
871
-
872
- if (result.status === 'completed') {
873
- success('Task completed');
874
- if (result.output) {
875
- print(result.output, getFormat(program));
876
- }
877
- } else {
878
- error(`Task ${result.status}: ${result.error || 'Unknown error'}`);
879
- process.exit(1);
880
- }
881
- } catch (err) {
882
- error(String(err));
883
- process.exit(1);
884
- }
885
- });
886
-
887
- // Parse and execute
888
- program.parse();