@smicolon/ai-kit 0.1.1 → 0.2.1
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 +26 -16
- package/dist/index.js +156 -62
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ AI coding tool pack manager. Install convention packs (agents, skills, commands,
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx @smicolon/ai-kit init
|
|
8
|
+
npx @smicolon/ai-kit@latest init
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
This walks you through selecting your AI tools and stack, then installs the right files in the right places.
|
|
@@ -17,8 +17,8 @@ This walks you through selecting your AI tools and stack, then installs the righ
|
|
|
17
17
|
Interactive first-time setup. Prompts for your AI tools, stack, and component preferences.
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npx @smicolon/ai-kit init
|
|
21
|
-
npx @smicolon/ai-kit init --cwd apps/web # monorepo sub-package
|
|
20
|
+
npx @smicolon/ai-kit@latest init
|
|
21
|
+
npx @smicolon/ai-kit@latest init --cwd apps/web # monorepo sub-package
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
### `add <pack>`
|
|
@@ -26,11 +26,11 @@ npx @smicolon/ai-kit init --cwd apps/web # monorepo sub-package
|
|
|
26
26
|
Add a pack to your project.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
npx @smicolon/ai-kit add django
|
|
30
|
-
npx @smicolon/ai-kit add django --skills-only
|
|
31
|
-
npx @smicolon/ai-kit add django --agents-only
|
|
32
|
-
npx @smicolon/ai-kit add django --rules-only
|
|
33
|
-
npx @smicolon/ai-kit add django --tools claude-code,cursor
|
|
29
|
+
npx @smicolon/ai-kit@latest add django
|
|
30
|
+
npx @smicolon/ai-kit@latest add django --skills-only
|
|
31
|
+
npx @smicolon/ai-kit@latest add django --agents-only
|
|
32
|
+
npx @smicolon/ai-kit@latest add django --rules-only
|
|
33
|
+
npx @smicolon/ai-kit@latest add django --tools claude-code,cursor
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
### `list`
|
|
@@ -38,8 +38,8 @@ npx @smicolon/ai-kit add django --tools claude-code,cursor
|
|
|
38
38
|
Show available or installed packs.
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
npx @smicolon/ai-kit list # available packs
|
|
42
|
-
npx @smicolon/ai-kit list --installed # installed packs
|
|
41
|
+
npx @smicolon/ai-kit@latest list # available packs
|
|
42
|
+
npx @smicolon/ai-kit@latest list --installed # installed packs
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### `remove <pack>`
|
|
@@ -47,7 +47,17 @@ npx @smicolon/ai-kit list --installed # installed packs
|
|
|
47
47
|
Remove a pack and all its installed files.
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
npx @smicolon/ai-kit remove django
|
|
50
|
+
npx @smicolon/ai-kit@latest remove django
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `search <query>`
|
|
54
|
+
|
|
55
|
+
Search packs by name or keyword.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx @smicolon/ai-kit@latest search auth
|
|
59
|
+
npx @smicolon/ai-kit@latest search frontend
|
|
60
|
+
npx @smicolon/ai-kit@latest search tdd
|
|
51
61
|
```
|
|
52
62
|
|
|
53
63
|
### `update [pack]`
|
|
@@ -55,8 +65,8 @@ npx @smicolon/ai-kit remove django
|
|
|
55
65
|
Update installed packs to latest versions.
|
|
56
66
|
|
|
57
67
|
```bash
|
|
58
|
-
npx @smicolon/ai-kit update # update all
|
|
59
|
-
npx @smicolon/ai-kit update django # update one
|
|
68
|
+
npx @smicolon/ai-kit@latest update # update all
|
|
69
|
+
npx @smicolon/ai-kit@latest update django # update one
|
|
60
70
|
```
|
|
61
71
|
|
|
62
72
|
## Supported AI Tools
|
|
@@ -116,15 +126,15 @@ your-project/
|
|
|
116
126
|
└── .gitignore # auto-updated
|
|
117
127
|
```
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
Tool preferences are stored globally at `~/.config/ai-kit/config.json` (pick once, works in all projects). Local `.ai-kit.json` tracks installed packs and files for clean removal — it's auto-added to `.gitignore`.
|
|
120
130
|
|
|
121
131
|
## Monorepo Support
|
|
122
132
|
|
|
123
133
|
Use `--cwd` to target a sub-package. Both the sub-package and root `.gitignore` are updated.
|
|
124
134
|
|
|
125
135
|
```bash
|
|
126
|
-
npx @smicolon/ai-kit init --cwd apps/web
|
|
127
|
-
npx @smicolon/ai-kit add django --cwd apps/web
|
|
136
|
+
npx @smicolon/ai-kit@latest init --cwd apps/web
|
|
137
|
+
npx @smicolon/ai-kit@latest add django --cwd apps/web
|
|
128
138
|
```
|
|
129
139
|
|
|
130
140
|
## License
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command7 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/init.ts
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import * as p from "@clack/prompts";
|
|
9
9
|
import pc from "picocolors";
|
|
10
|
-
import
|
|
10
|
+
import path6 from "path";
|
|
11
11
|
|
|
12
12
|
// src/tools.ts
|
|
13
13
|
var TOOL_REGISTRY = {
|
|
@@ -182,6 +182,8 @@ function resolvePack(plugin, marketplaceDir) {
|
|
|
182
182
|
name: plugin.name,
|
|
183
183
|
version: plugin.version,
|
|
184
184
|
description: plugin.description,
|
|
185
|
+
category: plugin.category ?? "",
|
|
186
|
+
keywords: plugin.keywords ?? [],
|
|
185
187
|
sourceDir,
|
|
186
188
|
agents: resolveFiles(plugin.agents),
|
|
187
189
|
commands: resolveFiles(plugin.commands),
|
|
@@ -201,10 +203,10 @@ function discoverPacks(startDir) {
|
|
|
201
203
|
}
|
|
202
204
|
const marketplaceDir = path.dirname(path.dirname(marketplacePath));
|
|
203
205
|
const raw = JSON.parse(fs.readFileSync(marketplacePath, "utf-8"));
|
|
204
|
-
return raw.plugins.map((
|
|
206
|
+
return raw.plugins.map((p3) => resolvePack(p3, marketplaceDir)).filter((p3) => fs.existsSync(p3.sourceDir));
|
|
205
207
|
}
|
|
206
208
|
function findPack(name, startDir) {
|
|
207
|
-
return discoverPacks(startDir).find((
|
|
209
|
+
return discoverPacks(startDir).find((p3) => p3.name === name);
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
// src/config.ts
|
|
@@ -258,6 +260,11 @@ function createDefaultConfig(tools) {
|
|
|
258
260
|
import fs3 from "fs";
|
|
259
261
|
import path3 from "path";
|
|
260
262
|
var MANAGED_COMMENT = "# AI coding tools (managed by @smicolon/ai-kit)";
|
|
263
|
+
var LOCAL_PATTERNS = [
|
|
264
|
+
".ai-kit.json",
|
|
265
|
+
"**/*.local.*",
|
|
266
|
+
"**/*.local.md"
|
|
267
|
+
];
|
|
261
268
|
function findGitRoot(startDir) {
|
|
262
269
|
let dir = startDir;
|
|
263
270
|
while (true) {
|
|
@@ -295,15 +302,15 @@ ${newEntries.join("\n")}
|
|
|
295
302
|
}
|
|
296
303
|
fs3.writeFileSync(gitignorePath, updated);
|
|
297
304
|
}
|
|
298
|
-
function updateGitignore(projectDir
|
|
299
|
-
if (dirs.length === 0) return;
|
|
300
|
-
const entries = dirs.map((d) => d.endsWith("/") ? d : `${d}/`);
|
|
305
|
+
function updateGitignore(projectDir) {
|
|
301
306
|
const projectGitignore = path3.join(projectDir, ".gitignore");
|
|
302
|
-
appendToGitignore(projectGitignore,
|
|
307
|
+
appendToGitignore(projectGitignore, LOCAL_PATTERNS);
|
|
303
308
|
const gitRoot = findGitRoot(projectDir);
|
|
304
309
|
if (gitRoot && path3.resolve(gitRoot) !== path3.resolve(projectDir)) {
|
|
305
310
|
const relFromRoot = path3.relative(gitRoot, projectDir);
|
|
306
|
-
const rootEntries =
|
|
311
|
+
const rootEntries = LOCAL_PATTERNS.map(
|
|
312
|
+
(e) => e.startsWith("**/") ? e : `${relFromRoot}/${e}`
|
|
313
|
+
);
|
|
307
314
|
appendToGitignore(path3.join(gitRoot, ".gitignore"), rootEntries);
|
|
308
315
|
}
|
|
309
316
|
}
|
|
@@ -565,32 +572,51 @@ function removePack2(projectDir, files) {
|
|
|
565
572
|
}
|
|
566
573
|
return removed;
|
|
567
574
|
}
|
|
568
|
-
function isSymlink(
|
|
575
|
+
function isSymlink(p3) {
|
|
569
576
|
try {
|
|
570
|
-
return fs5.lstatSync(
|
|
577
|
+
return fs5.lstatSync(p3).isSymbolicLink();
|
|
571
578
|
} catch {
|
|
572
579
|
return false;
|
|
573
580
|
}
|
|
574
581
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
582
|
+
|
|
583
|
+
// src/global-config.ts
|
|
584
|
+
import fs6 from "fs";
|
|
585
|
+
import path5 from "path";
|
|
586
|
+
import os from "os";
|
|
587
|
+
function getConfigDir() {
|
|
588
|
+
return path5.join(os.homedir(), ".config", "ai-kit");
|
|
589
|
+
}
|
|
590
|
+
function getConfigPath() {
|
|
591
|
+
return path5.join(getConfigDir(), "config.json");
|
|
592
|
+
}
|
|
593
|
+
function readGlobalConfig() {
|
|
594
|
+
const fp = getConfigPath();
|
|
595
|
+
if (!fs6.existsSync(fp)) return null;
|
|
596
|
+
try {
|
|
597
|
+
return JSON.parse(fs6.readFileSync(fp, "utf-8"));
|
|
598
|
+
} catch {
|
|
599
|
+
return null;
|
|
586
600
|
}
|
|
587
|
-
|
|
601
|
+
}
|
|
602
|
+
function writeGlobalConfig(config) {
|
|
603
|
+
const dir = getConfigDir();
|
|
604
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
605
|
+
fs6.writeFileSync(getConfigPath(), JSON.stringify(config, null, 2) + "\n");
|
|
606
|
+
}
|
|
607
|
+
function getGlobalTools() {
|
|
608
|
+
const config = readGlobalConfig();
|
|
609
|
+
return config?.tools ?? null;
|
|
610
|
+
}
|
|
611
|
+
function saveGlobalTools(tools) {
|
|
612
|
+
const existing = readGlobalConfig();
|
|
613
|
+
writeGlobalConfig({ ...existing, tools });
|
|
588
614
|
}
|
|
589
615
|
|
|
590
616
|
// src/commands/init.ts
|
|
591
617
|
var initCommand = new Command("init").description("Interactive first-time setup").option("--cwd <dir>", "Project directory (for monorepo sub-packages)").action(async (opts) => {
|
|
592
618
|
p.intro(pc.bgCyan(pc.black(" ai-kit ")));
|
|
593
|
-
const projectDir = opts.cwd ?
|
|
619
|
+
const projectDir = opts.cwd ? path6.resolve(opts.cwd) : process.cwd();
|
|
594
620
|
const existing = readConfig(projectDir);
|
|
595
621
|
if (existing) {
|
|
596
622
|
const action = await p.select({
|
|
@@ -610,13 +636,15 @@ var initCommand = new Command("init").description("Interactive first-time setup"
|
|
|
610
636
|
return;
|
|
611
637
|
}
|
|
612
638
|
}
|
|
613
|
-
const
|
|
614
|
-
|
|
639
|
+
const savedTools = getGlobalTools();
|
|
640
|
+
const toolSelection = await p.autocompleteMultiselect({
|
|
641
|
+
message: "Which AI coding tools do you use? (type to filter)",
|
|
615
642
|
options: TOOL_IDS.map((id) => ({
|
|
616
643
|
value: id,
|
|
617
644
|
label: TOOL_REGISTRY[id].label,
|
|
618
645
|
hint: TOOL_REGISTRY[id].hint
|
|
619
646
|
})),
|
|
647
|
+
initialValues: savedTools ?? [],
|
|
620
648
|
required: true
|
|
621
649
|
});
|
|
622
650
|
if (p.isCancel(toolSelection)) {
|
|
@@ -624,6 +652,7 @@ var initCommand = new Command("init").description("Interactive first-time setup"
|
|
|
624
652
|
return;
|
|
625
653
|
}
|
|
626
654
|
const selectedTools = toolSelection;
|
|
655
|
+
saveGlobalTools(selectedTools);
|
|
627
656
|
let packs;
|
|
628
657
|
try {
|
|
629
658
|
packs = discoverPacks();
|
|
@@ -632,8 +661,8 @@ var initCommand = new Command("init").description("Interactive first-time setup"
|
|
|
632
661
|
p.outro("Setup failed.");
|
|
633
662
|
return;
|
|
634
663
|
}
|
|
635
|
-
const packSelection = await p.
|
|
636
|
-
message: "
|
|
664
|
+
const packSelection = await p.autocompleteMultiselect({
|
|
665
|
+
message: "Which packs do you want to install? (type to filter)",
|
|
637
666
|
options: packs.map((pack) => ({
|
|
638
667
|
value: pack.name,
|
|
639
668
|
label: pack.name,
|
|
@@ -682,8 +711,7 @@ var initCommand = new Command("init").description("Interactive first-time setup"
|
|
|
682
711
|
const s = p.spinner();
|
|
683
712
|
s.start("Installing packs...");
|
|
684
713
|
let config = createDefaultConfig(selectedTools);
|
|
685
|
-
const selectedPacks = packs.filter((
|
|
686
|
-
let hadSkills = false;
|
|
714
|
+
const selectedPacks = packs.filter((p3) => selectedPackNames.includes(p3.name));
|
|
687
715
|
for (const pack of selectedPacks) {
|
|
688
716
|
const result = installPack({
|
|
689
717
|
pack,
|
|
@@ -692,40 +720,63 @@ var initCommand = new Command("init").description("Interactive first-time setup"
|
|
|
692
720
|
projectDir
|
|
693
721
|
});
|
|
694
722
|
config = mergeInstall(config, result);
|
|
695
|
-
if (result.installed.skills > 0) hadSkills = true;
|
|
696
723
|
}
|
|
697
724
|
writeConfig(projectDir, config);
|
|
698
|
-
updateGitignore(projectDir
|
|
725
|
+
updateGitignore(projectDir);
|
|
699
726
|
s.stop("Done!");
|
|
700
727
|
p.log.success(`Installed ${selectedPacks.length} pack(s) for ${selectedTools.length} tool(s):`);
|
|
701
728
|
for (const pack of selectedPacks) {
|
|
702
729
|
p.log.message(` ${pc.green("+")} ${pack.name} ${pc.dim(`v${pack.version}`)}`);
|
|
703
730
|
}
|
|
704
|
-
p.outro(pc.dim("
|
|
731
|
+
p.outro(pc.dim("Run ai-kit add <pack> to add more packs anytime."));
|
|
705
732
|
});
|
|
706
733
|
|
|
707
734
|
// src/commands/add.ts
|
|
708
735
|
import { Command as Command2 } from "commander";
|
|
709
|
-
import
|
|
736
|
+
import path7 from "path";
|
|
710
737
|
import pc2 from "picocolors";
|
|
711
|
-
|
|
712
|
-
|
|
738
|
+
import * as p2 from "@clack/prompts";
|
|
739
|
+
async function resolveTools(toolsFlag, projectDir) {
|
|
740
|
+
if (toolsFlag) {
|
|
741
|
+
return toolsFlag.split(",").map((t) => t.trim());
|
|
742
|
+
}
|
|
713
743
|
const config = readConfig(projectDir);
|
|
714
|
-
if (
|
|
715
|
-
|
|
716
|
-
pc2.red("No .ai-kit.json found. Run ") + pc2.cyan("ai-kit init") + pc2.red(" first.")
|
|
717
|
-
);
|
|
718
|
-
process.exit(1);
|
|
744
|
+
if (config?.tools?.length) {
|
|
745
|
+
return config.tools;
|
|
719
746
|
}
|
|
747
|
+
const globalTools = getGlobalTools();
|
|
748
|
+
if (globalTools?.length) {
|
|
749
|
+
return globalTools;
|
|
750
|
+
}
|
|
751
|
+
const selection = await p2.autocompleteMultiselect({
|
|
752
|
+
message: "Which AI coding tools do you use? (type to filter)",
|
|
753
|
+
options: TOOL_IDS.map((id) => ({
|
|
754
|
+
value: id,
|
|
755
|
+
label: TOOL_REGISTRY[id].label,
|
|
756
|
+
hint: TOOL_REGISTRY[id].hint
|
|
757
|
+
})),
|
|
758
|
+
required: true
|
|
759
|
+
});
|
|
760
|
+
if (p2.isCancel(selection)) return null;
|
|
761
|
+
const tools = selection;
|
|
762
|
+
saveGlobalTools(tools);
|
|
763
|
+
return tools;
|
|
764
|
+
}
|
|
765
|
+
var addCommand = new Command2("add").description("Add a pack to your project").argument("<pack>", "Pack name (e.g., django, nextjs)").option("--skills-only", "Only install skills").option("--agents-only", "Only install agents").option("--rules-only", "Only install rules").option("--commands-only", "Only install commands").option("--hooks-only", "Only install hooks").option("--tools <tools>", "Comma-separated tool IDs (overrides config)").option("--cwd <dir>", "Project directory (for monorepo sub-packages)").action(async (packName, opts) => {
|
|
766
|
+
const projectDir = opts.cwd ? path7.resolve(opts.cwd) : process.cwd();
|
|
720
767
|
const pack = findPack(packName);
|
|
721
768
|
if (!pack) {
|
|
722
|
-
const available = discoverPacks().map((
|
|
769
|
+
const available = discoverPacks().map((p3) => p3.name);
|
|
723
770
|
console.error(
|
|
724
771
|
pc2.red(`Pack "${packName}" not found.`) + "\nAvailable: " + available.join(", ")
|
|
725
772
|
);
|
|
726
773
|
process.exit(1);
|
|
727
774
|
}
|
|
728
|
-
const tools =
|
|
775
|
+
const tools = await resolveTools(opts.tools, projectDir);
|
|
776
|
+
if (!tools) {
|
|
777
|
+
console.log(pc2.dim("Cancelled."));
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
729
780
|
let filter;
|
|
730
781
|
if (opts.skillsOnly) filter = ["skills"];
|
|
731
782
|
else if (opts.agentsOnly) filter = ["agents"];
|
|
@@ -733,10 +784,12 @@ var addCommand = new Command2("add").description("Add a pack to your project").a
|
|
|
733
784
|
else if (opts.commandsOnly) filter = ["commands"];
|
|
734
785
|
else if (opts.hooksOnly) filter = ["hooks"];
|
|
735
786
|
const result = installPack({ pack, tools, filter, projectDir });
|
|
787
|
+
let config = readConfig(projectDir) ?? createDefaultConfig(tools);
|
|
788
|
+
config.tools = tools;
|
|
736
789
|
const updated = mergeInstall(config, result);
|
|
737
790
|
updated.packs[pack.name].version = pack.version;
|
|
738
791
|
writeConfig(projectDir, updated);
|
|
739
|
-
updateGitignore(projectDir
|
|
792
|
+
updateGitignore(projectDir);
|
|
740
793
|
const parts = [];
|
|
741
794
|
for (const [type, count] of Object.entries(result.installed)) {
|
|
742
795
|
if (count > 0) parts.push(`${count} ${type}`);
|
|
@@ -798,14 +851,14 @@ ${pc3.dim(`${packs.length} packs available`)}`);
|
|
|
798
851
|
|
|
799
852
|
// src/commands/remove.ts
|
|
800
853
|
import { Command as Command4 } from "commander";
|
|
801
|
-
import
|
|
854
|
+
import path8 from "path";
|
|
802
855
|
import pc4 from "picocolors";
|
|
803
856
|
var removeCommand = new Command4("remove").description("Remove a pack from your project").argument("<pack>", "Pack name to remove").option("--cwd <dir>", "Project directory").action((packName, opts) => {
|
|
804
|
-
const projectDir = opts.cwd ?
|
|
857
|
+
const projectDir = opts.cwd ? path8.resolve(opts.cwd) : process.cwd();
|
|
805
858
|
const config = readConfig(projectDir);
|
|
806
859
|
if (!config) {
|
|
807
|
-
console.
|
|
808
|
-
|
|
860
|
+
console.log(pc4.dim("No packs installed."));
|
|
861
|
+
return;
|
|
809
862
|
}
|
|
810
863
|
const packConfig = config.packs[packName];
|
|
811
864
|
if (!packConfig) {
|
|
@@ -828,23 +881,19 @@ var removeCommand = new Command4("remove").description("Remove a pack from your
|
|
|
828
881
|
|
|
829
882
|
// src/commands/update.ts
|
|
830
883
|
import { Command as Command5 } from "commander";
|
|
831
|
-
import
|
|
884
|
+
import path9 from "path";
|
|
832
885
|
import pc5 from "picocolors";
|
|
833
|
-
var updateCommand = new Command5("update").description("Update installed packs").argument("[pack]", "Pack name (omit to update all)").option("--cwd <dir>", "Project directory").action((packName, opts) => {
|
|
834
|
-
const projectDir = opts.cwd ?
|
|
886
|
+
var updateCommand = new Command5("update").description("Update installed packs").argument("[pack]", "Pack name (omit to update all)").option("--cwd <dir>", "Project directory").action(async (packName, opts) => {
|
|
887
|
+
const projectDir = opts.cwd ? path9.resolve(opts.cwd) : process.cwd();
|
|
835
888
|
const config = readConfig(projectDir);
|
|
836
|
-
if (!config) {
|
|
837
|
-
console.
|
|
838
|
-
|
|
839
|
-
}
|
|
840
|
-
const packsToUpdate = packName ? [packName] : Object.keys(config.packs);
|
|
841
|
-
if (packsToUpdate.length === 0) {
|
|
842
|
-
console.log(pc5.dim("No packs installed."));
|
|
889
|
+
if (!config || Object.keys(config.packs).length === 0) {
|
|
890
|
+
console.log(pc5.dim("No packs installed yet. Starting setup...\n"));
|
|
891
|
+
await initCommand.parseAsync(["init", ...opts.cwd ? ["--cwd", opts.cwd] : []], { from: "user" });
|
|
843
892
|
return;
|
|
844
893
|
}
|
|
894
|
+
const packsToUpdate = packName ? [packName] : Object.keys(config.packs);
|
|
845
895
|
let updated = 0;
|
|
846
896
|
let skipped = 0;
|
|
847
|
-
let hadSkills = false;
|
|
848
897
|
for (const name of packsToUpdate) {
|
|
849
898
|
const installed = config.packs[name];
|
|
850
899
|
if (!installed) {
|
|
@@ -874,14 +923,13 @@ var updateCommand = new Command5("update").description("Update installed packs")
|
|
|
874
923
|
const merged = mergeInstall(config, result);
|
|
875
924
|
merged.packs[name].version = available.version;
|
|
876
925
|
Object.assign(config, merged);
|
|
877
|
-
if (result.installed.skills > 0) hadSkills = true;
|
|
878
926
|
console.log(
|
|
879
927
|
pc5.green(` ${name}`) + ` ${pc5.dim(installed.version)} \u2192 ${pc5.cyan(available.version)}`
|
|
880
928
|
);
|
|
881
929
|
updated++;
|
|
882
930
|
}
|
|
883
931
|
writeConfig(projectDir, config);
|
|
884
|
-
updateGitignore(projectDir
|
|
932
|
+
updateGitignore(projectDir);
|
|
885
933
|
if (updated > 0) {
|
|
886
934
|
console.log(pc5.green(`
|
|
887
935
|
Updated ${updated} pack(s).`));
|
|
@@ -891,11 +939,57 @@ Updated ${updated} pack(s).`));
|
|
|
891
939
|
}
|
|
892
940
|
});
|
|
893
941
|
|
|
942
|
+
// src/commands/search.ts
|
|
943
|
+
import { Command as Command6 } from "commander";
|
|
944
|
+
import pc6 from "picocolors";
|
|
945
|
+
var searchCommand = new Command6("search").description("Search available packs by name or keyword").argument("<query>", "Search term (matches name, description, keywords)").action((query) => {
|
|
946
|
+
let packs;
|
|
947
|
+
try {
|
|
948
|
+
packs = discoverPacks();
|
|
949
|
+
} catch {
|
|
950
|
+
console.error(pc6.red("Could not find marketplace.json."));
|
|
951
|
+
process.exit(1);
|
|
952
|
+
}
|
|
953
|
+
const q = query.toLowerCase();
|
|
954
|
+
const matches = packs.filter((pack) => {
|
|
955
|
+
const haystack = [
|
|
956
|
+
pack.name,
|
|
957
|
+
pack.description,
|
|
958
|
+
pack.category,
|
|
959
|
+
...pack.keywords
|
|
960
|
+
].join(" ").toLowerCase();
|
|
961
|
+
return haystack.includes(q);
|
|
962
|
+
});
|
|
963
|
+
if (matches.length === 0) {
|
|
964
|
+
console.log(pc6.dim(`No packs matching "${query}".`));
|
|
965
|
+
console.log(pc6.dim(`
|
|
966
|
+
All packs: ${packs.map((p3) => p3.name).join(", ")}`));
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
console.log(pc6.bold(`Found ${matches.length} pack(s):
|
|
970
|
+
`));
|
|
971
|
+
for (const pack of matches) {
|
|
972
|
+
const counts = [];
|
|
973
|
+
if (pack.agents.length) counts.push(`${pack.agents.length} agents`);
|
|
974
|
+
if (pack.skills.length) counts.push(`${pack.skills.length} skills`);
|
|
975
|
+
if (pack.commands.length) counts.push(`${pack.commands.length} commands`);
|
|
976
|
+
if (pack.rules.length) counts.push(`${pack.rules.length} rules`);
|
|
977
|
+
console.log(
|
|
978
|
+
` ${pc6.cyan(pack.name)} ${pc6.dim(`v${pack.version}`)}
|
|
979
|
+
${pack.description}
|
|
980
|
+
${pc6.dim(counts.join(", "))}
|
|
981
|
+
${pc6.dim(`Install: npx @smicolon/ai-kit@latest add ${pack.name}`)}
|
|
982
|
+
`
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
|
|
894
987
|
// src/index.ts
|
|
895
|
-
var program = new
|
|
988
|
+
var program = new Command7().name("ai-kit").description("AI coding tool pack manager").version("0.0.1");
|
|
896
989
|
program.addCommand(initCommand);
|
|
897
990
|
program.addCommand(addCommand);
|
|
898
991
|
program.addCommand(listCommand);
|
|
899
992
|
program.addCommand(removeCommand);
|
|
900
993
|
program.addCommand(updateCommand);
|
|
994
|
+
program.addCommand(searchCommand);
|
|
901
995
|
program.parse();
|