From 4431ed833545a307a54015f1406e58c37164d681 Mon Sep 17 00:00:00 2001 From: ypshidifu Date: Thu, 24 Sep 2026 12:43:18 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E8=B0=83=E8=AF=95=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=92=8C=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + tui-plugins/oc-session-all-debug.js | 58 --------------- tui-plugins/readmcpcfg.test.mjs | 105 ---------------------------- 3 files changed, 2 insertions(+), 163 deletions(-) delete mode 100644 tui-plugins/oc-session-all-debug.js delete mode 100644 tui-plugins/readmcpcfg.test.mjs diff --git a/.gitignore b/.gitignore index 9a5a5ba..1b3de0f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ __pycache__/ # 备份与本地回滚产物 *.bak-* skills-backup/ +*-debug.js +*-test.js \ No newline at end of file diff --git a/tui-plugins/oc-session-all-debug.js b/tui-plugins/oc-session-all-debug.js deleted file mode 100644 index 46e8e7d..0000000 --- a/tui-plugins/oc-session-all-debug.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * OpenCode TUI Plugin: Show All Sessions (DEBUG VERSION) - * - * Minimal version to test if plugin loads without crashes. - * Only includes basic MCP toast suppression and keymap. - */ - -// ── Plugin ───────────────────────────────────────────────────────────── - -const tui = async (api) => { - // Log that we're alive - console.log("[oc-session-all] Plugin loaded successfully!"); - - // ─── MCP Error Toast Suppression ───────────────────────────────────── - api.event.on("tui.toast.show", (event) => { - const props = event.properties; - if ( - props.variant === "error" && - typeof props.message === "string" && - (props.message.toLowerCase().includes("mcp") || - props.message.toLowerCase().includes("mcp server") || - props.message.toLowerCase().includes("mcp error") || - props.message.toLowerCase().includes("failed to connect") || - props.message.toLowerCase().includes("connection refused")) - ) { - props.variant = "info"; - props.message = "MCP server offline (auto-reconnect when available)"; - props.duration = 2000; - } - }); - - // ─── Minimal keymap (just to test registration works) ───────────────── - try { - api.keymap.registerLayer({ - bindings: [ - { - key: "ctrl+o", - desc: "All sessions picker (debug)", - preventDefault: true, - cmd: () => { - console.log("[oc-session-all] Ctrl+O pressed!"); - api.ui.toast({ - message: "Plugin loaded! Ctrl+O works!", - variant: "info", - }); - }, - }, - ], - }); - console.log("[oc-session-all] Keymap registered successfully!"); - } catch (err) { - console.error("[oc-session-all] Keymap registration failed:", err); - } -}; - -// ── Export ────────────────────────────────────────────────────────────── - -export default { id: "oc-session-all-debug", tui }; diff --git a/tui-plugins/readmcpcfg.test.mjs b/tui-plugins/readmcpcfg.test.mjs deleted file mode 100644 index 5bd0758..0000000 --- a/tui-plugins/readmcpcfg.test.mjs +++ /dev/null @@ -1,105 +0,0 @@ -// readMcpCfg 单测:从 oc-session-all.js 源文件动态提取解析区块来测, -// 保证测的是源码本体(不是复制的逻辑)。 -// 场景:1) 键值格式 2) 旧三行格式+自动迁移 3) 路径失效自愈 -import { readFileSync, writeFileSync, mkdtempSync, existsSync, rmSync, mkdirSync } from "node:fs" -import { tmpdir } from "node:os" -import { join, dirname, basename } from "node:path" - -const SRC = join(import.meta.dirname, "oc-session-all.js") -const text = readFileSync(SRC, "utf8") - -// 抽取 CFG_TXT 定义到 activeHasMcp 之前的全部函数(含 ON_FLAG/writeMcpCfg/heal/readMcpCfg) -const start = text.indexOf("const CFG_TXT =") -const end = text.indexOf("function activeHasMcp") -if (start < 0 || end < 0 || end < start) { - console.error("EXTRACT_FAIL: markers not found") - process.exit(1) -} -const block = text.slice(start, end) - -const work = mkdtempSync(join(tmpdir(), "mcpcfg-test-")) -const LOG_DIR = work -const CFG_TXT = join(work, "mcpcfg.txt") -const ON_FLAG = join(work, "mcp.on.flag") -function log(m) { - /* silent in tests */ -} - -const moduleSrc = ` -import { existsSync, readFileSync, writeFileSync, readdirSync } from "node:fs" -import { join, basename, dirname } from "node:path" -const LOG_DIR = ${JSON.stringify(LOG_DIR)} -function log(m) {} -${block} -export { readMcpCfg, parseMode, writeMcpCfg } -` -const modPath = join(work, "extracted.mjs") -writeFileSync(modPath, moduleSrc, "utf8") -const { pathToFileURL } = await import("node:url") -const { readMcpCfg } = await import(pathToFileURL(modPath).href) - -let pass = 0 -let fail = 0 -function check(name, cond, extra) { - if (cond) { - pass++ - console.log("PASS " + name) - } else { - fail++ - console.log("FAIL " + name + (extra ? " | " + extra : "")) - } -} - -// ---- 回归:源文件 path 导入必须含 dirname ---- -// healShadowPath 用了 dirname;源文件缺导入时 ReferenceError 会被它自己的 -// catch 吞掉 → 影子自愈静默失效。prelude 里复制的导入会掩盖这个缺失 -// (曾导致 15/15 假绿),所以必须对源文件本体断言。 -const pathImportLine = (text.match(/^import\s*\{[^}]*\}\s*from\s*["']path["']/m) || [""])[0] -check( - "S0 源文件 path 导入含 dirname", - /dirname/.test(pathImportLine), - "import line=" + pathImportLine, -) - -// ---- 场景1:键值格式(注释+中文冒号)---- -const active = join(work, "opencode.json") -const shadow = join(work, "opencode.json.2") -writeFileSync(active, JSON.stringify({ mcp: { servers: { a: {} } }, tag: "on" })) -writeFileSync(shadow, JSON.stringify({ tag: "quiet" })) -writeFileSync( - CFG_TXT, - "# 注释行\n模式: 自动\n含MCP的配置: " + active + "\n安静配置: " + shadow + "\n", - "utf8", -) -let r = readMcpCfg() -check("S1 mode=auto", r.mode === "auto", "got=" + r.mode) -check("S1 active识别", r.activePath === active, "got=" + r.activePath) -check("S1 无error", !r.error, "err=" + r.error) -check("S1 不迁移(已是键值)", !r.migrated, "migrated=" + r.migrated) - -// ---- 场景2:旧三行格式 -> 解析 + 自动迁移写回 ---- -writeFileSync(CFG_TXT, "手动\n" + active + "\n" + shadow + "\n", "utf8") -r = readMcpCfg() -check("S2 mode=manual", r.mode === "manual", "got=" + r.mode) -check("S2 active识别", r.activePath === active, "got=" + r.activePath) -check("S2 迁移写回", existsSync(CFG_TXT) && readFileSync(CFG_TXT, "utf8").includes("模式:"), "no kv rewrite") -check("S2 迁移后路径保留", readFileSync(CFG_TXT, "utf8").includes(shadow), "shadow lost") -check("S2 再读仍正确", readMcpCfg().mode === "manual" && !readMcpCfg().error) - -// ---- 场景3:真实 bug 复现 —— 含MCP行指向的备份文件被删(.1 不存在)---- -const gone = join(work, "opencode.json.1") -writeFileSync(CFG_TXT, "模式: 自动\n含MCP的配置: " + gone + "\n安静配置: " + active + "\n", "utf8") -r = readMcpCfg() -check("S3 自愈后无error", !r.error, "err=" + r.error) -check("S3 healed=true", !!r.healed, "healed=" + r.healed) -check("S3 active=活文件", r.activePath === active, "ap=" + r.activePath) -check("S3 影子=存在的互补文件", r.shadowPath === shadow || r.quietPath === shadow || r.onPath === shadow, - "shadow=" + r.shadowPath + " on=" + r.onPath + " quiet=" + r.quietPath) -const rewritten = readFileSync(CFG_TXT, "utf8") -check("S3 写回含存在的影子路径", rewritten.includes(shadow), "rewritten=" + rewritten.replace(/\n/g, "|")) -check("S3 写回后二次读取仍OK", (() => { const r2 = readMcpCfg(); return !r2.error && r2.activePath === active })(), - "reread=" + JSON.stringify({ e: readMcpCfg().error })) - -rmSync(work, { recursive: true, force: true }) -console.log(`\nRESULT: ${pass} passed, ${fail} failed`) -process.exit(fail ? 1 : 0)