specmem-hardwicksoftware 3.7.11 → 3.7.12

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.
Files changed (2) hide show
  1. package/bootstrap.cjs +43 -23
  2. package/package.json +1 -1
package/bootstrap.cjs CHANGED
@@ -357,8 +357,10 @@ function killStaleBootstraps() {
357
357
  const currentPid = process.pid;
358
358
  const projectPath = process.env.SPECMEM_PROJECT_PATH;
359
359
 
360
+ if (!projectPath) return; // Can't scope without a project path
361
+
360
362
  try {
361
- // Find all node processes running bootstrap.cjs from this same directory
363
+ // Find all node processes running bootstrap.cjs
362
364
  const result = execSync(
363
365
  `ps aux | grep -E "node.*bootstrap\\.cjs" | grep -v grep | awk '{print $2}'`,
364
366
  { encoding: 'utf8', timeout: 5000 }
@@ -371,37 +373,55 @@ function killStaleBootstraps() {
371
373
  const pid = parseInt(pidStr.trim(), 10);
372
374
  if (isNaN(pid) || pid === currentPid) continue;
373
375
 
374
- // Check if this process is from the same project directory
376
+ // Check if this process serves the SAME project by reading its
377
+ // SPECMEM_PROJECT_PATH env var — this is the definitive project identity,
378
+ // not cwd which can differ from the actual project being served.
375
379
  try {
376
- const cwdLink = fs.readlinkSync(`/proc/${pid}/cwd`);
377
- if (cwdLink === projectPath || cwdLink.startsWith(projectPath + '/')) {
378
- // CRITICAL: Only kill processes older than 30 seconds to avoid race conditions
379
- // when spawns multiple MCP server attempts in quick succession
380
- try {
381
- const stat = fs.statSync(`/proc/${pid}`);
382
- const processAge = Date.now() - stat.ctimeMs;
383
- if (processAge < 30000) {
384
- startupLog(`CLEANUP: Skipping young process ${pid} (age: ${Math.round(processAge/1000)}s < 30s)`);
385
- continue;
380
+ let otherProjectPath = null;
381
+ try {
382
+ const environ = fs.readFileSync(`/proc/${pid}/environ`, 'utf8');
383
+ const envVars = environ.split('\0');
384
+ for (const v of envVars) {
385
+ if (v.startsWith('SPECMEM_PROJECT_PATH=')) {
386
+ otherProjectPath = v.substring('SPECMEM_PROJECT_PATH='.length);
387
+ break;
386
388
  }
387
- } catch (e) {
388
- // Can't determine age, skip to be safe
389
- continue;
390
389
  }
390
+ } catch (e) {
391
+ // Can't read environ (permissions), fall back to cwd check
392
+ try {
393
+ otherProjectPath = fs.readlinkSync(`/proc/${pid}/cwd`);
394
+ } catch { continue; } // Can't determine project — skip to be safe
395
+ }
391
396
 
392
- startupLog(`CLEANUP: Killing stale bootstrap process ${pid} (cwd: ${cwdLink})`);
393
- process.kill(pid, 'SIGTERM');
394
- // Give it a moment to die gracefully, then force kill
395
- setTimeout(() => {
396
- try { process.kill(pid, 'SIGKILL'); } catch (e) { /* already dead */ }
397
- }, 1000);
397
+ if (!otherProjectPath) continue; // Can't determine skip
398
+
399
+ // STRICT: Only kill if EXACT same project path
400
+ if (otherProjectPath !== projectPath) continue;
401
+
402
+ // Only kill processes older than 30 seconds to avoid race conditions
403
+ try {
404
+ const stat = fs.statSync(`/proc/${pid}`);
405
+ const processAge = Date.now() - stat.ctimeMs;
406
+ if (processAge < 30000) {
407
+ startupLog(`CLEANUP: Skipping young process ${pid} (age: ${Math.round(processAge/1000)}s < 30s)`);
408
+ continue;
409
+ }
410
+ } catch (e) {
411
+ // Can't determine age, skip to be safe
412
+ continue;
398
413
  }
414
+
415
+ startupLog(`CLEANUP: Killing stale bootstrap for same project ${pid} (project: ${otherProjectPath})`);
416
+ process.kill(pid, 'SIGTERM');
417
+ setTimeout(() => {
418
+ try { process.kill(pid, 'SIGKILL'); } catch (e) { /* already dead */ }
419
+ }, 1000);
399
420
  } catch (e) {
400
- // Process might have died or we can't read its cwd - ignore
421
+ // Process might have died or we can't read its info - skip
401
422
  }
402
423
  }
403
424
  } catch (e) {
404
- // Cleanup is best-effort - don't fail startup if it doesn't work
405
425
  startupLog(`CLEANUP: Could not check for stale processes: ${e.message}`);
406
426
  }
407
427
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specmem-hardwicksoftware",
3
- "version": "3.7.11",
3
+ "version": "3.7.12",
4
4
  "type": "module",
5
5
  "description": "Persistent memory system for coding sessions - semantic search with pgvector, token compression, team coordination, file watching. Needs root: installs system-wide hooks, manages docker/PostgreSQL, writes global configs, handles screen sessions. justcalljon.pro",
6
6
  "main": "dist/index.js",