ruvnet-brain 4.5.8 โ 4.5.9
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 +3 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/scripts/advocacy-catalog.mjs +1 -0
- package/plugin/scripts/ground-before-write.sh +27 -11
- package/plugin/scripts/grounding-code-projection.mjs +85 -0
- package/scripts/release-qualification-contract.mjs +9 -0
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/bin/install.mjs
CHANGED
|
@@ -461,7 +461,9 @@ function resolveCacheDir() {
|
|
|
461
461
|
);
|
|
462
462
|
info(`brain dir: ${c.bold(cacheDir)}`);
|
|
463
463
|
if (custom) info(`(from your RUVNET_BRAIN_KB override)`);
|
|
464
|
-
|
|
464
|
+
// Activation creates the KB from a validated stage. A placeholder here becomes a false prior
|
|
465
|
+
// generation, which the cleanup proof correctly retains because it has no SOURCE.json.
|
|
466
|
+
fs.mkdirSync(path.dirname(cacheDir), { recursive: true });
|
|
465
467
|
return { cacheDir, isCustom: Boolean(custom) };
|
|
466
468
|
}
|
|
467
469
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.9",
|
|
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": {
|
|
@@ -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 a UserPromptSubmit retrieve-and-inject grounding hook and a PreToolUse write gate that refuses ungrounded rUv-product code until search_ruvnet has been consulted (ADR-0012 / ADR-067).",
|
|
4
|
-
"version": "4.5.
|
|
4
|
+
"version": "4.5.9",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Stuart Kerr"
|
|
7
7
|
},
|
|
@@ -145,6 +145,7 @@ export const INTENTS = Object.freeze([
|
|
|
145
145
|
fit: 'the request is to retrieve by meaning rather than by literal match',
|
|
146
146
|
cues: Object.freeze([
|
|
147
147
|
/\bby meaning\b/,
|
|
148
|
+
/^(?:please\s+)?(?:search|retrieve|find)\s+(?:these|those|my|our|the)\s+(?:docs?|documents?|passages?|chunks?|notes?)\s+by meaning\b/,
|
|
148
149
|
/\bsemantic(ally)?\s+(search|retriev|match|similar)/,
|
|
149
150
|
/\b(instead of|rather than|not just|beyond)\s+(an?\s+)?(exact\s+)?(keywords?|string|substring|literal|grep)/,
|
|
150
151
|
/\bvector\s+(search|database|db|store|index|embedding)/,
|
|
@@ -98,11 +98,10 @@ SKIP_RECENCY=0
|
|
|
98
98
|
[ "${RUVNET_SKIP_GROUNDING_CHECK:-0}" = "1" ] && SKIP_RECENCY=1
|
|
99
99
|
|
|
100
100
|
# This gate is a BLOCKING wall (the #1-failure preventer), so by deliberate design (ADR-0021, and
|
|
101
|
-
# enforced by ground-before-write.test.mjs)
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
# no quotes) and file_path (a truncated path merely fails the extension check โ exit 0, harmless).
|
|
101
|
+
# enforced by ground-before-write.test.mjs) its default refusal depends on no JSON parser. The optional
|
|
102
|
+
# inert-code exemption below can narrow a valid input; a missing helper or any uncertainty leaves the
|
|
103
|
+
# raw product scan intact. The legacy field parser below selects only tool name and code-file path;
|
|
104
|
+
# it never supplies the code text used by the optional projection.
|
|
106
105
|
field() { local re="\"$1\"[[:space:]]*:[[:space:]]*\"([^\"]*)\""; [[ $INPUT =~ $re ]] && printf '%s' "${BASH_REMATCH[1]}"; }
|
|
107
106
|
|
|
108
107
|
# Case-insensitive (4.5): Grok sends `write` / `search_replace`; a case-sensitive match allowed a Grok
|
|
@@ -134,8 +133,8 @@ shopt -s nocasematch 2>/dev/null || true
|
|
|
134
133
|
STAMP_DIR="$HOME/.cache/ruvnet-brain/grounded"
|
|
135
134
|
NOW=$(date +%s 2>/dev/null) || exit 0
|
|
136
135
|
|
|
137
|
-
# Scan
|
|
138
|
-
#
|
|
136
|
+
# Scan raw product terms without a parser; the optional inert-text exemption below may narrow
|
|
137
|
+
# this result, but missing dependencies cannot erase the raw refusal.
|
|
139
138
|
MISSING=""
|
|
140
139
|
SEEN=""
|
|
141
140
|
for t in agentdb metaharness ruvector aidefence agentic-flow agentic-qe ruv-swarm rvf ruflo; do
|
|
@@ -156,10 +155,10 @@ done
|
|
|
156
155
|
# PASSED: a term the model has never grounded is stopped by stage 1 and never reaches here.
|
|
157
156
|
#
|
|
158
157
|
# โโ THE DEPENDENCY CONTRACT, AND WHY THIS DOES NOT BREAK IT โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
159
|
-
# Everything above this
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
158
|
+
# Everything above this marker remains pure bash: the recency wall computes a refusal without
|
|
159
|
+
# node/jq/python (ADR-0021). The optional exemption below can only narrow that raw result after
|
|
160
|
+
# proving an inert mention; absence or uncertainty retains it. The substance stage keeps its
|
|
161
|
+
# separate, explicitly fail-open contradiction contract.
|
|
163
162
|
#
|
|
164
163
|
# The substance stage is different in kind and is allowed one dependency, node, because deciding
|
|
165
164
|
# "does this write contradict the source the brain returned?" requires a real JSON parse of the
|
|
@@ -169,6 +168,23 @@ done
|
|
|
169
168
|
# produce a refusal here is a detector that found a contradiction, which is ADR-055 ยง1.2's
|
|
170
169
|
# "malfunction โ decision" applied to the one stage that has something to malfunction.
|
|
171
170
|
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
171
|
+
# Optional positive exemption (#373), only when a raw product mention exists. A missing helper,
|
|
172
|
+
# node, empty output or lexical uncertainty leaves the pure-bash result unchanged. This stage
|
|
173
|
+
# cannot manufacture a refusal and never changes the raw payload used by the substance wall.
|
|
174
|
+
PROJECTION="$(dirname "${BASH_SOURCE[0]}")/grounding-code-projection.mjs"
|
|
175
|
+
if [ -n "$SEEN" ] && [ -f "$PROJECTION" ] && command -v node >/dev/null 2>&1; then
|
|
176
|
+
PROJECTED=$(printf '%s' "$INPUT" | node "$PROJECTION" 2>/dev/null)
|
|
177
|
+
if [ "$?" = "0" ] && [ -n "$PROJECTED" ]; then
|
|
178
|
+
PROJECTED_MISSING=""; PROJECTED_SEEN=""
|
|
179
|
+
for t in $SEEN; do
|
|
180
|
+
[[ $PROJECTED == *"$t"* ]] || continue
|
|
181
|
+
PROJECTED_SEEN="$PROJECTED_SEEN$t "
|
|
182
|
+
[[ " $MISSING" == *" $t "* ]] && PROJECTED_MISSING="$PROJECTED_MISSING$t "
|
|
183
|
+
done
|
|
184
|
+
MISSING="$PROJECTED_MISSING"; SEEN="$PROJECTED_SEEN"
|
|
185
|
+
fi
|
|
186
|
+
fi
|
|
187
|
+
|
|
172
188
|
if [ -z "$MISSING" ] || [ "$SKIP_RECENCY" = "1" ]; then
|
|
173
189
|
[ -n "$SEEN" ] || exit 0
|
|
174
190
|
SUBSTANCE="$(dirname "${BASH_SOURCE[0]}")/grounding-substance.mjs"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Optional conservative #373 projection. Uncertainty keeps the original raw bash gate.
|
|
2
|
+
// Keep executable strings and paths: mentioning a product in code still requires grounding.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
export function codeWithoutInertText(source, python = false) {
|
|
7
|
+
if (/\r(?!\n)|[\u2028\u2029]/.test(source)) throw new Error('Unsupported line boundary');
|
|
8
|
+
// Template interpolation and Python f-string expressions need a parser, not a guessed lexer.
|
|
9
|
+
if ((!python && source.includes('`')) || (python && /(?:^|[^\w])(?:fr|rf|f)["']/i.test(source))) throw new Error('Interpolation requires original scan');
|
|
10
|
+
if (python) {
|
|
11
|
+
// A different source decoder can turn apparent comments into executable statements.
|
|
12
|
+
for (const line of source.split(/\r?\n/).slice(0, 2)) {
|
|
13
|
+
const cookie = line.match(/^[ \t\f]*#.*?coding[=:][ \t]*([^ \t\r\n]+)/i);
|
|
14
|
+
if (cookie && !/^utf[-_]?8$/i.test(cookie[1])) throw new Error('Unsupported source encoding');
|
|
15
|
+
}
|
|
16
|
+
if (/\\\r?\n/.test(source)) throw new Error('Continuation requires original scan');
|
|
17
|
+
}
|
|
18
|
+
let out = ''; let i = 0;
|
|
19
|
+
while (i < source.length) {
|
|
20
|
+
const c = source[i]; const pair = source.slice(i, i + 2);
|
|
21
|
+
if ((python && c === '#') || (!python && pair === '//')) {
|
|
22
|
+
const end = source.indexOf('\n', i); i = end < 0 ? source.length : end; continue;
|
|
23
|
+
}
|
|
24
|
+
if (!python && pair === '/*') {
|
|
25
|
+
const end = source.indexOf('*/', i + 2); if (end < 0) throw new Error('Incomplete comment');
|
|
26
|
+
out += ' '; i = end + 2; continue;
|
|
27
|
+
}
|
|
28
|
+
if (c === '"' || c === "'" || (!python && c === '`')) {
|
|
29
|
+
const start = i; const triple = python && source.slice(i, i + 3) === c.repeat(3);
|
|
30
|
+
const delimiter = triple ? c.repeat(3) : c;
|
|
31
|
+
i += delimiter.length;
|
|
32
|
+
let closed = false;
|
|
33
|
+
while (i < source.length) {
|
|
34
|
+
if (source[i] === '\\') { i += 2; continue; }
|
|
35
|
+
if (source.slice(i, i + delimiter.length) === delimiter) { i += delimiter.length; closed = true; break; }
|
|
36
|
+
if (!triple && c !== '`' && /[\r\n]/.test(source[i])) throw new Error('Incomplete string');
|
|
37
|
+
i++;
|
|
38
|
+
}
|
|
39
|
+
if (!closed) throw new Error('Incomplete string');
|
|
40
|
+
// Exempt only a leading module docstring before any executable text. Standalone-looking
|
|
41
|
+
// literals inside functions, open expressions or control flow retain the original scan.
|
|
42
|
+
const before = source.slice(source.lastIndexOf('\n', start - 1) + 1, start);
|
|
43
|
+
const endOfLine = source.indexOf('\n', i); const after = source.slice(i, endOfLine < 0 ? source.length : endOfLine);
|
|
44
|
+
const inert = triple && out.trim() === '' && !/\b(?:exec|eval|compile|__doc__)\b/.test(source) && /^[ \t]*$/.test(before) && /^[ \t\r]*(?:#.*)?$/.test(after);
|
|
45
|
+
out += inert ? ' ' : source.slice(start, i); continue;
|
|
46
|
+
}
|
|
47
|
+
// Regex literals, heredocs, language-specific nested comments etc. are not guessed.
|
|
48
|
+
if (!python && c === '/') throw new Error('Ambiguous slash');
|
|
49
|
+
if (!python && pair === '<' + '<') throw new Error('Unsupported heredoc');
|
|
50
|
+
out += c; i++;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function projectGroundingInput(raw) {
|
|
56
|
+
const event = JSON.parse(raw); const input = event.tool_input ?? event.toolInput;
|
|
57
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new Error('Unknown write input');
|
|
58
|
+
const file = input.file_path; if (typeof file !== 'string') throw new Error('Unknown path');
|
|
59
|
+
// Limited lexical scope; other languages retain their existing strict gate.
|
|
60
|
+
if (!/\.(?:py|[cm]?js|jsx|ts|tsx)$/.test(file)) throw new Error('Unsupported language');
|
|
61
|
+
// Partial edits have no enclosing lexical context. Only complete Write or a verified
|
|
62
|
+
// single Add File patch may receive an exemption; never reconstruct user files here.
|
|
63
|
+
const tool = event.tool_name ?? event.toolName;
|
|
64
|
+
let code;
|
|
65
|
+
if (tool === 'Write' && typeof input.content === 'string' && !Object.hasOwn(input, 'edits')) {
|
|
66
|
+
code = input.content;
|
|
67
|
+
} else if (tool === 'Edit' && typeof input.new_string === 'string' && input.new_string.startsWith('*** Begin Patch')) {
|
|
68
|
+
const lines = input.new_string.trimEnd().split(/\r?\n/);
|
|
69
|
+
if (lines[0] !== '*** Begin Patch' || lines[1] !== `*** Add File: ${file}`
|
|
70
|
+
|| lines.at(-1) !== '*** End Patch' || !lines.slice(2, -1).every((line) => line.startsWith('+'))) {
|
|
71
|
+
throw new Error('Ambiguous patch');
|
|
72
|
+
}
|
|
73
|
+
code = lines.slice(2, -1).map((line) => line.slice(1)).join('\n');
|
|
74
|
+
} else throw new Error('Partial or unknown write context');
|
|
75
|
+
const projectedCode = codeWithoutInertText(code, file.endsWith('.py'));
|
|
76
|
+
// Never exempt a product-owned path. Preserve managed-store paths even without a product name.
|
|
77
|
+
const projection = `${file}\n${projectedCode}`;
|
|
78
|
+
if (/\.swarm|(?:agentdb-)?memory\.db|memory_entries/i.test(projection)) throw new Error('Managed memory indicators need original scan');
|
|
79
|
+
return projection;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
83
|
+
try { process.stdout.write(projectGroundingInput(fs.readFileSync(0, 'utf8'))); }
|
|
84
|
+
catch { process.exitCode = 1; } // A failed exemption leaves the original guard in force.
|
|
85
|
+
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
// Reviewed stabilization release boundaries. Legacy tests remain developer diagnostics.
|
|
2
2
|
export const RELEASE_REQUIREMENTS = Object.freeze({
|
|
3
3
|
"source": [
|
|
4
|
+
{
|
|
5
|
+
"id": "bounded-advocacy-and-write-grounding",
|
|
6
|
+
"reason": "Explicit document meaning requests retain corroboration; literal searches stay silent; POSIX complete-write exemptions preserve executable and managed-store grounding",
|
|
7
|
+
"files": ["tests/unit/advocacy-route.test.mjs", "tests/unit/advocacy-catalog.test.mjs", "tests/unit/card-lane.test.mjs"],
|
|
8
|
+
"platformFiles": {
|
|
9
|
+
"linux": ["tests/unit/advocacy-route-budget.test.mjs", "tests/unit/ground-before-write.test.mjs", "tests/unit/grounding-code-projection.test.mjs"],
|
|
10
|
+
"macos": ["tests/unit/advocacy-route-budget.test.mjs", "tests/unit/ground-before-write.test.mjs", "tests/unit/grounding-code-projection.test.mjs"]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
4
13
|
{
|
|
5
14
|
"id": "owned-startup-execution-evidence",
|
|
6
15
|
"reason": "Opt-in native execution and private stage diagnostics bind released source and preserve unknown convergence and incomplete cleanup boundaries",
|