fix(host): 修掉『点打开没反应』——投递命令后必须等心跳确认,否则重新拉起

真机现象:DSH 重启会把浮窗进程一起带走(它是 DSH 进程树的后代),但 alive.json 心跳还新鲜,
插件以为它活着 → 只往 command.json 投了个 open,发给了已经不存在的进程,窗口当然不出来。
现在 controlFloat 投递后轮询心跳(最多 1.6s):没更新就判定它已死并重新 spawn(隐藏窗口)。
另:上下文占比兜底按 1M 生效,真机实测 ctx=0.176。
This commit is contained in:
2026-09-27 17:25:47 +08:00
parent 6ee713b145
commit f234213297
+24 -4
View File
@@ -608,8 +608,12 @@ export function apply(ctx, config) {
}
/** 壳每 700ms 写一次心跳,据此判断浮窗是否还活着 */
function aliveMtime() {
try { return fs.statSync(aliveFile).mtimeMs } catch { return 0 }
}
function shellAlive() {
try { return Date.now() - fs.statSync(aliveFile).mtimeMs < 8000 } catch { return false }
const t = aliveMtime()
return !!t && Date.now() - t < 8000
}
async function spawnShell() {
@@ -626,14 +630,30 @@ export function apply(ctx, config) {
} catch (e) { return { ok: false, error: String(e?.message || e) } }
}
/** 浮窗已经在跑就投递命令,否则按需拉起 */
/** 浮窗已经在跑就投递命令,否则按需拉起;投递后要等心跳确认,不能"发给死人" */
async function controlFloat(action) {
if (action === 'open' && !shellAlive()) return spawnShell()
if (action === 'close' && !shellAlive()) return { ok: true, via: 'already closed' }
if (shellAlive()) {
const before = aliveMtime()
const posted = await writeCommand(action)
if (posted.ok) {
// 等心跳更新(浮窗每 700ms 写一次 alive.json);没更新说明它其实已经死了 → 重新拉起
for (let i = 0; i < 8; i++) {
await new Promise((r) => setTimeout(r, 200))
if (aliveMtime() > before) return { ok: true, via: 'command file' }
}
log(`float did not acknowledge "${action}" within 1.6s; respawning`)
}
}
if (action === 'open' || action === 'fullscreen' || action === 'show') return spawnShell()
// close/hide 之类:没进程就算完成
return { ok: true, via: 'no shell running' }
}
async function writeCommand(action) {
try {
fs.mkdirSync(stateDir, { recursive: true })
fs.writeFileSync(cmdFile, JSON.stringify({ cmd: action, at: new Date().toISOString() }))
return { ok: true, via: 'command file' }
return { ok: true }
} catch (e) { return { ok: false, error: String(e?.message || e) } }
}