claude-memory-layer 1.0.12 → 1.0.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory-layer",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Claude Code plugin that learns from conversations to provide personalized assistance",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
6
+
7
+ cd "${ROOT_DIR}"
8
+
9
+ if [[ ! -f package.json ]]; then
10
+ echo "Error: package.json not found in ${ROOT_DIR}" >&2
11
+ exit 1
12
+ fi
13
+
14
+ old_version="$(node -p "require('./package.json').version")"
15
+ npm version patch --no-git-tag-version >/dev/null
16
+ new_version="$(node -p "require('./package.json').version")"
17
+
18
+ echo "Version bumped: ${old_version} -> ${new_version}"
@@ -126,19 +126,31 @@ export class SessionHistoryImporter {
126
126
 
127
127
  // Find project directory
128
128
  onProgress?.({ phase: 'scan', message: 'Scanning for session files...' });
129
- const projectDir = await this.findProjectDir(projectPath);
130
- if (!projectDir) {
129
+ const projectDirs = await this.findProjectDirs(projectPath);
130
+ if (projectDirs.length === 0) {
131
131
  result.errors.push(`Project directory not found for: ${projectPath}`);
132
132
  return result;
133
133
  }
134
134
 
135
- // Find all session files
136
- const sessionFiles = await this.findSessionFiles(projectDir);
135
+ // Find all session files across matched directories
136
+ const allSessionFiles: string[] = [];
137
+ for (const dir of projectDirs) {
138
+ const files = await this.findSessionFiles(dir);
139
+ allSessionFiles.push(...files);
140
+ }
141
+ const sessionFiles = [...new Set(allSessionFiles)];
137
142
  result.totalSessions = sessionFiles.length;
138
- onProgress?.({ phase: 'scan', message: `Found ${sessionFiles.length} sessions in ${path.basename(projectDir)}` });
143
+ onProgress?.({
144
+ phase: 'scan',
145
+ message: `Found ${sessionFiles.length} sessions in ${projectDirs.length} matched project folder(s)`
146
+ });
139
147
 
140
148
  if (options.verbose) {
141
- console.log(`Found ${sessionFiles.length} session files in ${projectDir}`);
149
+ console.log(`Matched project folders:`);
150
+ for (const dir of projectDirs) {
151
+ console.log(` - ${dir}`);
152
+ }
153
+ console.log(`Found ${sessionFiles.length} session files across matched folders`);
142
154
  }
143
155
 
144
156
  // Import each session
@@ -401,33 +413,52 @@ export class SessionHistoryImporter {
401
413
  }
402
414
 
403
415
  /**
404
- * Find project directory from project path
416
+ * Find project directories from project path.
417
+ * Supports wrappers (e.g. happy) that append extra path segments in folder names.
405
418
  */
406
- private async findProjectDir(projectPath: string): Promise<string | null> {
419
+ private async findProjectDirs(projectPath: string): Promise<string[]> {
407
420
  const projectsDir = path.join(this.claudeDir, 'projects');
408
421
  if (!fs.existsSync(projectsDir)) {
409
- return null;
422
+ return [];
410
423
  }
411
424
 
412
- // Claude uses a hash of the project path as directory name
413
- // Try to find matching directory by checking all projects
414
425
  const projectDirs = fs.readdirSync(projectsDir)
415
426
  .map(name => path.join(projectsDir, name))
416
427
  .filter(p => fs.statSync(p).isDirectory());
417
428
 
418
- // Look for directory that matches the project path pattern
419
- // The directory name format is: -home-user-project-name
420
- const normalizedPath = projectPath.replace(/\//g, '-').replace(/^-/, '');
429
+ const normalizedPath = projectPath.replace(/\/+/g, '/').replace(/\/$/, '');
430
+ const normalizedDashed = normalizedPath.replace(/\//g, '-').replace(/^-/, '');
431
+ const baseName = path.basename(normalizedPath);
421
432
 
422
- for (const dir of projectDirs) {
433
+ const scored = projectDirs.map((dir) => {
423
434
  const dirName = path.basename(dir);
424
- if (dirName.includes(normalizedPath) || normalizedPath.includes(dirName)) {
425
- return dir;
426
- }
427
- }
435
+ let score = 0;
436
+
437
+ // strong matches
438
+ if (dirName.includes(normalizedDashed)) score += 100;
439
+ if (normalizedDashed.includes(dirName)) score += 80;
440
+
441
+ // basename signal (handles wrappers adding extra suffix)
442
+ if (baseName && dirName.includes(baseName)) score += 30;
443
+
444
+ // token overlap signal
445
+ const pathTokens = normalizedDashed.split('-').filter(Boolean);
446
+ const tokenHits = pathTokens.filter(t => t.length >= 3 && dirName.includes(t)).length;
447
+ score += Math.min(tokenHits, 20);
428
448
 
429
- // If exact match not found, return first match or null
430
- return projectDirs.length > 0 ? projectDirs[0] : null;
449
+ return { dir, score, dirName };
450
+ }).filter(x => x.score > 0)
451
+ .sort((a, b) => b.score - a.score);
452
+
453
+ if (scored.length === 0) return [];
454
+
455
+ // Keep close matches (same family) to include wrapper-generated variants
456
+ const top = scored[0].score;
457
+ const threshold = Math.max(30, top - 25);
458
+
459
+ return scored
460
+ .filter(x => x.score >= threshold)
461
+ .map(x => x.dir);
431
462
  }
432
463
 
433
464
  /**
@@ -489,10 +520,7 @@ export class SessionHistoryImporter {
489
520
  let projectDirs: string[] = [];
490
521
 
491
522
  if (projectPath) {
492
- const projectDir = await this.findProjectDir(projectPath);
493
- if (projectDir) {
494
- projectDirs = [projectDir];
495
- }
523
+ projectDirs = await this.findProjectDirs(projectPath);
496
524
  } else {
497
525
  const projectsDir = path.join(this.claudeDir, 'projects');
498
526
  if (fs.existsSync(projectsDir)) {