refactor(keyword-detector): decouple from claude-code-hooks via ContextCollector pipeline

- keyword-detector now registers keywords to ContextCollector
- context-injector consumes and injects via chat.message hook
- Removed keyword detection logic from claude-code-hooks
- Hook order: keyword-detector → context-injector → claude-code-hooks
- ultrawork now works even when claude-code-hooks is disabled
This commit is contained in:
YeonGyu-Kim
2026-01-11 12:06:16 +09:00
parent 13b35b7f71
commit accb3bbf1e
6 changed files with 119 additions and 31 deletions
@@ -133,7 +133,7 @@ describe("createContextInjectorHook", () => {
})
describe("chat.message handler", () => {
it("is a no-op (context injection moved to messages transform)", async () => {
it("injects pending context into output parts", async () => {
// #given
const hook = createContextInjectorHook(collector)
const sessionID = "ses_hook1"
@@ -152,8 +152,9 @@ describe("createContextInjectorHook", () => {
await hook["chat.message"](input, output)
// #then
expect(output.parts[0].text).toBe("User message")
expect(collector.hasPending(sessionID)).toBe(true)
expect(output.parts[0].text).toContain("Hook context")
expect(output.parts[0].text).toContain("User message")
expect(collector.hasPending(sessionID)).toBe(false)
})
it("does nothing when no pending context", async () => {
+9 -3
View File
@@ -52,10 +52,16 @@ interface ChatMessageOutput {
export function createContextInjectorHook(collector: ContextCollector) {
return {
"chat.message": async (
_input: ChatMessageInput,
_output: ChatMessageOutput
input: ChatMessageInput,
output: ChatMessageOutput
): Promise<void> => {
void collector
const result = injectPendingContext(collector, input.sessionID, output.parts)
if (result.injected) {
log("[context-injector] Injected pending context via chat.message", {
sessionID: input.sessionID,
contextLength: result.contextLength,
})
}
},
}
}