ai-builder 0.1.6 → 0.1.8

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.
Files changed (3) hide show
  1. package/README.md +1 -13
  2. package/dist/index.js +156 -163
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -19,7 +19,6 @@
19
19
  ## Features
20
20
 
21
21
  - **Install artifacts** - Add skills, agents, and commands from the registry
22
- - **Install stacks** - Bundle multiple artifacts together for specific workflows
23
22
  - **Search the registry** - Find artifacts by name, description, or task category
24
23
  - **Manage installed artifacts** - List and remove artifacts from your project
25
24
  - **Self-update** - Keep the CLI up to date with a single command
@@ -72,7 +71,7 @@ Install an artifact from the registry:
72
71
  npx ai-builder add <type> <author/slug>
73
72
  ```
74
73
 
75
- **Types:** `skill`, `agent`, `command`, `stack`
74
+ **Types:** `skill`, `agent`, `command`
76
75
 
77
76
  **Examples:**
78
77
 
@@ -90,16 +89,6 @@ npx ai-builder add skill anthropic/mcp-builder
90
89
  npx ai-builder add agent git-town/code_reviewer --force
91
90
  ```
92
91
 
93
- **Stacks** bundle multiple artifacts together:
94
-
95
- ```bash
96
- # Install a stack (prompts for confirmation)
97
- npx ai-builder add stack my-stack
98
-
99
- # Skip confirmation
100
- npx ai-builder add stack my-stack --yes
101
- ```
102
-
103
92
  ### Remove
104
93
 
105
94
  Remove an installed artifact:
@@ -219,7 +208,6 @@ ai-builder completion zsh >> ~/.zshrc
219
208
  | **skill** | Background capabilities that enhance Claude's abilities | `.claude/skills/{name}/` |
220
209
  | **agent** | Specialized agents invoked with `@agent-name` | `.claude/agents/{name}.md` |
221
210
  | **command** | Slash commands invoked with `/command-name` | `.claude/commands/{name}.md` |
222
- | **stack** | Bundles of artifacts for specific workflows | Various locations |
223
211
 
224
212
  ---
225
213
 
package/dist/index.js CHANGED
@@ -5,10 +5,85 @@ import chalk8 from "chalk";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // src/commands/add.ts
8
- import * as readline from "readline";
9
8
  import chalk from "chalk";
10
9
  import ora from "ora";
11
10
 
11
+ // src/services/metadata.ts
12
+ import * as os2 from "os";
13
+
14
+ // src/services/anonymous-id.ts
15
+ import * as crypto from "crypto";
16
+ import * as fs from "fs";
17
+ import * as os from "os";
18
+ import * as path from "path";
19
+ var CONFIG_DIR = path.join(os.homedir(), ".config", "ai-builder");
20
+ var ANONYMOUS_ID_FILE = path.join(CONFIG_DIR, "anonymous-id");
21
+ function isValidUuid(str) {
22
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
23
+ return uuidRegex.test(str);
24
+ }
25
+ function getAnonymousId() {
26
+ if (fs.existsSync(ANONYMOUS_ID_FILE)) {
27
+ try {
28
+ const id = fs.readFileSync(ANONYMOUS_ID_FILE, "utf-8").trim();
29
+ if (isValidUuid(id)) {
30
+ return id;
31
+ }
32
+ } catch {
33
+ }
34
+ }
35
+ const newId = crypto.randomUUID();
36
+ try {
37
+ if (!fs.existsSync(CONFIG_DIR)) {
38
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
39
+ }
40
+ fs.writeFileSync(ANONYMOUS_ID_FILE, `${newId}
41
+ `, { mode: 384 });
42
+ } catch {
43
+ }
44
+ return newId;
45
+ }
46
+
47
+ // src/services/metadata.ts
48
+ function getShell() {
49
+ const shell = process.env.SHELL || process.env.COMSPEC;
50
+ if (!shell) return null;
51
+ const parts = shell.split(/[/\\]/);
52
+ return parts[parts.length - 1] || null;
53
+ }
54
+ function getTerminal() {
55
+ return process.env.TERM_PROGRAM || // iTerm.app, Apple_Terminal, vscode
56
+ process.env.TERMINAL_EMULATOR || // Some Linux terminals
57
+ (process.env.WT_SESSION ? "windows-terminal" : null);
58
+ }
59
+ function detectCi() {
60
+ return !!(process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.BUILD_NUMBER || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.TRAVIS || process.env.JENKINS_URL);
61
+ }
62
+ function getLocale() {
63
+ return process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || process.env.LANGUAGE || null;
64
+ }
65
+ function getTimezone() {
66
+ try {
67
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
68
+ } catch {
69
+ return process.env.TZ || null;
70
+ }
71
+ }
72
+ function collectMetadata() {
73
+ return {
74
+ anonymousId: getAnonymousId(),
75
+ osType: os2.platform(),
76
+ osVersion: os2.release(),
77
+ osArch: os2.arch(),
78
+ nodeVersion: process.version,
79
+ shell: getShell(),
80
+ terminal: getTerminal(),
81
+ isCi: detectCi(),
82
+ locale: getLocale(),
83
+ timezone: getTimezone()
84
+ };
85
+ }
86
+
12
87
  // src/services/api.ts
