@shadowob/cli 1.1.1 → 1.1.3-dev.261

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 +327 -214
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-T3BKMB7N.js";
7
7
 
8
8
  // src/index.ts
9
- import { Command as Command21 } from "commander";
9
+ import { Command as Command25 } from "commander";
10
10
 
11
11
  // src/commands/agents.ts
12
12
  import { Command } from "commander";
@@ -118,18 +118,21 @@ function createAgentsCommand() {
118
118
  process.exit(1);
119
119
  }
120
120
  });
121
- agents.command("create").description("Create a new agent").requiredOption("--name <name>", "Agent name").option("--display-name <name>", "Display name").option("--avatar-url <url>", "Avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
121
+ 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(
122
122
  async (options) => {
123
123
  try {
124
124
  const client = await getClient(options.profile);
125
125
  const agent = await client.createAgent({
126
126
  name: options.name,
127
+ username: options.username,
127
128
  displayName: options.displayName,
128
129
  avatarUrl: options.avatarUrl
129
130
  });
130
131
  output(agent, { json: options.json });
131
132
  } catch (error) {
132
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
133
+ outputError(error instanceof Error ? error.message : String(error), {
134
+ json: options.json
135
+ });
133
136
  process.exit(1);
134
137
  }
135
138
  }
@@ -145,7 +148,9 @@ function createAgentsCommand() {
145
148
  });
146
149
  output(agent, { json: options.json });
147
150
  } catch (error) {
148
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
151
+ outputError(error instanceof Error ? error.message : String(error), {
152
+ json: options.json
153
+ });
149
154
  process.exit(1);
150
155
  }
151
156
  }
@@ -210,94 +215,77 @@ function createAgentsCommand() {
210
215
  return agents;
211
216
  }
212
217
 
213
- // src/commands/apps.ts
218
+ // src/commands/api-tokens.ts
214
219
  import { Command as Command2 } from "commander";
