fix(plugin): capture compaction context during compaction

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-03-08 02:23:51 +09:00
parent c9e0428d80
commit cd6cc9e4fb
2 changed files with 24 additions and 9 deletions
+22 -8
View File
@@ -2,6 +2,10 @@ import { describe, expect, it, mock } from "bun:test"
describe("experimental.session.compacting handler", () => { describe("experimental.session.compacting handler", () => {
function createCompactingHandler(hooks: { function createCompactingHandler(hooks: {
compactionContextInjector?: {
capture: (sessionID: string) => Promise<void>
inject: (sessionID: string) => string
}
compactionTodoPreserver?: { capture: (sessionID: string) => Promise<void> } compactionTodoPreserver?: { capture: (sessionID: string) => Promise<void> }
claudeCodeHooks?: { claudeCodeHooks?: {
"experimental.session.compacting"?: ( "experimental.session.compacting"?: (
@@ -9,19 +13,19 @@ describe("experimental.session.compacting handler", () => {
output: { context: string[] }, output: { context: string[] },
) => Promise<void> ) => Promise<void>
} }
compactionContextInjector?: (sessionID: string) => string
}) { }) {
return async ( return async (
_input: { sessionID: string }, _input: { sessionID: string },
output: { context: string[] }, output: { context: string[] },
): Promise<void> => { ): Promise<void> => {
await hooks.compactionContextInjector?.capture(_input.sessionID)
await hooks.compactionTodoPreserver?.capture(_input.sessionID) await hooks.compactionTodoPreserver?.capture(_input.sessionID)
await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.(
_input, _input,
output, output,
) )
if (hooks.compactionContextInjector) { if (hooks.compactionContextInjector) {
output.context.push(hooks.compactionContextInjector(_input.sessionID)) output.context.push(hooks.compactionContextInjector.inject(_input.sessionID))
} }
} }
} }
@@ -33,6 +37,15 @@ describe("experimental.session.compacting handler", () => {
const callOrder: string[] = [] const callOrder: string[] = []
const handler = createCompactingHandler({ const handler = createCompactingHandler({
compactionContextInjector: {
capture: mock(async () => {
callOrder.push("checkpointCapture")
}),
inject: mock((sessionID: string) => {
callOrder.push("contextInjector")
return `context-for-${sessionID}`
}),
},
compactionTodoPreserver: { compactionTodoPreserver: {
capture: mock(async () => { callOrder.push("capture") }), capture: mock(async () => { callOrder.push("capture") }),
}, },
@@ -41,16 +54,12 @@ describe("experimental.session.compacting handler", () => {
callOrder.push("preCompact") callOrder.push("preCompact")
}), }),
}, },
compactionContextInjector: mock((sessionID: string) => {
callOrder.push("contextInjector")
return `context-for-${sessionID}`
}),
}) })
const output = { context: [] as string[] } const output = { context: [] as string[] }
await handler({ sessionID: "ses_test" }, output) await handler({ sessionID: "ses_test" }, output)
expect(callOrder).toEqual(["capture", "preCompact", "contextInjector"]) expect(callOrder).toEqual(["checkpointCapture", "capture", "preCompact", "contextInjector"])
expect(output.context).toEqual(["context-for-ses_test"]) expect(output.context).toEqual(["context-for-ses_test"])
}) })
@@ -77,17 +86,22 @@ describe("experimental.session.compacting handler", () => {
//#then handler completes without error and other hooks still run //#then handler completes without error and other hooks still run
it("handles null claudeCodeHooks gracefully", async () => { it("handles null claudeCodeHooks gracefully", async () => {
const captureMock = mock(async () => {}) const captureMock = mock(async () => {})
const checkpointCaptureMock = mock(async () => {})
const contextMock = mock(() => "injected-context") const contextMock = mock(() => "injected-context")
const handler = createCompactingHandler({ const handler = createCompactingHandler({
compactionContextInjector: {
capture: checkpointCaptureMock,
inject: contextMock,
},
compactionTodoPreserver: { capture: captureMock }, compactionTodoPreserver: { capture: captureMock },
claudeCodeHooks: undefined, claudeCodeHooks: undefined,
compactionContextInjector: contextMock,
}) })
const output = { context: [] as string[] } const output = { context: [] as string[] }
await handler({ sessionID: "ses_test" }, output) await handler({ sessionID: "ses_test" }, output)
expect(checkpointCaptureMock).toHaveBeenCalledWith("ses_test")
expect(captureMock).toHaveBeenCalledWith("ses_test") expect(captureMock).toHaveBeenCalledWith("ses_test")
expect(contextMock).toHaveBeenCalledWith("ses_test") expect(contextMock).toHaveBeenCalledWith("ses_test")
expect(output.context).toEqual(["injected-context"]) expect(output.context).toEqual(["injected-context"])
+2 -1
View File
@@ -83,13 +83,14 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
_input: { sessionID: string }, _input: { sessionID: string },
output: { context: string[] }, output: { context: string[] },
): Promise<void> => { ): Promise<void> => {
await hooks.compactionContextInjector?.capture(_input.sessionID)
await hooks.compactionTodoPreserver?.capture(_input.sessionID) await hooks.compactionTodoPreserver?.capture(_input.sessionID)
await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.( await hooks.claudeCodeHooks?.["experimental.session.compacting"]?.(
_input, _input,
output, output,
) )
if (hooks.compactionContextInjector) { if (hooks.compactionContextInjector) {
output.context.push(hooks.compactionContextInjector(_input.sessionID)) output.context.push(hooks.compactionContextInjector.inject(_input.sessionID))
} }
}, },
} }