agentscamp 0.6.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 CHANGED
@@ -6,37 +6,64 @@
6
6
 
7
7
  ## Quick start
8
8
 
9
+ Run it with no arguments and pick what to install:
10
+
9
11
  ```bash
10
- npx agentscamp add agents/api-architect
12
+ npx agentscamp
11
13
  ```
12
14
 
13
15
  ```
14
- agents/api-architect /your/project/.claude/agents/api-architect.md
15
- 1 installed
16
+ What do you want to install?
17
+ Everything 198 items
18
+ Agents only 58
19
+ Skills only 90
20
+ Commands only 50
21
+ Pick individual items…
22
+ Cancel
23
+ ```
24
+
25
+ Or skip the menu and install the whole catalog in one shot:
26
+
27
+ ```bash
28
+ npx agentscamp --all
29
+ ```
30
+
31
+ ```
32
+ Installing 198 items into ~/.claude …
33
+ ✓ 58 agents, 90 skills, 50 commands installed
34
+ 198 installed · ~/.claude
16
35
  ```
17
36
 
18
37
  ## Commands
19
38
 
20
- | Command | What it does |
21
- | ----------------------------- | ----------------------------------------------------------------------------------------- |
22
- | `npx agentscamp add <id...>` | Install one or more items (`agents/x`, `skills/x`, `commands/x`, or a bare slug if unique) |
23
- | `npx agentscamp list [type]` | List the whole catalog, or one type (`agents` \| `skills` \| `commands`) |
24
- | `npx agentscamp search <query>` | Search by name, title, topic, or description |
25
- | `npx agentscamp info <id>` | Show details and install paths for an item |
39
+ | Command | What it does |
40
+ | -------------------------------- | ------------------------------------------------------------------------------------------ |
41
+ | `npx agentscamp` | Interactive picker install everything, a whole type, or hand-pick items |
42
+ | `npx agentscamp --all` | Install the entire catalog, no prompts |
43
+ | `npx agentscamp install [type...]` | Install whole types (`agents` \| `skills` \| `commands`), `--all`, or pick interactively |
44
+ | `npx agentscamp add <id...>` | Install specific items (`agents/x`, `skills/x`, `commands/x`, or a bare slug if unique) |
45
+ | `npx agentscamp list [type]` | List the whole catalog, or one type |
46
+ | `npx agentscamp search <query>` | Search by name, title, topic, or description |
47
+ | `npx agentscamp info <id>` | Show details and install paths for an item |
26
48
 
27
49
  | Flag | Effect |
28
50
  | -------------- | ----------------------------------------------------------------------- |
29
- | `-g, --global` | Install to `~/.claude/` (default is `./.claude/` in the current project) |
30
- | `--project` | Install to `./.claude/` explicitly |
31
- | `-f, --force` | Overwrite existing files (re-running `add` without it is a safe no-op) |
51
+ | `-a, --all` | Install the whole catalog (with `install` or no command) |
52
+ | `-g, --global` | Install to `~/.claude/`, available in every project |
53
+ | `--project` | Install to `./.claude/` in the current project |
54
+ | `-f, --force` | Overwrite existing files (re-running without it is a safe no-op) |
32
55
 
33
56
  ## Where files go
34
57
 
35
- | Type | Project (default) | Global (`-g`) |
36
- | -------- | ----------------------------------- | ---------------------------------- |
37
- | Agents | `./.claude/agents/<name>.md` | `~/.claude/agents/<name>.md` |
38
- | Skills | `./.claude/skills/<name>/SKILL.md` | `~/.claude/skills/<name>/SKILL.md` |
39
- | Commands | `./.claude/commands/<name>.md` | `~/.claude/commands/<name>.md` |
58
+ Bulk installs (`install` / `--all` / the picker) default to **`~/.claude/`** so the
59
+ items are available in every project. Targeted `add` defaults to **`./.claude/`** in
60
+ the current project. Pass `-g` or `--project` anywhere to override.
61
+
62
+ | Type | Global (`install` default) | Project (`add` default, `--project`) |
63
+ | -------- | ---------------------------------- | ------------------------------------ |
64
+ | Agents | `~/.claude/agents/<name>.md` | `./.claude/agents/<name>.md` |
65
+ | Skills | `~/.claude/skills/<name>/SKILL.md` | `./.claude/skills/<name>/SKILL.md` |
66
+ | Commands | `~/.claude/commands/<name>.md` | `./.claude/commands/<name>.md` |
40
67
 
41
68
  These are Claude Code's standard locations — agents get delegated to automatically based on their description, skills load on demand, and commands run as `/<name>`.
42
69
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-06-18T02:50:33.985Z",
3
+ "generatedAt": "2026-06-20T01:43:19.461Z",
4
4
  "counts": {
5
5
  "agents": 58,
6
6
  "skills": 90,
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
- add <id...> Install one or more items (e.g. agents/prompt-engineer)
28
- list [type] List everything, or one type (agents | skills | commands)
29
- search <query> Search by name, title, topic, or description
30
- info <id> Show details and install paths for an item
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
- -g, --global Install to ~/.claude/ (default: ./.claude/ in the current project)
34
- --project Install to ./.claude/ explicitly
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 add agents/prompt-engineer
41
- npx agentscamp add skills/dependency-audit commands/plan-feature -g
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
- var DEFAULT_SCOPE = "project";
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 DEFAULT_SCOPE;
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("Nothing to add \u2014 usage: agentscamp add <type>/<slug> [...more]");
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
- let written = 0;
239
- let skipped = 0;
240
- let failed = 0;
241
- for (const r of resolutions) {
242
- if (r.kind !== "ok") continue;
243
- const result = installItem(r.item, { scope, force: flags.force });
244
- if (result.status === "written") {
245
- written++;
246
- console.log(c.green("\u2713 ") + `${r.item.id} ${c.dim("\u2192")} ${result.dest}`);
247
- } else if (result.status === "exists") {
248
- skipped++;
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
- const summary = [`${written} installed`];
258
- if (skipped) summary.push(`${skipped} already present`);
259
- if (failed) summary.push(`${failed} failed`);
260
- console.log(c.dim(summary.join(", ")));
261
- return failed > 0 ? 1 : 0;
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 with: npx agentscamp add <id>`));
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 || !command) {
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
- try {
376
- process.exitCode = main(process.argv.slice(2));
377
- } catch (e) {
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
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentscamp",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Install AgentsCamp agents, skills, and slash commands into Claude Code from your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",