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.
@@ -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-GE6lIBHK.js"></script>
10
- <link rel="modulepreload" crossorigin href="/assets/vendor-PvZNfVU0.js">
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-CzUoE1WP.css">
12
+ <link rel="stylesheet" crossorigin href="/assets/index-CoHGlKy9.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="app"></div>
@@ -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
  }