claude-mem 2.0.2

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/LICENSE ADDED
@@ -0,0 +1,31 @@
1
+ CLAUDE-MEM SOFTWARE LICENSE
2
+
3
+ Copyright (c) 2024 Alex Newman (@thedotmack). All rights reserved.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software in its compiled/distributed form via npm, to use the software
7
+ for any purpose, subject to the following conditions:
8
+
9
+ 1. USE RIGHTS: You may use the claude-mem CLI tool for personal or commercial
10
+ purposes without restriction.
11
+
12
+ 2. NO SOURCE CODE RIGHTS: This license does NOT grant access to source code,
13
+ modification rights, or redistribution rights. The software is provided
14
+ as-is in its compiled form only.
15
+
16
+ 3. NO REVERSE ENGINEERING: You may not reverse engineer, decompile, or
17
+ disassemble the software.
18
+
19
+ 4. NO REDISTRIBUTION: You may not redistribute, repackage, or resell this
20
+ software. Users must install it from the official npm registry.
21
+
22
+ 5. NO WARRANTY: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25
+
26
+ 6. LIMITATION OF LIABILITY: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
28
+ OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
29
+ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
+
31
+ For questions about this license, contact: thedotmack@gmail.com
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Claude Memory System
2
+
3
+ **Truth + Context = Clarity**
4
+
5
+
6
+ A professional CLI tool that transforms Claude Code conversation transcripts into a persistent, searchable knowledge graph. Never lose valuable context from your AI-assisted development sessions again.
7
+
8
+ ## What is Claude-Mem?
9
+
10
+ Claude Memory System automatically:
11
+ - 🗜️ **Compresses** your Claude Code conversations into structured knowledge
12
+ - 🔍 **Extracts** key components, patterns, decisions, and fixes
13
+ - 📚 **Archives** sessions for future reference
14
+ - 🚀 **Loads** relevant context when you start new sessions
15
+ - ⚡ **Integrates** seamlessly with Claude Code via hooks
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Install globally
21
+ npm install -g claude-mem
22
+
23
+ # Or use with npx (no install needed)
24
+ npx claude-mem install
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ 1. **Install the hooks into Claude Code:**
30
+ ```bash
31
+ claude-mem install
32
+ ```
33
+
34
+ 2. **Restart Claude Code** to load the new hooks
35
+
36
+ 3. **Use `/compact` in Claude Code** to trigger memory compression
37
+
38
+ 4. **Start new sessions** with automatic context loading
39
+
40
+ ## Commands
41
+
42
+ - `claude-mem install` - Set up Claude Code integration
43
+ - `claude-mem status` - Check system status
44
+ - `claude-mem compress <transcript>` - Manually compress a transcript
45
+ - `claude-mem load-context` - View stored memories
46
+ - `claude-mem logs` - View system logs
47
+ - `claude-mem uninstall` - Remove Claude Code hooks
48
+
49
+ ## How It Works
50
+
51
+ 1. When you use `/compact` in Claude Code, claude-mem automatically compresses your conversation
52
+ 2. Entities (components, patterns, fixes, etc.) are extracted and stored
53
+ 3. When you start a new Claude Code session, relevant context is automatically loaded
54
+ 4. Your knowledge base grows smarter with each session
55
+
56
+ ## Requirements
57
+
58
+ - Node.js 18.0 or higher
59
+ - Claude Code installed
60
+ - MCP memory server (automatically configured during install)
61
+
62
+ ## Storage
63
+
64
+ Your compressed memories are stored in:
65
+ - `~/.claude-mem/index/` - Searchable index
66
+ - `~/.claude-mem/archives/` - Original transcripts
67
+ - `~/.claude-mem/hooks/` - Integration scripts
68
+
69
+ ## Feedback
70
+
71
+ Please report issues or feedback at: https://github.com/thedotmack/claude-mem/issues
72
+
73
+ ## License
74
+
75
+ This software is free to use but is NOT open source. See LICENSE file for details.
76
+
77
+ ---
78
+
79
+ *Built with ❤️ for the Claude Code community*
package/claude-mem ADDED
Binary file
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 🔑 LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits
5
+ *
6
+ * OFFICIAL DOCS: Claude Code Hooks API v2025
7
+ * Last Verified: 2025-08-31
8
+ * @see https://docs.anthropic.com/en/docs/claude-code/hooks
9
+ *
10
+ * Claude Memory System - Pre-Compact Hook
11
+ *
12
+ * CRITICAL REQUIREMENTS:
13
+ * - Hook responses MUST use 'continue' field (boolean)
14
+ * - When continue is false, MUST provide 'stopReason' field
15
+ * - DO NOT use 'decision' or 'reason' fields (deprecated pattern)
16
+ * - PreCompact hooks DO NOT support hookSpecificOutput field
17
+ * - Exit codes: 0=success, 1=error shown to user, 2=error with stderr shown
18
+ *
19
+ * Valid Response Format:
20
+ * Success: { "continue": true }
21
+ * Failure: { "continue": false, "stopReason": "error message" }
22
+ *
23
+ * @docs-ref: Official hook response format specification
24
+ * @see https://docs.anthropic.com/claude-code/hooks#response-format
25
+ */
26
+
27
+ import { spawn } from 'child_process';
28
+ import { join, dirname } from 'path';
29
+ import { fileURLToPath } from 'url';
30
+ import { readFileSync, existsSync } from 'fs';
31
+
32
+ const __dirname = dirname(fileURLToPath(import.meta.url));
33
+
34
+ // Load configuration to get the CLI command name
35
+ let cliCommand = 'claude-mem'; // Default fallback
36
+ const configPath = join(__dirname, 'config.json');
37
+ if (existsSync(configPath)) {
38
+ try {
39
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
40
+ cliCommand = config.cliCommand || 'claude-mem';
41
+ } catch (e) {
42
+ // Fallback to default if config read fails
43
+ }
44
+ }
45
+
46
+ async function preCompactHook() {
47
+ let input = '';
48
+
49
+ // Read JSON input from stdin
50
+ process.stdin.on('data', chunk => {
51
+ input += chunk;
52
+ });
53
+
54
+ process.stdin.on('end', async () => {
55
+ try {
56
+ const data = JSON.parse(input);
57
+ const transcriptPath = data.transcript_path;
58
+
59
+ if (!transcriptPath) {
60
+ // Output error in Claude Code expected format
61
+ // @docs-ref: continue: false with stopReason for blocking operations
62
+ console.log(JSON.stringify({
63
+ continue: false,
64
+ stopReason: "No transcript path provided"
65
+ }));
66
+ process.exit(2); // Exit 2 tells Claude Code to show error
67
+ }
68
+
69
+ // Call the CLI compress command using configured name
70
+ const compressor = spawn(cliCommand, ['compress', transcriptPath], {
71
+ stdio: ['ignore', 'pipe', 'pipe'] // Capture output instead of inherit
72
+ });
73
+
74
+ let stdout = '';
75
+ let stderr = '';
76
+
77
+ compressor.stdout.on('data', (data) => {
78
+ stdout += data.toString();
79
+ });
80
+
81
+ compressor.stderr.on('data', (data) => {
82
+ stderr += data.toString();
83
+ });
84
+
85
+ compressor.on('close', (code) => {
86
+ if (code !== 0) {
87
+ // Check if it's the Claude Code executable error
88
+ if (stderr.includes('Claude Code executable not found')) {
89
+ // This is expected when running outside Claude Code context
90
+ // Just output success since we can't compress without Claude SDK
91
+ // @docs-ref: PreCompact hooks should only use continue field, not hookSpecificOutput
92
+ console.log(JSON.stringify({
93
+ continue: true,
94
+ suppressOutput: true,
95
+ systemMessage: "Memory compression skipped - Claude SDK not available in this context"
96
+ }));
97
+ process.exit(0);
98
+ } else {
99
+ // Real error - report it
100
+ // @docs-ref: Use continue: false with stopReason for errors
101
+ console.log(JSON.stringify({
102
+ continue: false,
103
+ stopReason: `Compression failed: ${stderr}`
104
+ }));
105
+ process.exit(2);
106
+ }
107
+ } else {
108
+ // Success! Output confirmation
109
+ // @docs-ref: PreCompact hooks should only use continue field for success
110
+ console.log(JSON.stringify({
111
+ continue: true,
112
+ suppressOutput: true,
113
+ systemMessage: "Memory compression completed successfully"
114
+ }));
115
+ process.exit(0);
116
+ }
117
+ });
118
+
119
+ compressor.on('error', (error) => {
120
+ // @docs-ref: Use continue: false with stopReason for errors
121
+ console.log(JSON.stringify({
122
+ continue: false,
123
+ stopReason: `Failed to start compression: ${error.message}`
124
+ }));
125
+ process.exit(2);
126
+ });
127
+
128
+ } catch (error) {
129
+ // @docs-ref: Use continue: false with stopReason for errors
130
+ console.log(JSON.stringify({
131
+ continue: false,
132
+ stopReason: `Hook error: ${error.message}`
133
+ }));
134
+ process.exit(2);
135
+ }
136
+ });
137
+ }
138
+
139
+ preCompactHook();
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 🔑 LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits
5
+ *
6
+ * OFFICIAL DOCS: Claude Code SessionEnd Hook v2025
7
+ * Last Verified: 2025-08-31
8
+ * @see https://docs.anthropic.com/en/docs/claude-code/hooks
9
+ *
10
+ * Claude Memory System - Session End Hook
11
+ * Triggers compression when session ends with reason 'clear'
12
+ *
13
+ * SessionEnd Hook Payload:
14
+ * {
15
+ * "session_id": "string",
16
+ * "transcript_path": "string",
17
+ * "cwd": "string",
18
+ * "hook_event_name": "SessionEnd",
19
+ * "reason": "exit" | "clear" | "error" | ...
20
+ * }
21
+ *
22
+ * Valid Response Format:
23
+ * Success: { "continue": true }
24
+ * Success with message: { "continue": true, "systemMessage": "string" }
25
+ * Failure: { "continue": false, "stopReason": "error message" }
26
+ *
27
+ * Note: SessionEnd hooks should generally always return continue: true
28
+ * to avoid blocking session termination.
29
+ *
30
+ * @docs-ref: SessionEnd hook should not block session ending
31
+ * @see https://docs.anthropic.com/claude-code/hooks#sessionend
32
+ */
33
+
34
+ import { spawn } from 'child_process';
35
+ import { join, dirname } from 'path';
36
+ import { fileURLToPath } from 'url';
37
+ import { readFileSync, existsSync } from 'fs';
38
+
39
+ const __dirname = dirname(fileURLToPath(import.meta.url));
40
+
41
+ // Load configuration to get the CLI command name
42
+ let cliCommand = 'claude-mem'; // Default fallback
43
+ const configPath = join(__dirname, 'config.json');
44
+ if (existsSync(configPath)) {
45
+ try {
46
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
47
+ cliCommand = config.cliCommand || 'claude-mem';
48
+ } catch (e) {
49
+ // Fallback to default if config read fails
50
+ }
51
+ }
52
+
53
+ async function sessionEndHook() {
54
+ let input = '';
55
+
56
+ // Read JSON input from stdin
57
+ process.stdin.on('data', chunk => {
58
+ input += chunk;
59
+ });
60
+
61
+ process.stdin.on('end', async () => {
62
+ try {
63
+ const data = JSON.parse(input);
64
+ const { reason, transcript_path, session_id } = data;
65
+
66
+ // Only proceed if reason is 'clear'
67
+ if (reason !== 'clear') {
68
+ // For other reasons, just continue without action
69
+ // @docs-ref: SessionEnd hooks should not use hookSpecificOutput
70
+ console.log(JSON.stringify({
71
+ continue: true
72
+ }));
73
+ process.exit(0);
74
+ }
75
+
76
+ // Validate transcript path
77
+ if (!transcript_path) {
78
+ // @docs-ref: SessionEnd should not block session ending
79
+ // Just continue even if we can't compress
80
+ console.log(JSON.stringify({
81
+ continue: true,
82
+ systemMessage: "Warning: No transcript path provided for compression"
83
+ }));
84
+ process.exit(0);
85
+ }
86
+
87
+ // Call the CLI compress command (same as pre-compact)
88
+ const compressor = spawn(cliCommand, ['compress', transcript_path], {
89
+ stdio: ['ignore', 'pipe', 'pipe']
90
+ });
91
+
92
+ let stdout = '';
93
+ let stderr = '';
94
+
95
+ compressor.stdout.on('data', (data) => {
96
+ stdout += data.toString();
97
+ });
98
+
99
+ compressor.stderr.on('data', (data) => {
100
+ stderr += data.toString();
101
+ });
102
+
103
+ compressor.on('close', (code) => {
104
+ if (code !== 0) {
105
+ // Check if it's the Claude Code executable error
106
+ if (stderr.includes('Claude Code executable not found')) {
107
+ // This is expected when running outside Claude Code context
108
+ // @docs-ref: SessionEnd hooks should not use hookSpecificOutput
109
+ console.log(JSON.stringify({
110
+ continue: true,
111
+ suppressOutput: true
112
+ }));
113
+ process.exit(0);
114
+ } else {
115
+ // Real error - report it but allow session to end
116
+ // @docs-ref: Always allow session to end, use systemMessage for errors
117
+ console.log(JSON.stringify({
118
+ continue: true,
119
+ systemMessage: `Memory compression failed: ${stderr}`
120
+ }));
121
+ process.exit(0);
122
+ }
123
+ } else {
124
+ // Success! Memory compressed before session clear
125
+ // @docs-ref: SessionEnd hooks should not use hookSpecificOutput
126
+ console.log(JSON.stringify({
127
+ continue: true,
128
+ suppressOutput: true,
129
+ systemMessage: "Memory compressed successfully before session clear"
130
+ }));
131
+ process.exit(0);
132
+ }
133
+ });
134
+
135
+ compressor.on('error', (error) => {
136
+ // Report error but allow session to end
137
+ // @docs-ref: Always allow session to end, use systemMessage for errors
138
+ console.log(JSON.stringify({
139
+ continue: true,
140
+ systemMessage: `Failed to start compression: ${error.message}`
141
+ }));
142
+ process.exit(0);
143
+ });
144
+
145
+ } catch (error) {
146
+ // Report error but allow session to end
147
+ // @docs-ref: Always allow session to end, use systemMessage for errors
148
+ console.log(JSON.stringify({
149
+ continue: true,
150
+ systemMessage: `Hook error: ${error.message}`
151
+ }));
152
+ process.exit(0);
153
+ }
154
+ });
155
+ }
156
+
157
+ sessionEndHook();
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 🔑 LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits
5
+ *
6
+ * OFFICIAL DOCS: Claude Code SessionStart Hook v2025
7
+ * Last Verified: 2025-08-31
8
+ * @see https://docs.anthropic.com/en/docs/claude-code/hooks
9
+ *
10
+ * SessionStart Hook Payload:
11
+ * {
12
+ * "session_id": "string",
13
+ * "transcript_path": "string",
14
+ * "hook_event_name": "SessionStart",
15
+ * "source": "startup" | "compact" | "vscode" | "web"
16
+ * }
17
+ *
18
+ * The 'source' field indicates how the session was initiated:
19
+ * - "startup": New session started normally
20
+ * - "compact": Session started after compaction
21
+ * - "vscode": Session initiated from VS Code
22
+ * - "web": Session initiated from web interface
23
+ *
24
+ * Valid Response Format:
25
+ * Success without context: { "continue": true }
26
+ * Success with context: {
27
+ * "continue": true,
28
+ * "hookSpecificOutput": {
29
+ * "hookEventName": "SessionStart",
30
+ * "additionalContext": "string" // Context to add to session
31
+ * }
32
+ * }
33
+ * Failure: { "continue": false, "stopReason": "error message" }
34
+ *
35
+ * @docs-ref: SessionStart supports hookSpecificOutput.additionalContext
36
+ * @see https://docs.anthropic.com/claude-code/hooks#sessionstart
37
+ */
38
+
39
+ import { spawn } from 'child_process';
40
+ import { join, dirname, basename } from 'path';
41
+ import { fileURLToPath } from 'url';
42
+ import { readFileSync, existsSync } from 'fs';
43
+
44
+ const __dirname = dirname(fileURLToPath(import.meta.url));
45
+
46
+ // Load configuration to get the CLI command name
47
+ let cliCommand = 'claude-mem'; // Default fallback
48
+ const configPath = join(__dirname, 'config.json');
49
+ if (existsSync(configPath)) {
50
+ try {
51
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
52
+ cliCommand = config.cliCommand || 'claude-mem';
53
+ } catch (e) {
54
+ // Fallback to default if config read fails
55
+ }
56
+ }
57
+
58
+ async function sessionStartHook() {
59
+ let input = '';
60
+
61
+ // Read JSON input from stdin
62
+ process.stdin.on('data', chunk => {
63
+ input += chunk;
64
+ });
65
+
66
+ process.stdin.on('end', async () => {
67
+ try {
68
+ const data = JSON.parse(input);
69
+
70
+ /**
71
+ * @docs-ref: SessionStart payload includes 'source' field, not 'reason'
72
+ * See: https://docs.anthropic.com/en/docs/claude-code/hooks#sessionstart
73
+ *
74
+ * The 'source' field indicates the session start context:
75
+ * - 'startup': New session (load context)
76
+ * - 'compact': Session after compaction (may want to load context)
77
+ * - 'vscode': VS Code initiated session
78
+ * - 'web': Web interface initiated session
79
+ *
80
+ * Note: Based on official docs, there is no 'continue' value for source.
81
+ * The previous check for 'reason === continue' was incorrect.
82
+ * We now skip context loading only for 'compact' source, as this
83
+ * indicates the session is continuing after compaction.
84
+ */
85
+ if (data.source === 'compact') { // ✅ Correctly check 'source' field per official docs
86
+ // @docs-ref: For compact source, skip loading context as session is continuing
87
+ console.log(JSON.stringify({
88
+ continue: true
89
+ // No additional context needed for compact continuation
90
+ }));
91
+ process.exit(0);
92
+ }
93
+
94
+ // Extract project name from transcript path if available
95
+ let projectName = null;
96
+ if (data.transcript_path) {
97
+ const dir = dirname(data.transcript_path);
98
+ const dirName = basename(dir);
99
+
100
+ // Extract project name from directory pattern
101
+ if (dirName.includes('-Scripts-')) {
102
+ const parts = dirName.split('-Scripts-');
103
+ if (parts.length > 1) {
104
+ projectName = parts[1];
105
+ }
106
+ } else {
107
+ projectName = dirName;
108
+ }
109
+
110
+ // Sanitize project name to match what compression uses
111
+ // This ensures we match the exact project name in the index
112
+ if (projectName) {
113
+ projectName = projectName.replace(/[^a-zA-Z0-9]/g, '_');
114
+ }
115
+ }
116
+
117
+ // Build command to run
118
+ const args = ['load-context', '--format', 'session-start'];
119
+
120
+ // Add project filter if we have a project name
121
+ if (projectName) {
122
+ args.push('--project', projectName);
123
+ }
124
+
125
+ // Call the CLI load-context command directly
126
+ // Use the configured CLI command name (claude-mem)
127
+ // This ensures we use the correct version with full summaries
128
+ const loader = spawn(cliCommand, args, {
129
+ stdio: ['ignore', 'pipe', 'pipe']
130
+ });
131
+
132
+ let stdout = '';
133
+ let stderr = '';
134
+
135
+ loader.stdout.on('data', (data) => {
136
+ stdout += data.toString();
137
+ });
138
+
139
+ loader.stderr.on('data', (data) => {
140
+ stderr += data.toString();
141
+ });
142
+
143
+ loader.on('close', (code) => {
144
+ if (code !== 0) {
145
+ // If load-context fails, just continue without context
146
+ // This could happen if no index exists yet
147
+ // @docs-ref: Always return valid response format
148
+ console.log(JSON.stringify({
149
+ continue: true
150
+ }));
151
+ process.exit(0);
152
+ }
153
+
154
+ // Output the formatted context for Claude to see using proper JSON format
155
+ // @docs-ref: SessionStart supports hookSpecificOutput.additionalContext
156
+ if (stdout && stdout.trim()) {
157
+ console.log(JSON.stringify({
158
+ continue: true,
159
+ hookSpecificOutput: {
160
+ hookEventName: "SessionStart",
161
+ additionalContext: stdout
162
+ }
163
+ }));
164
+ } else {
165
+ // No context to add, just continue
166
+ console.log(JSON.stringify({
167
+ continue: true
168
+ }));
169
+ }
170
+
171
+ process.exit(0);
172
+ });
173
+
174
+ loader.on('error', () => {
175
+ // If there's an error running the command, continue without context
176
+ // We don't want to break the session start
177
+ // @docs-ref: Always return valid response format
178
+ console.log(JSON.stringify({
179
+ continue: true
180
+ }));
181
+ process.exit(0);
182
+ });
183
+
184
+ } catch (error) {
185
+ // Any errors, just continue without additional context
186
+ // @docs-ref: Always return valid response format
187
+ console.log(JSON.stringify({
188
+ continue: true
189
+ }));
190
+ process.exit(0);
191
+ }
192
+ });
193
+ }
194
+
195
+ sessionStartHook();
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "claude-mem",
3
+ "version": "2.0.2",
4
+ "description": "Memory compression system for Claude Code - persist context across sessions",
5
+ "keywords": [
6
+ "claude",
7
+ "claude-code",
8
+ "mcp",
9
+ "memory",
10
+ "compression",
11
+ "knowledge-graph",
12
+ "transcript",
13
+ "cli"
14
+ ],
15
+ "author": "Alex Newman",
16
+ "license": "SEE LICENSE IN LICENSE",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/thedotmack/claude-mem.git"
20
+ },
21
+ "homepage": "https://github.com/thedotmack/claude-mem#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/thedotmack/claude-mem/issues"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "registry": "https://registry.npmjs.org/"
28
+ },
29
+ "bin": {
30
+ "claude-mem": "claude-mem"
31
+ },
32
+ "files": [
33
+ "claude-mem",
34
+ "hooks",
35
+ "src"
36
+ ]
37
+ }