From 04ae3642d96fbe2ec5a6cc1c9f171aaadf60e5c3 Mon Sep 17 00:00:00 2001 From: Kenny Date: Mon, 12 Jan 2026 21:19:05 -0500 Subject: [PATCH 1/2] fix(hooks): throw agent-friendly errors when todowrite receives invalid input --- src/hooks/claude-code-hooks/index.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/hooks/claude-code-hooks/index.ts b/src/hooks/claude-code-hooks/index.ts index 4ed5dac7..ad07f8ba 100644 --- a/src/hooks/claude-code-hooks/index.ts +++ b/src/hooks/claude-code-hooks/index.ts @@ -185,6 +185,30 @@ export function createClaudeCodeHooksHook( input: { tool: string; sessionID: string; callID: string }, output: { args: Record } ): Promise => { + if (input.tool === "todowrite" && typeof output.args.todos === "string") { + let parsed: unknown + try { + parsed = JSON.parse(output.args.todos) + } catch (e) { + throw new Error( + `[todowrite ERROR] Failed to parse todos string as JSON. ` + + `Received: ${output.args.todos.slice(0, 100)}... ` + + `Expected: Valid JSON array. Pass todos as an array, not a string.` + ) + } + + if (!Array.isArray(parsed)) { + throw new Error( + `[todowrite ERROR] Parsed JSON is not an array. ` + + `Received type: ${typeof parsed}. ` + + `Expected: Array of todo objects. Pass todos as [{id, content, status, priority}, ...].` + ) + } + + output.args.todos = parsed + log("todowrite: parsed todos string to array", { sessionID: input.sessionID }) + } + const claudeConfig = await loadClaudeHooksConfig() const extendedConfig = await loadPluginExtendedConfig() From 864656475a47979ba779efb2ce13ce75807537de Mon Sep 17 00:00:00 2001 From: Kenny Date: Mon, 12 Jan 2026 22:03:15 -0500 Subject: [PATCH 2/2] fix: only append ellipsis when string exceeds 100 chars --- src/hooks/claude-code-hooks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/claude-code-hooks/index.ts b/src/hooks/claude-code-hooks/index.ts index ad07f8ba..795dcda8 100644 --- a/src/hooks/claude-code-hooks/index.ts +++ b/src/hooks/claude-code-hooks/index.ts @@ -192,7 +192,7 @@ export function createClaudeCodeHooksHook( } catch (e) { throw new Error( `[todowrite ERROR] Failed to parse todos string as JSON. ` + - `Received: ${output.args.todos.slice(0, 100)}... ` + + `Received: ${output.args.todos.length > 100 ? output.args.todos.slice(0, 100) + '...' : output.args.todos} ` + `Expected: Valid JSON array. Pass todos as an array, not a string.` ) }