@kitnai/cli 0.1.0 → 0.1.2
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 +186 -0
- package/dist/index.js +694 -234
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29,8 +29,9 @@ var componentType, installedComponentSchema, configSchema, CONFIG_FILE;
|
|
|
29
29
|
var init_config = __esm({
|
|
30
30
|
"src/utils/config.ts"() {
|
|
31
31
|
"use strict";
|
|
32
|
-
componentType = z.enum(["kitn:agent", "kitn:tool", "kitn:skill", "kitn:storage"]);
|
|
32
|
+
componentType = z.enum(["kitn:agent", "kitn:tool", "kitn:skill", "kitn:storage", "kitn:package"]);
|
|
33
33
|
installedComponentSchema = z.object({
|
|
34
|
+
registry: z.string().optional(),
|
|
34
35
|
version: z.string(),
|
|
35
36
|
installedAt: z.string(),
|
|
36
37
|
files: z.array(z.string()),
|
|
@@ -39,71 +40,21 @@ var init_config = __esm({
|
|
|
39
40
|
configSchema = z.object({
|
|
40
41
|
$schema: z.string().optional(),
|
|
41
42
|
runtime: z.enum(["bun", "node", "deno"]),
|
|
43
|
+
framework: z.enum(["hono", "cloudflare", "elysia", "fastify", "express"]).optional(),
|
|
42
44
|
aliases: z.object({
|
|
45
|
+
base: z.string().optional(),
|
|
43
46
|
agents: z.string(),
|
|
44
47
|
tools: z.string(),
|
|
45
48
|
skills: z.string(),
|
|
46
49
|
storage: z.string()
|
|
47
50
|
}),
|
|
48
51
|
registries: z.record(z.string(), z.string()),
|
|
49
|
-
|
|
52
|
+
installed: z.record(z.string(), installedComponentSchema).optional()
|
|
50
53
|
});
|
|
51
54
|
CONFIG_FILE = "kitn.json";
|
|
52
55
|
}
|
|
53
56
|
});
|
|
54
57
|
|
|
55
|
-
// src/utils/detect.ts
|
|
56
|
-
import { access } from "fs/promises";
|
|
57
|
-
import { join as join2 } from "path";
|
|
58
|
-
async function detectPackageManager(dir) {
|
|
59
|
-
for (const [lockfile, pm] of LOCKFILE_MAP) {
|
|
60
|
-
try {
|
|
61
|
-
await access(join2(dir, lockfile));
|
|
62
|
-
return pm;
|
|
63
|
-
} catch {
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
var LOCKFILE_MAP;
|
|
69
|
-
var init_detect = __esm({
|
|
70
|
-
"src/utils/detect.ts"() {
|
|
71
|
-
"use strict";
|
|
72
|
-
LOCKFILE_MAP = [
|
|
73
|
-
["bun.lock", "bun"],
|
|
74
|
-
["bun.lockb", "bun"],
|
|
75
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
76
|
-
["yarn.lock", "yarn"],
|
|
77
|
-
["package-lock.json", "npm"]
|
|
78
|
-
];
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// src/installers/dep-installer.ts
|
|
83
|
-
import { execSync } from "child_process";
|
|
84
|
-
function installDependencies(pm, deps, projectDir) {
|
|
85
|
-
if (deps.length === 0) return;
|
|
86
|
-
const pkgs = deps.join(" ");
|
|
87
|
-
const cmd = (() => {
|
|
88
|
-
switch (pm) {
|
|
89
|
-
case "bun":
|
|
90
|
-
return `bun add ${pkgs}`;
|
|
91
|
-
case "pnpm":
|
|
92
|
-
return `pnpm add ${pkgs}`;
|
|
93
|
-
case "yarn":
|
|
94
|
-
return `yarn add ${pkgs}`;
|
|
95
|
-
case "npm":
|
|
96
|
-
return `npm install ${pkgs}`;
|
|
97
|
-
}
|
|
98
|
-
})();
|
|
99
|
-
execSync(cmd, { cwd: projectDir, stdio: "pipe" });
|
|
100
|
-
}
|
|
101
|
-
var init_dep_installer = __esm({
|
|
102
|
-
"src/installers/dep-installer.ts"() {
|
|
103
|
-
"use strict";
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
58
|
// src/commands/init.ts
|
|
108
59
|
var init_exports = {};
|
|
109
60
|
__export(init_exports, {
|
|
@@ -138,74 +89,81 @@ async function initCommand() {
|
|
|
138
89
|
p.cancel("Init cancelled.");
|
|
139
90
|
process.exit(0);
|
|
140
91
|
}
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
initialValue: "src/storage",
|
|
160
|
-
placeholder: "src/storage"
|
|
161
|
-
})
|
|
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);
|
|
105
|
+
}
|
|
106
|
+
const base = await p.text({
|
|
107
|
+
message: "Where should kitn packages be installed?",
|
|
108
|
+
initialValue: "src/ai",
|
|
109
|
+
placeholder: "src/ai"
|
|
162
110
|
});
|
|
163
|
-
if (p.isCancel(
|
|
111
|
+
if (p.isCancel(base)) {
|
|
164
112
|
p.cancel("Init cancelled.");
|
|
165
113
|
process.exit(0);
|
|
166
114
|
}
|
|
115
|
+
const baseDir = base;
|
|
167
116
|
const config = {
|
|
168
117
|
runtime,
|
|
118
|
+
framework,
|
|
169
119
|
aliases: {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
120
|
+
base: baseDir,
|
|
121
|
+
agents: `${baseDir}/agents`,
|
|
122
|
+
tools: `${baseDir}/tools`,
|
|
123
|
+
skills: `${baseDir}/skills`,
|
|
124
|
+
storage: `${baseDir}/storage`
|
|
174
125
|
},
|
|
175
126
|
registries: {
|
|
176
|
-
"@kitn": "https://kitn-ai.github.io/
|
|
127
|
+
"@kitn": "https://kitn-ai.github.io/registry/r/{type}/{name}.json"
|
|
177
128
|
}
|
|
178
129
|
};
|
|
179
130
|
const s = p.spinner();
|
|
180
131
|
s.start("Writing kitn.json");
|
|
181
132
|
await writeConfig(cwd, config);
|
|
182
133
|
s.stop("Created kitn.json");
|
|
183
|
-
|
|
184
|
-
if (pm) {
|
|
185
|
-
const shouldInstall = await p.confirm({
|
|
186
|
-
message: `Install @kitnai/server using ${pm}?`,
|
|
187
|
-
initialValue: true
|
|
188
|
-
});
|
|
189
|
-
if (!p.isCancel(shouldInstall) && shouldInstall) {
|
|
190
|
-
s.start("Installing @kitnai/server...");
|
|
191
|
-
try {
|
|
192
|
-
installDependencies(pm, ["@kitnai/server"], cwd);
|
|
193
|
-
s.stop("Installed @kitnai/server");
|
|
194
|
-
} catch {
|
|
195
|
-
s.stop(pc.yellow("Failed to install @kitnai/server \u2014 you can install it manually"));
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
} else {
|
|
199
|
-
p.log.info("No package manager detected. Install @kitnai/server manually.");
|
|
200
|
-
}
|
|
201
|
-
p.outro(pc.green("Done! Run `kitn add <component>` to add your first component."));
|
|
134
|
+
p.outro(pc.green("Done! Run `kitn add core` to install the engine, then `kitn add routes` for HTTP routes."));
|
|
202
135
|
}
|
|
203
136
|
var init_init = __esm({
|
|
204
137
|
"src/commands/init.ts"() {
|
|
205
138
|
"use strict";
|
|
206
139
|
init_config();
|
|
207
|
-
|
|
208
|
-
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// src/utils/detect.ts
|
|
144
|
+
import { access } from "fs/promises";
|
|
145
|
+
import { join as join2 } from "path";
|
|
146
|
+
async function detectPackageManager(dir) {
|
|
147
|
+
for (const [lockfile, pm] of LOCKFILE_MAP) {
|
|
148
|
+
try {
|
|
149
|
+
await access(join2(dir, lockfile));
|
|
150
|
+
return pm;
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
var LOCKFILE_MAP;
|
|
157
|
+
var init_detect = __esm({
|
|
158
|
+
"src/utils/detect.ts"() {
|
|
159
|
+
"use strict";
|
|
160
|
+
LOCKFILE_MAP = [
|
|
161
|
+
["bun.lock", "bun"],
|
|
162
|
+
["bun.lockb", "bun"],
|
|
163
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
164
|
+
["yarn.lock", "yarn"],
|
|
165
|
+
["package-lock.json", "npm"]
|
|
166
|
+
];
|
|
209
167
|
}
|
|
210
168
|
});
|
|
211
169
|
|
|
@@ -222,21 +180,22 @@ var init_fetcher = __esm({
|
|
|
222
180
|
this.registries = registries;
|
|
223
181
|
this.fetchFn = fetchFn ?? this.defaultFetch;
|
|
224
182
|
}
|
|
225
|
-
resolveUrl(name, typeDir) {
|
|
226
|
-
const template = this.registries[
|
|
227
|
-
if (!template) throw new Error(
|
|
228
|
-
|
|
183
|
+
resolveUrl(name, typeDir, namespace = "@kitn", version) {
|
|
184
|
+
const template = this.registries[namespace];
|
|
185
|
+
if (!template) throw new Error(`No registry configured for ${namespace}`);
|
|
186
|
+
const fileName = version ? `${name}@${version}` : name;
|
|
187
|
+
return template.replace("{name}", fileName).replace("{type}", typeDir);
|
|
229
188
|
}
|
|
230
|
-
async fetchItem(name, typeDir) {
|
|
231
|
-
const url = this.resolveUrl(name, typeDir);
|
|
189
|
+
async fetchItem(name, typeDir, namespace = "@kitn", version) {
|
|
190
|
+
const url = this.resolveUrl(name, typeDir, namespace, version);
|
|
232
191
|
if (!this.cache.has(url)) {
|
|
233
192
|
this.cache.set(url, this.fetchFn(url));
|
|
234
193
|
}
|
|
235
194
|
return this.cache.get(url);
|
|
236
195
|
}
|
|
237
|
-
async fetchIndex() {
|
|
238
|
-
const template = this.registries[
|
|
239
|
-
if (!template) throw new Error(
|
|
196
|
+
async fetchIndex(namespace = "@kitn") {
|
|
197
|
+
const template = this.registries[namespace];
|
|
198
|
+
if (!template) throw new Error(`No registry configured for ${namespace}`);
|
|
240
199
|
const baseUrl = template.replace("{type}/{name}.json", "registry.json");
|
|
241
200
|
const res = await fetch(baseUrl);
|
|
242
201
|
if (!res.ok) throw new Error(`Failed to fetch registry index: ${res.statusText}`);
|
|
@@ -342,6 +301,31 @@ var init_file_writer = __esm({
|
|
|
342
301
|
}
|
|
343
302
|
});
|
|
344
303
|
|
|
304
|
+
// src/installers/dep-installer.ts
|
|
305
|
+
import { execSync } from "child_process";
|
|
306
|
+
function installDependencies(pm, deps, projectDir) {
|
|
307
|
+
if (deps.length === 0) return;
|
|
308
|
+
const pkgs = deps.join(" ");
|
|
309
|
+
const cmd = (() => {
|
|
310
|
+
switch (pm) {
|
|
311
|
+
case "bun":
|
|
312
|
+
return `bun add ${pkgs}`;
|
|
313
|
+
case "pnpm":
|
|
314
|
+
return `pnpm add ${pkgs}`;
|
|
315
|
+
case "yarn":
|
|
316
|
+
return `yarn add ${pkgs}`;
|
|
317
|
+
case "npm":
|
|
318
|
+
return `npm install ${pkgs}`;
|
|
319
|
+
}
|
|
320
|
+
})();
|
|
321
|
+
execSync(cmd, { cwd: projectDir, stdio: "pipe" });
|
|
322
|
+
}
|
|
323
|
+
var init_dep_installer = __esm({
|
|
324
|
+
"src/installers/dep-installer.ts"() {
|
|
325
|
+
"use strict";
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
345
329
|
// src/installers/env-checker.ts
|
|
346
330
|
import pc2 from "picocolors";
|
|
347
331
|
function checkEnvVars(envVars) {
|
|
@@ -359,6 +343,76 @@ var init_env_checker = __esm({
|
|
|
359
343
|
}
|
|
360
344
|
});
|
|
361
345
|
|
|
346
|
+
// src/installers/import-rewriter.ts
|
|
347
|
+
import { relative, join as join3 } from "path";
|
|
348
|
+
function rewriteKitnImports(content, fileType, fileName, aliases) {
|
|
349
|
+
const sourceAliasKey = TYPE_TO_ALIAS_KEY[fileType];
|
|
350
|
+
if (!sourceAliasKey) return content;
|
|
351
|
+
const sourceDir = aliases[sourceAliasKey];
|
|
352
|
+
return content.replace(
|
|
353
|
+
/((?:import|export)\s+.*?\s+from\s+["'])@kitn\/([\w-]+)\/([^"']+)(["'])/g,
|
|
354
|
+
(_match, prefix, type, targetPath, quote) => {
|
|
355
|
+
if (!KNOWN_TYPES.includes(type)) {
|
|
356
|
+
return `${prefix}@kitn/${type}/${targetPath}${quote}`;
|
|
357
|
+
}
|
|
358
|
+
const targetDir = aliases[type];
|
|
359
|
+
const targetFile = join3(targetDir, targetPath);
|
|
360
|
+
let rel = relative(sourceDir, targetFile);
|
|
361
|
+
rel = rel.split("\\").join("/");
|
|
362
|
+
if (!rel.startsWith(".")) {
|
|
363
|
+
rel = `./${rel}`;
|
|
364
|
+
}
|
|
365
|
+
return `${prefix}${rel}${quote}`;
|
|
366
|
+
}
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
var KNOWN_TYPES, TYPE_TO_ALIAS_KEY;
|
|
370
|
+
var init_import_rewriter = __esm({
|
|
371
|
+
"src/installers/import-rewriter.ts"() {
|
|
372
|
+
"use strict";
|
|
373
|
+
KNOWN_TYPES = ["agents", "tools", "skills", "storage"];
|
|
374
|
+
TYPE_TO_ALIAS_KEY = {
|
|
375
|
+
"kitn:agent": "agents",
|
|
376
|
+
"kitn:tool": "tools",
|
|
377
|
+
"kitn:skill": "skills",
|
|
378
|
+
"kitn:storage": "storage"
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// src/installers/tsconfig-patcher.ts
|
|
384
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
385
|
+
import { join as join4 } from "path";
|
|
386
|
+
function patchTsconfig(tsconfigContent, paths) {
|
|
387
|
+
const config = JSON.parse(tsconfigContent);
|
|
388
|
+
if (!config.compilerOptions) {
|
|
389
|
+
config.compilerOptions = {};
|
|
390
|
+
}
|
|
391
|
+
if (!config.compilerOptions.paths) {
|
|
392
|
+
config.compilerOptions.paths = {};
|
|
393
|
+
}
|
|
394
|
+
for (const [key, value] of Object.entries(paths)) {
|
|
395
|
+
config.compilerOptions.paths[key] = value;
|
|
396
|
+
}
|
|
397
|
+
return JSON.stringify(config, null, 2) + "\n";
|
|
398
|
+
}
|
|
399
|
+
async function patchProjectTsconfig(projectDir, paths) {
|
|
400
|
+
const tsconfigPath = join4(projectDir, "tsconfig.json");
|
|
401
|
+
let content;
|
|
402
|
+
try {
|
|
403
|
+
content = await readFile3(tsconfigPath, "utf-8");
|
|
404
|
+
} catch {
|
|
405
|
+
content = "{}";
|
|
406
|
+
}
|
|
407
|
+
const patched = patchTsconfig(content, paths);
|
|
408
|
+
await writeFile3(tsconfigPath, patched);
|
|
409
|
+
}
|
|
410
|
+
var init_tsconfig_patcher = __esm({
|
|
411
|
+
"src/installers/tsconfig-patcher.ts"() {
|
|
412
|
+
"use strict";
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
362
416
|
// src/utils/hash.ts
|
|
363
417
|
import { createHash } from "crypto";
|
|
364
418
|
function contentHash(content) {
|
|
@@ -370,18 +424,52 @@ var init_hash = __esm({
|
|
|
370
424
|
}
|
|
371
425
|
});
|
|
372
426
|
|
|
427
|
+
// src/utils/parse-ref.ts
|
|
428
|
+
function parseComponentRef(input) {
|
|
429
|
+
let namespace = "@kitn";
|
|
430
|
+
let rest = input;
|
|
431
|
+
if (rest.startsWith("@")) {
|
|
432
|
+
const slashIdx = rest.indexOf("/");
|
|
433
|
+
if (slashIdx === -1) {
|
|
434
|
+
throw new Error(`Invalid component reference: ${input}. Expected @namespace/name`);
|
|
435
|
+
}
|
|
436
|
+
namespace = rest.slice(0, slashIdx);
|
|
437
|
+
rest = rest.slice(slashIdx + 1);
|
|
438
|
+
}
|
|
439
|
+
const atIdx = rest.indexOf("@");
|
|
440
|
+
if (atIdx === -1) {
|
|
441
|
+
return { namespace, name: rest, version: void 0 };
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
namespace,
|
|
445
|
+
name: rest.slice(0, atIdx),
|
|
446
|
+
version: rest.slice(atIdx + 1)
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
var init_parse_ref = __esm({
|
|
450
|
+
"src/utils/parse-ref.ts"() {
|
|
451
|
+
"use strict";
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
373
455
|
// src/registry/schema.ts
|
|
374
456
|
import { z as z2 } from "zod";
|
|
375
|
-
var componentType2, registryFileSchema, registryItemSchema, registryIndexItemSchema, registryIndexSchema, typeToDir;
|
|
457
|
+
var componentType2, registryFileSchema, changelogEntrySchema, registryItemSchema, registryIndexItemSchema, registryIndexSchema, typeToDir;
|
|
376
458
|
var init_schema = __esm({
|
|
377
459
|
"src/registry/schema.ts"() {
|
|
378
460
|
"use strict";
|
|
379
|
-
componentType2 = z2.enum(["kitn:agent", "kitn:tool", "kitn:skill", "kitn:storage"]);
|
|
461
|
+
componentType2 = z2.enum(["kitn:agent", "kitn:tool", "kitn:skill", "kitn:storage", "kitn:package"]);
|
|
380
462
|
registryFileSchema = z2.object({
|
|
381
463
|
path: z2.string(),
|
|
382
464
|
content: z2.string(),
|
|
383
465
|
type: componentType2
|
|
384
466
|
});
|
|
467
|
+
changelogEntrySchema = z2.object({
|
|
468
|
+
version: z2.string(),
|
|
469
|
+
date: z2.string(),
|
|
470
|
+
type: z2.enum(["feature", "fix", "breaking", "initial"]),
|
|
471
|
+
note: z2.string()
|
|
472
|
+
});
|
|
385
473
|
registryItemSchema = z2.object({
|
|
386
474
|
$schema: z2.string().optional(),
|
|
387
475
|
name: z2.string(),
|
|
@@ -392,9 +480,13 @@ var init_schema = __esm({
|
|
|
392
480
|
registryDependencies: z2.array(z2.string()).optional(),
|
|
393
481
|
envVars: z2.record(z2.string(), z2.string()).optional(),
|
|
394
482
|
files: z2.array(registryFileSchema),
|
|
483
|
+
installDir: z2.string().optional(),
|
|
484
|
+
tsconfig: z2.record(z2.string(), z2.array(z2.string())).optional(),
|
|
395
485
|
docs: z2.string().optional(),
|
|
396
486
|
categories: z2.array(z2.string()).optional(),
|
|
397
|
-
version: z2.string().optional()
|
|
487
|
+
version: z2.string().optional(),
|
|
488
|
+
updatedAt: z2.string().optional(),
|
|
489
|
+
changelog: z2.array(changelogEntrySchema).optional()
|
|
398
490
|
});
|
|
399
491
|
registryIndexItemSchema = z2.object({
|
|
400
492
|
name: z2.string(),
|
|
@@ -402,7 +494,9 @@ var init_schema = __esm({
|
|
|
402
494
|
description: z2.string(),
|
|
403
495
|
registryDependencies: z2.array(z2.string()).optional(),
|
|
404
496
|
categories: z2.array(z2.string()).optional(),
|
|
405
|
-
version: z2.string().optional()
|
|
497
|
+
version: z2.string().optional(),
|
|
498
|
+
versions: z2.array(z2.string()).optional(),
|
|
499
|
+
updatedAt: z2.string().optional()
|
|
406
500
|
});
|
|
407
501
|
registryIndexSchema = z2.object({
|
|
408
502
|
$schema: z2.string().optional(),
|
|
@@ -413,7 +507,8 @@ var init_schema = __esm({
|
|
|
413
507
|
"kitn:agent": "agents",
|
|
414
508
|
"kitn:tool": "tools",
|
|
415
509
|
"kitn:skill": "skills",
|
|
416
|
-
"kitn:storage": "storage"
|
|
510
|
+
"kitn:storage": "storage",
|
|
511
|
+
"kitn:package": "package"
|
|
417
512
|
};
|
|
418
513
|
}
|
|
419
514
|
});
|
|
@@ -425,7 +520,7 @@ __export(add_exports, {
|
|
|
425
520
|
});
|
|
426
521
|
import * as p2 from "@clack/prompts";
|
|
427
522
|
import pc3 from "picocolors";
|
|
428
|
-
import { join as
|
|
523
|
+
import { join as join5 } from "path";
|
|
429
524
|
async function addCommand(components, opts) {
|
|
430
525
|
p2.intro(pc3.bgCyan(pc3.black(" kitn add ")));
|
|
431
526
|
const cwd = process.cwd();
|
|
@@ -438,17 +533,26 @@ async function addCommand(components, opts) {
|
|
|
438
533
|
p2.log.error("Please specify at least one component to add.");
|
|
439
534
|
process.exit(1);
|
|
440
535
|
}
|
|
536
|
+
const resolvedComponents = components.map((c) => {
|
|
537
|
+
if (c === "routes") {
|
|
538
|
+
const fw = config.framework ?? "hono";
|
|
539
|
+
return fw;
|
|
540
|
+
}
|
|
541
|
+
return c;
|
|
542
|
+
});
|
|
543
|
+
const refs = resolvedComponents.map(parseComponentRef);
|
|
441
544
|
const fetcher = new RegistryFetcher(config.registries);
|
|
442
545
|
const s = p2.spinner();
|
|
443
546
|
s.start("Resolving dependencies...");
|
|
444
547
|
let resolved;
|
|
445
548
|
try {
|
|
446
|
-
resolved = await resolveDependencies(
|
|
447
|
-
const
|
|
549
|
+
resolved = await resolveDependencies(resolvedComponents, async (name) => {
|
|
550
|
+
const ref = refs.find((r) => r.name === name) ?? { namespace: "@kitn", name, version: void 0 };
|
|
551
|
+
const index = await fetcher.fetchIndex(ref.namespace);
|
|
448
552
|
const indexItem = index.items.find((i) => i.name === name);
|
|
449
|
-
if (!indexItem) throw new Error(`Component '${name}' not found in registry`);
|
|
553
|
+
if (!indexItem) throw new Error(`Component '${name}' not found in ${ref.namespace} registry`);
|
|
450
554
|
const dir = typeToDir[indexItem.type];
|
|
451
|
-
return fetcher.fetchItem(name, dir);
|
|
555
|
+
return fetcher.fetchItem(name, dir, ref.namespace, ref.version);
|
|
452
556
|
});
|
|
453
557
|
} catch (err) {
|
|
454
558
|
s.stop(pc3.red("Failed to resolve dependencies"));
|
|
@@ -458,7 +562,7 @@ async function addCommand(components, opts) {
|
|
|
458
562
|
s.stop(`Resolved ${resolved.length} component(s)`);
|
|
459
563
|
p2.log.info("Components to install:");
|
|
460
564
|
for (const item of resolved) {
|
|
461
|
-
const isExplicit = components.includes(item.name);
|
|
565
|
+
const isExplicit = resolvedComponents.includes(item.name) || components.includes(item.name);
|
|
462
566
|
const label = isExplicit ? item.name : `${item.name} ${pc3.dim("(dependency)")}`;
|
|
463
567
|
p2.log.message(` ${pc3.cyan(label)}`);
|
|
464
568
|
}
|
|
@@ -472,62 +576,68 @@ async function addCommand(components, opts) {
|
|
|
472
576
|
if (item.envVars) {
|
|
473
577
|
allEnvWarnings.push(...checkEnvVars(item.envVars));
|
|
474
578
|
}
|
|
475
|
-
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
case "
|
|
483
|
-
return "skills";
|
|
484
|
-
case "kitn:storage":
|
|
485
|
-
return "storage";
|
|
486
|
-
}
|
|
487
|
-
})();
|
|
488
|
-
const fileName = file.path.split("/").pop();
|
|
489
|
-
const targetPath = join3(cwd, config.aliases[aliasKey], fileName);
|
|
490
|
-
const relativePath = join3(config.aliases[aliasKey], fileName);
|
|
491
|
-
const status = await checkFileStatus(targetPath, file.content);
|
|
492
|
-
switch (status) {
|
|
493
|
-
case "new" /* New */:
|
|
494
|
-
await writeComponentFile(targetPath, file.content);
|
|
495
|
-
created.push(relativePath);
|
|
496
|
-
break;
|
|
497
|
-
case "identical" /* Identical */:
|
|
498
|
-
skipped.push(relativePath);
|
|
499
|
-
break;
|
|
500
|
-
case "different" /* Different */:
|
|
501
|
-
if (opts.overwrite) {
|
|
579
|
+
if (item.type === "kitn:package") {
|
|
580
|
+
const baseDir = config.aliases.base ?? "src/ai";
|
|
581
|
+
for (const file of item.files) {
|
|
582
|
+
const targetPath = join5(cwd, baseDir, file.path);
|
|
583
|
+
const relativePath = join5(baseDir, file.path);
|
|
584
|
+
const status = await checkFileStatus(targetPath, file.content);
|
|
585
|
+
switch (status) {
|
|
586
|
+
case "new" /* New */:
|
|
502
587
|
await writeComponentFile(targetPath, file.content);
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
options: [
|
|
511
|
-
{ value: "skip", label: "Keep local version" },
|
|
512
|
-
{ value: "overwrite", label: "Overwrite with registry version" }
|
|
513
|
-
]
|
|
514
|
-
});
|
|
515
|
-
if (!p2.isCancel(action) && action === "overwrite") {
|
|
588
|
+
created.push(relativePath);
|
|
589
|
+
break;
|
|
590
|
+
case "identical" /* Identical */:
|
|
591
|
+
skipped.push(relativePath);
|
|
592
|
+
break;
|
|
593
|
+
case "different" /* Different */:
|
|
594
|
+
if (opts.overwrite) {
|
|
516
595
|
await writeComponentFile(targetPath, file.content);
|
|
517
596
|
updated.push(relativePath);
|
|
518
597
|
} else {
|
|
519
|
-
|
|
598
|
+
const existing = await readExistingFile(targetPath);
|
|
599
|
+
const diff = generateDiff(relativePath, existing ?? "", file.content);
|
|
600
|
+
p2.log.message(pc3.dim(diff));
|
|
601
|
+
const action = await p2.select({
|
|
602
|
+
message: `${relativePath} already exists and differs. What to do?`,
|
|
603
|
+
options: [
|
|
604
|
+
{ value: "skip", label: "Keep local version" },
|
|
605
|
+
{ value: "overwrite", label: "Overwrite with registry version" }
|
|
606
|
+
]
|
|
607
|
+
});
|
|
608
|
+
if (!p2.isCancel(action) && action === "overwrite") {
|
|
609
|
+
await writeComponentFile(targetPath, file.content);
|
|
610
|
+
updated.push(relativePath);
|
|
611
|
+
} else {
|
|
612
|
+
skipped.push(relativePath);
|
|
613
|
+
}
|
|
520
614
|
}
|
|
521
|
-
|
|
522
|
-
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
523
617
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
618
|
+
if (item.tsconfig) {
|
|
619
|
+
const resolvedPaths = {};
|
|
620
|
+
const installDir = item.installDir ?? item.name;
|
|
621
|
+
for (const [key, values] of Object.entries(item.tsconfig)) {
|
|
622
|
+
resolvedPaths[key] = values.map((v) => `./${join5(baseDir, installDir, v)}`);
|
|
623
|
+
}
|
|
624
|
+
await patchProjectTsconfig(cwd, resolvedPaths);
|
|
625
|
+
p2.log.info(`Patched tsconfig.json with paths: ${Object.keys(resolvedPaths).join(", ")}`);
|
|
626
|
+
}
|
|
627
|
+
const installed = config.installed ?? {};
|
|
628
|
+
const allContent = item.files.map((f) => f.content).join("\n");
|
|
629
|
+
const ref = refs.find((r) => r.name === item.name) ?? { namespace: "@kitn", name: item.name, version: void 0 };
|
|
630
|
+
const installedKey = ref.namespace === "@kitn" ? item.name : `${ref.namespace}/${item.name}`;
|
|
631
|
+
installed[installedKey] = {
|
|
632
|
+
registry: ref.namespace,
|
|
633
|
+
version: item.version ?? "1.0.0",
|
|
634
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
635
|
+
files: item.files.map((f) => join5(baseDir, f.path)),
|
|
636
|
+
hash: contentHash(allContent)
|
|
637
|
+
};
|
|
638
|
+
config.installed = installed;
|
|
639
|
+
} else {
|
|
640
|
+
for (const file of item.files) {
|
|
531
641
|
const aliasKey = (() => {
|
|
532
642
|
switch (item.type) {
|
|
533
643
|
case "kitn:agent":
|
|
@@ -540,12 +650,75 @@ async function addCommand(components, opts) {
|
|
|
540
650
|
return "storage";
|
|
541
651
|
}
|
|
542
652
|
})();
|
|
543
|
-
const fileName =
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
653
|
+
const fileName = file.path.split("/").pop();
|
|
654
|
+
const targetPath = join5(cwd, config.aliases[aliasKey], fileName);
|
|
655
|
+
const relativePath = join5(config.aliases[aliasKey], fileName);
|
|
656
|
+
const content = rewriteKitnImports(file.content, item.type, fileName, config.aliases);
|
|
657
|
+
const status = await checkFileStatus(targetPath, content);
|
|
658
|
+
switch (status) {
|
|
659
|
+
case "new" /* New */:
|
|
660
|
+
await writeComponentFile(targetPath, content);
|
|
661
|
+
created.push(relativePath);
|
|
662
|
+
break;
|
|
663
|
+
case "identical" /* Identical */:
|
|
664
|
+
skipped.push(relativePath);
|
|
665
|
+
break;
|
|
666
|
+
case "different" /* Different */:
|
|
667
|
+
if (opts.overwrite) {
|
|
668
|
+
await writeComponentFile(targetPath, content);
|
|
669
|
+
updated.push(relativePath);
|
|
670
|
+
} else {
|
|
671
|
+
const existing = await readExistingFile(targetPath);
|
|
672
|
+
const diff = generateDiff(relativePath, existing ?? "", content);
|
|
673
|
+
p2.log.message(pc3.dim(diff));
|
|
674
|
+
const action = await p2.select({
|
|
675
|
+
message: `${relativePath} already exists and differs. What to do?`,
|
|
676
|
+
options: [
|
|
677
|
+
{ value: "skip", label: "Keep local version" },
|
|
678
|
+
{ value: "overwrite", label: "Overwrite with registry version" }
|
|
679
|
+
]
|
|
680
|
+
});
|
|
681
|
+
if (!p2.isCancel(action) && action === "overwrite") {
|
|
682
|
+
await writeComponentFile(targetPath, content);
|
|
683
|
+
updated.push(relativePath);
|
|
684
|
+
} else {
|
|
685
|
+
skipped.push(relativePath);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
const installed = config.installed ?? {};
|
|
692
|
+
const allContent = item.files.map((f) => {
|
|
693
|
+
const fn = f.path.split("/").pop();
|
|
694
|
+
return rewriteKitnImports(f.content, item.type, fn, config.aliases);
|
|
695
|
+
}).join("\n");
|
|
696
|
+
const ref = refs.find((r) => r.name === item.name) ?? { namespace: "@kitn", name: item.name, version: void 0 };
|
|
697
|
+
const installedKey = ref.namespace === "@kitn" ? item.name : `${ref.namespace}/${item.name}`;
|
|
698
|
+
installed[installedKey] = {
|
|
699
|
+
registry: ref.namespace,
|
|
700
|
+
version: item.version ?? "1.0.0",
|
|
701
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
702
|
+
files: item.files.map((f) => {
|
|
703
|
+
const aliasKey = (() => {
|
|
704
|
+
switch (item.type) {
|
|
705
|
+
case "kitn:agent":
|
|
706
|
+
return "agents";
|
|
707
|
+
case "kitn:tool":
|
|
708
|
+
return "tools";
|
|
709
|
+
case "kitn:skill":
|
|
710
|
+
return "skills";
|
|
711
|
+
case "kitn:storage":
|
|
712
|
+
return "storage";
|
|
713
|
+
}
|
|
714
|
+
})();
|
|
715
|
+
const fileName = f.path.split("/").pop();
|
|
716
|
+
return join5(config.aliases[aliasKey], fileName);
|
|
717
|
+
}),
|
|
718
|
+
hash: contentHash(allContent)
|
|
719
|
+
};
|
|
720
|
+
config.installed = installed;
|
|
721
|
+
}
|
|
549
722
|
}
|
|
550
723
|
await writeConfig(cwd, config);
|
|
551
724
|
const uniqueDeps = [...new Set(allDeps)];
|
|
@@ -594,7 +767,10 @@ var init_add = __esm({
|
|
|
594
767
|
init_file_writer();
|
|
595
768
|
init_dep_installer();
|
|
596
769
|
init_env_checker();
|
|
770
|
+
init_import_rewriter();
|
|
771
|
+
init_tsconfig_patcher();
|
|
597
772
|
init_hash();
|
|
773
|
+
init_parse_ref();
|
|
598
774
|
init_schema();
|
|
599
775
|
}
|
|
600
776
|
});
|
|
@@ -614,40 +790,70 @@ async function listCommand(opts) {
|
|
|
614
790
|
process.exit(1);
|
|
615
791
|
}
|
|
616
792
|
const fetcher = new RegistryFetcher(config.registries);
|
|
793
|
+
const namespacesToFetch = opts.registry ? [opts.registry] : Object.keys(config.registries);
|
|
794
|
+
if (opts.registry && !config.registries[opts.registry]) {
|
|
795
|
+
p3.log.error(`Registry ${pc4.bold(opts.registry)} is not configured. Run ${pc4.bold("kitn registry list")} to see configured registries.`);
|
|
796
|
+
process.exit(1);
|
|
797
|
+
}
|
|
617
798
|
const s = p3.spinner();
|
|
618
799
|
s.start("Fetching registry index...");
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
800
|
+
const allItems = [];
|
|
801
|
+
const errors = [];
|
|
802
|
+
for (const namespace of namespacesToFetch) {
|
|
803
|
+
try {
|
|
804
|
+
const index = await fetcher.fetchIndex(namespace);
|
|
805
|
+
for (const item of index.items) {
|
|
806
|
+
allItems.push({ ...item, namespace });
|
|
807
|
+
}
|
|
808
|
+
} catch (err) {
|
|
809
|
+
errors.push(`${namespace}: ${err.message}`);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
if (allItems.length === 0 && errors.length > 0) {
|
|
813
|
+
s.stop(pc4.red("Failed to fetch registries"));
|
|
814
|
+
for (const e of errors) p3.log.error(e);
|
|
625
815
|
process.exit(1);
|
|
626
816
|
}
|
|
627
|
-
s.stop(`Found ${
|
|
628
|
-
const
|
|
817
|
+
s.stop(`Found ${allItems.length} components across ${namespacesToFetch.length - errors.length} ${namespacesToFetch.length - errors.length === 1 ? "registry" : "registries"}`);
|
|
818
|
+
for (const e of errors) {
|
|
819
|
+
p3.log.warn(`${pc4.yellow("\u26A0")} Failed to fetch ${e}`);
|
|
820
|
+
}
|
|
821
|
+
const installed = config.installed ?? {};
|
|
629
822
|
const typeGroups = /* @__PURE__ */ new Map();
|
|
630
|
-
for (const item of
|
|
823
|
+
for (const item of allItems) {
|
|
631
824
|
if (opts.type && !item.type.endsWith(opts.type)) continue;
|
|
632
|
-
const
|
|
633
|
-
if (!typeGroups.has(
|
|
634
|
-
typeGroups.get(
|
|
825
|
+
const group = item.type.replace("kitn:", "");
|
|
826
|
+
if (!typeGroups.has(group)) typeGroups.set(group, []);
|
|
827
|
+
typeGroups.get(group).push(item);
|
|
635
828
|
}
|
|
636
|
-
|
|
829
|
+
let installedCount = 0;
|
|
830
|
+
let updateCount = 0;
|
|
831
|
+
for (const [group, items] of typeGroups) {
|
|
637
832
|
p3.log.message(pc4.bold(`
|
|
638
|
-
${
|
|
833
|
+
${group.charAt(0).toUpperCase() + group.slice(1)}s:`));
|
|
639
834
|
for (const item of items) {
|
|
640
|
-
const
|
|
835
|
+
const displayName = item.namespace === "@kitn" ? item.name : `${item.namespace}/${item.name}`;
|
|
836
|
+
const inst = installed[item.name] ?? installed[displayName];
|
|
641
837
|
if (opts.installed && !inst) continue;
|
|
838
|
+
const version = pc4.dim(`v${item.version ?? "1.0.0"}`);
|
|
642
839
|
if (inst) {
|
|
840
|
+
installedCount++;
|
|
643
841
|
const status = pc4.green("\u2713");
|
|
644
|
-
|
|
842
|
+
const hasUpdate = item.version && inst.version !== item.version;
|
|
843
|
+
const updateTag = hasUpdate ? pc4.yellow(` \u2B06 v${item.version} available`) : "";
|
|
844
|
+
if (hasUpdate) updateCount++;
|
|
845
|
+
p3.log.message(` ${status} ${displayName.padEnd(20)} ${version} ${pc4.dim(item.description)}${updateTag}`);
|
|
645
846
|
} else {
|
|
646
847
|
const status = pc4.dim("\u25CB");
|
|
647
|
-
p3.log.message(` ${status} ${
|
|
848
|
+
p3.log.message(` ${status} ${displayName.padEnd(20)} ${version} ${pc4.dim(item.description)}`);
|
|
648
849
|
}
|
|
649
850
|
}
|
|
650
851
|
}
|
|
852
|
+
const availableCount = allItems.length - installedCount;
|
|
853
|
+
const parts = [`${installedCount} installed`, `${availableCount} available`];
|
|
854
|
+
if (updateCount > 0) parts.push(`${updateCount} update${updateCount === 1 ? "" : "s"} available`);
|
|
855
|
+
p3.log.message("");
|
|
856
|
+
p3.log.message(pc4.dim(` ${parts.join(", ")}`));
|
|
651
857
|
}
|
|
652
858
|
var init_list = __esm({
|
|
653
859
|
"src/commands/list.ts"() {
|
|
@@ -663,7 +869,7 @@ __export(diff_exports, {
|
|
|
663
869
|
diffCommand: () => diffCommand
|
|
664
870
|
});
|
|
665
871
|
import * as p4 from "@clack/prompts";
|
|
666
|
-
import { join as
|
|
872
|
+
import { join as join6 } from "path";
|
|
667
873
|
async function diffCommand(componentName) {
|
|
668
874
|
const cwd = process.cwd();
|
|
669
875
|
const config = await readConfig(cwd);
|
|
@@ -671,48 +877,67 @@ async function diffCommand(componentName) {
|
|
|
671
877
|
p4.log.error("No kitn.json found. Run `kitn init` first.");
|
|
672
878
|
process.exit(1);
|
|
673
879
|
}
|
|
674
|
-
const
|
|
880
|
+
const input = componentName === "routes" ? config.framework ?? "hono" : componentName;
|
|
881
|
+
const ref = parseComponentRef(input);
|
|
882
|
+
const installedKey = ref.namespace === "@kitn" ? ref.name : `${ref.namespace}/${ref.name}`;
|
|
883
|
+
const installed = config.installed?.[installedKey];
|
|
675
884
|
if (!installed) {
|
|
676
|
-
p4.log.error(`Component '${
|
|
885
|
+
p4.log.error(`Component '${ref.name}' is not installed.`);
|
|
677
886
|
process.exit(1);
|
|
678
887
|
}
|
|
888
|
+
const namespace = installed.registry ?? ref.namespace;
|
|
679
889
|
const fetcher = new RegistryFetcher(config.registries);
|
|
680
|
-
const index = await fetcher.fetchIndex();
|
|
681
|
-
const indexItem = index.items.find((i) => i.name ===
|
|
890
|
+
const index = await fetcher.fetchIndex(namespace);
|
|
891
|
+
const indexItem = index.items.find((i) => i.name === ref.name);
|
|
682
892
|
if (!indexItem) {
|
|
683
|
-
p4.log.error(`Component '${
|
|
893
|
+
p4.log.error(`Component '${ref.name}' not found in ${namespace} registry.`);
|
|
684
894
|
process.exit(1);
|
|
685
895
|
}
|
|
686
896
|
const dir = typeToDir[indexItem.type];
|
|
687
|
-
const registryItem = await fetcher.fetchItem(
|
|
897
|
+
const registryItem = await fetcher.fetchItem(ref.name, dir, namespace, ref.version);
|
|
688
898
|
let hasDiff = false;
|
|
689
899
|
for (const file of registryItem.files) {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
900
|
+
if (indexItem.type === "kitn:package") {
|
|
901
|
+
const baseDir = config.aliases.base ?? "src/ai";
|
|
902
|
+
const localPath = join6(cwd, baseDir, file.path);
|
|
903
|
+
const relativePath = join6(baseDir, file.path);
|
|
904
|
+
const localContent = await readExistingFile(localPath);
|
|
905
|
+
if (localContent === null) {
|
|
906
|
+
p4.log.warn(`${relativePath}: file missing locally`);
|
|
907
|
+
hasDiff = true;
|
|
908
|
+
} else if (localContent !== file.content) {
|
|
909
|
+
const diff = generateDiff(relativePath, localContent, file.content);
|
|
910
|
+
console.log(diff);
|
|
911
|
+
hasDiff = true;
|
|
912
|
+
}
|
|
913
|
+
} else {
|
|
914
|
+
const fileName = file.path.split("/").pop();
|
|
915
|
+
const aliasKey = (() => {
|
|
916
|
+
switch (indexItem.type) {
|
|
917
|
+
case "kitn:agent":
|
|
918
|
+
return "agents";
|
|
919
|
+
case "kitn:tool":
|
|
920
|
+
return "tools";
|
|
921
|
+
case "kitn:skill":
|
|
922
|
+
return "skills";
|
|
923
|
+
case "kitn:storage":
|
|
924
|
+
return "storage";
|
|
925
|
+
}
|
|
926
|
+
})();
|
|
927
|
+
const localPath = join6(cwd, config.aliases[aliasKey], fileName);
|
|
928
|
+
const localContent = await readExistingFile(localPath);
|
|
929
|
+
if (localContent === null) {
|
|
930
|
+
p4.log.warn(`${fileName}: file missing locally`);
|
|
931
|
+
hasDiff = true;
|
|
932
|
+
} else if (localContent !== file.content) {
|
|
933
|
+
const diff = generateDiff(fileName, localContent, file.content);
|
|
934
|
+
console.log(diff);
|
|
935
|
+
hasDiff = true;
|
|
701
936
|
}
|
|
702
|
-
})();
|
|
703
|
-
const localPath = join4(cwd, config.aliases[aliasKey], fileName);
|
|
704
|
-
const localContent = await readExistingFile(localPath);
|
|
705
|
-
if (localContent === null) {
|
|
706
|
-
p4.log.warn(`${fileName}: file missing locally`);
|
|
707
|
-
hasDiff = true;
|
|
708
|
-
} else if (localContent !== file.content) {
|
|
709
|
-
const diff = generateDiff(fileName, localContent, file.content);
|
|
710
|
-
console.log(diff);
|
|
711
|
-
hasDiff = true;
|
|
712
937
|
}
|
|
713
938
|
}
|
|
714
939
|
if (!hasDiff) {
|
|
715
|
-
p4.log.success(`${
|
|
940
|
+
p4.log.success(`${ref.name}: up to date, no differences.`);
|
|
716
941
|
}
|
|
717
942
|
}
|
|
718
943
|
var init_diff = __esm({
|
|
@@ -721,6 +946,7 @@ var init_diff = __esm({
|
|
|
721
946
|
init_config();
|
|
722
947
|
init_fetcher();
|
|
723
948
|
init_file_writer();
|
|
949
|
+
init_parse_ref();
|
|
724
950
|
init_schema();
|
|
725
951
|
}
|
|
726
952
|
});
|
|
@@ -732,7 +958,7 @@ __export(remove_exports, {
|
|
|
732
958
|
});
|
|
733
959
|
import * as p5 from "@clack/prompts";
|
|
734
960
|
import pc5 from "picocolors";
|
|
735
|
-
import { join as
|
|
961
|
+
import { join as join7 } from "path";
|
|
736
962
|
import { unlink } from "fs/promises";
|
|
737
963
|
async function removeCommand(componentName) {
|
|
738
964
|
const cwd = process.cwd();
|
|
@@ -741,13 +967,16 @@ async function removeCommand(componentName) {
|
|
|
741
967
|
p5.log.error("No kitn.json found. Run `kitn init` first.");
|
|
742
968
|
process.exit(1);
|
|
743
969
|
}
|
|
744
|
-
const
|
|
970
|
+
const input = componentName === "routes" ? config.framework ?? "hono" : componentName;
|
|
971
|
+
const ref = parseComponentRef(input);
|
|
972
|
+
const installedKey = ref.namespace === "@kitn" ? ref.name : `${ref.namespace}/${ref.name}`;
|
|
973
|
+
const installed = config.installed?.[installedKey];
|
|
745
974
|
if (!installed) {
|
|
746
|
-
p5.log.error(`Component '${
|
|
975
|
+
p5.log.error(`Component '${ref.name}' is not installed.`);
|
|
747
976
|
process.exit(1);
|
|
748
977
|
}
|
|
749
978
|
const shouldRemove = await p5.confirm({
|
|
750
|
-
message: `Remove ${
|
|
979
|
+
message: `Remove ${ref.name}? This will delete ${installed.files.length} file(s).`,
|
|
751
980
|
initialValue: false
|
|
752
981
|
});
|
|
753
982
|
if (p5.isCancel(shouldRemove) || !shouldRemove) {
|
|
@@ -757,19 +986,19 @@ async function removeCommand(componentName) {
|
|
|
757
986
|
const deleted = [];
|
|
758
987
|
for (const filePath of installed.files) {
|
|
759
988
|
try {
|
|
760
|
-
await unlink(
|
|
989
|
+
await unlink(join7(cwd, filePath));
|
|
761
990
|
deleted.push(filePath);
|
|
762
991
|
} catch {
|
|
763
992
|
p5.log.warn(`Could not delete ${filePath} (may have been moved or renamed)`);
|
|
764
993
|
}
|
|
765
994
|
}
|
|
766
|
-
delete config.
|
|
767
|
-
if (Object.keys(config.
|
|
768
|
-
delete config.
|
|
995
|
+
delete config.installed[installedKey];
|
|
996
|
+
if (Object.keys(config.installed).length === 0) {
|
|
997
|
+
delete config.installed;
|
|
769
998
|
}
|
|
770
999
|
await writeConfig(cwd, config);
|
|
771
1000
|
if (deleted.length > 0) {
|
|
772
|
-
p5.log.success(`Removed ${
|
|
1001
|
+
p5.log.success(`Removed ${ref.name}:`);
|
|
773
1002
|
for (const f of deleted) p5.log.message(` ${pc5.red("-")} ${f}`);
|
|
774
1003
|
}
|
|
775
1004
|
}
|
|
@@ -777,6 +1006,7 @@ var init_remove = __esm({
|
|
|
777
1006
|
"src/commands/remove.ts"() {
|
|
778
1007
|
"use strict";
|
|
779
1008
|
init_config();
|
|
1009
|
+
init_parse_ref();
|
|
780
1010
|
}
|
|
781
1011
|
});
|
|
782
1012
|
|
|
@@ -785,13 +1015,226 @@ var update_exports = {};
|
|
|
785
1015
|
__export(update_exports, {
|
|
786
1016
|
updateCommand: () => updateCommand
|
|
787
1017
|
});
|
|
1018
|
+
import * as p6 from "@clack/prompts";
|
|
788
1019
|
async function updateCommand(components) {
|
|
1020
|
+
if (components.length === 0) {
|
|
1021
|
+
const cwd = process.cwd();
|
|
1022
|
+
const config = await readConfig(cwd);
|
|
1023
|
+
if (!config) {
|
|
1024
|
+
p6.log.error("No kitn.json found. Run `kitn init` first.");
|
|
1025
|
+
process.exit(1);
|
|
1026
|
+
}
|
|
1027
|
+
const installed = config.installed;
|
|
1028
|
+
if (!installed || Object.keys(installed).length === 0) {
|
|
1029
|
+
p6.log.info("No installed components to update.");
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
components = Object.keys(installed);
|
|
1033
|
+
}
|
|
789
1034
|
await addCommand(components, { overwrite: true });
|
|
790
1035
|
}
|
|
791
1036
|
var init_update = __esm({
|
|
792
1037
|
"src/commands/update.ts"() {
|
|
793
1038
|
"use strict";
|
|
794
1039
|
init_add();
|
|
1040
|
+
init_config();
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
// src/commands/info.ts
|
|
1045
|
+
var info_exports = {};
|
|
1046
|
+
__export(info_exports, {
|
|
1047
|
+
infoCommand: () => infoCommand
|
|
1048
|
+
});
|
|
1049
|
+
import * as p7 from "@clack/prompts";
|
|
1050
|
+
import pc6 from "picocolors";
|
|
1051
|
+
async function infoCommand(component) {
|
|
1052
|
+
const cwd = process.cwd();
|
|
1053
|
+
const config = await readConfig(cwd);
|
|
1054
|
+
if (!config) {
|
|
1055
|
+
p7.log.error("No kitn.json found. Run `kitn init` first.");
|
|
1056
|
+
process.exit(1);
|
|
1057
|
+
}
|
|
1058
|
+
const ref = parseComponentRef(component);
|
|
1059
|
+
const fetcher = new RegistryFetcher(config.registries);
|
|
1060
|
+
const s = p7.spinner();
|
|
1061
|
+
s.start("Fetching component info...");
|
|
1062
|
+
let index;
|
|
1063
|
+
try {
|
|
1064
|
+
index = await fetcher.fetchIndex(ref.namespace);
|
|
1065
|
+
} catch (err) {
|
|
1066
|
+
s.stop(pc6.red("Failed to fetch registry"));
|
|
1067
|
+
p7.log.error(err.message);
|
|
1068
|
+
process.exit(1);
|
|
1069
|
+
}
|
|
1070
|
+
const indexItem = index.items.find((i) => i.name === ref.name);
|
|
1071
|
+
if (!indexItem) {
|
|
1072
|
+
s.stop(pc6.red("Component not found"));
|
|
1073
|
+
p7.log.error(`Component '${ref.name}' not found in registry.`);
|
|
1074
|
+
process.exit(1);
|
|
1075
|
+
}
|
|
1076
|
+
const dir = typeToDir[indexItem.type];
|
|
1077
|
+
let item;
|
|
1078
|
+
try {
|
|
1079
|
+
item = await fetcher.fetchItem(ref.name, dir, ref.namespace, ref.version);
|
|
1080
|
+
} catch (err) {
|
|
1081
|
+
s.stop(pc6.red("Failed to fetch component"));
|
|
1082
|
+
p7.log.error(err.message);
|
|
1083
|
+
process.exit(1);
|
|
1084
|
+
}
|
|
1085
|
+
s.stop("Component found");
|
|
1086
|
+
const version = item.version ?? indexItem.version ?? "unknown";
|
|
1087
|
+
const typeName = indexItem.type.replace("kitn:", "");
|
|
1088
|
+
console.log();
|
|
1089
|
+
console.log(
|
|
1090
|
+
` ${pc6.bold(item.name)} ${pc6.cyan(`v${version}`)}${" ".repeat(Math.max(1, 40 - item.name.length - version.length - 2))}${pc6.dim(ref.namespace)}`
|
|
1091
|
+
);
|
|
1092
|
+
console.log(` ${pc6.dim(item.description)}`);
|
|
1093
|
+
console.log();
|
|
1094
|
+
console.log(` ${pc6.dim("Type:")} ${typeName}`);
|
|
1095
|
+
if (item.dependencies?.length) {
|
|
1096
|
+
console.log(
|
|
1097
|
+
` ${pc6.dim("Dependencies:")} ${item.dependencies.join(", ")}`
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1100
|
+
if (item.registryDependencies?.length) {
|
|
1101
|
+
console.log(
|
|
1102
|
+
` ${pc6.dim("Registry deps:")} ${item.registryDependencies.join(", ")}`
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
if (item.categories?.length) {
|
|
1106
|
+
console.log(
|
|
1107
|
+
` ${pc6.dim("Categories:")} ${item.categories.join(", ")}`
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
if (item.updatedAt) {
|
|
1111
|
+
console.log(` ${pc6.dim("Updated:")} ${item.updatedAt}`);
|
|
1112
|
+
}
|
|
1113
|
+
const versions = indexItem.versions;
|
|
1114
|
+
if (versions?.length) {
|
|
1115
|
+
console.log(` ${pc6.dim("Versions:")} ${versions.join(", ")}`);
|
|
1116
|
+
}
|
|
1117
|
+
if (item.changelog?.length) {
|
|
1118
|
+
console.log();
|
|
1119
|
+
console.log(` ${pc6.bold("Changelog:")}`);
|
|
1120
|
+
for (const entry of item.changelog) {
|
|
1121
|
+
const tag = entry.type === "feature" ? pc6.green(entry.type) : entry.type === "fix" ? pc6.yellow(entry.type) : entry.type === "breaking" ? pc6.red(entry.type) : pc6.dim(entry.type);
|
|
1122
|
+
console.log(
|
|
1123
|
+
` ${pc6.cyan(entry.version)} ${pc6.dim(entry.date)} ${tag} ${entry.note}`
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
console.log();
|
|
1128
|
+
const fileCount = item.files.length;
|
|
1129
|
+
console.log(` ${pc6.bold(`Files:`)} ${pc6.dim(`(${fileCount})`)}`);
|
|
1130
|
+
const maxShown = 10;
|
|
1131
|
+
for (const file of item.files.slice(0, maxShown)) {
|
|
1132
|
+
console.log(` ${pc6.dim(file.path)}`);
|
|
1133
|
+
}
|
|
1134
|
+
if (fileCount > maxShown) {
|
|
1135
|
+
console.log(` ${pc6.dim(`... and ${fileCount - maxShown} more`)}`);
|
|
1136
|
+
}
|
|
1137
|
+
const installed = config.installed?.[item.name];
|
|
1138
|
+
if (installed) {
|
|
1139
|
+
console.log();
|
|
1140
|
+
console.log(
|
|
1141
|
+
` ${pc6.green("Installed")} ${pc6.dim(`v${installed.version}`)}`
|
|
1142
|
+
);
|
|
1143
|
+
if (version !== installed.version) {
|
|
1144
|
+
console.log(
|
|
1145
|
+
` ${pc6.yellow("Update available:")} ${pc6.dim(`v${installed.version}`)} \u2192 ${pc6.cyan(`v${version}`)}`
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
console.log();
|
|
1150
|
+
}
|
|
1151
|
+
var init_info = __esm({
|
|
1152
|
+
"src/commands/info.ts"() {
|
|
1153
|
+
"use strict";
|
|
1154
|
+
init_config();
|
|
1155
|
+
init_parse_ref();
|
|
1156
|
+
init_fetcher();
|
|
1157
|
+
init_schema();
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
// src/commands/registry.ts
|
|
1162
|
+
var registry_exports = {};
|
|
1163
|
+
__export(registry_exports, {
|
|
1164
|
+
registryAddCommand: () => registryAddCommand,
|
|
1165
|
+
registryListCommand: () => registryListCommand,
|
|
1166
|
+
registryRemoveCommand: () => registryRemoveCommand
|
|
1167
|
+
});
|
|
1168
|
+
import * as p8 from "@clack/prompts";
|
|
1169
|
+
import pc7 from "picocolors";
|
|
1170
|
+
async function registryAddCommand(namespace, url, opts = {}) {
|
|
1171
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
1172
|
+
const config = await readConfig(cwd);
|
|
1173
|
+
if (!config) throw new Error("No kitn.json found. Run `kitn init` first.");
|
|
1174
|
+
if (!namespace.startsWith("@")) {
|
|
1175
|
+
throw new Error("Namespace must start with @ (e.g. @myteam)");
|
|
1176
|
+
}
|
|
1177
|
+
if (!url.includes("{type}")) {
|
|
1178
|
+
throw new Error("URL template must include {type} placeholder");
|
|
1179
|
+
}
|
|
1180
|
+
if (!url.includes("{name}")) {
|
|
1181
|
+
throw new Error("URL template must include {name} placeholder");
|
|
1182
|
+
}
|
|
1183
|
+
if (config.registries[namespace] && !opts.overwrite) {
|
|
1184
|
+
throw new Error(`Registry '${namespace}' is already configured. Use --overwrite to replace.`);
|
|
1185
|
+
}
|
|
1186
|
+
config.registries[namespace] = url;
|
|
1187
|
+
await writeConfig(cwd, config);
|
|
1188
|
+
p8.log.success(`Added registry ${pc7.bold(namespace)}`);
|
|
1189
|
+
p8.log.message(pc7.dim(` ${url}`));
|
|
1190
|
+
}
|
|
1191
|
+
async function registryRemoveCommand(namespace, opts = {}) {
|
|
1192
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
1193
|
+
const config = await readConfig(cwd);
|
|
1194
|
+
if (!config) throw new Error("No kitn.json found. Run `kitn init` first.");
|
|
1195
|
+
if (!config.registries[namespace]) {
|
|
1196
|
+
throw new Error(`Registry '${namespace}' is not configured.`);
|
|
1197
|
+
}
|
|
1198
|
+
if (namespace === "@kitn" && !opts.force) {
|
|
1199
|
+
throw new Error("Cannot remove the default @kitn registry. Use --force to override.");
|
|
1200
|
+
}
|
|
1201
|
+
const affectedComponents = [];
|
|
1202
|
+
if (config.installed) {
|
|
1203
|
+
for (const [name, entry] of Object.entries(config.installed)) {
|
|
1204
|
+
if (entry.registry === namespace) {
|
|
1205
|
+
affectedComponents.push(name);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
delete config.registries[namespace];
|
|
1210
|
+
await writeConfig(cwd, config);
|
|
1211
|
+
p8.log.success(`Removed registry ${pc7.bold(namespace)}`);
|
|
1212
|
+
if (affectedComponents.length > 0) {
|
|
1213
|
+
p8.log.warn(`${affectedComponents.length} installed component(s) referenced this registry:`);
|
|
1214
|
+
for (const name of affectedComponents) {
|
|
1215
|
+
p8.log.message(` ${pc7.yellow("!")} ${name}`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
return { affectedComponents };
|
|
1219
|
+
}
|
|
1220
|
+
async function registryListCommand(opts = {}) {
|
|
1221
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
1222
|
+
const config = await readConfig(cwd);
|
|
1223
|
+
if (!config) throw new Error("No kitn.json found. Run `kitn init` first.");
|
|
1224
|
+
const entries = Object.entries(config.registries).map(([namespace, url]) => ({ namespace, url }));
|
|
1225
|
+
if (entries.length === 0) {
|
|
1226
|
+
p8.log.message(pc7.dim(" No registries configured."));
|
|
1227
|
+
} else {
|
|
1228
|
+
for (const { namespace, url } of entries) {
|
|
1229
|
+
p8.log.message(` ${pc7.bold(namespace.padEnd(16))} ${pc7.dim(url)}`);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
return entries;
|
|
1233
|
+
}
|
|
1234
|
+
var init_registry = __esm({
|
|
1235
|
+
"src/commands/registry.ts"() {
|
|
1236
|
+
"use strict";
|
|
1237
|
+
init_config();
|
|
795
1238
|
}
|
|
796
1239
|
});
|
|
797
1240
|
|
|
@@ -806,7 +1249,7 @@ program.command("add").description("Add components from the kitn registry").argu
|
|
|
806
1249
|
const { addCommand: addCommand2 } = await Promise.resolve().then(() => (init_add(), add_exports));
|
|
807
1250
|
await addCommand2(components, opts);
|
|
808
1251
|
});
|
|
809
|
-
program.command("list").description("List available and installed components").option("-i, --installed", "only show installed components").option("-t, --type <type>", "filter by type (agent, tool, skill, storage)").action(async (opts) => {
|
|
1252
|
+
program.command("list").description("List available and installed components").option("-i, --installed", "only show installed components").option("-t, --type <type>", "filter by type (agent, tool, skill, storage, package)").option("-r, --registry <namespace>", "only show components from this registry").action(async (opts) => {
|
|
810
1253
|
const { listCommand: listCommand2 } = await Promise.resolve().then(() => (init_list(), list_exports));
|
|
811
1254
|
await listCommand2(opts);
|
|
812
1255
|
});
|
|
@@ -822,5 +1265,22 @@ program.command("update").description("Update installed components to latest reg
|
|
|
822
1265
|
const { updateCommand: updateCommand2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
823
1266
|
await updateCommand2(components);
|
|
824
1267
|
});
|
|
1268
|
+
program.command("info").description("Show details about a component").argument("<component>", "component name (e.g. weather-agent, @acme/tool@1.0.0)").action(async (component) => {
|
|
1269
|
+
const { infoCommand: infoCommand2 } = await Promise.resolve().then(() => (init_info(), info_exports));
|
|
1270
|
+
await infoCommand2(component);
|
|
1271
|
+
});
|
|
1272
|
+
var registry = program.command("registry").description("Manage component registries");
|
|
1273
|
+
registry.command("add").description("Add a component registry").argument("<namespace>", "registry namespace (e.g. @myteam)").argument("<url>", "URL template with {type} and {name} placeholders").option("-o, --overwrite", "overwrite if namespace already exists").action(async (namespace, url, opts) => {
|
|
1274
|
+
const { registryAddCommand: registryAddCommand2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
1275
|
+
await registryAddCommand2(namespace, url, opts);
|
|
1276
|
+
});
|
|
1277
|
+
registry.command("remove").description("Remove a component registry").argument("<namespace>", "registry namespace to remove (e.g. @myteam)").option("-f, --force", "allow removing the default @kitn registry").action(async (namespace, opts) => {
|
|
1278
|
+
const { registryRemoveCommand: registryRemoveCommand2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
1279
|
+
await registryRemoveCommand2(namespace, opts);
|
|
1280
|
+
});
|
|
1281
|
+
registry.command("list").description("List all configured registries").action(async () => {
|
|
1282
|
+
const { registryListCommand: registryListCommand2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
1283
|
+
await registryListCommand2();
|
|
1284
|
+
});
|
|
825
1285
|
program.parse();
|
|
826
1286
|
//# sourceMappingURL=index.js.map
|