zen-gitsync 2.11.39 → 2.12.3

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 (58) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +695 -695
  3. package/index.js +25 -11
  4. package/package.json +2 -2
  5. package/scripts/convert-colors-to-vars.cjs +286 -272
  6. package/scripts/convert-fontsize-to-vars.cjs +221 -207
  7. package/scripts/convert-spacing-to-vars.cjs +256 -242
  8. package/scripts/convert-to-standard-vars.cjs +282 -268
  9. package/scripts/release.js +599 -585
  10. package/src/config.js +350 -336
  11. package/src/gitCommit.js +455 -440
  12. package/src/ui/public/assets/EditorView-CbqSI9nw.css +1 -0
  13. package/src/ui/public/assets/EditorView-GS5cmh99.js +21 -0
  14. package/src/ui/public/assets/SourceMapView-DyMK80hS.css +1 -0
  15. package/src/ui/public/assets/SourceMapView-_YRtzmZZ.js +3 -0
  16. package/src/ui/public/assets/index-ML5Y-5lO.css +1 -0
  17. package/src/ui/public/assets/index-yky0Sd13.js +73 -0
  18. package/src/ui/public/assets/{ts.worker-Dth06zuC.js → ts.worker-METxwbDZ.js} +1 -16
  19. package/src/ui/public/assets/{vendor-B1T2uxYO.js → vendor-DITsiaGj.js} +294 -287
  20. package/src/ui/public/assets/vendor-q83wvJns.css +1 -0
  21. package/src/ui/public/index.html +4 -4
  22. package/src/ui/server/.claude/codediff.txt +6 -0
  23. package/src/ui/server/index.js +410 -396
  24. package/src/ui/server/middleware/requestLogger.js +51 -37
  25. package/src/ui/server/routes/branchStatus.js +101 -87
  26. package/src/ui/server/routes/code.js +110 -96
  27. package/src/ui/server/routes/codeAnalysis.js +995 -981
  28. package/src/ui/server/routes/config.js +1172 -1158
  29. package/src/ui/server/routes/exec.js +272 -258
  30. package/src/ui/server/routes/fileOpen.js +279 -265
  31. package/src/ui/server/routes/fs.js +701 -699
  32. package/src/ui/server/routes/git/diff.js +352 -338
  33. package/src/ui/server/routes/git/diffUtils.js +128 -114
  34. package/src/ui/server/routes/git/stash.js +552 -538
  35. package/src/ui/server/routes/git/tags.js +172 -158
  36. package/src/ui/server/routes/git.js +190 -176
  37. package/src/ui/server/routes/gitOps.js +1179 -1165
  38. package/src/ui/server/routes/instances.js +38 -24
  39. package/src/ui/server/routes/npm.js +1023 -1009
  40. package/src/ui/server/routes/process.js +82 -68
  41. package/src/ui/server/routes/status.js +67 -53
  42. package/src/ui/server/routes/terminal.js +319 -305
  43. package/src/ui/server/socket/registerUiSocketHandlers.js +226 -212
  44. package/src/ui/server/utils/createSavePortToFile.js +46 -32
  45. package/src/ui/server/utils/instanceRegistry.js +270 -256
  46. package/src/ui/server/utils/pathGuard.js +155 -0
  47. package/src/ui/server/utils/pathGuard.test.js +138 -0
  48. package/src/ui/server/utils/randomStartPort.js +51 -37
  49. package/src/ui/server/utils/startServerOnAvailablePort.js +101 -87
  50. package/src/utils/index.js +1058 -1044
  51. package/src/ui/public/assets/devopicons-QN4QXivI.woff2 +0 -0
  52. package/src/ui/public/assets/file-icons-C0jOugUK.woff2 +0 -0
  53. package/src/ui/public/assets/fontawesome-B-jkhYfk.woff2 +0 -0
  54. package/src/ui/public/assets/index-BvVl-092.js +0 -95
  55. package/src/ui/public/assets/index-DXO3Lvqi.css +0 -1
  56. package/src/ui/public/assets/mfixx-CpAhKOZz.woff2 +0 -0
  57. package/src/ui/public/assets/octicons-CaZ_fok2.woff2 +0 -0
  58. package/src/ui/public/assets/vendor-hOO_r_AU.css +0 -1
