@mcd0luo/celes-dsh-file-wake
v0.1.0
Published
文件级会话唤醒(第二唤醒通道,不依赖桥接 HTTP):监听 /server-center/runtime/state/session-wake/ 下的唤醒文件(文件名=sessionId),对目标会话 inbox.append + wakeDriver 进程内驱动新一轮处理,处理完将文件移入 done/(追加结果行),会话不可达则移入 failed/。host-only(依赖 schemastery 定义 Config schema)。
Readme
celes-dsh-file-wake —— 文件级会话唤醒(第二唤醒通道,不依赖桥接 HTTP)
背景(7:00 类事故):dsh 进程/会话/端口都活着,但桥接 HTTP(/celes-center/bridge/*)
挂起 → 外部连不上、桥接唤醒失效。本插件提供不依赖桥接 HTTP 的「及时」通信通道:
中枢(server-center)把唤醒请求写成
<watchDir>/<sessionId>文件 → 本插件在 dsh 进程内监听该目录(fs.watch+ 30s 轮询兜底)→ 新文件即对目标会话agent.inbox.append("next-step", …)+agent.wakeDriver()(进程内 API,不经任何 HTTP)→ 处理完把文件移入done/(追加结果行);会话不存在/不可达则移入failed/并记日志。
唤醒文件协议
- 文件名 = 目标会话 id,白名单
^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$(拒绝./../点前缀)。 - 内容 = 单行 JSON(中枢写侧同形态,见
server/src/modules/session-wake.ts):
{
"id": "<sessionId>",
"role": "user",
"source": { "kind": "plugin", "plugin": "celes-dsh-file-wake" },
"content": [{ "type": "text", "text": "<消息正文>" }],
"instance": "3180"
}instance可选:缺省 = 任意实例均可处理(多实例原子 rename 竞取,只处理一次); 指定 = 仅该实例处理(其余实例跳过不抢占)。- 结果行:处理完向文件追加一行
{"type":"result","ok":bool,"at":ISO[,error]}, 随后整体移入done/或failed/(目录结构:<watchDir>/{done,failed}/)。
处理流程(防失控/防双注入)
- 每轮先做认领残留回收:
.NAME.processing-<pid>属主进程已死或超时 (staleClaimMs,默认 60s)→ 还原为原文件名重排; - 扫描新文件:先只读解析 + 校验 + 实例路由(指向其它实例的文件跳过);
- 原子认领:
rename为.NAME.processing-<pid>(同盘原子;ENOENT=已被认领,跳过); - 注入:
agent.inbox.append("next-step", {id: file-wake-<ts>-<rand>, role:"user", source:{kind:"plugin",plugin:name}, content:[{type:"text",text}]})+agent.wakeDriver(); - 归档:追加结果行后 rename 进
done/(成功)或failed/(失败含原因); - 全程同步处理 +
processing重入守卫(watch 事件与轮询合并为一轮扫描)。
会话不在 live 注册表(parked/不存在)→ 移入 failed/ 并在活动日志记
wake-failed: 会话不在本实例 live 注册表。parked 会话的兜底:
中枢 wakeMode=both 会在此失败后降级走桥接 session.prompt(见中心侧文档)。
配置(设置面板「Celestea → 文件唤醒」或 settings.yaml celestea-file-wake: 节)
| 键 | 默认 | 说明 |
|---|---|---|
| enabled | true | 总开关(false 时不挂载任何监听) |
| watchDir | /server-center/runtime/state/session-wake | 唤醒目录(与中枢写侧同路径) |
| instance | 3180 | 本实例号(文件 JSON instance 路由匹配) |
| pollIntervalMs | 30000 | 轮询兜底间隔 |
| staleClaimMs | 60000 | 认领残留回收阈值 |
| maxBytes | 16384 | 单文件内容字节上限 |
| wrapTemplate | {message} | 注入消息模板({message} 替换为正文) |
运维
- 活动日志:
$DSH_HOME/celes-dsh-file-wake-activity.jsonl(apply/restore/delivered/failed)。 - 手工投递测试(会话
session-a存续时):
W=/server-center/runtime/state/session-wake
printf '%s\n' '{"id":"session-a","role":"user","source":{"kind":"plugin","plugin":"celes-dsh-file-wake"},"content":[{"type":"text","text":"(自测)请回复收到"}]}' > "$W/session-a"
# 插件应立即处理:ls "$W/done/session-a" 存在且尾行 {"type":"result","ok":true,...}- 严禁在生产目录直接手改插件(改源码走 server-center 仓 worktree
dsh-plugin/→ 部署脚本install-file-wake.sh,见其 README 注释)。
