@shadowob/cli 1.1.6 → 1.1.7
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.
|
@@ -8,6 +8,11 @@ import { homedir } from "os";
|
|
|
8
8
|
import { dirname, join } from "path";
|
|
9
9
|
var DEFAULT_CONFIG_DIR = join(homedir(), ".shadowob");
|
|
10
10
|
var _DEFAULT_CONFIG_FILE = join(DEFAULT_CONFIG_DIR, "shadowob.config.json");
|
|
11
|
+
function expandEnvPlaceholders(value) {
|
|
12
|
+
return value.replace(/\$\{(?:env:)?([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, key) => {
|
|
13
|
+
return process.env[key] ?? "";
|
|
14
|
+
});
|
|
15
|
+
}
|
|
11
16
|
var ConfigManager = class {
|
|
12
17
|
config = null;
|
|
13
18
|
configFile;
|
|
@@ -39,7 +44,12 @@ var ConfigManager = class {
|
|
|
39
44
|
const config = await this.load();
|
|
40
45
|
const profileName = name ?? config.currentProfile;
|
|
41
46
|
if (!profileName) return null;
|
|
42
|
-
|
|
47
|
+
const profile = config.profiles[profileName];
|
|
48
|
+
if (!profile) return null;
|
|
49
|
+
return {
|
|
50
|
+
serverUrl: expandEnvPlaceholders(profile.serverUrl),
|
|
51
|
+
token: expandEnvPlaceholders(profile.token)
|
|
52
|
+
};
|
|
43
53
|
}
|
|
44
54
|
async getCurrentProfileName() {
|
|
45
55
|
const config = await this.load();
|
|
@@ -110,21 +120,23 @@ var ConfigManager = class {
|
|
|
110
120
|
}
|
|
111
121
|
for (const [name, profile] of Object.entries(config.profiles)) {
|
|
112
122
|
const profileResult = { valid: true };
|
|
113
|
-
|
|
123
|
+
const serverUrl = expandEnvPlaceholders(profile.serverUrl);
|
|
124
|
+
const token = expandEnvPlaceholders(profile.token);
|
|
125
|
+
if (!serverUrl) {
|
|
114
126
|
profileResult.valid = false;
|
|
115
127
|
result.errors.push(`Profile "${name}" missing serverUrl`);
|
|
116
128
|
} else {
|
|
117
129
|
try {
|
|
118
|
-
new URL(
|
|
130
|
+
new URL(serverUrl);
|
|
119
131
|
} catch {
|
|
120
132
|
profileResult.valid = false;
|
|
121
|
-
result.errors.push(`Profile "${name}" has invalid serverUrl: ${
|
|
133
|
+
result.errors.push(`Profile "${name}" has invalid serverUrl: ${serverUrl}`);
|
|
122
134
|
}
|
|
123
135
|
}
|
|
124
|
-
if (!
|
|
136
|
+
if (!token) {
|
|
125
137
|
profileResult.valid = false;
|
|
126
138
|
result.errors.push(`Profile "${name}" missing token`);
|
|
127
|
-
} else if (!
|
|
139
|
+
} else if (!token.includes(".")) {
|
|
128
140
|
result.warnings.push(`Profile "${name}" token does not look like a JWT`);
|
|
129
141
|
}
|
|
130
142
|
result.profileResults[name] = profileResult;
|
|
@@ -164,6 +176,12 @@ var ConfigManager = class {
|
|
|
164
176
|
var configManager = new ConfigManager();
|
|
165
177
|
|
|
166
178
|
// src/utils/client.ts
|
|
179
|
+
var DEFAULT_SERVER_URL = "https://shadowob.com";
|
|
180
|
+
function resolveServerFlag(value) {
|
|
181
|
+
const server = value ?? process.env.SHADOWOB_SERVER_ID;
|
|
182
|
+
if (!server) throw new Error("Missing server. Pass --server or set SHADOWOB_SERVER_ID.");
|
|
183
|
+
return server;
|
|
184
|
+
}
|
|
167
185
|
async function getConfig(profile) {
|
|
168
186
|
const config = await configManager.getProfile(profile);
|
|
169
187
|
if (!config) {
|
|
@@ -251,6 +269,8 @@ async function handleCommand(fn, options, outputFn, errorFn) {
|
|
|
251
269
|
|
|
252
270
|
export {
|
|
253
271
|
configManager,
|
|
272
|
+
DEFAULT_SERVER_URL,
|
|
273
|
+
resolveServerFlag,
|
|
254
274
|
getClient,
|
|
255
275
|
getClientWithToken,
|
|
256
276
|
getSocket,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DEFAULT_SERVER_URL,
|
|
2
3
|
formatError,
|
|
3
4
|
getClient,
|
|
4
5
|
getClientWithToken,
|
|
@@ -10,9 +11,11 @@ import {
|
|
|
10
11
|
parseNonNegativeInt,
|
|
11
12
|
parsePositiveInt,
|
|
12
13
|
parsePrice,
|
|
13
|
-
requireOption
|
|
14
|
-
|
|
14
|
+
requireOption,
|
|
15
|
+
resolveServerFlag
|
|
16
|
+
} from "./chunk-S6XCO6ZW.js";
|
|
15
17
|
export {
|
|
18
|
+
DEFAULT_SERVER_URL,
|
|
16
19
|
formatError,
|
|
17
20
|
getClient,
|
|
18
21
|
getClientWithToken,
|
|
@@ -24,5 +27,6 @@ export {
|
|
|
24
27
|
parseNonNegativeInt,
|
|
25
28
|
parsePositiveInt,
|
|
26
29
|
parsePrice,
|
|
27
|
-
requireOption
|
|
30
|
+
requireOption,
|
|
31
|
+
resolveServerFlag
|
|
28
32
|
};
|
package/dist/index.js
CHANGED
|
@@ -4,13 +4,14 @@ import {
|
|
|
4
4
|
getClient,
|
|
5
5
|
getClientWithToken,
|
|
6
6
|
getSocket,
|
|
7
|
-
parsePositiveInt
|
|
8
|
-
|
|
7
|
+
parsePositiveInt,
|
|
8
|
+
resolveServerFlag
|
|
9
|
+
} from "./chunk-S6XCO6ZW.js";
|
|
9
10
|
|
|
10
11
|
// src/index.ts
|
|
11
12
|
import { Command as Command28 } from "commander";
|
|
12
13
|
|
|
13
|
-
// src/commands/
|
|
14
|
+
// src/commands/api-tokens.ts
|
|
14
15
|
import { Command } from "commander";
|
|
15
16
|
|
|
16
17
|
// src/utils/output.ts
|
|
@@ -88,139 +89,32 @@ function formatObject(obj) {
|
|
|
88
89
|
formattedValue = chalk.gray("null");
|
|
89
90
|
} else if (typeof value === "boolean") {
|
|
90
91
|
formattedValue = value ? chalk.green("true") : chalk.red("false");
|
|
91
|
-
} else if (
|
|
92
|
+
} else if (Array.isArray(value)) {
|
|
93
|
+
if (value.length > 0 && typeof value[0] === "object" && value[0] !== null) {
|
|
94
|
+
console.log(chalk.gray(formattedKey));
|
|
95
|
+
formatArray(value);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
92
98
|
formattedValue = JSON.stringify(value);
|
|
99
|
+
} else if (typeof value === "object") {
|
|
100
|
+
formattedValue = formatNestedValue(value);
|
|
93
101
|
} else {
|
|
94
102
|
formattedValue = String(value);
|
|
95
103
|
}
|
|
96
104
|
console.log(`${chalk.gray(formattedKey)} ${formattedValue}`);
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const client = await getClient(options.profile);
|
|
106
|
-
const agents2 = await client.listAgents();
|
|
107
|
-
output(agents2, { json: options.json });
|
|
108
|
-
} catch (error) {
|
|
109
|
-
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
110
|
-
process.exit(1);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
agents.command("get").description("Get agent details").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
|
|
114
|
-
try {
|
|
115
|
-
const client = await getClient(options.profile);
|
|
116
|
-
const agent = await client.getAgent(agentId);
|
|
117
|
-
output(agent, { json: options.json });
|
|
118
|
-
} catch (error) {
|
|
119
|
-
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
agents.command("create").description("Create a new agent").requiredOption("--name <name>", "Agent name").requiredOption("--username <username>", "Agent username").option("--display-name <name>", "Display name").option("--avatar-url <url>", "Avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
124
|
-
async (options) => {
|
|
125
|
-
try {
|
|
126
|
-
const client = await getClient(options.profile);
|
|
127
|
-
const agent = await client.createAgent({
|
|
128
|
-
name: options.name,
|
|
129
|
-
username: options.username,
|
|
130
|
-
displayName: options.displayName,
|
|
131
|
-
avatarUrl: options.avatarUrl
|
|
132
|
-
});
|
|
133
|
-
output(agent, { json: options.json });
|
|
134
|
-
} catch (error) {
|
|
135
|
-
outputError(error instanceof Error ? error.message : String(error), {
|
|
136
|
-
json: options.json
|
|
137
|
-
});
|
|
138
|
-
process.exit(1);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
);
|
|
142
|
-
agents.command("update").description("Update an agent").argument("<agent-id>", "Agent ID").option("--name <name>", "New name").option("--display-name <name>", "New display name").option("--avatar-url <url>", "New avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
143
|
-
async (agentId, options) => {
|
|
144
|
-
try {
|
|
145
|
-
const client = await getClient(options.profile);
|
|
146
|
-
const agent = await client.updateAgent(agentId, {
|
|
147
|
-
name: options.name,
|
|
148
|
-
displayName: options.displayName,
|
|
149
|
-
avatarUrl: options.avatarUrl
|
|
150
|
-
});
|
|
151
|
-
output(agent, { json: options.json });
|
|
152
|
-
} catch (error) {
|
|
153
|
-
outputError(error instanceof Error ? error.message : String(error), {
|
|
154
|
-
json: options.json
|
|
155
|
-
});
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
);
|
|
160
|
-
agents.command("delete").description("Delete an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
|
|
161
|
-
try {
|
|
162
|
-
const client = await getClient(options.profile);
|
|
163
|
-
await client.deleteAgent(agentId);
|
|
164
|
-
const outputOpts = { json: options.json };
|
|
165
|
-
outputSuccess("Agent deleted", outputOpts);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
168
|
-
process.exit(1);
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
agents.command("start").description("Start an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
|
|
172
|
-
try {
|
|
173
|
-
const client = await getClient(options.profile);
|
|
174
|
-
await client.startAgent(agentId);
|
|
175
|
-
const outputOpts = { json: options.json };
|
|
176
|
-
outputSuccess("Agent started", outputOpts);
|
|
177
|
-
} catch (error) {
|
|
178
|
-
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
179
|
-
process.exit(1);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
agents.command("stop").description("Stop an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
|
|
183
|
-
try {
|
|
184
|
-
const client = await getClient(options.profile);
|
|
185
|
-
await client.stopAgent(agentId);
|
|
186
|
-
const outputOpts = { json: options.json };
|
|
187
|
-
outputSuccess("Agent stopped", outputOpts);
|
|
188
|
-
} catch (error) {
|
|
189
|
-
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
190
|
-
process.exit(1);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
agents.command("token").description("Generate a new token for an agent").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
|
|
194
|
-
try {
|
|
195
|
-
const client = await getClient(options.profile);
|
|
196
|
-
const result = await client.generateAgentToken(agentId);
|
|
197
|
-
if (options.json) {
|
|
198
|
-
output(result, { json: true });
|
|
199
|
-
} else {
|
|
200
|
-
console.log(result.token);
|
|
201
|
-
}
|
|
202
|
-
} catch (error) {
|
|
203
|
-
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
agents.command("config").description("Get agent remote config").argument("<agent-id>", "Agent ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (agentId, options) => {
|
|
208
|
-
try {
|
|
209
|
-
const client = await getClient(options.profile);
|
|
210
|
-
const config = await client.getAgentConfig(agentId);
|
|
211
|
-
output(config, { json: options.json });
|
|
212
|
-
} catch (error) {
|
|
213
|
-
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
214
|
-
process.exit(1);
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
return agents;
|
|
107
|
+
function formatNestedValue(obj) {
|
|
108
|
+
const username = obj.username || obj.name || obj.displayName;
|
|
109
|
+
if (username) {
|
|
110
|
+
return username;
|
|
111
|
+
}
|
|
112
|
+
return JSON.stringify(obj);
|
|
218
113
|
}
|
|
219
114
|
|
|
220
115
|
// src/commands/api-tokens.ts
|
|
221
|
-
import { Command as Command2 } from "commander";
|
|
222
116
|
function createApiTokensCommand() {
|
|
223
|
-
const tokens = new
|
|
117
|
+
const tokens = new Command("api-tokens").description("API token management commands");
|
|
224
118
|
tokens.command("list").description("List all API tokens").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
|
|
225
119
|
try {
|
|
226
120
|
const client = await getClient(options.profile);
|
|
@@ -270,12 +164,7 @@ function createApiTokensCommand() {
|
|
|
270
164
|
// src/commands/app.ts
|
|
271
165
|
import { readFile, writeFile } from "fs/promises";
|
|
272
166
|
import { basename } from "path";
|
|
273
|
-
import { Command as
|
|
274
|
-
function resolveServer(value) {
|
|
275
|
-
const server = value ?? process.env.SHADOWOB_SERVER_ID;
|
|
276
|
-
if (!server) throw new Error("Missing server. Pass --server or set SHADOWOB_SERVER_ID.");
|
|
277
|
-
return server;
|
|
278
|
-
}
|
|
167
|
+
import { Command as Command2 } from "commander";
|
|
279
168
|
function parseJsonInput(value) {
|
|
280
169
|
if (!value) return {};
|
|
281
170
|
const parsed = JSON.parse(value);
|
|
@@ -287,16 +176,26 @@ function parseJsonInput(value) {
|
|
|
287
176
|
async function readJsonFile(path) {
|
|
288
177
|
return JSON.parse(await readFile(path, "utf8"));
|
|
289
178
|
}
|
|
179
|
+
function parsePermissions(value) {
|
|
180
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
181
|
+
}
|
|
290
182
|
function commandHandlerError(error, json) {
|
|
291
183
|
outputError(error instanceof Error ? error.message : String(error), { json });
|
|
292
184
|
process.exit(1);
|
|
293
185
|
}
|
|
294
186
|
function createAppCommand() {
|
|
295
|
-
const app = new
|
|
187
|
+
const app = new Command2("app").description("Server App integration commands");
|
|
296
188
|
app.command("list").description("List apps installed in a server").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
|
|
297
189
|
try {
|
|
298
190
|
const client = await getClient(options.profile);
|
|
299
|
-
|
|
191
|
+
const apps = await client.listServerApps(resolveServerFlag(options.server));
|
|
192
|
+
output(
|
|
193
|
+
apps.map((entry) => ({
|
|
194
|
+
id: entry.id,
|
|
195
|
+
name: `${entry.appKey} (${entry.name})`
|
|
196
|
+
})),
|
|
197
|
+
{ json: options.json }
|
|
198
|
+
);
|
|
300
199
|
} catch (error) {
|
|
301
200
|
commandHandlerError(error, options.json);
|
|
302
201
|
}
|
|
@@ -310,7 +209,7 @@ function createAppCommand() {
|
|
|
310
209
|
const client = await getClient(options.profile);
|
|
311
210
|
const manifest = options.manifestFile ? await readJsonFile(options.manifestFile) : void 0;
|
|
312
211
|
output(
|
|
313
|
-
await client.discoverServerApp(
|
|
212
|
+
await client.discoverServerApp(resolveServerFlag(options.server), {
|
|
314
213
|
manifestUrl: options.manifestUrl,
|
|
315
214
|
manifest
|
|
316
215
|
}),
|
|
@@ -329,7 +228,7 @@ function createAppCommand() {
|
|
|
329
228
|
}
|
|
330
229
|
const client = await getClient(options.profile);
|
|
331
230
|
const manifest = options.manifestFile ? await readJsonFile(options.manifestFile) : void 0;
|
|
332
|
-
const result = await client.installServerApp(
|
|
231
|
+
const result = await client.installServerApp(resolveServerFlag(options.server), {
|
|
333
232
|
manifestUrl: options.manifestUrl,
|
|
334
233
|
manifest
|
|
335
234
|
});
|
|
@@ -343,7 +242,7 @@ function createAppCommand() {
|
|
|
343
242
|
async (appKey, options) => {
|
|
344
243
|
try {
|
|
345
244
|
const client = await getClient(options.profile);
|
|
346
|
-
output(await client.getServerApp(
|
|
245
|
+
output(await client.getServerApp(resolveServerFlag(options.server), appKey), {
|
|
347
246
|
json: options.json
|
|
348
247
|
});
|
|
349
248
|
} catch (error) {
|
|
@@ -351,16 +250,57 @@ function createAppCommand() {
|
|
|
351
250
|
}
|
|
352
251
|
}
|
|
353
252
|
);
|
|
354
|
-
app.command("grant").description("Grant a Buddy access to an installed server App").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").requiredOption("--buddy <
|
|
253
|
+
app.command("grant").description("Grant a Buddy access to an installed server App").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").requiredOption("--buddy <buddy-id>", "Buddy ID").requiredOption("--permissions <permissions>", "Comma-separated permissions, or *").option("--approval-mode <mode>", "none, first_time, every_time, or policy", "none").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
355
254
|
async (appKey, options) => {
|
|
356
255
|
try {
|
|
357
256
|
const client = await getClient(options.profile);
|
|
358
|
-
const permissions = options.permissions
|
|
359
|
-
const result = await client.grantServerAppToBuddy(
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
257
|
+
const permissions = parsePermissions(options.permissions);
|
|
258
|
+
const result = await client.grantServerAppToBuddy(
|
|
259
|
+
resolveServerFlag(options.server),
|
|
260
|
+
appKey,
|
|
261
|
+
{
|
|
262
|
+
buddyAgentId: options.buddy,
|
|
263
|
+
permissions,
|
|
264
|
+
approvalMode: options.approvalMode
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
output(result, { json: options.json });
|
|
268
|
+
} catch (error) {
|
|
269
|
+
commandHandlerError(error, options.json);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
app.command("defaults").description("Set default app permissions that members and Buddies can use without prompting").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").requiredOption("--permissions <permissions>", "Comma-separated permissions, or *").option("--approval-mode <mode>", "none, first_time, every_time, or policy", "none").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
274
|
+
async (appKey, options) => {
|
|
275
|
+
try {
|
|
276
|
+
const client = await getClient(options.profile);
|
|
277
|
+
const result = await client.updateServerAppAccessPolicy(
|
|
278
|
+
resolveServerFlag(options.server),
|
|
279
|
+
appKey,
|
|
280
|
+
{
|
|
281
|
+
defaultPermissions: parsePermissions(options.permissions),
|
|
282
|
+
defaultApprovalMode: options.approvalMode
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
output(result, { json: options.json });
|
|
286
|
+
} catch (error) {
|
|
287
|
+
commandHandlerError(error, options.json);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
app.command("approve").description("Approve one app command for yourself or a Buddy after a first-use prompt").argument("<app-key>", "App key").argument("<command>", "Command name").requiredOption("--server <server>", "Server ID or slug").option("--buddy <buddy-id>", "Buddy ID to approve for").option("--no-remember", "Approve only the immediate retry window").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
292
|
+
async (appKey, commandName, options) => {
|
|
293
|
+
try {
|
|
294
|
+
const client = await getClient(options.profile);
|
|
295
|
+
const result = await client.approveServerAppCommand(
|
|
296
|
+
resolveServerFlag(options.server),
|
|
297
|
+
appKey,
|
|
298
|
+
{
|
|
299
|
+
commandName,
|
|
300
|
+
buddyAgentId: options.buddy,
|
|
301
|
+
remember: options.remember
|
|
302
|
+
}
|
|
303
|
+
);
|
|
364
304
|
output(result, { json: options.json });
|
|
365
305
|
} catch (error) {
|
|
366
306
|
commandHandlerError(error, options.json);
|
|
@@ -370,7 +310,7 @@ function createAppCommand() {
|
|
|
370
310
|
app.command("discover").description("Emit Skill-style command discovery for server Apps").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
|
|
371
311
|
try {
|
|
372
312
|
const client = await getClient(options.profile);
|
|
373
|
-
const server =
|
|
313
|
+
const server = resolveServerFlag(options.server);
|
|
374
314
|
const apps = await client.listServerApps(server);
|
|
375
315
|
const docs = await Promise.all(
|
|
376
316
|
apps.map((entry) => client.getServerAppSkills(server, entry.appKey))
|
|
@@ -388,7 +328,7 @@ function createAppCommand() {
|
|
|
388
328
|
async (appKey, options) => {
|
|
389
329
|
try {
|
|
390
330
|
const client = await getClient(options.profile);
|
|
391
|
-
const result = await client.getServerAppSkills(
|
|
331
|
+
const result = await client.getServerAppSkills(resolveServerFlag(options.server), appKey);
|
|
392
332
|
if (options.json) output(result, { json: true });
|
|
393
333
|
else console.log(result.markdown);
|
|
394
334
|
} catch (error) {
|
|
@@ -396,18 +336,22 @@ function createAppCommand() {
|
|
|
396
336
|
}
|
|
397
337
|
}
|
|
398
338
|
);
|
|
399
|
-
app.command("call").description("Call a server App command").argument("<app-key>", "App key").argument("<command>", "Command name").requiredOption("--server <server>", "Server ID or slug").option("--json-input <json>", "JSON command input").option("--input-file <path>", "Read JSON command input from file").option("--file <path>", "Attach a binary file").option("--field <field>", "Multipart file field name", "file").option("--output <path>", "Write binary dataBase64 response to this path").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
339
|
+
app.command("call").description("Call a server App command").argument("<app-key>", "App key").argument("<command>", "Command name").requiredOption("--server <server>", "Server ID or slug").option("--json-input <json>", "JSON command input").option("--input-file <path>", "Read JSON command input from file").option("--channel-id <id>", "Current Shadow channel ID for approval prompts and app context").option("--file <path>", "Attach a binary file").option("--field <field>", "Multipart file field name", "file").option("--output <path>", "Write binary dataBase64 response to this path").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
400
340
|
async (appKey, commandName, options) => {
|
|
401
341
|
try {
|
|
402
342
|
const client = await getClient(options.profile);
|
|
403
343
|
const input = options.inputFile ? await readJsonFile(options.inputFile) : parseJsonInput(options.jsonInput);
|
|
404
|
-
const server =
|
|
344
|
+
const server = resolveServerFlag(options.server);
|
|
405
345
|
const result = options.file ? await client.callServerAppCommandMultipart(server, appKey, commandName, {
|
|
406
346
|
input,
|
|
347
|
+
channelId: options.channelId,
|
|
407
348
|
file: new Blob([await readFile(options.file)]),
|
|
408
349
|
filename: basename(options.file),
|
|
409
350
|
field: options.field
|
|
410
|
-
}) : await client.callServerAppCommand(server, appKey, commandName, {
|
|
351
|
+
}) : await client.callServerAppCommand(server, appKey, commandName, {
|
|
352
|
+
input,
|
|
353
|
+
channelId: options.channelId
|
|
354
|
+
});
|
|
411
355
|
if (options.output && result && typeof result === "object" && "dataBase64" in result && typeof result.dataBase64 === "string") {
|
|
412
356
|
await writeFile(
|
|
413
357
|
options.output,
|
|
@@ -422,15 +366,28 @@ function createAppCommand() {
|
|
|
422
366
|
}
|
|
423
367
|
}
|
|
424
368
|
);
|
|
369
|
+
app.command("uninstall").description("Uninstall a server App").argument("<app-key>", "App key").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
370
|
+
async (appKey, options) => {
|
|
371
|
+
try {
|
|
372
|
+
const client = await getClient(options.profile);
|
|
373
|
+
await client.deleteServerApp(resolveServerFlag(options.server), appKey);
|
|
374
|
+
const outputOpts = { json: options.json };
|
|
375
|
+
if (options.json) output({ ok: true }, outputOpts);
|
|
376
|
+
else outputSuccess(`Uninstalled ${appKey}`, outputOpts);
|
|
377
|
+
} catch (error) {
|
|
378
|
+
commandHandlerError(error, options.json);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
);
|
|
425
382
|
return app;
|
|
426
383
|
}
|
|
427
384
|
|
|
428
385
|
// src/commands/auth.ts
|
|
429
386
|
import { ShadowClient } from "@shadowob/sdk";
|
|
430
|
-
import { Command as
|
|
387
|
+
import { Command as Command3 } from "commander";
|
|
431
388
|
function createAuthCommand() {
|
|
432
|
-
const auth = new
|
|
433
|
-
auth.command("login").description("Authenticate with a Shadow server").
|
|
389
|
+
const auth = new Command3("auth").description("Authentication commands");
|
|
390
|
+
auth.command("login").description("Authenticate with a Shadow server").option("--server-url <url>", "Shadow server URL", "https://shadowob.com").requiredOption("--token <token>", "JWT token").option("--profile <name>", "Profile name", "default").option("--json", "Output as JSON").action(
|
|
434
391
|
async (options) => {
|
|
435
392
|
try {
|
|
436
393
|
const client = new ShadowClient(options.serverUrl, options.token);
|
|
@@ -541,14 +498,135 @@ function createAuthCommand() {
|
|
|
541
498
|
return auth;
|
|
542
499
|
}
|
|
543
500
|
|
|
501
|
+
// src/commands/buddies.ts
|
|
502
|
+
import { Command as Command4 } from "commander";
|
|
503
|
+
function createBuddiesCommand() {
|
|
504
|
+
const buddies = new Command4("buddies").description("Buddy management commands");
|
|
505
|
+
buddies.command("list").description("List your buddies").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
|
|
506
|
+
try {
|
|
507
|
+
const client = await getClient(options.profile);
|
|
508
|
+
const agents = await client.listAgents();
|
|
509
|
+
output(agents, { json: options.json });
|
|
510
|
+
} catch (error) {
|
|
511
|
+
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
buddies.command("get").description("Get buddy details").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
|
|
516
|
+
try {
|
|
517
|
+
const client = await getClient(options.profile);
|
|
518
|
+
const agent = await client.getAgent(buddyId);
|
|
519
|
+
output(agent, { json: options.json });
|
|
520
|
+
} catch (error) {
|
|
521
|
+
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
522
|
+
process.exit(1);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
buddies.command("create").description("Create a new buddy").requiredOption("--name <name>", "Buddy name").requiredOption("--username <username>", "Buddy username").option("--display-name <name>", "Display name").option("--avatar-url <url>", "Avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
526
|
+
async (options) => {
|
|
527
|
+
try {
|
|
528
|
+
const client = await getClient(options.profile);
|
|
529
|
+
const agent = await client.createAgent({
|
|
530
|
+
name: options.name,
|
|
531
|
+
username: options.username,
|
|
532
|
+
displayName: options.displayName,
|
|
533
|
+
avatarUrl: options.avatarUrl
|
|
534
|
+
});
|
|
535
|
+
output(agent, { json: options.json });
|
|
536
|
+
} catch (error) {
|
|
537
|
+
outputError(error instanceof Error ? error.message : String(error), {
|
|
538
|
+
json: options.json
|
|
539
|
+
});
|
|
540
|
+
process.exit(1);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
buddies.command("update").description("Update a buddy").argument("<buddy-id>", "Buddy ID").option("--name <name>", "New name").option("--display-name <name>", "New display name").option("--avatar-url <url>", "New avatar URL").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
545
|
+
async (buddyId, options) => {
|
|
546
|
+
try {
|
|
547
|
+
const client = await getClient(options.profile);
|
|
548
|
+
const agent = await client.updateAgent(buddyId, {
|
|
549
|
+
name: options.name,
|
|
550
|
+
displayName: options.displayName,
|
|
551
|
+
avatarUrl: options.avatarUrl
|
|
552
|
+
});
|
|
553
|
+
output(agent, { json: options.json });
|
|
554
|
+
} catch (error) {
|
|
555
|
+
outputError(error instanceof Error ? error.message : String(error), {
|
|
556
|
+
json: options.json
|
|
557
|
+
});
|
|
558
|
+
process.exit(1);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
);
|
|
562
|
+
buddies.command("delete").description("Delete a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
|
|
563
|
+
try {
|
|
564
|
+
const client = await getClient(options.profile);
|
|
565
|
+
await client.deleteAgent(buddyId);
|
|
566
|
+
const outputOpts = { json: options.json };
|
|
567
|
+
outputSuccess("Buddy deleted", outputOpts);
|
|
568
|
+
} catch (error) {
|
|
569
|
+
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
570
|
+
process.exit(1);
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
buddies.command("start").description("Start a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
|
|
574
|
+
try {
|
|
575
|
+
const client = await getClient(options.profile);
|
|
576
|
+
await client.startAgent(buddyId);
|
|
577
|
+
const outputOpts = { json: options.json };
|
|
578
|
+
outputSuccess("Buddy started", outputOpts);
|
|
579
|
+
} catch (error) {
|
|
580
|
+
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
581
|
+
process.exit(1);
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
buddies.command("stop").description("Stop a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
|
|
585
|
+
try {
|
|
586
|
+
const client = await getClient(options.profile);
|
|
587
|
+
await client.stopAgent(buddyId);
|
|
588
|
+
const outputOpts = { json: options.json };
|
|
589
|
+
outputSuccess("Buddy stopped", outputOpts);
|
|
590
|
+
} catch (error) {
|
|
591
|
+
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
592
|
+
process.exit(1);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
buddies.command("token").description("Generate a new token for a buddy").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
|
|
596
|
+
try {
|
|
597
|
+
const client = await getClient(options.profile);
|
|
598
|
+
const result = await client.generateAgentToken(buddyId);
|
|
599
|
+
if (options.json) {
|
|
600
|
+
output(result, { json: true });
|
|
601
|
+
} else {
|
|
602
|
+
console.log(result.token);
|
|
603
|
+
}
|
|
604
|
+
} catch (error) {
|
|
605
|
+
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
buddies.command("config").description("Get buddy remote config").argument("<buddy-id>", "Buddy ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (buddyId, options) => {
|
|
610
|
+
try {
|
|
611
|
+
const client = await getClient(options.profile);
|
|
612
|
+
const config = await client.getAgentConfig(buddyId);
|
|
613
|
+
output(config, { json: options.json });
|
|
614
|
+
} catch (error) {
|
|
615
|
+
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
616
|
+
process.exit(1);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
return buddies;
|
|
620
|
+
}
|
|
621
|
+
|
|
544
622
|
// src/commands/channels.ts
|
|
545
623
|
import { Command as Command5 } from "commander";
|
|
546
624
|
function createChannelsCommand() {
|
|
547
625
|
const channels = new Command5("channels").description("Channel commands");
|
|
548
|
-
channels.command("list").description("List channels in a server").requiredOption("--server
|
|
626
|
+
channels.command("list").description("List channels in a server").requiredOption("--server <server>", "Server ID or slug").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (options) => {
|
|
549
627
|
try {
|
|
550
628
|
const client = await getClient(options.profile);
|
|
551
|
-
const channels2 = await client.getServerChannels(options.
|
|
629
|
+
const channels2 = await client.getServerChannels(resolveServerFlag(options.server));
|
|
552
630
|
output(channels2, { json: options.json });
|
|
553
631
|
} catch (error) {
|
|
554
632
|
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
@@ -565,11 +643,11 @@ function createChannelsCommand() {
|
|
|
565
643
|
process.exit(1);
|
|
566
644
|
}
|
|
567
645
|
});
|
|
568
|
-
channels.command("create").description("Create a channel").requiredOption("--server
|
|
646
|
+
channels.command("create").description("Create a channel").requiredOption("--server <server>", "Server ID or slug").requiredOption("--name <name>", "Channel name").option("--type <type>", "Channel type", "text").option("--description <desc>", "Channel description").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
569
647
|
async (options) => {
|
|
570
648
|
try {
|
|
571
649
|
const client = await getClient(options.profile);
|
|
572
|
-
const channel = await client.createChannel(options.
|
|
650
|
+
const channel = await client.createChannel(resolveServerFlag(options.server), {
|
|
573
651
|
name: options.name,
|
|
574
652
|
type: options.type,
|
|
575
653
|
description: options.description
|
|
@@ -840,10 +918,10 @@ function createCommerceCommand() {
|
|
|
840
918
|
})
|
|
841
919
|
);
|
|
842
920
|
const entitlements = commerce.command("entitlements").description("Purchase entitlement commands");
|
|
843
|
-
entitlements.command("list").description("List my purchase entitlements").option("--server
|
|
921
|
+
entitlements.command("list").description("List my purchase entitlements").option("--server <server>", "Limit to a server shop entitlement list").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
844
922
|
(options) => runCommand(options, async () => {
|
|
845
923
|
const client = await getClient(options.profile);
|
|
846
|
-
return options.
|
|
924
|
+
return options.server ? client.getEntitlements(resolveServerFlag(options.server)) : client.getAllEntitlements();
|
|
847
925
|
})
|
|
848
926
|
);
|
|
849
927
|
entitlements.command("get").description("Get purchase delivery detail").argument("<entitlement-id>", "Entitlement ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
@@ -1304,7 +1382,7 @@ function createListenCommand() {
|
|
|
1304
1382
|
try {
|
|
1305
1383
|
const eventTypes = options.eventType?.split(",").map((t) => t.trim());
|
|
1306
1384
|
if (options.mode === "poll") {
|
|
1307
|
-
const { getClient: getClient2 } = await import("./client-
|
|
1385
|
+
const { getClient: getClient2 } = await import("./client-VR35GYUZ.js");
|
|
1308
1386
|
const client = await getClient2(options.profile);
|
|
1309
1387
|
const limit = parseInt(options.last ?? "50", 10);
|
|
1310
1388
|
const result = await client.getMessages(channelId, limit);
|
|
@@ -1970,14 +2048,14 @@ function createProfileCommentsCommand() {
|
|
|
1970
2048
|
import { Command as Command20 } from "commander";
|
|
1971
2049
|
function createSearchCommand() {
|
|
1972
2050
|
const search = new Command20("search").description("Search commands");
|
|
1973
|
-
search.command("messages").description("Search messages").requiredOption("--query <text>", "Search query").option("--server
|
|
2051
|
+
search.command("messages").description("Search messages").requiredOption("--query <text>", "Search query").option("--server <server>", "Limit to server").option("--channel-id <id>", "Limit to channel").option("--limit <n>", "Number of results (1-100)", "20").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(
|
|
1974
2052
|
async (options) => {
|
|
1975
2053
|
try {
|
|
1976
2054
|
const client = await getClient(options.profile);
|
|
1977
2055
|
const limit = Math.min(Math.max(parseInt(options.limit ?? "20", 10), 1), 100);
|
|
1978
2056
|
const results = await client.searchMessages({
|
|
1979
2057
|
q: options.query,
|
|
1980
|
-
serverId: options.
|
|
2058
|
+
serverId: options.server ? resolveServerFlag(options.server) : void 0,
|
|
1981
2059
|
channelId: options.channelId,
|
|
1982
2060
|
limit
|
|
1983
2061
|
});
|
|
@@ -2001,7 +2079,10 @@ function createServersCommand() {
|
|
|
2001
2079
|
try {
|
|
2002
2080
|
const client = await getClient(options.profile);
|
|
2003
2081
|
const servers2 = await client.listServers();
|
|
2004
|
-
output(
|
|
2082
|
+
output(
|
|
2083
|
+
servers2.map((s) => s.server),
|
|
2084
|
+
{ json: options.json }
|
|
2085
|
+
);
|
|
2005
2086
|
} catch (error) {
|
|
2006
2087
|
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
2007
2088
|
process.exit(1);
|
|
@@ -2070,7 +2151,17 @@ function createServersCommand() {
|
|
|
2070
2151
|
try {
|
|
2071
2152
|
const client = await getClient(options.profile);
|
|
2072
2153
|
const members = await client.getMembers(serverId);
|
|
2073
|
-
output(
|
|
2154
|
+
output(
|
|
2155
|
+
members.map(
|
|
2156
|
+
(m) => ({
|
|
2157
|
+
id: m.id,
|
|
2158
|
+
userId: m.userId,
|
|
2159
|
+
username: m.user?.username ?? m.nickname ?? m.uid ?? "",
|
|
2160
|
+
role: m.role
|
|
2161
|
+
})
|
|
2162
|
+
),
|
|
2163
|
+
{ json: options.json }
|
|
2164
|
+
);
|
|
2074
2165
|
} catch (error) {
|
|
2075
2166
|
outputError(error instanceof Error ? error.message : String(error), { json: options.json });
|
|
2076
2167
|
process.exit(1);
|
|
@@ -2208,17 +2299,6 @@ function createShopCommand() {
|
|
|
2208
2299
|
}
|
|
2209
2300
|
}
|
|
2210
2301
|
);
|
|
2211
|
-
products.command("context").description("Get buyer-facing product context").argument("<product-id>", "Product ID").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (productId, options) => {
|
|
2212
|
-
try {
|
|
2213
|
-
const client = await getClient(options.profile);
|
|
2214
|
-
output(await client.getCommerceProductContext(productId), { json: options.json });
|
|
2215
|
-
} catch (error) {
|
|
2216
|
-
outputError(error instanceof Error ? error.message : String(error), {
|
|
2217
|
-
json: options.json
|
|
2218
|
-
});
|
|
2219
|
-
process.exit(1);
|
|
2220
|
-
}
|
|
2221
|
-
});
|
|
2222
2302
|
products.command("create-by-shop").description("Create a product by shop ID using a JSON payload").argument("<shop-id>", "Shop ID").requiredOption("--data <json>", "Product JSON payload").option("--profile <name>", "Profile to use").option("--json", "Output as JSON").action(async (shopId, options) => {
|
|
2223
2303
|
try {
|
|
2224
2304
|
const client = await getClient(options.profile);
|
|
@@ -4168,7 +4248,7 @@ program.addCommand(createAppCommand());
|
|
|
4168
4248
|
program.addCommand(createServersCommand());
|
|
4169
4249
|
program.addCommand(createChannelsCommand());
|
|
4170
4250
|
program.addCommand(createThreadsCommand());
|
|
4171
|
-
program.addCommand(
|
|
4251
|
+
program.addCommand(createBuddiesCommand());
|
|
4172
4252
|
program.addCommand(createListenCommand());
|
|
4173
4253
|
program.addCommand(createDirectMessagesCommand());
|
|
4174
4254
|
program.addCommand(createWorkspaceCommand());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shadowob/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "Shadow CLI — command-line interface for Shadow servers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"commander": "^13.1.0",
|
|
15
15
|
"chalk": "^5.4.1",
|
|
16
|
-
"@shadowob/sdk": "1.1.
|
|
16
|
+
"@shadowob/sdk": "1.1.7"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/node": "^22.15.21",
|