zen-gitsync 2.9.10 → 2.10.2
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/package.json +2 -1
- package/src/ui/public/assets/index-CoHGlKy9.css +1 -0
- package/src/ui/public/assets/index-Dux6vkbA.js +108 -0
- package/src/ui/public/assets/{vendor-PvZNfVU0.js → vendor-C0m4M1mM.js} +1 -1
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +5 -0
- package/src/ui/server/routes/code.js +96 -0
- package/src/ui/server/routes/config.js +54 -0
- package/src/ui/public/assets/index-CzUoE1WP.css +0 -1
- package/src/ui/public/assets/index-GE6lIBHK.js +0 -79
package/src/ui/public/index.html
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
8
|
<title>Zen GitSync</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-Dux6vkbA.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-C0m4M1mM.js">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/vendor-BUGaay5Z.css">
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CoHGlKy9.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="app"></div>
|
package/src/ui/server/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import { registerFsRoutes } from './routes/fs.js';
|
|
|
25
25
|
import { registerNpmRoutes } from './routes/npm.js';
|
|
26
26
|
import { registerFileOpenRoutes } from './routes/fileOpen.js';
|
|
27
27
|
import { registerGitOpsRoutes } from './routes/gitOps.js';
|
|
28
|
+
import { registerCodeRoutes } from './routes/code.js';
|
|
28
29
|
import { createSavePortToFile } from './utils/createSavePortToFile.js';
|
|
29
30
|
import { startServerOnAvailablePort } from './utils/startServerOnAvailablePort.js';
|
|
30
31
|
|
|
@@ -123,6 +124,10 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
123
124
|
runningProcesses
|
|
124
125
|
});
|
|
125
126
|
|
|
127
|
+
registerCodeRoutes({
|
|
128
|
+
app
|
|
129
|
+
});
|
|
130
|
+
|
|
126
131
|
registerTerminalRoutes({
|
|
127
132
|
app,
|
|
128
133
|
getCurrentProjectPath: () => currentProjectPath,
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as vm from 'node:vm';
|
|
2
|
+
|
|
3
|
+
function isPlainObject(value) {
|
|
4
|
+
return Object.prototype.toString.call(value) === '[object Object]';
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function normalizeOutputs(outputs) {
|
|
8
|
+
if (!isPlainObject(outputs)) return {};
|
|
9
|
+
|
|
10
|
+
const result = {};
|
|
11
|
+
const entries = Object.entries(outputs);
|
|
12
|
+
|
|
13
|
+
for (const [key, val] of entries) {
|
|
14
|
+
const safeKey = String(key || '').trim();
|
|
15
|
+
if (!safeKey) continue;
|
|
16
|
+
if (safeKey.length > 64) continue;
|
|
17
|
+
|
|
18
|
+
if (val === undefined || val === null) {
|
|
19
|
+
result[safeKey] = '';
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof val === 'string') {
|
|
24
|
+
result[safeKey] = val;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof val === 'number' || typeof val === 'boolean') {
|
|
29
|
+
result[safeKey] = String(val);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
result[safeKey] = JSON.stringify(val);
|
|
35
|
+
} catch {
|
|
36
|
+
result[safeKey] = String(val);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function registerCodeRoutes({ app }) {
|
|
44
|
+
app.post('/api/execute-code-node', async (req, res) => {
|
|
45
|
+
try {
|
|
46
|
+
const { script, input, param } = req.body || {};
|
|
47
|
+
|
|
48
|
+
if (!script || typeof script !== 'string' || !script.trim()) {
|
|
49
|
+
return res.status(400).json({ success: false, error: 'script 不能为空' });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const inputText = typeof input === 'string' ? input : (input === undefined || input === null ? '' : String(input));
|
|
53
|
+
|
|
54
|
+
const paramObj = (param && typeof param === 'object') ? param : undefined;
|
|
55
|
+
|
|
56
|
+
const wrapped = `"use strict";\n${script}\n`;
|
|
57
|
+
|
|
58
|
+
const sandbox = {
|
|
59
|
+
input: inputText,
|
|
60
|
+
param: paramObj,
|
|
61
|
+
main: undefined
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const context = vm.createContext(sandbox, {
|
|
65
|
+
name: 'code-node-sandbox'
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const vmScript = new vm.Script(wrapped, { filename: 'code-node.js' });
|
|
69
|
+
|
|
70
|
+
let result;
|
|
71
|
+
try {
|
|
72
|
+
result = vmScript.runInContext(context, { timeout: 800 });
|
|
73
|
+
} catch (e) {
|
|
74
|
+
return res.status(400).json({ success: false, error: e?.message || String(e) });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const mainFn = context.main || sandbox.main;
|
|
78
|
+
if (typeof mainFn !== 'function') {
|
|
79
|
+
return res.status(400).json({ success: false, error: '未找到 main(param) 函数' });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let finalResult = result;
|
|
83
|
+
try {
|
|
84
|
+
finalResult = mainFn(paramObj || {});
|
|
85
|
+
} catch (e) {
|
|
86
|
+
return res.status(400).json({ success: false, error: e?.message || String(e) });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const outputs = normalizeOutputs(finalResult);
|
|
90
|
+
|
|
91
|
+
return res.json({ success: true, outputs });
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return res.status(500).json({ success: false, error: error?.message || String(error) });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
@@ -58,6 +58,24 @@ export function registerConfigRoutes({
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// 初始化命令模板(首次安装/旧配置兼容)
|
|
62
|
+
if (!Array.isArray(config.commandTemplates)) {
|
|
63
|
+
config.commandTemplates = []
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (config.commandTemplates.length === 0) {
|
|
67
|
+
config.commandTemplates = [
|
|
68
|
+
'echo "{{cmd}}"',
|
|
69
|
+
'npm run dev',
|
|
70
|
+
'npm run build',
|
|
71
|
+
'git status',
|
|
72
|
+
'git add .',
|
|
73
|
+
'git commit -m "{{message}}" --no-verify',
|
|
74
|
+
'git push',
|
|
75
|
+
]
|
|
76
|
+
await configManager.saveConfig(config)
|
|
77
|
+
}
|
|
78
|
+
|
|
61
79
|
// console.log('获取配置成功')
|
|
62
80
|
res.json(config)
|
|
63
81
|
} catch (error) {
|
|
@@ -207,6 +225,14 @@ export function registerConfigRoutes({
|
|
|
207
225
|
config.messageTemplates.push(template)
|
|
208
226
|
await configManager.saveConfig(config)
|
|
209
227
|
}
|
|
228
|
+
} else if (type === 'command') {
|
|
229
|
+
if (!config.commandTemplates) {
|
|
230
|
+
config.commandTemplates = []
|
|
231
|
+
}
|
|
232
|
+
if (!config.commandTemplates.includes(template)) {
|
|
233
|
+
config.commandTemplates.push(template)
|
|
234
|
+
await configManager.saveConfig(config)
|
|
235
|
+
}
|
|
210
236
|
} else {
|
|
211
237
|
return res.status(400).json({ success: false, error: '不支持的模板类型' })
|
|
212
238
|
}
|
|
@@ -255,6 +281,14 @@ export function registerConfigRoutes({
|
|
|
255
281
|
await configManager.saveConfig(config)
|
|
256
282
|
}
|
|
257
283
|
}
|
|
284
|
+
} else if (type === 'command') {
|
|
285
|
+
if (config.commandTemplates) {
|
|
286
|
+
const index = config.commandTemplates.indexOf(template)
|
|
287
|
+
if (index !== -1) {
|
|
288
|
+
config.commandTemplates.splice(index, 1)
|
|
289
|
+
await configManager.saveConfig(config)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
258
292
|
} else {
|
|
259
293
|
return res.status(400).json({ success: false, error: '不支持的模板类型' })
|
|
260
294
|
}
|
|
@@ -315,6 +349,18 @@ export function registerConfigRoutes({
|
|
|
315
349
|
} else {
|
|
316
350
|
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
317
351
|
}
|
|
352
|
+
} else if (type === 'command') {
|
|
353
|
+
if (config.commandTemplates) {
|
|
354
|
+
const index = config.commandTemplates.indexOf(oldTemplate)
|
|
355
|
+
if (index !== -1) {
|
|
356
|
+
config.commandTemplates[index] = newTemplate
|
|
357
|
+
await configManager.saveConfig(config)
|
|
358
|
+
} else {
|
|
359
|
+
return res.status(404).json({ success: false, error: '未找到原模板' })
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
363
|
+
}
|
|
318
364
|
} else {
|
|
319
365
|
return res.status(400).json({ success: false, error: '不支持的模板类型' })
|
|
320
366
|
}
|
|
@@ -362,6 +408,14 @@ export function registerConfigRoutes({
|
|
|
362
408
|
} else {
|
|
363
409
|
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
364
410
|
}
|
|
411
|
+
} else if (type === 'command') {
|
|
412
|
+
if (config.commandTemplates) {
|
|
413
|
+
config.commandTemplates = config.commandTemplates.filter(t => t !== template)
|
|
414
|
+
config.commandTemplates.unshift(template)
|
|
415
|
+
await configManager.saveConfig(config)
|
|
416
|
+
} else {
|
|
417
|
+
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
418
|
+
}
|
|
365
419
|
} else {
|
|
366
420
|
return res.status(400).json({ success: false, error: '不支持的模板类型' })
|
|
367
421
|
}
|