@sciagent/cli 1.3.61 → 1.3.63

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/bin/sciagent.js CHANGED
@@ -25,7 +25,7 @@ const https = require('https');
25
25
  const http = require('http');
26
26
 
27
27
  // 当前版本号 - 与 postinstall.js 和 package.json 保持同步
28
- const CURRENT_VERSION = '1.3.61';
28
+ const CURRENT_VERSION = '1.3.63';
29
29
 
30
30
  // Releases 下载源配置(优先级从高到低)
31
31
  // JihuLab 通用包仓库(国内 CDN,速度快)作为主源
@@ -120,16 +120,42 @@ function applyPendingUpdate(installDir) {
120
120
  try {
121
121
  if (process.platform === 'win32') {
122
122
  // Windows: 使用 PowerShell
123
- const tmpScript = path.join(os.tmpdir(), 'sciagent-apply-update.ps1');
123
+ // 注意:脚本必须以 UTF-8 BOM 写入——PowerShell 5.1 对无 BOM 的
124
+ // UTF-8 脚本按系统 ANSI/GBK 解码,中文安装路径会乱码导致复制失败。
125
+ const tmpScript = path.join(os.tmpdir(), `sciagent-apply-update-${process.pid}.ps1`);
126
+ const logFile = path.join(installDir, 'update-apply.log');
127
+ const esc = (s) => String(s).replace(/'/g, "''");
124
128
  const scriptContent = [
125
- `$target = "${targetPath}"`,
126
- `Copy-Item -Path "${tempPath}" -Destination "$target" -Force`,
127
- 'if (Test-Path $target) { Write-Host "OK" } else { Write-Error "Copy failed"; exit 1 }'
129
+ `$ErrorActionPreference = 'Stop'`,
130
+ `$log = '${esc(logFile)}'`,
131
+ `function Write-Log([string]$msg) { try { $line = '[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg; Add-Content -Path $log -Value $line -Encoding UTF8 } catch {} }`,
132
+ `Write-Log 'npm applyPendingUpdate: helper started'`,
133
+ `try {`,
134
+ ` $target = '${esc(targetPath)}'`,
135
+ // 轮询等待旧 exe 解锁(最多 60s),避免直接覆盖运行中 exe 报
136
+ // "与运行的进程共享" / EPERM
137
+ ` if (Test-Path $target) {`,
138
+ ` $deadline = (Get-Date).AddSeconds(60)`,
139
+ ` $unlocked = $false`,
140
+ ` while ((Get-Date) -lt $deadline) {`,
141
+ ` try { $fs = [System.IO.File]::Open($target, 'Open', 'ReadWrite', 'None'); $fs.Close(); $unlocked = $true; break } catch { Start-Sleep -Milliseconds 500 }`,
142
+ ` }`,
143
+ ` if (-not $unlocked) { throw ('Timed out waiting for target to unlock: ' + $target) }`,
144
+ ` }`,
145
+ ` Copy-Item -Path '${esc(tempPath)}' -Destination $target -Force`,
146
+ ` if (-not (Test-Path $target)) { throw 'Copy failed' }`,
147
+ ` Write-Log 'npm applyPendingUpdate: replace OK'`,
148
+ ` Write-Host 'OK'`,
149
+ `} catch {`,
150
+ ` Write-Log ('npm applyPendingUpdate FAILED: ' + $_.Exception.ToString())`,
151
+ ` Write-Host ('FAILED: ' + $_.Exception.Message)`,
152
+ ` exit 1`,
153
+ `}`,
128
154
  ].join('\r\n');
129
- fs.writeFileSync(tmpScript, scriptContent, 'utf8');
155
+ fs.writeFileSync(tmpScript, '\ufeff' + scriptContent, 'utf8');
130
156
  try {
131
157
  execSync(`powershell -NoProfile -ExecutionPolicy Bypass -File "${tmpScript}"`, {
132
- stdio: 'pipe', timeout: 30000
158
+ stdio: 'pipe', timeout: 90000
133
159
  });
134
160
  } finally {
135
161
  try { fs.unlinkSync(tmpScript); } catch (e) {}
@@ -778,16 +804,40 @@ function downloadBinary(platform, arch, version) {
778
804
  // 尝试替换目标文件
779
805
  try {
780
806
  if (platform === 'win32') {
781
- const tmpScript = path.join(os.tmpdir(), 'sciagent-replace.ps1');
807
+ const tmpScript = path.join(os.tmpdir(), `sciagent-replace-${process.pid}.ps1`);
808
+ const logFile = path.join(installDir, 'update-apply.log');
809
+ const esc = (s) => String(s).replace(/'/g, "''");
810
+ // 脚本必须以 UTF-8 BOM 写入(PowerShell 5.1 无 BOM 按 ANSI/GBK
811
+ // 解码,中文路径乱码);并轮询等待运行中 exe 解锁后再覆盖。
782
812
  const scriptContent = [
783
- `$target = "${targetPath}"`,
784
- `Copy-Item -Path "${tempPath}" -Destination "$target" -Force`,
785
- 'if (Test-Path $target) { Write-Host "OK" } else { Write-Error "Copy failed"; exit 1 }'
813
+ `$ErrorActionPreference = 'Stop'`,
814
+ `$log = '${esc(logFile)}'`,
815
+ `function Write-Log([string]$msg) { try { $line = '[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg; Add-Content -Path $log -Value $line -Encoding UTF8 } catch {} }`,
816
+ `Write-Log 'downloadBinary replace: helper started'`,
817
+ `try {`,
818
+ ` $target = '${esc(targetPath)}'`,
819
+ ` if (Test-Path $target) {`,
820
+ ` $deadline = (Get-Date).AddSeconds(60)`,
821
+ ` $unlocked = $false`,
822
+ ` while ((Get-Date) -lt $deadline) {`,
823
+ ` try { $fs = [System.IO.File]::Open($target, 'Open', 'ReadWrite', 'None'); $fs.Close(); $unlocked = $true; break } catch { Start-Sleep -Milliseconds 500 }`,
824
+ ` }`,
825
+ ` if (-not $unlocked) { throw ('Timed out waiting for target to unlock: ' + $target) }`,
826
+ ` }`,
827
+ ` Copy-Item -Path '${esc(tempPath)}' -Destination $target -Force`,
828
+ ` if (-not (Test-Path $target)) { throw 'Copy failed' }`,
829
+ ` Write-Log 'downloadBinary replace: OK'`,
830
+ ` Write-Host 'OK'`,
831
+ `} catch {`,
832
+ ` Write-Log ('downloadBinary replace FAILED: ' + $_.Exception.ToString())`,
833
+ ` Write-Host ('FAILED: ' + $_.Exception.Message)`,
834
+ ` exit 1`,
835
+ `}`,
786
836
  ].join('\r\n');
787
- fs.writeFileSync(tmpScript, scriptContent, 'utf8');
837
+ fs.writeFileSync(tmpScript, '\ufeff' + scriptContent, 'utf8');
788
838
  try {
789
839
  execSync(`powershell -NoProfile -ExecutionPolicy Bypass -File "${tmpScript}"`, {
790
- stdio: 'pipe', timeout: 30000
840
+ stdio: 'pipe', timeout: 90000
791
841
  });
792
842
  } finally {
793
843
  try { fs.unlinkSync(tmpScript); } catch (e) {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sciagent/cli",
3
- "version": "1.3.61",
3
+ "version": "1.3.63",
4
4
  "description": "SciAgent CLI - AI Research Assistant",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -27,7 +27,7 @@ const ARCH_MAP = {
27
27
  };
28
28
 
29
29
  // 当前版本号 - 每次发布时同步更新
30
- const CURRENT_VERSION = '1.3.61';
30
+ const CURRENT_VERSION = '1.3.63';
31
31
 
32
32
  // GitHub Releases 回退版本列表(当当前版本的 release 不存在时尝试)
33
33
  const GITHUB_FALLBACK_VERSIONS = ['1.1.3', '1.0.50', '1.0.48', '1.0.46', '1.0.40', '1.0.38', '1.0.36'];
@@ -684,16 +684,41 @@ function tryReplaceBinary(tempPath, targetPath, installDir, version, platform) {
684
684
  // 先尝试直接复制
685
685
  if (process.platform === 'win32') {
686
686
  // Windows: 使用 PowerShell Copy-Item
687
- const tmpScript = path.join(os.tmpdir(), 'sciagent-replace.ps1');
687
+ // 脚本必须以 UTF-8 BOM 写入(PowerShell 5.1 无 BOM 按 ANSI/GBK 解码,
688
+ // 中文安装路径会乱码导致复制失败);并轮询等待 exe 解锁再覆盖。
689
+ const tmpScript = path.join(os.tmpdir(), `sciagent-replace-${process.pid}.ps1`);
690
+ const logFile = path.join(installDir, 'update-apply.log');
691
+ const esc = (s) => String(s).replace(/'/g, "''");
688
692
  const scriptContent = [
689
- `Copy-Item -Path "${tempPath}" -Destination "${targetPath}" -Force`,
690
- 'if (Test-Path $out) { Write-Host "OK" } else { Write-Error "Copy failed"; exit 1 }'
693
+ `$ErrorActionPreference = 'Stop'`,
694
+ `$log = '${esc(logFile)}'`,
695
+ `function Write-Log([string]$msg) { try { $line = '[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg; Add-Content -Path $log -Value $line -Encoding UTF8 } catch {} }`,
696
+ `Write-Log 'tryReplaceBinary: helper started'`,
697
+ `try {`,
698
+ ` $target = '${esc(targetPath)}'`,
699
+ ` if (Test-Path $target) {`,
700
+ ` $deadline = (Get-Date).AddSeconds(60)`,
701
+ ` $unlocked = $false`,
702
+ ` while ((Get-Date) -lt $deadline) {`,
703
+ ` try { $fs = [System.IO.File]::Open($target, 'Open', 'ReadWrite', 'None'); $fs.Close(); $unlocked = $true; break } catch { Start-Sleep -Milliseconds 500 }`,
704
+ ` }`,
705
+ ` if (-not $unlocked) { throw ('Timed out waiting for target to unlock: ' + $target) }`,
706
+ ` }`,
707
+ ` Copy-Item -Path '${esc(tempPath)}' -Destination $target -Force`,
708
+ ` if (-not (Test-Path $target)) { throw 'Copy failed' }`,
709
+ ` Write-Log 'tryReplaceBinary: replace OK'`,
710
+ ` Write-Host 'OK'`,
711
+ `} catch {`,
712
+ ` Write-Log ('tryReplaceBinary FAILED: ' + $_.Exception.ToString())`,
713
+ ` Write-Host ('FAILED: ' + $_.Exception.Message)`,
714
+ ` exit 1`,
715
+ `}`,
691
716
  ].join('\r\n');
692
- fs.writeFileSync(tmpScript, scriptContent, 'utf8');
717
+ fs.writeFileSync(tmpScript, '\ufeff' + scriptContent, 'utf8');
693
718
  try {
694
719
  execSync(`powershell -NoProfile -ExecutionPolicy Bypass -File "${tmpScript}"`, {
695
720
  stdio: 'pipe',
696
- timeout: 30000
721
+ timeout: 90000
697
722
  });
698
723
  } finally {
699
724
  try { fs.unlinkSync(tmpScript); } catch (e) {}