ruvnet-brain 4.3.15 → 4.3.16
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
CHANGED
|
@@ -7,7 +7,7 @@ Created: 2026-06-29 22:36:38 EDT
|
|
|
7
7
|
|
|
8
8
|
# 🧠 RuvNet Brain
|
|
9
9
|
|
|
10
|
-
### 🧠 RuvNet Brain — [](https://github.com/stuinfla/ruvnet-brain/blob/main/plugin/.claude-plugin/plugin.json)
|
|
11
11
|
|
|
12
12
|
**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.**
|
|
13
13
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.16",
|
|
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 77 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.3.
|
|
4
|
+
"version": "4.3.16",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Stuart Kerr"
|
|
7
7
|
},
|
|
@@ -106,6 +106,11 @@ verification → at most one revision. Both hosts design the ADR, DDD and intend
|
|
|
106
106
|
Agentic-QE then generates and executes the measurable test artifacts. A host merely completing is
|
|
107
107
|
not an accepted outcome.
|
|
108
108
|
|
|
109
|
+
When the duel returns `learningPersistenceRequest`, pass that request to Ruflo's structured
|
|
110
|
+
`memory_store` tool and verify the exact returned key. The coordinator never starts a second Ruflo
|
|
111
|
+
memory driver itself; without an MCP-aware caller it leaves `learningPersisted: false` and prints
|
|
112
|
+
the pending request so the completed duel is not mistaken for a persisted learning event.
|
|
113
|
+
|
|
109
114
|
Subscription-only is a billing boundary: verify with `claude auth status --json` and
|
|
110
115
|
`codex login status`, strip provider API-key variables from both child processes, and never fall back
|
|
111
116
|
to an API when a subscription is absent or capacity-limited. Subscription use consumes plan
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
|
-
import { spawn
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { probeSubscriptionHosts, subscriptionOnlyEnv } from './subscription-hosts.mjs';
|
|
7
7
|
|
|
@@ -67,15 +67,34 @@ function parseHostValue(host, stdout) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function spawnHost(binary, args, options) {
|
|
70
|
+
function spawnHost(binary, args, options, input = '') {
|
|
71
71
|
return new Promise((resolve) => {
|
|
72
72
|
const child = spawn(binary, args, options);
|
|
73
73
|
let stdout = '';
|
|
74
74
|
let stderr = '';
|
|
75
|
+
let inputError = null;
|
|
76
|
+
let settled = false;
|
|
77
|
+
const finish = (result) => {
|
|
78
|
+
if (settled) return;
|
|
79
|
+
settled = true;
|
|
80
|
+
resolve(result);
|
|
81
|
+
};
|
|
75
82
|
child.stdout.on('data', (chunk) => { stdout += chunk; });
|
|
76
83
|
child.stderr.on('data', (chunk) => { stderr += chunk; });
|
|
77
|
-
child.on('error', (error) =>
|
|
78
|
-
|
|
84
|
+
child.stdin.on('error', (error) => {
|
|
85
|
+
inputError = error;
|
|
86
|
+
stderr += `${stderr ? '\n' : ''}${error.message}`;
|
|
87
|
+
try { child.kill(); } catch { /* child may already be gone */ }
|
|
88
|
+
});
|
|
89
|
+
child.on('error', (error) => finish({ status: null, stdout, stderr: error.message, error }));
|
|
90
|
+
try {
|
|
91
|
+
child.stdin.end(input);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
inputError = error;
|
|
94
|
+
stderr += `${stderr ? '\n' : ''}${error.message}`;
|
|
95
|
+
try { child.kill(); } catch { /* child may already be gone */ }
|
|
96
|
+
}
|
|
97
|
+
child.on('close', (status) => finish({ status, stdout, stderr, error: inputError }));
|
|
79
98
|
});
|
|
80
99
|
}
|
|
81
100
|
|
|
@@ -87,20 +106,21 @@ export async function runSubscriptionHost(host, stage, payload, { cwd = process.
|
|
|
87
106
|
binary: 'claude',
|
|
88
107
|
args: [
|
|
89
108
|
'-p', '--output-format', 'json', '--permission-mode', 'plan',
|
|
90
|
-
'--tools', 'Read,Grep,Glob', '--no-session-persistence', '--effort', 'high',
|
|
109
|
+
'--tools', 'Read,Grep,Glob', '--no-session-persistence', '--effort', 'high',
|
|
91
110
|
],
|
|
92
111
|
}
|
|
93
112
|
: {
|
|
94
113
|
binary: 'codex',
|
|
95
114
|
args: [
|
|
96
115
|
'exec', '--ephemeral', '--sandbox', 'read-only', '--color', 'never', '--json',
|
|
97
|
-
'-m', 'gpt-5.6-sol', '-c', 'model_reasoning_effort="high"',
|
|
116
|
+
'-m', 'gpt-5.6-sol', '-c', 'model_reasoning_effort="high"',
|
|
98
117
|
],
|
|
99
118
|
};
|
|
100
|
-
const result = await spawnHost(command.binary, command.args, { cwd, env, stdio: ['
|
|
119
|
+
const result = await spawnHost(command.binary, command.args, { cwd, env, stdio: ['pipe', 'pipe', 'pipe'] }, prompt);
|
|
101
120
|
if (result.status !== 0) {
|
|
102
121
|
return {
|
|
103
122
|
ok: false,
|
|
123
|
+
error: result.stderr || `host exited without a status (${result.status})`,
|
|
104
124
|
reason: /limit|quota|capacity|usage/i.test(result.stderr)
|
|
105
125
|
? 'capacity-limited'
|
|
106
126
|
: 'host-failed',
|
|
@@ -109,11 +129,7 @@ export async function runSubscriptionHost(host, stage, payload, { cwd = process.
|
|
|
109
129
|
return { ok: true, value: parseHostValue(host, result.stdout) };
|
|
110
130
|
}
|
|
111
131
|
|
|
112
|
-
export
|
|
113
|
-
cwd = process.cwd(),
|
|
114
|
-
now = Date.now,
|
|
115
|
-
run = spawnSync,
|
|
116
|
-
} = {}) {
|
|
132
|
+
export function deliberationMemoryStoreRequest(receipt, { now = Date.now } = {}) {
|
|
117
133
|
const recordedAt = now();
|
|
118
134
|
const value = {
|
|
119
135
|
protocol: receipt.protocol,
|
|
@@ -125,21 +141,28 @@ export async function persistDeliberationReceipt(receipt, {
|
|
|
125
141
|
recordedAt: new Date(recordedAt).toISOString(),
|
|
126
142
|
};
|
|
127
143
|
const key = `dual-deliberation-${recordedAt}-${receipt.taskHash.slice(0, 12)}`;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
'
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
return {
|
|
145
|
+
tool: 'memory_store',
|
|
146
|
+
name: 'memory_store',
|
|
147
|
+
arguments: { key, value: JSON.stringify(value), namespace: 'ruvnet-brain' },
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function persistenceProof(proof, key) {
|
|
152
|
+
return proof === true || (proof?.stored === true && proof?.verified === true && proof?.key === key);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function persistDeliberationReceipt(receipt, {
|
|
156
|
+
now = Date.now,
|
|
157
|
+
memoryStore,
|
|
158
|
+
} = {}) {
|
|
159
|
+
const request = deliberationMemoryStoreRequest(receipt, { now });
|
|
160
|
+
if (typeof memoryStore !== 'function') return request;
|
|
161
|
+
try {
|
|
162
|
+
return persistenceProof(await memoryStore(request), request.arguments.key);
|
|
163
|
+
} catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
143
166
|
}
|
|
144
167
|
|
|
145
168
|
function missingHosts(probes) {
|
|
@@ -164,7 +187,6 @@ export async function deliberate(task, options = {}) {
|
|
|
164
187
|
runSubscriptionHost(host, stage, payload, { cwd: options.cwd })
|
|
165
188
|
));
|
|
166
189
|
const cwd = options.cwd ?? process.cwd();
|
|
167
|
-
const persist = options.persist ?? ((receipt) => persistDeliberationReceipt(receipt, { cwd }));
|
|
168
190
|
const eligibleHosts = HOSTS.filter((host) => probes[hostKey(host)]?.eligible);
|
|
169
191
|
|
|
170
192
|
if (eligibleHosts.length === 0) {
|
|
@@ -247,7 +269,18 @@ export async function deliberate(task, options = {}) {
|
|
|
247
269
|
roles,
|
|
248
270
|
accepted,
|
|
249
271
|
};
|
|
250
|
-
const
|
|
272
|
+
const learningPersistenceRequest = accepted
|
|
273
|
+
? deliberationMemoryStoreRequest(receipt, { now: options.now ?? Date.now })
|
|
274
|
+
: undefined;
|
|
275
|
+
let learningPersisted = false;
|
|
276
|
+
if (accepted && typeof options.persist === 'function') {
|
|
277
|
+
try {
|
|
278
|
+
const persisted = await options.persist(learningPersistenceRequest, receipt);
|
|
279
|
+
learningPersisted = persistenceProof(persisted, learningPersistenceRequest.arguments.key);
|
|
280
|
+
} catch {
|
|
281
|
+
learningPersisted = false;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
251
284
|
return {
|
|
252
285
|
status: accepted ? 'accepted' : 'unresolved',
|
|
253
286
|
dual: true,
|
|
@@ -256,6 +289,7 @@ export async function deliberate(task, options = {}) {
|
|
|
256
289
|
verification: verification.ok ? verification.value : undefined,
|
|
257
290
|
verifiedOutcome: accepted,
|
|
258
291
|
learningPersisted,
|
|
292
|
+
...(learningPersistenceRequest ? { learningPersistenceRequest } : {}),
|
|
259
293
|
};
|
|
260
294
|
}
|
|
261
295
|
|