@wendongfly/zihi 1.1.14 → 1.1.16
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/zihi.js +96 -0
- package/dist/admin.html +51 -0
- package/dist/index.js +3 -3
- package/dist/index.min.js +98 -91
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/bin/zihi.js
CHANGED
|
@@ -134,6 +134,18 @@ function printRunningInfo(info, opts = {}) {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
async function stopDaemon() {
|
|
137
|
+
// Linux 下优先使用 systemd
|
|
138
|
+
if (hasSystemdService()) {
|
|
139
|
+
try {
|
|
140
|
+
execSync('sudo systemctl stop zihi', { stdio: 'inherit' });
|
|
141
|
+
console.log('[zihi] 服务已停止');
|
|
142
|
+
return true;
|
|
143
|
+
} catch (e) {
|
|
144
|
+
console.error('[zihi] systemctl 停止失败:', e.message);
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
137
149
|
const info = readPidInfo();
|
|
138
150
|
if (!info || !info.pid) { console.log('[zihi] 没有正在运行的后台进程'); return false; }
|
|
139
151
|
if (!isPidAlive(info.pid)) {
|
|
@@ -154,7 +166,31 @@ async function stopDaemon() {
|
|
|
154
166
|
return true;
|
|
155
167
|
}
|
|
156
168
|
|
|
169
|
+
/** 检查是否已安装 systemd 服务 */
|
|
170
|
+
function hasSystemdService() {
|
|
171
|
+
if (process.platform !== 'linux') return false;
|
|
172
|
+
try {
|
|
173
|
+
execSync('systemctl cat zihi.service', { stdio: 'ignore', timeout: 2000 });
|
|
174
|
+
return true;
|
|
175
|
+
} catch { return false; }
|
|
176
|
+
}
|
|
177
|
+
|
|
157
178
|
async function startDaemon() {
|
|
179
|
+
// Linux 下优先使用 systemd
|
|
180
|
+
if (hasSystemdService()) {
|
|
181
|
+
console.log('[zihi] 检测到 systemd 服务,通过 systemctl 启动');
|
|
182
|
+
try {
|
|
183
|
+
execSync('sudo systemctl restart zihi', { stdio: 'inherit' });
|
|
184
|
+
console.log('[zihi] 服务已启动');
|
|
185
|
+
console.log(' 查看状态: sudo systemctl status zihi');
|
|
186
|
+
console.log(' 查看日志: sudo journalctl -u zihi -f');
|
|
187
|
+
process.exit(0);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
console.error('[zihi] systemctl 启动失败:', e.message);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
158
194
|
// 启动前唯一性校验
|
|
159
195
|
const running = await verifyRunning();
|
|
160
196
|
if (running) {
|
|
@@ -248,6 +284,66 @@ if (cmd === 'attach') {
|
|
|
248
284
|
console.log('[zihi] 日志文件不存在');
|
|
249
285
|
}
|
|
250
286
|
|
|
287
|
+
} else if (cmd === 'install' || cmd === 'service') {
|
|
288
|
+
// Linux systemd 服务安装
|
|
289
|
+
if (process.platform !== 'linux') {
|
|
290
|
+
console.log('[zihi] systemd 服务安装仅支持 Linux');
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
const servicePath = '/etc/systemd/system/zihi.service';
|
|
294
|
+
const user = process.env.SUDO_USER || process.env.USER || 'root';
|
|
295
|
+
const nodeBin = process.execPath;
|
|
296
|
+
const zihiBin = join(__dirname, 'zihi.js');
|
|
297
|
+
const port = process.env.PORT || '12345';
|
|
298
|
+
const unit = `[Unit]
|
|
299
|
+
Description=ZiHi - AI Agent Terminal Sharing
|
|
300
|
+
After=network.target
|
|
301
|
+
|
|
302
|
+
[Service]
|
|
303
|
+
Type=simple
|
|
304
|
+
User=${user}
|
|
305
|
+
Environment=PORT=${port}
|
|
306
|
+
Environment=ZIHI_DAEMON=1
|
|
307
|
+
ExecStart=${nodeBin} ${join(__dirname, 'daemon.js')}
|
|
308
|
+
Restart=on-failure
|
|
309
|
+
RestartSec=5
|
|
310
|
+
StandardOutput=append:${join(homedir(), '.zihi/daemon.log')}
|
|
311
|
+
StandardError=append:${join(homedir(), '.zihi/daemon.log')}
|
|
312
|
+
|
|
313
|
+
[Install]
|
|
314
|
+
WantedBy=multi-user.target
|
|
315
|
+
`;
|
|
316
|
+
try {
|
|
317
|
+
execSync(`sudo tee ${servicePath}`, { input: unit, stdio: ['pipe', 'ignore', 'inherit'] });
|
|
318
|
+
execSync('sudo systemctl daemon-reload', { stdio: 'inherit' });
|
|
319
|
+
execSync('sudo systemctl enable zihi', { stdio: 'inherit' });
|
|
320
|
+
execSync('sudo systemctl restart zihi', { stdio: 'inherit' });
|
|
321
|
+
console.log('\n[zihi] systemd 服务已安装并启动');
|
|
322
|
+
console.log(' 查看状态: sudo systemctl status zihi');
|
|
323
|
+
console.log(' 查看日志: sudo journalctl -u zihi -f');
|
|
324
|
+
console.log(' 停止服务: sudo systemctl stop zihi');
|
|
325
|
+
console.log(' 卸载服务: zihi uninstall');
|
|
326
|
+
} catch (e) {
|
|
327
|
+
console.error('[zihi] 安装失败:', e.message);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
} else if (cmd === 'uninstall') {
|
|
332
|
+
if (process.platform !== 'linux') {
|
|
333
|
+
console.log('[zihi] systemd 服务卸载仅支持 Linux');
|
|
334
|
+
process.exit(1);
|
|
335
|
+
}
|
|
336
|
+
try {
|
|
337
|
+
execSync('sudo systemctl stop zihi 2>/dev/null || true', { stdio: 'inherit' });
|
|
338
|
+
execSync('sudo systemctl disable zihi 2>/dev/null || true', { stdio: 'inherit' });
|
|
339
|
+
execSync('sudo rm -f /etc/systemd/system/zihi.service', { stdio: 'inherit' });
|
|
340
|
+
execSync('sudo systemctl daemon-reload', { stdio: 'inherit' });
|
|
341
|
+
console.log('[zihi] systemd 服务已卸载');
|
|
342
|
+
} catch (e) {
|
|
343
|
+
console.error('[zihi] 卸载失败:', e.message);
|
|
344
|
+
process.exit(1);
|
|
345
|
+
}
|
|
346
|
+
|
|
251
347
|
} else if (cmd === 'exclusive') {
|
|
252
348
|
// 独占模式开关
|
|
253
349
|
const { existsSync } = await import('fs');
|
package/dist/admin.html
CHANGED
|
@@ -106,6 +106,19 @@
|
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
108
108
|
|
|
109
|
+
<!-- Claude Code -->
|
|
110
|
+
<div class="card">
|
|
111
|
+
<h3>Claude Code</h3>
|
|
112
|
+
<div class="row">
|
|
113
|
+
<span id="claude-status">检测中...</span>
|
|
114
|
+
<div class="row-actions">
|
|
115
|
+
<button onclick="checkClaude()">检测</button>
|
|
116
|
+
<button onclick="installClaude()" class="btn-install">安装/更新</button>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<pre id="claude-log" style="display:none;font-size:0.72rem;background:#0d1117;border:1px solid rgba(255,255,255,0.1);border-radius:8px;padding:0.6rem;margin-top:0.5rem;max-height:240px;overflow:auto;white-space:pre-wrap;word-break:break-all;color:#b1bac4"></pre>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
109
122
|
<!-- 修改管理密码 -->
|
|
110
123
|
<div class="card">
|
|
111
124
|
<h3>修改管理密码</h3>
|
|
@@ -146,6 +159,7 @@ async function showAdmin() {
|
|
|
146
159
|
document.getElementById('pg-login').style.display = 'none';
|
|
147
160
|
document.getElementById('pg-admin').style.display = '';
|
|
148
161
|
await refresh();
|
|
162
|
+
checkClaude();
|
|
149
163
|
setInterval(refresh, 10000);
|
|
150
164
|
}
|
|
151
165
|
|
|
@@ -274,6 +288,43 @@ async function doUpgrade() {
|
|
|
274
288
|
} catch { msg.textContent = '连接失败'; btn.disabled = false; btn.textContent = '重试'; }
|
|
275
289
|
}
|
|
276
290
|
|
|
291
|
+
async function checkClaude() {
|
|
292
|
+
const st = document.getElementById('claude-status');
|
|
293
|
+
st.textContent = '检测中...';
|
|
294
|
+
try {
|
|
295
|
+
const r = await fetch('/api/admin/claude-status', { headers: H() });
|
|
296
|
+
const d = await r.json();
|
|
297
|
+
if (d.installed) {
|
|
298
|
+
st.innerHTML = '<span style="color:#3fb950">✓ 已安装</span> <span style="color:#8b949e;font-size:0.78rem">' + (d.version || '') + '</span>';
|
|
299
|
+
} else {
|
|
300
|
+
st.innerHTML = '<span style="color:#f85149">✗ 未安装</span>';
|
|
301
|
+
}
|
|
302
|
+
} catch {
|
|
303
|
+
st.textContent = '检测失败';
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function installClaude() {
|
|
308
|
+
if (!confirm('确定安装/更新 Claude Code?(可能需要几分钟)')) return;
|
|
309
|
+
var log = document.getElementById('claude-log');
|
|
310
|
+
log.style.display = 'block';
|
|
311
|
+
log.textContent = '开始安装...\n';
|
|
312
|
+
try {
|
|
313
|
+
var r = await fetch('/api/admin/install-claude', { method: 'POST', headers: H() });
|
|
314
|
+
var reader = r.body.getReader();
|
|
315
|
+
var decoder = new TextDecoder();
|
|
316
|
+
while (true) {
|
|
317
|
+
var chunk = await reader.read();
|
|
318
|
+
if (chunk.done) break;
|
|
319
|
+
log.textContent += decoder.decode(chunk.value);
|
|
320
|
+
log.scrollTop = log.scrollHeight;
|
|
321
|
+
}
|
|
322
|
+
checkClaude();
|
|
323
|
+
} catch (e) {
|
|
324
|
+
log.textContent += '\n[连接失败] ' + e.message;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
277
328
|
async function doRestart() {
|
|
278
329
|
if (!confirm('确定重启?')) return;
|
|
279
330
|
const msg = document.getElementById('op-msg');
|