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 +26 -8
- package/dist/hooks/post-tool-use.js +84 -2
- package/dist/hooks/session-end.js +22 -1
- package/dist/hooks/session-start.js +9 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# claude-session-continuity-mcp (v1.
|
|
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
|
[](https://www.npmjs.com/package/claude-session-continuity-mcp)
|
|
6
6
|
[](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
|
|
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)
|
|
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
|
|
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) -
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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._');
|