@smicolon/ai-kit 0.3.2 → 0.4.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.
Files changed (155) hide show
  1. package/README.md +73 -40
  2. package/dist/index.js +312 -127
  3. package/package.json +5 -5
  4. package/.claude-plugin/marketplace.json +0 -369
  5. package/packs/architect/CHANGELOG.md +0 -17
  6. package/packs/architect/README.md +0 -58
  7. package/packs/architect/agents/system-architect.md +0 -768
  8. package/packs/architect/commands/diagram-create.md +0 -300
  9. package/packs/better-auth/.mcp.json +0 -14
  10. package/packs/better-auth/CHANGELOG.md +0 -26
  11. package/packs/better-auth/README.md +0 -125
  12. package/packs/better-auth/agents/auth-architect.md +0 -278
  13. package/packs/better-auth/commands/auth-provider-add.md +0 -265
  14. package/packs/better-auth/commands/auth-setup.md +0 -298
  15. package/packs/better-auth/skills/auth-security/SKILL.md +0 -425
  16. package/packs/better-auth/skills/better-auth-patterns/SKILL.md +0 -455
  17. package/packs/dev-loop/CHANGELOG.md +0 -69
  18. package/packs/dev-loop/README.md +0 -155
  19. package/packs/dev-loop/commands/cancel-dev.md +0 -21
  20. package/packs/dev-loop/commands/dev-loop.md +0 -72
  21. package/packs/dev-loop/commands/dev-plan.md +0 -351
  22. package/packs/dev-loop/hooks/hooks.json +0 -15
  23. package/packs/dev-loop/hooks/stop-hook.sh +0 -178
  24. package/packs/dev-loop/scripts/setup-dev-loop.sh +0 -194
  25. package/packs/dev-loop/skills/tdd-planner/SKILL.md +0 -249
  26. package/packs/dev-loop/skills/tdd-planner/references/framework-patterns.md +0 -874
  27. package/packs/dev-loop/skills/tdd-planner/references/good-example.md +0 -260
  28. package/packs/dev-loop/skills/tdd-planner/references/plan-template.md +0 -275
  29. package/packs/django/CHANGELOG.md +0 -39
  30. package/packs/django/README.md +0 -92
  31. package/packs/django/agents/django-architect.md +0 -182
  32. package/packs/django/agents/django-builder.md +0 -250
  33. package/packs/django/agents/django-feature-based.md +0 -420
  34. package/packs/django/agents/django-reviewer.md +0 -253
  35. package/packs/django/agents/django-tester.md +0 -230
  36. package/packs/django/commands/api-endpoint.md +0 -285
  37. package/packs/django/commands/model-create.md +0 -178
  38. package/packs/django/commands/test-generate.md +0 -325
  39. package/packs/django/rules/migrations.md +0 -138
  40. package/packs/django/rules/models.md +0 -167
  41. package/packs/django/rules/serializers.md +0 -126
  42. package/packs/django/rules/services.md +0 -131
  43. package/packs/django/rules/tests.md +0 -140
  44. package/packs/django/rules/views.md +0 -102
  45. package/packs/django/skills/import-convention-enforcer/SKILL.md +0 -226
  46. package/packs/django/skills/import-convention-enforcer/patterns/django-imports.md +0 -343
  47. package/packs/django/skills/migration-safety-checker/SKILL.md +0 -375
  48. package/packs/django/skills/model-entity-validator/SKILL.md +0 -298
  49. package/packs/django/skills/performance-optimizer/SKILL.md +0 -447
  50. package/packs/django/skills/red-phase-verifier/SKILL.md +0 -180
  51. package/packs/django/skills/security-first-validator/SKILL.md +0 -435
  52. package/packs/django/skills/test-coverage-advisor/SKILL.md +0 -394
  53. package/packs/django/skills/test-validity-checker/SKILL.md +0 -194
  54. package/packs/failure-log/CHANGELOG.md +0 -20
  55. package/packs/failure-log/README.md +0 -168
  56. package/packs/failure-log/commands/failure-add.md +0 -106
  57. package/packs/failure-log/commands/failure-list.md +0 -89
  58. package/packs/failure-log/hooks/hooks.json +0 -16
  59. package/packs/failure-log/hooks/scripts/inject-failures.sh +0 -64
  60. package/packs/failure-log/skills/failure-log-manager/SKILL.md +0 -164
  61. package/packs/flutter/CHANGELOG.md +0 -19
  62. package/packs/flutter/README.md +0 -170
  63. package/packs/flutter/agents/flutter-architect.md +0 -166
  64. package/packs/flutter/agents/flutter-builder.md +0 -303
  65. package/packs/flutter/agents/release-manager.md +0 -355
  66. package/packs/flutter/commands/fastlane-setup.md +0 -188
  67. package/packs/flutter/commands/flutter-build.md +0 -90
  68. package/packs/flutter/commands/flutter-deploy.md +0 -133
  69. package/packs/flutter/commands/flutter-test.md +0 -117
  70. package/packs/flutter/commands/signing-setup.md +0 -209
  71. package/packs/flutter/hooks/hooks.json +0 -17
  72. package/packs/flutter/skills/fastlane-knowledge/SKILL.md +0 -193
  73. package/packs/flutter/skills/flutter-architecture/SKILL.md +0 -127
  74. package/packs/flutter/skills/store-publishing/SKILL.md +0 -163
  75. package/packs/hono/CHANGELOG.md +0 -19
  76. package/packs/hono/README.md +0 -143
  77. package/packs/hono/agents/hono-architect.md +0 -240
  78. package/packs/hono/agents/hono-builder.md +0 -285
  79. package/packs/hono/agents/hono-reviewer.md +0 -279
  80. package/packs/hono/agents/hono-tester.md +0 -346
  81. package/packs/hono/commands/middleware-create.md +0 -223
  82. package/packs/hono/commands/project-init.md +0 -306
  83. package/packs/hono/commands/route-create.md +0 -153
  84. package/packs/hono/commands/rpc-client.md +0 -263
  85. package/packs/hono/skills/cloudflare-bindings/SKILL.md +0 -408
  86. package/packs/hono/skills/hono-patterns/SKILL.md +0 -309
  87. package/packs/hono/skills/rpc-typesafe/SKILL.md +0 -388
  88. package/packs/hono/skills/zod-validation/SKILL.md +0 -332
  89. package/packs/nestjs/CHANGELOG.md +0 -29
  90. package/packs/nestjs/README.md +0 -75
  91. package/packs/nestjs/agents/nestjs-architect.md +0 -402
  92. package/packs/nestjs/agents/nestjs-builder.md +0 -301
  93. package/packs/nestjs/agents/nestjs-tester.md +0 -437
  94. package/packs/nestjs/commands/module-create.md +0 -369
  95. package/packs/nestjs/rules/controllers.md +0 -92
  96. package/packs/nestjs/rules/dto.md +0 -124
  97. package/packs/nestjs/rules/entities.md +0 -102
  98. package/packs/nestjs/rules/services.md +0 -106
  99. package/packs/nestjs/skills/barrel-export-manager/SKILL.md +0 -389
  100. package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +0 -365
  101. package/packs/nextjs/CHANGELOG.md +0 -36
  102. package/packs/nextjs/README.md +0 -76
  103. package/packs/nextjs/agents/frontend-tester.md +0 -680
  104. package/packs/nextjs/agents/frontend-visual.md +0 -820
  105. package/packs/nextjs/agents/nextjs-architect.md +0 -331
  106. package/packs/nextjs/agents/nextjs-modular.md +0 -433
  107. package/packs/nextjs/commands/component-create.md +0 -398
  108. package/packs/nextjs/rules/api-routes.md +0 -129
  109. package/packs/nextjs/rules/components.md +0 -106
  110. package/packs/nextjs/rules/hooks.md +0 -132
  111. package/packs/nextjs/skills/accessibility-validator/SKILL.md +0 -445
  112. package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +0 -399
  113. package/packs/nextjs/skills/react-form-validator/SKILL.md +0 -569
  114. package/packs/nuxtjs/CHANGELOG.md +0 -30
  115. package/packs/nuxtjs/README.md +0 -56
  116. package/packs/nuxtjs/agents/frontend-tester.md +0 -680
  117. package/packs/nuxtjs/agents/frontend-visual.md +0 -820
  118. package/packs/nuxtjs/agents/nuxtjs-architect.md +0 -537
  119. package/packs/nuxtjs/commands/component-create.md +0 -223
  120. package/packs/nuxtjs/rules/components.md +0 -101
  121. package/packs/nuxtjs/rules/composables.md +0 -118
  122. package/packs/nuxtjs/rules/server-routes.md +0 -127
  123. package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +0 -183
  124. package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +0 -196
  125. package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +0 -190
  126. package/packs/onboard/CHANGELOG.md +0 -22
  127. package/packs/onboard/README.md +0 -103
  128. package/packs/onboard/agents/onboard-guide.md +0 -118
  129. package/packs/onboard/commands/onboard.md +0 -313
  130. package/packs/onboard/skills/onboard-context-provider/SKILL.md +0 -98
  131. package/packs/tanstack-router/CHANGELOG.md +0 -30
  132. package/packs/tanstack-router/README.md +0 -113
  133. package/packs/tanstack-router/agents/tanstack-architect.md +0 -173
  134. package/packs/tanstack-router/agents/tanstack-builder.md +0 -360
  135. package/packs/tanstack-router/agents/tanstack-tester.md +0 -454
  136. package/packs/tanstack-router/commands/form-create.md +0 -313
  137. package/packs/tanstack-router/commands/query-create.md +0 -263
  138. package/packs/tanstack-router/commands/route-create.md +0 -190
  139. package/packs/tanstack-router/commands/table-create.md +0 -413
  140. package/packs/tanstack-router/skills/ai-patterns/SKILL.md +0 -370
  141. package/packs/tanstack-router/skills/db-patterns/SKILL.md +0 -346
  142. package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +0 -415
  143. package/packs/tanstack-router/skills/form-patterns/SKILL.md +0 -425
  144. package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +0 -341
  145. package/packs/tanstack-router/skills/query-patterns/SKILL.md +0 -359
  146. package/packs/tanstack-router/skills/router-patterns/SKILL.md +0 -285
  147. package/packs/tanstack-router/skills/store-patterns/SKILL.md +0 -351
  148. package/packs/tanstack-router/skills/table-patterns/SKILL.md +0 -531
  149. package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +0 -428
  150. package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +0 -490
  151. package/packs/worktree/CHANGELOG.md +0 -45
  152. package/packs/worktree/README.md +0 -219
  153. package/packs/worktree/commands/wt.md +0 -93
  154. package/packs/worktree/scripts/wt.sh +0 -957
  155. package/packs/worktree/skills/worktree-manager/SKILL.md +0 -113
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 Command7 } from "commander";
4
+ import { Command as Command8 } 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 path6 from "path";
10
+ import path7 from "path";
11
11
 
