From 54a2b54b8b96004caa961b755fce788f9432cff5 Mon Sep 17 00:00:00 2001 From: araharah-executor Date: Sat, 24 Oct 2026 03:08:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(04-04):=20register-commands=20arms=20every?= =?UTF-8?q?=20shadowing=20scope=20=E2=80=94=20stale=20all=5Fprivate=5Fchat?= =?UTF-8?q?s=20set=20hid=20/cari=20(device-gate=20finding)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot/scripts/register-commands.mjs | 38 +++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/bot/scripts/register-commands.mjs b/bot/scripts/register-commands.mjs index e8c4b71..6793abd 100644 --- a/bot/scripts/register-commands.mjs +++ b/bot/scripts/register-commands.mjs @@ -69,24 +69,38 @@ function menuFor(locale) { }); } -/* ————— exactly two API calls: default scope, then the ms scope (D-03/D-04) ————— */ +/* ————— scope set (device-gate fix 2026-10-24): Telegram resolves a chat's + * command menu from the NARROWEST scope that has ANY commands set — a stale + * all_private_chats set shadows the default scope entirely (the /cari-missing- + * from-menu incident). The script therefore arms every scope it may shadow: + * default (en) · default+ms · all_private_chats (en) · all_private_chats+ms + * and CLEARS the group scopes (leftover phase-2 experiments) so no junk set + * shadows anything elsewhere. ————— */ const API = `https://api.telegram.org/bot${token}/setMyCommands`; const JSON_HEADERS = { "content-type": "application/json" }; -const defaultPayload = { commands: menuFor("en"), bot_command_scope: { type: "default" } }; -const msPayload = { commands: menuFor("ms"), bot_command_scope: { type: "default" }, language_code: "ms" }; +const CALLS = [ + { label: "default (en)", body: { commands: menuFor("en"), bot_command_scope: { type: "default" } } }, + { label: "default (ms)", body: { commands: menuFor("ms"), bot_command_scope: { type: "default" }, language_code: "ms" } }, + { label: "all_private_chats (en)", body: { commands: menuFor("en"), bot_command_scope: { type: "all_private_chats" } } }, + { label: "all_private_chats (ms)", body: { commands: menuFor("ms"), bot_command_scope: { type: "all_private_chats" }, language_code: "ms" } }, + { label: "clear all_group_chats", body: { commands: [], bot_command_scope: { type: "all_group_chats" } } }, + { label: "clear all_chat_administrators", body: { commands: [], bot_command_scope: { type: "all_chat_administrators" } } }, +]; -const defaultRes = await fetch(API, { method: "POST", headers: JSON_HEADERS, body: JSON.stringify(defaultPayload) }); -const defaultBody = await defaultRes.json(); -console.log(`default scope -> ok:${defaultBody.ok} result:${JSON.stringify(defaultBody.result ?? null)}`); +let failed = null; +for (const call of CALLS) { + const res = await fetch(API, { method: "POST", headers: JSON_HEADERS, body: JSON.stringify(call.body) }); + const body = await res.json(); + console.log(`${call.label.padEnd(30)} -> ok:${body.ok} ${body.ok ? "" : JSON.stringify(body)}`); + if (!body.ok && failed === null) failed = body; +} -const msRes = await fetch(API, { method: "POST", headers: JSON_HEADERS, body: JSON.stringify(msPayload) }); -const msBody = await msRes.json(); -console.log(`ms scope -> ok:${msBody.ok} result:${JSON.stringify(msBody.result ?? null)}`); - -if (!defaultBody.ok || !msBody.ok) { - const firstError = !defaultBody.ok ? defaultBody : msBody; +if (!failed) { + console.log("all command scopes armed"); +} else { + const firstError = failed; console.error(`setMyCommands failed: ${firstError.error_code ?? "?"} ${firstError.description ?? "unknown error"}`); process.exit(1); }