mirror of
https://github.com/thedotmack/claude-mem.git
synced 2026-09-20 04:23:02 +08:00
* fix(opencode): stamp platform source on worker posts (#3678) * fix(opencode): scope platform source stamping to issue slice (#3678)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import { join } from "node:path";
|
||||
import { SettingsDefaultsManager } from "../../shared/SettingsDefaultsManager.js";
|
||||
import { normalizePlatformSource } from "../../shared/platform-source.js";
|
||||
|
||||
/**
|
||||
* OpenCode plugin event contract.
|
||||
@@ -116,7 +117,10 @@ function workerPostFireAndForget(
|
||||
fetch(`${WORKER_BASE_URL}${path}`, {
|
||||
method: "POST",
|
||||
headers: JSON_HEADERS,
|
||||
body: JSON.stringify(body),
|
||||
body: JSON.stringify({
|
||||
...body,
|
||||
platformSource: normalizePlatformSource("opencode"),
|
||||
}),
|
||||
}).catch((error: unknown) => {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if (!message.includes("ECONNREFUSED")) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
REGISTERED_OPENCODE_HOOKS,
|
||||
REAL_OPENCODE_EVENT_TYPES,
|
||||
} from "../../src/integrations/opencode-plugin/index";
|
||||
import { normalizePlatformSource } from "../../src/shared/platform-source";
|
||||
|
||||
/**
|
||||
* Regression guard for plan-08 (OpenCode event-contract correctness).
|
||||
@@ -176,6 +177,74 @@ describe("OpenCode plugin event contract", () => {
|
||||
expect(obsBody.tool_name).toBe("read");
|
||||
expect(obsBody.tool_input).toEqual({ path: "/a" });
|
||||
expect(obsBody.tool_response).toBe("file contents");
|
||||
expect(obsBody.platformSource).toBe(normalizePlatformSource("opencode"));
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
it("stamps every session-write POST and leaves GET and deletion unchanged", async () => {
|
||||
const requests: Array<{ method: string; url: string; body: Record<string, unknown> | null }> = [];
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: string | URL | Request, init?: RequestInit) => {
|
||||
requests.push({
|
||||
method: init?.method || "GET",
|
||||
url: String(url),
|
||||
body: init?.body ? JSON.parse(String(init.body)) : null,
|
||||
});
|
||||
return new Response(JSON.stringify({ content: [{ type: "text", text: "No observations found" }] }), {
|
||||
status: 200,
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const plugin = await ClaudeMemPlugin(pluginCtx);
|
||||
const expectedPlatformSource = normalizePlatformSource("opencode");
|
||||
|
||||
const postHookInvocations: Record<string, () => Promise<void>> = {
|
||||
"tool.execute.after": () => plugin["tool.execute.after"](
|
||||
{ tool: "read", sessionID: "ses_contract_tool", callID: "c1" },
|
||||
{ title: "Read", output: "tool output", metadata: {}, args: {} },
|
||||
),
|
||||
"chat.message": () => plugin["chat.message"](
|
||||
{},
|
||||
{
|
||||
message: { role: "assistant", sessionID: "ses_contract_chat" },
|
||||
parts: [{ type: "text", text: "assistant output" }],
|
||||
},
|
||||
),
|
||||
"experimental.session.compacting": () => plugin["experimental.session.compacting"]({ sessionID: "ses_contract_compact" }),
|
||||
event: () => plugin.event({ event: { type: "session.idle", properties: { sessionID: "ses_contract_idle" } } }),
|
||||
};
|
||||
for (const hook of REGISTERED_OPENCODE_HOOKS) {
|
||||
const invoke = postHookInvocations[hook];
|
||||
expect(invoke, `registered hook "${hook}" must have a POST contract case`).toBeDefined();
|
||||
await invoke!();
|
||||
}
|
||||
|
||||
const posts = requests.filter((request) => request.method === "POST");
|
||||
expect(posts).toHaveLength(8);
|
||||
expect(posts.map((request) => request.url)).toEqual([
|
||||
expect.stringContaining("/api/sessions/init"),
|
||||
expect.stringContaining("/api/sessions/observations"),
|
||||
expect.stringContaining("/api/sessions/init"),
|
||||
expect.stringContaining("/api/sessions/observations"),
|
||||
expect.stringContaining("/api/sessions/init"),
|
||||
expect.stringContaining("/api/sessions/summarize"),
|
||||
expect.stringContaining("/api/sessions/init"),
|
||||
expect.stringContaining("/api/sessions/summarize"),
|
||||
]);
|
||||
for (const post of posts) {
|
||||
expect(post.body?.platformSource).toBe(expectedPlatformSource);
|
||||
}
|
||||
|
||||
const postCountBeforeSearchAndDeletion = posts.length;
|
||||
await plugin.tool.claude_mem_search.execute({ query: "auth" });
|
||||
await plugin.event({ event: { type: "session.deleted", properties: { sessionID: "ses_contract_idle" } } });
|
||||
expect(requests.filter((request) => request.method === "POST")).toHaveLength(
|
||||
postCountBeforeSearchAndDeletion,
|
||||
);
|
||||
expect(requests.at(-1)?.method).toBe("GET");
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user