12
12
  // src/tools.ts
13
13
  var TOOL_REGISTRY = {
@@ -154,29 +154,123 @@ var TOOL_IDS = Object.keys(TOOL_REGISTRY);
154
154
  var CANONICAL_SKILLS_DIR = ".agents/skills";
155
155
 
156
156
  // src/discovery.ts
157
+ import fs2 from "fs";
158
+ import path2 from "path";
159
+
160
+ // src/registry.ts
157
161
  import fs from "fs";
158
162
  import path from "path";
163
+ import os from "os";
164
+ import { execSync } from "child_process";
165
+ var REPO = "smicolon/ai-kit";
166
+ var DEFAULT_BRANCH = "main";
167
+ function getCacheDir() {
168
+ return path.join(os.homedir(), ".config", "ai-kit", "cache");
169
+ }
170
+ function getRepoDir() {
171
+ return path.join(getCacheDir(), "repo");
172
+ }
173
+ function getCachedMarketplacePath() {
174
+ return path.join(getCacheDir(), "marketplace.json");
175
+ }
176
+ function rawUrl(branch, filePath) {
177
+ return `https://raw.githubusercontent.com/${REPO}/${branch}/${filePath}`;
178
+ }
179
+ function tarballUrl(branch) {
180
+ return `https://github.com/${REPO}/archive/refs/heads/${branch}.tar.gz`;
181
+ }
182
+ async function fetchMarketplaceRaw(branch) {
183
+ const url = rawUrl(branch, ".claude-plugin/marketplace.json");
184
+ const res = await fetch(url);
185
+ if (!res.ok) {
186
+ throw new Error(`Failed to fetch marketplace.json: ${res.status} ${res.statusText}`);
187
+ }
188
+ return res.text();
189
+ }
190
+ async function downloadRepo(branch) {
191
+ const cacheDir = getCacheDir();
192
+ const repoDir = getRepoDir();
193
+ const tarPath = path.join(cacheDir, "repo.tar.gz");
194
+ if (fs.existsSync(repoDir)) {
195
+ fs.rmSync(repoDir, { recursive: true });
196
+ }
197
+ fs.mkdirSync(repoDir, { recursive: true });
198
+ const url = tarballUrl(branch);
199
+ const res = await fetch(url);
200
+ if (!res.ok) {
201
+ throw new Error(`Failed to download repo tarball: ${res.status} ${res.statusText}`);
202
+ }
203
+ const buffer = Buffer.from(await res.arrayBuffer());
204
+ fs.writeFileSync(tarPath, buffer);
205
+ execSync(`tar xzf "${tarPath}" --strip-components=1 -C "${repoDir}"`, {
206
+ stdio: "ignore"
207
+ });
208
+ fs.unlinkSync(tarPath);
209
+ }
210
+ async function ensureRepo(options = {}) {
211
+ const branch = options.branch ?? DEFAULT_BRANCH;
212
+ const cacheDir = getCacheDir();
213
+ const repoDir = getRepoDir();
214
+ const cachedMpPath = getCachedMarketplacePath();
215
+ fs.mkdirSync(cacheDir, { recursive: true });
216
+ if (options.noCache) {
217
+ const mpContent = await fetchMarketplaceRaw(branch);
218
+ await downloadRepo(branch);
219
+ fs.writeFileSync(cachedMpPath, mpContent);
220
+ return repoDir;
221
+ }
222
+ try {
223
+ const remoteMp = await fetchMarketplaceRaw(branch);
224
+ let needsDownload = true;
225
+ if (fs.existsSync(cachedMpPath) && fs.existsSync(repoDir)) {
226
+ const cachedMp = fs.readFileSync(cachedMpPath, "utf-8");
227
+ needsDownload = remoteMp !== cachedMp;
228
+ }
229
+ if (needsDownload) {
230
+ await downloadRepo(branch);
231
+ fs.writeFileSync(cachedMpPath, remoteMp);
232
+ }
233
+ return repoDir;
234
+ } catch (err) {
235
+ if (fs.existsSync(repoDir) && fs.existsSync(path.join(repoDir, ".claude-plugin", "marketplace.json"))) {
236
+ const msg = err instanceof Error ? err.message : String(err);
237
+ console.error(`Warning: Could not reach GitHub (${msg}). Using cached packs.`);
238
+ return repoDir;
239
+ }
240
+ throw new Error(
241
+ "Could not fetch packs from GitHub and no local cache exists. Check your internet connection and try again."
242
+ );
243
+ }
244
+ }
245
+ function clearCache() {
246
+ const cacheDir = getCacheDir();
247
+ if (fs.existsSync(cacheDir)) {
248
+ fs.rmSync(cacheDir, { recursive: true });
249
+ }
250
+ }
251
+
252
+ // src/discovery.ts
159
253
  function findMarketplaceJson(startDir) {
160
254
  let dir = startDir;
161
255
  while (true) {
162
- const candidate = path.join(dir, ".claude-plugin", "marketplace.json");
163
- if (fs.existsSync(candidate)) return candidate;
164
- const parent = path.dirname(dir);
256
+ const candidate = path2.join(dir, ".claude-plugin", "marketplace.json");
257
+ if (fs2.existsSync(candidate)) return candidate;
258
+ const parent = path2.dirname(dir);
165
259
  if (parent === dir) return null;
166
260
  dir = parent;
167
261
  }
168
262
  }
169
263
  function resolvePack(plugin, marketplaceDir) {
170
- const sourceDir = path.resolve(marketplaceDir, plugin.source);
171
- const resolveFiles = (files) => (files ?? []).map((f) => path.resolve(sourceDir, f));
264
+ const sourceDir = path2.resolve(marketplaceDir, plugin.source);
265
+ const resolveFiles = (files) => (files ?? []).map((f) => path2.resolve(sourceDir, f));
172
266
  let rules = [];
173
- const rulesDir = path.join(sourceDir, "rules");
174
- if (fs.existsSync(rulesDir)) {
175
- rules = fs.readdirSync(rulesDir).filter((f) => f.endsWith(".md")).map((f) => path.join(rulesDir, f));
267
+ const rulesDir = path2.join(sourceDir, "rules");
268
+ if (fs2.existsSync(rulesDir)) {
269
+ rules = fs2.readdirSync(rulesDir).filter((f) => f.endsWith(".md")).map((f) => path2.join(rulesDir, f));
176
270
  }
177
271
  const skills = (plugin.skills ?? []).map((s) => {
178
- const skillMdPath = path.resolve(sourceDir, s);
179
- return path.dirname(skillMdPath);
272
+ const skillMdPath = path2.resolve(sourceDir, s);
273
+ return path2.dirname(skillMdPath);
180
274
  });
181
275
  return {
182
276
  name: plugin.name,
@@ -190,39 +284,48 @@ function resolvePack(plugin, marketplaceDir) {
190
284
  skills,
191
285
  rules,
192
286
  hooks: resolveFiles(plugin.hooks),
193
- mcpServers: plugin.mcpServers ? path.resolve(sourceDir, plugin.mcpServers) : void 0
287
+ mcpServers: plugin.mcpServers ? path2.resolve(sourceDir, plugin.mcpServers) : void 0
194
288
  };
195
289
  }
196
- function discoverPacks(startDir) {
197
- const start = startDir ?? path.dirname(new URL(import.meta.url).pathname);
198
- const marketplacePath = findMarketplaceJson(start);
199
- if (!marketplacePath) {
290
+ function resolvePacksFromPath(marketplacePath) {
291
+ const marketplaceDir = path2.dirname(path2.dirname(marketplacePath));
292
+ const raw = JSON.parse(fs2.readFileSync(marketplacePath, "utf-8"));
293
+ return raw.plugins.map((p3) => resolvePack(p3, marketplaceDir)).filter((p3) => fs2.existsSync(p3.sourceDir));
294
+ }
295
+ async function discoverPacks(registryOptions) {
296
+ const start = path2.dirname(new URL(import.meta.url).pathname);
297
+ const localPath = findMarketplaceJson(start);
298
+ if (localPath) {
299
+ return resolvePacksFromPath(localPath);
300
+ }
301
+ const repoDir = await ensureRepo(registryOptions);
302
+ const remotePath = path2.join(repoDir, ".claude-plugin", "marketplace.json");
303
+ if (!fs2.existsSync(remotePath)) {
200
304
  throw new Error(
201
- "Could not find .claude-plugin/marketplace.json. Make sure ai-kit is installed correctly."
305
+ "Could not find .claude-plugin/marketplace.json in cached repo. Try running: ai-kit cache clear"
202
306
  );
203
307
  }
204
- const marketplaceDir = path.dirname(path.dirname(marketplacePath));
205
- const raw = JSON.parse(fs.readFileSync(marketplacePath, "utf-8"));
206
- return raw.plugins.map((p3) => resolvePack(p3, marketplaceDir)).filter((p3) => fs.existsSync(p3.sourceDir));
308
+ return resolvePacksFromPath(remotePath);
207
309
  }
208
- function findPack(name, startDir) {
209
- return discoverPacks(startDir).find((p3) => p3.name === name);
310
+ async function findPack(name, registryOptions) {
311
+ const packs = await discoverPacks(registryOptions);
312
+ return packs.find((p3) => p3.name === name);
210
313
  }
211
314
 
212
315
  // src/config.ts
213
- import fs2 from "fs";
214
- import path2 from "path";
316
+ import fs3 from "fs";
317
+ import path3 from "path";
215
318
  var CONFIG_FILE = ".ai-kit.json";
216
319
  function configPath(projectDir) {
217
- return path2.join(projectDir, CONFIG_FILE);
320
+ return path3.join(projectDir, CONFIG_FILE);
218
321
  }
219
322
  function readConfig(projectDir) {
220
323
  const fp = configPath(projectDir);
221
- if (!fs2.existsSync(fp)) return null;
222
- return JSON.parse(fs2.readFileSync(fp, "utf-8"));
324
+ if (!fs3.existsSync(fp)) return null;
325
+ return JSON.parse(fs3.readFileSync(fp, "utf-8"));
223
326
  }
224
327
  function writeConfig(projectDir, config) {
225
- fs2.writeFileSync(configPath(projectDir), JSON.stringify(config, null, 2) + "\n");
328
+ fs3.writeFileSync(configPath(projectDir), JSON.stringify(config, null, 2) + "\n");
226
329
  }
227
330
  function mergeInstall(config, result) {
228
331
  const components = {};
@@ -257,8 +360,8 @@ function createDefaultConfig(tools) {
257
360
  }
258
361
 
259
362
  // src/gitignore.ts
260
- import fs3 from "fs";
261
- import path3 from "path";
363
+ import fs4 from "fs";
364
+ import path4 from "path";
262
365
  var MANAGED_COMMENT = "# AI coding tools (managed by @smicolon/ai-kit)";
263
366
  var LOCAL_PATTERNS = [
264
367
  ".ai-kit.json",
@@ -268,14 +371,14 @@ var LOCAL_PATTERNS = [
268
371
  function findGitRoot(startDir) {
269
372
  let dir = startDir;
270
373
  while (true) {
271
- if (fs3.existsSync(path3.join(dir, ".git"))) return dir;
272
- const parent = path3.dirname(dir);
374
+ if (fs4.existsSync(path4.join(dir, ".git"))) return dir;
375
+ const parent = path4.dirname(dir);
273
376
  if (parent === dir) return null;
274
377
  dir = parent;
275
378
  }
276
379
  }
277
380
  function appendToGitignore(gitignorePath, entries) {
278
- const existing = fs3.existsSync(gitignorePath) ? fs3.readFileSync(gitignorePath, "utf-8") : "";
381
+ const existing = fs4.existsSync(gitignorePath) ? fs4.readFileSync(gitignorePath, "utf-8") : "";
279
382
  const lines = existing.split("\n");
280
383
  const newEntries = entries.filter(
281
384
  (entry) => !lines.some(
@@ -300,29 +403,29 @@ ${newEntries.join("\n")}
300
403
  `;
301
404
  updated = existing.endsWith("\n") ? existing + block : existing + "\n" + block;
302
405
  }
303
- fs3.writeFileSync(gitignorePath, updated);
406
+ fs4.writeFileSync(gitignorePath, updated);
304
407
  }
305
408
  function updateGitignore(projectDir) {
306
- const projectGitignore = path3.join(projectDir, ".gitignore");
409
+ const projectGitignore = path4.join(projectDir, ".gitignore");
307
410
  appendToGitignore(projectGitignore, LOCAL_PATTERNS);
308
411
  const gitRoot = findGitRoot(projectDir);
309
- if (gitRoot && path3.resolve(gitRoot) !== path3.resolve(projectDir)) {
310
- const relFromRoot = path3.relative(gitRoot, projectDir);
412
+ if (gitRoot && path4.resolve(gitRoot) !== path4.resolve(projectDir)) {
413
+ const relFromRoot = path4.relative(gitRoot, projectDir);
311
414
  const rootEntries = LOCAL_PATTERNS.map(
312
415
  (e) => e.startsWith("**/") ? e : `${relFromRoot}/${e}`
313
416
  );
314
- appendToGitignore(path3.join(gitRoot, ".gitignore"), rootEntries);
417
+ appendToGitignore(path4.join(gitRoot, ".gitignore"), rootEntries);
315
418
  }
316
419
  }
317
420
 
318
421
  // src/installer.ts
319
- import fs5 from "fs";
320
- import path4 from "path";
422
+ import fs6 from "fs";
423
+ import path5 from "path";
321
424
 
322
425
  // src/converters/cursor-mdc.ts
323
- import fs4 from "fs";
426
+ import fs5 from "fs";
324
427
  function convertToMdc(mdFilePath, packName) {
325
- const content = fs4.readFileSync(mdFilePath, "utf-8");
428
+ const content = fs5.readFileSync(mdFilePath, "utf-8");
326
429
  const { frontmatter, body } = parseFrontmatter(content);
327
430
  const paths = frontmatter.paths;
328
431
  const globs = paths && paths.length > 0 ? paths.length === 1 ? paths[0] : paths.join(", ") : "";
@@ -377,63 +480,63 @@ function parseFrontmatter(content) {
377
480
  var trackedFiles = [];
378
481
  var currentProjectDir = "";
379
482
  function trackFile(absPath) {
380
- trackedFiles.push(path4.relative(currentProjectDir, absPath));
483
+ trackedFiles.push(path5.relative(currentProjectDir, absPath));
381
484
  }
382
485
  function ensureDir(dir) {
383
- fs5.mkdirSync(dir, { recursive: true });
486
+ fs6.mkdirSync(dir, { recursive: true });
384
487
  }
385
488
  function copyFile(src, dest) {
386
- ensureDir(path4.dirname(dest));
387
- fs5.copyFileSync(src, dest);
489
+ ensureDir(path5.dirname(dest));
490
+ fs6.copyFileSync(src, dest);
388
491
  trackFile(dest);
389
492
  }
390
493
  function copyDir(src, dest) {
391
494
  ensureDir(dest);
392
- for (const entry of fs5.readdirSync(src, { withFileTypes: true })) {
393
- const srcPath = path4.join(src, entry.name);
394
- const destPath = path4.join(dest, entry.name);
495
+ for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
496
+ const srcPath = path5.join(src, entry.name);
497
+ const destPath = path5.join(dest, entry.name);
395
498
  if (entry.isDirectory()) {
396
499
  copyDir(srcPath, destPath);
397
500
  } else {
398
- fs5.copyFileSync(srcPath, destPath);
501
+ fs6.copyFileSync(srcPath, destPath);
399
502
  trackFile(destPath);
400
503
  }
401
504
  }
402
505
  }
403
506
  function createSymlink(target, linkPath) {
404
- ensureDir(path4.dirname(linkPath));
405
- if (fs5.existsSync(linkPath)) {
406
- const stat = fs5.lstatSync(linkPath);
407
- if (stat.isSymbolicLink()) fs5.unlinkSync(linkPath);
507
+ ensureDir(path5.dirname(linkPath));
508
+ if (fs6.existsSync(linkPath)) {
509
+ const stat = fs6.lstatSync(linkPath);
510
+ if (stat.isSymbolicLink()) fs6.unlinkSync(linkPath);
408
511
  else return;
409
512
  }
410
513
  const type = process.platform === "win32" ? "junction" : void 0;
411
- fs5.symlinkSync(target, linkPath, type);
514
+ fs6.symlinkSync(target, linkPath, type);
412
515
  trackFile(linkPath);
413
516
  }
414
517
  function installSkills(skillDirs, tools, projectDir) {
415
518
  if (skillDirs.length === 0 || tools.length === 0) return 0;
416
519
  const skillTools = tools.filter((t) => TOOL_REGISTRY[t].components.skills);
417
520
  if (skillTools.length === 0) return 0;
418
- const canonicalBase = path4.join(projectDir, CANONICAL_SKILLS_DIR);
521
+ const canonicalBase = path5.join(projectDir, CANONICAL_SKILLS_DIR);
419
522
  let count = 0;
420
523
  for (const skillDir of skillDirs) {
421
- const skillName = path4.basename(skillDir);
422
- const canonicalDest = path4.join(canonicalBase, skillName);
423
- if (!fs5.existsSync(canonicalDest)) {
524
+ const skillName = path5.basename(skillDir);
525
+ const canonicalDest = path5.join(canonicalBase, skillName);
526
+ if (!fs6.existsSync(canonicalDest)) {
424
527
  copyDir(skillDir, canonicalDest);
425
528
  count++;
426
529
  }
427
530
  }
428
531
  for (const toolId of skillTools) {
429
- const toolSkillsDir = path4.join(projectDir, TOOL_REGISTRY[toolId].skillsDir);
430
- if (path4.resolve(toolSkillsDir) === path4.resolve(canonicalBase)) continue;
532
+ const toolSkillsDir = path5.join(projectDir, TOOL_REGISTRY[toolId].skillsDir);
533
+ if (path5.resolve(toolSkillsDir) === path5.resolve(canonicalBase)) continue;
431
534
  ensureDir(toolSkillsDir);
432
535
  for (const skillDir of skillDirs) {
433
- const skillName = path4.basename(skillDir);
434
- const canonicalDest = path4.join(canonicalBase, skillName);
435
- const linkPath = path4.join(toolSkillsDir, skillName);
436
- const relTarget = path4.relative(path4.dirname(linkPath), canonicalDest);
536
+ const skillName = path5.basename(skillDir);
537
+ const canonicalDest = path5.join(canonicalBase, skillName);
538
+ const linkPath = path5.join(toolSkillsDir, skillName);
539
+ const relTarget = path5.relative(path5.dirname(linkPath), canonicalDest);
437
540
  createSymlink(relTarget, linkPath);
438
541
  }
439
542
  }
@@ -444,18 +547,18 @@ function installMdFiles(files, componentType, tools, projectDir, packName) {
444
547
  for (const toolId of tools) {
445
548
  const targetDir = TOOL_REGISTRY[toolId].components[componentType];
446
549
  if (!targetDir) continue;
447
- const dest = path4.join(projectDir, targetDir);
550
+ const dest = path5.join(projectDir, targetDir);
448
551
  ensureDir(dest);
449
552
  for (const file of files) {
450
553
  if (componentType === "rules" && toolId === "cursor") {
451
554
  const mdcContent = convertToMdc(file, packName ?? "unknown");
452
- const mdcName = path4.basename(file, ".md") + ".mdc";
453
- const destPath = path4.join(dest, mdcName);
454
- ensureDir(path4.dirname(destPath));
455
- fs5.writeFileSync(destPath, mdcContent);
555
+ const mdcName = path5.basename(file, ".md") + ".mdc";
556
+ const destPath = path5.join(dest, mdcName);
557
+ ensureDir(path5.dirname(destPath));
558
+ fs6.writeFileSync(destPath, mdcContent);
456
559
  trackFile(destPath);
457
560
  } else {
458
- copyFile(file, path4.join(dest, path4.basename(file)));
561
+ copyFile(file, path5.join(dest, path5.basename(file)));
459
562
  }
460
563
  }
461
564
  }
@@ -465,24 +568,24 @@ function installHooks(hookFiles, tools, projectDir) {
465
568
  if (hookFiles.length === 0) return 0;
466
569
  if (!tools.includes("claude-code")) return 0;
467
570
  let count = 0;
468
- const targetHooksDir = path4.join(projectDir, ".claude", "hooks");
571
+ const targetHooksDir = path5.join(projectDir, ".claude", "hooks");
469
572
  for (const hookFile of hookFiles) {
470
- if (!fs5.existsSync(hookFile)) continue;
471
- const raw = JSON.parse(fs5.readFileSync(hookFile, "utf-8"));
573
+ if (!fs6.existsSync(hookFile)) continue;
574
+ const raw = JSON.parse(fs6.readFileSync(hookFile, "utf-8"));
472
575
  if (!raw.hooks || Object.keys(raw.hooks).length === 0) continue;
473
- const hookSourceDir = path4.dirname(hookFile);
576
+ const hookSourceDir = path5.dirname(hookFile);
474
577
  const scriptFiles = findScriptFiles(hookSourceDir);
475
578
  for (const script of scriptFiles) {
476
- const relPath = path4.relative(hookSourceDir, script);
477
- const destPath = path4.join(targetHooksDir, relPath);
579
+ const relPath = path5.relative(hookSourceDir, script);
580
+ const destPath = path5.join(targetHooksDir, relPath);
478
581
  copyFile(script, destPath);
479
- fs5.chmodSync(destPath, 493);
582
+ fs6.chmodSync(destPath, 493);
480
583
  }
481
584
  const rewritten = JSON.stringify(raw.hooks).replace(/\$\{CLAUDE_PLUGIN_ROOT\}\/hooks/g, ".claude/hooks");
482
- const projectHooksPath = path4.join(projectDir, ".claude", "hooks.json");
585
+ const projectHooksPath = path5.join(projectDir, ".claude", "hooks.json");
483
586
  let existing = {};
484
- if (fs5.existsSync(projectHooksPath)) {
485
- const parsed = JSON.parse(fs5.readFileSync(projectHooksPath, "utf-8"));
587
+ if (fs6.existsSync(projectHooksPath)) {
588
+ const parsed = JSON.parse(fs6.readFileSync(projectHooksPath, "utf-8"));
486
589
  existing = parsed.hooks ?? parsed;
487
590
  }
488
591
  const newHooks = JSON.parse(rewritten);
@@ -490,8 +593,8 @@ function installHooks(hookFiles, tools, projectDir) {
490
593
  if (!existing[event]) existing[event] = [];
491
594
  existing[event].push(...handlers);
492
595
  }
493
- ensureDir(path4.dirname(projectHooksPath));
494
- fs5.writeFileSync(
596
+ ensureDir(path5.dirname(projectHooksPath));
597
+ fs6.writeFileSync(
495
598
  projectHooksPath,
496
599
  JSON.stringify({ hooks: existing }, null, 2) + "\n"
497
600
  );
@@ -502,9 +605,9 @@ function installHooks(hookFiles, tools, projectDir) {
502
605
  }
503
606
  function findScriptFiles(dir) {
504
607
  const scripts = [];
505
- if (!fs5.existsSync(dir)) return scripts;
506
- for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
507
- const fullPath = path4.join(dir, entry.name);
608
+ if (!fs6.existsSync(dir)) return scripts;
609
+ for (const entry of fs6.readdirSync(dir, { withFileTypes: true })) {
610
+ const fullPath = path5.join(dir, entry.name);
508
611
  if (entry.isDirectory()) {
509
612
  scripts.push(...findScriptFiles(fullPath));
510
613
  } else if (/\.(sh|js|ts)$/.test(entry.name)) {
@@ -545,64 +648,64 @@ function installPack(options) {
545
648
  function removePack2(projectDir, files) {
546
649
  let removed = 0;
547
650
  for (const relFile of files) {
548
- const absPath = path4.join(projectDir, relFile);
549
- if (!fs5.existsSync(absPath) && !isSymlink(absPath)) continue;
651
+ const absPath = path5.join(projectDir, relFile);
652
+ if (!fs6.existsSync(absPath) && !isSymlink(absPath)) continue;
550
653
  if (isSymlink(absPath)) {
551
- fs5.unlinkSync(absPath);
552
- } else if (fs5.statSync(absPath).isDirectory()) {
553
- fs5.rmSync(absPath, { recursive: true });
654
+ fs6.unlinkSync(absPath);
655
+ } else if (fs6.statSync(absPath).isDirectory()) {
656
+ fs6.rmSync(absPath, { recursive: true });
554
657
  } else {
555
- fs5.unlinkSync(absPath);
658
+ fs6.unlinkSync(absPath);
556
659
  }
557
660
  removed++;
558
- let parent = path4.dirname(absPath);
661
+ let parent = path5.dirname(absPath);
559
662
  while (parent !== projectDir && parent.length > projectDir.length) {
560
663
  try {
561
- const entries = fs5.readdirSync(parent);
664
+ const entries = fs6.readdirSync(parent);
562
665
  if (entries.length === 0) {
563
- fs5.rmdirSync(parent);
666
+ fs6.rmdirSync(parent);
564
667
  } else {
565
668
  break;
566
669
  }
567
670
  } catch {
568
671
  break;
569
672
  }
570
- parent = path4.dirname(parent);
673
+ parent = path5.dirname(parent);
571
674
  }
572
675
  }
573
676
  return removed;
574
677
  }
575
678
  function isSymlink(p3) {
576
679
  try {
577
- return fs5.lstatSync(p3).isSymbolicLink();
680
+ return fs6.lstatSync(p3).isSymbolicLink();
578
681
  } catch {
579
682
  return false;
580
683
  }
581
684
  }
582
685
 
583
686
  // src/global-config.ts
584
- import fs6 from "fs";
585
- import path5 from "path";
586
- import os from "os";
687
+ import fs7 from "fs";
688
+ import path6 from "path";
689
+ import os2 from "os";
587
690
  function getConfigDir() {
588
- return path5.join(os.homedir(), ".config", "ai-kit");
691
+ return path6.join(os2.homedir(), ".config", "ai-kit");
589
692
  }
590
693
  function getConfigPath() {
591
- return path5.join(getConfigDir(), "config.json");
694
+ return path6.join(getConfigDir(), "config.json");
592
695
  }
593
696
  function readGlobalConfig() {
594
697
  const fp = getConfigPath();
595
- if (!fs6.existsSync(fp)) return null;
698
+ if (!fs7.existsSync(fp)) return null;
596
699
  try {
597
- return JSON.parse(fs6.readFileSync(fp, "utf-8"));
700
+ return JSON.parse(fs7.readFileSync(fp, "utf-8"));
598
701
  } catch {
599
702
  return null;
600
703
  }
601
704
  }
602
705
  function writeGlobalConfig(config) {
603
706
  const dir = getConfigDir();
604
- fs6.mkdirSync(dir, { recursive: true });
605
- fs6.writeFileSync(getConfigPath(), JSON.stringify(config, null, 2) + "\n");
707
+ fs7.mkdirSync(dir, { recursive: true });
708
+ fs7.writeFileSync(getConfigPath(), JSON.stringify(config, null, 2) + "\n");
606
709
  }
607
710
  function getGlobalTools() {
608
711
  const config = readGlobalConfig();
@@ -613,10 +716,19 @@ function saveGlobalTools(tools) {
613
716
  writeGlobalConfig({ ...existing, tools });
614
717
  }
615
718
 
719
+ // src/global-opts.ts
720
+ var _opts = {};
721
+ function setGlobalRegistryOptions(opts) {
722
+ _opts = opts;
723
+ }
724
+ function getRegistryOptions() {
725
+ return _opts;
726
+ }
727
+
616
728
  // src/commands/init.ts
617
729
  var initCommand = new Command("init").description("Interactive first-time setup").option("--cwd <dir>", "Project directory (for monorepo sub-packages)").action(async (opts) => {
618
730
  p.intro(pc.bgCyan(pc.black(" ai-kit ")));
619
- const projectDir = opts.cwd ? path6.resolve(opts.cwd) : process.cwd();
731
+ const projectDir = opts.cwd ? path7.resolve(opts.cwd) : process.cwd();
620
732
  const existing = readConfig(projectDir);
621
733
  if (existing) {
622
734
  const action = await p.select({
@@ -632,7 +744,58 @@ var initCommand = new Command("init").description("Interactive first-time setup"
632
744
  return;
633
745
  }
634
746
  if (action === "add") {
635
- p.outro(`Run ${pc.cyan("ai-kit add <pack>")} to add packs.`);
747
+ const s2 = p.spinner();
748
+ let packs2;
749
+ try {
750
+ s2.start("Fetching available packs...");
751
+ packs2 = await discoverPacks(getRegistryOptions());
752
+ s2.stop("Packs loaded.");
753
+ } catch {
754
+ s2.stop("Failed.");
755
+ p.log.error("Could not fetch packs.");
756
+ p.outro("Failed.");
757
+ return;
758
+ }
759
+ const installedNames = Object.keys(existing.packs);
760
+ const available = packs2.filter((pk) => !installedNames.includes(pk.name));
761
+ if (available.length === 0) {
762
+ p.outro("All packs are already installed!");
763
+ return;
764
+ }
765
+ const packSelection2 = await p.autocompleteMultiselect({
766
+ message: "Which packs do you want to add? (type to filter)",
767
+ options: available.map((pk) => ({
768
+ value: pk.name,
769
+ label: pk.name,
770
+ hint: pk.description
771
+ })),
772
+ required: true
773
+ });
774
+ if (p.isCancel(packSelection2)) {
775
+ p.outro("Cancelled.");
776
+ return;
777
+ }
778
+ const selectedNames = packSelection2;
779
+ const installSpinner2 = p.spinner();
780
+ installSpinner2.start("Installing packs...");
781
+ let config2 = existing;
782
+ const selectedPacks2 = packs2.filter((pk) => selectedNames.includes(pk.name));
783
+ for (const pack of selectedPacks2) {
784
+ const result = installPack({
785
+ pack,
786
+ tools: existing.tools,
787
+ projectDir
788
+ });
789
+ config2 = mergeInstall(config2, result);
790
+ config2.packs[pack.name].version = pack.version;
791
+ }
792
+ writeConfig(projectDir, config2);
793
+ updateGitignore(projectDir);
794
+ installSpinner2.stop("Done!");
795
+ for (const pack of selectedPacks2) {
796
+ p.log.message(` ${pc.green("+")} ${pack.name} ${pc.dim(`v${pack.version}`)}`);
797
+ }
798
+ p.outro(`Added ${selectedPacks2.length} pack(s).`);
636
799
  return;
637
800
  }
638
801
  }
@@ -653,10 +816,14 @@ var initCommand = new Command("init").description("Interactive first-time setup"
653
816
  }
654
817
  const selectedTools = toolSelection;
655
818
  saveGlobalTools(selectedTools);
819
+ const s = p.spinner();
656
820
  let packs;
657
821
  try {
658
- packs = discoverPacks();
822
+ s.start("Fetching available packs...");
823
+ packs = await discoverPacks(getRegistryOptions());
824
+ s.stop("Packs loaded.");
659
825
  } catch {
826
+ s.stop("Failed.");
660
827
  p.log.error("Could not find marketplace.json. Is ai-kit installed correctly?");
661
828
  p.outro("Setup failed.");
662
829
  return;
@@ -708,8 +875,8 @@ var initCommand = new Command("init").description("Interactive first-time setup"
708
875
  }
709
876
  filter = components;
710
877
  }
711
- const s = p.spinner();
712
- s.start("Installing packs...");
878
+ const installSpinner = p.spinner();
879
+ installSpinner.start("Installing packs...");
713
880
  let config = createDefaultConfig(selectedTools);
714
881
  const selectedPacks = packs.filter((p3) => selectedPackNames.includes(p3.name));
715
882
  for (const pack of selectedPacks) {
@@ -723,7 +890,7 @@ var initCommand = new Command("init").description("Interactive first-time setup"
723
890
  }
724
891
  writeConfig(projectDir, config);
725
892
  updateGitignore(projectDir);
726
- s.stop("Done!");
893
+ installSpinner.stop("Done!");
727
894
  p.log.success(`Installed ${selectedPacks.length} pack(s) for ${selectedTools.length} tool(s):`);
728
895
  for (const pack of selectedPacks) {
729
896
  p.log.message(` ${pc.green("+")} ${pack.name} ${pc.dim(`v${pack.version}`)}`);
@@ -733,7 +900,7 @@ var initCommand = new Command("init").description("Interactive first-time setup"
733
900
 
734
901
  // src/commands/add.ts
735
902
  import { Command as Command2 } from "commander";
736
- import path7 from "path";
903
+ import path8 from "path";
737
904
  import pc2 from "picocolors";
738
905
  import * as p2 from "@clack/prompts";
739
906
  async function resolveTools(toolsFlag, projectDir) {
@@ -763,10 +930,11 @@ async function resolveTools(toolsFlag, projectDir) {
763
930
  return tools;
764
931
  }
765
932
  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();
767
- const pack = findPack(packName);
933
+ const projectDir = opts.cwd ? path8.resolve(opts.cwd) : process.cwd();
934
+ const registryOpts = getRegistryOptions();
935
+ const pack = await findPack(packName, registryOpts);
768
936
  if (!pack) {
769
- const available = discoverPacks().map((p3) => p3.name);
937
+ const available = (await discoverPacks(registryOpts)).map((p3) => p3.name);
770
938
  console.error(
771
939
  pc2.red(`Pack "${packName}" not found.`) + "\nAvailable: " + available.join(", ")
772
940
  );
@@ -803,7 +971,7 @@ var addCommand = new Command2("add").description("Add a pack to your project").a
803
971
  // src/commands/list.ts
804
972
  import { Command as Command3 } from "commander";
805
973
  import pc3 from "picocolors";
806
- var listCommand = new Command3("list").description("List available or installed packs").option("--installed", "Show only installed packs").option("--cwd <dir>", "Project directory").action((opts) => {
974
+ var listCommand = new Command3("list").description("List available or installed packs").option("--installed", "Show only installed packs").option("--cwd <dir>", "Project directory").action(async (opts) => {
807
975
  const projectDir = opts.cwd ? opts.cwd : process.cwd();
808
976
  if (opts.installed) {
809
977
  const config2 = readConfig(projectDir);
@@ -822,7 +990,7 @@ ${pc3.dim(`Tools: ${config2.tools.join(", ")}`)}`);
822
990
  }
823
991
  let packs;
824
992
  try {
825
- packs = discoverPacks();
993
+ packs = await discoverPacks(getRegistryOptions());
826
994
  } catch {
827
995
  console.error(pc3.red("Could not find marketplace.json."));
828
996
  process.exit(1);
@@ -851,10 +1019,10 @@ ${pc3.dim(`${packs.length} packs available`)}`);
851
1019
 
852
1020
  // src/commands/remove.ts
853
1021
  import { Command as Command4 } from "commander";
854
- import path8 from "path";
1022
+ import path9 from "path";
855
1023
  import pc4 from "picocolors";
856
1024
  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) => {
857
- const projectDir = opts.cwd ? path8.resolve(opts.cwd) : process.cwd();
1025
+ const projectDir = opts.cwd ? path9.resolve(opts.cwd) : process.cwd();
858
1026
  const config = readConfig(projectDir);
859
1027
  if (!config) {
860
1028
  console.log(pc4.dim("No packs installed."));
@@ -881,16 +1049,17 @@ var removeCommand = new Command4("remove").description("Remove a pack from your
881
1049
 
882
1050
  // src/commands/update.ts
883
1051
  import { Command as Command5 } from "commander";
884
- import path9 from "path";
1052
+ import path10 from "path";
885
1053
  import pc5 from "picocolors";
886
1054
  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();
1055
+ const projectDir = opts.cwd ? path10.resolve(opts.cwd) : process.cwd();
888
1056
  const config = readConfig(projectDir);
889
1057
  if (!config || Object.keys(config.packs).length === 0) {
890
1058
  console.log(pc5.dim("No packs installed yet. Starting setup...\n"));
891
1059
  await initCommand.parseAsync(["init", ...opts.cwd ? ["--cwd", opts.cwd] : []], { from: "user" });
892
1060
  return;
893
1061
  }
1062
+ const registryOpts = { ...getRegistryOptions(), noCache: true };
894
1063
  const packsToUpdate = packName ? [packName] : Object.keys(config.packs);
895
1064
  let updated = 0;
896
1065
  let skipped = 0;
@@ -901,7 +1070,7 @@ var updateCommand = new Command5("update").description("Update installed packs")
901
1070
  skipped++;
902
1071
  continue;
903
1072
  }
904
- const available = findPack(name);
1073
+ const available = await findPack(name, registryOpts);
905
1074
  if (!available) {
906
1075
  console.log(pc5.yellow(`"${name}" not found in marketplace, skipping.`));
907
1076
  skipped++;
@@ -942,10 +1111,10 @@ Updated ${updated} pack(s).`));
942
1111
  // src/commands/search.ts
943
1112
  import { Command as Command6 } from "commander";
944
1113
  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) => {
1114
+ var searchCommand = new Command6("search").description("Search available packs by name or keyword").argument("<query>", "Search term (matches name, description, keywords)").action(async (query) => {
946
1115
  let packs;
947
1116
  try {
948
- packs = discoverPacks();
1117
+ packs = await discoverPacks(getRegistryOptions());
949
1118
  } catch {
950
1119
  console.error(pc6.red("Could not find marketplace.json."));
951
1120
  process.exit(1);
@@ -984,12 +1153,28 @@ All packs: ${packs.map((p3) => p3.name).join(", ")}`));
984
1153
  }
985
1154
  });
986
1155
 
1156
+ // src/commands/cache.ts
1157
+ import { Command as Command7 } from "commander";
1158
+ import pc7 from "picocolors";
1159
+ var cacheCommand = new Command7("cache").description("Manage cached packs");
1160
+ cacheCommand.command("clear").description("Clear cached packs (forces re-download on next run)").action(() => {
1161
+ clearCache();
1162
+ console.log(pc7.green("Cache cleared.") + " Packs will be re-downloaded on next run.");
1163
+ });
1164
+
987
1165
  // src/index.ts
988
- var program = new Command7().name("ai-kit").description("AI coding tool pack manager").version("0.0.1");
1166
+ var program = new Command8().name("ai-kit").description("AI coding tool pack manager").version("0.0.1").option("--no-cache", "Force re-download from GitHub (skip cache check)").option("--branch <branch>", "Use specific branch (default: main)").hook("preAction", () => {
1167
+ const opts = program.opts();
1168
+ setGlobalRegistryOptions({
1169
+ noCache: opts.cache === false,
1170
+ branch: opts.branch
1171
+ });
1172
+ });
989
1173
  program.addCommand(initCommand);
990
1174
  program.addCommand(addCommand);
991
1175
  program.addCommand(listCommand);
992
1176
  program.addCommand(removeCommand);
993
1177
  program.addCommand(updateCommand);
994
1178
  program.addCommand(searchCommand);
1179
+ program.addCommand(cacheCommand);
995
1180
  program.parse();