ruvnet-brain 4.5.13 → 4.5.14
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/bin/install.mjs
CHANGED
|
@@ -2140,8 +2140,18 @@ export function codexSessionSafety(status) {
|
|
|
2140
2140
|
};
|
|
2141
2141
|
}
|
|
2142
2142
|
|
|
2143
|
+
function codexAdministrativeProbeBinary() {
|
|
2144
|
+
if (process.env.CODEX_BIN) return process.env.CODEX_BIN;
|
|
2145
|
+
try {
|
|
2146
|
+
const brainHome = process.env.RUVNET_BRAIN_HOME || path.join(os.homedir(), '.cache', 'ruvnet-brain');
|
|
2147
|
+
const configured = JSON.parse(fs.readFileSync(path.join(brainHome, 'model-routing', 'terminal-launcher-config.json'), 'utf8'));
|
|
2148
|
+
if (typeof configured.realCodex === 'string' && path.isAbsolute(configured.realCodex)) return configured.realCodex;
|
|
2149
|
+
} catch { /* absent or malformed configuration retains the ordinary bounded PATH probe */ }
|
|
2150
|
+
return 'codex';
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2143
2153
|
function codexHooksList({
|
|
2144
|
-
codexBin =
|
|
2154
|
+
codexBin = codexAdministrativeProbeBinary(),
|
|
2145
2155
|
codexHome = codexHomeDir(),
|
|
2146
2156
|
cwd = process.cwd(),
|
|
2147
2157
|
timeoutMs = 8_000,
|
|
@@ -2997,13 +3007,7 @@ async function doctorRun({ json }) {
|
|
|
2997
3007
|
hostConvergence = classifyHostConvergence(recorded);
|
|
2998
3008
|
const codex = recorded.hosts?.codex;
|
|
2999
3009
|
if (codex?.state === 'ready' && codex.restartRequired === true && codex.restartScope === 'unproven') {
|
|
3000
|
-
|
|
3001
|
-
if (!process.env.CODEX_BIN) {
|
|
3002
|
-
try {
|
|
3003
|
-
const configured = JSON.parse(fs.readFileSync(path.join(path.dirname(convergencePath), 'model-routing', 'terminal-launcher-config.json'), 'utf8'));
|
|
3004
|
-
if (typeof configured.realCodex === 'string' && path.isAbsolute(configured.realCodex)) binary = configured.realCodex;
|
|
3005
|
-
} catch { /* native PATH resolution remains bounded and fail closed */ }
|
|
3006
|
-
}
|
|
3010
|
+
const binary = codexAdministrativeProbeBinary();
|
|
3007
3011
|
const fresh = await probeFreshCodexDeclarations({ binary, codexHome: codexHomeDir(), cwd: process.cwd(),
|
|
3008
3012
|
releasedPluginRoot: path.join(REPO_ROOT, 'plugin'), expectedVersion: PACKAGE_VERSION });
|
|
3009
3013
|
hostConvergence = reconcileFreshCodexDeclarations(recorded, fresh);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-brain",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.14",
|
|
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 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.14",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Stuart Kerr"
|
|
7
7
|
},
|
|
@@ -30,19 +30,22 @@ function verifyRefs(refs) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/**
|
|
33
|
+
/** Actual native bytes only; large histories use a source-bound native compaction projection. */
|
|
34
34
|
export async function captureNativeParentContext({ harness, sessionId, env = process.env,
|
|
35
35
|
evidenceRoot = path.join(env.HOME || os.homedir(), '.cache/ruvnet-brain/model-routing/parent-context'),
|
|
36
|
-
observeCodex } = {}) {
|
|
36
|
+
observeCodex, deadline = Infinity, signal } = {}) {
|
|
37
37
|
requireValue(process.platform !== 'win32', 'private native parent transcript capture unsupported on Windows; ACL proof unavailable');
|
|
38
38
|
if (!sessionId) return [];
|
|
39
39
|
requireValue(/^[a-f0-9-]{36}$/i.test(sessionId) && ['codex', 'claude-code'].includes(harness), 'native parent identity required');
|
|
40
|
-
let source, expected;
|
|
40
|
+
let source, expected, sourceBound, observedTurns, observedBytes;
|
|
41
41
|
if (harness === 'codex') {
|
|
42
42
|
const observe = observeCodex ?? (await import('./model-routing-execution-adapters.mjs')).readCodexWorkerObservation;
|
|
43
|
-
const observed = observe(sessionId, { home: env.CODEX_HOME || path.join(env.HOME || os.homedir(), '.codex'), allowHistory: true });
|
|
43
|
+
const observed = observe(sessionId, { home: env.CODEX_HOME || path.join(env.HOME || os.homedir(), '.codex'), allowHistory: true, deadline, signal });
|
|
44
44
|
requireValue(observed?.sessionId === sessionId && HASH.test(observed.evidence?.sha256 || ''), 'actual Codex parent evidence unproven');
|
|
45
|
-
source = observed.evidence.path; expected = observed.evidence.sha256;
|
|
45
|
+
source = observed.evidence.path; expected = observed.evidence.sha256; sourceBound = observed.evidence.sourceBound;
|
|
46
|
+
observedTurns = observed.turnCount; observedBytes = observed.evidence.byteLength;
|
|
47
|
+
const nativeHome = fs.realpathSync(env.CODEX_HOME || path.join(env.HOME || os.homedir(), '.codex'));
|
|
48
|
+
requireValue(source.startsWith(path.join(nativeHome, 'sessions') + path.sep), 'parent evidence escaped native session home');
|
|
46
49
|
} else {
|
|
47
50
|
const projects = path.join(env.CLAUDE_CONFIG_DIR || path.join(env.HOME || os.homedir(), '.claude'), 'projects');
|
|
48
51
|
const matches = [];
|
|
@@ -57,14 +60,54 @@ export async function captureNativeParentContext({ harness, sessionId, env = pro
|
|
|
57
60
|
requireValue(path.isAbsolute(source || '') && fs.realpathSync(source) === source, 'canonical native parent transcript required');
|
|
58
61
|
const fd = fs.openSync(source, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW); let bytes;
|
|
59
62
|
try {
|
|
60
|
-
const before = fs.fstatSync(fd);
|
|
61
|
-
requireValue(before.isFile() && before.uid === process.getuid
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
const before = fs.fstatSync(fd, { bigint: true }), limit = 16 * 1024 * 1024;
|
|
64
|
+
requireValue(before.isFile() && before.uid === BigInt(process.getuid()), 'owned bounded parent transcript required');
|
|
65
|
+
const live = () => requireValue(!signal?.aborted && Date.now() < deadline, 'parent capture cancelled or expired'); live();
|
|
66
|
+
if (before.size <= BigInt(limit)) {
|
|
67
|
+
sourceBound = undefined; bytes = Buffer.alloc(Number(before.size)); let offset = 0;
|
|
68
|
+
while (offset < bytes.length) {
|
|
69
|
+
live(); const count = fs.readSync(fd, bytes, offset, Math.min(256 * 1024, bytes.length - offset), offset);
|
|
70
|
+
requireValue(count > 0, 'parent transcript truncated while captured'); offset += count;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
requireValue(harness === 'codex' && sourceBound?.kind === 'native-compaction-projection'
|
|
75
|
+
&& sourceBound.nativeSessionId === sessionId && sourceBound.sourceSha256 === expected
|
|
76
|
+
&& sourceBound.sourceBytes === Number(before.size) && sourceBound.sourceBytes === observedBytes
|
|
77
|
+
&& sourceBound.fullTurnCount === observedTurns && sourceBound.omittedHistoryPrefix === true
|
|
78
|
+
&& Number.isSafeInteger(sourceBound.fullTurnCount) && sourceBound.fullTurnCount > 0
|
|
79
|
+
&& Array.isArray(sourceBound.ranges) && sourceBound.ranges.length >= 2 && sourceBound.ranges.length <= 3,
|
|
80
|
+
'bounded native compaction provenance required');
|
|
81
|
+
let total = 0, priorEnd = 0;
|
|
82
|
+
for (const range of sourceBound.ranges) {
|
|
83
|
+
requireValue(Number.isSafeInteger(range.offset) && range.offset >= priorEnd && Number.isSafeInteger(range.bytes)
|
|
84
|
+
&& range.bytes > 0 && range.offset + range.bytes <= Number(before.size), 'unsafe native projection range');
|
|
85
|
+
priorEnd = range.offset + range.bytes; total += range.bytes;
|
|
86
|
+
}
|
|
87
|
+
requireValue(sourceBound.ranges[0].offset === 0 && priorEnd === Number(before.size) && total <= limit, 'native projection exceeded bound');
|
|
88
|
+
const hash = crypto.createHash('sha256'), buffer = Buffer.alloc(256 * 1024), parts = []; let offset = 0;
|
|
89
|
+
while (offset < Number(before.size)) {
|
|
90
|
+
live(); const count = fs.readSync(fd, buffer, 0, Math.min(buffer.length, Number(before.size) - offset), offset);
|
|
91
|
+
requireValue(count > 0, 'parent transcript truncated while captured'); hash.update(buffer.subarray(0, count));
|
|
92
|
+
for (const range of sourceBound.ranges) {
|
|
93
|
+
const start = Math.max(offset, range.offset), end = Math.min(offset + count, range.offset + range.bytes);
|
|
94
|
+
if (end > start) parts.push(Buffer.from(buffer.subarray(start - offset, end - offset)));
|
|
95
|
+
}
|
|
96
|
+
offset += count;
|
|
97
|
+
}
|
|
98
|
+
requireValue(hash.digest('hex') === expected, 'parent transcript evidence changed'); bytes = Buffer.concat(parts, total);
|
|
99
|
+
const rows = new TextDecoder('utf-8', { fatal: true }).decode(bytes).trim().split('\n').map(line => JSON.parse(line));
|
|
100
|
+
requireValue(rows[0]?.type === 'session_meta' && rows[0].payload?.id === sessionId && rows.filter(row => row.type === 'session_meta').length === 1
|
|
101
|
+
&& rows.some(row => row.type === 'compacted' && Array.isArray(row.payload?.replacement_history)), 'native projection provenance mismatch');
|
|
102
|
+
sourceBound = { kind: sourceBound.kind, nativeSessionId: sessionId, sourceSha256: expected, sourceBytes: Number(before.size),
|
|
103
|
+
fullTurnCount: sourceBound.fullTurnCount, omittedHistoryPrefix: true, ranges: sourceBound.ranges, nativeHistoryMutated: false };
|
|
104
|
+
}
|
|
105
|
+
const after = fs.fstatSync(fd, { bigint: true }), current = fs.lstatSync(source, { bigint: true });
|
|
106
|
+
requireValue(['dev', 'ino', 'size', 'mtimeNs', 'ctimeNs'].every(key => before[key] === after[key] && after[key] === current[key])
|
|
107
|
+
&& !current.isSymbolicLink(), 'parent transcript changed while captured'); live();
|
|
65
108
|
} finally { fs.closeSync(fd); }
|
|
66
109
|
const digest = sha(bytes);
|
|
67
|
-
requireValue(bytes.length > 0 && (!expected || digest === expected), 'parent transcript evidence changed');
|
|
110
|
+
requireValue(bytes.length > 0 && (!expected || sourceBound || digest === expected), 'parent transcript evidence changed');
|
|
68
111
|
if (harness === 'claude-code') {
|
|
69
112
|
const rows = bytes.toString('utf8').split('\n').filter(Boolean).map(line => JSON.parse(line));
|
|
70
113
|
requireValue(rows.some(row => row.sessionId === sessionId), 'actual Claude transcript session identity missing');
|
|
@@ -77,7 +120,7 @@ export async function captureNativeParentContext({ harness, sessionId, env = pro
|
|
|
77
120
|
const file = path.join(directory, `${sessionId}.jsonl`);
|
|
78
121
|
const output = fs.openSync(file, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_NOFOLLOW, 0o600);
|
|
79
122
|
try { fs.writeFileSync(output, bytes); fs.fsyncSync(output); } finally { fs.closeSync(output); }
|
|
80
|
-
return [{ path: file, digest }];
|
|
123
|
+
return [{ path: file, digest, ...(sourceBound ? { sourceBound } : {}) }];
|
|
81
124
|
}
|
|
82
125
|
|
|
83
126
|
async function service() {
|
|
@@ -264,7 +307,7 @@ export async function runManagedPrompt({ originalPrompt, prompt = originalPrompt
|
|
|
264
307
|
}
|
|
265
308
|
if (!contextRefs.length && (retainedContext.sessionId || retainedContext.threadId)) {
|
|
266
309
|
contextRefs = await bounded(() => captureContext({ harness, sessionId: retainedContext.sessionId ?? retainedContext.threadId,
|
|
267
|
-
env: primaryOptions.env ?? process.env }));
|
|
310
|
+
env: primaryOptions.env ?? process.env, deadline, signal: combined }));
|
|
268
311
|
requireValue(contextRefs.length > 0, 'existing parent transcript required');
|
|
269
312
|
}
|
|
270
313
|
requireValue(original.length <= 120000, 'substantive request exceeds bounded completion-frame input');
|
|
@@ -18,36 +18,93 @@ export function nativeWorkflowBinaries(home = os.homedir()) {
|
|
|
18
18
|
return { claude: config.realClaude, codex: config.realCodex };
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export function readCodexWorkerObservation(sessionId, { home = process.env.CODEX_HOME || path.join(os.homedir(), '.codex'), now = Date.now(), expectedPriorTurns, evidencePath, allowHistory = false } = {}) {
|
|
21
|
+
export function readCodexWorkerObservation(sessionId, { home = process.env.CODEX_HOME || path.join(os.homedir(), '.codex'), now = Date.now(), expectedPriorTurns, evidencePath, expectedPrefix, allowHistory = false, deadline = Infinity, signal } = {}) {
|
|
22
22
|
if (!/^[a-f0-9-]{36}$/.test(sessionId || '')) throw blocked('Native worker session identity missing');
|
|
23
23
|
const matches = [];
|
|
24
24
|
const directories = [];
|
|
25
|
-
const base = path.join(home, 'sessions');
|
|
26
|
-
if (evidencePath)
|
|
25
|
+
const base = path.join(fs.existsSync(home) ? fs.realpathSync(home) : home, 'sessions');
|
|
26
|
+
if (evidencePath) {
|
|
27
|
+
const directory = fs.realpathSync(path.dirname(evidencePath));
|
|
28
|
+
if (!directory.startsWith(base + path.sep)) throw blocked('Native evidence escaped its session home');
|
|
29
|
+
evidencePath = path.join(directory, path.basename(evidencePath)); directories.push(directory);
|
|
30
|
+
}
|
|
27
31
|
else if ((expectedPriorTurns !== undefined || allowHistory) && fs.existsSync(base)) {
|
|
28
32
|
for (const year of fs.readdirSync(base)) if (/^\d{4}$/.test(year))
|
|
29
33
|
for (const month of fs.readdirSync(path.join(base, year))) if (/^\d{2}$/.test(month))
|
|
30
34
|
for (const day of fs.readdirSync(path.join(base, year, month))) if (/^\d{2}$/.test(day)) directories.push(path.join(base, year, month, day));
|
|
31
35
|
} else for (const offset of [0, 86400000]) {
|
|
32
36
|
const date = new Date(now - offset).toISOString().slice(0, 10).split('-');
|
|
33
|
-
directories.push(path.join(
|
|
37
|
+
directories.push(path.join(base, ...date));
|
|
34
38
|
}
|
|
35
39
|
for (const directory of new Set(directories)) {
|
|
36
40
|
if (!fs.existsSync(directory)) continue;
|
|
37
41
|
for (const name of fs.readdirSync(directory)) {
|
|
38
42
|
if (!name.endsWith(`-${sessionId}.jsonl`)) continue;
|
|
39
43
|
const file = path.join(directory, name), stat = fs.lstatSync(file);
|
|
40
|
-
if (!stat.isFile() || stat.isSymbolicLink() ||
|
|
41
|
-
matches.push({ file
|
|
44
|
+
if (!stat.isFile() || stat.isSymbolicLink() || fs.realpathSync(file) !== file || process.getuid && stat.uid !== process.getuid()) throw blocked('Unsafe native worker evidence file');
|
|
45
|
+
if (!evidencePath || evidencePath === file) matches.push({ file });
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
if (matches.length !== 1) throw blocked('Exact native worker rollout unavailable or ambiguous');
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
const file = matches[0].file, fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
50
|
+
const limit = 16 * 1024 * 1024, decoder = new TextDecoder('utf-8', { fatal: true }), hash = crypto.createHash('sha256');
|
|
51
|
+
const prefix = expectedPrefix && crypto.createHash('sha256'), buffer = Buffer.alloc(256 * 1024);
|
|
52
|
+
let before, offset = 0, rowOffset = 0, rowBytes = 0, parts = [], context, contextRange, meta, compact, turnCount = 0, metaCount = 0;
|
|
53
|
+
const live = () => { if (signal?.aborted || Date.now() >= deadline) throw blocked('Native evidence capture cancelled or expired'); };
|
|
54
|
+
const consume = () => {
|
|
55
|
+
let row;
|
|
56
|
+
try { row = JSON.parse(decoder.decode(Buffer.concat(parts, rowBytes))); } catch { throw blocked('Malformed native evidence record or UTF-8'); }
|
|
57
|
+
if (!row || typeof row !== 'object' || typeof row.type !== 'string') throw blocked('Malformed native evidence record');
|
|
58
|
+
const range = { offset: rowOffset, bytes: rowBytes };
|
|
59
|
+
if (row.type === 'session_meta') { metaCount++; meta = { ...range, id: row.payload?.id }; }
|
|
60
|
+
if (row.type === 'turn_context') { turnCount++; context = row.payload; contextRange = range; }
|
|
61
|
+
if (row.type === 'compacted') {
|
|
62
|
+
if (!Array.isArray(row.payload?.replacement_history) || !row.payload.replacement_history.length) throw blocked('Native compaction provenance unavailable');
|
|
63
|
+
compact = range;
|
|
64
|
+
}
|
|
65
|
+
rowOffset += rowBytes; rowBytes = 0; parts = [];
|
|
66
|
+
};
|
|
67
|
+
try {
|
|
68
|
+
before = fs.fstatSync(fd, { bigint: true });
|
|
69
|
+
if (!before.isFile() || process.getuid && before.uid !== BigInt(process.getuid()) || before.size > BigInt(Number.MAX_SAFE_INTEGER)
|
|
70
|
+
|| !process.getuid && before.size > BigInt(limit)) throw blocked('Unsafe native worker evidence file');
|
|
71
|
+
if (expectedPrefix && (!Number.isSafeInteger(expectedPrefix.bytes) || expectedPrefix.bytes < 0 || expectedPrefix.bytes > Number(before.size)
|
|
72
|
+
|| !/^[a-f0-9]{64}$/.test(expectedPrefix.sha256 || ''))) throw blocked('Native history prefix changed');
|
|
73
|
+
while (offset < Number(before.size)) {
|
|
74
|
+
live(); const count = fs.readSync(fd, buffer, 0, Math.min(buffer.length, Number(before.size) - offset), offset);
|
|
75
|
+
if (!count) throw blocked('Native evidence truncated during capture');
|
|
76
|
+
hash.update(buffer.subarray(0, count));
|
|
77
|
+
if (prefix && offset < expectedPrefix.bytes) prefix.update(buffer.subarray(0, Math.min(count, expectedPrefix.bytes - offset)));
|
|
78
|
+
let start = 0;
|
|
79
|
+
while (start < count) {
|
|
80
|
+
const newline = buffer.indexOf(10, start), end = newline >= start && newline < count ? newline + 1 : count;
|
|
81
|
+
const part = Buffer.from(buffer.subarray(start, end)); rowBytes += part.length;
|
|
82
|
+
if (rowBytes > limit) throw blocked('Native evidence record exceeded bound');
|
|
83
|
+
parts.push(part); if (end <= count && buffer[end - 1] === 10) consume(); start = end;
|
|
84
|
+
}
|
|
85
|
+
offset += count;
|
|
86
|
+
}
|
|
87
|
+
if (rowBytes) { if (Number(before.size) > limit) throw blocked('Partial native evidence terminal record'); consume(); }
|
|
88
|
+
const after = fs.fstatSync(fd, { bigint: true }), current = fs.lstatSync(file, { bigint: true });
|
|
89
|
+
if (['dev', 'ino', 'size', 'mtimeNs', 'ctimeNs'].some(key => before[key] !== after[key] || after[key] !== current[key]) || current.isSymbolicLink()) throw blocked('Native evidence changed during capture');
|
|
90
|
+
live();
|
|
91
|
+
} finally { fs.closeSync(fd); }
|
|
92
|
+
if (prefix && prefix.digest('hex') !== expectedPrefix.sha256) throw blocked('Native history prefix changed');
|
|
93
|
+
if (!turnCount || !context || !allowHistory && turnCount !== (expectedPriorTurns === undefined ? 1 : expectedPriorTurns + 1)) throw blocked('Native worker has unexpected turn history');
|
|
94
|
+
const sha256 = hash.digest('hex'), bytes = Number(before.size);
|
|
95
|
+
if (metaCount > 1 || meta && meta.id !== sessionId) throw blocked('Native history session provenance mismatch');
|
|
96
|
+
let sourceBound;
|
|
97
|
+
if (bytes > limit) {
|
|
98
|
+
if (metaCount !== 1 || meta?.id !== sessionId) throw blocked('Native history session provenance mismatch');
|
|
99
|
+
if (compact) {
|
|
100
|
+
const ranges = [{ offset: meta.offset, bytes: meta.bytes }, ...(contextRange.offset < compact.offset ? [contextRange] : []), { offset: compact.offset, bytes: bytes - compact.offset }];
|
|
101
|
+
if (ranges.some((range, index) => index && range.offset < ranges[index - 1].offset + ranges[index - 1].bytes)) throw blocked('Native projection provenance overlaps');
|
|
102
|
+
sourceBound = { kind: 'native-compaction-projection', nativeSessionId: sessionId, sourceSha256: sha256, sourceBytes: bytes,
|
|
103
|
+
fullTurnCount: turnCount, omittedHistoryPrefix: true, ranges };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
49
106
|
return { model: context.model, effort: context.effort, cwd: context.cwd, sandbox: context.sandbox_policy, sessionId,
|
|
50
|
-
turnCount
|
|
107
|
+
turnCount, evidence: { path: file, sha256, type: 'native-turn-context', byteLength: bytes, ...(sourceBound ? { sourceBound } : {}) } };
|
|
51
108
|
}
|
|
52
109
|
|
|
53
110
|
/** Only the installed user-owned Brain search server is projected into isolated native workers. */
|
|
@@ -96,7 +153,8 @@ export async function executeCodexWorkflowWorker({ binary, decision, prompt, cwd
|
|
|
96
153
|
if (performance.now() >= limit || signal?.aborted) throw blocked('Native worker deadline expired during readiness');
|
|
97
154
|
const spec = buildLaunch(decision, { cwd });
|
|
98
155
|
const evidenceHome = clean.CODEX_HOME || path.join(os.homedir(), '.codex');
|
|
99
|
-
const prior = sessionId ? observe(sessionId, { home: evidenceHome, expectedPriorTurns: undefined, allowHistory: true
|
|
156
|
+
const prior = sessionId ? observe(sessionId, { home: evidenceHome, expectedPriorTurns: undefined, allowHistory: true,
|
|
157
|
+
deadline: Date.now() + Math.max(0, limit - performance.now()), signal }) : null;
|
|
100
158
|
const args = sessionId ? ['exec', 'resume', '--ignore-user-config', '--skip-git-repo-check', '--json', '--model', decision.model,
|
|
101
159
|
'-c', `model_reasoning_effort=\"${decision.effort}\"`, '-c', 'model_provider=\"openai\"',
|
|
102
160
|
'-c', 'service_tier=\"default\"', '-c', `sandbox_mode=\"${readOnly ? 'read-only' : 'workspace-write'}\"`,
|
|
@@ -104,6 +162,7 @@ export async function executeCodexWorkflowWorker({ binary, decision, prompt, cwd
|
|
|
104
162
|
: [...spec.args.slice(0, -1), '--skip-git-repo-check', '--json', '--sandbox', readOnly ? 'read-only' : 'workspace-write',
|
|
105
163
|
'-c', 'features.multi_agent=false', '-c', 'features.multi_agent_v2=false', '-'];
|
|
106
164
|
args.splice(args.length - 1, 0, ...codexBrainSearchArguments(clean));
|
|
165
|
+
if (performance.now() >= limit || signal?.aborted) throw blocked('Native worker deadline expired before launch');
|
|
107
166
|
const result = await new Promise((resolve, reject) => {
|
|
108
167
|
const child = launch(binary, args, { cwd, env: clean, shell: false, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
109
168
|
let stdout = '', stderr = '', finished = false, timer, killTimer, cancelled = false, cancelReason;
|
|
@@ -140,7 +199,9 @@ export async function executeCodexWorkflowWorker({ binary, decision, prompt, cwd
|
|
|
140
199
|
throw blocked('Native Codex turn did not complete successfully');
|
|
141
200
|
}
|
|
142
201
|
if (sessionId && thread?.thread_id !== sessionId) throw blocked('Native parent session changed');
|
|
143
|
-
const observation = observe(thread?.thread_id,
|
|
202
|
+
const observation = observe(thread?.thread_id, { home: evidenceHome, deadline: Date.now() + Math.max(0, limit - performance.now()), signal,
|
|
203
|
+
...(sessionId ? { expectedPriorTurns: prior.turnCount, evidencePath: prior.evidence.path,
|
|
204
|
+
expectedPrefix: { bytes: prior.evidence.byteLength, sha256: prior.evidence.sha256 } } : {}) });
|
|
144
205
|
if (observation.model !== decision.model || observation.effort !== decision.effort || observation.cwd !== cwd
|
|
145
206
|
|| (readOnly && observation.sandbox?.type !== 'read-only')) throw blocked('Native worker model, effort, directory or sandbox mismatch');
|
|
146
207
|
const messages = events.filter(event => event.type === 'item.completed' && event.item?.type === 'agent_message');
|