@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/README.md +4 -5
- package/dist/index.js +306 -286
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -55,98 +55,90 @@ var init_config = __esm({
|
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
// src/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
81
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
137
|
-
"
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
331
|
-
import
|
|
332
|
-
import { readFile as
|
|
333
|
-
import { join as
|
|
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
|
|
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 =
|
|
366
|
-
const examplePath =
|
|
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
|
|
382
|
-
|
|
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
|
-
|
|
386
|
-
|
|
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 ?
|
|
392
|
-
|
|
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
|
|
386
|
+
const shouldPrompt = await p.confirm({
|
|
395
387
|
message: "Would you like to enter values now?",
|
|
396
388
|
initialValue: true
|
|
397
389
|
});
|
|
398
|
-
if (
|
|
399
|
-
|
|
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
|
|
400
|
+
value = await p.password({
|
|
409
401
|
message: `${key}:`
|
|
410
402
|
});
|
|
411
403
|
} else {
|
|
412
|
-
value = await
|
|
404
|
+
value = await p.text({
|
|
413
405
|
message: `${key}:`,
|
|
414
406
|
placeholder: config.description
|
|
415
407
|
});
|
|
416
408
|
}
|
|
417
|
-
if (
|
|
418
|
-
|
|
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
|
|
431
|
-
|
|
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
|
|
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 =
|
|
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
|
|
678
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
718
|
-
|
|
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
|
-
|
|
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} ${
|
|
726
|
-
|
|
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
|
-
|
|
756
|
-
const action = await
|
|
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 (!
|
|
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
|
-
|
|
829
|
-
const action = await
|
|
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 (!
|
|
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
|
-
|
|
828
|
+
p2.log.info(`Updated barrel file: ${join7(baseDir, "index.ts")}`);
|
|
916
829
|
if (!barrelExisted) {
|
|
917
|
-
|
|
830
|
+
p2.note(
|
|
918
831
|
[
|
|
919
|
-
`import {
|
|
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
|
-
`
|
|
927
|
-
`
|
|
834
|
+
`app.route("/api", ai.router);`,
|
|
835
|
+
`await ai.initialize();`
|
|
928
836
|
].join("\n"),
|
|
929
|
-
"Add this to your
|
|
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(
|
|
851
|
+
s.stop(pc3.yellow("Some dependencies failed to install"));
|
|
944
852
|
}
|
|
945
853
|
}
|
|
946
854
|
}
|
|
947
855
|
if (created.length > 0) {
|
|
948
|
-
|
|
949
|
-
for (const f of created)
|
|
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
|
-
|
|
953
|
-
for (const f of updated)
|
|
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
|
-
|
|
957
|
-
for (const f of skipped)
|
|
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
|
-
|
|
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 ${
|
|
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(`
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
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
|
-
|
|
992
|
-
for (const hint of hints)
|
|
890
|
+
p2.log.message(pc3.bold("\nNext steps:"));
|
|
891
|
+
for (const hint of hints) p2.log.message(hint);
|
|
993
892
|
}
|
|
994
|
-
|
|
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
|
|
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
|
|
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 =
|
|
1188
|
-
const relativePath =
|
|
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 =
|
|
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
|
|
1247
|
-
import { unlink, readFile as readFile7, writeFile as
|
|
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(
|
|
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 =
|
|
1283
|
-
const barrelDir =
|
|
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,
|
|
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
|
|
1304
|
-
p6.log.info(`Updated barrel file: ${
|
|
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
|
|
1359
|
-
import { join as
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
1407
|
-
if (await fileExists(
|
|
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 =
|
|
1433
|
-
await
|
|
1452
|
+
const typeDir = join11(resolvedOutput, dir);
|
|
1453
|
+
await mkdir5(typeDir, { recursive: true });
|
|
1434
1454
|
const itemJson = JSON.stringify(item, null, 2);
|
|
1435
|
-
const latestPath =
|
|
1455
|
+
const latestPath = join11(typeDir, `${item.name}.json`);
|
|
1436
1456
|
const latestRelative = `${dir}/${item.name}.json`;
|
|
1437
|
-
await
|
|
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 =
|
|
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
|
|
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 =
|
|
1482
|
-
await
|
|
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
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
1768
|
-
import { mkdir as
|
|
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 "@
|
|
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 "@
|
|
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 "@
|
|
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 =
|
|
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
|
|
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
|
|
1878
|
-
|
|
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
|
|
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.
|
|
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 () => {
|