@chatbi-v/cli 2.0.2 → 2.0.4

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.
Files changed (41) hide show
  1. package/bin/chatbi-cli.js +1 -2
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +2464 -188
  4. package/package.json +6 -3
  5. package/templates/app/package.json.hbs +5 -2
  6. package/templates/plugin/package.json.hbs +5 -5
  7. package/templates/plugin/tsconfig.json.hbs +1 -1
  8. package/dist/bench-ACSHVGHE.mjs +0 -77
  9. package/dist/build-UB4D3WNI.mjs +0 -11
  10. package/dist/chunk-4OD6C56P.mjs +0 -89
  11. package/dist/chunk-7A54IJI5.mjs +0 -6368
  12. package/dist/chunk-LJFX6MNO.mjs +0 -255
  13. package/dist/chunk-SBGVKO4C.mjs +0 -2255
  14. package/dist/chunk-TX5M36S5.mjs +0 -55
  15. package/dist/chunk-V7IEPMC4.mjs +0 -52
  16. package/dist/chunk-WCPZB47I.mjs +0 -262
  17. package/dist/chunk-WIVHOK75.mjs +0 -5292
  18. package/dist/chunk-Y24V4GQG.mjs +0 -9577
  19. package/dist/commands/add.js +0 -182
  20. package/dist/commands/bench.js +0 -100
  21. package/dist/commands/build.js +0 -290
  22. package/dist/commands/dev.js +0 -8
  23. package/dist/commands/discover.js +0 -25
  24. package/dist/commands/doctor.js +0 -231
  25. package/dist/commands/fetch.js +0 -41
  26. package/dist/commands/gl.js +0 -151
  27. package/dist/commands/init.js +0 -253
  28. package/dist/commands/install.js +0 -85
  29. package/dist/commands/ls.js +0 -46
  30. package/dist/commands/sync.js +0 -78
  31. package/dist/commands/use.js +0 -31
  32. package/dist/config.js +0 -70
  33. package/dist/corekit.js +0 -370
  34. package/dist/execa-METROS6Z.mjs +0 -17
  35. package/dist/fetch-7X2UFWIV.mjs +0 -10
  36. package/dist/index.cjs +0 -27278
  37. package/dist/index.mjs +0 -2769
  38. package/dist/init-QFRFYEA5.mjs +0 -12
  39. package/dist/sandbox.js +0 -522
  40. package/dist/sync-7HPKGVFY.mjs +0 -11
  41. package/dist/utils.js +0 -99
