@shadowob/cli 0.4.0 → 0.4.1

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 ADDED
@@ -0,0 +1,2074 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ configManager,
4
+ getClient,
5
+ getSocket
6
+ } from "./chunk-T3BKMB7N.js";
7
+
8
+ // src/index.ts
9
+ import { Command as Command21 } from "commander";
10
+
11
+ // src/commands/agents.ts
12
+ import { Command } from "commander";
13
+
14
+ // src/utils/output.ts
15
+ import chalk from "chalk";
16
+ function output(data, options) {
17
+ if (options.json) {
18
+ console.log(JSON.stringify(data, null, 2));
19
+ return;
20
+ }
21
+ if (data === null || data === void 0) {
22
+ return;
23
+ }
24
+ if (typeof data === "string") {
25
+ console.log(data);
26
+ return;
27
+ }
28
+ if (Array.isArray(data)) {
29
+ if (data.length === 0) {
30
+ console.log(chalk.gray("No results"));
31
+ return;
32
+ }
33
+ formatArray(data);
34
+ return;
35
+ }
36
+ if (typeof data === "object") {
37
+ formatObject(data);
38
+ return;
39
+ }
40
+ console.log(String(data));
41
+ }
42
+ function outputError(message, options) {
43
+ if (options.json) {
44
+ console.log(JSON.stringify({ error: message }, null, 2));
45
+ return;
46
+ }
47
+ console.error(chalk.red(`Error: ${message}`));
48
+ }
49
+ function outputSuccess(message, options) {
50
+ if (options.json) {
51
+ console.log(JSON.stringify({ success: true, message }, null, 2));
52
+ return;
53
+ }
54
+ console.log(chalk.green(message));
55
+ }
56
+ function formatArray(items) {
57
+ if (items.length === 0) return;
58
+ const first = items[0];
59
+ if (typeof first !== "object" || first === null) {
60
+ items.forEach((item) => {
61
+ console.log(String(item));
62
+ });
63
+ return;
64
+ }
65
+ const keys = Object.keys(first);
66
+ const idKey = keys.find((k) => k === "id") || keys[0];
67
+ const nameKey = keys.find((k) => k === "name" || k === "username" || k === "slug") || keys[1] || idKey;
68
+ for (const item of items) {
69
+ const obj = item;
70
+ const id = String(obj[idKey] ?? "");
71
+ const name = String(obj[nameKey] ?? "");
72
+ if (name && name !== id) {
73
+ console.log(`${chalk.cyan(id)} ${name}`);
74
+ } else {
75
+ console.log(chalk.cyan(id));
76
+ }
77
+ }
78
+ }
79
+ function formatObject(obj) {
80
+ const entries = Object.entries(obj);
81
+ const maxKeyLength = Math.max(...entries.map(([k]) => k.length));
82
+ for (const [key, value] of entries) {
83
+ const formattedKey = key.padEnd(maxKeyLength);
84
+ let formattedValue;
85
+ if (value === null || value === void 0) {
86
+ formattedValue = chalk.gray("null");
87
+ } else if (typeof value === "boolean") {
88
+ formattedValue = value ? chalk.green("true") : chalk.red("false");
89
+ } else if (typeof value === "object") {
90
+ formattedValue = JSON.stringify(value);
91
+ } else {
92
+ formattedValue = String(value);
93
+ }
94
+ console.log(`${chalk.gray(formattedKey)} ${formattedValue}`);
95
+ }
96
+ }
97
+
98
+ // src/commands/agents.ts
99
+ function createAgentsCommand() {
100
+ const agents = new Command("agents").description("Agent management commands");
101
+ agents.command("list").description("List your agents").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
102
+ try {
103
+ const client = await getClient(options.profile);
104
+ const agents2 = await client.listAgents();
105
+ output(agents2, { json: options.json });
106
+ } catch (error) {
107
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
108
+ process.exit(1);
109
+ }
110
+ });
111
+ 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) => {
112
+ try {
113
+ const client = await getClient(options.profile);
114
+ const agent = await client.getAgent(agentId);
115
+ output(agent, { json: options.json });
116
+ } catch (error) {
117
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
118
+ process.exit(1);
119
+ }
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(
122
+ async (options) => {
123
+ try {
124
+ const client = await getClient(options.profile);
125
+ const agent = await client.createAgent({
126
+ name: options.name,
127
+ displayName: options.displayName,
128
+ avatarUrl: options.avatarUrl
129
+ });
130
+ output(agent, { json: options.json });
131
+ } catch (error) {
132
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
133
+ process.exit(1);
134
+ }
135
+ }
136
+ );
137
+ 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(
138
+ async (agentId, options) => {
139
+ try {
140
+ const client = await getClient(options.profile);
141
+ const agent = await client.updateAgent(agentId, {
142
+ name: options.name,
143
+ displayName: options.displayName,
144
+ avatarUrl: options.avatarUrl
145
+ });
146
+ output(agent, { json: options.json });
147
+ } catch (error) {
148
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
149
+ process.exit(1);
150
+ }
151
+ }
152
+ );
153
+ 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) => {
154
+ try {
155
+ const client = await getClient(options.profile);
156
+ await client.deleteAgent(agentId);
157
+ const outputOpts = { json: options.json };
158
+ outputSuccess("Agent deleted", outputOpts);
159
+ } catch (error) {
160
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
161
+ process.exit(1);
162
+ }
163
+ });
164
+ 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) => {
165
+ try {
166
+ const client = await getClient(options.profile);
167
+ await client.startAgent(agentId);
168
+ const outputOpts = { json: options.json };
169
+ outputSuccess("Agent started", outputOpts);
170
+ } catch (error) {
171
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
172
+ process.exit(1);
173
+ }
174
+ });
175
+ 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) => {
176
+ try {
177
+ const client = await getClient(options.profile);
178
+ await client.stopAgent(agentId);
179
+ const outputOpts = { json: options.json };
180
+ outputSuccess("Agent stopped", outputOpts);
181
+ } catch (error) {
182
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
183
+ process.exit(1);
184
+ }
185
+ });
186
+ 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) => {
187
+ try {
188
+ const client = await getClient(options.profile);
189
+ const result = await client.generateAgentToken(agentId);
190
+ if (options.json) {
191
+ output(result, { json: true });
192
+ } else {
193
+ console.log(result.token);
194
+ }
195
+ } catch (error) {
196
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
197
+ process.exit(1);
198
+ }
199
+ });
200
+ 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) => {
201
+ try {
202
+ const client = await getClient(options.profile);
203
+ const config = await client.getAgentConfig(agentId);
204
+ output(config, { json: options.json });
205
+ } catch (error) {
206
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
207
+ process.exit(1);
208
+ }
209
+ });
210
+ return agents;
211
+ }
212
+
213
+ // src/commands/apps.ts
214
+ 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) => {
218
+ try {
219
+ const client = await getClient(options.profile);
220
+ const appsData = await client.listApps(serverId);
221
+ output(appsData, { json: options.json });
222
+ } catch (error) {
223
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
224
+ process.exit(1);
225
+ }
226
+ });
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);
238
+ }
239
+ }
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
+ }
258
+ }
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) => {
262
+ 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
272
+ });
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
+ 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 });
301
+ } catch (error) {
302
+ outputError(error instanceof Error ? error.message : String(error), {
303
+ json: options.json
304
+ });
305
+ process.exit(1);
306
+ }
307
+ }
308
+ );
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
+ auth.command("logout").description("Remove a profile").option("--profile <name>", "Profile name (default: current)").option("--json", "Output as JSON").action(async (options) => {
338
+ try {
339
+ const profileName = options.profile ?? await configManager.getCurrentProfileName();
340
+ if (!profileName) {
341
+ outputError("No profile specified and no current profile", { json: options.json });
342
+ process.exit(1);
343
+ }
344
+ const deleted = await configManager.deleteProfile(profileName);
345
+ if (!deleted) {
346
+ outputError(`Profile "${profileName}" not found`, { json: options.json });
347
+ process.exit(1);
348
+ }
349
+ const outputOpts = { json: options.json };
350
+ outputSuccess(`Logged out (${profileName})`, outputOpts);
351
+ } catch (error) {
352
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
353
+ process.exit(1);
354
+ }
355
+ });
356
+ auth.command("whoami").description("Show current user and profile").option("--profile <name>", "Profile name (default: current)").option("--json", "Output as JSON").action(async (options) => {
357
+ try {
358
+ const profileName = options.profile ?? await configManager.getCurrentProfileName();
359
+ const profile = await configManager.getProfile(options.profile);
360
+ if (!profile) {
361
+ outputError(
362
+ profileName ? `Profile "${profileName}" not found` : "Not authenticated. Run: shadowob auth login",
363
+ { json: options.json }
364
+ );
365
+ process.exit(1);
366
+ }
367
+ const client = new ShadowClient(profile.serverUrl, profile.token);
368
+ const user = await client.getMe();
369
+ const outputOpts = { json: options.json };
370
+ if (options.json) {
371
+ output({ profile: profileName, user, serverUrl: profile.serverUrl }, outputOpts);
372
+ } else {
373
+ console.log(`Profile: ${profileName}`);
374
+ console.log(`Server: ${profile.serverUrl}`);
375
+ console.log(`User: ${user.username}`);
376
+ if (user.displayName && user.displayName !== user.username) {
377
+ console.log(`Name: ${user.displayName}`);
378
+ }
379
+ }
380
+ } catch (error) {
381
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
382
+ process.exit(1);
383
+ }
384
+ });
385
+ auth.command("switch").description("Switch to a different profile").argument("<profile>", "Profile name").option("--json", "Output as JSON").action(async (profileName, options) => {
386
+ try {
387
+ const switched = await configManager.switchProfile(profileName);
388
+ if (!switched) {
389
+ outputError(`Profile "${profileName}" not found`, { json: options.json });
390
+ process.exit(1);
391
+ }
392
+ const outputOpts = { json: options.json };
393
+ outputSuccess(`Switched to profile: ${profileName}`, outputOpts);
394
+ } catch (error) {
395
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
396
+ process.exit(1);
397
+ }
398
+ });
399
+ auth.command("list").description("List all profiles").option("--json", "Output as JSON").action(async (options) => {
400
+ try {
401
+ const profiles = await configManager.listProfiles();
402
+ const current = await configManager.getCurrentProfileName();
403
+ const outputOpts = { json: options.json };
404
+ if (options.json) {
405
+ output({ profiles, current }, outputOpts);
406
+ } else {
407
+ if (profiles.length === 0) {
408
+ console.log("No profiles. Run: shadowob auth login");
409
+ return;
410
+ }
411
+ for (const name of profiles) {
412
+ const marker = name === current ? "* " : " ";
413
+ console.log(`${marker}${name}`);
414
+ }
415
+ }
416
+ } catch (error) {
417
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
418
+ process.exit(1);
419
+ }
420
+ });
421
+ return auth;
422
+ }
423
+
424
+ // src/commands/channels.ts
425
+ import { Command as Command4 } from "commander";
426
+ function createChannelsCommand() {
427
+ const channels = new Command4("channels").description("Channel commands");
428
+ 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) => {
429
+ try {
430
+ const client = await getClient(options.profile);
431
+ const channels2 = await client.getServerChannels(options.serverId);
432
+ output(channels2, { json: options.json });
433
+ } catch (error) {
434
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
435
+ process.exit(1);
436
+ }
437
+ });
438
+ channels.command("get").description("Get channel details").argument("<channel-id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (channelId, options) => {
439
+ try {
440
+ const client = await getClient(options.profile);
441
+ const channel = await client.getChannel(channelId);
442
+ output(channel, { json: options.json });
443
+ } catch (error) {
444
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
445
+ process.exit(1);
446
+ }
447
+ });
448
+ 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(
449
+ async (options) => {
450
+ try {
451
+ const client = await getClient(options.profile);
452
+ const channel = await client.createChannel(options.serverId, {
453
+ name: options.name,
454
+ type: options.type,
455
+ description: options.description
456
+ });
457
+ output(channel, { json: options.json });
458
+ } catch (error) {
459
+ outputError(error instanceof Error ? error.message : String(error), {
460
+ json: options.json
461
+ });
462
+ process.exit(1);
463
+ }
464
+ }
465
+ );
466
+ channels.command("delete").description("Delete a channel").argument("<channel-id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (channelId, options) => {
467
+ try {
468
+ const client = await getClient(options.profile);
469
+ await client.deleteChannel(channelId);
470
+ const outputOpts = { json: options.json };
471
+ outputSuccess("Channel deleted", outputOpts);
472
+ } catch (error) {
473
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
474
+ process.exit(1);
475
+ }
476
+ });
477
+ channels.command("messages").description("List messages in a 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(
478
+ async (channelId, options) => {
479
+ try {
480
+ const client = await getClient(options.profile);
481
+ const result = await client.getMessages(
482
+ channelId,
483
+ parseInt(options.limit ?? "50", 10),
484
+ options.cursor
485
+ );
486
+ output(result.messages, { json: options.json });
487
+ if (!options.json && result.hasMore) {
488
+ console.log("(has more messages)");
489
+ }
490
+ } catch (error) {
491
+ outputError(error instanceof Error ? error.message : String(error), {
492
+ json: options.json
493
+ });
494
+ process.exit(1);
495
+ }
496
+ }
497
+ );
498
+ channels.command("send").description("Send a message to a channel").argument("<channel-id>", "Channel ID").requiredOption("--content <text>", "Message content").option("--reply-to <id>", "Reply to message ID").option("--thread-id <id>", "Send to thread").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
499
+ async (channelId, options) => {
500
+ try {
501
+ const client = await getClient(options.profile);
502
+ const message = await client.sendMessage(channelId, options.content, {
503
+ replyToId: options.replyTo,
504
+ threadId: options.threadId
505
+ });
506
+ output(message, { json: options.json });
507
+ } catch (error) {
508
+ outputError(error instanceof Error ? error.message : String(error), {
509
+ json: options.json
510
+ });
511
+ process.exit(1);
512
+ }
513
+ }
514
+ );
515
+ channels.command("edit").description("Edit a message").argument("<message-id>", "Message ID").requiredOption("--content <text>", "New content").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
516
+ async (messageId, options) => {
517
+ try {
518
+ const client = await getClient(options.profile);
519
+ const message = await client.editMessage(messageId, options.content);
520
+ output(message, { json: options.json });
521
+ } catch (error) {
522
+ outputError(error instanceof Error ? error.message : String(error), {
523
+ json: options.json
524
+ });
525
+ process.exit(1);
526
+ }
527
+ }
528
+ );
529
+ channels.command("delete-message").description("Delete a message").argument("<message-id>", "Message ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (messageId, options) => {
530
+ try {
531
+ const client = await getClient(options.profile);
532
+ await client.deleteMessage(messageId);
533
+ const outputOpts = { json: options.json };
534
+ outputSuccess("Message deleted", outputOpts);
535
+ } catch (error) {
536
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
537
+ process.exit(1);
538
+ }
539
+ });
540
+ channels.command("react").description("Add a reaction to a message").argument("<message-id>", "Message ID").requiredOption("--emoji <emoji>", "Emoji to react with").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
541
+ async (messageId, options) => {
542
+ try {
543
+ const client = await getClient(options.profile);
544
+ await client.addReaction(messageId, options.emoji);
545
+ const outputOpts = { json: options.json };
546
+ outputSuccess("Reaction added", outputOpts);
547
+ } catch (error) {
548
+ outputError(error instanceof Error ? error.message : String(error), {
549
+ json: options.json
550
+ });
551
+ process.exit(1);
552
+ }
553
+ }
554
+ );
555
+ channels.command("unreact").description("Remove a reaction from a message").argument("<message-id>", "Message ID").requiredOption("--emoji <emoji>", "Emoji to remove").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
556
+ async (messageId, options) => {
557
+ try {
558
+ const client = await getClient(options.profile);
559
+ await client.removeReaction(messageId, options.emoji);
560
+ const outputOpts = { json: options.json };
561
+ outputSuccess("Reaction removed", outputOpts);
562
+ } catch (error) {
563
+ outputError(error instanceof Error ? error.message : String(error), {
564
+ json: options.json
565
+ });
566
+ process.exit(1);
567
+ }
568
+ }
569
+ );
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(
571
+ async (messageId, options) => {
572
+ try {
573
+ const client = await getClient(options.profile);
574
+ await client.pinMessage(messageId, options.channelId);
575
+ const outputOpts = { json: options.json };
576
+ outputSuccess("Message pinned", outputOpts);
577
+ } catch (error) {
578
+ outputError(error instanceof Error ? error.message : String(error), {
579
+ json: options.json
580
+ });
581
+ process.exit(1);
582
+ }
583
+ }
584
+ );
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(
586
+ async (messageId, options) => {
587
+ try {
588
+ const client = await getClient(options.profile);
589
+ await client.unpinMessage(messageId, options.channelId);
590
+ const outputOpts = { json: options.json };
591
+ outputSuccess("Message unpinned", outputOpts);
592
+ } catch (error) {
593
+ outputError(error instanceof Error ? error.message : String(error), {
594
+ json: options.json
595
+ });
596
+ process.exit(1);
597
+ }
598
+ }
599
+ );
600
+ channels.command("pinned").description("List pinned messages in a channel").argument("<channel-id>", "Channel ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (channelId, options) => {
601
+ try {
602
+ const client = await getClient(options.profile);
603
+ const messages = await client.getPinnedMessages(channelId);
604
+ output(messages, { json: options.json });
605
+ } catch (error) {
606
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
607
+ process.exit(1);
608
+ }
609
+ });
610
+ return channels;
611
+ }
612
+
613
+ // src/commands/config.ts
614
+ import { Command as Command5 } from "commander";
615
+ function createConfigCommand() {
616
+ const config = new Command5("config").description("Configuration management commands");
617
+ config.command("path").description("Show configuration file path").action(() => {
618
+ console.log(configManager.getConfigPath());
619
+ });
620
+ config.command("validate").description("Validate configuration file").option("--json", "Output as JSON").action(async (options) => {
621
+ try {
622
+ const result = await configManager.validate();
623
+ const outputOpts = { json: options.json };
624
+ if (options.json) {
625
+ output(result, outputOpts);
626
+ process.exit(result.valid ? 0 : 1);
627
+ return;
628
+ }
629
+ if (result.valid) {
630
+ outputSuccess("Configuration is valid", outputOpts);
631
+ if (result.warnings.length > 0) {
632
+ console.log("\nWarnings:");
633
+ for (const warning of result.warnings) {
634
+ console.log(` - ${warning}`);
635
+ }
636
+ }
637
+ process.exit(0);
638
+ } else {
639
+ outputError("Configuration is invalid", outputOpts);
640
+ if (result.errors.length > 0) {
641
+ console.log("\nErrors:");
642
+ for (const error of result.errors) {
643
+ console.log(` - ${error}`);
644
+ }
645
+ }
646
+ if (result.warnings.length > 0) {
647
+ console.log("\nWarnings:");
648
+ for (const warning of result.warnings) {
649
+ console.log(` - ${warning}`);
650
+ }
651
+ }
652
+ process.exit(1);
653
+ }
654
+ } catch (error) {
655
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
656
+ process.exit(1);
657
+ }
658
+ });
659
+ config.command("fix").description("Fix common configuration issues").option("--json", "Output as JSON").action(async (options) => {
660
+ try {
661
+ const result = await configManager.fix();
662
+ const outputOpts = { json: options.json };
663
+ if (options.json) {
664
+ output(result, outputOpts);
665
+ process.exit(0);
666
+ return;
667
+ }
668
+ if (result.fixed) {
669
+ outputSuccess("Configuration fixed", outputOpts);
670
+ console.log("\nChanges:");
671
+ for (const change of result.changes) {
672
+ console.log(` - ${change}`);
673
+ }
674
+ } else {
675
+ outputSuccess("No issues found", outputOpts);
676
+ }
677
+ process.exit(0);
678
+ } catch (error) {
679
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
680
+ process.exit(1);
681
+ }
682
+ });
683
+ return config;
684
+ }
685
+
686
+ // 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) => {
691
+ try {
692
+ const client = await getClient(options.profile);
693
+ const channels = await client.listDmChannels();
694
+ output(channels, { json: options.json });
695
+ } catch (error) {
696
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
697
+ process.exit(1);
698
+ }
699
+ });
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) => {
701
+ try {
702
+ const client = await getClient(options.profile);
703
+ const channel = await client.getChannel(dmChannelId);
704
+ output(channel, { json: options.json });
705
+ } catch (error) {
706
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
707
+ process.exit(1);
708
+ }
709
+ });
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) => {
711
+ try {
712
+ const client = await getClient(options.profile);
713
+ const channel = await client.createDmChannel(options.userId);
714
+ output(channel, { json: options.json });
715
+ } catch (error) {
716
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
717
+ process.exit(1);
718
+ }
719
+ });
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) => {
722
+ try {
723
+ const client = await getClient(options.profile);
724
+ const messages = await client.getDmMessages(
725
+ dmChannelId,
726
+ parseInt(options.limit ?? "50", 10),
727
+ options.cursor
728
+ );
729
+ output(messages, { json: options.json });
730
+ } catch (error) {
731
+ outputError(error instanceof Error ? error.message : String(error), {
732
+ json: options.json
733
+ });
734
+ process.exit(1);
735
+ }
736
+ }
737
+ );
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) => {
740
+ try {
741
+ const client = await getClient(options.profile);
742
+ const message = await client.sendDmMessage(dmChannelId, options.content);
743
+ output(message, { json: options.json });
744
+ } catch (error) {
745
+ outputError(error instanceof Error ? error.message : String(error), {
746
+ json: options.json
747
+ });
748
+ process.exit(1);
749
+ }
750
+ }
751
+ );
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) => {
753
+ try {
754
+ const client = await getClient(options.profile);
755
+ await client.markScopeRead({ channelId: dmChannelId });
756
+ const outputOpts = { json: options.json };
757
+ outputSuccess("DM channel marked as read", outputOpts);
758
+ } catch (error) {
759
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
760
+ process.exit(1);
761
+ }
762
+ });
763
+ return dms;
764
+ }
765
+
766
+ // src/commands/friends.ts
767
+ import { Command as Command7 } from "commander";
768
+ function createFriendsCommand() {
769
+ const friends = new Command7("friends").description("Friendship management commands");
770
+ friends.command("list").description("List friends").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
771
+ try {
772
+ const client = await getClient(options.profile);
773
+ const friendsData = await client.listFriends();
774
+ output(friendsData, { json: options.json });
775
+ } catch (error) {
776
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
777
+ process.exit(1);
778
+ }
779
+ });
780
+ friends.command("requests").description("List friend requests").option("--incoming", "Show only incoming requests").option("--outgoing", "Show only outgoing requests").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
781
+ async (options) => {
782
+ try {
783
+ const client = await getClient(options.profile);
784
+ let requests;
785
+ if (options.incoming) {
786
+ requests = await client.listPendingFriendRequests();
787
+ } else if (options.outgoing) {
788
+ requests = await client.listSentFriendRequests();
789
+ } else {
790
+ const [incoming, outgoing] = await Promise.all([
791
+ client.listPendingFriendRequests(),
792
+ client.listSentFriendRequests()
793
+ ]);
794
+ requests = [...incoming, ...outgoing];
795
+ }
796
+ output(requests, { json: options.json });
797
+ } catch (error) {
798
+ outputError(error instanceof Error ? error.message : String(error), {
799
+ json: options.json
800
+ });
801
+ process.exit(1);
802
+ }
803
+ }
804
+ );
805
+ friends.command("add").description("Send friend request by username").argument("<username>", "Username to add as friend").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (username, options) => {
806
+ try {
807
+ const client = await getClient(options.profile);
808
+ const result = await client.sendFriendRequest(username);
809
+ output(result, { json: options.json });
810
+ } catch (error) {
811
+ outputError(error instanceof Error ? error.message : String(error), {
812
+ json: options.json
813
+ });
814
+ process.exit(1);
815
+ }
816
+ });
817
+ friends.command("accept").description("Accept friend request").argument("<request-id>", "Friend request ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (requestId, options) => {
818
+ try {
819
+ const client = await getClient(options.profile);
820
+ const result = await client.acceptFriendRequest(requestId);
821
+ output(result, { json: options.json });
822
+ } catch (error) {
823
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
824
+ process.exit(1);
825
+ }
826
+ });
827
+ friends.command("reject").description("Reject friend request").argument("<request-id>", "Friend request ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (requestId, options) => {
828
+ try {
829
+ const client = await getClient(options.profile);
830
+ await client.rejectFriendRequest(requestId);
831
+ const outputOpts = { json: options.json };
832
+ outputSuccess("Friend request rejected", outputOpts);
833
+ } catch (error) {
834
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
835
+ process.exit(1);
836
+ }
837
+ });
838
+ friends.command("remove").description("Remove friend").argument("<friendship-id>", "Friendship ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (friendshipId, options) => {
839
+ try {
840
+ const client = await getClient(options.profile);
841
+ await client.removeFriend(friendshipId);
842
+ const outputOpts = { json: options.json };
843
+ outputSuccess("Friend removed", outputOpts);
844
+ } catch (error) {
845
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
846
+ process.exit(1);
847
+ }
848
+ });
849
+ return friends;
850
+ }
851
+
852
+ // src/commands/invites.ts
853
+ import { Command as Command8 } from "commander";
854
+ function createInvitesCommand() {
855
+ const invites = new Command8("invites").description("Invite code management commands");
856
+ invites.command("list").description("List your invite codes").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
857
+ try {
858
+ const client = await getClient(options.profile);
859
+ const invitesData = await client.listInvites();
860
+ output(invitesData, { json: options.json });
861
+ } catch (error) {
862
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
863
+ process.exit(1);
864
+ }
865
+ });
866
+ invites.command("create").description("Create invite codes").requiredOption("--count <n>", "Number of invites to create", "1").option("--note <text>", "Note for the invites").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
867
+ async (options) => {
868
+ try {
869
+ const client = await getClient(options.profile);
870
+ const count = Math.min(Math.max(parseInt(options.count ?? "1", 10), 1), 10);
871
+ const invites2 = await client.createInvites(count, options.note);
872
+ output(invites2, { json: options.json });
873
+ } catch (error) {
874
+ outputError(error instanceof Error ? error.message : String(error), {
875
+ json: options.json
876
+ });
877
+ process.exit(1);
878
+ }
879
+ }
880
+ );
881
+ invites.command("deactivate").description("Deactivate invite code").argument("<invite-id>", "Invite ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (inviteId, options) => {
882
+ try {
883
+ const client = await getClient(options.profile);
884
+ const invite = await client.deactivateInvite(inviteId);
885
+ output(invite, { json: options.json });
886
+ } catch (error) {
887
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
888
+ process.exit(1);
889
+ }
890
+ });
891
+ invites.command("delete").description("Delete invite code").argument("<invite-id>", "Invite ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (inviteId, options) => {
892
+ try {
893
+ const client = await getClient(options.profile);
894
+ await client.deleteInvite(inviteId);
895
+ const outputOpts = { json: options.json };
896
+ outputSuccess("Invite deleted", outputOpts);
897
+ } catch (error) {
898
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
899
+ process.exit(1);
900
+ }
901
+ });
902
+ return invites;
903
+ }
904
+
905
+ // src/commands/listen.ts
906
+ import { Command as Command9 } from "commander";
907
+ function createListenCommand() {
908
+ const listen = new Command9("listen").description("Listen to real-time events");
909
+ 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
+ async (channelId, options) => {
911
+ try {
912
+ const eventTypes = options.eventType?.split(",").map((t) => t.trim());
913
+ if (options.mode === "poll") {
914
+ const { getClient: getClient2 } = await import("./client-OCEGJPBJ.js");
915
+ const client = await getClient2(options.profile);
916
+ const limit = parseInt(options.last ?? "50", 10);
917
+ const result = await client.getMessages(channelId, limit);
918
+ if (options.json) {
919
+ for (const msg of result.messages) {
920
+ console.log(JSON.stringify({ type: "message:new", data: msg }));
921
+ }
922
+ } else {
923
+ for (const msg of result.messages) {
924
+ console.log(
925
+ `[${msg.createdAt}] ${msg.author?.username ?? "unknown"}: ${msg.content}`
926
+ );
927
+ }
928
+ }
929
+ return;
930
+ }
931
+ const socket = await getSocket(options.profile);
932
+ const timeoutMs = parseInt(options.timeout ?? "60", 10) * 1e3;
933
+ const maxCount = options.count ? parseInt(options.count, 10) : void 0;
934
+ let count = 0;
935
+ let timeoutId;
936
+ const cleanup = () => {
937
+ if (timeoutId) clearTimeout(timeoutId);
938
+ socket.disconnect();
939
+ };
940
+ timeoutId = setTimeout(() => {
941
+ if (!options.json) {
942
+ console.error("(timeout reached)");
943
+ }
944
+ cleanup();
945
+ process.exit(0);
946
+ }, timeoutMs);
947
+ const shouldOutput = (eventType) => {
948
+ if (!eventTypes) return true;
949
+ return eventTypes.includes(eventType);
950
+ };
951
+ const outputEvent = (type, data) => {
952
+ if (!shouldOutput(type)) return;
953
+ count++;
954
+ if (options.json) {
955
+ console.log(JSON.stringify({ type, data, timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
956
+ } else {
957
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
958
+ if (type === "message:new") {
959
+ const msg = data;
960
+ console.log(
961
+ `[${timestamp}] ${msg.author?.username ?? "unknown"}: ${msg.content ?? ""}`
962
+ );
963
+ } else {
964
+ console.log(`[${timestamp}] ${type}:`, JSON.stringify(data));
965
+ }
966
+ }
967
+ if (maxCount && count >= maxCount) {
968
+ cleanup();
969
+ process.exit(0);
970
+ }
971
+ };
972
+ socket.on("message:new", ((msg) => {
973
+ if (msg.channelId === channelId) {
974
+ outputEvent("message:new", msg);
975
+ }
976
+ }));
977
+ socket.on("message:updated", ((msg) => {
978
+ if (msg.channelId === channelId) {
979
+ outputEvent("message:updated", msg);
980
+ }
981
+ }));
982
+ socket.on("message:deleted", ((payload) => {
983
+ if (payload.channelId === channelId) {
984
+ outputEvent("message:deleted", payload);
985
+ }
986
+ }));
987
+ socket.on("reaction:add", ((payload) => {
988
+ outputEvent("reaction:add", payload);
989
+ }));
990
+ socket.on("reaction:remove", ((payload) => {
991
+ outputEvent("reaction:remove", payload);
992
+ }));
993
+ socket.on("member:typing", ((payload) => {
994
+ if (payload.channelId === channelId) {
995
+ outputEvent("member:typing", payload);
996
+ }
997
+ }));
998
+ socket.on("member:join", ((payload) => {
999
+ if (payload.channelId === channelId) {
1000
+ outputEvent("member:join", payload);
1001
+ }
1002
+ }));
1003
+ socket.on("member:leave", ((payload) => {
1004
+ if (payload.channelId === channelId) {
1005
+ outputEvent("member:leave", payload);
1006
+ }
1007
+ }));
1008
+ socket.connect();
1009
+ await socket.waitForConnect(5e3);
1010
+ await socket.joinChannel(channelId);
1011
+ if (!options.json) {
1012
+ console.error(`(listening to channel ${channelId}, timeout: ${timeoutMs}ms)`);
1013
+ }
1014
+ await new Promise(() => {
1015
+ });
1016
+ } catch (error) {
1017
+ outputError(error instanceof Error ? error.message : String(error), {
1018
+ json: options.json
1019
+ });
1020
+ process.exit(1);
1021
+ }
1022
+ }
1023
+ );
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
+ return listen;
1073
+ }
1074
+
1075
+ // src/commands/marketplace.ts
1076
+ import { Command as Command10 } from "commander";
1077
+ function createMarketplaceCommand() {
1078
+ const marketplace = new Command10("marketplace").description("Marketplace commands");
1079
+ const listings = marketplace.command("listings").description("Listing commands");
1080
+ 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
+ async (options) => {
1082
+ try {
1083
+ const client = await getClient(options.profile);
1084
+ const params = {};
1085
+ if (options.search) params.search = options.search;
1086
+ if (options.tags) params.tags = options.tags.split(",").map((t) => t.trim());
1087
+ if (options.minPrice) params.minPrice = parseFloat(options.minPrice);
1088
+ if (options.maxPrice) params.maxPrice = parseFloat(options.maxPrice);
1089
+ if (options.limit) params.limit = parseInt(options.limit, 10);
1090
+ if (options.offset) params.offset = parseInt(options.offset, 10);
1091
+ const results = await client.browseListings(params);
1092
+ output(results, { json: options.json });
1093
+ } catch (error) {
1094
+ outputError(error instanceof Error ? error.message : String(error), {
1095
+ json: options.json
1096
+ });
1097
+ process.exit(1);
1098
+ }
1099
+ }
1100
+ );
1101
+ listings.command("get").description("Get listing details").argument("<listing-id>", "Listing ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (listingId, options) => {
1102
+ try {
1103
+ const client = await getClient(options.profile);
1104
+ const listing = await client.getListing(listingId);
1105
+ output(listing, { json: options.json });
1106
+ } catch (error) {
1107
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1108
+ process.exit(1);
1109
+ }
1110
+ });
1111
+ listings.command("create").description("Create a listing").requiredOption("--agent-id <id>", "Agent ID").requiredOption("--title <title>", "Listing title").requiredOption("--price <n>", "Price per hour").option("--description <desc>", "Listing description").option("--tags <tags>", "Comma-separated tags").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1112
+ async (options) => {
1113
+ try {
1114
+ const client = await getClient(options.profile);
1115
+ const listing = await client.createListing({
1116
+ agentId: options.agentId,
1117
+ title: options.title,
1118
+ pricePerHour: parseFloat(options.price),
1119
+ description: options.description ?? "",
1120
+ tags: options.tags?.split(",").map((t) => t.trim())
1121
+ });
1122
+ output(listing, { json: options.json });
1123
+ } catch (error) {
1124
+ outputError(error instanceof Error ? error.message : String(error), {
1125
+ json: options.json
1126
+ });
1127
+ process.exit(1);
1128
+ }
1129
+ }
1130
+ );
1131
+ listings.command("update").description("Update a listing").argument("<listing-id>", "Listing ID").option("--title <title>", "New title").option("--price <n>", "New price per hour").option("--description <desc>", "New description").option("--tags <tags>", "Comma-separated tags").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1132
+ async (listingId, options) => {
1133
+ try {
1134
+ const client = await getClient(options.profile);
1135
+ const data = {};
1136
+ if (options.title) data.title = options.title;
1137
+ if (options.price) data.pricePerHour = parseFloat(options.price);
1138
+ if (options.description) data.description = options.description;
1139
+ if (options.tags) data.tags = options.tags.split(",").map((t) => t.trim());
1140
+ const listing = await client.updateListing(listingId, data);
1141
+ output(listing, { json: options.json });
1142
+ } catch (error) {
1143
+ outputError(error instanceof Error ? error.message : String(error), {
1144
+ json: options.json
1145
+ });
1146
+ process.exit(1);
1147
+ }
1148
+ }
1149
+ );
1150
+ listings.command("delete").description("Delete a listing").argument("<listing-id>", "Listing ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (listingId, options) => {
1151
+ try {
1152
+ const client = await getClient(options.profile);
1153
+ await client.deleteListing(listingId);
1154
+ const outputOpts = { json: options.json };
1155
+ outputSuccess("Listing deleted", outputOpts);
1156
+ } catch (error) {
1157
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1158
+ process.exit(1);
1159
+ }
1160
+ });
1161
+ const contracts = marketplace.command("contracts").description("Contract commands");
1162
+ contracts.command("list").description("List contracts").option("--as-renter", "Show only contracts where you are the renter").option("--as-owner", "Show only contracts where you are the owner").option("--active-only", "Show only active contracts").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1163
+ async (options) => {
1164
+ try {
1165
+ const client = await getClient(options.profile);
1166
+ const params = {};
1167
+ if (options.asRenter) params.role = "tenant";
1168
+ else if (options.asOwner) params.role = "owner";
1169
+ if (options.activeOnly) params.status = "active";
1170
+ const results = await client.listContracts(params);
1171
+ output(results, { json: options.json });
1172
+ } catch (error) {
1173
+ outputError(error instanceof Error ? error.message : String(error), {
1174
+ json: options.json
1175
+ });
1176
+ process.exit(1);
1177
+ }
1178
+ }
1179
+ );
1180
+ contracts.command("get").description("Get contract details").argument("<contract-id>", "Contract ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (contractId, options) => {
1181
+ try {
1182
+ const client = await getClient(options.profile);
1183
+ const contract = await client.getContract(contractId);
1184
+ output(contract, { json: options.json });
1185
+ } catch (error) {
1186
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1187
+ process.exit(1);
1188
+ }
1189
+ });
1190
+ contracts.command("create").description("Sign a contract for a listing").requiredOption("--listing-id <id>", "Listing ID").requiredOption("--hours <n>", "Number of hours").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1191
+ async (options) => {
1192
+ try {
1193
+ const client = await getClient(options.profile);
1194
+ const contract = await client.signContract({
1195
+ listingId: options.listingId,
1196
+ hours: parseInt(options.hours, 10)
1197
+ });
1198
+ output(contract, { json: options.json });
1199
+ } catch (error) {
1200
+ outputError(error instanceof Error ? error.message : String(error), {
1201
+ json: options.json
1202
+ });
1203
+ process.exit(1);
1204
+ }
1205
+ }
1206
+ );
1207
+ contracts.command("cancel").description("Terminate a contract").argument("<contract-id>", "Contract ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (contractId, options) => {
1208
+ try {
1209
+ const client = await getClient(options.profile);
1210
+ await client.terminateContract(contractId);
1211
+ const outputOpts = { json: options.json };
1212
+ outputSuccess("Contract terminated", outputOpts);
1213
+ } catch (error) {
1214
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1215
+ process.exit(1);
1216
+ }
1217
+ });
1218
+ return marketplace;
1219
+ }
1220
+
1221
+ // src/commands/media.ts
1222
+ import { readFileSync } from "fs";
1223
+ import { Command as Command11 } from "commander";
1224
+ function createMediaCommand() {
1225
+ const media = new Command11("media").description("Media management commands");
1226
+ 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
+ async (options) => {
1228
+ try {
1229
+ const client = await getClient(options.profile);
1230
+ const buffer = readFileSync(options.file);
1231
+ const filename = options.file.split("/").pop() || "file";
1232
+ const ext = filename.split(".").pop()?.toLowerCase();
1233
+ const contentTypeMap = {
1234
+ jpg: "image/jpeg",
1235
+ jpeg: "image/jpeg",
1236
+ png: "image/png",
1237
+ gif: "image/gif",
1238
+ webp: "image/webp",
1239
+ pdf: "application/pdf",
1240
+ txt: "text/plain",
1241
+ json: "application/json"
1242
+ };
1243
+ const contentType = contentTypeMap[ext || ""] || "application/octet-stream";
1244
+ const result = await client.uploadMedia(
1245
+ buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength),
1246
+ filename,
1247
+ contentType,
1248
+ options.messageId
1249
+ );
1250
+ output(result, { json: options.json });
1251
+ } catch (error) {
1252
+ outputError(error instanceof Error ? error.message : String(error), {
1253
+ json: options.json
1254
+ });
1255
+ process.exit(1);
1256
+ }
1257
+ }
1258
+ );
1259
+ media.command("download").description("Download a file").argument("<file-url>", "File URL or key").option("--output <path>", "Output file path").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1260
+ async (fileUrl, options) => {
1261
+ try {
1262
+ const client = await getClient(options.profile);
1263
+ const result = await client.downloadFile(fileUrl);
1264
+ if (options.output) {
1265
+ const { writeFileSync } = await import("fs");
1266
+ writeFileSync(options.output, Buffer.from(result.buffer));
1267
+ const outputOpts = { json: options.json };
1268
+ outputSuccess(`Downloaded to ${options.output}`, outputOpts);
1269
+ } else {
1270
+ output(
1271
+ {
1272
+ filename: result.filename,
1273
+ contentType: result.contentType,
1274
+ size: result.buffer.byteLength
1275
+ },
1276
+ { json: options.json }
1277
+ );
1278
+ }
1279
+ } catch (error) {
1280
+ outputError(error instanceof Error ? error.message : String(error), {
1281
+ json: options.json
1282
+ });
1283
+ process.exit(1);
1284
+ }
1285
+ }
1286
+ );
1287
+ return media;
1288
+ }
1289
+
1290
+ // src/commands/notifications.ts
1291
+ import { Command as Command12 } from "commander";
1292
+ function createNotificationsCommand() {
1293
+ const notifications = new Command12("notifications").description("Notification commands");
1294
+ 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
+ async (options) => {
1296
+ try {
1297
+ const client = await getClient(options.profile);
1298
+ const limit = parseInt(options.limit ?? "20", 10);
1299
+ const result = await client.listNotifications(limit);
1300
+ const notifications2 = Array.isArray(result) ? result : [];
1301
+ output(notifications2, { json: options.json });
1302
+ } catch (error) {
1303
+ outputError(error instanceof Error ? error.message : String(error), {
1304
+ json: options.json
1305
+ });
1306
+ process.exit(1);
1307
+ }
1308
+ }
1309
+ );
1310
+ notifications.command("mark-read").description("Mark notification as read").argument("<notification-id>", "Notification ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (notificationId, options) => {
1311
+ try {
1312
+ const client = await getClient(options.profile);
1313
+ await client.markNotificationRead(notificationId);
1314
+ const outputOpts = { json: options.json };
1315
+ outputSuccess("Notification marked as read", outputOpts);
1316
+ } catch (error) {
1317
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1318
+ process.exit(1);
1319
+ }
1320
+ });
1321
+ notifications.command("mark-all-read").description("Mark all notifications as read").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1322
+ try {
1323
+ const client = await getClient(options.profile);
1324
+ await client.markAllNotificationsRead();
1325
+ const outputOpts = { json: options.json };
1326
+ outputSuccess("All notifications marked as read", outputOpts);
1327
+ } catch (error) {
1328
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1329
+ process.exit(1);
1330
+ }
1331
+ });
1332
+ return notifications;
1333
+ }
1334
+
1335
+ // src/commands/oauth.ts
1336
+ import { Command as Command13 } from "commander";
1337
+ function createOAuthCommand() {
1338
+ const oauth = new Command13("oauth").description("OAuth management commands");
1339
+ oauth.command("list").description("List OAuth apps").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1340
+ try {
1341
+ const client = await getClient(options.profile);
1342
+ output([], { json: options.json });
1343
+ } catch (error) {
1344
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1345
+ process.exit(1);
1346
+ }
1347
+ });
1348
+ oauth.command("create").description("Create OAuth app").requiredOption("--name <name>", "App name").requiredOption("--redirect-uris <uris>", "Comma-separated redirect URIs").option("--scopes <scopes>", "Comma-separated scopes").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1349
+ async (options) => {
1350
+ try {
1351
+ const client = await getClient(options.profile);
1352
+ const app = await client.createOAuthApp({
1353
+ name: options.name,
1354
+ redirectUris: options.redirectUris.split(",").map((u) => u.trim()),
1355
+ scopes: options.scopes?.split(",").map((s) => s.trim())
1356
+ });
1357
+ output(app, { json: options.json });
1358
+ } catch (error) {
1359
+ outputError(error instanceof Error ? error.message : String(error), {
1360
+ json: options.json
1361
+ });
1362
+ process.exit(1);
1363
+ }
1364
+ }
1365
+ );
1366
+ oauth.command("update").description("Update OAuth app").argument("<app-id>", "App ID").option("--name <name>", "New name").option("--redirect-uris <uris>", "Comma-separated redirect URIs").option("--scopes <scopes>", "Comma-separated scopes").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1367
+ async (appId, options) => {
1368
+ try {
1369
+ const client = await getClient(options.profile);
1370
+ const data = {};
1371
+ if (options.name) data.name = options.name;
1372
+ if (options.redirectUris)
1373
+ data.redirectUris = options.redirectUris.split(",").map((u) => u.trim());
1374
+ if (options.scopes) data.scopes = options.scopes.split(",").map((s) => s.trim());
1375
+ const app = await client.updateOAuthApp(appId, data);
1376
+ output(app, { json: options.json });
1377
+ } catch (error) {
1378
+ outputError(error instanceof Error ? error.message : String(error), {
1379
+ json: options.json
1380
+ });
1381
+ process.exit(1);
1382
+ }
1383
+ }
1384
+ );
1385
+ oauth.command("delete").description("Delete OAuth app").argument("<app-id>", "App ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (appId, options) => {
1386
+ try {
1387
+ const client = await getClient(options.profile);
1388
+ await client.deleteOAuthApp(appId);
1389
+ const outputOpts = { json: options.json };
1390
+ outputSuccess("OAuth app deleted", outputOpts);
1391
+ } catch (error) {
1392
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1393
+ process.exit(1);
1394
+ }
1395
+ });
1396
+ return oauth;
1397
+ }
1398
+
1399
+ // src/commands/ping.ts
1400
+ import { Command as Command14 } from "commander";
1401
+ function createPingCommand() {
1402
+ const ping = new Command14("ping").description("Test connection to Shadow server");
1403
+ ping.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1404
+ const startTime = Date.now();
1405
+ const outputOpts = { json: options.json };
1406
+ try {
1407
+ const client = await getClient(options.profile);
1408
+ const user = await client.getMe();
1409
+ const latency = Date.now() - startTime;
1410
+ const result = {
1411
+ success: true,
1412
+ latency: `${latency}ms`,
1413
+ user: {
1414
+ id: user.id,
1415
+ username: user.username,
1416
+ displayName: user.displayName
1417
+ },
1418
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1419
+ };
1420
+ if (options.json) {
1421
+ output(result, outputOpts);
1422
+ } else {
1423
+ outputSuccess(`Connected to Shadow server (${latency}ms)`, outputOpts);
1424
+ console.log(`User: ${user.username} (${user.id})`);
1425
+ }
1426
+ process.exit(0);
1427
+ } catch (error) {
1428
+ const errorMessage = error instanceof Error ? error.message : String(error);
1429
+ const result = {
1430
+ success: false,
1431
+ error: errorMessage,
1432
+ latency: `${Date.now() - startTime}ms`,
1433
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1434
+ };
1435
+ if (options.json) {
1436
+ output(result, outputOpts);
1437
+ } else {
1438
+ outputError(`Failed to connect: ${errorMessage}`, outputOpts);
1439
+ console.log("\nTroubleshooting:");
1440
+ console.log(" - Check your server URL");
1441
+ console.log(" - Verify your token is valid");
1442
+ console.log(" - Run: shadowob config validate");
1443
+ }
1444
+ process.exit(1);
1445
+ }
1446
+ });
1447
+ return ping;
1448
+ }
1449
+
1450
+ // src/commands/search.ts
1451
+ import { Command as Command15 } from "commander";
1452
+ function createSearchCommand() {
1453
+ const search = new Command15("search").description("Search commands");
1454
+ 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
+ async (options) => {
1456
+ try {
1457
+ const client = await getClient(options.profile);
1458
+ const limit = Math.min(Math.max(parseInt(options.limit ?? "20", 10), 1), 100);
1459
+ const results = await client.searchMessages({
1460
+ q: options.query,
1461
+ serverId: options.serverId,
1462
+ channelId: options.channelId,
1463
+ limit
1464
+ });
1465
+ output(results, { json: options.json });
1466
+ } catch (error) {
1467
+ outputError(error instanceof Error ? error.message : String(error), {
1468
+ json: options.json
1469
+ });
1470
+ process.exit(1);
1471
+ }
1472
+ }
1473
+ );
1474
+ return search;
1475
+ }
1476
+
1477
+ // src/commands/servers.ts
1478
+ import { Command as Command16 } from "commander";
1479
+ function createServersCommand() {
1480
+ const servers = new Command16("servers").description("Server management commands");
1481
+ 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
+ try {
1483
+ const client = await getClient(options.profile);
1484
+ const servers2 = await client.listServers();
1485
+ output(servers2, { json: options.json });
1486
+ } catch (error) {
1487
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1488
+ process.exit(1);
1489
+ }
1490
+ });
1491
+ servers.command("get").description("Get server details").argument("<server-id>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
1492
+ try {
1493
+ const client = await getClient(options.profile);
1494
+ const server = await client.getServer(serverId);
1495
+ output(server, { json: options.json });
1496
+ } catch (error) {
1497
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1498
+ process.exit(1);
1499
+ }
1500
+ });
1501
+ servers.command("create").description("Create a new server").requiredOption("--name <name>", "Server name").option("--slug <slug>", "Server slug").option("--description <desc>", "Server description").option("--public", "Make server public").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1502
+ async (options) => {
1503
+ try {
1504
+ const client = await getClient(options.profile);
1505
+ const server = await client.createServer({
1506
+ name: options.name,
1507
+ slug: options.slug,
1508
+ description: options.description,
1509
+ isPublic: options.public
1510
+ });
1511
+ output(server, { json: options.json });
1512
+ } catch (error) {
1513
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1514
+ process.exit(1);
1515
+ }
1516
+ }
1517
+ );
1518
+ servers.command("join").description("Join a server").argument("<server-id>", "Server ID or slug").option("--invite-code <code>", "Invite code (if required)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1519
+ async (serverId, options) => {
1520
+ try {
1521
+ const client = await getClient(options.profile);
1522
+ const result = await client.joinServer(serverId, options.inviteCode);
1523
+ const outputOpts = { json: options.json };
1524
+ if (options.json) {
1525
+ output(result, outputOpts);
1526
+ } else {
1527
+ outputSuccess("Joined server", outputOpts);
1528
+ }
1529
+ } catch (error) {
1530
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1531
+ process.exit(1);
1532
+ }
1533
+ }
1534
+ );
1535
+ servers.command("leave").description("Leave a server").argument("<server-id>", "Server ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
1536
+ try {
1537
+ const client = await getClient(options.profile);
1538
+ await client.leaveServer(serverId);
1539
+ const outputOpts = { json: options.json };
1540
+ outputSuccess("Left server", outputOpts);
1541
+ } catch (error) {
1542
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1543
+ process.exit(1);
1544
+ }
1545
+ });
1546
+ servers.command("members").description("List server members").argument("<server-id>", "Server ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
1547
+ try {
1548
+ const client = await getClient(options.profile);
1549
+ const members = await client.getMembers(serverId);
1550
+ output(members, { json: options.json });
1551
+ } catch (error) {
1552
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1553
+ process.exit(1);
1554
+ }
1555
+ });
1556
+ servers.command("homepage").description("Get or set server homepage").argument("<server-id>", "Server ID or slug").option("--set <file>", 'Set homepage from HTML file (use "-" for stdin)').option("--clear", "Clear homepage (reset to default)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1557
+ async (serverId, options) => {
1558
+ try {
1559
+ const client = await getClient(options.profile);
1560
+ if (options.clear) {
1561
+ const result = await client.updateServerHomepage(serverId, null);
1562
+ output(result, { json: options.json });
1563
+ return;
1564
+ }
1565
+ if (options.set) {
1566
+ let html;
1567
+ if (options.set === "-") {
1568
+ const chunks = [];
1569
+ for await (const chunk of process.stdin) {
1570
+ chunks.push(Buffer.from(chunk));
1571
+ }
1572
+ html = Buffer.concat(chunks).toString("utf-8");
1573
+ } else {
1574
+ const { readFile: readFile2 } = await import("fs/promises");
1575
+ html = await readFile2(options.set, "utf-8");
1576
+ }
1577
+ const result = await client.updateServerHomepage(serverId, html);
1578
+ output(result, { json: options.json });
1579
+ return;
1580
+ }
1581
+ const server = await client.getServer(serverId);
1582
+ if (options.json) {
1583
+ output({ homepageHtml: server.homepageHtml }, { json: true });
1584
+ } else {
1585
+ console.log(server.homepageHtml ?? "(default homepage)");
1586
+ }
1587
+ } catch (error) {
1588
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1589
+ process.exit(1);
1590
+ }
1591
+ }
1592
+ );
1593
+ servers.command("discover").description("Discover public servers").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1594
+ try {
1595
+ const client = await getClient(options.profile);
1596
+ const servers2 = await client.discoverServers();
1597
+ output(servers2, { json: options.json });
1598
+ } catch (error) {
1599
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1600
+ process.exit(1);
1601
+ }
1602
+ });
1603
+ return servers;
1604
+ }
1605
+
1606
+ // src/commands/shop.ts
1607
+ import { Command as Command17 } from "commander";
1608
+ function createShopCommand() {
1609
+ const shop = new Command17("shop").description("Shop commands");
1610
+ 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
+ try {
1612
+ const client = await getClient(options.profile);
1613
+ const shopData = await client.getShop(serverId);
1614
+ output(shopData, { json: options.json });
1615
+ } catch (error) {
1616
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1617
+ process.exit(1);
1618
+ }
1619
+ });
1620
+ const products = shop.command("products").description("Product commands");
1621
+ products.command("list").description("List products").argument("<server-id>", "Server ID").option("--category-id <id>", "Filter by category").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1622
+ async (serverId, options) => {
1623
+ try {
1624
+ const client = await getClient(options.profile);
1625
+ const products2 = await client.listProducts(serverId, { categoryId: options.categoryId });
1626
+ output(products2, { json: options.json });
1627
+ } catch (error) {
1628
+ outputError(error instanceof Error ? error.message : String(error), {
1629
+ json: options.json
1630
+ });
1631
+ process.exit(1);
1632
+ }
1633
+ }
1634
+ );
1635
+ products.command("get").description("Get product details").argument("<server-id>", "Server ID").argument("<product-id>", "Product ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1636
+ async (serverId, productId, options) => {
1637
+ try {
1638
+ const client = await getClient(options.profile);
1639
+ const product = await client.getProduct(serverId, productId);
1640
+ output(product, { json: options.json });
1641
+ } catch (error) {
1642
+ outputError(error instanceof Error ? error.message : String(error), {
1643
+ json: options.json
1644
+ });
1645
+ process.exit(1);
1646
+ }
1647
+ }
1648
+ );
1649
+ const cart = shop.command("cart").description("Cart commands");
1650
+ cart.command("list").description("List cart items").argument("<server-id>", "Server ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
1651
+ try {
1652
+ const client = await getClient(options.profile);
1653
+ const cartData = await client.getCart(serverId);
1654
+ output(cartData, { json: options.json });
1655
+ } catch (error) {
1656
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1657
+ process.exit(1);
1658
+ }
1659
+ });
1660
+ const orders = shop.command("orders").description("Order commands");
1661
+ orders.command("list").description("List orders").argument("<server-id>", "Server ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
1662
+ try {
1663
+ const client = await getClient(options.profile);
1664
+ const orders2 = await client.listOrders(serverId);
1665
+ output(orders2, { json: options.json });
1666
+ } catch (error) {
1667
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1668
+ process.exit(1);
1669
+ }
1670
+ });
1671
+ orders.command("get").description("Get order details").argument("<server-id>", "Server ID").argument("<order-id>", "Order ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1672
+ async (serverId, orderId, options) => {
1673
+ try {
1674
+ const client = await getClient(options.profile);
1675
+ const order = await client.getOrder(serverId, orderId);
1676
+ output(order, { json: options.json });
1677
+ } catch (error) {
1678
+ outputError(error instanceof Error ? error.message : String(error), {
1679
+ json: options.json
1680
+ });
1681
+ process.exit(1);
1682
+ }
1683
+ }
1684
+ );
1685
+ const wallet = shop.command("wallet").description("Wallet commands");
1686
+ wallet.command("balance").description("Get wallet balance").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1687
+ try {
1688
+ const client = await getClient(options.profile);
1689
+ const wallet2 = await client.getWallet();
1690
+ output(wallet2, { json: options.json });
1691
+ } catch (error) {
1692
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1693
+ process.exit(1);
1694
+ }
1695
+ });
1696
+ return shop;
1697
+ }
1698
+
1699
+ // src/commands/status.ts
1700
+ import { Command as Command18 } from "commander";
1701
+ function createStatusCommand() {
1702
+ const status = new Command18("status").description("Show detailed status information");
1703
+ status.option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
1704
+ const outputOpts = { json: options.json };
1705
+ try {
1706
+ const profileName = options.profile ?? await configManager.getCurrentProfileName();
1707
+ const profile = await configManager.getProfile(options.profile);
1708
+ if (!profile) {
1709
+ outputError(
1710
+ profileName ? `Profile "${profileName}" not found` : "Not authenticated. Run: shadowob auth login",
1711
+ { json: options.json }
1712
+ );
1713
+ process.exit(1);
1714
+ }
1715
+ const client = await getClient(options.profile);
1716
+ const user = await client.getMe();
1717
+ const notifications = await client.listNotifications(1).catch(() => []);
1718
+ const statusInfo = {
1719
+ profile: {
1720
+ name: profileName,
1721
+ serverUrl: profile.serverUrl
1722
+ },
1723
+ user: {
1724
+ id: user.id,
1725
+ username: user.username,
1726
+ displayName: user.displayName,
1727
+ avatarUrl: user.avatarUrl
1728
+ },
1729
+ stats: {
1730
+ unreadNotifications: Array.isArray(notifications) ? notifications.length : 0
1731
+ },
1732
+ connection: {
1733
+ status: "connected",
1734
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1735
+ }
1736
+ };
1737
+ if (options.json) {
1738
+ output(statusInfo, outputOpts);
1739
+ } else {
1740
+ outputSuccess(`Connected as ${user.username}`, outputOpts);
1741
+ console.log("");
1742
+ console.log("Profile:");
1743
+ console.log(` Name: ${profileName}`);
1744
+ console.log(` Server: ${profile.serverUrl}`);
1745
+ console.log("");
1746
+ console.log("User:");
1747
+ console.log(` ID: ${user.id}`);
1748
+ console.log(` Username: ${user.username}`);
1749
+ if (user.displayName && user.displayName !== user.username) {
1750
+ console.log(` Display Name: ${user.displayName}`);
1751
+ }
1752
+ console.log("");
1753
+ console.log("Stats:");
1754
+ console.log(` Unread Notifications: ${statusInfo.stats.unreadNotifications}`);
1755
+ }
1756
+ process.exit(0);
1757
+ } catch (error) {
1758
+ const errorMessage = error instanceof Error ? error.message : String(error);
1759
+ if (options.json) {
1760
+ output(
1761
+ {
1762
+ error: errorMessage,
1763
+ connection: {
1764
+ status: "disconnected",
1765
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1766
+ }
1767
+ },
1768
+ outputOpts
1769
+ );
1770
+ } else {
1771
+ outputError(errorMessage, outputOpts);
1772
+ }
1773
+ process.exit(1);
1774
+ }
1775
+ });
1776
+ return status;
1777
+ }
1778
+
1779
+ // src/commands/threads.ts
1780
+ import { Command as Command19 } from "commander";
1781
+ function createThreadsCommand() {
1782
+ const threads = new Command19("threads").description("Thread commands");
1783
+ 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
+ try {
1785
+ const client = await getClient(options.profile);
1786
+ const threads2 = await client.listThreads(channelId);
1787
+ output(threads2, { json: options.json });
1788
+ } catch (error) {
1789
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1790
+ process.exit(1);
1791
+ }
1792
+ });
1793
+ threads.command("get").description("Get thread details").argument("<thread-id>", "Thread ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (threadId, options) => {
1794
+ try {
1795
+ const client = await getClient(options.profile);
1796
+ const thread = await client.getThread(threadId);
1797
+ output(thread, { json: options.json });
1798
+ } catch (error) {
1799
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1800
+ process.exit(1);
1801
+ }
1802
+ });
1803
+ threads.command("create").description("Create a thread").argument("<channel-id>", "Channel ID").requiredOption("--name <name>", "Thread name").requiredOption("--parent-message <id>", "Parent message ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1804
+ async (channelId, options) => {
1805
+ try {
1806
+ const client = await getClient(options.profile);
1807
+ const thread = await client.createThread(channelId, options.name, options.parentMessage);
1808
+ output(thread, { json: options.json });
1809
+ } catch (error) {
1810
+ outputError(error instanceof Error ? error.message : String(error), {
1811
+ json: options.json
1812
+ });
1813
+ process.exit(1);
1814
+ }
1815
+ }
1816
+ );
1817
+ threads.command("delete").description("Delete a thread").argument("<thread-id>", "Thread ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (threadId, options) => {
1818
+ try {
1819
+ const client = await getClient(options.profile);
1820
+ await client.deleteThread(threadId);
1821
+ const outputOpts = { json: options.json };
1822
+ outputSuccess("Thread deleted", outputOpts);
1823
+ } catch (error) {
1824
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1825
+ process.exit(1);
1826
+ }
1827
+ });
1828
+ threads.command("messages").description("List messages in a thread").argument("<thread-id>", "Thread 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(
1829
+ async (threadId, options) => {
1830
+ try {
1831
+ const client = await getClient(options.profile);
1832
+ const messages = await client.getThreadMessages(
1833
+ threadId,
1834
+ parseInt(options.limit ?? "50", 10),
1835
+ options.cursor
1836
+ );
1837
+ output(messages, { json: options.json });
1838
+ } catch (error) {
1839
+ outputError(error instanceof Error ? error.message : String(error), {
1840
+ json: options.json
1841
+ });
1842
+ process.exit(1);
1843
+ }
1844
+ }
1845
+ );
1846
+ threads.command("send").description("Send a message to a thread").argument("<thread-id>", "Thread ID").requiredOption("--content <text>", "Message content").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1847
+ async (threadId, options) => {
1848
+ try {
1849
+ const client = await getClient(options.profile);
1850
+ const message = await client.sendToThread(threadId, options.content);
1851
+ output(message, { json: options.json });
1852
+ } catch (error) {
1853
+ outputError(error instanceof Error ? error.message : String(error), {
1854
+ json: options.json
1855
+ });
1856
+ process.exit(1);
1857
+ }
1858
+ }
1859
+ );
1860
+ return threads;
1861
+ }
1862
+
1863
+ // src/commands/workspace.ts
1864
+ import { readFile } from "fs/promises";
1865
+ import { Command as Command20 } from "commander";
1866
+ function createWorkspaceCommand() {
1867
+ const workspace = new Command20("workspace").description("Workspace file management commands");
1868
+ 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
+ try {
1870
+ const client = await getClient(options.profile);
1871
+ const ws = await client.getWorkspace(serverId);
1872
+ output(ws, { json: options.json });
1873
+ } catch (error) {
1874
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1875
+ process.exit(1);
1876
+ }
1877
+ });
1878
+ workspace.command("tree").description("Get workspace file tree").argument("<server-id>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
1879
+ try {
1880
+ const client = await getClient(options.profile);
1881
+ const tree = await client.getWorkspaceTree(serverId);
1882
+ output(tree, { json: options.json });
1883
+ } catch (error) {
1884
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1885
+ process.exit(1);
1886
+ }
1887
+ });
1888
+ workspace.command("stats").description("Get workspace stats").argument("<server-id>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (serverId, options) => {
1889
+ try {
1890
+ const client = await getClient(options.profile);
1891
+ const stats = await client.getWorkspaceStats(serverId);
1892
+ output(stats, { json: options.json });
1893
+ } catch (error) {
1894
+ outputError(error instanceof Error ? error.message : String(error), { json: options.json });
1895
+ process.exit(1);
1896
+ }
1897
+ });
1898
+ workspace.command("children").description("List children in a folder").argument("<server-id>", "Server ID or slug").option("--parent-id <id>", "Parent folder ID (omit for root)").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1899
+ async (serverId, options) => {
1900
+ try {
1901
+ const client = await getClient(options.profile);
1902
+ const children = await client.getWorkspaceChildren(serverId, options.parentId ?? null);
1903
+ output(children, { json: options.json });
1904
+ } catch (error) {
1905
+ outputError(error instanceof Error ? error.message : String(error), {
1906
+ json: options.json
1907
+ });
1908
+ process.exit(1);
1909
+ }
1910
+ }
1911
+ );
1912
+ const files = workspace.command("files").description("File operations");
1913
+ files.command("get").description("Get file details").argument("<server-id>", "Server ID or slug").argument("<file-id>", "File ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1914
+ async (serverId, fileId, options) => {
1915
+ try {
1916
+ const client = await getClient(options.profile);
1917
+ const file = await client.getWorkspaceFile(serverId, fileId);
1918
+ output(file, { json: options.json });
1919
+ } catch (error) {
1920
+ outputError(error instanceof Error ? error.message : String(error), {
1921
+ json: options.json
1922
+ });
1923
+ process.exit(1);
1924
+ }
1925
+ }
1926
+ );
1927
+ files.command("update").description("Update a file").argument("<server-id>", "Server ID or slug").argument("<file-id>", "File ID").option("--name <name>", "New name").option("--parent-id <id>", "New parent folder ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1928
+ async (serverId, fileId, options) => {
1929
+ try {
1930
+ const client = await getClient(options.profile);
1931
+ const file = await client.updateWorkspaceFile(serverId, fileId, {
1932
+ name: options.name,
1933
+ parentId: options.parentId
1934
+ });
1935
+ output(file, { json: options.json });
1936
+ } catch (error) {
1937
+ outputError(error instanceof Error ? error.message : String(error), {
1938
+ json: options.json
1939
+ });
1940
+ process.exit(1);
1941
+ }
1942
+ }
1943
+ );
1944
+ files.command("delete").description("Delete a file").argument("<server-id>", "Server ID or slug").argument("<file-id>", "File ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1945
+ async (serverId, fileId, options) => {
1946
+ try {
1947
+ const client = await getClient(options.profile);
1948
+ await client.deleteWorkspaceFile(serverId, fileId);
1949
+ const outputOpts = { json: options.json };
1950
+ outputSuccess("File deleted", outputOpts);
1951
+ } catch (error) {
1952
+ outputError(error instanceof Error ? error.message : String(error), {
1953
+ json: options.json
1954
+ });
1955
+ process.exit(1);
1956
+ }
1957
+ }
1958
+ );
1959
+ files.command("upload").description("Upload a file").argument("<server-id>", "Server ID or slug").requiredOption("--file <path>", "File path to upload").option("--name <name>", "File name (defaults to filename)").option("--parent-id <id>", "Parent folder ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1960
+ async (serverId, options) => {
1961
+ try {
1962
+ const client = await getClient(options.profile);
1963
+ const content = await readFile(options.file);
1964
+ const blob = new Blob([content]);
1965
+ const name = options.name ?? options.file.split("/").pop() ?? "upload";
1966
+ const result = await client.uploadWorkspaceFile(serverId, blob, name, options.parentId);
1967
+ output(result, { json: options.json });
1968
+ } catch (error) {
1969
+ outputError(error instanceof Error ? error.message : String(error), {
1970
+ json: options.json
1971
+ });
1972
+ process.exit(1);
1973
+ }
1974
+ }
1975
+ );
1976
+ files.command("search").description("Search files").argument("<server-id>", "Server ID or slug").option("--search-text <text>", "Search text").option("--ext <ext>", "File extension").option("--parent-id <id>", "Parent folder ID").option("--limit <n>", "Limit results", "50").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1977
+ async (serverId, options) => {
1978
+ try {
1979
+ const client = await getClient(options.profile);
1980
+ const files2 = await client.searchWorkspaceFiles(serverId, {
1981
+ searchText: options.searchText,
1982
+ ext: options.ext,
1983
+ parentId: options.parentId,
1984
+ limit: parseInt(options.limit ?? "50", 10)
1985
+ });
1986
+ output(files2, { json: options.json });
1987
+ } catch (error) {
1988
+ outputError(error instanceof Error ? error.message : String(error), {
1989
+ json: options.json
1990
+ });
1991
+ process.exit(1);
1992
+ }
1993
+ }
1994
+ );
1995
+ const folders = workspace.command("folders").description("Folder operations");
1996
+ folders.command("create").description("Create a folder").argument("<server-id>", "Server ID or slug").requiredOption("--name <name>", "Folder name").option("--parent-id <id>", "Parent folder ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
1997
+ async (serverId, options) => {
1998
+ try {
1999
+ const client = await getClient(options.profile);
2000
+ const folder = await client.createWorkspaceFolder(serverId, {
2001
+ name: options.name,
2002
+ parentId: options.parentId
2003
+ });
2004
+ output(folder, { json: options.json });
2005
+ } catch (error) {
2006
+ outputError(error instanceof Error ? error.message : String(error), {
2007
+ json: options.json
2008
+ });
2009
+ process.exit(1);
2010
+ }
2011
+ }
2012
+ );
2013
+ folders.command("update").description("Update a folder").argument("<server-id>", "Server ID or slug").argument("<folder-id>", "Folder ID").option("--name <name>", "New name").option("--parent-id <id>", "New parent folder ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
2014
+ async (serverId, folderId, options) => {
2015
+ try {
2016
+ const client = await getClient(options.profile);
2017
+ const folder = await client.updateWorkspaceFolder(serverId, folderId, {
2018
+ name: options.name,
2019
+ parentId: options.parentId
2020
+ });
2021
+ output(folder, { json: options.json });
2022
+ } catch (error) {
2023
+ outputError(error instanceof Error ? error.message : String(error), {
2024
+ json: options.json
2025
+ });
2026
+ process.exit(1);
2027
+ }
2028
+ }
2029
+ );
2030
+ folders.command("delete").description("Delete a folder").argument("<server-id>", "Server ID or slug").argument("<folder-id>", "Folder ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
2031
+ async (serverId, folderId, options) => {
2032
+ try {
2033
+ const client = await getClient(options.profile);
2034
+ await client.deleteWorkspaceFolder(serverId, folderId);
2035
+ const outputOpts = { json: options.json };
2036
+ outputSuccess("Folder deleted", outputOpts);
2037
+ } catch (error) {
2038
+ outputError(error instanceof Error ? error.message : String(error), {
2039
+ json: options.json
2040
+ });
2041
+ process.exit(1);
2042
+ }
2043
+ }
2044
+ );
2045
+ return workspace;
2046
+ }
2047
+
2048
+ // src/index.ts
2049
+ var program = new Command21();
2050
+ program.name("shadowob").description("Shadow CLI \u2014 command-line interface for Shadow servers").version("0.1.0").configureHelp({
2051
+ sortSubcommands: true
2052
+ });
2053
+ program.option("--profile <name>", "Profile to use (default: current)");
2054
+ program.addCommand(createAuthCommand());
2055
+ program.addCommand(createServersCommand());
2056
+ program.addCommand(createChannelsCommand());
2057
+ program.addCommand(createThreadsCommand());
2058
+ program.addCommand(createAgentsCommand());
2059
+ program.addCommand(createListenCommand());
2060
+ program.addCommand(createDmsCommand());
2061
+ program.addCommand(createWorkspaceCommand());
2062
+ program.addCommand(createShopCommand());
2063
+ program.addCommand(createAppsCommand());
2064
+ program.addCommand(createNotificationsCommand());
2065
+ program.addCommand(createFriendsCommand());
2066
+ program.addCommand(createInvitesCommand());
2067
+ program.addCommand(createOAuthCommand());
2068
+ program.addCommand(createMarketplaceCommand());
2069
+ program.addCommand(createMediaCommand());
2070
+ program.addCommand(createSearchCommand());
2071
+ program.addCommand(createConfigCommand());
2072
+ program.addCommand(createPingCommand());
2073
+ program.addCommand(createStatusCommand());
2074
+ program.parse();