total-recall-brain 3.43.1 → 3.43.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "total-recall-brain",
|
|
3
|
-
"version": "3.43.
|
|
3
|
+
"version": "3.43.2",
|
|
4
4
|
"description": "The Vibe Coding Brain & Autonomous Software Factory: memory, rules, secrets, and 33 visual plugins automatically managed across all your devices.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/cli/release.mjs
CHANGED
|
@@ -197,11 +197,13 @@ export function consumerState(root, pkg, version = null) {
|
|
|
197
197
|
const declaredFiles = [];
|
|
198
198
|
const pkgFile = path.join(root, 'package.json');
|
|
199
199
|
let declared = null;
|
|
200
|
+
let devOnly = false;
|
|
200
201
|
if (fs.existsSync(pkgFile)) {
|
|
201
202
|
try {
|
|
202
203
|
const j = JSON.parse(fs.readFileSync(pkgFile, 'utf8'));
|
|
203
204
|
const all = { ...(j.dependencies || {}), ...(j.devDependencies || {}), ...(j.optionalDependencies || {}) };
|
|
204
205
|
declared = all[pkg] ?? null;
|
|
206
|
+
devOnly = Boolean(j.devDependencies?.[pkg]) && !j.dependencies?.[pkg] && !j.optionalDependencies?.[pkg];
|
|
205
207
|
if (declared) declaredFiles.push(pkgFile);
|
|
206
208
|
} catch {
|
|
207
209
|
/* unreadable package.json is reported as unknown, not as satisfied */
|
|
@@ -243,6 +245,10 @@ export function consumerState(root, pkg, version = null) {
|
|
|
243
245
|
/* keep looking */
|
|
244
246
|
}
|
|
245
247
|
}
|
|
248
|
+
// A checkout with no copy of a dev dependency runs under the shared install. Nothing there is stale.
|
|
249
|
+
if (!installed && devOnly) {
|
|
250
|
+
return { root, declared, want, range, installed: null, satisfied: true, pinBehind: false, devNotInstalled: true, reason: 'dev-not-installed' };
|
|
251
|
+
}
|
|
246
252
|
// What a consumer runs is what counts, and the version named is the question. A pin can lag on
|
|
247
253
|
// purpose, because `update` installs plugin copies with --no-save. Comparing against the pin
|
|
248
254
|
// would fail those and pass a consumer whose pin and install both lag.
|
|
@@ -285,6 +291,7 @@ export function verifyConsumers(pkg, version, opts = {}) {
|
|
|
285
291
|
failing: failing.length,
|
|
286
292
|
failures: failing.map((s) => ({ root: s.root, declared: s.declared, installed: s.installed, reason: s.reason })),
|
|
287
293
|
pin_behind: relevant.filter((s) => s.pinBehind).map((s) => ({ root: s.root, declared: s.declared, installed: s.installed })),
|
|
294
|
+
dev_not_installed: relevant.filter((s) => s.devNotInstalled).map((s) => s.root),
|
|
288
295
|
};
|
|
289
296
|
}
|
|
290
297
|
|
|
@@ -369,6 +376,7 @@ export async function run(argv = process.argv, deps = {}) {
|
|
|
369
376
|
}
|
|
370
377
|
log(` ✓ ${pkg}@${version} verified: registry + ${consumers.consumers}/${consumers.consumers} consumers`);
|
|
371
378
|
if (consumers.pin_behind.length) log(` ${consumers.pin_behind.length} run it with an older pin in package.json, such as ${consumers.pin_behind[0].root}`);
|
|
379
|
+
if (consumers.dev_not_installed.length) log(` ${consumers.dev_not_installed.length} keep no dev copy of it and run under the shared install`);
|
|
372
380
|
continue;
|
|
373
381
|
}
|
|
374
382
|
|
|
@@ -40,7 +40,9 @@ export async function runAutomaticBrainUpdates({brainDir,fleet=false,force=false
|
|
|
40
40
|
if(!force && !isPackageAutoUpdateEnabled())return {skipped:true,reason:'disabled',results:[]};
|
|
41
41
|
const file=path.join(brainDir,'memory-derived/automatic-brain-updates.json');
|
|
42
42
|
let saved;try{saved=JSON.parse(fs.readFileSync(file,'utf8'));}catch{}
|
|
43
|
-
|
|
43
|
+
// Fast retry is for this machine's own failures. A peer with no update transport fails every
|
|
44
|
+
// run, and counting it made maintenance run back to back forever.
|
|
45
|
+
const delay=(saved?.local_failed??saved?.failed)?Math.min(intervalMs,5*60*1000):intervalMs;
|
|
44
46
|
if(!force && !skipThrottle && saved?.checkedAt && now()>=saved.checkedAt && now()-saved.checkedAt<delay)return {skipped:true,reason:'throttled',results:[]};
|
|
45
47
|
fs.mkdirSync(path.dirname(file),{recursive:true});
|
|
46
48
|
const lock=`${file}.lock`;
|
|
@@ -185,6 +185,22 @@ function targetSpec(key, version) {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/** Dry by default. Resolve releases once; install independently; verify actual resolution. */
|
|
188
|
+
/**
|
|
189
|
+
* A checkout that keeps no copy of a dev dependency runs under the shared install, so it has no
|
|
190
|
+
* old version to replace. Its pin stays current, and its dev tree is its owner's to install: one
|
|
191
|
+
* plugin's tree is about 460 MB, so restoring them all automatically could fill a disk.
|
|
192
|
+
*/
|
|
193
|
+
const absentDevDep = (dep) => dep.section === 'devDependencies' && !dep.file;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The daemon runs with NODE_ENV=production, and under that npm and pnpm remove dev dependencies
|
|
197
|
+
* from whatever they install in. An install that wants a runtime tree says so with a flag.
|
|
198
|
+
*/
|
|
199
|
+
function installEnv(env = process.env) {
|
|
200
|
+
const { NODE_ENV, npm_config_omit, NPM_CONFIG_OMIT, npm_config_production, NPM_CONFIG_PRODUCTION, ...kept } = env;
|
|
201
|
+
return kept;
|
|
202
|
+
}
|
|
203
|
+
|
|
188
204
|
export async function updateAllBrains(opts = {}) {
|
|
189
205
|
const dryRun = opts.dryRun !== false;
|
|
190
206
|
const exec = opts.exec || spawnSync;
|
|
@@ -245,9 +261,12 @@ export async function updateAllBrains(opts = {}) {
|
|
|
245
261
|
row.status = 'failed'; row.error = 'Newer local/preview package; refusing an implicit downgrade'; continue;
|
|
246
262
|
}
|
|
247
263
|
const shared = isLink(path.join(owner.owner, 'node_modules')) || isLink(path.join(consumer.root, 'node_modules'));
|
|
248
|
-
const needsChange = shared || consumer.deps.some(dep =>
|
|
249
|
-
|
|
250
|
-
|
|
264
|
+
const needsChange = shared || consumer.deps.some(dep => {
|
|
265
|
+
const pinLags = !consumer.runtimeOnly && dep.declared !== targetSpec(dep.key, versions[dep.package]);
|
|
266
|
+
if (absentDevDep(dep)) return pinLags;
|
|
267
|
+
return pinLags || dep.version !== versions[dep.package]
|
|
268
|
+
|| !dep.file?.startsWith(path.join(owner.owner, 'node_modules') + path.sep);
|
|
269
|
+
});
|
|
251
270
|
if (!needsChange) continue;
|
|
252
271
|
row.status = dryRun ? 'would_update' : 'pending';
|
|
253
272
|
if (!groups.has(owner.owner)) groups.set(owner.owner, { ...owner, consumers: [] });
|
|
@@ -264,8 +283,8 @@ export async function updateAllBrains(opts = {}) {
|
|
|
264
283
|
const runtimeOnly = group.consumers.every(({ consumer }) => consumer.runtimeOnly);
|
|
265
284
|
const unpinned = runtimeOnly && group.manager === 'npm';
|
|
266
285
|
const needsInstall = group.consumers.some(({ consumer }) =>
|
|
267
|
-
isLink(path.join(consumer.root, 'node_modules')) || consumer.deps.some(dep =>
|
|
268
|
-
dep.version !== versions[dep.package] || !dep.file?.startsWith(path.join(group.owner, 'node_modules') + path.sep)));
|
|
286
|
+
isLink(path.join(consumer.root, 'node_modules')) || consumer.deps.some(dep => !absentDevDep(dep)
|
|
287
|
+
&& (dep.version !== versions[dep.package] || !dep.file?.startsWith(path.join(group.owner, 'node_modules') + path.sep))));
|
|
269
288
|
try {
|
|
270
289
|
lockFd = acquireBrainUpdateLock(lock, opts.lockWaitMs === undefined ? {} : { waitMs: opts.lockWaitMs });
|
|
271
290
|
for (const name of ['package-lock.json', 'npm-shrinkwrap.json', 'pnpm-lock.yaml']) {
|
|
@@ -294,7 +313,7 @@ export async function updateAllBrains(opts = {}) {
|
|
|
294
313
|
if (unpinned) args.push('--no-save', ...new Set(group.consumers.flatMap(({ consumer }) =>
|
|
295
314
|
consumer.deps.map(dep => `${dep.key}@${targetSpec(dep.key, versions[dep.package])}`))));
|
|
296
315
|
else if (!needsInstall) args.push(group.manager === 'pnpm' ? '--lockfile-only' : '--package-lock-only');
|
|
297
|
-
const install = exec(group.manager, args, { cwd: group.owner, encoding: 'utf8',
|
|
316
|
+
const install = exec(group.manager, args, { cwd: group.owner, env: installEnv(), encoding: 'utf8',
|
|
298
317
|
timeout: 600000, maxBuffer: 8 * 1024 * 1024 });
|
|
299
318
|
if (install.status !== 0) throw new Error(install.error?.message || install.stderr?.trim().slice(-1500) || `Install exited ${install.status}`);
|
|
300
319
|
for (const { consumer, row } of group.consumers) {
|
|
@@ -309,6 +328,7 @@ export async function updateAllBrains(opts = {}) {
|
|
|
309
328
|
const placed = (file) => Boolean(file) && allowedRoots.some((root) => file.startsWith(root));
|
|
310
329
|
const bad = consumer.deps.find(dep => {
|
|
311
330
|
const actual = installedBrainPackage(consumer.root, dep.key);
|
|
331
|
+
if (absentDevDep(dep) && !actual.file) return false;
|
|
312
332
|
return actual.version !== versions[dep.package] || !placed(actual.file);
|
|
313
333
|
});
|
|
314
334
|
// A link is only a fault when it escapes every legitimate root; a self-contained one is fine.
|