diff --git a/README.md b/README.md index 1fff063..454008e 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login - 要收尾时调用 `kt_finish_task`,默认只生成计划和 review;需要执行验证时显式传 `runValidation=true`。 - 大方向结束前调用 `kt_workstream_closeout` 或 `pnpm run workstream-closeout`;必须分别传入 `--review` 的 KT 全局审查证据和 `--superpowers-review` 的 Superpowers code review 证据;如果识别到测试流、卡点、误报、清理、部署观测或命令模板,要先升级对应 ktWorkflow 规则再报告完成。 - 文件改动完成并验证后调用 `kt_global_code_review`,或运行 `pnpm run global-review`;它只读扫描,不删除文件、不提交代码。`findings` 先判定真实风险或工具误报,真实风险修业务代码,误报修 `mcp/ktWorkflow/src/tools/review.ts` 并复跑。 -- QQBot NapCat 登录 review 会检查验证码 pending、Docker 日志窗口、API Pod 读取超时,以及 `needNewDevice/jumpUrl` 是否被保留为 `deviceVerifyUrl` pending 状态。 +- QQBot NapCat 登录 review 会检查验证码 pending、Docker 日志窗口、API Pod 读取超时,以及 `needNewDevice/jumpUrl` 是否进入 `GetNewDeviceQRCode -> PollNewDeviceQR -> NewDeviceLogin` 或兼容的 `deviceVerifyUrl` pending 状态。 - 代码或配置改动后调用 `kt_change_doc_sync`,把需要同步的 README/API/AGENTS/docs/Obsidian/skill/ktWorkflow 入口补齐;无需同步时把原因写进收尾证据。 - 报告非平凡任务完成前调用 `kt_workflow_loop_audit`,确认测试证据、文档同步、历史清理最终 `deleted=0`、问题固化、ktWorkflow 升级、KT 全局 review 和 Superpowers code review 都过门;清理证据必须显式传入,不能依赖缺省值。 - 要提交或推送时先调用 `kt_commit_plan` / `kt_push_plan`,按仓库分组确认范围。 diff --git a/src/selfTest.ts b/src/selfTest.ts index 1d90baf..38600ac 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -256,11 +256,17 @@ export async function runSelfTest(): Promise { " }", "}", "if (captchaResult?.needNewDevice && captchaResult.jumpUrl) {", - " return this.keepDeviceVerifyPending(session, captchaResult.jumpUrl, '验证码已通过');", + " return this.startNewDeviceVerification(session, container, captchaResult);", "}", - "private keepDeviceVerifyPending(session, deviceVerifyUrl) {", - " session.deviceVerifyUrl = deviceVerifyUrl;", + "private async startNewDeviceVerification(session, container, captchaResult) {", + " session.deviceVerifyUrl = captchaResult.jumpUrl;", " session.captchaUrl = undefined;", + " session.newDeviceQrcode = await this.client.GetNewDeviceQRCode();", + " session.newDeviceStatus = 'qr-pending';", + "}", + "private async pollNewDeviceVerification(session) {", + " await this.client.PollNewDeviceQR();", + " await this.client.NewDeviceLogin();", "}", "private async detectPasswordCaptchaUrl(container, sinceMs, allowTailFallback = true) {", " await this.containerService.detectRuntimeCaptchaUrl(container, sinceMs);", @@ -290,7 +296,8 @@ export async function runSelfTest(): Promise { (item) => item.category === "qqbot-napcat-captcha-log-window-late" || item.category === "qqbot-napcat-captcha-status-before-log-url" || - item.category === "qqbot-napcat-captcha-status-clears-pending", + item.category === "qqbot-napcat-captcha-status-clears-pending" || + item.category === "qqbot-napcat-new-device-drops-pending", ) ) { throw new Error("QQBot captcha flow valid self-check produced false positive"); diff --git a/src/tools/review.ts b/src/tools/review.ts index f3511f8..7c43e88 100644 --- a/src/tools/review.ts +++ b/src/tools/review.ts @@ -560,10 +560,30 @@ export function findQqbotNapcatCaptchaFlowFindings( }); } + const hasLegacyDeviceVerifyPending = + content.includes("keepDeviceVerifyPending") && + content.includes("deviceVerifyUrl"); + const hasNapcatNewDeviceApiFlow = + content.includes("GetNewDeviceQRCode") && + content.includes("PollNewDeviceQR") && + content.includes("NewDeviceLogin") && + content.includes("deviceVerifyUrl") && + content.includes("newDeviceQrcode") && + content.includes("newDeviceStatus") && + content.includes("session.captchaUrl = undefined"); + const hasNapcatNewDeviceWrapperFlow = + content.includes("startNewDeviceVerification") && + content.includes("pollNewDeviceVerification") && + content.includes("completePasswordLoginAfterChallenge") && + content.includes("deviceVerifyUrl") && + content.includes("newDeviceQrcode") && + content.includes("newDeviceStatus") && + content.includes("session.captchaUrl = undefined"); if ( content.includes("needNewDevice") && - (!content.includes("keepDeviceVerifyPending") || - !content.includes("deviceVerifyUrl")) + !hasLegacyDeviceVerifyPending && + !hasNapcatNewDeviceApiFlow && + !hasNapcatNewDeviceWrapperFlow ) { findings.push({ category: "qqbot-napcat-new-device-drops-pending",