13
88
  var API_BASE = process.env.AI_BUILDER_API_URL || "https://aibuilder.sh/api";
14
89
  var isDebug = process.env.DEBUG?.includes("ai-builder");
@@ -67,49 +142,47 @@ async function searchArtifacts(options) {
67
142
  }
68
143
  async function trackInstall(type, slug, cliVersion) {
69
144
  try {
145
+ const metadata = collectMetadata();
70
146
  const response = await fetch(`${API_BASE}/install-events`, {
71
147
  method: "POST",
72
148
  headers: { "Content-Type": "application/json" },
73
- body: JSON.stringify({ type, slug, cliVersion })
149
+ body: JSON.stringify({ type, slug, cliVersion, metadata })
74
150
  });
75
151
  const result = await response.json();
76
- logger.debug({ type, slug, cliVersion, status: response.status, result }, "Install tracked");
152
+ logger.debug(
153
+ {
154
+ type,
155
+ slug,
156
+ cliVersion,
157
+ anonymousId: metadata.anonymousId,
158
+ status: response.status,
159
+ result
160
+ },
161
+ "Install tracked"
162
+ );
77
163
  } catch (error) {
78
164
  logger.debug({ err: error, type, slug }, "Install tracking failed (non-critical)");
79
165
  }
80
166
  }
81
- async function resolveStack(slug) {
82
- const url = `${API_BASE}/stacks/${encodeURIComponent(slug)}`;
83
- const timer = logger.startTimer("api-resolve-stack");
84
- const response = await fetch(url);
85
- if (!response.ok) {
86
- const errorBody = await response.json().catch(() => ({ error: "Unknown error" }));
87
- timer.done({ slug, status: response.status, success: false });
88
- throw new Error(errorBody.error || `Failed to resolve stack: ${response.status}`);
89
- }
90
- const result = await response.json();
91
- timer.done({ slug, artifactCount: result.artifactCount, status: response.status, success: true });
92
- return result;
93
- }
94
167
 
95
168
  // src/services/installer.ts
96
- import * as fs2 from "fs";
97
- import * as path2 from "path";
169
+ import * as fs3 from "fs";
170
+ import * as path3 from "path";
98
171
 
99
172
  // src/services/lock-file.ts
100
- import * as fs from "fs";
101
- import * as path from "path";
173
+ import * as fs2 from "fs";
174
+ import * as path2 from "path";
102
175
  var LOCK_FILE_NAME = "ai-builder.lock.json";
103
176
  function getLockFilePath() {
104
- return path.join(process.cwd(), ".claude", LOCK_FILE_NAME);
177
+ return path2.join(process.cwd(), ".claude", LOCK_FILE_NAME);
105
178
  }
