specmem-hardwicksoftware 3.5.21 → 3.5.22

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": "specmem-hardwicksoftware",
3
- "version": "3.5.21",
3
+ "version": "3.5.22",
4
4
  "type": "module",
5
5
  "description": "SpecMem - Speculative Memory for Claude Code. Auto-configures hooks, docker, embeddings. https://justcalljon.pro",
6
6
  "main": "dist/index.js",
@@ -274,56 +274,77 @@ function checkPostgres() {
274
274
  function installPostgres() {
275
275
  log.header('Installing PostgreSQL');
276
276
 
277
+ const PG_TIMEOUT = 180000; // 3 minute timeout for PG install
278
+
277
279
  if (IS_MAC) {
278
280
  log.step(1, 'Installing via Homebrew...');
279
281
 
280
282
  // Check if Homebrew exists
281
283
  if (!commandExists('brew')) {
282
284
  log.info('Installing Homebrew first...');
283
- run('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"');
285
+ run('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { timeout: 300000 });
284
286
  }
285
287
 
286
- run('brew install postgresql@16');
287
- run('brew services start postgresql@16');
288
+ run('brew install postgresql@16', { timeout: PG_TIMEOUT });
289
+ run('brew services start postgresql@16', { timeout: 30000 });
288
290
 
289
291
  // Add to PATH
290
- const brewPrefix = execSync('brew --prefix', { encoding: 'utf8' }).trim();
291
- const pgPath = `${brewPrefix}/opt/postgresql@16/bin`;
292
- log.info(`Add to PATH: export PATH="${pgPath}:$PATH"`);
292
+ try {
293
+ const brewPrefix = execSync('brew --prefix', { encoding: 'utf8', timeout: 10000 }).trim();
294
+ const pgPath = `${brewPrefix}/opt/postgresql@16/bin`;
295
+ log.info(`Add to PATH: export PATH="${pgPath}:$PATH"`);
296
+ } catch (e) {}
293
297
 
294
298
  } else if (IS_LINUX) {
295
299
  log.step(1, 'Detecting Linux distribution...');
296
300
 
297
301
  // Check for apt (Debian/Ubuntu)
298
302
  if (commandExists('apt-get')) {
299
- log.step(2, 'Installing via apt...');
300
- run('sudo apt-get update');
301
- run('sudo apt-get install -y postgresql postgresql-contrib');
302
- run('sudo systemctl start postgresql');
303
- run('sudo systemctl enable postgresql');
303
+ log.step(2, 'Installing via apt (timeout: 3 min)...');
304
+ run('sudo apt-get update', { timeout: 60000 });
305
+ const result = run('sudo apt-get install -y postgresql postgresql-contrib', { timeout: PG_TIMEOUT });
306
+ if (!result.success) {
307
+ log.warn('PostgreSQL install timed out or failed');
308
+ log.info('Try manually: sudo apt-get install -y postgresql postgresql-contrib');
309
+ return false;
310
+ }
311
+ run('sudo systemctl start postgresql', { timeout: 30000 });
312
+ run('sudo systemctl enable postgresql', { timeout: 30000 });
304
313
  }
305
314
  // Check for yum/dnf (RHEL/CentOS/Fedora)
306
315
  else if (commandExists('dnf')) {
307
- log.step(2, 'Installing via dnf...');
308
- run('sudo dnf install -y postgresql-server postgresql-contrib');
309
- run('sudo postgresql-setup --initdb');
310
- run('sudo systemctl start postgresql');
311
- run('sudo systemctl enable postgresql');
316
+ log.step(2, 'Installing via dnf (timeout: 3 min)...');
317
+ const result = run('sudo dnf install -y postgresql-server postgresql-contrib', { timeout: PG_TIMEOUT });
318
+ if (!result.success) {
319
+ log.warn('PostgreSQL install timed out');
320
+ return false;
321
+ }
322
+ run('sudo postgresql-setup --initdb', { timeout: 60000 });
323
+ run('sudo systemctl start postgresql', { timeout: 30000 });
324
+ run('sudo systemctl enable postgresql', { timeout: 30000 });
312
325
  }
313
326
  else if (commandExists('yum')) {
314
- log.step(2, 'Installing via yum...');
315
- run('sudo yum install -y postgresql-server postgresql-contrib');
316
- run('sudo postgresql-setup initdb');
317
- run('sudo systemctl start postgresql');
318
- run('sudo systemctl enable postgresql');
327
+ log.step(2, 'Installing via yum (timeout: 3 min)...');
328
+ const result = run('sudo yum install -y postgresql-server postgresql-contrib', { timeout: PG_TIMEOUT });
329
+ if (!result.success) {
330
+ log.warn('PostgreSQL install timed out');
331
+ return false;
332
+ }
333
+ run('sudo postgresql-setup initdb', { timeout: 60000 });
334
+ run('sudo systemctl start postgresql', { timeout: 30000 });
335
+ run('sudo systemctl enable postgresql', { timeout: 30000 });
319
336
  }
320
337
  // Check for pacman (Arch)
321
338
  else if (commandExists('pacman')) {
322
- log.step(2, 'Installing via pacman...');
323
- run('sudo pacman -S --noconfirm postgresql');
324
- run('sudo -u postgres initdb -D /var/lib/postgres/data');
325
- run('sudo systemctl start postgresql');
326
- run('sudo systemctl enable postgresql');
339
+ log.step(2, 'Installing via pacman (timeout: 3 min)...');
340
+ const result = run('sudo pacman -S --noconfirm postgresql', { timeout: PG_TIMEOUT });
341
+ if (!result.success) {
342
+ log.warn('PostgreSQL install timed out');
343
+ return false;
344
+ }
345
+ run('sudo -u postgres initdb -D /var/lib/postgres/data', { timeout: 60000 });
346
+ run('sudo systemctl start postgresql', { timeout: 30000 });
347
+ run('sudo systemctl enable postgresql', { timeout: 30000 });
327
348
  }
328
349
  else {
329
350
  log.error('Could not detect package manager. Please install PostgreSQL manually.');
@@ -337,8 +358,9 @@ function installPostgres() {
337
358
  return false;
338
359
  }
339
360
 
340
- // Verify installation
341
- const check = run('pg_isready', { silent: true });
361
+ // Verify installation with timeout
362
+ log.info('Verifying PostgreSQL installation...');
363
+ const check = run('pg_isready', { silent: true, timeout: 10000 });
342
364
  if (check.success) {
343
365
  log.success('PostgreSQL installed and running!');
344
366
  return true;
@@ -347,12 +369,23 @@ function installPostgres() {
347
369
  // Try starting the service
348
370
  log.info('Trying to start PostgreSQL service...');
349
371
  if (IS_MAC) {
350
- run('brew services start postgresql@16');
372
+ run('brew services start postgresql@16', { timeout: 30000 });
351
373
  } else if (IS_LINUX) {
352
- run('sudo systemctl start postgresql');
374
+ run('sudo systemctl start postgresql', { timeout: 30000 });
375
+ }
376
+
377
+ // Wait up to 30 seconds for PG to be ready
378
+ for (let i = 0; i < 6; i++) {
379
+ if (run('pg_isready', { silent: true, timeout: 5000 }).success) {
380
+ log.success('PostgreSQL is ready');
381
+ return true;
382
+ }
383
+ log.info('Waiting for PostgreSQL to start...');
384
+ run('sleep 5', { silent: true });
353
385
  }
354
386
 
355
- return run('pg_isready', { silent: true }).success;
387
+ log.warn('PostgreSQL may not be fully started - continuing anyway');
388
+ return true; // Continue setup, might work
356
389
  }
357
390
 
358
391
  // ============================================================================
@@ -367,7 +400,7 @@ function checkPgvector() {
367
400
 
368
401
  const result = run(
369
402
  `sudo -u postgres psql -c "SELECT 1 FROM pg_available_extensions WHERE name = 'vector';" 2>/dev/null`,
370
- { silent: true }
403
+ { silent: true, timeout: 15000 }
371
404
  );
372
405
 
373
406
  if (result.success && result.output && result.output.includes('1')) {
@@ -385,30 +418,33 @@ function checkPgvector() {
385
418
  function installPgvector() {
386
419
  log.header('Installing pgvector Extension');
387
420
 
421
+ const PGVECTOR_TIMEOUT = 120000; // 2 minute timeout
422
+
388
423
  if (IS_MAC) {
389
424
  log.step(1, 'Installing pgvector via Homebrew...');
390
- run('brew install pgvector');
425
+ run('brew install pgvector', { timeout: PGVECTOR_TIMEOUT });
391
426
 
392
427
  } else if (IS_LINUX) {
393
428
  // Try apt first (Ubuntu/Debian have pgvector in repos now)
394
429
  if (commandExists('apt-get')) {
395
- log.step(1, 'Trying apt install...');
396
- const aptResult = run('sudo apt-get install -y postgresql-16-pgvector 2>/dev/null || sudo apt-get install -y postgresql-pgvector 2>/dev/null', { silent: true });
430
+ log.step(1, 'Trying apt install (timeout: 2 min)...');
431
+ const aptResult = run('sudo apt-get install -y postgresql-16-pgvector 2>/dev/null || sudo apt-get install -y postgresql-pgvector 2>/dev/null', { silent: true, timeout: PGVECTOR_TIMEOUT });
397
432
 
398
433
  if (!aptResult.success) {
399
- log.step(2, 'Building pgvector from source...');
434
+ log.step(2, 'Building pgvector from source (timeout: 3 min)...');
400
435
  buildPgvectorFromSource();
401
436
  }
402
437
  } else {
403
- log.step(1, 'Building pgvector from source...');
438
+ log.step(1, 'Building pgvector from source (timeout: 3 min)...');
404
439
  buildPgvectorFromSource();
405
440
  }
406
441
  }
407
442
 
408
- // Verify
443
+ // Verify with timeout
444
+ log.info('Verifying pgvector installation...');
409
445
  const check = run(
410
446
  `sudo -u postgres psql -c "SELECT 1 FROM pg_available_extensions WHERE name = 'vector';" 2>/dev/null`,
411
- { silent: true }
447
+ { silent: true, timeout: 15000 }
412
448
  );
413
449
 
414
450
  if (check.success && check.output && check.output.includes('1')) {
@@ -416,7 +452,8 @@ function installPgvector() {
416
452
  return true;
417
453
  }
418
454
 
419
- log.warn('pgvector may need manual installation');
455
+ log.warn('pgvector install may have timed out - continuing anyway');
456
+ log.info('SpecMem can work without pgvector (reduced functionality)');
420
457
  return false;
421
458
  }
422
459
 
@@ -426,21 +463,33 @@ function installPgvector() {
426
463
  function buildPgvectorFromSource() {
427
464
  log.info('Building pgvector from source...');
428
465
 
466
+ const BUILD_TIMEOUT = 180000; // 3 minute timeout for build
467
+
429
468
  // Install build dependencies
430
469
  if (commandExists('apt-get')) {
431
- run('sudo apt-get install -y build-essential git postgresql-server-dev-all');
470
+ run('sudo apt-get install -y build-essential git postgresql-server-dev-all', { timeout: 120000 });
432
471
  } else if (commandExists('dnf')) {
433
- run('sudo dnf install -y gcc make git postgresql-devel');
472
+ run('sudo dnf install -y gcc make git postgresql-devel', { timeout: 120000 });
434
473
  } else if (commandExists('yum')) {
435
- run('sudo yum install -y gcc make git postgresql-devel');
474
+ run('sudo yum install -y gcc make git postgresql-devel', { timeout: 120000 });
436
475
  }
437
476
 
438
- // Clone and build
477
+ // Clone and build with timeout
439
478
  const tmpDir = '/tmp/pgvector-build';
440
- run(`rm -rf ${tmpDir}`);
441
- run(`git clone --branch v0.7.4 https://github.com/pgvector/pgvector.git ${tmpDir}`);
442
- run(`cd ${tmpDir} && make && sudo make install`);
443
- run(`rm -rf ${tmpDir}`);
479
+ run(`rm -rf ${tmpDir}`, { timeout: 10000 });
480
+
481
+ const cloneResult = run(`git clone --branch v0.7.4 https://github.com/pgvector/pgvector.git ${tmpDir}`, { timeout: 60000 });
482
+ if (!cloneResult.success) {
483
+ log.warn('Failed to clone pgvector repo - skipping');
484
+ return;
485
+ }
486
+
487
+ const buildResult = run(`cd ${tmpDir} && make && sudo make install`, { timeout: BUILD_TIMEOUT });
488
+ if (!buildResult.success) {
489
+ log.warn('pgvector build timed out or failed');
490
+ }
491
+
492
+ run(`rm -rf ${tmpDir}`, { timeout: 10000 });
444
493
  }
445
494
 
446
495
  // ============================================================================
@@ -821,6 +870,7 @@ function installDockerLinux() {
821
870
 
822
871
  /**
823
872
  * Configure Docker for non-root usage on Linux
873
+ * SECURITY: Binds Docker to 127.0.0.1 only (no external access)
824
874
  */
825
875
  function configureDockerLinux() {
826
876
  log.step('→', 'Configuring Docker for non-root usage...');
@@ -830,9 +880,46 @@ function configureDockerLinux() {
830
880
  // Add user to docker group
831
881
  run(`sudo usermod -aG docker ${user}`);
832
882
 
883
+ // SECURITY: Configure Docker to bind to localhost only
884
+ log.step('→', 'Securing Docker to localhost only (127.0.0.1)...');
885
+ const daemonConfig = {
886
+ "iptables": true,
887
+ "ip": "127.0.0.1",
888
+ "ip-forward": false,
889
+ "userland-proxy": true,
890
+ "live-restore": true,
891
+ "log-driver": "json-file",
892
+ "log-opts": {
893
+ "max-size": "10m",
894
+ "max-file": "3"
895
+ }
896
+ };
897
+
898
+ try {
899
+ const daemonJsonPath = '/etc/docker/daemon.json';
900
+ run('sudo mkdir -p /etc/docker');
901
+
902
+ // Check if config exists and merge
903
+ let existingConfig = {};
904
+ if (fs.existsSync(daemonJsonPath)) {
905
+ try {
906
+ existingConfig = JSON.parse(fs.readFileSync(daemonJsonPath, 'utf8'));
907
+ } catch (e) {}
908
+ }
909
+
910
+ const mergedConfig = { ...existingConfig, ...daemonConfig };
911
+ const configJson = JSON.stringify(mergedConfig, null, 2);
912
+
913
+ // Write via sudo
914
+ run(`echo '${configJson}' | sudo tee ${daemonJsonPath}`);
915
+ log.success('Docker configured for localhost-only access (127.0.0.1)');
916
+ } catch (e) {
917
+ log.warn('Could not configure Docker daemon.json - manual security review recommended');
918
+ }
919
+
833
920
  // Enable and start Docker service
834
921
  run('sudo systemctl enable docker');
835
- run('sudo systemctl start docker');
922
+ run('sudo systemctl restart docker'); // Restart to apply new config
836
923
 
837
924
  // Set up Docker to start on boot
838
925
  run('sudo systemctl enable containerd');