Repository navigation
Add 蹬王之王 (expiry-guardian): 额度到期雷达 + 无头守护进程 + Bot 看门狗(完整功能版;只读版见 #47) - #39
Hylouis233 wants to merge 1 commit into
Conversation
MyPrototypeWhat
left a comment
There was a problem hiding this comment.
感谢继续打磨!v1.5 复用唤醒会话、按次数给唤醒封顶、acked 改成带时间窗口而不是永久拉黑,这几处都是实打实的改进,测试也补得很全(reset-card-autouse 自带的测试在本地全部通过)。
不过上一轮的三个必改项在 0a433bf 上都还在,另外这版新增了一个校验错误:
需要修改
- 登录凭据(未修复):Node 入口(
miniapp/node/server.mjs)和 Rust daemon(daemon/rust/src/api.rs)仍然在获取 MiniMax Code 的登录凭据并用来调用账号接口。社区插件不能读取 MiniMax Code 的登录凭据,这部分请先暂停。 - 内部数据库(未修复):
daemon/rust/src/goal_sync.rs仍通过sqlite3直接UPDATEgoal 状态,并把原因写成用户暂停。不能直接读写 MiniMax Code 的内部数据库,请删掉 goal 暂停/恢复这条路径(可以只在插件自己的数据目录里记账,并提示用户手动处理)。README 的 Data & access 里相应的说明也请一并更新。 minimax-ai/minimax-bot的改动请拆成单独的 PR(未修复):本 PR 仍包含对plugins/minimax-ai/minimax-bot的改动(版本到 0.7.4、重试策略、README 等)。这部分和"蹬王之王"不是同一件事,放在一起不方便分别 review 和回滚,请拆到单独的 PR,并在描述里写清楚改动理由和复现场景。另外:engine.mjs第 83 行的/\bbad request\b|\bnot found\b/匹配范围较宽,你自己新增的turn-retry-forever.test.mjs里「确定性失败不被当成暂时性错误」这一条在本地也是失败的(HTTP 400 Bad Request被判成可重试),拆分时请一并修正,并给连续重试设个上限。- 校验错误(新):v1.5 把
plugin.json的name从reset-card-autouse改成了expiry-guardian,npm run check报LAYOUT_NAME_MISMATCH(目录名和name必须一致)。请改回reset-card-autouse,或者同时改目录名。
建议(可选)
- MCP 服务器名称:
servers.mcp.json里新增了一个叫minimax-bot的 MCP 服务器,与官方插件同名,容易让用户和模型混淆;且它和expiry-guardian指向同一个实现。建议只保留一个、用本插件自己的名字。 - MCP instructions 与工具不一致:
initialize的 instructions 里提到watchdog_use_card,但工具列表里并没有这个工具(只有 status / wake / decide)。请删掉这句,避免模型去调用不存在的工具。watchdog_decide只做判定不扣卡、扣卡仍须用户在面板上点按钮,这个设计很好,请保持。serverInfo.version也还是 1.4.0。 - 唤醒机制:唤醒仍是起一个 Agent 回合、让模型给其他会话发消息。这依赖目前没有文档承诺的行为,以后可能失效;而且每次唤醒都会消耗 token、并往其他插件的会话里写消息。建议在 README 的 "Data & access" 里明确写出这三点,token 消耗统一成一个数字(目前文中有约 47k / 93k 两种说法)。
- 代码注释和
docs/BOT_DIAGNOSIS.md里有不少针对宿主实现细节的推断,建议精简成"做了什么、对用户有什么影响",这些细节不保证稳定。
关于 #28:#39 已包含 #28 的全部内容,请关闭 #28,后续只在 #39 上继续。
本地结果(Node 20):npm run check 失败,reset-card-autouse 1 个错误(见第 4 条)、3 个警告;node --test:reset-card-autouse 全部通过;minimax-bot 的 turn-retry-forever.test.mjs 里 1 条失败(另有 7 个 minimax-bot 测试文件在 main 上同样失败,与本 PR 无关)。
|
|
||
|
|
||
| // ── OAuth lease:与桌面端同一套登录态 ──────────────────────────────────────── | ||
| const LEASE_SOCK = join(homedir(), '.minimax', 'run', 'mcode-auth-lease-v1.sock'); |
There was a problem hiding this comment.
必改:社区插件不能读取 MiniMax Code 的登录凭据,这部分请先暂停。
|
|
||
| /// 向桌面端的 lease socket 取一个短期 access token。 | ||
| /// 协议:4 字节大端长度前缀 + JSON。详见 packages/oauth-lease-protocol。 | ||
| pub fn acquire_lease_token() -> Option<String> { |
There was a problem hiding this comment.
必改:同上,daemon 也不能读取 MiniMax Code 的登录凭据,这部分请先暂停。
| BEGIN IMMEDIATE;\n\ | ||
| CREATE TEMP TABLE _newly AS\n\ | ||
| \x20 SELECT goal_id, session_id FROM local_runtime_thread_goals WHERE status='active';\n\ | ||
| UPDATE local_runtime_thread_goals\n\ |
There was a problem hiding this comment.
必改:不能直接读写 MiniMax Code 的内部数据库。这里直接改 goal 状态并记为用户暂停,请移除这条路径。
| @@ -0,0 +1,21 @@ | |||
| { | |||
| "schemaVersion": 1, | |||
| "name": "expiry-guardian", | |||
There was a problem hiding this comment.
必改:name 必须与目录名 reset-card-autouse 一致,当前 npm run check 报 LAYOUT_NAME_MISMATCH。
| // 要求形如 `HTTP 400` / `status 404` / `code=422` / `400 Bad Request`。 | ||
| /\b(?:http|status(?:\s+code)?|code)\s*[:=]?\s*(400|404|422)\b/i, | ||
| /\b(400|404|422)\s+(bad request|not found|unprocessable\w*)/i, | ||
| /\bbad request\b|\bnot found\b|\bunprocessable\w*\b/i, |
There was a problem hiding this comment.
必改(拆分):请把 minimax-bot 的改动拆到单独 PR 并写明理由。另外这个模式会把 HTTP 400 Bad Request 判成可重试,本 PR 自带的 turn-retry-forever.test.mjs 对应用例在本地失败。
| { | ||
| "schemaVersion": 1, | ||
| "mcpServers": { | ||
| "minimax-bot": { |
There was a problem hiding this comment.
建议:MCP 服务器名 minimax-bot 与官方插件同名,建议去掉,只保留本插件自己的名字。
| serverInfo: { name: 'expiry-guardian', version: '1.4.0' }, | ||
| instructions: | ||
| '蹬王之王:追踪额度与重置卡到期时间,并守护挂掉的 MiniMax Bot。' + | ||
| '用 watchdog_status 查状态、watchdog_wake 立即叫醒挂掉的 bot、watchdog_use_card 立即用掉该用的重置卡。', |
There was a problem hiding this comment.
建议:instructions 提到的 watchdog_use_card 不存在,请删掉;serverInfo.version 也请更新。
| * 而 45 个 bot 会话的 `purpose` 全是 `miniapp:minimax-bot` | ||
| * ⇒ 蹬王之王对这些会话直接 `agent.run` **永远被拒**(实测每 30 秒 6 条全拒)。 | ||
| * | ||
| * ## 那怎么唤醒?—— 在一个 agent 回合里用 `mavis` 工具的 `session send` |
There was a problem hiding this comment.
建议:这条唤醒路径依赖未公开的行为,请在 README "Data & access" 里说明,并写清每次唤醒的 token 消耗和会往其他会话写消息。
| ## Data & access | ||
|
|
||
| - **Files read:** `~/.config/mcode-reset-card/*.json` (its own config and ledgers), | ||
| `~/.minimax/v2/sqlite/runtime-state.sqlite` (read and, for goal status, written). |
There was a problem hiding this comment.
改完凭据和数据库两项后,请同步更新这里以及第 267 行的 Files read / Credentials 说明。
MyPrototypeWhat
left a comment
There was a problem hiding this comment.
感谢继续更新!这一轮的两个修复都很好:mcp.mjs 里 watchdog_status 补上了 await,MCP 工具不再永远返回 {};server.mjs:1027 的 platformRes → platform 拼写错误也修掉了,看板不会再因为它整个挂掉,而且都配了测试(tests/mcp.test.mjs、tests/server-lint.test.mjs,在 Node 20 上通过)。另外加了 .gitignore、把 __pycache__ 移出仓库,也很好。
不过这一版没有改动下面几项必须修改的问题(下面引用的行号在 78ec38e 上都已重新核对过),所以这次还是 Request changes。
必须修改
-
登录凭据(仍未修复)
社区插件不能读取 MiniMax Code 的登录凭据,这部分请先暂停。目前miniapp/node/server.mjs:39-40、daemon/rust/src/api.rs:197和daemon/reset_card_autouse.py:643-660还在读.cap文件、通过 lease socket 取 access token,再拿它调用额度/重置卡接口。另外reset_card_autouse.py:713-718会把 token 写到~/.config/mcode-reset-card/token,后面:735还会从这里读回来。凭据不能落盘,这部分要一起去掉。 -
直接读写 MiniMax Code 内部数据库(仍未修复)
插件不能直接打开~/.minimax/v2/sqlite/runtime-state.sqlite来读写。- 改目标状态:
goal_sync.rs:210、:279、:1232(UPDATE ...)。 - 读回合记录:
goal_sync.rs:428、bot_guard.rs:1073。 - 直接删除:
goal_sync.rs:932purge_stale_session_sends→:967、goal_sync.rs:895、goal_wake.rs:453(DELETE FROM ...)。这些操作会直接删掉 MiniMax Code 自己的数据,删了就恢复不了,风险比 UPDATE 更大,请全部去掉。
- 改目标状态:
-
读取其他插件的数据目录(仍未修复)
bot_guard.rs:75-78会读minimax-bot的plugin-data/.../minimax-bot/state.json,拿到所有 bot 和会话 id,然后由miniapp/node/bot_wakeup.mjs向这些会话发消息把它们唤醒。插件只能用自己的数据,不能读其他插件的数据,更不能凭这些数据去操作其他插件的会话。请把这部分删掉。 -
minimax-bot 的改动请拆成单独的 PR(仍未修复)
PR 描述说这次不涉及 minimax-bot,但 diff 里还有 commit b446936 / 9a1cc5c 带进来的 7 个plugins/minimax-ai/minimax-bot/*文件(plugin.json 改成 0.7.4、engine.mjs、README、client、两个测试)。请把它们从这个 PR 里移出去,另开一个 PR 单独讨论(不是拒绝这些改动)。另外,tests/turn-retry-forever.test.mjs在 Node 20 上还是有 1 项失败:HTTP 400 被当成可重试的错误了,这个可以在新 PR 里修。 -
npm run check/npm run validate不通过(仍未修复)
LAYOUT_NAME_MISMATCH:目录名是reset-card-autouse,.minimax-plugin/plugin.json:3的 name 是expiry-guardian,两者必须一致。请统一插件名和目录名(改目录名的话,PR 里的路径也要跟着改)。
建议(不阻塞)
server.mjs:1561还在处理/mcp/minimax-bot路径,但端点已经从声明里删掉了,可以一起清理。miniapp/node/*.test.mjs会触发ENTRY_STDOUT警告,建议把测试统一放到tests/下。这一版新加的mcp.test.mjs、server-lint.test.mjs在miniapp/node/和tests/下各有一份完全相同的副本,保留tests/下的一份就够了。- 删掉上面这些逻辑之后,README / docs 里相应的说明也请同步更新。
|
|
||
|
|
||
| // ── OAuth lease:与桌面端同一套登录态 ──────────────────────────────────────── | ||
| const LEASE_SOCK = join(homedir(), '.minimax', 'run', 'mcode-auth-lease-v1.sock'); |
There was a problem hiding this comment.
社区插件不能读取 MiniMax Code 的登录凭据,这部分请先暂停。
| /// 向桌面端的 lease socket 取一个短期 access token。 | ||
| /// 协议:4 字节大端长度前缀 + JSON。详见 packages/oauth-lease-protocol。 | ||
| pub fn acquire_lease_token() -> Option<String> { | ||
| let capability = std::fs::read_to_string(home().join(LEASE_CAP)) |
There was a problem hiding this comment.
同上:这里读凭据并取 access token,请删除。
|
|
||
|
|
||
| # ── 命令 ────────────────────────────────────────────────────────────────────── | ||
| AUTH_CAP_FILE = os.path.expanduser("~/.minimax/run/mcode-auth-lease-v1.cap") |
There was a problem hiding this comment.
同上:这里读凭据文件、通过 lease socket 取 token,请删除。
| return token if isinstance(token, str) and token else None | ||
|
|
||
|
|
||
| def persist_token(token: str) -> None: |
There was a problem hiding this comment.
token 不能落盘,请删除 persist_token,以及 :735 的读回逻辑。
| BEGIN IMMEDIATE;\n\ | ||
| CREATE TEMP TABLE _newly AS\n\ | ||
| \x20 SELECT goal_id, session_id FROM local_runtime_thread_goals WHERE status='active';\n\ | ||
| UPDATE local_runtime_thread_goals\n\ |
There was a problem hiding this comment.
不能直接 UPDATE MiniMax Code 的内部数据库,请去掉。
| continue; | ||
| } | ||
| let del = format!( | ||
| "DELETE FROM local_runtime_queue_items\n\ |
There was a problem hiding this comment.
这里会直接删除 MiniMax Code 自己的数据,而且无法恢复,请去掉(:895、goal_wake.rs:453 也一样)。
| // 同一目标的**旧 epoch** 残留项也要清掉:它们永远不会被消费(epoch 对不上会被 | ||
| // 准入判据 cancel),却会一直占着队列位置。 | ||
| let stale = format!( | ||
| "DELETE FROM local_runtime_queue_items\n\ |
There was a problem hiding this comment.
同上,直接 DELETE,请去掉。
| fn bot_state_path() -> Option<PathBuf> { | ||
| std::env::var("HOME").ok().map(|h| { | ||
| PathBuf::from(h) | ||
| .join(".minimax/v2/plugin-data/liveboards/minimax-bot/state.json") |
There was a problem hiding this comment.
这里读的是其他插件的数据目录,请不要读,也不要据此唤醒其他插件的会话。
| /** Failure reasons a retry cannot fix; anything else (or no reason from an older Host) may be retried. */ | ||
| const NO_RETRY_REASONS = new Set(['auth', 'quota', 'context_too_long', 'blocked', 'invalid_request']); | ||
|
|
||
| /** |
There was a problem hiding this comment.
这个文件和本插件无关,请拆到单独的 PR;另外 400 不应该重试。
| @@ -0,0 +1,21 @@ | |||
| { | |||
| "schemaVersion": 1, | |||
| "name": "expiry-guardian", | |||
There was a problem hiding this comment.
这里和目录名不一致,会触发 LAYOUT_NAME_MISMATCH,导致 check 失败。
15d6578 to
02a6c11
Compare
02a6c11 to
88e8a98
Compare
关于上一轮 review 的回应先谢过前两轮的意见。这一轮只动了不需要产品决策的部分: 已处理(可以在本地复现)
校验结果: 还没动的三项,需要先定方向(这三条会决定插件还剩多少功能,所以想先听意见再动):
我的理解是:第 1 条去掉后,额度/重置卡这条主线就没有数据源了(看板的到期雷达依赖账号接口);第 3 条去掉后,整个 Bot 看门狗就没有 bot 名单了(名字与会话 id 都来自 minimax-bot 的数据目录)。所以这三条不是「删几段代码」,而是要重新界定这个插件还做什么。 想请教一下:
如果按这个方向,剩下能交付的就是:到期雷达(只读本地账本)、触发线配置、决策逻辑与三方可执行性、以及那套「静默失效全部变成会说话」的加固。这三块我可以马上拆成独立 PR 发出来评审,不用等这三项定完。 (本 PR 先保持在「只含插件 + 根 README 登记」的状态,等方向定了我再改。) |
MyPrototypeWhat
left a comment
There was a problem hiding this comment.
感谢这一轮的更新,也谢谢你在评论里把剩下的问题一条条列出来!这一版修好的部分都确认过了:
- 目录改成了
plugins/hylouis233/expiry-guardian,和plugin.json的 name 一致;两个根 README 也补上了本插件那一行。npm run check/npm run validate现在都通过了。 miniapp/node/下重复的测试删掉了,只保留tests/下的一份(node --test tests/*.test.mjs在 Node 20 上 6/6 通过)。- MCP 只保留了
expiry-guardian一个端点,server.mjs里/mcp/minimax-bot的路由也删掉了,不会再和官方插件重名。 watchdog_use_card去掉了,mcp.mjs的说明改成了“只判定不扣卡”的watchdog_decide,测试里也确认了没有扣卡工具。
下面回答你问的三个问题(行号都在 88e8a98 上核对过)。这几项还在代码里,所以这次还是 Request changes。
必须修改
-
登录凭据
社区插件不能读取 MiniMax Code 的登录凭据,这部分请先暂停。涉及的代码:miniapp/node/server.mjs:39-40、daemon/rust/src/api.rs:197、daemon/reset_card_autouse.py:643-660;另外reset_card_autouse.py:713-718把 token 写到~/.config/mcode-reset-card/token,:735又从这里读回来,这部分也要一起去掉。 -
直接读写 MiniMax Code 内部数据库:请全部去掉
插件不能直接打开~/.minimax/v2/sqlite/runtime-state.sqlite,读、改、删、插入都不行。- 改目标状态:
goal_sync.rs:210、:279、:1232(UPDATE ...)。 - 读回合记录:
goal_sync.rs:428、bot_guard.rs:1158、:1161-1163(accepted_at_ms)。 - 插入执行队列:
goal_wake.rs:465(INSERT OR IGNORE INTO ...)。插件不能直接往 MiniMax Code 的执行队列里插入任务。 - 直接删除:
goal_sync.rs:895、:967(purge_stale_session_sends,:932)、goal_wake.rs:453(DELETE FROM ...)。
也就是说,按现在的实现方式,Goal 暂停/恢复和 Bot 看门狗这两块这一轮请先整体移除。
- 改目标状态:
-
读取其他插件的数据:请去掉
bot_guard.rs:75-78读的是minimax-bot的state.json。插件只能用自己的数据,不能读其他插件的数据,也不能据此去唤醒其他插件的会话(miniapp/node/bot_wakeup.mjs)。
关于拆分
很欢迎你提的方案:把只读、能直接交付的部分(基于本地账本的到期雷达、触发配置、决策逻辑、静默失败的加固)单独开一个 PR。直接把这个 PR 裁到这个范围也可以,两种方式都行。只要不涉及上面三项,我们会尽快看。
另外,范围缩到只读的到期雷达之后,根目录 README.md / README.zh-CN.md 里本插件那一行(现在写的是自动暂停 Goal、自动恢复和唤醒)和插件自己的 README / docs 也要同步改,只写插件实际做的事情。
建议(不阻塞)
README.zh-CN.md:83链到的是plugins/hylouis233/expiry-guardian/README.zh-CN.md,但这个文件不存在(中文 README 在docs/README.zh-CN.md)。请把链接改成docs/README.zh-CN.md,或者在插件根目录放一份。main.rs:387的catch_unwind在 release 构建下不起作用:Cargo.toml:16设了panic = "abort",panic 时进程会直接退出,不会被这里接住。保留守护进程的话,二选一处理一下(README 里的说法也要对应改)。
|
|
||
|
|
||
| // ── OAuth lease:与桌面端同一套登录态 ──────────────────────────────────────── | ||
| const LEASE_SOCK = join(homedir(), '.minimax', 'run', 'mcode-auth-lease-v1.sock'); |
There was a problem hiding this comment.
社区插件不能读取 MiniMax Code 的登录凭据,这部分请先暂停。
| /// 向桌面端的 lease socket 取一个短期 access token。 | ||
| /// 协议:4 字节大端长度前缀 + JSON。详见 packages/oauth-lease-protocol。 | ||
| pub fn acquire_lease_token() -> Option<String> { | ||
| let capability = std::fs::read_to_string(home().join(LEASE_CAP)) |
There was a problem hiding this comment.
同上:这里读凭据并取 access token,请删除。
|
|
||
|
|
||
| # ── 命令 ────────────────────────────────────────────────────────────────────── | ||
| AUTH_CAP_FILE = os.path.expanduser("~/.minimax/run/mcode-auth-lease-v1.cap") |
There was a problem hiding this comment.
同上:这里读凭据文件、通过 lease socket 取 token,请删除。
| return token if isinstance(token, str) and token else None | ||
|
|
||
|
|
||
| def persist_token(token: str) -> None: |
There was a problem hiding this comment.
token 不能落盘,请删除 persist_token,以及 :735 的读回逻辑。
| BEGIN IMMEDIATE;\n\ | ||
| CREATE TEMP TABLE _newly AS\n\ | ||
| \x20 SELECT goal_id, session_id FROM local_runtime_thread_goals WHERE status='active';\n\ | ||
| UPDATE local_runtime_thread_goals\n\ |
There was a problem hiding this comment.
不能直接 UPDATE MiniMax Code 的内部数据库,请去掉(:279、:1232 也一样)。
| continue; | ||
| } | ||
| let del = format!( | ||
| "DELETE FROM local_runtime_queue_items\n\ |
There was a problem hiding this comment.
这里会直接删除 MiniMax Code 自己的数据,而且无法恢复,请去掉(:895 也一样)。
| // 同一目标的**旧 epoch** 残留项也要清掉:它们永远不会被消费(epoch 对不上会被 | ||
| // 准入判据 cancel),却会一直占着队列位置。 | ||
| let stale = format!( | ||
| "DELETE FROM local_runtime_queue_items\n\ |
There was a problem hiding this comment.
同上,直接 DELETE,请去掉。
|
|
||
| // client_request_id 上有唯一索引,重复投递会被数据库挡住 ⇒ 天然幂等。 | ||
| let sql = format!( | ||
| "INSERT OR IGNORE INTO local_runtime_queue_items\n\ |
There was a problem hiding this comment.
插件不能直接往 MiniMax Code 的执行队列里插入任务,请去掉。
| IFNULL(s.error_code, 0) AS error_code, IFNULL(s.error_message, '') AS error_message,\n\ | ||
| IFNULL((SELECT MAX(m.created_at_ms) FROM local_runtime_message_rows m\n\ | ||
| WHERE m.session_id = s.session_id), 0) AS last_activity,\n\ | ||
| (SELECT t.status FROM local_runtime_turn_ingress t\n\ |
There was a problem hiding this comment.
不能直接读内部数据库,请去掉(:1161 的 accepted_at_ms 子查询也一样)。
| fn bot_state_path() -> Option<PathBuf> { | ||
| std::env::var("HOME").ok().map(|h| { | ||
| PathBuf::from(h) | ||
| .join(".minimax/v2/plugin-data/liveboards/minimax-bot/state.json") |
There was a problem hiding this comment.
这里读的是其他插件的数据目录,请不要读,也不要据此唤醒其他插件的会话。
88e8a98 to
852152b
Compare
Mini App 看板 + Rust 后台守护进程,通过 macOS launchd 常驻(与桌面端完全独立)。
## 两个设计要点
### 1. 彻底不依赖 cron
唤醒链路是「两段跳」:
```
Rust 守护进程(Host 之外) 蹬王之王自己的 MiniApp(Host 之内)
判定谁挂了 起一个 agent 回合
写一条唤醒请求 ──────▶ 该回合的 agent 用 mavis 工具的 session send
记账 把续跑消息送进目标 bot 的**原会话**
```
为什么不是 cron:实测 cron 目标会话会被运行时自动归档,跑完即触发
CRON_SESSION_TARGET_ARCHIVED。任何由专用宿主承载的值守都不可靠。
### 2. 把「静默失效」变成会说话
「守护进程在跑、日志干净、实际一个 bot 都没被看护」比报错更坏。这一版修掉六个实例,
每一个都在生产里实测复现过:
| # | 症状 | 根因 |
| --- | --- | --- |
| 1 | 整个 Bot 看门狗静默失效(45 分钟零条日志) | minimax-bot 状态文件里一个被截断的代理对转义,Python/Node 能解析、只有 Rust 的 serde_json 严格拒绝 ⇒ 名单读不出来 |
| 2 | 11 次唤醒里 8 次是误判 | 拿会话上的 error_code 判「坏没坏」——那是陈旧值(运行时不清它)。那 8 个 bot 的最新回合其实是 completed。改看 local_runtime_turn_ingress 里最新回合的状态 |
| 3 | 已投递过的请求每 30 分钟重投一次 | acked 的 30 分钟窗口同时管「投递过了吗」与「多久能再救」。拆成两个键:投递判据永久(唯一实例 id),频率限制单独用 bot 键 + 时间戳 |
| 4 | 「读不到 bot 名单」一个字都不打 | 守护进程看起来一切正常,实际是瞎的 ⇒ 明确告警 |
| 5 | 守护进程 panic 崩溃循环 | 解析器按字节切 &str ⇒ 遇到中文 panic。改纯字节解析 + catch_unwind 兜底 |
| 6 | 3 次失败封顶失效 ⇒ 无限唤醒 | 「按 acked 清理失败计数」在 acked 永久化后变成误伤。失败计数只在成功时归零 |
另外修掉两个「看板整个是坏的」:doBuildSnapshot() 里一个拼写错误(platform 写成
platformRes)让取数整个抛异常(v1.2 引入,活了 4 个版本);MCP 工具漏了 await ⇒
JSON.stringify(Promise) = "{}" ⇒ watchdog_status 永远返回空。
### 3. 唤醒链路自检
宿主重启后不会自动拉起任何 MiniApp ⇒ 那段时间「判定」照常、「投递」空转。
守护进程现在会明确告警,运行时恢复后也会说。另有「投递空转」检测。
## 其它
- **local MCP 端点**:watchdog_status / watchdog_wake / watchdog_decide(刻意不暴露扣卡)
- **客户端 401 自愈**:连续 3 次 401 ⇒ 整页重载(上限 5 次)
- **唤醒会话复用**:唤醒不再每次冷启动(实测一轮唤醒 6 个 bot,新建会话数 = 0)
- **瞬时错误不重发**(BUSY / AGENT_OUTCOME_UNKNOWN)⇒ bot 不会收到重复的续跑消息
- **一致性是测出来的**:Rust / Python / MiniApp 三方决策逐字比对 19/19,
校验器带「注入漂移必须被抓到」的自检
## 校验
上游 npm run validate 对本插件 OK(0 错 0 警)、repository: OK、npm test 69/69。
本插件:Rust 75/75、Python 20/20、MiniApp 118/118、三方一致性 19/19。
## 文档
- plugins/hylouis233/expiry-guardian/README.md —— 英文
- plugins/hylouis233/expiry-guardian/docs/README.zh-CN.md —— 中文
- plugins/hylouis233/expiry-guardian/docs/BOT_DIAGNOSIS.md —— 排查手册
852152b to
9e27259
Compare
只读版已另开 #47管理员 review 提的三条红线(不读宿主凭据 / 不读写宿主内部数据库 / 不读别的插件的数据), ⇒ 两个 PR 是二选一:
决策逻辑两边一字未改(三方 19/19 逐字一致),差别只在「数据从哪来」 |
|
这个 PR 已被 #47 取代,先关掉,完整版保留在我自己的 fork 上。 原因:这一版仍然触碰了社区插件不能碰的三类宿主私有数据 ——
按 review 的要求("只要不涉及上面三项,我们会尽快看"),这三项必须拿掉才能被审。 完整功能版(自动扣卡 / 目标暂停恢复 / Bot 看门狗)我会继续在自己的 fork 上维护和使用: |
这是什么
蹬王之王(Expiry Guardian) 的完整版。
launchd常驻,与桌面端完全独立本 PR 只新增
plugins/hylouis233/expiry-guardian/,另外在两个根 README 的MiniApps 表里各加一行登记(上游校验要求每个插件都有登记行)。
管理员在 review 里提了三条社区插件的硬红线:
.cap取 token 调账号接口UPDATE/DELETE/INSERT目标与执行队列、读回合记录state.json拿 bot 与会话 id 去发消息⇒ 本 PR 是完整功能版(自动扣卡、自动暂停目标、自动叫醒 bot),
但它违反了上面三条红线。
⇒ #47 是同功能的只读版:同样的决策逻辑、同样的看板,
但数据源换成本地账本,且不碰宿主任何私有数据、不做任何写操作。
请 review 时先决定走哪条路:
否则这份代码进不了社区仓库
差别只在「数据从哪来」与「能不能自动执行」
两个设计要点
1. 彻底不依赖 cron
唤醒链路是「两段跳」:
为什么不是 cron:实测 cron 目标会话会被运行时自动归档,跑完即触发
CRON_SESSION_TARGET_ARCHIVED。任何由专用宿主承载的值守都不可靠。v1.4 起把 cron 相关代码删干净(
goal_wake::set_cron_armed/goal_sync::reconcile_resume_cron/config::resumeCronId/d_cron())。2. 把「静默失效」变成会说话
「守护进程在跑、日志干净、实际一个 bot 都没被看护」比报错更坏。
这一版修掉了六个实例,每一个都在生产里实测复现过:
serde_json严格拒绝 ⇒ 名单读不出来error_code判「坏没坏」——那是陈旧值(运行时不清它)。那 8 个 bot 的最新回合其实是completed。⇒ 改看local_runtime_turn_ingress里最新回合的状态&str⇒ 遇到中文 panic。⇒ 改纯字节解析 +catch_unwind兜底另外修掉两个「看板整个是坏的」:
doBuildSnapshot()里一个拼写错误(platform→platformRes)⇒ 取数整个抛异常⇒ 额度/决策/卡片全拿不到(v1.2 引入,活了 4 个版本)
await⇒JSON.stringify(Promise)="{}"⇒watchdog_status永远返回空3. 唤醒链路自检
宿主重启后不会自动拉起任何 MiniApp ⇒ 那段时间「判定」照常、「投递」空转。
守护进程现在会明确告警,运行时恢复后也会说。
另有「投递空转」检测:运行时在跑但积压 15 轮不减少 ⇒ 告警。
从宿主外拉起 MiniApp 的每一条路都实测堵死(队列写入 / loopback 凭据 /
宿主 HTTP / deeplink / 官方插件),完整对照表见
docs/README.zh-CN.md。其它
watchdog_status/watchdog_wake/watchdog_decide(刻意不暴露扣卡 —— 扣卡是真实写操作)
BUSY/AGENT_OUTCOME_UNKNOWN)⇒ bot 不会收到重复的续跑消息且校验器带「注入漂移必须被抓到」的自检
校验
npm run validaterepository: OKnpm test文档
plugins/hylouis233/expiry-guardian/README.md—— 英文plugins/hylouis233/expiry-guardian/docs/README.zh-CN.md—— 中文plugins/hylouis233/expiry-guardian/docs/BOT_DIAGNOSIS.md—— 排查手册