package/dist/index.js CHANGED
@@ -1,201 +1,2477 @@
1
- "use strict";
2
- /**
3
- * @file index.ts
4
- * @description CLI 入口文件,定义所有命令行指令及交互逻辑
5
- * @author ChatBI Team
6
- */
7
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
- if (k2 === undefined) k2 = k;
9
- var desc = Object.getOwnPropertyDescriptor(m, k);
10
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
- desc = { enumerable: true, get: function() { return m[k]; } };
12
- }
13
- Object.defineProperty(o, k2, desc);
14
- }) : (function(o, m, k, k2) {
15
- if (k2 === undefined) k2 = k;
16
- o[k2] = m[k];
17
- }));
18
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
- Object.defineProperty(o, "default", { enumerable: true, value: v });
20
- }) : function(o, v) {
21
- o["default"] = v;
22
- });
23
- var __importStar = (this && this.__importStar) || (function () {
24
- var ownKeys = function(o) {
25
- ownKeys = Object.getOwnPropertyNames || function (o) {
26
- var ar = [];
27
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
- return ar;
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js
18
+ import path from "path";
19
+ import { fileURLToPath } from "url";
20
+ var getFilename, getDirname, __dirname;
21
+ var init_esm_shims = __esm({
22
+ "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js"() {
23
+ "use strict";
24
+ getFilename = () => fileURLToPath(import.meta.url);
25
+ getDirname = () => path.dirname(getFilename());
26
+ __dirname = /* @__PURE__ */ getDirname();
27
+ }
28
+ });
29
+
30
+ // src/utils.ts
31
+ import path2 from "path";
32
+ import fs from "fs-extra";
33
+ import pc from "picocolors";
34
+ import ora from "ora";
35
+ import boxen from "boxen";
36
+ var _require, _dirname, logger, createSpinner, printBox, findPackageRoot, getCliRoot;
37
+ var init_utils = __esm({
38
+ "src/utils.ts"() {
39
+ "use strict";
40
+ init_esm_shims();
41
+ _require = __require;
42
+ _dirname = __dirname;
43
+ logger = {
44
+ info: (msg) => console.log(pc.cyan(`\u2139 ${msg}`)),
45
+ success: (msg) => console.log(pc.green(`\u2714 ${msg}`)),
46
+ warn: (msg) => console.log(pc.yellow(`\u26A0 ${msg}`)),
47
+ error: (msg, err) => {
48
+ console.error(pc.red(`
49
+ \u274C ${msg}`));
50
+ if (err) {
51
+ if (err instanceof Error) {
52
+ console.error(pc.gray(err.stack || err.message));
53
+ } else {
54
+ console.error(pc.gray(String(err)));
55
+ }
56
+ }
57
+ },
58
+ bold: (msg) => pc.bold(msg),
59
+ cyan: (msg) => pc.cyan(msg),
60
+ green: (msg) => pc.green(msg),
61
+ yellow: (msg) => pc.yellow(msg),
62
+ red: (msg) => pc.red(msg),
63
+ gray: (msg) => pc.gray(msg)
64
+ };
65
+ createSpinner = (msg) => ora({
66
+ text: pc.cyan(msg),
67
+ color: "cyan"
68
+ });
69
+ printBox = (msg, title, options = {}) => {
70
+ console.log("\n" + boxen(msg, {
71
+ padding: 1,
72
+ borderStyle: "round",
73
+ borderColor: "cyan",
74
+ title,
75
+ titleAlignment: "center",
76
+ ...options
77
+ }));
78
+ };
79
+ findPackageRoot = (pkgName) => {
80
+ try {
81
+ const pkgPath = _require.resolve(`${pkgName}/package.json`);
82
+ return path2.dirname(pkgPath);
83
+ } catch (e) {
84
+ if (pkgName === "@chatbi-v/cli") {
85
+ return path2.resolve(_dirname, "../../");
86
+ }
87
+ const localPath = path2.resolve(_dirname, "../../node_modules", pkgName);
88
+ if (fs.existsSync(localPath)) {
89
+ return localPath;
90
+ }
91
+ throw new Error(`\u65E0\u6CD5\u627E\u5230\u5305 ${pkgName}\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u901A\u8FC7 pnpm/npm \u5B89\u88C5\u3002`);
92
+ }
93
+ };
94
+ getCliRoot = async () => {
95
+ let myCliRoot = "";
96
+ let checkDir = _dirname;
97
+ while (checkDir !== path2.parse(checkDir).root) {
98
+ if (fs.existsSync(path2.join(checkDir, "package.json"))) {
99
+ const pkg = await fs.readJson(path2.join(checkDir, "package.json"));
100
+ if (pkg.name === "@chatbi-v/cli") {
101
+ myCliRoot = checkDir;
102
+ break;
103
+ }
104
+ }
105
+ checkDir = path2.dirname(checkDir);
106
+ }
107
+ if (!myCliRoot) {
108
+ myCliRoot = findPackageRoot("@chatbi-v/cli");
109
+ }
110
+ return myCliRoot;
111
+ };
112
+ }
113
+ });
114
+
115
+ // src/sandbox.ts
116
+ import fs2 from "fs-extra";
117
+ import path3 from "path";
118
+ import os from "os";
119
+ import pc2 from "picocolors";
120
+ import { execa } from "execa";
121
+ import Handlebars from "handlebars";
122
+ import fg from "fast-glob";
123
+ var Sandbox;
124
+ var init_sandbox = __esm({
125
+ "src/sandbox.ts"() {
126
+ "use strict";
127
+ init_esm_shims();
128
+ init_utils();
129
+ Sandbox = class _Sandbox {
130
+ static {
131
+ this.BASE_DIR = path3.join(os.homedir(), ".chatbi-v-core");
132
+ }
133
+ static {
134
+ this.CORE_PACKAGES = [
135
+ "@chatbi-v/core",
136
+ "@chatbi-v/mocks",
137
+ "@chatbi-v/tsconfig",
138
+ "@chatbi-v/tailwind-config",
139
+ "@chatbi-v/plugin-theme-manager",
140
+ "@chatbi-v/plugin-layout-transform",
141
+ "@chatbi-v/plugin-system-monitor"
142
+ ];
143
+ }
144
+ static {
145
+ this.RUNTIME_DEPS = [
146
+ "@ant-design/x",
147
+ "@ant-design/icons",
148
+ "antd",
149
+ "react",
150
+ "react-dom",
151
+ "lucide-react",
152
+ "framer-motion",
153
+ "clsx",
154
+ "tailwind-merge",
155
+ "react-router-dom",
156
+ "zustand",
157
+ "axios",
158
+ "less",
159
+ "vite"
160
+ ];
161
+ }
162
+ static getRoot() {
163
+ return this.BASE_DIR;
164
+ }
165
+ static getVersionRoot() {
166
+ return path3.join(this.BASE_DIR, "versions");
167
+ }
168
+ static getVersionPath(version) {
169
+ if (version === "current") {
170
+ return path3.join(this.BASE_DIR, "versions", "current");
171
+ }
172
+ return path3.join(this.BASE_DIR, "versions", version);
173
+ }
174
+ /**
175
+ * 优雅清理缓存环境
176
+ * @param cwd 当前工作目录
177
+ * @param deep 是否递归清理子包
178
+ */
179
+ static async clean(cwd, deep = false) {
180
+ const localCache = path3.join(cwd, ".chatbi");
181
+ if (fs2.existsSync(localCache)) {
182
+ await fs2.remove(localCache);
183
+ }
184
+ if (deep) {
185
+ const pkgPath = path3.join(cwd, "package.json");
186
+ if (fs2.existsSync(pkgPath)) {
187
+ const pkg = await fs2.readJson(pkgPath);
188
+ if (pkg.workspaces || fs2.existsSync(path3.join(cwd, "pnpm-workspace.yaml"))) {
189
+ const subDirs = ["apps", "plugins", "packages"];
190
+ for (const dir of subDirs) {
191
+ const dirPath = path3.join(cwd, dir);
192
+ if (fs2.existsSync(dirPath)) {
193
+ const entries = await fs2.readdir(dirPath, { withFileTypes: true });
194
+ for (const entry of entries) {
195
+ if (entry.isDirectory()) {
196
+ const subPkgCache = path3.join(dirPath, entry.name, ".chatbi");
197
+ if (fs2.existsSync(subPkgCache)) {
198
+ await fs2.remove(subPkgCache);
199
+ }
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+ }
207
+ if (fs2.existsSync(this.BASE_DIR)) {
208
+ await fs2.remove(this.BASE_DIR);
209
+ }
210
+ }
211
+ /**
212
+ * 准备内核沙箱环境 (安装/更新)
213
+ */
214
+ static async prepare(version, force = false) {
215
+ const versionPath = this.getVersionPath(version);
216
+ if (fs2.existsSync(versionPath) && !force) {
217
+ if (fs2.existsSync(path3.join(versionPath, "node_modules/tailwindcss")) && fs2.existsSync(path3.join(versionPath, "node_modules/react-router-dom"))) {
218
+ return versionPath;
219
+ }
220
+ }
221
+ if (fs2.existsSync(versionPath)) {
222
+ await fs2.remove(path3.join(versionPath, "node_modules"));
223
+ await fs2.remove(path3.join(versionPath, "pnpm-lock.yaml"));
224
+ }
225
+ await fs2.ensureDir(versionPath);
226
+ const spinner = createSpinner(`\u6B63\u5728\u521D\u59CB\u5316\u5185\u6838\u6C99\u7BB1 ${pc2.cyan(version)}...`).start();
227
+ try {
228
+ const rootPkgJson = {
229
+ name: `chatbi-sandbox-${version}`,
230
+ private: true,
231
+ dependencies: {},
232
+ devDependencies: {
233
+ "tailwindcss": "^3.4.1",
234
+ "autoprefixer": "^10.4.17",
235
+ "postcss": "^8.4.35",
236
+ "vite": "^5.0.8",
237
+ "@vitejs/plugin-react": "^4.2.1",
238
+ "less": "^4.2.0",
239
+ "typescript": "^5.3.3",
240
+ "@types/react": "^18.3.1",
241
+ "@types/react-dom": "^18.3.1",
242
+ "@types/node": "^20.11.20"
243
+ }
244
+ };
245
+ for (const pkgName of _Sandbox.CORE_PACKAGES) {
246
+ rootPkgJson.dependencies[pkgName] = pkgName === "@chatbi-v/core" ? version : "latest";
247
+ }
248
+ for (const pkgName of _Sandbox.RUNTIME_DEPS) {
249
+ if (!rootPkgJson.dependencies[pkgName]) {
250
+ rootPkgJson.dependencies[pkgName] = "latest";
251
+ }
252
+ }
253
+ rootPkgJson.dependencies["react"] = "^18.3.1";
254
+ rootPkgJson.dependencies["react-dom"] = "^18.3.1";
255
+ rootPkgJson.dependencies["antd"] = "^5.20.0";
256
+ await fs2.writeJson(path3.join(versionPath, "package.json"), rootPkgJson, { spaces: 2 });
257
+ await fs2.writeFile(path3.join(versionPath, ".npmrc"), "shamefully-hoist=true\nauto-install-peers=true\n");
258
+ spinner.text = pc2.gray(" \u{1F50D} \u68C0\u67E5\u672C\u5730\u5F00\u53D1\u73AF\u5883...");
259
+ const isLocalDev = await this.tryLinkLocalPackages(versionPath);
260
+ const installArgs = ["install"];
261
+ if (isLocalDev) {
262
+ installArgs.push("--no-frozen-lockfile");
263
+ }
264
+ spinner.text = pc2.gray(` \u23F3 \u6267\u884C pnpm ${installArgs.join(" ")}...`);
265
+ await execa("pnpm", installArgs, { cwd: versionPath });
266
+ spinner.text = pc2.gray(" \u{1F3A8} \u540C\u6B65 Shell \u6A21\u677F...");
267
+ await this.ensureShell(version, force);
268
+ spinner.succeed(pc2.green(`\u5185\u6838\u6C99\u7BB1 ${version} \u521D\u59CB\u5316\u6210\u529F`));
269
+ } catch (e) {
270
+ spinner.fail(pc2.red(`\u5185\u6838\u6C99\u7BB1\u521D\u59CB\u5316\u5931\u8D25: ${e.message}`));
271
+ throw e;
272
+ }
273
+ return versionPath;
274
+ }
275
+ /**
276
+ * 确保 Shell 模板已同步到沙箱
277
+ */
278
+ static async ensureShell(version, force = false) {
279
+ const versionPath = this.getVersionPath(version);
280
+ const shellDestDir = path3.join(versionPath, "shell");
281
+ const needsRender = force || !fs2.existsSync(shellDestDir) || !fs2.existsSync(path3.join(shellDestDir, "tsconfig.paths.json"));
282
+ if (!needsRender) {
283
+ return shellDestDir;
284
+ }
285
+ const cliRoot = await getCliRoot();
286
+ const shellTemplateDir = path3.join(cliRoot, "templates", "app");
287
+ if (fs2.existsSync(shellTemplateDir)) {
288
+ await fs2.remove(shellDestDir);
289
+ await fs2.ensureDir(path3.join(shellDestDir, "empty"));
290
+ let kernelVersion = version;
291
+ const templateData = {
292
+ name: "chatbi-shell",
293
+ projectName: "chatbi-shell",
294
+ projectTitle: "ChatBI Shell",
295
+ projectVersion: "0.1.0",
296
+ version: kernelVersion,
297
+ cliVersion: version,
298
+ theme: "standard",
299
+ isNebula: false,
300
+ isGlass: false,
301
+ isBusiness: true,
302
+ isApp: true,
303
+ isShell: true,
304
+ tsconfigPath: "./tsconfig.paths.json"
305
+ };
306
+ await this.renderDirectory(shellTemplateDir, shellDestDir, templateData);
307
+ const tsConfigPaths = {
308
+ compilerOptions: {
309
+ baseUrl: ".",
310
+ paths: {
311
+ "@/*": ["./src/*"]
312
+ }
313
+ }
314
+ };
315
+ await fs2.writeJson(path3.join(shellDestDir, "tsconfig.paths.json"), tsConfigPaths, { spaces: 2 });
316
+ }
317
+ return shellDestDir;
318
+ }
319
+ /**
320
+ * 递归渲染目录模板
321
+ */
322
+ static async renderDirectory(srcDir, destDir, data) {
323
+ const entries = await fs2.readdir(srcDir, { withFileTypes: true });
324
+ for (const entry of entries) {
325
+ const srcPath = path3.join(srcDir, entry.name);
326
+ const destPath = path3.join(destDir, entry.name.replace(/\.hbs$/, ""));
327
+ if (entry.isDirectory()) {
328
+ await fs2.ensureDir(destPath);
329
+ await this.renderDirectory(srcPath, destPath, data);
330
+ } else {
331
+ if (entry.name.endsWith(".hbs")) {
332
+ const content = await fs2.readFile(srcPath, "utf-8");
333
+ const hasHandlebarsVars = content.includes("{{");
334
+ if (hasHandlebarsVars) {
335
+ try {
336
+ const safeContent = content.replace(/\{\{(?!\s*([#/]?(?:if|else|each|with|unless|name|version|projectName|projectTitle|projectVersion|cliVersion|tsconfigPath|theme|isNebula|isGlass|isBusiness|isApp|isShell|pluginName|pluginPackageName|pluginVersion|pluginDisplayName|pluginDescription|pluginClassName|pluginPath|pluginFolderName|pluginType|pluginId|className))\b)/g, "\\{{");
337
+ const template = Handlebars.compile(safeContent);
338
+ const result = template(data);
339
+ await fs2.outputFile(destPath, result);
340
+ } catch (e) {
341
+ let result = content;
342
+ for (const [key, val] of Object.entries(data)) {
343
+ const regex = new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, "g");
344
+ result = result.replace(regex, String(val));
345
+ }
346
+ await fs2.outputFile(destPath, result);
347
+ }
348
+ } else {
349
+ await fs2.outputFile(destPath, content);
350
+ }
351
+ } else {
352
+ await fs2.copy(srcPath, destPath);
353
+ }
354
+ }
355
+ }
356
+ }
357
+ /**
358
+ * 注入项目虚拟上下文 (tsconfig, alias)
359
+ */
360
+ static async injectContext(projectRoot, version) {
361
+ const chatbiDir = path3.join(projectRoot, ".chatbi");
362
+ await fs2.ensureDir(chatbiDir);
363
+ const versionPath = this.getVersionPath(version);
364
+ const sandboxNodeModules = path3.join(versionPath, "node_modules");
365
+ const corePaths = {};
366
+ for (const pkgName of _Sandbox.CORE_PACKAGES) {
367
+ corePaths[pkgName] = [`./node_modules/${pkgName}`];
368
+ corePaths[`${pkgName}/*`] = [`./node_modules/${pkgName}/*`];
369
+ }
370
+ for (const pkgName of _Sandbox.RUNTIME_DEPS) {
371
+ corePaths[pkgName] = [`./node_modules/${pkgName}`];
372
+ corePaths[`${pkgName}/*`] = [`./node_modules/${pkgName}/*`];
373
+ if (["react", "react-dom", "node"].includes(pkgName)) {
374
+ const typeName = pkgName === "node" ? "node" : pkgName;
375
+ corePaths[`@types/${typeName}`] = [`./node_modules/@types/${typeName}`];
376
+ corePaths[`@types/${typeName}/*`] = [`./node_modules/@types/${typeName}/*`];
377
+ }
378
+ }
379
+ corePaths["@types/*"] = ["./node_modules/@types/*"];
380
+ corePaths["vite/client"] = ["./node_modules/vite/client.d.ts"];
381
+ const baseConfigPath = path3.join(sandboxNodeModules, "@chatbi-v/tsconfig/base.json");
382
+ let projectPaths = { "@/*": ["../src/*"] };
383
+ const tsConfig = {
384
+ extends: baseConfigPath,
385
+ compilerOptions: {
386
+ baseUrl: ".",
387
+ moduleResolution: "bundler",
388
+ skipLibCheck: true,
389
+ // Fix: Use relative path to the symlinked node_modules in .chatbi
390
+ // This is much more robust as it works relative to the config file (.chatbi/tsconfig.json)
391
+ typeRoots: [
392
+ "./node_modules/@types"
393
+ ],
394
+ // Crucial for symlinked node_modules: treat them as if they are in the project
395
+ preserveSymlinks: true,
396
+ paths: {
397
+ ...corePaths,
398
+ ...projectPaths,
399
+ // Fallback: Try to find anything else in the virtual node_modules
400
+ "*": ["./node_modules/*"]
401
+ }
402
+ }
29
403
  };
30
- return ownKeys(o);
404
+ await fs2.writeJson(path3.join(chatbiDir, "tsconfig.json"), tsConfig, { spaces: 2 });
405
+ await fs2.writeJson(path3.join(chatbiDir, "tsconfig.paths.json"), { compilerOptions: tsConfig.compilerOptions }, { spaces: 2 });
406
+ const virtualNodeModules = path3.join(chatbiDir, "node_modules");
407
+ if (!fs2.existsSync(sandboxNodeModules)) {
408
+ return;
409
+ }
410
+ try {
411
+ try {
412
+ const stats = await fs2.lstat(virtualNodeModules);
413
+ if (stats) {
414
+ await fs2.remove(virtualNodeModules);
415
+ }
416
+ } catch (e) {
417
+ }
418
+ await fs2.ensureSymlink(sandboxNodeModules, virtualNodeModules, "dir");
419
+ const rootNodeModules = path3.join(projectRoot, "node_modules");
420
+ let rootNmExists = false;
421
+ try {
422
+ rootNmExists = fs2.existsSync(rootNodeModules);
423
+ } catch (e) {
424
+ }
425
+ if (!rootNmExists) {
426
+ try {
427
+ await fs2.ensureSymlink(sandboxNodeModules, rootNodeModules, "dir");
428
+ } catch (linkErr) {
429
+ const appsDir = path3.join(projectRoot, "apps");
430
+ if (fs2.existsSync(appsDir)) {
431
+ const appDirs = await fg("*", { cwd: appsDir, onlyDirectories: true, absolute: true });
432
+ for (const appDir of appDirs) {
433
+ const appNm = path3.join(appDir, "node_modules");
434
+ if (!fs2.existsSync(appNm)) {
435
+ await fs2.ensureSymlink(sandboxNodeModules, appNm, "dir").catch(() => {
436
+ });
437
+ }
438
+ }
439
+ }
440
+ }
441
+ }
442
+ } catch (e) {
443
+ }
444
+ const gitignorePath = path3.join(projectRoot, ".gitignore");
445
+ if (fs2.existsSync(gitignorePath)) {
446
+ let content = await fs2.readFile(gitignorePath, "utf-8");
447
+ if (!content.includes(".chatbi")) {
448
+ await fs2.appendFile(gitignorePath, "\n# ChatBI\n.chatbi\n");
449
+ }
450
+ }
451
+ }
452
+ /**
453
+ * 获取核心库的 Vite Alias 配置
454
+ */
455
+ static getCoreAlias(version) {
456
+ const versionPath = this.getVersionPath(version);
457
+ const sandboxNodeModules = path3.join(versionPath, "node_modules");
458
+ const aliases = {};
459
+ for (const pkg of this.CORE_PACKAGES) {
460
+ aliases[pkg] = path3.join(sandboxNodeModules, pkg);
461
+ }
462
+ return aliases;
463
+ }
464
+ /**
465
+ * 尝试将本地包 Link 到沙箱中 (模拟安装)
466
+ */
467
+ static async tryLinkLocalPackages(versionPath) {
468
+ try {
469
+ const cliRoot = await getCliRoot();
470
+ let projectRoot = path3.resolve(cliRoot, "../../..");
471
+ let currentDir = cliRoot;
472
+ while (currentDir !== path3.parse(currentDir).root) {
473
+ if (fs2.existsSync(path3.join(currentDir, "pnpm-workspace.yaml"))) {
474
+ projectRoot = currentDir;
475
+ break;
476
+ }
477
+ currentDir = path3.dirname(currentDir);
478
+ }
479
+ const possiblePackagesDirs = [
480
+ path3.join(projectRoot, "packages"),
481
+ // 兼容某些特殊结构,比如 chatbi-v 仓库
482
+ path3.resolve(projectRoot, "../chatbi-v/packages")
483
+ ];
484
+ const localPackages = {};
485
+ const patterns = possiblePackagesDirs.filter((dir) => fs2.existsSync(dir)).map((dir) => path3.join(dir, "**/package.json"));
486
+ if (patterns.length > 0) {
487
+ const pkgJsonFiles = await fg(patterns, {
488
+ ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"],
489
+ absolute: true,
490
+ deep: 5
491
+ // 允许一定的嵌套深度
492
+ });
493
+ for (const pkgJsonPath of pkgJsonFiles) {
494
+ try {
495
+ const pkgJson = await fs2.readJson(pkgJsonPath);
496
+ if (this.CORE_PACKAGES.includes(pkgJson.name) || this.RUNTIME_DEPS.includes(pkgJson.name)) {
497
+ localPackages[pkgJson.name] = path3.dirname(pkgJsonPath);
498
+ }
499
+ } catch (e) {
500
+ }
501
+ }
502
+ }
503
+ if (Object.keys(localPackages).length === 0) {
504
+ return false;
505
+ }
506
+ const linkSummary = Object.entries(localPackages).map(([name, pkgPath]) => `${pc2.cyan(name.padEnd(30))} -> ${pc2.gray(pkgPath)}`).join("\n");
507
+ printBox(
508
+ pc2.green("\u{1F517} \u5DF2\u68C0\u6D4B\u5230\u672C\u5730\u5F00\u53D1\u73AF\u5883\uFF0C\u5C06\u94FE\u63A5\u4EE5\u4E0B\u6838\u5FC3\u5305\uFF1A\n\n") + linkSummary,
509
+ "Monorepo Link Mode"
510
+ );
511
+ const sandboxNodeModules = path3.join(versionPath, "node_modules");
512
+ await fs2.ensureDir(sandboxNodeModules);
513
+ for (const [name, pkgPath] of Object.entries(localPackages)) {
514
+ const targetLinkPath = path3.join(sandboxNodeModules, name);
515
+ await fs2.ensureDir(path3.dirname(targetLinkPath));
516
+ try {
517
+ const stats = await fs2.lstat(targetLinkPath).catch(() => null);
518
+ if (stats) {
519
+ await fs2.remove(targetLinkPath);
520
+ }
521
+ } catch (e) {
522
+ }
523
+ await fs2.symlink(pkgPath, targetLinkPath, "dir");
524
+ }
525
+ const sandboxPkgJsonPath = path3.join(versionPath, "package.json");
526
+ const sandboxPkgJson = await fs2.readJson(sandboxPkgJsonPath);
527
+ const sections = ["dependencies", "devDependencies"];
528
+ let modified = false;
529
+ for (const section of sections) {
530
+ if (sandboxPkgJson[section]) {
531
+ for (const [name, pkgPath] of Object.entries(localPackages)) {
532
+ if (sandboxPkgJson[section][name]) {
533
+ sandboxPkgJson[section][name] = `link:${pkgPath}`;
534
+ modified = true;
535
+ }
536
+ }
537
+ }
538
+ }
539
+ if (modified) {
540
+ await fs2.writeJson(sandboxPkgJsonPath, sandboxPkgJson, { spaces: 2 });
541
+ }
542
+ return true;
543
+ } catch (e) {
544
+ console.warn(pc2.yellow(` \u26A0\uFE0F Link \u672C\u5730\u6E90\u7801\u5931\u8D25\uFF0C\u5C06\u5C1D\u8BD5\u4ECE NPM \u5B89\u88C5: ${e.message}`));
545
+ return false;
546
+ }
547
+ }
548
+ /**
549
+ * 切换全局当前使用的内核版本
550
+ */
551
+ static async useVersion(version) {
552
+ const versionRoot = this.getVersionRoot();
553
+ const currentLinkPath = path3.join(versionRoot, "current");
554
+ const targetPath = this.getVersionPath(version);
555
+ if (!fs2.existsSync(targetPath)) {
556
+ throw new Error(`\u7248\u672C ${version} \u5C1A\u672A\u5B89\u88C5`);
557
+ }
558
+ if (fs2.existsSync(currentLinkPath)) {
559
+ await fs2.remove(currentLinkPath);
560
+ }
561
+ await fs2.symlink(targetPath, currentLinkPath, "dir");
562
+ }
563
+ /**
564
+ * 可视化展示沙箱状态
565
+ */
566
+ static async visualizeStatus(projectRoot) {
567
+ const version = await this.getCurrentVersion(projectRoot);
568
+ const versionPath = this.getVersionPath(version);
569
+ const isInstalled = fs2.existsSync(versionPath);
570
+ const sandboxNm = path3.join(versionPath, "node_modules");
571
+ let statusText = "";
572
+ statusText += `${pc2.bold("\u5F53\u524D\u5185\u6838\u7248\u672C:")} ${pc2.cyan(version)}
573
+ `;
574
+ statusText += `${pc2.bold("\u6C99\u7BB1\u5B89\u88C5\u8DEF\u5F84:")} ${pc2.gray(versionPath)}
575
+ `;
576
+ statusText += `${pc2.bold("\u5B89\u88C5\u72B6\u6001:")} ${isInstalled ? pc2.green("\u5DF2\u5C31\u7EEA") : pc2.red("\u672A\u5B89\u88C5")}
577
+ `;
578
+ if (isInstalled) {
579
+ const corePkgs = this.CORE_PACKAGES.map((pkg) => {
580
+ const pkgPath = path3.join(sandboxNm, pkg);
581
+ const exists = fs2.existsSync(pkgPath);
582
+ let linkTarget = "";
583
+ if (exists) {
584
+ try {
585
+ const stats = fs2.lstatSync(pkgPath);
586
+ if (stats.isSymbolicLink()) {
587
+ linkTarget = ` -> ${pc2.yellow(fs2.readlinkSync(pkgPath))}`;
588
+ }
589
+ } catch (e) {
590
+ }
591
+ }
592
+ return ` ${exists ? pc2.green("\u2713") : pc2.red("\u2717")} ${pkg.padEnd(30)}${linkTarget}`;
593
+ }).join("\n");
594
+ statusText += `
595
+ ${pc2.bold("\u6838\u5FC3\u7EC4\u4EF6\u72B6\u6001:")}
596
+ ${corePkgs}`;
597
+ }
598
+ printBox(statusText, "ChatBI \u5185\u6838\u53EF\u89C2\u6D4B\u6027\u9762\u677F");
599
+ }
600
+ /**
601
+ * 获取当前项目使用的内核版本
602
+ */
603
+ static async getCurrentVersion(projectRoot) {
604
+ try {
605
+ const chatbiDir = path3.join(projectRoot, ".chatbi");
606
+ const tsconfigPath = path3.join(chatbiDir, "tsconfig.json");
607
+ if (fs2.existsSync(tsconfigPath)) {
608
+ const tsconfig = await fs2.readJson(tsconfigPath);
609
+ if (tsconfig.extends && tsconfig.extends.includes("/versions/")) {
610
+ const parts = tsconfig.extends.split("/");
611
+ const vIdx = parts.indexOf("versions");
612
+ if (vIdx !== -1 && parts[vIdx + 1]) {
613
+ return parts[vIdx + 1];
614
+ }
615
+ }
616
+ }
617
+ } catch (e) {
618
+ }
619
+ return "current";
620
+ }
31
621
  };
32
- return function (mod) {
33
- if (mod && mod.__esModule) return mod;
34
- var result = {};
35
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
- __setModuleDefault(result, mod);
37
- return result;
622
+ }
623
+ });
624
+
625
+ // src/config.ts
626
+ import fs3 from "fs-extra";
627
+ import path4 from "path";
628
+ import { createJiti } from "jiti";
629
+ var ConfigManager;
630
+ var init_config = __esm({
631
+ "src/config.ts"() {
632
+ "use strict";
633
+ init_esm_shims();
634
+ init_utils();
635
+ ConfigManager = class {
636
+ static {
637
+ this.CONFIG_FILES = [
638
+ "chatbi.config.ts",
639
+ "chatbi.config.js",
640
+ "chatbi.config.json",
641
+ ".chatbirc",
642
+ ".chatbirc.json"
643
+ ];
644
+ }
645
+ /**
646
+ * 加载项目配置
647
+ * @param cwd 项目根目录
648
+ */
649
+ static async loadConfig(cwd = process.cwd()) {
650
+ const config = {};
651
+ const versionFilePath = path4.join(cwd, ".chatbi-version");
652
+ if (fs3.existsSync(versionFilePath)) {
653
+ try {
654
+ const version = (await fs3.readFile(versionFilePath, "utf-8")).trim();
655
+ if (version) {
656
+ config.coreVersion = version;
657
+ }
658
+ } catch (e) {
659
+ }
660
+ }
661
+ const jiti = createJiti(cwd);
662
+ for (const file of this.CONFIG_FILES) {
663
+ const configPath = path4.join(cwd, file);
664
+ if (fs3.existsSync(configPath)) {
665
+ try {
666
+ let projectConfig = {};
667
+ if (file.endsWith(".ts") || file.endsWith(".js")) {
668
+ const mod = await jiti.import(configPath, { default: true });
669
+ projectConfig = mod.default || mod || {};
670
+ } else if (file.endsWith(".json") || file.startsWith(".chatbirc")) {
671
+ projectConfig = await fs3.readJson(configPath);
672
+ }
673
+ return {
674
+ ...projectConfig,
675
+ ...config
676
+ };
677
+ } catch (e) {
678
+ logger.error(`\u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6 ${file} \u5931\u8D25`, e);
679
+ }
680
+ }
681
+ }
682
+ return config;
683
+ }
38
684
  };
39
- })();
40
- var __importDefault = (this && this.__importDefault) || function (mod) {
41
- return (mod && mod.__esModule) ? mod : { "default": mod };
42
- };
43
- Object.defineProperty(exports, "__esModule", { value: true });
44
- const cac_1 = __importDefault(require("cac"));
45
- const picocolors_1 = __importDefault(require("picocolors"));
46
- const figlet_1 = __importDefault(require("figlet"));
47
- const gradient_string_1 = __importDefault(require("gradient-string"));
48
- const boxen_1 = __importDefault(require("boxen"));
49
- const build_1 = require("./commands/build");
50
- const dev_1 = require("./commands/dev");
51
- const init_1 = require("./commands/init");
52
- const add_1 = require("./commands/add");
53
- const gl_1 = require("./commands/gl");
54
- const sync_1 = require("./commands/sync");
55
- const doctor_1 = require("./commands/doctor");
56
- const discover_1 = require("./commands/discover");
57
- const ls_1 = require("./commands/ls");
58
- const use_1 = require("./commands/use");
59
- const fetch_1 = require("./commands/fetch");
60
- const install_1 = require("./commands/install");
61
- const package_json_1 = __importDefault(require("../package.json"));
62
- const utils_1 = require("./utils");
63
- const cli = (0, cac_1.default)('chatbi-cli');
64
- // 打印漂亮的 Header
65
- const showHeader = () => {
66
- const title = figlet_1.default.textSync('ChatBI-V CLI', { font: 'Standard' });
67
- console.log(gradient_string_1.default.pastel.multiline(title));
68
- console.log((0, boxen_1.default)(picocolors_1.default.cyan(`ChatBI-V 统一开发工具 v${package_json_1.default.version}`), {
69
- padding: 0,
70
- margin: { top: 1, bottom: 1 },
71
- borderStyle: 'round',
72
- borderColor: 'cyan',
73
- title: 'CoreKit Enabled',
74
- titleAlignment: 'center'
75
- }));
76
- };
77
- /**
78
- * 包装命令 Action,统一错误处理
79
- */
80
- const wrapAction = (action, commandName) => {
81
- return async (...args) => {
82
- showHeader();
685
+ }
686
+ });
687
+
688
+ // src/corekit.ts
689
+ import path5 from "path";
690
+ import fs4 from "fs-extra";
691
+ import pc3 from "picocolors";
692
+ import prompts from "prompts";
693
+ import fg2 from "fast-glob";
694
+ var CoreKit;
695
+ var init_corekit = __esm({
696
+ "src/corekit.ts"() {
697
+ "use strict";
698
+ init_esm_shims();
699
+ init_utils();
700
+ init_sandbox();
701
+ init_config();
702
+ CoreKit = class {
703
+ /**
704
+ * 解析项目模式
705
+ */
706
+ static async detectMode(cwd) {
707
+ const pkgPath = path5.join(cwd, "package.json");
708
+ if (!fs4.existsSync(pkgPath)) return "app";
709
+ const pkg = await fs4.readJson(pkgPath);
710
+ if (pkg.workspaces || fs4.existsSync(path5.join(cwd, "pnpm-workspace.yaml"))) {
711
+ return "monorepo";
712
+ }
713
+ if (pkg.chatbi?.type === "plugin" || pkg.plugin === true) return "plugin";
714
+ if (pkg.chatbi?.type === "app") return "app";
715
+ const pluginEntries = await fg2(["index.plugin.{ts,js}", "src/index.plugin.{ts,js}"], { cwd });
716
+ if (pluginEntries.length > 0) return "plugin";
717
+ if (fs4.existsSync(path5.join(cwd, "index.html"))) {
718
+ return "app";
719
+ }
720
+ if (fs4.existsSync(path5.join(cwd, "src/index.ts")) || fs4.existsSync(path5.join(cwd, "src/index.tsx"))) {
721
+ if (pkg.bin) return "lib";
722
+ if (pkg.peerDependencies?.react && !pkg.dependencies?.react) return "plugin";
723
+ return "lib";
724
+ }
725
+ return "app";
726
+ }
727
+ /**
728
+ * 获取当前生效的内核版本
729
+ * 优先序:项目配置 > 全局 current 软链 > 最新安装的版本
730
+ */
731
+ static async resolveVersion(projectRoot) {
732
+ if (projectRoot) {
733
+ const config = await ConfigManager.loadConfig(projectRoot);
734
+ if (config.coreVersion) return config.coreVersion;
735
+ }
736
+ try {
737
+ const cliRoot = await getCliRoot();
738
+ const cliVersionFile = path5.join(cliRoot, ".chatbi-version");
739
+ if (fs4.existsSync(cliVersionFile)) {
740
+ const version = (await fs4.readFile(cliVersionFile, "utf-8")).trim();
741
+ if (version) return version;
742
+ }
743
+ } catch (e) {
744
+ }
745
+ const currentLinkPath = path5.join(Sandbox.getVersionRoot(), "current");
746
+ if (fs4.existsSync(currentLinkPath)) {
747
+ try {
748
+ const realPath = await fs4.realpath(currentLinkPath);
749
+ return path5.basename(realPath);
750
+ } catch (e) {
751
+ }
752
+ }
753
+ const versions = await this.listVersions();
754
+ return versions[0] || "latest";
755
+ }
756
+ /**
757
+ * 列出所有已安装版本
758
+ */
759
+ static async listVersions() {
760
+ const versionsDir = Sandbox.getVersionRoot();
761
+ if (!fs4.existsSync(versionsDir)) return [];
762
+ const dirs = await fg2("*", {
763
+ cwd: versionsDir,
764
+ onlyDirectories: true,
765
+ deep: 1
766
+ });
767
+ return dirs.filter((d) => d !== "current").sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
768
+ }
769
+ /**
770
+ * 自动发现项目中的插件
771
+ */
772
+ static async discoverPlugins(rootDir) {
773
+ const pluginsDir = path5.join(rootDir, "plugins");
774
+ if (!fs4.existsSync(pluginsDir)) return [];
775
+ const pkgFiles = await fg2("*/package.json", { cwd: pluginsDir, absolute: true });
776
+ const plugins = [];
777
+ for (const pkgPath of pkgFiles) {
778
+ try {
779
+ const pkg = await fs4.readJson(pkgPath);
780
+ const pluginPath = path5.dirname(pkgPath);
781
+ plugins.push({
782
+ name: pkg.name || path5.basename(pluginPath),
783
+ path: pluginPath,
784
+ id: path5.basename(pluginPath)
785
+ });
786
+ } catch (e) {
787
+ }
788
+ }
789
+ return plugins;
790
+ }
791
+ /**
792
+ * 启动开发环境 (统一入口)
793
+ */
794
+ static async startDev(cwd, options = {}) {
795
+ const mode = await this.detectMode(cwd);
796
+ const version = await this.resolveVersion(cwd);
797
+ printBox(
798
+ `${pc3.cyan(pc3.bold("\u{1F680} ChatBI Dev Server"))}
799
+
800
+ ${pc3.gray("Mode: ")} ${pc3.yellow(mode)}
801
+ ${pc3.gray("Kernel: ")} ${pc3.green(version)}
802
+ ${pc3.gray("Root: ")} ${pc3.white(cwd)}`,
803
+ "Dev Server"
804
+ );
805
+ const spinner = createSpinner("\u6B63\u5728\u51C6\u5907\u6C99\u7BB1\u73AF\u5883...").start();
806
+ try {
807
+ await Sandbox.prepare(version);
808
+ spinner.text = pc3.cyan("\u6B63\u5728\u6CE8\u5165\u865A\u62DF\u4E0A\u4E0B\u6587...");
809
+ await Sandbox.injectContext(cwd, version);
810
+ spinner.succeed(pc3.green("\u73AF\u5883\u5C31\u7EEA"));
811
+ if (mode === "plugin") {
812
+ await this.startPluginDevServer(cwd, version, options.port);
813
+ } else if (mode === "app") {
814
+ await this.startAppDevServer(cwd, version, options.port);
815
+ } else {
816
+ await this.startMonorepoDevServer(cwd, version, options.port);
817
+ }
818
+ } catch (e) {
819
+ spinner.fail(pc3.red(`\u542F\u52A8\u5931\u8D25: ${e.message}`));
820
+ }
821
+ }
822
+ /**
823
+ * 启动 Monorepo 开发服务器
824
+ */
825
+ static async startMonorepoDevServer(rootDir, version, customPort) {
826
+ const appsDir = path5.join(rootDir, "apps");
827
+ if (!fs4.existsSync(appsDir)) {
828
+ logger.warn("\u5F53\u524D Monorepo \u4E0B\u672A\u627E\u5230 apps/ \u76EE\u5F55");
829
+ return;
830
+ }
831
+ const pkgFiles = await fg2("*/package.json", { cwd: appsDir, absolute: true });
832
+ const apps = pkgFiles.map((pkgPath) => ({
833
+ name: path5.basename(path5.dirname(pkgPath)),
834
+ path: path5.dirname(pkgPath)
835
+ }));
836
+ if (apps.length === 0) {
837
+ logger.warn("\u5F53\u524D Monorepo \u4E0B\u672A\u627E\u5230\u4EFB\u4F55\u5E94\u7528 (apps/)");
838
+ return;
839
+ }
840
+ const response = await prompts({
841
+ type: "select",
842
+ name: "appPath",
843
+ message: "\u8BF7\u9009\u62E9\u8981\u542F\u52A8\u7684\u5E94\u7528:",
844
+ choices: apps.map((app) => ({ title: app.name, value: app.path })),
845
+ initial: 0
846
+ });
847
+ if (!response.appPath) {
848
+ logger.info("\u5DF2\u53D6\u6D88");
849
+ return;
850
+ }
851
+ await this.startAppDevServer(response.appPath, version, customPort);
852
+ }
853
+ /**
854
+ * 启动插件开发服务器 (Hosted Mode)
855
+ */
856
+ static async startPluginDevServer(pluginDir, version, customPort) {
857
+ logger.info("\u6B63\u5728\u542F\u52A8\u6258\u7BA1\u5F0F Shell...");
858
+ const shellPort = customPort || 5173;
859
+ const sandboxRoot = Sandbox.getRoot();
860
+ const versionPath = Sandbox.getVersionPath(version);
861
+ const sandboxNodeModules = path5.join(versionPath, "node_modules");
862
+ const shellDir = await Sandbox.ensureShell(version);
863
+ const coreAlias = Sandbox.getCoreAlias(version);
864
+ const tailwindPath = path5.join(sandboxNodeModules, "tailwindcss");
865
+ const autoprefixerPath = path5.join(sandboxNodeModules, "autoprefixer");
866
+ let pluginEntry = path5.join(pluginDir, "src/index.tsx");
867
+ if (!fs4.existsSync(pluginEntry)) {
868
+ pluginEntry = path5.join(pluginDir, "src/index.ts");
869
+ }
870
+ const define = {
871
+ "process.env.CHATBI_PLUGIN_PATH": JSON.stringify(pluginDir)
872
+ };
873
+ const { createServer } = await import("vite");
83
874
  try {
84
- await action(...args);
875
+ const server = await createServer({
876
+ root: shellDir,
877
+ configFile: false,
878
+ css: {
879
+ postcss: {
880
+ plugins: [
881
+ __require(tailwindPath)({
882
+ presets: [__require(path5.join(sandboxNodeModules, "@chatbi-v/tailwind-config"))],
883
+ darkMode: "class",
884
+ content: [
885
+ path5.join(shellDir, "index.html"),
886
+ path5.join(shellDir, "src/**/*.{ts,tsx}"),
887
+ path5.join(pluginDir, "src/**/*.{ts,tsx}")
888
+ ]
889
+ }),
890
+ __require(autoprefixerPath)
891
+ ]
892
+ }
893
+ },
894
+ server: {
895
+ port: shellPort,
896
+ host: true,
897
+ fs: {
898
+ allow: [
899
+ sandboxRoot,
900
+ pluginDir,
901
+ path5.resolve(pluginDir, "../../")
902
+ ]
903
+ }
904
+ },
905
+ resolve: {
906
+ alias: {
907
+ ...coreAlias,
908
+ "react": path5.join(sandboxNodeModules, "react"),
909
+ "react-dom": path5.join(sandboxNodeModules, "react-dom"),
910
+ "@": path5.join(shellDir, "src"),
911
+ // 关键:将虚拟模块指向用户插件
912
+ "virtual:user-plugin": pluginEntry,
913
+ // 防止 glob 报错,提供空的映射
914
+ "@chatbi-plugins": path5.join(shellDir, "empty"),
915
+ "@chatbi-apps": path5.join(shellDir, "empty")
916
+ }
917
+ },
918
+ define
919
+ });
920
+ await server.listen();
921
+ const localUrl = `http://localhost:${shellPort}/`;
922
+ printBox(
923
+ `${pc3.green(pc3.bold("\u2705 \u6258\u7BA1\u5F0F Shell \u5DF2\u542F\u52A8"))}
924
+
925
+ ${pc3.white("Local: ")} ${pc3.cyan(pc3.underline(localUrl))}`,
926
+ "Shell Success"
927
+ );
928
+ } catch (e) {
929
+ logger.error("Shell \u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25", e);
85
930
  }
86
- catch (e) {
87
- utils_1.logger.error(`${commandName} 执行失败`, e);
88
- process.exit(1);
931
+ }
932
+ /**
933
+ * 启动应用开发服务器 (Integrated Mode)
934
+ */
935
+ static async startAppDevServer(appDir, version, customPort) {
936
+ logger.info("\u6B63\u5728\u542F\u52A8\u5E94\u7528...");
937
+ const versionPath = Sandbox.getVersionPath(version);
938
+ const sandboxNodeModules = path5.join(versionPath, "node_modules");
939
+ const coreAlias = Sandbox.getCoreAlias(version);
940
+ const { createServer, loadConfigFromFile } = await import("vite");
941
+ try {
942
+ const configContext = { command: "serve", mode: "development" };
943
+ const userConfig = await loadConfigFromFile(configContext, void 0, appDir).catch(() => null);
944
+ const server = await createServer({
945
+ root: appDir,
946
+ // 这里我们允许用户有自己的 vite config,但我们会 merge alias
947
+ // 实际场景中可能需要写一个 Vite 插件来做这件事,这里简单处理
948
+ resolve: {
949
+ alias: {
950
+ ...coreAlias,
951
+ // 补充常用的基础依赖映射,防止用户 vite.config.ts 中的插件找不到依赖
952
+ "react": path5.join(sandboxNodeModules, "react"),
953
+ "react-dom": path5.join(sandboxNodeModules, "react-dom"),
954
+ "@vitejs/plugin-react": path5.join(sandboxNodeModules, "@vitejs/plugin-react")
955
+ }
956
+ },
957
+ server: {
958
+ port: customPort || 3e3,
959
+ host: true,
960
+ fs: {
961
+ allow: [
962
+ Sandbox.getRoot(),
963
+ appDir,
964
+ // 允许访问沙箱中的所有依赖
965
+ sandboxNodeModules
966
+ ]
967
+ }
968
+ }
969
+ });
970
+ await server.listen();
971
+ const localUrl = `http://localhost:${server.config.server.port}/`;
972
+ printBox(
973
+ `${pc3.green(pc3.bold("\u2705 \u5E94\u7528\u5DF2\u6210\u529F\u542F\u52A8"))}
974
+
975
+ ${pc3.white("Local: ")} ${pc3.cyan(pc3.underline(localUrl))}`,
976
+ "App Success"
977
+ );
978
+ } catch (e) {
979
+ logger.error("\u5E94\u7528\u542F\u52A8\u5931\u8D25", e);
89
980
  }
981
+ }
90
982
  };
91
- };
92
- cli
93
- .command('dev', '启动开发服务器')
94
- .alias('d')
95
- .option('--port <port>', '端口号')
96
- .action(wrapAction(dev_1.dev, 'dev'));
97
- cli
98
- .command('build', '构建当前项目')
99
- .alias('b')
100
- .option('--watch', '开启监听模式')
101
- .action(wrapAction(build_1.build, 'build'));
102
- cli
103
- .command('fetch <version>', '获取指定版本的内核 (支持打包)')
104
- .option('--pack', '打包为离线安装包 (.tgz)')
105
- .action(wrapAction(fetch_1.fetch, 'fetch'));
106
- cli
107
- .command('install <target>', '安装内核 (支持版本号或离线包路径)')
108
- .action(wrapAction(install_1.install, 'install'));
109
- cli
110
- .command('init [name]', '初始化一个新的业务插件项目')
111
- .alias('create')
112
- .alias('i')
113
- .option('--project-type <type>', '项目类型 (monorepo | app | plugin)')
114
- .option('--include-app', 'Monorepo 中包含 App')
115
- .option('--no-include-app', 'Monorepo 中不包含 App')
116
- .option('--include-plugin', 'Monorepo 中包含 Plugin')
117
- .option('--no-include-plugin', 'Monorepo 中不包含 Plugin')
118
- .option('--plugin-type <type>', '插件类型 (business | system)')
119
- .option('--theme <theme>', '主题 (standard | nebula | glass)')
120
- .action(wrapAction(async (name, options) => {
121
- await (0, init_1.init)({
122
- name,
123
- projectType: options.projectType,
124
- includeApp: options.includeApp,
125
- includePlugin: options.includePlugin,
126
- pluginType: options.pluginType,
127
- theme: options.theme
983
+ }
984
+ });
985
+
986
+ // src/commands/build.ts
987
+ var build_exports = {};
988
+ __export(build_exports, {
989
+ build: () => build
990
+ });
991
+ import { execa as execa2 } from "execa";
992
+ import fs5 from "fs-extra";
993
+ import path6 from "path";
994
+ import pc4 from "picocolors";
995
+ import { build as tsupBuild } from "tsup";
996
+ async function build(options) {
997
+ const cwd = process.cwd();
998
+ const pkgPath = path6.join(cwd, "package.json");
999
+ if (!fs5.existsSync(pkgPath)) {
1000
+ logger.error(`\u5728 ${cwd} \u4E2D\u672A\u627E\u5230 package.json`);
1001
+ return;
1002
+ }
1003
+ const pkg = await fs5.readJson(pkgPath);
1004
+ if (options.force) {
1005
+ const spinnerClean = createSpinner("\u6B63\u5728\u6E05\u7406\u7F13\u5B58\u73AF\u5883...").start();
1006
+ try {
1007
+ await Sandbox.clean(cwd, true);
1008
+ spinnerClean.succeed("\u7F13\u5B58\u73AF\u5883\u6E05\u7406\u5B8C\u6210");
1009
+ } catch (e) {
1010
+ spinnerClean.fail("\u7F13\u5B58\u6E05\u7406\u5931\u8D25");
1011
+ logger.error("\u6E05\u7406\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF", e);
1012
+ }
1013
+ }
1014
+ const version = await CoreKit.resolveVersion(cwd);
1015
+ logger.info(`\u6B63\u5728\u6784\u5EFA\u9879\u76EE: ${pc4.bold(pkg.name || "unnamed")} (\u5185\u6838\u7248\u672C: ${version})
1016
+ `);
1017
+ const spinner = createSpinner("\u6B63\u5728\u51C6\u5907\u6784\u5EFA\u73AF\u5883...").start();
1018
+ spinner.text = "\u6B63\u5728\u540C\u6B65\u6C99\u7BB1\u5185\u6838...";
1019
+ await Sandbox.prepare(version, options.force);
1020
+ if (pkg.workspaces || fs5.existsSync(path6.join(cwd, "pnpm-workspace.yaml"))) {
1021
+ spinner.text = "\u68C0\u6D4B\u5230 Monorepo\uFF0C\u6B63\u5728\u521D\u59CB\u5316\u6839\u76EE\u5F55\u4E0A\u4E0B\u6587...";
1022
+ await Sandbox.injectContext(cwd, version);
1023
+ spinner.text = "\u6B63\u5728\u540C\u6B65\u5B50\u5305\u4E0A\u4E0B\u6587...";
1024
+ const subDirs = ["apps", "plugins", "packages"];
1025
+ for (const dir of subDirs) {
1026
+ const dirPath = path6.join(cwd, dir);
1027
+ if (fs5.existsSync(dirPath)) {
1028
+ const entries = await fs5.readdir(dirPath, { withFileTypes: true });
1029
+ for (const entry2 of entries) {
1030
+ if (entry2.isDirectory()) {
1031
+ const subPkgPath = path6.join(dirPath, entry2.name);
1032
+ if (fs5.existsSync(path6.join(subPkgPath, "package.json"))) {
1033
+ await Sandbox.injectContext(subPkgPath, version);
1034
+ }
1035
+ }
1036
+ }
1037
+ }
1038
+ }
1039
+ } else {
1040
+ await Sandbox.injectContext(cwd, version);
1041
+ }
1042
+ spinner.succeed("\u6784\u5EFA\u73AF\u5883\u5C31\u7EEA");
1043
+ if (pkg.scripts && pkg.scripts.build && !process.env.CHATBI_CLI_INTERNAL) {
1044
+ const buildScript = pkg.scripts.build;
1045
+ if (!buildScript.includes("chatbi-cli build") && !buildScript.includes("chatbi build")) {
1046
+ logger.info(`\u68C0\u6D4B\u5230\u81EA\u5B9A\u4E49 build \u811A\u672C\uFF0C\u6B63\u5728\u6267\u884C: ${pc4.cyan("npm run build")}`);
1047
+ const args = ["run", "build"];
1048
+ if (options.watch) {
1049
+ args.push("--", "--watch");
1050
+ }
1051
+ await execa2("npm", args, {
1052
+ stdio: "inherit",
1053
+ env: { ...process.env, CHATBI_CLI_INTERNAL: "true" }
1054
+ });
1055
+ return;
1056
+ }
1057
+ }
1058
+ const mode = await CoreKit.detectMode(cwd);
1059
+ if (mode === "monorepo") {
1060
+ logger.info("\u68C0\u6D4B\u5230 Monorepo \u9879\u76EE\uFF0C\u6B63\u5728\u9012\u5F52\u6784\u5EFA\u5B50\u5305...");
1061
+ await execa2("pnpm", ["-r", "build"], { stdio: "inherit", cwd });
1062
+ return;
1063
+ }
1064
+ if (mode === "app") {
1065
+ logger.info("\u6B63\u5728\u6784\u5EFA\u5E94\u7528 (Vite)...");
1066
+ const { build: viteBuild } = await import("vite");
1067
+ const coreAlias = Sandbox.getCoreAlias(version);
1068
+ await viteBuild({
1069
+ root: cwd,
1070
+ configFile: fs5.existsSync(path6.join(cwd, "vite.config.ts")) ? void 0 : false,
1071
+ resolve: {
1072
+ alias: {
1073
+ ...coreAlias
1074
+ }
1075
+ },
1076
+ build: {
1077
+ watch: options.watch ? {} : null,
1078
+ outDir: "dist",
1079
+ emptyOutDir: true,
1080
+ minify: !options.watch ? "esbuild" : false
1081
+ // 生产环境开启压缩混淆
1082
+ },
1083
+ server: {
1084
+ fs: {
1085
+ allow: [
1086
+ Sandbox.getRoot(),
1087
+ cwd
1088
+ ]
1089
+ }
1090
+ }
1091
+ });
1092
+ if (!options.watch) {
1093
+ printBox(
1094
+ pc4.green(pc4.bold("\u2728 \u5E94\u7528\u6784\u5EFA\u6210\u529F!")) + "\n\n" + pc4.white("\u4EA7\u7269\u76EE\u5F55: ") + pc4.cyan("dist"),
1095
+ "Build Success"
1096
+ );
1097
+ }
1098
+ return;
1099
+ }
1100
+ let entry = ["src/index.ts"];
1101
+ if (fs5.existsSync(path6.join(cwd, "src/index.tsx"))) {
1102
+ entry = ["src/index.tsx"];
1103
+ } else if (!fs5.existsSync(path6.join(cwd, "src/index.ts"))) {
1104
+ logger.error("\u672A\u627E\u5230\u5165\u53E3\u6587\u4EF6\u3002\u671F\u671B src/index.ts \u6216 src/index.tsx");
1105
+ return;
1106
+ }
1107
+ const isPlugin = mode === "plugin";
1108
+ if (!options.watch) {
1109
+ await fs5.remove(path6.join(cwd, "dist"));
1110
+ const tsbuildinfo = path6.join(cwd, "tsconfig.tsbuildinfo");
1111
+ if (fs5.existsSync(tsbuildinfo)) {
1112
+ await fs5.remove(tsbuildinfo);
1113
+ }
1114
+ }
1115
+ const external = [
1116
+ "react",
1117
+ "react-dom",
1118
+ "react/jsx-runtime",
1119
+ "react-is",
1120
+ "antd",
1121
+ "@ant-design/icons",
1122
+ "@ant-design/x",
1123
+ ...Object.keys(pkg.dependencies || {}),
1124
+ ...Object.keys(pkg.peerDependencies || {})
1125
+ ];
1126
+ if (isPlugin) {
1127
+ const coreDeps = Sandbox.CORE_PACKAGES;
1128
+ coreDeps.forEach((dep) => {
1129
+ if (!external.includes(dep)) {
1130
+ external.push(dep);
1131
+ }
128
1132
  });
129
- }, 'init'));
130
- cli
131
- .command('add [name]', '在当前项目中添加一个新插件')
132
- .option('-t, --type <type>', '插件类型 (business | system)')
133
- .option('--display-name <name>', '插件显示名称')
134
- .option('--desc <description>', '插件描述')
135
- .action(wrapAction(async (name, options) => {
136
- await (0, add_1.add)({
137
- name,
138
- type: options.type,
139
- displayName: options.displayName,
140
- description: options.desc
1133
+ }
1134
+ const commonConfig = {
1135
+ entry,
1136
+ dts: false,
1137
+ clean: false,
1138
+ sourcemap: false,
1139
+ target: "esnext",
1140
+ platform: isPlugin ? "browser" : "node",
1141
+ external,
1142
+ minify: !options.watch,
1143
+ // 生产环境开启压缩混淆
1144
+ watch: options.watch,
1145
+ silent: true,
1146
+ esbuildOptions(options2) {
1147
+ options2.logOverride = {
1148
+ "empty-import-meta": "silent"
1149
+ };
1150
+ options2.external = options2.external || [];
1151
+ const forceExternal = [
1152
+ "react",
1153
+ "react-dom",
1154
+ "antd",
1155
+ "@ant-design/icons",
1156
+ "@ant-design/x",
1157
+ ...Sandbox.CORE_PACKAGES
1158
+ ];
1159
+ forceExternal.forEach((dep) => {
1160
+ if (!options2.external.includes(dep)) {
1161
+ options2.external.push(dep);
1162
+ }
1163
+ });
1164
+ }
1165
+ };
1166
+ const buildSpinner = createSpinner("\u6B63\u5728\u7F16\u8BD1\u6E90\u7801...").start();
1167
+ if (isPlugin) {
1168
+ buildSpinner.text = "\u6B63\u5728\u6784\u5EFA ESM \u683C\u5F0F...";
1169
+ await tsupBuild({
1170
+ ...commonConfig,
1171
+ format: ["esm"],
1172
+ outExtension: () => ({ js: ".mjs" })
141
1173
  });
142
- }, 'add'));
143
- cli
144
- .command('update [targetVersion]', '更新内核版本')
145
- .alias('up')
146
- .action(wrapAction(async (targetVersion) => {
147
- const { sync } = await Promise.resolve().then(() => __importStar(require('./commands/sync')));
148
- await sync({ version: targetVersion, force: true });
149
- utils_1.logger.success('更新完成!');
150
- }, 'update'));
151
- cli
152
- .command('sync', '同步内核依赖与规范')
153
- .alias('s')
154
- .option('-v, --core-version <version>', '指定内核版本')
155
- .option('-f, --force', '强制重新初始化内核沙箱')
156
- .option('--clean', '清理并重置沙箱')
157
- .action(wrapAction(async (options) => {
158
- await (0, sync_1.sync)({ ...options, version: options.coreVersion });
159
- console.log('');
160
- await (0, doctor_1.doctor)({ fix: false });
161
- }, 'sync'));
162
- cli
163
- .command('doctor', '诊断项目健康状况并修复')
164
- .alias('dr')
165
- .option('--fix', '自动修复发现的问题')
166
- .action(wrapAction(doctor_1.doctor, 'doctor'));
167
- cli
168
- .command('list', '列出所有已安装的内核沙箱版本')
169
- .alias('ls')
170
- .action(wrapAction(ls_1.ls, 'ls'));
171
- cli
172
- .command('use <version>', '切换当前项目使用的内核版本')
173
- .alias('u')
174
- .option('--global', '切换全局默认内核版本')
175
- .action(wrapAction(use_1.use, 'use'));
176
- cli
177
- .command('gl', '使用 AI 脚手架生成代码或文档')
178
- .option('-t, --type <type>', '生成类型 (plugin|util|doc|component)')
179
- .option('-p, --prompt <prompt>', 'AI 需求描述')
180
- .action(wrapAction(gl_1.gl, 'gl'));
181
- cli
182
- .command('discover', '扫描并发现当前项目中的插件')
183
- .action(wrapAction(discover_1.discover, 'discover'));
184
- cli
185
- .command('bench', '运行 CLI 性能基准测试')
186
- .action(wrapAction(async () => {
187
- const { bench } = await Promise.resolve().then(() => __importStar(require('./commands/bench')));
188
- await bench();
189
- }, 'bench'));
190
- cli.help((sections) => {
1174
+ buildSpinner.text = "\u6B63\u5728\u6784\u5EFA IIFE \u683C\u5F0F (Plugin)...";
1175
+ await tsupBuild({
1176
+ ...commonConfig,
1177
+ format: ["iife"],
1178
+ globalName: pkg.name.replace(/[^a-zA-Z0-9]/g, "_"),
1179
+ outExtension: () => ({ js: ".plugin.js" }),
1180
+ platform: "browser",
1181
+ define: {
1182
+ "import.meta.env": "process.env"
1183
+ },
1184
+ esbuildOptions(options2) {
1185
+ options2.logOverride = {
1186
+ "empty-import-meta": "silent"
1187
+ };
1188
+ options2.external = options2.external || [];
1189
+ const forceExternal = [
1190
+ "react",
1191
+ "react-dom",
1192
+ "antd",
1193
+ "@ant-design/icons",
1194
+ "@ant-design/x",
1195
+ ...Sandbox.CORE_PACKAGES
1196
+ ];
1197
+ forceExternal.forEach((dep) => {
1198
+ if (!options2.external.includes(dep)) {
1199
+ options2.external.push(dep);
1200
+ }
1201
+ });
1202
+ }
1203
+ });
1204
+ } else {
1205
+ buildSpinner.text = "\u6B63\u5728\u7F16\u8BD1\u6E90\u7801...";
1206
+ await tsupBuild({
1207
+ ...commonConfig,
1208
+ format: ["cjs", "esm"],
1209
+ outExtension({ format }) {
1210
+ return { js: format === "esm" ? ".mjs" : ".cjs" };
1211
+ }
1212
+ });
1213
+ }
1214
+ buildSpinner.succeed("\u6E90\u7801\u7F16\u8BD1\u5B8C\u6210");
1215
+ if (!options.watch) {
1216
+ const dtsSpinner = createSpinner("\u6B63\u5728\u751F\u6210\u7C7B\u578B\u5B9A\u4E49...").start();
1217
+ try {
1218
+ const localTsc = path6.join(cwd, "node_modules/.bin/tsc");
1219
+ const sandboxTsc = path6.join(Sandbox.getVersionPath(version), "node_modules/.bin/tsc");
1220
+ let tscBin = "tsc";
1221
+ if (fs5.existsSync(localTsc)) {
1222
+ tscBin = localTsc;
1223
+ } else if (fs5.existsSync(sandboxTsc)) {
1224
+ tscBin = sandboxTsc;
1225
+ } else {
1226
+ if (fs5.existsSync(path6.join(cwd, "pnpm-lock.yaml"))) {
1227
+ await execa2("pnpm", ["exec", "tsc", "--build", "tsconfig.json"]);
1228
+ dtsSpinner.succeed("\u7C7B\u578B\u5B9A\u4E49\u751F\u6210\u5B8C\u6210");
1229
+ } else {
1230
+ await execa2("npx", ["-p", "typescript", "tsc", "--build", "tsconfig.json"]);
1231
+ dtsSpinner.succeed("\u7C7B\u578B\u5B9A\u4E49\u751F\u6210\u5B8C\u6210");
1232
+ }
1233
+ }
1234
+ if (tscBin !== "tsc") {
1235
+ await execa2(tscBin, ["--build", "tsconfig.json"]);
1236
+ dtsSpinner.succeed("\u7C7B\u578B\u5B9A\u4E49\u751F\u6210\u5B8C\u6210");
1237
+ }
1238
+ } catch (e) {
1239
+ dtsSpinner.warn("\u7C7B\u578B\u751F\u6210\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u9879\u76EE\u4E2D\u7684 tsconfig.json \u914D\u7F6E");
1240
+ }
1241
+ printBox(
1242
+ pc4.green(pc4.bold("\u2728 \u6784\u5EFA\u5B8C\u6210!")) + "\n\n" + pc4.white("\u4EA7\u7269\u76EE\u5F55: ") + pc4.cyan("dist") + "\n" + pc4.white("\u6784\u5EFA\u6A21\u5F0F: ") + pc4.cyan(isPlugin ? "Plugin" : "Library"),
1243
+ "Build Success"
1244
+ );
1245
+ }
1246
+ }
1247
+ var init_build = __esm({
1248
+ "src/commands/build.ts"() {
1249
+ "use strict";
1250
+ init_esm_shims();
1251
+ init_sandbox();
1252
+ init_corekit();
1253
+ init_utils();
1254
+ }
1255
+ });
1256
+
1257
+ // src/commands/sync.ts
1258
+ var sync_exports = {};
1259
+ __export(sync_exports, {
1260
+ sync: () => sync
1261
+ });
1262
+ import fs6 from "fs-extra";
1263
+ import path7 from "path";
1264
+ import pc5 from "picocolors";
1265
+ async function sync(options = {}) {
1266
+ const cwd = options.cwd || process.cwd();
1267
+ const pkgPath = path7.join(cwd, "package.json");
1268
+ if (!fs6.existsSync(pkgPath)) {
1269
+ logger.error("\u672A\u627E\u5230 package.json\u3002\u8BF7\u5728\u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u8FD0\u884C\u3002");
1270
+ return;
1271
+ }
1272
+ const pkg = await fs6.readJson(pkgPath);
1273
+ let version = options.version;
1274
+ if (!version) {
1275
+ version = await CoreKit.resolveVersion(cwd);
1276
+ }
1277
+ if (options.clean) {
1278
+ const cleanSpinner = createSpinner(`\u6B63\u5728\u6E05\u7406\u6C99\u7BB1\u7248\u672C ${version}...`).start();
1279
+ await Sandbox.cleanVersion(version);
1280
+ cleanSpinner.succeed(`\u6C99\u7BB1\u7248\u672C ${version} \u5DF2\u6E05\u7406`);
1281
+ }
1282
+ const mainSpinner = createSpinner(`\u6B63\u5728\u540C\u6B65\u5185\u6838\u4F9D\u8D56 (\u7248\u672C: ${version})...`).start();
1283
+ mainSpinner.text = "\u6B63\u5728\u540C\u6B65\u6C99\u7BB1\u5185\u6838...";
1284
+ await Sandbox.prepare(version, options.force);
1285
+ mainSpinner.text = "\u6B63\u5728\u751F\u6210\u865A\u62DF\u4E0A\u4E0B\u6587...";
1286
+ if (options.version) {
1287
+ const versionFilePath = path7.join(cwd, ".chatbi-version");
1288
+ await fs6.writeFile(versionFilePath, version, "utf-8");
1289
+ }
1290
+ await Sandbox.injectContext(cwd, version);
1291
+ let modified = false;
1292
+ const deps = pkg.dependencies || {};
1293
+ const devDeps = pkg.devDependencies || {};
1294
+ const isVirtualMode = true;
1295
+ if (isVirtualMode) {
1296
+ for (const pkgName of Sandbox.CORE_PACKAGES) {
1297
+ if (deps[pkgName]) {
1298
+ delete deps[pkgName];
1299
+ modified = true;
1300
+ }
1301
+ if (devDeps[pkgName]) {
1302
+ delete devDeps[pkgName];
1303
+ modified = true;
1304
+ }
1305
+ }
1306
+ }
1307
+ if (modified) {
1308
+ pkg.dependencies = deps;
1309
+ pkg.devDependencies = devDeps;
1310
+ await fs6.writeJson(pkgPath, pkg, { spaces: 2 });
1311
+ mainSpinner.succeed("\u5185\u6838\u540C\u6B65\u5B8C\u6210 (\u4F9D\u8D56\u5DF2\u4F18\u5316)");
1312
+ } else {
1313
+ mainSpinner.succeed("\u5185\u6838\u540C\u6B65\u5B8C\u6210");
1314
+ }
1315
+ if (!options.silent) {
1316
+ printBox(
1317
+ `${pc5.green(pc5.bold("\u2728 \u5185\u6838\u540C\u6B65\u6210\u529F!"))}
1318
+
1319
+ ${pc5.white("\u5F53\u524D\u7248\u672C: ")} ${pc5.cyan(version)}
1320
+ ${pc5.white("\u6C99\u7BB1\u8DEF\u5F84: ")} ${pc5.gray(Sandbox.getVersionPath(version))}
1321
+
1322
+ ${pc5.white("\u63D0\u793A: ")} \u9879\u76EE\u73B0\u5728\u901A\u8FC7\u865A\u62DF\u522B\u540D\u5F15\u7528\u6838\u5FC3\u5305\uFF0C\u65E0\u9700\u663E\u5F0F\u5B89\u88C5\u4F9D\u8D56\u3002`,
1323
+ "Sync Success"
1324
+ );
1325
+ }
1326
+ }
1327
+ var init_sync = __esm({
1328
+ "src/commands/sync.ts"() {
1329
+ "use strict";
1330
+ init_esm_shims();
1331
+ init_utils();
1332
+ init_sandbox();
1333
+ init_corekit();
1334
+ }
1335
+ });
1336
+
1337
+ // src/commands/init.ts
1338
+ var init_exports = {};
1339
+ __export(init_exports, {
1340
+ init: () => init
1341
+ });
1342
+ import fs7 from "fs-extra";
1343
+ import path8 from "path";
1344
+ import pc6 from "picocolors";
1345
+ import Handlebars2 from "handlebars";
1346
+ import prompts2 from "prompts";
1347
+ async function init(options) {
1348
+ let { name, template, pluginType = "business", theme = "standard", projectType, includeApp, includePlugin } = options;
1349
+ const response = await prompts2([
1350
+ // ... (prompts remain the same)
1351
+ {
1352
+ type: name ? null : "text",
1353
+ name: "projectName",
1354
+ message: "\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0:",
1355
+ initial: "my-chatbi-workspace"
1356
+ },
1357
+ {
1358
+ type: projectType ? null : "select",
1359
+ name: "projectType",
1360
+ message: "\u8BF7\u9009\u62E9\u9879\u76EE\u7C7B\u578B:",
1361
+ choices: [
1362
+ { title: "Monorepo Workspace (\u5B8C\u6574\u5DE5\u4F5C\u7A7A\u95F4)", value: "monorepo", description: "\u5305\u542B Apps \u548C Plugins \u7684\u591A\u5305\u7BA1\u7406\u7ED3\u6784" },
1363
+ { title: "Host App (\u72EC\u7ACB\u5BBF\u4E3B\u5E94\u7528)", value: "app", description: "\u72EC\u7ACB\u7684 ChatBI \u5E94\u7528\u6846\u67B6" },
1364
+ { title: "Plugin (\u72EC\u7ACB\u63D2\u4EF6)", value: "plugin", description: "\u72EC\u7ACB\u7684\u4E1A\u52A1\u6216\u7CFB\u7EDF\u63D2\u4EF6" }
1365
+ ],
1366
+ initial: 0
1367
+ },
1368
+ // Monorepo specific questions
1369
+ {
1370
+ type: (prev) => (projectType === "monorepo" || prev === "monorepo") && includeApp === void 0 ? "confirm" : null,
1371
+ name: "includeApp",
1372
+ message: "\u662F\u5426\u521D\u59CB\u5316\u9ED8\u8BA4 Host App?",
1373
+ initial: true
1374
+ },
1375
+ {
1376
+ type: (prev) => (projectType === "monorepo" || prev === "monorepo") && includePlugin === void 0 ? "confirm" : null,
1377
+ name: "includePlugin",
1378
+ message: "\u662F\u5426\u521D\u59CB\u5316\u793A\u4F8B Plugin?",
1379
+ initial: true
1380
+ },
1381
+ // Plugin specific questions
1382
+ {
1383
+ type: (prev, values) => (projectType === "plugin" || values.projectType === "plugin" || (includePlugin || values.includePlugin)) && !pluginType ? "select" : null,
1384
+ name: "pluginType",
1385
+ message: "\u8BF7\u9009\u62E9\u63D2\u4EF6\u7C7B\u578B:",
1386
+ choices: [
1387
+ { title: "Business (\u4E1A\u52A1\u63D2\u4EF6)", value: "business", description: "\u4FA7\u91CD\u4E8E\u4E1A\u52A1\u903B\u8F91\u548C UI \u5C55\u793A" },
1388
+ { title: "System (\u7CFB\u7EDF\u63D2\u4EF6)", value: "system", description: "\u4FA7\u91CD\u4E8E\u7CFB\u7EDF\u80FD\u529B\u548C\u5E95\u5C42\u6269\u5C55" }
1389
+ ],
1390
+ initial: 0
1391
+ },
1392
+ // Theme selection (for App)
1393
+ {
1394
+ type: (prev, values) => (projectType === "app" || values.projectType === "app" || (includeApp || values.includeApp)) && !theme ? "select" : null,
1395
+ name: "theme",
1396
+ message: "\u8BF7\u9009\u62E9\u5E94\u7528\u9ED8\u8BA4\u4E3B\u9898:",
1397
+ choices: [
1398
+ { title: "Standard (\u7ECF\u5178\u84DD)", value: "standard" },
1399
+ { title: "Nebula (\u661F\u4E91\u7D2B)", value: "nebula" },
1400
+ { title: "Glass (\u6BDB\u73BB\u7483)", value: "glass" }
1401
+ ],
1402
+ initial: 0
1403
+ }
1404
+ ], {
1405
+ onCancel: () => {
1406
+ logger.warn("\u5DF2\u53D6\u6D88\u521D\u59CB\u5316");
1407
+ process.exit(0);
1408
+ }
1409
+ });
1410
+ name = name || response.projectName;
1411
+ projectType = projectType || response.projectType || "monorepo";
1412
+ pluginType = pluginType || response.pluginType || pluginType;
1413
+ theme = theme || response.theme || theme;
1414
+ const finalIncludeApp = includeApp !== void 0 ? includeApp : response.includeApp !== void 0 ? response.includeApp : true;
1415
+ const finalIncludePlugin = includePlugin !== void 0 ? includePlugin : response.includePlugin !== void 0 ? response.includePlugin : true;
1416
+ const isAppIncluded = finalIncludeApp;
1417
+ const isPluginIncluded = finalIncludePlugin;
1418
+ const rootDir = process.cwd();
1419
+ const targetDir = path8.resolve(rootDir, name);
1420
+ if (fs7.existsSync(targetDir)) {
1421
+ logger.error(`\u76EE\u5F55 ${name} \u5DF2\u5B58\u5728\u3002`);
1422
+ return;
1423
+ }
1424
+ logger.info(`\u6B63\u5728\u521D\u59CB\u5316\u9879\u76EE: ${pc6.bold(name)}...`);
1425
+ logger.info(pc6.gray(`\u7C7B\u578B: ${projectType} | \u4E3B\u9898: ${theme || "N/A"}`));
1426
+ console.log("");
1427
+ try {
1428
+ const myCliRoot = await getCliRoot();
1429
+ const cliPkg = await fs7.readJson(path8.join(myCliRoot, "package.json"));
1430
+ const cliVersion = cliPkg.version;
1431
+ let kernelVersion = cliVersion;
1432
+ const kernelVersionFile = path8.join(myCliRoot, ".chatbi-version");
1433
+ if (fs7.existsSync(kernelVersionFile)) {
1434
+ kernelVersion = (await fs7.readFile(kernelVersionFile, "utf-8")).trim();
1435
+ }
1436
+ const renderTemplate = async (templateName, destDir, extraData = {}) => {
1437
+ const srcDir = path8.join(myCliRoot, "templates", templateName);
1438
+ if (!fs7.existsSync(srcDir)) {
1439
+ throw new Error(`\u627E\u4E0D\u5230\u6A21\u677F: ${templateName}\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84 ${srcDir} \u662F\u5426\u6B63\u786E\u3002`);
1440
+ }
1441
+ await fs7.ensureDir(destDir);
1442
+ const templateData = {
1443
+ name: path8.basename(destDir),
1444
+ projectName: name,
1445
+ // Original project name from CLI argument
1446
+ projectTitle: name.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" "),
1447
+ projectVersion: "0.1.0",
1448
+ version: kernelVersion,
1449
+ // 使用内核版本作为依赖版本
1450
+ cliVersion,
1451
+ // CLI 自身版本
1452
+ pluginType,
1453
+ theme,
1454
+ isNebula: theme === "nebula",
1455
+ isGlass: theme === "glass",
1456
+ isBusiness: pluginType === "business",
1457
+ isApp: projectType === "app" || isAppIncluded,
1458
+ // Zero Dependency Mode: No explicit core path needed in package.json
1459
+ // tsconfig extends the virtual paths config
1460
+ tsconfigPath: projectType === "monorepo" ? "../../.chatbi/tsconfig.json" : "./.chatbi/tsconfig.json",
1461
+ ...extraData
1462
+ };
1463
+ const processFiles = async (currentSrc, currentDest) => {
1464
+ const files = await fs7.readdir(currentSrc);
1465
+ for (const file of files) {
1466
+ if (file === ".DS_Store") continue;
1467
+ const srcPath = path8.join(currentSrc, file);
1468
+ const stats = await fs7.stat(srcPath);
1469
+ if (stats.isDirectory()) {
1470
+ const destPath = path8.join(currentDest, file);
1471
+ await fs7.ensureDir(destPath);
1472
+ await processFiles(srcPath, destPath);
1473
+ } else if (file.endsWith(".hbs")) {
1474
+ const content = await fs7.readFile(srcPath, "utf-8");
1475
+ let result = content;
1476
+ const hasHandlebarsVars = content.includes("{{");
1477
+ if (hasHandlebarsVars) {
1478
+ try {
1479
+ const safeContent = content.replace(/\{\{(?!\s*([#/]?(?:if|else|each|with|unless|name|version|projectName|projectTitle|projectVersion|cliVersion|tsconfigPath|theme|isNebula|isGlass|isBusiness|isApp|isShell|pluginName|pluginPackageName|pluginVersion|pluginDisplayName|pluginDescription|pluginClassName|pluginPath|pluginFolderName|pluginType|pluginId|className))\b)/g, "\\{{");
1480
+ const templateFn = Handlebars2.compile(safeContent);
1481
+ result = templateFn(templateData);
1482
+ } catch (e) {
1483
+ result = content;
1484
+ for (const [key, val] of Object.entries(templateData)) {
1485
+ const regex = new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, "g");
1486
+ result = result.replace(regex, String(val));
1487
+ }
1488
+ }
1489
+ }
1490
+ const destPath = path8.join(currentDest, file.replace(/\.hbs$/, ""));
1491
+ await fs7.outputFile(destPath, result);
1492
+ } else {
1493
+ const destPath = path8.join(currentDest, file);
1494
+ await fs7.copy(srcPath, destPath);
1495
+ }
1496
+ }
1497
+ };
1498
+ await processFiles(srcDir, destDir);
1499
+ };
1500
+ const spinner = createSpinner("\u6B63\u5728\u751F\u6210\u9879\u76EE\u7ED3\u6784...").start();
1501
+ if (projectType === "monorepo") {
1502
+ spinner.text = "\u6B63\u5728\u751F\u6210 Monorepo \u9AA8\u67B6...";
1503
+ await renderTemplate("monorepo", targetDir, { name });
1504
+ if (isAppIncluded) {
1505
+ spinner.text = "\u6B63\u5728\u751F\u6210 Host App...";
1506
+ const appDir = path8.join(targetDir, "apps", "main");
1507
+ await renderTemplate("app", appDir, { name: "@chatbi-v/main" });
1508
+ }
1509
+ if (isPluginIncluded) {
1510
+ spinner.text = "\u6B63\u5728\u751F\u6210 Demo Plugin...";
1511
+ const pluginDir = path8.join(targetDir, "plugins", "plugin-demo");
1512
+ await renderTemplate("plugin", pluginDir, {
1513
+ name: "@chatbi-v/plugin-demo",
1514
+ pluginId: "demo",
1515
+ pluginName: "demo",
1516
+ pluginPackageName: "@chatbi-v/plugin-demo",
1517
+ pluginVersion: "0.1.0",
1518
+ pluginDisplayName: "\u793A\u4F8B\u63D2\u4EF6",
1519
+ pluginDescription: "\u8FD9\u662F\u4E00\u4E2A\u521D\u59CB\u5316\u7684\u793A\u4F8B\u63D2\u4EF6",
1520
+ pluginClassName: "DemoPlugin",
1521
+ pluginPath: "plugin-demo",
1522
+ pluginFolderName: "plugin-demo",
1523
+ className: "DemoPlugin"
1524
+ });
1525
+ }
1526
+ } else if (projectType === "app") {
1527
+ spinner.text = "\u6B63\u5728\u751F\u6210\u72EC\u7ACB\u5E94\u7528...";
1528
+ await renderTemplate("app", targetDir, { name });
1529
+ } else if (projectType === "plugin") {
1530
+ spinner.text = "\u6B63\u5728\u751F\u6210\u72EC\u7ACB\u63D2\u4EF6...";
1531
+ await renderTemplate("plugin", targetDir, {
1532
+ name: `@chatbi-v/plugin-${name}`,
1533
+ pluginId: name,
1534
+ pluginName: name,
1535
+ pluginPackageName: `@chatbi-v/plugin-${name}`,
1536
+ pluginVersion: "0.1.0",
1537
+ pluginDisplayName: name,
1538
+ pluginDescription: "A ChatBI-V Plugin",
1539
+ pluginClassName: name.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""),
1540
+ pluginPath: name,
1541
+ pluginFolderName: name,
1542
+ className: name.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")
1543
+ });
1544
+ }
1545
+ spinner.succeed("\u9879\u76EE\u7ED3\u6784\u751F\u6210\u5B8C\u6210");
1546
+ const syncSpinner = createSpinner("\u6B63\u5728\u540C\u6B65\u5185\u6838\u4F9D\u8D56...").start();
1547
+ await sync({ cwd: targetDir, silent: true });
1548
+ syncSpinner.succeed("\u5185\u6838\u4F9D\u8D56\u540C\u6B65\u5B8C\u6210");
1549
+ const configSpinner = createSpinner("\u6B63\u5728\u751F\u6210\u9879\u76EE\u914D\u7F6E...").start();
1550
+ const cliConfig = {
1551
+ coreVersion: kernelVersion
1552
+ };
1553
+ await fs7.writeJson(path8.join(targetDir, "chatbi.config.json"), cliConfig, { spaces: 2 });
1554
+ configSpinner.succeed("\u9879\u76EE\u914D\u7F6E\u751F\u6210\u5B8C\u6210");
1555
+ printBox(
1556
+ `${pc6.green(pc6.bold("\u2728 \u9879\u76EE\u5DF2\u6210\u529F\u521B\u5EFA!"))}
1557
+
1558
+ ${pc6.white("\u63A5\u4E0B\u6765\u4F60\u53EF\u4EE5:")}
1559
+ ${pc6.cyan(` cd ${name}`)}
1560
+ ${pc6.cyan(" pnpm install")}
1561
+ ${pc6.cyan(" pnpm dev")}`,
1562
+ "Success"
1563
+ );
1564
+ } catch (error) {
1565
+ logger.error("\u521D\u59CB\u5316\u5931\u8D25", error);
1566
+ throw error;
1567
+ }
1568
+ }
1569
+ var init_init = __esm({
1570
+ "src/commands/init.ts"() {
1571
+ "use strict";
1572
+ init_esm_shims();
1573
+ init_utils();
1574
+ init_sync();
1575
+ }
1576
+ });
1577
+
1578
+ // src/commands/fetch.ts
1579
+ var fetch_exports = {};
1580
+ __export(fetch_exports, {
1581
+ fetch: () => fetch
1582
+ });
1583
+ import path13 from "path";
1584
+ import pc12 from "picocolors";
1585
+ import { execa as execa4 } from "execa";
1586
+ async function fetch(version, options = {}) {
1587
+ const fetchSpinner = createSpinner(`\u6B63\u5728\u83B7\u53D6\u5185\u6838\u7248\u672C ${pc12.cyan(version)}...`).start();
1588
+ const versionPath = await Sandbox.prepare(version, true);
1589
+ fetchSpinner.succeed(`\u5185\u6838\u7248\u672C ${pc12.cyan(version)} \u83B7\u53D6\u6210\u529F`);
1590
+ if (options.pack) {
1591
+ const packSpinner = createSpinner("\u6B63\u5728\u6253\u5305\u79BB\u7EBF\u8D44\u6E90...").start();
1592
+ const tgzName = `chatbi-core-${version}.tgz`;
1593
+ const tgzPath = path13.resolve(process.cwd(), tgzName);
1594
+ await execa4("tar", [
1595
+ "-czf",
1596
+ tgzPath,
1597
+ "-C",
1598
+ path13.dirname(versionPath),
1599
+ path13.basename(versionPath)
1600
+ ]);
1601
+ packSpinner.succeed("\u79BB\u7EBF\u8D44\u6E90\u6253\u5305\u5B8C\u6210");
1602
+ printBox(
1603
+ `${pc12.green(pc12.bold("\u2728 \u79BB\u7EBF\u5305\u5DF2\u751F\u6210!"))}
1604
+
1605
+ ${pc12.white("\u6587\u4EF6\u8DEF\u5F84: ")} ${pc12.cyan(tgzPath)}
1606
+ ${pc12.white("\u5B89\u88C5\u547D\u4EE4: ")} ${pc12.gray(`chatbi install ${tgzName}`)}`,
1607
+ "Pack Success"
1608
+ );
1609
+ } else {
1610
+ logger.success(`\u5185\u6838\u7248\u672C ${pc12.cyan(version)} \u5DF2\u51C6\u5907\u5C31\u7EEA\u3002`);
1611
+ }
1612
+ }
1613
+ var init_fetch = __esm({
1614
+ "src/commands/fetch.ts"() {
1615
+ "use strict";
1616
+ init_esm_shims();
1617
+ init_sandbox();
1618
+ init_utils();
1619
+ }
1620
+ });
1621
+
1622
+ // src/commands/bench.ts
1623
+ var bench_exports = {};
1624
+ __export(bench_exports, {
1625
+ bench: () => bench
1626
+ });
1627
+ import pc14 from "picocolors";
1628
+ import fs13 from "fs-extra";
1629
+ import path15 from "path";
1630
+ import os2 from "os";
1631
+ async function bench() {
1632
+ logger.info("\u6B63\u5728\u542F\u52A8 CLI \u6027\u80FD\u57FA\u51C6\u6D4B\u8BD5...");
1633
+ const results = [];
1634
+ const tmpDir = path15.join(os2.tmpdir(), `chatbi-bench-${Date.now()}`);
1635
+ await fs13.ensureDir(tmpDir);
1636
+ try {
1637
+ const initSpinner = createSpinner("\u6B63\u5728\u6D4B\u8BD5: \u521D\u59CB\u5316\u63D2\u4EF6\u9879\u76EE (init)...").start();
1638
+ const startInit = Date.now();
1639
+ const { init: init2 } = await Promise.resolve().then(() => (init_init(), init_exports));
1640
+ const testProjDir = path15.join(tmpDir, "bench-proj");
1641
+ await init2({ name: "bench-proj", projectType: "plugin", cwd: tmpDir });
1642
+ const endInit = Date.now();
1643
+ const initTime = (endInit - startInit) / 1e3;
1644
+ initSpinner.succeed(`\u521D\u59CB\u5316\u5B8C\u6210: ${pc14.cyan(initTime.toFixed(2) + "s")}`);
1645
+ results.push({
1646
+ scene: "\u521D\u59CB\u5316\u63D2\u4EF6\u9879\u76EE (init)",
1647
+ target: "\u2264 5.0 s",
1648
+ actual: `${initTime.toFixed(2)} s`
1649
+ });
1650
+ const syncSpinner = createSpinner("\u6B63\u5728\u6D4B\u8BD5: \u6C99\u7BB1\u73AF\u5883\u540C\u6B65 (sync)...").start();
1651
+ const startSync = Date.now();
1652
+ const { sync: sync2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
1653
+ await sync2({ cwd: testProjDir });
1654
+ const endSync = Date.now();
1655
+ const syncTime = (endSync - startSync) / 1e3;
1656
+ syncSpinner.succeed(`\u540C\u6B65\u5B8C\u6210: ${pc14.cyan(syncTime.toFixed(2) + "s")}`);
1657
+ results.push({
1658
+ scene: "\u6C99\u7BB1\u73AF\u5883\u540C\u6B65 (sync)",
1659
+ target: "\u2264 2.0 s",
1660
+ actual: `${syncTime.toFixed(2)} s`
1661
+ });
1662
+ const buildSpinner = createSpinner("\u6B63\u5728\u6D4B\u8BD5: \u63D2\u4EF6\u9879\u76EE\u6784\u5EFA (build)...").start();
1663
+ const startBuild = Date.now();
1664
+ const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
1665
+ const originalCwd = process.cwd();
1666
+ process.chdir(testProjDir);
1667
+ await build2({ watch: false });
1668
+ process.chdir(originalCwd);
1669
+ const endBuild = Date.now();
1670
+ const buildTime = (endBuild - startBuild) / 1e3;
1671
+ buildSpinner.succeed(`\u6784\u5EFA\u5B8C\u6210: ${pc14.cyan(buildTime.toFixed(2) + "s")}`);
1672
+ results.push({
1673
+ scene: "\u63D2\u4EF6\u9879\u76EE\u6784\u5EFA (build)",
1674
+ target: "\u2264 10.0 s",
1675
+ actual: `${buildTime.toFixed(2)} s`
1676
+ });
1677
+ printBox(
1678
+ `${pc14.green(pc14.bold("\u2728 \u57FA\u51C6\u6D4B\u8BD5\u5B8C\u6210!"))}
1679
+
1680
+ ` + results.map((r) => `${pc14.white(r.scene.padEnd(20))}: ${pc14.cyan(r.actual)} (\u76EE\u6807 ${r.target})`).join("\n"),
1681
+ "Benchmark Results"
1682
+ );
1683
+ } finally {
1684
+ await fs13.remove(tmpDir);
1685
+ }
1686
+ }
1687
+ var init_bench = __esm({
1688
+ "src/commands/bench.ts"() {
1689
+ "use strict";
1690
+ init_esm_shims();
1691
+ init_utils();
1692
+ }
1693
+ });
1694
+
1695
+ // src/index.ts
1696
+ init_esm_shims();
1697
+ init_build();
1698
+ import cac from "cac";
1699
+ import pc15 from "picocolors";
1700
+ import figlet from "figlet";
1701
+ import gradient from "gradient-string";
1702
+ import boxen2 from "boxen";
1703
+
1704
+ // src/commands/dev.ts
1705
+ init_esm_shims();
1706
+ init_corekit();
1707
+ async function dev(options = {}) {
1708
+ const cwd = process.cwd();
1709
+ await CoreKit.startDev(cwd, options);
1710
+ }
1711
+
1712
+ // src/index.ts
1713
+ init_init();
1714
+
1715
+ // src/commands/add.ts
1716
+ init_esm_shims();
1717
+ init_utils();
1718
+ init_config();
1719
+ import fs8 from "fs-extra";
1720
+ import path9 from "path";
1721
+ import pc7 from "picocolors";
1722
+ import prompts3 from "prompts";
1723
+ import Handlebars3 from "handlebars";
1724
+ async function add(options) {
1725
+ let { name, type, displayName, description } = options;
1726
+ const cwd = process.cwd();
1727
+ const pkgPath = path9.join(cwd, "package.json");
1728
+ if (!fs8.existsSync(pkgPath)) {
1729
+ logger.error("\u672A\u627E\u5230 package.json\u3002\u8BF7\u5728 ChatBI-V \u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u8FD0\u884C\u6B64\u547D\u4EE4\u3002");
1730
+ return;
1731
+ }
1732
+ const pkg = await fs8.readJson(pkgPath);
1733
+ const isMonorepo = pkg.workspaces && (pkg.workspaces.includes("plugins/*") || pkg.workspaces.packages?.includes("plugins/*"));
1734
+ if (!isMonorepo) {
1735
+ logger.error("\u5F53\u524D\u4E0D\u662F Monorepo \u9879\u76EE\uFF0C\u65E0\u6CD5\u6DFB\u52A0\u63D2\u4EF6 (\u8BF7\u5728\u5305\u542B plugins/ \u5DE5\u4F5C\u7A7A\u95F4\u7684\u9879\u76EE\u4E2D\u8FD0\u884C)");
1736
+ process.exit(1);
1737
+ }
1738
+ const response = await prompts3([
1739
+ {
1740
+ type: name ? null : "text",
1741
+ name: "pluginName",
1742
+ message: "\u8BF7\u8F93\u5165\u63D2\u4EF6\u540D\u79F0 (ID, \u5EFA\u8BAE\u5C0F\u5199\u548C\u4E2D\u5212\u7EBF):",
1743
+ initial: "my-custom-plugin",
1744
+ validate: (value) => /^[a-z0-9-]+$/.test(value) || "\u540D\u79F0\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E2D\u5212\u7EBF"
1745
+ },
1746
+ {
1747
+ type: displayName ? null : "text",
1748
+ name: "pluginDisplayName",
1749
+ message: "\u8BF7\u8F93\u5165\u63D2\u4EF6\u663E\u793A\u540D\u79F0 (\u4E2D\u6587):",
1750
+ initial: (prev) => prev || name
1751
+ },
1752
+ {
1753
+ type: description ? null : "text",
1754
+ name: "pluginDescription",
1755
+ message: "\u8BF7\u8F93\u5165\u63D2\u4EF6\u63CF\u8FF0:",
1756
+ initial: "\u4E00\u4E2A\u7B80\u5355\u7684 ChatBI-V \u63D2\u4EF6"
1757
+ },
1758
+ {
1759
+ type: type ? null : "select",
1760
+ name: "pluginType",
1761
+ message: "\u8BF7\u9009\u62E9\u63D2\u4EF6\u7C7B\u578B:",
1762
+ choices: [
1763
+ { title: "Business (\u4E1A\u52A1\u63D2\u4EF6)", value: "business", description: "\u5305\u542B UI \u754C\u9762\u548C\u4E1A\u52A1\u903B\u8F91" },
1764
+ { title: "System (\u7CFB\u7EDF\u63D2\u4EF6)", value: "system", description: "\u4FA7\u91CD\u4E8E\u5E95\u5C42\u80FD\u529B\u548C\u7CFB\u7EDF\u6269\u5C55" }
1765
+ ],
1766
+ initial: 0
1767
+ }
1768
+ ], {
1769
+ onCancel: () => {
1770
+ logger.warn("\u5DF2\u53D6\u6D88\u6DFB\u52A0\u63D2\u4EF6");
1771
+ process.exit(0);
1772
+ }
1773
+ });
1774
+ name = name || response.pluginName;
1775
+ type = type || response.pluginType;
1776
+ displayName = displayName || response.pluginDisplayName || name;
1777
+ description = description || response.pluginDescription || "";
1778
+ let cleanName = name;
1779
+ if (cleanName.endsWith("-plugin")) {
1780
+ cleanName = cleanName.replace(/-plugin$/, "");
1781
+ }
1782
+ const folderName = cleanName.startsWith("plugin-") ? cleanName : `plugin-${cleanName}`;
1783
+ const pluginDir = path9.resolve(cwd, "plugins", folderName);
1784
+ if (fs8.existsSync(pluginDir)) {
1785
+ logger.error(`\u63D2\u4EF6\u76EE\u5F55 ${folderName} \u5DF2\u5B58\u5728\u3002`);
1786
+ return;
1787
+ }
1788
+ const spinner = createSpinner(`\u6B63\u5728\u6DFB\u52A0\u65B0\u63D2\u4EF6: ${pc7.bold(name)}...`).start();
1789
+ const myCliRoot = await getCliRoot();
1790
+ const templateDir = path9.join(myCliRoot, "templates/plugin");
1791
+ if (!fs8.existsSync(templateDir)) {
1792
+ spinner.fail("\u627E\u4E0D\u5230\u63D2\u4EF6\u6A21\u677F");
1793
+ throw new Error(`\u627E\u4E0D\u5230\u63D2\u4EF6\u6A21\u677F: ${templateDir}`);
1794
+ }
1795
+ const targetDir = pluginDir;
1796
+ spinner.text = "\u6B63\u5728\u52A0\u8F7D\u914D\u7F6E...";
1797
+ const config = await ConfigManager.loadConfig(cwd);
1798
+ const coreSource = config.coreSource || "local";
1799
+ let corePath = "file:../../.chatbi/core";
1800
+ if (coreSource === "npm") {
1801
+ if (!config.coreVersion) {
1802
+ const cliPkg = await fs8.readJson(path9.join(myCliRoot, "package.json"));
1803
+ corePath = cliPkg.version;
1804
+ } else {
1805
+ corePath = config.coreVersion;
1806
+ }
1807
+ }
1808
+ const data = {
1809
+ // 兼容旧模板
1810
+ name: `@chatbi-v/${folderName}`,
1811
+ pluginId: cleanName,
1812
+ pluginType: type,
1813
+ className: cleanName.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""),
1814
+ isBusiness: type === "business",
1815
+ corePath,
1816
+ // 新模板变量
1817
+ pluginName: cleanName,
1818
+ pluginPackageName: `@chatbi-v/${folderName}`,
1819
+ pluginVersion: "0.1.0",
1820
+ pluginDisplayName: displayName,
1821
+ pluginDescription: description,
1822
+ pluginClassName: cleanName.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""),
1823
+ pluginPath: folderName,
1824
+ pluginFolderName: folderName,
1825
+ // Fix: 注入 tsconfigPath,确保 tsconfig.json 能正确 extend
1826
+ tsconfigPath: "../../.chatbi/tsconfig.json"
1827
+ };
1828
+ const renderFile = async (src, dest) => {
1829
+ const content = await fs8.readFile(src, "utf-8");
1830
+ let result = content;
1831
+ const hasHandlebarsVars = content.includes("{{");
1832
+ if (hasHandlebarsVars) {
1833
+ try {
1834
+ const safeContent = content.replace(/\{\{(?!\s*([#/]?(?:if|else|each|with|unless|name|version|projectName|projectTitle|projectVersion|cliVersion|tsconfigPath|theme|isNebula|isGlass|isBusiness|isApp|isShell|pluginName|pluginPackageName|pluginVersion|pluginDisplayName|pluginDescription|pluginClassName|pluginPath|pluginFolderName|pluginType|pluginId|className))\b)/g, "\\{{");
1835
+ const templateFn = Handlebars3.compile(safeContent);
1836
+ result = templateFn(data);
1837
+ } catch (e) {
1838
+ result = content;
1839
+ for (const [key, val] of Object.entries(data)) {
1840
+ const regex = new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, "g");
1841
+ result = result.replace(regex, String(val));
1842
+ }
1843
+ }
1844
+ }
1845
+ await fs8.outputFile(dest.replace(".hbs", ""), result);
1846
+ };
1847
+ const processTemplates = async (currentSrc, currentDest) => {
1848
+ const files = await fs8.readdir(currentSrc);
1849
+ for (const file of files) {
1850
+ const srcPath = path9.join(currentSrc, file);
1851
+ const destPath = path9.join(currentDest, file);
1852
+ const stats = await fs8.stat(srcPath);
1853
+ if (stats.isDirectory()) {
1854
+ await fs8.ensureDir(destPath);
1855
+ await processTemplates(srcPath, destPath);
1856
+ } else if (file.endsWith(".hbs")) {
1857
+ await renderFile(srcPath, destPath);
1858
+ } else {
1859
+ await fs8.copy(srcPath, destPath);
1860
+ }
1861
+ }
1862
+ };
1863
+ spinner.text = "\u6B63\u5728\u751F\u6210\u63D2\u4EF6\u6587\u4EF6...";
1864
+ await processTemplates(templateDir, targetDir);
1865
+ spinner.succeed(`\u63D2\u4EF6 ${pc7.bold(name)} \u6DFB\u52A0\u6210\u529F\uFF01`);
1866
+ printBox(
1867
+ `${pc7.green(pc7.bold("\u2728 \u63D2\u4EF6\u521B\u5EFA\u6210\u529F!"))}
1868
+
1869
+ ${pc7.white("\u9879\u76EE\u8DEF\u5F84: ")} ${pc7.cyan(`plugins/${folderName}`)}
1870
+ ${pc7.white("\u63D2\u4EF6 ID: ")} ${pc7.cyan(cleanName)}
1871
+ ${pc7.white("\u63D2\u4EF6\u7C7B\u578B: ")} ${pc7.cyan(type)}
1872
+
1873
+ ${pc7.white("\u63A5\u4E0B\u6765\u4F60\u53EF\u4EE5:")}
1874
+ ${pc7.cyan(" pnpm dev")} \u542F\u52A8\u5F00\u53D1\u73AF\u5883\u67E5\u770B\u6548\u679C`,
1875
+ "Plugin Created"
1876
+ );
1877
+ }
1878
+
1879
+ // src/commands/gl.ts
1880
+ init_esm_shims();
1881
+ init_utils();
1882
+ import fs9 from "fs-extra";
1883
+ import path10 from "path";
1884
+ import pc8 from "picocolors";
1885
+ import prompts4 from "prompts";
1886
+ import { execa as execa3 } from "execa";
1887
+ async function gl(options) {
1888
+ const { type: initialType, prompt: initialPrompt } = options;
1889
+ const cwd = process.cwd();
1890
+ const pkgPath = path10.join(cwd, "package.json");
1891
+ if (!fs9.existsSync(pkgPath)) {
1892
+ logger.error("\u672A\u627E\u5230 package.json\u3002\u8BF7\u5728 ChatBI-V \u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u8FD0\u884C\u6B64\u547D\u4EE4\u3002");
1893
+ return;
1894
+ }
1895
+ const response = await prompts4([
1896
+ {
1897
+ type: initialType ? null : "select",
1898
+ name: "genType",
1899
+ message: "\u8BF7\u9009\u62E9 AI \u811A\u624B\u67B6\u6307\u4EE4:",
1900
+ choices: [
1901
+ { title: "\u{1F916} smart", value: "smart", description: "\u667A\u80FD\u51B3\u7B56 (\u6839\u636E\u9700\u6C42\u81EA\u52A8\u9009\u62E9\u5DE5\u5177)" },
1902
+ { title: "\u{1F50C} plugin", value: "plugin", description: "\u751F\u6210\u65B0\u63D2\u4EF6" },
1903
+ { title: "\u{1F9E9} component", value: "component", description: "\u751F\u6210\u4E1A\u52A1\u7EC4\u4EF6" },
1904
+ { title: "\u{1F4E1} api", value: "api", description: "\u751F\u6210 API \u5B9A\u4E49\u4E0E\u8BF7\u6C42\u51FD\u6570" },
1905
+ { title: "\u{1F3AD} mock", value: "mock", description: "\u751F\u6210 Mock \u6D4B\u8BD5\u6570\u636E" },
1906
+ { title: "\u{1F6E0}\uFE0F util", value: "util", description: "\u751F\u6210\u5DE5\u5177\u51FD\u6570" },
1907
+ { title: "\u{1F4C4} doc", value: "doc", description: "\u751F\u6210\u9879\u76EE\u6587\u6863" },
1908
+ { title: "\u2728 chat", value: "chat", description: "\u81EA\u7531\u5BF9\u8BDD" }
1909
+ ],
1910
+ initial: 0
1911
+ },
1912
+ {
1913
+ type: (prev, values) => initialPrompt || values.genType === "chat" ? null : "text",
1914
+ name: "userPrompt",
1915
+ message: "\u8BF7\u8F93\u5165\u8BE6\u7EC6\u9700\u6C42\u63CF\u8FF0:",
1916
+ initial: initialPrompt || ""
1917
+ }
1918
+ ], {
1919
+ onCancel: () => {
1920
+ logger.warn("\u5DF2\u53D6\u6D88 AI \u751F\u6210");
1921
+ process.exit(0);
1922
+ }
1923
+ });
1924
+ const genType = initialType || response.genType;
1925
+ const userPrompt = initialPrompt || response.userPrompt;
1926
+ if (!userPrompt && genType !== "chat") {
1927
+ logger.error("\u9700\u6C42\u63CF\u8FF0\u4E0D\u80FD\u4E3A\u7A7A\u3002");
1928
+ return;
1929
+ }
1930
+ logger.info(`\u6B63\u5728\u547C\u53EB AI \u5F15\u64CE [\u6A21\u5F0F: ${pc8.bold(genType)}]...`);
1931
+ const toolsContext = `
1932
+ [Available Tools & Capabilities]
1933
+ - Tool: plugin -> For creating new feature modules. Requires: name, type (business|system).
1934
+ - Tool: component -> For UI elements. Tech: AntD5, Tailwind.
1935
+ - Tool: api -> For network requests. Structure: src/api/[name].ts, uses shared request util, defines TS interfaces.
1936
+ - Tool: mock -> For dev data. Structure: mock/[name].ts, follows Mock.js or MSW format.
1937
+ - Tool: util -> For pure functions. Structure: src/utils/[name].ts, requires unit tests.
1938
+ - Tool: doc -> For documentation. Format: Markdown, structure: docs/[type]/[name].md.
1939
+
1940
+ [Tool Functions Implementation Details]
1941
+ - API Function: Should include request method, URL, params/data types, and response type. Use '@chatbi-v/core/request'.
1942
+ - Mock Function: Should provide realistic data based on API definition.
1943
+ - Plugin Function: Should follow the Micro-Kernel architecture, registering to 'pluginManager'.
1944
+
1945
+ [Requirement Slots / Missing Info]
1946
+ If the user's request is ambiguous or missing key information, you MUST output: "SLOT_REQUIRED: [Field Name] | [Question to User]".
1947
+ `.trim();
1948
+ const templatesContext = `
1949
+ [Project Templates Structure]
1950
+ - Plugin: class extends Plugin, metadata: { id, name, version, type, routes, extensions }.
1951
+ - API: export const fetchData = (params: T) => request.get<R>('/url', { params }).
1952
+ - Mock: export default { 'GET /api/test': { code: 200, data: {} } }.
1953
+ - UI: React 18, Ant Design 5, Tailwind CSS 3.
1954
+ `.trim();
1955
+ const systemContext = `[Context: ChatBI-V System | Dir: ${cwd} | Tech: React18, AntD5, Tailwind, Micro-Kernel]
1956
+ ${toolsContext}
1957
+ ${templatesContext}
1958
+
1959
+ [Decision Logic]
1960
+ If genType is 'smart', you must first decide which tool is most appropriate.
1961
+ If the requirement is clear, proceed with generation.
1962
+ If not, use the SLOT_REQUIRED format.`.trim();
1963
+ const finalPrompt = userPrompt ? `${systemContext}
1964
+
1965
+ [User Request]: ${userPrompt}` : systemContext;
1966
+ const geminiCmd = genType === "smart" ? "chat" : genType;
1967
+ const spinner = createSpinner("AI \u5F15\u64CE\u6B63\u5728\u601D\u8003\u4E2D... (\u53EF\u80FD\u9700\u8981\u51E0\u5341\u79D2\uFF0C\u8BF7\u8010\u5FC3\u7B49\u5F85)");
1968
+ let currentPrompt = finalPrompt;
1969
+ let retry = true;
1970
+ while (retry) {
1971
+ spinner.start();
1972
+ try {
1973
+ const { stdout } = await execa3("gemini", [geminiCmd, currentPrompt], {
1974
+ stdio: "pipe"
1975
+ });
1976
+ spinner.stop();
1977
+ if (stdout.includes("SLOT_REQUIRED:")) {
1978
+ const slots = [];
1979
+ const lines = stdout.split("\n");
1980
+ for (const line of lines) {
1981
+ if (line.includes("SLOT_REQUIRED:")) {
1982
+ const match = line.match(/SLOT_REQUIRED:\s*([^|]+)\|\s*(.+)/);
1983
+ if (match) {
1984
+ slots.push({
1985
+ type: "text",
1986
+ name: match[1].trim(),
1987
+ message: match[2].trim()
1988
+ });
1989
+ }
1990
+ }
1991
+ }
1992
+ if (slots.length > 0) {
1993
+ logger.info(pc8.yellow("\n\u{1F4DD} AI \u9700\u8981\u66F4\u591A\u4FE1\u606F\u4EE5\u7EE7\u7EED:"));
1994
+ const answers = await prompts4(slots, {
1995
+ onCancel: () => process.exit(0)
1996
+ });
1997
+ const answerContext = Object.entries(answers).map(([k, v]) => `[${k}]: ${v}`).join("\n");
1998
+ currentPrompt += `
1999
+
2000
+ [User Answers]:
2001
+ ${answerContext}
2002
+
2003
+ Please proceed with generation based on these answers.`;
2004
+ logger.info("\u6B63\u5728\u6839\u636E\u60A8\u7684\u53CD\u9988\u91CD\u65B0\u547C\u53EB AI...");
2005
+ continue;
2006
+ }
2007
+ }
2008
+ console.log("\n" + stdout);
2009
+ retry = false;
2010
+ logger.success(`AI \u547D\u4EE4 [gemini ${geminiCmd}] \u6267\u884C\u5B8C\u6BD5!`);
2011
+ } catch (error) {
2012
+ spinner.stop();
2013
+ if (error.code === "ENOENT") {
2014
+ logger.error("\u672A\u5728\u7CFB\u7EDF\u4E2D\u627E\u5230 `gemini-cli` \u547D\u4EE4\u3002");
2015
+ logger.info(pc8.yellow("\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 gemini-cli \u5E76\u5C06\u5176\u6DFB\u52A0\u5230\u7CFB\u7EDF PATH \u4E2D\u3002"));
2016
+ } else {
2017
+ logger.error(`AI \u751F\u6210\u8FC7\u7A0B\u4E2D\u51FA\u9519: ${error.message}`);
2018
+ }
2019
+ throw error;
2020
+ }
2021
+ }
2022
+ }
2023
+
2024
+ // src/index.ts
2025
+ init_sync();
2026
+
2027
+ // src/commands/doctor.ts
2028
+ init_esm_shims();
2029
+ init_utils();
2030
+ init_sandbox();
2031
+ init_corekit();
2032
+ import fs10 from "fs-extra";
2033
+ import path11 from "path";
2034
+ import pc9 from "picocolors";
2035
+ import glob from "fast-glob";
2036
+ async function doctor(options = {}) {
2037
+ logger.info("\u6B63\u5728\u8BCA\u65AD\u9879\u76EE\u5065\u5EB7\u72B6\u51B5...\n");
2038
+ const cwd = process.cwd();
2039
+ let hasIssues = false;
2040
+ const issues = [];
2041
+ logger.info(pc9.bold("Step 1: \u68C0\u67E5\u57FA\u7840\u73AF\u5883..."));
2042
+ const nodeVersion = process.version;
2043
+ if (parseInt(nodeVersion.slice(1).split(".")[0]) < 18) {
2044
+ logger.error(`Node.js \u7248\u672C\u592A\u4F4E: ${nodeVersion} (\u8981\u6C42 >=18)`);
2045
+ hasIssues = true;
2046
+ issues.push(`Node.js \u7248\u672C\u8FC7\u4F4E (${nodeVersion})`);
2047
+ } else {
2048
+ logger.success(`Node.js \u7248\u672C: ${nodeVersion}`);
2049
+ }
2050
+ try {
2051
+ const { execa: execa6 } = await import("execa");
2052
+ const { stdout: pnpmVer } = await execa6("pnpm", ["-v"]);
2053
+ logger.success(`pnpm \u7248\u672C: ${pnpmVer}`);
2054
+ } catch (e) {
2055
+ logger.warn("\u672A\u68C0\u6D4B\u5230 pnpm\uFF0C\u5EFA\u8BAE\u5B89\u88C5\u4EE5\u83B7\u5F97\u6700\u4F73\u4F53\u9A8C");
2056
+ }
2057
+ logger.info(pc9.bold("\nStep 2: \u68C0\u67E5\u5185\u6838\u6C99\u7BB1\u73AF\u5883..."));
2058
+ const version = await CoreKit.resolveVersion(cwd);
2059
+ const versionPath = Sandbox.getVersionPath(version);
2060
+ if (!fs10.existsSync(versionPath)) {
2061
+ logger.error(`\u5185\u6838\u6C99\u7BB1\u7248\u672C ${version} \u5C1A\u672A\u5B89\u88C5`);
2062
+ console.log(pc9.gray(` \u5EFA\u8BAE\u8FD0\u884C 'chatbi sync' \u6216 'chatbi use ${version}' \u8FDB\u884C\u5B89\u88C5\u3002`));
2063
+ hasIssues = true;
2064
+ issues.push(`\u5185\u6838\u6C99\u7BB1\u672A\u5B89\u88C5 (${version})`);
2065
+ } else {
2066
+ logger.success(`\u5185\u6838\u6C99\u7BB1\u5C31\u7EEA (\u7248\u672C: ${version})`);
2067
+ const sandboxNm = path11.join(versionPath, "node_modules");
2068
+ if (!fs10.existsSync(sandboxNm)) {
2069
+ logger.warn("\u6C99\u7BB1\u4F9D\u8D56\u672A\u5B89\u88C5\uFF0C\u5C06\u5BFC\u81F4\u6784\u5EFA\u5931\u8D25");
2070
+ hasIssues = true;
2071
+ issues.push("\u6C99\u7BB1\u4F9D\u8D56\u7F3A\u5931");
2072
+ }
2073
+ const missingDeps = [];
2074
+ for (const dep of Sandbox.CORE_PACKAGES) {
2075
+ if (!fs10.existsSync(path11.join(sandboxNm, dep))) {
2076
+ missingDeps.push(dep);
2077
+ }
2078
+ }
2079
+ if (missingDeps.length > 0) {
2080
+ }
2081
+ }
2082
+ logger.info(pc9.bold("\nStep 3: \u68C0\u67E5\u865A\u62DF\u4F9D\u8D56\u6620\u5C04..."));
2083
+ const chatbiDir = path11.join(cwd, ".chatbi");
2084
+ if (!fs10.existsSync(chatbiDir)) {
2085
+ logger.warn("\u672A\u53D1\u73B0\u865A\u62DF\u4F9D\u8D56\u914D\u7F6E (.chatbi \u76EE\u5F55)");
2086
+ hasIssues = true;
2087
+ issues.push("\u7F3A\u5931 .chatbi \u76EE\u5F55");
2088
+ } else {
2089
+ const pathsJson = path11.join(chatbiDir, "tsconfig.paths.json");
2090
+ const aliasJson = path11.join(chatbiDir, "vite.alias.json");
2091
+ if (!fs10.existsSync(pathsJson) || !fs10.existsSync(aliasJson)) {
2092
+ logger.warn("\u865A\u62DF\u4F9D\u8D56\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B8C\u6574");
2093
+ hasIssues = true;
2094
+ issues.push("\u865A\u62DF\u4F9D\u8D56\u914D\u7F6E\u4E0D\u5B8C\u6574");
2095
+ } else {
2096
+ logger.success("\u865A\u62DF\u4F9D\u8D56\u914D\u7F6E\u5DF2\u751F\u6210");
2097
+ }
2098
+ }
2099
+ const tsConfigPath = path11.join(cwd, "tsconfig.json");
2100
+ if (fs10.existsSync(tsConfigPath)) {
2101
+ try {
2102
+ const tsConfig = await fs10.readJson(tsConfigPath);
2103
+ const extendsPath = tsConfig.extends;
2104
+ const expectedPaths = ["./.chatbi/tsconfig.paths.json", ".chatbi/tsconfig.paths.json"];
2105
+ let hasExtend = false;
2106
+ if (typeof extendsPath === "string") {
2107
+ hasExtend = expectedPaths.includes(extendsPath);
2108
+ } else if (Array.isArray(extendsPath)) {
2109
+ hasExtend = extendsPath.some((p) => expectedPaths.includes(p));
2110
+ }
2111
+ if (!hasExtend) {
2112
+ logger.warn("tsconfig.json \u672A\u7EE7\u627F\u865A\u62DF\u4F9D\u8D56\u914D\u7F6E");
2113
+ hasIssues = true;
2114
+ issues.push("tsconfig.json \u914D\u7F6E\u7F3A\u5931");
2115
+ } else {
2116
+ logger.success("tsconfig.json \u914D\u7F6E\u6B63\u5E38");
2117
+ }
2118
+ } catch (e) {
2119
+ logger.error("\u89E3\u6790 tsconfig.json \u5931\u8D25");
2120
+ }
2121
+ }
2122
+ const viteConfigPath = path11.join(cwd, "vite.config.ts");
2123
+ if (fs10.existsSync(viteConfigPath)) {
2124
+ const content = await fs10.readFile(viteConfigPath, "utf-8");
2125
+ if (!content.includes("vite.alias.json")) {
2126
+ logger.warn("vite.config.ts \u53EF\u80FD\u672A\u52A0\u8F7D\u865A\u62DF\u522B\u540D\u914D\u7F6E");
2127
+ }
2128
+ }
2129
+ logger.info(pc9.bold("\nStep 4: \u626B\u63CF\u4EE3\u7801\u89C4\u5219..."));
2130
+ const rules = [
2131
+ {
2132
+ id: "plugin-lifecycle-init",
2133
+ description: "\u63D2\u4EF6\u751F\u547D\u5468\u671F init() \u5DF2\u53D8\u66F4\u4E3A onLoad()",
2134
+ pattern: /async\s+init\s*\(\s*context\s*:\s*PluginContext\s*\)/g,
2135
+ fix: (content) => content.replace(/async\s+init\s*\(\s*context\s*:\s*PluginContext\s*\)/g, "async onLoad(context: PluginContext)")
2136
+ },
2137
+ {
2138
+ id: "plugin-lifecycle-destroy",
2139
+ description: "\u63D2\u4EF6\u751F\u547D\u5468\u671F destroy() \u5DF2\u53D8\u66F4\u4E3A onUnload()",
2140
+ pattern: /async\s+destroy\s*\(\s*\)/g,
2141
+ fix: (content) => content.replace(/async\s+destroy\s*\(\s*\)/g, "async onUnload()")
2142
+ }
2143
+ ];
2144
+ const files = await glob(["src/**/*.{ts,tsx}"], { cwd, absolute: true });
2145
+ const codeIssues = [];
2146
+ if (files.length > 0) {
2147
+ const scanSpinner = createSpinner(`\u6B63\u5728\u626B\u63CF ${files.length} \u4E2A\u6587\u4EF6...`).start();
2148
+ for (const file of files) {
2149
+ const content = await fs10.readFile(file, "utf-8");
2150
+ for (const rule of rules) {
2151
+ if (rule.pattern.test(content)) {
2152
+ codeIssues.push({
2153
+ file,
2154
+ ruleId: rule.id,
2155
+ description: rule.description,
2156
+ rule
2157
+ });
2158
+ }
2159
+ }
2160
+ }
2161
+ if (codeIssues.length > 0) {
2162
+ scanSpinner.fail(`\u53D1\u73B0 ${codeIssues.length} \u4E2A\u4EE3\u7801\u89C4\u8303\u95EE\u9898`);
2163
+ hasIssues = true;
2164
+ codeIssues.forEach((issue) => {
2165
+ const relativePath = path11.relative(cwd, issue.file);
2166
+ issues.push(`\u4EE3\u7801\u89C4\u8303 [${issue.ruleId}]: ${relativePath}`);
2167
+ });
2168
+ } else {
2169
+ scanSpinner.succeed("\u4EE3\u7801\u89C4\u8303\u68C0\u67E5\u901A\u8FC7");
2170
+ }
2171
+ }
2172
+ if (!hasIssues) {
2173
+ printBox(
2174
+ pc9.green(pc9.bold("\u2728 \u8BCA\u65AD\u5B8C\u6210\uFF1A\u9879\u76EE\u4E00\u5207\u6B63\u5E38\uFF01")),
2175
+ "Doctor Report"
2176
+ );
2177
+ } else {
2178
+ const issueList = issues.map((i) => pc9.red(`\u2022 ${i}`)).join("\n");
2179
+ printBox(
2180
+ `${pc9.yellow(pc9.bold("\u26A0\uFE0F \u8BCA\u65AD\u5B8C\u6210\uFF1A\u53D1\u73B0\u4EE5\u4E0B\u95EE\u9898"))}
2181
+
2182
+ ${issueList}
2183
+
2184
+ ${pc9.cyan("\u5EFA\u8BAE\u6839\u636E\u63D0\u793A\u8FDB\u884C\u4FEE\u590D")}`,
2185
+ "Doctor Report"
2186
+ );
2187
+ if (options.fix) {
2188
+ if (codeIssues.length > 0) {
2189
+ const fixSpinner = createSpinner("\u6B63\u5728\u4FEE\u590D\u4EE3\u7801\u89C4\u8303\u95EE\u9898...").start();
2190
+ for (const issue of codeIssues) {
2191
+ const content = await fs10.readFile(issue.file, "utf-8");
2192
+ const newContent = issue.rule.fix(content);
2193
+ await fs10.writeFile(issue.file, newContent);
2194
+ }
2195
+ fixSpinner.succeed("\u4EE3\u7801\u4FEE\u590D\u5B8C\u6210");
2196
+ }
2197
+ logger.info("\u6B63\u5728\u4FEE\u590D\u73AF\u5883\u914D\u7F6E...");
2198
+ const { sync: sync2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
2199
+ await sync2({ force: true });
2200
+ logger.success("\u81EA\u52A8\u4FEE\u590D\u5B8C\u6210\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C\u8BCA\u65AD\u3002");
2201
+ }
2202
+ }
2203
+ }
2204
+
2205
+ // src/commands/discover.ts
2206
+ init_esm_shims();
2207
+ init_corekit();
2208
+ init_utils();
2209
+ import pc10 from "picocolors";
2210
+ async function discover() {
2211
+ const cwd = process.cwd();
2212
+ const spinner = createSpinner("\u6B63\u5728\u626B\u63CF\u9879\u76EE\u4E2D\u7684\u63D2\u4EF6...").start();
2213
+ const plugins = await CoreKit.discoverPlugins(cwd);
2214
+ if (plugins.length === 0) {
2215
+ spinner.warn("\u672A\u53D1\u73B0\u4EFB\u4F55\u63D2\u4EF6");
2216
+ logger.info(pc10.gray("\u8BF7\u786E\u4FDD\u63D2\u4EF6\u4F4D\u4E8E plugins/ \u76EE\u5F55\u4E0B\uFF0C\u4E14\u5305\u542B package.json\u3002"));
2217
+ } else {
2218
+ spinner.succeed(`\u53D1\u73B0\u4E86 ${pc10.cyan(plugins.length)} \u4E2A\u63D2\u4EF6`);
2219
+ const pluginList = plugins.map((p) => `- ${pc10.bold(p.name)} ${pc10.gray(`(${p.id})`)}
2220
+ ${pc10.gray(p.path)}`).join("\n\n");
2221
+ printBox(
2222
+ `${pc10.green(pc10.bold("\u2728 \u63D2\u4EF6\u626B\u63CF\u7ED3\u679C"))}
2223
+
2224
+ ${pluginList}`,
2225
+ "Plugin Discovery"
2226
+ );
2227
+ }
2228
+ }
2229
+
2230
+ // src/commands/ls.ts
2231
+ init_esm_shims();
2232
+ init_corekit();
2233
+ init_sandbox();
2234
+ init_utils();
2235
+ import pc11 from "picocolors";
2236
+ async function ls() {
2237
+ const versions = await CoreKit.listVersions();
2238
+ const currentVersion = await CoreKit.resolveVersion(process.cwd());
2239
+ const globalCurrentVersion = await CoreKit.resolveVersion();
2240
+ logger.info("\u5DF2\u5B89\u88C5\u7684\u5185\u6838\u6C99\u7BB1\u7248\u672C:");
2241
+ if (versions.length === 0) {
2242
+ logger.warn("\u5C1A\u672A\u5B89\u88C5\u4EFB\u4F55\u7248\u672C\uFF0C\u8BF7\u8FD0\u884C chatbi sync \u8FDB\u884C\u5B89\u88C5\u3002");
2243
+ } else {
2244
+ const list = versions.map((v) => {
2245
+ const isGlobalCurrent = v === globalCurrentVersion;
2246
+ const isProjectCurrent = v === currentVersion;
2247
+ let prefix = " ";
2248
+ if (isProjectCurrent) {
2249
+ prefix = pc11.green(" *");
2250
+ } else if (isGlobalCurrent) {
2251
+ prefix = pc11.blue(" >");
2252
+ }
2253
+ let suffix = "";
2254
+ if (isProjectCurrent && isGlobalCurrent) {
2255
+ suffix = pc11.gray(" (\u5F53\u524D\u9879\u76EE & \u5168\u5C40)");
2256
+ } else if (isProjectCurrent) {
2257
+ suffix = pc11.gray(" (\u5F53\u524D\u9879\u76EE)");
2258
+ } else if (isGlobalCurrent) {
2259
+ suffix = pc11.gray(" (\u5168\u5C40)");
2260
+ }
2261
+ return `${prefix} ${pc11.white(v)}${suffix}`;
2262
+ }).join("\n");
2263
+ printBox(
2264
+ list + pc11.gray("\n\n\u63D0\u793A: * \u5F53\u524D\u9879\u76EE\u4F7F\u7528, > \u5168\u5C40\u9ED8\u8BA4\u4F7F\u7528"),
2265
+ "Kernel Versions"
2266
+ );
2267
+ }
2268
+ await Sandbox.visualizeStatus(process.cwd());
2269
+ }
2270
+
2271
+ // src/commands/use.ts
2272
+ init_esm_shims();
2273
+ init_sandbox();
2274
+ init_corekit();
2275
+ init_sync();
2276
+ init_utils();
2277
+ import fs11 from "fs-extra";
2278
+ import path12 from "path";
2279
+ async function use(version, options = {}) {
2280
+ const versions = await CoreKit.listVersions();
2281
+ if (!versions.includes(version)) {
2282
+ logger.warn(`\u7248\u672C ${version} \u5C1A\u672A\u5B89\u88C5\uFF0C\u6B63\u5728\u5C1D\u8BD5\u5B89\u88C5...`);
2283
+ await Sandbox.prepare(version);
2284
+ }
2285
+ if (options.global) {
2286
+ await Sandbox.useVersion(version);
2287
+ logger.success(`\u5DF2\u5207\u6362\u5168\u5C40\u5185\u6838\u7248\u672C\u81F3: ${version}`);
2288
+ } else {
2289
+ const cwd = process.cwd();
2290
+ const versionFilePath = path12.join(cwd, ".chatbi-version");
2291
+ await fs11.writeFile(versionFilePath, version, "utf-8");
2292
+ logger.success(`\u5DF2\u5207\u6362\u5F53\u524D\u9879\u76EE\u5185\u6838\u7248\u672C\u4E3A: ${version}`);
2293
+ }
2294
+ await sync({ version, force: false });
2295
+ }
2296
+
2297
+ // src/index.ts
2298
+ init_fetch();
2299
+
2300
+ // src/commands/install.ts
2301
+ init_esm_shims();
2302
+ init_sandbox();
2303
+ init_utils();
2304
+ import fs12 from "fs-extra";
2305
+ import path14 from "path";
2306
+ import pc13 from "picocolors";
2307
+ import { execa as execa5 } from "execa";
2308
+ async function install(target) {
2309
+ if (target.endsWith(".tgz") && fs12.existsSync(target)) {
2310
+ const spinner = createSpinner(`\u6B63\u5728\u5B89\u88C5\u672C\u5730\u79BB\u7EBF\u5305: ${pc13.bold(target)}...`).start();
2311
+ try {
2312
+ const tgzPath = path14.resolve(target);
2313
+ const match = path14.basename(target).match(/chatbi-core-(.+)\.tgz/);
2314
+ let version = "unknown";
2315
+ if (match) {
2316
+ version = match[1];
2317
+ }
2318
+ if (version === "unknown") {
2319
+ spinner.warn("\u65E0\u6CD5\u4ECE\u6587\u4EF6\u540D\u8BC6\u522B\u7248\u672C\uFF0C\u5C06\u4F7F\u7528\u5F53\u524D\u65F6\u95F4\u6233\u4F5C\u4E3A\u7248\u672C\u53F7");
2320
+ version = `local-${Date.now()}`;
2321
+ }
2322
+ const versionRoot = Sandbox.getVersionRoot();
2323
+ await fs12.ensureDir(versionRoot);
2324
+ spinner.text = "\u6B63\u5728\u89E3\u538B\u6587\u4EF6...";
2325
+ await execa5("tar", ["-xzf", tgzPath, "-C", versionRoot]);
2326
+ spinner.succeed(`\u672C\u5730\u5305\u5DF2\u5B89\u88C5\u81F3\u6C99\u7BB1: ${version}`);
2327
+ spinner.text = "\u6B63\u5728\u51C6\u5907\u5185\u6838\u73AF\u5883...";
2328
+ await Sandbox.prepare(version);
2329
+ spinner.succeed("\u5185\u6838\u73AF\u5883\u5C31\u7EEA");
2330
+ printBox(
2331
+ pc13.green(pc13.bold("\u2728 \u672C\u5730\u5185\u6838\u5B89\u88C5\u6210\u529F!")) + "\n\n" + pc13.white("\u7248\u672C: ") + pc13.cyan(version) + "\n" + pc13.white("\u8DEF\u5F84: ") + pc13.gray(Sandbox.getVersionPath(version)),
2332
+ "Install Success"
2333
+ );
2334
+ } catch (e) {
2335
+ spinner.fail("\u5B89\u88C5\u5931\u8D25");
2336
+ throw e;
2337
+ }
2338
+ } else {
2339
+ const { fetch: fetch2 } = await Promise.resolve().then(() => (init_fetch(), fetch_exports));
2340
+ await fetch2(target);
2341
+ }
2342
+ }
2343
+
2344
+ // package.json
2345
+ var package_default = {
2346
+ name: "@chatbi-v/cli",
2347
+ version: "2.0.4",
2348
+ description: "Standardized CLI tooling for ChatBI Monorepo",
2349
+ type: "module",
2350
+ main: "dist/index.js",
2351
+ module: "dist/index.js",
2352
+ types: "dist/index.d.ts",
2353
+ bin: {
2354
+ "chatbi-cli": "./bin/chatbi-cli.js"
2355
+ },
2356
+ files: [
2357
+ "dist",
2358
+ "bin",
2359
+ "templates"
2360
+ ],
2361
+ publishConfig: {
2362
+ access: "public"
2363
+ },
2364
+ scripts: {
2365
+ build: "tsup",
2366
+ dev: "tsup --watch",
2367
+ test: "vitest"
2368
+ },
2369
+ dependencies: {
2370
+ boxen: "^8.0.1",
2371
+ cac: "^6.7.14",
2372
+ execa: "^8.0.1",
2373
+ "fast-glob": "^3.3.3",
2374
+ figlet: "^1.9.4",
2375
+ "fs-extra": "^11.2.0",
2376
+ "gradient-string": "^3.0.0",
2377
+ handlebars: "^4.7.8",
2378
+ jiti: "^2.6.1",
2379
+ ora: "^7.0.1",
2380
+ picocolors: "^1.0.0",
2381
+ prompts: "^2.4.2",
2382
+ tsup: "^8.5.1",
2383
+ typescript: "^5.0.0",
2384
+ vite: "^5.4.21"
2385
+ },
2386
+ devDependencies: {
2387
+ "@types/boxen": "^3.0.5",
2388
+ "@types/figlet": "^1.7.0",
2389
+ "@types/fs-extra": "^11.0.0",
2390
+ "@types/gradient-string": "^1.1.6",
2391
+ "@types/node": "^20.0.0",
2392
+ "@types/prompts": "^2.4.9",
2393
+ "@vitest/coverage-v8": "1.6.1",
2394
+ tsup: "^8.5.1",
2395
+ vitest: "^1.0.0"
2396
+ }
2397
+ };
2398
+
2399
+ // src/index.ts
2400
+ init_utils();
2401
+ var cli = cac("chatbi-cli");
2402
+ var showHeader = () => {
2403
+ const title = figlet.textSync("ChatBI-V CLI", { font: "Standard" });
2404
+ console.log(gradient.pastel.multiline(title));
2405
+ console.log(
2406
+ boxen2(pc15.cyan(`ChatBI-V \u7EDF\u4E00\u5F00\u53D1\u5DE5\u5177 v${package_default.version}`), {
2407
+ padding: 0,
2408
+ margin: { top: 1, bottom: 1 },
2409
+ borderStyle: "round",
2410
+ borderColor: "cyan",
2411
+ title: "CoreKit Enabled",
2412
+ titleAlignment: "center"
2413
+ })
2414
+ );
2415
+ };
2416
+ var wrapAction = (action, commandName) => {
2417
+ return async (...args) => {
191
2418
  showHeader();
192
- sections[0].body = picocolors_1.default.white('ChatBI-V 开发者命令行工具,助力快速开发和构建插件。');
2419
+ try {
2420
+ await action(...args);
2421
+ } catch (e) {
2422
+ logger.error(`${commandName} \u6267\u884C\u5931\u8D25`, e);
2423
+ process.exit(1);
2424
+ }
2425
+ };
2426
+ };
2427
+ cli.command("dev", "\u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668").alias("d").option("--port <port>", "\u7AEF\u53E3\u53F7").action(wrapAction(dev, "dev"));
2428
+ cli.command("build", "\u6784\u5EFA\u5F53\u524D\u9879\u76EE").alias("b").option("--watch", "\u5F00\u542F\u76D1\u542C\u6A21\u5F0F").option("--force", "\u5F3A\u5236\u91CD\u65B0\u521D\u59CB\u5316\u73AF\u5883 (\u6E05\u7406\u7F13\u5B58)").action(wrapAction(build, "build"));
2429
+ cli.command("fetch <version>", "\u83B7\u53D6\u6307\u5B9A\u7248\u672C\u7684\u5185\u6838 (\u652F\u6301\u6253\u5305)").option("--pack", "\u6253\u5305\u4E3A\u79BB\u7EBF\u5B89\u88C5\u5305 (.tgz)").action(wrapAction(fetch, "fetch"));
2430
+ cli.command("install <target>", "\u5B89\u88C5\u5185\u6838 (\u652F\u6301\u7248\u672C\u53F7\u6216\u79BB\u7EBF\u5305\u8DEF\u5F84)").action(wrapAction(install, "install"));
2431
+ cli.command("init [name]", "\u521D\u59CB\u5316\u4E00\u4E2A\u65B0\u7684\u4E1A\u52A1\u63D2\u4EF6\u9879\u76EE").alias("create").alias("i").option("--project-type <type>", "\u9879\u76EE\u7C7B\u578B (monorepo | app | plugin)").option("--include-app", "Monorepo \u4E2D\u5305\u542B App").option("--no-include-app", "Monorepo \u4E2D\u4E0D\u5305\u542B App").option("--include-plugin", "Monorepo \u4E2D\u5305\u542B Plugin").option("--no-include-plugin", "Monorepo \u4E2D\u4E0D\u5305\u542B Plugin").option("--plugin-type <type>", "\u63D2\u4EF6\u7C7B\u578B (business | system)").option("--theme <theme>", "\u4E3B\u9898 (standard | nebula | glass)").action(wrapAction(async (name, options) => {
2432
+ await init({
2433
+ name,
2434
+ projectType: options.projectType,
2435
+ includeApp: options.includeApp,
2436
+ includePlugin: options.includePlugin,
2437
+ pluginType: options.pluginType,
2438
+ theme: options.theme
2439
+ });
2440
+ }, "init"));
2441
+ cli.command("add [name]", "\u5728\u5F53\u524D\u9879\u76EE\u4E2D\u6DFB\u52A0\u4E00\u4E2A\u65B0\u63D2\u4EF6").option("-t, --type <type>", "\u63D2\u4EF6\u7C7B\u578B (business | system)").option("--display-name <name>", "\u63D2\u4EF6\u663E\u793A\u540D\u79F0").option("--desc <description>", "\u63D2\u4EF6\u63CF\u8FF0").action(wrapAction(async (name, options) => {
2442
+ await add({
2443
+ name,
2444
+ type: options.type,
2445
+ displayName: options.displayName,
2446
+ description: options.desc
2447
+ });
2448
+ }, "add"));
2449
+ cli.command("update [targetVersion]", "\u66F4\u65B0\u5185\u6838\u7248\u672C").alias("up").action(wrapAction(async (targetVersion) => {
2450
+ const { sync: sync2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
2451
+ await sync2({ version: targetVersion, force: true });
2452
+ logger.success("\u66F4\u65B0\u5B8C\u6210\uFF01");
2453
+ }, "update"));
2454
+ cli.command("sync", "\u540C\u6B65\u5185\u6838\u4F9D\u8D56\u4E0E\u89C4\u8303").alias("s").option("-v, --core-version <version>", "\u6307\u5B9A\u5185\u6838\u7248\u672C").option("-f, --force", "\u5F3A\u5236\u91CD\u65B0\u521D\u59CB\u5316\u5185\u6838\u6C99\u7BB1").option("--clean", "\u6E05\u7406\u5E76\u91CD\u7F6E\u6C99\u7BB1").action(wrapAction(async (options) => {
2455
+ await sync({ ...options, version: options.coreVersion });
2456
+ console.log("");
2457
+ await doctor({ fix: false });
2458
+ }, "sync"));
2459
+ cli.command("doctor", "\u8BCA\u65AD\u9879\u76EE\u5065\u5EB7\u72B6\u51B5\u5E76\u4FEE\u590D").alias("dr").option("--fix", "\u81EA\u52A8\u4FEE\u590D\u53D1\u73B0\u7684\u95EE\u9898").action(wrapAction(doctor, "doctor"));
2460
+ cli.command("list", "\u5217\u51FA\u6240\u6709\u5DF2\u5B89\u88C5\u7684\u5185\u6838\u6C99\u7BB1\u7248\u672C").alias("ls").action(wrapAction(ls, "ls"));
2461
+ cli.command("use <version>", "\u5207\u6362\u5F53\u524D\u9879\u76EE\u4F7F\u7528\u7684\u5185\u6838\u7248\u672C").alias("u").option("--global", "\u5207\u6362\u5168\u5C40\u9ED8\u8BA4\u5185\u6838\u7248\u672C").action(wrapAction(use, "use"));
2462
+ cli.command("gl", "\u4F7F\u7528 AI \u811A\u624B\u67B6\u751F\u6210\u4EE3\u7801\u6216\u6587\u6863").option("-t, --type <type>", "\u751F\u6210\u7C7B\u578B (plugin|util|doc|component)").option("-p, --prompt <prompt>", "AI \u9700\u6C42\u63CF\u8FF0").action(wrapAction(gl, "gl"));
2463
+ cli.command("discover", "\u626B\u63CF\u5E76\u53D1\u73B0\u5F53\u524D\u9879\u76EE\u4E2D\u7684\u63D2\u4EF6").action(wrapAction(discover, "discover"));
2464
+ cli.command("bench", "\u8FD0\u884C CLI \u6027\u80FD\u57FA\u51C6\u6D4B\u8BD5").action(wrapAction(async () => {
2465
+ const { bench: bench2 } = await Promise.resolve().then(() => (init_bench(), bench_exports));
2466
+ await bench2();
2467
+ }, "bench"));
2468
+ cli.help((sections) => {
2469
+ showHeader();
2470
+ sections[0].body = pc15.white("ChatBI-V \u5F00\u53D1\u8005\u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u52A9\u529B\u5FEB\u901F\u5F00\u53D1\u548C\u6784\u5EFA\u63D2\u4EF6\u3002");
193
2471
  });
194
- cli.version(package_json_1.default.version);
195
- // 处理空命令
2472
+ cli.version(package_default.version);
196
2473
  if (process.argv.length <= 2) {
197
- cli.outputHelp();
198
- }
199
- else {
200
- cli.parse();
2474
+ cli.outputHelp();
2475
+ } else {
2476
+ cli.parse();
201
2477
  }