@sdsrs/code-graph 0.57.0 → 0.59.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.
@@ -4,7 +4,7 @@
4
4
  "author": {
5
5
  "name": "sdsrs"
6
6
  },
7
- "version": "0.57.0",
7
+ "version": "0.59.0",
8
8
  "keywords": [
9
9
  "code-graph",
10
10
  "ast",
@@ -24,6 +24,15 @@ function readAdoptedBy(filePath) {
24
24
  return m ? m[1] : null;
25
25
  } catch { return null; }
26
26
  }
27
+ // Atomic write (tmp in same dir → rename) so a crash mid-write can't leave a
28
+ // half-written MEMORY.md / detail file — the dir is shared with claude-mem-lite,
29
+ // which reads MEMORY.md on every keyword match. Mirrors lifecycle.js
30
+ // writeJsonAtomic / auto-update.js binary promote; accepts a string or Buffer.
31
+ function writeFileAtomic(filePath, data) {
32
+ const tmp = filePath + '.tmp.' + process.pid;
33
+ fs.writeFileSync(tmp, data);
34
+ fs.renameSync(tmp, filePath);
35
+ }
27
36
  // One-liner per MEMORY.md spec ("each entry should be one line"). All routing
28
37
  // triggers from prior multi-line block preserved verbatim — collapsing to single
29
38
  // line is a structural fix, not a signal change. Decision table lives in the
@@ -354,7 +363,7 @@ function adopt({ cwd, home, templatePath } = {}) {
354
363
  // ADOPTED_BY_RE strip below).
355
364
  const tplBody = fs.readFileSync(tpl);
356
365
  const marker = Buffer.from(`<!-- adopted-by: ${effectiveCwd} -->\n`);
357
- fs.writeFileSync(target, Buffer.concat([marker, tplBody]));
366
+ writeFileAtomic(target, Buffer.concat([marker, tplBody]));
358
367
 
359
368
  const indexPath = path.join(dir, 'MEMORY.md');
360
369
  const index = fs.existsSync(indexPath) ? fs.readFileSync(indexPath, 'utf8') : '# Memory Index\n';
@@ -372,7 +381,7 @@ function adopt({ cwd, home, templatePath } = {}) {
372
381
  const cleaned = stripSentinelBlock(index);
373
382
  const healed = cleaned !== index;
374
383
  const base = cleaned.endsWith('\n') ? cleaned : cleaned + '\n';
375
- fs.writeFileSync(indexPath, base + desiredBlock + '\n');
384
+ writeFileAtomic(indexPath, base + desiredBlock + '\n');
376
385
  return { ok: true, target, indexPath, indexed: true, healed, collisionWith };
377
386
  }
378
387
 
@@ -479,7 +488,7 @@ function unadopt({ cwd, home } = {}) {
479
488
  const before = fs.readFileSync(indexPath, 'utf8');
480
489
  const after = stripSentinelBlock(before);
481
490
  if (after !== before) {
482
- fs.writeFileSync(indexPath, after);
491
+ writeFileAtomic(indexPath, after);
483
492
  indexPruned = true;
484
493
  }
485
494
  }
@@ -90,6 +90,21 @@ test('adopt preserves existing MEMORY.md content and appends', () => {
90
90
  } finally { sb.cleanup(); }
91
91
  });
92
92
 
93
+ test('adopt + unadopt write atomically — no .tmp residue in the memory dir', () => {
94
+ // The memory dir is shared with claude-mem-lite, which reads MEMORY.md on
95
+ // every keyword match; a non-atomic write crashing mid-flight would corrupt
96
+ // it. adopt/unadopt now go through writeFileAtomic (tmp + rename). Proof the
97
+ // rename completed cleanly across all three write sites (detail file + adopt
98
+ // index + unadopt prune): no leftover `*.tmp.<pid>` entries.
99
+ const sb = makeSandbox();
100
+ try {
101
+ adopt({ cwd: sb.cwd, home: sb.home });
102
+ unadopt({ cwd: sb.cwd, home: sb.home });
103
+ const residue = fs.readdirSync(sb.dir).filter((f) => f.includes('.tmp.'));
104
+ assert.deepStrictEqual(residue, [], `no atomic-write tmp residue; found: ${residue}`);
105
+ } finally { sb.cleanup(); }
106
+ });
107
+
93
108
  test('adopt refuses a non-project cwd even when the memory dir already exists (regression: /tmp adoption)', () => {
94
109
  // Bug: the isProjectRoot guard was nested inside `if (!fs.existsSync(dir))`,
95
110
  // so when Claude Code had already created ~/.claude/projects/<slug>/memory
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sdsrs/code-graph",
3
- "version": "0.57.0",
3
+ "version": "0.59.0",
4
4
  "description": "MCP server that indexes codebases into an AST knowledge graph with semantic search, call graph traversal, and HTTP route tracing",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,10 +35,10 @@
35
35
  "node": ">=16"
36
36
  },
37
37
  "optionalDependencies": {
38
- "@sdsrs/code-graph-linux-x64": "0.57.0",
39
- "@sdsrs/code-graph-linux-arm64": "0.57.0",
40
- "@sdsrs/code-graph-darwin-x64": "0.57.0",
41
- "@sdsrs/code-graph-darwin-arm64": "0.57.0",
42
- "@sdsrs/code-graph-win32-x64": "0.57.0"
38
+ "@sdsrs/code-graph-linux-x64": "0.59.0",
39
+ "@sdsrs/code-graph-linux-arm64": "0.59.0",
40
+ "@sdsrs/code-graph-darwin-x64": "0.59.0",
41
+ "@sdsrs/code-graph-darwin-arm64": "0.59.0",
42
+ "@sdsrs/code-graph-win32-x64": "0.59.0"
43
43
  }
44
44
  }