@kitnai/cli 0.1.22 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +438 -106
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,9 +9,72 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/utils/detect.ts
|
|
13
|
+
import { access } from "fs/promises";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
async function detectPackageManager(dir) {
|
|
16
|
+
for (const [lockfile, pm] of LOCKFILE_MAP) {
|
|
17
|
+
try {
|
|
18
|
+
await access(join(dir, lockfile));
|
|
19
|
+
return pm;
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function getRunCommand(pm) {
|
|
26
|
+
switch (pm) {
|
|
27
|
+
case "bun":
|
|
28
|
+
return "bunx";
|
|
29
|
+
case "pnpm":
|
|
30
|
+
return "pnpm dlx";
|
|
31
|
+
case "yarn":
|
|
32
|
+
return "yarn dlx";
|
|
33
|
+
case "npm":
|
|
34
|
+
return "npx";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function detectCliInstaller() {
|
|
38
|
+
const userAgent = process.env.npm_config_user_agent ?? "";
|
|
39
|
+
if (userAgent.startsWith("bun/")) return "bun";
|
|
40
|
+
if (userAgent.startsWith("pnpm/")) return "pnpm";
|
|
41
|
+
if (userAgent.startsWith("yarn/")) return "yarn";
|
|
42
|
+
if (userAgent.startsWith("npm/")) return "npm";
|
|
43
|
+
const invoker = process.env._ ?? "";
|
|
44
|
+
if (invoker.includes("bun")) return "bun";
|
|
45
|
+
if (invoker.includes("pnpm")) return "pnpm";
|
|
46
|
+
if (invoker.includes("yarn")) return "yarn";
|
|
47
|
+
return "npm";
|
|
48
|
+
}
|
|
49
|
+
function getGlobalInstallCommand(pm, pkg) {
|
|
50
|
+
switch (pm) {
|
|
51
|
+
case "bun":
|
|
52
|
+
return `bun install -g ${pkg}`;
|
|
53
|
+
case "pnpm":
|
|
54
|
+
return `pnpm add -g ${pkg}`;
|
|
55
|
+
case "yarn":
|
|
56
|
+
return `yarn global add ${pkg}`;
|
|
57
|
+
case "npm":
|
|
58
|
+
return `npm install -g ${pkg}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
var LOCKFILE_MAP;
|
|
62
|
+
var init_detect = __esm({
|
|
63
|
+
"src/utils/detect.ts"() {
|
|
64
|
+
"use strict";
|
|
65
|
+
LOCKFILE_MAP = [
|
|
66
|
+
["bun.lock", "bun"],
|
|
67
|
+
["bun.lockb", "bun"],
|
|
68
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
69
|
+
["yarn.lock", "yarn"],
|
|
70
|
+
["package-lock.json", "npm"]
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
12
75
|
// src/utils/update-check.ts
|
|
13
76
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
14
|
-
import { join } from "path";
|
|
77
|
+
import { join as join2 } from "path";
|
|
15
78
|
import { homedir } from "os";
|
|
16
79
|
import pc from "picocolors";
|
|
17
80
|
async function readCache() {
|
|
@@ -65,10 +128,13 @@ function startUpdateCheck(currentVersion) {
|
|
|
65
128
|
}
|
|
66
129
|
}
|
|
67
130
|
if (latest && isNewer(latest, currentVersion)) {
|
|
131
|
+
const pm = detectCliInstaller();
|
|
132
|
+
const runCmd = `${getRunCommand(pm)} @kitnai/cli@latest`;
|
|
133
|
+
const installCmd = getGlobalInstallCommand(pm, "@kitnai/cli");
|
|
68
134
|
message = [
|
|
69
135
|
"",
|
|
70
136
|
pc.yellow(` Update available: ${pc.dim(currentVersion)} \u2192 ${pc.green(latest)}`),
|
|
71
|
-
pc.dim(` Run ${pc.cyan(
|
|
137
|
+
pc.dim(` Run ${pc.cyan(runCmd)} or ${pc.cyan(installCmd)}`),
|
|
72
138
|
""
|
|
73
139
|
].join("\n");
|
|
74
140
|
}
|
|
@@ -83,15 +149,16 @@ var CACHE_DIR, CACHE_FILE, CHECK_INTERVAL;
|
|
|
83
149
|
var init_update_check = __esm({
|
|
84
150
|
"src/utils/update-check.ts"() {
|
|
85
151
|
"use strict";
|
|
86
|
-
|
|
87
|
-
|
|
152
|
+
init_detect();
|
|
153
|
+
CACHE_DIR = join2(homedir(), ".kitn");
|
|
154
|
+
CACHE_FILE = join2(CACHE_DIR, "update-check.json");
|
|
88
155
|
CHECK_INTERVAL = 60 * 60 * 1e3;
|
|
89
156
|
}
|
|
90
157
|
});
|
|
91
158
|
|
|
92
159
|
// src/utils/config.ts
|
|
93
160
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
94
|
-
import { join as
|
|
161
|
+
import { join as join3 } from "path";
|
|
95
162
|
import { z } from "zod";
|
|
96
163
|
function getRegistryUrl(entry) {
|
|
97
164
|
return typeof entry === "string" ? entry : entry.url;
|
|
@@ -102,7 +169,7 @@ function resolveRoutesAlias(config) {
|
|
|
102
169
|
}
|
|
103
170
|
async function readConfig(projectDir) {
|
|
104
171
|
try {
|
|
105
|
-
const raw = await readFile2(
|
|
172
|
+
const raw = await readFile2(join3(projectDir, CONFIG_FILE), "utf-8");
|
|
106
173
|
return configSchema.parse(JSON.parse(raw));
|
|
107
174
|
} catch {
|
|
108
175
|
return null;
|
|
@@ -110,16 +177,16 @@ async function readConfig(projectDir) {
|
|
|
110
177
|
}
|
|
111
178
|
async function writeConfig(projectDir, config) {
|
|
112
179
|
const data = { $schema: "https://kitn.dev/schema/config.json", ...config };
|
|
113
|
-
await writeFile2(
|
|
180
|
+
await writeFile2(join3(projectDir, CONFIG_FILE), JSON.stringify(data, null, 2) + "\n");
|
|
114
181
|
}
|
|
115
182
|
function getInstallPath(config, type, fileName, namespace) {
|
|
116
183
|
const aliasKey = typeToAliasKey[type];
|
|
117
184
|
const base = config.aliases[aliasKey];
|
|
118
185
|
if (namespace && namespace !== "@kitn") {
|
|
119
186
|
const nsDir = namespace.replace("@", "");
|
|
120
|
-
return
|
|
187
|
+
return join3(base, nsDir, fileName);
|
|
121
188
|
}
|
|
122
|
-
return
|
|
189
|
+
return join3(base, fileName);
|
|
123
190
|
}
|
|
124
191
|
var componentType, installedComponentSchema, registryEntrySchema, registryValueSchema, configSchema, FRAMEWORK_TO_ADAPTER, CONFIG_FILE, typeToAliasKey;
|
|
125
192
|
var init_config = __esm({
|
|
@@ -128,10 +195,13 @@ var init_config = __esm({
|
|
|
128
195
|
componentType = z.enum(["kitn:agent", "kitn:tool", "kitn:skill", "kitn:storage", "kitn:package"]);
|
|
129
196
|
installedComponentSchema = z.object({
|
|
130
197
|
registry: z.string().optional(),
|
|
198
|
+
type: componentType,
|
|
199
|
+
slot: z.string().optional(),
|
|
131
200
|
version: z.string(),
|
|
132
201
|
installedAt: z.string(),
|
|
133
202
|
files: z.array(z.string()),
|
|
134
|
-
hash: z.string()
|
|
203
|
+
hash: z.string(),
|
|
204
|
+
registryDependencies: z.array(z.string()).optional()
|
|
135
205
|
});
|
|
136
206
|
registryEntrySchema = z.object({
|
|
137
207
|
url: z.string(),
|
|
@@ -142,7 +212,7 @@ var init_config = __esm({
|
|
|
142
212
|
configSchema = z.object({
|
|
143
213
|
$schema: z.string().optional(),
|
|
144
214
|
runtime: z.enum(["bun", "node", "deno"]),
|
|
145
|
-
framework: z.enum(["hono", "cloudflare", "elysia", "fastify", "express"]).optional(),
|
|
215
|
+
framework: z.enum(["hono", "hono-openapi", "cloudflare", "elysia", "fastify", "express"]).optional(),
|
|
146
216
|
aliases: z.object({
|
|
147
217
|
base: z.string().optional(),
|
|
148
218
|
agents: z.string(),
|
|
@@ -155,6 +225,7 @@ var init_config = __esm({
|
|
|
155
225
|
});
|
|
156
226
|
FRAMEWORK_TO_ADAPTER = {
|
|
157
227
|
hono: "hono",
|
|
228
|
+
"hono-openapi": "hono-openapi",
|
|
158
229
|
elysia: "elysia"
|
|
159
230
|
};
|
|
160
231
|
CONFIG_FILE = "kitn.json";
|
|
@@ -169,7 +240,7 @@ var init_config = __esm({
|
|
|
169
240
|
|
|
170
241
|
// src/installers/tsconfig-patcher.ts
|
|
171
242
|
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
172
|
-
import { join as
|
|
243
|
+
import { join as join4 } from "path";
|
|
173
244
|
function stripJsonc(text3) {
|
|
174
245
|
return text3.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([}\]])/g, "$1");
|
|
175
246
|
}
|
|
@@ -208,7 +279,7 @@ function patchTsconfig(tsconfigContent, paths, removePrefixes) {
|
|
|
208
279
|
return JSON.stringify(config, null, 2) + "\n";
|
|
209
280
|
}
|
|
210
281
|
async function patchProjectTsconfig(projectDir, paths, removePrefixes) {
|
|
211
|
-
const tsconfigPath =
|
|
282
|
+
const tsconfigPath = join4(projectDir, "tsconfig.json");
|
|
212
283
|
let content;
|
|
213
284
|
try {
|
|
214
285
|
content = await readFile3(tsconfigPath, "utf-8");
|
|
@@ -258,33 +329,6 @@ var init_barrel_manager = __esm({
|
|
|
258
329
|
}
|
|
259
330
|
});
|
|
260
331
|
|
|
261
|
-
// src/utils/detect.ts
|
|
262
|
-
import { access } from "fs/promises";
|
|
263
|
-
import { join as join4 } from "path";
|
|
264
|
-
async function detectPackageManager(dir) {
|
|
265
|
-
for (const [lockfile, pm] of LOCKFILE_MAP) {
|
|
266
|
-
try {
|
|
267
|
-
await access(join4(dir, lockfile));
|
|
268
|
-
return pm;
|
|
269
|
-
} catch {
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
var LOCKFILE_MAP;
|
|
275
|
-
var init_detect = __esm({
|
|
276
|
-
"src/utils/detect.ts"() {
|
|
277
|
-
"use strict";
|
|
278
|
-
LOCKFILE_MAP = [
|
|
279
|
-
["bun.lock", "bun"],
|
|
280
|
-
["bun.lockb", "bun"],
|
|
281
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
282
|
-
["yarn.lock", "yarn"],
|
|
283
|
-
["package-lock.json", "npm"]
|
|
284
|
-
];
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
|
|
288
332
|
// src/registry/fetcher.ts
|
|
289
333
|
function urlOf(entry) {
|
|
290
334
|
return typeof entry === "string" ? entry : entry.url;
|
|
@@ -728,6 +772,7 @@ var init_schema = __esm({
|
|
|
728
772
|
tsconfig: z2.record(z2.string(), z2.array(z2.string())).optional(),
|
|
729
773
|
envVars: z2.record(z2.string(), envVarConfigSchema).optional(),
|
|
730
774
|
categories: z2.array(z2.string()).optional(),
|
|
775
|
+
slot: z2.string().optional(),
|
|
731
776
|
docs: z2.string().optional(),
|
|
732
777
|
changelog: z2.array(changelogEntrySchema).optional()
|
|
733
778
|
});
|
|
@@ -745,6 +790,7 @@ var init_schema = __esm({
|
|
|
745
790
|
tsconfig: z2.record(z2.string(), z2.array(z2.string())).optional(),
|
|
746
791
|
docs: z2.string().optional(),
|
|
747
792
|
categories: z2.array(z2.string()).optional(),
|
|
793
|
+
slot: z2.string().optional(),
|
|
748
794
|
version: z2.string().optional(),
|
|
749
795
|
updatedAt: z2.string().optional(),
|
|
750
796
|
changelog: z2.array(changelogEntrySchema).optional()
|
|
@@ -755,6 +801,7 @@ var init_schema = __esm({
|
|
|
755
801
|
description: z2.string(),
|
|
756
802
|
registryDependencies: z2.array(z2.string()).optional(),
|
|
757
803
|
categories: z2.array(z2.string()).optional(),
|
|
804
|
+
slot: z2.string().optional(),
|
|
758
805
|
version: z2.string().optional(),
|
|
759
806
|
versions: z2.array(z2.string()).optional(),
|
|
760
807
|
updatedAt: z2.string().optional()
|
|
@@ -781,9 +828,9 @@ __export(add_exports, {
|
|
|
781
828
|
});
|
|
782
829
|
import * as p2 from "@clack/prompts";
|
|
783
830
|
import pc3 from "picocolors";
|
|
784
|
-
import { join as join7 } from "path";
|
|
831
|
+
import { join as join7, dirname as dirname3 } from "path";
|
|
785
832
|
import { existsSync } from "fs";
|
|
786
|
-
import { readFile as readFile6, writeFile as writeFile6, mkdir as mkdir3 } from "fs/promises";
|
|
833
|
+
import { readFile as readFile6, writeFile as writeFile6, mkdir as mkdir3, unlink } from "fs/promises";
|
|
787
834
|
import { relative as relative2 } from "path";
|
|
788
835
|
async function addCommand(components, opts) {
|
|
789
836
|
p2.intro(pc3.bgCyan(pc3.black(" kitn add ")));
|
|
@@ -794,8 +841,63 @@ async function addCommand(components, opts) {
|
|
|
794
841
|
process.exit(1);
|
|
795
842
|
}
|
|
796
843
|
if (components.length === 0) {
|
|
797
|
-
|
|
798
|
-
|
|
844
|
+
const fetcher2 = new RegistryFetcher(config.registries);
|
|
845
|
+
const s2 = p2.spinner();
|
|
846
|
+
s2.start("Fetching registry...");
|
|
847
|
+
const allItems = [];
|
|
848
|
+
for (const namespace of Object.keys(config.registries)) {
|
|
849
|
+
try {
|
|
850
|
+
const index = await fetcher2.fetchIndex(namespace);
|
|
851
|
+
for (const item of index.items) {
|
|
852
|
+
allItems.push({ name: item.name, type: item.type, description: item.description, namespace });
|
|
853
|
+
}
|
|
854
|
+
} catch {
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
s2.stop(`Found ${allItems.length} component(s)`);
|
|
858
|
+
if (allItems.length === 0) {
|
|
859
|
+
p2.log.warn("No components found in configured registries.");
|
|
860
|
+
process.exit(0);
|
|
861
|
+
}
|
|
862
|
+
const installed = new Set(Object.keys(config.installed ?? {}));
|
|
863
|
+
const typeLabels = {
|
|
864
|
+
"kitn:agent": "Agents",
|
|
865
|
+
"kitn:tool": "Tools",
|
|
866
|
+
"kitn:skill": "Skills",
|
|
867
|
+
"kitn:storage": "Storage",
|
|
868
|
+
"kitn:package": "Packages"
|
|
869
|
+
};
|
|
870
|
+
const groups = /* @__PURE__ */ new Map();
|
|
871
|
+
for (const item of allItems) {
|
|
872
|
+
if (!groups.has(item.type)) groups.set(item.type, []);
|
|
873
|
+
groups.get(item.type).push(item);
|
|
874
|
+
}
|
|
875
|
+
const options = [];
|
|
876
|
+
for (const [type, items] of groups) {
|
|
877
|
+
const label = typeLabels[type] ?? type;
|
|
878
|
+
options.push({ value: `__separator_${type}`, label: pc3.bold(`\u2500\u2500 ${label} ${"\u2500".repeat(Math.max(0, 40 - label.length))}`), hint: "" });
|
|
879
|
+
for (const item of items) {
|
|
880
|
+
const isInstalled = installed.has(item.name);
|
|
881
|
+
options.push({
|
|
882
|
+
value: item.name,
|
|
883
|
+
label: isInstalled ? pc3.dim(`${item.name} (installed)`) : item.name,
|
|
884
|
+
hint: item.description
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const selected = await p2.multiselect({
|
|
889
|
+
message: "Select components to install:",
|
|
890
|
+
options
|
|
891
|
+
});
|
|
892
|
+
if (p2.isCancel(selected)) {
|
|
893
|
+
p2.cancel("Cancelled.");
|
|
894
|
+
process.exit(0);
|
|
895
|
+
}
|
|
896
|
+
components = selected.filter((s3) => !s3.startsWith("__separator_"));
|
|
897
|
+
if (components.length === 0) {
|
|
898
|
+
p2.log.warn("No components selected.");
|
|
899
|
+
process.exit(0);
|
|
900
|
+
}
|
|
799
901
|
}
|
|
800
902
|
let typeFilter;
|
|
801
903
|
const firstAlias = resolveTypeAlias(components[0]);
|
|
@@ -853,7 +955,45 @@ async function addCommand(components, opts) {
|
|
|
853
955
|
matches = matches.filter((m) => m.type === filteredType);
|
|
854
956
|
}
|
|
855
957
|
if (matches.length === 0) {
|
|
856
|
-
|
|
958
|
+
let fuzzyMatches = allIndexItems.filter(
|
|
959
|
+
(i) => i.name.includes(name) && (ref.namespace === "@kitn" || i.namespace === ref.namespace)
|
|
960
|
+
);
|
|
961
|
+
if (typeFilter) {
|
|
962
|
+
const filteredType = toComponentType(typeFilter);
|
|
963
|
+
fuzzyMatches = fuzzyMatches.filter((m) => m.type === filteredType);
|
|
964
|
+
}
|
|
965
|
+
if (fuzzyMatches.length === 0) {
|
|
966
|
+
newExpandedNames.push(name);
|
|
967
|
+
} else if (fuzzyMatches.length === 1) {
|
|
968
|
+
preResolvedTypes.set(fuzzyMatches[0].name, fuzzyMatches[0].type);
|
|
969
|
+
newExpandedNames.push(fuzzyMatches[0].name);
|
|
970
|
+
} else {
|
|
971
|
+
s.stop("Multiple matches found");
|
|
972
|
+
if (!process.stdin.isTTY) {
|
|
973
|
+
const suggestions = fuzzyMatches.map((m) => `${m.name} (${m.type.replace("kitn:", "")})`).join(", ");
|
|
974
|
+
p2.log.error(
|
|
975
|
+
`Component ${pc3.bold(name)} not found. Did you mean one of: ${suggestions}`
|
|
976
|
+
);
|
|
977
|
+
process.exit(1);
|
|
978
|
+
}
|
|
979
|
+
const selected = await p2.multiselect({
|
|
980
|
+
message: `No exact match for ${pc3.bold(name)}. Select component(s) to install:`,
|
|
981
|
+
options: fuzzyMatches.map((m) => ({
|
|
982
|
+
value: `${m.name}::${m.type}`,
|
|
983
|
+
label: `${m.name} ${pc3.dim(`(${m.type.replace("kitn:", "")})`)}`
|
|
984
|
+
}))
|
|
985
|
+
});
|
|
986
|
+
if (p2.isCancel(selected)) {
|
|
987
|
+
p2.cancel("Cancelled.");
|
|
988
|
+
process.exit(0);
|
|
989
|
+
}
|
|
990
|
+
for (const sel of selected) {
|
|
991
|
+
const [selName, selType] = sel.split("::");
|
|
992
|
+
preResolvedTypes.set(selName, selType);
|
|
993
|
+
newExpandedNames.push(selName);
|
|
994
|
+
}
|
|
995
|
+
s.start("Resolving dependencies...");
|
|
996
|
+
}
|
|
857
997
|
} else if (matches.length === 1) {
|
|
858
998
|
preResolvedTypes.set(name, matches[0].type);
|
|
859
999
|
newExpandedNames.push(name);
|
|
@@ -913,6 +1053,68 @@ async function addCommand(components, opts) {
|
|
|
913
1053
|
process.exit(1);
|
|
914
1054
|
}
|
|
915
1055
|
s.stop(`Resolved ${resolved.length} component(s)`);
|
|
1056
|
+
const slotReplacements = /* @__PURE__ */ new Map();
|
|
1057
|
+
for (const item of resolved) {
|
|
1058
|
+
if (!item.slot) continue;
|
|
1059
|
+
const existing = Object.entries(config.installed ?? {}).find(
|
|
1060
|
+
([key, entry]) => key !== item.name && entry.slot === item.slot
|
|
1061
|
+
);
|
|
1062
|
+
if (!existing) continue;
|
|
1063
|
+
const [existingKey] = existing;
|
|
1064
|
+
const action = await p2.select({
|
|
1065
|
+
message: `${pc3.bold(existingKey)} already fills the ${pc3.cyan(item.slot)} slot. What would you like to do?`,
|
|
1066
|
+
options: [
|
|
1067
|
+
{ value: "replace", label: `Replace ${existingKey} with ${item.name}` },
|
|
1068
|
+
{ value: "add", label: `Add alongside ${existingKey}` }
|
|
1069
|
+
]
|
|
1070
|
+
});
|
|
1071
|
+
if (p2.isCancel(action)) {
|
|
1072
|
+
p2.cancel("Cancelled.");
|
|
1073
|
+
process.exit(0);
|
|
1074
|
+
}
|
|
1075
|
+
if (action === "replace") {
|
|
1076
|
+
slotReplacements.set(existingKey, item.name);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (slotReplacements.size > 0) {
|
|
1080
|
+
const baseDir2 = config.aliases.base ?? "src/ai";
|
|
1081
|
+
for (const [oldKey] of slotReplacements) {
|
|
1082
|
+
const oldEntry = config.installed[oldKey];
|
|
1083
|
+
if (!oldEntry) continue;
|
|
1084
|
+
for (const filePath of oldEntry.files) {
|
|
1085
|
+
try {
|
|
1086
|
+
await unlink(join7(cwd, filePath));
|
|
1087
|
+
} catch {
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
const barrelPath2 = join7(cwd, baseDir2, "index.ts");
|
|
1091
|
+
const barrelEligibleDirs = /* @__PURE__ */ new Set([
|
|
1092
|
+
config.aliases.agents,
|
|
1093
|
+
config.aliases.tools,
|
|
1094
|
+
config.aliases.skills
|
|
1095
|
+
]);
|
|
1096
|
+
if (existsSync(barrelPath2)) {
|
|
1097
|
+
let barrelContent = await readFile6(barrelPath2, "utf-8");
|
|
1098
|
+
let barrelChanged = false;
|
|
1099
|
+
for (const filePath of oldEntry.files) {
|
|
1100
|
+
const fileDir = dirname3(filePath);
|
|
1101
|
+
if (!barrelEligibleDirs.has(fileDir)) continue;
|
|
1102
|
+
const barrelDir2 = join7(cwd, baseDir2);
|
|
1103
|
+
const importPath = "./" + relative2(barrelDir2, join7(cwd, filePath)).replace(/\\/g, "/");
|
|
1104
|
+
const updated2 = removeImportFromBarrel(barrelContent, importPath);
|
|
1105
|
+
if (updated2 !== barrelContent) {
|
|
1106
|
+
barrelContent = updated2;
|
|
1107
|
+
barrelChanged = true;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
if (barrelChanged) {
|
|
1111
|
+
await writeFile6(barrelPath2, barrelContent);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
delete config.installed[oldKey];
|
|
1115
|
+
p2.log.info(`Replaced ${pc3.dim(oldKey)} \u2192 ${pc3.cyan(slotReplacements.get(oldKey))}`);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
916
1118
|
p2.log.info("Components to install:\n" + resolved.map((item) => {
|
|
917
1119
|
const isExplicit = expandedNames.includes(item.name) || components.includes(item.name);
|
|
918
1120
|
const label = isExplicit ? item.name : `${item.name} ${pc3.dim("(dependency)")}`;
|
|
@@ -978,10 +1180,13 @@ async function addCommand(components, opts) {
|
|
|
978
1180
|
const installedKey = ref.namespace === "@kitn" ? item.name : `${ref.namespace}/${item.name}`;
|
|
979
1181
|
installed[installedKey] = {
|
|
980
1182
|
registry: ref.namespace,
|
|
1183
|
+
type: item.type,
|
|
1184
|
+
...item.slot && { slot: item.slot },
|
|
981
1185
|
version: item.version ?? "1.0.0",
|
|
982
1186
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
983
1187
|
files: item.files.map((f) => join7(baseDir2, f.path)),
|
|
984
|
-
hash: contentHash(allContent)
|
|
1188
|
+
hash: contentHash(allContent),
|
|
1189
|
+
registryDependencies: item.registryDependencies
|
|
985
1190
|
};
|
|
986
1191
|
config.installed = installed;
|
|
987
1192
|
} else {
|
|
@@ -1047,13 +1252,16 @@ async function addCommand(components, opts) {
|
|
|
1047
1252
|
const installedKey = ns === "@kitn" ? item.name : `${ns}/${item.name}`;
|
|
1048
1253
|
installed[installedKey] = {
|
|
1049
1254
|
registry: ns,
|
|
1255
|
+
type: item.type,
|
|
1256
|
+
...item.slot && { slot: item.slot },
|
|
1050
1257
|
version: item.version ?? "1.0.0",
|
|
1051
1258
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1052
1259
|
files: item.files.map((f) => {
|
|
1053
1260
|
const fileName = f.path.split("/").pop();
|
|
1054
1261
|
return getInstallPath(config, item.type, fileName, ns);
|
|
1055
1262
|
}),
|
|
1056
|
-
hash: contentHash(allContent)
|
|
1263
|
+
hash: contentHash(allContent),
|
|
1264
|
+
registryDependencies: item.registryDependencies
|
|
1057
1265
|
};
|
|
1058
1266
|
config.installed = installed;
|
|
1059
1267
|
}
|
|
@@ -1175,6 +1383,28 @@ import * as p3 from "@clack/prompts";
|
|
|
1175
1383
|
import pc4 from "picocolors";
|
|
1176
1384
|
import { mkdir as mkdir4, writeFile as writeFile7 } from "fs/promises";
|
|
1177
1385
|
import { join as join8 } from "path";
|
|
1386
|
+
function getPluginTemplate(framework) {
|
|
1387
|
+
const adapterName = framework === "hono-openapi" ? "hono-openapi" : framework;
|
|
1388
|
+
return `import { createAIPlugin } from "@kitn/adapters/${adapterName}";
|
|
1389
|
+
import { registerWithPlugin } from "./index.js";
|
|
1390
|
+
|
|
1391
|
+
export const ai = createAIPlugin({
|
|
1392
|
+
// To enable agent chat, add an AI provider:
|
|
1393
|
+
// https://sdk.vercel.ai/providers/ai-sdk-providers
|
|
1394
|
+
//
|
|
1395
|
+
// Example with OpenRouter (access to many models):
|
|
1396
|
+
// import { openrouter } from "@openrouter/ai-sdk-provider";
|
|
1397
|
+
// model: (id) => openrouter(id ?? "openai/gpt-4o-mini"),
|
|
1398
|
+
//
|
|
1399
|
+
// Example with OpenAI directly:
|
|
1400
|
+
// import { openai } from "@ai-sdk/openai";
|
|
1401
|
+
// model: (id) => openai(id ?? "gpt-4o-mini"),
|
|
1402
|
+
});
|
|
1403
|
+
|
|
1404
|
+
// Flush all auto-registered components into the plugin
|
|
1405
|
+
registerWithPlugin(ai);
|
|
1406
|
+
`;
|
|
1407
|
+
}
|
|
1178
1408
|
async function initCommand(opts = {}) {
|
|
1179
1409
|
p3.intro(pc4.bgCyan(pc4.black(" kitn init ")));
|
|
1180
1410
|
const cwd = process.cwd();
|
|
@@ -1218,6 +1448,31 @@ async function initCommand(opts = {}) {
|
|
|
1218
1448
|
}
|
|
1219
1449
|
runtime = selected;
|
|
1220
1450
|
}
|
|
1451
|
+
const validFrameworks = ["hono", "hono-openapi", "elysia"];
|
|
1452
|
+
let framework;
|
|
1453
|
+
if (opts.framework) {
|
|
1454
|
+
if (!validFrameworks.includes(opts.framework)) {
|
|
1455
|
+
p3.log.error(`Invalid framework: ${opts.framework}. Must be one of: ${validFrameworks.join(", ")}`);
|
|
1456
|
+
process.exit(1);
|
|
1457
|
+
}
|
|
1458
|
+
framework = opts.framework;
|
|
1459
|
+
} else if (opts.yes) {
|
|
1460
|
+
framework = "hono";
|
|
1461
|
+
} else {
|
|
1462
|
+
const selected = await p3.select({
|
|
1463
|
+
message: "Which HTTP framework do you use?",
|
|
1464
|
+
options: [
|
|
1465
|
+
{ value: "hono", label: "Hono", hint: "recommended" },
|
|
1466
|
+
{ value: "hono-openapi", label: "Hono + OpenAPI", hint: "zod-openapi routes with /doc endpoint" },
|
|
1467
|
+
{ value: "elysia", label: "Elysia", hint: "Bun-native framework" }
|
|
1468
|
+
]
|
|
1469
|
+
});
|
|
1470
|
+
if (p3.isCancel(selected)) {
|
|
1471
|
+
p3.cancel("Init cancelled.");
|
|
1472
|
+
process.exit(0);
|
|
1473
|
+
}
|
|
1474
|
+
framework = selected;
|
|
1475
|
+
}
|
|
1221
1476
|
let baseDir;
|
|
1222
1477
|
if (opts.base) {
|
|
1223
1478
|
baseDir = opts.base;
|
|
@@ -1237,7 +1492,7 @@ async function initCommand(opts = {}) {
|
|
|
1237
1492
|
}
|
|
1238
1493
|
const config = {
|
|
1239
1494
|
runtime,
|
|
1240
|
-
framework
|
|
1495
|
+
framework,
|
|
1241
1496
|
aliases: {
|
|
1242
1497
|
base: baseDir,
|
|
1243
1498
|
agents: `${baseDir}/agents`,
|
|
@@ -1263,20 +1518,21 @@ async function initCommand(opts = {}) {
|
|
|
1263
1518
|
["@kitn", "@kitnai"]
|
|
1264
1519
|
);
|
|
1265
1520
|
p3.log.info(`Patched tsconfig.json with path: ${pc4.bold("@kitn/*")}`);
|
|
1266
|
-
p3.log.info("Installing core engine and
|
|
1521
|
+
p3.log.info("Installing core engine and adapter...");
|
|
1267
1522
|
await addCommand(["core", "routes"], { overwrite: true });
|
|
1268
1523
|
const aiDir = join8(cwd, baseDir);
|
|
1269
1524
|
await mkdir4(aiDir, { recursive: true });
|
|
1270
1525
|
const barrelPath = join8(aiDir, "index.ts");
|
|
1271
1526
|
await writeFile7(barrelPath, createBarrelFile());
|
|
1272
1527
|
const pluginPath = join8(aiDir, "plugin.ts");
|
|
1273
|
-
await writeFile7(pluginPath,
|
|
1528
|
+
await writeFile7(pluginPath, getPluginTemplate(framework));
|
|
1274
1529
|
p3.log.success(`Created ${pc4.bold(baseDir + "/plugin.ts")} \u2014 configure your AI provider there`);
|
|
1530
|
+
const mountCode = framework === "elysia" ? `app.use(ai.router);` : `app.route("/api", ai.router);`;
|
|
1275
1531
|
p3.note(
|
|
1276
1532
|
[
|
|
1277
1533
|
`import { ai } from "./${baseDir.replace(/^src\//, "")}/plugin";`,
|
|
1278
1534
|
``,
|
|
1279
|
-
|
|
1535
|
+
mountCode
|
|
1280
1536
|
].join("\n"),
|
|
1281
1537
|
"Add this to your server entry point:"
|
|
1282
1538
|
);
|
|
@@ -1291,7 +1547,6 @@ async function initCommand(opts = {}) {
|
|
|
1291
1547
|
);
|
|
1292
1548
|
p3.outro("Done!");
|
|
1293
1549
|
}
|
|
1294
|
-
var PLUGIN_TEMPLATE;
|
|
1295
1550
|
var init_init = __esm({
|
|
1296
1551
|
"src/commands/init.ts"() {
|
|
1297
1552
|
"use strict";
|
|
@@ -1299,25 +1554,6 @@ var init_init = __esm({
|
|
|
1299
1554
|
init_tsconfig_patcher();
|
|
1300
1555
|
init_barrel_manager();
|
|
1301
1556
|
init_add();
|
|
1302
|
-
PLUGIN_TEMPLATE = `import { createAIPlugin } from "@kitn/routes";
|
|
1303
|
-
import { registerWithPlugin } from "./index.js";
|
|
1304
|
-
|
|
1305
|
-
export const ai = createAIPlugin({
|
|
1306
|
-
// To enable agent chat, add an AI provider:
|
|
1307
|
-
// https://sdk.vercel.ai/providers/ai-sdk-providers
|
|
1308
|
-
//
|
|
1309
|
-
// Example with OpenRouter (access to many models):
|
|
1310
|
-
// import { openrouter } from "@openrouter/ai-sdk-provider";
|
|
1311
|
-
// model: (id) => openrouter(id ?? "openai/gpt-4o-mini"),
|
|
1312
|
-
//
|
|
1313
|
-
// Example with OpenAI directly:
|
|
1314
|
-
// import { openai } from "@ai-sdk/openai";
|
|
1315
|
-
// model: (id) => openai(id ?? "gpt-4o-mini"),
|
|
1316
|
-
});
|
|
1317
|
-
|
|
1318
|
-
// Flush all auto-registered components into the plugin
|
|
1319
|
-
registerWithPlugin(ai);
|
|
1320
|
-
`;
|
|
1321
1557
|
}
|
|
1322
1558
|
});
|
|
1323
1559
|
|
|
@@ -1542,36 +1778,16 @@ __export(remove_exports, {
|
|
|
1542
1778
|
});
|
|
1543
1779
|
import * as p6 from "@clack/prompts";
|
|
1544
1780
|
import pc6 from "picocolors";
|
|
1545
|
-
import { join as join10, relative as relative3, dirname as
|
|
1546
|
-
import { unlink, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
|
|
1781
|
+
import { join as join10, relative as relative3, dirname as dirname4 } from "path";
|
|
1782
|
+
import { unlink as unlink2, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
|
|
1547
1783
|
import { existsSync as existsSync2 } from "fs";
|
|
1548
|
-
async function
|
|
1549
|
-
const cwd = process.cwd();
|
|
1550
|
-
const config = await readConfig(cwd);
|
|
1551
|
-
if (!config) {
|
|
1552
|
-
p6.log.error("No kitn.json found. Run `kitn init` first.");
|
|
1553
|
-
process.exit(1);
|
|
1554
|
-
}
|
|
1555
|
-
const input = componentName === "routes" ? resolveRoutesAlias(config) : componentName;
|
|
1556
|
-
const ref = parseComponentRef(input);
|
|
1557
|
-
const installedKey = ref.namespace === "@kitn" ? ref.name : `${ref.namespace}/${ref.name}`;
|
|
1784
|
+
async function removeSingleComponent(installedKey, config, cwd) {
|
|
1558
1785
|
const installed = config.installed?.[installedKey];
|
|
1559
|
-
if (!installed)
|
|
1560
|
-
p6.log.error(`Component '${ref.name}' is not installed.`);
|
|
1561
|
-
process.exit(1);
|
|
1562
|
-
}
|
|
1563
|
-
const shouldRemove = await p6.confirm({
|
|
1564
|
-
message: `Remove ${ref.name}? This will delete ${installed.files.length} file(s).`,
|
|
1565
|
-
initialValue: false
|
|
1566
|
-
});
|
|
1567
|
-
if (p6.isCancel(shouldRemove) || !shouldRemove) {
|
|
1568
|
-
p6.cancel("Remove cancelled.");
|
|
1569
|
-
process.exit(0);
|
|
1570
|
-
}
|
|
1786
|
+
if (!installed) return;
|
|
1571
1787
|
const deleted = [];
|
|
1572
1788
|
for (const filePath of installed.files) {
|
|
1573
1789
|
try {
|
|
1574
|
-
await
|
|
1790
|
+
await unlink2(join10(cwd, filePath));
|
|
1575
1791
|
deleted.push(filePath);
|
|
1576
1792
|
} catch {
|
|
1577
1793
|
p6.log.warn(`Could not delete ${filePath} (may have been moved or renamed)`);
|
|
@@ -1589,7 +1805,7 @@ async function removeCommand(componentName) {
|
|
|
1589
1805
|
let barrelContent = await readFile7(barrelPath, "utf-8");
|
|
1590
1806
|
let barrelChanged = false;
|
|
1591
1807
|
for (const filePath of deleted) {
|
|
1592
|
-
const fileDir =
|
|
1808
|
+
const fileDir = dirname4(filePath);
|
|
1593
1809
|
if (!barrelEligibleDirs.has(fileDir)) continue;
|
|
1594
1810
|
const importPath = "./" + relative3(barrelDir, join10(cwd, filePath)).replace(/\\/g, "/");
|
|
1595
1811
|
const updated = removeImportFromBarrel(barrelContent, importPath);
|
|
@@ -1604,14 +1820,113 @@ async function removeCommand(componentName) {
|
|
|
1604
1820
|
}
|
|
1605
1821
|
}
|
|
1606
1822
|
delete config.installed[installedKey];
|
|
1823
|
+
if (deleted.length > 0) {
|
|
1824
|
+
p6.log.success(`Removed ${installedKey}:
|
|
1825
|
+
` + deleted.map((f) => ` ${pc6.red("-")} ${f}`).join("\n"));
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
async function offerOrphanRemoval(removedDeps, config, cwd) {
|
|
1829
|
+
if (removedDeps.size === 0) return;
|
|
1830
|
+
const remaining = Object.entries(config.installed ?? {});
|
|
1831
|
+
const neededDeps = /* @__PURE__ */ new Set();
|
|
1832
|
+
for (const [, entry] of remaining) {
|
|
1833
|
+
const deps = entry.registryDependencies;
|
|
1834
|
+
if (deps) {
|
|
1835
|
+
for (const dep of deps) {
|
|
1836
|
+
neededDeps.add(dep);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
const orphans = [...removedDeps].filter(
|
|
1841
|
+
(dep) => dep !== "core" && !neededDeps.has(dep) && config.installed?.[dep]
|
|
1842
|
+
);
|
|
1843
|
+
if (orphans.length === 0) return;
|
|
1844
|
+
const selected = await p6.multiselect({
|
|
1845
|
+
message: "The following dependencies are no longer used. Remove them?",
|
|
1846
|
+
options: orphans.map((dep) => ({
|
|
1847
|
+
value: dep,
|
|
1848
|
+
label: dep,
|
|
1849
|
+
hint: `${config.installed[dep].files.length} file(s)`
|
|
1850
|
+
})),
|
|
1851
|
+
initialValues: orphans
|
|
1852
|
+
// all checked by default
|
|
1853
|
+
});
|
|
1854
|
+
if (p6.isCancel(selected)) return;
|
|
1855
|
+
for (const key of selected) {
|
|
1856
|
+
await removeSingleComponent(key, config, cwd);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
async function removeCommand(componentName) {
|
|
1860
|
+
const cwd = process.cwd();
|
|
1861
|
+
const config = await readConfig(cwd);
|
|
1862
|
+
if (!config) {
|
|
1863
|
+
p6.log.error("No kitn.json found. Run `kitn init` first.");
|
|
1864
|
+
process.exit(1);
|
|
1865
|
+
}
|
|
1866
|
+
if (!componentName) {
|
|
1867
|
+
const installed2 = config.installed ?? {};
|
|
1868
|
+
const installedKeys = Object.keys(installed2);
|
|
1869
|
+
if (installedKeys.length === 0) {
|
|
1870
|
+
p6.log.warn("No components installed.");
|
|
1871
|
+
process.exit(0);
|
|
1872
|
+
}
|
|
1873
|
+
const selected = await p6.multiselect({
|
|
1874
|
+
message: "Select components to remove:",
|
|
1875
|
+
options: installedKeys.map((key) => ({
|
|
1876
|
+
value: key,
|
|
1877
|
+
label: key,
|
|
1878
|
+
hint: `${installed2[key].files.length} file(s)`
|
|
1879
|
+
}))
|
|
1880
|
+
});
|
|
1881
|
+
if (p6.isCancel(selected)) {
|
|
1882
|
+
p6.cancel("Cancelled.");
|
|
1883
|
+
process.exit(0);
|
|
1884
|
+
}
|
|
1885
|
+
const selectedKeys = selected;
|
|
1886
|
+
if (selectedKeys.length === 0) {
|
|
1887
|
+
p6.log.warn("No components selected.");
|
|
1888
|
+
process.exit(0);
|
|
1889
|
+
}
|
|
1890
|
+
for (const key of selectedKeys) {
|
|
1891
|
+
await removeSingleComponent(key, config, cwd);
|
|
1892
|
+
}
|
|
1893
|
+
const allRemovedDeps = /* @__PURE__ */ new Set();
|
|
1894
|
+
for (const key of selectedKeys) {
|
|
1895
|
+
const entry = installed2[key];
|
|
1896
|
+
if (entry?.registryDependencies) {
|
|
1897
|
+
for (const dep of entry.registryDependencies) {
|
|
1898
|
+
allRemovedDeps.add(dep);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
await offerOrphanRemoval(allRemovedDeps, config, cwd);
|
|
1903
|
+
await writeConfig(cwd, config);
|
|
1904
|
+
p6.outro(pc6.green("Done!"));
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
const input = componentName === "routes" ? resolveRoutesAlias(config) : componentName;
|
|
1908
|
+
const ref = parseComponentRef(input);
|
|
1909
|
+
const installedKey = ref.namespace === "@kitn" ? ref.name : `${ref.namespace}/${ref.name}`;
|
|
1910
|
+
const installed = config.installed?.[installedKey];
|
|
1911
|
+
if (!installed) {
|
|
1912
|
+
p6.log.error(`Component '${ref.name}' is not installed.`);
|
|
1913
|
+
process.exit(1);
|
|
1914
|
+
}
|
|
1915
|
+
const shouldRemove = await p6.confirm({
|
|
1916
|
+
message: `Remove ${ref.name}? This will delete ${installed.files.length} file(s).`,
|
|
1917
|
+
initialValue: false
|
|
1918
|
+
});
|
|
1919
|
+
if (p6.isCancel(shouldRemove) || !shouldRemove) {
|
|
1920
|
+
p6.cancel("Remove cancelled.");
|
|
1921
|
+
process.exit(0);
|
|
1922
|
+
}
|
|
1923
|
+
await removeSingleComponent(installedKey, config, cwd);
|
|
1924
|
+
const removedDeps = new Set(installed.registryDependencies ?? []);
|
|
1925
|
+
await offerOrphanRemoval(removedDeps, config, cwd);
|
|
1607
1926
|
if (Object.keys(config.installed).length === 0) {
|
|
1608
1927
|
delete config.installed;
|
|
1609
1928
|
}
|
|
1610
1929
|
await writeConfig(cwd, config);
|
|
1611
|
-
if (deleted.length > 0) {
|
|
1612
|
-
p6.log.success(`Removed ${ref.name}:
|
|
1613
|
-
` + deleted.map((f) => ` ${pc6.red("-")} ${f}`).join("\n"));
|
|
1614
|
-
}
|
|
1615
1930
|
}
|
|
1616
1931
|
var init_remove = __esm({
|
|
1617
1932
|
"src/commands/remove.ts"() {
|
|
@@ -1946,6 +2261,7 @@ var check_exports = {};
|
|
|
1946
2261
|
__export(check_exports, {
|
|
1947
2262
|
checkCommand: () => checkCommand
|
|
1948
2263
|
});
|
|
2264
|
+
import { execSync as execSync2 } from "child_process";
|
|
1949
2265
|
import * as p10 from "@clack/prompts";
|
|
1950
2266
|
import pc9 from "picocolors";
|
|
1951
2267
|
async function checkCommand(currentVersion) {
|
|
@@ -1961,7 +2277,22 @@ async function checkCommand(currentVersion) {
|
|
|
1961
2277
|
}
|
|
1962
2278
|
if (isNewer(latest, currentVersion)) {
|
|
1963
2279
|
s.stop(pc9.yellow(`Update available: ${currentVersion} \u2192 ${latest}`));
|
|
1964
|
-
|
|
2280
|
+
const pm = detectCliInstaller();
|
|
2281
|
+
const installCmd = getGlobalInstallCommand(pm, "@kitnai/cli");
|
|
2282
|
+
const shouldUpdate = await p10.confirm({ message: "Update now?" });
|
|
2283
|
+
if (p10.isCancel(shouldUpdate) || !shouldUpdate) {
|
|
2284
|
+
p10.log.message(` Run: ${pc9.cyan(installCmd)}`);
|
|
2285
|
+
} else {
|
|
2286
|
+
const us = p10.spinner();
|
|
2287
|
+
us.start("Updating...");
|
|
2288
|
+
try {
|
|
2289
|
+
execSync2(installCmd, { stdio: "pipe" });
|
|
2290
|
+
us.stop(pc9.green(`Updated to v${latest}`));
|
|
2291
|
+
} catch {
|
|
2292
|
+
us.stop(pc9.red("Update failed"));
|
|
2293
|
+
p10.log.message(` Run manually: ${pc9.cyan(installCmd)}`);
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
1965
2296
|
} else {
|
|
1966
2297
|
s.stop(pc9.green("You're on the latest version"));
|
|
1967
2298
|
}
|
|
@@ -1970,6 +2301,7 @@ async function checkCommand(currentVersion) {
|
|
|
1970
2301
|
var init_check = __esm({
|
|
1971
2302
|
"src/commands/check.ts"() {
|
|
1972
2303
|
"use strict";
|
|
2304
|
+
init_detect();
|
|
1973
2305
|
init_update_check();
|
|
1974
2306
|
}
|
|
1975
2307
|
});
|
|
@@ -2073,14 +2405,14 @@ var init_registry = __esm({
|
|
|
2073
2405
|
// src/index.ts
|
|
2074
2406
|
init_update_check();
|
|
2075
2407
|
import { Command } from "commander";
|
|
2076
|
-
var VERSION = true ? "0.1.
|
|
2408
|
+
var VERSION = true ? "0.1.24" : "0.0.0-dev";
|
|
2077
2409
|
var printUpdateNotice = startUpdateCheck(VERSION);
|
|
2078
2410
|
var program = new Command().name("kitn").description("Install AI agent components from the kitn registry").version(VERSION);
|
|
2079
|
-
program.command("init").description("Initialize kitn in your project").option("-r, --runtime <runtime>", "runtime to use (bun, node, deno)").option("-b, --base <path>", "base directory for components (default: src/ai)").option("-y, --yes", "accept all defaults without prompting").action(async (opts) => {
|
|
2411
|
+
program.command("init").description("Initialize kitn in your project").option("-r, --runtime <runtime>", "runtime to use (bun, node, deno)").option("-f, --framework <framework>", "HTTP framework (hono, hono-openapi, elysia)").option("-b, --base <path>", "base directory for components (default: src/ai)").option("-y, --yes", "accept all defaults without prompting").action(async (opts) => {
|
|
2080
2412
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2081
2413
|
await initCommand2(opts);
|
|
2082
2414
|
});
|
|
2083
|
-
program.command("add").description("Add components from the registry (supports type-first: kitn add agent <name>)").argument("[components...]", "component names or type followed by names").option("-o, --overwrite", "overwrite existing files without prompting").option("-t, --type <type>", "filter by component type during resolution").action(async (components, opts) => {
|
|
2415
|
+
program.command("add").alias("install").description("Add components from the registry (supports type-first: kitn add agent <name>)").argument("[components...]", "component names or type followed by names").option("-o, --overwrite", "overwrite existing files without prompting").option("-t, --type <type>", "filter by component type during resolution").action(async (components, opts) => {
|
|
2084
2416
|
const { addCommand: addCommand2 } = await Promise.resolve().then(() => (init_add(), add_exports));
|
|
2085
2417
|
await addCommand2(components, opts);
|
|
2086
2418
|
});
|
|
@@ -2092,7 +2424,7 @@ program.command("diff").description("Show differences between local and registry
|
|
|
2092
2424
|
const { diffCommand: diffCommand2 } = await Promise.resolve().then(() => (init_diff(), diff_exports));
|
|
2093
2425
|
await diffCommand2(component);
|
|
2094
2426
|
});
|
|
2095
|
-
program.command("remove").description("Remove an installed component").argument("
|
|
2427
|
+
program.command("remove").alias("uninstall").description("Remove an installed component").argument("[component]", "component name to remove (interactive if omitted)").action(async (component) => {
|
|
2096
2428
|
const { removeCommand: removeCommand2 } = await Promise.resolve().then(() => (init_remove(), remove_exports));
|
|
2097
2429
|
await removeCommand2(component);
|
|
2098
2430
|
});
|