@@ -1,37 +1,51 @@
1
- export function createRequestLogger({ chalk }) {
2
- return (req, res, next) => {
3
- const startTime = Date.now();
4
- const requestTime = new Date().toLocaleString('zh-CN', { hour12: false });
5
-
6
- res.on('finish', () => {
7
- const duration = Date.now() - startTime;
8
- const statusCode = res.statusCode;
9
-
10
- let statusColor = chalk.green;
11
- if (statusCode >= 400 && statusCode < 500) {
12
- statusColor = chalk.yellow;
13
- } else if (statusCode >= 500) {
14
- statusColor = chalk.red;
15
- }
16
-
17
- let durationColor = chalk.gray;
18
- if (duration > 1000) {
19
- durationColor = chalk.red;
20
- } else if (duration > 500) {
21
- durationColor = chalk.yellow;
22
- } else if (duration > 200) {
23
- durationColor = chalk.cyan;
24
- }
25
-
26
- console.log(
27
- chalk.dim(`[${requestTime}]`),
28
- chalk.bold(req.method),
29
- req.url,
30
- statusColor(`[${statusCode}]`),
31
- durationColor(`${duration}ms`)
32
- );
33
- });
34
-
35
- next();
36
- };
37
- }
1
+ // Copyright 2026 xz333221
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ export function createRequestLogger({ chalk }) {
16
+ return (req, res, next) => {
17
+ const startTime = Date.now();
18
+ const requestTime = new Date().toLocaleString('zh-CN', { hour12: false });
19
+
20
+ res.on('finish', () => {
21
+ const duration = Date.now() - startTime;
22
+ const statusCode = res.statusCode;
23
+
24
+ let statusColor = chalk.green;
25
+ if (statusCode >= 400 && statusCode < 500) {
26
+ statusColor = chalk.yellow;
27
+ } else if (statusCode >= 500) {
28
+ statusColor = chalk.red;
29
+ }
30
+
31
+ let durationColor = chalk.gray;
32
+ if (duration > 1000) {
33
+ durationColor = chalk.red;
34
+ } else if (duration > 500) {
35
+ durationColor = chalk.yellow;
36
+ } else if (duration > 200) {
37
+ durationColor = chalk.cyan;
38
+ }
39
+
40
+ console.log(
41
+ chalk.dim(`[${requestTime}]`),
42
+ chalk.bold(req.method),
43
+ req.url,
44
+ statusColor(`[${statusCode}]`),
45
+ durationColor(`${duration}ms`)
46
+ );
47
+ });
48
+
49
+ next();
50
+ };
51
+ }
@@ -1,87 +1,101 @@
1
- export function registerBranchStatusRoutes({
2
- app,
3
- execGitCommand,
4
- getIsGitRepo,
5
- getBranchStatusCache,
6
- setBranchStatusCache,
7
- getRecentPushStatus,
8
- setRecentPushStatus
9
- }) {
10
- // 获取当前分支 - 直接读取,不缓存(git symbolic-ref 极快,<5ms)
11
- app.get('/api/branch', async (req, res) => {
12
- try {
13
- const { stdout } = await execGitCommand('git symbolic-ref --short HEAD');
14
- res.json({ branch: stdout.trim() });
15
- } catch (error) {
16
- res.status(500).json({ error: error.message });
17
- }
18
- });
19
-
20
- // 获取分支与远程的差异状态(领先/落后提交数)
21
- app.get('/api/branch-status', async (req, res) => {
22
- try {
23
- if (!getIsGitRepo()) {
24
- return res.json({ hasUpstream: false, ahead: 0, behind: 0 });
25
- }
26
-
27
- const now = Date.now();
28
- const forceRefresh = req.query.force === 'true';
29
-
30
- const recentPushStatus = getRecentPushStatus();
31
- const branchStatusCache = getBranchStatusCache();
32
-
33
- // push 后10秒内直接返回同步状态
34
- if (recentPushStatus.justPushed &&
35
- (now - recentPushStatus.pushTime) < recentPushStatus.validDuration) {
36
- console.log('检测到最近推送过,直接返回同步状态');
37
- return res.json({
38
- hasUpstream: true,
39
- upstreamBranch: branchStatusCache.upstreamBranch || 'origin/main',
40
- ahead: 0,
41
- behind: 0
42
- });
43
- }
44
-
45
- // 5秒缓存分支名,防止短时间内重复执行 git symbolic-ref / git rev-parse
46
- const branchInfoCacheValid = !forceRefresh &&
47
- branchStatusCache.currentBranch &&
48
- branchStatusCache.upstreamBranch &&
49
- (now - branchStatusCache.lastUpdate) < branchStatusCache.cacheTimeout;
50
-
51
- let currentBranch, upstreamBranch;
52
-
53
- if (branchInfoCacheValid) {
54
- currentBranch = branchStatusCache.currentBranch;
55
- upstreamBranch = branchStatusCache.upstreamBranch;
56
- console.log(`使用5秒缓存的分支名: ${currentBranch} -> ${upstreamBranch}`);
57
- } else {
58
- // 直接读取,不再走5分钟长缓存
59
- const { stdout: branchOut } = await execGitCommand('git symbolic-ref --short HEAD');
60
- currentBranch = branchOut.trim();
61
-
62
- const { stdout: upstreamOut } = await execGitCommand(
63
- 'git rev-parse --abbrev-ref --symbolic-full-name @{u}',
64
- { ignoreError: true }
65
- );
66
- upstreamBranch = upstreamOut.trim() || null;
67
-
68
- if (!upstreamBranch) {
69
- setBranchStatusCache({ currentBranch: null, upstreamBranch: null, lastUpdate: 0, cacheTimeout: 5000 });
70
- return res.json({ hasUpstream: false, ahead: 0, behind: 0 });
71
- }
72
-
73
- setBranchStatusCache({ currentBranch, upstreamBranch, lastUpdate: now, cacheTimeout: 5000 });
74
- }
75
-
76
- const { stdout: aheadBehindOutput } = await execGitCommand(
77
- `git rev-list --left-right --count ${currentBranch}...${upstreamBranch}`
78
- );
79
- const [ahead, behind] = aheadBehindOutput.trim().split('\t').map(Number);
80
-
81
- res.json({ hasUpstream: true, upstreamBranch, ahead, behind });
82
- } catch (error) {
83
- console.error('获取分支状态失败:', error);
84
- res.status(500).json({ error: error.message });
85
- }
86
- });
87
- }
1
+ // Copyright 2026 xz333221
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ export function registerBranchStatusRoutes({
16
+ app,
17
+ execGitCommand,
18
+ getIsGitRepo,
19
+ getBranchStatusCache,
20
+ setBranchStatusCache,
21
+ getRecentPushStatus,
22
+ setRecentPushStatus
23
+ }) {
24
+ // 获取当前分支 - 直接读取,不缓存(git symbolic-ref 极快,<5ms)
25
+ app.get('/api/branch', async (req, res) => {
26
+ try {
27
+ const { stdout } = await execGitCommand('git symbolic-ref --short HEAD');
28
+ res.json({ branch: stdout.trim() });
29
+ } catch (error) {
30
+ res.status(500).json({ error: error.message });
31
+ }
32
+ });
33
+
34
+ // 获取分支与远程的差异状态(领先/落后提交数)
35
+ app.get('/api/branch-status', async (req, res) => {
36
+ try {
37
+ if (!getIsGitRepo()) {
38
+ return res.json({ hasUpstream: false, ahead: 0, behind: 0 });
39
+ }
40
+
41
+ const now = Date.now();
42
+ const forceRefresh = req.query.force === 'true';
43
+
44
+ const recentPushStatus = getRecentPushStatus();
45
+ const branchStatusCache = getBranchStatusCache();
46
+
47
+ // push 后10秒内直接返回同步状态
48
+ if (recentPushStatus.justPushed &&
49
+ (now - recentPushStatus.pushTime) < recentPushStatus.validDuration) {
50
+ console.log('检测到最近推送过,直接返回同步状态');
51
+ return res.json({
52
+ hasUpstream: true,
53
+ upstreamBranch: branchStatusCache.upstreamBranch || 'origin/main',
54
+ ahead: 0,
55
+ behind: 0
56
+ });
57
+ }
58
+
59
+ // 5秒缓存分支名,防止短时间内重复执行 git symbolic-ref / git rev-parse
60
+ const branchInfoCacheValid = !forceRefresh &&
61
+ branchStatusCache.currentBranch &&
62
+ branchStatusCache.upstreamBranch &&
63
+ (now - branchStatusCache.lastUpdate) < branchStatusCache.cacheTimeout;
64
+
65
+ let currentBranch, upstreamBranch;
66
+
67
+ if (branchInfoCacheValid) {
68
+ currentBranch = branchStatusCache.currentBranch;
69
+ upstreamBranch = branchStatusCache.upstreamBranch;
70
+ console.log(`使用5秒缓存的分支名: ${currentBranch} -> ${upstreamBranch}`);
71
+ } else {
72
+ // 直接读取,不再走5分钟长缓存
73
+ const { stdout: branchOut } = await execGitCommand('git symbolic-ref --short HEAD');
74
+ currentBranch = branchOut.trim();
75
+
76
+ const { stdout: upstreamOut } = await execGitCommand(
77
+ 'git rev-parse --abbrev-ref --symbolic-full-name @{u}',
78
+ { ignoreError: true }
79
+ );
80
+ upstreamBranch = upstreamOut.trim() || null;
81
+
82
+ if (!upstreamBranch) {
83
+ setBranchStatusCache({ currentBranch: null, upstreamBranch: null, lastUpdate: 0, cacheTimeout: 5000 });
84
+ return res.json({ hasUpstream: false, ahead: 0, behind: 0 });
85
+ }
86
+
87
+ setBranchStatusCache({ currentBranch, upstreamBranch, lastUpdate: now, cacheTimeout: 5000 });
88
+ }
89
+
90
+ const { stdout: aheadBehindOutput } = await execGitCommand(
91
+ `git rev-list --left-right --count ${currentBranch}...${upstreamBranch}`
92
+ );
93
+ const [ahead, behind] = aheadBehindOutput.trim().split('\t').map(Number);
94
+
95
+ res.json({ hasUpstream: true, upstreamBranch, ahead, behind });
96
+ } catch (error) {
97
+ console.error('获取分支状态失败:', error);
98
+ res.status(500).json({ error: error.message });
99
+ }
100
+ });
101
+ }
@@ -1,96 +1,110 @@
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
- }
1
+ // Copyright 2026 xz333221
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+ import * as vm from 'node:vm';
16
+
17
+ function isPlainObject(value) {
18
+ return Object.prototype.toString.call(value) === '[object Object]';
19
+ }
20
+
21
+ function normalizeOutputs(outputs) {
22
+ if (!isPlainObject(outputs)) return {};
23
+
24
+ const result = {};
25
+ const entries = Object.entries(outputs);
26
+
27
+ for (const [key, val] of entries) {
28
+ const safeKey = String(key || '').trim();
29
+ if (!safeKey) continue;
30
+ if (safeKey.length > 64) continue;
31
+
32
+ if (val === undefined || val === null) {
33
+ result[safeKey] = '';
34
+ continue;
35
+ }
36
+
37
+ if (typeof val === 'string') {
38
+ result[safeKey] = val;
39
+ continue;
40
+ }
41
+
42
+ if (typeof val === 'number' || typeof val === 'boolean') {
43
+ result[safeKey] = String(val);
44
+ continue;
45
+ }
46
+
47
+ try {
48
+ result[safeKey] = JSON.stringify(val);
49
+ } catch {
50
+ result[safeKey] = String(val);
51
+ }
52
+ }
53
+
54
+ return result;
55
+ }
56
+
57
+ export function registerCodeRoutes({ app }) {
58
+ app.post('/api/execute-code-node', async (req, res) => {
59
+ try {
60
+ const { script, input, param } = req.body || {};
61
+
62
+ if (!script || typeof script !== 'string' || !script.trim()) {
63
+ return res.status(400).json({ success: false, error: 'script 不能为空' });
64
+ }
65
+
66
+ const inputText = typeof input === 'string' ? input : (input === undefined || input === null ? '' : String(input));
67
+
68
+ const paramObj = (param && typeof param === 'object') ? param : undefined;
69
+
70
+ const wrapped = `"use strict";\n${script}\n`;
71
+
72
+ const sandbox = {
73
+ input: inputText,
74
+ param: paramObj,
75
+ main: undefined
76
+ };
77
+
78
+ const context = vm.createContext(sandbox, {
79
+ name: 'code-node-sandbox'
80
+ });
81
+
82
+ const vmScript = new vm.Script(wrapped, { filename: 'code-node.js' });
83
+
84
+ let result;
85
+ try {
86
+ result = vmScript.runInContext(context, { timeout: 800 });
87
+ } catch (e) {
88
+ return res.status(400).json({ success: false, error: e?.message || String(e) });
89
+ }
90
+
91
+ const mainFn = context.main || sandbox.main;
92
+ if (typeof mainFn !== 'function') {
93
+ return res.status(400).json({ success: false, error: '未找到 main(param) 函数' });
94
+ }
95
+
96
+ let finalResult = result;
97
+ try {
98
+ finalResult = mainFn(paramObj || {});
99
+ } catch (e) {
100
+ return res.status(400).json({ success: false, error: e?.message || String(e) });
101
+ }
102
+
103
+ const outputs = normalizeOutputs(finalResult);
104
+
105
+ return res.json({ success: true, outputs });
106
+ } catch (error) {
107
+ return res.status(500).json({ success: false, error: error?.message || String(error) });
108
+ }
109
+ });
110
+ }