@simonyea/holysheep-cli 1.7.65 → 1.7.67

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simonyea/holysheep-cli",
3
- "version": "1.7.65",
3
+ "version": "1.7.67",
4
4
  "description": "Claude Code/Cursor/Cline API relay for China — ¥1=$1, WeChat/Alipay payment, no credit card, no VPN. One command setup for all AI coding tools.",
5
5
  "keywords": [
6
6
  "openai-china",
@@ -479,16 +479,26 @@ async function doUpgradeTool(id, name) {
479
479
  openConsole(`${t('upgradeOne')}: ${name}`)
480
480
  document.getElementById('console-section').classList.add('busy')
481
481
 
482
+ let upgraded = false
482
483
  await streamSSE('/api/tool/upgrade', { toolId: id }, (ev) => {
483
484
  if (ev.type === 'progress') appendLog(ev.message, 'info')
484
485
  else if (ev.type === 'output') appendLogRaw(ev.text)
485
486
  else if (ev.type === 'done') {
487
+ upgraded = ev.success
486
488
  appendLog(ev.success ? `\n✓ ${t('configSuccess')}` : `\n✗ ${t('configFailed')}`, ev.success ? 'ok' : 'err')
487
489
  }
488
490
  })
489
491
 
490
492
  document.getElementById('console-section').classList.remove('busy')
491
493
  busy = false
494
+
495
+ if (upgraded && id === 'holysheep') {
496
+ appendLog(`\n${lang === 'zh' ? '⚠ HolySheep CLI 已升级,需要重启 WebUI 服务。正在重启...' : '⚠ HolySheep CLI upgraded. Restarting WebUI...'}`, 'warn')
497
+ // 调用后端重启,3 秒后刷新页面
498
+ try { await fetch('/api/restart', { method: 'POST' }) } catch {}
499
+ setTimeout(() => location.reload(), 4000)
500
+ return
501
+ }
492
502
  loadTools()
493
503
  }
494
504
 
@@ -26,15 +26,20 @@ function maskKey(key) {
26
26
  return key.slice(0, 6) + '...' + key.slice(-4)
27
27
  }
28
28
 
29
- async function fetchWithRetry(url, opts = {}, retries = 3) {
29
+ async function fetchWithRetry(url, opts = {}, retries = 3, timeoutMs = 20000) {
30
30
  const fetch = require('node-fetch')
31
31
  for (let i = 0; i < retries; i++) {
32
+ const controller = new AbortController()
33
+ const timer = setTimeout(() => controller.abort(), timeoutMs)
32
34
  try {
33
- return await fetch(url, { timeout: 10000, ...opts })
35
+ const res = await fetch(url, { ...opts, signal: controller.signal })
36
+ clearTimeout(timer)
37
+ return res
34
38
  } catch (e) {
35
- // DNS 暂时失败 (EAI_AGAIN) 或网络抖动,重试
36
- if (i < retries - 1 && (e.code === 'EAI_AGAIN' || e.code === 'ETIMEDOUT' || e.code === 'ECONNRESET' || e.type === 'system')) {
37
- await new Promise(r => setTimeout(r, 1500 * (i + 1)))
39
+ clearTimeout(timer)
40
+ const retryable = e.code === 'EAI_AGAIN' || e.code === 'ETIMEDOUT' || e.code === 'ECONNRESET' || e.code === 'ECONNREFUSED' || e.type === 'system' || e.name === 'AbortError'
41
+ if (i < retries - 1 && retryable) {
42
+ await new Promise(r => setTimeout(r, 2000 * (i + 1)))
38
43
  continue
39
44
  }
40
45
  throw e
@@ -698,6 +703,17 @@ async function handleRequest(req, res) {
698
703
  if (route === '/api/tool/upgrade' && req.method === 'POST') return await handleToolUpgrade(req, res)
699
704
  if (route === '/api/env' && req.method === 'GET') return handleEnv(req, res)
700
705
  if (route === '/api/env/clean' && req.method === 'POST') return handleEnvClean(req, res)
706
+ if (route === '/api/restart' && req.method === 'POST') {
707
+ json(res, { ok: true })
708
+ // 升级后用新版 hs web 重启自身
709
+ const port = req.headers.host?.split(':')[1] || '9876'
710
+ setTimeout(() => {
711
+ const child = spawn(process.execPath, [path.join(__dirname, '..', 'index.js'), 'web', '--port', port, '--no-open'], { detached: true, stdio: 'ignore' })
712
+ child.unref()
713
+ process.exit(0)
714
+ }, 500)
715
+ return
716
+ }
701
717
 
702
718
  res.writeHead(404)
703
719
  res.end('Not Found')