memorix 0.9.6 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.9.8] — 2026-02-25
6
+
7
+ ### Fixed
8
+ - **Claude Code hooks installed to wrong file** — Hooks were written to `.github/hooks/memorix.json` but Claude Code reads from `.claude/settings.local.json` (project-level) or `~/.claude/settings.json` (global). Now correctly writes to `.claude/settings.local.json` for project-level installation.
9
+ - **Hooks merge overwrites existing settings** — Shallow spread `{...existing, ...generated}` would overwrite the entire `hooks` key, destroying user's other hook configurations. Now deep-merges the `hooks` object so existing hooks from other tools are preserved.
10
+
11
+ ## [0.9.7] — 2026-02-25
12
+
13
+ ### Fixed
14
+ - **Claude Code hooks never triggering auto-memory** — Claude Code sends `hook_event_name` (snake_case) but the normalizer expected `hookEventName` (camelCase). This caused **every event** (SessionStart, UserPromptSubmit, PostToolUse, PreCompact, Stop) to be misidentified as `post_tool`, breaking event routing, prompt extraction, memory injection, and session tracking. Also fixed `session_id` → `sessionId` and `tool_response` → `toolResult` field mappings.
15
+ - **Empty content extraction from Claude Code tool events** — `extractContent()` now unpacks `toolInput` fields (Bash commands, Write file content, etc.) when no other content is available. Previously tool events produced empty or near-empty content strings.
16
+ - **User prompts silently dropped** — `MIN_STORE_LENGTH=100` was too high for typical user prompts. Added `MIN_PROMPT_LENGTH=20` specifically for `user_prompt` events.
17
+ - **Post-tool events too aggressively filtered** — Tool events with substantial content (>200 chars) are now stored even without keyword pattern matches.
18
+
5
19
  ## [0.9.6] — 2026-02-25
6
20
 
7
21
  ### Fixed
