@shadowob/cli 1.1.6 → 1.1.8

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/index.js CHANGED
@@ -4,13 +4,14 @@ import {
4
4
  getClient,
5
5
  getClientWithToken,
6
6
  getSocket,
7
- parsePositiveInt
8
- } from "./chunk-E364BDQO.js";
7
+ parsePositiveInt,
8
+ resolveServerFlag
9
+ } from "./chunk-S6XCO6ZW.js";
9
10
 
10
11
  // src/index.ts
11
- import { Command as Command28 } from "commander";
12
+ import { Command as Command29 } from "commander";
12
13
 
13
- // src/commands/agents.ts
14
+ // src/commands/api-tokens.ts
14
15
  import { Command } from "commander";
15
16
 
16
17
  // src/utils/output.ts
@@ -88,139 +89,32 @@ function formatObject(obj) {
88
89
  formattedValue = chalk.gray("null");
89
90
  } else if (typeof value === "boolean") {
90
91
  formattedValue = value ? chalk.green("true") : chalk.red("false");
91
- } else if (typeof value === "object") {
92
+ } else if (Array.isArray(value)) {
93
+ if (value.length > 0 && typeof value[0] === "object" && value[0] !== null) {
94
+ console.log(chalk.gray(formattedKey));
95
+ formatArray(value);
96
+ continue;
97
+ }
92
98
  formattedValue = JSON.stringify(value);
99
+ } else if (typeof value === "object") {
100
+ formattedValue = formatNestedValue(value);
93
101
  } else {
94
102
  formattedValue = String(value);
95
103
  }
96
104
  console.log(`${chalk.gray(formattedKey)} ${formattedValue}`);
97
105
  }
98
106
  }
99
-
100
- // src/commands/agents.ts
101
- function createAgentsCommand() {
102
- const agents = new Command("agents").description("Agent management commands");
103
- agents.command("list").description("List your agents").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
104
- try {
105
- const client = await getClient(options.profile);
106
- const agents2 = await client.listAgents();
107
- output(agents2, { json: options.json });
108
- } catch (error) {
109
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
110
- process.exit(1);
111
- }
112
- });
113
- agents.command("get").description("Get agent details").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
114
- try {
115
- const client = await getClient(options.profile);
116
- const agent = await client.getAgent(agentId);
117
- output(agent, { json: options.json });
118
- } catch (error) {
119
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
120
- process.exit(1);
121
- }
122
- });
123
- agents.command("create").description("Create a new agent").requiredOption("--name <name>", "Agent name").requiredOption("--username <username>", "Agent username").option("--display-name <name>", "Display name").option("--avatar-url <url>", "Avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
124
- async (options) => {
125
- try {
126
- const client = await getClient(options.profile);
127
- const agent = await client.createAgent({
128
- name: options.name,
129
- username: options.username,
130
- displayName: options.displayName,
131
- avatarUrl: options.avatarUrl
132
- });
133
- output(agent, { json: options.json });
134
- } catch (error) {
135
- outputError(error instanceof Error ? error.message : String(error), {
136
- json: options.json
137
- });
138
- process.exit(1);
139
- }
140
- }
141
- );
142
- agents.command("update").description("Update an agent").argument("<agent-id>", "Agent ID").option("--name <name>", "New name").option("--display-name <name>", "New display name").option("--avatar-url <url>", "New avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
143
- async (agentId, options) => {
144
- try {
145
- const client = await getClient(options.profile);
146
- const agent = await client.updateAgent(agentId, {
147
- name: options.name,
148
- displayName: options.displayName,
149
- avatarUrl: options.avatarUrl
150
- });
151
- output(agent, { json: options.json });
152
- } catch (error) {
153
- outputError(error instanceof Error ? error.message : String(error), {
154
- json: options.json
155
- });
156
- process.exit(1);
157
- }
158
- }
159
- );
160
- agents.command("delete").description("Delete an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
161
- try {
162
- const client = await getClient(options.profile);
163
- await client.deleteAgent(agentId);
164
- const outputOpts = { json: options.json };
165
- outputSuccess("Agent deleted", outputOpts);
166
- } catch (error) {
167
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
168
- process.exit(1);
169
- }
170
- });
171
- agents.command("start").description("Start an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
172
- try {
173
- const client = await getClient(options.profile);
174
- await client.startAgent(agentId);
175
- const outputOpts = { json: options.json };
176
- outputSuccess("Agent started", outputOpts);
177
- } catch (error) {
178
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
179
- process.exit(1);
180
- }
181
- });
182
- agents.command("stop").description("Stop an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
183
- try {
184
- const client = await getClient(options.profile);
185
- await client.stopAgent(agentId);
186
- const outputOpts = { json: options.json };
187
- outputSuccess("Agent stopped", outputOpts);
188
- } catch (error) {
189
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
190
- process.exit(1);
191
- }
192
- });
193
- agents.command("token").description("Generate a new token for an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
194
- try {
195
- const client = await getClient(options.profile);
196
- const result = await client.generateAgentToken(agentId);
197
- if (options.json) {
198
- output(result, { json: true });
199
- } else {
200
- console.log(result.token);
201
- }
202
- } catch (error) {
203
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
204
- process.exit(1);
205
- }
206
- });
207
- agents.command("config").description("Get agent remote config").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
208
- try {
209
- const client = await getClient(options.profile);
210
- const config = await client.getAgentConfig(agentId);
211
- output(config, { json: options.json });
212
- } catch (error) {
213
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
214
- process.exit(1);
215
- }
216
- });
217
- return agents;
107
+ function formatNestedValue(obj) {
108
+ const username = obj.username || obj.name || obj.displayName;
109
+ if (username) {
110
+ return username;
111
+ }
112
+ return JSON.stringify(obj);
218
113
  }
219
114
 
220
115
  // src/commands/api-tokens.ts
