移除调试文件和目录
This commit is contained in:
@@ -14,3 +14,5 @@ __pycache__/
|
||||
# 备份与本地回滚产物
|
||||
*.bak-*
|
||||
skills-backup/
|
||||
*-debug.js
|
||||
*-test.js
|
||||
@@ -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 };
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user