specmem-hardwicksoftware 3.7.29 → 3.7.31
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/bootstrap.cjs +19 -0
- package/claude-hooks/settings.json +99 -0
- package/claude-hooks/specmem-search-enforcer.cjs +229 -0
- package/claude-hooks/specmem-search-tracker.cjs +71 -0
- package/dist/config.js +11 -16
- package/dist/db/connectionPoolGoBrrr.js +3 -3
- package/dist/index.js +21 -4
- package/dist/mcp/compactionProxy.js +52 -17
- package/dist/mcp/embeddingServerManager.js +15 -1
- package/dist/mcp/mcpProtocolHandler.js +22 -4
- package/dist/mcp/specMemServer.js +16 -3
- package/dist/mcp/toolRegistry.js +19 -21
- package/dist/tools/goofy/checkSyncStatus.js +14 -7
- package/dist/watcher/fileWatcher.js +57 -20
- package/dist/watcher/syncChecker.js +11 -7
- package/package.json +1 -1
- package/scripts/global-postinstall.cjs +7 -2
- package/scripts/specmem-init.cjs +91 -111
- package/specmem/model-config.json +26 -6
- package/specmem/supervisord.conf +1 -1
- package/specmem/user-config.json +12 -0
package/scripts/specmem-init.cjs
CHANGED
|
@@ -3202,11 +3202,11 @@ const TIER_CONFIG = {
|
|
|
3202
3202
|
const MAX_EMBED_CHARS = 8000;
|
|
3203
3203
|
|
|
3204
3204
|
// ============================================================================
|
|
3205
|
-
// STAGE
|
|
3205
|
+
// STAGE 2: PROJECT ANALYSIS
|
|
3206
3206
|
// ============================================================================
|
|
3207
3207
|
|
|
3208
3208
|
async function analyzeProject(projectPath, ui) {
|
|
3209
|
-
ui.setStage(
|
|
3209
|
+
ui.setStage(2, 'PROJECT ANALYSIS');
|
|
3210
3210
|
|
|
3211
3211
|
const results = {
|
|
3212
3212
|
tier: 'small',
|
|
@@ -3386,11 +3386,11 @@ async function analyzeProject(projectPath, ui) {
|
|
|
3386
3386
|
}
|
|
3387
3387
|
|
|
3388
3388
|
// ============================================================================
|
|
3389
|
-
// STAGE
|
|
3389
|
+
// STAGE 3: SCORCHED EARTH - Wipe everything and rebuild fresh
|
|
3390
3390
|
// ============================================================================
|
|
3391
3391
|
|
|
3392
3392
|
async function scorchedEarth(projectPath, ui) {
|
|
3393
|
-
ui.setStage(
|
|
3393
|
+
ui.setStage(3, 'CLEANUP');
|
|
3394
3394
|
|
|
3395
3395
|
const specmemDir = path.join(projectPath, 'specmem');
|
|
3396
3396
|
const projectDir = path.join(projectPath, '.claude');
|
|
@@ -3539,11 +3539,11 @@ async function scorchedEarth(projectPath, ui) {
|
|
|
3539
3539
|
}
|
|
3540
3540
|
|
|
3541
3541
|
// ============================================================================
|
|
3542
|
-
// STAGE
|
|
3542
|
+
// STAGE 4: MODEL OPTIMIZATION
|
|
3543
3543
|
// ============================================================================
|
|
3544
3544
|
|
|
3545
3545
|
async function optimizeModel(projectPath, analysis, ui) {
|
|
3546
|
-
ui.setStage(
|
|
3546
|
+
ui.setStage(4, 'BLAST OFF 🚀');
|
|
3547
3547
|
|
|
3548
3548
|
const recommended = TIER_CONFIG[analysis.tier];
|
|
3549
3549
|
|
|
@@ -3750,7 +3750,7 @@ async function optimizeModel(projectPath, analysis, ui) {
|
|
|
3750
3750
|
* This ensures the overflow queue is pre-populated before launches.
|
|
3751
3751
|
*/
|
|
3752
3752
|
async function coldStartEmbeddingDocker(projectPath, modelConfig, ui, codebaseResult) {
|
|
3753
|
-
ui.setStage(
|
|
3753
|
+
ui.setStage(5, 'EMBEDDING DOCKER');
|
|
3754
3754
|
|
|
3755
3755
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
3756
3756
|
// 🔒 PRE-FLIGHT ACK CHECK - Verify optimizations before starting embedding 🔒
|
|
@@ -4129,7 +4129,7 @@ async function waitForEmbeddingReady(sockPath, opts = {}) {
|
|
|
4129
4129
|
}
|
|
4130
4130
|
|
|
4131
4131
|
async function indexCodebase(projectPath, ui, embeddingResult) {
|
|
4132
|
-
ui.setStage(
|
|
4132
|
+
ui.setStage(6, 'CODEBASE INDEXING');
|
|
4133
4133
|
|
|
4134
4134
|
const { Pool } = require('pg');
|
|
4135
4135
|
const crypto = require('crypto');
|
|
@@ -5982,11 +5982,11 @@ async function extractDefinitions(content, filePath, language, fileId) {
|
|
|
5982
5982
|
}
|
|
5983
5983
|
|
|
5984
5984
|
// ============================================================================
|
|
5985
|
-
// STAGE
|
|
5985
|
+
// STAGE 7: TOKEN COMPRESSION
|
|
5986
5986
|
// ============================================================================
|
|
5987
5987
|
|
|
5988
5988
|
async function compressTokens(projectPath, ui) {
|
|
5989
|
-
ui.setStage(
|
|
5989
|
+
ui.setStage(8, 'TOKEN COMPRESSION');
|
|
5990
5990
|
|
|
5991
5991
|
// Import compressor inline
|
|
5992
5992
|
let compress;
|
|
@@ -6085,11 +6085,11 @@ async function compressTokens(projectPath, ui) {
|
|
|
6085
6085
|
|
|
6086
6086
|
|
|
6087
6087
|
// ============================================================================
|
|
6088
|
-
// STAGE
|
|
6088
|
+
// STAGE 8: COMMAND DEPLOYMENT
|
|
6089
6089
|
// ============================================================================
|
|
6090
6090
|
|
|
6091
6091
|
async function deployCommands(projectPath, ui) {
|
|
6092
|
-
ui.setStage(
|
|
6092
|
+
ui.setStage(9, 'COMMAND DEPLOYMENT');
|
|
6093
6093
|
|
|
6094
6094
|
const globalCmdsDir = path.join(os.homedir(), '.claude', 'commands');
|
|
6095
6095
|
const projectCmdsDir = path.join(projectPath, '.claude', 'commands');
|
|
@@ -6167,7 +6167,7 @@ async function deployCommands(projectPath, ui) {
|
|
|
6167
6167
|
* so they're searchable via find_memory from the start.
|
|
6168
6168
|
*/
|
|
6169
6169
|
async function extractSessions(projectPath, ui, embeddingResult = null) {
|
|
6170
|
-
ui.setStage(
|
|
6170
|
+
ui.setStage(7, 'SESSION EXTRACTION');
|
|
6171
6171
|
|
|
6172
6172
|
const claudeDir = path.join(os.homedir(), '.claude');
|
|
6173
6173
|
const projectsDir = path.join(claudeDir, 'projects');
|
|
@@ -6812,11 +6812,11 @@ async function extractSessions(projectPath, ui, embeddingResult = null) {
|
|
|
6812
6812
|
}
|
|
6813
6813
|
|
|
6814
6814
|
// ============================================================================
|
|
6815
|
-
// STAGE
|
|
6815
|
+
// STAGE 10: FINAL VERIFICATION
|
|
6816
6816
|
// ============================================================================
|
|
6817
6817
|
|
|
6818
6818
|
async function finalVerification(projectPath, analysis, modelConfig, ui) {
|
|
6819
|
-
ui.setStage(
|
|
6819
|
+
ui.setStage(10, 'FINAL VERIFICATION');
|
|
6820
6820
|
|
|
6821
6821
|
const checks = {
|
|
6822
6822
|
modelConfig: false,
|
|
@@ -8799,9 +8799,14 @@ CREATE INDEX IF NOT EXISTS idx_embedding_queue_project ON embedding_queue (proje
|
|
|
8799
8799
|
? path.join(specmemPkg, 'mcp-proxy.cjs')
|
|
8800
8800
|
: path.join(specmemPkg, 'bootstrap.cjs');
|
|
8801
8801
|
// Container mode: postgres via unix socket in specmem/run/, user=specmem, trust auth
|
|
8802
|
+
// Socket dir bind-mounted to /data/run in container — PG socket appears here after container starts
|
|
8802
8803
|
// Legacy mode: postgres on localhost:5432, legacy credentials
|
|
8803
8804
|
const isContainerMode = process.env.SPECMEM_CONTAINER_MODE === 'true';
|
|
8804
8805
|
const runDir = path.join(projectPath, 'specmem', 'run');
|
|
8806
|
+
if (isContainerMode) {
|
|
8807
|
+
// Ensure socket directory exists on host — container bind-mounts dataDir:/data
|
|
8808
|
+
try { fs.mkdirSync(runDir, { recursive: true }); } catch (e) { /* may already exist */ }
|
|
8809
|
+
}
|
|
8805
8810
|
const dbEnv = isContainerMode ? {
|
|
8806
8811
|
SPECMEM_DB_HOST: runDir,
|
|
8807
8812
|
SPECMEM_DB_PORT: "5432",
|
|
@@ -8955,32 +8960,44 @@ function registerProjectInRegistry(projectPath, globalDir) {
|
|
|
8955
8960
|
}
|
|
8956
8961
|
|
|
8957
8962
|
// ============================================================================
|
|
8958
|
-
// MODEL DOWNLOAD — ensures ML models exist before init proceeds
|
|
8963
|
+
// MODEL DOWNLOAD — Stage 1: ensures all ML models exist before init proceeds
|
|
8959
8964
|
// ============================================================================
|
|
8960
8965
|
|
|
8961
8966
|
/**
|
|
8962
|
-
*
|
|
8963
|
-
*
|
|
8964
|
-
*
|
|
8967
|
+
* Stage 1: MODEL DOWNLOAD
|
|
8968
|
+
* Checks for all required ML models. If any are missing, auto-downloads
|
|
8969
|
+
* the combined models tarball from GitHub release — no prompting.
|
|
8970
|
+
*
|
|
8971
|
+
* Models bundled in npm (always present after install):
|
|
8972
|
+
* - all-MiniLM-L6-v2 (embedding)
|
|
8973
|
+
* - minisbd (sentence boundary)
|
|
8974
|
+
*
|
|
8975
|
+
* Models NOT in npm (LFS-only, downloaded via release tarball):
|
|
8976
|
+
* - pythia-410m-onnx-quant (mini-COT)
|
|
8977
|
+
* - argos-translate (translation en↔zh/zt)
|
|
8965
8978
|
*/
|
|
8966
|
-
async function ensureModels() {
|
|
8979
|
+
async function ensureModels(ui) {
|
|
8967
8980
|
const specmemRoot = path.resolve(__dirname, '..');
|
|
8968
|
-
const
|
|
8981
|
+
const modelsDir = path.join(specmemRoot, 'embedding-sandbox', 'models');
|
|
8982
|
+
const version = SPECMEM_VERSION;
|
|
8969
8983
|
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
8984
|
+
const sentinels = [
|
|
8985
|
+
{ name: 'Mini-COT (Pythia)', path: path.join(modelsDir, 'pythia-410m-onnx-quant', 'model_quantized.onnx') },
|
|
8986
|
+
{ name: 'Translation (Argos)', path: path.join(modelsDir, 'argos-translate', 'translate-en_zh-1_9', 'model', 'model.bin') },
|
|
8987
|
+
];
|
|
8988
|
+
|
|
8989
|
+
const missing = sentinels.filter(s => !fs.existsSync(s.path));
|
|
8990
|
+
|
|
8991
|
+
if (missing.length === 0) {
|
|
8992
|
+
initLog('[MODELS] All models present — skipping download');
|
|
8993
|
+
if (ui) ui.setSubStatus('✓ All ML models present');
|
|
8973
8994
|
return;
|
|
8974
8995
|
}
|
|
8975
8996
|
|
|
8976
|
-
initLog(
|
|
8997
|
+
initLog(`[MODELS] Missing: ${missing.map(s => s.name).join(', ')}`);
|
|
8998
|
+
if (ui) ui.setSubStatus(`↓ Downloading ML models (~570MB)...`);
|
|
8977
8999
|
|
|
8978
|
-
|
|
8979
|
-
const modelsDir = path.join(specmemRoot, 'embedding-sandbox', 'models');
|
|
8980
|
-
const version = SPECMEM_VERSION;
|
|
8981
|
-
const releaseUrl = `https://github.com/jonhardwick-spec/specmem/releases/download/v${version}/specmem-models-${version}.tar.gz`;
|
|
8982
|
-
|
|
8983
|
-
// Check if install path is globally owned (needs sudo for extraction)
|
|
9000
|
+
// Check write perms
|
|
8984
9001
|
let needsSudo = false;
|
|
8985
9002
|
try {
|
|
8986
9003
|
fs.accessSync(path.join(specmemRoot, 'embedding-sandbox'), fs.constants.W_OK);
|
|
@@ -8988,102 +9005,62 @@ async function ensureModels() {
|
|
|
8988
9005
|
needsSudo = true;
|
|
8989
9006
|
}
|
|
8990
9007
|
|
|
8991
|
-
if (!nohup) {
|
|
8992
|
-
console.log('');
|
|
8993
|
-
console.log(drawBox([
|
|
8994
|
-
`${c.bold}${c.yellow}ML Models Required${c.reset}`,
|
|
8995
|
-
'',
|
|
8996
|
-
`SpecMem needs to download ML models (~500MB).`,
|
|
8997
|
-
`These are stripped from npm to keep installs fast.`,
|
|
8998
|
-
'',
|
|
8999
|
-
`${c.dim}Source: GitHub release v${version}${c.reset}`,
|
|
9000
|
-
needsSudo ? `${c.yellow}Note: Install path requires sudo for extraction${c.reset}` : '',
|
|
9001
|
-
].filter(Boolean), { borderColor: c.yellow }));
|
|
9002
|
-
|
|
9003
|
-
const readline = require('readline');
|
|
9004
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
9005
|
-
|
|
9006
|
-
const answer = await new Promise((resolve) => {
|
|
9007
|
-
rl.question(` ${c.bold}Download models?${c.reset} [Y/n] `, (ans) => {
|
|
9008
|
-
rl.close();
|
|
9009
|
-
resolve(ans.trim().toLowerCase());
|
|
9010
|
-
});
|
|
9011
|
-
});
|
|
9012
|
-
|
|
9013
|
-
if (answer === 'n' || answer === 'no') {
|
|
9014
|
-
console.log(` ${c.yellow}⚠${c.reset} Skipped model download — embedding features will not work.`);
|
|
9015
|
-
initLog('[MODELS] User declined model download');
|
|
9016
|
-
return;
|
|
9017
|
-
}
|
|
9018
|
-
} else {
|
|
9019
|
-
console.log(` ${c.dim}[nohup] Auto-downloading ML models (~500MB)...${c.reset}`);
|
|
9020
|
-
}
|
|
9021
|
-
|
|
9022
|
-
// Download
|
|
9023
|
-
const tmpTarball = path.join(os.tmpdir(), `specmem-models-${version}.tar.gz`);
|
|
9024
|
-
|
|
9025
|
-
// Prefer curl, fall back to wget
|
|
9026
9008
|
const hasCurl = (() => { try { execSync('which curl', { stdio: 'pipe' }); return true; } catch { return false; } })();
|
|
9027
9009
|
const hasWget = (() => { try { execSync('which wget', { stdio: 'pipe' }); return true; } catch { return false; } })();
|
|
9028
9010
|
|
|
9029
9011
|
if (!hasCurl && !hasWget) {
|
|
9030
|
-
console.log(` ${c.red}✗${c.reset} Neither curl nor wget found — cannot download models.`);
|
|
9031
|
-
console.log(` ${c.dim}Install curl or wget and re-run specmem init.${c.reset}`);
|
|
9032
9012
|
initLog('[MODELS] ERROR: no curl or wget');
|
|
9013
|
+
if (ui) ui.setSubStatus('⚠ curl/wget not found — ML models unavailable (mini-COT/translation disabled)');
|
|
9033
9014
|
return;
|
|
9034
9015
|
}
|
|
9035
9016
|
|
|
9036
|
-
|
|
9037
|
-
|
|
9017
|
+
const releaseUrl = `https://github.com/jonhardwick-spec/specmem/releases/download/v${version}/specmem-models-${version}.tar.gz`;
|
|
9018
|
+
const tmpTarball = path.join(os.tmpdir(), `specmem-models-${version}.tar.gz`);
|
|
9019
|
+
|
|
9020
|
+
initLog(`[MODELS] Downloading: ${releaseUrl}`);
|
|
9038
9021
|
|
|
9039
9022
|
try {
|
|
9040
9023
|
const dlCmd = hasCurl
|
|
9041
9024
|
? `curl -fSL --progress-bar -o "${tmpTarball}" "${releaseUrl}"`
|
|
9042
9025
|
: `wget --progress=bar:force -O "${tmpTarball}" "${releaseUrl}"`;
|
|
9043
|
-
|
|
9044
|
-
execSync(dlCmd, { stdio: 'inherit', timeout: 600000 });
|
|
9026
|
+
execSync(dlCmd, { stdio: 'pipe', timeout: 900000 }); // 15 min timeout for ~570MB
|
|
9045
9027
|
} catch (e) {
|
|
9046
|
-
|
|
9047
|
-
|
|
9028
|
+
initLog(`[MODELS] Download failed: ${e.message}`);
|
|
9029
|
+
if (ui) ui.setSubStatus(`⚠ Model download failed — mini-COT/translation disabled`);
|
|
9048
9030
|
try { fs.unlinkSync(tmpTarball); } catch {}
|
|
9049
9031
|
return;
|
|
9050
9032
|
}
|
|
9051
9033
|
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
initLog('[MODELS] Extracting to: ' + modelsDir);
|
|
9034
|
+
if (ui) ui.setSubStatus('⤳ Extracting ML models...');
|
|
9035
|
+
initLog(`[MODELS] Extracting to: ${modelsDir}`);
|
|
9055
9036
|
|
|
9056
9037
|
try {
|
|
9057
|
-
// Ensure models directory exists
|
|
9058
9038
|
const mkdirCmd = `mkdir -p "${modelsDir}"`;
|
|
9059
9039
|
const extractCmd = `tar xzf "${tmpTarball}" -C "${modelsDir}"`;
|
|
9060
|
-
|
|
9061
9040
|
if (needsSudo) {
|
|
9062
9041
|
execSync(`sudo ${mkdirCmd}`, { stdio: 'pipe' });
|
|
9063
|
-
execSync(`sudo ${extractCmd}`, { stdio: '
|
|
9064
|
-
// Fix ownership so specmem can read
|
|
9042
|
+
execSync(`sudo ${extractCmd}`, { stdio: 'pipe', timeout: 180000 });
|
|
9065
9043
|
execSync(`sudo chmod -R a+rX "${modelsDir}"`, { stdio: 'pipe' });
|
|
9066
9044
|
} else {
|
|
9067
9045
|
execSync(mkdirCmd, { stdio: 'pipe' });
|
|
9068
|
-
execSync(extractCmd, { stdio: '
|
|
9046
|
+
execSync(extractCmd, { stdio: 'pipe', timeout: 180000 });
|
|
9069
9047
|
}
|
|
9070
9048
|
} catch (e) {
|
|
9071
|
-
|
|
9072
|
-
|
|
9049
|
+
initLog(`[MODELS] Extraction failed: ${e.message}`);
|
|
9050
|
+
if (ui) ui.setSubStatus('⚠ Model extraction failed');
|
|
9073
9051
|
try { fs.unlinkSync(tmpTarball); } catch {}
|
|
9074
9052
|
return;
|
|
9075
9053
|
}
|
|
9076
9054
|
|
|
9077
|
-
// Cleanup tarball
|
|
9078
9055
|
try { fs.unlinkSync(tmpTarball); } catch {}
|
|
9079
9056
|
|
|
9080
|
-
|
|
9081
|
-
if (
|
|
9082
|
-
|
|
9083
|
-
|
|
9057
|
+
const stillMissing = sentinels.filter(s => !fs.existsSync(s.path));
|
|
9058
|
+
if (stillMissing.length === 0) {
|
|
9059
|
+
initLog('[MODELS] All models OK after download');
|
|
9060
|
+
if (ui) ui.setSubStatus('✓ ML models downloaded and ready');
|
|
9084
9061
|
} else {
|
|
9085
|
-
|
|
9086
|
-
|
|
9062
|
+
initLog(`[MODELS] Still missing after download: ${stillMissing.map(s => s.name).join(', ')}`);
|
|
9063
|
+
if (ui) ui.setSubStatus(`⚠ Still missing: ${stillMissing.map(s => s.name).join(', ')}`);
|
|
9087
9064
|
}
|
|
9088
9065
|
}
|
|
9089
9066
|
|
|
@@ -9193,9 +9170,6 @@ async function main() {
|
|
|
9193
9170
|
}
|
|
9194
9171
|
}
|
|
9195
9172
|
|
|
9196
|
-
// ========== ENSURE ML MODELS ==========
|
|
9197
|
-
await ensureModels();
|
|
9198
|
-
|
|
9199
9173
|
// Animated banner with sliding red highlight (screen already cleared at startup)
|
|
9200
9174
|
const _dbg = (m) => { try { fs.appendFileSync('/tmp/init-trace.log', `${Date.now()} ${m}\n`); } catch {} };
|
|
9201
9175
|
_dbg('PRE-BANNER');
|
|
@@ -9858,16 +9832,22 @@ ${lastOutput}
|
|
|
9858
9832
|
|
|
9859
9833
|
// Adjust total stages based on mode
|
|
9860
9834
|
if (!launchScreens) {
|
|
9861
|
-
ui.totalStages =
|
|
9835
|
+
ui.totalStages = 10; // No screen sessions stage
|
|
9862
9836
|
} else if (skipScorchedEarth) {
|
|
9863
|
-
ui.totalStages =
|
|
9837
|
+
ui.totalStages = 3; // Quick mode: models + analyze + screens
|
|
9864
9838
|
} else {
|
|
9865
|
-
ui.totalStages =
|
|
9839
|
+
ui.totalStages = 11; // Full mode with screen sessions
|
|
9866
9840
|
}
|
|
9867
9841
|
|
|
9868
9842
|
ui.start();
|
|
9869
9843
|
_dbg('POST-UI-START');
|
|
9870
9844
|
|
|
9845
|
+
// ==========================================================================
|
|
9846
|
+
// STAGE 1: MODEL DOWNLOAD — auto-fetch any missing ML models
|
|
9847
|
+
// ==========================================================================
|
|
9848
|
+
ui.setStage(1, 'MODEL DOWNLOAD');
|
|
9849
|
+
await ensureModels(ui);
|
|
9850
|
+
|
|
9871
9851
|
// ==========================================================================
|
|
9872
9852
|
// CONTAINER FAST-PATH: If podman/docker is available, use container mode
|
|
9873
9853
|
// This replaces stages 2-9 with: pull image → start container → deploy hooks → verify
|
|
@@ -9953,14 +9933,14 @@ ${lastOutput}
|
|
|
9953
9933
|
}
|
|
9954
9934
|
|
|
9955
9935
|
if (useContainerMode && !skipScorchedEarth) {
|
|
9956
|
-
// Container mode:
|
|
9957
|
-
ui.totalStages = launchScreens ?
|
|
9936
|
+
// Container mode: Stage 1 = models, then container stages
|
|
9937
|
+
ui.totalStages = launchScreens ? 8 : 7;
|
|
9958
9938
|
|
|
9959
|
-
// Stage
|
|
9939
|
+
// Stage 2: Analyze project
|
|
9960
9940
|
const analysis = await analyzeProject(projectPath, ui);
|
|
9961
9941
|
|
|
9962
|
-
// Stage
|
|
9963
|
-
ui.setStage(
|
|
9942
|
+
// Stage 3: Container engine — pull image if needed
|
|
9943
|
+
ui.setStage(3, 'CONTAINER ENGINE');
|
|
9964
9944
|
ui.setStatus('Pulling specmem-brain image...');
|
|
9965
9945
|
const containerImage = process.env.SPECMEM_CONTAINER_IMAGE || 'ghcr.io/hardwicksoftware/specmem-brain:latest';
|
|
9966
9946
|
const rtCmd = (() => {
|
|
@@ -10012,8 +9992,8 @@ ${lastOutput}
|
|
|
10012
9992
|
console.log('');
|
|
10013
9993
|
process.exit(1);
|
|
10014
9994
|
} else {
|
|
10015
|
-
// Stage
|
|
10016
|
-
ui.setStage(
|
|
9995
|
+
// Stage 4: Start container
|
|
9996
|
+
ui.setStage(4, 'CONTAINER START');
|
|
10017
9997
|
ui.setStatus('Starting specmem-brain...');
|
|
10018
9998
|
const dirName = path.basename(projectPath).replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
10019
9999
|
const containerName = `specmem-brain-${dirName}`;
|
|
@@ -10412,8 +10392,8 @@ priority=999
|
|
|
10412
10392
|
process.env.SPECMEM_TRANSLATE_SOCKET = path.join(runDir, 'translate.sock');
|
|
10413
10393
|
process.env.SPECMEM_MINICOT_SOCKET = path.join(runDir, 'minicot.sock');
|
|
10414
10394
|
|
|
10415
|
-
// Stage
|
|
10416
|
-
ui.setStage(
|
|
10395
|
+
// Stage 5: PostgreSQL client tools (psql) — hooks shell out to psql for DB queries
|
|
10396
|
+
ui.setStage(5, 'PSQL CLIENT');
|
|
10417
10397
|
ui.setStatus('Checking psql...');
|
|
10418
10398
|
|
|
10419
10399
|
let hasPsqlClient = false;
|
|
@@ -10512,8 +10492,8 @@ priority=999
|
|
|
10512
10492
|
console.log(` ${c.dim}Hooks that query the DB will fail without it.${c.reset}`);
|
|
10513
10493
|
}
|
|
10514
10494
|
|
|
10515
|
-
// Stage
|
|
10516
|
-
ui.setStage(
|
|
10495
|
+
// Stage 6: Deploy hooks + MCP config + verify
|
|
10496
|
+
ui.setStage(6, 'HOOKS & CONFIG');
|
|
10517
10497
|
ui.setStatus('Deploying Claude hooks...');
|
|
10518
10498
|
syncHooksAndSettings();
|
|
10519
10499
|
ui.setStatus('Hooks deployed');
|
|
@@ -10619,9 +10599,9 @@ priority=999
|
|
|
10619
10599
|
}, null, 2));
|
|
10620
10600
|
} catch {}
|
|
10621
10601
|
|
|
10622
|
-
// Stage
|
|
10623
|
-
_dbg('STAGE-
|
|
10624
|
-
ui.setStage(
|
|
10602
|
+
// Stage 7: CODEBASE INDEXING
|
|
10603
|
+
_dbg('STAGE-7-CODEBASE-INDEXING');
|
|
10604
|
+
ui.setStage(7, 'CODEBASE INDEXING');
|
|
10625
10605
|
ui.enableFileFeed(true);
|
|
10626
10606
|
ui.setStatus('Waiting for container services...');
|
|
10627
10607
|
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
"cpus": 8
|
|
14
14
|
},
|
|
15
15
|
"embedding": {
|
|
16
|
-
"batchSize":
|
|
16
|
+
"batchSize": 64,
|
|
17
17
|
"maxConcurrent": 5,
|
|
18
|
-
"timeout": 45000
|
|
18
|
+
"timeout": 45000,
|
|
19
|
+
"throttleDelayMs": 50
|
|
19
20
|
},
|
|
20
21
|
"watcher": {
|
|
21
22
|
"debounceMs": 750,
|
|
@@ -33,13 +34,13 @@
|
|
|
33
34
|
"maxChunks": 75
|
|
34
35
|
},
|
|
35
36
|
"resources": {
|
|
36
|
-
"cpuMin":
|
|
37
|
-
"cpuMax":
|
|
37
|
+
"cpuMin": 10,
|
|
38
|
+
"cpuMax": 45,
|
|
38
39
|
"cpuCoreMin": 1,
|
|
39
40
|
"cpuCoreMax": 4,
|
|
40
41
|
"ramMinMb": 4000,
|
|
41
|
-
"ramMaxMb":
|
|
42
|
-
"updatedAt": "2026-02-
|
|
42
|
+
"ramMaxMb": 13500,
|
|
43
|
+
"updatedAt": "2026-02-24T11:56:33.760Z"
|
|
43
44
|
},
|
|
44
45
|
"resourcePool": {
|
|
45
46
|
"embedding": {
|
|
@@ -79,5 +80,24 @@
|
|
|
79
80
|
"description": "Adaptive batch sizing based on CPU/RAM"
|
|
80
81
|
},
|
|
81
82
|
"enabledAt": "2026-02-12T23:19:17.948Z"
|
|
83
|
+
},
|
|
84
|
+
"powerMode": {
|
|
85
|
+
"level": "high",
|
|
86
|
+
"description": "Max Performance - for 16GB+ RAM systems",
|
|
87
|
+
"lazyLoading": false,
|
|
88
|
+
"diskCache": false,
|
|
89
|
+
"diskCacheMaxMb": 0,
|
|
90
|
+
"aggressiveCleanup": false,
|
|
91
|
+
"idleUnloadSeconds": 0,
|
|
92
|
+
"batchSize": 32,
|
|
93
|
+
"throttleDelayMs": 50,
|
|
94
|
+
"setAt": "2026-02-24T11:57:23.121Z"
|
|
95
|
+
},
|
|
96
|
+
"heavyOps": {
|
|
97
|
+
"enabled": true,
|
|
98
|
+
"enabledAt": "2026-02-24T11:57:35.508Z",
|
|
99
|
+
"originalBatchSize": 32,
|
|
100
|
+
"batchSizeMultiplier": 2,
|
|
101
|
+
"throttleReduction": 0.2
|
|
82
102
|
}
|
|
83
103
|
}
|
package/specmem/supervisord.conf
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
; ============================================
|
|
2
2
|
; SPECMEM BRAIN CONTAINER - DYNAMIC SUPERVISORD CONFIG
|
|
3
|
-
; Generated by specmem-init at 2026-02-
|
|
3
|
+
; Generated by specmem-init at 2026-02-24T11:53:24.816Z
|
|
4
4
|
; Thread counts from model-config.json resourcePool
|
|
5
5
|
; ============================================
|
|
6
6
|
|
package/specmem/user-config.json
CHANGED
|
@@ -7,5 +7,17 @@
|
|
|
7
7
|
"serviceMode": {
|
|
8
8
|
"enabled": false,
|
|
9
9
|
"disabledAt": "2026-02-18T21:38:50.526Z"
|
|
10
|
+
},
|
|
11
|
+
"powerMode": {
|
|
12
|
+
"level": "high",
|
|
13
|
+
"description": "Max Performance - for 16GB+ RAM systems",
|
|
14
|
+
"lazyLoading": false,
|
|
15
|
+
"diskCache": false,
|
|
16
|
+
"diskCacheMaxMb": 0,
|
|
17
|
+
"aggressiveCleanup": false,
|
|
18
|
+
"idleUnloadSeconds": 0,
|
|
19
|
+
"batchSize": 32,
|
|
20
|
+
"throttleDelayMs": 50,
|
|
21
|
+
"setAt": "2026-02-24T11:57:23.121Z"
|
|
10
22
|
}
|
|
11
23
|
}
|