@kitnai/cli 0.1.10 → 0.1.11

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/dist/index.js CHANGED
@@ -55,98 +55,90 @@ var init_config = __esm({
55
55
  }
56
56
  });
57
57
 
58
- // src/commands/init.ts
59
- var init_exports = {};
60
- __export(init_exports, {
61
- initCommand: () => initCommand
62
- });
63
- import * as p from "@clack/prompts";
64
- import pc2 from "picocolors";
65
- async function initCommand() {
66
- p.intro(pc2.bgCyan(pc2.black(" kitn ")));
67
- const cwd = process.cwd();
68
- const existing = await readConfig(cwd);
69
- if (existing) {
70
- p.log.warn("kitn.json already exists in this directory.");
71
- const shouldContinue = await p.confirm({
72
- message: "Overwrite existing configuration?",
73
- initialValue: false
74
- });
75
- if (p.isCancel(shouldContinue) || !shouldContinue) {
76
- p.cancel("Init cancelled.");
77
- process.exit(0);
58
+ // src/installers/tsconfig-patcher.ts
59
+ import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
60
+ import { join as join3 } from "path";
61
+ function stripJsonc(text3) {
62
+ return text3.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([}\]])/g, "$1");
63
+ }
64
+ function patchTsconfig(tsconfigContent, paths, removePrefixes) {
65
+ const config = JSON.parse(stripJsonc(tsconfigContent));
66
+ if (!config.compilerOptions) {
67
+ config.compilerOptions = {};
68
+ }
69
+ if (!config.compilerOptions.paths) {
70
+ config.compilerOptions.paths = {};
71
+ }
72
+ if (removePrefixes) {
73
+ for (const key of Object.keys(config.compilerOptions.paths)) {
74
+ if (removePrefixes.some((prefix) => key.startsWith(prefix))) {
75
+ delete config.compilerOptions.paths[key];
76
+ }
78
77
  }
79
78
  }
80
- const runtime = await p.select({
81
- message: "Which runtime do you use?",
82
- options: [
83
- { value: "bun", label: "Bun", hint: "recommended" },
84
- { value: "node", label: "Node.js" },
85
- { value: "deno", label: "Deno" }
86
- ]
87
- });
88
- if (p.isCancel(runtime)) {
89
- p.cancel("Init cancelled.");
90
- process.exit(0);
79
+ for (const [key, value] of Object.entries(paths)) {
80
+ config.compilerOptions.paths[key] = value;
91
81
  }
92
- const framework = await p.select({
93
- message: "Which framework are you using?",
94
- options: [
95
- { value: "hono", label: "Hono", hint: "recommended" },
96
- { value: "cloudflare", label: "Cloudflare Workers", hint: "coming soon" },
97
- { value: "elysia", label: "Elysia", hint: "coming soon" },
98
- { value: "fastify", label: "Fastify", hint: "coming soon" },
99
- { value: "express", label: "Express", hint: "coming soon" }
100
- ]
101
- });
102
- if (p.isCancel(framework)) {
103
- p.cancel("Init cancelled.");
104
- process.exit(0);
82
+ return JSON.stringify(config, null, 2) + "\n";
83
+ }
84
+ async function patchProjectTsconfig(projectDir, paths, removePrefixes) {
85
+ const tsconfigPath = join3(projectDir, "tsconfig.json");
86
+ let content;
87
+ try {
88
+ content = await readFile3(tsconfigPath, "utf-8");
89
+ } catch {
90
+ content = "{}";
105
91
  }
106
- const base = await p.text({
107
- message: "Where should kitn packages be installed?",
108
- initialValue: "src/ai",
109
- placeholder: "src/ai"
110
- });
111
- if (p.isCancel(base)) {
112
- p.cancel("Init cancelled.");
113
- process.exit(0);
92
+ const patched = patchTsconfig(content, paths, removePrefixes);
93
+ await writeFile3(tsconfigPath, patched);
94
+ }
95
+ var init_tsconfig_patcher = __esm({
96
+ "src/installers/tsconfig-patcher.ts"() {
97
+ "use strict";
114
98
  }
115
- const baseDir = base;
116
- const config = {
117
- runtime,
118
- framework,
119
- aliases: {
120
- base: baseDir,
121
- agents: `${baseDir}/agents`,
122
- tools: `${baseDir}/tools`,
123
- skills: `${baseDir}/skills`,
124
- storage: `${baseDir}/storage`
125
- },
126
- registries: {
127
- "@kitn": "https://kitn-ai.github.io/registry/r/{type}/{name}.json"
128
- }
129
- };
130
- const s = p.spinner();
131
- s.start("Writing kitn.json");
132
- await writeConfig(cwd, config);
133
- s.stop("Created kitn.json");
134
- p.outro(pc2.green("Done! Run `kitn add core` to install the engine, then `kitn add routes` for HTTP routes."));
99
+ });
100
+
101
+ // src/installers/barrel-manager.ts
102
+ function createBarrelFile() {
103
+ return `${BARREL_COMMENT}
104
+ ${EXPORT_LINE}
105
+ `;
135
106
  }
136
- var init_init = __esm({
137
- "src/commands/init.ts"() {
107
+ function addImportToBarrel(content, importPath) {
108
+ const importLine = `import "${importPath}";`;
109
+ if (content.includes(importLine)) return content;
110
+ const exportIndex = content.indexOf(EXPORT_LINE);
111
+ if (exportIndex === -1) {
112
+ return `${content.trimEnd()}
113
+ ${importLine}
114
+ ${EXPORT_LINE}
115
+ `;
116
+ }
117
+ const before = content.slice(0, exportIndex);
118
+ const after = content.slice(exportIndex);
119
+ return `${before}${importLine}
120
+ ${after}`;
121
+ }
122
+ function removeImportFromBarrel(content, importPath) {
123
+ const importLine = `import "${importPath}";`;
124
+ return content.split("\n").filter((line) => line.trim() !== importLine).join("\n");
125
+ }
126
+ var EXPORT_LINE, BARREL_COMMENT;
127
+ var init_barrel_manager = __esm({
128
+ "src/installers/barrel-manager.ts"() {
138
129
  "use strict";
139
- init_config();
130
+ EXPORT_LINE = 'export { registerWithPlugin } from "@kitn/core";';
131
+ BARREL_COMMENT = "// Managed by kitn CLI \u2014 components auto-imported below";
140
132
  }
141
133
  });
142
134
 
143
135
  // src/utils/detect.ts
144
136
  import { access } from "fs/promises";
145
- import { join as join3 } from "path";
137
+ import { join as join4 } from "path";
146
138
  async function detectPackageManager(dir) {
147
139
  for (const [lockfile, pm] of LOCKFILE_MAP) {
148
140
  try {
149
- await access(join3(dir, lockfile));
141
+ await access(join4(dir, lockfile));
150
142
  return pm;
151
143
  } catch {
152
144
  }
@@ -269,7 +261,7 @@ var init_resolver = __esm({
269
261
  });
270
262
 
271
263
  // src/installers/file-writer.ts
272
- import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir2, access as access2 } from "fs/promises";
264
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir2, access as access2 } from "fs/promises";
273
265
  import { dirname } from "path";
274
266
  import { createPatch } from "diff";
275
267
  async function checkFileStatus(filePath, newContent) {
@@ -278,7 +270,7 @@ async function checkFileStatus(filePath, newContent) {
278
270
  } catch {
279
271
  return "new" /* New */;
280
272
  }
281
- const existing = await readFile3(filePath, "utf-8");
273
+ const existing = await readFile4(filePath, "utf-8");
282
274
  return existing === newContent ? "identical" /* Identical */ : "different" /* Different */;
283
275
  }
284
276
  function generateDiff(filePath, oldContent, newContent) {
@@ -286,14 +278,14 @@ function generateDiff(filePath, oldContent, newContent) {
286
278
  }
287
279
  async function readExistingFile(filePath) {
288
280
  try {
289
- return await readFile3(filePath, "utf-8");
281
+ return await readFile4(filePath, "utf-8");
290
282
  } catch {
291
283
  return null;
292
284
  }
293
285
  }
294
286
  async function writeComponentFile(filePath, content) {
295
287
  await mkdir2(dirname(filePath), { recursive: true });
296
- await writeFile3(filePath, content);
288
+ await writeFile4(filePath, content);
297
289
  }
298
290
  var init_file_writer = __esm({
299
291
  "src/installers/file-writer.ts"() {
@@ -327,10 +319,10 @@ var init_dep_installer = __esm({
327
319
  });
328
320
 
329
321
  // src/installers/env-writer.ts
330
- import * as p2 from "@clack/prompts";
331
- import pc3 from "picocolors";
332
- import { readFile as readFile4, writeFile as writeFile4, access as access3 } from "fs/promises";
333
- import { join as join4 } from "path";
322
+ import * as p from "@clack/prompts";
323
+ import pc2 from "picocolors";
324
+ import { readFile as readFile5, writeFile as writeFile5, access as access3 } from "fs/promises";
325
+ import { join as join5 } from "path";
334
326
  function parseEnvKeys(content) {
335
327
  const keys = /* @__PURE__ */ new Set();
336
328
  for (const line of content.split("\n")) {
@@ -345,7 +337,7 @@ function parseEnvKeys(content) {
345
337
  }
346
338
  async function readEnvFile(path) {
347
339
  try {
348
- return await readFile4(path, "utf-8");
340
+ return await readFile5(path, "utf-8");
349
341
  } catch {
350
342
  return "";
351
343
  }
@@ -362,8 +354,8 @@ function collectEnvVars(items) {
362
354
  async function handleEnvVars(cwd, envVars) {
363
355
  const keys = Object.keys(envVars);
364
356
  if (keys.length === 0) return;
365
- const envPath = join4(cwd, ".env");
366
- const examplePath = join4(cwd, ".env.example");
357
+ const envPath = join5(cwd, ".env");
358
+ const examplePath = join5(cwd, ".env.example");
367
359
  const envContent = await readEnvFile(envPath);
368
360
  const exampleContent = await readEnvFile(examplePath);
369
361
  const envKeys = parseEnvKeys(envContent);
@@ -378,25 +370,25 @@ async function handleEnvVars(cwd, envVars) {
378
370
  lines.push(`# ${config.description}${config.url ? ` (${config.url})` : ""}`);
379
371
  lines.push(`${key}=`);
380
372
  }
381
- await writeFile4(examplePath, exampleContent + lines.join("\n") + "\n");
382
- p2.log.info(`Updated ${pc3.cyan(".env.example")} with ${missingFromExample.length} variable(s)`);
373
+ await writeFile5(examplePath, exampleContent + lines.join("\n") + "\n");
374
+ p.log.info(`Updated ${pc2.cyan(".env.example")} with ${missingFromExample.length} variable(s)`);
383
375
  }
384
376
  if (missingFromEnv.length === 0) return;
385
- p2.log.message("");
386
- p2.log.warn(
377
+ p.log.message("");
378
+ p.log.warn(
387
379
  `${missingFromEnv.length} environment variable(s) needed:`
388
380
  );
389
381
  for (const key of missingFromEnv) {
390
382
  const config = envVars[key];
391
- const req = config.required !== false ? pc3.red("*") : "";
392
- p2.log.message(` ${pc3.yellow(key)}${req}: ${config.description}${config.url ? pc3.dim(` -> ${config.url}`) : ""}`);
383
+ const req = config.required !== false ? pc2.red("*") : "";
384
+ p.log.message(` ${pc2.yellow(key)}${req}: ${config.description}${config.url ? pc2.dim(` -> ${config.url}`) : ""}`);
393
385
  }
394
- const shouldPrompt = await p2.confirm({
386
+ const shouldPrompt = await p.confirm({
395
387
  message: "Would you like to enter values now?",
396
388
  initialValue: true
397
389
  });
398
- if (p2.isCancel(shouldPrompt) || !shouldPrompt) {
399
- p2.log.info(`Add them to ${pc3.cyan(".env")} when ready.`);
390
+ if (p.isCancel(shouldPrompt) || !shouldPrompt) {
391
+ p.log.info(`Add them to ${pc2.cyan(".env")} when ready.`);
400
392
  return;
401
393
  }
402
394
  const newEntries = [];
@@ -405,17 +397,17 @@ async function handleEnvVars(cwd, envVars) {
405
397
  const isSecret = config.secret !== false;
406
398
  let value;
407
399
  if (isSecret) {
408
- value = await p2.password({
400
+ value = await p.password({
409
401
  message: `${key}:`
410
402
  });
411
403
  } else {
412
- value = await p2.text({
404
+ value = await p.text({
413
405
  message: `${key}:`,
414
406
  placeholder: config.description
415
407
  });
416
408
  }
417
- if (p2.isCancel(value)) {
418
- p2.log.info(`Skipped remaining variables. Add them to ${pc3.cyan(".env")} when ready.`);
409
+ if (p.isCancel(value)) {
410
+ p.log.info(`Skipped remaining variables. Add them to ${pc2.cyan(".env")} when ready.`);
419
411
  break;
420
412
  }
421
413
  if (value) {
@@ -427,8 +419,8 @@ async function handleEnvVars(cwd, envVars) {
427
419
  const lines = [];
428
420
  if (existingEnv && !existingEnv.endsWith("\n")) lines.push("");
429
421
  lines.push(...newEntries);
430
- await writeFile4(envPath, existingEnv + lines.join("\n") + "\n");
431
- p2.log.success(`Wrote ${newEntries.length} variable(s) to ${pc3.cyan(".env")}`);
422
+ await writeFile5(envPath, existingEnv + lines.join("\n") + "\n");
423
+ p.log.success(`Wrote ${newEntries.length} variable(s) to ${pc2.cyan(".env")}`);
432
424
  }
433
425
  }
434
426
  var init_env_writer = __esm({
@@ -438,7 +430,7 @@ var init_env_writer = __esm({
438
430
  });
439
431
 
440
432
  // src/installers/import-rewriter.ts
441
- import { relative, join as join5 } from "path";
433
+ import { relative, join as join6 } from "path";
442
434
  function rewriteKitnImports(content, fileType, fileName, aliases) {
443
435
  const sourceAliasKey = TYPE_TO_ALIAS_KEY[fileType];
444
436
  if (!sourceAliasKey) return content;
@@ -450,7 +442,7 @@ function rewriteKitnImports(content, fileType, fileName, aliases) {
450
442
  return `${prefix}@kitn/${type}/${targetPath}${quote}`;
451
443
  }
452
444
  const targetDir = aliases[type];
453
- const targetFile = join5(targetDir, targetPath);
445
+ const targetFile = join6(targetDir, targetPath);
454
446
  let rel = relative(sourceDir, targetFile);
455
447
  rel = rel.split("\\").join("/");
456
448
  if (!rel.startsWith(".")) {
@@ -474,76 +466,6 @@ var init_import_rewriter = __esm({
474
466
  }
475
467
  });
476
468
 
477
- // src/installers/tsconfig-patcher.ts
478
- import { readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
479
- import { join as join6 } from "path";
480
- function stripJsonc(text3) {
481
- return text3.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([}\]])/g, "$1");
482
- }
483
- function patchTsconfig(tsconfigContent, paths) {
484
- const config = JSON.parse(stripJsonc(tsconfigContent));
485
- if (!config.compilerOptions) {
486
- config.compilerOptions = {};
487
- }
488
- if (!config.compilerOptions.paths) {
489
- config.compilerOptions.paths = {};
490
- }
491
- for (const [key, value] of Object.entries(paths)) {
492
- config.compilerOptions.paths[key] = value;
493
- }
494
- return JSON.stringify(config, null, 2) + "\n";
495
- }
496
- async function patchProjectTsconfig(projectDir, paths) {
497
- const tsconfigPath = join6(projectDir, "tsconfig.json");
498
- let content;
499
- try {
500
- content = await readFile5(tsconfigPath, "utf-8");
501
- } catch {
502
- content = "{}";
503
- }
504
- const patched = patchTsconfig(content, paths);
505
- await writeFile5(tsconfigPath, patched);
506
- }
507
- var init_tsconfig_patcher = __esm({
508
- "src/installers/tsconfig-patcher.ts"() {
509
- "use strict";
510
- }
511
- });
512
-
513
- // src/installers/barrel-manager.ts
514
- function createBarrelFile() {
515
- return `${BARREL_COMMENT}
516
- ${EXPORT_LINE}
517
- `;
518
- }
519
- function addImportToBarrel(content, importPath) {
520
- const importLine = `import "${importPath}";`;
521
- if (content.includes(importLine)) return content;
522
- const exportIndex = content.indexOf(EXPORT_LINE);
523
- if (exportIndex === -1) {
524
- return `${content.trimEnd()}
525
- ${importLine}
526
- ${EXPORT_LINE}
527
- `;
528
- }
529
- const before = content.slice(0, exportIndex);
530
- const after = content.slice(exportIndex);
531
- return `${before}${importLine}
532
- ${after}`;
533
- }
534
- function removeImportFromBarrel(content, importPath) {
535
- const importLine = `import "${importPath}";`;
536
- return content.split("\n").filter((line) => line.trim() !== importLine).join("\n");
537
- }
538
- var EXPORT_LINE, BARREL_COMMENT;
539
- var init_barrel_manager = __esm({
540
- "src/installers/barrel-manager.ts"() {
541
- "use strict";
542
- EXPORT_LINE = 'export { registerWithPlugin } from "@kitnai/core";';
543
- BARREL_COMMENT = "// Managed by kitn CLI \u2014 components auto-imported below";
544
- }
545
- });
546
-
547
469
  // src/utils/hash.ts
548
470
  import { createHash } from "crypto";
549
471
  function contentHash(content) {
@@ -674,22 +596,22 @@ var add_exports = {};
674
596
  __export(add_exports, {
675
597
  addCommand: () => addCommand
676
598
  });
677
- import * as p3 from "@clack/prompts";
678
- import pc4 from "picocolors";
599
+ import * as p2 from "@clack/prompts";
600
+ import pc3 from "picocolors";
679
601
  import { join as join7 } from "path";
680
602
  import { existsSync } from "fs";
681
603
  import { readFile as readFile6, writeFile as writeFile6, mkdir as mkdir3 } from "fs/promises";
682
604
  import { relative as relative2 } from "path";
683
605
  async function addCommand(components, opts) {
684
- p3.intro(pc4.bgCyan(pc4.black(" kitn add ")));
606
+ p2.intro(pc3.bgCyan(pc3.black(" kitn add ")));
685
607
  const cwd = process.cwd();
686
608
  const config = await readConfig(cwd);
687
609
  if (!config) {
688
- p3.log.error("No kitn.json found. Run `kitn init` first.");
610
+ p2.log.error("No kitn.json found. Run `kitn init` first.");
689
611
  process.exit(1);
690
612
  }
691
613
  if (components.length === 0) {
692
- p3.log.error("Please specify at least one component to add.");
614
+ p2.log.error("Please specify at least one component to add.");
693
615
  process.exit(1);
694
616
  }
695
617
  const resolvedComponents = components.map((c) => {
@@ -701,7 +623,7 @@ async function addCommand(components, opts) {
701
623
  });
702
624
  const refs = resolvedComponents.map(parseComponentRef);
703
625
  const fetcher = new RegistryFetcher(config.registries);
704
- const s = p3.spinner();
626
+ const s = p2.spinner();
705
627
  s.start("Resolving dependencies...");
706
628
  let resolved;
707
629
  try {
@@ -714,16 +636,16 @@ async function addCommand(components, opts) {
714
636
  return fetcher.fetchItem(name, dir, ref.namespace, ref.version);
715
637
  });
716
638
  } catch (err) {
717
- s.stop(pc4.red("Failed to resolve dependencies"));
718
- p3.log.error(err.message);
639
+ s.stop(pc3.red("Failed to resolve dependencies"));
640
+ p2.log.error(err.message);
719
641
  process.exit(1);
720
642
  }
721
643
  s.stop(`Resolved ${resolved.length} component(s)`);
722
- p3.log.info("Components to install:");
644
+ p2.log.info("Components to install:");
723
645
  for (const item of resolved) {
724
646
  const isExplicit = resolvedComponents.includes(item.name) || components.includes(item.name);
725
- const label = isExplicit ? item.name : `${item.name} ${pc4.dim("(dependency)")}`;
726
- p3.log.message(` ${pc4.cyan(label)}`);
647
+ const label = isExplicit ? item.name : `${item.name} ${pc3.dim("(dependency)")}`;
648
+ p2.log.message(` ${pc3.cyan(label)}`);
727
649
  }
728
650
  const created = [];
729
651
  const updated = [];
@@ -752,15 +674,15 @@ async function addCommand(components, opts) {
752
674
  } else {
753
675
  const existing = await readExistingFile(targetPath);
754
676
  const diff = generateDiff(relativePath, existing ?? "", file.content);
755
- p3.log.message(pc4.dim(diff));
756
- const action = await p3.select({
677
+ p2.log.message(pc3.dim(diff));
678
+ const action = await p2.select({
757
679
  message: `${relativePath} already exists and differs. What to do?`,
758
680
  options: [
759
681
  { value: "skip", label: "Keep local version" },
760
682
  { value: "overwrite", label: "Overwrite with registry version" }
761
683
  ]
762
684
  });
763
- if (!p3.isCancel(action) && action === "overwrite") {
685
+ if (!p2.isCancel(action) && action === "overwrite") {
764
686
  await writeComponentFile(targetPath, file.content);
765
687
  updated.push(relativePath);
766
688
  } else {
@@ -770,15 +692,6 @@ async function addCommand(components, opts) {
770
692
  break;
771
693
  }
772
694
  }
773
- if (item.tsconfig) {
774
- const resolvedPaths = {};
775
- const installDir = item.installDir ?? item.name;
776
- for (const [key, values] of Object.entries(item.tsconfig)) {
777
- resolvedPaths[key] = values.map((v) => `./${join7(baseDir2, installDir, v)}`);
778
- }
779
- await patchProjectTsconfig(cwd, resolvedPaths);
780
- p3.log.info(`Patched tsconfig.json with paths: ${Object.keys(resolvedPaths).join(", ")}`);
781
- }
782
695
  const installed = config.installed ?? {};
783
696
  const allContent = item.files.map((f) => f.content).join("\n");
784
697
  const ref = refs.find((r) => r.name === item.name) ?? { namespace: "@kitn", name: item.name, version: void 0 };
@@ -825,15 +738,15 @@ async function addCommand(components, opts) {
825
738
  } else {
826
739
  const existing = await readExistingFile(targetPath);
827
740
  const diff = generateDiff(relativePath, existing ?? "", content);
828
- p3.log.message(pc4.dim(diff));
829
- const action = await p3.select({
741
+ p2.log.message(pc3.dim(diff));
742
+ const action = await p2.select({
830
743
  message: `${relativePath} already exists and differs. What to do?`,
831
744
  options: [
832
745
  { value: "skip", label: "Keep local version" },
833
746
  { value: "overwrite", label: "Overwrite with registry version" }
834
747
  ]
835
748
  });
836
- if (!p3.isCancel(action) && action === "overwrite") {
749
+ if (!p2.isCancel(action) && action === "overwrite") {
837
750
  await writeComponentFile(targetPath, content);
838
751
  updated.push(relativePath);
839
752
  } else {
@@ -912,21 +825,16 @@ async function addCommand(components, opts) {
912
825
  barrelContent = addImportToBarrel(barrelContent, importPath);
913
826
  }
914
827
  await writeFile6(barrelPath, barrelContent);
915
- p3.log.info(`Updated barrel file: ${join7(baseDir, "index.ts")}`);
828
+ p2.log.info(`Updated barrel file: ${join7(baseDir, "index.ts")}`);
916
829
  if (!barrelExisted) {
917
- p3.note(
830
+ p2.note(
918
831
  [
919
- `import { createAIPlugin } from "@kitnai/hono";`,
920
- `import { registerWithPlugin } from "./ai";`,
921
- ``,
922
- `const plugin = createAIPlugin({`,
923
- ` model: (model) => yourProvider(model ?? "default-model"),`,
924
- `});`,
832
+ `import { ai } from "./${baseDir}/plugin.js";`,
925
833
  ``,
926
- `registerWithPlugin(plugin);`,
927
- `app.route("/api", plugin.app);`
834
+ `app.route("/api", ai.router);`,
835
+ `await ai.initialize();`
928
836
  ].join("\n"),
929
- "Add this to your app setup"
837
+ "Add this to your server entry point"
930
838
  );
931
839
  }
932
840
  }
@@ -940,58 +848,49 @@ async function addCommand(components, opts) {
940
848
  installDependencies(pm, uniqueDeps, cwd);
941
849
  s.stop("Dependencies installed");
942
850
  } catch {
943
- s.stop(pc4.yellow("Some dependencies failed to install"));
851
+ s.stop(pc3.yellow("Some dependencies failed to install"));
944
852
  }
945
853
  }
946
854
  }
947
855
  if (created.length > 0) {
948
- p3.log.success(`Created ${created.length} file(s):`);
949
- for (const f of created) p3.log.message(` ${pc4.green("+")} ${f}`);
856
+ p2.log.success(`Created ${created.length} file(s):`);
857
+ for (const f of created) p2.log.message(` ${pc3.green("+")} ${f}`);
950
858
  }
951
859
  if (updated.length > 0) {
952
- p3.log.success(`Updated ${updated.length} file(s):`);
953
- for (const f of updated) p3.log.message(` ${pc4.yellow("~")} ${f}`);
860
+ p2.log.success(`Updated ${updated.length} file(s):`);
861
+ for (const f of updated) p2.log.message(` ${pc3.yellow("~")} ${f}`);
954
862
  }
955
863
  if (skipped.length > 0) {
956
- p3.log.info(`Skipped ${skipped.length} file(s):`);
957
- for (const f of skipped) p3.log.message(` ${pc4.dim("-")} ${f}`);
864
+ p2.log.info(`Skipped ${skipped.length} file(s):`);
865
+ for (const f of skipped) p2.log.message(` ${pc3.dim("-")} ${f}`);
958
866
  }
959
867
  const allEnvVars = collectEnvVars(resolved);
960
868
  await handleEnvVars(cwd, allEnvVars);
961
869
  for (const item of resolved) {
962
870
  if (item.docs) {
963
- p3.log.info(`${pc4.bold(item.name)}: ${item.docs}`);
871
+ p2.log.info(`${pc3.bold(item.name)}: ${item.docs}`);
964
872
  }
965
873
  }
966
874
  const installedNames = new Set(resolved.map((r) => r.name));
967
875
  const hints = [];
968
876
  if (installedNames.has("core") && !installedNames.has(config.framework ?? "hono")) {
969
- hints.push(`Run ${pc4.cyan(`kitn add routes`)} to install the HTTP adapter.`);
877
+ hints.push(`Run ${pc3.cyan(`kitn add routes`)} to install the HTTP adapter.`);
970
878
  }
971
879
  const fw = config.framework ?? "hono";
972
880
  if (installedNames.has(fw) || installedNames.has("core") && installedNames.has(fw)) {
973
- hints.push(`Add this to your server entry point:`);
974
- if (fw === "hono") {
975
- hints.push("");
976
- hints.push(pc4.dim(` import { Hono } from "hono";`));
977
- hints.push(pc4.dim(` import { createAIPlugin } from "@kitnai/hono";`));
978
- hints.push(pc4.dim(` import { yourProvider } from "your-ai-provider";`));
979
- hints.push(pc4.dim(``));
980
- hints.push(pc4.dim(` const plugin = createAIPlugin({`));
981
- hints.push(pc4.dim(` model: (model) => yourProvider(model ?? "default-model"),`));
982
- hints.push(pc4.dim(` });`));
983
- hints.push(pc4.dim(``));
984
- hints.push(pc4.dim(` const app = new Hono();`));
985
- hints.push(pc4.dim(` app.route("/api", plugin.app);`));
986
- hints.push(pc4.dim(` await plugin.initialize();`));
987
- hints.push("");
988
- }
881
+ hints.push(`Configure your AI provider in ${pc3.bold(baseDir + "/plugin.ts")}, then add to your server:`);
882
+ hints.push("");
883
+ hints.push(pc3.dim(` import { ai } from "./${baseDir}/plugin.js";`));
884
+ hints.push(pc3.dim(``));
885
+ hints.push(pc3.dim(` app.route("/api", ai.router);`));
886
+ hints.push(pc3.dim(` await ai.initialize();`));
887
+ hints.push("");
989
888
  }
990
889
  if (hints.length > 0) {
991
- p3.log.message(pc4.bold("\nNext steps:"));
992
- for (const hint of hints) p3.log.message(hint);
890
+ p2.log.message(pc3.bold("\nNext steps:"));
891
+ for (const hint of hints) p2.log.message(hint);
993
892
  }
994
- p3.outro(pc4.green("Done!"));
893
+ p2.outro(pc3.green("Done!"));
995
894
  }
996
895
  var init_add = __esm({
997
896
  "src/commands/add.ts"() {
@@ -1004,7 +903,6 @@ var init_add = __esm({
1004
903
  init_dep_installer();
1005
904
  init_env_writer();
1006
905
  init_import_rewriter();
1007
- init_tsconfig_patcher();
1008
906
  init_barrel_manager();
1009
907
  init_hash();
1010
908
  init_parse_ref();
@@ -1012,6 +910,126 @@ var init_add = __esm({
1012
910
  }
1013
911
  });
1014
912
 
913
+ // src/commands/init.ts
914
+ var init_exports = {};
915
+ __export(init_exports, {
916
+ initCommand: () => initCommand
917
+ });
918
+ import * as p3 from "@clack/prompts";
919
+ import pc4 from "picocolors";
920
+ import { mkdir as mkdir4, writeFile as writeFile7 } from "fs/promises";
921
+ import { join as join8 } from "path";
922
+ async function initCommand() {
923
+ p3.intro(pc4.bgCyan(pc4.black(" kitn init ")));
924
+ const cwd = process.cwd();
925
+ const existing = await readConfig(cwd);
926
+ if (existing) {
927
+ p3.log.warn("kitn.json already exists in this directory.");
928
+ const shouldContinue = await p3.confirm({
929
+ message: "Overwrite existing configuration?",
930
+ initialValue: false
931
+ });
932
+ if (p3.isCancel(shouldContinue) || !shouldContinue) {
933
+ p3.cancel("Init cancelled.");
934
+ process.exit(0);
935
+ }
936
+ }
937
+ const runtime = await p3.select({
938
+ message: "Which runtime do you use?",
939
+ options: [
940
+ { value: "bun", label: "Bun", hint: "recommended" },
941
+ { value: "node", label: "Node.js" },
942
+ { value: "deno", label: "Deno" }
943
+ ]
944
+ });
945
+ if (p3.isCancel(runtime)) {
946
+ p3.cancel("Init cancelled.");
947
+ process.exit(0);
948
+ }
949
+ const base = await p3.text({
950
+ message: "Where should kitn components be installed?",
951
+ initialValue: "src/ai",
952
+ placeholder: "src/ai"
953
+ });
954
+ if (p3.isCancel(base)) {
955
+ p3.cancel("Init cancelled.");
956
+ process.exit(0);
957
+ }
958
+ const baseDir = base;
959
+ const config = {
960
+ runtime,
961
+ framework: "hono",
962
+ aliases: {
963
+ base: baseDir,
964
+ agents: `${baseDir}/agents`,
965
+ tools: `${baseDir}/tools`,
966
+ skills: `${baseDir}/skills`,
967
+ storage: `${baseDir}/storage`
968
+ },
969
+ registries: {
970
+ "@kitn": "https://kitn-ai.github.io/registry/r/{type}/{name}.json"
971
+ }
972
+ };
973
+ const s = p3.spinner();
974
+ s.start("Writing kitn.json");
975
+ await writeConfig(cwd, config);
976
+ s.stop("Created kitn.json");
977
+ await patchProjectTsconfig(
978
+ cwd,
979
+ { "@kitn/*": [`./${baseDir}/*`] },
980
+ ["@kitn", "@kitnai"]
981
+ );
982
+ p3.log.info(`Patched tsconfig.json with path: ${pc4.bold("@kitn/*")}`);
983
+ p3.log.info("Installing core engine and routes...");
984
+ await addCommand(["core", "routes"], { overwrite: true });
985
+ const aiDir = join8(cwd, baseDir);
986
+ await mkdir4(aiDir, { recursive: true });
987
+ const barrelPath = join8(aiDir, "index.ts");
988
+ await writeFile7(barrelPath, createBarrelFile());
989
+ const pluginPath = join8(aiDir, "plugin.ts");
990
+ await writeFile7(pluginPath, PLUGIN_TEMPLATE);
991
+ p3.log.success(`Created ${pc4.bold(baseDir + "/plugin.ts")} \u2014 configure your AI provider there`);
992
+ p3.note(
993
+ [
994
+ `import { ai } from "./${baseDir}/plugin.js";`,
995
+ ``,
996
+ `app.route("/api", ai.router);`,
997
+ `await ai.initialize();`
998
+ ].join("\n"),
999
+ "Add this to your server entry point:"
1000
+ );
1001
+ p3.outro("Done!");
1002
+ }
1003
+ var PLUGIN_TEMPLATE;
1004
+ var init_init = __esm({
1005
+ "src/commands/init.ts"() {
1006
+ "use strict";
1007
+ init_config();
1008
+ init_tsconfig_patcher();
1009
+ init_barrel_manager();
1010
+ init_add();
1011
+ PLUGIN_TEMPLATE = `import { createAIPlugin } from "@kitn/routes";
1012
+ import { registerWithPlugin } from "./index.js";
1013
+
1014
+ export const ai = createAIPlugin({
1015
+ // To enable agent chat, add an AI provider:
1016
+ // https://sdk.vercel.ai/providers/ai-sdk-providers
1017
+ //
1018
+ // Example with OpenRouter (access to many models):
1019
+ // import { openrouter } from "@openrouter/ai-sdk-provider";
1020
+ // model: (id) => openrouter(id ?? "openai/gpt-4o-mini"),
1021
+ //
1022
+ // Example with OpenAI directly:
1023
+ // import { openai } from "@ai-sdk/openai";
1024
+ // model: (id) => openai(id ?? "gpt-4o-mini"),
1025
+ });
1026
+
1027
+ // Flush all auto-registered components into the plugin
1028
+ registerWithPlugin(ai);
1029
+ `;
1030
+ }
1031
+ });
1032
+
1015
1033
  // src/commands/list.ts
1016
1034
  var list_exports = {};
1017
1035
  __export(list_exports, {
@@ -1066,6 +1084,7 @@ async function listCommand(typeFilter, opts) {
1066
1084
  for (const item of allItems) {
1067
1085
  const group = item.type.replace("kitn:", "");
1068
1086
  if (resolvedType && group !== resolvedType) continue;
1087
+ if (!resolvedType && group === "package") continue;
1069
1088
  if (!typeGroups.has(group)) typeGroups.set(group, []);
1070
1089
  typeGroups.get(group).push(item);
1071
1090
  }
@@ -1121,7 +1140,8 @@ async function listCommand(typeFilter, opts) {
1121
1140
  console.log(pc5.dim(`
1122
1141
  No ${resolvedType} components found.`));
1123
1142
  }
1124
- const parts = [`${installedCount} installed`, `${allItems.length - installedCount} available`];
1143
+ const totalShown = [...typeGroups.values()].reduce((sum, items) => sum + items.length, 0);
1144
+ const parts = [`${installedCount} installed`, `${totalShown - installedCount} available`];
1125
1145
  if (updateCount > 0) parts.push(pc5.yellow(`${updateCount} update${updateCount === 1 ? "" : "s"}`));
1126
1146
  console.log(`
1127
1147
  ${pc5.dim(parts.join(" \xB7 "))}
@@ -1154,7 +1174,7 @@ __export(diff_exports, {
1154
1174
  diffCommand: () => diffCommand
1155
1175
  });
1156
1176
  import * as p5 from "@clack/prompts";
1157
- import { join as join8 } from "path";
1177
+ import { join as join9 } from "path";
1158
1178
  async function diffCommand(componentName) {
1159
1179
  const cwd = process.cwd();
1160
1180
  const config = await readConfig(cwd);
@@ -1184,8 +1204,8 @@ async function diffCommand(componentName) {
1184
1204
  for (const file of registryItem.files) {
1185
1205
  if (indexItem.type === "kitn:package") {
1186
1206
  const baseDir = config.aliases.base ?? "src/ai";
1187
- const localPath = join8(cwd, baseDir, file.path);
1188
- const relativePath = join8(baseDir, file.path);
1207
+ const localPath = join9(cwd, baseDir, file.path);
1208
+ const relativePath = join9(baseDir, file.path);
1189
1209
  const localContent = await readExistingFile(localPath);
1190
1210
  if (localContent === null) {
1191
1211
  p5.log.warn(`${relativePath}: file missing locally`);
@@ -1209,7 +1229,7 @@ async function diffCommand(componentName) {
1209
1229
  return "storage";
1210
1230
  }
1211
1231
  })();
1212
- const localPath = join8(cwd, config.aliases[aliasKey], fileName);
1232
+ const localPath = join9(cwd, config.aliases[aliasKey], fileName);
1213
1233
  const localContent = await readExistingFile(localPath);
1214
1234
  if (localContent === null) {
1215
1235
  p5.log.warn(`${fileName}: file missing locally`);
@@ -1243,8 +1263,8 @@ __export(remove_exports, {
1243
1263
  });
1244
1264
  import * as p6 from "@clack/prompts";
1245
1265
  import pc6 from "picocolors";
1246
- import { join as join9, relative as relative3, dirname as dirname3 } from "path";
1247
- import { unlink, readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
1266
+ import { join as join10, relative as relative3, dirname as dirname3 } from "path";
1267
+ import { unlink, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
1248
1268
  import { existsSync as existsSync2 } from "fs";
1249
1269
  async function removeCommand(componentName) {
1250
1270
  const cwd = process.cwd();
@@ -1272,15 +1292,15 @@ async function removeCommand(componentName) {
1272
1292
  const deleted = [];
1273
1293
  for (const filePath of installed.files) {
1274
1294
  try {
1275
- await unlink(join9(cwd, filePath));
1295
+ await unlink(join10(cwd, filePath));
1276
1296
  deleted.push(filePath);
1277
1297
  } catch {
1278
1298
  p6.log.warn(`Could not delete ${filePath} (may have been moved or renamed)`);
1279
1299
  }
1280
1300
  }
1281
1301
  const baseDir = config.aliases.base ?? "src/ai";
1282
- const barrelPath = join9(cwd, baseDir, "index.ts");
1283
- const barrelDir = join9(cwd, baseDir);
1302
+ const barrelPath = join10(cwd, baseDir, "index.ts");
1303
+ const barrelDir = join10(cwd, baseDir);
1284
1304
  const barrelEligibleDirs = /* @__PURE__ */ new Set([
1285
1305
  config.aliases.agents,
1286
1306
  config.aliases.tools,
@@ -1292,7 +1312,7 @@ async function removeCommand(componentName) {
1292
1312
  for (const filePath of deleted) {
1293
1313
  const fileDir = dirname3(filePath);
1294
1314
  if (!barrelEligibleDirs.has(fileDir)) continue;
1295
- const importPath = "./" + relative3(barrelDir, join9(cwd, filePath)).replace(/\\/g, "/");
1315
+ const importPath = "./" + relative3(barrelDir, join10(cwd, filePath)).replace(/\\/g, "/");
1296
1316
  const updated = removeImportFromBarrel(barrelContent, importPath);
1297
1317
  if (updated !== barrelContent) {
1298
1318
  barrelContent = updated;
@@ -1300,8 +1320,8 @@ async function removeCommand(componentName) {
1300
1320
  }
1301
1321
  }
1302
1322
  if (barrelChanged) {
1303
- await writeFile7(barrelPath, barrelContent);
1304
- p6.log.info(`Updated barrel file: ${join9(baseDir, "index.ts")}`);
1323
+ await writeFile8(barrelPath, barrelContent);
1324
+ p6.log.info(`Updated barrel file: ${join10(baseDir, "index.ts")}`);
1305
1325
  }
1306
1326
  }
1307
1327
  delete config.installed[installedKey];
@@ -1355,8 +1375,8 @@ var init_update = __esm({
1355
1375
  });
1356
1376
 
1357
1377
  // src/registry/build-output.ts
1358
- import { readdir, writeFile as writeFile8, mkdir as mkdir4, access as access4 } from "fs/promises";
1359
- import { join as join10, resolve } from "path";
1378
+ import { readdir, writeFile as writeFile9, mkdir as mkdir5, access as access4 } from "fs/promises";
1379
+ import { join as join11, resolve } from "path";
1360
1380
  async function fileExists(path) {
1361
1381
  try {
1362
1382
  await access4(path);
@@ -1373,13 +1393,13 @@ async function walkForRegistryJson(dir) {
1373
1393
  } catch {
1374
1394
  return results;
1375
1395
  }
1376
- if (await fileExists(join10(dir, "registry.json"))) {
1396
+ if (await fileExists(join11(dir, "registry.json"))) {
1377
1397
  results.push(dir);
1378
1398
  return results;
1379
1399
  }
1380
1400
  for (const entry of entries) {
1381
1401
  if (entry.isDirectory() && !SKIP_DIRS.has(entry.name)) {
1382
- const subResults = await walkForRegistryJson(join10(dir, entry.name));
1402
+ const subResults = await walkForRegistryJson(join11(dir, entry.name));
1383
1403
  results.push(...subResults);
1384
1404
  }
1385
1405
  }
@@ -1391,7 +1411,7 @@ async function scanForComponents(cwd, paths) {
1391
1411
  const results = [];
1392
1412
  for (const p12 of paths) {
1393
1413
  const absPath = resolve(resolvedCwd, p12);
1394
- if (await fileExists(join10(absPath, "registry.json"))) {
1414
+ if (await fileExists(join11(absPath, "registry.json"))) {
1395
1415
  results.push(absPath);
1396
1416
  continue;
1397
1417
  }
@@ -1403,8 +1423,8 @@ async function scanForComponents(cwd, paths) {
1403
1423
  }
1404
1424
  for (const entry of entries) {
1405
1425
  if (entry.isDirectory()) {
1406
- const subDir = join10(absPath, entry.name);
1407
- if (await fileExists(join10(subDir, "registry.json"))) {
1426
+ const subDir = join11(absPath, entry.name);
1427
+ if (await fileExists(join11(subDir, "registry.json"))) {
1408
1428
  results.push(subDir);
1409
1429
  }
1410
1430
  }
@@ -1429,21 +1449,21 @@ async function writeRegistryOutput(outputDir, items) {
1429
1449
  const indexItems = [];
1430
1450
  for (const item of items) {
1431
1451
  const dir = typeToDir[item.type];
1432
- const typeDir = join10(resolvedOutput, dir);
1433
- await mkdir4(typeDir, { recursive: true });
1452
+ const typeDir = join11(resolvedOutput, dir);
1453
+ await mkdir5(typeDir, { recursive: true });
1434
1454
  const itemJson = JSON.stringify(item, null, 2);
1435
- const latestPath = join10(typeDir, `${item.name}.json`);
1455
+ const latestPath = join11(typeDir, `${item.name}.json`);
1436
1456
  const latestRelative = `${dir}/${item.name}.json`;
1437
- await writeFile8(latestPath, itemJson, "utf-8");
1457
+ await writeFile9(latestPath, itemJson, "utf-8");
1438
1458
  written.push(latestRelative);
1439
1459
  if (item.version) {
1440
1460
  const versionedFilename = `${item.name}@${item.version}.json`;
1441
- const versionedPath = join10(typeDir, versionedFilename);
1461
+ const versionedPath = join11(typeDir, versionedFilename);
1442
1462
  const versionedRelative = `${dir}/${versionedFilename}`;
1443
1463
  if (await fileExists(versionedPath)) {
1444
1464
  skipped.push(versionedRelative);
1445
1465
  } else {
1446
- await writeFile8(versionedPath, itemJson, "utf-8");
1466
+ await writeFile9(versionedPath, itemJson, "utf-8");
1447
1467
  written.push(versionedRelative);
1448
1468
  }
1449
1469
  }
@@ -1478,8 +1498,8 @@ async function writeRegistryOutput(outputDir, items) {
1478
1498
  version: "1",
1479
1499
  items: indexItems
1480
1500
  };
1481
- const indexPath = join10(resolvedOutput, "registry.json");
1482
- await writeFile8(indexPath, JSON.stringify(index, null, 2), "utf-8");
1501
+ const indexPath = join11(resolvedOutput, "registry.json");
1502
+ await writeFile9(indexPath, JSON.stringify(index, null, 2), "utf-8");
1483
1503
  written.push("registry.json");
1484
1504
  return { written, skipped };
1485
1505
  }
@@ -1502,7 +1522,7 @@ var init_build_output = __esm({
1502
1522
 
1503
1523
  // src/registry/builder.ts
1504
1524
  import { readFile as readFile9, readdir as readdir2 } from "fs/promises";
1505
- import { join as join11, relative as relative5 } from "path";
1525
+ import { join as join12, relative as relative5 } from "path";
1506
1526
  function isExcludedDevDep(name) {
1507
1527
  return EXCLUDED_DEV_DEPS.has(name) || name.startsWith("@types/");
1508
1528
  }
@@ -1514,7 +1534,7 @@ async function readTsFiles(dir, baseDir, exclude) {
1514
1534
  const results = [];
1515
1535
  const entries = await readdir2(dir, { withFileTypes: true });
1516
1536
  for (const entry of entries) {
1517
- const fullPath = join11(dir, entry.name);
1537
+ const fullPath = join12(dir, entry.name);
1518
1538
  const relPath = relative5(baseDir, fullPath);
1519
1539
  if (entry.isDirectory()) {
1520
1540
  const nested = await readTsFiles(fullPath, baseDir, exclude);
@@ -1532,7 +1552,7 @@ async function readTsFiles(dir, baseDir, exclude) {
1532
1552
  async function buildComponent(componentDir) {
1533
1553
  let rawConfig;
1534
1554
  try {
1535
- rawConfig = await readFile9(join11(componentDir, "registry.json"), "utf-8");
1555
+ rawConfig = await readFile9(join12(componentDir, "registry.json"), "utf-8");
1536
1556
  } catch {
1537
1557
  throw new Error(
1538
1558
  `No registry.json found in ${componentDir}. Every component must have a registry.json file.`
@@ -1548,7 +1568,7 @@ async function buildComponent(componentDir) {
1548
1568
  }
1549
1569
  let pkg = null;
1550
1570
  try {
1551
- const rawPkg = await readFile9(join11(componentDir, "package.json"), "utf-8");
1571
+ const rawPkg = await readFile9(join12(componentDir, "package.json"), "utf-8");
1552
1572
  pkg = JSON.parse(rawPkg);
1553
1573
  } catch {
1554
1574
  }
@@ -1605,7 +1625,7 @@ async function buildComponent(componentDir) {
1605
1625
  let files;
1606
1626
  if (isPackage) {
1607
1627
  const sourceDir = config.sourceDir ?? "src";
1608
- const sourcePath = join11(componentDir, sourceDir);
1628
+ const sourcePath = join12(componentDir, sourceDir);
1609
1629
  const exclude = config.exclude ?? [];
1610
1630
  let tsFiles;
1611
1631
  try {
@@ -1628,7 +1648,7 @@ async function buildComponent(componentDir) {
1628
1648
  }
1629
1649
  files = await Promise.all(
1630
1650
  config.files.map(async (filePath) => {
1631
- const fullPath = join11(componentDir, filePath);
1651
+ const fullPath = join12(componentDir, filePath);
1632
1652
  let content;
1633
1653
  try {
1634
1654
  content = await readFile9(fullPath, "utf-8");
@@ -1764,8 +1784,8 @@ __export(create_exports, {
1764
1784
  });
1765
1785
  import * as p9 from "@clack/prompts";
1766
1786
  import pc8 from "picocolors";
1767
- import { join as join12 } from "path";
1768
- import { mkdir as mkdir5, writeFile as writeFile9 } from "fs/promises";
1787
+ import { join as join13 } from "path";
1788
+ import { mkdir as mkdir6, writeFile as writeFile10 } from "fs/promises";
1769
1789
  function toCamelCase(str) {
1770
1790
  return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
1771
1791
  }
@@ -1791,7 +1811,7 @@ function generateRegistryJson(type, name, sourceFile) {
1791
1811
  }
1792
1812
  function generateAgentSource(name) {
1793
1813
  const camel = toCamelCase(name);
1794
- return `import { registerAgent } from "@kitnai/core";
1814
+ return `import { registerAgent } from "@kitn/core";
1795
1815
 
1796
1816
  const SYSTEM_PROMPT = "You are a helpful assistant.";
1797
1817
 
@@ -1805,7 +1825,7 @@ registerAgent({
1805
1825
  }
1806
1826
  function generateToolSource(name) {
1807
1827
  const camel = toCamelCase(name);
1808
- return `import { registerTool } from "@kitnai/core";
1828
+ return `import { registerTool } from "@kitn/core";
1809
1829
  import { tool } from "ai";
1810
1830
  import { z } from "zod";
1811
1831
 
@@ -1842,7 +1862,7 @@ Describe what this skill does and how to use it.
1842
1862
  }
1843
1863
  function generateStorageSource(name) {
1844
1864
  const camel = toCamelCase("create-" + name);
1845
- return `import type { StorageProvider } from "@kitnai/core";
1865
+ return `import type { StorageProvider } from "@kitn/core";
1846
1866
 
1847
1867
  export function ${camel}(config?: Record<string, unknown>): StorageProvider {
1848
1868
  // TODO: implement storage provider
@@ -1866,16 +1886,16 @@ async function createComponent(type, name, opts) {
1866
1886
  );
1867
1887
  }
1868
1888
  const cwd = opts?.cwd ?? process.cwd();
1869
- const dir = join12(cwd, name);
1889
+ const dir = join13(cwd, name);
1870
1890
  if (await dirExists(dir)) {
1871
1891
  throw new Error(`Directory "${name}" already exists`);
1872
1892
  }
1873
- await mkdir5(dir, { recursive: true });
1893
+ await mkdir6(dir, { recursive: true });
1874
1894
  const validType = type;
1875
1895
  const sourceFile = validType === "skill" ? "README.md" : `${name}.ts`;
1876
1896
  const registryJson = generateRegistryJson(validType, name, sourceFile);
1877
- await writeFile9(
1878
- join12(dir, "registry.json"),
1897
+ await writeFile10(
1898
+ join13(dir, "registry.json"),
1879
1899
  JSON.stringify(registryJson, null, 2) + "\n"
1880
1900
  );
1881
1901
  let source;
@@ -1893,7 +1913,7 @@ async function createComponent(type, name, opts) {
1893
1913
  source = generateStorageSource(name);
1894
1914
  break;
1895
1915
  }
1896
- await writeFile9(join12(dir, sourceFile), source);
1916
+ await writeFile10(join13(dir, sourceFile), source);
1897
1917
  return { dir, files: ["registry.json", sourceFile] };
1898
1918
  }
1899
1919
  async function createCommand(type, name) {
@@ -2196,7 +2216,7 @@ function startUpdateCheck(currentVersion) {
2196
2216
  }
2197
2217
 
2198
2218
  // src/index.ts
2199
- var VERSION = true ? "0.1.10" : "0.0.0-dev";
2219
+ var VERSION = true ? "0.1.11" : "0.0.0-dev";
2200
2220
  var printUpdateNotice = startUpdateCheck(VERSION);
2201
2221
  var program = new Command().name("kitn").description("Install AI agent components from the kitn registry").version(VERSION);
2202
2222
  program.command("init").description("Initialize kitn in your project").action(async () => {