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.
- package/README.md +54 -0
- package/dist/index.js +408 -59
- 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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
53
|
+
const timer = logger.startTimer("api-search");
|
|
39
54
|
const response = await fetch(url);
|
|
40
55
|
if (!response.ok) {
|
|
41
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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:
|
|
345
|
-
agent:
|
|
346
|
-
command:
|
|
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(
|
|
581
|
+
console.log(chalk3.dim(`No ${options.type}s installed.`));
|
|
356
582
|
} else {
|
|
357
|
-
console.log(
|
|
583
|
+
console.log(chalk3.dim("No artifacts installed."));
|
|
358
584
|
}
|
|
359
585
|
console.log();
|
|
360
586
|
console.log("Install artifacts with:");
|
|
361
|
-
console.log(`${
|
|
587
|
+
console.log(`${chalk3.green(" $ ")}ai-builder add agent anthropic/frontend-tester`);
|
|
362
588
|
return;
|
|
363
589
|
}
|
|
364
590
|
console.log();
|
|
365
|
-
console.log(
|
|
591
|
+
console.log(chalk3.bold("Installed Artifacts"));
|
|
366
592
|
console.log();
|
|
367
593
|
console.log(
|
|
368
|
-
`${
|
|
594
|
+
`${chalk3.dim(" ") + padEnd("TYPE", 10) + padEnd("NAME", 30) + padEnd("AUTHOR", 15)}INSTALLED`
|
|
369
595
|
);
|
|
370
|
-
console.log(
|
|
596
|
+
console.log(chalk3.dim(` ${"-".repeat(70)}`));
|
|
371
597
|
for (const artifact of artifacts) {
|
|
372
|
-
const typeColor = TYPE_COLORS[artifact.type] ||
|
|
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 =
|
|
376
|
-
const date =
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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} ${
|
|
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(
|
|
677
|
+
console.log(chalk4.green(`Removed ${type} ${chalk4.bold(slug)}`));
|
|
452
678
|
} else {
|
|
453
|
-
console.log(
|
|
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} ${
|
|
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
|
|
697
|
+
import chalk5 from "chalk";
|
|
472
698
|
import ora2 from "ora";
|
|
473
699
|
var TYPE_COLORS2 = {
|
|
474
|
-
skill:
|
|
475
|
-
agent:
|
|
476
|
-
command:
|
|
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(
|
|
716
|
+
console.log(chalk5.dim(`No results found for "${query}"`));
|
|
491
717
|
return;
|
|
492
718
|
}
|
|
493
719
|
console.log();
|
|
494
|
-
console.log(
|
|
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] ||
|
|
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} ${
|
|
501
|
-
console.log(` ${
|
|
726
|
+
console.log(` ${typeLabel} ${chalk5.bold(artifact.name)}`);
|
|
727
|
+
console.log(` ${chalk5.cyan(fullSlug)}`);
|
|
502
728
|
if (artifact.summary) {
|
|
503
|
-
console.log(` ${
|
|
729
|
+
console.log(` ${chalk5.dim(truncate(artifact.summary, 60))}`);
|
|
504
730
|
}
|
|
505
|
-
console.log(` ${
|
|
731
|
+
console.log(` ${chalk5.dim(`${formatNumber(artifact.installCount)} installs`)}`);
|
|
506
732
|
console.log();
|
|
507
733
|
}
|
|
508
734
|
if (total > artifacts.length) {
|
|
509
|
-
console.log(
|
|
510
|
-
console.log(
|
|
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
|
-
`${
|
|
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(
|
|
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(
|
|
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(
|
|
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(`${
|
|
557
|
-
console.log(`${
|
|
558
|
-
console.log(`${
|
|
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 ${
|
|
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.
|
|
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"
|