mneme-ai 2.75.1 → 2.75.2

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.
@@ -38,17 +38,27 @@
38
38
  * without running the IO side effects (guarded by require.main === module).
39
39
  *
40
40
  * RELATIONSHIP TO THE SHIPPED preinstall. This module is the unit-tested +
41
- * SUPER-QUAN-probed REFERENCE implementation (and a runtime helper for
42
- * `mneme upgrade`). It is NOT what npm runs at preinstall: the actual
43
- * `scripts.preinstall` is a LEAN, hand-authored inline `node -e` (a mirror of
44
- * the same algorithm — image-kill + heartbeat-lease reap + cmdline-match kill
45
- * + Handle-Oracle + sweep). Why a separate lean copy? npm wraps preinstall in
46
- * `cmd /d /s /c "..."` and Windows caps that at ~8191 chars v2.75.0 tried to
47
- * GENERATE the inline from this full file (18.5 KB) and shipped an
48
- * uninstallable package ("command line is too long"). The lean inline stays
49
- * well under the limit; a TG length-guard (probe.preinstall.reaps_node_daemon)
50
- * + the P7 tests keep it honest. Referencing a package file from preinstall is
51
- * NOT an option either (the v2.19.48/49 scar: file may not exist pre-extract).
41
+ * SUPER-QUAN-probed REFERENCE implementation of the FULL reaper (incl. the
42
+ * cmdline-match daemon kill), AND a runtime helper for `mneme upgrade` (which
43
+ * runs in a normal node context, free of the cmd.exe constraints below).
44
+ *
45
+ * It is NOT what npm runs at preinstall. The shipped `scripts.preinstall` is a
46
+ * LEAN inline `node -e` that does the cmd-SAFE subset: trail + image-kill +
47
+ * heartbeat-PID reap (which already covers `node.exe …mneme.js`, since the
48
+ * daemon registers a .beat) + Handle-Oracle DLL gate + sweep. It deliberately
49
+ * OMITS the cmdline-match OS-process query, because that needs PowerShell/wmic
50
+ * with pipes/quotes that DO NOT survive `cmd /d /s /c "node -e \"…\""`:
51
+ * v2.75.0 generated the inline from this whole 18.5 KB file exceeded
52
+ * the Windows cmd.exe ~8191-char limit → "command line is too long".
53
+ * • v2.75.1 — a leaner inline still embedded a PowerShell `… | Select-Object`
54
+ * with literal double-quotes; the `"` broke cmd quoting and exposed `|` to
55
+ * cmd → "'Select-Object' is not recognized" → uninstallable on Windows.
56
+ * Lesson: the inline must be < 8000 chars AND contain ZERO literal `"`. Guards:
57
+ * probe.preinstall.reaps_node_daemon (length + no-double-quote + markers) and
58
+ * P7 (incl. a faithful `cmd /d /s /c` smoke). Referencing a package file from
59
+ * preinstall is also out (v2.19.48/49 scar: file may not exist pre-extract).
60
+ * The cmdline-match safety-net therefore lives HERE, for the `mneme upgrade`
61
+ * path, not in the npm preinstall.
52
62
  */
53
63
 
54
64
  "use strict";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mneme-ai",
3
- "version": "2.75.1",
3
+ "version": "2.75.2",
4
4
  "mcpName": "io.github.patsa2561-art/mneme-ai",
5
5
  "description": "Mneme — the memory layer for your codebase. Knows the WHY, the WHAT, the WHERE-IT-BREAKS.",
6
6
  "type": "module",
@@ -29,13 +29,13 @@
29
29
  "build": "tsc -b",
30
30
  "clean": "tsc -b --clean",
31
31
  "postinstall": "node bin/postinstall-mneme-lite.cjs",
