memorix 0.9.13 → 0.9.15
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 +16 -2
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/cli/index.js +52 -5
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [0.9.
|
|
5
|
+
## [0.9.15] — 2026-02-26
|
|
6
6
|
|
|
7
7
|
### Fixed
|
|
8
|
-
-
|
|
8
|
+
- **Feedback visibility** — Hook auto-stores were silent. Now returns `systemMessage` to the agent after each save, e.g. `🟢 Memorix saved: Updated auth.ts [what-changed]`. Gives Codex-like visibility into what memorix is recording.
|
|
9
|
+
- **File-modifying tools always store** — Write/Edit/MultiEdit tool events were rejected when content lacked pattern keywords (e.g., writing utility functions with no "error"/"fix" keywords). Now file-modifying tools always store if content > 100 chars, classified as `what-changed` by default.
|
|
10
|
+
- **PreCompact low-quality spam** — PreCompact events stored empty/minimal observations with no meaningful content. Now requires `MIN_STORE_LENGTH` (100 chars) to store.
|
|
11
|
+
- **Normalizer prompt extraction** — `normalizeClaude` only extracted `prompt` for `user_prompt` events. Now extracts for all events (PreCompact, etc.), preserving context that would otherwise be lost.
|
|
12
|
+
|
|
13
|
+
## [0.9.14] — 2026-02-26
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **🔴 Critical: Hooks never auto-store during development** — Two root causes:
|
|
17
|
+
1. `extractContent()` had a fatal `parts.length === 0` guard that skipped rich `toolInput` data (file content, edit diffs, commands) whenever `toolResult` was present. Since all agents send short `toolResult` like `"File written successfully"` (28 chars), the content was always < 100 chars and got rejected by `MIN_STORE_LENGTH`.
|
|
18
|
+
2. Bash/shell tool events (npm install, npm test, git commands) also got rejected because their content (~90 chars) fell below the generic `post_tool` threshold of 200 chars, even though commands are inherently meaningful.
|
|
19
|
+
- **Fix**: Always extract `toolInput` fields alongside `toolResult`. Bash tools now use a dedicated low-threshold path (50 chars) with noise command filtering, matching the `post_command` logic.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- **12 Claude Code E2E tests** — Validates the full hook pipeline (stdin JSON → normalize → handleHookEvent → observation) for Write, Edit, Bash, UserPromptSubmit, SessionStart, Stop, PreCompact, and edge cases (noise filtering, memorix recursion skip, short prompts).
|
|
9
23
|
|
|
10
24
|
## [0.9.12] — 2026-02-25
|
|
11
25
|
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<a href="https://www.npmjs.com/package/memorix"><img src="https://img.shields.io/npm/dm/memorix.svg?style=flat-square&color=blue" alt="npm downloads"></a>
|
|
9
9
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-green.svg?style=flat-square" alt="License"></a>
|
|
10
10
|
<a href="https://github.com/AVIDS2/memorix"><img src="https://img.shields.io/github/stars/AVIDS2/memorix?style=flat-square&color=yellow" alt="GitHub stars"></a>
|
|
11
|
-
<img src="https://img.shields.io/badge/tests-
|
|
11
|
+
<img src="https://img.shields.io/badge/tests-505%20passed-brightgreen?style=flat-square" alt="Tests">
|
|
12
12
|
</p>
|
|
13
13
|
<p align="center">
|
|
14
14
|
<img src="https://img.shields.io/badge/Works%20with-Cursor-orange?style=flat-square" alt="Cursor">
|
package/README.zh-CN.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<a href="https://www.npmjs.com/package/memorix"><img src="https://img.shields.io/npm/dm/memorix.svg?style=flat-square&color=blue" alt="npm downloads"></a>
|
|
9
9
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-green.svg?style=flat-square" alt="License"></a>
|
|
10
10
|
<a href="https://github.com/AVIDS2/memorix"><img src="https://img.shields.io/github/stars/AVIDS2/memorix?style=flat-square&color=yellow" alt="GitHub stars"></a>
|
|
11
|
-
<img src="https://img.shields.io/badge/tests-
|
|
11
|
+
<img src="https://img.shields.io/badge/tests-505%20passed-brightgreen?style=flat-square" alt="Tests">
|
|
12
12
|
</p>
|
|
13
13
|
<p align="center">
|
|
14
14
|
<img src="https://img.shields.io/badge/Works%20with-Cursor-orange?style=flat-square" alt="Cursor">
|
package/dist/cli/index.js
CHANGED
|
@@ -43369,8 +43369,8 @@ function normalizeClaude(payload, event) {
|
|
|
43369
43369
|
result.filePath = toolInput?.file_path ?? toolInput?.filePath;
|
|
43370
43370
|
}
|
|
43371
43371
|
}
|
|
43372
|
-
if (
|
|
43373
|
-
result.userPrompt = payload.prompt
|
|
43372
|
+
if (payload.prompt) {
|
|
43373
|
+
result.userPrompt = payload.prompt;
|
|
43374
43374
|
}
|
|
43375
43375
|
return result;
|
|
43376
43376
|
}
|
|
@@ -43747,6 +43747,7 @@ var init_pattern_detector = __esm({
|
|
|
43747
43747
|
var handler_exports = {};
|
|
43748
43748
|
__export(handler_exports, {
|
|
43749
43749
|
handleHookEvent: () => handleHookEvent,
|
|
43750
|
+
resetCooldowns: () => resetCooldowns,
|
|
43750
43751
|
runHook: () => runHook
|
|
43751
43752
|
});
|
|
43752
43753
|
function isInCooldown(eventKey) {
|
|
@@ -43757,6 +43758,9 @@ function isInCooldown(eventKey) {
|
|
|
43757
43758
|
function markTriggered(eventKey) {
|
|
43758
43759
|
cooldowns.set(eventKey, Date.now());
|
|
43759
43760
|
}
|
|
43761
|
+
function resetCooldowns() {
|
|
43762
|
+
cooldowns.clear();
|
|
43763
|
+
}
|
|
43760
43764
|
function extractContent(input) {
|
|
43761
43765
|
const parts = [];
|
|
43762
43766
|
if (input.userPrompt) parts.push(input.userPrompt);
|
|
@@ -43822,7 +43826,8 @@ function generateTitle(input, patternType) {
|
|
|
43822
43826
|
}
|
|
43823
43827
|
function buildObservation(input, content) {
|
|
43824
43828
|
const pattern = detectBestPattern(content);
|
|
43825
|
-
const
|
|
43829
|
+
const fallbackType = input.filePath ? "what-changed" : "discovery";
|
|
43830
|
+
const obsType = pattern ? patternToObservationType(pattern.type) : fallbackType;
|
|
43826
43831
|
return {
|
|
43827
43832
|
entityName: deriveEntityName(input),
|
|
43828
43833
|
type: obsType,
|
|
@@ -43922,11 +43927,16 @@ ${lines.join("\n")}`;
|
|
|
43922
43927
|
}
|
|
43923
43928
|
};
|
|
43924
43929
|
}
|
|
43925
|
-
case "pre_compact":
|
|
43930
|
+
case "pre_compact": {
|
|
43931
|
+
const compactContent = extractContent(input);
|
|
43932
|
+
if (compactContent.length < MIN_STORE_LENGTH) {
|
|
43933
|
+
return { observation: null, output: defaultOutput };
|
|
43934
|
+
}
|
|
43926
43935
|
return {
|
|
43927
|
-
observation: buildObservation(input,
|
|
43936
|
+
observation: buildObservation(input, compactContent),
|
|
43928
43937
|
output: defaultOutput
|
|
43929
43938
|
};
|
|
43939
|
+
}
|
|
43930
43940
|
case "session_end":
|
|
43931
43941
|
return {
|
|
43932
43942
|
observation: buildObservation(input, extractContent(input)),
|
|
@@ -43976,9 +43986,32 @@ ${lines.join("\n")}`;
|
|
|
43976
43986
|
return { observation: null, output: defaultOutput };
|
|
43977
43987
|
}
|
|
43978
43988
|
const toolContent = extractContent(input);
|
|
43989
|
+
if (input.command) {
|
|
43990
|
+
if (NOISE_COMMANDS.some((r4) => r4.test(input.command))) {
|
|
43991
|
+
return { observation: null, output: defaultOutput };
|
|
43992
|
+
}
|
|
43993
|
+
if (toolContent.length < 50) {
|
|
43994
|
+
return { observation: null, output: defaultOutput };
|
|
43995
|
+
}
|
|
43996
|
+
markTriggered(toolKey);
|
|
43997
|
+
return {
|
|
43998
|
+
observation: buildObservation(input, toolContent),
|
|
43999
|
+
output: defaultOutput
|
|
44000
|
+
};
|
|
44001
|
+
}
|
|
43979
44002
|
if (toolContent.length < MIN_STORE_LENGTH) {
|
|
43980
44003
|
return { observation: null, output: defaultOutput };
|
|
43981
44004
|
}
|
|
44005
|
+
const isFileModifyingTool = /^(write|edit|multi_?edit|multiedittool|create|patch|insert)/i.test(
|
|
44006
|
+
input.toolName ?? ""
|
|
44007
|
+
);
|
|
44008
|
+
if (isFileModifyingTool) {
|
|
44009
|
+
markTriggered(toolKey);
|
|
44010
|
+
return {
|
|
44011
|
+
observation: buildObservation(input, toolContent),
|
|
44012
|
+
output: defaultOutput
|
|
44013
|
+
};
|
|
44014
|
+
}
|
|
43982
44015
|
const toolPattern = detectBestPattern(toolContent);
|
|
43983
44016
|
if (!toolPattern && toolContent.length < 200) {
|
|
43984
44017
|
return { observation: null, output: defaultOutput };
|
|
@@ -44039,6 +44072,20 @@ async function runHook() {
|
|
|
44039
44072
|
const dataDir = await getProjectDataDir2(project.id);
|
|
44040
44073
|
await initObservations2(dataDir);
|
|
44041
44074
|
await storeObservation2({ ...observation, projectId: project.id });
|
|
44075
|
+
const TYPE_EMOJI = {
|
|
44076
|
+
"gotcha": "\u{1F534}",
|
|
44077
|
+
"decision": "\u{1F7E4}",
|
|
44078
|
+
"problem-solution": "\u{1F7E1}",
|
|
44079
|
+
"trade-off": "\u2696\uFE0F",
|
|
44080
|
+
"discovery": "\u{1F7E3}",
|
|
44081
|
+
"how-it-works": "\u{1F535}",
|
|
44082
|
+
"what-changed": "\u{1F7E2}",
|
|
44083
|
+
"why-it-exists": "\u{1F7E0}",
|
|
44084
|
+
"session-request": "\u{1F3AF}"
|
|
44085
|
+
};
|
|
44086
|
+
const emoji2 = TYPE_EMOJI[observation.type] ?? "\u{1F4DD}";
|
|
44087
|
+
output.systemMessage = (output.systemMessage ?? "") + `
|
|
44088
|
+
${emoji2} Memorix saved: ${observation.title} [${observation.type}]`;
|
|
44042
44089
|
} catch {
|
|
44043
44090
|
}
|
|
44044
44091
|
}
|