package/dist/cli/index.js CHANGED
@@ -3823,6 +3823,7 @@ ${resolveHookCommand()} hook
3823
3823
  function getProjectConfigPath(agent, projectRoot) {
3824
3824
  switch (agent) {
3825
3825
  case "claude":
3826
+ return path6.join(projectRoot, ".claude", "settings.local.json");
3826
3827
  case "copilot":
3827
3828
  return path6.join(projectRoot, ".github", "hooks", "memorix.json");
3828
3829
  case "windsurf":
@@ -3930,10 +3931,12 @@ async function installHooks(agent, projectRoot, global = false) {
3930
3931
  existing = JSON.parse(content);
3931
3932
  } catch {
3932
3933
  }
3933
- const merged = {
3934
- ...existing,
3935
- ...generated
3936
- };
3934
+ const gen = generated;
3935
+ const merged = { ...existing };
3936
+ if (gen.hooks && typeof gen.hooks === "object") {
3937
+ const existingHooks = existing.hooks && typeof existing.hooks === "object" ? existing.hooks : {};
3938
+ merged.hooks = { ...existingHooks, ...gen.hooks };
3939
+ }
3937
3940
  await fs4.writeFile(configPath, JSON.stringify(merged, null, 2), "utf-8");
3938
3941
  }
3939
3942
  const events = [];
@@ -6894,9 +6897,8 @@ var init_sync = __esm({
6894
6897
  function detectAgent(payload) {
6895
6898
  if ("agent_action_name" in payload) return "windsurf";
6896
6899
  if ("hook_event_name" in payload && "conversation_id" in payload) return "cursor";
6897
- if ("hookEventName" in payload) {
6898
- return "copilot";
6899
- }
6900
+ if ("hook_event_name" in payload) return "claude";
6901
+ if ("hookEventName" in payload) return "copilot";
6900
6902
  if ("event_type" in payload) return "kiro";
6901
6903
  if ("hook_type" in payload) return "codex";
6902
6904
  return "claude";
@@ -6907,8 +6909,9 @@ function extractEventName(payload, agent) {
6907
6909
  return payload.agent_action_name ?? "";
6908
6910
  case "cursor":
6909
6911
  return payload.hook_event_name ?? "";
6910
- case "copilot":
6911
6912
  case "claude":
6913
+ return payload.hook_event_name ?? payload.hookEventName ?? "";
6914
+ case "copilot":
6912
6915
  return payload.hookEventName ?? "";
6913
6916
  case "kiro":
6914
6917
  return payload.event_type ?? "";
@@ -6920,7 +6923,7 @@ function extractEventName(payload, agent) {
6920
6923
  }
6921
6924
  function normalizeClaude(payload, event) {
6922
6925
  const result = {
6923
- sessionId: payload.sessionId ?? "",
6926
+ sessionId: payload.session_id ?? payload.sessionId ?? "",
6924
6927
  cwd: payload.cwd ?? "",
6925
6928
  transcriptPath: payload.transcript_path
6926
6929
  };
@@ -6928,10 +6931,18 @@ function normalizeClaude(payload, event) {
6928
6931
  if (toolName) {
6929
6932
  result.toolName = toolName;
6930
6933
  result.toolInput = payload.tool_input;
6931
- result.toolResult = payload.tool_result;
6932
- if (toolName === "write" || toolName === "edit" || toolName === "multi_edit") {
6933
- const input = payload.tool_input;
6934
- result.filePath = input?.file_path ?? input?.filePath;
6934
+ const toolResponse = payload.tool_response ?? payload.tool_result;
6935
+ if (typeof toolResponse === "string") {
6936
+ result.toolResult = toolResponse;
6937
+ } else if (toolResponse && typeof toolResponse === "object") {
6938
+ result.toolResult = JSON.stringify(toolResponse);
6939
+ }
6940
+ const toolInput = payload.tool_input;
6941
+ if (/^bash$/i.test(toolName) && toolInput?.command) {
6942
+ result.command = toolInput.command;
6943
+ }
6944
+ if (/^(write|edit|multi_edit|multiedittool)$/i.test(toolName)) {
6945
+ result.filePath = toolInput?.file_path ?? toolInput?.filePath;
6935
6946
  }
6936
6947
  }
6937
6948
  if (event === "user_prompt") {
@@ -7231,6 +7242,19 @@ function extractContent(input) {
7231
7242
  parts.push(`Edit: ${edit.oldString} \u2192 ${edit.newString}`);
7232
7243
  }
7233
7244
  }
7245
+ if (parts.length === 0 && input.toolInput && typeof input.toolInput === "object") {
7246
+ if (input.toolName) parts.push(`Tool: ${input.toolName}`);
7247
+ if (input.toolInput.command) parts.push(`Command: ${input.toolInput.command}`);
7248
+ if (input.toolInput.file_path) parts.push(`File: ${input.toolInput.file_path}`);
7249
+ if (input.toolInput.content) {
7250
+ const content = input.toolInput.content;
7251
+ parts.push(content.slice(0, 1e3));
7252
+ }
7253
+ if (parts.length <= 1) {
7254
+ const summary = JSON.stringify(input.toolInput).slice(0, 500);
7255
+ parts.push(summary);
7256
+ }
7257
+ }
7234
7258
  return parts.join("\n").slice(0, MAX_CONTENT_LENGTH);
7235
7259
  }
7236
7260
  function deriveEntityName(input) {
@@ -7421,7 +7445,7 @@ ${lines.join("\n")}`;
7421
7445
  return { observation: null, output: defaultOutput };
7422
7446
  }
7423
7447
  const toolPattern = detectBestPattern(toolContent);
7424
- if (!toolPattern) {
7448
+ if (!toolPattern && toolContent.length < 200) {
7425
7449
  return { observation: null, output: defaultOutput };
7426
7450
  }
7427
7451
  markTriggered(toolKey);
@@ -7437,7 +7461,8 @@ ${lines.join("\n")}`;
7437
7461
  return { observation: null, output: defaultOutput };
7438
7462
  }
7439
7463
  const content = extractContent(input);
7440
- if (content.length < MIN_STORE_LENGTH) {
7464
+ const minLen = input.event === "user_prompt" ? MIN_PROMPT_LENGTH : MIN_STORE_LENGTH;
7465
+ if (content.length < minLen) {
7441
7466
  return { observation: null, output: defaultOutput };
7442
7467
  }
7443
7468
  detectBestPattern(content);
@@ -7484,7 +7509,7 @@ async function runHook() {
7484
7509
  }
7485
7510
  process.stdout.write(JSON.stringify(output));
7486
7511
  }
7487
- var cooldowns, COOLDOWN_MS, MIN_STORE_LENGTH, MIN_EDIT_LENGTH, NOISE_COMMANDS, MAX_CONTENT_LENGTH;
7512
+ var cooldowns, COOLDOWN_MS, MIN_STORE_LENGTH, MIN_PROMPT_LENGTH, MIN_EDIT_LENGTH, NOISE_COMMANDS, MAX_CONTENT_LENGTH;
7488
7513
  var init_handler = __esm({
7489
7514
  "src/hooks/handler.ts"() {
7490
7515
  "use strict";
@@ -7494,6 +7519,7 @@ var init_handler = __esm({
7494
7519
  cooldowns = /* @__PURE__ */ new Map();
7495
7520
  COOLDOWN_MS = 3e4;
7496
7521
  MIN_STORE_LENGTH = 100;
7522
+ MIN_PROMPT_LENGTH = 20;
7497
7523
  MIN_EDIT_LENGTH = 30;
7498
7524
  NOISE_COMMANDS = [
7499
7525
  /^(ls|dir|cd|pwd|echo|cat|type|head|tail|wc|find|which|where|whoami)\b/i,