- background_output: snapshot read cursor before consuming, restore on /undo message removal so re-reads return data (fixes #2915) - MCP loader: preserve oauth field in transformMcpServer, add scope/ projectPath filtering so local-scoped MCPs only load in matching directories (fixes #2917) - runtime-fallback: add 'reached your usage limit' to retryable error patterns so quota exhaustion triggers model fallback (fixes #2918) Verified: bun test (4606 pass / 0 fail), tsc --noEmit clean
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
|
import { mkdirSync, rmSync, writeFileSync } from "fs"
|
|
import { tmpdir } from "os"
|
|
import { join } from "path"
|
|
import type { LoadedPlugin } from "./types"
|
|
|
|
const TEST_DIR = join(tmpdir(), `plugin-mcp-loader-test-${Date.now()}`)
|
|
const PROJECT_DIR = join(TEST_DIR, "project")
|
|
const PLUGIN_DIR = join(TEST_DIR, "plugin")
|
|
const MCP_CONFIG_PATH = join(PLUGIN_DIR, "mcp.json")
|
|
|
|
describe("loadPluginMcpServers", () => {
|
|
beforeEach(() => {
|
|
mkdirSync(PROJECT_DIR, { recursive: true })
|
|
mkdirSync(PLUGIN_DIR, { recursive: true })
|
|
mock.module("../../shared/logger", () => ({
|
|
log: () => {},
|
|
}))
|
|
})
|
|
|
|
afterEach(() => {
|
|
mock.restore()
|
|
rmSync(TEST_DIR, { recursive: true, force: true })
|
|
})
|
|
|
|
describe("#given plugin MCP entries with local scope metadata", () => {
|
|
it("#when loading plugin MCP servers #then only entries matching the current cwd are included", async () => {
|
|
writeFileSync(
|
|
MCP_CONFIG_PATH,
|
|
JSON.stringify({
|
|
mcpServers: {
|
|
globalServer: {
|
|
command: "npx",
|
|
args: ["global-plugin-server"],
|
|
},
|
|
matchingLocal: {
|
|
command: "npx",
|
|
args: ["matching-plugin-local"],
|
|
scope: "local",
|
|
projectPath: PROJECT_DIR,
|
|
},
|
|
nonMatchingLocal: {
|
|
command: "npx",
|
|
args: ["non-matching-plugin-local"],
|
|
scope: "local",
|
|
projectPath: join(PROJECT_DIR, "other-project"),
|
|
},
|
|
},
|
|
})
|
|
)
|
|
|
|
const plugin: LoadedPlugin = {
|
|
name: "demo-plugin",
|
|
version: "1.0.0",
|
|
scope: "project",
|
|
installPath: PLUGIN_DIR,
|
|
pluginKey: "demo-plugin@test",
|
|
mcpPath: MCP_CONFIG_PATH,
|
|
}
|
|
|
|
const originalCwd = process.cwd()
|
|
process.chdir(PROJECT_DIR)
|
|
|
|
try {
|
|
const { loadPluginMcpServers } = await import("./mcp-server-loader")
|
|
const servers = await loadPluginMcpServers([plugin])
|
|
|
|
expect(servers).toHaveProperty("demo-plugin:globalServer")
|
|
expect(servers).toHaveProperty("demo-plugin:matchingLocal")
|
|
expect(servers).not.toHaveProperty("demo-plugin:nonMatchingLocal")
|
|
} finally {
|
|
process.chdir(originalCwd)
|
|
}
|
|
})
|
|
})
|
|
})
|