32
- "preinstall": "node -e \"try{const fs=require('node:fs');const path=require('node:path');const os=require('node:os');const{spawnSync}=require('node:child_process');const crypto=require('node:crypto');const w=process.platform==='win32';const home=os.homedir();const organ=path.join(home,'.mneme-global');const trailPath=path.join(organ,'preinstall-trail.jsonl');const trailSecret=process.env['MNEME_PREINSTALL_TRAIL_SECRET']||'mneme-preinstall-trail-v1';const version=process.env['npm_package_version']||'unknown';try{if(!fs.existsSync(organ))fs.mkdirSync(organ,{recursive:true,mode:0o700})}catch(e){}const lastSig=()=>{try{if(!fs.existsSync(trailPath))return'genesis';const lines=fs.readFileSync(trailPath,'utf8').trim().split('\\\\n').filter(Boolean);if(lines.length===0)return'genesis';const last=JSON.parse(lines[lines.length-1]);return typeof last?.sig==='string'?last.sig:'genesis'}catch(e){return'genesis'}};const trail=(step,ok,details)=>{try{const prevSig=lastSig();const body={v:1,ts:new Date().toISOString(),version,step,ok,...(details?{details}:{}),pid:process.pid,prevSig};const sig=crypto.createHmac('sha256',trailSecret).update(prevSig+'::'+JSON.stringify(body)).digest('hex');fs.appendFileSync(trailPath,JSON.stringify({...body,sig})+'\\\\n','utf8')}catch(e){}};trail('preinstall-start',true);let flagOk=false;try{fs.writeFileSync(path.join(organ,'install-incoming.flag'),JSON.stringify({v:1,announcedAt:new Date().toISOString(),announcerPid:process.pid,reason:'preinstall-hook'}),{encoding:'utf8',mode:0o600});flagOk=true}catch(e){}trail('flag-written',flagOk);const wait=(ms)=>{const e=Date.now()+ms;while(Date.now()<e){}};const isDaemon=(c)=>{c=(c||'').toLowerCase();if(!c)return false;if(c.includes('preinstall-mneme')||c.includes('postinstall-mneme'))return false;const refs=/(^|[\\\\\\\\/\\\\s\\\"'])mneme\\\\.js([\\\\s\\\"']|$)/.test(c)||c.includes('bin\\\\\\\\mneme.js')||c.includes('bin/mneme.js')||c.includes('mneme-ai');const dae=c.includes('nucleus')||c.includes('daemon')||c.includes('--detach');return refs&&dae};const killPid=(pid)=>{if(!pid||pid<=0||pid===process.pid)return;if(w){spawnSync('taskkill',['/F','/PID',pid.toString(),'/T'],{shell:true,windowsHide:true,timeout:3000,stdio:'ignore'})}else{try{process.kill(pid,'SIGTERM')}catch(e){}wait(100);try{process.kill(pid,'SIGKILL')}catch(e){}}};if(w){spawnSync('taskkill',['/F','/IM','mneme.exe','/T'],{shell:true,windowsHide:true,timeout:5000,stdio:'ignore'})}else{spawnSync('mneme',['daemon','stop'],{timeout:8000,stdio:'ignore'})}let reaped=0;try{const beatDir=path.join(organ,'heartbeats');if(fs.existsSync(beatDir)){for(const f of fs.readdirSync(beatDir)){const m=f.match(/^(\\\\d+)\\\\.beat$/);if(m){const pid=parseInt(m[1]);if(pid>0&&pid!==process.pid){killPid(pid);try{fs.unlinkSync(path.join(beatDir,f));reaped++}catch(e){}}}}}}catch(e){}trail('heartbeat-reaped',true,{reaped});let cmdKilled=0;try{let procs=[];if(w){let r=spawnSync('wmic',['process','get','Name,ProcessId,CommandLine','/format:csv'],{shell:true,windowsHide:true,timeout:6000,encoding:'utf8'});let txt=(r&&r.stdout)||'';if(/ProcessId/i.test(txt)){const lines=txt.split(/\\\\r?\\\\n/).map(l=>l.trim()).filter(Boolean);const hi=lines.findIndex(l=>/ProcessId/i.test(l)&&l.includes(','));for(let i=hi+1;i<lines.length;i++){const row=lines[i];const f=row.indexOf(',');const la=row.lastIndexOf(',');if(f<0||la<=f)continue;const pid=parseInt(row.slice(la+1).trim());const cmd=row.slice(f+1,la).trim();if(pid>0)procs.push({pid,cmd})}}else{const ps=spawnSync('powershell',['-NoProfile','-NonInteractive','-Command',\\\"Get-CimInstance Win32_Process -Filter \\\\\\\"Name='node.exe'\\\\\\\" | Select-Object ProcessId,CommandLine | ConvertTo-Csv -NoTypeInformation\\\"],{windowsHide:true,timeout:8000,encoding:'utf8'});for(const line of(((ps&&ps.stdout)||'').split(/\\\\r?\\\\n/))){const mm=line.match(/^\\\"?(\\\\d+)\\\"?\\\\s*,\\\\s*\\\"?(.*?)\\\"?$/);if(mm){const pid=parseInt(mm[1]);if(pid>0)procs.push({pid,cmd:mm[2]||''})}}}}else{const r=spawnSync('ps',['-eo','pid=,args='],{timeout:6000,encoding:'utf8'});for(const line of(((r&&r.stdout)||'').split(/\\\\r?\\\\n/))){const t=line.trim();const mm=t.match(/^(\\\\d+)\\\\s+(.*)$/);if(mm){const pid=parseInt(mm[1]);if(pid>0)procs.push({pid,cmd:mm[2]})}}}const seen=new Set();for(const p of procs){if(p.pid===process.pid||seen.has(p.pid))continue;if(isDaemon(p.cmd)){seen.add(p.pid);killPid(p.pid);cmdKilled++}}}catch(e){}trail('cmdline-reaped',true,{cmdKilled});let renamed=0;let prefixesChecked=[];try{const candidatePrefixes=w?[path.join(home,'AppData','Roaming','npm'),path.dirname(process.execPath),'C:\\\\\\\\nvm4w\\\\\\\\nodejs',path.join(home,'AppData','Local','nvm')]:['/usr/local/lib','/usr/lib',path.join(home,'.npm-global'),path.join(home,'.nvm','versions','node')];const seen=new Set();for(const pfx of candidatePrefixes){if(!fs.existsSync(pfx))continue;let nodeModulesBases=[];if(fs.existsSync(path.join(pfx,'node_modules')))nodeModulesBases.push(path.join(pfx,'node_modules'));try{for(const entry of fs.readdirSync(pfx)){const sub=path.join(pfx,entry,'node_modules');if(fs.existsSync(sub))nodeModulesBases.push(sub);const sub2=path.join(pfx,entry,'nodejs','node_modules');if(fs.existsSync(sub2))nodeModulesBases.push(sub2)}}catch(e){}for(const nm of nodeModulesBases){if(seen.has(nm))continue;seen.add(nm);prefixesChecked.push(nm);const npmGlobal=path.join(nm,'mneme-ai');if(!fs.existsSync(npmGlobal))continue;const dllPaths=w?[path.join(npmGlobal,'node_modules','@img','sharp-libvips-win32-x64','lib','libvips-42.dll'),path.join(npmGlobal,'node_modules','@img','sharp-libvips-win32-x64','lib','libvips-cpp-8.17.3.dll'),path.join(npmGlobal,'node_modules','sharp','build','Release','sharp-win32-x64.node')]:[];for(const dll of dllPaths){if(!fs.existsSync(dll))continue;let freed=false;for(let i=0;i<40;i++){try{const fd=fs.openSync(dll,'r+');fs.closeSync(fd);freed=true;break}catch(e2){wait(50)}}if(!freed){try{fs.renameSync(dll,dll+'.locked-'+Date.now()+'-'+process.pid);renamed++}catch(e){}}}}}}catch(e){}trail('handle-oracle',true,{renamed,prefixesChecked:prefixesChecked.length});let swept=0;try{const candidates=w?[path.join(home,'AppData','Roaming','npm','node_modules'),path.join(path.dirname(process.execPath),'node_modules')]:['/usr/local/lib/node_modules',path.join(home,'.npm-global','node_modules')];for(const npmParent of candidates){if(!fs.existsSync(npmParent))continue;try{for(const entry of fs.readdirSync(npmParent)){if(entry.startsWith('.mneme-ai-')){try{fs.rmSync(path.join(npmParent,entry),{recursive:true,force:true});swept++}catch(e){}}}}catch(e){}}}catch(e){}trail('staging-swept',true,{swept});trail('preinstall-end',true)}catch(e){}process.exit(0)\""
32
+ "preinstall": "node -e \"try{const fs=require('node:fs');const path=require('node:path');const os=require('node:os');const{spawnSync}=require('node:child_process');const crypto=require('node:crypto');const w=process.platform==='win32';const home=os.homedir();const organ=path.join(home,'.mneme-global');const trailPath=path.join(organ,'preinstall-trail.jsonl');const trailSecret=process.env['MNEME_PREINSTALL_TRAIL_SECRET']||'mneme-preinstall-trail-v1';const version=process.env['npm_package_version']||'unknown';try{if(!fs.existsSync(organ))fs.mkdirSync(organ,{recursive:true,mode:0o700})}catch(e){}const lastSig=()=>{try{if(!fs.existsSync(trailPath))return'genesis';const lines=fs.readFileSync(trailPath,'utf8').trim().split('\\\\n').filter(Boolean);if(lines.length===0)return'genesis';const last=JSON.parse(lines[lines.length-1]);return typeof last?.sig==='string'?last.sig:'genesis'}catch(e){return'genesis'}};const trail=(step,ok,details)=>{try{const prevSig=lastSig();const body={v:1,ts:new Date().toISOString(),version,step,ok,...(details?{details}:{}),pid:process.pid,prevSig};const sig=crypto.createHmac('sha256',trailSecret).update(prevSig+'::'+JSON.stringify(body)).digest('hex');fs.appendFileSync(trailPath,JSON.stringify({...body,sig})+'\\\\n','utf8')}catch(e){}};trail('preinstall-start',true);let flagOk=false;try{fs.writeFileSync(path.join(organ,'install-incoming.flag'),JSON.stringify({v:1,announcedAt:new Date().toISOString(),announcerPid:process.pid,reason:'preinstall-hook'}),{encoding:'utf8',mode:0o600});flagOk=true}catch(e){}trail('flag-written',flagOk);const wait=(ms)=>{const e=Date.now()+ms;while(Date.now()<e){}};wait(300);if(w){const r=spawnSync('taskkill',['/F','/IM','mneme.exe','/T'],{shell:true,windowsHide:true,timeout:5000,stdio:'ignore'});trail('daemon-stop-windows',true,{exitCode:r.status});let reaped=0;try{const beatDir=path.join(organ,'heartbeats');if(fs.existsSync(beatDir)){for(const f of fs.readdirSync(beatDir)){const m=f.match(/^(\\\\d+)\\\\.beat$/);if(m){const pid=parseInt(m[1]);if(pid>0&&pid!==process.pid){spawnSync('taskkill',['/F','/PID',pid.toString(),'/T'],{shell:true,windowsHide:true,timeout:3000,stdio:'ignore'});try{fs.unlinkSync(path.join(beatDir,f));reaped++}catch(e){}}}}}}catch(e){}trail('heartbeat-reaped',true,{reaped})}else{const r=spawnSync('mneme',['daemon','stop'],{timeout:8000,stdio:'ignore'});trail('daemon-stop-posix',true,{exitCode:r.status});let reaped=0;try{const beatDir=path.join(organ,'heartbeats');if(fs.existsSync(beatDir)){for(const f of fs.readdirSync(beatDir)){const m=f.match(/^(\\\\d+)\\\\.beat$/);if(m){const pid=parseInt(m[1]);if(pid>0&&pid!==process.pid){try{process.kill(pid,'SIGTERM')}catch(e){}wait(100);try{process.kill(pid,'SIGKILL')}catch(e){}try{fs.unlinkSync(path.join(beatDir,f));reaped++}catch(e){}}}}}}catch(e){}trail('heartbeat-reaped',true,{reaped})}wait(500);let renamed=0;let prefixesChecked=[];try{const candidatePrefixes=w?[path.join(home,'AppData','Roaming','npm'),path.dirname(process.execPath),'C:\\\\\\\\nvm4w\\\\\\\\nodejs',path.join(home,'AppData','Local','nvm')]:['/usr/local/lib','/usr/lib',path.join(home,'.npm-global'),path.join(home,'.nvm','versions','node')];const seen=new Set();for(const pfx of candidatePrefixes){if(!fs.existsSync(pfx))continue;let nodeModulesBases=[];if(fs.existsSync(path.join(pfx,'node_modules')))nodeModulesBases.push(path.join(pfx,'node_modules'));try{for(const entry of fs.readdirSync(pfx)){const sub=path.join(pfx,entry,'node_modules');if(fs.existsSync(sub))nodeModulesBases.push(sub);const sub2=path.join(pfx,entry,'nodejs','node_modules');if(fs.existsSync(sub2))nodeModulesBases.push(sub2)}}catch(e){}for(const nm of nodeModulesBases){if(seen.has(nm))continue;seen.add(nm);prefixesChecked.push(nm);const npmGlobal=path.join(nm,'mneme-ai');if(!fs.existsSync(npmGlobal))continue;const dllPaths=w?[path.join(npmGlobal,'node_modules','@img','sharp-libvips-win32-x64','lib','libvips-42.dll'),path.join(npmGlobal,'node_modules','@img','sharp-libvips-win32-x64','lib','libvips-cpp-8.17.3.dll'),path.join(npmGlobal,'node_modules','sharp','build','Release','sharp-win32-x64.node')]:[];for(const dll of dllPaths){if(!fs.existsSync(dll))continue;let freed=false;for(let i=0;i<40;i++){try{const fd=fs.openSync(dll,'r+');fs.closeSync(fd);freed=true;break}catch(e2){wait(50)}}if(!freed){try{fs.renameSync(dll,dll+'.locked-'+Date.now()+'-'+process.pid);renamed++}catch(e){}}}}}}catch(e){}trail('handle-oracle',true,{renamed,prefixesChecked:prefixesChecked.length});let swept=0;try{const candidates=w?[path.join(home,'AppData','Roaming','npm','node_modules'),path.join(path.dirname(process.execPath),'node_modules')]:['/usr/local/lib/node_modules',path.join(home,'.npm-global','node_modules')];for(const npmParent of candidates){if(!fs.existsSync(npmParent))continue;try{for(const entry of fs.readdirSync(npmParent)){if(entry.startsWith('.mneme-ai-')){try{fs.rmSync(path.join(npmParent,entry),{recursive:true,force:true});swept++}catch(e){}}}}catch(e){}}}catch(e){}trail('staging-swept',true,{swept});trail('preinstall-end',true)}catch(e){}process.exit(0)\""
33
33
  },
34
34
  "dependencies": {
35
- "@mneme-ai/core": "2.75.1",
36
- "@mneme-ai/correlator": "2.75.1",
37
- "@mneme-ai/embeddings": "2.75.1",
38
- "@mneme-ai/mcp": "2.75.1",
35
+ "@mneme-ai/core": "2.75.2",
36
+ "@mneme-ai/correlator": "2.75.2",
37
+ "@mneme-ai/embeddings": "2.75.2",
38
+ "@mneme-ai/mcp": "2.75.2",
39
39
  "commander": "^14.0.3",
40
40
  "kleur": "^4.1.5"
41
41
  },