zen-gitsync 2.6.4 → 2.6.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.
- package/package.json +2 -2
- package/src/ui/public/assets/index-D0xeSSyV.js +59 -0
- package/src/ui/public/assets/index-DmFxzTUu.css +1 -0
- package/src/ui/public/assets/vendor-CiRPTLQ-.js +68 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +384 -212
- package/src/ui/public/assets/index-42GyTYVk.css +0 -1
- package/src/ui/public/assets/index-C-nRMJvh.js +0 -59
- package/src/ui/public/assets/vendor-DtkI0iJs.js +0 -68
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 - Git同步工具</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-D0xeSSyV.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-CiRPTLQ-.js">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/vendor-D9qDBEE1.css">
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DmFxzTUu.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="app"></div>
|
package/src/ui/server/index.js
CHANGED
|
@@ -7,23 +7,15 @@ import open from 'open';
|
|
|
7
7
|
import config from '../../config.js';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import fs from 'fs/promises';
|
|
10
|
+
import fsSync from 'fs';
|
|
10
11
|
import os from 'os';
|
|
11
12
|
import { Server } from 'socket.io';
|
|
12
|
-
import chokidar from 'chokidar';
|
|
13
13
|
import { spawn } from 'child_process';
|
|
14
14
|
// import { exec } from 'child_process';
|
|
15
15
|
|
|
16
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
17
|
const __dirname = path.dirname(__filename);
|
|
18
18
|
const configManager = config; // 确保 configManager 可用
|
|
19
|
-
|
|
20
|
-
// 文件系统变动监控器
|
|
21
|
-
let watcher = null;
|
|
22
|
-
// 防抖计时器
|
|
23
|
-
let debounceTimer = null;
|
|
24
|
-
// 防抖延迟时间 (毫秒)
|
|
25
|
-
const DEBOUNCE_DELAY = 1000;
|
|
26
|
-
|
|
27
19
|
// 分支状态缓存
|
|
28
20
|
let branchStatusCache = {
|
|
29
21
|
currentBranch: null,
|
|
@@ -661,12 +653,6 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
661
653
|
console.warn('初始化项目配置失败:', e?.message || e);
|
|
662
654
|
}
|
|
663
655
|
|
|
664
|
-
// 关闭旧的文件监控
|
|
665
|
-
if (watcher) {
|
|
666
|
-
watcher.close().catch(err => console.error('关闭旧监控器失败:', err));
|
|
667
|
-
watcher = null;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
656
|
// 通知所有旧房间的客户端项目已切换
|
|
671
657
|
io.to(projectRoomId).emit('project_changed', {
|
|
672
658
|
oldProjectPath: currentProjectPath,
|
|
@@ -694,11 +680,6 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
694
680
|
projectRoomId = newProjectRoomId;
|
|
695
681
|
isGitRepo = false;
|
|
696
682
|
|
|
697
|
-
if (watcher) {
|
|
698
|
-
watcher.close().catch(err => console.error('关闭监控器失败:', err));
|
|
699
|
-
watcher = null;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
683
|
// 通知所有旧房间的客户端项目已切换
|
|
703
684
|
io.to(projectRoomId).emit('project_changed', {
|
|
704
685
|
oldProjectPath: currentProjectPath,
|
|
@@ -1446,6 +1427,53 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
1446
1427
|
}
|
|
1447
1428
|
})
|
|
1448
1429
|
|
|
1430
|
+
// 置顶模板
|
|
1431
|
+
app.post('/api/config/pin-template', express.json(), async (req, res) => {
|
|
1432
|
+
try {
|
|
1433
|
+
const { template, type } = req.body
|
|
1434
|
+
|
|
1435
|
+
if (!template || !type) {
|
|
1436
|
+
return res.status(400).json({ success: false, error: '缺少必要参数' })
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
const config = await configManager.loadConfig()
|
|
1440
|
+
|
|
1441
|
+
if (type === 'description') {
|
|
1442
|
+
if (config.descriptionTemplates) {
|
|
1443
|
+
// 删除原位置的模板
|
|
1444
|
+
config.descriptionTemplates = config.descriptionTemplates.filter(t => t !== template)
|
|
1445
|
+
// 添加到第一位
|
|
1446
|
+
config.descriptionTemplates.unshift(template)
|
|
1447
|
+
await configManager.saveConfig(config)
|
|
1448
|
+
} else {
|
|
1449
|
+
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
1450
|
+
}
|
|
1451
|
+
} else if (type === 'scope') {
|
|
1452
|
+
if (config.scopeTemplates) {
|
|
1453
|
+
config.scopeTemplates = config.scopeTemplates.filter(t => t !== template)
|
|
1454
|
+
config.scopeTemplates.unshift(template)
|
|
1455
|
+
await configManager.saveConfig(config)
|
|
1456
|
+
} else {
|
|
1457
|
+
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
1458
|
+
}
|
|
1459
|
+
} else if (type === 'message') {
|
|
1460
|
+
if (config.messageTemplates) {
|
|
1461
|
+
config.messageTemplates = config.messageTemplates.filter(t => t !== template)
|
|
1462
|
+
config.messageTemplates.unshift(template)
|
|
1463
|
+
await configManager.saveConfig(config)
|
|
1464
|
+
} else {
|
|
1465
|
+
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
1466
|
+
}
|
|
1467
|
+
} else {
|
|
1468
|
+
return res.status(400).json({ success: false, error: '不支持的模板类型' })
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
res.json({ success: true })
|
|
1472
|
+
} catch (error) {
|
|
1473
|
+
res.status(500).json({ success: false, error: error.message })
|
|
1474
|
+
}
|
|
1475
|
+
})
|
|
1476
|
+
|
|
1449
1477
|
// 保存自定义命令
|
|
1450
1478
|
app.post('/api/config/save-custom-command', express.json(), async (req, res) => {
|
|
1451
1479
|
try {
|
|
@@ -3369,7 +3397,8 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3369
3397
|
path: dir,
|
|
3370
3398
|
relativePath: relativePath || '.',
|
|
3371
3399
|
name: packageData.name || path.basename(dir),
|
|
3372
|
-
scripts: packageData.scripts
|
|
3400
|
+
scripts: packageData.scripts,
|
|
3401
|
+
version: packageData.version || '0.0.0'
|
|
3373
3402
|
});
|
|
3374
3403
|
return true;
|
|
3375
3404
|
}
|
|
@@ -3555,6 +3584,340 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3555
3584
|
});
|
|
3556
3585
|
}
|
|
3557
3586
|
});
|
|
3587
|
+
|
|
3588
|
+
// API: 更新npm版本号
|
|
3589
|
+
app.post('/api/update-npm-version', async (req, res) => {
|
|
3590
|
+
try {
|
|
3591
|
+
const { packagePath, versionType } = req.body;
|
|
3592
|
+
|
|
3593
|
+
if (!packagePath || !versionType) {
|
|
3594
|
+
return res.status(400).json({
|
|
3595
|
+
success: false,
|
|
3596
|
+
error: '缺少必要参数: packagePath, versionType'
|
|
3597
|
+
});
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3600
|
+
// 确保路径指向package.json文件
|
|
3601
|
+
let packageJsonPath = path.resolve(packagePath);
|
|
3602
|
+
if (fsSync.existsSync(packageJsonPath) && fsSync.statSync(packageJsonPath).isDirectory()) {
|
|
3603
|
+
packageJsonPath = path.join(packageJsonPath, 'package.json');
|
|
3604
|
+
}
|
|
3605
|
+
|
|
3606
|
+
// 检查文件是否存在
|
|
3607
|
+
if (!fsSync.existsSync(packageJsonPath)) {
|
|
3608
|
+
return res.status(404).json({
|
|
3609
|
+
success: false,
|
|
3610
|
+
error: '找不到package.json文件'
|
|
3611
|
+
});
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3614
|
+
// 读取package.json
|
|
3615
|
+
const packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, 'utf8'));
|
|
3616
|
+
|
|
3617
|
+
if (!packageJson.version) {
|
|
3618
|
+
return res.status(400).json({
|
|
3619
|
+
success: false,
|
|
3620
|
+
error: 'package.json中没有version字段'
|
|
3621
|
+
});
|
|
3622
|
+
}
|
|
3623
|
+
|
|
3624
|
+
const oldVersion = packageJson.version;
|
|
3625
|
+
const versionParts = oldVersion.split('.').map(Number);
|
|
3626
|
+
|
|
3627
|
+
// 根据类型增加版本号
|
|
3628
|
+
switch (versionType) {
|
|
3629
|
+
case 'major':
|
|
3630
|
+
versionParts[0]++;
|
|
3631
|
+
versionParts[1] = 0;
|
|
3632
|
+
versionParts[2] = 0;
|
|
3633
|
+
break;
|
|
3634
|
+
case 'minor':
|
|
3635
|
+
versionParts[1]++;
|
|
3636
|
+
versionParts[2] = 0;
|
|
3637
|
+
break;
|
|
3638
|
+
case 'patch':
|
|
3639
|
+
versionParts[2]++;
|
|
3640
|
+
break;
|
|
3641
|
+
default:
|
|
3642
|
+
return res.status(400).json({
|
|
3643
|
+
success: false,
|
|
3644
|
+
error: '无效的版本类型,必须是 major, minor 或 patch'
|
|
3645
|
+
});
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
const newVersion = versionParts.join('.');
|
|
3649
|
+
packageJson.version = newVersion;
|
|
3650
|
+
|
|
3651
|
+
// 写回文件
|
|
3652
|
+
fsSync.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8');
|
|
3653
|
+
|
|
3654
|
+
console.log(`已更新npm版本号: ${oldVersion} → ${newVersion} (${packagePath})`);
|
|
3655
|
+
|
|
3656
|
+
res.json({
|
|
3657
|
+
success: true,
|
|
3658
|
+
oldVersion,
|
|
3659
|
+
newVersion
|
|
3660
|
+
});
|
|
3661
|
+
} catch (error) {
|
|
3662
|
+
console.error('更新版本号失败:', error);
|
|
3663
|
+
res.status(500).json({
|
|
3664
|
+
success: false,
|
|
3665
|
+
error: `更新版本号失败: ${error.message}`
|
|
3666
|
+
});
|
|
3667
|
+
}
|
|
3668
|
+
});
|
|
3669
|
+
|
|
3670
|
+
// API: 添加npm脚本
|
|
3671
|
+
app.post('/api/add-npm-script', async (req, res) => {
|
|
3672
|
+
try {
|
|
3673
|
+
const { packagePath, scriptName, scriptCommand } = req.body;
|
|
3674
|
+
|
|
3675
|
+
if (!packagePath || !scriptName || !scriptCommand) {
|
|
3676
|
+
return res.status(400).json({
|
|
3677
|
+
success: false,
|
|
3678
|
+
error: '缺少必要参数: packagePath, scriptName, scriptCommand'
|
|
3679
|
+
});
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3682
|
+
// 确保路径指向package.json文件
|
|
3683
|
+
let packageJsonPath = path.resolve(packagePath);
|
|
3684
|
+
if (fsSync.existsSync(packageJsonPath) && fsSync.statSync(packageJsonPath).isDirectory()) {
|
|
3685
|
+
packageJsonPath = path.join(packageJsonPath, 'package.json');
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
// 检查文件是否存在
|
|
3689
|
+
if (!fsSync.existsSync(packageJsonPath)) {
|
|
3690
|
+
return res.status(404).json({
|
|
3691
|
+
success: false,
|
|
3692
|
+
error: '找不到package.json文件'
|
|
3693
|
+
});
|
|
3694
|
+
}
|
|
3695
|
+
|
|
3696
|
+
// 读取package.json
|
|
3697
|
+
const packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, 'utf8'));
|
|
3698
|
+
|
|
3699
|
+
// 确保scripts对象存在
|
|
3700
|
+
if (!packageJson.scripts) {
|
|
3701
|
+
packageJson.scripts = {};
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3704
|
+
// 检查脚本是否已存在
|
|
3705
|
+
if (packageJson.scripts[scriptName]) {
|
|
3706
|
+
return res.status(400).json({
|
|
3707
|
+
success: false,
|
|
3708
|
+
error: `脚本 "${scriptName}" 已存在`
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3712
|
+
// 添加脚本
|
|
3713
|
+
packageJson.scripts[scriptName] = scriptCommand;
|
|
3714
|
+
|
|
3715
|
+
// 写回文件(保持格式化)
|
|
3716
|
+
fsSync.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8');
|
|
3717
|
+
|
|
3718
|
+
console.log(`已添加npm脚本: ${scriptName} = ${scriptCommand} (${packagePath})`);
|
|
3719
|
+
|
|
3720
|
+
res.json({
|
|
3721
|
+
success: true,
|
|
3722
|
+
scriptName,
|
|
3723
|
+
scriptCommand
|
|
3724
|
+
});
|
|
3725
|
+
} catch (error) {
|
|
3726
|
+
console.error('添加npm脚本失败:', error);
|
|
3727
|
+
res.status(500).json({
|
|
3728
|
+
success: false,
|
|
3729
|
+
error: `添加npm脚本失败: ${error.message}`
|
|
3730
|
+
});
|
|
3731
|
+
}
|
|
3732
|
+
});
|
|
3733
|
+
|
|
3734
|
+
// API: 更新npm脚本
|
|
3735
|
+
app.post('/api/update-npm-script', async (req, res) => {
|
|
3736
|
+
try {
|
|
3737
|
+
const { packagePath, scriptName, scriptCommand, oldScriptName } = req.body;
|
|
3738
|
+
|
|
3739
|
+
if (!packagePath || !scriptName || !scriptCommand) {
|
|
3740
|
+
return res.status(400).json({
|
|
3741
|
+
success: false,
|
|
3742
|
+
error: '缺少必要参数: packagePath, scriptName, scriptCommand'
|
|
3743
|
+
});
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3746
|
+
// 确保路径指向package.json文件
|
|
3747
|
+
let packageJsonPath = path.resolve(packagePath);
|
|
3748
|
+
if (fsSync.existsSync(packageJsonPath) && fsSync.statSync(packageJsonPath).isDirectory()) {
|
|
3749
|
+
packageJsonPath = path.join(packageJsonPath, 'package.json');
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
// 检查文件是否存在
|
|
3753
|
+
if (!fsSync.existsSync(packageJsonPath)) {
|
|
3754
|
+
return res.status(404).json({
|
|
3755
|
+
success: false,
|
|
3756
|
+
error: '找不到package.json文件'
|
|
3757
|
+
});
|
|
3758
|
+
}
|
|
3759
|
+
|
|
3760
|
+
// 读取package.json
|
|
3761
|
+
const packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, 'utf8'));
|
|
3762
|
+
|
|
3763
|
+
// 确保scripts对象存在
|
|
3764
|
+
if (!packageJson.scripts) {
|
|
3765
|
+
packageJson.scripts = {};
|
|
3766
|
+
}
|
|
3767
|
+
|
|
3768
|
+
// 如果改了脚本名称,删除旧的
|
|
3769
|
+
if (oldScriptName && oldScriptName !== scriptName) {
|
|
3770
|
+
delete packageJson.scripts[oldScriptName];
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
// 更新脚本
|
|
3774
|
+
packageJson.scripts[scriptName] = scriptCommand;
|
|
3775
|
+
|
|
3776
|
+
// 写回文件
|
|
3777
|
+
fsSync.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8');
|
|
3778
|
+
|
|
3779
|
+
console.log(`已更新npm脚本: ${scriptName} = ${scriptCommand} (${packagePath})`);
|
|
3780
|
+
|
|
3781
|
+
res.json({
|
|
3782
|
+
success: true,
|
|
3783
|
+
scriptName,
|
|
3784
|
+
scriptCommand
|
|
3785
|
+
});
|
|
3786
|
+
} catch (error) {
|
|
3787
|
+
console.error('更新npm脚本失败:', error);
|
|
3788
|
+
res.status(500).json({
|
|
3789
|
+
success: false,
|
|
3790
|
+
error: `更新npm脚本失败: ${error.message}`
|
|
3791
|
+
});
|
|
3792
|
+
}
|
|
3793
|
+
});
|
|
3794
|
+
|
|
3795
|
+
// API: 删除npm脚本
|
|
3796
|
+
app.post('/api/delete-npm-script', async (req, res) => {
|
|
3797
|
+
try {
|
|
3798
|
+
const { packagePath, scriptName } = req.body;
|
|
3799
|
+
|
|
3800
|
+
if (!packagePath || !scriptName) {
|
|
3801
|
+
return res.status(400).json({
|
|
3802
|
+
success: false,
|
|
3803
|
+
error: '缺少必要参数: packagePath, scriptName'
|
|
3804
|
+
});
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3807
|
+
// 确保路径指向package.json文件
|
|
3808
|
+
let packageJsonPath = path.resolve(packagePath);
|
|
3809
|
+
if (fsSync.existsSync(packageJsonPath) && fsSync.statSync(packageJsonPath).isDirectory()) {
|
|
3810
|
+
packageJsonPath = path.join(packageJsonPath, 'package.json');
|
|
3811
|
+
}
|
|
3812
|
+
|
|
3813
|
+
// 检查文件是否存在
|
|
3814
|
+
if (!fsSync.existsSync(packageJsonPath)) {
|
|
3815
|
+
return res.status(404).json({
|
|
3816
|
+
success: false,
|
|
3817
|
+
error: '找不到package.json文件'
|
|
3818
|
+
});
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
// 读取package.json
|
|
3822
|
+
const packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, 'utf8'));
|
|
3823
|
+
|
|
3824
|
+
// 检查scripts对象和脚本是否存在
|
|
3825
|
+
if (!packageJson.scripts || !packageJson.scripts[scriptName]) {
|
|
3826
|
+
return res.status(404).json({
|
|
3827
|
+
success: false,
|
|
3828
|
+
error: `脚本 "${scriptName}" 不存在`
|
|
3829
|
+
});
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
// 删除脚本
|
|
3833
|
+
delete packageJson.scripts[scriptName];
|
|
3834
|
+
|
|
3835
|
+
// 写回文件
|
|
3836
|
+
fsSync.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8');
|
|
3837
|
+
|
|
3838
|
+
console.log(`已删除npm脚本: ${scriptName} (${packagePath})`);
|
|
3839
|
+
|
|
3840
|
+
res.json({
|
|
3841
|
+
success: true,
|
|
3842
|
+
scriptName
|
|
3843
|
+
});
|
|
3844
|
+
} catch (error) {
|
|
3845
|
+
console.error('删除npm脚本失败:', error);
|
|
3846
|
+
res.status(500).json({
|
|
3847
|
+
success: false,
|
|
3848
|
+
error: `删除npm脚本失败: ${error.message}`
|
|
3849
|
+
});
|
|
3850
|
+
}
|
|
3851
|
+
});
|
|
3852
|
+
|
|
3853
|
+
// API: 置顶npm脚本
|
|
3854
|
+
app.post('/api/pin-npm-script', async (req, res) => {
|
|
3855
|
+
try {
|
|
3856
|
+
const { packagePath, scriptName } = req.body;
|
|
3857
|
+
|
|
3858
|
+
if (!packagePath || !scriptName) {
|
|
3859
|
+
return res.status(400).json({
|
|
3860
|
+
success: false,
|
|
3861
|
+
error: '缺少必要参数: packagePath, scriptName'
|
|
3862
|
+
});
|
|
3863
|
+
}
|
|
3864
|
+
|
|
3865
|
+
// 确保路径指向package.json文件
|
|
3866
|
+
let packageJsonPath = path.resolve(packagePath);
|
|
3867
|
+
if (fsSync.existsSync(packageJsonPath) && fsSync.statSync(packageJsonPath).isDirectory()) {
|
|
3868
|
+
packageJsonPath = path.join(packageJsonPath, 'package.json');
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3871
|
+
// 检查文件是否存在
|
|
3872
|
+
if (!fsSync.existsSync(packageJsonPath)) {
|
|
3873
|
+
return res.status(404).json({
|
|
3874
|
+
success: false,
|
|
3875
|
+
error: '找不到package.json文件'
|
|
3876
|
+
});
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3879
|
+
// 读取package.json
|
|
3880
|
+
const packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, 'utf8'));
|
|
3881
|
+
|
|
3882
|
+
// 检查scripts对象和脚本是否存在
|
|
3883
|
+
if (!packageJson.scripts || !packageJson.scripts[scriptName]) {
|
|
3884
|
+
return res.status(404).json({
|
|
3885
|
+
success: false,
|
|
3886
|
+
error: `脚本 "${scriptName}" 不存在`
|
|
3887
|
+
});
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
// 保存要置顶的脚本内容
|
|
3891
|
+
const scriptCommand = packageJson.scripts[scriptName];
|
|
3892
|
+
|
|
3893
|
+
// 删除该脚本
|
|
3894
|
+
delete packageJson.scripts[scriptName];
|
|
3895
|
+
|
|
3896
|
+
// 创建新的scripts对象,将置顶脚本放在最前面
|
|
3897
|
+
const newScripts = {
|
|
3898
|
+
[scriptName]: scriptCommand,
|
|
3899
|
+
...packageJson.scripts
|
|
3900
|
+
};
|
|
3901
|
+
|
|
3902
|
+
packageJson.scripts = newScripts;
|
|
3903
|
+
|
|
3904
|
+
// 写回文件
|
|
3905
|
+
fsSync.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8');
|
|
3906
|
+
|
|
3907
|
+
console.log(`已置顶npm脚本: ${scriptName} (${packagePath})`);
|
|
3908
|
+
|
|
3909
|
+
res.json({
|
|
3910
|
+
success: true,
|
|
3911
|
+
scriptName
|
|
3912
|
+
});
|
|
3913
|
+
} catch (error) {
|
|
3914
|
+
console.error('置顶npm脚本失败:', error);
|
|
3915
|
+
res.status(500).json({
|
|
3916
|
+
success: false,
|
|
3917
|
+
error: `置顶npm脚本失败: ${error.message}`
|
|
3918
|
+
});
|
|
3919
|
+
}
|
|
3920
|
+
});
|
|
3558
3921
|
|
|
3559
3922
|
// Socket.io 实时更新
|
|
3560
3923
|
io.on('connection', (socket) => {
|
|
@@ -3571,34 +3934,6 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3571
3934
|
const history = getCommandHistory();
|
|
3572
3935
|
socket.emit('initial_command_history', { history });
|
|
3573
3936
|
|
|
3574
|
-
// 发送项目信息给客户端
|
|
3575
|
-
socket.emit('project_info', {
|
|
3576
|
-
projectPath: currentProjectPath,
|
|
3577
|
-
projectRoomId: projectRoomId
|
|
3578
|
-
});
|
|
3579
|
-
|
|
3580
|
-
// 客户端可以请求开始/停止监控
|
|
3581
|
-
socket.on('start_monitoring', () => {
|
|
3582
|
-
if (!watcher) {
|
|
3583
|
-
initFileSystemWatcher().catch(err => console.error('[文件监控] 初始化失败:', err));
|
|
3584
|
-
socket.emit('monitoring_status', { active: true });
|
|
3585
|
-
}
|
|
3586
|
-
});
|
|
3587
|
-
|
|
3588
|
-
// 处理客户端加入新房间的请求
|
|
3589
|
-
socket.on('join_room', (roomId) => {
|
|
3590
|
-
socket.join(roomId);
|
|
3591
|
-
console.log(`客户端 ${socket.id} 已加入房间: ${roomId}`);
|
|
3592
|
-
});
|
|
3593
|
-
|
|
3594
|
-
socket.on('stop_monitoring', () => {
|
|
3595
|
-
if (watcher) {
|
|
3596
|
-
watcher.close().catch(err => console.error('关闭监控器失败:', err));
|
|
3597
|
-
watcher = null;
|
|
3598
|
-
socket.emit('monitoring_status', { active: false });
|
|
3599
|
-
}
|
|
3600
|
-
});
|
|
3601
|
-
|
|
3602
3937
|
// 请求完整命令历史
|
|
3603
3938
|
socket.on('request_full_history', () => {
|
|
3604
3939
|
const fullHistory = getCommandHistory();
|
|
@@ -3618,158 +3953,6 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3618
3953
|
});
|
|
3619
3954
|
});
|
|
3620
3955
|
|
|
3621
|
-
// 读取并解析.gitignore文件
|
|
3622
|
-
async function parseGitignore(projectPath) {
|
|
3623
|
-
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
3624
|
-
const ignorePatterns = [
|
|
3625
|
-
/(^|[\/\\])\../, // 始终忽略.开头的文件(除了.gitignore本身)
|
|
3626
|
-
'**/.git/**', // 始终忽略.git目录
|
|
3627
|
-
|
|
3628
|
-
// 额外排除常见的编译产物和大文件,减少监控开销
|
|
3629
|
-
'**/*.umd.cjs', // UMD打包文件
|
|
3630
|
-
'**/*.min.js', // 压缩JS文件
|
|
3631
|
-
'**/*.bundle.js', // Webpack打包文件
|
|
3632
|
-
'**/*.dist.js', // 构建产物
|
|
3633
|
-
'**/*.prod.js', // 生产环境文件
|
|
3634
|
-
'**/lib/**', // 通常是编译产物
|
|
3635
|
-
'**/es/**', // ES模块编译产物
|
|
3636
|
-
'**/esm/**', // ES模块编译产物
|
|
3637
|
-
'**/*.map', // Source map文件
|
|
3638
|
-
'**/*.chunk.js', // 代码分割chunk
|
|
3639
|
-
];
|
|
3640
|
-
|
|
3641
|
-
try {
|
|
3642
|
-
const gitignoreContent = await fs.readFile(gitignorePath, 'utf8');
|
|
3643
|
-
const lines = gitignoreContent.split('\n');
|
|
3644
|
-
let validRules = 0;
|
|
3645
|
-
|
|
3646
|
-
for (let line of lines) {
|
|
3647
|
-
line = line.trim();
|
|
3648
|
-
|
|
3649
|
-
// 跳过空行和注释
|
|
3650
|
-
if (!line || line.startsWith('#')) continue;
|
|
3651
|
-
|
|
3652
|
-
// 移除行尾的空格
|
|
3653
|
-
line = line.replace(/\s+$/, '');
|
|
3654
|
-
|
|
3655
|
-
// 跳过否定规则(chokidar不支持否定规则,这些规则会被忽略)
|
|
3656
|
-
if (line.startsWith('!')) {
|
|
3657
|
-
continue;
|
|
3658
|
-
}
|
|
3659
|
-
|
|
3660
|
-
// 将gitignore规则转换为glob模式
|
|
3661
|
-
let pattern;
|
|
3662
|
-
|
|
3663
|
-
// 如果以/开头,表示从根目录开始匹配
|
|
3664
|
-
if (line.startsWith('/')) {
|
|
3665
|
-
pattern = line.substring(1);
|
|
3666
|
-
// 如果是目录,添加/**后缀
|
|
3667
|
-
if (!pattern.includes('*') && !pattern.includes('.')) {
|
|
3668
|
-
ignorePatterns.push(pattern);
|
|
3669
|
-
ignorePatterns.push(pattern + '/**');
|
|
3670
|
-
} else {
|
|
3671
|
-
ignorePatterns.push(pattern);
|
|
3672
|
-
}
|
|
3673
|
-
} else if (line.endsWith('/')) {
|
|
3674
|
-
// 明确的目录规则
|
|
3675
|
-
const dirName = line.slice(0, -1);
|
|
3676
|
-
ignorePatterns.push('**/' + dirName);
|
|
3677
|
-
ignorePatterns.push('**/' + dirName + '/**');
|
|
3678
|
-
} else {
|
|
3679
|
-
// 文件或目录规则
|
|
3680
|
-
// 如果包含*通配符,直接使用
|
|
3681
|
-
if (line.includes('*')) {
|
|
3682
|
-
ignorePatterns.push('**/' + line);
|
|
3683
|
-
} else {
|
|
3684
|
-
// 既匹配文件也匹配目录
|
|
3685
|
-
ignorePatterns.push('**/' + line);
|
|
3686
|
-
ignorePatterns.push('**/' + line + '/**');
|
|
3687
|
-
}
|
|
3688
|
-
}
|
|
3689
|
-
|
|
3690
|
-
validRules++;
|
|
3691
|
-
}
|
|
3692
|
-
|
|
3693
|
-
console.log(`[文件监控] 从.gitignore读取了 ${validRules} 条有效的忽略规则`);
|
|
3694
|
-
} catch (error) {
|
|
3695
|
-
// .gitignore不存在或读取失败,使用默认规则
|
|
3696
|
-
console.log('[文件监控] 未找到.gitignore,使用默认忽略规则');
|
|
3697
|
-
ignorePatterns.push(
|
|
3698
|
-
'**/node_modules/**',
|
|
3699
|
-
'**/dist/**',
|
|
3700
|
-
'**/build/**',
|
|
3701
|
-
'**/coverage/**',
|
|
3702
|
-
'**/.nuxt/**',
|
|
3703
|
-
'**/.next/**',
|
|
3704
|
-
'**/out/**',
|
|
3705
|
-
'**/*.log'
|
|
3706
|
-
);
|
|
3707
|
-
}
|
|
3708
|
-
|
|
3709
|
-
return ignorePatterns;
|
|
3710
|
-
}
|
|
3711
|
-
|
|
3712
|
-
// 初始化文件系统监控
|
|
3713
|
-
async function initFileSystemWatcher() {
|
|
3714
|
-
// 停止已有的监控器
|
|
3715
|
-
if (watcher) {
|
|
3716
|
-
watcher.close().catch(err => console.error('关闭旧监控器失败:', err));
|
|
3717
|
-
}
|
|
3718
|
-
|
|
3719
|
-
try {
|
|
3720
|
-
// 获取当前工作目录
|
|
3721
|
-
const currentDir = process.cwd();
|
|
3722
|
-
|
|
3723
|
-
console.log(`初始化文件系统监控器,路径: ${currentDir}`);
|
|
3724
|
-
|
|
3725
|
-
// 检查是否是Git仓库
|
|
3726
|
-
if (!isGitRepo) {
|
|
3727
|
-
console.log('当前目录不是Git仓库,不启动监控');
|
|
3728
|
-
return;
|
|
3729
|
-
}
|
|
3730
|
-
|
|
3731
|
-
const watcherStartTime = Date.now();
|
|
3732
|
-
console.log('[文件监控] 开始初始化监控器...');
|
|
3733
|
-
|
|
3734
|
-
// 从.gitignore读取忽略规则
|
|
3735
|
-
const ignorePatterns = await parseGitignore(currentDir);
|
|
3736
|
-
|
|
3737
|
-
// 使用chokidar监控文件变动
|
|
3738
|
-
watcher = chokidar.watch(currentDir, {
|
|
3739
|
-
ignored: ignorePatterns,
|
|
3740
|
-
persistent: true,
|
|
3741
|
-
ignoreInitial: true, // 忽略初始扫描时的文件
|
|
3742
|
-
depth: 10, // 限制扫描深度,避免过深的目录结构
|
|
3743
|
-
awaitWriteFinish: {
|
|
3744
|
-
stabilityThreshold: 300, // 等待文件写入完成的时间
|
|
3745
|
-
pollInterval: 100 // 轮询间隔
|
|
3746
|
-
}
|
|
3747
|
-
});
|
|
3748
|
-
|
|
3749
|
-
// 合并所有变动事件到一个处理程序
|
|
3750
|
-
const events = ['add', 'change', 'unlink'];
|
|
3751
|
-
events.forEach(event => {
|
|
3752
|
-
watcher.on(event, path => {
|
|
3753
|
-
console.log(`检测到文件变动 [${event}]: ${path}`);
|
|
3754
|
-
debouncedNotifyChanges();
|
|
3755
|
-
});
|
|
3756
|
-
});
|
|
3757
|
-
|
|
3758
|
-
watcher.on('ready', () => {
|
|
3759
|
-
const initTime = Date.now() - watcherStartTime;
|
|
3760
|
-
console.log(`[文件监控] 监控器初始化完成,耗时 ${initTime}ms`);
|
|
3761
|
-
});
|
|
3762
|
-
|
|
3763
|
-
watcher.on('error', error => {
|
|
3764
|
-
console.error('[文件监控] 监控错误:', error);
|
|
3765
|
-
});
|
|
3766
|
-
|
|
3767
|
-
console.log('[文件监控] 监控器已启动(异步初始化中...)');
|
|
3768
|
-
} catch (error) {
|
|
3769
|
-
console.error('启动文件监控失败:', error);
|
|
3770
|
-
}
|
|
3771
|
-
}
|
|
3772
|
-
|
|
3773
3956
|
// 获取并广播Git状态 (优化版本 - 只获取porcelain格式)
|
|
3774
3957
|
async function getAndBroadcastStatus() {
|
|
3775
3958
|
try {
|
|
@@ -3801,17 +3984,6 @@ async function startUIServer(noOpen = false, savePort = false) {
|
|
|
3801
3984
|
}
|
|
3802
3985
|
}
|
|
3803
3986
|
|
|
3804
|
-
// 防抖处理函数
|
|
3805
|
-
function debouncedNotifyChanges() {
|
|
3806
|
-
if (debounceTimer) {
|
|
3807
|
-
clearTimeout(debounceTimer);
|
|
3808
|
-
}
|
|
3809
|
-
|
|
3810
|
-
debounceTimer = setTimeout(() => {
|
|
3811
|
-
getAndBroadcastStatus();
|
|
3812
|
-
}, DEBOUNCE_DELAY);
|
|
3813
|
-
}
|
|
3814
|
-
|
|
3815
3987
|
// 检查当前目录是否是Git仓库
|
|
3816
3988
|
let isGitRepo = false;
|
|
3817
3989
|
try {
|