106
179
  function readLockFile() {
107
180
  const lockPath = getLockFilePath();
108
- if (!fs.existsSync(lockPath)) {
181
+ if (!fs2.existsSync(lockPath)) {
109
182
  return { version: 1, artifacts: {} };
110
183
  }
111
184
  try {
112
- const content = fs.readFileSync(lockPath, "utf-8");
185
+ const content = fs2.readFileSync(lockPath, "utf-8");
113
186
  return JSON.parse(content);
114
187
  } catch {
115
188
  return { version: 1, artifacts: {} };
@@ -117,11 +190,11 @@ function readLockFile() {
117
190
  }
118
191
  function writeLockFile(lockFile) {
119
192
  const lockPath = getLockFilePath();
120
- const lockDir = path.dirname(lockPath);
121
- if (!fs.existsSync(lockDir)) {
122
- fs.mkdirSync(lockDir, { recursive: true });
193
+ const lockDir = path2.dirname(lockPath);
194
+ if (!fs2.existsSync(lockDir)) {
195
+ fs2.mkdirSync(lockDir, { recursive: true });
123
196
  }
124
- fs.writeFileSync(lockPath, `${JSON.stringify(lockFile, null, 2)}
197
+ fs2.writeFileSync(lockPath, `${JSON.stringify(lockFile, null, 2)}
125
198
  `);
126
199
  }
127
200
  function addToLockFile(entry) {
@@ -148,82 +221,82 @@ function isInstalled(type, author, slug) {
148
221
 
149
222
  // src/services/installer.ts
150
223
  function getInstallPath(type, artifactName) {
151
- const basePath = path2.join(process.cwd(), ".claude");
224
+ const basePath = path3.join(process.cwd(), ".claude");
152
225
  switch (type) {
153
226
  case "skill":
154
- return path2.join(basePath, "skills", artifactName);
227
+ return path3.join(basePath, "skills", artifactName);
155
228
  case "agent":
156
- return path2.join(basePath, "agents", `${artifactName}.md`);
229
+ return path3.join(basePath, "agents", `${artifactName}.md`);
157
230
  case "command":
158
- return path2.join(basePath, "commands", `${artifactName}.md`);
231
+ return path3.join(basePath, "commands", `${artifactName}.md`);
159
232
  default:
160
233
  throw new Error(`Unknown artifact type: ${type}`);
161
234
  }
162
235
  }
163
236
  function installArtifact(artifact, options = {}) {
164
- const artifactName = artifact.slug.split("/")[1];
237
+ const artifactName = artifact.name;
165
238
  const installPath = getInstallPath(artifact.type, artifactName);
166
239
  const files = [];
167
240
  if (!options.force && isInstalled(artifact.type, artifact.author, artifactName || artifact.name)) {
168
241
  return { installed: false, files: [] };
169
242
  }
170
- const dir = artifact.type === "skill" ? installPath : path2.dirname(installPath);
171
- if (!fs2.existsSync(dir)) {
172
- fs2.mkdirSync(dir, { recursive: true });
243
+ const dir = artifact.type === "skill" ? installPath : path3.dirname(installPath);
244
+ if (!fs3.existsSync(dir)) {
245
+ fs3.mkdirSync(dir, { recursive: true });
173
246
  }
174
247
  if (artifact.type === "skill") {
175
- const skillMdPath = path2.join(installPath, "SKILL.md");
176
- fs2.writeFileSync(skillMdPath, artifact.content);
248
+ const skillMdPath = path3.join(installPath, "SKILL.md");
249
+ fs3.writeFileSync(skillMdPath, artifact.content);
177
250
  files.push(skillMdPath);
178
251
  if (artifact.bundleFiles) {
179
252
  for (const [filename, content] of Object.entries(artifact.bundleFiles)) {
180
- const filePath = path2.join(installPath, filename);
181
- fs2.mkdirSync(path2.dirname(filePath), { recursive: true });
182
- fs2.writeFileSync(filePath, content);
253
+ const filePath = path3.join(installPath, filename);
254
+ fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
255
+ fs3.writeFileSync(filePath, content);
183
256
  files.push(filePath);
184
257
  }
185
258
  }
186
259
  } else {
187
- fs2.writeFileSync(installPath, artifact.content);
260
+ fs3.writeFileSync(installPath, artifact.content);
188
261
  files.push(installPath);
189
262
  }
190
263
  addToLockFile({
191
264
  type: artifact.type,
192
- slug: artifactName || artifact.name,
265
+ slug: artifact.name,
193
266
  author: artifact.author,
194
267
  name: artifact.name,
195
268
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
196
- files: files.map((f) => path2.relative(process.cwd(), f))
269
+ files: files.map((f) => path3.relative(process.cwd(), f))
197
270
  });
198
271
  return { installed: true, files };
199
272
  }
200
273
  function uninstallArtifact(type, author, slug) {
201
274
  const installPath = getInstallPath(type, slug);
202
- if (!fs2.existsSync(installPath)) {
275
+ if (!fs3.existsSync(installPath)) {
203
276
  return false;
204
277
  }
205
278
  if (type === "skill") {
206
- fs2.rmSync(installPath, { recursive: true, force: true });
279
+ fs3.rmSync(installPath, { recursive: true, force: true });
207
280
  } else {
208
- fs2.unlinkSync(installPath);
281
+ fs3.unlinkSync(installPath);
209
282
  }
210
283
  removeFromLockFile(type, author, slug);
211
284
  return true;
212
285
  }
213
286
 
214
287
  // src/commands/add.ts
215
- var VALID_TYPES = ["skill", "agent", "command", "stack"];
288
+ var VALID_TYPES = ["skill", "agent", "command"];
216
289
  var CLI_VERSION = "0.1.0";
217
290
  async function addCommand(type, slug, options) {
218
291
  if (!type) {
219
292
  console.log(chalk.red("Error: Missing artifact type."));
220
293
  console.log("Usage: ai-builder add <type> <author/slug>");
221
- console.log("Types: skill, agent, command, stack");
294
+ console.log("Types: skill, agent, command");
222
295
  process.exit(1);
223
296
  }
224
297
  if (!VALID_TYPES.includes(type)) {
225
298
  console.log(chalk.red(`Error: Invalid type "${type}".`));
226
- console.log("Valid types: skill, agent, command, stack");
299
+ console.log("Valid types: skill, agent, command");
227
300
  process.exit(1);
228
301
  }
229
302
  if (!slug) {
@@ -232,33 +305,28 @@ async function addCommand(type, slug, options) {
232
305
  console.log("Example: ai-builder add agent anthropic/frontend-tester");
233
306
  process.exit(1);
234
307
  }
235
- if (type !== "stack" && !slug.includes("/")) {
308
+ if (!slug.includes("/")) {
236
309
  console.log(chalk.red("Error: Invalid slug format."));
237
310
  console.log("Expected format: author/artifact-name");
238
311
  console.log("Example: anthropic/frontend-tester");
239
312
  process.exit(1);
240
313
  }
241
- if (type === "stack") {
242
- await installStack(slug, options);
243
- return;
244
- }
245
314
  const [author, artifactSlug] = slug.split("/");
246
- if (!options.force && isInstalled(type, author, artifactSlug)) {
247
- console.log(chalk.yellow(`${type} ${chalk.bold(slug)} is already installed.`));
248
- console.log("Use --force to reinstall.");
249
- return;
250
- }
251
- const spinner = ora(`Resolving ${type} ${chalk.cyan(slug)}...`).start();
315
+ const isUpdate = isInstalled(type, author, artifactSlug);
316
+ const actionVerb = isUpdate ? "Updating" : "Resolving";
317
+ const spinner = ora(`${actionVerb} ${type} ${chalk.cyan(slug)}...`).start();
252
318
  try {
253
319
  const artifact = await resolveArtifact(type, slug);
254
- spinner.text = `Installing ${artifact.name}...`;
255
- const { installed } = installArtifact(artifact, { force: options.force });
320
+ const installVerb = isUpdate ? "Updating" : "Installing";
321
+ spinner.text = `${installVerb} ${artifact.name}...`;
322
+ const { installed } = installArtifact(artifact, { force: isUpdate || options.force });
256
323
  if (!installed) {
257
- spinner.warn(`${artifact.name} is already installed. Use --force to reinstall.`);
324
+ spinner.warn(`${artifact.name} could not be installed.`);
258
325
  return;
259
326
  }
327
+ const successVerb = isUpdate ? "Updated" : "Installed";
260
328
  spinner.succeed(
261
- `Installed ${chalk.green(artifact.name)} to ${chalk.dim(artifact.installPath)}`
329
+ `${successVerb} ${chalk.green(artifact.name)} to ${chalk.dim(artifact.installPath)}`
262
330
  );
263
331
  console.log();
264
332
  printUsageHint(type, artifactSlug);
@@ -284,85 +352,11 @@ function printUsageHint(type, slug) {
284
352
  break;
285
353
  }
286
354
  }
287
- async function installStack(stackSlug, options) {
288
- const spinner = ora(`Resolving stack ${chalk.cyan(stackSlug)}...`).start();
289
- try {
290
- const stack = await resolveStack(stackSlug);
291
- spinner.stop();
292
- console.log();
293
- console.log(chalk.bold(`Stack: ${stack.title}`));
294
- if (stack.summary) {
295
- console.log(chalk.dim(stack.summary));
296
- }
297
- console.log();
298
- console.log(`This will install ${chalk.cyan(stack.artifactCount)} artifacts:`);
299
- console.log();
300
- for (const artifact of stack.artifacts) {
301
- const typeColor = artifact.type === "skill" ? chalk.blue : artifact.type === "agent" ? chalk.magenta : chalk.green;
302
- console.log(` ${typeColor(`[${artifact.type}]`)} ${artifact.name}`);
303
- console.log(` ${chalk.dim(artifact.slug)}`);
304
- if (artifact.installNotes) {
305
- console.log(` ${chalk.yellow(`Note: ${artifact.installNotes}`)}`);
306
- }
307
- }
308
- console.log();
309
- if (!options.yes) {
310
- const confirmed = await confirm("Proceed with installation?");
311
- if (!confirmed) {
312
- console.log("Cancelled.");
313
- return;
314
- }
315
- }
316
- console.log();
317
- let installed = 0;
318
- let skipped = 0;
319
- for (const artifact of stack.artifacts) {
320
- const artifactSpinner = ora(`Installing ${artifact.name}...`).start();
321
- try {
322
- const resolved = await resolveArtifact(artifact.type, artifact.slug);
323
- const result = installArtifact(resolved, { force: options.force });
324
- if (result.installed) {
325
- artifactSpinner.succeed(`Installed ${chalk.green(artifact.name)}`);
326
- await trackInstall(artifact.type, artifact.slug, CLI_VERSION);
327
- installed++;
328
- } else {
329
- artifactSpinner.info(`${artifact.name} already installed`);
330
- skipped++;
331
- }
332
- } catch (error) {
333
- const message = error instanceof Error ? error.message : "Unknown error";
334
- artifactSpinner.fail(`Failed to install ${artifact.name}: ${chalk.dim(message)}`);
335
- }
336
- }
337
- console.log();
338
- console.log(
339
- `${chalk.green("Done!")} Installed ${installed} artifact${installed === 1 ? "" : "s"}${skipped > 0 ? `, skipped ${skipped}` : ""}`
340
- );
341
- console.log();
342
- console.log(chalk.dim(`Learn more: https://aibuilder.sh/stacks/${stackSlug}`));
343
- } catch (error) {
344
- const message = error instanceof Error ? error.message : "Unknown error";
345
- spinner.fail(chalk.red(`Failed to resolve stack: ${message}`));
346
- process.exit(1);
347
- }
348
- }
349
- async function confirm(question) {
350
- const rl = readline.createInterface({
351
- input: process.stdin,
352
- output: process.stdout
353
- });
354
- return new Promise((resolve) => {
355
- rl.question(`${question} ${chalk.dim("[y/N]")} `, (answer) => {
356
- rl.close();
357
- resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
358
- });
359
- });
360
- }
361
355
 
362
356
  // src/commands/completion.ts
363
- import * as fs3 from "fs";
364
- import * as os from "os";
365
- import * as path3 from "path";
357
+ import * as fs4 from "fs";
358
+ import * as os3 from "os";
359
+ import * as path4 from "path";
366
360
  import chalk2 from "chalk";
367
361
  var BASH_COMPLETION = `
368
362
  # ai-builder bash completion
@@ -371,7 +365,7 @@ _ai_builder_completions() {
371
365
  _get_comp_words_by_ref -n : cur prev words cword
372
366
 
373
367
  local commands="add remove rm list ls search status update completion"
374
- local types="skill agent command stack"
368
+ local types="skill agent command"
375
369
 
376
370
  case "\${prev}" in
377
371
  ai-builder)
@@ -425,7 +419,7 @@ _ai_builder() {
425
419
  local -a commands types
426
420
 
427
421
  commands=(
428
- 'add:Install an artifact or stack'
422
+ 'add:Install an artifact'
429
423
  'remove:Remove an installed artifact'
430
424
  'rm:Remove an installed artifact'
431
425
  'list:List installed artifacts'
@@ -436,7 +430,7 @@ _ai_builder() {
436
430
  'completion:Generate shell completions'
437
431
  )
438
432
 
439
- types=(skill agent command stack)
433
+ types=(skill agent command)
440
434
 
441
435
  _arguments -C \\
442
436
  '1:command:->command' \\
@@ -450,10 +444,9 @@ _ai_builder() {
450
444
  case "$words[1]" in
451
445
  add|remove|rm)
452
446
  _arguments \\
453
- '1:type:(skill agent command stack)' \\
447
+ '1:type:(skill agent command)' \\
454
448
  '2:slug:' \\
455
449
  '--force[Overwrite existing artifacts]' \\
456
- '--yes[Skip confirmation]' \\
457
450
  '--help[Show help]'
458
451
  ;;
459
452
  list|ls)
@@ -488,14 +481,14 @@ _ai_builder() {
488
481
  _ai_builder "$@"
489
482
  `.trim();
490
483
  function getShellConfigPath(shell) {
491
- const home = os.homedir();
484
+ const home = os3.homedir();
492
485
  if (shell === "bash") {
493
- const bashrc = path3.join(home, ".bashrc");
494
- const bashProfile = path3.join(home, ".bash_profile");
495
- return fs3.existsSync(bashrc) ? bashrc : bashProfile;
486
+ const bashrc = path4.join(home, ".bashrc");
487
+ const bashProfile = path4.join(home, ".bash_profile");
488
+ return fs4.existsSync(bashrc) ? bashrc : bashProfile;
496
489
  }
497
490
  if (shell === "zsh") {
498
- return path3.join(home, ".zshrc");
491
+ return path4.join(home, ".zshrc");
499
492
  }
500
493
  return null;
501
494
  }
@@ -523,14 +516,14 @@ function completionCommand(shell, options) {
523
516
  }
524
517
  const completion = detectedShell === "zsh" ? ZSH_COMPLETION : BASH_COMPLETION;
525
518
  const marker = "# ai-builder completion";
526
- const existingContent = fs3.existsSync(configPath) ? fs3.readFileSync(configPath, "utf-8") : "";
519
+ const existingContent = fs4.existsSync(configPath) ? fs4.readFileSync(configPath, "utf-8") : "";
527
520
  if (existingContent.includes(marker)) {
528
521
  console.log(chalk2.yellow(`
529
522
  Completion already installed in ${configPath}`));
530
523
  console.log(chalk2.dim(" Restart your terminal to apply changes\n"));
531
524
  return;
532
525
  }
533
- fs3.appendFileSync(configPath, `
526
+ fs4.appendFileSync(configPath, `
534
527
  ${completion}
535
528
  `);
536
529
  console.log(chalk2.green(`
@@ -634,7 +627,7 @@ function formatDate(isoDate) {
634
627
  }
635
628
 
636
629
  // src/commands/remove.ts
637
- import * as readline2 from "readline";
630
+ import * as readline from "readline";
638
631
  import chalk4 from "chalk";
639
632
  var VALID_TYPES2 = ["skill", "agent", "command"];
640
633
  async function removeCommand(type, slug, options) {
@@ -667,7 +660,7 @@ async function removeCommand(type, slug, options) {
667
660
  return;
668
661
  }
669
662
  if (!options.yes) {
670
- const confirmed = await confirm2(`Remove ${type} ${chalk4.cyan(slug)}?`);
663
+ const confirmed = await confirm(`Remove ${type} ${chalk4.cyan(slug)}?`);
671
664
  if (!confirmed) {
672
665
  console.log("Cancelled.");
673
666
  return;
@@ -681,8 +674,8 @@ async function removeCommand(type, slug, options) {
681
674
  process.exit(1);
682
675
  }
683
676
  }
684
- async function confirm2(question) {
685
- const rl = readline2.createInterface({
677
+ async function confirm(question) {
678
+ const rl = readline.createInterface({
686
679
  input: process.stdin,
687
680
  output: process.stdout
688
681
  });
@@ -766,8 +759,8 @@ function formatNumber(num) {
766
759
  }
767
760
 
768
761
  // src/commands/status.ts
769
- import * as fs4 from "fs";
770
- import * as path4 from "path";
762
+ import * as fs5 from "fs";
763
+ import * as path5 from "path";
771
764
  import chalk6 from "chalk";
772
765
 
773
766
  // src/version.ts
@@ -781,8 +774,8 @@ var API_BASE2 = process.env.AI_BUILDER_API_URL || "https://aibuilder.sh/api";
781
774
  async function statusCommand() {
782
775
  console.log(chalk6.cyan.bold("\n ai-builder status\n"));
783
776
  console.log(` ${chalk6.dim("Version:")} ${chalk6.white(version)}`);
784
- const claudeDir = path4.join(process.cwd(), ".claude");
785
- const claudeDirExists = fs4.existsSync(claudeDir);
777
+ const claudeDir = path5.join(process.cwd(), ".claude");
778
+ const claudeDirExists = fs5.existsSync(claudeDir);
786
779
  console.log(
787
780
  ` ${chalk6.dim("Claude dir:")} ${claudeDirExists ? chalk6.green(".claude/ found") : chalk6.yellow(".claude/ not found")}`
788
781
  );
@@ -883,7 +876,7 @@ async function updateCommand(options) {
883
876
  // src/index.ts
884
877
  var program = new Command();
885
878
  program.name("ai-builder").description("CLI for installing Claude Code artifacts from aibuilder.sh").version(version);
886
- program.command("add").description("Install an artifact or stack").argument("[type]", "Artifact type: skill, agent, command, or stack").argument("[slug]", "Artifact slug in author/name format").option("-f, --force", "Overwrite existing artifacts").option("-y, --yes", "Skip confirmation for stacks").action(addCommand);
879
+ program.command("add").description("Install an artifact").argument("[type]", "Artifact type: skill, agent, or command").argument("[slug]", "Artifact slug in author/name format").option("-f, --force", "Overwrite existing artifacts").action(addCommand);
887
880
  program.command("remove").alias("rm").description("Remove an installed artifact").argument("[type]", "Artifact type: skill, agent, or command").argument("[slug]", "Artifact slug in author/name format").option("-y, --yes", "Skip confirmation").action(removeCommand);
888
881
  program.command("list").alias("ls").description("List installed artifacts").option("-t, --type <type>", "Filter by type: skill, agent, or command").action(listCommand);
889
882
  program.command("search").description("Search the registry for artifacts").argument("<query>", "Search query").option("-t, --type <type>", "Filter by type: skill, agent, or command").option("--task <task>", "Filter by task category").option("-l, --limit <number>", "Number of results", "10").action(searchCommand);
@@ -904,7 +897,7 @@ program.action(() => {
904
897
  console.log(" ai-builder update Update CLI");
905
898
  console.log("\n Examples:");
906
899
  console.log(`${chalk8.green(" $ ")}ai-builder add agent anthropic/frontend-tester`);
907
- console.log(`${chalk8.green(" $ ")}ai-builder add stack nextjs-fullstack`);
900
+ console.log(`${chalk8.green(" $ ")}ai-builder add skill anthropic/code-reviewer`);
908
901
  console.log(`${chalk8.green(" $ ")}ai-builder search "test generator"`);
909
902
  console.log(`
910
903
  Learn more at ${chalk8.cyan("https://aibuilder.sh")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-builder",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "CLI for installing Claude Code artifacts from aibuilder.sh",
5
5
  "type": "module",
6
6
  "bin": {