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