@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.
- package/bin/chatbi-cli.js +1 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2464 -188
- package/package.json +6 -3
- package/templates/app/package.json.hbs +5 -2
- package/templates/plugin/package.json.hbs +5 -5
- package/templates/plugin/tsconfig.json.hbs +1 -1
- package/dist/bench-ACSHVGHE.mjs +0 -77
- package/dist/build-UB4D3WNI.mjs +0 -11
- package/dist/chunk-4OD6C56P.mjs +0 -89
- package/dist/chunk-7A54IJI5.mjs +0 -6368
- package/dist/chunk-LJFX6MNO.mjs +0 -255
- package/dist/chunk-SBGVKO4C.mjs +0 -2255
- package/dist/chunk-TX5M36S5.mjs +0 -55
- package/dist/chunk-V7IEPMC4.mjs +0 -52
- package/dist/chunk-WCPZB47I.mjs +0 -262
- package/dist/chunk-WIVHOK75.mjs +0 -5292
- package/dist/chunk-Y24V4GQG.mjs +0 -9577
- package/dist/commands/add.js +0 -182
- package/dist/commands/bench.js +0 -100
- package/dist/commands/build.js +0 -290
- package/dist/commands/dev.js +0 -8
- package/dist/commands/discover.js +0 -25
- package/dist/commands/doctor.js +0 -231
- package/dist/commands/fetch.js +0 -41
- package/dist/commands/gl.js +0 -151
- package/dist/commands/init.js +0 -253
- package/dist/commands/install.js +0 -85
- package/dist/commands/ls.js +0 -46
- package/dist/commands/sync.js +0 -78
- package/dist/commands/use.js +0 -31
- package/dist/config.js +0 -70
- package/dist/corekit.js +0 -370
- package/dist/execa-METROS6Z.mjs +0 -17
- package/dist/fetch-7X2UFWIV.mjs +0 -10
- package/dist/index.cjs +0 -27278
- package/dist/index.mjs +0 -2769
- package/dist/init-QFRFYEA5.mjs +0 -12
- package/dist/sandbox.js +0 -522
- package/dist/sync-7HPKGVFY.mjs +0 -11
- package/dist/utils.js +0 -99
package/dist/index.js
CHANGED
|
@@ -1,201 +1,2477 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
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(
|
|
195
|
-
// 处理空命令
|
|
2472
|
+
cli.version(package_default.version);
|
|
196
2473
|
if (process.argv.length <= 2) {
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
cli.parse();
|
|
2474
|
+
cli.outputHelp();
|
|
2475
|
+
} else {
|
|
2476
|
+
cli.parse();
|
|
201
2477
|
}
|