Sign In

verbative-memory

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

verbative-memory - npm Package Compare versions

Comparing version
1.1.0
to
1.1.1
+115
-13
bin/verbative-memory.js

@@ -11,3 +11,6 @@ #!/usr/bin/env node

*
* Everything runs on-device; the only network use is these one-time downloads.
* Engine updates ride npm versions: each download is stamped with the package
* version that fetched it, and a version bump re-downloads (an existence-only
* gate left early adopters on the first engine build forever). Everything runs
* on-device; the only network use is these per-version downloads.
*/

@@ -50,3 +53,3 @@ "use strict";

async function download(url, dest) {
process.stderr.write("verbative-memory: downloading " + path.basename(dest) + " (one-time)...\n");
process.stderr.write("verbative-memory: downloading " + path.basename(dest) + "...\n");
const res = await fetch(url, { redirect: "follow" });

@@ -67,5 +70,95 @@ if (!res.ok) throw new Error("download failed (" + res.status + "): " + url);

function readMarker(file) {
try {
return fs.readFileSync(file, "utf8").trim();
} catch {
return "";
}
}
// Clear a prior install (dir or single file) so the fresh extract lands clean.
// Windows forbids DELETING a running exe/loaded DLL but allows RENAMING it
// (same lesson as the extension's binary refresh): when the delete leaves
// locked survivors, move them into a .trash-* sibling — live processes keep
// running from the moved files, the extract path is free, and the trash is
// purged on a later run.
function clearForReplace(target, binDir) {
try {
fs.rmSync(target, { recursive: true, force: true });
} catch {
/* locked leftovers handled below */
}
if (!fs.existsSync(target)) return;
const trash = path.join(binDir, ".trash-" + Date.now());
const sweep = (from, to) => {
fs.mkdirSync(to, { recursive: true });
for (const e of fs.readdirSync(from, { withFileTypes: true })) {
try {
if (e.isDirectory()) {
sweep(path.join(from, e.name), path.join(to, e.name));
fs.rmdirSync(path.join(from, e.name));
} else {
fs.renameSync(path.join(from, e.name), path.join(to, e.name));
}
} catch {
/* a straggler is fine — tar can overwrite what it CAN unlink */
}
}
};
try {
if (fs.statSync(target).isDirectory()) {
sweep(target, path.join(trash, path.basename(target)));
fs.rmdirSync(target);
} else {
fs.mkdirSync(trash, { recursive: true });
fs.renameSync(target, path.join(trash, path.basename(target)));
}
} catch {
/* best effort */
}
}
function purgeTrash(binDir) {
try {
for (const e of fs.readdirSync(binDir)) {
if (e.startsWith(".trash-")) {
try {
fs.rmSync(path.join(binDir, e), { recursive: true, force: true });
} catch {
/* still pinned by a live process — next time */
}
}
}
} catch {
/* bin dir may not exist yet */
}
}
// After an engine UPDATE the resident memory server keeps serving from the OLD
// binary (it owns the shared socket and never exits on its own) — stop it once
// so the next call respawns from the fresh download. Best-effort and safe: the
// server restarts on demand, and hook/MCP calls no-op gracefully while it is
// down.
function bounceResidentServer() {
try {
if (process.platform === "win32") {
spawnSync(
path.join(process.env.SystemRoot || "C:\\Windows", "System32", "taskkill.exe"),
["/F", "/T", "/IM", "verbative-hooks.exe"],
{ stdio: "ignore" },
);
} else {
spawnSync("pkill", ["-f", "verbative-hooks.*__memory-server"], { stdio: "ignore" });
}
} catch {
/* best effort */
}
}
async function ensureCore(root) {
const tag = platformTag();
const coreDir = path.join(root, "bin", "verbative-memory-core");
const binDir = path.join(root, "bin");
const pkgVersion = require("../package.json").version;
purgeTrash(binDir);
const coreDir = path.join(binDir, "verbative-memory-core");
const core = path.join(

@@ -76,18 +169,28 @@ coreDir,

);
if (!fs.existsSync(core)) {
const archive = path.join(root, "bin", "core.tar.gz");
// Version marker lives INSIDE the replaced dir so it can never go stale
// independently of the payload. Missing marker (pre-1.1.1 installs) reads as
// "" and triggers the one catch-up re-download.
const coreMarker = path.join(coreDir, ".verbative-memory-core.version");
if (!fs.existsSync(core) || readMarker(coreMarker) !== pkgVersion) {
const hadPrior = fs.existsSync(core);
const archive = path.join(binDir, "core.tar.gz");
await download(`${DIST}/verbative-memory-core-${tag}.tar.gz`, archive);
clearForReplace(coreDir, binDir);
extractTarGz(archive, coreDir);
fs.chmodSync(core, 0o755);
fs.writeFileSync(coreMarker, pkgVersion);
if (hadPrior) bounceResidentServer();
}
const llm = path.join(
root,
"bin",
binDir,
process.platform === "win32" ? "verbative-llm.exe" : "verbative-llm",
);
if (!fs.existsSync(llm)) {
const archive = path.join(root, "bin", "llm.tar.gz");
const llmMarker = path.join(binDir, ".verbative-llm.version");
if (!fs.existsSync(llm) || readMarker(llmMarker) !== pkgVersion) {
const archive = path.join(binDir, "llm.tar.gz");
await download(`${DIST}/verbative-llm-${tag}.tar.gz`, archive);
extractTarGz(archive, path.join(root, "bin"));
clearForReplace(llm, binDir);
extractTarGz(archive, binDir);
fs.chmodSync(llm, 0o755);
fs.writeFileSync(llmMarker, pkgVersion);
}

@@ -150,4 +253,3 @@ return { core, llm };

// session-start warning (same stale rule the extension already migrated away).
for (const rule of ["Edit(.verbative/**)"])
if (!allow.includes(rule)) allow.push(rule);
for (const rule of ["Edit(.verbative/**)"]) if (!allow.includes(rule)) allow.push(rule);
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });

@@ -278,3 +380,3 @@ fs.writeFileSync(settingsPath, JSON.stringify(data, null, 2) + "\n");

module.exports = { autoRegisterClaudeHooks, unregisterClaudeHooks, handleCliCommand };
module.exports = { autoRegisterClaudeHooks, unregisterClaudeHooks, handleCliCommand, ensureCore };
if (require.main !== module) return;

@@ -281,0 +383,0 @@

+1
-1
{
"name": "verbative-memory",
"version": "1.1.0",
"version": "1.1.1",
"mcpName": "io.github.verbative/verbative-memory",

@@ -5,0 +5,0 @@ "description": "On-device memory system for AI coding agents — dual-layer engine (distilled facts + lossless event ledger), automatically captured and injected, exposed over MCP. Shared across agents, persistent across sessions; files in your repo.",