mulby-cli 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/PLUGIN_DEVELOP_PROMPT.md +1164 -0
  2. package/README.md +852 -0
  3. package/assets/default-icon.png +0 -0
  4. package/dist/commands/ai-session.js +44 -0
  5. package/dist/commands/build.js +111 -0
  6. package/dist/commands/config-ai.js +291 -0
  7. package/dist/commands/config.js +53 -0
  8. package/dist/commands/create/ai-create.js +183 -0
  9. package/dist/commands/create/assets.js +53 -0
  10. package/dist/commands/create/basic.js +72 -0
  11. package/dist/commands/create/index.js +73 -0
  12. package/dist/commands/create/react.js +136 -0
  13. package/dist/commands/create/templates/basic.js +383 -0
  14. package/dist/commands/create/templates/react/backend.js +72 -0
  15. package/dist/commands/create/templates/react/config.js +166 -0
  16. package/dist/commands/create/templates/react/docs.js +78 -0
  17. package/dist/commands/create/templates/react/hooks.js +469 -0
  18. package/dist/commands/create/templates/react/index.js +41 -0
  19. package/dist/commands/create/templates/react/types.js +1228 -0
  20. package/dist/commands/create/templates/react/ui.js +528 -0
  21. package/dist/commands/create/templates/react.js +1888 -0
  22. package/dist/commands/dev.js +141 -0
  23. package/dist/commands/pack.js +160 -0
  24. package/dist/commands/resume.js +97 -0
  25. package/dist/commands/test-ui.js +50 -0
  26. package/dist/index.js +71 -0
  27. package/dist/services/ai/PLUGIN_API.md +1102 -0
  28. package/dist/services/ai/PLUGIN_DEVELOP_PROMPT.md +1164 -0
  29. package/dist/services/ai/context-manager.js +639 -0
  30. package/dist/services/ai/index.js +88 -0
  31. package/dist/services/ai/knowledge.js +52 -0
  32. package/dist/services/ai/prompts.js +114 -0
  33. package/dist/services/ai/providers/base.js +38 -0
  34. package/dist/services/ai/providers/claude.js +284 -0
  35. package/dist/services/ai/providers/deepseek.js +28 -0
  36. package/dist/services/ai/providers/gemini.js +191 -0
  37. package/dist/services/ai/providers/glm.js +31 -0
  38. package/dist/services/ai/providers/minimax.js +27 -0
  39. package/dist/services/ai/providers/openai.js +177 -0
  40. package/dist/services/ai/tools.js +204 -0
  41. package/dist/services/ai-generator.js +968 -0
  42. package/dist/services/config-manager.js +117 -0
  43. package/dist/services/dependency-manager.js +236 -0
  44. package/dist/services/file-writer.js +66 -0
  45. package/dist/services/plan-adapter.js +244 -0
  46. package/dist/services/plan-command-handler.js +172 -0
  47. package/dist/services/plan-manager.js +502 -0
  48. package/dist/services/session-manager.js +113 -0
  49. package/dist/services/task-analyzer.js +136 -0
  50. package/dist/services/tui/index.js +57 -0
  51. package/dist/services/tui/store.js +123 -0
  52. package/dist/types/ai.js +172 -0
  53. package/dist/types/plan.js +2 -0
  54. package/dist/ui/Terminal.js +56 -0
  55. package/dist/ui/components/InputArea.js +176 -0
  56. package/dist/ui/components/LogArea.js +19 -0
  57. package/dist/ui/components/PlanPanel.js +69 -0
  58. package/dist/ui/components/SelectArea.js +13 -0
  59. package/package.json +45 -0
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.dev = dev;
40
+ const fs = __importStar(require("fs-extra"));
41
+ const path = __importStar(require("path"));
42
+ const esbuild = __importStar(require("esbuild"));
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const child_process_1 = require("child_process");
45
+ let viteProcess = null;
46
+ async function dev() {
47
+ const cwd = process.cwd();
48
+ const manifestPath = path.join(cwd, 'manifest.json');
49
+ if (!fs.existsSync(manifestPath)) {
50
+ console.log(chalk_1.default.red('错误: 未找到 manifest.json'));
51
+ process.exit(1);
52
+ }
53
+ const manifest = fs.readJsonSync(manifestPath);
54
+ const hasUI = !!manifest.ui;
55
+ const entryPoint = path.join(cwd, 'src/main.ts');
56
+ console.log(chalk_1.default.blue('启动开发模式...'));
57
+ console.log();
58
+ // 确保 dist 目录存在
59
+ fs.ensureDirSync(path.join(cwd, 'dist'));
60
+ // 1. 启动后端监听
61
+ if (fs.existsSync(entryPoint)) {
62
+ await startBackendWatch(cwd, entryPoint);
63
+ }
64
+ // 2. 启动 UI 开发服务器(如果有)
65
+ if (hasUI) {
66
+ await startViteDevServer(cwd);
67
+ }
68
+ console.log();
69
+ console.log(chalk_1.default.gray('按 Ctrl+C 退出'));
70
+ // 处理退出
71
+ process.on('SIGINT', cleanup);
72
+ process.on('SIGTERM', cleanup);
73
+ }
74
+ async function startBackendWatch(cwd, entryPoint) {
75
+ const ctx = await esbuild.context({
76
+ entryPoints: [entryPoint],
77
+ bundle: true,
78
+ platform: 'node',
79
+ outfile: path.join(cwd, 'dist/main.js'),
80
+ sourcemap: true
81
+ });
82
+ await ctx.watch();
83
+ console.log(chalk_1.default.green('✓ 后端监听已启动'));
84
+ // 监听文件变化并输出日志
85
+ const chokidar = await Promise.resolve().then(() => __importStar(require('chokidar')));
86
+ const watcher = chokidar.watch(['src/main.ts', 'src/**/*.ts'], {
87
+ cwd,
88
+ ignoreInitial: true,
89
+ ignored: ['src/ui/**']
90
+ });
91
+ watcher.on('change', (file) => {
92
+ console.log(chalk_1.default.yellow(`[后端] 文件变化: ${file}`));
93
+ });
94
+ }
95
+ async function startViteDevServer(cwd) {
96
+ const viteConfig = path.join(cwd, 'vite.config.ts');
97
+ if (!fs.existsSync(viteConfig)) {
98
+ console.log(chalk_1.default.yellow('跳过 UI 开发服务器: 未找到 vite.config.ts'));
99
+ return;
100
+ }
101
+ // 每次启动开发模式都构建 UI
102
+ // 这样应用可以加载最新的插件 UI
103
+ console.log(chalk_1.default.blue('构建 UI...'));
104
+ await new Promise((resolve, reject) => {
105
+ const viteBuild = (0, child_process_1.spawn)('npx', ['vite', 'build'], {
106
+ cwd,
107
+ stdio: 'inherit',
108
+ shell: true
109
+ });
110
+ viteBuild.on('close', (code) => {
111
+ if (code === 0) {
112
+ console.log(chalk_1.default.green('✓ UI 构建完成: ui/'));
113
+ resolve();
114
+ }
115
+ else {
116
+ reject(new Error(`Vite 构建失败,退出码: ${code}`));
117
+ }
118
+ });
119
+ viteBuild.on('error', reject);
120
+ });
121
+ console.log();
122
+ console.log(chalk_1.default.blue('启动 Vite 开发服务器...'));
123
+ console.log(chalk_1.default.gray(' 💡 提示: Vite 开发服务器提供 UI 预览,修改 UI 代码后'));
124
+ console.log(chalk_1.default.gray(' 在 Mulby 中点击「刷新插件」或执行 npm run build 更新'));
125
+ console.log();
126
+ viteProcess = (0, child_process_1.spawn)('npx', ['vite', '--host'], {
127
+ cwd,
128
+ stdio: 'inherit',
129
+ shell: true
130
+ });
131
+ viteProcess.on('error', (err) => {
132
+ console.log(chalk_1.default.red('Vite 启动失败:'), err);
133
+ });
134
+ }
135
+ function cleanup() {
136
+ console.log(chalk_1.default.blue('\n停止开发模式...'));
137
+ if (viteProcess) {
138
+ viteProcess.kill();
139
+ }
140
+ process.exit(0);
141
+ }
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.pack = pack;
40
+ const fs = __importStar(require("fs-extra"));
41
+ const path = __importStar(require("path"));
42
+ const archiver_1 = __importDefault(require("archiver"));
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ async function pack() {
45
+ const cwd = process.cwd();
46
+ const manifestPath = path.join(cwd, 'manifest.json');
47
+ if (!fs.existsSync(manifestPath)) {
48
+ console.log(chalk_1.default.red('错误: 未找到 manifest.json'));
49
+ process.exit(1);
50
+ }
51
+ const manifest = fs.readJsonSync(manifestPath);
52
+ const distMain = path.join(cwd, 'dist/main.js');
53
+ if (!fs.existsSync(distMain)) {
54
+ console.log(chalk_1.default.red('错误: 未找到 dist/main.js,请先运行 build'));
55
+ process.exit(1);
56
+ }
57
+ const outputName = `${manifest.name}-${manifest.version}.inplugin`;
58
+ const outputPath = path.join(cwd, outputName);
59
+ console.log(chalk_1.default.blue(`打包插件: ${outputName}`));
60
+ await createArchive(cwd, outputPath, manifest);
61
+ console.log(chalk_1.default.green(`✓ 打包成功: ${outputName}`));
62
+ }
63
+ async function createArchive(cwd, outputPath, manifest) {
64
+ return new Promise((resolve, reject) => {
65
+ const output = fs.createWriteStream(outputPath);
66
+ const archive = (0, archiver_1.default)('zip', { zlib: { level: 9 } });
67
+ output.on('close', () => resolve());
68
+ archive.on('error', (err) => reject(err));
69
+ archive.pipe(output);
70
+ // 添加 manifest.json
71
+ archive.file(path.join(cwd, 'manifest.json'), { name: 'manifest.json' });
72
+ // 添加打包后的 main.js
73
+ archive.file(path.join(cwd, 'dist/main.js'), { name: 'main.js' });
74
+ // 添加图标(如果存在)
75
+ const iconPath = path.join(cwd, 'icon.png');
76
+ if (fs.existsSync(iconPath)) {
77
+ archive.file(iconPath, { name: 'icon.png' });
78
+ }
79
+ // 添加 UI 目录(如果存在)
80
+ const uiDir = path.join(cwd, 'ui');
81
+ if (fs.existsSync(uiDir)) {
82
+ archive.directory(uiDir, 'ui');
83
+ }
84
+ // 添加 preload 脚本(如果在 manifest 中配置了)
85
+ if (manifest.preload) {
86
+ const preloadPath = path.join(cwd, manifest.preload);
87
+ if (fs.existsSync(preloadPath)) {
88
+ archive.file(preloadPath, { name: manifest.preload });
89
+ console.log(chalk_1.default.gray(` + ${manifest.preload}`));
90
+ // 当有 preload 时,打包 node_modules 中的生产依赖
91
+ const nodeModulesDir = path.join(cwd, 'node_modules');
92
+ const pkgJsonPath = path.join(cwd, 'package.json');
93
+ if (fs.existsSync(nodeModulesDir) && fs.existsSync(pkgJsonPath)) {
94
+ const pkgJson = fs.readJsonSync(pkgJsonPath);
95
+ const dependencies = Object.keys(pkgJson.dependencies || {});
96
+ if (dependencies.length > 0) {
97
+ console.log(chalk_1.default.gray(' + node_modules/ (生产依赖)'));
98
+ // 打包每个生产依赖及其子依赖
99
+ for (const dep of dependencies) {
100
+ const depPath = path.join(nodeModulesDir, dep);
101
+ if (fs.existsSync(depPath)) {
102
+ archive.directory(depPath, `node_modules/${dep}`);
103
+ }
104
+ }
105
+ // 递归收集所有需要的依赖(包括依赖的依赖)
106
+ const allDeps = collectAllDependencies(cwd, dependencies);
107
+ for (const dep of allDeps) {
108
+ if (!dependencies.includes(dep)) {
109
+ const depPath = path.join(nodeModulesDir, dep);
110
+ if (fs.existsSync(depPath)) {
111
+ archive.directory(depPath, `node_modules/${dep}`);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
118
+ else {
119
+ console.log(chalk_1.default.yellow(`警告: preload 文件不存在: ${manifest.preload}`));
120
+ }
121
+ }
122
+ // 添加 README.md(如果存在)
123
+ const readmePath = path.join(cwd, 'README.md');
124
+ if (fs.existsSync(readmePath)) {
125
+ archive.file(readmePath, { name: 'README.md' });
126
+ }
127
+ archive.finalize();
128
+ });
129
+ }
130
+ /**
131
+ * 递归收集所有依赖(包括依赖的依赖)
132
+ */
133
+ function collectAllDependencies(cwd, dependencies) {
134
+ const nodeModulesDir = path.join(cwd, 'node_modules');
135
+ const collected = new Set();
136
+ const queue = [...dependencies];
137
+ while (queue.length > 0) {
138
+ const dep = queue.shift();
139
+ if (collected.has(dep))
140
+ continue;
141
+ collected.add(dep);
142
+ // 读取该依赖的 package.json 获取其依赖
143
+ const depPkgPath = path.join(nodeModulesDir, dep, 'package.json');
144
+ if (fs.existsSync(depPkgPath)) {
145
+ try {
146
+ const depPkg = fs.readJsonSync(depPkgPath);
147
+ const subDeps = Object.keys(depPkg.dependencies || {});
148
+ for (const subDep of subDeps) {
149
+ if (!collected.has(subDep)) {
150
+ queue.push(subDep);
151
+ }
152
+ }
153
+ }
154
+ catch {
155
+ // 忽略读取错误
156
+ }
157
+ }
158
+ }
159
+ return Array.from(collected);
160
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resume = resume;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ const session_manager_1 = require("../services/session-manager");
10
+ const ai_generator_1 = require("../services/ai-generator");
11
+ async function resume(options) {
12
+ const sessionManager = session_manager_1.SessionManager.getInstance();
13
+ const cwd = process.cwd();
14
+ console.log(chalk_1.default.gray(`Checking for sessions in ${cwd}...`));
15
+ const session = sessionManager.getLatestSessionForDir(cwd);
16
+ if (!session) {
17
+ console.log(chalk_1.default.yellow('No active AI session found for this directory.'));
18
+ console.log('You can start a new one with: mulby create <name> --ai');
19
+ return;
20
+ }
21
+ console.log(chalk_1.default.green(`Found session: ${session.id}`));
22
+ console.log(chalk_1.default.blue(`Description: ${session.description}`));
23
+ console.log(chalk_1.default.gray(`Status: ${session.status}`));
24
+ // Check for interrupted tool execution (dangling tool calls)
25
+ // Check for interrupted tool execution (dangling tool calls)
26
+ // Find the last assistant message
27
+ let lastAssistantIdx = -1;
28
+ for (let i = session.conversationHistory.length - 1; i >= 0; i--) {
29
+ if (session.conversationHistory[i].role === 'assistant') {
30
+ lastAssistantIdx = i;
31
+ break;
32
+ }
33
+ }
34
+ if (lastAssistantIdx !== -1) {
35
+ const lastAsstMsg = session.conversationHistory[lastAssistantIdx];
36
+ if (lastAsstMsg.tool_calls && lastAsstMsg.tool_calls.length > 0) {
37
+ console.log(chalk_1.default.cyan(`Debug: Checking tool chain integrity for Assistant Msg #${lastAssistantIdx}...`));
38
+ // 1. Identify valid tool responses that exist *anywhere* after the assistant
39
+ // logic: we want to keep valid tool responses but remove 'user' junk in between
40
+ const subsequentMessages = session.conversationHistory.slice(lastAssistantIdx + 1);
41
+ const validToolResponses = subsequentMessages.filter(m => m.role === 'tool' &&
42
+ lastAsstMsg.tool_calls.some(c => c.id === m.tool_call_id));
43
+ // 2. Check if we need to repair (if there are intervening junk OR missing calls)
44
+ // If subsequentMessages has more items than validToolResponses, there is junk.
45
+ // If validToolResponses.length < tool_calls.length, there are missing calls.
46
+ const hasJunk = subsequentMessages.length > validToolResponses.length;
47
+ const hasMissingKeys = validToolResponses.length < lastAsstMsg.tool_calls.length;
48
+ if (hasJunk || hasMissingKeys) {
49
+ console.log(chalk_1.default.yellow(`⚠️ Detected broken tool chain (Junk: ${hasJunk}, Missing: ${hasMissingKeys}). Repairing...`));
50
+ // 3. Rebuild history
51
+ // Keep everything up to Assistant
52
+ const newHistory = session.conversationHistory.slice(0, lastAssistantIdx + 1);
53
+ // Add valid existing responses
54
+ // We map tool_calls to preserve order or just push what we found?
55
+ // OpenAI prefers order matching tool_calls usually, but ID matching is key.
56
+ // Let's iterate tool_calls and find response or create fake.
57
+ for (const call of lastAsstMsg.tool_calls) {
58
+ const existing = validToolResponses.find(m => m.tool_call_id === call.id);
59
+ if (existing) {
60
+ newHistory.push(existing);
61
+ }
62
+ else {
63
+ newHistory.push({
64
+ role: 'tool',
65
+ tool_call_id: call.id,
66
+ name: call.function.name,
67
+ content: 'Session resumed. Tool execution interrupted or failed to save.'
68
+ });
69
+ }
70
+ }
71
+ // Update session
72
+ session.conversationHistory = newHistory;
73
+ sessionManager.saveSession(session);
74
+ console.log(chalk_1.default.green('✓ History repaired. Removed intervening user messages and filled missing tool outputs.'));
75
+ }
76
+ }
77
+ }
78
+ // If session is completed or failed, we might want to check if user wants to continue
79
+ if (session.status === 'completed' || session.status === 'failed') {
80
+ const { confirm } = await inquirer_1.default.prompt([{
81
+ type: 'confirm',
82
+ name: 'confirm',
83
+ message: `Session is marked as ${session.status}. Do you want to continue working on it?`,
84
+ default: true
85
+ }]);
86
+ if (!confirm) {
87
+ return;
88
+ }
89
+ session.status = 'generating';
90
+ sessionManager.saveSession(session);
91
+ }
92
+ // Start UI
93
+ // Note: AIAgent will look for system prompt in history or default.
94
+ // Since we are resuming, we assume the agent can handle context.
95
+ const agent = new ai_generator_1.AIAgent(session);
96
+ await agent.start({ waitForInput: true });
97
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const chalk_1 = __importDefault(require("chalk"));
7
+ const tui_1 = require("../services/tui");
8
+ async function main() {
9
+ console.log('Starting UI Test...');
10
+ tui_1.tui.start();
11
+ tui_1.tui.log('Welcome to Mulby CLI UI Test');
12
+ tui_1.tui.log('This line should appear in the scrollable log area.');
13
+ let counter = 0;
14
+ const interval = setInterval(() => {
15
+ counter++;
16
+ tui_1.tui.log(`Auto log message #${counter} - ${new Date().toLocaleTimeString()}`);
17
+ tui_1.tui.setStatus(`Processing... (${counter}/10)`);
18
+ if (counter >= 10) {
19
+ clearInterval(interval);
20
+ tui_1.tui.log(chalk_1.default.green('Auto logging finished.'));
21
+ tui_1.tui.setStatus('Ready');
22
+ }
23
+ }, 1000);
24
+ try {
25
+ const name = await tui_1.tui.prompt('What is your name?');
26
+ tui_1.tui.log(chalk_1.default.cyan(`Hello, ${name}!`));
27
+ const cmd = await tui_1.tui.prompt('Type a command like /help:');
28
+ tui_1.tui.log(`You typed: ${cmd}`);
29
+ if (cmd.startsWith('/')) {
30
+ tui_1.tui.log(chalk_1.default.yellow('Command detected!'));
31
+ }
32
+ const confirm = await tui_1.tui.prompt('Do you want to exit? (y/n)');
33
+ if (confirm === 'y') {
34
+ tui_1.tui.log('Exiting...');
35
+ }
36
+ else {
37
+ tui_1.tui.log('Staying alive for 2 more seconds...');
38
+ await new Promise(r => setTimeout(r, 2000));
39
+ }
40
+ }
41
+ catch (e) {
42
+ tui_1.tui.log(chalk_1.default.red('Error during prompt: ' + e));
43
+ }
44
+ finally {
45
+ tui_1.tui.stop();
46
+ console.log('UI Test Finished.');
47
+ process.exit(0);
48
+ }
49
+ }
50
+ main().catch(console.error);
package/dist/index.js ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const create_1 = require("./commands/create");
9
+ const build_1 = require("./commands/build");
10
+ const pack_1 = require("./commands/pack");
11
+ const dev_1 = require("./commands/dev");
12
+ const config_1 = require("./commands/config");
13
+ const config_ai_1 = require("./commands/config-ai");
14
+ const ai_session_1 = require("./commands/ai-session");
15
+ const fs_1 = require("fs");
16
+ const path_1 = require("path");
17
+ const resume_1 = require("./commands/resume");
18
+ const chalk_1 = __importDefault(require("chalk"));
19
+ // 全局错误处理 - 防止进程意外退出
20
+ process.on('uncaughtException', (err) => {
21
+ console.error(chalk_1.default.red('\n❌ Uncaught Exception:'));
22
+ console.error(chalk_1.default.red(err.stack || err.message));
23
+ process.exit(1);
24
+ });
25
+ process.on('unhandledRejection', (reason, promise) => {
26
+ console.error(chalk_1.default.red('\n❌ Unhandled Promise Rejection:'));
27
+ console.error(chalk_1.default.red(reason instanceof Error ? reason.stack || reason.message : String(reason)));
28
+ // 不立即退出,让程序有机会处理
29
+ });
30
+ // 读取 package.json 获取版本号
31
+ const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', 'package.json'), 'utf-8'));
32
+ const program = new commander_1.Command();
33
+ program
34
+ .name('mulby')
35
+ .description('Mulby 插件开发 CLI 工具')
36
+ .version(pkg.version);
37
+ program
38
+ .command('create <name>')
39
+ .description('创建新插件项目')
40
+ .option('-t, --template <template>', '模板类型: react (默认) | basic', 'react')
41
+ .option('--ai', '使用 AI 辅助生成插件')
42
+ .option('--desc <description>', '此插件的简单功能描述')
43
+ .option('--resume [sessionId]', '恢复 AI 生成会话')
44
+ .action(create_1.create);
45
+ program
46
+ .command('build')
47
+ .description('构建插件')
48
+ .action(build_1.build);
49
+ program
50
+ .command('pack')
51
+ .description('打包成 .inplugin 文件')
52
+ .action(pack_1.pack);
53
+ program
54
+ .command('dev')
55
+ .description('开发模式(热重载)')
56
+ .action(dev_1.dev);
57
+ program
58
+ .command('config <action> [key] [value]')
59
+ .description('管理配置 (get, set, delete, list)')
60
+ .action(config_1.configCommand);
61
+ // 添加 AI 配置命令(独立的顶级命令)
62
+ program.addCommand((0, config_ai_1.createAIConfigCommand)());
63
+ program
64
+ .command('ai-session <action> [sessionId]')
65
+ .description('管理 AI 会话 (list, resume)')
66
+ .action(ai_session_1.sessionCommand);
67
+ program
68
+ .command('resume')
69
+ .description('恢复当前目录的 AI 会话')
70
+ .action(resume_1.resume);
71
+ program.parse();