221
- import { Command as Command2 } from "commander";
222
116
  function createApiTokensCommand() {
223
- const tokens = new Command2("api-tokens").description("API token management commands");
117
+ const tokens = new Command("api-tokens").description("API token management commands");
224
118
  tokens.command("list").description("List all API tokens").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
225
119
  try {
226
120
  const client = await getClient(options.profile);
@@ -270,12 +164,7 @@ function createApiTokensCommand() {
270
164
  // src/commands/app.ts
271
165
  import { readFile, writeFile } from "fs/promises";
272
166
  import { basename } from "path";
273
- import { Command as Command3 } from "commander";
274
- function resolveServer(value) {
275
- const server = value ?? process.env.SHADOWOB_SERVER_ID;
276
- if (!server) throw new Error("Missing server. Pass --server or set SHADOWOB_SERVER_ID.");
277
- return server;
278
- }
167
+ import { Command as Command2 } from "commander";
279
168
  function parseJsonInput(value) {
280
169
  if (!value) return {};
281
170
  const parsed = JSON.parse(value);
@@ -287,16 +176,135 @@ function parseJsonInput(value) {
287
176
  async function readJsonFile(path) {
288
177
  return JSON.parse(await readFile(path, "utf8"));
289
178
  }
179
+ function parsePermissions(value) {
180
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
181
+ }
290
182
  function commandHandlerError(error, json) {
291
183
  outputError(error instanceof Error ? error.message : String(error), { json });
292
184
  process.exit(1);
293
185
  }
186
+ function prettyJson(value) {
187
+ return JSON.stringify(value, null, 2);
188
+ }
189
+ function commandSummary(command) {
190
+ return command.help?.summary ?? command.description ?? command.title ?? command.permission;
191
+ }
192
+ function formatAppCommandHelp(input) {
193
+ const { appKey, serverId, manifest, commandName } = input;
194
+ const command = commandName ? manifest.commands.find((item) => item.name === commandName) : void 0;
195
+ if (commandName && !command) throw new Error(`App command not found: ${commandName}`);
196
+ if (!command) {
197
+ const lines2 = [
198
+ `${manifest.name} (${appKey})`,
199
+ manifest.description ?? "",
200
+ manifest.help?.overview ?? "",
201
+ "",
202
+ "Usage:",
203
+ ` shadowob app call ${appKey} <command> --server "${serverId}" --json-input '<input-json>' --json`,
204
+ ` shadowob app call ${appKey} <command> --server "${serverId}" --help`,
205
+ manifest.binary?.supported ? ` shadowob app call ${appKey} <command> --server "${serverId}" --file ./asset.png --json-input '<input-json>' --json` : "",
206
+ "",
207
+ "Commands:",
208
+ ...manifest.commands.map((item) => ` ${item.name.padEnd(24)} ${commandSummary(item)}`),
209
+ manifest.realtime ? [
210
+ "",
211
+ "Realtime:",
212
+ ` shadowob app events ${appKey} --server "${serverId}" --json`,
213
+ manifest.realtime.subscribe?.help ?? "",
214
+ manifest.realtime.publish?.help ?? ""
215
+ ].join("\n") : ""
216
+ ];
217
+ return lines2.filter(Boolean).join("\n");
218
+ }
219
+ const help = command.help;
220
+ const usage = help?.usage ?? `shadowob app call ${appKey} ${command.name} --server "${serverId}" --json-input '<input-json>' --json`;
221
+ const lines = [
222
+ `${manifest.name} ${command.name}`,
223
+ commandSummary(command),
224
+ "",
225
+ "Usage:",
226
+ ` ${usage}`,
227
+ command.binary?.supported || command.input === "multipart" ? ` shadowob app call ${appKey} ${command.name} --server "${serverId}" --file ./asset.png --json-input '<input-json>' --json` : "",
228
+ help?.details ? ["", help.details].join("\n") : "",
229
+ help?.examples?.length ? [
230
+ "",
231
+ "Examples:",
232
+ ...help.examples.flatMap((example) => {
233
+ const rendered = example.command ? [` ${example.command}`] : example.input !== void 0 ? [` ${prettyJson(example.input).replace(/\n/g, "\n ")}`] : [];
234
+ return example.title ? [` # ${example.title}`, ...rendered] : rendered;
235
+ })
236
+ ].join("\n") : "",
237
+ command.inputSchema ? ["", "Input schema:", prettyJson(command.inputSchema)].join("\n") : ""
238
+ ];
239
+ return lines.filter(Boolean).join("\n");
240
+ }
241
+ function parseSseEvents(chunk, carry) {
242
+ const frames = `${carry}${chunk}`.split(/\r?\n\r?\n/u);
243
+ return {
244
+ complete: frames.slice(0, -1),
245
+ carry: frames.at(-1) ?? ""
246
+ };
247
+ }
248
+ function decodeSseFrame(frame) {
249
+ let event = "message";
250
+ const data = [];
251
+ for (const line of frame.split(/\r?\n/u)) {
252
+ if (line.startsWith("event:")) event = line.slice(6).trim();
253
+ if (line.startsWith("data:")) data.push(line.slice(5).trimStart());
254
+ }
255
+ return { event, data: data.join("\n") };
256
+ }
257
+ async function streamServerAppEvents(input) {
258
+ const response = await fetch(input.url, { headers: { Accept: "text/event-stream" } });
259
+ if (!response.ok || !response.body) {
260
+ throw new Error(`Event stream failed (${response.status})`);
261
+ }
262
+ const reader = response.body.getReader();
263
+ const decoder = new TextDecoder();
264
+ let carry = "";
265
+ let count = 0;
266
+ const stop = () => reader.cancel().catch(() => void 0);
267
+ process.once("SIGINT", stop);
268
+ try {
269
+ while (true) {
270
+ const next = await reader.read();
271
+ if (next.done) break;
272
+ const parsed = parseSseEvents(decoder.decode(next.value, { stream: true }), carry);
273
+ carry = parsed.carry;
274
+ for (const frame of parsed.complete) {
275
+ const decoded = decodeSseFrame(frame);
276
+ if (!decoded.data || input.event && decoded.event !== input.event) continue;
277
+ let payload = decoded.data;
278
+ try {
279
+ payload = JSON.parse(decoded.data);
280
+ } catch {
281
+ }
282
+ if (input.json) console.log(JSON.stringify({ event: decoded.event, data: payload }));
283
+ else
284
+ console.log(
285
+ `[${decoded.event}] ${typeof payload === "string" ? payload : prettyJson(payload)}`
286
+ );
287
+ count += 1;
288
+ if (input.limit && count >= input.limit) return;
289
+ }
290
+ }
291
+ } finally {
292
+ process.off("SIGINT", stop);
293
+ }
294
+ }
294
295
  function createAppCommand() {
295
- const app = new Command3("app").description("Server App integration commands");
296
+ const app = new Command2("app").description("Server App integration commands");
296
297
  app.command("list").description("List apps installed in a server").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
297
298
  try {
298
299
  const client = await getClient(options.profile);
299
- output(await client.listServerApps(resolveServer(options.server)), { json: options.json });
300
+ const apps = await client.listServerApps(resolveServerFlag(options.server));
301
+ output(
302
+ apps.map((entry) => ({
303
+ id: entry.id,
304
+ name: `${entry.appKey} (${entry.name})`
305
+ })),
306
+ { json: options.json }
307
+ );
300
308
  } catch (error) {
301
309
  commandHandlerError(error, options.json);
302
310
  }
@@ -310,7 +318,7 @@ function createAppCommand() {
310
318
  const client = await getClient(options.profile);
311
319
  const manifest = options.manifestFile ? await readJsonFile(options.manifestFile) : void 0;
312
320
  output(
313
- await client.discoverServerApp(resolveServer(options.server), {
321
+ await client.discoverServerApp(resolveServerFlag(options.server), {
314
322
  manifestUrl: options.manifestUrl,
315
323
  manifest
316
324
  }),
@@ -329,7 +337,7 @@ function createAppCommand() {
329
337
  }
330
338
  const client = await getClient(options.profile);
331
339
  const manifest = options.manifestFile ? await readJsonFile(options.manifestFile) : void 0;
332
- const result = await client.installServerApp(resolveServer(options.server), {
340
+ const result = await client.installServerApp(resolveServerFlag(options.server), {
333
341
  manifestUrl: options.manifestUrl,
334
342
  manifest
335
343
  });
@@ -343,7 +351,7 @@ function createAppCommand() {
343
351
  async (appKey, options) => {
344
352
  try {
345
353
  const client = await getClient(options.profile);
346
- output(await client.getServerApp(resolveServer(options.server), appKey), {
354
+ output(await client.getServerApp(resolveServerFlag(options.server), appKey), {
347
355
  json: options.json
348
356
  });
349
357
  } catch (error) {
@@ -351,16 +359,57 @@ function createAppCommand() {
351
359
  }
352
360
  }
353
361
  );
354
- app.command("grant").description("Grant a Buddy access to an installed server App").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").requiredOption("--buddy <agent-id>", "Buddy agent ID").requiredOption("--permissions <permissions>", "Comma-separated permissions, or *").option("--approval-mode <mode>", "none, first_time, every_time, or policy", "none").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
362
+ app.command("grant").description("Grant a Buddy access to an installed server App").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").requiredOption("--buddy <buddy-id>", "Buddy ID").requiredOption("--permissions <permissions>", "Comma-separated permissions, or *").option("--approval-mode <mode>", "none, first_time, every_time, or policy", "none").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
355
363
  async (appKey, options) => {
356
364
  try {
357
365
  const client = await getClient(options.profile);
358
- const permissions = options.permissions.split(",").map((item) => item.trim()).filter(Boolean);
359
- const result = await client.grantServerAppToBuddy(resolveServer(options.server), appKey, {
360
- buddyAgentId: options.buddy,
361
- permissions,
362
- approvalMode: options.approvalMode
363
- });
366
+ const permissions = parsePermissions(options.permissions);
367
+ const result = await client.grantServerAppToBuddy(
368
+ resolveServerFlag(options.server),
369
+ appKey,
370
+ {
371
+ buddyAgentId: options.buddy,
372
+ permissions,
373
+ approvalMode: options.approvalMode
374
+ }
375
+ );
376
+ output(result, { json: options.json });
377
+ } catch (error) {
378
+ commandHandlerError(error, options.json);
379
+ }
380
+ }
381
+ );
382
+ app.command("defaults").description("Set default app permissions that members and Buddies can use without prompting").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").requiredOption("--permissions <permissions>", "Comma-separated permissions, or *").option("--approval-mode <mode>", "none, first_time, every_time, or policy", "none").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
383
+ async (appKey, options) => {
384
+ try {
385
+ const client = await getClient(options.profile);
386
+ const result = await client.updateServerAppAccessPolicy(
387
+ resolveServerFlag(options.server),
388
+ appKey,
389
+ {
390
+ defaultPermissions: parsePermissions(options.permissions),
391
+ defaultApprovalMode: options.approvalMode
392
+ }
393
+ );
394
+ output(result, { json: options.json });
395
+ } catch (error) {
396
+ commandHandlerError(error, options.json);
397
+ }
398
+ }
399
+ );
400
+ app.command("approve").description("Approve one app command for yourself or a Buddy after a first-use prompt").argument("<app-key>", "App key").argument("<command>", "Command name").requiredOption("--server <server>", "Server ID or slug").option("--buddy <buddy-id>", "Buddy ID to approve for").option("--no-remember", "Approve only the immediate retry window").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
401
+ async (appKey, commandName, options) => {
402
+ try {
403
+ const client = await getClient(options.profile);
404
+ const result = await client.approveServerAppCommand(
405
+ resolveServerFlag(options.server),
406
+ appKey,
407
+ {
408
+ commandName,
409
+ buddyAgentId: options.buddy,
410
+ remember: options.remember
411
+ }
412
+ );
364
413
  output(result, { json: options.json });
365
414
  } catch (error) {
366
415
  commandHandlerError(error, options.json);
@@ -370,7 +419,7 @@ function createAppCommand() {
370
419
  app.command("discover").description("Emit Skill-style command discovery for server Apps").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
371
420
  try {
372
421
  const client = await getClient(options.profile);
373
- const server = resolveServer(options.server);
422
+ const server = resolveServerFlag(options.server);
374
423
  const apps = await client.listServerApps(server);
375
424
  const docs = await Promise.all(
376
425
  apps.map((entry) => client.getServerAppSkills(server, entry.appKey))
@@ -388,7 +437,7 @@ function createAppCommand() {
388
437
  async (appKey, options) => {
389
438
  try {
390
439
  const client = await getClient(options.profile);
391
- const result = await client.getServerAppSkills(resolveServer(options.server), appKey);
440
+ const result = await client.getServerAppSkills(resolveServerFlag(options.server), appKey);
392
441
  if (options.json) output(result, { json: true });
393
442
  else console.log(result.markdown);
394
443
  } catch (error) {
@@ -396,18 +445,81 @@ function createAppCommand() {
396
445
  }
397
446
  }
398
447
  );
399
- app.command("call").description("Call a server App command").argument("<app-key>", "App key").argument("<command>", "Command name").requiredOption("--server <server>", "Server ID or slug").option("--json-input <json>", "JSON command input").option("--input-file <path>", "Read JSON command input from file").option("--file <path>", "Attach a binary file").option("--field <field>", "Multipart file field name", "file").option("--output <path>", "Write binary dataBase64 response to this path").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
448
+ app.command("events").description("Subscribe to an installed server App event stream").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").option("--event <event>", "Only print one event type").option("--limit <count>", "Stop after this many matching events").option("--profile <name>", "Profile to use").option("--json", "Output as JSON lines").action(
449
+ async (appKey, options) => {
450
+ try {
451
+ const client = await getClient(options.profile);
452
+ const launch = await client.createServerAppLaunch(
453
+ resolveServerFlag(options.server),
454
+ appKey
455
+ );
456
+ const limit = options.limit ? Number.parseInt(options.limit, 10) : void 0;
457
+ if (limit !== void 0 && (!Number.isFinite(limit) || limit < 1)) {
458
+ throw new Error("--limit must be a positive integer");
459
+ }
460
+ await streamServerAppEvents({
461
+ url: client.serverAppEventStreamUrl(launch.eventStreamPath),
462
+ event: options.event,
463
+ limit,
464
+ json: options.json
465
+ });
466
+ } catch (error) {
467
+ commandHandlerError(error, options.json);
468
+ }
469
+ }
470
+ );
471
+ app.command("call").description("Call a server App command").helpOption(false).argument("[app-key]", "App key").argument("[command]", "Command name").option("--server <server>", "Server ID or slug").option("--json-input <json>", "JSON command input").option("--input-file <path>", "Read JSON command input from file").option("--channel-id <id>", "Current Shadow channel ID for approval prompts and app context").option("--task-message-id <id>", "Inbox task message ID to bind this app command to").option("--task-card-id <id>", "Inbox task card ID to bind this app command to").option("--task-claim-id <id>", "Inbox task claim ID to bind this app command to").option("--file <path>", "Attach a binary file").option("--field <field>", "Multipart file field name", "file").option("--output <path>", "Write binary dataBase64 response to this path").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").option("-h, --help", "Show app or command help from the installed manifest").action(
400
472
  async (appKey, commandName, options) => {
401
473
  try {
474
+ if (options.help) {
475
+ if (!appKey) {
476
+ console.log(
477
+ [
478
+ "Usage:",
479
+ " shadowob app call <app-key> <command> --server <server> --json-input '<input-json>' --json",
480
+ " shadowob app call <app-key> <command> --server <server> --help"
481
+ ].join("\n")
482
+ );
483
+ return;
484
+ }
485
+ const client2 = await getClient(options.profile);
486
+ const server2 = resolveServerFlag(options.server);
487
+ const app2 = await client2.getServerApp(server2, appKey);
488
+ console.log(
489
+ formatAppCommandHelp({
490
+ appKey,
491
+ serverId: app2.serverId,
492
+ manifest: app2.manifest,
493
+ commandName
494
+ })
495
+ );
496
+ return;
497
+ }
498
+ if (!appKey) throw new Error("Missing app key");
499
+ if (!commandName) throw new Error("Missing command name");
402
500
  const client = await getClient(options.profile);
403
501
  const input = options.inputFile ? await readJsonFile(options.inputFile) : parseJsonInput(options.jsonInput);
404
- const server = resolveServer(options.server);
502
+ const server = resolveServerFlag(options.server);
503
+ if ((options.taskMessageId || options.taskCardId || options.taskClaimId) && !(options.taskMessageId && options.taskCardId)) {
504
+ throw new Error("--task-message-id and --task-card-id are required together");
505
+ }
506
+ const task = options.taskMessageId && options.taskCardId ? {
507
+ messageId: options.taskMessageId,
508
+ cardId: options.taskCardId,
509
+ ...options.taskClaimId ? { claimId: options.taskClaimId } : {}
510
+ } : void 0;
405
511
  const result = options.file ? await client.callServerAppCommandMultipart(server, appKey, commandName, {
406
512
  input,
513
+ channelId: options.channelId,
514
+ task,
407
515
  file: new Blob([await readFile(options.file)]),
408
516
  filename: basename(options.file),
409
517
  field: options.field
410
- }) : await client.callServerAppCommand(server, appKey, commandName, { input });
518
+ }) : await client.callServerAppCommand(server, appKey, commandName, {
519
+ input,
520
+ channelId: options.channelId,
521
+ task
522
+ });
411
523
  if (options.output && result && typeof result === "object" && "dataBase64" in result && typeof result.dataBase64 === "string") {
412
524
  await writeFile(
413
525
  options.output,
@@ -422,15 +534,28 @@ function createAppCommand() {
422
534
  }
423
535
  }
424
536
  );
537
+ app.command("uninstall").description("Uninstall a server App").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
538
+ async (appKey, options) => {
539
+ try {
540
+ const client = await getClient(options.profile);
541
+ await client.deleteServerApp(resolveServerFlag(options.server), appKey);
542
+ const outputOpts = { json: options.json };
543
+ if (options.json) output({ ok: true }, outputOpts);
544
+ else outputSuccess(`Uninstalled ${appKey}`, outputOpts);
545
+ } catch (error) {
546
+ commandHandlerError(error, options.json);
547
+ }
548
+ }
549
+ );
425
550
  return app;
426
551
  }
427
552
 
428
553
  // src/commands/auth.ts
429
554
  import { ShadowClient } from "@shadowob/sdk";
430
- import { Command as Command4 } from "commander";
555
+ import { Command as Command3 } from "commander";
431
556
  function createAuthCommand() {
432
- const auth = new Command4("auth").description("Authentication commands");
433
- auth.command("login").description("Authenticate with a Shadow server").requiredOption("--server-url <url>", "Shadow server URL").requiredOption("--token <token>", "JWT token").option("--profile <name>", "Profile name", "default").option("--json", "Output as JSON").action(
557
+ const auth = new Command3("auth").description("Authentication commands");
558
+ auth.command("login").description("Authenticate with a Shadow server").option("--server-url <url>", "Shadow server URL", "https://shadowob.com").requiredOption("--token <token>", "JWT token").option("--profile <name>", "Profile name", "default").option("--json", "Output as JSON").action(
434
559
  async (options) => {
435
560
  try {
436
561
  const client = new ShadowClient(options.serverUrl, options.token);
@@ -541,14 +666,135 @@ function createAuthCommand() {
541
666
  return auth;
542
667
  }
543
668
 
669
+ // src/commands/buddies.ts
670
+ import { Command as Command4 } from "commander";
671
+ function createBuddiesCommand() {
672
+ const buddies = new Command4("buddies").description("Buddy management commands");
673
+ buddies.command("list").description("List your buddies").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
674
+ try {
675
+ const client = await getClient(options.profile);
676
+ const agents = await client.listAgents();
677
+ output(agents, { json: options.json });
678
+ } catch (error) {
679
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
680
+ process.exit(1);
681
+ }
682
+ });
683
+ buddies.command("get").description("Get buddy details").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
684
+ try {
685
+ const client = await getClient(options.profile);
686
+ const agent = await client.getAgent(buddyId);
687
+ output(agent, { json: options.json });
688
+ } catch (error) {
689
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
690
+ process.exit(1);
691
+ }
692
+ });
693
+ buddies.command("create").description("Create a new buddy").requiredOption("--name <name>", "Buddy name").requiredOption("--username <username>", "Buddy username").option("--display-name <name>", "Display name").option("--avatar-url <url>", "Avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
694
+ async (options) => {
695
+ try {
696
+ const client = await getClient(options.profile);
697
+ const agent = await client.createAgent({
698
+ name: options.name,
699
+ username: options.username,
700
+ displayName: options.displayName,
701
+ avatarUrl: options.avatarUrl
702
+ });
703
+ output(agent, { json: options.json });
704
+ } catch (error) {
705
+ outputError(error instanceof Error ? error.message : String(error), {
706
+ json: options.json
707
+ });
708
+ process.exit(1);
709
+ }
710
+ }
711
+ );
712
+ buddies.command("update").description("Update a buddy").argument("<buddy-id>", "Buddy ID").option("--name <name>", "New name").option("--display-name <name>", "New display name").option("--avatar-url <url>", "New avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
713
+ async (buddyId, options) => {
714
+ try {
715
+ const client = await getClient(options.profile);
716
+ const agent = await client.updateAgent(buddyId, {
717
+ name: options.name,
718
+ displayName: options.displayName,
719
+ avatarUrl: options.avatarUrl
720
+ });
721
+ output(agent, { json: options.json });
722
+ } catch (error) {
723
+ outputError(error instanceof Error ? error.message : String(error), {
724
+ json: options.json
725
+ });
726
+ process.exit(1);
727
+ }
728
+ }
729
+ );
730
+ buddies.command("delete").description("Delete a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
731
+ try {
732
+ const client = await getClient(options.profile);
733
+ await client.deleteAgent(buddyId);
734
+ const outputOpts = { json: options.json };
735
+ outputSuccess("Buddy deleted", outputOpts);
736
+ } catch (error) {
737
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
738
+ process.exit(1);
739
+ }
740
+ });
741
+ buddies.command("start").description("Start a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
742
+ try {
743
+ const client = await getClient(options.profile);
744
+ await client.startAgent(buddyId);
745
+ const outputOpts = { json: options.json };
746
+ outputSuccess("Buddy started", outputOpts);
747
+ } catch (error) {
748
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
749
+ process.exit(1);
750
+ }
751
+ });
752
+ buddies.command("stop").description("Stop a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
753
+ try {
754
+ const client = await getClient(options.profile);
755
+ await client.stopAgent(buddyId);
756
+ const outputOpts = { json: options.json };
757
+ outputSuccess("Buddy stopped", outputOpts);
758
+ } catch (error) {
759
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
760
+ process.exit(1);
761
+ }
762
+ });
763
+ buddies.command("token").description("Generate a new token for a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
764
+ try {
765
+ const client = await getClient(options.profile);
766
+ const result = await client.generateAgentToken(buddyId);
767
+ if (options.json) {
768
+ output(result, { json: true });
769
+ } else {
770
+ console.log(result.token);
771
+ }
772
+ } catch (error) {
773
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
774
+ process.exit(1);
775
+ }
776
+ });
777
+ buddies.command("config").description("Get buddy remote config").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
778
+ try {
779
+ const client = await getClient(options.profile);
780
+ const config = await client.getAgentConfig(buddyId);
781
+ output(config, { json: options.json });
782
+ } catch (error) {
783
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
784
+ process.exit(1);
785
+ }
786
+ });
787
+ return buddies;
788
+ }
789
+
544
790
  // src/commands/channels.ts
545
791
  import { Command as Command5 } from "commander";
546
792
  function createChannelsCommand() {
547
793
  const channels = new Command5("channels").description("Channel commands");
548
- channels.command("list").description("List channels in a server").requiredOption("--server-id <id>", "Server ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
794
+ channels.command("list").description("List channels in a server").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
549
795
  try {
550
796
  const client = await getClient(options.profile);
551
- const channels2 = await client.getServerChannels(options.serverId);
797
+ const channels2 = await client.getServerChannels(resolveServerFlag(options.server));
552
798
  output(channels2, { json: options.json });
553
799
  } catch (error) {
554
800
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
@@ -565,11 +811,11 @@ function createChannelsCommand() {
565
811
  process.exit(1);
566
812
  }
567
813
  });
568
- channels.command("create").description("Create a channel").requiredOption("--server-id <id>", "Server ID").requiredOption("--name <name>", "Channel name").option("--type <type>", "Channel type", "text").option("--description <desc>", "Channel description").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
814
+ channels.command("create").description("Create a channel").requiredOption("--server <server>", "Server ID or slug").requiredOption("--name <name>", "Channel name").option("--type <type>", "Channel type", "text").option("--description <desc>", "Channel description").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
569
815
  async (options) => {
570
816
  try {
571
817
  const client = await getClient(options.profile);
572
- const channel = await client.createChannel(options.serverId, {
818
+ const channel = await client.createChannel(resolveServerFlag(options.server), {
573
819
  name: options.name,
574
820
  type: options.type,
575
821
  description: options.description
@@ -840,10 +1086,10 @@ function createCommerceCommand() {
840
1086
  })
841
1087
  );
842
1088
  const entitlements = commerce.command("entitlements").description("Purchase entitlement commands");
843
- entitlements.command("list").description("List my purchase entitlements").option("--server-id <id>", "Limit to a server shop entitlement list").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1089
+ entitlements.command("list").description("List my purchase entitlements").option("--server <server>", "Limit to a server shop entitlement list").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
844
1090
  (options) => runCommand(options, async () => {
845
1091
  const client = await getClient(options.profile);
846
- return options.serverId ? client.getEntitlements(options.serverId) : client.getAllEntitlements();
1092
+ return options.server ? client.getEntitlements(resolveServerFlag(options.server)) : client.getAllEntitlements();
847
1093
  })
848
1094
  );
849
1095
  entitlements.command("get").description("Get purchase delivery detail").argument("<entitlement-id>", "Entitlement ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
@@ -1242,10 +1488,213 @@ function createFriendsCommand() {
1242
1488
  return friends;
1243
1489
  }
1244
1490
 
1245
- // src/commands/invites.ts
1491
+ // src/commands/inbox.ts
1246
1492
  import { Command as Command12 } from "commander";
1493
+ var TASK_STATUSES = /* @__PURE__ */ new Set([
1494
+ "queued",
1495
+ "claimed",
1496
+ "running",
1497
+ "completed",
1498
+ "failed",
1499
+ "canceled",
1500
+ "transferred"
1501
+ ]);
1502
+ function parseTaskStatus(value) {
1503
+ if (!TASK_STATUSES.has(value)) {
1504
+ throw new Error(`Invalid task status: ${value}`);
1505
+ }
1506
+ return value;
1507
+ }
1508
+ function parseJsonOption(value, label) {
1509
+ if (!value) return void 0;
1510
+ try {
1511
+ return JSON.parse(value);
1512
+ } catch {
1513
+ throw new Error(`Invalid JSON for ${label}`);
1514
+ }
1515
+ }
1516
+ function parseTaskSourceOption(value) {
1517
+ const source = parseJsonOption(value, "source-json");
1518
+ if (!source) return void 0;
1519
+ if (typeof source.kind !== "string" || !source.kind.trim()) {
1520
+ throw new Error("Invalid source-json: kind is required");
1521
+ }
1522
+ return source;
1523
+ }
1524
+ function createInboxCommand() {
1525
+ const inbox = new Command12("inbox").description("Buddy Inbox task-card commands");
1526
+ inbox.command("list").description("List Buddy Inbox entries").option("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1527
+ try {
1528
+ const client = await getClient(options.profile);
1529
+ const result = options.server ? await client.listServerBuddyInboxes(resolveServerFlag(options.server)) : await client.listBuddyInboxes();
1530
+ output(result, { json: options.json });
1531
+ } catch (error) {
1532
+ outputError(error instanceof Error ? error.message : String(error), {
1533
+ json: options.json
1534
+ });
1535
+ process.exit(1);
1536
+ }
1537
+ });
1538
+ inbox.command("ensure").description("Create or repair a Buddy Inbox channel").requiredOption("--server <server>", "Server ID or slug").requiredOption("--agent <agent-id>", "Buddy agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1539
+ async (options) => {
1540
+ try {
1541
+ const client = await getClient(options.profile);
1542
+ const result = await client.ensureBuddyInbox(
1543
+ resolveServerFlag(options.server),
1544
+ options.agent
1545
+ );
1546
+ output(result, { json: options.json });
1547
+ } catch (error) {
1548
+ outputError(error instanceof Error ? error.message : String(error), {
1549
+ json: options.json
1550
+ });
1551
+ process.exit(1);
1552
+ }
1553
+ }
1554
+ );
1555
+ inbox.command("enqueue").description("Enqueue a new task card into a Buddy Inbox").requiredOption("--title <title>", "Task title").option("--body <text>", "Task body").option("--priority <priority>", "low|normal|high|urgent").option("--idempotency-key <key>", "Idempotency key").option("--server <server>", "Server ID or slug; required with --agent").option("--agent <agent-id>", "Buddy agent ID").option("--channel <channel-id>", "Buddy Inbox channel ID").option("--source-json <json>", "Task source JSON").option("--data-json <json>", "Task data JSON").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1556
+ async (options) => {
1557
+ try {
1558
+ const client = await getClient(options.profile);
1559
+ const task = {
1560
+ title: options.title
1561
+ };
1562
+ if (options.body) task.body = options.body;
1563
+ if (options.priority) task.priority = options.priority;
1564
+ if (options.idempotencyKey) task.idempotencyKey = options.idempotencyKey;
1565
+ const source = parseTaskSourceOption(options.sourceJson);
1566
+ if (source) task.source = source;
1567
+ const data = parseJsonOption(options.dataJson, "data-json");
1568
+ if (data) task.data = data;
1569
+ const result = options.channel ? await client.enqueueInboxTask(options.channel, task) : options.server && options.agent ? await client.enqueueInboxTaskForAgent(
1570
+ resolveServerFlag(options.server),
1571
+ options.agent,
1572
+ task
1573
+ ) : null;
1574
+ if (!result) throw new Error("Provide either --channel or both --server and --agent");
1575
+ output(result, { json: options.json });
1576
+ } catch (error) {
1577
+ outputError(error instanceof Error ? error.message : String(error), {
1578
+ json: options.json
1579
+ });
1580
+ process.exit(1);
1581
+ }
1582
+ }
1583
+ );
1584
+ inbox.command("policy").description("Read or update a Buddy Inbox admission policy").requiredOption("--server <server>", "Server ID or slug").requiredOption("--agent <agent-id>", "Buddy agent ID").option("--set-json <json>", "Admission policy JSON to write").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1585
+ async (options) => {
1586
+ try {
1587
+ const client = await getClient(options.profile);
1588
+ const server = resolveServerFlag(options.server);
1589
+ const policy = options.setJson ? parseJsonOption(options.setJson, "set-json") : null;
1590
+ const result = options.setJson ? await client.updateBuddyInboxAdmissionPolicy(server, options.agent, policy) : await client.getBuddyInboxAdmissionPolicy(server, options.agent);
1591
+ output(result, { json: options.json });
1592
+ } catch (error) {
1593
+ outputError(error instanceof Error ? error.message : String(error), {
1594
+ json: options.json
1595
+ });
1596
+ process.exit(1);
1597
+ }
1598
+ }
1599
+ );
1600
+ inbox.command("claim").description("Claim an Inbox task card by message/card id").argument("<message-id>", "Message ID containing the task card").argument("<card-id>", "Task card ID").option("--ttl-seconds <n>", "Claim TTL in seconds", "3600").option("--note <text>", "Progress note").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1601
+ async (messageId, cardId, options) => {
1602
+ try {
1603
+ const client = await getClient(options.profile);
1604
+ const message = await client.claimTaskCard(messageId, cardId, {
1605
+ ttlSeconds: parsePositiveInt(options.ttlSeconds ?? "3600", "ttl-seconds"),
1606
+ note: options.note
1607
+ });
1608
+ output(message, { json: options.json });
1609
+ } catch (error) {
1610
+ outputError(error instanceof Error ? error.message : String(error), {
1611
+ json: options.json
1612
+ });
1613
+ process.exit(1);
1614
+ }
1615
+ }
1616
+ );
1617
+ inbox.command("update").description("Update an Inbox task card status").argument("<message-id>", "Message ID containing the task card").argument("<card-id>", "Task card ID").requiredOption(
1618
+ "--status <status>",
1619
+ "queued|claimed|running|completed|failed|canceled|transferred"
1620
+ ).option("--note <text>", "Progress note").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1621
+ async (messageId, cardId, options) => {
1622
+ try {
1623
+ const client = await getClient(options.profile);
1624
+ const message = await client.updateTaskCard(messageId, cardId, {
1625
+ status: parseTaskStatus(options.status),
1626
+ note: options.note
1627
+ });
1628
+ output(message, { json: options.json });
1629
+ } catch (error) {
1630
+ outputError(error instanceof Error ? error.message : String(error), {
1631
+ json: options.json
1632
+ });
1633
+ process.exit(1);
1634
+ }
1635
+ }
1636
+ );
1637
+ inbox.command("retry").description("Copy a failed task card into a new queued task and mark the original transferred").argument("<message-id>", "Message ID containing the task card").argument("<card-id>", "Task card ID").option("--note <text>", "Transfer note").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1638
+ async (messageId, cardId, options) => {
1639
+ try {
1640
+ const client = await getClient(options.profile);
1641
+ const result = await client.retryTaskCard(messageId, cardId, { note: options.note });
1642
+ output(result, { json: options.json });
1643
+ } catch (error) {
1644
+ outputError(error instanceof Error ? error.message : String(error), {
1645
+ json: options.json
1646
+ });
1647
+ process.exit(1);
1648
+ }
1649
+ }
1650
+ );
1651
+ inbox.command("claim-next").description("Claim the next available task in a Buddy Inbox").requiredOption("--server <server>", "Server ID or slug").requiredOption("--agent <agent-id>", "Buddy agent ID").option("--ttl-seconds <n>", "Claim TTL in seconds", "3600").option("--note <text>", "Progress note").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1652
+ async (options) => {
1653
+ try {
1654
+ const client = await getClient(options.profile);
1655
+ const result = await client.claimNextInboxTask(
1656
+ resolveServerFlag(options.server),
1657
+ options.agent,
1658
+ {
1659
+ ttlSeconds: parsePositiveInt(options.ttlSeconds ?? "3600", "ttl-seconds"),
1660
+ note: options.note
1661
+ }
1662
+ );
1663
+ output(result, { json: options.json });
1664
+ } catch (error) {
1665
+ outputError(error instanceof Error ? error.message : String(error), {
1666
+ json: options.json
1667
+ });
1668
+ process.exit(1);
1669
+ }
1670
+ }
1671
+ );
1672
+ inbox.command("promote").description("Promote a chat message into a Buddy Inbox task").argument("<message-id>", "Source message ID").requiredOption("--server <server>", "Server ID or slug").requiredOption("--agent <agent-id>", "Buddy agent ID").option("--title <title>", "Task title override").option("--priority <priority>", "low|normal|high|urgent").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1673
+ async (messageId, options) => {
1674
+ try {
1675
+ const client = await getClient(options.profile);
1676
+ const message = await client.promoteMessageToInboxTask(messageId, {
1677
+ serverId: resolveServerFlag(options.server),
1678
+ agentId: options.agent,
1679
+ title: options.title,
1680
+ priority: options.priority
1681
+ });
1682
+ output(message, { json: options.json });
1683
+ } catch (error) {
1684
+ outputError(error instanceof Error ? error.message : String(error), {
1685
+ json: options.json
1686
+ });
1687
+ process.exit(1);
1688
+ }
1689
+ }
1690
+ );
1691
+ return inbox;
1692
+ }
1693
+
1694
+ // src/commands/invites.ts
1695
+ import { Command as Command13 } from "commander";
1247
1696
  function createInvitesCommand() {
1248
- const invites = new Command12("invites").description("Invite code management commands");
1697
+ const invites = new Command13("invites").description("Invite code management commands");
1249
1698
  invites.command("list").description("List your invite codes").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1250
1699
  try {
1251
1700
  const client = await getClient(options.profile);
@@ -1296,15 +1745,15 @@ function createInvitesCommand() {
1296
1745
  }
1297
1746
 
1298
1747
  // src/commands/listen.ts
1299
- import { Command as Command13 } from "commander";
1748
+ import { Command as Command14 } from "commander";
1300
1749
  function createListenCommand() {
1301
- const listen = new Command13("listen").description("Listen to real-time events");
1750
+ const listen = new Command14("listen").description("Listen to real-time events");
1302
1751
  listen.command("channel").description("Listen to events in a channel").argument("<channel-id>", "Channel ID").option("--mode <mode>", "Listen mode: stream or poll", "stream").option("--timeout <seconds>", "Timeout in seconds (stream mode)", "60").option("--count <n>", "Stop after N events (stream mode)").option("--since <duration>", "Poll events since duration (e.g., 5m, 1h)", "5m").option("--last <n>", "Poll last N messages", "50").option("--event-type <type>", "Filter by event type (comma-separated)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON (one per line)").action(
1303
1752
  async (channelId, options) => {
1304
1753
  try {
1305
1754
  const eventTypes = options.eventType?.split(",").map((t) => t.trim());
1306
1755
  if (options.mode === "poll") {
1307
- const { getClient: getClient2 } = await import("./client-ZIUDIQPZ.js");
1756
+ const { getClient: getClient2 } = await import("./client-VR35GYUZ.js");
1308
1757
  const client = await getClient2(options.profile);
1309
1758
  const limit = parseInt(options.last ?? "50", 10);
1310
1759
  const result = await client.getMessages(channelId, limit);
@@ -1418,9 +1867,9 @@ function createListenCommand() {
1418
1867
  }
1419
1868
 
1420
1869
  // src/commands/marketplace.ts
1421
- import { Command as Command14 } from "commander";
1870
+ import { Command as Command15 } from "commander";
1422
1871
  function createMarketplaceCommand() {
1423
- const marketplace = new Command14("marketplace").description("Marketplace commands");
1872
+ const marketplace = new Command15("marketplace").description("Marketplace commands");
1424
1873
  const listings = marketplace.command("listings").description("Listing commands");
1425
1874
  listings.command("list").description("Browse marketplace listings").option("--search <text>", "Search query").option("--tags <tags>", "Comma-separated tags").option("--min-price <n>", "Minimum price per hour").option("--max-price <n>", "Maximum price per hour").option("--limit <n>", "Number of results", "20").option("--offset <n>", "Pagination offset", "0").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1426
1875
  async (options) => {
@@ -1565,9 +2014,9 @@ function createMarketplaceCommand() {
1565
2014
 
1566
2015
  // src/commands/media.ts
1567
2016
  import { readFileSync } from "fs";
1568
- import { Command as Command15 } from "commander";
2017
+ import { Command as Command16 } from "commander";
1569
2018
  function createMediaCommand() {
1570
- const media = new Command15("media").description("Media management commands");
2019
+ const media = new Command16("media").description("Media management commands");
1571
2020
  media.command("upload").description("Upload a file").requiredOption("--file <path>", "File path to upload").option("--message-id <id>", "Associate with message").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1572
2021
  async (options) => {
1573
2022
  try {
@@ -1633,9 +2082,9 @@ function createMediaCommand() {
1633
2082
  }
1634
2083
 
1635
2084
  // src/commands/notifications.ts
1636
- import { Command as Command16 } from "commander";
2085
+ import { Command as Command17 } from "commander";
1637
2086
  function createNotificationsCommand() {
1638
- const notifications = new Command16("notifications").description("Notification commands");
2087
+ const notifications = new Command17("notifications").description("Notification commands");
1639
2088
  notifications.command("list").description("List notifications").option("--unread-only", "Show only unread notifications").option("--limit <n>", "Number of notifications", "20").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1640
2089
  async (options) => {
1641
2090
  try {
@@ -1714,7 +2163,7 @@ function splitIds(value) {
1714
2163
  }
1715
2164
 
1716
2165
  // src/commands/oauth.ts
1717
- import { Command as Command17 } from "commander";
2166
+ import { Command as Command18 } from "commander";
1718
2167
  function resolveOAuthAccessToken(options) {
1719
2168
  const token = options.accessToken || process.env.SHADOWOB_OAUTH_TOKEN;
1720
2169
  if (!token) {
@@ -1731,7 +2180,7 @@ function parseMetadata2(value) {
1731
2180
  return parsed;
1732
2181
  }
1733
2182
  function createOAuthCommand() {
1734
- const oauth = new Command17("oauth").description("OAuth management commands");
2183
+ const oauth = new Command18("oauth").description("OAuth management commands");
1735
2184
  oauth.command("list").description("List OAuth apps").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1736
2185
  try {
1737
2186
  const client = await getClient(options.profile);
@@ -1864,9 +2313,9 @@ function createOAuthCommand() {
1864
2313
  }
1865
2314
 
1866
2315
  // src/commands/ping.ts
1867
- import { Command as Command18 } from "commander";
2316
+ import { Command as Command19 } from "commander";
1868
2317
  function createPingCommand() {
1869
- const ping = new Command18("ping").description("Test connection to Shadow server");
2318
+ const ping = new Command19("ping").description("Test connection to Shadow server");
1870
2319
  ping.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1871
2320
  const startTime = Date.now();
1872
2321
  const outputOpts = { json: options.json };
@@ -1915,9 +2364,9 @@ function createPingCommand() {
1915
2364
  }
1916
2365
 
1917
2366
  // src/commands/profile-comments.ts
1918
- import { Command as Command19 } from "commander";
2367
+ import { Command as Command20 } from "commander";
1919
2368
  function createProfileCommentsCommand() {
1920
- const comments = new Command19("profile-comments").description(
2369
+ const comments = new Command20("profile-comments").description(
1921
2370
  "Profile comment management commands"
1922
2371
  );
1923
2372
  comments.command("get").description("Get comments for a user profile").argument("<user-id>", "Profile user ID").option("--limit <n>", "Number of results", "20").option("--offset <n>", "Offset for pagination", "0").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (userId, options) => {
@@ -1967,17 +2416,17 @@ function createProfileCommentsCommand() {
1967
2416
  }
1968
2417
 
1969
2418
  // src/commands/search.ts
1970
- import { Command as Command20 } from "commander";
2419
+ import { Command as Command21 } from "commander";
1971
2420
  function createSearchCommand() {
1972
- const search = new Command20("search").description("Search commands");
1973
- search.command("messages").description("Search messages").requiredOption("--query <text>", "Search query").option("--server-id <id>", "Limit to server").option("--channel-id <id>", "Limit to channel").option("--limit <n>", "Number of results (1-100)", "20").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
2421
+ const search = new Command21("search").description("Search commands");
2422
+ search.command("messages").description("Search messages").requiredOption("--query <text>", "Search query").option("--server <server>", "Limit to server").option("--channel-id <id>", "Limit to channel").option("--limit <n>", "Number of results (1-100)", "20").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1974
2423
  async (options) => {
1975
2424
  try {
1976
2425
  const client = await getClient(options.profile);
1977
2426
  const limit = Math.min(Math.max(parseInt(options.limit ?? "20", 10), 1), 100);
1978
2427
  const results = await client.searchMessages({
1979
2428
  q: options.query,
1980
- serverId: options.serverId,
2429
+ serverId: options.server ? resolveServerFlag(options.server) : void 0,
1981
2430
  channelId: options.channelId,
1982
2431
  limit
1983
2432
  });
@@ -1994,14 +2443,17 @@ function createSearchCommand() {
1994
2443
  }
1995
2444
 
1996
2445
  // src/commands/servers.ts
1997
- import { Command as Command21 } from "commander";
2446
+ import { Command as Command22 } from "commander";
1998
2447
  function createServersCommand() {
1999
- const servers = new Command21("servers").description("Server management commands");
2448
+ const servers = new Command22("servers").description("Server management commands");
2000
2449
  servers.command("list").description("List all servers you have joined").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
2001
2450
  try {
2002
2451
  const client = await getClient(options.profile);
2003
2452
  const servers2 = await client.listServers();
2004
- output(servers2, { json: options.json });
2453
+ output(
2454
+ servers2.map((s) => s.server),
2455
+ { json: options.json }
2456
+ );
2005
2457
  } catch (error) {
2006
2458
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
2007
2459
  process.exit(1);
@@ -2070,7 +2522,17 @@ function createServersCommand() {
2070
2522
  try {
2071
2523
  const client = await getClient(options.profile);
2072
2524
  const members = await client.getMembers(serverId);
2073
- output(members, { json: options.json });
2525
+ output(
2526
+ members.map(
2527
+ (m) => ({
2528
+ id: m.id,
2529
+ userId: m.userId,
2530
+ username: m.user?.username ?? m.nickname ?? m.uid ?? "",
2531
+ role: m.role
2532
+ })
2533
+ ),
2534
+ { json: options.json }
2535
+ );
2074
2536
  } catch (error) {
2075
2537
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
2076
2538
  process.exit(1);
@@ -2090,7 +2552,7 @@ function createServersCommand() {
2090
2552
  }
2091
2553
 
2092
2554
  // src/commands/shop.ts
2093
- import { Command as Command22 } from "commander";
2555
+ import { Command as Command23 } from "commander";
2094
2556
  function parseJsonObject(value, optionName) {
2095
2557
  if (!value) return {};
2096
2558
  const parsed = JSON.parse(value);
@@ -2108,7 +2570,7 @@ function parseOptionalNumber(value, optionName) {
2108
2570
  return parsed;
2109
2571
  }
2110
2572
  function createShopCommand() {
2111
- const shop = new Command22("shop").description("Shop commands");
2573
+ const shop = new Command23("shop").description("Shop commands");
2112
2574
  shop.command("get").description("Get shop info").argument("<server-id>", "Server ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
2113
2575
  try {
2114
2576
  const client = await getClient(options.profile);
@@ -2208,17 +2670,6 @@ function createShopCommand() {
2208
2670
  }
2209
2671
  }
2210
2672
  );
2211
- products.command("context").description("Get buyer-facing product context").argument("<product-id>", "Product ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (productId, options) => {
2212
- try {
2213
- const client = await getClient(options.profile);
2214
- output(await client.getCommerceProductContext(productId), { json: options.json });
2215
- } catch (error) {
2216
- outputError(error instanceof Error ? error.message : String(error), {
2217
- json: options.json
2218
- });
2219
- process.exit(1);
2220
- }
2221
- });
2222
2673
  products.command("create-by-shop").description("Create a product by shop ID using a JSON payload").argument("<shop-id>", "Shop ID").requiredOption("--data <json>", "Product JSON payload").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (shopId, options) => {
2223
2674
  try {
2224
2675
  const client = await getClient(options.profile);
@@ -2461,9 +2912,9 @@ function createShopCommand() {
2461
2912
  }
2462
2913
 
2463
2914
  // src/commands/status.ts
2464
- import { Command as Command23 } from "commander";
2915
+ import { Command as Command24 } from "commander";
2465
2916
  function createStatusCommand() {
2466
- const status = new Command23("status").description("Show detailed status information");
2917
+ const status = new Command24("status").description("Show detailed status information");
2467
2918
  status.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
2468
2919
  const outputOpts = { json: options.json };
2469
2920
  try {
@@ -2541,9 +2992,9 @@ function createStatusCommand() {
2541
2992
  }
2542
2993
 
2543
2994
  // src/commands/threads.ts
2544
- import { Command as Command24 } from "commander";
2995
+ import { Command as Command25 } from "commander";
2545
2996
  function createThreadsCommand() {
2546
- const threads = new Command24("threads").description("Thread commands");
2997
+ const threads = new Command25("threads").description("Thread commands");
2547
2998
  threads.command("list").description("List threads in a channel").argument("<channel-id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (channelId, options) => {
2548
2999
  try {
2549
3000
  const client = await getClient(options.profile);
@@ -2626,7 +3077,7 @@ function createThreadsCommand() {
2626
3077
 
2627
3078
  // src/commands/voice.ts
2628
3079
  import { join as join2 } from "path";
2629
- import { Command as Command25 } from "commander";
3080
+ import { Command as Command26 } from "commander";
2630
3081
 
2631
3082
  // src/utils/voice-media-bridge.ts
2632
3083
  import { execFileSync as execFileSync2, spawn } from "child_process";
@@ -3761,7 +4212,7 @@ function resolveProfileOption(options, command) {
3761
4212
  return options.profile ?? command.optsWithGlobals().profile;
3762
4213
  }
3763
4214
  function createVoiceCommand() {
3764
- const voice = new Command25("voice").description("Voice channel commands");
4215
+ const voice = new Command26("voice").description("Voice channel commands");
3765
4216
  voice.command("join").description("Join a voice channel and print Agora connection info").argument("<channel-id>", "Voice channel ID").option("--muted", "Join muted").option("--deafened", "Join deafened").option("--watch", "Keep the process attached and print voice events").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
3766
4217
  async (channelId, options, command) => {
3767
4218
  try {
@@ -3901,7 +4352,7 @@ function createVoiceCommand() {
3901
4352
  }
3902
4353
  }
3903
4354
  );
3904
- const browser = new Command25("browser").description("Voice bridge browser runtime commands");
4355
+ const browser = new Command26("browser").description("Voice bridge browser runtime commands");
3905
4356
  browser.command("install").description("Install an isolated Chromium runtime for voice bridge tests").option("--json", "Output as JSON").action(async (options) => {
3906
4357
  try {
3907
4358
  const executable = await installVoiceTestBrowser({ json: options.json });
@@ -3932,9 +4383,9 @@ function createVoiceCommand() {
3932
4383
  }
3933
4384
 
3934
4385
  // src/commands/voice-enhance.ts
3935
- import { Command as Command26 } from "commander";
4386
+ import { Command as Command27 } from "commander";
3936
4387
  function createVoiceEnhanceCommand() {
3937
- const voice = new Command26("voice-enhance").description("Voice enhancement commands");
4388
+ const voice = new Command27("voice-enhance").description("Voice enhancement commands");
3938
4389
  voice.command("enhance").description("Enhance a voice transcript").requiredOption("--transcript <text>", "Transcript text to enhance").option("--language <lang>", "Language code (e.g. zh-CN, en-US)").option("--no-self-correction", "Disable self-correction").option("--no-list-formatting", "Disable list formatting").option("--no-filler-removal", "Disable filler word removal").option("--tone-adjustment", "Enable tone adjustment").option("--target-tone <tone>", "Target tone (formal, casual, professional)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
3939
4390
  try {
3940
4391
  const client = await getClient(options.profile);
@@ -3974,9 +4425,9 @@ function createVoiceEnhanceCommand() {
3974
4425
 
3975
4426
  // src/commands/workspace.ts
3976
4427
  import { readFile as readFile3 } from "fs/promises";
3977
- import { Command as Command27 } from "commander";
4428
+ import { Command as Command28 } from "commander";
3978
4429
  function createWorkspaceCommand() {
3979
- const workspace = new Command27("workspace").description("Workspace file management commands");
4430
+ const workspace = new Command28("workspace").description("Workspace file management commands");
3980
4431
  workspace.command("get").description("Get workspace info").argument("<server-id>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
3981
4432
  try {
3982
4433
  const client = await getClient(options.profile);
@@ -4158,7 +4609,7 @@ function createWorkspaceCommand() {
4158
4609
  }
4159
4610
 
4160
4611
  // src/index.ts
4161
- var program = new Command28();
4612
+ var program = new Command29();
4162
4613
  program.name("shadowob").description("Shadow CLI \u2014 command-line interface for Shadow servers").version("0.1.0").configureHelp({
4163
4614
  sortSubcommands: true
4164
4615
  });
@@ -4168,7 +4619,8 @@ program.addCommand(createAppCommand());
4168
4619
  program.addCommand(createServersCommand());
4169
4620
  program.addCommand(createChannelsCommand());
4170
4621
  program.addCommand(createThreadsCommand());
4171
- program.addCommand(createAgentsCommand());
4622
+ program.addCommand(createBuddiesCommand());
4623
+ program.addCommand(createInboxCommand());
4172
4624
  program.addCommand(createListenCommand());
4173
4625
  program.addCommand(createDirectMessagesCommand());
4174
4626
  program.addCommand(createWorkspaceCommand());