@kitnai/cli 0.1.16 → 0.1.18
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 +36 -7
- package/dist/index.js +340 -144
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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";
|
|
@@ -565,6 +645,41 @@ var init_parse_ref = __esm({
|
|
|
565
645
|
}
|
|
566
646
|
});
|
|
567
647
|
|
|
648
|
+
// src/utils/type-aliases.ts
|
|
649
|
+
function resolveTypeAlias(input) {
|
|
650
|
+
return TYPE_ALIASES[input.toLowerCase()];
|
|
651
|
+
}
|
|
652
|
+
function toComponentType(shortType) {
|
|
653
|
+
const ct = SHORT_TO_COMPONENT[shortType];
|
|
654
|
+
if (!ct) throw new Error(`Unknown component type: ${shortType}`);
|
|
655
|
+
return ct;
|
|
656
|
+
}
|
|
657
|
+
var TYPE_ALIASES, SHORT_TO_COMPONENT;
|
|
658
|
+
var init_type_aliases = __esm({
|
|
659
|
+
"src/utils/type-aliases.ts"() {
|
|
660
|
+
"use strict";
|
|
661
|
+
TYPE_ALIASES = {
|
|
662
|
+
agent: "agent",
|
|
663
|
+
agents: "agent",
|
|
664
|
+
tool: "tool",
|
|
665
|
+
tools: "tool",
|
|
666
|
+
skill: "skill",
|
|
667
|
+
skills: "skill",
|
|
668
|
+
storage: "storage",
|
|
669
|
+
storages: "storage",
|
|
670
|
+
package: "package",
|
|
671
|
+
packages: "package"
|
|
672
|
+
};
|
|
673
|
+
SHORT_TO_COMPONENT = {
|
|
674
|
+
agent: "kitn:agent",
|
|
675
|
+
tool: "kitn:tool",
|
|
676
|
+
skill: "kitn:skill",
|
|
677
|
+
storage: "kitn:storage",
|
|
678
|
+
package: "kitn:package"
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
|
|
568
683
|
// src/registry/schema.ts
|
|
569
684
|
import { z as z2 } from "zod";
|
|
570
685
|
var componentType2, registryFileSchema, changelogEntrySchema, envVarConfigSchema, componentConfigSchema, registryItemSchema, registryIndexItemSchema, registryIndexSchema, typeToDir;
|
|
@@ -674,6 +789,29 @@ async function addCommand(components, opts) {
|
|
|
674
789
|
p2.log.error("Please specify at least one component to add.");
|
|
675
790
|
process.exit(1);
|
|
676
791
|
}
|
|
792
|
+
let typeFilter;
|
|
793
|
+
const firstAlias = resolveTypeAlias(components[0]);
|
|
794
|
+
if (firstAlias) {
|
|
795
|
+
if (components.length === 1) {
|
|
796
|
+
p2.log.error(
|
|
797
|
+
`${pc3.bold(components[0])} looks like a type, not a component name. Usage: ${pc3.cyan(`kitn add ${components[0]} <name>`)}`
|
|
798
|
+
);
|
|
799
|
+
process.exit(1);
|
|
800
|
+
}
|
|
801
|
+
typeFilter = firstAlias;
|
|
802
|
+
components = components.slice(1);
|
|
803
|
+
}
|
|
804
|
+
if (opts.type) {
|
|
805
|
+
const flagAlias = resolveTypeAlias(opts.type);
|
|
806
|
+
if (!flagAlias) {
|
|
807
|
+
p2.log.error(`Unknown type ${pc3.bold(opts.type)}. Valid types: agent, tool, skill, storage, package`);
|
|
808
|
+
process.exit(1);
|
|
809
|
+
}
|
|
810
|
+
if (typeFilter && typeFilter !== flagAlias) {
|
|
811
|
+
p2.log.warn(`Positional type ${pc3.bold(typeFilter)} overridden by --type ${pc3.bold(flagAlias)}`);
|
|
812
|
+
}
|
|
813
|
+
typeFilter = flagAlias;
|
|
814
|
+
}
|
|
677
815
|
const resolvedComponents = components.map((c) => {
|
|
678
816
|
if (c === "routes") {
|
|
679
817
|
const fw2 = config.framework ?? "hono";
|
|
@@ -685,12 +823,79 @@ async function addCommand(components, opts) {
|
|
|
685
823
|
const fetcher = new RegistryFetcher(config.registries);
|
|
686
824
|
const s = p2.spinner();
|
|
687
825
|
s.start("Resolving dependencies...");
|
|
826
|
+
const preResolvedTypes = /* @__PURE__ */ new Map();
|
|
827
|
+
let expandedNames = [...resolvedComponents];
|
|
828
|
+
try {
|
|
829
|
+
const namespacesToFetch = Object.keys(config.registries);
|
|
830
|
+
const allIndexItems = [];
|
|
831
|
+
for (const namespace of namespacesToFetch) {
|
|
832
|
+
try {
|
|
833
|
+
const index = await fetcher.fetchIndex(namespace);
|
|
834
|
+
for (const item of index.items) {
|
|
835
|
+
allIndexItems.push({ name: item.name, type: item.type, namespace });
|
|
836
|
+
}
|
|
837
|
+
} catch {
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
const newExpandedNames = [];
|
|
841
|
+
for (const name of resolvedComponents) {
|
|
842
|
+
const ref = refs.find((r) => r.name === name) ?? { namespace: "@kitn", name, version: void 0 };
|
|
843
|
+
let matches = allIndexItems.filter((i) => i.name === name && (ref.namespace === "@kitn" || i.namespace === ref.namespace));
|
|
844
|
+
if (typeFilter) {
|
|
845
|
+
const filteredType = toComponentType(typeFilter);
|
|
846
|
+
matches = matches.filter((m) => m.type === filteredType);
|
|
847
|
+
}
|
|
848
|
+
if (matches.length === 0) {
|
|
849
|
+
newExpandedNames.push(name);
|
|
850
|
+
} else if (matches.length === 1) {
|
|
851
|
+
preResolvedTypes.set(name, matches[0].type);
|
|
852
|
+
newExpandedNames.push(name);
|
|
853
|
+
} else {
|
|
854
|
+
const uniqueTypes = [...new Set(matches.map((m) => m.type))];
|
|
855
|
+
if (uniqueTypes.length === 1) {
|
|
856
|
+
preResolvedTypes.set(name, uniqueTypes[0]);
|
|
857
|
+
newExpandedNames.push(name);
|
|
858
|
+
} else {
|
|
859
|
+
s.stop("Disambiguation needed");
|
|
860
|
+
if (!process.stdin.isTTY) {
|
|
861
|
+
const typeNames = uniqueTypes.map((t) => t.replace("kitn:", "")).join(", ");
|
|
862
|
+
p2.log.error(
|
|
863
|
+
`Multiple components named ${pc3.bold(name)} found (${typeNames}). Specify the type: ${pc3.cyan(`kitn add ${uniqueTypes[0].replace("kitn:", "")} ${name}`)}`
|
|
864
|
+
);
|
|
865
|
+
process.exit(1);
|
|
866
|
+
}
|
|
867
|
+
const selected = await p2.multiselect({
|
|
868
|
+
message: `Multiple types found for ${pc3.bold(name)}. Which do you want to install?`,
|
|
869
|
+
options: uniqueTypes.map((t) => ({
|
|
870
|
+
value: t,
|
|
871
|
+
label: `${name} ${pc3.dim(`(${t.replace("kitn:", "")})`)}`
|
|
872
|
+
}))
|
|
873
|
+
});
|
|
874
|
+
if (p2.isCancel(selected)) {
|
|
875
|
+
p2.cancel("Cancelled.");
|
|
876
|
+
process.exit(0);
|
|
877
|
+
}
|
|
878
|
+
for (const type of selected) {
|
|
879
|
+
preResolvedTypes.set(name, type);
|
|
880
|
+
newExpandedNames.push(name);
|
|
881
|
+
}
|
|
882
|
+
s.start("Resolving dependencies...");
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
expandedNames = newExpandedNames;
|
|
887
|
+
} catch (err) {
|
|
888
|
+
s.stop(pc3.red("Failed to resolve dependencies"));
|
|
889
|
+
p2.log.error(err.message);
|
|
890
|
+
process.exit(1);
|
|
891
|
+
}
|
|
688
892
|
let resolved;
|
|
689
893
|
try {
|
|
690
|
-
resolved = await resolveDependencies(
|
|
894
|
+
resolved = await resolveDependencies(expandedNames, async (name) => {
|
|
691
895
|
const ref = refs.find((r) => r.name === name) ?? { namespace: "@kitn", name, version: void 0 };
|
|
692
896
|
const index = await fetcher.fetchIndex(ref.namespace);
|
|
693
|
-
const
|
|
897
|
+
const preResolved = preResolvedTypes.get(name);
|
|
898
|
+
const indexItem = preResolved ? index.items.find((i) => i.name === name && i.type === preResolved) : index.items.find((i) => i.name === name);
|
|
694
899
|
if (!indexItem) throw new Error(`Component '${name}' not found in ${ref.namespace} registry`);
|
|
695
900
|
const dir = typeToDir[indexItem.type];
|
|
696
901
|
return fetcher.fetchItem(name, dir, ref.namespace, ref.version);
|
|
@@ -702,7 +907,7 @@ async function addCommand(components, opts) {
|
|
|
702
907
|
}
|
|
703
908
|
s.stop(`Resolved ${resolved.length} component(s)`);
|
|
704
909
|
p2.log.info("Components to install:\n" + resolved.map((item) => {
|
|
705
|
-
const isExplicit =
|
|
910
|
+
const isExplicit = expandedNames.includes(item.name) || components.includes(item.name);
|
|
706
911
|
const label = isExplicit ? item.name : `${item.name} ${pc3.dim("(dependency)")}`;
|
|
707
912
|
return ` ${pc3.cyan(label)}`;
|
|
708
913
|
}).join("\n"));
|
|
@@ -714,6 +919,13 @@ async function addCommand(components, opts) {
|
|
|
714
919
|
for (const item of resolved) {
|
|
715
920
|
if (item.dependencies) allDeps.push(...item.dependencies);
|
|
716
921
|
if (item.devDependencies) allDevDeps.push(...item.devDependencies);
|
|
922
|
+
const existingInstall = (config.installed ?? {})[item.name];
|
|
923
|
+
if (existingInstall && item.type === "kitn:package") {
|
|
924
|
+
const allContent = item.files.map((f) => f.content).join("\n");
|
|
925
|
+
if (contentHash(allContent) === existingInstall.hash) {
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
717
929
|
if (item.type === "kitn:package") {
|
|
718
930
|
const baseDir2 = config.aliases.base ?? "src/ai";
|
|
719
931
|
for (const file of item.files) {
|
|
@@ -899,7 +1111,7 @@ async function addCommand(components, opts) {
|
|
|
899
1111
|
}
|
|
900
1112
|
}
|
|
901
1113
|
if (created.length > 0) {
|
|
902
|
-
p2.log.success(`
|
|
1114
|
+
p2.log.success(`Added ${created.length} file(s):
|
|
903
1115
|
` + created.map((f) => ` ${pc3.green("+")} ${f}`).join("\n"));
|
|
904
1116
|
}
|
|
905
1117
|
if (updated.length > 0) {
|
|
@@ -917,13 +1129,14 @@ async function addCommand(components, opts) {
|
|
|
917
1129
|
p2.log.info(`${pc3.bold(item.name)}: ${item.docs}`);
|
|
918
1130
|
}
|
|
919
1131
|
}
|
|
920
|
-
const
|
|
1132
|
+
const resolvedNames = new Set(resolved.map((r) => r.name));
|
|
1133
|
+
const projectInstalled = new Set(Object.keys(config.installed ?? {}));
|
|
921
1134
|
const hints = [];
|
|
922
|
-
|
|
1135
|
+
const fw = config.framework ?? "hono";
|
|
1136
|
+
if (resolvedNames.has("core") && !resolvedNames.has(fw) && !projectInstalled.has(fw)) {
|
|
923
1137
|
hints.push(`Run ${pc3.cyan(`kitn add routes`)} to install the HTTP adapter.`);
|
|
924
1138
|
}
|
|
925
|
-
|
|
926
|
-
if (installedNames.has(fw) || installedNames.has("core") && installedNames.has(fw)) {
|
|
1139
|
+
if (resolvedNames.has(fw)) {
|
|
927
1140
|
hints.push(`Configure your AI provider in ${pc3.bold(baseDir + "/plugin.ts")}, then add to your server:`);
|
|
928
1141
|
hints.push("");
|
|
929
1142
|
hints.push(pc3.dim(` import { ai } from "./${baseDir.replace(/^src\//, "")}/plugin";`));
|
|
@@ -951,6 +1164,7 @@ var init_add = __esm({
|
|
|
951
1164
|
init_barrel_manager();
|
|
952
1165
|
init_hash();
|
|
953
1166
|
init_parse_ref();
|
|
1167
|
+
init_type_aliases();
|
|
954
1168
|
init_schema();
|
|
955
1169
|
}
|
|
956
1170
|
});
|
|
@@ -964,43 +1178,66 @@ import * as p3 from "@clack/prompts";
|
|
|
964
1178
|
import pc4 from "picocolors";
|
|
965
1179
|
import { mkdir as mkdir4, writeFile as writeFile7 } from "fs/promises";
|
|
966
1180
|
import { join as join8 } from "path";
|
|
967
|
-
async function initCommand() {
|
|
1181
|
+
async function initCommand(opts = {}) {
|
|
968
1182
|
p3.intro(pc4.bgCyan(pc4.black(" kitn init ")));
|
|
969
1183
|
const cwd = process.cwd();
|
|
970
1184
|
const existing = await readConfig(cwd);
|
|
971
1185
|
if (existing) {
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1186
|
+
if (opts.yes) {
|
|
1187
|
+
p3.log.warn("kitn.json already exists \u2014 overwriting (--yes).");
|
|
1188
|
+
} else {
|
|
1189
|
+
p3.log.warn("kitn.json already exists in this directory.");
|
|
1190
|
+
const shouldContinue = await p3.confirm({
|
|
1191
|
+
message: "Overwrite existing configuration?",
|
|
1192
|
+
initialValue: false
|
|
1193
|
+
});
|
|
1194
|
+
if (p3.isCancel(shouldContinue) || !shouldContinue) {
|
|
1195
|
+
p3.cancel("Init cancelled.");
|
|
1196
|
+
process.exit(0);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
let runtime;
|
|
1201
|
+
if (opts.runtime) {
|
|
1202
|
+
if (!["bun", "node", "deno"].includes(opts.runtime)) {
|
|
1203
|
+
p3.log.error(`Invalid runtime: ${opts.runtime}. Must be bun, node, or deno.`);
|
|
1204
|
+
process.exit(1);
|
|
1205
|
+
}
|
|
1206
|
+
runtime = opts.runtime;
|
|
1207
|
+
} else if (opts.yes) {
|
|
1208
|
+
runtime = "bun";
|
|
1209
|
+
} else {
|
|
1210
|
+
const selected = await p3.select({
|
|
1211
|
+
message: "Which runtime do you use?",
|
|
1212
|
+
options: [
|
|
1213
|
+
{ value: "bun", label: "Bun", hint: "recommended" },
|
|
1214
|
+
{ value: "node", label: "Node.js" },
|
|
1215
|
+
{ value: "deno", label: "Deno" }
|
|
1216
|
+
]
|
|
976
1217
|
});
|
|
977
|
-
if (p3.isCancel(
|
|
1218
|
+
if (p3.isCancel(selected)) {
|
|
978
1219
|
p3.cancel("Init cancelled.");
|
|
979
1220
|
process.exit(0);
|
|
980
1221
|
}
|
|
1222
|
+
runtime = selected;
|
|
981
1223
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
});
|
|
999
|
-
if (p3.isCancel(base)) {
|
|
1000
|
-
p3.cancel("Init cancelled.");
|
|
1001
|
-
process.exit(0);
|
|
1224
|
+
let baseDir;
|
|
1225
|
+
if (opts.base) {
|
|
1226
|
+
baseDir = opts.base;
|
|
1227
|
+
} else if (opts.yes) {
|
|
1228
|
+
baseDir = "src/ai";
|
|
1229
|
+
} else {
|
|
1230
|
+
const base = await p3.text({
|
|
1231
|
+
message: "Where should kitn components be installed?",
|
|
1232
|
+
initialValue: "src/ai",
|
|
1233
|
+
placeholder: "src/ai"
|
|
1234
|
+
});
|
|
1235
|
+
if (p3.isCancel(base)) {
|
|
1236
|
+
p3.cancel("Init cancelled.");
|
|
1237
|
+
process.exit(0);
|
|
1238
|
+
}
|
|
1239
|
+
baseDir = base;
|
|
1002
1240
|
}
|
|
1003
|
-
const baseDir = base;
|
|
1004
1241
|
const config = {
|
|
1005
1242
|
runtime,
|
|
1006
1243
|
framework: "hono",
|
|
@@ -1047,6 +1284,15 @@ async function initCommand() {
|
|
|
1047
1284
|
].join("\n"),
|
|
1048
1285
|
"Add this to your server entry point:"
|
|
1049
1286
|
);
|
|
1287
|
+
p3.log.message(
|
|
1288
|
+
[
|
|
1289
|
+
pc4.bold("Add your first agent:"),
|
|
1290
|
+
` ${pc4.cyan("kitn add weather-agent")}`,
|
|
1291
|
+
"",
|
|
1292
|
+
pc4.bold("Browse all components:"),
|
|
1293
|
+
` ${pc4.cyan("kitn list")}`
|
|
1294
|
+
].join("\n")
|
|
1295
|
+
);
|
|
1050
1296
|
p3.outro("Done!");
|
|
1051
1297
|
}
|
|
1052
1298
|
var PLUGIN_TEMPLATE;
|
|
@@ -1094,7 +1340,7 @@ async function listCommand(typeFilter, opts) {
|
|
|
1094
1340
|
process.exit(1);
|
|
1095
1341
|
}
|
|
1096
1342
|
const rawType = typeFilter ?? opts.type;
|
|
1097
|
-
const resolvedType = rawType ?
|
|
1343
|
+
const resolvedType = rawType ? resolveTypeAlias(rawType) : void 0;
|
|
1098
1344
|
if (rawType && !resolvedType) {
|
|
1099
1345
|
p4.log.error(`Unknown type ${pc5.bold(rawType)}. Valid types: agent, tool, skill, storage, package`);
|
|
1100
1346
|
process.exit(1);
|
|
@@ -1196,24 +1442,12 @@ async function listCommand(typeFilter, opts) {
|
|
|
1196
1442
|
${pc5.dim(parts.join(" \xB7 "))}
|
|
1197
1443
|
`);
|
|
1198
1444
|
}
|
|
1199
|
-
var TYPE_ALIASES;
|
|
1200
1445
|
var init_list = __esm({
|
|
1201
1446
|
"src/commands/list.ts"() {
|
|
1202
1447
|
"use strict";
|
|
1203
1448
|
init_config();
|
|
1449
|
+
init_type_aliases();
|
|
1204
1450
|
init_fetcher();
|
|
1205
|
-
TYPE_ALIASES = {
|
|
1206
|
-
agent: "agent",
|
|
1207
|
-
agents: "agent",
|
|
1208
|
-
tool: "tool",
|
|
1209
|
-
tools: "tool",
|
|
1210
|
-
skill: "skill",
|
|
1211
|
-
skills: "skill",
|
|
1212
|
-
storage: "storage",
|
|
1213
|
-
storages: "storage",
|
|
1214
|
-
package: "package",
|
|
1215
|
-
packages: "package"
|
|
1216
|
-
};
|
|
1217
1451
|
}
|
|
1218
1452
|
});
|
|
1219
1453
|
|
|
@@ -1458,8 +1692,8 @@ async function scanForComponents(cwd, paths) {
|
|
|
1458
1692
|
const resolvedCwd = resolve(cwd);
|
|
1459
1693
|
if (paths && paths.length > 0) {
|
|
1460
1694
|
const results = [];
|
|
1461
|
-
for (const
|
|
1462
|
-
const absPath = resolve(resolvedCwd,
|
|
1695
|
+
for (const p13 of paths) {
|
|
1696
|
+
const absPath = resolve(resolvedCwd, p13);
|
|
1463
1697
|
if (await fileExists(join11(absPath, "registry.json"))) {
|
|
1464
1698
|
results.push(absPath);
|
|
1465
1699
|
continue;
|
|
@@ -2099,6 +2333,39 @@ var init_info = __esm({
|
|
|
2099
2333
|
}
|
|
2100
2334
|
});
|
|
2101
2335
|
|
|
2336
|
+
// src/commands/check.ts
|
|
2337
|
+
var check_exports = {};
|
|
2338
|
+
__export(check_exports, {
|
|
2339
|
+
checkCommand: () => checkCommand
|
|
2340
|
+
});
|
|
2341
|
+
import * as p11 from "@clack/prompts";
|
|
2342
|
+
import pc10 from "picocolors";
|
|
2343
|
+
async function checkCommand(currentVersion) {
|
|
2344
|
+
p11.intro(pc10.bgCyan(pc10.black(" kitn check ")));
|
|
2345
|
+
p11.log.info(`kitn v${currentVersion}`);
|
|
2346
|
+
const s = p11.spinner();
|
|
2347
|
+
s.start("Checking for updates...");
|
|
2348
|
+
const latest = await fetchLatestVersion();
|
|
2349
|
+
if (!latest) {
|
|
2350
|
+
s.stop(pc10.yellow("Could not reach the npm registry"));
|
|
2351
|
+
p11.outro("Try again later.");
|
|
2352
|
+
return;
|
|
2353
|
+
}
|
|
2354
|
+
if (isNewer(latest, currentVersion)) {
|
|
2355
|
+
s.stop(pc10.yellow(`Update available: ${currentVersion} \u2192 ${latest}`));
|
|
2356
|
+
p11.log.message(` Run: ${pc10.cyan("npm i -g @kitnai/cli")}`);
|
|
2357
|
+
} else {
|
|
2358
|
+
s.stop(pc10.green("You're on the latest version"));
|
|
2359
|
+
}
|
|
2360
|
+
p11.outro("");
|
|
2361
|
+
}
|
|
2362
|
+
var init_check = __esm({
|
|
2363
|
+
"src/commands/check.ts"() {
|
|
2364
|
+
"use strict";
|
|
2365
|
+
init_update_check();
|
|
2366
|
+
}
|
|
2367
|
+
});
|
|
2368
|
+
|
|
2102
2369
|
// src/commands/registry.ts
|
|
2103
2370
|
var registry_exports = {};
|
|
2104
2371
|
__export(registry_exports, {
|
|
@@ -2106,8 +2373,8 @@ __export(registry_exports, {
|
|
|
2106
2373
|
registryListCommand: () => registryListCommand,
|
|
2107
2374
|
registryRemoveCommand: () => registryRemoveCommand
|
|
2108
2375
|
});
|
|
2109
|
-
import * as
|
|
2110
|
-
import
|
|
2376
|
+
import * as p12 from "@clack/prompts";
|
|
2377
|
+
import pc11 from "picocolors";
|
|
2111
2378
|
async function registryAddCommand(namespace, url, opts = {}) {
|
|
2112
2379
|
const cwd = opts.cwd ?? process.cwd();
|
|
2113
2380
|
const config = await readConfig(cwd);
|
|
@@ -2133,10 +2400,10 @@ async function registryAddCommand(namespace, url, opts = {}) {
|
|
|
2133
2400
|
config.registries[namespace] = url;
|
|
2134
2401
|
}
|
|
2135
2402
|
await writeConfig(cwd, config);
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
if (opts.homepage)
|
|
2139
|
-
if (opts.description)
|
|
2403
|
+
p12.log.success(`Added registry ${pc11.bold(namespace)}`);
|
|
2404
|
+
p12.log.message(pc11.dim(` ${url}`));
|
|
2405
|
+
if (opts.homepage) p12.log.message(pc11.dim(` Homepage: ${opts.homepage}`));
|
|
2406
|
+
if (opts.description) p12.log.message(pc11.dim(` ${opts.description}`));
|
|
2140
2407
|
}
|
|
2141
2408
|
async function registryRemoveCommand(namespace, opts = {}) {
|
|
2142
2409
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -2158,10 +2425,10 @@ async function registryRemoveCommand(namespace, opts = {}) {
|
|
|
2158
2425
|
}
|
|
2159
2426
|
delete config.registries[namespace];
|
|
2160
2427
|
await writeConfig(cwd, config);
|
|
2161
|
-
|
|
2428
|
+
p12.log.success(`Removed registry ${pc11.bold(namespace)}`);
|
|
2162
2429
|
if (affectedComponents.length > 0) {
|
|
2163
|
-
|
|
2164
|
-
` + affectedComponents.map((name) => ` ${
|
|
2430
|
+
p12.log.warn(`${affectedComponents.length} installed component(s) referenced this registry:
|
|
2431
|
+
` + affectedComponents.map((name) => ` ${pc11.yellow("!")} ${name}`).join("\n"));
|
|
2165
2432
|
}
|
|
2166
2433
|
return { affectedComponents };
|
|
2167
2434
|
}
|
|
@@ -2176,15 +2443,15 @@ async function registryListCommand(opts = {}) {
|
|
|
2176
2443
|
return { namespace, url, homepage, description };
|
|
2177
2444
|
});
|
|
2178
2445
|
if (entries.length === 0) {
|
|
2179
|
-
|
|
2446
|
+
p12.log.message(pc11.dim(" No registries configured."));
|
|
2180
2447
|
} else {
|
|
2181
2448
|
const lines = [];
|
|
2182
2449
|
for (const { namespace, url, homepage, description } of entries) {
|
|
2183
|
-
lines.push(` ${
|
|
2450
|
+
lines.push(` ${pc11.bold(namespace.padEnd(16))} ${pc11.dim(url)}`);
|
|
2184
2451
|
if (description) lines.push(` ${" ".repeat(16)} ${description}`);
|
|
2185
|
-
if (homepage) lines.push(` ${" ".repeat(16)} ${
|
|
2452
|
+
if (homepage) lines.push(` ${" ".repeat(16)} ${pc11.dim(homepage)}`);
|
|
2186
2453
|
}
|
|
2187
|
-
|
|
2454
|
+
p12.log.message(lines.join("\n"));
|
|
2188
2455
|
}
|
|
2189
2456
|
return entries;
|
|
2190
2457
|
}
|
|
@@ -2196,91 +2463,16 @@ var init_registry = __esm({
|
|
|
2196
2463
|
});
|
|
2197
2464
|
|
|
2198
2465
|
// src/index.ts
|
|
2466
|
+
init_update_check();
|
|
2199
2467
|
import { Command } from "commander";
|
|
2200
|
-
|
|
2201
|
-
// src/utils/update-check.ts
|
|
2202
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
2203
|
-
import { join } from "path";
|
|
2204
|
-
import { homedir } from "os";
|
|
2205
|
-
import pc from "picocolors";
|
|
2206
|
-
var CACHE_DIR = join(homedir(), ".kitn");
|
|
2207
|
-
var CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
2208
|
-
var CHECK_INTERVAL = 60 * 60 * 1e3;
|
|
2209
|
-
async function readCache() {
|
|
2210
|
-
try {
|
|
2211
|
-
const raw = await readFile(CACHE_FILE, "utf-8");
|
|
2212
|
-
return JSON.parse(raw);
|
|
2213
|
-
} catch {
|
|
2214
|
-
return null;
|
|
2215
|
-
}
|
|
2216
|
-
}
|
|
2217
|
-
async function writeCache(entry) {
|
|
2218
|
-
try {
|
|
2219
|
-
await mkdir(CACHE_DIR, { recursive: true });
|
|
2220
|
-
await writeFile(CACHE_FILE, JSON.stringify(entry));
|
|
2221
|
-
} catch {
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2224
|
-
async function fetchLatestVersion() {
|
|
2225
|
-
try {
|
|
2226
|
-
const controller = new AbortController();
|
|
2227
|
-
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
2228
|
-
const res = await fetch("https://registry.npmjs.org/@kitnai/cli/latest", {
|
|
2229
|
-
signal: controller.signal
|
|
2230
|
-
});
|
|
2231
|
-
clearTimeout(timeout);
|
|
2232
|
-
if (!res.ok) return null;
|
|
2233
|
-
const data = await res.json();
|
|
2234
|
-
return data.version ?? null;
|
|
2235
|
-
} catch {
|
|
2236
|
-
return null;
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
function isNewer(latest, current) {
|
|
2240
|
-
const [lMaj, lMin, lPat] = latest.split(".").map(Number);
|
|
2241
|
-
const [cMaj, cMin, cPat] = current.split(".").map(Number);
|
|
2242
|
-
if (lMaj !== cMaj) return lMaj > cMaj;
|
|
2243
|
-
if (lMin !== cMin) return lMin > cMin;
|
|
2244
|
-
return lPat > cPat;
|
|
2245
|
-
}
|
|
2246
|
-
function startUpdateCheck(currentVersion) {
|
|
2247
|
-
let message = "";
|
|
2248
|
-
const check = (async () => {
|
|
2249
|
-
const cache = await readCache();
|
|
2250
|
-
let latest = null;
|
|
2251
|
-
if (cache && Date.now() - cache.checkedAt < CHECK_INTERVAL) {
|
|
2252
|
-
latest = cache.latest;
|
|
2253
|
-
} else {
|
|
2254
|
-
latest = await fetchLatestVersion();
|
|
2255
|
-
if (latest) {
|
|
2256
|
-
await writeCache({ latest, checkedAt: Date.now() });
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
if (latest && isNewer(latest, currentVersion)) {
|
|
2260
|
-
message = [
|
|
2261
|
-
"",
|
|
2262
|
-
pc.yellow(` Update available: ${pc.dim(currentVersion)} \u2192 ${pc.green(latest)}`),
|
|
2263
|
-
pc.dim(` Run ${pc.cyan("npx @kitnai/cli@latest")} or ${pc.cyan("npm i -g @kitnai/cli")}`),
|
|
2264
|
-
""
|
|
2265
|
-
].join("\n");
|
|
2266
|
-
}
|
|
2267
|
-
})();
|
|
2268
|
-
check.catch(() => {
|
|
2269
|
-
});
|
|
2270
|
-
return () => {
|
|
2271
|
-
if (message) process.stderr.write(message);
|
|
2272
|
-
};
|
|
2273
|
-
}
|
|
2274
|
-
|
|
2275
|
-
// src/index.ts
|
|
2276
|
-
var VERSION = true ? "0.1.16" : "0.0.0-dev";
|
|
2468
|
+
var VERSION = true ? "0.1.18" : "0.0.0-dev";
|
|
2277
2469
|
var printUpdateNotice = startUpdateCheck(VERSION);
|
|
2278
2470
|
var program = new Command().name("kitn").description("Install AI agent components from the kitn registry").version(VERSION);
|
|
2279
|
-
program.command("init").description("Initialize kitn in your project").action(async () => {
|
|
2471
|
+
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) => {
|
|
2280
2472
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2281
|
-
await initCommand2();
|
|
2473
|
+
await initCommand2(opts);
|
|
2282
2474
|
});
|
|
2283
|
-
program.command("add").description("Add components from the kitn
|
|
2475
|
+
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) => {
|
|
2284
2476
|
const { addCommand: addCommand2 } = await Promise.resolve().then(() => (init_add(), add_exports));
|
|
2285
2477
|
await addCommand2(components, opts);
|
|
2286
2478
|
});
|
|
@@ -2312,6 +2504,10 @@ program.command("info").description("Show details about a component").argument("
|
|
|
2312
2504
|
const { infoCommand: infoCommand2 } = await Promise.resolve().then(() => (init_info(), info_exports));
|
|
2313
2505
|
await infoCommand2(component);
|
|
2314
2506
|
});
|
|
2507
|
+
program.command("check").description("Check for CLI updates").action(async () => {
|
|
2508
|
+
const { checkCommand: checkCommand2 } = await Promise.resolve().then(() => (init_check(), check_exports));
|
|
2509
|
+
await checkCommand2(VERSION);
|
|
2510
|
+
});
|
|
2315
2511
|
var registry = program.command("registry").description("Manage component registries");
|
|
2316
2512
|
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) => {
|
|
2317
2513
|
const { registryAddCommand: registryAddCommand2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|