deskbuddy 0.2.0-beta.2 → 0.2.0-beta.4
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/dist/cli.js +1862 -344
- package/dist/hook.cjs +77 -4
- package/dist/wake.cjs +764 -0
- package/hook/hook.cjs +77 -4
- package/hook/wake.cjs +764 -0
- package/package.json +2 -2
package/hook/hook.cjs
CHANGED
|
@@ -26,7 +26,7 @@ const MAX_SESSIONS = 20
|
|
|
26
26
|
* 快照整包带的能力声明(前置 spec 2026-09-29 §4.4,服务端写 deskbuddy:caps:{clientId})。
|
|
27
27
|
* 与 src/core/snapshot.ts 的 CAPS 一致
|
|
28
28
|
*/
|
|
29
|
-
const CAPS = ['cmd_result', 'window_inject']
|
|
29
|
+
const CAPS = ['cmd_result', 'window_inject', 'resume_ended']
|
|
30
30
|
/** 状态文件里保留的最近事件条数,与 src/core/state.ts 的 RECENT_MAX 一致 */
|
|
31
31
|
const RECENT_MAX = 8
|
|
32
32
|
const REPORT_TIMEOUT_MS = 2000
|
|
@@ -556,6 +556,40 @@ function writeState(s) {
|
|
|
556
556
|
fs.renameSync(tmp, statePath(s.sessionId))
|
|
557
557
|
}
|
|
558
558
|
|
|
559
|
+
// ---------- 已结束记录(与 src/core/ended.ts 同构,续跑方案 spec 2026-09-29 §5.1) ----------
|
|
560
|
+
|
|
561
|
+
const ENDED_TTL_MS = 7 * 24 * 60 * 60 * 1000
|
|
562
|
+
|
|
563
|
+
function writeEnded(s, now) {
|
|
564
|
+
const sid = String((s && s.sessionId) || '')
|
|
565
|
+
if (!/^[A-Za-z0-9_-]{1,64}$/.test(sid)) return
|
|
566
|
+
try {
|
|
567
|
+
const dir = path.join(deskbuddyHome(), 'ended')
|
|
568
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 })
|
|
569
|
+
const t = now || Date.now()
|
|
570
|
+
const rec = { sessionId: sid, tool: s.tool || '', cwd: s.cwd || '', interactive: s.interactive === true, endedAt: t }
|
|
571
|
+
const file = path.join(dir, sid + '.json')
|
|
572
|
+
fs.writeFileSync(file + '.tmp', JSON.stringify(rec), { encoding: 'utf8', mode: 0o600 })
|
|
573
|
+
fs.renameSync(file + '.tmp', file)
|
|
574
|
+
for (const n of fs.readdirSync(dir)) {
|
|
575
|
+
const f = path.join(dir, n)
|
|
576
|
+
try {
|
|
577
|
+
if (t - fs.statSync(f).mtimeMs > ENDED_TTL_MS) fs.rmSync(f, { force: true })
|
|
578
|
+
} catch (e) {
|
|
579
|
+
/* ignore */
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
} catch (e) {
|
|
583
|
+
/* 记不下:只是这个会话结束后不能从设备续跑 */
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/** 会话结束:先写已结束记录,再删状态(删状态的地方都走这里,/clear 除外) */
|
|
588
|
+
function retireState(s, now) {
|
|
589
|
+
writeEnded(s, now)
|
|
590
|
+
removeState(s.sessionId)
|
|
591
|
+
}
|
|
592
|
+
|
|
559
593
|
function removeState(sessionId) {
|
|
560
594
|
try {
|
|
561
595
|
fs.rmSync(statePath(sessionId), { force: true })
|
|
@@ -591,7 +625,7 @@ function readAliveStates(tool) {
|
|
|
591
625
|
}
|
|
592
626
|
if (!s || s.tool !== tool) continue
|
|
593
627
|
if (s.pid && !isAlive(s.pid, s.pidName)) {
|
|
594
|
-
|
|
628
|
+
retireState(s) // 窗口已关:记下已结束、剔除并自我清理,state 目录不再无限增长
|
|
595
629
|
continue
|
|
596
630
|
}
|
|
597
631
|
alive.push(s)
|
|
@@ -764,8 +798,35 @@ async function reportIfAuthorized(tool, nowMs) {
|
|
|
764
798
|
// clientId 为空说明还没 setup 过(服务端靠 clientId ↔ userId 绑定关系认人):
|
|
765
799
|
// 绝不能在这里现编一个,那等于凭空造出一台没人认领的机器
|
|
766
800
|
if (!cfg.clientId || cfg.enabledTools.indexOf(tool) === -1) return
|
|
801
|
+
// Codex:以 daemon 连着的 app-server 清单判 remoteWindow(切片 B);Claude Code:状态文件 + 窗口唤醒标记
|
|
767
802
|
const remote = tool === 'codex' ? readCodexRemote() || new Set() : null
|
|
768
|
-
await postReport(cfg, buildSnapshot(readAliveStates(tool), tool, cfg, nowMs, remote))
|
|
803
|
+
await postReport(cfg, buildSnapshot(withWake(readAliveStates(tool)), tool, cfg, nowMs, remote))
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// ---------- 窗口唤醒(asyncRewake,与 src/core/wake.ts 同构) ----------
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* daemon 写的 `wake/marks/<sessionId>.json`:这个会话开着的窗口里有等待者,设备指令能直接唤醒窗口执行。
|
|
810
|
+
* 标记里的智能体进程还在才算(kill 0,不查进程名:每次上报都要调)
|
|
811
|
+
*/
|
|
812
|
+
function wakeMarked(sessionId) {
|
|
813
|
+
const safe = String(sessionId).replace(/[^A-Za-z0-9_-]/g, '')
|
|
814
|
+
if (!safe) return false
|
|
815
|
+
try {
|
|
816
|
+
const m = JSON.parse(fs.readFileSync(path.join(deskbuddyHome(), 'wake', 'marks', safe + '.json'), 'utf8'))
|
|
817
|
+
// 写标记的 daemon 死了就不算(daemon 退出来不及清标记时,不能一直误报 remoteWindow)
|
|
818
|
+
const daemonPid = Number(m && m.daemonPid) || 0
|
|
819
|
+
if (!daemonPid || !pidExists(daemonPid)) return false
|
|
820
|
+
const pid = Number(m && m.agentPid) || 0
|
|
821
|
+
return pid > 0 ? pidExists(pid) : true
|
|
822
|
+
} catch (e) {
|
|
823
|
+
return false
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/** 上报前叠加唤醒标记:能被唤醒的会话带 remoteWindow=true(服务端据此放行 8348) */
|
|
828
|
+
function withWake(states) {
|
|
829
|
+
return states.map((s) => (s.remoteWindow === true || !wakeMarked(s.sessionId) ? s : Object.assign({}, s, { remoteWindow: true })))
|
|
769
830
|
}
|
|
770
831
|
|
|
771
832
|
/**
|
|
@@ -1063,8 +1124,13 @@ async function main(argv) {
|
|
|
1063
1124
|
if (event === 'SessionEnd' && payload.reason === 'clear') {
|
|
1064
1125
|
const old = readState(sessionId)
|
|
1065
1126
|
if (old && old.pid) markClear(old.pid, sessionId)
|
|
1127
|
+
// /clear 引起的结束交给别名改绑,不写已结束记录
|
|
1128
|
+
removeState(sessionId)
|
|
1129
|
+
} else {
|
|
1130
|
+
// 先记下已结束(设备再回复时续跑要知道 cwd),再删状态。状态文件没有就用这次事件里的 cwd
|
|
1131
|
+
const old = readState(sessionId)
|
|
1132
|
+
retireState(old || { sessionId: sessionId, tool: tool, cwd: payload.cwd || '', interactive: false })
|
|
1066
1133
|
}
|
|
1067
|
-
removeState(sessionId)
|
|
1068
1134
|
// 删完补发一次剩余会话,否则这条会一直挂在屏上等服务端失联 TTL。
|
|
1069
1135
|
// 关掉最后一个窗口时发的是空列表——服务端放行空快照,该机器该工具随即从屏上消失
|
|
1070
1136
|
await reportIfAuthorized(tool, Date.now())
|
|
@@ -1165,12 +1231,15 @@ module.exports = {
|
|
|
1165
1231
|
main,
|
|
1166
1232
|
mapEvent,
|
|
1167
1233
|
processName,
|
|
1234
|
+
parentPid,
|
|
1168
1235
|
readAiTitle,
|
|
1169
1236
|
readAliveStates,
|
|
1170
1237
|
readCodexThreadName,
|
|
1171
1238
|
readGitBranch,
|
|
1172
1239
|
readState,
|
|
1173
1240
|
removeState,
|
|
1241
|
+
retireState,
|
|
1242
|
+
writeEnded,
|
|
1174
1243
|
resolveAgentPid,
|
|
1175
1244
|
resolveTitle,
|
|
1176
1245
|
takeNotice,
|
|
@@ -1192,4 +1261,8 @@ module.exports = {
|
|
|
1192
1261
|
noteWindow,
|
|
1193
1262
|
readWindow,
|
|
1194
1263
|
windowOwns,
|
|
1264
|
+
wakeMarked,
|
|
1265
|
+
withWake,
|
|
1266
|
+
detectInteractive,
|
|
1267
|
+
pidExists,
|
|
1195
1268
|
}
|