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,528 @@
1
+ "use strict";
2
+ /**
3
+ * React 插件模板 - UI 代码生成器
4
+ * 包含:index.html, main.tsx, App.tsx, styles.css
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.buildIndexHtml = buildIndexHtml;
8
+ exports.buildMainTsx = buildMainTsx;
9
+ exports.buildAppTsx = buildAppTsx;
10
+ exports.buildStylesCss = buildStylesCss;
11
+ /**
12
+ * 生成 index.html 内容
13
+ */
14
+ function buildIndexHtml(name) {
15
+ return `<!DOCTYPE html>
16
+ <html lang="zh-CN">
17
+ <head>
18
+ <meta charset="UTF-8">
19
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
20
+ <title>${name}</title>
21
+ </head>
22
+ <body>
23
+ <div id="root"></div>
24
+ <script type="module" src="./main.tsx"></script>
25
+ </body>
26
+ </html>
27
+ `;
28
+ }
29
+ /**
30
+ * 生成 main.tsx 入口文件内容
31
+ */
32
+ function buildMainTsx() {
33
+ return `import { StrictMode } from 'react'
34
+ import { createRoot } from 'react-dom/client'
35
+ import App from './App'
36
+ import './styles.css'
37
+
38
+ createRoot(document.getElementById('root')!).render(
39
+ <StrictMode>
40
+ <App />
41
+ </StrictMode>
42
+ )
43
+ `;
44
+ }
45
+ /**
46
+ * 生成 App.tsx 主应用组件内容
47
+ * 通用数据展示型布局:接收主进程传递的文字、附件、图像,分类展示
48
+ */
49
+ function buildAppTsx(name) {
50
+ return `import { useEffect, useState } from 'react'
51
+ import { FileText, Image, Copy, Inbox, Paperclip } from 'lucide-react'
52
+ import { useMulby } from './hooks/useMulby'
53
+
54
+ // 附件类型定义
55
+ interface Attachment {
56
+ id: string
57
+ name: string
58
+ size: number
59
+ kind: 'file' | 'image'
60
+ mime?: string
61
+ ext?: string
62
+ path?: string
63
+ dataUrl?: string
64
+ }
65
+
66
+ interface PluginInitData {
67
+ pluginName: string
68
+ featureCode: string
69
+ input: string
70
+ mode?: string
71
+ route?: string
72
+ attachments?: Attachment[]
73
+ }
74
+
75
+ export default function App() {
76
+ const [input, setInput] = useState('')
77
+ const [attachments, setAttachments] = useState<Attachment[]>([])
78
+ const { clipboard, notification, host } = useMulby('${name}')
79
+
80
+ // 按类型分组附件
81
+ const images = attachments.filter((a) => a.kind === 'image')
82
+ const files = attachments.filter((a) => a.kind === 'file')
83
+ const hasContent = input || images.length > 0 || files.length > 0
84
+
85
+ useEffect(() => {
86
+ // 初始化主题
87
+ const params = new URLSearchParams(window.location.search)
88
+ const initialTheme = (params.get('theme') as 'light' | 'dark') || 'light'
89
+ document.documentElement.classList.toggle('dark', initialTheme === 'dark')
90
+
91
+ // 监听主题变化
92
+ window.mulby?.onThemeChange?.((newTheme: 'light' | 'dark') => {
93
+ document.documentElement.classList.toggle('dark', newTheme === 'dark')
94
+ })
95
+
96
+ // 接收插件初始化数据
97
+ window.mulby?.onPluginInit?.((data: PluginInitData) => {
98
+ if (data.input) setInput(data.input)
99
+ if (data.attachments) setAttachments(data.attachments)
100
+ })
101
+ }, [])
102
+
103
+ // 复制文本到剪贴板
104
+ const handleCopyText = async () => {
105
+ if (!input) return
106
+ await clipboard.writeText(input)
107
+ notification.show('已复制到剪贴板', 'success')
108
+ }
109
+
110
+ // 示例:调用后端 host 方法
111
+ const handleCallHost = async () => {
112
+ try {
113
+ const result = await host.call('processData', { value: input })
114
+ console.log('Host 返回:', result.data)
115
+ notification.show('后端处理成功', 'success')
116
+ } catch (err: any) {
117
+ notification.show(\`错误: \${err.message}\`, 'error')
118
+ }
119
+ }
120
+
121
+ // 格式化文件大小
122
+ const formatSize = (bytes: number) => {
123
+ if (bytes < 1024) return \`\${bytes} B\`
124
+ if (bytes < 1024 * 1024) return \`\${(bytes / 1024).toFixed(1)} KB\`
125
+ return \`\${(bytes / 1024 / 1024).toFixed(1)} MB\`
126
+ }
127
+
128
+ return (
129
+ <div className="plugin-root">
130
+ {/* 头部 */}
131
+ <header className="header">
132
+ <h1 className="header-title">${name}</h1>
133
+ {attachments.length > 0 && (
134
+ <span className="badge">
135
+ <Paperclip size={12} />
136
+ {attachments.length}
137
+ </span>
138
+ )}
139
+ </header>
140
+
141
+ {/* 主内容区 */}
142
+ <main className="main">
143
+ {!hasContent ? (
144
+ <div className="empty-state">
145
+ <Inbox size={40} strokeWidth={1.5} />
146
+ <p className="empty-title">暂无数据</p>
147
+ <p className="empty-hint">等待主进程传入文字或附件</p>
148
+ </div>
149
+ ) : (
150
+ <div className="content-flow">
151
+ {/* 文本区域 */}
152
+ {input && (
153
+ <section className="section">
154
+ <div className="section-head">
155
+ <h2>文本内容</h2>
156
+ <button className="btn-ghost" onClick={handleCopyText}>
157
+ <Copy size={13} />
158
+ 复制
159
+ </button>
160
+ </div>
161
+ <div className="text-block">{input}</div>
162
+ </section>
163
+ )}
164
+
165
+ {/* 图片网格 */}
166
+ {images.length > 0 && (
167
+ <section className="section">
168
+ <div className="section-head">
169
+ <h2><Image size={14} /> 图片 ({images.length})</h2>
170
+ </div>
171
+ <div className="image-grid">
172
+ {images.map((img, i) => (
173
+ <div key={img.id || i} className="image-cell">
174
+ <img
175
+ src={img.dataUrl || \`file://\${img.path}\`}
176
+ alt={img.name}
177
+ loading="lazy"
178
+ />
179
+ <span className="image-name">{img.name}</span>
180
+ </div>
181
+ ))}
182
+ </div>
183
+ </section>
184
+ )}
185
+
186
+ {/* 文件列表 */}
187
+ {files.length > 0 && (
188
+ <section className="section">
189
+ <div className="section-head">
190
+ <h2><FileText size={14} /> 文件 ({files.length})</h2>
191
+ </div>
192
+ <div className="file-list">
193
+ {files.map((file, i) => (
194
+ <div key={file.id || i} className="file-row">
195
+ <FileText size={16} className="file-icon" />
196
+ <span className="file-name">{file.name}</span>
197
+ <span className="file-size">{formatSize(file.size)}</span>
198
+ </div>
199
+ ))}
200
+ </div>
201
+ </section>
202
+ )}
203
+ </div>
204
+ )}
205
+ </main>
206
+
207
+ {/* 底部操作 */}
208
+ <footer className="footer">
209
+ <button className="btn-primary" onClick={handleCallHost}>调用后端</button>
210
+ <button className="btn-secondary" onClick={handleCopyText} disabled={!input}>
211
+ <Copy size={13} />
212
+ 复制文本
213
+ </button>
214
+ </footer>
215
+ </div>
216
+ )
217
+ }
218
+ `;
219
+ }
220
+ /**
221
+ * 生成 styles.css 全局样式内容
222
+ * 扁平化设计:纯色背景、细边框、无投影/渐变/毛玻璃
223
+ */
224
+ function buildStylesCss() {
225
+ return `@tailwind base;
226
+ @tailwind components;
227
+ @tailwind utilities;
228
+
229
+ /* ===== 亮色主题 ===== */
230
+ :root {
231
+ --bg: #f7f8fa;
232
+ --surface: #ffffff;
233
+ --border: #e5e7eb;
234
+ --border-hover: #d1d5db;
235
+ --text-1: #1a1a1a;
236
+ --text-2: #6b7280;
237
+ --text-3: #9ca3af;
238
+ --accent: #3b82f6;
239
+ --accent-hover: #2563eb;
240
+ --accent-soft: rgba(59, 130, 246, 0.08);
241
+ --tag-bg: rgba(59, 130, 246, 0.1);
242
+ --tag-text: #2563eb;
243
+ }
244
+
245
+ /* ===== 暗色主题(与主进程 slate-blue 色调对齐) ===== */
246
+ :root.dark {
247
+ --bg: #0f172a;
248
+ --surface: #1e293b;
249
+ --border: #334155;
250
+ --border-hover: #475569;
251
+ --text-1: #f1f5f9;
252
+ --text-2: #94a3b8;
253
+ --text-3: #64748b;
254
+ --accent: #3b82f6;
255
+ --accent-hover: #60a5fa;
256
+ --accent-soft: rgba(59, 130, 246, 0.1);
257
+ --tag-bg: rgba(59, 130, 246, 0.15);
258
+ --tag-text: #93c5fd;
259
+ }
260
+
261
+ /* ===== 基础 ===== */
262
+ * { box-sizing: border-box; margin: 0; padding: 0; }
263
+
264
+ html, body, #root { width: 100%; height: 100%; }
265
+
266
+ body {
267
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
268
+ background: var(--bg);
269
+ color: var(--text-1);
270
+ }
271
+
272
+ /* ===== 整体布局 ===== */
273
+ .plugin-root {
274
+ display: flex;
275
+ flex-direction: column;
276
+ height: 100%;
277
+ max-height: 100vh;
278
+ }
279
+
280
+ /* ===== 头部 ===== */
281
+ .header {
282
+ display: flex;
283
+ align-items: center;
284
+ gap: 8px;
285
+ padding: 14px 20px;
286
+ border-bottom: 1px solid var(--border);
287
+ background: var(--surface);
288
+ }
289
+
290
+ .header-title {
291
+ font-size: 15px;
292
+ font-weight: 600;
293
+ letter-spacing: -0.01em;
294
+ }
295
+
296
+ .badge {
297
+ display: inline-flex;
298
+ align-items: center;
299
+ gap: 4px;
300
+ padding: 2px 8px;
301
+ border-radius: 10px;
302
+ background: var(--tag-bg);
303
+ color: var(--tag-text);
304
+ font-size: 11px;
305
+ font-weight: 600;
306
+ }
307
+
308
+ /* ===== 主内容 ===== */
309
+ .main {
310
+ flex: 1;
311
+ overflow-y: auto;
312
+ padding: 16px 20px;
313
+ }
314
+
315
+ /* ===== 空状态 ===== */
316
+ .empty-state {
317
+ display: flex;
318
+ flex-direction: column;
319
+ align-items: center;
320
+ justify-content: center;
321
+ gap: 8px;
322
+ height: 100%;
323
+ min-height: 180px;
324
+ color: var(--text-3);
325
+ }
326
+
327
+ .empty-title {
328
+ font-size: 14px;
329
+ font-weight: 500;
330
+ color: var(--text-2);
331
+ }
332
+
333
+ .empty-hint {
334
+ font-size: 12px;
335
+ }
336
+
337
+ /* ===== 内容区 ===== */
338
+ .content-flow {
339
+ display: flex;
340
+ flex-direction: column;
341
+ gap: 16px;
342
+ }
343
+
344
+ /* ===== Section ===== */
345
+ .section {
346
+ display: flex;
347
+ flex-direction: column;
348
+ gap: 8px;
349
+ }
350
+
351
+ .section-head {
352
+ display: flex;
353
+ align-items: center;
354
+ justify-content: space-between;
355
+ }
356
+
357
+ .section-head h2 {
358
+ font-size: 12px;
359
+ font-weight: 600;
360
+ color: var(--text-2);
361
+ text-transform: uppercase;
362
+ letter-spacing: 0.03em;
363
+ display: inline-flex;
364
+ align-items: center;
365
+ gap: 5px;
366
+ }
367
+
368
+ /* ===== 文本块 ===== */
369
+ .text-block {
370
+ font-size: 14px;
371
+ line-height: 1.7;
372
+ white-space: pre-wrap;
373
+ word-break: break-word;
374
+ padding: 12px;
375
+ border-radius: 8px;
376
+ border: 1px solid var(--border);
377
+ background: var(--surface);
378
+ max-height: 280px;
379
+ overflow-y: auto;
380
+ }
381
+
382
+ /* ===== 图片网格 ===== */
383
+ .image-grid {
384
+ display: grid;
385
+ grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
386
+ gap: 8px;
387
+ }
388
+
389
+ .image-cell {
390
+ border-radius: 8px;
391
+ border: 1px solid var(--border);
392
+ overflow: hidden;
393
+ background: var(--surface);
394
+ transition: border-color 150ms;
395
+ }
396
+
397
+ .image-cell:hover {
398
+ border-color: var(--border-hover);
399
+ }
400
+
401
+ .image-cell img {
402
+ display: block;
403
+ width: 100%;
404
+ aspect-ratio: 1;
405
+ object-fit: cover;
406
+ }
407
+
408
+ .image-name {
409
+ display: block;
410
+ padding: 5px 8px;
411
+ font-size: 11px;
412
+ color: var(--text-2);
413
+ white-space: nowrap;
414
+ overflow: hidden;
415
+ text-overflow: ellipsis;
416
+ }
417
+
418
+ /* ===== 文件列表 ===== */
419
+ .file-list {
420
+ display: flex;
421
+ flex-direction: column;
422
+ gap: 4px;
423
+ }
424
+
425
+ .file-row {
426
+ display: flex;
427
+ align-items: center;
428
+ gap: 8px;
429
+ padding: 8px 10px;
430
+ border-radius: 6px;
431
+ transition: background-color 120ms;
432
+ }
433
+
434
+ .file-row:hover {
435
+ background: var(--accent-soft);
436
+ }
437
+
438
+ .file-icon {
439
+ flex-shrink: 0;
440
+ color: var(--text-3);
441
+ }
442
+
443
+ .file-name {
444
+ flex: 1;
445
+ min-width: 0;
446
+ font-size: 13px;
447
+ white-space: nowrap;
448
+ overflow: hidden;
449
+ text-overflow: ellipsis;
450
+ }
451
+
452
+ .file-size {
453
+ font-size: 11px;
454
+ color: var(--text-3);
455
+ flex-shrink: 0;
456
+ }
457
+
458
+ /* ===== 按钮 ===== */
459
+ button {
460
+ border: none;
461
+ border-radius: 6px;
462
+ padding: 6px 14px;
463
+ font-size: 13px;
464
+ font-weight: 500;
465
+ display: inline-flex;
466
+ align-items: center;
467
+ gap: 5px;
468
+ cursor: pointer;
469
+ transition: background-color 120ms, opacity 120ms;
470
+ }
471
+
472
+ button:disabled {
473
+ opacity: 0.4;
474
+ cursor: not-allowed;
475
+ }
476
+
477
+ .btn-primary {
478
+ background: var(--accent);
479
+ color: #fff;
480
+ }
481
+
482
+ .btn-primary:hover:not(:disabled) {
483
+ background: var(--accent-hover);
484
+ }
485
+
486
+ .btn-secondary {
487
+ background: var(--accent-soft);
488
+ color: var(--accent);
489
+ }
490
+
491
+ .btn-secondary:hover:not(:disabled) {
492
+ background: var(--tag-bg);
493
+ }
494
+
495
+ .btn-ghost {
496
+ background: transparent;
497
+ color: var(--text-2);
498
+ padding: 4px 8px;
499
+ font-size: 12px;
500
+ }
501
+
502
+ .btn-ghost:hover {
503
+ background: var(--accent-soft);
504
+ color: var(--accent);
505
+ }
506
+
507
+ /* ===== 底部 ===== */
508
+ .footer {
509
+ display: flex;
510
+ align-items: center;
511
+ gap: 8px;
512
+ padding: 12px 20px;
513
+ border-top: 1px solid var(--border);
514
+ background: var(--surface);
515
+ }
516
+
517
+ /* ===== 响应式 ===== */
518
+ @media (max-width: 480px) {
519
+ .header, .main, .footer { padding-left: 14px; padding-right: 14px; }
520
+ .image-grid { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); }
521
+ }
522
+
523
+ /* ===== 减少动画偏好 ===== */
524
+ @media (prefers-reduced-motion: reduce) {
525
+ * { transition: none !important; }
526
+ }
527
+ `;
528
+ }