claude-session-continuity-mcp 1.11.0 → 1.12.1

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # claude-session-continuity-mcp (v1.10.0)
1
+ # claude-session-continuity-mcp (v1.12.1)
2
2
 
3
- > **Zero Re-explanation Session Continuity for Claude Code** — Automatic context capture + semantic search
3
+ > **Zero Re-explanation Session Continuity for Claude Code** — Automatic context capture + semantic search + auto error→solution pipeline
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/claude-session-continuity-mcp.svg)](https://www.npmjs.com/package/claude-session-continuity-mcp)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -27,7 +27,7 @@ Every new Claude Code session:
27
27
  ```bash
28
28
  # Session start → Auto-loads relevant context + recent session history
29
29
  # When asking → Auto-injects relevant memories/solutions
30
- # During conversation → Tracks active files (no noise memories)
30
+ # During conversation → Tracks active files + auto-injects error solutions
31
31
  # On compact → Structured handover context for continuity
32
32
  # On exit → Extracts commits, decisions, error-fix pairs from transcript
33
33
  ```
@@ -108,7 +108,7 @@ npm install claude-session-continuity-mcp
108
108
  |------|---------|----------|
109
109
  | `SessionStart` | `claude-hook-session-start` | Auto-loads project context on session start |
110
110
  | `UserPromptSubmit` | `claude-hook-user-prompt` | Auto-injects relevant memories + past reference search |
111
- | `PostToolUse` | `claude-hook-post-tool` | Tracks active files (Edit, Write) no noise memories |
111
+ | `PostToolUse` | `claude-hook-post-tool` | Tracks active files (Edit, Write) + auto-injects error solutions (Bash) |
112
112
  | `PreCompact` | `claude-hook-pre-compact` | Structured handover context before compression |
113
113
  | `Stop` | `claude-hook-session-end` | Extracts commits, decisions, error-fix pairs from transcript |
114
114
 
@@ -144,7 +144,10 @@ After installation, restart Claude Code to activate the hooks.
144
144
  | 📊 **Memory Classification** | 5 types: observation, decision, learning, error, pattern |
145
145
  | ✅ **Integrated Verification** | One-click build/test/lint execution |
146
146
  | 📋 **Task Management** | Priority-based task management |
147
- | 🔧 **Solution Archive** | Auto-search error solutions |
147
+ | 🔧 **Auto Error→Solution** | **(v1.12.0)** Bash errors auto-detect inject past solutions; session-end auto-records error-fix pairs |
148
+ | 💰 **Token Efficiency** | **(v1.11.0)** Removed loadContext from UserPromptSubmit (saves 24-60K tokens/session) |
149
+ | 📑 **Progressive Disclosure** | **(v1.11.0)** memory_search returns index first, memory_get for full content |
150
+ | ⏳ **Temporal Decay** | **(v1.11.0)** Memory scoring with type-specific half-lives for relevance |
148
151
  | 📝 **Structured Handover** | **(v1.10.0)** PreCompact saves work summary, active files, pending actions |
149
152
  | 🚪 **Smart Session End** | **(v1.10.0)** Extracts commits, decisions, error-fix pairs from transcript |
150
153
  | 🗑️ **Auto Noise Cleanup** | **(v1.10.0)** Auto-deletes stale observation memories (3d+) |
@@ -165,10 +168,12 @@ After installation, restart Claude Code to activate the hooks.
165
168
 
166
169
  **UserPromptSubmit Hook** (`npx claude-hook-user-prompt`):
167
170
  - Runs on every prompt submission
171
+ - **(v1.11.0)** No longer calls loadContext() — saves 24-60K tokens/session
168
172
  - Injects relevant context (filtered: decisions, learnings, errors only)
169
173
 
170
174
  **PostToolUse Hook** (`npx claude-hook-post-tool`):
171
175
  - Tracks hot file paths and updates `active_context.recent_files`
176
+ - **(v1.12.0)** Auto-detects Bash errors → searches solutions DB → injects past solutions into context
172
177
  - **No longer creates observation memories** (v1.10.0 — eliminates `[File Change]` noise)
173
178
 
174
179
  **PreCompact Hook** (`npx claude-hook-pre-compact`):
@@ -178,7 +183,9 @@ After installation, restart Claude Code to activate the hooks.
178
183
  **Stop Hook** (`npx claude-hook-session-end`):
179
184
  - Extracts commit messages from JSONL transcript (`git commit -m` patterns)
180
185
  - Extracts error-fix pairs (error → resolution within 3 messages)
186
+ - **(v1.12.0)** Auto-records error→fix pairs to solutions table for future reuse
181
187
  - Extracts decisions ("because", "instead of", "chose" patterns)
188
+ - **(v1.11.0)** Single-pass transcript parsing (4 JSONL reads → 1)
182
189
  - Stores structured metadata in `sessions.issues` column as JSON
183
190
 
184
191
  ### Example Output (Session Start)
@@ -280,7 +287,7 @@ Now we use `npm exec --`:
280
287
 
281
288
  ---
282
289
 
283
- ## Tools (v5 API) - 24 Focused Tools
290
+ ## Tools (v5 API) - 25 Focused Tools
284
291
 
285
292
  ### 1. Session Lifecycle (4) ⭐
286
293
 
@@ -363,7 +370,7 @@ verify_test({ project: "my-app" })
363
370
  verify_all({ project: "my-app" })
364
371
  ```
365
372
 
366
- ### 6. Memory System (4)
373
+ ### 6. Memory System (5)
367
374
 
368
375
  ```javascript
369
376
  // Store a classified memory
@@ -376,7 +383,7 @@ memory_store({
376
383
  relatedTo: 23 // Connect to existing memory
377
384
  })
378
385
 
379
- // Search memories (keyword or semantic)
386
+ // Search memories — returns index (id, type, tags, score) for token efficiency
380
387
  memory_search({
381
388
  query: "state management test",
382
389
  type: "learning",
@@ -384,6 +391,9 @@ memory_search({
384
391
  limit: 10
385
392
  })
386
393
 
394
+ // Get full memory content by ID (v1.11.0)
395
+ memory_get({ memoryId: 23 })
396
+
387
397
  // Find related memories (graph + semantic)
388
398
  memory_related({
389
399
  memoryId: 23,
@@ -528,6 +538,14 @@ npm run test:coverage
528
538
  - [x] Smart session-end: commit/decision/error-fix extraction from transcript (v1.10.0)
529
539
  - [x] Auto noise cleanup (3d+ observations, 14d+ auto-compact) (v1.10.0)
530
540
  - [x] 3 recent sessions display with structured metadata (v1.10.0)
541
+ - [x] Token efficiency — remove loadContext from UserPromptSubmit, saves 24-60K tokens/session (v1.11.0)
542
+ - [x] Single-pass transcript parsing, 4 JSONL reads → 1 (v1.11.0)
543
+ - [x] Temporal decay for memory scoring with type-specific half-lives (v1.11.0)
544
+ - [x] Progressive disclosure — memory_search returns index, memory_get for full content (v1.11.0)
545
+ - [x] Memory consolidation via Jaccard similarity (v1.11.0)
546
+ - [x] Auto error→solution pipeline — PostToolUse detects Bash errors, injects past solutions (v1.12.0)
547
+ - [x] SessionEnd auto-records error-fix pairs to solutions table (v1.12.0)
548
+ - [x] Cross-project solution search with current project prioritization (v1.12.0)
531
549
  - [ ] sqlite-vec native vector search (v2 - when data > 1000 records)
532
550
  - [ ] Web dashboard
533
551
  - [ ] Cloud sync option
@@ -7,6 +7,58 @@
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
9
  import Database from 'better-sqlite3';
10
+ // ===== 에러 감지 → 솔루션 자동 주입 =====
11
+ const ERROR_PATTERNS = [
12
+ /(?:error|Error|ERROR)\s*[:\[]/,
13
+ /(?:FAILED|FAIL|failed)\s/,
14
+ /(?:Cannot find|Module not found|No such file)/,
15
+ /(?:Permission denied|EACCES|EPERM)/,
16
+ /(?:command not found|ENOENT)/,
17
+ /exit code [1-9]/,
18
+ /(?:TypeError|SyntaxError|ReferenceError|RangeError)\s*:/,
19
+ /(?:FATAL|panic|segfault)/i,
20
+ ];
21
+ function extractErrorSignature(output) {
22
+ const lines = output.split('\n');
23
+ for (const line of lines) {
24
+ const trimmed = line.trim();
25
+ if (trimmed.length < 10)
26
+ continue;
27
+ for (const pattern of ERROR_PATTERNS) {
28
+ if (pattern.test(trimmed)) {
29
+ // 에러 라인에서 시그니처 추출 (파일 경로/라인번호 제거, 핵심만)
30
+ return trimmed
31
+ .replace(/\s+at\s+.+$/, '') // stack trace 제거
32
+ .replace(/\(.*?\)/g, '') // 경로 괄호 제거
33
+ .slice(0, 80)
34
+ .trim();
35
+ }
36
+ }
37
+ }
38
+ return null;
39
+ }
40
+ function searchSolutions(db, project, errorSig) {
41
+ try {
42
+ // 에러 키워드 추출 (3글자 이상 단어)
43
+ const keywords = errorSig.split(/\s+/).filter(w => w.length > 3).slice(0, 3);
44
+ if (keywords.length === 0)
45
+ return [];
46
+ const likeConditions = keywords.map(() => 'error_signature LIKE ?').join(' OR ');
47
+ const likeParams = keywords.map(k => `%${k}%`);
48
+ return db.prepare(`
49
+ SELECT error_signature, solution, project, created_at
50
+ FROM solutions
51
+ WHERE (${likeConditions})
52
+ ORDER BY
53
+ CASE WHEN project = ? THEN 0 ELSE 1 END,
54
+ created_at DESC
55
+ LIMIT 2
56
+ `).all(...likeParams, project);
57
+ }
58
+ catch {
59
+ return [];
60
+ }
61
+ }
10
62
  function detectWorkspaceRoot(cwd) {
11
63
  let current = cwd;
12
64
  const root = path.parse(current).root;
@@ -107,10 +159,40 @@ async function main() {
107
159
  inputData += chunk;
108
160
  }
109
161
  const input = inputData ? JSON.parse(inputData) : {};
162
+ const toolName = input.tool_name;
163
+ if (!toolName) {
164
+ process.exit(0);
165
+ }
166
+ // Bash 에러 감지 → 솔루션 자동 주입
167
+ if (toolName === 'Bash' && input.tool_result) {
168
+ const errorSig = extractErrorSignature(input.tool_result);
169
+ if (errorSig) {
170
+ const cwd = input.cwd || process.cwd();
171
+ const project = detectProject(cwd);
172
+ const dbPath = getDbPath(cwd);
173
+ if (fs.existsSync(dbPath)) {
174
+ try {
175
+ const db = new Database(dbPath, { readonly: true });
176
+ const solutions = searchSolutions(db, project, errorSig);
177
+ db.close();
178
+ if (solutions.length > 0) {
179
+ const lines = ['## Past solutions for similar error\n'];
180
+ for (const s of solutions) {
181
+ const sol = s.solution.length > 100 ? s.solution.slice(0, 100) + '...' : s.solution;
182
+ const date = s.created_at?.slice(0, 10) || '';
183
+ lines.push(`- **${s.error_signature.slice(0, 60)}** → ${sol} (${s.project}, ${date})`);
184
+ }
185
+ console.log(`\n<past-solution>\n${lines.join('\n')}\n</past-solution>\n`);
186
+ }
187
+ }
188
+ catch { /* ignore */ }
189
+ }
190
+ }
191
+ process.exit(0);
192
+ }
110
193
  const TRACKED_TOOLS = ['Edit', 'Write', 'Read', 'Glob', 'Grep'];
111
194
  const IGNORED_PATTERNS = ['node_modules', '.git/', 'dist/', 'build/', '.next/', 'coverage/', '.DS_Store'];
112
- const toolName = input.tool_name;
113
- if (!toolName || !TRACKED_TOOLS.includes(toolName)) {
195
+ if (!TRACKED_TOOLS.includes(toolName)) {
114
196
  process.exit(0);
115
197
  }
116
198
  // Read/Glob/Grep에서도 파일 경로 추출
@@ -237,6 +237,7 @@ async function parseTranscriptSinglePass(transcriptPath) {
237
237
  decisions: [],
238
238
  userRequests: { firstRequest: '', allRequests: [] },
239
239
  recentAssistantMessages: [],
240
+ errorFixPairs: [],
240
241
  };
241
242
  if (!transcriptPath || !fs.existsSync(transcriptPath))
242
243
  return result;
@@ -354,7 +355,11 @@ async function parseTranscriptSinglePass(transcriptPath) {
354
355
  const errorStr = stripMarkdown(errorMatch[0]).slice(0, 80);
355
356
  const fixLine = recentEntries[j].text.split('\n').find(l => fixRe.test(l));
356
357
  const fixStr = fixLine ? stripMarkdown(fixLine).slice(0, 80) : 'resolved';
357
- pairSet.add(`${errorStr} → ${fixStr}`);
358
+ const pairKey = `${errorStr} → ${fixStr}`;
359
+ if (!pairSet.has(pairKey)) {
360
+ pairSet.add(pairKey);
361
+ result.errorFixPairs.push({ error: errorStr, fix: fixStr });
362
+ }
358
363
  break;
359
364
  }
360
365
  }
@@ -427,6 +432,7 @@ async function main() {
427
432
  commitMessages: [], errorsSolved: [], decisions: [],
428
433
  userRequests: { firstRequest: '', allRequests: [] },
429
434
  recentAssistantMessages: [],
435
+ errorFixPairs: [],
430
436
  };
431
437
  if (input.transcript_path) {
432
438
  transcript = await parseTranscriptSinglePass(input.transcript_path);
@@ -547,10 +553,25 @@ async function main() {
547
553
  INSERT OR REPLACE INTO active_context (project, current_state, recent_files, updated_at)
548
554
  VALUES (?, ?, ?, datetime('now'))
549
555
  `).run(project, lastWork, JSON.stringify(modifiedFiles.slice(0, 15)));
556
+ // 에러→솔루션 자동 기록 (solutions 테이블)
557
+ let solutionsRecorded = 0;
558
+ if (transcript.errorFixPairs.length > 0) {
559
+ try {
560
+ for (const pair of transcript.errorFixPairs) {
561
+ const existing = db.prepare('SELECT id FROM solutions WHERE project = ? AND error_signature = ? LIMIT 1').get(project, pair.error);
562
+ if (!existing) {
563
+ db.prepare('INSERT INTO solutions (project, error_signature, solution) VALUES (?, ?, ?)').run(project, pair.error, pair.fix);
564
+ solutionsRecorded++;
565
+ }
566
+ }
567
+ }
568
+ catch { /* solutions table may not exist */ }
569
+ }
550
570
  db.close();
551
571
  console.log(`[SessionEnd] Saved session for ${project}`);
552
572
  console.log(` Last work: ${lastWork.slice(0, 80)}`);
553
573
  console.log(` Commits: ${commitMessages.length}, Decisions: ${decisions.length}, Errors: ${errorsSolved.length}`);
574
+ console.log(` Solutions auto-recorded: ${solutionsRecorded}`);
554
575
  console.log(` Modified files: ${modifiedFiles.length}`);
555
576
  console.log(` Next tasks: ${nextTasks.length}`);
556
577
  process.exit(0);
@@ -176,6 +176,15 @@ function loadContext(dbPath, project) {
176
176
  }
177
177
  }
178
178
  catch { /* ignore */ }
179
+ // 솔루션 통계 (1줄)
180
+ try {
181
+ const solCount = db.prepare('SELECT COUNT(*) as cnt FROM solutions WHERE project = ?').get(project)?.cnt || 0;
182
+ if (solCount > 0) {
183
+ lines.push(`Solutions: ${solCount} recorded (auto-injected on error)`);
184
+ lines.push('');
185
+ }
186
+ }
187
+ catch { /* solutions table may not exist */ }
179
188
  db.close();
180
189
  lines.push('---');
181
190
  lines.push('_Auto-injected by session-continuity v2. Use `session_end` when done._');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-session-continuity-mcp",
3
- "version": "1.11.0",
3
+ "version": "1.12.1",
4
4
  "description": "Session Continuity for Claude Code - Never re-explain your project again",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",