memorix 0.9.7 → 0.9.9

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,19 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.9.9] — 2026-02-25
6
+
7
+ ### Fixed
8
+ - **Cursor hooks config format invalid** — Generated config was missing required `version` field and used objects instead of arrays for hook scripts. Cursor requires `{ version: 1, hooks: { eventName: [{ command: "..." }] } }` format. Added `sessionStart`, `beforeShellExecution`, `afterMCPExecution`, `preCompact` events.
9
+ - **Cursor agent detection failed** — Cursor does NOT send `hook_event_name` like Claude Code. Detection now uses Cursor-specific fields (`workspace_roots`, `is_background_agent`, `composer_mode`). Event type inferred from payload structure (e.g., `old_content`/`new_content` → `afterFileEdit`).
10
+ - **Cursor `session_id` field not read** — Normalizer expected `conversation_id` but Cursor sends `session_id`. Now reads both with fallback.
11
+
12
+ ## [0.9.8] — 2026-02-25
13
+
14
+ ### Fixed
15
+ - **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.
16
+ - **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.
17
+
5
18
  ## [0.9.7] — 2026-02-25
6
19
 
7
20
  ### Fixed
package/dist/cli/index.js CHANGED
@@ -3791,17 +3791,17 @@ function generateWindsurfConfig() {
3791
3791
  }
3792
3792
  function generateCursorConfig() {
3793
3793
  const cmd = `${resolveHookCommand()} hook`;
3794
+ const hookScript = { command: cmd };
3794
3795
  return {
3796
+ version: 1,
3795
3797
  hooks: {
3796
- beforeSubmitPrompt: {
3797
- command: cmd
3798
- },
3799
- afterFileEdit: {
3800
- command: cmd
3801
- },
3802
- stop: {
3803
- command: cmd
3804
- }
3798
+ sessionStart: [hookScript],
3799
+ beforeSubmitPrompt: [hookScript],
3800
+ afterFileEdit: [hookScript],
3801
+ beforeShellExecution: [hookScript],
3802
+ afterMCPExecution: [hookScript],
3803
+ preCompact: [hookScript],
3804
+ stop: [hookScript]
3805
3805
  }
3806
3806
  };
3807
3807
  }
@@ -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 = [];
@@ -6893,7 +6896,7 @@ var init_sync = __esm({
6893
6896
  // src/hooks/normalizer.ts
6894
6897
  function detectAgent(payload) {
6895
6898
  if ("agent_action_name" in payload) return "windsurf";
6896
- if ("hook_event_name" in payload && "conversation_id" in payload) return "cursor";
6899
+ if ("workspace_roots" in payload || "is_background_agent" in payload || "composer_mode" in payload) return "cursor";
6897
6900
  if ("hook_event_name" in payload) return "claude";
6898
6901
  if ("hookEventName" in payload) return "copilot";
6899
6902
  if ("event_type" in payload) return "kiro";
@@ -6905,7 +6908,7 @@ function extractEventName(payload, agent) {
6905
6908
  case "windsurf":
6906
6909
  return payload.agent_action_name ?? "";
6907
6910
  case "cursor":
6908
- return payload.hook_event_name ?? "";
6911
+ return inferCursorEvent(payload);
6909
6912
  case "claude":
6910
6913
  return payload.hook_event_name ?? payload.hookEventName ?? "";
6911
6914
  case "copilot":
@@ -6981,9 +6984,20 @@ function normalizeWindsurf(payload, event) {
6981
6984
  }
6982
6985
  return result;
6983
6986
  }
6987
+ function inferCursorEvent(payload) {
6988
+ if ("composer_mode" in payload) return "sessionStart";
6989
+ if ("prompt" in payload) return "beforeSubmitPrompt";
6990
+ if ("old_content" in payload || "new_content" in payload) return "afterFileEdit";
6991
+ if ("command" in payload && "cwd" in payload) return "beforeShellExecution";
6992
+ if ("trigger" in payload && "context_usage_percent" in payload) return "preCompact";
6993
+ if ("reason" in payload && "duration_ms" in payload) return "sessionEnd";
6994
+ if ("mcp_server_name" in payload) return "afterMCPExecution";
6995
+ if ("reason" in payload) return "stop";
6996
+ return "";
6997
+ }
6984
6998
  function normalizeCursor(payload, event) {
6985
6999
  const result = {
6986
- sessionId: payload.conversation_id ?? "",
7000
+ sessionId: payload.session_id ?? payload.conversation_id ?? "",
6987
7001
  cwd: payload.cwd ?? ""
6988
7002
  };
6989
7003
  const roots = payload.workspace_roots;
@@ -7000,6 +7014,11 @@ function normalizeCursor(payload, event) {
7000
7014
  case "post_edit":
7001
7015
  result.filePath = payload.file_path ?? "";
7002
7016
  break;
7017
+ case "post_tool":
7018
+ result.toolName = payload.mcp_server_name ?? "";
7019
+ result.toolInput = payload.mcp_tool_input;
7020
+ result.toolResult = payload.mcp_tool_output;
7021
+ break;
7003
7022
  }
7004
7023
  return result;
7005
7024
  }
@@ -7066,11 +7085,16 @@ var init_normalizer = __esm({
7066
7085
  pre_mcp_tool_use: "post_tool",
7067
7086
  post_mcp_tool_use: "post_tool",
7068
7087
  post_cascade_response: "post_response",
7069
- // Cursor
7088
+ // Cursor (camelCase event names)
7089
+ sessionStart: "session_start",
7090
+ sessionEnd: "session_end",
7070
7091
  beforeSubmitPrompt: "user_prompt",
7071
7092
  beforeShellExecution: "post_command",
7093
+ afterShellExecution: "post_command",
7072
7094
  beforeMCPExecution: "post_tool",
7095
+ afterMCPExecution: "post_tool",
7073
7096
  afterFileEdit: "post_edit",
7097
+ preCompact: "pre_compact",
7074
7098
  stop: "session_end"
7075
7099
  };
7076
7100
  }