ai-builder 0.1.2 → 0.1.4

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 +54 -0
  2. package/dist/index.js +408 -59
  3. package/package.json +1 -2
package/README.md CHANGED
@@ -22,6 +22,8 @@
22
22
  - **Install stacks** - Bundle multiple artifacts together for specific workflows
23
23
  - **Search the registry** - Find artifacts by name, description, or task category
24
24
  - **Manage installed artifacts** - List and remove artifacts from your project
25
+ - **Self-update** - Keep the CLI up to date with a single command
26
+ - **Shell completions** - Tab completion for bash and zsh
25
27
 
26
28
  ---
27
29
 
@@ -156,6 +158,58 @@ npx ai-builder search "nextjs" --task frontend
156
158
  npx ai-builder search "database" --limit 5
157
159
  ```
158
160
 
161
+ ### Status
162
+
163
+ Show CLI status and installed artifacts:
164
+
165
+ ```bash
166
+ npx ai-builder status
167
+ ```
168
+
169
+ **Output includes:**
170
+ - CLI version
171
+ - Claude directory detection
172
+ - Installed artifact counts by type
173
+ - Registry connectivity check
174
+
175
+ ### Update
176
+
177
+ Update the CLI to the latest version:
178
+
179
+ ```bash
180
+ npx ai-builder update
181
+ ```
182
+
183
+ **Options:**
184
+
185
+ ```bash
186
+ # Check for updates without installing
187
+ npx ai-builder update --check
188
+ ```
189
+
190
+ ### Completion
191
+
192
+ Generate shell completions for bash or zsh:
193
+
194
+ ```bash
195
+ # Output completion script
196
+ npx ai-builder completion bash
197
+ npx ai-builder completion zsh
198
+
199
+ # Auto-install for current shell
200
+ npx ai-builder completion --setup
201
+ ```
202
+
203
+ **Manual installation:**
204
+
205
+ ```bash
206
+ # Bash
207
+ ai-builder completion bash >> ~/.bashrc
208
+
209
+ # Zsh
210
+ ai-builder completion zsh >> ~/.zshrc
211
+ ```
212
+
159
213
  ---
160
214
 
161
215
  ## Artifact Types
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import chalk5 from "chalk";
4
+ import chalk8 from "chalk";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // src/commands/add.ts
@@ -10,19 +10,34 @@ import chalk from "chalk";
10
10
  import ora from "ora";
11
11
 
12
12
  // src/services/api.ts
13
- import { createCliLogger } from "@aibuilder/logger/adapters/cli";
14
13
  var API_BASE = process.env.AI_BUILDER_API_URL || "https://aibuilder.sh/api";
15
- var logger = createCliLogger({ base: { module: "cli:api" } });
14
+ var isDebug = process.env.DEBUG?.includes("ai-builder");
15
+ var logger = {
16
+ debug: (ctx, msg) => {
17
+ if (isDebug) console.error(`[debug] ${msg}`, ctx);
18
+ },
19
+ startTimer: (name) => {
20
+ const start = Date.now();
21
+ return {
22
+ done: (ctx) => {
23
+ if (isDebug) {
24
+ const durationMs = Date.now() - start;
25
+ console.error(`[debug] ${name}`, { ...ctx, durationMs });
26
+ }
27
+ }
28
+ };
29
+ }
30
+ };
16
31
  async function resolveArtifact(type, slug) {
17
32
  const url = `${API_BASE}/resolve?type=${encodeURIComponent(type)}&slug=${encodeURIComponent(slug)}`;
18
- logger.debug({ type, slug, url }, "Resolving artifact");
33
+ const timer = logger.startTimer("api-resolve");
19
34
  const response = await fetch(url);
20
35
  if (!response.ok) {
21
36
  const errorBody = await response.json().catch(() => ({ error: "Unknown error" }));
22
- logger.error({ type, slug, status: response.status }, "Failed to resolve artifact");
37
+ timer.done({ type, slug, status: response.status, success: false });
23
38
  throw new Error(errorBody.error || `Failed to resolve artifact: ${response.status}`);
24
39
  }
25
- logger.debug({ type, slug }, "Artifact resolved successfully");
40
+ timer.done({ type, slug, status: response.status, success: true });
26
41
  return response.json();
27
42
  }
28
43
  async function searchArtifacts(options) {
@@ -35,39 +50,44 @@ async function searchArtifacts(options) {
35
50
  if (options.task) params.set("task", options.task);
36
51
  if (options.limit) params.set("limit", options.limit.toString());
37
52
  const url = `${API_BASE}/artifacts?${params.toString()}`;
38
- logger.debug({ options, url }, "Searching artifacts");
53
+ const timer = logger.startTimer("api-search");
39
54
  const response = await fetch(url);
40
55
  if (!response.ok) {
41
- logger.error({ status: response.status, options }, "Search failed");
56
+ timer.done({ query: options.query, status: response.status, success: false });
42
57
  throw new Error(`Failed to search artifacts: ${response.status}`);
43
58
  }
44
59
  const result = await response.json();
45
- logger.debug({ resultCount: result.artifacts.length, total: result.total }, "Search completed");
60
+ timer.done({
61
+ query: options.query,
62
+ resultCount: result.artifacts.length,
63
+ total: result.total,
64
+ success: true
65
+ });
46
66
  return result;
47
67
  }
48
68
  async function trackInstall(type, slug, cliVersion) {
49
69
  try {
50
- await fetch(`${API_BASE}/install-events`, {
70
+ const response = await fetch(`${API_BASE}/install-events`, {
51
71
  method: "POST",
52
72
  headers: { "Content-Type": "application/json" },
53
73
  body: JSON.stringify({ type, slug, cliVersion })
54
74
  });
55
- logger.debug({ type, slug, cliVersion }, "Install tracked");
75
+ logger.debug({ type, slug, cliVersion, status: response.status }, "Install tracked");
56
76
  } catch (error) {
57
77
  logger.debug({ err: error, type, slug }, "Install tracking failed (non-critical)");
58
78
  }
59
79
  }
60
80
  async function resolveStack(slug) {
61
81
  const url = `${API_BASE}/stacks/${encodeURIComponent(slug)}`;
62
- logger.debug({ slug, url }, "Resolving stack");
82
+ const timer = logger.startTimer("api-resolve-stack");
63
83
  const response = await fetch(url);
64
84
  if (!response.ok) {
65
85
  const errorBody = await response.json().catch(() => ({ error: "Unknown error" }));
66
- logger.error({ slug, status: response.status }, "Failed to resolve stack");
86
+ timer.done({ slug, status: response.status, success: false });
67
87
  throw new Error(errorBody.error || `Failed to resolve stack: ${response.status}`);
68
88
  }
69
89
  const result = await response.json();
70
- logger.debug({ slug, artifactCount: result.artifactCount }, "Stack resolved successfully");
90
+ timer.done({ slug, artifactCount: result.artifactCount, status: response.status, success: true });
71
91
  return result;
72
92
  }
73
93
 
@@ -338,12 +358,218 @@ async function confirm(question) {
338
358
  });
339
359
  }
340
360
 
341
- // src/commands/list.ts
361
+ // src/commands/completion.ts
362
+ import * as fs3 from "fs";
363
+ import * as os from "os";
364
+ import * as path3 from "path";
342
365
  import chalk2 from "chalk";
366
+ var BASH_COMPLETION = `
367
+ # ai-builder bash completion
368
+ _ai_builder_completions() {
369
+ local cur prev words cword
370
+ _get_comp_words_by_ref -n : cur prev words cword
371
+
372
+ local commands="add remove rm list ls search status update completion"
373
+ local types="skill agent command stack"
374
+
375
+ case "\${prev}" in
376
+ ai-builder)
377
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
378
+ return 0
379
+ ;;
380
+ add|remove|rm)
381
+ COMPREPLY=( $(compgen -W "\${types}" -- "\${cur}") )
382
+ return 0
383
+ ;;
384
+ -t|--type)
385
+ COMPREPLY=( $(compgen -W "skill agent command" -- "\${cur}") )
386
+ return 0
387
+ ;;
388
+ completion)
389
+ COMPREPLY=( $(compgen -W "bash zsh --setup" -- "\${cur}") )
390
+ return 0
391
+ ;;
392
+ esac
393
+
394
+ if [[ "\${cur}" == -* ]]; then
395
+ local opts="--help --version"
396
+ case "\${words[1]}" in
397
+ add)
398
+ opts="--force --yes --help"
399
+ ;;
400
+ remove|rm)
401
+ opts="--yes --help"
402
+ ;;
403
+ list|ls)
404
+ opts="--type --help"
405
+ ;;
406
+ search)
407
+ opts="--type --task --limit --help"
408
+ ;;
409
+ update)
410
+ opts="--check --help"
411
+ ;;
412
+ esac
413
+ COMPREPLY=( $(compgen -W "\${opts}" -- "\${cur}") )
414
+ return 0
415
+ fi
416
+ }
417
+
418
+ complete -F _ai_builder_completions ai-builder
419
+ `.trim();
420
+ var ZSH_COMPLETION = `
421
+ #compdef ai-builder
422
+
423
+ _ai_builder() {
424
+ local -a commands types
425
+
426
+ commands=(
427
+ 'add:Install an artifact or stack'
428
+ 'remove:Remove an installed artifact'
429
+ 'rm:Remove an installed artifact'
430
+ 'list:List installed artifacts'
431
+ 'ls:List installed artifacts'
432
+ 'search:Search the registry for artifacts'
433
+ 'status:Show CLI status'
434
+ 'update:Update the CLI'
435
+ 'completion:Generate shell completions'
436
+ )
437
+
438
+ types=(skill agent command stack)
439
+
440
+ _arguments -C \\
441
+ '1:command:->command' \\
442
+ '*::arg:->args'
443
+
444
+ case "$state" in
445
+ command)
446
+ _describe -t commands 'ai-builder command' commands
447
+ ;;
448
+ args)
449
+ case "$words[1]" in
450
+ add|remove|rm)
451
+ _arguments \\
452
+ '1:type:(skill agent command stack)' \\
453
+ '2:slug:' \\
454
+ '--force[Overwrite existing artifacts]' \\
455
+ '--yes[Skip confirmation]' \\
456
+ '--help[Show help]'
457
+ ;;
458
+ list|ls)
459
+ _arguments \\
460
+ '--type[Filter by type]:type:(skill agent command)' \\
461
+ '--help[Show help]'
462
+ ;;
463
+ search)
464
+ _arguments \\
465
+ '1:query:' \\
466
+ '--type[Filter by type]:type:(skill agent command)' \\
467
+ '--task[Filter by task category]:task:' \\
468
+ '--limit[Number of results]:limit:' \\
469
+ '--help[Show help]'
470
+ ;;
471
+ update)
472
+ _arguments \\
473
+ '--check[Check for updates without installing]' \\
474
+ '--help[Show help]'
475
+ ;;
476
+ completion)
477
+ _arguments \\
478
+ '1:shell:(bash zsh)' \\
479
+ '--setup[Auto-install to shell config]' \\
480
+ '--help[Show help]'
481
+ ;;
482
+ esac
483
+ ;;
484
+ esac
485
+ }
486
+
487
+ _ai_builder "$@"
488
+ `.trim();
489
+ function getShellConfigPath(shell) {
490
+ const home = os.homedir();
491
+ if (shell === "bash") {
492
+ const bashrc = path3.join(home, ".bashrc");
493
+ const bashProfile = path3.join(home, ".bash_profile");
494
+ return fs3.existsSync(bashrc) ? bashrc : bashProfile;
495
+ }
496
+ if (shell === "zsh") {
497
+ return path3.join(home, ".zshrc");
498
+ }
499
+ return null;
500
+ }
501
+ function detectShell() {
502
+ const shell = process.env.SHELL || "";
503
+ if (shell.includes("zsh")) return "zsh";
504
+ if (shell.includes("bash")) return "bash";
505
+ return null;
506
+ }
507
+ function completionCommand(shell, options) {
508
+ if (options?.setup) {
509
+ const detectedShell = detectShell();
510
+ if (!detectedShell) {
511
+ console.error(chalk2.red("\n Could not detect shell. Use:"));
512
+ console.error(chalk2.dim(" ai-builder completion bash >> ~/.bashrc"));
513
+ console.error(chalk2.dim(" ai-builder completion zsh >> ~/.zshrc\n"));
514
+ process.exit(1);
515
+ }
516
+ const configPath = getShellConfigPath(detectedShell);
517
+ if (!configPath) {
518
+ console.error(chalk2.red(`
519
+ Could not find config for ${detectedShell}
520
+ `));
521
+ process.exit(1);
522
+ }
523
+ const completion = detectedShell === "zsh" ? ZSH_COMPLETION : BASH_COMPLETION;
524
+ const marker = "# ai-builder completion";
525
+ const existingContent = fs3.existsSync(configPath) ? fs3.readFileSync(configPath, "utf-8") : "";
526
+ if (existingContent.includes(marker)) {
527
+ console.log(chalk2.yellow(`
528
+ Completion already installed in ${configPath}`));
529
+ console.log(chalk2.dim(" Restart your terminal to apply changes\n"));
530
+ return;
531
+ }
532
+ fs3.appendFileSync(configPath, `
533
+ ${completion}
534
+ `);
535
+ console.log(chalk2.green(`
536
+ Completion installed to ${configPath}`));
537
+ console.log(chalk2.dim(` Restart your terminal or run: source ${configPath}
538
+ `));
539
+ return;
540
+ }
541
+ if (!shell) {
542
+ console.log(chalk2.cyan.bold("\n ai-builder completion\n"));
543
+ console.log(" Generate shell completions for ai-builder.\n");
544
+ console.log(" Usage:");
545
+ console.log(" ai-builder completion bash Output bash completion");
546
+ console.log(" ai-builder completion zsh Output zsh completion");
547
+ console.log(" ai-builder completion --setup Auto-install for current shell\n");
548
+ console.log(" Manual installation:");
549
+ console.log(chalk2.dim(" ai-builder completion bash >> ~/.bashrc"));
550
+ console.log(chalk2.dim(" ai-builder completion zsh >> ~/.zshrc\n"));
551
+ return;
552
+ }
553
+ if (shell === "bash") {
554
+ console.log(BASH_COMPLETION);
555
+ return;
556
+ }
557
+ if (shell === "zsh") {
558
+ console.log(ZSH_COMPLETION);
559
+ return;
560
+ }
561
+ console.error(chalk2.red(`
562
+ Unsupported shell: ${shell}`));
563
+ console.error(chalk2.dim(" Supported: bash, zsh\n"));
564
+ process.exit(1);
565
+ }
566
+
567
+ // src/commands/list.ts
568
+ import chalk3 from "chalk";
343
569
  var TYPE_COLORS = {
344
- skill: chalk2.blue,
345
- agent: chalk2.magenta,
346
- command: chalk2.green
570
+ skill: chalk3.blue,
571
+ agent: chalk3.magenta,
572
+ command: chalk3.green
347
573
  };
348
574
  async function listCommand(options) {
349
575
  let artifacts = getInstalledArtifacts();
@@ -352,33 +578,33 @@ async function listCommand(options) {
352
578
  }
353
579
  if (artifacts.length === 0) {
354
580
  if (options.type) {
355
- console.log(chalk2.dim(`No ${options.type}s installed.`));
581
+ console.log(chalk3.dim(`No ${options.type}s installed.`));
356
582
  } else {
357
- console.log(chalk2.dim("No artifacts installed."));
583
+ console.log(chalk3.dim("No artifacts installed."));
358
584
  }
359
585
  console.log();
360
586
  console.log("Install artifacts with:");
361
- console.log(`${chalk2.green(" $ ")}ai-builder add agent anthropic/frontend-tester`);
587
+ console.log(`${chalk3.green(" $ ")}ai-builder add agent anthropic/frontend-tester`);
362
588
  return;
363
589
  }
364
590
  console.log();
365
- console.log(chalk2.bold("Installed Artifacts"));
591
+ console.log(chalk3.bold("Installed Artifacts"));
366
592
  console.log();
367
593
  console.log(
368
- `${chalk2.dim(" ") + padEnd("TYPE", 10) + padEnd("NAME", 30) + padEnd("AUTHOR", 15)}INSTALLED`
594
+ `${chalk3.dim(" ") + padEnd("TYPE", 10) + padEnd("NAME", 30) + padEnd("AUTHOR", 15)}INSTALLED`
369
595
  );
370
- console.log(chalk2.dim(` ${"-".repeat(70)}`));
596
+ console.log(chalk3.dim(` ${"-".repeat(70)}`));
371
597
  for (const artifact of artifacts) {
372
- const typeColor = TYPE_COLORS[artifact.type] || chalk2.white;
598
+ const typeColor = TYPE_COLORS[artifact.type] || chalk3.white;
373
599
  const typeLabel = typeColor(padEnd(artifact.type, 10));
374
600
  const name = padEnd(artifact.name, 30);
375
- const author = chalk2.dim(padEnd(artifact.author, 15));
376
- const date = chalk2.dim(formatDate(artifact.installedAt));
601
+ const author = chalk3.dim(padEnd(artifact.author, 15));
602
+ const date = chalk3.dim(formatDate(artifact.installedAt));
377
603
  console.log(` ${typeLabel}${name}${author}${date}`);
378
604
  }
379
605
  console.log();
380
606
  console.log(
381
- chalk2.dim(` ${artifacts.length} artifact${artifacts.length === 1 ? "" : "s"} installed`)
607
+ chalk3.dim(` ${artifacts.length} artifact${artifacts.length === 1 ? "" : "s"} installed`)
382
608
  );
383
609
  console.log();
384
610
  }
@@ -408,39 +634,39 @@ function formatDate(isoDate) {
408
634
 
409
635
  // src/commands/remove.ts
410
636
  import * as readline2 from "readline";
411
- import chalk3 from "chalk";
637
+ import chalk4 from "chalk";
412
638
  var VALID_TYPES2 = ["skill", "agent", "command"];
413
639
  async function removeCommand(type, slug, options) {
414
640
  if (!type) {
415
- console.log(chalk3.red("Error: Missing artifact type."));
641
+ console.log(chalk4.red("Error: Missing artifact type."));
416
642
  console.log("Usage: ai-builder remove <type> <author/slug>");
417
643
  console.log("Types: skill, agent, command");
418
644
  process.exit(1);
419
645
  }
420
646
  if (!VALID_TYPES2.includes(type)) {
421
- console.log(chalk3.red(`Error: Invalid type "${type}".`));
647
+ console.log(chalk4.red(`Error: Invalid type "${type}".`));
422
648
  console.log("Valid types: skill, agent, command");
423
649
  process.exit(1);
424
650
  }
425
651
  if (!slug) {
426
- console.log(chalk3.red("Error: Missing artifact slug."));
652
+ console.log(chalk4.red("Error: Missing artifact slug."));
427
653
  console.log("Usage: ai-builder remove <type> <author/slug>");
428
654
  console.log("Example: ai-builder remove agent anthropic/frontend-tester");
429
655
  process.exit(1);
430
656
  }
431
657
  if (!slug.includes("/")) {
432
- console.log(chalk3.red("Error: Invalid slug format."));
658
+ console.log(chalk4.red("Error: Invalid slug format."));
433
659
  console.log("Expected format: author/artifact-name");
434
660
  console.log("Example: anthropic/frontend-tester");
435
661
  process.exit(1);
436
662
  }
437
663
  const [author, artifactSlug] = slug.split("/");
438
664
  if (!isInstalled(type, author, artifactSlug)) {
439
- console.log(chalk3.yellow(`${type} ${chalk3.bold(slug)} is not installed.`));
665
+ console.log(chalk4.yellow(`${type} ${chalk4.bold(slug)} is not installed.`));
440
666
  return;
441
667
  }
442
668
  if (!options.yes) {
443
- const confirmed = await confirm2(`Remove ${type} ${chalk3.cyan(slug)}?`);
669
+ const confirmed = await confirm2(`Remove ${type} ${chalk4.cyan(slug)}?`);
444
670
  if (!confirmed) {
445
671
  console.log("Cancelled.");
446
672
  return;
@@ -448,9 +674,9 @@ async function removeCommand(type, slug, options) {
448
674
  }
449
675
  const removed = uninstallArtifact(type, author, artifactSlug);
450
676
  if (removed) {
451
- console.log(chalk3.green(`Removed ${type} ${chalk3.bold(slug)}`));
677
+ console.log(chalk4.green(`Removed ${type} ${chalk4.bold(slug)}`));
452
678
  } else {
453
- console.log(chalk3.red(`Failed to remove ${type} ${slug}`));
679
+ console.log(chalk4.red(`Failed to remove ${type} ${slug}`));
454
680
  process.exit(1);
455
681
  }
456
682
  }
@@ -460,7 +686,7 @@ async function confirm2(question) {
460
686
  output: process.stdout
461
687
  });
462
688
  return new Promise((resolve) => {
463
- rl.question(`${question} ${chalk3.dim("[y/N]")} `, (answer) => {
689
+ rl.question(`${question} ${chalk4.dim("[y/N]")} `, (answer) => {
464
690
  rl.close();
465
691
  resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
466
692
  });
@@ -468,12 +694,12 @@ async function confirm2(question) {
468
694
  }
469
695
 
470
696
  // src/commands/search.ts
471
- import chalk4 from "chalk";
697
+ import chalk5 from "chalk";
472
698
  import ora2 from "ora";
473
699
  var TYPE_COLORS2 = {
474
- skill: chalk4.blue,
475
- agent: chalk4.magenta,
476
- command: chalk4.green
700
+ skill: chalk5.blue,
701
+ agent: chalk5.magenta,
702
+ command: chalk5.green
477
703
  };
478
704
  async function searchCommand(query, options) {
479
705
  const limit = Number.parseInt(options.limit || "10", 10);
@@ -487,40 +713,40 @@ async function searchCommand(query, options) {
487
713
  });
488
714
  spinner.stop();
489
715
  if (artifacts.length === 0) {
490
- console.log(chalk4.dim(`No results found for "${query}"`));
716
+ console.log(chalk5.dim(`No results found for "${query}"`));
491
717
  return;
492
718
  }
493
719
  console.log();
494
- console.log(chalk4.bold(`Found ${total} result${total === 1 ? "" : "s"}`));
720
+ console.log(chalk5.bold(`Found ${total} result${total === 1 ? "" : "s"}`));
495
721
  console.log();
496
722
  for (const artifact of artifacts) {
497
- const typeColor = TYPE_COLORS2[artifact.type] || chalk4.white;
723
+ const typeColor = TYPE_COLORS2[artifact.type] || chalk5.white;
498
724
  const typeLabel = typeColor(`[${artifact.type}]`);
499
725
  const fullSlug = `${artifact.author}/${artifact.slug}`;
500
- console.log(` ${typeLabel} ${chalk4.bold(artifact.name)}`);
501
- console.log(` ${chalk4.cyan(fullSlug)}`);
726
+ console.log(` ${typeLabel} ${chalk5.bold(artifact.name)}`);
727
+ console.log(` ${chalk5.cyan(fullSlug)}`);
502
728
  if (artifact.summary) {
503
- console.log(` ${chalk4.dim(truncate(artifact.summary, 60))}`);
729
+ console.log(` ${chalk5.dim(truncate(artifact.summary, 60))}`);
504
730
  }
505
- console.log(` ${chalk4.dim(`${formatNumber(artifact.installCount)} installs`)}`);
731
+ console.log(` ${chalk5.dim(`${formatNumber(artifact.installCount)} installs`)}`);
506
732
  console.log();
507
733
  }
508
734
  if (total > artifacts.length) {
509
- console.log(chalk4.dim(` ... and ${total - artifacts.length} more results`));
510
- console.log(chalk4.dim(" Use --limit to see more results"));
735
+ console.log(chalk5.dim(` ... and ${total - artifacts.length} more results`));
736
+ console.log(chalk5.dim(" Use --limit to see more results"));
511
737
  console.log();
512
738
  }
513
739
  console.log("Install with:");
514
740
  if (artifacts.length > 0) {
515
741
  const first = artifacts[0];
516
742
  console.log(
517
- `${chalk4.green(" $ ")}ai-builder add ${first.type} ${first.author}/${first.slug}`
743
+ `${chalk5.green(" $ ")}ai-builder add ${first.type} ${first.author}/${first.slug}`
518
744
  );
519
745
  }
520
746
  console.log();
521
747
  } catch (error) {
522
748
  const message = error instanceof Error ? error.message : "Unknown error";
523
- spinner.fail(chalk4.red(`Search failed: ${message}`));
749
+ spinner.fail(chalk5.red(`Search failed: ${message}`));
524
750
  process.exit(1);
525
751
  }
526
752
  }
@@ -538,26 +764,149 @@ function formatNumber(num) {
538
764
  return num.toString();
539
765
  }
540
766
 
767
+ // src/commands/status.ts
768
+ import * as fs4 from "fs";
769
+ import * as path4 from "path";
770
+ import chalk6 from "chalk";
771
+
772
+ // src/version.ts
773
+ import { createRequire } from "module";
774
+ var require2 = createRequire(import.meta.url);
775
+ var pkg = require2("../package.json");
776
+ var version = pkg.version;
777
+
778
+ // src/commands/status.ts
779
+ var API_BASE2 = process.env.AI_BUILDER_API_URL || "https://aibuilder.sh/api";
780
+ async function statusCommand() {
781
+ console.log(chalk6.cyan.bold("\n ai-builder status\n"));
782
+ console.log(` ${chalk6.dim("Version:")} ${chalk6.white(version)}`);
783
+ const claudeDir = path4.join(process.cwd(), ".claude");
784
+ const claudeDirExists = fs4.existsSync(claudeDir);
785
+ console.log(
786
+ ` ${chalk6.dim("Claude dir:")} ${claudeDirExists ? chalk6.green(".claude/ found") : chalk6.yellow(".claude/ not found")}`
787
+ );
788
+ const installed = getInstalledArtifacts();
789
+ const byType = installed.reduce(
790
+ (acc, artifact) => {
791
+ acc[artifact.type] = (acc[artifact.type] || 0) + 1;
792
+ return acc;
793
+ },
794
+ {}
795
+ );
796
+ if (installed.length === 0) {
797
+ console.log(` ${chalk6.dim("Installed:")} ${chalk6.dim("none")}`);
798
+ } else {
799
+ const summary = Object.entries(byType).map(([type, count]) => `${count} ${type}${count > 1 ? "s" : ""}`).join(", ");
800
+ console.log(` ${chalk6.dim("Installed:")} ${chalk6.white(summary)}`);
801
+ }
802
+ process.stdout.write(` ${chalk6.dim("Registry:")} `);
803
+ try {
804
+ const start = Date.now();
805
+ const response = await fetch(`${API_BASE2}/artifacts?limit=1`);
806
+ const latency = Date.now() - start;
807
+ if (response.ok) {
808
+ console.log(chalk6.green("connected") + chalk6.dim(` (${latency}ms)`));
809
+ } else {
810
+ console.log(chalk6.red(`error ${response.status}`));
811
+ }
812
+ } catch {
813
+ console.log(chalk6.red("unreachable"));
814
+ }
815
+ console.log();
816
+ }
817
+
818
+ // src/commands/update.ts
819
+ import { execFileSync } from "child_process";
820
+ import chalk7 from "chalk";
821
+ var NPM_REGISTRY = "https://registry.npmjs.org/ai-builder";
822
+ async function getLatestVersion() {
823
+ const response = await fetch(NPM_REGISTRY);
824
+ if (!response.ok) {
825
+ throw new Error(`Failed to fetch package info: ${response.status}`);
826
+ }
827
+ const data = await response.json();
828
+ return data["dist-tags"].latest;
829
+ }
830
+ function compareVersions(current, latest) {
831
+ const currentParts = current.split(".").map(Number);
832
+ const latestParts = latest.split(".").map(Number);
833
+ for (let i = 0; i < 3; i++) {
834
+ if (latestParts[i] > currentParts[i]) return 1;
835
+ if (latestParts[i] < currentParts[i]) return -1;
836
+ }
837
+ return 0;
838
+ }
839
+ async function updateCommand(options) {
840
+ console.log(chalk7.cyan.bold("\n ai-builder update\n"));
841
+ console.log(` ${chalk7.dim("Current version:")} ${chalk7.white(version)}`);
842
+ process.stdout.write(` ${chalk7.dim("Latest version:")} `);
843
+ let latestVersion;
844
+ try {
845
+ latestVersion = await getLatestVersion();
846
+ console.log(chalk7.white(latestVersion));
847
+ } catch {
848
+ console.log(chalk7.red("failed to fetch"));
849
+ console.log(chalk7.dim("\n Could not reach npm registry\n"));
850
+ process.exit(1);
851
+ }
852
+ const comparison = compareVersions(version, latestVersion);
853
+ if (comparison === 0) {
854
+ console.log(chalk7.green("\n You are on the latest version!\n"));
855
+ return;
856
+ }
857
+ if (comparison < 0) {
858
+ console.log(chalk7.yellow("\n Your version is newer than published\n"));
859
+ return;
860
+ }
861
+ if (options.check) {
862
+ console.log(chalk7.yellow(`
863
+ Update available: ${version} \u2192 ${latestVersion}`));
864
+ console.log(chalk7.dim(` Run 'ai-builder update' to install
865
+ `));
866
+ return;
867
+ }
868
+ console.log(chalk7.dim(`
869
+ Updating to ${latestVersion}...`));
870
+ try {
871
+ execFileSync("npm", ["install", "-g", "ai-builder@latest"], { stdio: "inherit" });
872
+ console.log(chalk7.green(`
873
+ Updated to ${latestVersion}!
874
+ `));
875
+ } catch {
876
+ console.log(chalk7.red("\n Update failed. Try running:"));
877
+ console.log(chalk7.dim(" npm install -g ai-builder@latest\n"));
878
+ process.exit(1);
879
+ }
880
+ }
881
+
541
882
  // src/index.ts
542
883
  var program = new Command();
543
- program.name("ai-builder").description("CLI for installing Claude Code artifacts from aibuilder.sh").version("0.1.0");
884
+ program.name("ai-builder").description("CLI for installing Claude Code artifacts from aibuilder.sh").version(version);
544
885
  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);
545
886
  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);
546
887
  program.command("list").alias("ls").description("List installed artifacts").option("-t, --type <type>", "Filter by type: skill, agent, or command").action(listCommand);
547
888
  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);
889
+ program.command("status").description("Show CLI status and installed artifacts").action(statusCommand);
890
+ program.command("update").description("Update the CLI to the latest version").option("-c, --check", "Check for updates without installing").action(updateCommand);
891
+ program.command("completion").description("Generate shell completions").argument("[shell]", "Shell type: bash or zsh").option("-s, --setup", "Auto-install completion for current shell").action(completionCommand);
548
892
  program.action(() => {
549
- console.log(chalk5.cyan.bold("\n ai-builder") + chalk5.dim(" - Claude Code artifact registry\n"));
893
+ console.log(
894
+ chalk8.cyan.bold("\n ai-builder") + chalk8.dim(` v${version} - Claude Code artifact registry
895
+ `)
896
+ );
550
897
  console.log(" Usage:");
551
898
  console.log(" ai-builder add <type> <author/slug> Install an artifact");
552
899
  console.log(" ai-builder remove <type> <slug> Remove an artifact");
553
900
  console.log(" ai-builder list List installed");
554
901
  console.log(" ai-builder search <query> Search registry");
902
+ console.log(" ai-builder status Show CLI status");
903
+ console.log(" ai-builder update Update CLI");
555
904
  console.log("\n Examples:");
556
- console.log(`${chalk5.green(" $ ")}ai-builder add agent anthropic/frontend-tester`);
557
- console.log(`${chalk5.green(" $ ")}ai-builder add stack nextjs-fullstack`);
558
- console.log(`${chalk5.green(" $ ")}ai-builder search "test generator"`);
905
+ console.log(`${chalk8.green(" $ ")}ai-builder add agent anthropic/frontend-tester`);
906
+ console.log(`${chalk8.green(" $ ")}ai-builder add stack nextjs-fullstack`);
907
+ console.log(`${chalk8.green(" $ ")}ai-builder search "test generator"`);
559
908
  console.log(`
560
- Learn more at ${chalk5.cyan("https://aibuilder.sh")}
909
+ Learn more at ${chalk8.cyan("https://aibuilder.sh")}
561
910
  `);
562
911
  });
563
912
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-builder",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "CLI for installing Claude Code artifacts from aibuilder.sh",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,7 +22,6 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@aibuilder/logger": "workspace:*",
26
25
  "chalk": "^5.3.0",
27
26
  "commander": "^12.1.0",
28
27
  "ora": "^8.1.0"