@protoboxai/cli 1.0.0
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/README.md +78 -0
- package/bin/protobox.js +8 -0
- package/dist/cli.js +60 -0
- package/dist/commands/auth.js +294 -0
- package/dist/commands/chat.js +203 -0
- package/dist/commands/config.js +237 -0
- package/dist/commands/health.js +59 -0
- package/dist/commands/index.js +25 -0
- package/dist/commands/knowledge.js +539 -0
- package/dist/commands/mcp.js +589 -0
- package/dist/commands/prompts.js +295 -0
- package/dist/commands/tools.js +632 -0
- package/dist/commands/toolsets.js +464 -0
- package/dist/commands/workspaces.js +170 -0
- package/dist/index.js +6 -0
- package/dist/utils/config-store.js +209 -0
- package/dist/utils/output.js +221 -0
- package/dist/utils/sdk-factory.js +46 -0
- package/package.json +62 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { confirm } from "@inquirer/prompts";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { createSdk } from "../utils/sdk-factory.js";
|
|
7
|
+
import {
|
|
8
|
+
printSuccess,
|
|
9
|
+
printError,
|
|
10
|
+
printInfo,
|
|
11
|
+
printLabel,
|
|
12
|
+
printBlank,
|
|
13
|
+
printSimpleTable,
|
|
14
|
+
isJsonOutput,
|
|
15
|
+
printJson,
|
|
16
|
+
formatDate
|
|
17
|
+
} from "../utils/output.js";
|
|
18
|
+
const TOOLSET_TEMPLATE = {
|
|
19
|
+
name: "my-toolset",
|
|
20
|
+
description: "A curated collection of tools for a specific use case",
|
|
21
|
+
tools: ["tool-id-1", "tool-id-2"],
|
|
22
|
+
toolOverrides: {
|
|
23
|
+
"tool-id-1": {
|
|
24
|
+
name: "custom_name",
|
|
25
|
+
description: "Override description for this tool"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
isEnabled: true,
|
|
29
|
+
tags: ["production", "customer-facing"]
|
|
30
|
+
};
|
|
31
|
+
function createToolsetsCommand() {
|
|
32
|
+
const toolsets = new Command("toolsets").description("Manage MCP toolsets (collections of tools)").addHelpText(
|
|
33
|
+
"after",
|
|
34
|
+
`
|
|
35
|
+
What are Toolsets?
|
|
36
|
+
Toolsets group multiple tools together and allow you to customize how they
|
|
37
|
+
appear to AI agents. Use toolsets to:
|
|
38
|
+
- Create curated tool collections for specific use cases
|
|
39
|
+
- Override tool names/descriptions per context
|
|
40
|
+
- Enable/disable entire groups of tools at once
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
$ chanl toolsets list # List all toolsets
|
|
44
|
+
$ chanl toolsets create -f toolset.json # Create new toolset
|
|
45
|
+
$ chanl toolsets add-tools <id> -t id1,id2 # Add tools to toolset`
|
|
46
|
+
);
|
|
47
|
+
toolsets.command("list").description("List all toolsets in the workspace").option("-e, --enabled", "Show only enabled toolsets").option("-d, --disabled", "Show only disabled toolsets").option("--tag <tag>", "Filter by tag").option("-s, --search <search>", "Search by name or description").option("-l, --limit <number>", "Items per page (default: 20)", "20").option("-p, --page <number>", "Page number (default: 1)", "1").addHelpText(
|
|
48
|
+
"after",
|
|
49
|
+
`
|
|
50
|
+
Examples:
|
|
51
|
+
$ chanl toolsets list # List all
|
|
52
|
+
$ chanl toolsets list --enabled # Only enabled
|
|
53
|
+
$ chanl toolsets list --search "api" # Search by name`
|
|
54
|
+
).action(handleToolsetsList);
|
|
55
|
+
toolsets.command("get <id>").description("Get detailed info about a toolset").addHelpText(
|
|
56
|
+
"after",
|
|
57
|
+
`
|
|
58
|
+
Example:
|
|
59
|
+
$ chanl toolsets get 507f1f77bcf86cd799439011`
|
|
60
|
+
).action(handleToolsetsGet);
|
|
61
|
+
toolsets.command("create").description("Create a new toolset from JSON file").option("-f, --file <path>", "Path to JSON file with toolset definition").option("--template", "Output a sample JSON template").addHelpText(
|
|
62
|
+
"after",
|
|
63
|
+
`
|
|
64
|
+
Examples:
|
|
65
|
+
$ chanl toolsets create --template > my-toolset.json # Generate template
|
|
66
|
+
$ chanl toolsets create -f my-toolset.json # Create from file
|
|
67
|
+
|
|
68
|
+
Required JSON fields:
|
|
69
|
+
name Toolset name
|
|
70
|
+
description What this toolset is for
|
|
71
|
+
tools Array of tool IDs to include
|
|
72
|
+
|
|
73
|
+
Optional fields:
|
|
74
|
+
toolOverrides Override name/description per tool
|
|
75
|
+
isEnabled Enable immediately (default: true)
|
|
76
|
+
tags Array of category tags`
|
|
77
|
+
).action(handleToolsetsCreate);
|
|
78
|
+
toolsets.command("update <id>").description("Update a toolset from JSON file").requiredOption("-f, --file <path>", "Path to JSON file with updates").addHelpText(
|
|
79
|
+
"after",
|
|
80
|
+
`
|
|
81
|
+
Example:
|
|
82
|
+
$ chanl toolsets update 507f1f77bcf86cd799439011 -f updates.json`
|
|
83
|
+
).action(handleToolsetsUpdate);
|
|
84
|
+
toolsets.command("delete <id>").description("Delete a toolset permanently").option("-y, --yes", "Skip confirmation prompt").addHelpText(
|
|
85
|
+
"after",
|
|
86
|
+
`
|
|
87
|
+
Examples:
|
|
88
|
+
$ chanl toolsets delete 507f1f77bcf86cd799439011 # With confirmation
|
|
89
|
+
$ chanl toolsets delete 507f1f77bcf86cd799439011 -y # Skip confirmation`
|
|
90
|
+
).action(handleToolsetsDelete);
|
|
91
|
+
toolsets.command("enable <id>").description("Enable a toolset (makes its tools available)").action(handleToolsetsEnable);
|
|
92
|
+
toolsets.command("disable <id>").description("Disable a toolset (hides its tools)").action(handleToolsetsDisable);
|
|
93
|
+
toolsets.command("add-tools <id>").description("Add tools to an existing toolset").requiredOption("-t, --tools <ids>", "Comma-separated tool IDs").addHelpText(
|
|
94
|
+
"after",
|
|
95
|
+
`
|
|
96
|
+
Example:
|
|
97
|
+
$ chanl toolsets add-tools 507f1f77bcf86cd799439011 -t tool1,tool2,tool3`
|
|
98
|
+
).action(handleToolsetsAddTools);
|
|
99
|
+
toolsets.command("remove-tools <id>").description("Remove tools from a toolset").requiredOption("-t, --tools <ids>", "Comma-separated tool IDs").addHelpText(
|
|
100
|
+
"after",
|
|
101
|
+
`
|
|
102
|
+
Example:
|
|
103
|
+
$ chanl toolsets remove-tools 507f1f77bcf86cd799439011 -t tool1,tool2`
|
|
104
|
+
).action(handleToolsetsRemoveTools);
|
|
105
|
+
return toolsets;
|
|
106
|
+
}
|
|
107
|
+
async function handleToolsetsList(options) {
|
|
108
|
+
const sdk = createSdk();
|
|
109
|
+
if (!sdk) return;
|
|
110
|
+
const spinner = ora("Fetching toolsets...").start();
|
|
111
|
+
try {
|
|
112
|
+
let enabled;
|
|
113
|
+
if (options.enabled) enabled = true;
|
|
114
|
+
else if (options.disabled) enabled = false;
|
|
115
|
+
const response = await sdk.toolsets.list({
|
|
116
|
+
enabled,
|
|
117
|
+
tag: options.tag,
|
|
118
|
+
search: options.search,
|
|
119
|
+
limit: parseInt(options.limit, 10),
|
|
120
|
+
page: parseInt(options.page, 10)
|
|
121
|
+
});
|
|
122
|
+
spinner.stop();
|
|
123
|
+
if (!response.success || !response.data) {
|
|
124
|
+
printError("Failed to fetch toolsets", response.message);
|
|
125
|
+
process.exitCode = 1;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const toolsets = response.data.items || response.data.data || [];
|
|
129
|
+
const total = response.data.total ?? response.data.pagination?.total ?? toolsets.length;
|
|
130
|
+
const pagination = response.data.pagination || {
|
|
131
|
+
page: parseInt(options.page, 10),
|
|
132
|
+
limit: parseInt(options.limit, 10),
|
|
133
|
+
totalPages: Math.ceil(total / parseInt(options.limit, 10)),
|
|
134
|
+
hasNext: false,
|
|
135
|
+
hasPrev: false
|
|
136
|
+
};
|
|
137
|
+
if (isJsonOutput()) {
|
|
138
|
+
printJson({ toolsets, total, pagination });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (toolsets.length === 0) {
|
|
142
|
+
printInfo("No toolsets found");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
printBlank();
|
|
146
|
+
printSimpleTable(
|
|
147
|
+
["Name", "Tool Count", "Enabled", "Tags", "Version"],
|
|
148
|
+
toolsets.map((toolset) => [
|
|
149
|
+
toolset.name,
|
|
150
|
+
(toolset.toolCount ?? toolset.tools?.length ?? 0).toString(),
|
|
151
|
+
toolset.enabled ? chalk.green("Yes") : chalk.red("No"),
|
|
152
|
+
toolset.tags && toolset.tags.length > 0 ? toolset.tags.join(", ") : "-",
|
|
153
|
+
toolset.version
|
|
154
|
+
])
|
|
155
|
+
);
|
|
156
|
+
printBlank();
|
|
157
|
+
printInfo(`Total: ${total} toolsets (Page ${pagination.page} of ${pagination.totalPages})`);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
spinner.fail("Failed to fetch toolsets");
|
|
160
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
161
|
+
printError("Error", message);
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function handleToolsetsGet(id) {
|
|
166
|
+
const sdk = createSdk();
|
|
167
|
+
if (!sdk) return;
|
|
168
|
+
const spinner = ora("Fetching toolset...").start();
|
|
169
|
+
try {
|
|
170
|
+
const response = await sdk.toolsets.get(id);
|
|
171
|
+
spinner.stop();
|
|
172
|
+
if (!response.success || !response.data) {
|
|
173
|
+
printError("Failed to fetch toolset", response.message);
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const toolset = response.data;
|
|
178
|
+
if (isJsonOutput()) {
|
|
179
|
+
printJson(toolset);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
printBlank();
|
|
183
|
+
printToolsetDetails(toolset);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
spinner.fail("Failed to fetch toolset");
|
|
186
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
187
|
+
printError("Error", message);
|
|
188
|
+
process.exitCode = 1;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function handleToolsetsCreate(options) {
|
|
192
|
+
if (options.template) {
|
|
193
|
+
console.log(JSON.stringify(TOOLSET_TEMPLATE, null, 2));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (!options.file) {
|
|
197
|
+
printError("Missing required option", "Use '-f, --file <path>' or '--template' for sample JSON");
|
|
198
|
+
printInfo("Run 'chanl toolsets create --help' for usage");
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const sdk = createSdk();
|
|
203
|
+
if (!sdk) return;
|
|
204
|
+
let input;
|
|
205
|
+
try {
|
|
206
|
+
const content = await readFile(options.file, "utf-8");
|
|
207
|
+
input = JSON.parse(content);
|
|
208
|
+
} catch (error) {
|
|
209
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
210
|
+
printError("Failed to read file", message);
|
|
211
|
+
process.exitCode = 1;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const spinner = ora("Creating toolset...").start();
|
|
215
|
+
try {
|
|
216
|
+
const response = await sdk.toolsets.create(input);
|
|
217
|
+
spinner.stop();
|
|
218
|
+
if (!response.success || !response.data) {
|
|
219
|
+
printError("Failed to create toolset", response.message);
|
|
220
|
+
process.exitCode = 1;
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const toolset = response.data;
|
|
224
|
+
if (isJsonOutput()) {
|
|
225
|
+
printJson({ success: true, toolset });
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
printSuccess(`Created toolset: ${toolset.name} (${toolset.id})`);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
spinner.fail("Failed to create toolset");
|
|
231
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
232
|
+
printError("Error", message);
|
|
233
|
+
process.exitCode = 1;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async function handleToolsetsUpdate(id, options) {
|
|
237
|
+
const sdk = createSdk();
|
|
238
|
+
if (!sdk) return;
|
|
239
|
+
let input;
|
|
240
|
+
try {
|
|
241
|
+
const content = await readFile(options.file, "utf-8");
|
|
242
|
+
input = JSON.parse(content);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
245
|
+
printError("Failed to read file", message);
|
|
246
|
+
process.exitCode = 1;
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const spinner = ora("Updating toolset...").start();
|
|
250
|
+
try {
|
|
251
|
+
const response = await sdk.toolsets.update(id, input);
|
|
252
|
+
spinner.stop();
|
|
253
|
+
if (!response.success || !response.data) {
|
|
254
|
+
printError("Failed to update toolset", response.message);
|
|
255
|
+
process.exitCode = 1;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const toolset = response.data;
|
|
259
|
+
if (isJsonOutput()) {
|
|
260
|
+
printJson({ success: true, toolset });
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
printSuccess(`Updated toolset: ${toolset.name} (${toolset.id})`);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
spinner.fail("Failed to update toolset");
|
|
266
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
267
|
+
printError("Error", message);
|
|
268
|
+
process.exitCode = 1;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async function handleToolsetsDelete(id, options) {
|
|
272
|
+
const sdk = createSdk();
|
|
273
|
+
if (!sdk) return;
|
|
274
|
+
if (!options.yes) {
|
|
275
|
+
try {
|
|
276
|
+
const confirmed = await confirm({
|
|
277
|
+
message: `Are you sure you want to delete toolset '${id}'?`,
|
|
278
|
+
default: false
|
|
279
|
+
});
|
|
280
|
+
if (!confirmed) {
|
|
281
|
+
printInfo("Deletion cancelled");
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
} catch {
|
|
285
|
+
printBlank();
|
|
286
|
+
printInfo("Deletion cancelled");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const spinner = ora("Deleting toolset...").start();
|
|
291
|
+
try {
|
|
292
|
+
const response = await sdk.toolsets.delete(id);
|
|
293
|
+
spinner.stop();
|
|
294
|
+
if (!response.success) {
|
|
295
|
+
printError("Failed to delete toolset", response.message);
|
|
296
|
+
process.exitCode = 1;
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (isJsonOutput()) {
|
|
300
|
+
printJson({ success: true, deleted: true, id });
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
printSuccess(`Deleted toolset: ${id}`);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
spinner.fail("Failed to delete toolset");
|
|
306
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
307
|
+
printError("Error", message);
|
|
308
|
+
process.exitCode = 1;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async function handleToolsetsEnable(id) {
|
|
312
|
+
const sdk = createSdk();
|
|
313
|
+
if (!sdk) return;
|
|
314
|
+
const spinner = ora("Enabling toolset...").start();
|
|
315
|
+
try {
|
|
316
|
+
const response = await sdk.toolsets.enable(id);
|
|
317
|
+
spinner.stop();
|
|
318
|
+
if (!response.success || !response.data) {
|
|
319
|
+
printError("Failed to enable toolset", response.message);
|
|
320
|
+
process.exitCode = 1;
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const toolset = response.data;
|
|
324
|
+
if (isJsonOutput()) {
|
|
325
|
+
printJson({ success: true, toolset });
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
printSuccess(`Enabled toolset: ${toolset.name} (${toolset.id})`);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
spinner.fail("Failed to enable toolset");
|
|
331
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
332
|
+
printError("Error", message);
|
|
333
|
+
process.exitCode = 1;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
async function handleToolsetsDisable(id) {
|
|
337
|
+
const sdk = createSdk();
|
|
338
|
+
if (!sdk) return;
|
|
339
|
+
const spinner = ora("Disabling toolset...").start();
|
|
340
|
+
try {
|
|
341
|
+
const response = await sdk.toolsets.disable(id);
|
|
342
|
+
spinner.stop();
|
|
343
|
+
if (!response.success || !response.data) {
|
|
344
|
+
printError("Failed to disable toolset", response.message);
|
|
345
|
+
process.exitCode = 1;
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const toolset = response.data;
|
|
349
|
+
if (isJsonOutput()) {
|
|
350
|
+
printJson({ success: true, toolset });
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
printSuccess(`Disabled toolset: ${toolset.name} (${toolset.id})`);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
spinner.fail("Failed to disable toolset");
|
|
356
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
357
|
+
printError("Error", message);
|
|
358
|
+
process.exitCode = 1;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
async function handleToolsetsAddTools(id, options) {
|
|
362
|
+
const sdk = createSdk();
|
|
363
|
+
if (!sdk) return;
|
|
364
|
+
const toolIds = options.tools.split(",").map((t) => t.trim()).filter(Boolean);
|
|
365
|
+
if (toolIds.length === 0) {
|
|
366
|
+
printError("No tool IDs provided", "Provide tool IDs with --tools flag");
|
|
367
|
+
process.exitCode = 1;
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const spinner = ora("Adding tools to toolset...").start();
|
|
371
|
+
try {
|
|
372
|
+
const response = await sdk.toolsets.manageTools(id, { add: toolIds });
|
|
373
|
+
spinner.stop();
|
|
374
|
+
if (!response.success || !response.data) {
|
|
375
|
+
printError("Failed to add tools", response.message);
|
|
376
|
+
process.exitCode = 1;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const toolset = response.data;
|
|
380
|
+
if (isJsonOutput()) {
|
|
381
|
+
printJson({ success: true, toolset });
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
printSuccess(`Added ${toolIds.length} tool(s) to toolset: ${toolset.name}`);
|
|
385
|
+
printInfo(`Toolset now has ${toolset.toolCount} tool(s)`);
|
|
386
|
+
} catch (error) {
|
|
387
|
+
spinner.fail("Failed to add tools");
|
|
388
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
389
|
+
printError("Error", message);
|
|
390
|
+
process.exitCode = 1;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async function handleToolsetsRemoveTools(id, options) {
|
|
394
|
+
const sdk = createSdk();
|
|
395
|
+
if (!sdk) return;
|
|
396
|
+
const toolIds = options.tools.split(",").map((t) => t.trim()).filter(Boolean);
|
|
397
|
+
if (toolIds.length === 0) {
|
|
398
|
+
printError("No tool IDs provided", "Provide tool IDs with --tools flag");
|
|
399
|
+
process.exitCode = 1;
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const spinner = ora("Removing tools from toolset...").start();
|
|
403
|
+
try {
|
|
404
|
+
const response = await sdk.toolsets.manageTools(id, { remove: toolIds });
|
|
405
|
+
spinner.stop();
|
|
406
|
+
if (!response.success || !response.data) {
|
|
407
|
+
printError("Failed to remove tools", response.message);
|
|
408
|
+
process.exitCode = 1;
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const toolset = response.data;
|
|
412
|
+
if (isJsonOutput()) {
|
|
413
|
+
printJson({ success: true, toolset });
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
printSuccess(`Removed ${toolIds.length} tool(s) from toolset: ${toolset.name}`);
|
|
417
|
+
printInfo(`Toolset now has ${toolset.toolCount} tool(s)`);
|
|
418
|
+
} catch (error) {
|
|
419
|
+
spinner.fail("Failed to remove tools");
|
|
420
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
421
|
+
printError("Error", message);
|
|
422
|
+
process.exitCode = 1;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function printToolsetDetails(toolset) {
|
|
426
|
+
printLabel("Name", toolset.name);
|
|
427
|
+
printLabel("ID", toolset.id);
|
|
428
|
+
printLabel("Description", toolset.description);
|
|
429
|
+
printLabel("Version", toolset.version);
|
|
430
|
+
printLabel("Enabled", toolset.enabled ? chalk.green("Yes") : chalk.red("No"));
|
|
431
|
+
printLabel("Public", toolset.isPublic ? chalk.green("Yes") : chalk.red("No"));
|
|
432
|
+
if (toolset.registryId) {
|
|
433
|
+
printLabel("Registry ID", toolset.registryId);
|
|
434
|
+
}
|
|
435
|
+
if (toolset.tags && toolset.tags.length > 0) {
|
|
436
|
+
printLabel("Tags", toolset.tags.join(", "));
|
|
437
|
+
}
|
|
438
|
+
printBlank();
|
|
439
|
+
printInfo(`Tools (${toolset.toolCount}):`);
|
|
440
|
+
if (toolset.tools.length > 0) {
|
|
441
|
+
for (const toolId of toolset.tools) {
|
|
442
|
+
console.log(chalk.gray(` - ${toolId}`));
|
|
443
|
+
}
|
|
444
|
+
} else {
|
|
445
|
+
console.log(chalk.gray(" No tools in this toolset"));
|
|
446
|
+
}
|
|
447
|
+
if (toolset.toolOverrides && Object.keys(toolset.toolOverrides).length > 0) {
|
|
448
|
+
printBlank();
|
|
449
|
+
printInfo("Tool Overrides:");
|
|
450
|
+
for (const [toolId, override] of Object.entries(toolset.toolOverrides)) {
|
|
451
|
+
console.log(chalk.gray(` ${toolId}:`));
|
|
452
|
+
if (override.name) console.log(chalk.gray(` name: ${override.name}`));
|
|
453
|
+
if (override.description) console.log(chalk.gray(` description: ${override.description}`));
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
printBlank();
|
|
457
|
+
printLabel("Created", formatDate(toolset.createdAt));
|
|
458
|
+
printLabel("Updated", formatDate(toolset.updatedAt));
|
|
459
|
+
printBlank();
|
|
460
|
+
}
|
|
461
|
+
export {
|
|
462
|
+
createToolsetsCommand
|
|
463
|
+
};
|
|
464
|
+
//# sourceMappingURL=toolsets.js.map
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { createSdk } from "../utils/sdk-factory.js";
|
|
5
|
+
import { configStore } from "../utils/config-store.js";
|
|
6
|
+
import {
|
|
7
|
+
printError,
|
|
8
|
+
printSuccess,
|
|
9
|
+
printInfo,
|
|
10
|
+
printBlank,
|
|
11
|
+
printSimpleTable,
|
|
12
|
+
printLabel,
|
|
13
|
+
isJsonOutput,
|
|
14
|
+
printJson,
|
|
15
|
+
formatDate
|
|
16
|
+
} from "../utils/output.js";
|
|
17
|
+
function createWorkspacesCommand() {
|
|
18
|
+
const workspaces = new Command("workspaces").description("Manage workspaces").addHelpText(
|
|
19
|
+
"after",
|
|
20
|
+
`
|
|
21
|
+
What are Workspaces?
|
|
22
|
+
Workspaces are isolated environments for organizing agents, tools, and
|
|
23
|
+
configurations. Switch between workspaces to manage different projects.
|
|
24
|
+
|
|
25
|
+
Quick Start:
|
|
26
|
+
$ chanl workspaces list # List your workspaces
|
|
27
|
+
$ chanl workspaces get <id> # View workspace details
|
|
28
|
+
$ chanl workspaces use <id> # Set active workspace`
|
|
29
|
+
);
|
|
30
|
+
workspaces.command("list").description("List workspaces").addHelpText(
|
|
31
|
+
"after",
|
|
32
|
+
`
|
|
33
|
+
Examples:
|
|
34
|
+
$ chanl workspaces list # List all workspaces
|
|
35
|
+
$ chanl workspaces list --json # Output as JSON`
|
|
36
|
+
).action(handleWorkspacesList);
|
|
37
|
+
workspaces.command("get <id>").description("Get workspace details").addHelpText(
|
|
38
|
+
"after",
|
|
39
|
+
`
|
|
40
|
+
Examples:
|
|
41
|
+
$ chanl workspaces get ws_abc123 # Get workspace details
|
|
42
|
+
$ chanl workspaces get ws_abc123 --json # Output as JSON`
|
|
43
|
+
).action(handleWorkspacesGet);
|
|
44
|
+
workspaces.command("use <id>").description("Set active workspace (saves to config)").addHelpText(
|
|
45
|
+
"after",
|
|
46
|
+
`
|
|
47
|
+
Examples:
|
|
48
|
+
$ chanl workspaces use ws_abc123 # Switch to workspace
|
|
49
|
+
|
|
50
|
+
This saves the workspace ID to your CLI config. All subsequent commands
|
|
51
|
+
will use this workspace by default.`
|
|
52
|
+
).action(handleWorkspacesUse);
|
|
53
|
+
return workspaces;
|
|
54
|
+
}
|
|
55
|
+
async function handleWorkspacesList() {
|
|
56
|
+
const sdk = createSdk();
|
|
57
|
+
if (!sdk) return;
|
|
58
|
+
const spinner = ora("Fetching workspaces...").start();
|
|
59
|
+
try {
|
|
60
|
+
const response = await sdk.workspace.getAll();
|
|
61
|
+
spinner.stop();
|
|
62
|
+
if (!response.success || !response.data) {
|
|
63
|
+
printError("Failed to fetch workspaces", response.message);
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const workspaces = Array.isArray(response.data) ? response.data : [];
|
|
68
|
+
const currentWorkspaceId = configStore.getWorkspaceId();
|
|
69
|
+
if (isJsonOutput()) {
|
|
70
|
+
printJson(workspaces);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (workspaces.length === 0) {
|
|
74
|
+
printInfo("No workspaces found");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
printBlank();
|
|
78
|
+
printSimpleTable(
|
|
79
|
+
["", "ID", "Name", "Description", "Created"],
|
|
80
|
+
workspaces.map((ws) => [
|
|
81
|
+
ws.id === currentWorkspaceId ? chalk.green("*") : " ",
|
|
82
|
+
ws.id,
|
|
83
|
+
(ws.name || "Untitled").slice(0, 30),
|
|
84
|
+
(ws.description || "-").slice(0, 40),
|
|
85
|
+
formatDate(ws.createdAt)
|
|
86
|
+
])
|
|
87
|
+
);
|
|
88
|
+
printBlank();
|
|
89
|
+
if (currentWorkspaceId) {
|
|
90
|
+
printInfo(`Active workspace: ${currentWorkspaceId}`);
|
|
91
|
+
}
|
|
92
|
+
printInfo(`Total: ${workspaces.length} workspaces`);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
spinner.fail("Failed to fetch workspaces");
|
|
95
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
96
|
+
printError("Error", message);
|
|
97
|
+
process.exitCode = 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function handleWorkspacesGet(id) {
|
|
101
|
+
const sdk = createSdk();
|
|
102
|
+
if (!sdk) return;
|
|
103
|
+
const spinner = ora("Fetching workspace...").start();
|
|
104
|
+
try {
|
|
105
|
+
const response = await sdk.workspace.getById(id);
|
|
106
|
+
spinner.stop();
|
|
107
|
+
if (!response.success || !response.data) {
|
|
108
|
+
printError("Failed to fetch workspace", response.message);
|
|
109
|
+
process.exitCode = 1;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const workspace = response.data;
|
|
113
|
+
if (isJsonOutput()) {
|
|
114
|
+
printJson(workspace);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
printBlank();
|
|
118
|
+
console.log(chalk.bold("Workspace Details:"));
|
|
119
|
+
printLabel("ID", workspace.id);
|
|
120
|
+
printLabel("Name", workspace.name);
|
|
121
|
+
if (workspace.description) printLabel("Description", workspace.description);
|
|
122
|
+
if (workspace.createdAt) printLabel("Created", formatDate(workspace.createdAt));
|
|
123
|
+
if (workspace.updatedAt) printLabel("Updated", formatDate(workspace.updatedAt));
|
|
124
|
+
const currentWorkspaceId = configStore.getWorkspaceId();
|
|
125
|
+
if (workspace.id === currentWorkspaceId) {
|
|
126
|
+
printBlank();
|
|
127
|
+
printInfo("This is your active workspace");
|
|
128
|
+
}
|
|
129
|
+
printBlank();
|
|
130
|
+
} catch (error) {
|
|
131
|
+
spinner.fail("Failed to fetch workspace");
|
|
132
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
133
|
+
printError("Error", message);
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async function handleWorkspacesUse(id) {
|
|
138
|
+
const sdk = createSdk();
|
|
139
|
+
if (!sdk) return;
|
|
140
|
+
const spinner = ora("Verifying workspace...").start();
|
|
141
|
+
try {
|
|
142
|
+
const response = await sdk.workspace.getById(id);
|
|
143
|
+
spinner.stop();
|
|
144
|
+
if (!response.success || !response.data) {
|
|
145
|
+
printError("Workspace not found", response.message || `Could not find workspace: ${id}`);
|
|
146
|
+
process.exitCode = 1;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const workspace = response.data;
|
|
150
|
+
configStore.setWorkspaceId(id);
|
|
151
|
+
if (isJsonOutput()) {
|
|
152
|
+
printJson({
|
|
153
|
+
success: true,
|
|
154
|
+
workspaceId: id,
|
|
155
|
+
name: workspace.name
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
printSuccess(`Active workspace set to: ${workspace.name} (${id})`);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
spinner.fail("Failed to set workspace");
|
|
162
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
163
|
+
printError("Error", message);
|
|
164
|
+
process.exitCode = 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export {
|
|
168
|
+
createWorkspacesCommand
|
|
169
|
+
};
|
|
170
|
+
//# sourceMappingURL=workspaces.js.map
|