ruvnet-brain 4.0.2 โ 4.0.5
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 +1 -1
- package/bin/install.mjs +215 -31
- package/docs/RELEASE-NOTES-4.0.md +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/commands/whats-new.md +6 -6
- package/plugin/docs/RELEASE-NOTES-4.0.md +88 -0
- package/plugin/mcp/server.mjs +70 -33
- package/plugin/scripts/hook-shim.mjs +27 -22
- package/plugin/scripts/lesson-command-scope.mjs +133 -0
- package/plugin/scripts/lesson-gate.mjs +401 -0
- package/plugin/scripts/lesson-presentation.mjs +99 -0
- package/plugin/scripts/lesson-store.mjs +452 -0
- package/plugin/scripts/route-dispatch.sh +1 -0
- package/plugin/scripts/session-start-core.mjs +28 -2
- package/plugin/scripts/verify-interface.sh +1 -0
- package/plugin/scripts/whats-new.mjs +42 -0
- package/plugin/skills/release-proof/SKILL.md +21 -4
- package/plugin/skills/release-proof/references/receipt-contract.md +8 -2
- package/plugin/skills/release-proof/scripts/release-proof.mjs +77 -1
- package/plugin/skills/ruvnet-brain/SKILL.md +22 -7
- package/plugin/skills/whats-new/SKILL.md +4 -4
- package/scripts/build-bundle.mjs +34 -25
- package/scripts/fix-workstream.mjs +291 -0
- package/scripts/health-repair.mjs +14 -27
- package/scripts/issue-fix.mjs +135 -216
- package/scripts/learning-replay-cli.mjs +236 -0
- package/scripts/learning-replay-contract.mjs +255 -0
- package/scripts/learning-replay-execution.mjs +193 -0
- package/scripts/learning-replay-fixture.mjs +380 -0
- package/scripts/learning-replay-proof.mjs +459 -0
- package/scripts/learning-replay.mjs +10 -1565
- package/scripts/lesson-gate.mjs +3 -679
- package/scripts/lesson-store.mjs +4 -447
- package/scripts/memory-doctor.mjs +80 -9
- package/scripts/nightly-wrapper.sh +20 -28
- package/scripts/onboarding-console.mjs +302 -95
- package/scripts/protected-release-invocation.mjs +76 -0
- package/scripts/publication-receipt.mjs +307 -0
- package/scripts/release-authority.mjs +93 -0
- package/scripts/release-vector.mjs +49 -25
- package/scripts/release.mjs +55 -11
- package/scripts/self-update.mjs +15 -227
- package/scripts/stabilization-receipt.mjs +108 -0
- package/scripts/wired-check.mjs +3 -0
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
|
|
package/bin/install.mjs
CHANGED
|
@@ -604,7 +604,7 @@ function installReader(cacheDir) {
|
|
|
604
604
|
// though installation was green. Persist the exact runtime shipped by the installer underneath the
|
|
605
605
|
// installed KB: Node then resolves optional reader dependencies from `<cacheDir>/node_modules`, and
|
|
606
606
|
// both Claude Code and Codex get one stable path with no source clone or second package install.
|
|
607
|
-
export function
|
|
607
|
+
export function beginConsoleRuntimeTransaction(cacheDir, sourceRoot = REPO_ROOT) {
|
|
608
608
|
const runtime = path.join(cacheDir, '.console-runtime');
|
|
609
609
|
const staged = `${runtime}.tmp-${process.pid}`;
|
|
610
610
|
const prior = `${runtime}.prior-${process.pid}`;
|
|
@@ -631,16 +631,103 @@ export function installConsoleRuntime(cacheDir, sourceRoot = REPO_ROOT) {
|
|
|
631
631
|
fs.cpSync(source, target, { recursive: true, force: true, preserveTimestamps: true });
|
|
632
632
|
}
|
|
633
633
|
|
|
634
|
-
|
|
634
|
+
let packageManifest;
|
|
635
635
|
try {
|
|
636
|
-
fs.
|
|
637
|
-
fs.rmSync(prior, { recursive: true, force: true });
|
|
636
|
+
packageManifest = JSON.parse(fs.readFileSync(path.join(staged, 'package.json'), 'utf8'));
|
|
638
637
|
} catch (error) {
|
|
639
|
-
if (fs.existsSync(prior) && !fs.existsSync(runtime)) fs.renameSync(prior, runtime);
|
|
640
638
|
fs.rmSync(staged, { recursive: true, force: true });
|
|
639
|
+
throw new Error(`console runtime identity is invalid: ${error.message}`);
|
|
640
|
+
}
|
|
641
|
+
if (!packageManifest.version || packageManifest.version !== PACKAGE_VERSION) {
|
|
642
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
643
|
+
throw new Error(`console runtime version ${packageManifest.version || '(missing)'} does not match candidate ${PACKAGE_VERSION}`);
|
|
644
|
+
}
|
|
645
|
+
const stagedEntry = path.join(staged, 'scripts', 'onboarding-console.mjs');
|
|
646
|
+
for (const syntaxTarget of [stagedEntry, path.join(staged, 'bin', 'install.mjs')]) {
|
|
647
|
+
const checked = spawnSync(process.execPath, ['--check', syntaxTarget], { encoding: 'utf8' });
|
|
648
|
+
if (checked.error || checked.status !== 0) {
|
|
649
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
650
|
+
throw new Error(`console runtime failed syntax verification: ${path.relative(staged, syntaxTarget)}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
const identity = {
|
|
654
|
+
product: 'ruvnet-brain-console-runtime',
|
|
655
|
+
schema: 1,
|
|
656
|
+
apiContract: 1,
|
|
657
|
+
runtimeVersion: packageManifest.version,
|
|
658
|
+
entrypoint: 'scripts/onboarding-console.mjs',
|
|
659
|
+
sourceSha256: crypto.createHash('sha256').update(fs.readFileSync(stagedEntry)).digest('hex'),
|
|
660
|
+
};
|
|
661
|
+
fs.writeFileSync(path.join(staged, 'runtime-identity.json'), `${JSON.stringify(identity, null, 2)}\n`, { mode: 0o600 });
|
|
662
|
+
|
|
663
|
+
let state = 'staged';
|
|
664
|
+
const entry = path.join(runtime, identity.entrypoint);
|
|
665
|
+
return {
|
|
666
|
+
identity,
|
|
667
|
+
entry,
|
|
668
|
+
activate() {
|
|
669
|
+
if (state !== 'staged') throw new Error(`console runtime transaction cannot activate from ${state}`);
|
|
670
|
+
if (fs.existsSync(runtime)) fs.renameSync(runtime, prior);
|
|
671
|
+
try {
|
|
672
|
+
fs.renameSync(staged, runtime);
|
|
673
|
+
state = 'active';
|
|
674
|
+
return entry;
|
|
675
|
+
} catch (error) {
|
|
676
|
+
if (fs.existsSync(prior) && !fs.existsSync(runtime)) fs.renameSync(prior, runtime);
|
|
677
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
678
|
+
state = 'rolled-back';
|
|
679
|
+
throw error;
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
commit() {
|
|
683
|
+
if (state !== 'active') throw new Error(`console runtime transaction cannot commit from ${state}`);
|
|
684
|
+
fs.rmSync(prior, { recursive: true, force: true });
|
|
685
|
+
state = 'committed';
|
|
686
|
+
return entry;
|
|
687
|
+
},
|
|
688
|
+
rollback() {
|
|
689
|
+
if (state === 'staged') fs.rmSync(staged, { recursive: true, force: true });
|
|
690
|
+
if (state === 'active') {
|
|
691
|
+
fs.rmSync(runtime, { recursive: true, force: true });
|
|
692
|
+
if (fs.existsSync(prior)) fs.renameSync(prior, runtime);
|
|
693
|
+
}
|
|
694
|
+
fs.rmSync(staged, { recursive: true, force: true });
|
|
695
|
+
fs.rmSync(prior, { recursive: true, force: true });
|
|
696
|
+
state = 'rolled-back';
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
export function installConsoleRuntime(cacheDir, sourceRoot = REPO_ROOT) {
|
|
702
|
+
const transaction = beginConsoleRuntimeTransaction(cacheDir, sourceRoot);
|
|
703
|
+
try {
|
|
704
|
+
transaction.activate();
|
|
705
|
+
return transaction.commit();
|
|
706
|
+
} catch (error) {
|
|
707
|
+
transaction.rollback();
|
|
641
708
|
throw error;
|
|
642
709
|
}
|
|
643
|
-
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export function consoleRestartState(identity, {
|
|
713
|
+
receiptDir = path.join(process.env.RUVNET_BRAIN_HOME || path.join(os.homedir(), '.cache', 'ruvnet-brain'), 'console-instances'),
|
|
714
|
+
} = {}) {
|
|
715
|
+
let receipts = [];
|
|
716
|
+
try {
|
|
717
|
+
receipts = fs.readdirSync(receiptDir)
|
|
718
|
+
.filter((name) => name.endsWith('.json'))
|
|
719
|
+
.map((name) => {
|
|
720
|
+
try { return JSON.parse(fs.readFileSync(path.join(receiptDir, name), 'utf8')); }
|
|
721
|
+
catch { return null; }
|
|
722
|
+
})
|
|
723
|
+
.filter((receipt) => receipt?.product === 'ruvnet-brain-console' && receipt.schema === 1);
|
|
724
|
+
} catch { /* no running Console receipts is the ordinary ready state */ }
|
|
725
|
+
const staleInstances = receipts.filter((receipt) => receipt.sourceSha256 !== identity.sourceSha256).length;
|
|
726
|
+
return {
|
|
727
|
+
state: staleInstances > 0 ? 'pending-console-restart' : 'ready',
|
|
728
|
+
instanceReceipts: receipts.length,
|
|
729
|
+
staleInstances,
|
|
730
|
+
};
|
|
644
731
|
}
|
|
645
732
|
|
|
646
733
|
// โโ plugin presence: the ONLY reliable proof the slash commands will exist โโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -798,6 +885,7 @@ function codexManagedBlock(serverPath) {
|
|
|
798
885
|
'[mcp_servers.ruvnet-brain]',
|
|
799
886
|
'command = "node"',
|
|
800
887
|
`args = [${JSON.stringify(serverPath)}]`,
|
|
888
|
+
'startup_timeout_sec = 30',
|
|
801
889
|
CODEX_BLOCK_END,
|
|
802
890
|
].join('\n');
|
|
803
891
|
}
|
|
@@ -855,7 +943,11 @@ function removeCodexWiring() {
|
|
|
855
943
|
// What the doctor asserts from disk โ never from the fact that we once ran. "Wired" means our entry
|
|
856
944
|
// is in the config AND the server.mjs it points at is really there, because a registration pointing
|
|
857
945
|
// at a deleted file is worse than no registration: Codex fails at spawn time with nothing to read.
|
|
858
|
-
export function codexStatus({
|
|
946
|
+
export function codexStatus({
|
|
947
|
+
configPath = codexConfigPath(),
|
|
948
|
+
codexDir = codexHomeDir(),
|
|
949
|
+
brainHome = path.join(path.dirname(codexDir), '.cache', 'ruvnet-brain'),
|
|
950
|
+
} = {}) {
|
|
859
951
|
let host = false;
|
|
860
952
|
try { host = fs.existsSync(codexDir); } catch { /* unreadable โ treat as absent */ }
|
|
861
953
|
if (!host) return { host: false, wired: false, serverPath: null, serverExists: false };
|
|
@@ -866,7 +958,63 @@ export function codexStatus({ configPath = codexConfigPath(), codexDir = codexHo
|
|
|
866
958
|
try { serverPath = m ? JSON.parse(m[1]) : null; } catch { /* malformed entry โ treat as absent */ }
|
|
867
959
|
let serverExists = false;
|
|
868
960
|
try { serverExists = serverPath ? fs.existsSync(serverPath) : false; } catch { /* unreadable */ }
|
|
869
|
-
|
|
961
|
+
const section = m ? text.slice(m.index).split(/\n[ \t]*\[/, 1)[0] : '';
|
|
962
|
+
const timeoutMatch = /(?:^|\n)[ \t]*startup_timeout_sec\s*=\s*(\d+)/.exec(section);
|
|
963
|
+
const startupTimeoutSec = timeoutMatch ? Number(timeoutMatch[1]) : null;
|
|
964
|
+
const readinessReceipt = (() => {
|
|
965
|
+
try { return JSON.parse(fs.readFileSync(path.join(brainHome, 'mcp-readiness.json'), 'utf8')); }
|
|
966
|
+
catch { return null; }
|
|
967
|
+
})();
|
|
968
|
+
let live = false;
|
|
969
|
+
if (readinessReceipt?.state === 'ready'
|
|
970
|
+
&& Number.isInteger(readinessReceipt.pid)
|
|
971
|
+
&& Number.isInteger(readinessReceipt.workerPid)) {
|
|
972
|
+
try {
|
|
973
|
+
process.kill(readinessReceipt.pid, 0);
|
|
974
|
+
process.kill(readinessReceipt.workerPid, 0);
|
|
975
|
+
live = true;
|
|
976
|
+
} catch { /* stale process or worker receipt */ }
|
|
977
|
+
}
|
|
978
|
+
const readiness = live ? 'ready' : readinessReceipt?.state === 'degraded' ? 'degraded' : 'registered';
|
|
979
|
+
return {
|
|
980
|
+
host: true,
|
|
981
|
+
wired: Boolean(serverPath) && serverExists,
|
|
982
|
+
serverPath,
|
|
983
|
+
serverExists,
|
|
984
|
+
startupTimeoutSec,
|
|
985
|
+
readiness,
|
|
986
|
+
live,
|
|
987
|
+
readinessReceipt,
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
export function codexMcpGuidance(status) {
|
|
992
|
+
if (!status?.wired) {
|
|
993
|
+
return { healthy: false, blocking: true, summary: 'Codex MCP is not registered to a usable server.', detail: null };
|
|
994
|
+
}
|
|
995
|
+
if (status.live && status.readiness === 'ready') {
|
|
996
|
+
return {
|
|
997
|
+
healthy: true,
|
|
998
|
+
blocking: false,
|
|
999
|
+
summary: `Codex MCP ready and live; discovery uses a ${status.startupTimeoutSec ?? 'configured'}s startup deadline.`,
|
|
1000
|
+
detail: 'A running MCP shell completed worker initialize and warmup.',
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
if (status.readiness === 'degraded') {
|
|
1004
|
+
const receipt = status.readinessReceipt || {};
|
|
1005
|
+
return {
|
|
1006
|
+
healthy: false,
|
|
1007
|
+
blocking: true,
|
|
1008
|
+
summary: 'Codex MCP is registered but degraded.',
|
|
1009
|
+
detail: `${receipt.phase || 'startup'}: ${receipt.error || 'worker readiness failed'}`,
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
return {
|
|
1013
|
+
healthy: false,
|
|
1014
|
+
blocking: false,
|
|
1015
|
+
summary: `Codex MCP is registered with a ${status.startupTimeoutSec ?? 'missing'}s startup deadline; live readiness is not yet proven.`,
|
|
1016
|
+
detail: 'The first real search establishes worker readiness without removing search_ruvnet from discovery.',
|
|
1017
|
+
};
|
|
870
1018
|
}
|
|
871
1019
|
|
|
872
1020
|
// Atomic file replacement: produce the new bytes BESIDE the target, then rename() over it. Against
|
|
@@ -1678,11 +1826,14 @@ async function doctor() {
|
|
|
1678
1826
|
// from disk (our entry present AND the server.mjs it names really there), never asserted from the
|
|
1679
1827
|
// fact that an install once ran.
|
|
1680
1828
|
const cx = codexStatus();
|
|
1829
|
+
let codexMcp = null;
|
|
1681
1830
|
let codexLifecycle = null;
|
|
1682
1831
|
if (!cx.host) {
|
|
1683
1832
|
console.log(` ${c.dim('Codex: no host detected (no ~/.codex) โ nothing to wire.')}`);
|
|
1684
1833
|
} else if (cx.wired) {
|
|
1685
|
-
|
|
1834
|
+
codexMcp = codexMcpGuidance(cx);
|
|
1835
|
+
console.log(` ${codexMcp.healthy ? c.green('โ') : codexMcp.blocking ? c.yellow('!') : c.dim('โ')} ${codexMcp.summary}`);
|
|
1836
|
+
if (codexMcp.detail) console.log(` ${codexMcp.detail}`);
|
|
1686
1837
|
codexLifecycle = await codexLifecycleStatus();
|
|
1687
1838
|
printCodexLifecycle(codexLifecycle);
|
|
1688
1839
|
} else {
|
|
@@ -1751,10 +1902,12 @@ async function doctor() {
|
|
|
1751
1902
|
&& !codexLifecycleGuidance(codexLifecycle).intentional,
|
|
1752
1903
|
);
|
|
1753
1904
|
const codexWiringFailed = Boolean(cx.host && !cx.wired);
|
|
1905
|
+
const codexReadinessFailed = Boolean(codexMcp?.blocking);
|
|
1754
1906
|
const failed = (hookResult ? hookResult.exitCode !== 0 : !allGreen)
|
|
1755
1907
|
|| groundingUnprovenPersisted
|
|
1756
1908
|
|| codexLifecycleFailed
|
|
1757
1909
|
|| codexWiringFailed
|
|
1910
|
+
|| codexReadinessFailed
|
|
1758
1911
|
|| Boolean(rufloOperational && !rufloOperational.healthy);
|
|
1759
1912
|
if (failed && !hookResult && !groundingUnprovenPersisted) {
|
|
1760
1913
|
console.log(` ${c.red('โ FAILING')} โ the warnings above are real. Re-run ${c.bold('npx ruvnet-brain')} to repair.`);
|
|
@@ -2018,32 +2171,61 @@ function missingUpdaterHelp(kbDir) {
|
|
|
2018
2171
|
console.error(` โ the current bundle ships forge-update.mjs; then this command will work.`);
|
|
2019
2172
|
}
|
|
2020
2173
|
|
|
2021
|
-
function syncHostsAfterUpdate() {
|
|
2174
|
+
export function syncHostsAfterUpdate(cacheDir = resolvedKbDir(), {
|
|
2175
|
+
sourceRoot = REPO_ROOT,
|
|
2176
|
+
brainHome = process.env.RUVNET_BRAIN_HOME || path.join(os.homedir(), '.cache', 'ruvnet-brain'),
|
|
2177
|
+
consoleReceiptDir = path.join(brainHome, 'console-instances'),
|
|
2178
|
+
wireClaude = wirePlugin,
|
|
2179
|
+
wireCodexHost: detectCodexHost = wireCodexHost,
|
|
2180
|
+
wireCodexPlugin: installCodexPlugin = wireCodexPlugin,
|
|
2181
|
+
runStableSpine = (apply) => spawnSync(
|
|
2182
|
+
process.execPath,
|
|
2183
|
+
[apply, '--auto', '--expected-version', PACKAGE_VERSION],
|
|
2184
|
+
{ stdio: 'inherit', env: process.env },
|
|
2185
|
+
),
|
|
2186
|
+
} = {}) {
|
|
2022
2187
|
const results = {};
|
|
2023
|
-
|
|
2024
|
-
if (results.claude.host && !results.claude.wired) return { ok: false, results };
|
|
2188
|
+
let runtimeTransaction;
|
|
2025
2189
|
try {
|
|
2026
|
-
|
|
2190
|
+
runtimeTransaction = beginConsoleRuntimeTransaction(cacheDir, sourceRoot);
|
|
2191
|
+
} catch (error) {
|
|
2192
|
+
return { ok: false, results, error: `Console runtime staging failed: ${error.message}` };
|
|
2193
|
+
}
|
|
2194
|
+
const fail = (detail = {}) => {
|
|
2195
|
+
runtimeTransaction.rollback();
|
|
2196
|
+
return { ok: false, results, ...detail };
|
|
2197
|
+
};
|
|
2198
|
+
|
|
2199
|
+
try {
|
|
2200
|
+
results.claude = wireClaude === wirePlugin
|
|
2201
|
+
? wirePlugin({ expectedVersion: PACKAGE_VERSION, requireManaged: true })
|
|
2202
|
+
: wireClaude({ expectedVersion: PACKAGE_VERSION, requireManaged: true });
|
|
2203
|
+
if (results.claude.host && !results.claude.wired) return fail();
|
|
2204
|
+
results.codexHost = detectCodexHost();
|
|
2027
2205
|
if (results.codexHost.host) {
|
|
2028
|
-
results.codex =
|
|
2206
|
+
results.codex = installCodexPlugin({ expectedVersion: PACKAGE_VERSION });
|
|
2029
2207
|
if (!['unchanged', 'installed', 'updated', 'disabled'].includes(results.codex.action)) {
|
|
2030
|
-
return
|
|
2208
|
+
return fail();
|
|
2031
2209
|
}
|
|
2032
2210
|
}
|
|
2033
2211
|
} catch (error) {
|
|
2034
2212
|
results.codex = { action: 'failed', error: error?.message || String(error) };
|
|
2035
|
-
return
|
|
2213
|
+
return fail();
|
|
2036
2214
|
}
|
|
2037
2215
|
|
|
2038
|
-
const apply = path.join(
|
|
2039
|
-
if (!fs.existsSync(apply)) return {
|
|
2040
|
-
const applied =
|
|
2216
|
+
const apply = path.join(sourceRoot, 'plugin', 'scripts', 'update-apply.mjs');
|
|
2217
|
+
if (!fs.existsSync(apply)) return fail({ error: 'Stable Spine updater missing from package' });
|
|
2218
|
+
const applied = runStableSpine(apply);
|
|
2041
2219
|
const okApplied = !applied.error && applied.status === 0;
|
|
2042
2220
|
if (okApplied) {
|
|
2043
|
-
const
|
|
2044
|
-
const receiptPath = path.join(home, 'host-convergence.json');
|
|
2221
|
+
const receiptPath = path.join(brainHome, 'host-convergence.json');
|
|
2045
2222
|
try {
|
|
2046
|
-
|
|
2223
|
+
runtimeTransaction.activate();
|
|
2224
|
+
results.consoleRuntime = {
|
|
2225
|
+
...runtimeTransaction.identity,
|
|
2226
|
+
...consoleRestartState(runtimeTransaction.identity, { receiptDir: consoleReceiptDir }),
|
|
2227
|
+
};
|
|
2228
|
+
fs.mkdirSync(brainHome, { recursive: true });
|
|
2047
2229
|
const tmp = `${receiptPath}.tmp-${process.pid}`;
|
|
2048
2230
|
fs.writeFileSync(tmp, JSON.stringify({
|
|
2049
2231
|
desiredVersion: PACKAGE_VERSION,
|
|
@@ -2052,13 +2234,16 @@ function syncHostsAfterUpdate() {
|
|
|
2052
2234
|
claude: { state: results.claude.host ? 'ready' : 'absent', version: results.claude.version || null },
|
|
2053
2235
|
codex: { state: results.codex?.action === 'disabled' ? 'disabled' : (results.codexHost?.host ? 'ready' : 'absent'), version: results.codex?.version || null },
|
|
2054
2236
|
},
|
|
2237
|
+
consoleRuntime: results.consoleRuntime,
|
|
2055
2238
|
}, null, 2));
|
|
2056
2239
|
fs.renameSync(tmp, receiptPath);
|
|
2240
|
+
runtimeTransaction.commit();
|
|
2057
2241
|
} catch (error) {
|
|
2058
|
-
return {
|
|
2242
|
+
return fail({ applyStatus: applied.status, error: `Console runtime convergence failed: ${error.message}` });
|
|
2059
2243
|
}
|
|
2060
2244
|
}
|
|
2061
|
-
return {
|
|
2245
|
+
if (!okApplied) return fail({ applyStatus: applied.status, error: applied.error?.message || 'Stable Spine activation failed' });
|
|
2246
|
+
return { ok: true, results, applyStatus: applied.status };
|
|
2062
2247
|
}
|
|
2063
2248
|
|
|
2064
2249
|
function runUpdate() {
|
|
@@ -2103,7 +2288,7 @@ function runUpdate() {
|
|
|
2103
2288
|
}
|
|
2104
2289
|
if (updateStatus === 0) {
|
|
2105
2290
|
info(c.dim('\nsynchronizing every detected host to this exact published versionโฆ\n'));
|
|
2106
|
-
const convergence = syncHostsAfterUpdate();
|
|
2291
|
+
const convergence = syncHostsAfterUpdate(kbDir);
|
|
2107
2292
|
if (!convergence.ok) {
|
|
2108
2293
|
warn(`host synchronization is incomplete โ runtime stays on the prior verified generation${convergence.error ? ` (${convergence.error})` : ''}`);
|
|
2109
2294
|
updateStatus = 1;
|
|
@@ -2477,15 +2662,14 @@ function printFootprint({ heading = 'What this put on your machine' } = {}) {
|
|
|
2477
2662
|
}
|
|
2478
2663
|
|
|
2479
2664
|
function showWhatsNew() {
|
|
2480
|
-
const
|
|
2481
|
-
|
|
2482
|
-
|
|
2665
|
+
const executable = path.join(REPO_ROOT, 'plugin', 'scripts', 'whats-new.mjs');
|
|
2666
|
+
const result = spawnSync(process.execPath, [executable], { stdio: 'inherit' });
|
|
2667
|
+
if (result.error) {
|
|
2668
|
+
console.error(`RuvNet Brain What's New failed: ${result.error.message}`);
|
|
2483
2669
|
process.exitCode = 1;
|
|
2484
2670
|
return;
|
|
2485
2671
|
}
|
|
2486
|
-
|
|
2487
|
-
process.stdout.write(text);
|
|
2488
|
-
if (!text.endsWith('\n')) process.stdout.write('\n');
|
|
2672
|
+
process.exitCode = result.status === 0 ? 0 : 1;
|
|
2489
2673
|
}
|
|
2490
2674
|
|
|
2491
2675
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# RuvNet-Brain 4.0 line โ what's new (the major-release highlights)
|
|
2
2
|
|
|
3
|
-
Updated: 2026-
|
|
3
|
+
Updated: 2026-08-01
|
|
4
4
|
|
|
5
5
|
> **Source of truth** for the `/whats-new` command and the first-run upgrade message. Curated, honest,
|
|
6
6
|
> major-only โ not the point-release churn. If a claim here isn't true of the shipping build, it does not
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.5",
|
|
4
4
|
"description": "One-command installer for RuvNet Brain โ 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": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
3
|
"description": "RuvNet brain transplant for Claude Code โ grounds every RuvNet decision in real source across 69 rUv repositories, prefers Ruflo / RuVector-RVF / AgentDB over training-prior defaults (pgvector, Pinecone, hand-rolled cosine), and can pull in any RuvNet repo on demand. Ships an enforced UserPromptSubmit retrieve-and-inject grounding hook that sharply reduces drift.",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.5",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Stuart Kerr"
|
|
7
7
|
},
|
|
@@ -9,14 +9,15 @@ The user wants the headline story of the **major** release they're on โ the 4.
|
|
|
9
9
|
**not** the "3.9.x โ 3.9.y" point-release churn. Deliver it warmly and honestly, then offer the Console.
|
|
10
10
|
|
|
11
11
|
**First, ground โ never recite this from memory (it drifts every release):**
|
|
12
|
-
1.
|
|
12
|
+
1. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/whats-new.mjs"`. This reads the running version and curated
|
|
13
|
+
notes from the same immutable installed payload. If it exits nonzero, report that exact failure;
|
|
14
|
+
do not substitute a checkout, download, or another installed version. State the version honestly.
|
|
13
15
|
**Do NOT claim "you're on 4.0"** unless the version literally starts with `4.` โ per ADR-042 the
|
|
14
16
|
number stays `3.9.x-dev` until the 4.0 line is field-verified. The honest framing is: *"these are the
|
|
15
17
|
4.0-line enhancements, and you already have them โ the version stamps to 4.0 once they're proven in
|
|
16
18
|
real use."*
|
|
17
|
-
2.
|
|
18
|
-
|
|
19
|
-
version framing.
|
|
19
|
+
2. Treat the executable's notes as the source of truth โ summarize them, don't invent beside them,
|
|
20
|
+
and carry their honest version framing.
|
|
20
21
|
|
|
21
22
|
**Then tell them what the 4.0 line is โ the honest headline (adapt to the notes file; do NOT overclaim):**
|
|
22
23
|
|
|
@@ -49,8 +50,7 @@ word โ or type `/rvbc`."* If they say yes, follow `rvbc.md` in this same direc
|
|
|
49
50
|
warm heads-up about the ~20s scan).
|
|
50
51
|
|
|
51
52
|
**Honesty rules for this command (same as the product):**
|
|
52
|
-
- If
|
|
53
|
-
you can verify โ never fabricate a highlight.
|
|
53
|
+
- If the installed executable fails, report its failure and do not fabricate a highlight.
|
|
54
54
|
- Never claim a metric ("40% better", "95/100") the release has not independently earned. The self-
|
|
55
55
|
measurement is new and still filling; say so plainly.
|
|
56
56
|
- This is the MAJOR story only. If the user wants the point-release detail, point them at the repo's
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# RuvNet-Brain 4.0 line โ what's new (the major-release highlights)
|
|
2
|
+
|
|
3
|
+
Updated: 2026-08-01
|
|
4
|
+
|
|
5
|
+
> **Source of truth** for the `/whats-new` command and the first-run upgrade message. Curated, honest,
|
|
6
|
+
> major-only โ not the point-release churn. If a claim here isn't true of the shipping build, it does not
|
|
7
|
+
> belong here. The self-measurement claims are deliberately hedged: they are *new and filling*, not
|
|
8
|
+
> *proven*.
|
|
9
|
+
>
|
|
10
|
+
> **VERSION STATUS:** the public release line is now 4.x. Publication does not erase the remaining
|
|
11
|
+
> acceptance obligations: the exact public artifact must still pass the fail-closed release contract
|
|
12
|
+
> through fresh Claude Code and Codex hosts. Anything not proven through that boundary is listed as a
|
|
13
|
+
> limitation, never converted into a capability claim.
|
|
14
|
+
|
|
15
|
+
**One line:** the 4.0 line is where the brain got **honest, legible, fast, and self-measuring** โ and
|
|
16
|
+
it's landing now.
|
|
17
|
+
|
|
18
|
+
## The big things
|
|
19
|
+
|
|
20
|
+
### Release proof is fail-closed
|
|
21
|
+
The 4.0 release path now separates a clean candidate seal from a post-publication seal. Dirty
|
|
22
|
+
lineage, zero/skipped/todo tests, open issues, red or pending exact-SHA workflows, a missing
|
|
23
|
+
`ruvnet-brain` self-RVF store, weak query-deadline margin, missing independent graders,
|
|
24
|
+
host/artifact mismatches, and public-byte drift are release failures rather than warnings.
|
|
25
|
+
`npm run release:proof -- --status --quick` shows the current live blockers.
|
|
26
|
+
|
|
27
|
+
### 1. The Console is the front door
|
|
28
|
+
Type `/rvbc` and your whole RuvNet stack is on one live local page: what's installed, what the AI has
|
|
29
|
+
actually learned from *your* projects (real memories + distilled lessons, drill-down to the verbatim
|
|
30
|
+
cards), which subscription pays for what, and one-click **reversible** fixes for anything stale. New in
|
|
31
|
+
4.0:
|
|
32
|
+
- a plain-English **explainer on every card** (no more guessing what "trust & provenance" means),
|
|
33
|
+
- every suggestion carries its **blast radius** โ *just this project* vs *every project ยท this machine*,
|
|
34
|
+
- **safe on/off checkboxes** that appear *only* where the undo is proven,
|
|
35
|
+
- a **terminal-first install** โ the granular "here's exactly what I'll do, uncheck any of it" flow runs
|
|
36
|
+
in your terminal, where an `npx` user expects it.
|
|
37
|
+
|
|
38
|
+
### 2. It will not lie about your machine
|
|
39
|
+
Every number is measured live from your setup. **"We couldn't check" never renders as "off."** One
|
|
40
|
+
project's state can never leak into another project's view (a real bug 4.0 fixed in the console itself).
|
|
41
|
+
Empty-first, honest-always.
|
|
42
|
+
|
|
43
|
+
### 3. Fast โ and it tells you when it's ready
|
|
44
|
+
The console and tips page paint in **well under a second** (measured, with a QE suite that runs every
|
|
45
|
+
time). On a first scan it shows a **countdown** and then says *"it's live โ take a look at your page,"*
|
|
46
|
+
so you're never staring at a blank screen wondering if it hung.
|
|
47
|
+
|
|
48
|
+
### 4. It measures itself now
|
|
49
|
+
The brain records when it offered help and whether you acted on it โ so over time it can **prove** it's
|
|
50
|
+
improving instead of asserting it. **Honest caveat:** this instrumentation is *new* and has only just
|
|
51
|
+
started collecting. 4.0 is not a claim of "proven better in the field" โ it is the release that makes
|
|
52
|
+
that proof *possible*, and the evidence accrues as you use it.
|
|
53
|
+
|
|
54
|
+
### 5. It learns across your projects
|
|
55
|
+
A lesson proven in one project can be **promoted to your global brain** and applied everywhere โ and it
|
|
56
|
+
now **survives an update** (tested against the real updater, not argued).
|
|
57
|
+
|
|
58
|
+
### 6. Runs on your account, cheapest capable model
|
|
59
|
+
The QE suite and model routing use **your Claude account, not an API key**, at the least-powerful model
|
|
60
|
+
that does the job. Nothing bills silently.
|
|
61
|
+
|
|
62
|
+
### 7. Claude Code and Codex share one active runtime
|
|
63
|
+
Both hosts are wired to the same Stable Spine generation: the MCP search shell, lifecycle hooks,
|
|
64
|
+
skills and update behavior advance as one versioned runtime instead of being installed as unrelated
|
|
65
|
+
copies.
|
|
66
|
+
|
|
67
|
+
### 8. Source grounding is an RVF-native product surface
|
|
68
|
+
The Brain searches per-repository RuVector RVF stores, joins hits to their source passages, and
|
|
69
|
+
returns cited repository paths. Model memory is not accepted as evidence for rUv-stack claims.
|
|
70
|
+
|
|
71
|
+
### 9. Quality and harness workflows are explicit
|
|
72
|
+
Agentic-QE is the testing fleet. Harness scoring evaluates the orchestration layer, and cost-aware
|
|
73
|
+
routing can select cheaper capable models when the required provider access is configured. These are
|
|
74
|
+
named workflows a user can request, not silent substitutes.
|
|
75
|
+
|
|
76
|
+
## What 4.0 deliberately does NOT claim
|
|
77
|
+
Stated up front because overclaiming is the one thing this product cannot do:
|
|
78
|
+
- **Not** "proven X% better" โ the outcome ledger is still filling (see #4).
|
|
79
|
+
- **Not** "fully proactive / anticipatory" โ the brain still mostly speaks when you open the console or
|
|
80
|
+
ask; the in-session, unprompted surface is the next frontier, not a shipped 4.0 guarantee.
|
|
81
|
+
- **Not** independently graded โฅ95 on the exact public artifact. A score is not a release substitute.
|
|
82
|
+
- **Not** fully accepted while any critical exact-artifact, host, retrieval, version-convergence or
|
|
83
|
+
recovery invariant is FAIL, UNKNOWN, skipped or mocked-only.
|
|
84
|
+
|
|
85
|
+
## For upgraders
|
|
86
|
+
On the first real major-version transition, the installer/session experience presents the concise
|
|
87
|
+
highlights once. Run `npx ruvnet-brain --whats-new` at any time to read this full list again, or
|
|
88
|
+
`npx ruvnet-brain --what-changed` to inspect the exact machine footprint and undo path for each piece.
|