ruvnet-brain 3.9.18-dev β 3.9.51-dev
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/README.md +9 -6
- package/bin/install.mjs +167 -7
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# π§ RuvNet Brain
|
|
6
6
|
|
|
7
|
-
### π§ RuvNet Brain β [](https://github.com/stuinfla/ruvnet-brain/blob/main/plugin/.claude-plugin/plugin.json)
|
|
8
8
|
|
|
9
9
|
**A portable, source-grounded brain over Reuven Cohen's (rUv's) RuvNet stack β delivered as a Claude Code plugin that makes Claude _use_ the stack instead of fighting it.**
|
|
10
10
|
|
|
@@ -142,9 +142,12 @@ answers the question the owner has been asking for weeks β **"what is actually
|
|
|
142
142
|
had zero call sites; the client referenced it only in comments. Built-tested-unwired is this
|
|
143
143
|
project's signature failure, and it happened three times in one night.
|
|
144
144
|
|
|
145
|
-
Honest limit: this is
|
|
146
|
-
(contextual, anticipatory, compounding) and
|
|
147
|
-
|
|
145
|
+
Honest limit: this is still a dev release, **not 4.0**. 4.0 requires levels 3β5 of ADR-028's ladder
|
|
146
|
+
(contextual, anticipatory, compounding) **shipped and independently graded β₯95**. The mechanisms now
|
|
147
|
+
exist β L3's delivery seam (the chokepoint), an L4 goal surface, and L5 cross-project promotion (lessons
|
|
148
|
+
promoted to your global brain, survival proven by isolation) β but the ladder still grades **L2βL3**,
|
|
149
|
+
because L3 is built rather than live (deploy-gated) and the five acceptance metrics aren't all measured.
|
|
150
|
+
See `docs/4.0-READINESS.md` and `docs/4.0-EXECUTIVE-BRIEFING.md` (last independent grade: 70/100 overall).
|
|
148
151
|
|
|
149
152
|
<details>
|
|
150
153
|
<summary><b>Earlier — what 3.5 shipped</b> · it stopped waiting to be asked. <i>Expand for the receipts.</i></summary>
|
|
@@ -406,7 +409,7 @@ Plus: the **βtake the wheelβ behavioral pipeline** (below), a **4-level beha
|
|
|
406
409
|
|
|
407
410
|
## How it works
|
|
408
411
|
|
|
409
|
-
The expensive work happens **once, at build time**: every covered repo is deep-walked (whole files, full function bodies, plus a symbol index), embedded into **two** vector variants (MiniLM-384 for edge/portability, bge-768 for depth) stored on-disk in **RVF / HNSW**, and distilled into a concepts + capability layer of per-repo primers and cards. That's **149,
|
|
412
|
+
The expensive work happens **once, at build time**: every covered repo is deep-walked (whole files, full function bodies, plus a symbol index), embedded into **two** vector variants (MiniLM-384 for edge/portability, bge-768 for depth) stored on-disk in **RVF / HNSW**, and distilled into a concepts + capability layer of per-repo primers and cards. That's **149,729 source chunks**. At **query time**, `search_ruvnet` searches every repo's store at once, pools the hits, and runs them through **one cross-encoder rerank** on a common scale β so the truly relevant file wins regardless of which repo it lives in β then returns whole source files, each labeled by repo and path.
|
|
410
413
|
|
|
411
414
|

