Files
oh-my-pi/packages/coding-agent/test/acp-mcp-isolation.test.ts
T
oldschoola 14252e71cb fix: Windows test failures — path handling, EBUSY, SQLite handle leaks
Fix all Windows-specific test failures caused by path handling problems
and EBUSY errors from unclosed SQLite database handles.

Root causes fixed:
1. POSIX path assumptions: replaced hard-coded file:///tmp, /repo, etc.
   with pathToFileURL/path.resolve/path.join computed expectations
2. shortenPath() now normalizes backslashes to forward slashes after ~
   and respects home directory boundaries
3. HistoryStorage.resetInstance() leaked its Database — added #close()
   that finalizes all prepared statements and closes the DB
4. AgentStorage gained the same resetInstance()/#close() pattern
5. SqliteAuthCredentialStore.close() leaked one-off prepared statements
   from inline this.#db.prepare() calls — wrapped each in try/finally
6. model-cache.ts used a process-global DB even for custom dbPath —
   now opens/closes per-call via withModelCacheDb
7. createAgentSession leaked AuthStorage on construction failure —
   added ownsAuthStorage cleanup in catch block
8. MnemopiBackend.removeDbFiles() now truly best-effort (catches errors)
9. TempDir retry window expanded from 4x10ms to 40x25ms
10. TempDir prefix convention: non-@ prefixes created dirs relative to
    cwd instead of os.tmpdir() — all test temp dirs now use @ prefix
11. Shell-escaped interpolated paths in bash tool tests
12. git core.autocrlf false in autoresearch test repo init

All 522 previously-failing Windows tests now pass.
2026-06-18 21:32:38 -07:00

78 lines
2.9 KiB
TypeScript

/**
* Regression test for issue #1234.
*
* `omp acp` must not auto-discover host `.mcp.json` servers when creating a
* session for an ACP client. MCP server ownership belongs entirely to the ACP
* client (`session/new.mcpServers` → `AcpAgent#configureMcpServers`); letting
* `createAgentSession` run on-disk discovery in parallel registers host MCP
* tools that shadow the client-supplied ones in the session tool registry.
*
* The contract enforced here is narrow on purpose: every call routed through
* the ACP session factory must reach `createAgentSession` with
* `enableMCP: false`, regardless of what `baseOptions` carries.
*/
import { describe, expect, it } from "bun:test";
import { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
import { createAcpSessionFactory } from "@oh-my-pi/pi-coding-agent/main";
import type { CreateAgentSessionOptions, CreateAgentSessionResult } from "@oh-my-pi/pi-coding-agent/sdk";
import type { AgentSession } from "@oh-my-pi/pi-coding-agent/session/agent-session";
import { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
import { TempDir } from "@oh-my-pi/pi-utils";
describe("createAcpSessionFactory MCP isolation (issue #1234)", () => {
it("forces enableMCP=false even when baseOptions opts in", async () => {
const tempDir = TempDir.createSync("@pi-acp-mcp-isolation-");
let authStorage: AuthStorage | undefined;
try {
authStorage = await AuthStorage.create(tempDir.join("auth.db"));
const modelRegistry = new ModelRegistry(authStorage);
const settings = Settings.isolated({});
const fakeSession = {} as AgentSession;
const captured: CreateAgentSessionOptions[] = [];
const createSession = async (options: CreateAgentSessionOptions): Promise<CreateAgentSessionResult> => {
captured.push(options);
return {
session: fakeSession,
extensionsResult: {
extensions: [],
errors: [],
runner: undefined,
} as unknown as CreateAgentSessionResult["extensionsResult"],
setToolUIContext: () => {},
eventBus: {
emit: () => {},
on: () => () => {},
off: () => {},
} as unknown as CreateAgentSessionResult["eventBus"],
};
};
// baseOptions deliberately sets enableMCP=true to prove the factory ignores it.
const factory = createAcpSessionFactory({
baseOptions: { enableMCP: true } as CreateAgentSessionOptions,
settings,
sessionDir: tempDir.join("sessions"),
authStorage,
modelRegistry,
parsedArgs: {},
rawArgs: [],
createSession,
});
const result = await factory(tempDir.path());
expect(result).toBe(fakeSession);
expect(captured).toHaveLength(1);
expect(captured[0].enableMCP).toBe(false);
} finally {
try {
authStorage?.close();
} finally {
await Bun.sleep(0);
await tempDir.remove();
}
}
});
});