agentscamp 0.5.0 → 0.7.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 +46 -19
- package/content/manifest.json +212 -2
- package/content/skills/circular-dependency-breaker.md +48 -0
- package/content/skills/commit-splitter.md +54 -0
- package/content/skills/dashboard-designer.md +38 -0
- package/content/skills/deadlock-diagnoser.md +45 -0
- package/content/skills/feature-flag-retirer.md +44 -0
- package/content/skills/flamegraph-analyzer.md +35 -0
- package/content/skills/git-blame-investigator.md +34 -0
- package/content/skills/graphql-schema-designer.md +49 -0
- package/content/skills/hallucination-evaluator.md +40 -0
- package/content/skills/integration-test-designer.md +81 -0
- package/content/skills/model-router-designer.md +39 -0
- package/content/skills/onboarding-guide-writer.md +84 -0
- package/content/skills/rbac-designer.md +82 -0
- package/content/skills/release-notes-writer.md +78 -0
- package/content/skills/web-vitals-optimizer.md +34 -0
- package/dist/index.js +400 -43
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { homedir as homedir2 } from "node:os";
|
|
5
|
+
|
|
3
6
|
// src/output.ts
|
|
4
7
|
var useColor = process.stdout.isTTY && !process.env.NO_COLOR && process.env.TERM !== "dumb";
|
|
5
8
|
function paint(code) {
|
|
@@ -21,24 +24,35 @@ function printHelp(version) {
|
|
|
21
24
|
${c.bold("agentscamp")} v${version} \u2014 install AgentsCamp agents, skills & slash commands into Claude Code
|
|
22
25
|
|
|
23
26
|
${c.bold("Usage")}
|
|
27
|
+
npx agentscamp Pick what to install (interactive)
|
|
28
|
+
npx agentscamp --all Install the entire catalog
|
|
24
29
|
npx agentscamp <command> [args] [flags]
|
|
25
30
|
|
|
26
31
|
${c.bold("Commands")}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
install [type...] Install everything (--all), whole types (agents | skills |
|
|
33
|
+
commands), or pick interactively when run with no args
|
|
34
|
+
add <id...> Install specific items (e.g. agents/prompt-engineer)
|
|
35
|
+
list [type] List everything, or one type (agents | skills | commands)
|
|
36
|
+
search <query> Search by name, title, topic, or description
|
|
37
|
+
info <id> Show details and install paths for an item
|
|
31
38
|
|
|
32
39
|
${c.bold("Flags")}
|
|
33
|
-
-
|
|
34
|
-
|
|
40
|
+
-a, --all With install (or no command): install the whole catalog
|
|
41
|
+
-g, --global Install to ~/.claude/, available in every project
|
|
42
|
+
--project Install to ./.claude/ in the current project
|
|
35
43
|
-f, --force Overwrite existing files
|
|
36
44
|
-h, --help Show this help
|
|
37
45
|
-v, --version Show version
|
|
38
46
|
|
|
47
|
+
${c.bold("Scope")}
|
|
48
|
+
install defaults to ~/.claude/ (every project); add defaults to ./.claude/.
|
|
49
|
+
Pass -g/--project anywhere to override.
|
|
50
|
+
|
|
39
51
|
${c.bold("Examples")}
|
|
40
|
-
npx agentscamp
|
|
41
|
-
npx agentscamp
|
|
52
|
+
npx agentscamp ${c.dim("# interactive picker")}
|
|
53
|
+
npx agentscamp --all ${c.dim("# everything, into ~/.claude/")}
|
|
54
|
+
npx agentscamp install agents ${c.dim("# all agents")}
|
|
55
|
+
npx agentscamp add skills/dependency-audit commands/plan-feature
|
|
42
56
|
npx agentscamp search "code review"
|
|
43
57
|
|
|
44
58
|
Browse everything with full docs at ${c.cyan("https://agentscamp.com")}
|
|
@@ -53,6 +67,8 @@ var FLAG_MAP = {
|
|
|
53
67
|
"--project": "project",
|
|
54
68
|
"-f": "force",
|
|
55
69
|
"--force": "force",
|
|
70
|
+
"-a": "all",
|
|
71
|
+
"--all": "all",
|
|
56
72
|
"-h": "help",
|
|
57
73
|
"--help": "help",
|
|
58
74
|
"-v": "version",
|
|
@@ -63,6 +79,7 @@ function parseArgs(argv) {
|
|
|
63
79
|
global: false,
|
|
64
80
|
project: false,
|
|
65
81
|
force: false,
|
|
82
|
+
all: false,
|
|
66
83
|
help: false,
|
|
67
84
|
version: false
|
|
68
85
|
};
|
|
@@ -110,14 +127,13 @@ function packageVersion() {
|
|
|
110
127
|
}
|
|
111
128
|
|
|
112
129
|
// src/install.ts
|
|
113
|
-
|
|
114
|
-
function resolveScope(flags) {
|
|
130
|
+
function resolveScope(flags, fallback = "project") {
|
|
115
131
|
if (flags.global && flags.project) {
|
|
116
132
|
throw new CliError("Pass either --global or --project, not both.");
|
|
117
133
|
}
|
|
118
134
|
if (flags.global) return "global";
|
|
119
135
|
if (flags.project) return "project";
|
|
120
|
-
return
|
|
136
|
+
return fallback;
|
|
121
137
|
}
|
|
122
138
|
function installRoot(scope) {
|
|
123
139
|
return scope === "global" ? path.join(homedir(), ".claude") : path.resolve(process.cwd(), ".claude");
|
|
@@ -139,6 +155,229 @@ function installItem(item, opts) {
|
|
|
139
155
|
}
|
|
140
156
|
}
|
|
141
157
|
|
|
158
|
+
// src/prompt.ts
|
|
159
|
+
var out = process.stdout;
|
|
160
|
+
function isInteractive() {
|
|
161
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
162
|
+
}
|
|
163
|
+
function parseKey(s) {
|
|
164
|
+
if (s === "") return "ctrl-c";
|
|
165
|
+
if (s === "\r" || s === "\n") return "enter";
|
|
166
|
+
if (s === "\x1B[A") return "up";
|
|
167
|
+
if (s === "\x1B[B") return "down";
|
|
168
|
+
if (s === "\x1B[C") return "right";
|
|
169
|
+
if (s === "\x1B[D") return "left";
|
|
170
|
+
if (s === "\x1B[H" || s === "\x1B[1~") return "home";
|
|
171
|
+
if (s === "\x1B[F" || s === "\x1B[4~") return "end";
|
|
172
|
+
if (s === " ") return "space";
|
|
173
|
+
if (s === "\x1B") return "esc";
|
|
174
|
+
const l = s.toLowerCase();
|
|
175
|
+
if (l === "k") return "up";
|
|
176
|
+
if (l === "j") return "down";
|
|
177
|
+
if (l === "a") return "a";
|
|
178
|
+
if (l === "q") return "q";
|
|
179
|
+
return "other";
|
|
180
|
+
}
|
|
181
|
+
var HIDE = "\x1B[?25l";
|
|
182
|
+
var SHOW = "\x1B[?25h";
|
|
183
|
+
function termWidth() {
|
|
184
|
+
return Math.max(20, out.columns || 80);
|
|
185
|
+
}
|
|
186
|
+
function clip(s, max) {
|
|
187
|
+
if (max <= 0) return "";
|
|
188
|
+
if (s.length <= max) return s;
|
|
189
|
+
if (max === 1) return "\u2026";
|
|
190
|
+
return s.slice(0, max - 1) + "\u2026";
|
|
191
|
+
}
|
|
192
|
+
function run(frame, onKey) {
|
|
193
|
+
return new Promise((resolve) => {
|
|
194
|
+
const stdin = process.stdin;
|
|
195
|
+
let lastHeight = 0;
|
|
196
|
+
function moveToFrameTop() {
|
|
197
|
+
if (lastHeight > 0) {
|
|
198
|
+
out.write("\r");
|
|
199
|
+
if (lastHeight > 1) out.write(`\x1B[${lastHeight - 1}A`);
|
|
200
|
+
out.write("\x1B[J");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function render() {
|
|
204
|
+
const f = frame();
|
|
205
|
+
moveToFrameTop();
|
|
206
|
+
out.write(f);
|
|
207
|
+
lastHeight = f.split("\n").length;
|
|
208
|
+
}
|
|
209
|
+
function cleanup() {
|
|
210
|
+
stdin.removeListener("data", onData);
|
|
211
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
212
|
+
stdin.pause();
|
|
213
|
+
moveToFrameTop();
|
|
214
|
+
out.write(SHOW);
|
|
215
|
+
}
|
|
216
|
+
function onData(chunk) {
|
|
217
|
+
const key = parseKey(String(chunk));
|
|
218
|
+
if (key === "ctrl-c") {
|
|
219
|
+
cleanup();
|
|
220
|
+
out.write(c.dim("Cancelled.") + "\n");
|
|
221
|
+
process.exit(130);
|
|
222
|
+
}
|
|
223
|
+
const action = onKey(key);
|
|
224
|
+
if (action === "done") {
|
|
225
|
+
cleanup();
|
|
226
|
+
resolve();
|
|
227
|
+
} else if (action === "render") {
|
|
228
|
+
render();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
out.write(HIDE);
|
|
232
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
233
|
+
stdin.resume();
|
|
234
|
+
stdin.setEncoding("utf8");
|
|
235
|
+
stdin.on("data", onData);
|
|
236
|
+
render();
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
async function selectOne(message, choices) {
|
|
240
|
+
let cursor = 0;
|
|
241
|
+
let cancelled = false;
|
|
242
|
+
const help = c.dim("(\u2191/\u2193 move \xB7 \u23CE select \xB7 esc cancel)");
|
|
243
|
+
function frame() {
|
|
244
|
+
const width = termWidth();
|
|
245
|
+
const lines = [`${c.bold(message)} ${help}`];
|
|
246
|
+
for (let i = 0; i < choices.length; i++) {
|
|
247
|
+
const ch = choices[i];
|
|
248
|
+
const active = i === cursor;
|
|
249
|
+
const ptr = active ? c.cyan("\u276F") : " ";
|
|
250
|
+
const hintLen = ch.hint ? ch.hint.length + 2 : 0;
|
|
251
|
+
const label = clip(ch.label, width - 2 - hintLen);
|
|
252
|
+
const labelC = active ? c.cyan(label) : label;
|
|
253
|
+
const hint = ch.hint ? " " + c.dim(ch.hint) : "";
|
|
254
|
+
lines.push(`${ptr} ${labelC}${hint}`);
|
|
255
|
+
}
|
|
256
|
+
return lines.join("\n");
|
|
257
|
+
}
|
|
258
|
+
await run(frame, (key) => {
|
|
259
|
+
switch (key) {
|
|
260
|
+
case "up":
|
|
261
|
+
cursor = (cursor - 1 + choices.length) % choices.length;
|
|
262
|
+
return "render";
|
|
263
|
+
case "down":
|
|
264
|
+
cursor = (cursor + 1) % choices.length;
|
|
265
|
+
return "render";
|
|
266
|
+
case "home":
|
|
267
|
+
cursor = 0;
|
|
268
|
+
return "render";
|
|
269
|
+
case "end":
|
|
270
|
+
cursor = choices.length - 1;
|
|
271
|
+
return "render";
|
|
272
|
+
case "enter":
|
|
273
|
+
return "done";
|
|
274
|
+
case "esc":
|
|
275
|
+
case "q":
|
|
276
|
+
cancelled = true;
|
|
277
|
+
return "done";
|
|
278
|
+
default:
|
|
279
|
+
return "ignore";
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
return cancelled ? null : choices[cursor].value;
|
|
283
|
+
}
|
|
284
|
+
async function multiSelect(message, entries) {
|
|
285
|
+
const itemPositions = entries.map((e, i) => e.kind === "item" ? i : -1).filter((i) => i >= 0);
|
|
286
|
+
if (itemPositions.length === 0) return [];
|
|
287
|
+
const selected = /* @__PURE__ */ new Set();
|
|
288
|
+
let ci = 0;
|
|
289
|
+
let top = 0;
|
|
290
|
+
let cancelled = false;
|
|
291
|
+
const viewH = Math.min(entries.length, Math.max(4, (out.rows || 24) - 5));
|
|
292
|
+
function cursorEntry() {
|
|
293
|
+
return itemPositions[ci];
|
|
294
|
+
}
|
|
295
|
+
function clampWindow() {
|
|
296
|
+
const cur = cursorEntry();
|
|
297
|
+
if (cur < top) top = cur;
|
|
298
|
+
else if (cur >= top + viewH) top = cur - viewH + 1;
|
|
299
|
+
top = Math.max(0, Math.min(top, Math.max(0, entries.length - viewH)));
|
|
300
|
+
}
|
|
301
|
+
function rowFor(entry, gi, width) {
|
|
302
|
+
if (entry.kind === "header") {
|
|
303
|
+
return c.dim(" " + clip(entry.label, width - 2));
|
|
304
|
+
}
|
|
305
|
+
const active = gi === cursorEntry();
|
|
306
|
+
const ptr = active ? c.cyan("\u276F") : " ";
|
|
307
|
+
const box = selected.has(entry.id) ? c.green("\u25C9") : c.dim("\u25EF");
|
|
308
|
+
const used = 4;
|
|
309
|
+
const hintLen = entry.hint ? entry.hint.length + 2 : 0;
|
|
310
|
+
const name = clip(entry.label, width - used - hintLen);
|
|
311
|
+
const nameC = active ? c.cyan(name) : name;
|
|
312
|
+
const room = width - used - name.length - 2;
|
|
313
|
+
const hint = entry.hint && room > 4 ? " " + c.dim(clip(entry.hint, room)) : "";
|
|
314
|
+
return `${ptr} ${box} ${nameC}${hint}`;
|
|
315
|
+
}
|
|
316
|
+
function frame() {
|
|
317
|
+
clampWindow();
|
|
318
|
+
const width = termWidth();
|
|
319
|
+
const lines = [
|
|
320
|
+
`${c.bold(message)} ${c.dim(`(${selected.size} selected)`)}`
|
|
321
|
+
];
|
|
322
|
+
lines.push(
|
|
323
|
+
top > 0 ? c.dim(` \u2191 ${top} more above`) : ""
|
|
324
|
+
);
|
|
325
|
+
for (let row = 0; row < viewH; row++) {
|
|
326
|
+
const gi = top + row;
|
|
327
|
+
lines.push(gi < entries.length ? rowFor(entries[gi], gi, width) : "");
|
|
328
|
+
}
|
|
329
|
+
const below = entries.length - (top + viewH);
|
|
330
|
+
lines.push(below > 0 ? c.dim(` \u2193 ${below} more below`) : "");
|
|
331
|
+
lines.push(
|
|
332
|
+
c.dim("space toggle \xB7 a all/none \xB7 \u2191/\u2193 move \xB7 \u23CE confirm \xB7 esc cancel")
|
|
333
|
+
);
|
|
334
|
+
return lines.join("\n");
|
|
335
|
+
}
|
|
336
|
+
function move(delta) {
|
|
337
|
+
ci = (ci + delta + itemPositions.length) % itemPositions.length;
|
|
338
|
+
}
|
|
339
|
+
await run(frame, (key) => {
|
|
340
|
+
switch (key) {
|
|
341
|
+
case "up":
|
|
342
|
+
move(-1);
|
|
343
|
+
return "render";
|
|
344
|
+
case "down":
|
|
345
|
+
move(1);
|
|
346
|
+
return "render";
|
|
347
|
+
case "home":
|
|
348
|
+
ci = 0;
|
|
349
|
+
return "render";
|
|
350
|
+
case "end":
|
|
351
|
+
ci = itemPositions.length - 1;
|
|
352
|
+
return "render";
|
|
353
|
+
case "space": {
|
|
354
|
+
const e = entries[cursorEntry()];
|
|
355
|
+
if (e.kind === "item") {
|
|
356
|
+
if (selected.has(e.id)) selected.delete(e.id);
|
|
357
|
+
else selected.add(e.id);
|
|
358
|
+
}
|
|
359
|
+
return "render";
|
|
360
|
+
}
|
|
361
|
+
case "a": {
|
|
362
|
+
const allIds = itemPositions.map((p) => entries[p].id);
|
|
363
|
+
if (selected.size === allIds.length) selected.clear();
|
|
364
|
+
else for (const id of allIds) selected.add(id);
|
|
365
|
+
return "render";
|
|
366
|
+
}
|
|
367
|
+
case "enter":
|
|
368
|
+
return "done";
|
|
369
|
+
case "esc":
|
|
370
|
+
case "q":
|
|
371
|
+
cancelled = true;
|
|
372
|
+
return "done";
|
|
373
|
+
default:
|
|
374
|
+
return "ignore";
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
if (cancelled) return null;
|
|
378
|
+
return itemPositions.map((p) => entries[p].id).filter((id) => selected.has(id));
|
|
379
|
+
}
|
|
380
|
+
|
|
142
381
|
// src/resolve.ts
|
|
143
382
|
var TYPE_ALIASES = {
|
|
144
383
|
agent: "agent",
|
|
@@ -203,6 +442,12 @@ var PLURAL = {
|
|
|
203
442
|
skill: "skills",
|
|
204
443
|
command: "commands"
|
|
205
444
|
};
|
|
445
|
+
var SINGULAR = {
|
|
446
|
+
agent: "agent",
|
|
447
|
+
skill: "skill",
|
|
448
|
+
command: "command"
|
|
449
|
+
};
|
|
450
|
+
var TYPE_ORDER = ["agent", "skill", "command"];
|
|
206
451
|
function requireNode20() {
|
|
207
452
|
const major = Number(process.versions.node.split(".")[0]);
|
|
208
453
|
if (major < 20) {
|
|
@@ -212,11 +457,64 @@ function requireNode20() {
|
|
|
212
457
|
process.exit(1);
|
|
213
458
|
}
|
|
214
459
|
}
|
|
460
|
+
function tilde(p) {
|
|
461
|
+
const home = homedir2();
|
|
462
|
+
return p === home || p.startsWith(home + "/") ? "~" + p.slice(home.length) : p;
|
|
463
|
+
}
|
|
464
|
+
function installItems(items, scope, force, opts) {
|
|
465
|
+
if (items.length === 0) {
|
|
466
|
+
console.log(c.dim("Nothing to install."));
|
|
467
|
+
return 0;
|
|
468
|
+
}
|
|
469
|
+
const root = installRoot(scope);
|
|
470
|
+
if (!opts.verbose) {
|
|
471
|
+
console.log(
|
|
472
|
+
c.dim(`Installing ${items.length} items into ${tilde(root)} \u2026`)
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
let written = 0;
|
|
476
|
+
let skipped = 0;
|
|
477
|
+
let failed = 0;
|
|
478
|
+
const writtenByType = { agent: 0, skill: 0, command: 0 };
|
|
479
|
+
for (const item of items) {
|
|
480
|
+
const result = installItem(item, { scope, force });
|
|
481
|
+
if (result.status === "written") {
|
|
482
|
+
written++;
|
|
483
|
+
writtenByType[item.type]++;
|
|
484
|
+
if (opts.verbose) {
|
|
485
|
+
console.log(c.green("\u2713 ") + `${item.id} ${c.dim("\u2192")} ${result.dest}`);
|
|
486
|
+
}
|
|
487
|
+
} else if (result.status === "exists") {
|
|
488
|
+
skipped++;
|
|
489
|
+
if (opts.verbose) {
|
|
490
|
+
console.log(
|
|
491
|
+
c.yellow("\u2022 ") + `${item.id} already installed at ${result.dest} ${c.dim("(use --force to overwrite)")}`
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
failed++;
|
|
496
|
+
console.error(c.red("\u2717 ") + `${item.id}: ${result.message}`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (!opts.verbose && written > 0) {
|
|
500
|
+
const parts = TYPE_ORDER.filter((t) => writtenByType[t] > 0).map(
|
|
501
|
+
(t) => `${writtenByType[t]} ${writtenByType[t] === 1 ? SINGULAR[t] : PLURAL[t]}`
|
|
502
|
+
);
|
|
503
|
+
console.log(c.green("\u2713 ") + `${parts.join(", ")} installed`);
|
|
504
|
+
}
|
|
505
|
+
const summary = [`${written} installed`];
|
|
506
|
+
if (skipped) summary.push(`${skipped} already present`);
|
|
507
|
+
if (failed) summary.push(`${failed} failed`);
|
|
508
|
+
console.log(c.dim(`${summary.join(", ")} \xB7 ${tilde(root)}`));
|
|
509
|
+
return failed > 0 ? 1 : 0;
|
|
510
|
+
}
|
|
215
511
|
function cmdAdd(refs, flags) {
|
|
216
512
|
if (refs.length === 0) {
|
|
217
|
-
throw new CliError(
|
|
513
|
+
throw new CliError(
|
|
514
|
+
"Nothing to add \u2014 usage: agentscamp add <type>/<slug> [...more] (or: agentscamp install)"
|
|
515
|
+
);
|
|
218
516
|
}
|
|
219
|
-
const scope = resolveScope(flags);
|
|
517
|
+
const scope = resolveScope(flags, "project");
|
|
220
518
|
const { items } = loadManifest();
|
|
221
519
|
const resolutions = refs.map((ref) => resolveRef(ref, items));
|
|
222
520
|
let resolutionFailed = false;
|
|
@@ -235,30 +533,81 @@ function cmdAdd(refs, flags) {
|
|
|
235
533
|
}
|
|
236
534
|
}
|
|
237
535
|
if (resolutionFailed) return 1;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
console.log(
|
|
250
|
-
c.yellow("\u2022 ") + `${r.item.id} already installed at ${result.dest} ${c.dim("(use --force to overwrite)")}`
|
|
251
|
-
);
|
|
252
|
-
} else {
|
|
253
|
-
failed++;
|
|
254
|
-
console.error(c.red("\u2717 ") + `${r.item.id}: ${result.message}`);
|
|
536
|
+
const chosen = resolutions.flatMap((r) => r.kind === "ok" ? [r.item] : []);
|
|
537
|
+
return installItems(chosen, scope, flags.force, { verbose: true });
|
|
538
|
+
}
|
|
539
|
+
function pickerEntries(items) {
|
|
540
|
+
const entries = [];
|
|
541
|
+
for (const t of TYPE_ORDER) {
|
|
542
|
+
const list = items.filter((i) => i.type === t);
|
|
543
|
+
if (list.length === 0) continue;
|
|
544
|
+
entries.push({ kind: "header", label: `${PLURAL[t]} (${list.length})` });
|
|
545
|
+
for (const i of list) {
|
|
546
|
+
entries.push({ kind: "item", id: i.id, label: i.id, hint: i.title });
|
|
255
547
|
}
|
|
256
548
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
549
|
+
return entries;
|
|
550
|
+
}
|
|
551
|
+
async function interactiveInstall(items, scope, force) {
|
|
552
|
+
const count = (t) => items.filter((i) => i.type === t).length;
|
|
553
|
+
const choice = await selectOne("What do you want to install?", [
|
|
554
|
+
{ value: "all", label: "Everything", hint: `${items.length} items` },
|
|
555
|
+
{ value: "agent", label: "Agents only", hint: String(count("agent")) },
|
|
556
|
+
{ value: "skill", label: "Skills only", hint: String(count("skill")) },
|
|
557
|
+
{ value: "command", label: "Commands only", hint: String(count("command")) },
|
|
558
|
+
{ value: "pick", label: "Pick individual items\u2026" },
|
|
559
|
+
{ value: "cancel", label: "Cancel" }
|
|
560
|
+
]);
|
|
561
|
+
if (choice === null || choice === "cancel") {
|
|
562
|
+
console.log(c.dim("Nothing installed."));
|
|
563
|
+
return 0;
|
|
564
|
+
}
|
|
565
|
+
let chosen;
|
|
566
|
+
if (choice === "all") {
|
|
567
|
+
chosen = items;
|
|
568
|
+
} else if (choice === "pick") {
|
|
569
|
+
const ids = await multiSelect("Select items to install", pickerEntries(items));
|
|
570
|
+
if (ids === null) {
|
|
571
|
+
console.log(c.dim("Nothing installed."));
|
|
572
|
+
return 0;
|
|
573
|
+
}
|
|
574
|
+
if (ids.length === 0) {
|
|
575
|
+
console.log(c.dim("No items selected \u2014 nothing installed."));
|
|
576
|
+
return 0;
|
|
577
|
+
}
|
|
578
|
+
const idSet = new Set(ids);
|
|
579
|
+
chosen = items.filter((i) => idSet.has(i.id));
|
|
580
|
+
} else {
|
|
581
|
+
chosen = items.filter((i) => i.type === choice);
|
|
582
|
+
}
|
|
583
|
+
return installItems(chosen, scope, force, { verbose: chosen.length <= 12 });
|
|
584
|
+
}
|
|
585
|
+
function cmdInstall(positionals, flags) {
|
|
586
|
+
const scope = resolveScope(flags, "global");
|
|
587
|
+
const { items } = loadManifest();
|
|
588
|
+
if (flags.all) {
|
|
589
|
+
return installItems(items, scope, flags.force, { verbose: false });
|
|
590
|
+
}
|
|
591
|
+
if (positionals.length > 0) {
|
|
592
|
+
const types = [];
|
|
593
|
+
for (const p of positionals) {
|
|
594
|
+
const t = normalizeType(p.toLowerCase());
|
|
595
|
+
if (!t) {
|
|
596
|
+
throw new CliError(
|
|
597
|
+
`"${p}" is not a type \u2014 use agents, skills or commands (to install one item: agentscamp add ${p})`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
if (!types.includes(t)) types.push(t);
|
|
601
|
+
}
|
|
602
|
+
const chosen = items.filter((i) => types.includes(i.type));
|
|
603
|
+
return installItems(chosen, scope, flags.force, { verbose: false });
|
|
604
|
+
}
|
|
605
|
+
if (isInteractive()) {
|
|
606
|
+
return interactiveInstall(items, scope, flags.force);
|
|
607
|
+
}
|
|
608
|
+
throw new CliError(
|
|
609
|
+
"install needs a target in a non-interactive shell \u2014 try: agentscamp install --all (or: agents | skills | commands)"
|
|
610
|
+
);
|
|
262
611
|
}
|
|
263
612
|
function cmdList(typeArg) {
|
|
264
613
|
const { items } = loadManifest();
|
|
@@ -291,7 +640,7 @@ ${c.bold(PLURAL[t])} ${c.dim(`(${list.length})`)}`);
|
|
|
291
640
|
}
|
|
292
641
|
}
|
|
293
642
|
console.log(c.dim(`
|
|
294
|
-
Install
|
|
643
|
+
Install everything: npx agentscamp --all \xB7 one item: npx agentscamp add <id>`));
|
|
295
644
|
return 0;
|
|
296
645
|
}
|
|
297
646
|
function cmdSearch(query) {
|
|
@@ -346,18 +695,26 @@ Install: ${c.cyan(`npx agentscamp add ${item.id}`)}
|
|
|
346
695
|
`);
|
|
347
696
|
return 0;
|
|
348
697
|
}
|
|
349
|
-
function main(argv) {
|
|
698
|
+
async function main(argv) {
|
|
350
699
|
requireNode20();
|
|
351
700
|
const { command, positionals, flags } = parseArgs(argv);
|
|
352
701
|
if (flags.version) {
|
|
353
702
|
console.log(packageVersion());
|
|
354
703
|
return 0;
|
|
355
704
|
}
|
|
356
|
-
if (flags.help
|
|
705
|
+
if (flags.help) {
|
|
706
|
+
printHelp(packageVersion());
|
|
707
|
+
return 0;
|
|
708
|
+
}
|
|
709
|
+
if (!command) {
|
|
710
|
+
if (flags.all || isInteractive()) return cmdInstall([], flags);
|
|
357
711
|
printHelp(packageVersion());
|
|
358
712
|
return 0;
|
|
359
713
|
}
|
|
360
714
|
switch (command) {
|
|
715
|
+
case "install":
|
|
716
|
+
case "i":
|
|
717
|
+
return cmdInstall(positionals, flags);
|
|
361
718
|
case "add":
|
|
362
719
|
return cmdAdd(positionals, flags);
|
|
363
720
|
case "list":
|
|
@@ -368,17 +725,17 @@ function main(argv) {
|
|
|
368
725
|
return cmdInfo(positionals[0]);
|
|
369
726
|
default:
|
|
370
727
|
throw new CliError(
|
|
371
|
-
`Unknown command "${command}" \u2014 commands: add, list, search, info (see --help)`
|
|
728
|
+
`Unknown command "${command}" \u2014 commands: install, add, list, search, info (see --help)`
|
|
372
729
|
);
|
|
373
730
|
}
|
|
374
731
|
}
|
|
375
|
-
|
|
376
|
-
process.exitCode =
|
|
377
|
-
}
|
|
732
|
+
main(process.argv.slice(2)).then((code) => {
|
|
733
|
+
process.exitCode = code;
|
|
734
|
+
}).catch((e) => {
|
|
378
735
|
if (e instanceof CliError) {
|
|
379
736
|
console.error(c.red("\u2717 ") + e.message);
|
|
380
737
|
process.exitCode = 1;
|
|
381
738
|
} else {
|
|
382
739
|
throw e;
|
|
383
740
|
}
|
|
384
|
-
}
|
|
741
|
+
});
|