|
|
412
415
|
|
|
@@ -516,7 +519,7 @@ node forge-ask-all.mjs --dir . --q "How does RuVector implement HNSW vector sear
|
|
|
516
519
|
|
|
517
520
|
This project versions in the open (see the live badge up top for the exact plugin version; the downloadable knowledge bundle is a separate track) β we don't claim βdone,β βcomplete,β or βzero hallucinations.β Where it stands:
|
|
518
521
|
|
|
519
|
-
- β
**The grounding brain is real and proven** β 54 public stores Β· 149,
|
|
522
|
+
- β
**The grounding brain is real and proven** β 54 public stores Β· 149,729 public source chunks (57 built stores incl. private), dual embeddings, cross-encoder rerank, plugin (MCP tool + enforcement hook + skill), all re-runnable.
|
|
520
523
|
- β
**Code-level depth** β the code-rich repos are indexed to full function bodies; βhow is it implemented?β returns the implementation. Verified in the shipped bundle (clean-room 3/3).
|
|
521
524
|
- β
**Routing holds** β named 47/48, described 26/28, scenario 7/8; behavioral L1βL4 all pass; private stores fenced out of the public bundle (zero-leak verified).
|
|
522
525
|
- β οΈ **Two routing residuals** (above) β surfaced, not hidden.
|
package/bin/install.mjs
CHANGED
|
@@ -1412,6 +1412,12 @@ function disableSpendGuard() {
|
|
|
1412
1412
|
else ok('spend watchdog was already off β nothing to remove (safe to run any time)');
|
|
1413
1413
|
}
|
|
1414
1414
|
|
|
1415
|
+
// Default STATE_PATH from scripts/upgrade-notice.mjs, duplicated (not imported β see the cmpTag()
|
|
1416
|
+
// comment above this file's own rule on why) so machineFootprint()/uninstallAll() can find and
|
|
1417
|
+
// remove it without a module this file may not statically depend on.
|
|
1418
|
+
const upgradeNoticeStatePath = () =>
|
|
1419
|
+
process.env.RUVNET_UPGRADE_NOTICE_FILE || path.join(os.homedir(), '.config', 'ruvnet-brain', 'upgrade-notice.json');
|
|
1420
|
+
|
|
1415
1421
|
/**
|
|
1416
1422
|
* Everything this installer can leave on a machine, DERIVED from disk β never asserted.
|
|
1417
1423
|
*
|
|
@@ -1435,7 +1441,14 @@ export function machineFootprint() {
|
|
|
1435
1441
|
if (cmds) items.push({
|
|
1436
1442
|
label: 'Claude Code plugin',
|
|
1437
1443
|
path: path.dirname(cmds),
|
|
1438
|
-
|
|
1444
|
+
// `claude plugin uninstall` removes the INSTALLED plugin only β it leaves the marketplace itself
|
|
1445
|
+
// registered (a separate git clone + registry entry: `claude plugin marketplace list` still
|
|
1446
|
+
// shows it, and wirePlugin() above is the thing that added it via `claude plugin marketplace add
|
|
1447
|
+
// stuinfla/ruvnet-brain`). Verified live against `claude plugin marketplace --help` (marketplace
|
|
1448
|
+
// name = "ruvnet-brain", from this repo's own .claude-plugin/marketplace.json) that `remove` takes
|
|
1449
|
+
// that same short name. Without this second command someone who ran every undo we printed would
|
|
1450
|
+
// still have us registered as a marketplace.
|
|
1451
|
+
undo: 'claude plugin uninstall ruvnet-brain@ruvnet-brain && claude plugin marketplace remove ruvnet-brain',
|
|
1439
1452
|
});
|
|
1440
1453
|
const cmdPath = path.join(os.homedir(), '.claude', 'CLAUDE.md');
|
|
1441
1454
|
try {
|
|
@@ -1457,12 +1470,21 @@ export function machineFootprint() {
|
|
|
1457
1470
|
add('Status-bar preference', path.join(telemetryStateDir(), '.statusline-pref'), 'delete this file');
|
|
1458
1471
|
add('Model-router files', path.join(os.homedir(), '.claude', 'model-router'),
|
|
1459
1472
|
'rm -rf ~/.claude/model-router');
|
|
1460
|
-
//
|
|
1461
|
-
//
|
|
1473
|
+
// GAP FIX: this used to be a loose `.includes('ruvnet-brain')` substring test against the WHOLE
|
|
1474
|
+
// settings.json file β which (a) could also fire on something unrelated (e.g. a marketplace
|
|
1475
|
+
// autoUpdate setting that merely mentions our name) and get mislabeled as "the statusLine entry",
|
|
1476
|
+
// and (b) meant this was ALWAYS reported as a manual edit, never auto-removed, even though this
|
|
1477
|
+
// installer is the one that wrote the key and knows exactly what it wrote. detectStatusLine() now
|
|
1478
|
+
// checks the actual parsed statusLine.command against the exact string writeSettingsStatusLine()
|
|
1479
|
+
// writes β precise enough that removeSettingsStatusLine() (called from uninstallAll()) can safely
|
|
1480
|
+
// reverse just this key, the same way removeClaudeMdBlock() reverses just its own block. A status
|
|
1481
|
+
// line a user has since edited or folded into their own script no longer matches and is correctly
|
|
1482
|
+
// left off this list entirely (nothing to claim, nothing to undo).
|
|
1462
1483
|
try {
|
|
1463
|
-
const settings =
|
|
1464
|
-
|
|
1465
|
-
|
|
1484
|
+
const settings = settingsJsonPath();
|
|
1485
|
+
const detected = detectStatusLine(settings);
|
|
1486
|
+
if (detected.hasStatusLine && !detected.parseError && detected.command === `node "${statuslineHelperPath()}"`) {
|
|
1487
|
+
items.push({ label: 'The statusLine entry in settings.json', path: settings, undo: 'npx ruvnet-brain --uninstall (removes just this key; settings.json is backed up first)' });
|
|
1466
1488
|
}
|
|
1467
1489
|
} catch { /* unreadable β do not claim it */ }
|
|
1468
1490
|
try {
|
|
@@ -1471,6 +1493,14 @@ export function machineFootprint() {
|
|
|
1471
1493
|
items.push({ label: 'The search_ruvnet MCP server registration', path: claudeJson, undo: 'claude mcp remove ruvnet-brain --scope user' });
|
|
1472
1494
|
}
|
|
1473
1495
|
} catch { /* unreadable β do not claim it */ }
|
|
1496
|
+
// GAP FIX: recordNotified() (scripts/upgrade-notice.mjs, invoked from main() and runDemo() below)
|
|
1497
|
+
// writes this file the first time a "what's new" notice is shown β a real disk artifact this
|
|
1498
|
+
// installer's own code path creates, that was never listed here and never removed on --uninstall.
|
|
1499
|
+
// Path duplicated rather than imported (see the cmpTag() comment above: this file must not import
|
|
1500
|
+
// from scripts/ at module scope, since scripts/upgrade-notice.mjs isn't in the npm `files` list β
|
|
1501
|
+
// it only reaches a user via a repo clone or `npx github:...`, never a plain npm publish; harmless
|
|
1502
|
+
// no-op existence check either way). Env override name matches STATE_PATH there exactly.
|
|
1503
|
+
add('Upgrade-notice state (release-notice tracking)', upgradeNoticeStatePath(), 'delete this file');
|
|
1474
1504
|
|
|
1475
1505
|
return items;
|
|
1476
1506
|
}
|
|
@@ -1551,7 +1581,10 @@ function uninstallAll() {
|
|
|
1551
1581
|
// ours to delete, so they are handed over as commands.
|
|
1552
1582
|
const AUTO = new Set(['Brain bundle (knowledge base)', 'Nightly updater (LaunchAgent)',
|
|
1553
1583
|
'Spend watchdog (LaunchAgent)', 'Spend watchdog script', 'CLAUDE.md block (6 lines, between markers)',
|
|
1554
|
-
'Model-router files', 'Status-bar version script', 'Status-bar preference', 'Usage-counts preference'
|
|
1584
|
+
'Model-router files', 'Status-bar version script', 'Status-bar preference', 'Usage-counts preference',
|
|
1585
|
+
// Two gaps closed here: the statusLine KEY is now removable in place (we know exactly what we
|
|
1586
|
+
// wrote β see removeSettingsStatusLine()), and the upgrade-notice tracker is a file we fully own.
|
|
1587
|
+
'The statusLine entry in settings.json', 'Upgrade-notice state (release-notice tracking)']);
|
|
1555
1588
|
const willRemove = before.filter((it) => AUTO.has(it.label));
|
|
1556
1589
|
const manual = before.filter((it) => !AUTO.has(it.label));
|
|
1557
1590
|
|
|
@@ -1570,6 +1603,14 @@ function uninstallAll() {
|
|
|
1570
1603
|
const claudeMd = removeClaudeMdBlock();
|
|
1571
1604
|
if (claudeMd === 'removed') ok('removed our block from ~/.claude/CLAUDE.md (your content untouched, backup saved)');
|
|
1572
1605
|
|
|
1606
|
+
// GAP FIX: this used to be permanently "manual" β machineFootprint() treated ANY settings.json edit
|
|
1607
|
+
// as something only the user could safely touch. That blanket rule was right for edits we cannot
|
|
1608
|
+
// attribute with confidence, but wrong for this one specific key: we wrote it ourselves and know
|
|
1609
|
+
// the exact string we wrote, so we can reverse exactly that (never a status line the user has since
|
|
1610
|
+
// customized β removeSettingsStatusLine() checks the live command before touching anything).
|
|
1611
|
+
const statusLine = removeSettingsStatusLine();
|
|
1612
|
+
if (statusLine === 'removed') ok('removed the statusLine entry from ~/.claude/settings.json (your other settings untouched, backup saved)');
|
|
1613
|
+
|
|
1573
1614
|
// NEVER rm -rf A PATH WE HAVE NOT PROVEN IS OURS. resolvedKbDir() honours $RUVNET_BRAIN_KB, which
|
|
1574
1615
|
// the docs encourage for custom install locations β so `RUVNET_BRAIN_KB=$HOME npx ruvnet-brain
|
|
1575
1616
|
// --uninstall` would have recursively deleted the user's home directory. Found by adversarial
|
|
@@ -1600,6 +1641,11 @@ function uninstallAll() {
|
|
|
1600
1641
|
['status-bar script', path.join(os.homedir(), '.cache', 'ruvnet-brain', 'ruvnet-brain-statusline.cjs')],
|
|
1601
1642
|
['status-bar preference', path.join(telemetryStateDir(), '.statusline-pref')],
|
|
1602
1643
|
['usage-counts preference', telemetryConsentPath()],
|
|
1644
|
+
// GAP FIX: written by recordNotified() (scripts/upgrade-notice.mjs) whenever the "what's new"
|
|
1645
|
+
// notice fires from main()/runDemo() below β a single-purpose file under a directory this
|
|
1646
|
+
// installer alone writes to, safe to remove outright (not the whole ~/.config/ruvnet-brain/ dir,
|
|
1647
|
+
// which can also hold lessons.json/settings.json this installer never creates and must not touch).
|
|
1648
|
+
['upgrade-notice state', upgradeNoticeStatePath()],
|
|
1603
1649
|
]) {
|
|
1604
1650
|
if (!fs.existsSync(target)) continue;
|
|
1605
1651
|
try { fs.rmSync(target, { recursive: true, force: true }); ok(`removed the ${label}`); }
|
|
@@ -1932,6 +1978,91 @@ export async function offerTelemetry(cacheDir) {
|
|
|
1932
1978
|
* So: persistent background jobs and global-config edits require their OWN explicit flag. There is
|
|
1933
1979
|
* no combination of `-y` alone that installs a daemon.
|
|
1934
1980
|
*/
|
|
1981
|
+
/**
|
|
1982
|
+
* THE PLAN β everything this run may do, stated BEFORE the first thing is done.
|
|
1983
|
+
*
|
|
1984
|
+
* WHY THIS EXISTS (real user feedback, 2026-07-24, relayed by the owner): people were not running
|
|
1985
|
+
* `npx ruvnet-brain` *because they could not tell what it would do.* One of them, a sophisticated
|
|
1986
|
+
* user, put the general objection precisely: he dislikes "the virus/plugin approach⦠it all works in
|
|
1987
|
+
* memory, with invisible hooks and all."
|
|
1988
|
+
*
|
|
1989
|
+
* The installer already asked consent for every high-impact step β watchdog, nightly updates,
|
|
1990
|
+
* telemetry, stack tools, statusline. That was necessary and NOT sufficient: consent granted one
|
|
1991
|
+
* question at a time, after the run has already started, never tells you the SHAPE of what you
|
|
1992
|
+
* agreed to. You cannot decline a thing you have not yet been told is coming, and a person deciding
|
|
1993
|
+
* whether to paste a command into their terminal is deciding about the whole run, not about step 4.
|
|
1994
|
+
*
|
|
1995
|
+
* So: the whole list, up front, with what each one costs you and how to undo it. Steps marked [?] are
|
|
1996
|
+
* asked individually as before β this screen does not replace those prompts, it makes them
|
|
1997
|
+
* predictable. Nothing here mutates anything; it prints and waits.
|
|
1998
|
+
*
|
|
1999
|
+
* TRUTHFULNESS RULE: every line below names a real step this file performs and a real reversal
|
|
2000
|
+
* command. If a step is added to the installer and not to this list, the list becomes a lie about
|
|
2001
|
+
* the installer β which is worse than having no list. Keep them together.
|
|
2002
|
+
*/
|
|
2003
|
+
async function printPlanAndConfirm() {
|
|
2004
|
+
const H = os.homedir();
|
|
2005
|
+
const short = (p) => p.replace(H, '~');
|
|
2006
|
+
|
|
2007
|
+
const steps = [
|
|
2008
|
+
{ auto: true, name: 'Download the knowledge base',
|
|
2009
|
+
// short() already renders $HOME as "~"; prefixing another one produced "~~/.cache/β¦".
|
|
2010
|
+
cost: short(resolveCacheDir().cacheDir),
|
|
2011
|
+
what: 'Real rUv source, on your disk, so answers cite files instead of guessing.',
|
|
2012
|
+
undo: 'npx ruvnet-brain --uninstall' },
|
|
2013
|
+
{ auto: true, name: 'Register the Claude Code plugin + MCP server',
|
|
2014
|
+
cost: `an entry in ${short(path.join(H, '.claude'))}`,
|
|
2015
|
+
what: 'Gives Claude a search_ruvnet tool. Adds no hooks you have not agreed to.',
|
|
2016
|
+
undo: 'npx ruvnet-brain --uninstall' },
|
|
2017
|
+
{ ask: true, name: 'Add rUv tools you are missing',
|
|
2018
|
+
cost: 'npm installs, only the ones you pick',
|
|
2019
|
+
what: 'So the brain can build with them, not just answer questions about them.',
|
|
2020
|
+
undo: 'npm uninstall -g <tool>' },
|
|
2021
|
+
{ ask: true, name: 'Nightly auto-updates',
|
|
2022
|
+
cost: 'one LaunchAgent',
|
|
2023
|
+
what: 'Keeps the KB and plugin current. Recommended β rUv ships fast, and a stale brain is the main way this stops being useful.',
|
|
2024
|
+
undo: 'npx ruvnet-brain --disable-nightly' },
|
|
2025
|
+
{ ask: true, name: 'Spend watchdog',
|
|
2026
|
+
cost: 'one LaunchAgent',
|
|
2027
|
+
what: 'Warns you if an agent fleet starts burning API credit unexpectedly.',
|
|
2028
|
+
undo: 'npx ruvnet-brain --disable-spend-guard' },
|
|
2029
|
+
{ ask: true, name: 'Status-bar version segment',
|
|
2030
|
+
cost: 'one line in settings.json',
|
|
2031
|
+
what: 'Shows which brain version is live while you work.',
|
|
2032
|
+
undo: 'npx ruvnet-brain --no-statusline, or delete the statusLine entry' },
|
|
2033
|
+
{ ask: true, name: 'Anonymous usage counts',
|
|
2034
|
+
cost: 'a counter ping',
|
|
2035
|
+
what: 'Installs and searches only β never your queries, your code, or your paths.',
|
|
2036
|
+
undo: 'npx ruvnet-brain --no-telemetry' },
|
|
2037
|
+
];
|
|
2038
|
+
|
|
2039
|
+
console.log(` ${c.bold('Here is everything this will do.')} Nothing has happened yet.\n`);
|
|
2040
|
+
for (const s of steps) {
|
|
2041
|
+
const mark = s.auto ? c.green('β') : c.cyan('?');
|
|
2042
|
+
console.log(` ${mark} ${c.bold(s.name)} ${c.dim('Β· ' + s.cost)}`);
|
|
2043
|
+
console.log(` ${s.what}`);
|
|
2044
|
+
console.log(` ${c.dim('undo: ' + s.undo)}\n`);
|
|
2045
|
+
}
|
|
2046
|
+
console.log(` ${c.green('β')} happens automatically. ${c.cyan('?')} is asked first β and "no" is a complete answer.`);
|
|
2047
|
+
console.log(` ${c.dim('Every step is reversible, and `npx ruvnet-brain --what-changed` lists everything it touched.')}\n`);
|
|
2048
|
+
|
|
2049
|
+
// FLAG_YES means the caller already decided; a plan screen that blocks automation would break
|
|
2050
|
+
// agentic-kit and every scripted install. Print it, then proceed β the information is the point,
|
|
2051
|
+
// the pause is a courtesy to humans.
|
|
2052
|
+
if (FLAG_YES || FLAG_AUTO || !process.stdin.isTTY) {
|
|
2053
|
+
console.log(c.dim(' (non-interactive β continuing)\n'));
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
2057
|
+
const a = await new Promise((r) => rl.question(` ${c.cyan('?')} Continue? ${c.dim('[Y/n]')} `, r));
|
|
2058
|
+
rl.close();
|
|
2059
|
+
if (/^n/i.test(String(a).trim())) {
|
|
2060
|
+
console.log(`\n Stopped. Nothing was changed.\n`);
|
|
2061
|
+
process.exit(0);
|
|
2062
|
+
}
|
|
2063
|
+
console.log('');
|
|
2064
|
+
}
|
|
2065
|
+
|
|
1935
2066
|
function ask(question, def = false, { blanketYes = true } = {}) {
|
|
1936
2067
|
if (FLAG_YES && blanketYes) return Promise.resolve(true);
|
|
1937
2068
|
if (!process.stdin.isTTY) return Promise.resolve(def);
|
|
@@ -2224,6 +2355,33 @@ function writeSettingsStatusLine(detected, command) {
|
|
|
2224
2355
|
return backup;
|
|
2225
2356
|
}
|
|
2226
2357
|
|
|
2358
|
+
// The uninstall-side mirror of writeSettingsStatusLine() above β this installer is the ONLY writer
|
|
2359
|
+
// that can safely reverse this specific edit, because it is the only one that knows the EXACT string
|
|
2360
|
+
// it wrote. Match on that exact command (never a loose "mentions ruvnet-brain" guess β see the
|
|
2361
|
+
// machineFootprint() comment this replaces) so a status line the user has since folded their own
|
|
2362
|
+
// script into, or edited by hand, is left completely alone. Same "refuse rather than guess"
|
|
2363
|
+
// discipline removeClaudeMdBlock() already applies to CLAUDE.md, and the same backup-first courtesy.
|
|
2364
|
+
function removeSettingsStatusLine() {
|
|
2365
|
+
const settingsPath = settingsJsonPath();
|
|
2366
|
+
const detected = detectStatusLine(settingsPath);
|
|
2367
|
+
if (!detected.exists || detected.parseError || !detected.hasStatusLine) return 'absent';
|
|
2368
|
+
const ours = `node "${statuslineHelperPath()}"`;
|
|
2369
|
+
if (detected.command !== ours) return 'not-ours'; // never touch a status line we didn't write
|
|
2370
|
+
try {
|
|
2371
|
+
const backup = backupSettingsJson(settingsPath);
|
|
2372
|
+
const next = { ...(detected.json || {}) };
|
|
2373
|
+
delete next.statusLine;
|
|
2374
|
+
const tmp = `${settingsPath}.ruvnet-tmp`;
|
|
2375
|
+
fs.writeFileSync(tmp, JSON.stringify(next, null, 2) + '\n');
|
|
2376
|
+
fs.renameSync(tmp, settingsPath);
|
|
2377
|
+
info(c.dim(` your original is saved at ${backup}`));
|
|
2378
|
+
return 'removed';
|
|
2379
|
+
} catch (e) {
|
|
2380
|
+
warn(`couldn't remove the statusLine entry (${e.message}) β remove it yourself from ${settingsPath}`);
|
|
2381
|
+
return 'error';
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2227
2385
|
// Only called after explicit consent. NEVER overwrites an existing statusLine β detectStatusLine()
|
|
2228
2386
|
// is the single source of truth for "is one already there", checked fresh right before any write.
|
|
2229
2387
|
function applyStatusline() {
|
|
@@ -2491,6 +2649,8 @@ It is safe to re-run at any time. After installing, restart Claude Code so the g
|
|
|
2491
2649
|
}
|
|
2492
2650
|
}
|
|
2493
2651
|
|
|
2652
|
+
await printPlanAndConfirm();
|
|
2653
|
+
|
|
2494
2654
|
const { cacheDir, isCustom } = resolveCacheDir();
|
|
2495
2655
|
|
|
2496
2656
|
// ββ "ALREADY PRESENT" IS THE WRONG QUESTION β ask "already CURRENT" ββββββββββββββββββββββββββ
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.51-dev",
|
|
4
4
|
"description": "One-command installer for RuvNet Brain \u2014 a portable, source-grounded brain over rUv's RuvNet building blocks, delivered as a Claude Code plugin so Claude uses the stack instead of fighting it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"falsify": "node scripts/falsify.mjs",
|
|
32
32
|
"sbom": "npx --yes @cyclonedx/cyclonedx-npm --omit dev --output-file sbom/ruvnet-brain.cdx.json --mc-type application --validate",
|
|
33
33
|
"wired:check": "node scripts/wired-check.mjs --check",
|
|
34
|
-
"doc:currency": "node scripts/doc-currency.mjs --check"
|
|
34
|
+
"doc:currency": "node scripts/doc-currency.mjs --check",
|
|
35
|
+
"status:check": "node scripts/status-honesty.mjs"
|
|
35
36
|
},
|
|
36
37
|
"files": [
|
|
37
38
|
"bin/install.mjs",
|