@bbigbang/cli 0.1.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/dist/cliSupport.d.ts +166 -0
- package/dist/cliSupport.js +1306 -0
- package/dist/commandCatalog.d.ts +36 -0
- package/dist/commandCatalog.js +152 -0
- package/dist/commands/actionCommands.d.ts +3 -0
- package/dist/commands/actionCommands.js +43 -0
- package/dist/commands/authManualCommands.d.ts +3 -0
- package/dist/commands/authManualCommands.js +60 -0
- package/dist/commands/channelWorkspaceCommands.d.ts +3 -0
- package/dist/commands/channelWorkspaceCommands.js +105 -0
- package/dist/commands/contextCommands.d.ts +3 -0
- package/dist/commands/contextCommands.js +253 -0
- package/dist/commands/memoryCommands.d.ts +3 -0
- package/dist/commands/memoryCommands.js +154 -0
- package/dist/commands/messageCommands.d.ts +3 -0
- package/dist/commands/messageCommands.js +241 -0
- package/dist/commands/panelCommands.d.ts +3 -0
- package/dist/commands/panelCommands.js +218 -0
- package/dist/commands/reminderCommands.d.ts +3 -0
- package/dist/commands/reminderCommands.js +220 -0
- package/dist/commands/skillToolAttachmentCommands.d.ts +3 -0
- package/dist/commands/skillToolAttachmentCommands.js +261 -0
- package/dist/commands/taskCommands.d.ts +3 -0
- package/dist/commands/taskCommands.js +195 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/dist/manual/generated/command-catalog.json +12452 -0
- package/dist/manual/topics/cli-overview.md +116 -0
- package/dist/manual/topics/commands.md +706 -0
- package/dist/manual/topics/examples.md +194 -0
- package/dist/manual/topics/index.md +11 -0
- package/dist/program.d.ts +5 -0
- package/dist/program.js +52 -0
- package/package.json +43 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { Option } from 'commander';
|
|
3
|
+
import { AGENT_COMMAND_ERROR_CODES, AgentCommandError, MUTATION_HINTS, appendCommonBody, createRuntime, formatMessageHeld, isHeldResponse, isMessageNotResolved, isSuppressedResponse, parseNonNegativeInteger, parsePositiveInteger, readRequiredStdin, repeatOption, requireString, responseError, withHint, writeOutput, writeReceipt } from '../cliSupport.js';
|
|
4
|
+
export function registerMessageCommands(program, options) {
|
|
5
|
+
const message = program.command('message').description('Message operations');
|
|
6
|
+
message.command('send')
|
|
7
|
+
.description('Send a message from stdin')
|
|
8
|
+
.option('--target <target>', 'Target: #channel, dm:@name, or thread target. Defaults to the current conversation when omitted.')
|
|
9
|
+
.addOption(new Option('--channel <target>', 'Alias for --target.').hideHelp())
|
|
10
|
+
.option('--kind <kind>', 'Message kind: progress or final', 'progress')
|
|
11
|
+
.option('--peer-delivery <mode>', 'Shared-surface peer delivery: silent, batch, or immediate')
|
|
12
|
+
.option('--attachment-id <id>', 'Attachment id to include; repeatable', repeatOption)
|
|
13
|
+
.option('--panel-id <id>', 'Panel id to include; repeatable', repeatOption)
|
|
14
|
+
.option('--panel-preview-id <id>', 'Ephemeral panel preview id to include; repeatable', repeatOption)
|
|
15
|
+
.option('--tool-id <id>', 'Tool id to include; repeatable', repeatOption)
|
|
16
|
+
.option('--slash-command-failed <reason>', 'Allow a final reply for /panel, /panel:plan, or /tool when the requested artifact cannot be created; requires a clear reason')
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
const runtime = createRuntime(program, options);
|
|
19
|
+
const target = (typeof opts.target === 'string' ? opts.target.trim() : '')
|
|
20
|
+
|| (typeof opts.channel === 'string' ? opts.channel.trim() : '');
|
|
21
|
+
const peerDelivery = typeof opts.peerDelivery === 'string' ? opts.peerDelivery.trim() : '';
|
|
22
|
+
const slashCommandFailureReason = typeof opts.slashCommandFailed === 'string'
|
|
23
|
+
? opts.slashCommandFailed.trim()
|
|
24
|
+
: '';
|
|
25
|
+
const content = await readRequiredStdin(runtime.io.stdin, 'message content');
|
|
26
|
+
const kind = opts.kind === 'final' ? 'final' : 'progress';
|
|
27
|
+
if (slashCommandFailureReason && kind !== 'final') {
|
|
28
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.INVALID_ARG, '--slash-command-failed is only supported with --kind final.');
|
|
29
|
+
}
|
|
30
|
+
if (opts.slashCommandFailed !== undefined && !slashCommandFailureReason) {
|
|
31
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.INVALID_ARG, '--slash-command-failed requires a non-empty reason.');
|
|
32
|
+
}
|
|
33
|
+
const clientMessageId = resolveMessageSendClientMessageId(runtime, {
|
|
34
|
+
target,
|
|
35
|
+
content: content.trim(),
|
|
36
|
+
kind,
|
|
37
|
+
peerDelivery,
|
|
38
|
+
attachmentIds: opts.attachmentId ?? [],
|
|
39
|
+
panelIds: opts.panelId ?? [],
|
|
40
|
+
panelPreviewIds: opts.panelPreviewId ?? [],
|
|
41
|
+
toolIds: opts.toolId ?? [],
|
|
42
|
+
});
|
|
43
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/send`, appendCommonBody(runtime, {
|
|
44
|
+
...(target ? { target } : {}),
|
|
45
|
+
content,
|
|
46
|
+
kind,
|
|
47
|
+
clientMessageId,
|
|
48
|
+
...(peerDelivery ? { peer_delivery: peerDelivery } : {}),
|
|
49
|
+
...(opts.attachmentId?.length ? { attachmentIds: opts.attachmentId } : {}),
|
|
50
|
+
...(opts.panelId?.length ? { panelIds: opts.panelId } : {}),
|
|
51
|
+
...(opts.panelPreviewId?.length ? { panelPreviewIds: opts.panelPreviewId } : {}),
|
|
52
|
+
...(opts.toolId?.length ? { toolIds: opts.toolId } : {}),
|
|
53
|
+
...(slashCommandFailureReason ? { slashCommandFailureReason } : {}),
|
|
54
|
+
}));
|
|
55
|
+
if (!response.ok)
|
|
56
|
+
throw responseError(response, 'send failed');
|
|
57
|
+
if (isSuppressedResponse(response.data)) {
|
|
58
|
+
const data = response.data;
|
|
59
|
+
const message = typeof data.message === 'string' && data.message.trim()
|
|
60
|
+
? data.message.trim()
|
|
61
|
+
: 'Message suppressed by platform policy.';
|
|
62
|
+
writeOutput(runtime, message, response.data);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (isHeldResponse(response.data)) {
|
|
66
|
+
writeOutput(runtime, formatMessageHeld(target || 'current conversation', response.data), response.data);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const data = response.data;
|
|
70
|
+
const messageId = typeof data?.messageId === 'string' ? data.messageId : '';
|
|
71
|
+
if (!messageId) {
|
|
72
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MISSING_MESSAGE_ID, 'send returned success without a messageId; nothing was confirmed posted.');
|
|
73
|
+
}
|
|
74
|
+
const sentTarget = String(data.target ?? (target || 'current conversation'));
|
|
75
|
+
writeOutput(runtime, withHint(`Message sent to ${sentTarget}. Message ID: ${messageId}`, MUTATION_HINTS.messageSend), response.data);
|
|
76
|
+
writeReceipt(runtime, {
|
|
77
|
+
op: 'message.send',
|
|
78
|
+
ok: true,
|
|
79
|
+
kind,
|
|
80
|
+
messageId,
|
|
81
|
+
target: sentTarget,
|
|
82
|
+
...(runtime.runId ? { runId: runtime.runId } : {}),
|
|
83
|
+
...(runtime.context.conversationId ? { conversationId: runtime.context.conversationId } : {}),
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
message.command('check')
|
|
87
|
+
.description('Check for pending messages')
|
|
88
|
+
.option('--channel <target>', 'Optional channel/DM target filter')
|
|
89
|
+
.action(async (opts) => {
|
|
90
|
+
const runtime = createRuntime(program, options);
|
|
91
|
+
const params = new URLSearchParams();
|
|
92
|
+
if (opts.channel)
|
|
93
|
+
params.set('channel', opts.channel);
|
|
94
|
+
if (runtime.context.conversationId)
|
|
95
|
+
params.set('conversationId', runtime.context.conversationId);
|
|
96
|
+
if (runtime.runId)
|
|
97
|
+
params.set('runId', runtime.runId);
|
|
98
|
+
if (runtime.turnId)
|
|
99
|
+
params.set('turnId', runtime.turnId);
|
|
100
|
+
if (runtime.traceId)
|
|
101
|
+
params.set('traceId', runtime.traceId);
|
|
102
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/receive?${params.toString()}`, undefined, { retry: 'never' });
|
|
103
|
+
if (!response.ok)
|
|
104
|
+
throw responseError(response, 'receive failed');
|
|
105
|
+
const data = response.data;
|
|
106
|
+
const count = data?.messages?.length ?? 0;
|
|
107
|
+
writeOutput(runtime, count > 0 ? `Received ${count} message(s).` : 'No new messages.', response.data);
|
|
108
|
+
});
|
|
109
|
+
message.command('read')
|
|
110
|
+
.description('Read message history')
|
|
111
|
+
.requiredOption('--channel <target>', 'Channel, DM, or thread target')
|
|
112
|
+
.option('--limit <n>', 'Max messages to return')
|
|
113
|
+
.option('--around <idOrSeq>', 'Center around message id prefix or seq')
|
|
114
|
+
.option('--before <seq>', 'Read before seq')
|
|
115
|
+
.option('--after <seq>', 'Read after seq')
|
|
116
|
+
.option('--include-root', 'Include thread root when reading a thread')
|
|
117
|
+
.action(async (opts) => {
|
|
118
|
+
const runtime = createRuntime(program, options);
|
|
119
|
+
const params = new URLSearchParams();
|
|
120
|
+
params.set('channel', requireString(opts.channel, '--channel'));
|
|
121
|
+
const limit = parsePositiveInteger('limit', opts.limit);
|
|
122
|
+
if (limit !== undefined)
|
|
123
|
+
params.set('limit', String(Math.min(limit, 100)));
|
|
124
|
+
if (opts.around !== undefined)
|
|
125
|
+
params.set('around', String(opts.around));
|
|
126
|
+
const before = parseNonNegativeInteger('before', opts.before);
|
|
127
|
+
const after = parseNonNegativeInteger('after', opts.after);
|
|
128
|
+
if (before !== undefined)
|
|
129
|
+
params.set('before', String(before));
|
|
130
|
+
if (after !== undefined)
|
|
131
|
+
params.set('after', String(after));
|
|
132
|
+
if (opts.includeRoot)
|
|
133
|
+
params.set('include_root', 'true');
|
|
134
|
+
if (runtime.context.conversationId)
|
|
135
|
+
params.set('conversationId', runtime.context.conversationId);
|
|
136
|
+
if (runtime.runId)
|
|
137
|
+
params.set('runId', runtime.runId);
|
|
138
|
+
if (runtime.turnId)
|
|
139
|
+
params.set('turnId', runtime.turnId);
|
|
140
|
+
if (runtime.traceId)
|
|
141
|
+
params.set('traceId', runtime.traceId);
|
|
142
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/history?${params.toString()}`);
|
|
143
|
+
if (!response.ok)
|
|
144
|
+
throw responseError(response, 'history fetch failed');
|
|
145
|
+
const data = response.data;
|
|
146
|
+
writeOutput(runtime, `Read ${data?.messages?.length ?? 0} message(s).`, response.data);
|
|
147
|
+
});
|
|
148
|
+
message.command('search')
|
|
149
|
+
.description('Search visible messages')
|
|
150
|
+
.requiredOption('--query <q>', 'Search query')
|
|
151
|
+
.option('--channel <target>', 'Optional channel, DM, or thread target')
|
|
152
|
+
.option('--limit <n>', 'Max results')
|
|
153
|
+
.action(async (opts) => {
|
|
154
|
+
const runtime = createRuntime(program, options);
|
|
155
|
+
const query = requireString(opts.query, '--query');
|
|
156
|
+
const params = new URLSearchParams();
|
|
157
|
+
params.set('q', query);
|
|
158
|
+
const limit = parsePositiveInteger('limit', opts.limit);
|
|
159
|
+
if (limit !== undefined)
|
|
160
|
+
params.set('limit', String(Math.min(limit, 20)));
|
|
161
|
+
if (opts.channel)
|
|
162
|
+
params.set('channel', String(opts.channel));
|
|
163
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/search?${params.toString()}`);
|
|
164
|
+
if (!response.ok)
|
|
165
|
+
throw responseError(response, 'message search failed');
|
|
166
|
+
const data = response.data;
|
|
167
|
+
writeOutput(runtime, `Found ${data?.results?.length ?? 0} message(s).`, response.data);
|
|
168
|
+
});
|
|
169
|
+
message.command('resolve')
|
|
170
|
+
.description('Resolve one message by id or prefix inside a target')
|
|
171
|
+
.requiredOption('--channel <target>', 'Channel, DM, or thread target from search/read output')
|
|
172
|
+
.requiredOption('--message-id <id>', 'Message id or unique prefix')
|
|
173
|
+
.action(async (opts) => {
|
|
174
|
+
const runtime = createRuntime(program, options);
|
|
175
|
+
const channel = requireString(opts.channel, '--channel');
|
|
176
|
+
const messageId = requireString(opts.messageId, '--message-id');
|
|
177
|
+
const params = new URLSearchParams();
|
|
178
|
+
params.set('channel', channel);
|
|
179
|
+
params.set('around', messageId);
|
|
180
|
+
params.set('limit', '1');
|
|
181
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/history?${params.toString()}`);
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
if (isMessageNotResolved(response)) {
|
|
184
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MESSAGE_NOT_RESOLVED, `No message matching ${messageId} was returned for ${channel}.`, { status: response.status, suggestedNextAction: 'Run bigbang message search again and pass the returned target and msg id to resolve.' });
|
|
185
|
+
}
|
|
186
|
+
throw responseError(response, 'message resolve failed');
|
|
187
|
+
}
|
|
188
|
+
const data = response.data;
|
|
189
|
+
const resolved = Array.isArray(data?.messages)
|
|
190
|
+
? data.messages.find((item) => typeof item?.id === 'string' && item.id.startsWith(messageId))
|
|
191
|
+
: null;
|
|
192
|
+
if (!resolved) {
|
|
193
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.MESSAGE_NOT_RESOLVED, `No message matching ${messageId} was returned for ${channel}.`, { suggestedNextAction: 'Run bigbang message search again and pass the returned target and msg id to resolve.' });
|
|
194
|
+
}
|
|
195
|
+
const outputData = response.data && typeof response.data === 'object'
|
|
196
|
+
? { ...response.data, resolved }
|
|
197
|
+
: { resolved };
|
|
198
|
+
writeOutput(runtime, `Resolved message ${String(resolved.id)} in ${channel}.`, outputData);
|
|
199
|
+
});
|
|
200
|
+
message.command('react')
|
|
201
|
+
.description('Add or remove a reaction on a message')
|
|
202
|
+
.option('--message-id <id>', 'Message id')
|
|
203
|
+
.option('--emoji <emoji>', 'Emoji to react with')
|
|
204
|
+
.option('--remove', 'Remove the reaction instead of adding it')
|
|
205
|
+
.option('--channel <target>', 'Optional channel, DM, or thread target hint; validated against the message channel')
|
|
206
|
+
.action(async (opts) => {
|
|
207
|
+
const runtime = createRuntime(program, options);
|
|
208
|
+
const messageId = requireString(opts.messageId, '--message-id');
|
|
209
|
+
const emoji = requireString(opts.emoji, '--emoji');
|
|
210
|
+
const channel = typeof opts.channel === 'string' ? opts.channel.trim() : '';
|
|
211
|
+
const agentId = encodeURIComponent(runtime.context.agentId);
|
|
212
|
+
const encodedMessageId = encodeURIComponent(messageId);
|
|
213
|
+
const encodedEmoji = encodeURIComponent(emoji);
|
|
214
|
+
if (opts.remove) {
|
|
215
|
+
const params = new URLSearchParams();
|
|
216
|
+
if (channel)
|
|
217
|
+
params.set('channel', channel);
|
|
218
|
+
const qs = params.toString();
|
|
219
|
+
const response = await runtime.client.request('DELETE', `/api/internal/agent/${agentId}/messages/${encodedMessageId}/reactions/${encodedEmoji}${qs ? `?${qs}` : ''}`);
|
|
220
|
+
if (!response.ok)
|
|
221
|
+
throw responseError(response, 'remove reaction failed');
|
|
222
|
+
writeOutput(runtime, `Removed ${emoji} reaction from ${messageId}.`, response.data);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const body = { emoji };
|
|
226
|
+
if (channel)
|
|
227
|
+
body.channel = channel;
|
|
228
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${agentId}/messages/${encodedMessageId}/reactions`, body);
|
|
229
|
+
if (!response.ok)
|
|
230
|
+
throw responseError(response, 'add reaction failed');
|
|
231
|
+
writeOutput(runtime, `Reacted with ${emoji} on ${messageId}.`, response.data);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function resolveMessageSendClientMessageId(runtime, params) {
|
|
235
|
+
const override = runtime.env.BIGBANG_MESSAGE_SEND_OPERATION_ID?.trim()
|
|
236
|
+
|| runtime.env.BIGBANG_MESSAGE_SEND_OPERATION_ID?.trim();
|
|
237
|
+
if (override)
|
|
238
|
+
return override;
|
|
239
|
+
void params;
|
|
240
|
+
return `client-${randomUUID()}-bigbang-send`;
|
|
241
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { AGENT_COMMAND_ERROR_CODES, AgentCommandError, MUTATION_HINTS, appendCommonBody, createRuntime, formatPanelVersionConflict, isVersionConflict, normalizePanelPayload, parseJsonStdinOrThrow, parseNonNegativeInteger, parsePositiveInteger, readRequiredStdin, repeatOption, requireString, responseError, summarizePanelCollaborators, summarizePanelComponents, summarizePanelState, withHint, writeJson, writeOutput } from '../cliSupport.js';
|
|
3
|
+
export function registerPanelCommands(program, options) {
|
|
4
|
+
const panel = program.command('panel').description('Panel operations');
|
|
5
|
+
panel.command('create')
|
|
6
|
+
.description('Create a new panel from stdin JSON')
|
|
7
|
+
.action(async () => {
|
|
8
|
+
const runtime = createRuntime(program, options);
|
|
9
|
+
const payload = normalizePanelPayload(await parseJsonStdinOrThrow(runtime, 'panel create JSON payload'), 'panel create');
|
|
10
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels`, appendCommonBody(runtime, payload));
|
|
11
|
+
if (!response.ok)
|
|
12
|
+
throw responseError(response, 'panel create failed');
|
|
13
|
+
const data = response.data;
|
|
14
|
+
writeOutput(runtime, withHint(`Panel created. panel_id=${String(data.panel_id ?? '')} version=${String(data.version ?? '')}`, MUTATION_HINTS.panelInspect), response.data);
|
|
15
|
+
});
|
|
16
|
+
panel.command('upsert')
|
|
17
|
+
.description('Create or update a stable-handle panel from stdin JSON')
|
|
18
|
+
.action(async () => {
|
|
19
|
+
const runtime = createRuntime(program, options);
|
|
20
|
+
const payload = normalizePanelPayload(await parseJsonStdinOrThrow(runtime, 'panel upsert JSON payload'), 'panel upsert');
|
|
21
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/upsert`, appendCommonBody(runtime, payload));
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
if (isVersionConflict(response)) {
|
|
24
|
+
writeOutput(runtime, formatPanelVersionConflict(response.data), response.data);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
throw responseError(response, 'panel upsert failed');
|
|
28
|
+
}
|
|
29
|
+
const data = response.data;
|
|
30
|
+
writeOutput(runtime, withHint(`Panel upserted. panel_id=${String(data.panel_id ?? '')} version=${String(data.version ?? '')}`, MUTATION_HINTS.panelInspect), response.data);
|
|
31
|
+
});
|
|
32
|
+
panel.command('patch')
|
|
33
|
+
.description('Patch a panel from stdin JSON')
|
|
34
|
+
.requiredOption('--panel-id <id>', 'Panel id')
|
|
35
|
+
.action(async (opts) => {
|
|
36
|
+
const runtime = createRuntime(program, options);
|
|
37
|
+
const panelId = requireString(opts.panelId, '--panel-id');
|
|
38
|
+
const payload = normalizePanelPayload(await parseJsonStdinOrThrow(runtime, 'panel patch JSON payload'), 'panel patch');
|
|
39
|
+
const response = await runtime.client.request('PATCH', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/${encodeURIComponent(panelId)}`, appendCommonBody(runtime, payload));
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
if (isVersionConflict(response)) {
|
|
42
|
+
writeOutput(runtime, formatPanelVersionConflict(response.data), response.data);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
throw responseError(response, 'panel patch failed');
|
|
46
|
+
}
|
|
47
|
+
const data = response.data;
|
|
48
|
+
writeOutput(runtime, `Panel patched. panel_id=${String(data.panel_id ?? panelId)} version=${String(data.version ?? '')}`, response.data);
|
|
49
|
+
});
|
|
50
|
+
panel.command('read-rows')
|
|
51
|
+
.description('Read panel rows')
|
|
52
|
+
.requiredOption('--panel-id <id>', 'Panel id')
|
|
53
|
+
.option('--conversation-id <id>', 'Panel owner conversation id')
|
|
54
|
+
.option('--row-index <n>', 'Specific row index to read; repeat for multiple rows', repeatOption)
|
|
55
|
+
.option('--limit <n>', 'Maximum rows')
|
|
56
|
+
.option('--cursor <cursor>', 'Pagination cursor')
|
|
57
|
+
.action(async (opts) => {
|
|
58
|
+
const runtime = createRuntime(program, options);
|
|
59
|
+
const body = {};
|
|
60
|
+
if (opts.conversationId)
|
|
61
|
+
body.conversationId = opts.conversationId;
|
|
62
|
+
else if (runtime.context.conversationId)
|
|
63
|
+
body.conversationId = runtime.context.conversationId;
|
|
64
|
+
const rowIndices = Array.isArray(opts.rowIndex)
|
|
65
|
+
? opts.rowIndex.map((value) => {
|
|
66
|
+
const parsed = parseNonNegativeInteger('row-index', value);
|
|
67
|
+
if (parsed === undefined) {
|
|
68
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.INVALID_ARG, '--row-index is required.');
|
|
69
|
+
}
|
|
70
|
+
return parsed;
|
|
71
|
+
})
|
|
72
|
+
: undefined;
|
|
73
|
+
if (rowIndices !== undefined && rowIndices.length > 0)
|
|
74
|
+
body.row_indices = rowIndices;
|
|
75
|
+
const limit = parsePositiveInteger('limit', opts.limit);
|
|
76
|
+
if (limit !== undefined)
|
|
77
|
+
body.limit = limit;
|
|
78
|
+
if (opts.cursor)
|
|
79
|
+
body.cursor = opts.cursor;
|
|
80
|
+
const panelId = requireString(opts.panelId, '--panel-id');
|
|
81
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/${encodeURIComponent(panelId)}/rows/read`, body);
|
|
82
|
+
if (!response.ok)
|
|
83
|
+
throw responseError(response, 'read panel rows failed');
|
|
84
|
+
const data = response.data;
|
|
85
|
+
writeOutput(runtime, `Read ${data?.rows?.length ?? 0} row(s).`, response.data);
|
|
86
|
+
});
|
|
87
|
+
panel.command('read-events')
|
|
88
|
+
.description('Read panel semantic events')
|
|
89
|
+
.requiredOption('--panel-id <id>', 'Panel id')
|
|
90
|
+
.option('--conversation-id <id>', 'Panel owner conversation id')
|
|
91
|
+
.option('--limit <n>', 'Maximum events')
|
|
92
|
+
.option('--after-event-id <id>', 'Only return events after this event id')
|
|
93
|
+
.action(async (opts) => {
|
|
94
|
+
const runtime = createRuntime(program, options);
|
|
95
|
+
const body = {};
|
|
96
|
+
if (opts.conversationId)
|
|
97
|
+
body.conversationId = opts.conversationId;
|
|
98
|
+
else if (runtime.context.conversationId)
|
|
99
|
+
body.conversationId = runtime.context.conversationId;
|
|
100
|
+
const limit = parsePositiveInteger('limit', opts.limit);
|
|
101
|
+
if (limit !== undefined)
|
|
102
|
+
body.limit = limit;
|
|
103
|
+
const afterEventId = parseNonNegativeInteger('after-event-id', opts.afterEventId);
|
|
104
|
+
if (afterEventId !== undefined)
|
|
105
|
+
body.after_event_id = afterEventId;
|
|
106
|
+
const panelId = requireString(opts.panelId, '--panel-id');
|
|
107
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/${encodeURIComponent(panelId)}/events/read`, body);
|
|
108
|
+
if (!response.ok)
|
|
109
|
+
throw responseError(response, 'read panel events failed');
|
|
110
|
+
const data = response.data;
|
|
111
|
+
writeOutput(runtime, `Read ${data?.events?.length ?? 0} event(s).`, response.data);
|
|
112
|
+
});
|
|
113
|
+
panel.command('state')
|
|
114
|
+
.description('Read current saved panel state for this agent surface')
|
|
115
|
+
.requiredOption('--panel-id <id>', 'Panel id')
|
|
116
|
+
.action(async (opts) => {
|
|
117
|
+
const runtime = createRuntime(program, options);
|
|
118
|
+
const panelId = requireString(opts.panelId, '--panel-id');
|
|
119
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/${encodeURIComponent(panelId)}/state`);
|
|
120
|
+
if (!response.ok)
|
|
121
|
+
throw responseError(response, 'read panel state failed');
|
|
122
|
+
writeOutput(runtime, summarizePanelState(response.data), response.data);
|
|
123
|
+
});
|
|
124
|
+
const createPanelPreview = async (opts) => {
|
|
125
|
+
const runtime = createRuntime(program, options);
|
|
126
|
+
const raw = typeof opts.specPath === 'string' && opts.specPath.trim()
|
|
127
|
+
? readFileSync(opts.specPath.trim(), 'utf8')
|
|
128
|
+
: await readRequiredStdin(runtime.io.stdin, 'panel preview JSON payload');
|
|
129
|
+
let parsed;
|
|
130
|
+
try {
|
|
131
|
+
parsed = JSON.parse(raw);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.INVALID_JSON_STDIN, `Invalid panel preview JSON: ${error?.message ?? String(error)}`);
|
|
135
|
+
}
|
|
136
|
+
const payload = normalizePanelPayload(parsed, 'panel preview');
|
|
137
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/preview`, appendCommonBody(runtime, payload));
|
|
138
|
+
if (!response.ok)
|
|
139
|
+
throw responseError(response, 'panel preview failed');
|
|
140
|
+
const data = response.data;
|
|
141
|
+
const previewId = String(data.panel_preview_id ?? data.previewId ?? '');
|
|
142
|
+
writeOutput(runtime, withHint(`Panel preview created. panel_preview_id=${previewId}`, `Next: bigbang message send --kind final --panel-preview-id ${previewId}`), response.data);
|
|
143
|
+
};
|
|
144
|
+
const panelPreview = panel.command('preview')
|
|
145
|
+
.description('Panel preview operations')
|
|
146
|
+
.option('--spec-path <path>', 'Alias for preview create: read preview spec JSON from this file instead of stdin')
|
|
147
|
+
.action(createPanelPreview);
|
|
148
|
+
panelPreview.command('create')
|
|
149
|
+
.description('Create an ephemeral read-only panel preview from stdin JSON or --spec-path')
|
|
150
|
+
.option('--spec-path <path>', 'Read preview spec JSON from this file instead of stdin')
|
|
151
|
+
.action(createPanelPreview);
|
|
152
|
+
panelPreview.command('show')
|
|
153
|
+
.description('Show an ephemeral panel preview spec')
|
|
154
|
+
.requiredOption('--preview-id <id>', 'Panel preview id')
|
|
155
|
+
.action(async (opts) => {
|
|
156
|
+
const runtime = createRuntime(program, options);
|
|
157
|
+
const previewId = requireString(opts.previewId, '--preview-id');
|
|
158
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/preview/${encodeURIComponent(previewId)}`);
|
|
159
|
+
if (!response.ok)
|
|
160
|
+
throw responseError(response, 'panel preview show failed');
|
|
161
|
+
writeJson(runtime, response.data);
|
|
162
|
+
});
|
|
163
|
+
const panelCollaborators = panel.command('collaborators').description('Panel collaborator operations');
|
|
164
|
+
panelCollaborators.command('list')
|
|
165
|
+
.description('List panel owner/collaborator agents')
|
|
166
|
+
.requiredOption('--panel-id <id>', 'Panel id')
|
|
167
|
+
.action(async (opts) => {
|
|
168
|
+
const runtime = createRuntime(program, options);
|
|
169
|
+
const panelId = requireString(opts.panelId, '--panel-id');
|
|
170
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/${encodeURIComponent(panelId)}/collaborators`);
|
|
171
|
+
if (!response.ok)
|
|
172
|
+
throw responseError(response, 'list panel collaborators failed');
|
|
173
|
+
writeOutput(runtime, summarizePanelCollaborators(response.data), response.data);
|
|
174
|
+
});
|
|
175
|
+
panelCollaborators.command('add')
|
|
176
|
+
.description('Owner-only: add a collaborator agent to a panel')
|
|
177
|
+
.requiredOption('--panel-id <id>', 'Panel id')
|
|
178
|
+
.option('--agent-id <id>', 'Collaborator agent id')
|
|
179
|
+
.option('--agent-name <name>', 'Collaborator agent display name')
|
|
180
|
+
.action(async (opts) => {
|
|
181
|
+
const runtime = createRuntime(program, options);
|
|
182
|
+
const panelId = requireString(opts.panelId, '--panel-id');
|
|
183
|
+
const collaboratorAgentId = typeof opts.agentId === 'string' ? opts.agentId.trim() : '';
|
|
184
|
+
const collaboratorName = typeof opts.agentName === 'string' ? opts.agentName.trim() : '';
|
|
185
|
+
if (!collaboratorAgentId && !collaboratorName) {
|
|
186
|
+
throw new AgentCommandError(AGENT_COMMAND_ERROR_CODES.INVALID_ARG, 'Provide --agent-id or --agent-name.');
|
|
187
|
+
}
|
|
188
|
+
const response = await runtime.client.request('POST', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/${encodeURIComponent(panelId)}/collaborators`, {
|
|
189
|
+
...(collaboratorAgentId ? { collaboratorAgentId } : {}),
|
|
190
|
+
...(collaboratorName ? { collaboratorName } : {}),
|
|
191
|
+
});
|
|
192
|
+
if (!response.ok)
|
|
193
|
+
throw responseError(response, 'add panel collaborator failed');
|
|
194
|
+
writeOutput(runtime, summarizePanelCollaborators(response.data), response.data);
|
|
195
|
+
});
|
|
196
|
+
panelCollaborators.command('remove')
|
|
197
|
+
.description('Owner-only: remove a non-owner collaborator agent from a panel')
|
|
198
|
+
.requiredOption('--panel-id <id>', 'Panel id')
|
|
199
|
+
.requiredOption('--agent-id <id>', 'Collaborator agent id')
|
|
200
|
+
.action(async (opts) => {
|
|
201
|
+
const runtime = createRuntime(program, options);
|
|
202
|
+
const panelId = requireString(opts.panelId, '--panel-id');
|
|
203
|
+
const collaboratorAgentId = requireString(opts.agentId, '--agent-id');
|
|
204
|
+
const response = await runtime.client.request('DELETE', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/panels/${encodeURIComponent(panelId)}/collaborators/${encodeURIComponent(collaboratorAgentId)}`);
|
|
205
|
+
if (!response.ok)
|
|
206
|
+
throw responseError(response, 'remove panel collaborator failed');
|
|
207
|
+
writeOutput(runtime, summarizePanelCollaborators(response.data), response.data);
|
|
208
|
+
});
|
|
209
|
+
panel.command('components')
|
|
210
|
+
.description('List available panel UI component contracts')
|
|
211
|
+
.action(async () => {
|
|
212
|
+
const runtime = createRuntime(program, options);
|
|
213
|
+
const response = await runtime.client.request('GET', `/api/internal/agent/${encodeURIComponent(runtime.context.agentId)}/ui-components`);
|
|
214
|
+
if (!response.ok)
|
|
215
|
+
throw responseError(response, 'list panel components failed');
|
|
216
|
+
writeOutput(runtime, summarizePanelComponents(response.data), response.data);
|
|
217
|
+
});
|
|
218
|
+
}
|