@hasna/connectors 0.1.0 → 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.
- package/LICENSE +191 -0
- package/README.md +19 -13
- package/bin/index.js +171 -69
- package/bin/mcp.js +24 -18
- package/bin/serve.js +94 -32
- package/connectors/connect-anthropic/package.json +2 -2
- package/connectors/connect-aws/package.json +2 -2
- package/connectors/connect-brandsight/package.json +2 -2
- package/connectors/connect-cloudflare/.env.example +0 -5
- package/connectors/connect-cloudflare/package.json +2 -2
- package/connectors/connect-discord/package.json +2 -2
- package/connectors/connect-docker/package.json +2 -2
- package/connectors/connect-e2b/package.json +2 -2
- package/connectors/connect-elevenlabs/package.json +2 -2
- package/connectors/connect-exa/package.json +2 -2
- package/connectors/connect-figma/package.json +2 -2
- package/connectors/connect-firecrawl/package.json +2 -2
- package/connectors/connect-github/package.json +2 -2
- package/connectors/connect-gmail/package.json +2 -2
- package/connectors/connect-google/package.json +2 -2
- package/connectors/connect-googlecalendar/package.json +2 -2
- package/connectors/connect-googlecloud/package.json +2 -2
- package/connectors/connect-googlecontacts/package.json +2 -2
- package/connectors/connect-googledocs/package.json +2 -2
- package/connectors/connect-googledrive/package.json +2 -2
- package/connectors/connect-googlegemini/package.json +2 -2
- package/connectors/connect-googlesheets/package.json +2 -2
- package/connectors/connect-googletasks/package.json +2 -2
- package/connectors/connect-hedra/package.json +2 -2
- package/connectors/connect-heygen/package.json +2 -2
- package/connectors/connect-huggingface/package.json +2 -2
- package/connectors/connect-icons8/package.json +2 -2
- package/connectors/connect-maropost/package.json +2 -2
- package/connectors/connect-mercury/package.json +2 -2
- package/connectors/connect-meta/package.json +2 -2
- package/connectors/connect-midjourney/package.json +2 -2
- package/connectors/connect-mistral/package.json +2 -2
- package/connectors/connect-mixpanel/package.json +2 -2
- package/connectors/connect-notion/.env.example +0 -5
- package/connectors/connect-notion/package.json +2 -2
- package/connectors/connect-openai/package.json +2 -2
- package/connectors/connect-openweathermap/package.json +2 -2
- package/connectors/connect-pandadoc/package.json +2 -2
- package/connectors/connect-quo/package.json +2 -2
- package/connectors/connect-reddit/package.json +2 -2
- package/connectors/connect-reducto/package.json +1 -1
- package/connectors/connect-resend/package.json +2 -2
- package/connectors/connect-revolut/package.json +2 -2
- package/connectors/connect-sedo/package.json +2 -2
- package/connectors/connect-sentry/package.json +2 -2
- package/connectors/connect-shadcn/package.json +2 -2
- package/connectors/connect-snap/package.json +2 -2
- package/connectors/connect-stabilityai/package.json +2 -2
- package/connectors/connect-stripe/package.json +2 -2
- package/connectors/connect-stripeatlas/package.json +2 -2
- package/connectors/connect-substack/package.json +2 -2
- package/connectors/connect-tiktok/package.json +2 -2
- package/connectors/connect-tinker/package.json +2 -2
- package/connectors/connect-twilio/package.json +4 -4
- package/connectors/connect-uspto/package.json +2 -2
- package/connectors/connect-x/package.json +2 -2
- package/connectors/connect-xads/package.json +2 -2
- package/connectors/connect-xai/package.json +2 -2
- package/connectors/connect-youtube/package.json +2 -2
- package/connectors/connect-zoom/package.json +2 -2
- package/dist/cli/cli.test.d.ts +1 -0
- package/dist/cli/components/App.d.ts +6 -0
- package/dist/cli/components/CategorySelect.d.ts +6 -0
- package/dist/cli/components/ConnectorSelect.d.ts +10 -0
- package/dist/cli/components/Header.d.ts +6 -0
- package/dist/cli/components/InstallProgress.d.ts +8 -0
- package/dist/cli/components/SearchView.d.ts +8 -0
- package/dist/cli/components/components.test.d.ts +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -16
- package/dist/lib/installer.d.ts +55 -0
- package/dist/lib/installer.test.d.ts +1 -0
- package/dist/lib/registry.d.ts +18 -0
- package/dist/lib/registry.test.d.ts +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/mcp.test.d.ts +1 -0
- package/dist/server/auth.d.ts +70 -0
- package/dist/server/dashboard.d.ts +5 -0
- package/dist/server/index.d.ts +6 -0
- package/dist/server/serve.d.ts +12 -0
- package/dist/server/server.test.d.ts +1 -0
- package/package.json +5 -4
- package/connectors/connect-browseruse/.env.example +0 -7
- package/connectors/connect-browseruse/.npmrc.example +0 -2
- package/connectors/connect-browseruse/AGENTS.md +0 -172
- package/connectors/connect-browseruse/CLAUDE.md +0 -172
- package/connectors/connect-browseruse/GEMINI.md +0 -172
- package/connectors/connect-browseruse/README.md +0 -153
- package/connectors/connect-browseruse/package.json +0 -52
- package/connectors/connect-browseruse/src/api/billing.ts +0 -32
- package/connectors/connect-browseruse/src/api/browsers.ts +0 -50
- package/connectors/connect-browseruse/src/api/client.ts +0 -168
- package/connectors/connect-browseruse/src/api/files.ts +0 -70
- package/connectors/connect-browseruse/src/api/index.ts +0 -95
- package/connectors/connect-browseruse/src/api/profiles.ts +0 -59
- package/connectors/connect-browseruse/src/api/sessions.ts +0 -88
- package/connectors/connect-browseruse/src/api/skills.ts +0 -194
- package/connectors/connect-browseruse/src/api/tasks.ts +0 -127
- package/connectors/connect-browseruse/src/cli/index.ts +0 -888
- package/connectors/connect-browseruse/src/index.ts +0 -35
- package/connectors/connect-browseruse/src/types/index.ts +0 -312
- package/connectors/connect-browseruse/src/utils/config.ts +0 -212
- package/connectors/connect-browseruse/src/utils/output.ts +0 -119
- 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();
|