@shadowob/cli 1.1.7 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +409 -37
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-S6XCO6ZW.js";
10
10
 
11
11
  // src/index.ts
12
- import { Command as Command28 } from "commander";
12
+ import { Command as Command29 } from "commander";
13
13
 
14
14
  // src/commands/api-tokens.ts
15
15
  import { Command } from "commander";
@@ -183,6 +183,115 @@ function commandHandlerError(error, json) {
183
183
  outputError(error instanceof Error ? error.message : String(error), { json });
184
184
  process.exit(1);
185
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
+ }
186
295
  function createAppCommand() {
187
296
  const app = new Command2("app").description("Server App integration commands");
188
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) => {
@@ -336,21 +445,80 @@ function createAppCommand() {
336
445
  }
337
446
  }
338
447
  );
339
- 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("--channel-id <id>", "Current Shadow channel ID for approval prompts and app context").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(
340
472
  async (appKey, commandName, options) => {
341
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");
342
500
  const client = await getClient(options.profile);
343
501
  const input = options.inputFile ? await readJsonFile(options.inputFile) : parseJsonInput(options.jsonInput);
344
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;
345
511
  const result = options.file ? await client.callServerAppCommandMultipart(server, appKey, commandName, {
346
512
  input,
347
513
  channelId: options.channelId,
514
+ task,
348
515
  file: new Blob([await readFile(options.file)]),
349
516
  filename: basename(options.file),
350
517
  field: options.field
351
518
  }) : await client.callServerAppCommand(server, appKey, commandName, {
352
519
  input,
353
- channelId: options.channelId
520
+ channelId: options.channelId,
521
+ task
354
522
  });
355
523
  if (options.output && result && typeof result === "object" && "dataBase64" in result && typeof result.dataBase64 === "string") {
356
524
  await writeFile(
@@ -1320,10 +1488,213 @@ function createFriendsCommand() {
1320
1488
  return friends;
1321
1489
  }
1322
1490
 
1323
- // src/commands/invites.ts
1491
+ // src/commands/inbox.ts
1324
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";
1325
1696
  function createInvitesCommand() {
1326
- const invites = new Command12("invites").description("Invite code management commands");
1697
+ const invites = new Command13("invites").description("Invite code management commands");
1327
1698
  invites.command("list").description("List your invite codes").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1328
1699
  try {
1329
1700
  const client = await getClient(options.profile);
@@ -1374,9 +1745,9 @@ function createInvitesCommand() {
1374
1745
  }
1375
1746
 
1376
1747
  // src/commands/listen.ts
1377
- import { Command as Command13 } from "commander";
1748
+ import { Command as Command14 } from "commander";
1378
1749
  function createListenCommand() {
1379
- const listen = new Command13("listen").description("Listen to real-time events");
1750
+ const listen = new Command14("listen").description("Listen to real-time events");
1380
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(
1381
1752
  async (channelId, options) => {
1382
1753
  try {
@@ -1496,9 +1867,9 @@ function createListenCommand() {
1496
1867
  }
1497
1868
 
1498
1869
  // src/commands/marketplace.ts
1499
- import { Command as Command14 } from "commander";
1870
+ import { Command as Command15 } from "commander";
1500
1871
  function createMarketplaceCommand() {
1501
- const marketplace = new Command14("marketplace").description("Marketplace commands");
1872
+ const marketplace = new Command15("marketplace").description("Marketplace commands");
1502
1873
  const listings = marketplace.command("listings").description("Listing commands");
1503
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(
1504
1875
  async (options) => {
@@ -1643,9 +2014,9 @@ function createMarketplaceCommand() {
1643
2014
 
1644
2015
  // src/commands/media.ts
1645
2016
  import { readFileSync } from "fs";
1646
- import { Command as Command15 } from "commander";
2017
+ import { Command as Command16 } from "commander";
1647
2018
  function createMediaCommand() {
1648
- const media = new Command15("media").description("Media management commands");
2019
+ const media = new Command16("media").description("Media management commands");
1649
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(
1650
2021
  async (options) => {
1651
2022
  try {
@@ -1711,9 +2082,9 @@ function createMediaCommand() {
1711
2082
  }
1712
2083
 
1713
2084
  // src/commands/notifications.ts
1714
- import { Command as Command16 } from "commander";
2085
+ import { Command as Command17 } from "commander";
1715
2086
  function createNotificationsCommand() {
1716
- const notifications = new Command16("notifications").description("Notification commands");
2087
+ const notifications = new Command17("notifications").description("Notification commands");
1717
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(
1718
2089
  async (options) => {
1719
2090
  try {
@@ -1792,7 +2163,7 @@ function splitIds(value) {
1792
2163
  }
1793
2164
 
1794
2165
  // src/commands/oauth.ts
1795
- import { Command as Command17 } from "commander";
2166
+ import { Command as Command18 } from "commander";
1796
2167
  function resolveOAuthAccessToken(options) {
1797
2168
  const token = options.accessToken || process.env.SHADOWOB_OAUTH_TOKEN;
1798
2169
  if (!token) {
@@ -1809,7 +2180,7 @@ function parseMetadata2(value) {
1809
2180
  return parsed;
1810
2181
  }
1811
2182
  function createOAuthCommand() {
1812
- const oauth = new Command17("oauth").description("OAuth management commands");
2183
+ const oauth = new Command18("oauth").description("OAuth management commands");
1813
2184
  oauth.command("list").description("List OAuth apps").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1814
2185
  try {
1815
2186
  const client = await getClient(options.profile);
@@ -1942,9 +2313,9 @@ function createOAuthCommand() {
1942
2313
  }
1943
2314
 
1944
2315
  // src/commands/ping.ts
1945
- import { Command as Command18 } from "commander";
2316
+ import { Command as Command19 } from "commander";
1946
2317
  function createPingCommand() {
1947
- const ping = new Command18("ping").description("Test connection to Shadow server");
2318
+ const ping = new Command19("ping").description("Test connection to Shadow server");
1948
2319
  ping.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1949
2320
  const startTime = Date.now();
1950
2321
  const outputOpts = { json: options.json };
@@ -1993,9 +2364,9 @@ function createPingCommand() {
1993
2364
  }
1994
2365
 
1995
2366
  // src/commands/profile-comments.ts
1996
- import { Command as Command19 } from "commander";
2367
+ import { Command as Command20 } from "commander";
1997
2368
  function createProfileCommentsCommand() {
1998
- const comments = new Command19("profile-comments").description(
2369
+ const comments = new Command20("profile-comments").description(
1999
2370
  "Profile comment management commands"
2000
2371
  );
2001
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) => {
@@ -2045,9 +2416,9 @@ function createProfileCommentsCommand() {
2045
2416
  }
2046
2417
 
2047
2418
  // src/commands/search.ts
2048
- import { Command as Command20 } from "commander";
2419
+ import { Command as Command21 } from "commander";
2049
2420
  function createSearchCommand() {
2050
- const search = new Command20("search").description("Search commands");
2421
+ const search = new Command21("search").description("Search commands");
2051
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(
2052
2423
  async (options) => {
2053
2424
  try {
@@ -2072,9 +2443,9 @@ function createSearchCommand() {
2072
2443
  }
2073
2444
 
2074
2445
  // src/commands/servers.ts
2075
- import { Command as Command21 } from "commander";
2446
+ import { Command as Command22 } from "commander";
2076
2447
  function createServersCommand() {
2077
- const servers = new Command21("servers").description("Server management commands");
2448
+ const servers = new Command22("servers").description("Server management commands");
2078
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) => {
2079
2450
  try {
2080
2451
  const client = await getClient(options.profile);
@@ -2181,7 +2552,7 @@ function createServersCommand() {
2181
2552
  }
2182
2553
 
2183
2554
  // src/commands/shop.ts
2184
- import { Command as Command22 } from "commander";
2555
+ import { Command as Command23 } from "commander";
2185
2556
  function parseJsonObject(value, optionName) {
2186
2557
  if (!value) return {};
2187
2558
  const parsed = JSON.parse(value);
@@ -2199,7 +2570,7 @@ function parseOptionalNumber(value, optionName) {
2199
2570
  return parsed;
2200
2571
  }
2201
2572
  function createShopCommand() {
2202
- const shop = new Command22("shop").description("Shop commands");
2573
+ const shop = new Command23("shop").description("Shop commands");
2203
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) => {
2204
2575
  try {
2205
2576
  const client = await getClient(options.profile);
@@ -2541,9 +2912,9 @@ function createShopCommand() {
2541
2912
  }
2542
2913
 
2543
2914
  // src/commands/status.ts
2544
- import { Command as Command23 } from "commander";
2915
+ import { Command as Command24 } from "commander";
2545
2916
  function createStatusCommand() {
2546
- const status = new Command23("status").description("Show detailed status information");
2917
+ const status = new Command24("status").description("Show detailed status information");
2547
2918
  status.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
2548
2919
  const outputOpts = { json: options.json };
2549
2920
  try {
@@ -2621,9 +2992,9 @@ function createStatusCommand() {
2621
2992
  }
2622
2993
 
2623
2994
  // src/commands/threads.ts
2624
- import { Command as Command24 } from "commander";
2995
+ import { Command as Command25 } from "commander";
2625
2996
  function createThreadsCommand() {
2626
- const threads = new Command24("threads").description("Thread commands");
2997
+ const threads = new Command25("threads").description("Thread commands");
2627
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) => {
2628
2999
  try {
2629
3000
  const client = await getClient(options.profile);
@@ -2706,7 +3077,7 @@ function createThreadsCommand() {
2706
3077
 
2707
3078
  // src/commands/voice.ts
2708
3079
  import { join as join2 } from "path";
2709
- import { Command as Command25 } from "commander";
3080
+ import { Command as Command26 } from "commander";
2710
3081
 
2711
3082
  // src/utils/voice-media-bridge.ts
2712
3083
  import { execFileSync as execFileSync2, spawn } from "child_process";
@@ -3841,7 +4212,7 @@ function resolveProfileOption(options, command) {
3841
4212
  return options.profile ?? command.optsWithGlobals().profile;
3842
4213
  }
3843
4214
  function createVoiceCommand() {
3844
- const voice = new Command25("voice").description("Voice channel commands");
4215
+ const voice = new Command26("voice").description("Voice channel commands");
3845
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(
3846
4217
  async (channelId, options, command) => {
3847
4218
  try {
@@ -3981,7 +4352,7 @@ function createVoiceCommand() {
3981
4352
  }
3982
4353
  }
3983
4354
  );
3984
- const browser = new Command25("browser").description("Voice bridge browser runtime commands");
4355
+ const browser = new Command26("browser").description("Voice bridge browser runtime commands");
3985
4356
  browser.command("install").description("Install an isolated Chromium runtime for voice bridge tests").option("--json", "Output as JSON").action(async (options) => {
3986
4357
  try {
3987
4358
  const executable = await installVoiceTestBrowser({ json: options.json });
@@ -4012,9 +4383,9 @@ function createVoiceCommand() {
4012
4383
  }
4013
4384
 
4014
4385
  // src/commands/voice-enhance.ts
4015
- import { Command as Command26 } from "commander";
4386
+ import { Command as Command27 } from "commander";
4016
4387
  function createVoiceEnhanceCommand() {
4017
- const voice = new Command26("voice-enhance").description("Voice enhancement commands");
4388
+ const voice = new Command27("voice-enhance").description("Voice enhancement commands");
4018
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) => {
4019
4390
  try {
4020
4391
  const client = await getClient(options.profile);
@@ -4054,9 +4425,9 @@ function createVoiceEnhanceCommand() {
4054
4425
 
4055
4426
  // src/commands/workspace.ts
4056
4427
  import { readFile as readFile3 } from "fs/promises";
4057
- import { Command as Command27 } from "commander";
4428
+ import { Command as Command28 } from "commander";
4058
4429
  function createWorkspaceCommand() {
4059
- const workspace = new Command27("workspace").description("Workspace file management commands");
4430
+ const workspace = new Command28("workspace").description("Workspace file management commands");
4060
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) => {
4061
4432
  try {
4062
4433
  const client = await getClient(options.profile);
@@ -4238,7 +4609,7 @@ function createWorkspaceCommand() {
4238
4609
  }
4239
4610
 
4240
4611
  // src/index.ts
4241
- var program = new Command28();
4612
+ var program = new Command29();
4242
4613
  program.name("shadowob").description("Shadow CLI \u2014 command-line interface for Shadow servers").version("0.1.0").configureHelp({
4243
4614
  sortSubcommands: true
4244
4615
  });
@@ -4249,6 +4620,7 @@ program.addCommand(createServersCommand());
4249
4620
  program.addCommand(createChannelsCommand());
4250
4621
  program.addCommand(createThreadsCommand());
4251
4622
  program.addCommand(createBuddiesCommand());
4623
+ program.addCommand(createInboxCommand());
4252
4624
  program.addCommand(createListenCommand());
4253
4625
  program.addCommand(createDirectMessagesCommand());
4254
4626
  program.addCommand(createWorkspaceCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadowob/cli",
3
- "version": "1.1.7",
3
+ "version": "1.1.9",
4
4
  "description": "Shadow CLI — command-line interface for Shadow servers",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -13,7 +13,7 @@
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
15
  "chalk": "^5.4.1",
16
- "@shadowob/sdk": "1.1.7"
16
+ "@shadowob/sdk": "1.1.9"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/node": "^22.15.21",