@bctrl/cli 0.1.3 → 0.1.5
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 +95 -95
- package/dist/api/auth.d.ts +5 -6
- package/dist/api/auth.js +4 -5
- package/dist/api/client.d.ts +1 -0
- package/dist/api/client.js +3 -0
- package/dist/api/errors.js +2 -2
- package/dist/bin/bctrl.js +0 -0
- package/dist/commands/ai/index.js +71 -106
- package/dist/commands/{browser → api-key}/index.d.ts +1 -1
- package/dist/commands/api-key/index.js +47 -0
- package/dist/commands/auth/login.js +2 -1
- package/dist/commands/auth/status.js +5 -0
- package/dist/commands/browser-extension/index.d.ts +3 -0
- package/dist/commands/browser-extension/index.js +85 -0
- package/dist/commands/file/index.js +26 -21
- package/dist/commands/{invocation → help}/index.d.ts +1 -1
- package/dist/commands/help/index.js +17 -0
- package/dist/commands/proxy/index.d.ts +3 -0
- package/dist/commands/proxy/index.js +72 -0
- package/dist/commands/run/index.js +227 -160
- package/dist/commands/runtime/index.js +343 -118
- package/dist/commands/shared/help.d.ts +1 -0
- package/dist/commands/shared/help.js +10 -6
- package/dist/commands/shared/operation.d.ts +83 -0
- package/dist/commands/shared/{rest.js → operation.js} +81 -32
- package/dist/commands/space/index.js +62 -68
- package/dist/commands/space/list.d.ts +1 -11
- package/dist/commands/space/list.js +12 -20
- package/dist/commands/subaccount/index.js +56 -125
- package/dist/commands/tool/index.js +28 -22
- package/dist/commands/tool-call/index.js +11 -6
- package/dist/commands/toolset/index.js +16 -15
- package/dist/commands/usage/index.d.ts +3 -0
- package/dist/commands/usage/index.js +13 -0
- package/dist/commands/vault/index.js +115 -34
- package/dist/config/auth-store.d.ts +10 -12
- package/dist/config/auth-store.js +4 -5
- package/dist/generated/help.d.ts +5992 -71
- package/dist/generated/help.js +7918 -123
- package/dist/generated/openapi-routes.d.ts +391 -0
- package/dist/generated/openapi-routes.js +100 -0
- package/dist/generated/openapi-types.d.ts +13755 -0
- package/dist/generated/openapi-types.js +5 -0
- package/dist/openapi.d.ts +20 -0
- package/dist/openapi.js +1 -0
- package/dist/root.js +10 -4
- package/package.json +47 -45
- package/dist/commands/browser/index.js +0 -53
- package/dist/commands/invocation/index.js +0 -36
- package/dist/commands/shared/rest.d.ts +0 -54
|
@@ -2,16 +2,18 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { readBlob, readJsonFile, writeBinary } from '../shared/io.js';
|
|
3
3
|
import { parsePositiveInteger } from '../shared/options.js';
|
|
4
4
|
import { addOutputFlags, outputData } from '../shared/output.js';
|
|
5
|
-
import {
|
|
5
|
+
import { createOperationDeleteCommand, createOperationJsonBodyCommand, createOperationListCommand, createOperationViewCommand, downloadOperation, uploadOperationFile, } from '../shared/operation.js';
|
|
6
6
|
export function createFileCommand(factory) {
|
|
7
7
|
const command = new Command('file').description('Upload, download, and manage BCTRL files');
|
|
8
|
-
command.addCommand(
|
|
8
|
+
command.addCommand(createOperationListCommand(factory, {
|
|
9
|
+
operationId: 'files.list',
|
|
9
10
|
description: 'List files',
|
|
10
|
-
path: '/files',
|
|
11
11
|
configure: (cmd) => cmd
|
|
12
12
|
.option('--space <id>', 'Filter by space id')
|
|
13
13
|
.option('--source <source>', 'Filter by file source')
|
|
14
14
|
.option('--prefix <path>', 'Filter by path prefix')
|
|
15
|
+
.option('--folders', 'Directory view: direct files plus subfolder rollups')
|
|
16
|
+
.option('--created-after <iso>', 'Only files created after this timestamp')
|
|
15
17
|
.option('--query <text>', 'Search query')
|
|
16
18
|
.option('-L, --limit <number>', 'Maximum number of results to return', parsePositiveInteger)
|
|
17
19
|
.option('--cursor <cursor>', 'Pagination cursor'),
|
|
@@ -19,26 +21,28 @@ export function createFileCommand(factory) {
|
|
|
19
21
|
spaceId: typeof options.space === 'string' ? options.space : undefined,
|
|
20
22
|
source: typeof options.source === 'string' ? options.source : undefined,
|
|
21
23
|
prefix: typeof options.prefix === 'string' ? options.prefix : undefined,
|
|
22
|
-
|
|
24
|
+
include: options.folders === true ? 'folders' : undefined,
|
|
25
|
+
createdAfter: typeof options.createdAfter === 'string' ? options.createdAfter : undefined,
|
|
26
|
+
// The public query param is `q` (was sent as `query`, which the API ignores).
|
|
27
|
+
q: typeof options.query === 'string' ? options.query : undefined,
|
|
23
28
|
limit: typeof options.limit === 'number' ? options.limit : undefined,
|
|
24
29
|
cursor: typeof options.cursor === 'string' ? options.cursor : undefined,
|
|
25
30
|
}),
|
|
26
31
|
}));
|
|
27
|
-
command.addCommand(
|
|
32
|
+
command.addCommand(createOperationViewCommand(factory, {
|
|
33
|
+
operationId: 'files.get',
|
|
34
|
+
name: 'get',
|
|
28
35
|
description: 'View file metadata',
|
|
29
|
-
path: '/files/{fileId}',
|
|
30
36
|
argName: 'fileId',
|
|
31
37
|
}));
|
|
32
38
|
command.addCommand(addOutputFlags(new Command('upload')
|
|
33
39
|
.description('Upload a file')
|
|
34
40
|
.argument('<path>')
|
|
35
|
-
.
|
|
41
|
+
.option('--space <id>', 'Space id; omitted uses caller default space')
|
|
36
42
|
.option('--path <storagePath>', 'Storage path')
|
|
37
|
-
.option('--name <name>', 'Display name'))
|
|
38
|
-
.action(async (path, options) => {
|
|
39
|
-
const client = await factory.apiClient();
|
|
43
|
+
.option('--name <name>', 'Display name')).action(async (path, options) => {
|
|
40
44
|
const file = await readBlob(path);
|
|
41
|
-
const result = await
|
|
45
|
+
const result = await uploadOperationFile(factory, 'files.upload', {
|
|
42
46
|
file: file.blob,
|
|
43
47
|
fileName: options.name ?? file.fileName,
|
|
44
48
|
query: { spaceId: options.space },
|
|
@@ -54,23 +58,24 @@ export function createFileCommand(factory) {
|
|
|
54
58
|
.argument('<id>')
|
|
55
59
|
.requiredOption('--to <path>', 'Output path, or - for stdout')
|
|
56
60
|
.action(async (id, options) => {
|
|
57
|
-
const
|
|
58
|
-
|
|
61
|
+
const data = await downloadOperation(factory, 'files.content', {
|
|
62
|
+
pathParams: { fileId: id },
|
|
63
|
+
});
|
|
59
64
|
await writeBinary(options.to, data);
|
|
60
65
|
}));
|
|
61
|
-
command.addCommand(
|
|
62
|
-
|
|
66
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
67
|
+
operationId: 'files.update',
|
|
68
|
+
name: 'patch',
|
|
63
69
|
description: 'Edit file metadata',
|
|
64
|
-
method: 'patch',
|
|
65
|
-
path: '/files/{fileId}',
|
|
66
70
|
argNames: ['fileId'],
|
|
67
71
|
configure: (cmd) => cmd
|
|
68
72
|
.option('--name <name>', 'Display name')
|
|
69
73
|
.option('--metadata-file <path>', 'Metadata JSON file')
|
|
70
74
|
.option('--input <path>', 'Read full JSON request body from file, or - for stdin'),
|
|
71
75
|
body: async (_args, options) => {
|
|
72
|
-
if (typeof options.input === 'string')
|
|
73
|
-
return readJsonFile(options.input);
|
|
76
|
+
if (typeof options.input === 'string') {
|
|
77
|
+
return (await readJsonFile(options.input));
|
|
78
|
+
}
|
|
74
79
|
return {
|
|
75
80
|
name: options.name,
|
|
76
81
|
metadata: typeof options.metadataFile === 'string'
|
|
@@ -79,9 +84,9 @@ export function createFileCommand(factory) {
|
|
|
79
84
|
};
|
|
80
85
|
},
|
|
81
86
|
}));
|
|
82
|
-
command.addCommand(
|
|
87
|
+
command.addCommand(createOperationDeleteCommand(factory, {
|
|
88
|
+
operationId: 'files.delete',
|
|
83
89
|
description: 'Delete a file',
|
|
84
|
-
path: '/files/{fileId}',
|
|
85
90
|
argNames: ['fileId'],
|
|
86
91
|
}));
|
|
87
92
|
return command;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { addOutputFlags } from '../shared/output.js';
|
|
3
|
+
import { outputFlags, requestOperationAndPrint } from '../shared/operation.js';
|
|
4
|
+
export function createHelpCommand(factory) {
|
|
5
|
+
return addOutputFlags(new Command('help')
|
|
6
|
+
.description('Get BCTRL API help')
|
|
7
|
+
.option('--topic <topic>', 'Help topic')
|
|
8
|
+
.option('--audience <audience>', 'Help audience')).action(async (options) => {
|
|
9
|
+
await requestOperationAndPrint(factory, 'help', {
|
|
10
|
+
query: {
|
|
11
|
+
topic: options.topic,
|
|
12
|
+
audience: options.audience,
|
|
13
|
+
},
|
|
14
|
+
output: outputFlags(options),
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { addOutputFlags } from '../shared/output.js';
|
|
3
|
+
import { addPaginationFlags, createOperationDeleteCommand, createOperationJsonBodyCommand, createOperationListCommand, createOperationViewCommand, outputFlags, requestOperationAndPrint, } from '../shared/operation.js';
|
|
4
|
+
export function createProxyCommand(factory) {
|
|
5
|
+
const command = new Command('proxy').description('Manage proxies');
|
|
6
|
+
command.addCommand(createOperationListCommand(factory, {
|
|
7
|
+
operationId: 'proxies.list',
|
|
8
|
+
description: 'List proxies',
|
|
9
|
+
}));
|
|
10
|
+
command.addCommand(createOperationViewCommand(factory, {
|
|
11
|
+
operationId: 'proxies.get',
|
|
12
|
+
name: 'get',
|
|
13
|
+
description: 'Get a proxy',
|
|
14
|
+
argName: 'proxyId',
|
|
15
|
+
}));
|
|
16
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
17
|
+
operationId: 'proxies.create',
|
|
18
|
+
name: 'create',
|
|
19
|
+
description: 'Create a proxy',
|
|
20
|
+
}));
|
|
21
|
+
command.addCommand(createOperationJsonBodyCommand(factory, {
|
|
22
|
+
operationId: 'proxies.update',
|
|
23
|
+
name: 'patch',
|
|
24
|
+
description: 'Update a proxy',
|
|
25
|
+
argNames: ['proxyId'],
|
|
26
|
+
}));
|
|
27
|
+
command.addCommand(addOutputFlags(new Command('test').description('Test a proxy').argument('<proxyId>')).action(async (proxyId, options) => {
|
|
28
|
+
await requestOperationAndPrint(factory, 'proxies.test', {
|
|
29
|
+
pathParams: { proxyId },
|
|
30
|
+
output: outputFlags(options),
|
|
31
|
+
});
|
|
32
|
+
}));
|
|
33
|
+
command.addCommand(createOperationDeleteCommand(factory, {
|
|
34
|
+
operationId: 'proxies.delete',
|
|
35
|
+
description: 'Delete a proxy',
|
|
36
|
+
argNames: ['proxyId'],
|
|
37
|
+
}));
|
|
38
|
+
command.addCommand(createProxyPoolCommand(factory));
|
|
39
|
+
return command;
|
|
40
|
+
}
|
|
41
|
+
function createProxyPoolCommand(factory) {
|
|
42
|
+
const command = new Command('pool').description('Inspect managed proxy pools');
|
|
43
|
+
command.addCommand(createOperationListCommand(factory, {
|
|
44
|
+
operationId: 'proxies.pools.list',
|
|
45
|
+
description: 'List proxy pools',
|
|
46
|
+
configure: (cmd) => addPaginationFlags(cmd)
|
|
47
|
+
.option('--country <country>', 'Filter by ISO country code')
|
|
48
|
+
.option('--category <category>', 'Filter by category')
|
|
49
|
+
.option('--available <boolean>', 'Filter by availability'),
|
|
50
|
+
query: (options) => ({
|
|
51
|
+
country: typeof options.country === 'string' ? options.country : undefined,
|
|
52
|
+
category: typeof options.category === 'string' ? options.category : undefined,
|
|
53
|
+
available: typeof options.available === 'string' ? parseBooleanFlag(options.available) : undefined,
|
|
54
|
+
limit: typeof options.limit === 'number' ? options.limit : undefined,
|
|
55
|
+
cursor: typeof options.cursor === 'string' ? options.cursor : undefined,
|
|
56
|
+
}),
|
|
57
|
+
}));
|
|
58
|
+
command.addCommand(createOperationViewCommand(factory, {
|
|
59
|
+
operationId: 'proxies.pools.get',
|
|
60
|
+
name: 'get',
|
|
61
|
+
description: 'Get a proxy pool',
|
|
62
|
+
argName: 'poolId',
|
|
63
|
+
}));
|
|
64
|
+
return command;
|
|
65
|
+
}
|
|
66
|
+
function parseBooleanFlag(value) {
|
|
67
|
+
if (value === 'true')
|
|
68
|
+
return true;
|
|
69
|
+
if (value === 'false')
|
|
70
|
+
return false;
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
@@ -3,57 +3,242 @@ import { CliError } from '../../runtime/errors.js';
|
|
|
3
3
|
import { readJsonFile, writeBinary } from '../shared/io.js';
|
|
4
4
|
import { parsePositiveInteger } from '../shared/options.js';
|
|
5
5
|
import { addOutputFlags } from '../shared/output.js';
|
|
6
|
-
import { addPaginationFlags,
|
|
6
|
+
import { addPaginationFlags, createOperationJsonBodyCommand, createOperationListCommand, createOperationViewCommand, downloadOperation, outputFlags, requestOperation, requestOperationAndPrint, streamOperationText, } from '../shared/operation.js';
|
|
7
7
|
export function createRunCommand(factory) {
|
|
8
|
-
const command = new Command('run').description('Inspect and stream
|
|
9
|
-
command.addCommand(
|
|
8
|
+
const command = new Command('run').description('Inspect and stream runs');
|
|
9
|
+
command.addCommand(createOperationListCommand(factory, {
|
|
10
|
+
operationId: 'runs.list',
|
|
10
11
|
description: 'List runs',
|
|
11
|
-
path: '/runs',
|
|
12
12
|
configure: (cmd) => addPaginationFlags(cmd)
|
|
13
13
|
.option('--space <id>', 'Filter by space id')
|
|
14
14
|
.option('--runtime <id>', 'Filter by runtime id')
|
|
15
|
-
.option('--status <status>', 'Filter by run status')
|
|
15
|
+
.option('--status <status>', 'Filter by run status')
|
|
16
|
+
.option('--subaccount <id>', 'Filter by subaccount id'),
|
|
16
17
|
query: (options) => ({
|
|
17
18
|
spaceId: typeof options.space === 'string' ? options.space : undefined,
|
|
18
19
|
runtimeId: typeof options.runtime === 'string' ? options.runtime : undefined,
|
|
19
20
|
status: typeof options.status === 'string' ? options.status : undefined,
|
|
21
|
+
subaccountId: typeof options.subaccount === 'string' ? options.subaccount : undefined,
|
|
20
22
|
limit: typeof options.limit === 'number' ? options.limit : undefined,
|
|
21
23
|
cursor: typeof options.cursor === 'string' ? options.cursor : undefined,
|
|
22
24
|
}),
|
|
23
25
|
}));
|
|
24
|
-
command.addCommand(
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
command.addCommand(createOperationViewCommand(factory, {
|
|
27
|
+
operationId: 'runs.get',
|
|
28
|
+
name: 'get',
|
|
29
|
+
description: 'Get a run',
|
|
30
|
+
argName: 'runId',
|
|
27
31
|
}));
|
|
32
|
+
command.addCommand(createRunActivityCommand(factory));
|
|
28
33
|
command.addCommand(createRunEventsCommand(factory));
|
|
29
|
-
command.addCommand(createRunCommandsCommand(factory));
|
|
30
34
|
command.addCommand(createRunFilesCommand(factory));
|
|
31
|
-
command.addCommand(
|
|
32
|
-
command.addCommand(
|
|
33
|
-
command.addCommand(
|
|
34
|
-
command.addCommand(createRunViewerCommand(factory, '
|
|
35
|
-
command.addCommand(createRunViewerCommand(factory, 'recording', 'Mint a recording viewer URL'));
|
|
35
|
+
command.addCommand(createRunInvocationsCommand(factory));
|
|
36
|
+
command.addCommand(createRunInvocationCommand(factory));
|
|
37
|
+
command.addCommand(createRunViewerCommand(factory, 'live', 'Create a live viewer URL'));
|
|
38
|
+
command.addCommand(createRunViewerCommand(factory, 'recording', 'Create a recording viewer URL'));
|
|
36
39
|
return command;
|
|
37
40
|
}
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
function createRunActivityCommand(factory) {
|
|
42
|
+
const command = new Command('activity').description('Inspect run activities');
|
|
43
|
+
command.addCommand(createRunActivityListCommand(factory));
|
|
44
|
+
command.addCommand(createSseCommand(factory, {
|
|
45
|
+
name: 'stream',
|
|
46
|
+
description: 'Stream run activities',
|
|
47
|
+
operationId: 'runs.activity.stream',
|
|
48
|
+
configure: (cmd) => addPaginationFlags(cmd)
|
|
49
|
+
.option('--view <view>', 'Activity view')
|
|
50
|
+
.option('--type <type>', 'Filter by activity type')
|
|
51
|
+
.option('--category <category>', 'Filter by activity category')
|
|
52
|
+
.option('--severity <severity>', 'Filter by severity')
|
|
53
|
+
.option('--invocation <id>', 'Filter by invocation id')
|
|
54
|
+
.option('--file <id>', 'Filter by file id'),
|
|
55
|
+
query: (options) => ({
|
|
56
|
+
view: typeof options.view === 'string' ? options.view : undefined,
|
|
57
|
+
type: typeof options.type === 'string' ? options.type : undefined,
|
|
58
|
+
category: typeof options.category === 'string' ? options.category : undefined,
|
|
59
|
+
severity: typeof options.severity === 'string' ? options.severity : undefined,
|
|
60
|
+
invocationId: typeof options.invocation === 'string' ? options.invocation : undefined,
|
|
61
|
+
fileId: typeof options.file === 'string' ? options.file : undefined,
|
|
62
|
+
limit: typeof options.limit === 'number' ? options.limit : undefined,
|
|
63
|
+
cursor: typeof options.cursor === 'string' ? options.cursor : undefined,
|
|
64
|
+
}),
|
|
65
|
+
}));
|
|
66
|
+
return command;
|
|
67
|
+
}
|
|
68
|
+
function createRunActivityListCommand(factory) {
|
|
69
|
+
return addOutputFlags(addPaginationFlags(new Command('list').description('List run activities').argument('<runId>'))
|
|
70
|
+
.option('--view <view>', 'Activity view')
|
|
71
|
+
.option('--type <type>', 'Filter by activity type')
|
|
72
|
+
.option('--category <category>', 'Filter by activity category')
|
|
73
|
+
.option('--severity <severity>', 'Filter by severity')
|
|
74
|
+
.option('--invocation <id>', 'Filter by invocation id')
|
|
75
|
+
.option('--file <id>', 'Filter by file id')).action(async (runId, options) => {
|
|
76
|
+
await requestOperationAndPrint(factory, 'runs.activity.list', {
|
|
77
|
+
pathParams: { runId },
|
|
78
|
+
query: {
|
|
79
|
+
view: options.view,
|
|
80
|
+
type: options.type,
|
|
81
|
+
category: options.category,
|
|
82
|
+
severity: options.severity,
|
|
83
|
+
invocationId: options.invocation,
|
|
84
|
+
fileId: options.file,
|
|
85
|
+
limit: options.limit,
|
|
86
|
+
cursor: options.cursor,
|
|
87
|
+
},
|
|
88
|
+
output: outputFlags(options),
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function createRunEventsCommand(factory) {
|
|
93
|
+
const command = new Command('events').description('Inspect run events');
|
|
94
|
+
command.addCommand(createRunEventsListCommand(factory));
|
|
95
|
+
command.addCommand(createSseCommand(factory, {
|
|
96
|
+
name: 'stream',
|
|
97
|
+
description: 'Stream run events',
|
|
98
|
+
operationId: 'runs.events.stream',
|
|
99
|
+
configure: (cmd) => addPaginationFlags(cmd)
|
|
100
|
+
.option('--type <type>', 'Filter by event type')
|
|
101
|
+
.option('--status <status>', 'Filter by event status')
|
|
102
|
+
.option('--page-id <id>', 'Filter by page id')
|
|
103
|
+
.option('--context-id <id>', 'Filter by browser context id'),
|
|
104
|
+
query: (options) => ({
|
|
105
|
+
type: typeof options.type === 'string' ? options.type : undefined,
|
|
106
|
+
status: typeof options.status === 'string' ? options.status : undefined,
|
|
107
|
+
pageId: typeof options.pageId === 'string' ? options.pageId : undefined,
|
|
108
|
+
contextId: typeof options.contextId === 'string' ? options.contextId : undefined,
|
|
109
|
+
limit: typeof options.limit === 'number' ? options.limit : undefined,
|
|
110
|
+
cursor: typeof options.cursor === 'string' ? options.cursor : undefined,
|
|
111
|
+
}),
|
|
112
|
+
}));
|
|
113
|
+
return command;
|
|
114
|
+
}
|
|
115
|
+
function createRunEventsListCommand(factory) {
|
|
116
|
+
return addOutputFlags(addPaginationFlags(new Command('list').description('List run events').argument('<runId>'))
|
|
117
|
+
.option('--type <type>', 'Filter by event type')
|
|
118
|
+
.option('--status <status>', 'Filter by event status')
|
|
119
|
+
.option('--page-id <id>', 'Filter by page id')
|
|
120
|
+
.option('--context-id <id>', 'Filter by browser context id')).action(async (runId, options) => {
|
|
121
|
+
await requestOperationAndPrint(factory, 'runs.events.list', {
|
|
122
|
+
pathParams: { runId },
|
|
123
|
+
query: {
|
|
124
|
+
type: options.type,
|
|
125
|
+
status: options.status,
|
|
126
|
+
pageId: options.pageId,
|
|
127
|
+
contextId: options.contextId,
|
|
128
|
+
limit: options.limit,
|
|
129
|
+
cursor: options.cursor,
|
|
130
|
+
},
|
|
131
|
+
output: outputFlags(options),
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function createRunFilesCommand(factory) {
|
|
136
|
+
const command = new Command('files').description('Inspect run files');
|
|
137
|
+
command.addCommand(createRunFilesListCommand(factory));
|
|
138
|
+
command.addCommand(createRunFilesExportCommand(factory));
|
|
139
|
+
return command;
|
|
140
|
+
}
|
|
141
|
+
function createRunFilesListCommand(factory) {
|
|
142
|
+
return addOutputFlags(addPaginationFlags(new Command('list').description('List run files').argument('<runId>')).option('--type <type>', 'Filter by file type')).action(async (runId, options) => {
|
|
143
|
+
await requestOperationAndPrint(factory, 'runs.files.list', {
|
|
144
|
+
pathParams: { runId },
|
|
145
|
+
query: {
|
|
146
|
+
type: options.type,
|
|
147
|
+
limit: options.limit,
|
|
148
|
+
cursor: options.cursor,
|
|
149
|
+
},
|
|
150
|
+
output: outputFlags(options),
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function createRunFilesExportCommand(factory) {
|
|
155
|
+
return addOutputFlags(new Command('export')
|
|
156
|
+
.description('Export run files as an archive')
|
|
157
|
+
.argument('<runId>')
|
|
158
|
+
.requiredOption('--to <path>', 'Output archive path, or - for stdout')
|
|
159
|
+
.option('--name <name>', 'Export file name', 'run-files.zip')
|
|
160
|
+
.option('--type <type...>', 'Filter exported file types')
|
|
161
|
+
.option('--input <path>', 'Read JSON request body from file, or - for stdin')).action(async (runId, options) => {
|
|
162
|
+
const body = typeof options.input === 'string'
|
|
163
|
+
? await readJsonFile(options.input)
|
|
164
|
+
: {
|
|
165
|
+
format: 'zip',
|
|
166
|
+
name: options.name,
|
|
167
|
+
filter: options.type ? { type: options.type } : undefined,
|
|
168
|
+
};
|
|
169
|
+
const result = (await requestOperation(factory, 'runs.files.export', {
|
|
170
|
+
pathParams: { runId },
|
|
171
|
+
body: body,
|
|
172
|
+
}));
|
|
173
|
+
const fileId = result.fileId ?? result.id;
|
|
174
|
+
if (!fileId) {
|
|
175
|
+
throw new CliError('Expected run export response to include fileId');
|
|
176
|
+
}
|
|
177
|
+
const data = await downloadOperation(factory, 'files.content', {
|
|
178
|
+
pathParams: { fileId },
|
|
179
|
+
});
|
|
180
|
+
await writeBinary(options.to, data);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function createRunInvocationsCommand(factory) {
|
|
184
|
+
const command = addOutputFlags(addPaginationFlags(new Command('invocations').description('List run invocations').argument('<runId>'))
|
|
185
|
+
.option('--status <status>', 'Filter by invocation status')
|
|
186
|
+
.option('--action <action>', 'Filter by invocation action'));
|
|
187
|
+
command.action(async (runId, options) => {
|
|
188
|
+
await requestOperationAndPrint(factory, 'runs.invocations.list', {
|
|
189
|
+
pathParams: { runId },
|
|
50
190
|
query: {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
connectionId: options.connection,
|
|
191
|
+
status: options.status,
|
|
192
|
+
action: options.action,
|
|
54
193
|
limit: options.limit,
|
|
55
194
|
cursor: options.cursor,
|
|
56
195
|
},
|
|
196
|
+
output: outputFlags(options),
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
return command;
|
|
200
|
+
}
|
|
201
|
+
function createRunInvocationCommand(factory) {
|
|
202
|
+
const command = new Command('invocation').description('Inspect run invocations');
|
|
203
|
+
command.addCommand(addOutputFlags(new Command('get')
|
|
204
|
+
.description('Get a run invocation')
|
|
205
|
+
.argument('<runId>')
|
|
206
|
+
.argument('<invocationId>')).action(async (runId, invocationId, options) => {
|
|
207
|
+
await requestOperationAndPrint(factory, 'runs.invocations.get', {
|
|
208
|
+
pathParams: { runId, invocationId },
|
|
209
|
+
output: outputFlags(options),
|
|
210
|
+
});
|
|
211
|
+
}));
|
|
212
|
+
return command;
|
|
213
|
+
}
|
|
214
|
+
function createRunViewerCommand(factory, name, description) {
|
|
215
|
+
return createOperationJsonBodyCommand(factory, {
|
|
216
|
+
operationId: name === 'live' ? 'runs.live' : 'runs.recording',
|
|
217
|
+
name,
|
|
218
|
+
description,
|
|
219
|
+
argNames: ['runId'],
|
|
220
|
+
configure: (cmd) => cmd
|
|
221
|
+
.option('--expires-in-seconds <seconds>', 'Viewer expiration in seconds', parsePositiveInteger)
|
|
222
|
+
.option('--control <none|input>', 'Live viewer control mode')
|
|
223
|
+
.option('--input <path>', 'Read JSON request body from file, or - for stdin'),
|
|
224
|
+
body: async (_args, options) => {
|
|
225
|
+
if (typeof options.input === 'string') {
|
|
226
|
+
return (await readJsonFile(options.input));
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
expiresInSeconds: typeof options.expiresInSeconds === 'number' ? options.expiresInSeconds : undefined,
|
|
230
|
+
control: name === 'live' ? options.control : undefined,
|
|
231
|
+
};
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function createSseCommand(factory, config) {
|
|
236
|
+
let command = new Command(config.name).description(config.description).argument('<runId>');
|
|
237
|
+
command = config.configure(command);
|
|
238
|
+
return command.action(async (runId, options) => {
|
|
239
|
+
const stream = await streamOperationText(factory, config.operationId, {
|
|
240
|
+
pathParams: { runId },
|
|
241
|
+
query: config.query(options),
|
|
57
242
|
});
|
|
58
243
|
await renderSseStream(factory, stream);
|
|
59
244
|
});
|
|
@@ -110,138 +295,20 @@ function formatRunEvent(value) {
|
|
|
110
295
|
if (!value || typeof value !== 'object')
|
|
111
296
|
return JSON.stringify(value);
|
|
112
297
|
const event = value;
|
|
113
|
-
const time = typeof event.time === 'string'
|
|
298
|
+
const time = typeof event.time === 'string'
|
|
299
|
+
? event.time
|
|
300
|
+
: typeof event.createdAt === 'string'
|
|
301
|
+
? event.createdAt
|
|
302
|
+
: '';
|
|
114
303
|
const label = [event.category, event.type].filter((part) => typeof part === 'string').join('/');
|
|
115
304
|
const status = typeof event.status === 'string' ? ` ${event.status}` : '';
|
|
116
|
-
const name = typeof event.
|
|
117
|
-
|
|
305
|
+
const name = typeof event.title === 'string'
|
|
306
|
+
? ` ${event.title}`
|
|
307
|
+
: typeof event.name === 'string'
|
|
308
|
+
? ` ${event.name}`
|
|
309
|
+
: '';
|
|
310
|
+
const suffix = event.data && Object.keys(event.data).length > 0
|
|
311
|
+
? ` ${JSON.stringify(event.data)}`
|
|
312
|
+
: '';
|
|
118
313
|
return [time, label || 'event'].filter(Boolean).join(' ') + status + name + suffix;
|
|
119
314
|
}
|
|
120
|
-
function createRunEventsCommand(factory) {
|
|
121
|
-
return addOutputFlags(new Command('events')
|
|
122
|
-
.description('List run events')
|
|
123
|
-
.argument('<id>')
|
|
124
|
-
.option('--type <type...>', 'Filter by event type')
|
|
125
|
-
.option('--category <category...>', 'Filter by event category')
|
|
126
|
-
.option('--connection <id>', 'Filter by connection id')
|
|
127
|
-
.option('-L, --limit <number>', 'Maximum number of results to return', parsePositiveInteger)
|
|
128
|
-
.option('--cursor <cursor>', 'Pagination cursor'))
|
|
129
|
-
.action(async (id, options) => {
|
|
130
|
-
await requestAndPrint(factory, 'get', `/runs/${encodeURIComponent(id)}/events`, {
|
|
131
|
-
query: {
|
|
132
|
-
type: options.type?.join(','),
|
|
133
|
-
category: options.category?.join(','),
|
|
134
|
-
connectionId: options.connection,
|
|
135
|
-
limit: options.limit,
|
|
136
|
-
cursor: options.cursor,
|
|
137
|
-
},
|
|
138
|
-
output: options,
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
function createRunCommandsCommand(factory) {
|
|
143
|
-
return addOutputFlags(new Command('commands')
|
|
144
|
-
.description('List run commands')
|
|
145
|
-
.argument('<id>')
|
|
146
|
-
.option('--type <type>', 'Filter by command type')
|
|
147
|
-
.option('--connection <id>', 'Filter by connection id')
|
|
148
|
-
.option('-L, --limit <number>', 'Maximum number of results to return', parsePositiveInteger)
|
|
149
|
-
.option('--cursor <cursor>', 'Pagination cursor'))
|
|
150
|
-
.action(async (id, options) => {
|
|
151
|
-
await requestAndPrint(factory, 'get', `/runs/${encodeURIComponent(id)}/commands`, {
|
|
152
|
-
query: {
|
|
153
|
-
type: options.type,
|
|
154
|
-
connectionId: options.connection,
|
|
155
|
-
limit: options.limit,
|
|
156
|
-
cursor: options.cursor,
|
|
157
|
-
},
|
|
158
|
-
output: options,
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
function createRunFilesCommand(factory) {
|
|
163
|
-
return addOutputFlags(new Command('files')
|
|
164
|
-
.description('List run files')
|
|
165
|
-
.argument('<id>')
|
|
166
|
-
.option('--type <type>', 'Filter by file type')
|
|
167
|
-
.option('-L, --limit <number>', 'Maximum number of results to return', parsePositiveInteger)
|
|
168
|
-
.option('--cursor <cursor>', 'Pagination cursor'))
|
|
169
|
-
.action(async (id, options) => {
|
|
170
|
-
await requestAndPrint(factory, 'get', `/runs/${encodeURIComponent(id)}/files`, {
|
|
171
|
-
query: { type: options.type, limit: options.limit, cursor: options.cursor },
|
|
172
|
-
output: options,
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
function createRunExportCommand(factory) {
|
|
177
|
-
return addOutputFlags(new Command('export')
|
|
178
|
-
.description('Export run files as an archive')
|
|
179
|
-
.argument('<id>')
|
|
180
|
-
.requiredOption('--to <path>', 'Output archive path, or - for stdout')
|
|
181
|
-
.option('--name <name>', 'Export file name', 'run-files.zip')
|
|
182
|
-
.option('--type <type...>', 'Filter exported file types'))
|
|
183
|
-
.action(async (id, options) => {
|
|
184
|
-
const client = await factory.apiClient();
|
|
185
|
-
const result = await client.post(`/runs/${encodeURIComponent(id)}/files/export`, {
|
|
186
|
-
body: {
|
|
187
|
-
format: 'zip',
|
|
188
|
-
name: options.name,
|
|
189
|
-
filter: options.type ? { type: options.type } : undefined,
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
const fileId = result.fileId ?? result.id;
|
|
193
|
-
if (!fileId) {
|
|
194
|
-
throw new CliError('Expected run export response to include fileId');
|
|
195
|
-
}
|
|
196
|
-
const data = await client.download(`/files/${encodeURIComponent(fileId)}/content`);
|
|
197
|
-
await writeBinary(options.to, data);
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
function createRunWaitCommand(factory) {
|
|
201
|
-
return createJsonBodyCommand(factory, {
|
|
202
|
-
name: 'wait',
|
|
203
|
-
description: 'Wait for a run event',
|
|
204
|
-
method: 'post',
|
|
205
|
-
path: '/runs/{id}/events/wait',
|
|
206
|
-
argNames: ['id'],
|
|
207
|
-
configure: (cmd) => cmd
|
|
208
|
-
.option('--type <type...>', 'Event type')
|
|
209
|
-
.option('--category <category...>', 'Event category')
|
|
210
|
-
.option('--connection <id>', 'Connection id')
|
|
211
|
-
.option('--cursor <cursor>', 'Cursor')
|
|
212
|
-
.option('--timeout-ms <ms>', 'Timeout in milliseconds')
|
|
213
|
-
.option('--input <path>', 'Read JSON request body from file, or - for stdin'),
|
|
214
|
-
body: async (_args, options) => {
|
|
215
|
-
if (typeof options.input === 'string')
|
|
216
|
-
return readJsonFile(options.input);
|
|
217
|
-
return {
|
|
218
|
-
type: options.type,
|
|
219
|
-
category: options.category,
|
|
220
|
-
connectionId: options.connection,
|
|
221
|
-
cursor: options.cursor,
|
|
222
|
-
timeoutMs: options.timeoutMs ? Number(options.timeoutMs) : undefined,
|
|
223
|
-
};
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
function createRunViewerCommand(factory, name, description) {
|
|
228
|
-
return createJsonBodyCommand(factory, {
|
|
229
|
-
name,
|
|
230
|
-
description,
|
|
231
|
-
method: 'post',
|
|
232
|
-
path: `/runs/{id}/${name}`,
|
|
233
|
-
argNames: ['id'],
|
|
234
|
-
configure: (cmd) => cmd
|
|
235
|
-
.option('--expires-in-seconds <seconds>', 'Viewer expiration in seconds')
|
|
236
|
-
.option('--control <none|input>', 'Live viewer control mode')
|
|
237
|
-
.option('--input <path>', 'Read JSON request body from file, or - for stdin'),
|
|
238
|
-
body: async (_args, options) => {
|
|
239
|
-
if (typeof options.input === 'string')
|
|
240
|
-
return readJsonFile(options.input);
|
|
241
|
-
return {
|
|
242
|
-
expiresInSeconds: options.expiresInSeconds ? Number(options.expiresInSeconds) : undefined,
|
|
243
|
-
control: name === 'live' ? options.control : undefined,
|
|
244
|
-
};
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
}
|