215
- function createAppsCommand() {
216
- const apps = new Command2("apps").description("App management commands");
217
- apps.command("list").description("List apps in a server").argument("<server-id>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
220
+ function createApiTokensCommand() {
221
+ const tokens = new Command2("api-tokens").description("API token management commands");
222
+ tokens.command("list").description("List all API tokens").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
218
223
  try {
219
224
  const client = await getClient(options.profile);
220
- const appsData = await client.listApps(serverId);
221
- output(appsData, { json: options.json });
225
+ const tokens2 = await client.listApiTokens();
226
+ output(tokens2, { json: options.json });
222
227
  } catch (error) {
223
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
228
+ outputError(error instanceof Error ? error.message : String(error), {
229
+ json: options.json
230
+ });
224
231
  process.exit(1);
225
232
  }
226
233
  });
227
- apps.command("get").description("Get app details").argument("<server-id>", "Server ID or slug").argument("<app-id>", "App ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
228
- async (serverId, appId, options) => {
229
- try {
230
- const client = await getClient(options.profile);
231
- const app = await client.getApp(serverId, appId);
232
- output(app, { json: options.json });
233
- } catch (error) {
234
- outputError(error instanceof Error ? error.message : String(error), {
235
- json: options.json
236
- });
237
- process.exit(1);
234
+ tokens.command("create").description("Create a new API token").requiredOption("--name <name>", "Token name").option("--scope <scope>", "Token scope").option("--expires-in-days <days>", "Expiration in days").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
235
+ try {
236
+ const client = await getClient(options.profile);
237
+ const token = await client.createApiToken({
238
+ name: options.name,
239
+ scope: options.scope,
240
+ expiresInDays: options.expiresInDays ? Number(options.expiresInDays) : void 0
241
+ });
242
+ output(token, { json: options.json });
243
+ if (!options.json) {
244
+ console.log("\n\u26A0\uFE0F Save this token now \u2014 it won't be shown again!");
238
245
  }
246
+ } catch (error) {
247
+ outputError(error instanceof Error ? error.message : String(error), {
248
+ json: options.json
249
+ });
250
+ process.exit(1);
239
251
  }
240
- );
241
- apps.command("create").description("Create an app").argument("<server-id>", "Server ID or slug").requiredOption("--name <name>", "App name").requiredOption("--type <type>", "App type (url, workspace, static)").option("--url <url>", "Source URL for URL apps").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
242
- async (serverId, options) => {
243
- try {
244
- const client = await getClient(options.profile);
245
- const app = await client.createApp(serverId, {
246
- name: options.name,
247
- slug: options.name.toLowerCase().replace(/\s+/g, "-"),
248
- type: options.type,
249
- url: options.url
250
- });
251
- output(app, { json: options.json });
252
- } catch (error) {
253
- outputError(error instanceof Error ? error.message : String(error), {
254
- json: options.json
255
- });
256
- process.exit(1);
257
- }
252
+ });
253
+ tokens.command("delete").description("Delete an API token").argument("<token-id>", "Token ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (tokenId, options) => {
254
+ try {
255
+ const client = await getClient(options.profile);
256
+ await client.deleteApiToken(tokenId);
257
+ output({ ok: true }, { json: options.json });
258
+ } catch (error) {
259
+ outputError(error instanceof Error ? error.message : String(error), {
260
+ json: options.json
261
+ });
262
+ process.exit(1);
258
263
  }
259
- );
260
- apps.command("update").description("Update an app").argument("<server-id>", "Server ID or slug").argument("<app-id>", "App ID").option("--name <name>", "New name").option("--url <url>", "New source URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
261
- async (serverId, appId, options) => {
264
+ });
265
+ return tokens;
266
+ }
267
+
268
+ // src/commands/auth.ts
269
+ import { ShadowClient } from "@shadowob/sdk";
270
+ import { Command as Command3 } from "commander";
271
+ function createAuthCommand() {
272
+ const auth = new Command3("auth").description("Authentication commands");
273
+ 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(
274
+ async (options) => {
262
275
  try {
263
- const client = await getClient(options.profile);
264
- const app = await client.updateApp(serverId, appId, {
265
- name: options.name,
266
- url: options.url
267
- });
268
- output(app, { json: options.json });
269
- } catch (error) {
270
- outputError(error instanceof Error ? error.message : String(error), {
271
- json: options.json
276
+ const client = new ShadowClient(options.serverUrl, options.token);
277
+ const user = await client.getMe();
278
+ await configManager.setProfile(options.profile, {
279
+ serverUrl: options.serverUrl,
280
+ token: options.token
272
281
  });
273
- process.exit(1);
274
- }
275
- }
276
- );
277
- apps.command("delete").description("Delete an app").argument("<server-id>", "Server ID or slug").argument("<app-id>", "App ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
278
- async (serverId, appId, options) => {
279
- try {
280
- const client = await getClient(options.profile);
281
- await client.deleteApp(serverId, appId);
282
+ await configManager.switchProfile(options.profile);
282
283
  const outputOpts = { json: options.json };
283
- outputSuccess("App deleted", outputOpts);
284
- } catch (error) {
285
- outputError(error instanceof Error ? error.message : String(error), {
286
- json: options.json
287
- });
288
- process.exit(1);
289
- }
290
- }
291
- );
292
- apps.command("publish").description("Publish app from workspace").argument("<server-id>", "Server ID or slug").requiredOption("--name <name>", "App name").requiredOption("--slug <slug>", "App slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
293
- async (serverId, options) => {
294
- try {
295
- const client = await getClient(options.profile);
296
- const app = await client.publishApp(serverId, {
297
- name: options.name,
298
- slug: options.slug
299
- });
300
- output(app, { json: options.json });
284
+ if (options.json) {
285
+ output({ success: true, profile: options.profile, user }, outputOpts);
286
+ } else {
287
+ outputSuccess(`Logged in as ${user.username} (${options.profile})`, outputOpts);
288
+ }
301
289
  } catch (error) {
302
290
  outputError(error instanceof Error ? error.message : String(error), {
303
291
  json: options.json
@@ -306,34 +294,6 @@ function createAppsCommand() {
306
294
  }
307
295
  }
308
296
  );
309
- return apps;
310
- }
311
-
312
- // src/commands/auth.ts
313
- import { Command as Command3 } from "commander";
314
- import { ShadowClient } from "@shadowob/sdk";
315
- function createAuthCommand() {
316
- const auth = new Command3("auth").description("Authentication commands");
317
- 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(async (options) => {
318
- try {
319
- const client = new ShadowClient(options.serverUrl, options.token);
320
- const user = await client.getMe();
321
- await configManager.setProfile(options.profile, {
322
- serverUrl: options.serverUrl,
323
- token: options.token
324
- });
325
- await configManager.switchProfile(options.profile);
326
- const outputOpts = { json: options.json };
327
- if (options.json) {
328
- output({ success: true, profile: options.profile, user }, outputOpts);
329
- } else {
330
- outputSuccess(`Logged in as ${user.username} (${options.profile})`, outputOpts);
331
- }
332
- } catch (error) {
333
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
334
- process.exit(1);
335
- }
336
- });
337
297
  auth.command("logout").description("Remove a profile").option("--profile <name>", "Profile name (default: current)").option("--json", "Output as JSON").action(async (options) => {
338
298
  try {
339
299
  const profileName = options.profile ?? await configManager.getCurrentProfileName();
@@ -567,7 +527,7 @@ function createChannelsCommand() {
567
527
  }
568
528
  }
569
529
  );
570
- channels.command("pin").description("Pin a message").argument("<message-id>", "Message ID").option("--channel-id <id>", "Channel ID (if not in channel context)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
530
+ channels.command("pin").description("Pin a message").argument("<message-id>", "Message ID").requiredOption("--channel-id <id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
571
531
  async (messageId, options) => {
572
532
  try {
573
533
  const client = await getClient(options.profile);
@@ -582,7 +542,7 @@ function createChannelsCommand() {
582
542
  }
583
543
  }
584
544
  );
585
- channels.command("unpin").description("Unpin a message").argument("<message-id>", "Message ID").option("--channel-id <id>", "Channel ID (if not in channel context)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
545
+ channels.command("unpin").description("Unpin a message").argument("<message-id>", "Message ID").requiredOption("--channel-id <id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
586
546
  async (messageId, options) => {
587
547
  try {
588
548
  const client = await getClient(options.profile);
@@ -610,10 +570,37 @@ function createChannelsCommand() {
610
570
  return channels;
611
571
  }
612
572
 
613
- // src/commands/config.ts
573
+ // src/commands/cloud.ts
574
+ import { execFileSync, spawnSync } from "child_process";
614
575
  import { Command as Command5 } from "commander";
576
+ function createCloudCommand() {
577
+ const cloud = new Command5("cloud").description("Shadow Cloud \u2014 deploy AI agent clusters to Kubernetes (via shadowob-cloud)").allowUnknownOption(true).allowExcessArguments(true).action(async (_, cmd) => {
578
+ const args = cmd.args ?? [];
579
+ ensureCloudCliInstalled();
580
+ spawnCloudCli(args);
581
+ });
582
+ return cloud;
583
+ }
584
+ function ensureCloudCliInstalled() {
585
+ try {
586
+ execFileSync("shadowob-cloud", ["--version"], { stdio: "ignore" });
587
+ } catch {
588
+ console.error("shadowob-cloud is not installed.");
589
+ console.error("Install it with: npm install -g @shadowob/cloud");
590
+ process.exit(1);
591
+ }
592
+ }
593
+ function spawnCloudCli(args) {
594
+ const result = spawnSync("shadowob-cloud", args, { stdio: "inherit" });
595
+ if (result.status !== null) {
596
+ process.exit(result.status);
597
+ }
598
+ }
599
+
600
+ // src/commands/config.ts
601
+ import { Command as Command6 } from "commander";
615
602
  function createConfigCommand() {
616
- const config = new Command5("config").description("Configuration management commands");
603
+ const config = new Command6("config").description("Configuration management commands");
617
604
  config.command("path").description("Show configuration file path").action(() => {
618
605
  console.log(configManager.getConfigPath());
619
606
  });
@@ -683,50 +670,89 @@ function createConfigCommand() {
683
670
  return config;
684
671
  }
685
672
 
673
+ // src/commands/discover.ts
674
+ import { Command as Command7 } from "commander";
675
+ function createDiscoverCommand() {
676
+ const discover = new Command7("discover").description("Discover popular servers and channels");
677
+ discover.command("feed").description("Get the discovery feed").option("--type <type>", "Filter by type (all, servers, channels, rentals)", "all").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 (options) => {
678
+ try {
679
+ const client = await getClient(options.profile);
680
+ const result = await client.discoverFeed({
681
+ type: options.type,
682
+ limit: Number(options.limit),
683
+ offset: Number(options.offset)
684
+ });
685
+ output(result, { json: options.json });
686
+ } catch (error) {
687
+ outputError(error instanceof Error ? error.message : String(error), {
688
+ json: options.json
689
+ });
690
+ process.exit(1);
691
+ }
692
+ });
693
+ discover.command("search").description("Search the discovery index").requiredOption("--query <text>", "Search query").option("--type <type>", "Filter by type (all, servers, channels, rentals)", "all").option("--limit <n>", "Number of results", "20").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
694
+ try {
695
+ const client = await getClient(options.profile);
696
+ const result = await client.discoverSearch({
697
+ q: options.query,
698
+ type: options.type,
699
+ limit: Number(options.limit)
700
+ });
701
+ output(result, { json: options.json });
702
+ } catch (error) {
703
+ outputError(error instanceof Error ? error.message : String(error), {
704
+ json: options.json
705
+ });
706
+ process.exit(1);
707
+ }
708
+ });
709
+ return discover;
710
+ }
711
+
686
712
  // src/commands/dms.ts
687
- import { Command as Command6 } from "commander";
688
- function createDmsCommand() {
689
- const dms = new Command6("dms").description("Direct message commands");
690
- dms.command("list").description("List DM channels").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
713
+ import { Command as Command8 } from "commander";
714
+ function createDirectMessagesCommand() {
715
+ const dms = new Command8("dms").description("Direct message commands");
716
+ dms.command("list").description("List direct channels").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
691
717
  try {
692
718
  const client = await getClient(options.profile);
693
- const channels = await client.listDmChannels();
719
+ const channels = await client.listDirectChannels();
694
720
  output(channels, { json: options.json });
695
721
  } catch (error) {
696
722
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
697
723
  process.exit(1);
698
724
  }
699
725
  });
700
- dms.command("get").description("Get DM channel details").argument("<dm-channel-id>", "DM Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (dmChannelId, options) => {
726
+ dms.command("get").description("Get direct channel details").argument("<channel-id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (channelId, options) => {
701
727
  try {
702
728
  const client = await getClient(options.profile);
703
- const channel = await client.getChannel(dmChannelId);
729
+ const channel = await client.getChannel(channelId);
704
730
  output(channel, { json: options.json });
705
731
  } catch (error) {
706
732
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
707
733
  process.exit(1);
708
734
  }
709
735
  });
710
- dms.command("create").description("Create a DM channel with a user").requiredOption("--user-id <id>", "User ID to DM with").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
736
+ dms.command("create").description("Create a direct channel with a user").requiredOption("--user-id <id>", "User ID to message").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
711
737
  try {
712
738
  const client = await getClient(options.profile);
713
- const channel = await client.createDmChannel(options.userId);
739
+ const channel = await client.createDirectChannel(options.userId);
714
740
  output(channel, { json: options.json });
715
741
  } catch (error) {
716
742
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
717
743
  process.exit(1);
718
744
  }
719
745
  });
720
- dms.command("messages").description("List messages in a DM channel").argument("<dm-channel-id>", "DM Channel ID").option("--limit <n>", "Number of messages", "50").option("--cursor <cursor>", "Pagination cursor").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
721
- async (dmChannelId, options) => {
746
+ dms.command("messages").description("List messages in a direct channel").argument("<channel-id>", "Channel ID").option("--limit <n>", "Number of messages", "50").option("--cursor <cursor>", "Pagination cursor").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
747
+ async (channelId, options) => {
722
748
  try {
723
749
  const client = await getClient(options.profile);
724
- const messages = await client.getDmMessages(
725
- dmChannelId,
750
+ const page = await client.getMessages(
751
+ channelId,
726
752
  parseInt(options.limit ?? "50", 10),
727
753
  options.cursor
728
754
  );
729
- output(messages, { json: options.json });
755
+ output(page.messages, { json: options.json });
730
756
  } catch (error) {
731
757
  outputError(error instanceof Error ? error.message : String(error), {
732
758
  json: options.json
@@ -735,11 +761,11 @@ function createDmsCommand() {
735
761
  }
736
762
  }
737
763
  );
738
- dms.command("send").description("Send a DM message").argument("<dm-channel-id>", "DM Channel ID").requiredOption("--content <text>", "Message content").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
739
- async (dmChannelId, options) => {
764
+ dms.command("send").description("Send a direct message").argument("<channel-id>", "Channel ID").requiredOption("--content <text>", "Message content").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
765
+ async (channelId, options) => {
740
766
  try {
741
767
  const client = await getClient(options.profile);
742
- const message = await client.sendDmMessage(dmChannelId, options.content);
768
+ const message = await client.sendMessage(channelId, options.content);
743
769
  output(message, { json: options.json });
744
770
  } catch (error) {
745
771
  outputError(error instanceof Error ? error.message : String(error), {
@@ -749,12 +775,12 @@ function createDmsCommand() {
749
775
  }
750
776
  }
751
777
  );
752
- dms.command("mark-read").description("Mark DM channel as read").argument("<dm-channel-id>", "DM Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (dmChannelId, options) => {
778
+ dms.command("mark-read").description("Mark direct channel as read").argument("<channel-id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (channelId, options) => {
753
779
  try {
754
780
  const client = await getClient(options.profile);
755
- await client.markScopeRead({ channelId: dmChannelId });
781
+ await client.markScopeRead({ channelId });
756
782
  const outputOpts = { json: options.json };
757
- outputSuccess("DM channel marked as read", outputOpts);
783
+ outputSuccess("Direct channel marked as read", outputOpts);
758
784
  } catch (error) {
759
785
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
760
786
  process.exit(1);
@@ -764,9 +790,9 @@ function createDmsCommand() {
764
790
  }
765
791
 
766
792
  // src/commands/friends.ts
767
- import { Command as Command7 } from "commander";
793
+ import { Command as Command9 } from "commander";
768
794
  function createFriendsCommand() {
769
- const friends = new Command7("friends").description("Friendship management commands");
795
+ const friends = new Command9("friends").description("Friendship management commands");
770
796
  friends.command("list").description("List friends").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
771
797
  try {
772
798
  const client = await getClient(options.profile);
@@ -850,9 +876,9 @@ function createFriendsCommand() {
850
876
  }
851
877
 
852
878
  // src/commands/invites.ts
853
- import { Command as Command8 } from "commander";
879
+ import { Command as Command10 } from "commander";
854
880
  function createInvitesCommand() {
855
- const invites = new Command8("invites").description("Invite code management commands");
881
+ const invites = new Command10("invites").description("Invite code management commands");
856
882
  invites.command("list").description("List your invite codes").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
857
883
  try {
858
884
  const client = await getClient(options.profile);
@@ -903,9 +929,9 @@ function createInvitesCommand() {
903
929
  }
904
930
 
905
931
  // src/commands/listen.ts
906
- import { Command as Command9 } from "commander";
932
+ import { Command as Command11 } from "commander";
907
933
  function createListenCommand() {
908
- const listen = new Command9("listen").description("Listen to real-time events");
934
+ const listen = new Command11("listen").description("Listen to real-time events");
909
935
  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(
910
936
  async (channelId, options) => {
911
937
  try {
@@ -1021,61 +1047,13 @@ function createListenCommand() {
1021
1047
  }
1022
1048
  }
1023
1049
  );
1024
- listen.command("dm").description("Listen to DM events").argument("<dm-channel-id>", "DM Channel ID").option("--timeout <seconds>", "Timeout in seconds", "60").option("--count <n>", "Stop after N events").option("--profile <name>", "Profile to use").option("--json", "Output as JSON (one per line)").action(
1025
- async (dmChannelId, options) => {
1026
- try {
1027
- const socket = await getSocket(options.profile);
1028
- const timeoutMs = parseInt(options.timeout ?? "60", 10) * 1e3;
1029
- const maxCount = options.count ? parseInt(options.count, 10) : void 0;
1030
- let count = 0;
1031
- let timeoutId;
1032
- const cleanup = () => {
1033
- if (timeoutId) clearTimeout(timeoutId);
1034
- socket.disconnect();
1035
- };
1036
- timeoutId = setTimeout(() => {
1037
- cleanup();
1038
- process.exit(0);
1039
- }, timeoutMs);
1040
- socket.on("dm:message:new", ((msg) => {
1041
- if (msg.dmChannelId !== dmChannelId) return;
1042
- count++;
1043
- if (options.json) {
1044
- console.log(JSON.stringify({ type: "dm:message:new", data: msg }));
1045
- } else {
1046
- const timestamp = new Date(msg.createdAt ?? Date.now()).toLocaleTimeString();
1047
- console.log(
1048
- `[${timestamp}] ${msg.author?.username ?? "unknown"}: ${msg.content ?? ""}`
1049
- );
1050
- }
1051
- if (maxCount && count >= maxCount) {
1052
- cleanup();
1053
- process.exit(0);
1054
- }
1055
- }));
1056
- socket.connect();
1057
- await socket.waitForConnect(5e3);
1058
- socket.joinDmChannel(dmChannelId);
1059
- if (!options.json) {
1060
- console.error(`(listening to DM channel ${dmChannelId}, timeout: ${timeoutMs}ms)`);
1061
- }
1062
- await new Promise(() => {
1063
- });
1064
- } catch (error) {
1065
- outputError(error instanceof Error ? error.message : String(error), {
1066
- json: options.json
1067
- });
1068
- process.exit(1);
1069
- }
1070
- }
1071
- );
1072
1050
  return listen;
1073
1051
  }
1074
1052
 
1075
1053
  // src/commands/marketplace.ts
1076
- import { Command as Command10 } from "commander";
1054
+ import { Command as Command12 } from "commander";
1077
1055
  function createMarketplaceCommand() {
1078
- const marketplace = new Command10("marketplace").description("Marketplace commands");
1056
+ const marketplace = new Command12("marketplace").description("Marketplace commands");
1079
1057
  const listings = marketplace.command("listings").description("Listing commands");
1080
1058
  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(
1081
1059
  async (options) => {
@@ -1220,9 +1198,9 @@ function createMarketplaceCommand() {
1220
1198
 
1221
1199
  // src/commands/media.ts
1222
1200
  import { readFileSync } from "fs";
1223
- import { Command as Command11 } from "commander";
1201
+ import { Command as Command13 } from "commander";
1224
1202
  function createMediaCommand() {
1225
- const media = new Command11("media").description("Media management commands");
1203
+ const media = new Command13("media").description("Media management commands");
1226
1204
  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(
1227
1205
  async (options) => {
1228
1206
  try {
@@ -1288,9 +1266,9 @@ function createMediaCommand() {
1288
1266
  }
1289
1267
 
1290
1268
  // src/commands/notifications.ts
1291
- import { Command as Command12 } from "commander";
1269
+ import { Command as Command14 } from "commander";
1292
1270
  function createNotificationsCommand() {
1293
- const notifications = new Command12("notifications").description("Notification commands");
1271
+ const notifications = new Command14("notifications").description("Notification commands");
1294
1272
  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(
1295
1273
  async (options) => {
1296
1274
  try {
@@ -1333,13 +1311,14 @@ function createNotificationsCommand() {
1333
1311
  }
1334
1312
 
1335
1313
  // src/commands/oauth.ts
1336
- import { Command as Command13 } from "commander";
1314
+ import { Command as Command15 } from "commander";
1337
1315
  function createOAuthCommand() {
1338
- const oauth = new Command13("oauth").description("OAuth management commands");
1316
+ const oauth = new Command15("oauth").description("OAuth management commands");
1339
1317
  oauth.command("list").description("List OAuth apps").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1340
1318
  try {
1341
1319
  const client = await getClient(options.profile);
1342
- output([], { json: options.json });
1320
+ const apps = await client.listOAuthApps();
1321
+ output(apps, { json: options.json });
1343
1322
  } catch (error) {
1344
1323
  outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1345
1324
  process.exit(1);
@@ -1393,13 +1372,44 @@ function createOAuthCommand() {
1393
1372
  process.exit(1);
1394
1373
  }
1395
1374
  });
1375
+ oauth.command("reset-secret").description("Reset OAuth app client secret").argument("<app-id>", "App ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (appId, options) => {
1376
+ try {
1377
+ const client = await getClient(options.profile);
1378
+ const result = await client.resetOAuthAppSecret(appId);
1379
+ output(result, { json: options.json });
1380
+ } catch (error) {
1381
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1382
+ process.exit(1);
1383
+ }
1384
+ });
1385
+ oauth.command("consents").description("List OAuth consents (authorized apps)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1386
+ try {
1387
+ const client = await getClient(options.profile);
1388
+ const consents = await client.listOAuthConsents();
1389
+ output(consents, { json: options.json });
1390
+ } catch (error) {
1391
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1392
+ process.exit(1);
1393
+ }
1394
+ });
1395
+ oauth.command("revoke").description("Revoke OAuth consent for an app").argument("<app-id>", "App ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (appId, options) => {
1396
+ try {
1397
+ const client = await getClient(options.profile);
1398
+ await client.revokeOAuthConsent(appId);
1399
+ const outputOpts = { json: options.json };
1400
+ outputSuccess("OAuth consent revoked", outputOpts);
1401
+ } catch (error) {
1402
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1403
+ process.exit(1);
1404
+ }
1405
+ });
1396
1406
  return oauth;
1397
1407
  }
1398
1408
 
1399
1409
  // src/commands/ping.ts
1400
- import { Command as Command14 } from "commander";
1410
+ import { Command as Command16 } from "commander";
1401
1411
  function createPingCommand() {
1402
- const ping = new Command14("ping").description("Test connection to Shadow server");
1412
+ const ping = new Command16("ping").description("Test connection to Shadow server");
1403
1413
  ping.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1404
1414
  const startTime = Date.now();
1405
1415
  const outputOpts = { json: options.json };
@@ -1447,10 +1457,62 @@ function createPingCommand() {
1447
1457
  return ping;
1448
1458
  }
1449
1459
 
1460
+ // src/commands/profile-comments.ts
1461
+ import { Command as Command17 } from "commander";
1462
+ function createProfileCommentsCommand() {
1463
+ const comments = new Command17("profile-comments").description(
1464
+ "Profile comment management commands"
1465
+ );
1466
+ 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) => {
1467
+ try {
1468
+ const client = await getClient(options.profile);
1469
+ const result = await client.getProfileComments(userId, {
1470
+ limit: Number(options.limit),
1471
+ offset: Number(options.offset)
1472
+ });
1473
+ output(result, { json: options.json });
1474
+ } catch (error) {
1475
+ outputError(error instanceof Error ? error.message : String(error), {
1476
+ json: options.json
1477
+ });
1478
+ process.exit(1);
1479
+ }
1480
+ });
1481
+ comments.command("create").description("Create a profile comment").requiredOption("--user-id <id>", "Profile user ID").requiredOption("--content <text>", "Comment content").option("--parent-id <id>", "Parent comment ID (for replies)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1482
+ try {
1483
+ const client = await getClient(options.profile);
1484
+ const result = await client.createProfileComment({
1485
+ profileUserId: options.userId,
1486
+ content: options.content,
1487
+ parentId: options.parentId
1488
+ });
1489
+ output(result, { json: options.json });
1490
+ } catch (error) {
1491
+ outputError(error instanceof Error ? error.message : String(error), {
1492
+ json: options.json
1493
+ });
1494
+ process.exit(1);
1495
+ }
1496
+ });
1497
+ comments.command("delete").description("Delete a profile comment").argument("<comment-id>", "Comment ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (commentId, options) => {
1498
+ try {
1499
+ const client = await getClient(options.profile);
1500
+ await client.deleteProfileComment(commentId);
1501
+ output({ ok: true }, { json: options.json });
1502
+ } catch (error) {
1503
+ outputError(error instanceof Error ? error.message : String(error), {
1504
+ json: options.json
1505
+ });
1506
+ process.exit(1);
1507
+ }
1508
+ });
1509
+ return comments;
1510
+ }
1511
+
1450
1512
  // src/commands/search.ts
1451
- import { Command as Command15 } from "commander";
1513
+ import { Command as Command18 } from "commander";
1452
1514
  function createSearchCommand() {
1453
- const search = new Command15("search").description("Search commands");
1515
+ const search = new Command18("search").description("Search commands");
1454
1516
  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(
1455
1517
  async (options) => {
1456
1518
  try {
@@ -1475,9 +1537,9 @@ function createSearchCommand() {
1475
1537
  }
1476
1538
 
1477
1539
  // src/commands/servers.ts
1478
- import { Command as Command16 } from "commander";
1540
+ import { Command as Command19 } from "commander";
1479
1541
  function createServersCommand() {
1480
- const servers = new Command16("servers").description("Server management commands");
1542
+ const servers = new Command19("servers").description("Server management commands");
1481
1543
  servers.command("list").description("List all servers you have joined").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1482
1544
  try {
1483
1545
  const client = await getClient(options.profile);
@@ -1510,7 +1572,9 @@ function createServersCommand() {
1510
1572
  });
1511
1573
  output(server, { json: options.json });
1512
1574
  } catch (error) {
1513
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1575
+ outputError(error instanceof Error ? error.message : String(error), {
1576
+ json: options.json
1577
+ });
1514
1578
  process.exit(1);
1515
1579
  }
1516
1580
  }
@@ -1527,7 +1591,9 @@ function createServersCommand() {
1527
1591
  outputSuccess("Joined server", outputOpts);
1528
1592
  }
1529
1593
  } catch (error) {
1530
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1594
+ outputError(error instanceof Error ? error.message : String(error), {
1595
+ json: options.json
1596
+ });
1531
1597
  process.exit(1);
1532
1598
  }
1533
1599
  }
@@ -1585,7 +1651,9 @@ function createServersCommand() {
1585
1651
  console.log(server.homepageHtml ?? "(default homepage)");
1586
1652
  }
1587
1653
  } catch (error) {
1588
- outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1654
+ outputError(error instanceof Error ? error.message : String(error), {
1655
+ json: options.json
1656
+ });
1589
1657
  process.exit(1);
1590
1658
  }
1591
1659
  }
@@ -1604,9 +1672,9 @@ function createServersCommand() {
1604
1672
  }
1605
1673
 
1606
1674
  // src/commands/shop.ts
1607
- import { Command as Command17 } from "commander";
1675
+ import { Command as Command20 } from "commander";
1608
1676
  function createShopCommand() {
1609
- const shop = new Command17("shop").description("Shop commands");
1677
+ const shop = new Command20("shop").description("Shop commands");
1610
1678
  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) => {
1611
1679
  try {
1612
1680
  const client = await getClient(options.profile);
@@ -1697,9 +1765,9 @@ function createShopCommand() {
1697
1765
  }
1698
1766
 
1699
1767
  // src/commands/status.ts
1700
- import { Command as Command18 } from "commander";
1768
+ import { Command as Command21 } from "commander";
1701
1769
  function createStatusCommand() {
1702
- const status = new Command18("status").description("Show detailed status information");
1770
+ const status = new Command21("status").description("Show detailed status information");
1703
1771
  status.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1704
1772
  const outputOpts = { json: options.json };
1705
1773
  try {
@@ -1777,9 +1845,9 @@ function createStatusCommand() {
1777
1845
  }
1778
1846
 
1779
1847
  // src/commands/threads.ts
1780
- import { Command as Command19 } from "commander";
1848
+ import { Command as Command22 } from "commander";
1781
1849
  function createThreadsCommand() {
1782
- const threads = new Command19("threads").description("Thread commands");
1850
+ const threads = new Command22("threads").description("Thread commands");
1783
1851
  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) => {
1784
1852
  try {
1785
1853
  const client = await getClient(options.profile);
@@ -1860,11 +1928,52 @@ function createThreadsCommand() {
1860
1928
  return threads;
1861
1929
  }
1862
1930
 
1931
+ // src/commands/voice-enhance.ts
1932
+ import { Command as Command23 } from "commander";
1933
+ function createVoiceEnhanceCommand() {
1934
+ const voice = new Command23("voice-enhance").description("Voice enhancement commands");
1935
+ 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) => {
1936
+ try {
1937
+ const client = await getClient(options.profile);
1938
+ const result = await client.enhanceVoice({
1939
+ transcript: options.transcript,
1940
+ language: options.language,
1941
+ options: {
1942
+ enableSelfCorrection: options.selfCorrection !== false,
1943
+ enableListFormatting: options.listFormatting !== false,
1944
+ enableFillerRemoval: options.fillerRemoval !== false,
1945
+ enableToneAdjustment: options.toneAdjustment === true,
1946
+ targetTone: options.targetTone
1947
+ }
1948
+ });
1949
+ output(result, { json: options.json });
1950
+ } catch (error) {
1951
+ outputError(error instanceof Error ? error.message : String(error), {
1952
+ json: options.json
1953
+ });
1954
+ process.exit(1);
1955
+ }
1956
+ });
1957
+ voice.command("config").description("Get voice enhancement config").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1958
+ try {
1959
+ const client = await getClient(options.profile);
1960
+ const config = await client.getVoiceConfig();
1961
+ output(config, { json: options.json });
1962
+ } catch (error) {
1963
+ outputError(error instanceof Error ? error.message : String(error), {
1964
+ json: options.json
1965
+ });
1966
+ process.exit(1);
1967
+ }
1968
+ });
1969
+ return voice;
1970
+ }
1971
+
1863
1972
  // src/commands/workspace.ts
1864
1973
  import { readFile } from "fs/promises";
1865
- import { Command as Command20 } from "commander";
1974
+ import { Command as Command24 } from "commander";
1866
1975
  function createWorkspaceCommand() {
1867
- const workspace = new Command20("workspace").description("Workspace file management commands");
1976
+ const workspace = new Command24("workspace").description("Workspace file management commands");
1868
1977
  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) => {
1869
1978
  try {
1870
1979
  const client = await getClient(options.profile);
@@ -2046,7 +2155,7 @@ function createWorkspaceCommand() {
2046
2155
  }
2047
2156
 
2048
2157
  // src/index.ts
2049
- var program = new Command21();
2158
+ var program = new Command25();
2050
2159
  program.name("shadowob").description("Shadow CLI \u2014 command-line interface for Shadow servers").version("0.1.0").configureHelp({
2051
2160
  sortSubcommands: true
2052
2161
  });
@@ -2057,10 +2166,9 @@ program.addCommand(createChannelsCommand());
2057
2166
  program.addCommand(createThreadsCommand());
2058
2167
  program.addCommand(createAgentsCommand());
2059
2168
  program.addCommand(createListenCommand());
2060
- program.addCommand(createDmsCommand());
2169
+ program.addCommand(createDirectMessagesCommand());
2061
2170
  program.addCommand(createWorkspaceCommand());
2062
2171
  program.addCommand(createShopCommand());
2063
- program.addCommand(createAppsCommand());
2064
2172
  program.addCommand(createNotificationsCommand());
2065
2173
  program.addCommand(createFriendsCommand());
2066
2174
  program.addCommand(createInvitesCommand());
@@ -2071,4 +2179,9 @@ program.addCommand(createSearchCommand());
2071
2179
  program.addCommand(createConfigCommand());
2072
2180
  program.addCommand(createPingCommand());
2073
2181
  program.addCommand(createStatusCommand());
2182
+ program.addCommand(createCloudCommand());
2183
+ program.addCommand(createApiTokensCommand());
2184
+ program.addCommand(createDiscoverCommand());
2185
+ program.addCommand(createProfileCommentsCommand());
2186
+ program.addCommand(createVoiceEnhanceCommand());
2074
2187
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadowob/cli",
3
- "version": "1.1.1",
3
+ "version": "1.1.3-dev.261",
4
4
  "description": "Shadow CLI — command-line interface for Shadow servers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "commander": "^13.1.0",
14
14
  "chalk": "^5.4.1",
15
- "@shadowob/sdk": "1.1.1"
15
+ "@shadowob/sdk": "1.1.3-dev.261"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "^22.15.21",
@@ -22,7 +22,7 @@
22
22
  "vitest": "^4.1.0"
23
23
  },
24
24
  "engines": {
25
- "node": ">=22"
25
+ "node": ">=22.14.0"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"
@@ -31,7 +31,7 @@
31
31
  "build": "tsup src/index.ts --format esm --out-dir dist --clean",
32
32
  "dev": "tsup src/index.ts --format esm --out-dir dist --clean --watch",
33
33
  "lint": "biome lint .",
34
- "typecheck": "pnpm --filter @shadowob/shared build && pnpm --filter @shadowob/sdk build && tsc --noEmit",
34
+ "typecheck": "tsc --noEmit",
35
35
  "test": "vitest run --exclude=__tests__/e2e/**",
36
36
  "test:watch": "vitest --exclude=__tests__/e2e/**",
37
37
  "test:e2e": "vitest run __tests__/e2e"