@simonyea/holysheep-cli 1.7.59 → 1.7.61
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 +1 -1
- package/src/tools/openclaw.js +1 -1
- package/src/webui/index.html +35 -3
- package/src/webui/server.js +52 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simonyea/holysheep-cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.61",
|
|
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",
|
package/src/tools/openclaw.js
CHANGED
|
@@ -699,7 +699,7 @@ module.exports = {
|
|
|
699
699
|
'--auth-choice', 'custom-api-key',
|
|
700
700
|
'--custom-base-url', bridgeBaseUrl,
|
|
701
701
|
'--custom-api-key', apiKey,
|
|
702
|
-
'--custom-model-id', resolvedPrimaryModel,
|
|
702
|
+
'--custom-model-id', resolvedPrimaryModel.replace(/\[.*\]/, ''),
|
|
703
703
|
'--custom-compatibility', 'openai',
|
|
704
704
|
'--gateway-port', String(gatewayPort),
|
|
705
705
|
]
|
package/src/webui/index.html
CHANGED
|
@@ -129,6 +129,9 @@ a:hover { text-decoration: underline; }
|
|
|
129
129
|
.footer-links { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; font-size: 0.85rem; margin-bottom: 8px; }
|
|
130
130
|
.footer-sub { font-size: 0.78rem; color: var(--text2); }
|
|
131
131
|
|
|
132
|
+
/* Update banner */
|
|
133
|
+
.update-banner { background: var(--primary-dim); border: 1px solid var(--primary); border-radius: 8px; padding: 10px 16px; margin-bottom: 16px; display: flex; align-items: center; justify-content: space-between; font-size: 0.85rem; }
|
|
134
|
+
|
|
132
135
|
/* Misc */
|
|
133
136
|
.loading { color: var(--text2); font-size: 0.85rem; }
|
|
134
137
|
.hidden { display: none !important; }
|
|
@@ -184,7 +187,8 @@ const I18N = {
|
|
|
184
187
|
installSuccess: '安装完成', installFailed: '安装失败',
|
|
185
188
|
needLogin: '请先登录', cleanDone: '已清理',
|
|
186
189
|
hotReload: '已生效,无需重启', needRestart: '重启终端后生效',
|
|
187
|
-
launch: '启动命令',
|
|
190
|
+
launch: '启动命令', upgradeOne: '升级',
|
|
191
|
+
updateAvailable: '有新版本可用', updateNow: '立即升级',
|
|
188
192
|
},
|
|
189
193
|
en: {
|
|
190
194
|
loggedIn: 'Logged in', notLoggedIn: 'Not logged in', login: 'Login', logout: 'Logout',
|
|
@@ -206,7 +210,8 @@ const I18N = {
|
|
|
206
210
|
installSuccess: 'Installed', installFailed: 'Install failed',
|
|
207
211
|
needLogin: 'Please login first', cleanDone: 'Cleaned',
|
|
208
212
|
hotReload: 'Active, no restart needed', needRestart: 'Restart terminal to apply',
|
|
209
|
-
launch: 'Launch',
|
|
213
|
+
launch: 'Launch', upgradeOne: 'Upgrade',
|
|
214
|
+
updateAvailable: 'Update available', updateNow: 'Update now',
|
|
210
215
|
},
|
|
211
216
|
}
|
|
212
217
|
|
|
@@ -251,6 +256,11 @@ async function loadAccount() {
|
|
|
251
256
|
|
|
252
257
|
document.getElementById('version').textContent = 'v' + (s.version || '')
|
|
253
258
|
|
|
259
|
+
// 版本更新提示
|
|
260
|
+
if (s.updateAvailable) {
|
|
261
|
+
document.getElementById('version').innerHTML = `v${s.version} <span style="color:var(--primary);cursor:pointer" onclick="doUpgradeTool('holysheep','HolySheep CLI')" title="${t('updateNow')}">→ v${s.updateAvailable} ${t('updateNow')}</span>`
|
|
262
|
+
}
|
|
263
|
+
|
|
254
264
|
if (s.loggedIn) {
|
|
255
265
|
const hasBalance = !b.error && typeof b.balance === 'number'
|
|
256
266
|
el.innerHTML = `<div class="card account-card account-logged-in">
|
|
@@ -333,12 +343,15 @@ function renderToolCard(tool) {
|
|
|
333
343
|
} else if (!tool.configured) {
|
|
334
344
|
dotClass = 'dot-warn'
|
|
335
345
|
statusBadges = `<span class="badge badge-ok">${t('installed')}</span> <span class="badge badge-warn">${t('notConfigured')}</span>`
|
|
336
|
-
|
|
346
|
+
const upgradeBtn = tool.canUpgrade ? `<button class="btn btn-outline btn-sm" onclick="doUpgradeTool('${tool.id}','${esc(tool.name)}')" ${busy ? 'disabled' : ''}>${t('upgradeOne')}</button>` : ''
|
|
347
|
+
actions = `<button class="btn btn-primary btn-sm" onclick="doConfigureTool('${tool.id}','${esc(tool.name)}')" ${busy ? 'disabled' : ''}>${t('configure')}</button>${upgradeBtn}`
|
|
337
348
|
hintLine = tool.version ? `<span class="mono" style="font-size:0.78rem;color:var(--text2)">${esc(tool.version)}</span>` : ''
|
|
338
349
|
} else {
|
|
339
350
|
dotClass = 'dot-ok'
|
|
340
351
|
statusBadges = `<span class="badge badge-ok">${t('installed')}</span> <span class="badge badge-ok">${t('configured')}</span>`
|
|
352
|
+
const upgradeBtn = tool.canUpgrade ? `<button class="btn btn-outline btn-sm" onclick="doUpgradeTool('${tool.id}','${esc(tool.name)}')" ${busy ? 'disabled' : ''}>${t('upgradeOne')}</button>` : ''
|
|
341
353
|
actions = `<button class="btn btn-outline btn-sm" onclick="doConfigureTool('${tool.id}','${esc(tool.name)}')" ${busy ? 'disabled' : ''}>${t('reconfigure')}</button>
|
|
354
|
+
${upgradeBtn}
|
|
342
355
|
<button class="btn btn-danger btn-sm" onclick="doResetTool('${tool.id}','${esc(tool.name)}')" ${busy ? 'disabled' : ''}>${t('reset')}</button>`
|
|
343
356
|
hintLine = tool.version ? `<span class="mono" style="font-size:0.78rem;color:var(--text2)">${esc(tool.version)}</span>` : ''
|
|
344
357
|
}
|
|
@@ -445,6 +458,25 @@ async function doUpgrade() {
|
|
|
445
458
|
loadTools()
|
|
446
459
|
}
|
|
447
460
|
|
|
461
|
+
async function doUpgradeTool(id, name) {
|
|
462
|
+
if (busy) return
|
|
463
|
+
busy = true
|
|
464
|
+
openConsole(`${t('upgradeOne')}: ${name}`)
|
|
465
|
+
document.getElementById('console-section').classList.add('busy')
|
|
466
|
+
|
|
467
|
+
await streamSSE('/api/tool/upgrade', { toolId: id }, (ev) => {
|
|
468
|
+
if (ev.type === 'progress') appendLog(ev.message, 'info')
|
|
469
|
+
else if (ev.type === 'output') appendLogRaw(ev.text)
|
|
470
|
+
else if (ev.type === 'done') {
|
|
471
|
+
appendLog(ev.success ? `\n✓ ${t('configSuccess')}` : `\n✗ ${t('configFailed')}`, ev.success ? 'ok' : 'err')
|
|
472
|
+
}
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
document.getElementById('console-section').classList.remove('busy')
|
|
476
|
+
busy = false
|
|
477
|
+
loadTools()
|
|
478
|
+
}
|
|
479
|
+
|
|
448
480
|
// ── Console ──────────────────────────────────────────────────────────────────
|
|
449
481
|
function openConsole(title) {
|
|
450
482
|
const area = document.getElementById('console-section')
|
package/src/webui/server.js
CHANGED
|
@@ -96,6 +96,7 @@ const AUTO_INSTALL = {
|
|
|
96
96
|
// ── UPGRADABLE_TOOLS (from upgrade.js) ───────────────────────────────────────
|
|
97
97
|
|
|
98
98
|
const UPGRADABLE_TOOLS = [
|
|
99
|
+
{ name: 'HolySheep CLI', id: 'holysheep', command: 'hs', versionCmd: 'hs --version', npmPkg: '@simonyea/holysheep-cli', installCmd: 'npm install -g @simonyea/holysheep-cli@latest' },
|
|
99
100
|
{
|
|
100
101
|
name: 'Claude Code', id: 'claude-code', command: 'claude',
|
|
101
102
|
versionCmd: 'claude --version', npmPkg: null,
|
|
@@ -104,6 +105,9 @@ const UPGRADABLE_TOOLS = [
|
|
|
104
105
|
: 'curl -fsSL https://claude.ai/install.sh | bash',
|
|
105
106
|
},
|
|
106
107
|
{ name: 'Codex CLI', id: 'codex', command: 'codex', versionCmd: 'codex --version', npmPkg: '@openai/codex', installCmd: 'npm install -g @openai/codex@latest' },
|
|
108
|
+
{ name: 'Droid CLI', id: 'droid', command: 'droid', versionCmd: 'droid --version', npmPkg: null, installCmd: 'brew install --cask droid' },
|
|
109
|
+
{ name: 'OpenCode', id: 'opencode', command: 'opencode', versionCmd: 'opencode --version', npmPkg: 'opencode-ai', installCmd: 'npm install -g opencode-ai@latest' },
|
|
110
|
+
{ name: 'OpenClaw', id: 'openclaw', command: 'openclaw', versionCmd: 'openclaw --version', npmPkg: 'openclaw', installCmd: 'npm install -g openclaw@latest --ignore-scripts' },
|
|
107
111
|
{ name: 'Gemini CLI', id: 'gemini-cli', command: 'gemini', versionCmd: 'gemini --version', npmPkg: '@google/gemini-cli', installCmd: 'npm install -g @google/gemini-cli@latest' },
|
|
108
112
|
]
|
|
109
113
|
|
|
@@ -270,6 +274,7 @@ async function handleTools(_req, res) {
|
|
|
270
274
|
hint: t.hint || null,
|
|
271
275
|
launchCmd: t.launchCmd || null,
|
|
272
276
|
canAutoInstall: !!AUTO_INSTALL[t.id],
|
|
277
|
+
canUpgrade: !!UPGRADABLE_TOOLS.find(u => u.id === t.id),
|
|
273
278
|
}
|
|
274
279
|
})
|
|
275
280
|
json(res, tools)
|
|
@@ -497,7 +502,7 @@ async function handleToolConfigure(req, res) {
|
|
|
497
502
|
'claude-opus-4-6', 'claude-opus-4-6[1m]',
|
|
498
503
|
'MiniMax-M2.7-highspeed', 'claude-haiku-4-5',
|
|
499
504
|
]
|
|
500
|
-
const primaryModel =
|
|
505
|
+
const primaryModel = 'claude-sonnet-4-6[1m]'
|
|
501
506
|
|
|
502
507
|
sseEmit(res, { type: 'progress', message: `正在配置 ${tool.name}...` })
|
|
503
508
|
|
|
@@ -537,6 +542,51 @@ async function handleToolConfigure(req, res) {
|
|
|
537
542
|
})
|
|
538
543
|
}
|
|
539
544
|
|
|
545
|
+
// ── Single-tool upgrade (SSE) ────────────────────────────────────────────────
|
|
546
|
+
|
|
547
|
+
async function handleToolUpgrade(req, res) {
|
|
548
|
+
const body = await parseBody(req)
|
|
549
|
+
const { toolId } = body
|
|
550
|
+
const entry = UPGRADABLE_TOOLS.find(t => t.id === toolId)
|
|
551
|
+
if (!entry) return json(res, { error: '不支持升级此工具' }, 400)
|
|
552
|
+
|
|
553
|
+
sseStart(res)
|
|
554
|
+
|
|
555
|
+
let localVer = null
|
|
556
|
+
try {
|
|
557
|
+
const out = execSync(entry.versionCmd, { stdio: 'pipe', timeout: 10000 }).toString().trim()
|
|
558
|
+
const m = out.match(/(\d+\.\d+\.\d+[\w.-]*)/)
|
|
559
|
+
localVer = m ? m[1] : out.split('\n')[0].slice(0, 30)
|
|
560
|
+
} catch {}
|
|
561
|
+
|
|
562
|
+
sseEmit(res, { type: 'progress', message: `${entry.name} 当前版本: ${localVer || '未知'}` })
|
|
563
|
+
sseEmit(res, { type: 'progress', message: `正在升级 ${entry.name}...` })
|
|
564
|
+
|
|
565
|
+
const ok = await new Promise(resolve => {
|
|
566
|
+
const child = spawn(entry.installCmd, [], { shell: true })
|
|
567
|
+
child.stdout?.on('data', chunk => sseEmit(res, { type: 'output', text: chunk.toString() }))
|
|
568
|
+
child.stderr?.on('data', chunk => sseEmit(res, { type: 'output', text: chunk.toString() }))
|
|
569
|
+
child.on('close', code => resolve(code === 0))
|
|
570
|
+
child.on('error', () => resolve(false))
|
|
571
|
+
})
|
|
572
|
+
|
|
573
|
+
let newVer = null
|
|
574
|
+
try {
|
|
575
|
+
const out = execSync(entry.versionCmd, { stdio: 'pipe', timeout: 10000 }).toString().trim()
|
|
576
|
+
const m = out.match(/(\d+\.\d+\.\d+[\w.-]*)/)
|
|
577
|
+
newVer = m ? m[1] : null
|
|
578
|
+
} catch {}
|
|
579
|
+
|
|
580
|
+
if (ok) {
|
|
581
|
+
sseEmit(res, { type: 'progress', message: `✓ ${entry.name} 升级成功: ${localVer || '?'} → ${newVer || 'latest'}` })
|
|
582
|
+
} else {
|
|
583
|
+
sseEmit(res, { type: 'progress', message: `✗ ${entry.name} 升级失败` })
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
sseEmit(res, { type: 'done', success: ok, localVer, newVer })
|
|
587
|
+
res.end()
|
|
588
|
+
}
|
|
589
|
+
|
|
540
590
|
// ── Single-tool reset ────────────────────────────────────────────────────────
|
|
541
591
|
|
|
542
592
|
async function handleToolReset(req, res) {
|
|
@@ -632,6 +682,7 @@ async function handleRequest(req, res) {
|
|
|
632
682
|
if (route === '/api/tool/install' && req.method === 'POST') return await handleToolInstall(req, res)
|
|
633
683
|
if (route === '/api/tool/configure' && req.method === 'POST') return await handleToolConfigure(req, res)
|
|
634
684
|
if (route === '/api/tool/reset' && req.method === 'POST') return await handleToolReset(req, res)
|
|
685
|
+
if (route === '/api/tool/upgrade' && req.method === 'POST') return await handleToolUpgrade(req, res)
|
|
635
686
|
if (route === '/api/env' && req.method === 'GET') return handleEnv(req, res)
|
|
636
687
|
if (route === '/api/env/clean' && req.method === 'POST') return handleEnvClean(req, res)
|
|
637
688
|
|