specmem-hardwicksoftware 3.7.1 → 3.7.3
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.
|
@@ -117,10 +117,10 @@ const SOURCE_COMMANDS_DIR = path.join(SPECMEM_ROOT, 'commands');
|
|
|
117
117
|
const HOOK_ENV = {
|
|
118
118
|
SPECMEM_HOME: path.join(HOME_DIR, '.specmem'), // Dynamic path using os.homedir()
|
|
119
119
|
SPECMEM_PKG: SPECMEM_ROOT, // Use detected package root
|
|
120
|
-
// Per-project socket paths - ${
|
|
120
|
+
// Per-project socket paths - ${PWD} is expanded at MCP server startup
|
|
121
121
|
SPECMEM_RUN_DIR: '${cwd}/specmem/sockets',
|
|
122
122
|
SPECMEM_EMBEDDING_SOCKET: '${cwd}/specmem/sockets/embeddings.sock',
|
|
123
|
-
SPECMEM_PROJECT_PATH: '${
|
|
123
|
+
SPECMEM_PROJECT_PATH: '${PWD}', // Dynamically set by Code
|
|
124
124
|
SPECMEM_SEARCH_LIMIT: '5',
|
|
125
125
|
SPECMEM_THRESHOLD: '0.30',
|
|
126
126
|
SPECMEM_MAX_CONTENT: '200'
|
|
@@ -213,7 +213,7 @@ export function isSpecmemMcpConfigured(projectPath) {
|
|
|
213
213
|
if (projectPath) {
|
|
214
214
|
const configuredPath = specmem.env?.SPECMEM_PROJECT_PATH;
|
|
215
215
|
// ${PWD} and ${cwd} are expanded at runtime by Claude Code, so they're valid
|
|
216
|
-
if (configuredPath && configuredPath !== '${PWD}' && configuredPath !== '${
|
|
216
|
+
if (configuredPath && configuredPath !== '${PWD}' && configuredPath !== '${PWD}' && configuredPath !== projectPath) {
|
|
217
217
|
return false;
|
|
218
218
|
}
|
|
219
219
|
}
|
|
@@ -236,17 +236,16 @@ function configureMcpServer() {
|
|
|
236
236
|
config.mcpServers = {};
|
|
237
237
|
}
|
|
238
238
|
// Build the SpecMem MCP server config
|
|
239
|
-
// CRITICAL: ${
|
|
240
|
-
// NOTE: ${PWD} resolves at MCP server startup, ${cwd} resolves per-invocation
|
|
239
|
+
// CRITICAL: ${PWD} is expanded at MCP server startup to current working directory
|
|
241
240
|
const specmemConfig = {
|
|
242
241
|
command: 'node',
|
|
243
242
|
args: ['--max-old-space-size=250', BOOTSTRAP_PATH],
|
|
244
243
|
env: {
|
|
245
|
-
// Core paths - ${
|
|
244
|
+
// Core paths - ${PWD} gives us project isolation (dynamic per-directory)
|
|
246
245
|
HOME: HOME_DIR,
|
|
247
|
-
SPECMEM_PROJECT_PATH: '${
|
|
248
|
-
SPECMEM_WATCHER_ROOT_PATH: '${
|
|
249
|
-
SPECMEM_CODEBASE_PATH: '${
|
|
246
|
+
SPECMEM_PROJECT_PATH: '${PWD}',
|
|
247
|
+
SPECMEM_WATCHER_ROOT_PATH: '${PWD}',
|
|
248
|
+
SPECMEM_CODEBASE_PATH: '${PWD}',
|
|
250
249
|
// Database (use environment values or defaults)
|
|
251
250
|
SPECMEM_DB_HOST: process.env.SPECMEM_DB_HOST || 'localhost',
|
|
252
251
|
SPECMEM_DB_PORT: process.env.SPECMEM_DB_PORT || '5432',
|
|
@@ -332,7 +331,7 @@ function fixProjectMcpConfigs() {
|
|
|
332
331
|
if (!specmem.env) {
|
|
333
332
|
specmem.env = {};
|
|
334
333
|
}
|
|
335
|
-
if (!specmem.env.SPECMEM_PROJECT_PATH || specmem.env.SPECMEM_PROJECT_PATH === '${PWD}' || specmem.env.SPECMEM_PROJECT_PATH === '${
|
|
334
|
+
if (!specmem.env.SPECMEM_PROJECT_PATH || specmem.env.SPECMEM_PROJECT_PATH === '${PWD}' || specmem.env.SPECMEM_PROJECT_PATH === '${PWD}') {
|
|
336
335
|
specmem.env.SPECMEM_PROJECT_PATH = projectPath;
|
|
337
336
|
}
|
|
338
337
|
logger.info({ projectPath, oldArgs: args, newArgs: updatedArgs }, '[ConfigInjector] Fixed outdated specmem path in project config');
|
|
@@ -349,9 +348,9 @@ function fixProjectMcpConfigs() {
|
|
|
349
348
|
args: ['--max-old-space-size=250', BOOTSTRAP_PATH],
|
|
350
349
|
env: {
|
|
351
350
|
HOME: HOME_DIR,
|
|
352
|
-
SPECMEM_PROJECT_PATH: '${
|
|
353
|
-
SPECMEM_WATCHER_ROOT_PATH: '${
|
|
354
|
-
SPECMEM_CODEBASE_PATH: '${
|
|
351
|
+
SPECMEM_PROJECT_PATH: '${PWD}',
|
|
352
|
+
SPECMEM_WATCHER_ROOT_PATH: '${PWD}',
|
|
353
|
+
SPECMEM_CODEBASE_PATH: '${PWD}',
|
|
355
354
|
SPECMEM_DB_HOST: process.env.SPECMEM_DB_HOST || 'localhost',
|
|
356
355
|
SPECMEM_DB_PORT: process.env.SPECMEM_DB_PORT || '5432',
|
|
357
356
|
SPECMEM_SESSION_WATCHER_ENABLED: 'true',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specmem-hardwicksoftware",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.3",
|
|
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",
|
package/scripts/specmem-init.cjs
CHANGED
|
@@ -3596,7 +3596,8 @@ async function indexCodebase(projectPath, ui, embeddingResult) {
|
|
|
3596
3596
|
// Revalidate socket path after failures (may have been restarted externally)
|
|
3597
3597
|
async function revalidateSocket() {
|
|
3598
3598
|
const projectSocketPath = path.join(projectPath, 'specmem', 'sockets', 'embeddings.sock');
|
|
3599
|
-
const
|
|
3599
|
+
const projDirName = path.basename(projectPath).replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
3600
|
+
const sharedSocketPath = path.join(os.homedir(), '.specmem', projDirName, 'sockets', 'embeddings.sock');
|
|
3600
3601
|
|
|
3601
3602
|
// Check project socket first (preferred)
|
|
3602
3603
|
if (fs.existsSync(projectSocketPath)) {
|
|
@@ -3609,7 +3610,7 @@ async function indexCodebase(projectPath, ui, embeddingResult) {
|
|
|
3609
3610
|
}
|
|
3610
3611
|
}
|
|
3611
3612
|
|
|
3612
|
-
// Fallback to shared socket
|
|
3613
|
+
// Fallback to shared socket (home dir)
|
|
3613
3614
|
if (fs.existsSync(sharedSocketPath)) {
|
|
3614
3615
|
activeSocketPath = sharedSocketPath;
|
|
3615
3616
|
const healthy = await checkSocketHealth();
|
|
@@ -3620,6 +3621,70 @@ async function indexCodebase(projectPath, ui, embeddingResult) {
|
|
|
3620
3621
|
}
|
|
3621
3622
|
}
|
|
3622
3623
|
|
|
3624
|
+
// Fallback to /tmp shared sockets
|
|
3625
|
+
for (let i = 0; i < 5; i++) {
|
|
3626
|
+
const tmpSocket = `/tmp/specmem-embed-${i}.sock`;
|
|
3627
|
+
if (fs.existsSync(tmpSocket)) {
|
|
3628
|
+
activeSocketPath = tmpSocket;
|
|
3629
|
+
const healthy = await checkSocketHealth();
|
|
3630
|
+
if (healthy) {
|
|
3631
|
+
initLog(`Revalidated socket: using /tmp shared socket at ${tmpSocket}`);
|
|
3632
|
+
consecutiveEmbeddingFailures = 0;
|
|
3633
|
+
return true;
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3638
|
+
// AUTO-RESTART: If no socket found, try restarting the embedding server
|
|
3639
|
+
initLog('Socket revalidation: no socket found, attempting auto-restart of embedding server...');
|
|
3640
|
+
try {
|
|
3641
|
+
const { spawn } = require('child_process');
|
|
3642
|
+
const possiblePythonPaths = [
|
|
3643
|
+
path.join(__dirname, '..', 'embedding-sandbox', 'frankenstein-embeddings.py'),
|
|
3644
|
+
path.join(projectPath, 'embedding-sandbox', 'frankenstein-embeddings.py'),
|
|
3645
|
+
'/opt/specmem/embedding-sandbox/frankenstein-embeddings.py'
|
|
3646
|
+
];
|
|
3647
|
+
let embeddingScript = null;
|
|
3648
|
+
for (const p of possiblePythonPaths) {
|
|
3649
|
+
if (fs.existsSync(p)) { embeddingScript = p; break; }
|
|
3650
|
+
}
|
|
3651
|
+
if (embeddingScript) {
|
|
3652
|
+
const socketsDir = path.join(projectPath, 'specmem', 'sockets');
|
|
3653
|
+
if (!fs.existsSync(socketsDir)) fs.mkdirSync(socketsDir, { recursive: true });
|
|
3654
|
+
// Clean stale socket
|
|
3655
|
+
if (fs.existsSync(projectSocketPath)) {
|
|
3656
|
+
try { fs.unlinkSync(projectSocketPath); } catch { /* ignore */ }
|
|
3657
|
+
}
|
|
3658
|
+
const pythonPath = getPythonPath();
|
|
3659
|
+
const proc = spawn(pythonPath, [embeddingScript], {
|
|
3660
|
+
cwd: path.dirname(embeddingScript),
|
|
3661
|
+
env: { ...process.env, SPECMEM_SOCKET_PATH: projectSocketPath, SPECMEM_PROJECT_PATH: projectPath },
|
|
3662
|
+
detached: true,
|
|
3663
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
3664
|
+
});
|
|
3665
|
+
proc.stdout.on('data', () => {});
|
|
3666
|
+
proc.stderr.on('data', () => {});
|
|
3667
|
+
proc.on('error', () => {});
|
|
3668
|
+
proc.unref();
|
|
3669
|
+
// Wait up to 15s for socket to appear
|
|
3670
|
+
for (let i = 0; i < 30; i++) {
|
|
3671
|
+
await new Promise(r => setTimeout(r, 500));
|
|
3672
|
+
if (fs.existsSync(projectSocketPath)) {
|
|
3673
|
+
activeSocketPath = projectSocketPath;
|
|
3674
|
+
const healthy = await checkSocketHealth();
|
|
3675
|
+
if (healthy) {
|
|
3676
|
+
initLog(`Embedding server auto-restarted successfully, socket at ${projectSocketPath}`);
|
|
3677
|
+
consecutiveEmbeddingFailures = 0;
|
|
3678
|
+
return true;
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
initLog('Embedding server auto-restart: socket did not appear within 15s');
|
|
3683
|
+
}
|
|
3684
|
+
} catch (restartErr) {
|
|
3685
|
+
initLog(`Embedding server auto-restart failed: ${restartErr.message || restartErr}`);
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3623
3688
|
initLog('Socket revalidation failed: no healthy socket found');
|
|
3624
3689
|
return false;
|
|
3625
3690
|
}
|