@kitnai/cli 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/index.js +385 -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
|
-
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
94
|
-
import { join as
|
|
160
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink } from "fs/promises";
|
|
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,28 +177,49 @@ 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");
|
|
181
|
+
}
|
|
182
|
+
async function readLock(projectDir) {
|
|
183
|
+
try {
|
|
184
|
+
const raw = await readFile2(join3(projectDir, LOCK_FILE), "utf-8");
|
|
185
|
+
return lockSchema.parse(JSON.parse(raw));
|
|
186
|
+
} catch {
|
|
187
|
+
return {};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function writeLock(projectDir, lock) {
|
|
191
|
+
if (Object.keys(lock).length === 0) {
|
|
192
|
+
try {
|
|
193
|
+
await unlink(join3(projectDir, LOCK_FILE));
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
await writeFile2(join3(projectDir, LOCK_FILE), JSON.stringify(lock, null, 2) + "\n");
|
|
114
199
|
}
|
|
115
200
|
function getInstallPath(config, type, fileName, namespace) {
|
|
116
201
|
const aliasKey = typeToAliasKey[type];
|
|
117
202
|
const base = config.aliases[aliasKey];
|
|
118
203
|
if (namespace && namespace !== "@kitn") {
|
|
119
204
|
const nsDir = namespace.replace("@", "");
|
|
120
|
-
return
|
|
205
|
+
return join3(base, nsDir, fileName);
|
|
121
206
|
}
|
|
122
|
-
return
|
|
207
|
+
return join3(base, fileName);
|
|
123
208
|
}
|
|
124
|
-
var componentType, installedComponentSchema, registryEntrySchema, registryValueSchema, configSchema, FRAMEWORK_TO_ADAPTER, CONFIG_FILE, typeToAliasKey;
|
|
209
|
+
var componentType, installedComponentSchema, registryEntrySchema, registryValueSchema, configSchema, FRAMEWORK_TO_ADAPTER, CONFIG_FILE, LOCK_FILE, lockSchema, typeToAliasKey;
|
|
125
210
|
var init_config = __esm({
|
|
126
211
|
"src/utils/config.ts"() {
|
|
127
212
|
"use strict";
|
|
128
213
|
componentType = z.enum(["kitn:agent", "kitn:tool", "kitn:skill", "kitn:storage", "kitn:package"]);
|
|
129
214
|
installedComponentSchema = z.object({
|
|
130
215
|
registry: z.string().optional(),
|
|
216
|
+
type: componentType.optional(),
|
|
217
|
+
slot: z.string().optional(),
|
|
131
218
|
version: z.string(),
|
|
132
219
|
installedAt: z.string(),
|
|
133
220
|
files: z.array(z.string()),
|
|
134
|
-
hash: z.string()
|
|
221
|
+
hash: z.string(),
|
|
222
|
+
registryDependencies: z.array(z.string()).optional()
|
|
135
223
|
});
|
|
136
224
|
registryEntrySchema = z.object({
|
|
137
225
|
url: z.string(),
|
|
@@ -150,8 +238,7 @@ var init_config = __esm({
|
|
|
150
238
|
skills: z.string(),
|
|
151
239
|
storage: z.string()
|
|
152
240
|
}),
|
|
153
|
-
registries: z.record(z.string(), registryValueSchema)
|
|
154
|
-
installed: z.record(z.string(), installedComponentSchema).optional()
|
|
241
|
+
registries: z.record(z.string(), registryValueSchema)
|
|
155
242
|
});
|
|
156
243
|
FRAMEWORK_TO_ADAPTER = {
|
|
157
244
|
hono: "hono",
|
|
@@ -159,6 +246,8 @@ var init_config = __esm({
|
|
|
159
246
|
elysia: "elysia"
|
|
160
247
|
};
|
|
161
248
|
CONFIG_FILE = "kitn.json";
|
|
249
|
+
LOCK_FILE = "kitn.lock";
|
|
250
|
+
lockSchema = z.record(z.string(), installedComponentSchema);
|
|
162
251
|
typeToAliasKey = {
|
|
163
252
|
"kitn:agent": "agents",
|
|
164
253
|
"kitn:tool": "tools",
|
|
@@ -170,7 +259,7 @@ var init_config = __esm({
|
|
|
170
259
|
|
|
171
260
|
// src/installers/tsconfig-patcher.ts
|
|
172
261
|
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
173
|
-
import { join as
|
|
262
|
+
import { join as join4 } from "path";
|
|
174
263
|
function stripJsonc(text3) {
|
|
175
264
|
return text3.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([}\]])/g, "$1");
|
|
176
265
|
}
|
|
@@ -209,7 +298,7 @@ function patchTsconfig(tsconfigContent, paths, removePrefixes) {
|
|
|
209
298
|
return JSON.stringify(config, null, 2) + "\n";
|
|
210
299
|
}
|
|
211
300
|
async function patchProjectTsconfig(projectDir, paths, removePrefixes) {
|
|
212
|
-
const tsconfigPath =
|
|
301
|
+
const tsconfigPath = join4(projectDir, "tsconfig.json");
|
|
213
302
|
let content;
|
|
214
303
|
try {
|
|
215
304
|
content = await readFile3(tsconfigPath, "utf-8");
|
|
@@ -259,33 +348,6 @@ var init_barrel_manager = __esm({
|
|
|
259
348
|
}
|
|
260
349
|
});
|
|
261
350
|
|
|
262
|
-
// src/utils/detect.ts
|
|
263
|
-
import { access } from "fs/promises";
|
|
264
|
-
import { join as join4 } from "path";
|
|
265
|
-
async function detectPackageManager(dir) {
|
|
266
|
-
for (const [lockfile, pm] of LOCKFILE_MAP) {
|
|
267
|
-
try {
|
|
268
|
-
await access(join4(dir, lockfile));
|
|
269
|
-
return pm;
|
|
270
|
-
} catch {
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
var LOCKFILE_MAP;
|
|
276
|
-
var init_detect = __esm({
|
|
277
|
-
"src/utils/detect.ts"() {
|
|
278
|
-
"use strict";
|
|
279
|
-
LOCKFILE_MAP = [
|
|
280
|
-
["bun.lock", "bun"],
|
|
281
|
-
["bun.lockb", "bun"],
|
|
282
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
283
|
-
["yarn.lock", "yarn"],
|
|
284
|
-
["package-lock.json", "npm"]
|
|
285
|
-
];
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
|
|
289
351
|
// src/registry/fetcher.ts
|
|
290
352
|
function urlOf(entry) {
|
|
291
353
|
return typeof entry === "string" ? entry : entry.url;
|
|
@@ -729,6 +791,7 @@ var init_schema = __esm({
|
|
|
729
791
|
tsconfig: z2.record(z2.string(), z2.array(z2.string())).optional(),
|
|
730
792
|
envVars: z2.record(z2.string(), envVarConfigSchema).optional(),
|
|
731
793
|
categories: z2.array(z2.string()).optional(),
|
|
794
|
+
slot: z2.string().optional(),
|
|
732
795
|
docs: z2.string().optional(),
|
|
733
796
|
changelog: z2.array(changelogEntrySchema).optional()
|
|
734
797
|
});
|
|
@@ -746,6 +809,7 @@ var init_schema = __esm({
|
|
|
746
809
|
tsconfig: z2.record(z2.string(), z2.array(z2.string())).optional(),
|
|
747
810
|
docs: z2.string().optional(),
|
|
748
811
|
categories: z2.array(z2.string()).optional(),
|
|
812
|
+
slot: z2.string().optional(),
|
|
749
813
|
version: z2.string().optional(),
|
|
750
814
|
updatedAt: z2.string().optional(),
|
|
751
815
|
changelog: z2.array(changelogEntrySchema).optional()
|
|
@@ -756,6 +820,7 @@ var init_schema = __esm({
|
|
|
756
820
|
description: z2.string(),
|
|
757
821
|
registryDependencies: z2.array(z2.string()).optional(),
|
|
758
822
|
categories: z2.array(z2.string()).optional(),
|
|
823
|
+
slot: z2.string().optional(),
|
|
759
824
|
version: z2.string().optional(),
|
|
760
825
|
versions: z2.array(z2.string()).optional(),
|
|
761
826
|
updatedAt: z2.string().optional()
|
|
@@ -782,9 +847,9 @@ __export(add_exports, {
|
|
|
782
847
|
});
|
|
783
848
|
import * as p2 from "@clack/prompts";
|
|
784
849
|
import pc3 from "picocolors";
|
|
785
|
-
import { join as join7 } from "path";
|
|
850
|
+
import { join as join7, dirname as dirname3 } from "path";
|
|
786
851
|
import { existsSync } from "fs";
|
|
787
|
-
import { readFile as readFile6, writeFile as writeFile6, mkdir as mkdir3 } from "fs/promises";
|
|
852
|
+
import { readFile as readFile6, writeFile as writeFile6, mkdir as mkdir3, unlink as unlink2 } from "fs/promises";
|
|
788
853
|
import { relative as relative2 } from "path";
|
|
789
854
|
async function addCommand(components, opts) {
|
|
790
855
|
p2.intro(pc3.bgCyan(pc3.black(" kitn add ")));
|
|
@@ -794,9 +859,65 @@ async function addCommand(components, opts) {
|
|
|
794
859
|
p2.log.error("No kitn.json found. Run `kitn init` first.");
|
|
795
860
|
process.exit(1);
|
|
796
861
|
}
|
|
862
|
+
const lock = await readLock(cwd);
|
|
797
863
|
if (components.length === 0) {
|
|
798
|
-
|
|
799
|
-
|
|
864
|
+
const fetcher2 = new RegistryFetcher(config.registries);
|
|
865
|
+
const s2 = p2.spinner();
|
|
866
|
+
s2.start("Fetching registry...");
|
|
867
|
+
const allItems = [];
|
|
868
|
+
for (const namespace of Object.keys(config.registries)) {
|
|
869
|
+
try {
|
|
870
|
+
const index = await fetcher2.fetchIndex(namespace);
|
|
871
|
+
for (const item of index.items) {
|
|
872
|
+
allItems.push({ name: item.name, type: item.type, description: item.description, namespace });
|
|
873
|
+
}
|
|
874
|
+
} catch {
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
s2.stop(`Found ${allItems.length} component(s)`);
|
|
878
|
+
if (allItems.length === 0) {
|
|
879
|
+
p2.log.warn("No components found in configured registries.");
|
|
880
|
+
process.exit(0);
|
|
881
|
+
}
|
|
882
|
+
const installed = new Set(Object.keys(lock));
|
|
883
|
+
const typeLabels = {
|
|
884
|
+
"kitn:agent": "Agents",
|
|
885
|
+
"kitn:tool": "Tools",
|
|
886
|
+
"kitn:skill": "Skills",
|
|
887
|
+
"kitn:storage": "Storage",
|
|
888
|
+
"kitn:package": "Packages"
|
|
889
|
+
};
|
|
890
|
+
const groups = /* @__PURE__ */ new Map();
|
|
891
|
+
for (const item of allItems) {
|
|
892
|
+
if (!groups.has(item.type)) groups.set(item.type, []);
|
|
893
|
+
groups.get(item.type).push(item);
|
|
894
|
+
}
|
|
895
|
+
const options = [];
|
|
896
|
+
for (const [type, items] of groups) {
|
|
897
|
+
const label = typeLabels[type] ?? type;
|
|
898
|
+
options.push({ value: `__separator_${type}`, label: pc3.bold(`\u2500\u2500 ${label} ${"\u2500".repeat(Math.max(0, 40 - label.length))}`), hint: "" });
|
|
899
|
+
for (const item of items) {
|
|
900
|
+
const isInstalled = installed.has(item.name);
|
|
901
|
+
options.push({
|
|
902
|
+
value: item.name,
|
|
903
|
+
label: isInstalled ? pc3.dim(`${item.name} (installed)`) : item.name,
|
|
904
|
+
hint: item.description
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
const selected = await p2.multiselect({
|
|
909
|
+
message: "Select components to install:",
|
|
910
|
+
options
|
|
911
|
+
});
|
|
912
|
+
if (p2.isCancel(selected)) {
|
|
913
|
+
p2.cancel("Cancelled.");
|
|
914
|
+
process.exit(0);
|
|
915
|
+
}
|
|
916
|
+
components = selected.filter((s3) => !s3.startsWith("__separator_"));
|
|
917
|
+
if (components.length === 0) {
|
|
918
|
+
p2.log.warn("No components selected.");
|
|
919
|
+
process.exit(0);
|
|
920
|
+
}
|
|
800
921
|
}
|
|
801
922
|
let typeFilter;
|
|
802
923
|
const firstAlias = resolveTypeAlias(components[0]);
|
|
@@ -952,6 +1073,68 @@ async function addCommand(components, opts) {
|
|
|
952
1073
|
process.exit(1);
|
|
953
1074
|
}
|
|
954
1075
|
s.stop(`Resolved ${resolved.length} component(s)`);
|
|
1076
|
+
const slotReplacements = /* @__PURE__ */ new Map();
|
|
1077
|
+
for (const item of resolved) {
|
|
1078
|
+
if (!item.slot) continue;
|
|
1079
|
+
const existing = Object.entries(lock).find(
|
|
1080
|
+
([key, entry]) => key !== item.name && entry.slot === item.slot
|
|
1081
|
+
);
|
|
1082
|
+
if (!existing) continue;
|
|
1083
|
+
const [existingKey] = existing;
|
|
1084
|
+
const action = await p2.select({
|
|
1085
|
+
message: `${pc3.bold(existingKey)} already fills the ${pc3.cyan(item.slot)} slot. What would you like to do?`,
|
|
1086
|
+
options: [
|
|
1087
|
+
{ value: "replace", label: `Replace ${existingKey} with ${item.name}` },
|
|
1088
|
+
{ value: "add", label: `Add alongside ${existingKey}` }
|
|
1089
|
+
]
|
|
1090
|
+
});
|
|
1091
|
+
if (p2.isCancel(action)) {
|
|
1092
|
+
p2.cancel("Cancelled.");
|
|
1093
|
+
process.exit(0);
|
|
1094
|
+
}
|
|
1095
|
+
if (action === "replace") {
|
|
1096
|
+
slotReplacements.set(existingKey, item.name);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
if (slotReplacements.size > 0) {
|
|
1100
|
+
const baseDir2 = config.aliases.base ?? "src/ai";
|
|
1101
|
+
for (const [oldKey] of slotReplacements) {
|
|
1102
|
+
const oldEntry = lock[oldKey];
|
|
1103
|
+
if (!oldEntry) continue;
|
|
1104
|
+
for (const filePath of oldEntry.files) {
|
|
1105
|
+
try {
|
|
1106
|
+
await unlink2(join7(cwd, filePath));
|
|
1107
|
+
} catch {
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
const barrelPath2 = join7(cwd, baseDir2, "index.ts");
|
|
1111
|
+
const barrelEligibleDirs = /* @__PURE__ */ new Set([
|
|
1112
|
+
config.aliases.agents,
|
|
1113
|
+
config.aliases.tools,
|
|
1114
|
+
config.aliases.skills
|
|
1115
|
+
]);
|
|
1116
|
+
if (existsSync(barrelPath2)) {
|
|
1117
|
+
let barrelContent = await readFile6(barrelPath2, "utf-8");
|
|
1118
|
+
let barrelChanged = false;
|
|
1119
|
+
for (const filePath of oldEntry.files) {
|
|
1120
|
+
const fileDir = dirname3(filePath);
|
|
1121
|
+
if (!barrelEligibleDirs.has(fileDir)) continue;
|
|
1122
|
+
const barrelDir2 = join7(cwd, baseDir2);
|
|
1123
|
+
const importPath = "./" + relative2(barrelDir2, join7(cwd, filePath)).replace(/\\/g, "/");
|
|
1124
|
+
const updated2 = removeImportFromBarrel(barrelContent, importPath);
|
|
1125
|
+
if (updated2 !== barrelContent) {
|
|
1126
|
+
barrelContent = updated2;
|
|
1127
|
+
barrelChanged = true;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
if (barrelChanged) {
|
|
1131
|
+
await writeFile6(barrelPath2, barrelContent);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
delete lock[oldKey];
|
|
1135
|
+
p2.log.info(`Replaced ${pc3.dim(oldKey)} \u2192 ${pc3.cyan(slotReplacements.get(oldKey))}`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
955
1138
|
p2.log.info("Components to install:\n" + resolved.map((item) => {
|
|
956
1139
|
const isExplicit = expandedNames.includes(item.name) || components.includes(item.name);
|
|
957
1140
|
const label = isExplicit ? item.name : `${item.name} ${pc3.dim("(dependency)")}`;
|
|
@@ -965,7 +1148,7 @@ async function addCommand(components, opts) {
|
|
|
965
1148
|
for (const item of resolved) {
|
|
966
1149
|
if (item.dependencies) allDeps.push(...item.dependencies);
|
|
967
1150
|
if (item.devDependencies) allDevDeps.push(...item.devDependencies);
|
|
968
|
-
const existingInstall =
|
|
1151
|
+
const existingInstall = lock[item.name];
|
|
969
1152
|
if (existingInstall && item.type === "kitn:package") {
|
|
970
1153
|
const allContent = item.files.map((f) => f.content).join("\n");
|
|
971
1154
|
if (contentHash(allContent) === existingInstall.hash) {
|
|
@@ -1011,18 +1194,19 @@ async function addCommand(components, opts) {
|
|
|
1011
1194
|
break;
|
|
1012
1195
|
}
|
|
1013
1196
|
}
|
|
1014
|
-
const installed = config.installed ?? {};
|
|
1015
1197
|
const allContent = item.files.map((f) => f.content).join("\n");
|
|
1016
1198
|
const ref = refs.find((r) => r.name === item.name) ?? { namespace: "@kitn", name: item.name, version: void 0 };
|
|
1017
1199
|
const installedKey = ref.namespace === "@kitn" ? item.name : `${ref.namespace}/${item.name}`;
|
|
1018
|
-
|
|
1200
|
+
lock[installedKey] = {
|
|
1019
1201
|
registry: ref.namespace,
|
|
1202
|
+
type: item.type,
|
|
1203
|
+
...item.slot && { slot: item.slot },
|
|
1020
1204
|
version: item.version ?? "1.0.0",
|
|
1021
1205
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1022
1206
|
files: item.files.map((f) => join7(baseDir2, f.path)),
|
|
1023
|
-
hash: contentHash(allContent)
|
|
1207
|
+
hash: contentHash(allContent),
|
|
1208
|
+
registryDependencies: item.registryDependencies
|
|
1024
1209
|
};
|
|
1025
|
-
config.installed = installed;
|
|
1026
1210
|
} else {
|
|
1027
1211
|
const ref = refs.find((r) => r.name === item.name) ?? { namespace: "@kitn", name: item.name, version: void 0 };
|
|
1028
1212
|
const ns = ref.namespace;
|
|
@@ -1078,23 +1262,24 @@ async function addCommand(components, opts) {
|
|
|
1078
1262
|
break;
|
|
1079
1263
|
}
|
|
1080
1264
|
}
|
|
1081
|
-
const installed = config.installed ?? {};
|
|
1082
1265
|
const allContent = item.files.map((f) => {
|
|
1083
1266
|
const fn = f.path.split("/").pop();
|
|
1084
1267
|
return rewriteKitnImports(f.content, item.type, fn, config.aliases);
|
|
1085
1268
|
}).join("\n");
|
|
1086
1269
|
const installedKey = ns === "@kitn" ? item.name : `${ns}/${item.name}`;
|
|
1087
|
-
|
|
1270
|
+
lock[installedKey] = {
|
|
1088
1271
|
registry: ns,
|
|
1272
|
+
type: item.type,
|
|
1273
|
+
...item.slot && { slot: item.slot },
|
|
1089
1274
|
version: item.version ?? "1.0.0",
|
|
1090
1275
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1091
1276
|
files: item.files.map((f) => {
|
|
1092
1277
|
const fileName = f.path.split("/").pop();
|
|
1093
1278
|
return getInstallPath(config, item.type, fileName, ns);
|
|
1094
1279
|
}),
|
|
1095
|
-
hash: contentHash(allContent)
|
|
1280
|
+
hash: contentHash(allContent),
|
|
1281
|
+
registryDependencies: item.registryDependencies
|
|
1096
1282
|
};
|
|
1097
|
-
config.installed = installed;
|
|
1098
1283
|
}
|
|
1099
1284
|
}
|
|
1100
1285
|
const BARREL_ELIGIBLE = /* @__PURE__ */ new Set(["kitn:agent", "kitn:tool", "kitn:skill"]);
|
|
@@ -1139,6 +1324,7 @@ async function addCommand(components, opts) {
|
|
|
1139
1324
|
}
|
|
1140
1325
|
}
|
|
1141
1326
|
await writeConfig(cwd, config);
|
|
1327
|
+
await writeLock(cwd, lock);
|
|
1142
1328
|
const uniqueDeps = [...new Set(allDeps)];
|
|
1143
1329
|
const uniqueDevDeps = [...new Set(allDevDeps)].filter((d) => !uniqueDeps.includes(d));
|
|
1144
1330
|
const totalDeps = uniqueDeps.length + uniqueDevDeps.length;
|
|
@@ -1175,7 +1361,7 @@ async function addCommand(components, opts) {
|
|
|
1175
1361
|
}
|
|
1176
1362
|
}
|
|
1177
1363
|
const resolvedNames = new Set(resolved.map((r) => r.name));
|
|
1178
|
-
const projectInstalled = new Set(Object.keys(
|
|
1364
|
+
const projectInstalled = new Set(Object.keys(lock));
|
|
1179
1365
|
const hints = [];
|
|
1180
1366
|
const adapterName = resolveRoutesAlias(config);
|
|
1181
1367
|
if (resolvedNames.has("core") && !resolvedNames.has(adapterName) && !projectInstalled.has(adapterName)) {
|
|
@@ -1437,7 +1623,7 @@ async function listCommand(typeFilter, opts) {
|
|
|
1437
1623
|
for (const e of errors) {
|
|
1438
1624
|
p4.log.warn(`${pc5.yellow("\u26A0")} Failed to fetch ${e}`);
|
|
1439
1625
|
}
|
|
1440
|
-
const installed =
|
|
1626
|
+
const installed = await readLock(cwd);
|
|
1441
1627
|
const typeGroups = /* @__PURE__ */ new Map();
|
|
1442
1628
|
for (const item of allItems) {
|
|
1443
1629
|
const group = item.type.replace("kitn:", "");
|
|
@@ -1530,8 +1716,9 @@ async function diffCommand(componentName) {
|
|
|
1530
1716
|
}
|
|
1531
1717
|
const input = componentName === "routes" ? resolveRoutesAlias(config) : componentName;
|
|
1532
1718
|
const ref = parseComponentRef(input);
|
|
1719
|
+
const lock = await readLock(cwd);
|
|
1533
1720
|
const installedKey = ref.namespace === "@kitn" ? ref.name : `${ref.namespace}/${ref.name}`;
|
|
1534
|
-
const installed =
|
|
1721
|
+
const installed = lock[installedKey];
|
|
1535
1722
|
if (!installed) {
|
|
1536
1723
|
p5.log.error(`Component '${ref.name}' is not installed.`);
|
|
1537
1724
|
process.exit(1);
|
|
@@ -1609,36 +1796,16 @@ __export(remove_exports, {
|
|
|
1609
1796
|
});
|
|
1610
1797
|
import * as p6 from "@clack/prompts";
|
|
1611
1798
|
import pc6 from "picocolors";
|
|
1612
|
-
import { join as join10, relative as relative3, dirname as
|
|
1613
|
-
import { unlink, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
|
|
1799
|
+
import { join as join10, relative as relative3, dirname as dirname4 } from "path";
|
|
1800
|
+
import { unlink as unlink3, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
|
|
1614
1801
|
import { existsSync as existsSync2 } from "fs";
|
|
1615
|
-
async function
|
|
1616
|
-
const
|
|
1617
|
-
|
|
1618
|
-
if (!config) {
|
|
1619
|
-
p6.log.error("No kitn.json found. Run `kitn init` first.");
|
|
1620
|
-
process.exit(1);
|
|
1621
|
-
}
|
|
1622
|
-
const input = componentName === "routes" ? resolveRoutesAlias(config) : componentName;
|
|
1623
|
-
const ref = parseComponentRef(input);
|
|
1624
|
-
const installedKey = ref.namespace === "@kitn" ? ref.name : `${ref.namespace}/${ref.name}`;
|
|
1625
|
-
const installed = config.installed?.[installedKey];
|
|
1626
|
-
if (!installed) {
|
|
1627
|
-
p6.log.error(`Component '${ref.name}' is not installed.`);
|
|
1628
|
-
process.exit(1);
|
|
1629
|
-
}
|
|
1630
|
-
const shouldRemove = await p6.confirm({
|
|
1631
|
-
message: `Remove ${ref.name}? This will delete ${installed.files.length} file(s).`,
|
|
1632
|
-
initialValue: false
|
|
1633
|
-
});
|
|
1634
|
-
if (p6.isCancel(shouldRemove) || !shouldRemove) {
|
|
1635
|
-
p6.cancel("Remove cancelled.");
|
|
1636
|
-
process.exit(0);
|
|
1637
|
-
}
|
|
1802
|
+
async function removeSingleComponent(installedKey, lock, config, cwd) {
|
|
1803
|
+
const entry = lock[installedKey];
|
|
1804
|
+
if (!entry) return;
|
|
1638
1805
|
const deleted = [];
|
|
1639
|
-
for (const filePath of
|
|
1806
|
+
for (const filePath of entry.files) {
|
|
1640
1807
|
try {
|
|
1641
|
-
await
|
|
1808
|
+
await unlink3(join10(cwd, filePath));
|
|
1642
1809
|
deleted.push(filePath);
|
|
1643
1810
|
} catch {
|
|
1644
1811
|
p6.log.warn(`Could not delete ${filePath} (may have been moved or renamed)`);
|
|
@@ -1656,7 +1823,7 @@ async function removeCommand(componentName) {
|
|
|
1656
1823
|
let barrelContent = await readFile7(barrelPath, "utf-8");
|
|
1657
1824
|
let barrelChanged = false;
|
|
1658
1825
|
for (const filePath of deleted) {
|
|
1659
|
-
const fileDir =
|
|
1826
|
+
const fileDir = dirname4(filePath);
|
|
1660
1827
|
if (!barrelEligibleDirs.has(fileDir)) continue;
|
|
1661
1828
|
const importPath = "./" + relative3(barrelDir, join10(cwd, filePath)).replace(/\\/g, "/");
|
|
1662
1829
|
const updated = removeImportFromBarrel(barrelContent, importPath);
|
|
@@ -1670,16 +1837,111 @@ async function removeCommand(componentName) {
|
|
|
1670
1837
|
p6.log.info(`Updated barrel file: ${join10(baseDir, "index.ts")}`);
|
|
1671
1838
|
}
|
|
1672
1839
|
}
|
|
1673
|
-
delete
|
|
1674
|
-
if (Object.keys(config.installed).length === 0) {
|
|
1675
|
-
delete config.installed;
|
|
1676
|
-
}
|
|
1677
|
-
await writeConfig(cwd, config);
|
|
1840
|
+
delete lock[installedKey];
|
|
1678
1841
|
if (deleted.length > 0) {
|
|
1679
|
-
p6.log.success(`Removed ${
|
|
1842
|
+
p6.log.success(`Removed ${installedKey}:
|
|
1680
1843
|
` + deleted.map((f) => ` ${pc6.red("-")} ${f}`).join("\n"));
|
|
1681
1844
|
}
|
|
1682
1845
|
}
|
|
1846
|
+
async function offerOrphanRemoval(removedDeps, lock, config, cwd) {
|
|
1847
|
+
if (removedDeps.size === 0) return;
|
|
1848
|
+
const remaining = Object.entries(lock);
|
|
1849
|
+
const neededDeps = /* @__PURE__ */ new Set();
|
|
1850
|
+
for (const [, entry] of remaining) {
|
|
1851
|
+
if (entry.registryDependencies) {
|
|
1852
|
+
for (const dep of entry.registryDependencies) {
|
|
1853
|
+
neededDeps.add(dep);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
const orphans = [...removedDeps].filter(
|
|
1858
|
+
(dep) => dep !== "core" && !neededDeps.has(dep) && lock[dep]
|
|
1859
|
+
);
|
|
1860
|
+
if (orphans.length === 0) return;
|
|
1861
|
+
const selected = await p6.multiselect({
|
|
1862
|
+
message: "The following dependencies are no longer used. Remove them?",
|
|
1863
|
+
options: orphans.map((dep) => ({
|
|
1864
|
+
value: dep,
|
|
1865
|
+
label: dep,
|
|
1866
|
+
hint: `${lock[dep].files.length} file(s)`
|
|
1867
|
+
})),
|
|
1868
|
+
initialValues: orphans
|
|
1869
|
+
// all checked by default
|
|
1870
|
+
});
|
|
1871
|
+
if (p6.isCancel(selected)) return;
|
|
1872
|
+
for (const key of selected) {
|
|
1873
|
+
await removeSingleComponent(key, lock, config, cwd);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
async function removeCommand(componentName) {
|
|
1877
|
+
const cwd = process.cwd();
|
|
1878
|
+
const config = await readConfig(cwd);
|
|
1879
|
+
if (!config) {
|
|
1880
|
+
p6.log.error("No kitn.json found. Run `kitn init` first.");
|
|
1881
|
+
process.exit(1);
|
|
1882
|
+
}
|
|
1883
|
+
const lock = await readLock(cwd);
|
|
1884
|
+
if (!componentName) {
|
|
1885
|
+
const installedKeys = Object.keys(lock);
|
|
1886
|
+
if (installedKeys.length === 0) {
|
|
1887
|
+
p6.log.warn("No components installed.");
|
|
1888
|
+
process.exit(0);
|
|
1889
|
+
}
|
|
1890
|
+
const selected = await p6.multiselect({
|
|
1891
|
+
message: "Select components to remove:",
|
|
1892
|
+
options: installedKeys.map((key) => ({
|
|
1893
|
+
value: key,
|
|
1894
|
+
label: key,
|
|
1895
|
+
hint: `${lock[key].files.length} file(s)`
|
|
1896
|
+
}))
|
|
1897
|
+
});
|
|
1898
|
+
if (p6.isCancel(selected)) {
|
|
1899
|
+
p6.cancel("Cancelled.");
|
|
1900
|
+
process.exit(0);
|
|
1901
|
+
}
|
|
1902
|
+
const selectedKeys = selected;
|
|
1903
|
+
if (selectedKeys.length === 0) {
|
|
1904
|
+
p6.log.warn("No components selected.");
|
|
1905
|
+
process.exit(0);
|
|
1906
|
+
}
|
|
1907
|
+
const allRemovedDeps = /* @__PURE__ */ new Set();
|
|
1908
|
+
for (const key of selectedKeys) {
|
|
1909
|
+
const entry2 = lock[key];
|
|
1910
|
+
if (entry2?.registryDependencies) {
|
|
1911
|
+
for (const dep of entry2.registryDependencies) {
|
|
1912
|
+
allRemovedDeps.add(dep);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
for (const key of selectedKeys) {
|
|
1917
|
+
await removeSingleComponent(key, lock, config, cwd);
|
|
1918
|
+
}
|
|
1919
|
+
await offerOrphanRemoval(allRemovedDeps, lock, config, cwd);
|
|
1920
|
+
await writeLock(cwd, lock);
|
|
1921
|
+
p6.outro(pc6.green("Done!"));
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
const input = componentName === "routes" ? resolveRoutesAlias(config) : componentName;
|
|
1925
|
+
const ref = parseComponentRef(input);
|
|
1926
|
+
const installedKey = ref.namespace === "@kitn" ? ref.name : `${ref.namespace}/${ref.name}`;
|
|
1927
|
+
const entry = lock[installedKey];
|
|
1928
|
+
if (!entry) {
|
|
1929
|
+
p6.log.error(`Component '${ref.name}' is not installed.`);
|
|
1930
|
+
process.exit(1);
|
|
1931
|
+
}
|
|
1932
|
+
const shouldRemove = await p6.confirm({
|
|
1933
|
+
message: `Remove ${ref.name}? This will delete ${entry.files.length} file(s).`,
|
|
1934
|
+
initialValue: false
|
|
1935
|
+
});
|
|
1936
|
+
if (p6.isCancel(shouldRemove) || !shouldRemove) {
|
|
1937
|
+
p6.cancel("Remove cancelled.");
|
|
1938
|
+
process.exit(0);
|
|
1939
|
+
}
|
|
1940
|
+
const removedDeps = new Set(entry.registryDependencies ?? []);
|
|
1941
|
+
await removeSingleComponent(installedKey, lock, config, cwd);
|
|
1942
|
+
await offerOrphanRemoval(removedDeps, lock, config, cwd);
|
|
1943
|
+
await writeLock(cwd, lock);
|
|
1944
|
+
}
|
|
1683
1945
|
var init_remove = __esm({
|
|
1684
1946
|
"src/commands/remove.ts"() {
|
|
1685
1947
|
"use strict";
|
|
@@ -1703,12 +1965,12 @@ async function updateCommand(components) {
|
|
|
1703
1965
|
p7.log.error("No kitn.json found. Run `kitn init` first.");
|
|
1704
1966
|
process.exit(1);
|
|
1705
1967
|
}
|
|
1706
|
-
const
|
|
1707
|
-
if (
|
|
1968
|
+
const lock = await readLock(cwd);
|
|
1969
|
+
if (Object.keys(lock).length === 0) {
|
|
1708
1970
|
p7.log.info("No installed components to update.");
|
|
1709
1971
|
return;
|
|
1710
1972
|
}
|
|
1711
|
-
components = Object.keys(
|
|
1973
|
+
components = Object.keys(lock);
|
|
1712
1974
|
}
|
|
1713
1975
|
await addCommand(components, { overwrite: true });
|
|
1714
1976
|
}
|
|
@@ -1984,7 +2246,8 @@ async function infoCommand(component) {
|
|
|
1984
2246
|
if (fileCount > maxShown) {
|
|
1985
2247
|
console.log(` ${pc8.dim(`... and ${fileCount - maxShown} more`)}`);
|
|
1986
2248
|
}
|
|
1987
|
-
const
|
|
2249
|
+
const lock = await readLock(cwd);
|
|
2250
|
+
const installed = lock[item.name];
|
|
1988
2251
|
if (installed) {
|
|
1989
2252
|
console.log();
|
|
1990
2253
|
console.log(
|
|
@@ -2013,6 +2276,7 @@ var check_exports = {};
|
|
|
2013
2276
|
__export(check_exports, {
|
|
2014
2277
|
checkCommand: () => checkCommand
|
|
2015
2278
|
});
|
|
2279
|
+
import { execSync as execSync2 } from "child_process";
|
|
2016
2280
|
import * as p10 from "@clack/prompts";
|
|
2017
2281
|
import pc9 from "picocolors";
|
|
2018
2282
|
async function checkCommand(currentVersion) {
|
|
@@ -2028,7 +2292,22 @@ async function checkCommand(currentVersion) {
|
|
|
2028
2292
|
}
|
|
2029
2293
|
if (isNewer(latest, currentVersion)) {
|
|
2030
2294
|
s.stop(pc9.yellow(`Update available: ${currentVersion} \u2192 ${latest}`));
|
|
2031
|
-
|
|
2295
|
+
const pm = detectCliInstaller();
|
|
2296
|
+
const installCmd = getGlobalInstallCommand(pm, "@kitnai/cli");
|
|
2297
|
+
const shouldUpdate = await p10.confirm({ message: "Update now?" });
|
|
2298
|
+
if (p10.isCancel(shouldUpdate) || !shouldUpdate) {
|
|
2299
|
+
p10.log.message(` Run: ${pc9.cyan(installCmd)}`);
|
|
2300
|
+
} else {
|
|
2301
|
+
const us = p10.spinner();
|
|
2302
|
+
us.start("Updating...");
|
|
2303
|
+
try {
|
|
2304
|
+
execSync2(installCmd, { stdio: "pipe" });
|
|
2305
|
+
us.stop(pc9.green(`Updated to v${latest}`));
|
|
2306
|
+
} catch {
|
|
2307
|
+
us.stop(pc9.red("Update failed"));
|
|
2308
|
+
p10.log.message(` Run manually: ${pc9.cyan(installCmd)}`);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2032
2311
|
} else {
|
|
2033
2312
|
s.stop(pc9.green("You're on the latest version"));
|
|
2034
2313
|
}
|
|
@@ -2037,6 +2316,7 @@ async function checkCommand(currentVersion) {
|
|
|
2037
2316
|
var init_check = __esm({
|
|
2038
2317
|
"src/commands/check.ts"() {
|
|
2039
2318
|
"use strict";
|
|
2319
|
+
init_detect();
|
|
2040
2320
|
init_update_check();
|
|
2041
2321
|
}
|
|
2042
2322
|
});
|
|
@@ -2090,12 +2370,11 @@ async function registryRemoveCommand(namespace, opts = {}) {
|
|
|
2090
2370
|
if (namespace === "@kitn" && !opts.force) {
|
|
2091
2371
|
throw new Error("Cannot remove the default @kitn registry. Use --force to override.");
|
|
2092
2372
|
}
|
|
2373
|
+
const lock = await readLock(cwd);
|
|
2093
2374
|
const affectedComponents = [];
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
affectedComponents.push(name);
|
|
2098
|
-
}
|
|
2375
|
+
for (const [name, entry] of Object.entries(lock)) {
|
|
2376
|
+
if (entry.registry === namespace) {
|
|
2377
|
+
affectedComponents.push(name);
|
|
2099
2378
|
}
|
|
2100
2379
|
}
|
|
2101
2380
|
delete config.registries[namespace];
|
|
@@ -2140,14 +2419,14 @@ var init_registry = __esm({
|
|
|
2140
2419
|
// src/index.ts
|
|
2141
2420
|
init_update_check();
|
|
2142
2421
|
import { Command } from "commander";
|
|
2143
|
-
var VERSION = true ? "0.1.
|
|
2422
|
+
var VERSION = true ? "0.1.25" : "0.0.0-dev";
|
|
2144
2423
|
var printUpdateNotice = startUpdateCheck(VERSION);
|
|
2145
2424
|
var program = new Command().name("kitn").description("Install AI agent components from the kitn registry").version(VERSION);
|
|
2146
2425
|
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) => {
|
|
2147
2426
|
const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2148
2427
|
await initCommand2(opts);
|
|
2149
2428
|
});
|
|
2150
|
-
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) => {
|
|
2429
|
+
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) => {
|
|
2151
2430
|
const { addCommand: addCommand2 } = await Promise.resolve().then(() => (init_add(), add_exports));
|
|
2152
2431
|
await addCommand2(components, opts);
|
|
2153
2432
|
});
|
|
@@ -2159,7 +2438,7 @@ program.command("diff").description("Show differences between local and registry
|
|
|
2159
2438
|
const { diffCommand: diffCommand2 } = await Promise.resolve().then(() => (init_diff(), diff_exports));
|
|
2160
2439
|
await diffCommand2(component);
|
|
2161
2440
|
});
|
|
2162
|
-
program.command("remove").description("Remove an installed component").argument("
|
|
2441
|
+
program.command("remove").alias("uninstall").description("Remove an installed component").argument("[component]", "component name to remove (interactive if omitted)").action(async (component) => {
|
|
2163
2442
|
const { removeCommand: removeCommand2 } = await Promise.resolve().then(() => (init_remove(), remove_exports));
|
|
2164
2443
|
await removeCommand2(component);
|
|
2165
2444
|
});
|