@bctrl/cli 0.1.8 → 0.1.9
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/README.md +18 -94
- package/dist/api/client.d.ts +1 -0
- package/dist/api/client.js +1 -0
- package/dist/api/errors.js +2 -2
- package/dist/commands/{vault → account}/index.d.ts +1 -1
- package/dist/commands/account/index.js +21 -0
- package/dist/commands/ai/index.js +13 -8
- package/dist/commands/api-key/index.js +1 -1
- package/dist/commands/browser-extension/index.js +8 -8
- package/dist/commands/conversation/index.d.ts +3 -0
- package/dist/commands/conversation/index.js +51 -0
- package/dist/commands/file/index.js +8 -3
- package/dist/commands/run/index.js +23 -292
- package/dist/commands/runtime/index.js +32 -453
- package/dist/commands/shared/operation.d.ts +3 -0
- package/dist/commands/shared/operation.js +20 -7
- package/dist/commands/space/index.js +0 -25
- package/dist/commands/subaccount/index.js +2 -2
- package/dist/commands/tool/index.js +15 -5
- package/dist/commands/tool-call/index.js +22 -6
- package/dist/commands/toolset/index.js +1 -1
- package/dist/commands/view/index.d.ts +3 -0
- package/dist/commands/view/index.js +26 -0
- package/dist/commands/webhook/index.d.ts +3 -0
- package/dist/commands/webhook/index.js +64 -0
- package/dist/generated/help.d.ts +4896 -5977
- package/dist/generated/help.js +6208 -7532
- package/dist/generated/openapi-routes.d.ts +114 -142
- package/dist/generated/openapi-routes.js +37 -44
- package/dist/generated/openapi-types.d.ts +4451 -5302
- package/dist/root.js +8 -2
- package/package.json +1 -1
- package/dist/commands/vault/index.js +0 -171
package/README.md
CHANGED
|
@@ -1,113 +1,37 @@
|
|
|
1
1
|
# BCTRL CLI
|
|
2
2
|
|
|
3
|
-
Command-line tools for BCTRL cloud browser automation. Use it to create browser runtimes, start live sessions, submit hosted invocations, inspect runs and files, and manage account resources from a terminal or script.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
3
|
```bash
|
|
8
4
|
npm install -g @bctrl/cli
|
|
5
|
+
bctrl auth login
|
|
9
6
|
```
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## Authenticate
|
|
14
|
-
|
|
15
|
-
For an interactive terminal, start the browser approval flow and wait for completion:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
bctrl auth login --url --wait
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
For CI, agents, or one-off shells, use an API key:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
export BCTRL_API_KEY="bctrl_..."
|
|
25
|
-
bctrl auth status
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
`BCTRL_API_KEY` takes precedence over credentials stored by `bctrl auth login`.
|
|
29
|
-
|
|
30
|
-
## Quick Start
|
|
31
|
-
|
|
32
|
-
Create a browser runtime, start it, run an extraction task, then stop it:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
bctrl runtime create --name research-browser --json
|
|
36
|
-
bctrl runtime start <runtime-id> --json
|
|
37
|
-
|
|
38
|
-
bctrl runtime invocation create <runtime-id> \
|
|
39
|
-
--action extract \
|
|
40
|
-
--instruction "Extract the page title." \
|
|
41
|
-
--json
|
|
42
|
-
|
|
43
|
-
bctrl runtime invocation wait <runtime-id> <invocation-id> --json
|
|
44
|
-
bctrl runtime stop <runtime-id>
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
For full request bodies, pass JSON with `--body`. Inline JSON, `@file`, and `-` for stdin are supported:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
bctrl runtime invocation create <runtime-id> \
|
|
51
|
-
--body '{"action":"observe","instruction":"Summarize the current page."}' \
|
|
52
|
-
--json
|
|
53
|
-
|
|
54
|
-
cat invocation.json | bctrl runtime invocation create <runtime-id> --body - --json
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Use `--params` for path and query overrides when you need the exact API surface:
|
|
8
|
+
Create and start runtimes with `bctrl runtime`. Automation is exposed through a
|
|
9
|
+
small generic Tool interface:
|
|
58
10
|
|
|
59
11
|
```bash
|
|
60
|
-
bctrl
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
## Output
|
|
12
|
+
bctrl tools call stagehand.act \
|
|
13
|
+
--body '{"runtimeId":"rt_...","instruction":"Click Continue"}'
|
|
64
14
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
bctrl runtime list --json
|
|
15
|
+
bctrl tools start captcha.solve --body '{"runtimeId":"rt_..."}'
|
|
16
|
+
bctrl tool-calls result call_... --params '{"waitSeconds":60}'
|
|
69
17
|
```
|
|
70
18
|
|
|
71
|
-
|
|
19
|
+
Use persistent conversations for long-running agents:
|
|
72
20
|
|
|
73
21
|
```bash
|
|
74
|
-
bctrl
|
|
22
|
+
bctrl conversations create \
|
|
23
|
+
--body '{"agent":"browser-use","runtimeId":"rt_..."}'
|
|
24
|
+
bctrl conversations message conv_... --body '{"text":"Complete checkout"}'
|
|
25
|
+
bctrl conversations stream conv_...
|
|
75
26
|
```
|
|
76
27
|
|
|
77
|
-
|
|
28
|
+
Every automation path contributes to one Run:
|
|
78
29
|
|
|
79
30
|
```bash
|
|
80
|
-
bctrl
|
|
31
|
+
bctrl runs trace run_...
|
|
32
|
+
bctrl runs events run_...
|
|
33
|
+
bctrl runs stream run_...
|
|
81
34
|
```
|
|
82
35
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
bctrl runtime list \
|
|
87
|
-
--json \
|
|
88
|
-
--template '{{#each data}}{{id}} {{status}}{{newline}}{{/each}}'
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Common Commands
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
bctrl space list
|
|
95
|
-
bctrl runtime create --name browser-task
|
|
96
|
-
bctrl runtime start <runtime-id>
|
|
97
|
-
bctrl runtime target create <runtime-id> --uri https://example.com --activate
|
|
98
|
-
bctrl runtime invocation create <runtime-id> --action act --instruction "Click the sign in button"
|
|
99
|
-
bctrl run list --json
|
|
100
|
-
bctrl runtime stop <runtime-id>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Run any command with `--help` for the exact arguments and flags:
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
bctrl runtime invocation create --help
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## Documentation
|
|
110
|
-
|
|
111
|
-
- CLI guide: https://platform.bctrl.ai/cli
|
|
112
|
-
- Command reference: https://platform.bctrl.ai/cli/reference
|
|
113
|
-
- API reference: https://platform.bctrl.ai/api-reference
|
|
36
|
+
All JSON-body commands accept inline JSON, `@file.json`, or `-` for stdin through
|
|
37
|
+
`--body`. Use `--json`, `--jq`, or `--template` to control output.
|
package/dist/api/client.d.ts
CHANGED
package/dist/api/client.js
CHANGED
|
@@ -120,6 +120,7 @@ function requestHeaders(token, options, accept) {
|
|
|
120
120
|
authorization: `Bearer ${token}`,
|
|
121
121
|
'user-agent': 'BCTRL CLI',
|
|
122
122
|
...(options?.actingSubaccountId ? { 'BCTRL-Subaccount-Id': options.actingSubaccountId } : {}),
|
|
123
|
+
...(options?.runtimeId ? { 'BCTRL-Runtime-Id': options.runtimeId } : {}),
|
|
123
124
|
};
|
|
124
125
|
}
|
|
125
126
|
function buildUrl(baseUrl, path, query) {
|
package/dist/api/errors.js
CHANGED
|
@@ -77,8 +77,8 @@ function suggestionForApiError(error) {
|
|
|
77
77
|
return commandWithOptionalSpace('bctrl toolset list', error.details);
|
|
78
78
|
case 'tool_call.not_found':
|
|
79
79
|
return 'bctrl tool-call list';
|
|
80
|
-
case '
|
|
81
|
-
return 'bctrl
|
|
80
|
+
case 'tool.not_found':
|
|
81
|
+
return 'bctrl tools list';
|
|
82
82
|
case 'browser_extension.not_found':
|
|
83
83
|
return 'bctrl browser extension list';
|
|
84
84
|
case 'ai_credential.not_found':
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { addOutputFlags } from '../shared/output.js';
|
|
3
|
+
import { createOperationJsonBodyCommand, outputFlags, requestOperationAndPrint, } from '../shared/operation.js';
|
|
4
|
+
export function createAccountCommand(factory) {
|
|
5
|
+
const command = new Command('account').description('Manage organization settings');
|
|
6
|
+
command.addCommand(addOutputFlags(new Command('get').description('Get organization settings')).action(async (options) => {
|
|
7
|
+
await requestOperationAndPrint(factory, 'account.get', {
|
|
8
|
+
output: outputFlags(options),
|
|
9
|
+
});
|
|
10
|
+
}));
|
|
11
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
12
|
+
operationId: 'account.update',
|
|
13
|
+
name: 'patch',
|
|
14
|
+
description: 'Update organization settings (use --body for branding merge-patch JSON)',
|
|
15
|
+
configure: (cmd) => cmd.option('--dry-run', 'Validate and resolve without persisting'),
|
|
16
|
+
query: (_args, options) => ({
|
|
17
|
+
dryRun: options.dryRun === true,
|
|
18
|
+
}),
|
|
19
|
+
}));
|
|
20
|
+
return command;
|
|
21
|
+
}
|
|
@@ -70,14 +70,19 @@ function createAiCredentialWriteCommand(factory, name, operationId, argNames = [
|
|
|
70
70
|
name,
|
|
71
71
|
description: name === 'create' ? 'Create an AI credential' : 'Update an AI credential',
|
|
72
72
|
argNames,
|
|
73
|
-
configure: (cmd) =>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
configure: (cmd) => {
|
|
74
|
+
const configured = cmd
|
|
75
|
+
.option('--name <name>', 'Credential name')
|
|
76
|
+
.option('--provider <provider>', 'Provider key')
|
|
77
|
+
.option('--api-key <key>', 'Provider API key')
|
|
78
|
+
.option('--status <status>', 'Credential status')
|
|
79
|
+
.option('--default-model <model>', 'Default model')
|
|
80
|
+
.option('--base-url <url>', 'Custom provider base URL');
|
|
81
|
+
if (name === 'create') {
|
|
82
|
+
configured.option('--subaccount-id <id>', 'Use this Subaccount account context with an Organization key');
|
|
83
|
+
}
|
|
84
|
+
return configured;
|
|
85
|
+
},
|
|
81
86
|
body: async (_args, options) => {
|
|
82
87
|
return {
|
|
83
88
|
name: options.name,
|
|
@@ -23,7 +23,7 @@ export function createApiKeyCommand(factory) {
|
|
|
23
23
|
description: 'Create an API key',
|
|
24
24
|
configure: (cmd) => cmd
|
|
25
25
|
.option('--name <name>', 'API key name')
|
|
26
|
-
.option('--subaccount-id <id>', 'Create a
|
|
26
|
+
.option('--subaccount-id <id>', 'Create a key confined to this Subaccount')
|
|
27
27
|
.option('--expires-at <iso>', 'Expiration timestamp'),
|
|
28
28
|
body: async (_args, options) => {
|
|
29
29
|
return {
|
|
@@ -5,7 +5,7 @@ import { actingSubaccountOption, createOperationDeleteCommand, createOperationJs
|
|
|
5
5
|
export function createBrowserExtensionCommand(factory) {
|
|
6
6
|
const command = new Command('browser-extension').description('Manage browser extensions');
|
|
7
7
|
command.addCommand(createOperationListCommand(factory, {
|
|
8
|
-
operationId: 'browser
|
|
8
|
+
operationId: 'browser.extensions.list',
|
|
9
9
|
description: 'List browser extensions',
|
|
10
10
|
configure: (cmd) => cmd
|
|
11
11
|
.option('--subaccount-id <id>', 'Filter by subaccount id')
|
|
@@ -20,7 +20,7 @@ export function createBrowserExtensionCommand(factory) {
|
|
|
20
20
|
actingSubaccountId: actingSubaccountOption(),
|
|
21
21
|
}));
|
|
22
22
|
command.addCommand(createOperationViewCommand(factory, {
|
|
23
|
-
operationId: 'browser
|
|
23
|
+
operationId: 'browser.extensions.get',
|
|
24
24
|
name: 'get',
|
|
25
25
|
description: 'Get a browser extension',
|
|
26
26
|
argName: 'extensionId',
|
|
@@ -29,9 +29,9 @@ export function createBrowserExtensionCommand(factory) {
|
|
|
29
29
|
.description('Upload a browser extension package')
|
|
30
30
|
.argument('<path>')
|
|
31
31
|
.option('--name <name>', 'Display name')
|
|
32
|
-
.option('--subaccount-id <id>', 'Create
|
|
32
|
+
.option('--subaccount-id <id>', 'Create in this Subaccount account context with an Organization key')).action(async (path, options) => {
|
|
33
33
|
const file = await readBlob(path);
|
|
34
|
-
const result = await uploadOperationFile(factory, 'browser
|
|
34
|
+
const result = await uploadOperationFile(factory, 'browser.extensions.create', {
|
|
35
35
|
file: file.blob,
|
|
36
36
|
fileName: file.fileName,
|
|
37
37
|
fields: {
|
|
@@ -42,13 +42,13 @@ export function createBrowserExtensionCommand(factory) {
|
|
|
42
42
|
await outputData(factory.io, result, options);
|
|
43
43
|
}));
|
|
44
44
|
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
45
|
-
operationId: 'browser
|
|
45
|
+
operationId: 'browser.extensions.create',
|
|
46
46
|
name: 'import',
|
|
47
47
|
description: 'Import a browser extension from a URL',
|
|
48
48
|
configure: (cmd) => cmd
|
|
49
49
|
.option('--url <url>', 'Extension URL')
|
|
50
50
|
.option('--name <name>', 'Display name')
|
|
51
|
-
.option('--subaccount-id <id>', 'Create
|
|
51
|
+
.option('--subaccount-id <id>', 'Create in this Subaccount account context with an Organization key'),
|
|
52
52
|
body: async (_args, options) => {
|
|
53
53
|
return {
|
|
54
54
|
url: options.url,
|
|
@@ -58,7 +58,7 @@ export function createBrowserExtensionCommand(factory) {
|
|
|
58
58
|
actingSubaccountId: (_args, options) => actingSubaccountOption()(options),
|
|
59
59
|
}));
|
|
60
60
|
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
61
|
-
operationId: 'browser
|
|
61
|
+
operationId: 'browser.extensions.update',
|
|
62
62
|
name: 'patch',
|
|
63
63
|
description: 'Update a browser extension',
|
|
64
64
|
argNames: ['extensionId'],
|
|
@@ -69,7 +69,7 @@ export function createBrowserExtensionCommand(factory) {
|
|
|
69
69
|
},
|
|
70
70
|
}));
|
|
71
71
|
command.addCommand(createOperationDeleteCommand(factory, {
|
|
72
|
-
operationId: 'browser
|
|
72
|
+
operationId: 'browser.extensions.delete',
|
|
73
73
|
description: 'Delete a browser extension',
|
|
74
74
|
argNames: ['extensionId'],
|
|
75
75
|
}));
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { createOperationJsonBodyCommand, createOperationListCommand, createOperationViewCommand, streamOperationText, } from '../shared/operation.js';
|
|
3
|
+
export function createConversationCommand(factory) {
|
|
4
|
+
const command = new Command('conversations').description('Converse with runtime agents');
|
|
5
|
+
command.addCommand(createOperationListCommand(factory, {
|
|
6
|
+
operationId: 'conversations.list',
|
|
7
|
+
description: 'List conversations',
|
|
8
|
+
}));
|
|
9
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
10
|
+
operationId: 'conversations.create',
|
|
11
|
+
name: 'create',
|
|
12
|
+
description: 'Create a conversation',
|
|
13
|
+
}));
|
|
14
|
+
command.addCommand(createOperationViewCommand(factory, {
|
|
15
|
+
operationId: 'conversations.get',
|
|
16
|
+
name: 'get',
|
|
17
|
+
description: 'Get a conversation and its messages',
|
|
18
|
+
argName: 'conversationId',
|
|
19
|
+
}));
|
|
20
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
21
|
+
operationId: 'conversations.update',
|
|
22
|
+
name: 'patch',
|
|
23
|
+
description: 'Update the default agent, model, toolset, or title',
|
|
24
|
+
argNames: ['conversationId'],
|
|
25
|
+
}));
|
|
26
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
27
|
+
operationId: 'conversations.messages.create',
|
|
28
|
+
name: 'message',
|
|
29
|
+
description: 'Send a message and start an agent turn',
|
|
30
|
+
argNames: ['conversationId'],
|
|
31
|
+
}));
|
|
32
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
33
|
+
operationId: 'conversations.cancel',
|
|
34
|
+
name: 'cancel',
|
|
35
|
+
description: 'Cancel the active agent turn',
|
|
36
|
+
argNames: ['conversationId'],
|
|
37
|
+
}));
|
|
38
|
+
command.addCommand(new Command('stream')
|
|
39
|
+
.description('Stream normalized conversation events')
|
|
40
|
+
.argument('<conversationId>')
|
|
41
|
+
.option('--after <cursor>', 'Resume after a stream cursor')
|
|
42
|
+
.action(async (conversationId, options) => {
|
|
43
|
+
const stream = await streamOperationText(factory, 'conversations.stream', {
|
|
44
|
+
pathParams: { conversationId },
|
|
45
|
+
query: { after: options.after },
|
|
46
|
+
});
|
|
47
|
+
for await (const chunk of stream)
|
|
48
|
+
factory.io.writeOut(chunk);
|
|
49
|
+
}));
|
|
50
|
+
return command;
|
|
51
|
+
}
|
|
@@ -10,21 +10,26 @@ export function createFileCommand(factory) {
|
|
|
10
10
|
description: 'List files',
|
|
11
11
|
configure: (cmd) => cmd
|
|
12
12
|
.option('--space <id>', 'Filter by space id')
|
|
13
|
+
.option('--run <id>', 'Filter by run id')
|
|
14
|
+
.option('--runtime <id>', 'Filter by runtime id')
|
|
15
|
+
.option('--type <type...>', 'Filter by file artifact type')
|
|
13
16
|
.option('--source <source>', 'Filter by file source')
|
|
14
17
|
.option('--prefix <path>', 'Filter by path prefix')
|
|
15
18
|
.option('--folders', 'Directory view: direct files plus subfolder rollups')
|
|
16
19
|
.option('--created-after <iso>', 'Only files created after this timestamp')
|
|
17
|
-
.option('--
|
|
20
|
+
.option('--q <text>', 'Search query')
|
|
18
21
|
.option('-L, --limit <number>', 'Maximum number of results to return', parsePositiveInteger)
|
|
19
22
|
.option('--cursor <cursor>', 'Pagination cursor'),
|
|
20
23
|
query: (options) => ({
|
|
21
24
|
spaceId: typeof options.space === 'string' ? options.space : undefined,
|
|
25
|
+
runId: typeof options.run === 'string' ? options.run : undefined,
|
|
26
|
+
runtimeId: typeof options.runtime === 'string' ? options.runtime : undefined,
|
|
27
|
+
type: Array.isArray(options.type) ? options.type : undefined,
|
|
22
28
|
source: typeof options.source === 'string' ? options.source : undefined,
|
|
23
29
|
prefix: typeof options.prefix === 'string' ? options.prefix : undefined,
|
|
24
30
|
include: options.folders === true ? 'folders' : undefined,
|
|
25
31
|
createdAfter: typeof options.createdAfter === 'string' ? options.createdAfter : undefined,
|
|
26
|
-
|
|
27
|
-
q: typeof options.query === 'string' ? options.query : undefined,
|
|
32
|
+
q: typeof options.q === 'string' ? options.q : undefined,
|
|
28
33
|
limit: typeof options.limit === 'number' ? options.limit : undefined,
|
|
29
34
|
cursor: typeof options.cursor === 'string' ? options.cursor : undefined,
|
|
30
35
|
}),
|