From 58e85960a103088cf9ff8bddb0c9a4c6b7efd7ad Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 4 Apr 2026 01:12:35 +0900 Subject: [PATCH 1/3] test(mcp): add regression coverage for transcript and disable overrides Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../claude-code-mcp-loader/loader.test.ts | 35 +++++++++ .../claude-code-hooks/transcript.test.ts | 78 +++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/src/features/claude-code-mcp-loader/loader.test.ts b/src/features/claude-code-mcp-loader/loader.test.ts index 48ab1a288..4e7719cb6 100644 --- a/src/features/claude-code-mcp-loader/loader.test.ts +++ b/src/features/claude-code-mcp-loader/loader.test.ts @@ -138,6 +138,41 @@ describe("getSystemMcpServerNames", () => { } }) + it("removes a server name when a higher-precedence config disables it", async () => { + // given + writeFileSync(join(TEST_HOME, ".claude.json"), JSON.stringify({ + mcpServers: { + playwright: { + command: "npx", + args: ["@playwright/mcp@latest"], + }, + }, + })) + writeFileSync(join(TEST_DIR, ".mcp.json"), JSON.stringify({ + mcpServers: { + playwright: { + command: "npx", + args: ["@playwright/mcp@latest"], + disabled: true, + }, + }, + })) + + const originalCwd = process.cwd() + process.chdir(TEST_DIR) + + try { + // when + const { getSystemMcpServerNames } = await import("./loader") + const names = getSystemMcpServerNames() + + // then + expect(names.has("playwright")).toBe(false) + } finally { + process.chdir(originalCwd) + } + }) + it("merges server names from multiple .mcp.json files", async () => { // given mkdirSync(join(TEST_DIR, ".claude"), { recursive: true }) diff --git a/src/hooks/claude-code-hooks/transcript.test.ts b/src/hooks/claude-code-hooks/transcript.test.ts index a31aa3922..d7c4837f4 100644 --- a/src/hooks/claude-code-hooks/transcript.test.ts +++ b/src/hooks/claude-code-hooks/transcript.test.ts @@ -99,4 +99,82 @@ describe("transcript caching", () => { expect(client.session.messages).toHaveBeenCalledTimes(2) }) + + it("keeps intermediate tool calls across sequential transcript rebuilds", async () => { + // given + const client = createMockClient([]) + + // when + const firstPath = await buildTranscriptFromSession( + client, + "ses_sequential", + "/tmp", + "bash", + { command: "echo first" } + ) + const secondPath = await buildTranscriptFromSession( + client, + "ses_sequential", + "/tmp", + "read", + { filePath: "/tmp/second.txt" } + ) + const thirdPath = await buildTranscriptFromSession( + client, + "ses_sequential", + "/tmp", + "write", + { filePath: "/tmp/third.txt", content: "third" } + ) + + // then + expect(firstPath).not.toBeNull() + expect(secondPath).not.toBeNull() + expect(thirdPath).not.toBeNull() + + if (thirdPath) { + const content = readFileSync(thirdPath, "utf-8") + + expect(content).toContain("Bash") + expect(content).toContain("Read") + expect(content).toContain("Write") + } + + deleteTempTranscript(firstPath) + deleteTempTranscript(secondPath) + deleteTempTranscript(thirdPath) + }) + + it("cleans up previous temp transcript files when rebuilding cached transcripts", async () => { + // given + const client = createMockClient([]) + + // when + const firstPath = await buildTranscriptFromSession( + client, + "ses_cleanup", + "/tmp", + "bash", + { command: "echo first" } + ) + const secondPath = await buildTranscriptFromSession( + client, + "ses_cleanup", + "/tmp", + "read", + { filePath: "/tmp/second.txt" } + ) + + // then + expect(firstPath).not.toBeNull() + expect(secondPath).not.toBeNull() + + if (firstPath && secondPath) { + expect(existsSync(firstPath)).toBe(false) + expect(existsSync(secondPath)).toBe(true) + } + + deleteTempTranscript(firstPath) + deleteTempTranscript(secondPath) + }) }) From 35c34ea06b380cd065b25490116c472ded518b74 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 4 Apr 2026 01:13:02 +0900 Subject: [PATCH 2/3] fix(hooks): preserve transcript cache history across rebuilds Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/hooks/claude-code-hooks/transcript.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/hooks/claude-code-hooks/transcript.ts b/src/hooks/claude-code-hooks/transcript.ts index 2c1c56723..ce1f9c98e 100644 --- a/src/hooks/claude-code-hooks/transcript.ts +++ b/src/hooks/claude-code-hooks/transcript.ts @@ -165,10 +165,12 @@ export async function buildTranscriptFromSession( ): Promise { try { let baseEntries: string[] + let previousTempPath: string | null = null const cached = transcriptCache.get(sessionId) if (cached && isCacheValid(cached)) { baseEntries = cached.baseEntries + previousTempPath = cached.tempPath } else { // Fetch full session messages (only on first call or cache expiry) const response = await client.session.messages({ @@ -199,6 +201,10 @@ export async function buildTranscriptFromSession( // Append current tool call const allEntries = [...baseEntries, buildCurrentEntry(currentToolName, currentToolInput)] + if (previousTempPath) { + try { unlinkSync(previousTempPath) } catch { /* ignore */ } + } + const tempPath = join( tmpdir(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl` @@ -208,7 +214,9 @@ export async function buildTranscriptFromSession( // Update cache temp path for cleanup tracking const cacheEntry = transcriptCache.get(sessionId) if (cacheEntry) { + cacheEntry.baseEntries = allEntries cacheEntry.tempPath = tempPath + cacheEntry.createdAt = Date.now() } return tempPath From 67145b5339ea28b7648359f0e36fd2c6aa879011 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 4 Apr 2026 01:13:23 +0900 Subject: [PATCH 3/3] fix(mcp): honor disabled server overrides in system name discovery Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/features/claude-code-mcp-loader/loader.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/features/claude-code-mcp-loader/loader.ts b/src/features/claude-code-mcp-loader/loader.ts index 49c56ca2f..7be6a9ac7 100644 --- a/src/features/claude-code-mcp-loader/loader.ts +++ b/src/features/claude-code-mcp-loader/loader.ts @@ -59,7 +59,10 @@ export function getSystemMcpServerNames(): Set { if (!config?.mcpServers) continue for (const [name, serverConfig] of Object.entries(config.mcpServers)) { - if (serverConfig.disabled) continue + if (serverConfig.disabled) { + names.delete(name) + continue + } if (!shouldLoadMcpServer(serverConfig, cwd)) continue names.add(name) }