From 8e07bd8af81289c165646372612aadbb6e33804f Mon Sep 17 00:00:00 2001 From: youpaishidifu Date: Mon, 19 Oct 2026 11:46:33 +0800 Subject: [PATCH] =?UTF-8?q?tui.js=EF=BC=9A/manage=20=E6=9D=A5=E6=BA=90B?= =?UTF-8?q?=E6=94=B9=E8=AF=BB=20credential=20=E8=A1=A8(active=3D1=20?= =?UTF-8?q?=E7=9A=84=20integration=5Fid)=E5=89=8D=E7=BC=80=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=20catalog=EF=BC=8C=E8=83=BD=E7=AE=A1=E5=88=B0?= =?UTF-8?q?=E5=86=85=E7=BD=AE=20/connect=20=E7=9A=84=20provider(=E5=A6=82?= =?UTF-8?q?=20Xiaomi=20=E5=85=A8=E5=AE=B6=E6=97=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tui-plugins/oc-session-all.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/tui-plugins/oc-session-all.js b/tui-plugins/oc-session-all.js index 12c466e..3e58948 100644 --- a/tui-plugins/oc-session-all.js +++ b/tui-plugins/oc-session-all.js @@ -426,17 +426,17 @@ function mmReadCatalog() { return new Promise((resolve) => { try { const py = process.platform === "win32" ? "python" : "python3" - // 注意两点坑: - // 1. Python `-c` 单行里 `if row: import sys;` 非法(import 不能跟 if 同行)→ 提前 import sys - // 2. Windows 控制台默认 GBK 编码,catalog 含非 GBK 字符(如 U+2011)会 UnicodeEncodeError - // → 用 sys.stdout.buffer.write 走原始字节(utf-8 编码),Node 侧按 utf-8 解码 + // 读 catalog + credential(credential 表存 /connect 传 key 的内置 provider,如 xiaomi) + // 坑:① Python -c 单行里 if row: import sys 非法 ② Windows GBK 编码 → 全走 buffer.write utf-8 const script = - "import sqlite3,os,sys;" + + "import sqlite3,os,sys,json;" + "db=os.path.join(os.path.expanduser('~'),'.local','share','opencode','opencode.db');" + "con=sqlite3.connect(db);" + "row=con.execute(\"SELECT value FROM kv WHERE key='models-dev:catalog'\").fetchone();" + + "creds=[r[0] for r in con.execute(\"SELECT integration_id FROM credential WHERE active=1\").fetchall()];" + "con.close();" + - "sys.stdout.buffer.write(row[0].encode('utf-8')) if row else None" + "obj={'catalog':(row[0] if row else None),'credentials':creds};" + + "sys.stdout.buffer.write(json.dumps(obj, ensure_ascii=False).encode('utf-8'))" const r = spawn(py, ["-c", script], { stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, PYTHONIOENCODING: "utf-8", PYTHONUTF8: "1" }, @@ -500,24 +500,27 @@ async function openModelManager(context) { } // 来源 B:catalog 里「已连接内置 provider」。 - // 「已连接」= 该 provider 的 env 字段里的某个 API key 存在于 process.env - // (用户 /connect 时 OC 把 key 注入当前进程环境,运行时态,不落在文件里)。 - // 只列「能判定已连接」的 catalog provider,不会全量拉 232 个。 + // credential 表存的是"集成名"(如 xiaomi),catalog 存的是"具体 providerID"(xiaomi、 + // xiaomi-token-plan-cn、xiaomi-token-plan-sgp、xiaomi-token-plan-ams 等)。 + // 匹配规则:catalog providerID 以 credential.integration_id 开头(前缀匹配)就算已连接。 const cat = await mmReadCatalog() - if (cat && cat.body) { + if (cat && cat.catalog && cat.credentials) { let body = {} try { - body = JSON.parse(cat.body) + body = JSON.parse(cat.catalog) } catch (e) { log("[oc-session-all] /manage catalog body parse 失败: " + e.message) } + const credentials = Array.isArray(cat.credentials) ? cat.credentials : [] + if (credentials.length === 0) { + log("[oc-session-all] /manage credential 表无 active=1 记录(没 /connect 过内置 provider)") + } for (const cid of Object.keys(body)) { const cv = body[cid] || {} const models = Object.keys((cv && cv.models) || {}) if (models.length === 0) continue - // 已连接判定:provider.env 数组里任一 key 在 process.env 里有值 - const envs = Array.isArray(cv.env) ? cv.env : [] - const isConnected = envs.some((k) => process.env && process.env[k]) + // 前缀匹配:providerID 以某个 credential.integration_id 开头 + const isConnected = credentials.some((integ) => cid === integ || cid.startsWith(integ + "-") || cid.startsWith(integ + "_")) if (!isConnected) continue const name = cv.name || cid addProvider(name, models, "catalog")