claude-cortex 1.7.2 → 1.8.0

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.
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Session Start Hook for Claude Memory - Auto-Recall Context
4
+ *
5
+ * This script runs when Claude Code starts a new session and:
6
+ * 1. Detects the current project from the working directory
7
+ * 2. Retrieves relevant context from memory
8
+ * 3. Outputs it so Claude has immediate access to project knowledge
9
+ *
10
+ * The goal: Claude always starts with relevant project context.
11
+ */
12
+
13
+ import Database from 'better-sqlite3';
14
+ import { existsSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { homedir } from 'os';
17
+
18
+ // Database paths (with legacy fallback)
19
+ const NEW_DB_DIR = join(homedir(), '.claude-cortex');
20
+ const LEGACY_DB_DIR = join(homedir(), '.claude-memory');
21
+
22
+ // Auto-detect: use new path if it exists, or if legacy doesn't exist (new install)
23
+ function getDbPath() {
24
+ const newPath = join(NEW_DB_DIR, 'memories.db');
25
+ const legacyPath = join(LEGACY_DB_DIR, 'memories.db');
26
+ if (existsSync(newPath) || !existsSync(legacyPath)) {
27
+ return { dir: NEW_DB_DIR, path: newPath };
28
+ }
29
+ return { dir: LEGACY_DB_DIR, path: legacyPath };
30
+ }
31
+
32
+ const { dir: DB_DIR, path: DB_PATH } = getDbPath();
33
+
34
+ // Configuration
35
+ const MAX_CONTEXT_MEMORIES = 15;
36
+ const MIN_SALIENCE_THRESHOLD = 0.3;
37
+
38
+ // ==================== PROJECT DETECTION (Mirrors src/context/project-context.ts) ====================
39
+
40
+ const SKIP_DIRECTORIES = [
41
+ 'src', 'lib', 'dist', 'build', 'out',
42
+ 'node_modules', '.git', '.next', '.cache',
43
+ 'test', 'tests', '__tests__', 'spec',
44
+ 'bin', 'scripts', 'config', 'public', 'static',
45
+ ];
46
+
47
+ function extractProjectFromPath(path) {
48
+ if (!path) return null;
49
+
50
+ const segments = path.split(/[/\\]/).filter(Boolean);
51
+ if (segments.length === 0) return null;
52
+
53
+ for (let i = segments.length - 1; i >= 0; i--) {
54
+ const segment = segments[i];
55
+ if (!SKIP_DIRECTORIES.includes(segment.toLowerCase())) {
56
+ if (segment.startsWith('.')) continue;
57
+ return segment;
58
+ }
59
+ }
60
+
61
+ return null;
62
+ }
63
+
64
+ // ==================== CONTEXT RETRIEVAL ====================
65
+
66
+ function getProjectContext(db, project) {
67
+ const memories = [];
68
+
69
+ // Get high-priority memories for this project
70
+ const highPriority = db.prepare(`
71
+ SELECT id, title, content, category, type, salience, tags, created_at
72
+ FROM memories
73
+ WHERE (project = ? OR project IS NULL)
74
+ AND salience >= ?
75
+ AND type IN ('long_term', 'episodic')
76
+ ORDER BY salience DESC, last_accessed DESC
77
+ LIMIT ?
78
+ `).all(project, MIN_SALIENCE_THRESHOLD, MAX_CONTEXT_MEMORIES);
79
+
80
+ memories.push(...highPriority);
81
+
82
+ // If we don't have enough, get recent memories too
83
+ if (memories.length < 5) {
84
+ const recent = db.prepare(`
85
+ SELECT id, title, content, category, type, salience, tags, created_at
86
+ FROM memories
87
+ WHERE (project = ? OR project IS NULL)
88
+ AND id NOT IN (${memories.map(m => m.id).join(',') || '0'})
89
+ ORDER BY created_at DESC
90
+ LIMIT ?
91
+ `).all(project, 5 - memories.length);
92
+
93
+ memories.push(...recent);
94
+ }
95
+
96
+ return memories;
97
+ }
98
+
99
+ function formatContext(memories, project) {
100
+ if (memories.length === 0) {
101
+ return null;
102
+ }
103
+
104
+ const lines = [
105
+ `# Project Context: ${project}`,
106
+ '',
107
+ ];
108
+
109
+ // Group by category
110
+ const byCategory = {};
111
+ for (const mem of memories) {
112
+ const cat = mem.category || 'note';
113
+ if (!byCategory[cat]) byCategory[cat] = [];
114
+ byCategory[cat].push(mem);
115
+ }
116
+
117
+ // Priority order for categories
118
+ const categoryOrder = ['architecture', 'pattern', 'preference', 'error', 'context', 'learning', 'note', 'todo'];
119
+
120
+ for (const cat of categoryOrder) {
121
+ if (!byCategory[cat] || byCategory[cat].length === 0) continue;
122
+
123
+ const categoryTitle = cat.charAt(0).toUpperCase() + cat.slice(1);
124
+ lines.push(`## ${categoryTitle}`);
125
+
126
+ for (const mem of byCategory[cat]) {
127
+ const salience = Math.round(mem.salience * 100);
128
+ lines.push(`- **${mem.title}** (${salience}% salience)`);
129
+ // Truncate long content
130
+ const content = mem.content.length > 200
131
+ ? mem.content.slice(0, 200) + '...'
132
+ : mem.content;
133
+ lines.push(` ${content}`);
134
+ }
135
+ lines.push('');
136
+ }
137
+
138
+ return lines.join('\n');
139
+ }
140
+
141
+ // ==================== MAIN HOOK LOGIC ====================
142
+
143
+ let input = '';
144
+ process.stdin.setEncoding('utf8');
145
+
146
+ process.stdin.on('readable', () => {
147
+ let chunk;
148
+ while ((chunk = process.stdin.read()) !== null) {
149
+ input += chunk;
150
+ }
151
+ });
152
+
153
+ process.stdin.on('end', () => {
154
+ try {
155
+ const hookData = JSON.parse(input || '{}');
156
+ const project = extractProjectFromPath(hookData.cwd || process.cwd());
157
+
158
+ if (!project) {
159
+ // No project detected, skip context retrieval
160
+ process.exit(0);
161
+ }
162
+
163
+ // Check if database exists
164
+ if (!existsSync(DB_PATH)) {
165
+ console.error('[session-start] Memory database not found, skipping context retrieval');
166
+ process.exit(0);
167
+ }
168
+
169
+ // Connect to database (read-only to avoid contention)
170
+ // timeout: 5000ms to handle busy database during concurrent access
171
+ const db = new Database(DB_PATH, { readonly: true, timeout: 5000 });
172
+
173
+ // Get project context
174
+ const memories = getProjectContext(db, project);
175
+ const context = formatContext(memories, project);
176
+
177
+ db.close();
178
+
179
+ // Proactive memory instructions
180
+ const proactiveInstructions = `
181
+ ## IMPORTANT: Proactive Memory Use
182
+
183
+ You have access to a persistent memory system. Use it proactively:
184
+
185
+ **ALWAYS use \`remember\` immediately when:**
186
+ - Making architecture/design decisions
187
+ - Fixing bugs (capture the root cause and solution)
188
+ - Learning something new about the codebase
189
+ - User states a preference
190
+ - Completing significant features
191
+
192
+ **Don't wait** - call \`remember\` right after the event, not at the end of the session.
193
+ `;
194
+
195
+ if (context) {
196
+ // Output context to stdout - this will be shown to Claude
197
+ console.log(`
198
+ 🧠 CLAUDE CORTEX - Project "${project}"
199
+
200
+ ${context}
201
+ ${proactiveInstructions}
202
+ `);
203
+ console.error(`[claude-cortex] Session start: loaded ${memories.length} memories for "${project}"`);
204
+ } else {
205
+ console.log(`
206
+ 🧠 CLAUDE CORTEX - New project "${project}"
207
+
208
+ No stored memories yet for this project.
209
+ ${proactiveInstructions}
210
+ `);
211
+ console.error(`[claude-cortex] Session start: no memories found for "${project}"`);
212
+ }
213
+
214
+ process.exit(0);
215
+ } catch (error) {
216
+ console.error(`[session-start] Error: ${error.message}`);
217
+ process.exit(0); // Don't block session start on errors
218
+ }
219
+ });
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # Claude Memory Dashboard Startup Script
3
+ # Starts both the API server and Next.js dashboard
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
7
+ LOG_DIR="$HOME/.claude-memory/logs"
8
+
9
+ # Create log directory
10
+ mkdir -p "$LOG_DIR"
11
+
12
+ # Kill any existing instances
13
+ pkill -f "node.*visualization-server" 2>/dev/null
14
+ pkill -f "next-server.*3030" 2>/dev/null
15
+
16
+ # Wait for processes to stop
17
+ sleep 1
18
+
19
+ # Start API server (port 3001)
20
+ cd "$PROJECT_DIR"
21
+ nohup npm run dev:api > "$LOG_DIR/api-server.log" 2>&1 &
22
+ API_PID=$!
23
+ echo "API server started (PID: $API_PID)"
24
+
25
+ # Wait for API to be ready
26
+ sleep 2
27
+
28
+ # Start Next.js dashboard (port 3030)
29
+ cd "$PROJECT_DIR/dashboard"
30
+ nohup npm run dev > "$LOG_DIR/dashboard.log" 2>&1 &
31
+ DASHBOARD_PID=$!
32
+ echo "Dashboard started (PID: $DASHBOARD_PID)"
33
+
34
+ # Save PIDs for later shutdown
35
+ echo "$API_PID" > "$LOG_DIR/api-server.pid"
36
+ echo "$DASHBOARD_PID" > "$LOG_DIR/dashboard.pid"
37
+
38
+ echo "Claude Memory Dashboard running:"
39
+ echo " - API: http://localhost:3001"
40
+ echo " - Dashboard: http://localhost:3030"
41
+ echo " - Logs: $LOG_DIR"
@@ -0,0 +1,21 @@
1
+ #!/bin/bash
2
+ # Stop Claude Memory Dashboard
3
+
4
+ LOG_DIR="$HOME/.claude-memory/logs"
5
+
6
+ # Kill by PID files if they exist
7
+ if [ -f "$LOG_DIR/api-server.pid" ]; then
8
+ kill $(cat "$LOG_DIR/api-server.pid") 2>/dev/null
9
+ rm "$LOG_DIR/api-server.pid"
10
+ fi
11
+
12
+ if [ -f "$LOG_DIR/dashboard.pid" ]; then
13
+ kill $(cat "$LOG_DIR/dashboard.pid") 2>/dev/null
14
+ rm "$LOG_DIR/dashboard.pid"
15
+ fi
16
+
17
+ # Also kill by process name as fallback
18
+ pkill -f "node.*visualization-server" 2>/dev/null
19
+ pkill -f "next-server.*3030" 2>/dev/null
20
+
21
+ echo "Claude Memory Dashboard stopped"