@kitnai/cli 0.1.15 → 0.1.17
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 +27 -4
- package/dist/index.js +247 -129
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,14 +27,27 @@ pnpm dlx @kitnai/cli init
|
|
|
27
27
|
Initialize kitn in your project. Creates `kitn.json`, installs the core engine and Hono routes, and sets up tsconfig path aliases.
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
+
# Interactive (prompts for runtime and base directory)
|
|
30
31
|
kitn init
|
|
32
|
+
|
|
33
|
+
# Non-interactive with flags
|
|
34
|
+
kitn init --runtime bun --base src/ai
|
|
35
|
+
|
|
36
|
+
# Accept all defaults (runtime=bun, base=src/ai)
|
|
37
|
+
kitn init -y
|
|
31
38
|
```
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
**Flags:**
|
|
41
|
+
|
|
42
|
+
| Flag | Description |
|
|
43
|
+
|------|-------------|
|
|
44
|
+
| `-r, --runtime <runtime>` | Runtime to use (`bun`, `node`, `deno`) — skips runtime prompt |
|
|
45
|
+
| `-b, --base <path>` | Base directory for components (default: `src/ai`) — skips path prompt |
|
|
46
|
+
| `-y, --yes` | Accept all defaults without prompting |
|
|
47
|
+
|
|
48
|
+
When flags are provided, the corresponding prompts are skipped. This enables scripting and CI usage.
|
|
36
49
|
|
|
37
|
-
After
|
|
50
|
+
After setup, the CLI automatically installs the core engine and HTTP routes into your project.
|
|
38
51
|
|
|
39
52
|
### `kitn add [components...]`
|
|
40
53
|
|
|
@@ -180,6 +193,16 @@ kitn build
|
|
|
180
193
|
kitn build src/components --output dist/r
|
|
181
194
|
```
|
|
182
195
|
|
|
196
|
+
### `kitn check`
|
|
197
|
+
|
|
198
|
+
Check for CLI updates.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
kitn check
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Shows the current version and whether a newer version is available on npm.
|
|
205
|
+
|
|
183
206
|
### `kitn registry`
|
|
184
207
|
|
|
185
208
|
Manage component registries.
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,86 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/utils/update-check.ts
|
|
13
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
import { homedir } from "os";
|
|
16
|
+
import pc from "picocolors";
|
|
17
|
+
async function readCache() {
|
|
18
|
+
try {
|
|
19
|
+
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
20
|
+
return JSON.parse(raw);
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function writeCache(entry) {
|
|
26
|
+
try {
|
|
27
|
+
await mkdir(CACHE_DIR, { recursive: true });
|
|
28
|
+
await writeFile(CACHE_FILE, JSON.stringify(entry));
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function fetchLatestVersion() {
|
|
33
|
+
try {
|
|
34
|
+
const controller = new AbortController();
|
|
35
|
+
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
36
|
+
const res = await fetch("https://registry.npmjs.org/@kitnai/cli/latest", {
|
|
37
|
+
signal: controller.signal
|
|
38
|
+
});
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
if (!res.ok) return null;
|
|
41
|
+
const data = await res.json();
|
|
42
|
+
return data.version ?? null;
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function isNewer(latest, current) {
|
|
48
|
+
const [lMaj, lMin, lPat] = latest.split(".").map(Number);
|
|
49
|
+
const [cMaj, cMin, cPat] = current.split(".").map(Number);
|
|
50
|
+
if (lMaj !== cMaj) return lMaj > cMaj;
|
|
51
|
+
if (lMin !== cMin) return lMin > cMin;
|
|
52
|
+
return lPat > cPat;
|
|
53
|
+
}
|
|
54
|
+
function startUpdateCheck(currentVersion) {
|
|
55
|
+
let message = "";
|
|
56
|
+
const check = (async () => {
|
|
57
|
+
const cache = await readCache();
|
|
58
|
+
let latest = null;
|
|
59
|
+
if (cache && Date.now() - cache.checkedAt < CHECK_INTERVAL) {
|
|
60
|
+
latest = cache.latest;
|
|
61
|
+
} else {
|
|
62
|
+
latest = await fetchLatestVersion();
|
|
63
|
+
if (latest) {
|
|
64
|
+
await writeCache({ latest, checkedAt: Date.now() });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (latest && isNewer(latest, currentVersion)) {
|
|
68
|
+
message = [
|
|
69
|
+
"",
|
|
70
|
+
pc.yellow(` Update available: ${pc.dim(currentVersion)} \u2192 ${pc.green(latest)}`),
|
|
71
|
+
pc.dim(` Run ${pc.cyan("npx @kitnai/cli@latest")} or ${pc.cyan("npm i -g @kitnai/cli")}`),
|
|
72
|
+
""
|
|
73
|
+
].join("\n");
|
|
74
|
+
}
|
|
75
|
+
})();
|
|
76
|
+
check.catch(() => {
|
|
77
|
+
});
|
|
78
|
+
return () => {
|
|
79
|
+
if (message) process.stderr.write(message);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
var CACHE_DIR, CACHE_FILE, CHECK_INTERVAL;
|
|
83
|
+
var init_update_check = __esm({
|
|
84
|
+
"src/utils/update-check.ts"() {
|
|
85
|
+
"use strict";
|
|
86
|
+
CACHE_DIR = join(homedir(), ".kitn");
|
|
87
|
+
CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
88
|
+
CHECK_INTERVAL = 60 * 60 * 1e3;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
12
92
|
// src/utils/config.ts
|
|
13
93
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
14
94
|
import { join as join2 } from "path";
|
|
@@ -103,6 +183,20 @@ function patchTsconfig(tsconfigContent, paths, removePrefixes) {
|
|
|
103
183
|
for (const [key, value] of Object.entries(paths)) {
|
|
104
184
|
config.compilerOptions.paths[key] = value;
|
|
105
185
|
}
|
|
186
|
+
const ES_TARGETS = ["es3", "es5", "es6", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020", "es2021"];
|
|
187
|
+
const currentTarget = (config.compilerOptions.target ?? "").toLowerCase();
|
|
188
|
+
if (!currentTarget || ES_TARGETS.includes(currentTarget)) {
|
|
189
|
+
config.compilerOptions.target = "ES2022";
|
|
190
|
+
}
|
|
191
|
+
if (!config.compilerOptions.moduleResolution) {
|
|
192
|
+
config.compilerOptions.moduleResolution = "bundler";
|
|
193
|
+
}
|
|
194
|
+
if (!config.compilerOptions.module) {
|
|
195
|
+
config.compilerOptions.module = "ESNext";
|
|
196
|
+
}
|
|
197
|
+
if (config.compilerOptions.skipLibCheck === void 0) {
|
|
198
|
+
config.compilerOptions.skipLibCheck = true;
|
|
199
|
+
}
|
|
106
200
|
return JSON.stringify(config, null, 2) + "\n";
|
|
107
201
|
}
|
|
108
202
|
async function patchProjectTsconfig(projectDir, paths, removePrefixes) {
|
|
@@ -341,6 +435,23 @@ function installDependencies(pm, deps, projectDir) {
|
|
|
341
435
|
})();
|
|
342
436
|
execSync(cmd, { cwd: projectDir, stdio: "pipe" });
|
|
343
437
|
}
|
|
438
|
+
function installDevDependencies(pm, deps, projectDir) {
|
|
439
|
+
if (deps.length === 0) return;
|
|
440
|
+
const pkgs = deps.join(" ");
|
|
441
|
+
const cmd = (() => {
|
|
442
|
+
switch (pm) {
|
|
443
|
+
case "bun":
|
|
444
|
+
return `bun add -d ${pkgs}`;
|
|
445
|
+
case "pnpm":
|
|
446
|
+
return `pnpm add -D ${pkgs}`;
|
|
447
|
+
case "yarn":
|
|
448
|
+
return `yarn add -D ${pkgs}`;
|
|
449
|
+
case "npm":
|
|
450
|
+
return `npm install -D ${pkgs}`;
|
|
451
|
+
}
|
|
452
|
+
})();
|
|
453
|
+
execSync(cmd, { cwd: projectDir, stdio: "pipe" });
|
|
454
|
+
}
|
|
344
455
|
var init_dep_installer = __esm({
|
|
345
456
|
"src/installers/dep-installer.ts"() {
|
|
346
457
|
"use strict";
|
|
@@ -679,8 +790,17 @@ async function addCommand(components, opts) {
|
|
|
679
790
|
const updated = [];
|
|
680
791
|
const skipped = [];
|
|
681
792
|
const allDeps = [];
|
|
793
|
+
const allDevDeps = [];
|
|
682
794
|
for (const item of resolved) {
|
|
683
795
|
if (item.dependencies) allDeps.push(...item.dependencies);
|
|
796
|
+
if (item.devDependencies) allDevDeps.push(...item.devDependencies);
|
|
797
|
+
const existingInstall = (config.installed ?? {})[item.name];
|
|
798
|
+
if (existingInstall && item.type === "kitn:package") {
|
|
799
|
+
const allContent = item.files.map((f) => f.content).join("\n");
|
|
800
|
+
if (contentHash(allContent) === existingInstall.hash) {
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
684
804
|
if (item.type === "kitn:package") {
|
|
685
805
|
const baseDir2 = config.aliases.base ?? "src/ai";
|
|
686
806
|
for (const file of item.files) {
|
|
@@ -850,12 +970,15 @@ async function addCommand(components, opts) {
|
|
|
850
970
|
}
|
|
851
971
|
await writeConfig(cwd, config);
|
|
852
972
|
const uniqueDeps = [...new Set(allDeps)];
|
|
853
|
-
|
|
973
|
+
const uniqueDevDeps = [...new Set(allDevDeps)].filter((d) => !uniqueDeps.includes(d));
|
|
974
|
+
const totalDeps = uniqueDeps.length + uniqueDevDeps.length;
|
|
975
|
+
if (totalDeps > 0) {
|
|
854
976
|
const pm = await detectPackageManager(cwd);
|
|
855
977
|
if (pm) {
|
|
856
|
-
s.start(`Installing ${
|
|
978
|
+
s.start(`Installing ${totalDeps} npm dependenc${totalDeps === 1 ? "y" : "ies"}...`);
|
|
857
979
|
try {
|
|
858
|
-
installDependencies(pm, uniqueDeps, cwd);
|
|
980
|
+
if (uniqueDeps.length > 0) installDependencies(pm, uniqueDeps, cwd);
|
|
981
|
+
if (uniqueDevDeps.length > 0) installDevDependencies(pm, uniqueDevDeps, cwd);
|
|
859
982
|
s.stop("Dependencies installed");
|
|
860
983
|
} catch {
|
|
861
984
|
s.stop(pc3.yellow("Some dependencies failed to install"));
|
|
@@ -863,7 +986,7 @@ async function addCommand(components, opts) {
|
|
|
863
986
|
}
|
|
864
987
|
}
|
|
865
988
|
if (created.length > 0) {
|
|
866
|
-
p2.log.success(`
|
|
989
|
+
p2.log.success(`Added ${created.length} file(s):
|
|
867
990
|
` + created.map((f) => ` ${pc3.green("+")} ${f}`).join("\n"));
|
|
868
991
|
}
|
|
869
992
|
if (updated.length > 0) {
|
|
@@ -881,13 +1004,14 @@ async function addCommand(components, opts) {
|
|
|
881
1004
|
p2.log.info(`${pc3.bold(item.name)}: ${item.docs}`);
|
|
882
1005
|
}
|
|
883
1006
|
}
|
|
884
|
-
const
|
|
1007
|
+
const resolvedNames = new Set(resolved.map((r) => r.name));
|
|
1008
|
+
const projectInstalled = new Set(Object.keys(config.installed ?? {}));
|
|
885
1009
|
const hints = [];
|
|
886
|
-
|
|
1010
|
+
const fw = config.framework ?? "hono";
|
|
1011
|
+
if (resolvedNames.has("core") && !resolvedNames.has(fw) && !projectInstalled.has(fw)) {
|
|
887
1012
|
hints.push(`Run ${pc3.cyan(`kitn add routes`)} to install the HTTP adapter.`);
|
|
888
1013
|
}
|
|
889
|
-
|
|
890
|
-
if (installedNames.has(fw) || installedNames.has("core") && installedNames.has(fw)) {
|
|
1014
|
+
if (resolvedNames.has(fw)) {
|
|
891
1015
|
hints.push(`Configure your AI provider in ${pc3.bold(baseDir + "/plugin.ts")}, then add to your server:`);
|
|
892
1016
|
hints.push("");
|
|
893
1017
|
hints.push(pc3.dim(` import { ai } from "./${baseDir.replace(/^src\//, "")}/plugin";`));
|
|
@@ -928,43 +1052,66 @@ import * as p3 from "@clack/prompts";
|
|
|
928
1052
|
import pc4 from "picocolors";
|
|
929
1053
|
import { mkdir as mkdir4, writeFile as writeFile7 } from "fs/promises";
|
|
930
1054
|
import { join as join8 } from "path";
|
|
931
|
-
async function initCommand() {
|
|
1055
|
+
async function initCommand(opts = {}) {
|
|
932
1056
|
p3.intro(pc4.bgCyan(pc4.black(" kitn init ")));
|
|
933
1057
|
const cwd = process.cwd();
|
|
934
1058
|
const existing = await readConfig(cwd);
|
|
935
1059
|
if (existing) {
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1060
|
+
if (opts.yes) {
|
|
1061
|
+
p3.log.warn("kitn.json already exists \u2014 overwriting (--yes).");
|
|
1062
|
+
} else {
|
|
1063
|
+
p3.log.warn("kitn.json already exists in this directory.");
|
|
1064
|
+
const shouldContinue = await p3.confirm({
|
|
1065
|
+
message: "Overwrite existing configuration?",
|
|
1066
|
+
initialValue: false
|
|
1067
|
+
});
|
|
1068
|
+
if (p3.isCancel(shouldContinue) || !shouldContinue) {
|
|
1069
|
+
p3.cancel("Init cancelled.");
|
|
1070
|
+
process.exit(0);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
let runtime;
|
|
1075
|
+
if (opts.runtime) {
|
|
1076
|
+
if (!["bun", "node", "deno"].includes(opts.runtime)) {
|
|
1077
|
+
p3.log.error(`Invalid runtime: ${opts.runtime}. Must be bun, node, or deno.`);
|
|
1078
|
+
process.exit(1);
|
|
1079
|
+
}
|
|
1080
|
+
runtime = opts.runtime;
|
|
1081
|
+
} else if (opts.yes) {
|
|
1082
|
+
runtime = "bun";
|
|
1083
|
+
} else {
|
|
1084
|
+
const selected = await p3.select({
|
|
1085
|
+
message: "Which runtime do you use?",
|
|
1086
|
+
options: [
|
|
1087
|
+
{ value: "bun", label: "Bun", hint: "recommended" },
|
|
1088
|
+
{ value: "node", label: "Node.js" },
|
|
1089
|
+
{ value: "deno", label: "Deno" }
|
|
1090
|
+
]
|
|
940
1091
|
});
|
|
941
|
-
if (p3.isCancel(
|
|
1092
|
+
if (p3.isCancel(selected)) {
|
|
942
1093
|
p3.cancel("Init cancelled.");
|
|
943
1094
|
process.exit(0);
|
|
944
1095
|
}
|
|
1096
|
+
runtime = selected;
|
|
945
1097
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
});
|
|
963
|
-
if (p3.isCancel(base)) {
|
|
964
|
-
p3.cancel("Init cancelled.");
|
|
965
|
-
process.exit(0);
|
|
1098
|
+
let baseDir;
|
|
1099
|
+
if (opts.base) {
|
|
1100
|
+
baseDir = opts.base;
|
|
1101
|
+
} else if (opts.yes) {
|
|
1102
|
+
baseDir = "src/ai";
|
|
1103
|
+
} else {
|
|
1104
|
+
const base = await p3.text({
|
|
1105
|
+
message: "Where should kitn components be installed?",
|
|
1106
|
+
initialValue: "src/ai",
|
|
1107
|
+
placeholder: "src/ai"
|
|
1108
|
+
});
|
|
1109
|
+
if (p3.isCancel(base)) {
|
|
1110
|
+
p3.cancel("Init cancelled.");
|
|
1111
|
+
process.exit(0);
|
|
1112
|
+
}
|
|
1113
|
+
baseDir = base;
|
|
966
1114
|
}
|
|
967
|
-
const baseDir = base;
|
|
968
1115
|
const config = {
|
|
969
1116
|
runtime,
|
|
970
1117
|
framework: "hono",
|
|
@@ -1011,6 +1158,15 @@ async function initCommand() {
|
|
|
1011
1158
|
].join("\n"),
|
|
1012
1159
|
"Add this to your server entry point:"
|
|
1013
1160
|
);
|
|
1161
|
+
p3.log.message(
|
|
1162
|
+
[
|
|
1163
|
+
pc4.bold("Add your first agent:"),
|
|
1164
|
+
` ${pc4.cyan("kitn add weather-agent")}`,
|
|
1165
|
+
"",
|
|
1166
|
+
pc4.bold("Browse all components:"),
|
|
1167
|
+
` ${pc4.cyan("kitn list")}`
|
|
1168
|
+
].join("\n")
|
|
1169
|
+
);
|
|
1014
1170
|
p3.outro("Done!");
|
|
1015
1171
|
}
|
|
1016
1172
|
var PLUGIN_TEMPLATE;
|
|
@@ -1422,8 +1578,8 @@ async function scanForComponents(cwd, paths) {
|
|
|
1422
1578
|
const resolvedCwd = resolve(cwd);
|
|
1423
1579
|
if (paths && paths.length > 0) {
|
|
1424
1580
|
const results = [];
|
|
1425
|
-
for (const
|
|
1426
|
-
const absPath = resolve(resolvedCwd,
|
|
1581
|
+
for (const p13 of paths) {
|
|
1582
|
+
const absPath = resolve(resolvedCwd, p13);
|
|
1427
1583
|
if (await fileExists(join11(absPath, "registry.json"))) {
|
|
1428
1584
|
results.push(absPath);
|
|
1429
1585
|
continue;
|
|
@@ -2063,6 +2219,39 @@ var init_info = __esm({
|
|
|
2063
2219
|
}
|
|
2064
2220
|
});
|
|
2065
2221
|
|
|
2222
|
+
// src/commands/check.ts
|
|
2223
|
+
var check_exports = {};
|
|
2224
|
+
__export(check_exports, {
|
|
2225
|
+
checkCommand: () => checkCommand
|
|
2226
|
+
});
|
|
2227
|
+
import * as p11 from "@clack/prompts";
|
|
2228
|
+
import pc10 from "picocolors";
|
|
2229
|
+
async function checkCommand(currentVersion) {
|
|
2230
|
+
p11.intro(pc10.bgCyan(pc10.black(" kitn check ")));
|
|
2231
|
+
p11.log.info(`kitn v${currentVersion}`);
|
|
2232
|
+
const s = p11.spinner();
|
|
2233
|
+
s.start("Checking for updates...");
|
|
2234
|
+
const latest = await fetchLatestVersion();
|
|
2235
|
+
if (!latest) {
|
|
2236
|
+
s.stop(pc10.yellow("Could not reach the npm registry"));
|
|
2237
|
+
p11.outro("Try again later.");
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
if (isNewer(latest, currentVersion)) {
|
|
2241
|
+
s.stop(pc10.yellow(`Update available: ${currentVersion} \u2192 ${latest}`));
|
|
2242
|
+
p11.log.message(` Run: ${pc10.cyan("npm i -g @kitnai/cli")}`);
|
|
2243
|
+
} else {
|
|
2244
|
+
s.stop(pc10.green("You're on the latest version"));
|
|
2245
|
+
}
|
|
2246
|
+
p11.outro("");
|
|
2247
|
+
}
|
|
2248
|
+
var init_check = __esm({
|
|
2249
|
+
"src/commands/check.ts"() {
|
|
2250
|
+
"use strict";
|
|
2251
|
+
init_update_check();
|
|
2252
|
+
}
|
|
2253
|
+
});
|
|
2254
|
+
|
|
2066
2255
|
// src/commands/registry.ts
|
|
2067
2256
|
var registry_exports = {};
|
|
2068
2257
|
__export(registry_exports, {
|
|
@@ -2070,8 +2259,8 @@ __export(registry_exports, {
|
|
|
2070
2259
|
registryListCommand: () => registryListCommand,
|
|
2071
2260
|
registryRemoveCommand: () => registryRemoveCommand
|
|
2072
2261
|
});
|
|
2073
|
-
import * as
|
|
2074
|
-
import
|
|
2262
|
+
import * as p12 from "@clack/prompts";
|
|
2263
|
+
import pc11 from "picocolors";
|
|
2075
2264
|
async function registryAddCommand(namespace, url, opts = {}) {
|
|
2076
2265
|
const cwd = opts.cwd ?? process.cwd();
|
|
2077
2266
|
const config = await readConfig(cwd);
|
|
@@ -2097,10 +2286,10 @@ async function registryAddCommand(namespace, url, opts = {}) {
|
|
|
2097
2286
|
config.registries[namespace] = url;
|
|
2098
2287
|
}
|
|
2099
2288
|
await writeConfig(cwd, config);
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
if (opts.homepage)
|
|
2103
|
-
if (opts.description)
|
|
2289
|
+
p12.log.success(`Added registry ${pc11.bold(namespace)}`);
|
|
2290
|
+
p12.log.message(pc11.dim(` ${url}`));
|
|
2291
|
+
if (opts.homepage) p12.log.message(pc11.dim(` Homepage: ${opts.homepage}`));
|
|
2292
|
+
if (opts.description) p12.log.message(pc11.dim(` ${opts.description}`));
|
|
2104
2293
|
}
|
|
2105
2294
|
async function registryRemoveCommand(namespace, opts = {}) {
|
|
2106
2295
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -2122,10 +2311,10 @@ async function registryRemoveCommand(namespace, opts = {}) {
|
|
|
2122
2311
|
}
|
|
2123
2312
|
delete config.registries[namespace];
|
|
2124
2313
|
await writeConfig(cwd, config);
|
|
2125
|
-
|
|
2314
|
+
p12.log.success(`Removed registry ${pc11.bold(namespace)}`);
|
|
2126
2315
|
if (affectedComponents.length > 0) {
|
|
2127
|
-
|
|
2128
|
-
` + affectedComponents.map((name) => ` ${
|
|
2316
|
+
p12.log.warn(`${affectedComponents.length} installed component(s) referenced this registry:
|
|
2317
|
+
` + affectedComponents.map((name) => ` ${pc11.yellow("!")} ${name}`).join("\n"));
|
|
2129
2318
|
}
|
|
2130
2319
|
return { affectedComponents };
|
|
2131
2320
|
}
|
|
@@ -2140,15 +2329,15 @@ async function registryListCommand(opts = {}) {
|
|
|
2140
2329
|
return { namespace, url, homepage, description };
|
|
2141
2330
|
});
|
|
2142
2331
|
if (entries.length === 0) {
|
|
2143
|
-
|
|
2332
|
+
p12.log.message(pc11.dim(" No registries configured."));
|
|
2144
2333
|
} else {
|
|
2145
2334
|
const lines = [];
|
|
2146
2335
|
for (const { namespace, url, homepage, description } of entries) {
|
|
2147
|
-
lines.push(` ${
|
|
2336
|
+
lines.push(` ${pc11.bold(namespace.padEnd(16))} ${pc11.dim(url)}`);
|
|
2148
2337
|
if (description) lines.push(` ${" ".repeat(16)} ${description}`);
|
|
2149
|
-
if (homepage) lines.push(` ${" ".repeat(16)} ${
|
|
2338
|
+
if (homepage) lines.push(` ${" ".repeat(16)} ${pc11.dim(homepage)}`);
|
|
2150
2339
|
}
|
|
2151
|
-
|
|
2340
|
+
p12.log.message(lines.join("\n"));
|
|
2152
2341
|
}
|
|
2153
2342
|
return entries;
|
|
2154
2343
|
}
|
|
@@ -2160,89 +2349,14 @@ var init_registry = __esm({
|
|
|
2160
2349
|
});
|
|
2161
2350
|
|
|
2162
2351
|
// src/index.ts
|
|
2352
|
+
init_update_check();
|
|
2163
2353
|
import { Command } from "commander";
|
|
2164
|
-
|
|
2165
|
-
// src/utils/update-check.ts
|
|
2166
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
2167
|
-
import { join } from "path";
|
|
2168
|
-
import { homedir } from "os";
|
|
2169
|
-
import pc from "picocolors";
|
|
2170
|
-
var CACHE_DIR = join(homedir(), ".kitn");
|
|
2171
|
-
var CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
2172
|
-
var CHECK_INTERVAL = 60 * 60 * 1e3;
|
|
2173
|
-
async function readCache() {
|
|
2174
|
-
try {
|
|
2175
|
-
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
2176
|
-
return JSON.parse(raw);
|
|
2177
|
-
} catch {
|
|
2178
|
-
return null;
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
async function writeCache(entry) {
|
|
2182
|
-
try {
|
|
2183
|
-
await mkdir(CACHE_DIR, { recursive: true });
|
|
2184
|
-
await writeFile(CACHE_FILE, JSON.stringify(entry));
|
|
2185
|
-
} catch {
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
async function fetchLatestVersion() {
|
|
2189
|
-
try {
|
|
2190
|
-
const controller = new AbortController();
|
|
2191
|
-
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
2192
|
-
const res = await fetch("https://registry.npmjs.org/@kitnai/cli/latest", {
|
|
2193
|
-
signal: controller.signal
|
|
2194
|
-
});
|
|
2195
|
-
clearTimeout(timeout);
|
|
2196
|
-
if (!res.ok) return null;
|
|
2197
|
-
const data = await res.json();
|
|
2198
|
-
return data.version ?? null;
|
|
2199
|
-
} catch {
|
|
2200
|
-
return null;
|
|
2201
|
-
}
|
|
2202
|
-
}
|
|
2203
|
-
function isNewer(latest, current) {
|
|
2204
|
-
const [lMaj, lMin, lPat] = latest.split(".").map(Number);
|
|
2205
|
-
const [cMaj, cMin, cPat] = current.split(".").map(Number);
|
|
2206
|
-
if (lMaj !== cMaj) return lMaj > cMaj;
|
|
2207
|
-
if (lMin !== cMin) return lMin > cMin;
|
|
2208
|
-
return lPat > cPat;
|
|
2209
|
-
}
|
|
2210
|
-
function startUpdateCheck(currentVersion) {
|
|
2211
|
-
let message = "";
|
|
2212
|
-
const check = (async () => {
|
|
2213
|
-
const cache = await readCache();
|
|
2214
|
-
let latest = null;
|
|
2215
|
-
if (cache && Date.now() - cache.checkedAt < CHECK_INTERVAL) {
|
|
2216
|
-
latest = cache.latest;
|
|
2217
|
-
} else {
|
|
2218
|
-
latest = await fetchLatestVersion();
|
|
2219
|
-
if (latest) {
|
|
2220
|
-
await writeCache({ latest, checkedAt: Date.now() });
|
|
2221
|
-
}
|
|
2222
|
-
}
|
|
2223
|
-
if (latest && isNewer(latest, currentVersion)) {
|
|
2224
|
-
message = [
|
|
2225
|
-
"",
|
|
2226
|
-
pc.yellow(` Update available: ${pc.dim(currentVersion)} \u2192 ${pc.green(latest)}`),
|
|
2227
|
-
pc.dim(` Run ${pc.cyan("npx @kitnai/cli@latest")} or ${pc.cyan("npm i -g @kitnai/cli")}`),
|
|
2228
|
-
""
|
|
2229
|
-
].join("\n");
|
|
2230
|
-
}
|
|
2231
|
-
})();
|
|
2232
|
-
check.catch(() => {
|
|
2233
|
-
});
|
|
2234
|
-
return () => {
|
|
2235
|
-
if (message) process.stderr.write(message);
|
|
2236
|
-
};
|
|
2237
|
-
}
|
|
2238
|
-
|
|
2239
|
-
// src/index.ts
|
|
2240
|
-
var VERSION = true ? "0.1.15" : "0.0.0-dev";
|
|
2354
|
+
var VERSION = true ? "0.1.17" : "0.0.0-dev";
|
|
2241
2355
|
var printUpdateNotice = startUpdateCheck(VERSION);
|
|
2242
2356
|
var program = new Command().name("kitn").description("Install AI agent components from the kitn registry").version(VERSION);
|
|
2243
|
-
program.command("init").description("Initialize kitn in your project").action(async () => {
|
|
2357
|
+
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) => {
|
|
2244
2358
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2245
|
-
await initCommand2();
|
|
2359
|
+
await initCommand2(opts);
|
|
2246
2360
|
});
|
|
2247
2361
|
program.command("add").description("Add components from the kitn registry").argument("[components...]", "component names to install").option("-o, --overwrite", "overwrite existing files without prompting").option("-t, --type <type>", "filter by component type").action(async (components, opts) => {
|
|
2248
2362
|
const { addCommand: addCommand2 } = await Promise.resolve().then(() => (init_add(), add_exports));
|
|
@@ -2276,6 +2390,10 @@ program.command("info").description("Show details about a component").argument("
|
|
|
2276
2390
|
const { infoCommand: infoCommand2 } = await Promise.resolve().then(() => (init_info(), info_exports));
|
|
2277
2391
|
await infoCommand2(component);
|
|
2278
2392
|
});
|
|
2393
|
+
program.command("check").description("Check for CLI updates").action(async () => {
|
|
2394
|
+
const { checkCommand: checkCommand2 } = await Promise.resolve().then(() => (init_check(), check_exports));
|
|
2395
|
+
await checkCommand2(VERSION);
|
|
2396
|
+
});
|
|
2279
2397
|
var registry = program.command("registry").description("Manage component registries");
|
|
2280
2398
|
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").option("--homepage <url>", "registry homepage URL").option("--description <text>", "short description of the registry").action(async (namespace, url, opts) => {
|
|
2281
2399
|
const { registryAddCommand: registryAddCommand2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|