Skip to content

Commit db51019

Browse files
author
evolver-publish
committed
Release v1.89.5
1 parent 8355370 commit db51019

95 files changed

Lines changed: 4072 additions & 201 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,14 @@ how `setup-hooks --platform=codex` wires Evolver in), but it does **not**
146146
emit a session transcript file the way Cursor / Claude Code / opencode do.
147147
That means `evolver --review` cannot read raw session logs on Codex.
148148

149+
`setup-hooks --platform=codex` is lifecycle integration only; it does not route
150+
Codex model requests through Evolver Proxy. To route Codex model traffic, run
151+
Evolver Proxy and configure Codex with a user-level OpenAI Responses-compatible
152+
custom provider whose `base_url` points at the proxy's `/v1` endpoint and whose
153+
command-backed auth runs `evolver proxy-token` or the absolute `node index.js
154+
proxy-token --settings ...` helper emitted by `scripts/internal-proxy-env.sh
155+
--codex-config` from a source checkout.
156+
149157
Evolver compensates by reading, in order:
150158

151159
1. `MEMORY.md` / `USER.md` in the workspace root (if you maintain them);

index.js

Lines changed: 116 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,65 @@
11
#!/usr/bin/env node
2+
function _printProxyTokenUsage(out = process.stderr) {
3+
out.write('Usage: node index.js proxy-token [--settings FILE]\n');
4+
}
5+
6+
function _readProxyTokenFromSettingsFile(fs, settingsFile) {
7+
try {
8+
const parsed = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
9+
return parsed && parsed.proxy && typeof parsed.proxy.token === 'string'
10+
? parsed.proxy.token
11+
: '';
12+
} catch {
13+
return '';
14+
}
15+
}
16+
17+
// `proxy-token` is a credential helper for Codex. Handle it before loading any
18+
// project .env so a workspace cannot change EVOLVER_SETTINGS_DIR or other local
19+
// state used to find the proxy token.
20+
if (process.argv[2] === 'proxy-token') {
21+
try {
22+
const _fs = require('fs');
23+
const _os = require('os');
24+
const _path = require('path');
25+
let settingsFile = '';
26+
for (let i = 3; i < process.argv.length; i++) {
27+
const arg = process.argv[i];
28+
if (arg === '-h' || arg === '--help') {
29+
_printProxyTokenUsage(process.stdout);
30+
process.exit(0);
31+
}
32+
if (arg === '--settings') {
33+
if (!process.argv[i + 1]) {
34+
_printProxyTokenUsage();
35+
console.error('[proxy-token] missing value for --settings');
36+
process.exit(2);
37+
}
38+
settingsFile = process.argv[i + 1];
39+
i++;
40+
continue;
41+
}
42+
_printProxyTokenUsage();
43+
console.error('[proxy-token] unknown argument');
44+
process.exit(2);
45+
}
46+
const defaultSettingsFile = _path.join(
47+
process.env.EVOLVER_SETTINGS_DIR || _path.join(_os.homedir(), '.evolver'),
48+
'settings.json',
49+
);
50+
const token = _readProxyTokenFromSettingsFile(_fs, settingsFile || defaultSettingsFile);
51+
if (!token) {
52+
console.error('[proxy-token] no active proxy token found; start evolver with EVOMAP_PROXY=1 first');
53+
process.exit(1);
54+
}
55+
process.stdout.write(token + '\n');
56+
process.exit(0);
57+
} catch (e) {
58+
console.error('[proxy-token] Failed:', e && e.message || e);
59+
process.exit(1);
60+
}
61+
}
62+
263
// Load .env BEFORE any internal require so that a2aProtocol and ATP
364
// modules see A2A_NODE_SECRET / A2A_NODE_ID / A2A_HUB_URL at first
465
// access and never fall back to a stale persisted/cached secret.
@@ -625,7 +686,7 @@ async function main() {
625686
// failure mode obvious.
626687
try {
627688
const { execSync } = require('child_process');
628-
execSync('git --version', { stdio: 'ignore', timeout: 5000 });
689+
execSync('git --version', { stdio: 'ignore', timeout: 5000, windowsHide: true });
629690
} catch (_gitErr) {
630691
console.error('');
631692
console.error('[Preflight] Could not run "git --version". Evolver requires git to be installed and available on PATH.');
@@ -1166,6 +1227,24 @@ async function main() {
11661227
const { registerMailboxTransport } = require('./src/gep/mailboxTransport');
11671228
registerMailboxTransport();
11681229
process.env.A2A_TRANSPORT = 'mailbox';
1230+
try {
1231+
const a2a = require('./src/gep/a2aProtocol');
1232+
a2a.startSystemdNotifyWatchdog(function () {
1233+
try {
1234+
const proxy = proxyInfo && proxyInfo.proxy;
1235+
const lifecycle = proxy && proxy.lifecycle;
1236+
if (lifecycle && typeof lifecycle.getHeartbeatStats === 'function') {
1237+
const stats = lifecycle.getHeartbeatStats();
1238+
// Hub-backed lifecycle stats are authoritative even when stopped;
1239+
// systemd should starve and restart instead of seeing a false ping.
1240+
if (stats && (stats.running || proxy.hubUrl)) return stats;
1241+
}
1242+
} catch (_) {}
1243+
return { running: true, consecutiveFailures: 0, lastTickAt: Date.now() };
1244+
});
1245+
} catch (sdErr) {
1246+
console.warn('[Heartbeat] systemd notify/watchdog setup failed: ' + (sdErr && sdErr.message || sdErr));
1247+
}
11691248
} else {
11701249
const a2a = require('./src/gep/a2aProtocol');
11711250
try { a2a.startHeartbeat(); }
@@ -1825,9 +1904,9 @@ async function main() {
18251904
const repoRoot = getRepoRoot();
18261905
let diff = '';
18271906
try {
1828-
const unstaged = execSync('git diff', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER }).trim();
1829-
const staged = execSync('git diff --cached', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER }).trim();
1830-
const untracked = execSync('git ls-files --others --exclude-standard', { cwd: repoRoot, encoding: 'utf8', timeout: 10000, maxBuffer: MAX_EXEC_BUFFER }).trim();
1907+
const unstaged = execSync('git diff', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER, windowsHide: true }).trim();
1908+
const staged = execSync('git diff --cached', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER, windowsHide: true }).trim();
1909+
const untracked = execSync('git ls-files --others --exclude-standard', { cwd: repoRoot, encoding: 'utf8', timeout: 10000, maxBuffer: MAX_EXEC_BUFFER, windowsHide: true }).trim();
18311910
if (staged) diff += '=== Staged Changes ===\n' + staged + '\n\n';
18321911
if (unstaged) diff += '=== Unstaged Changes ===\n' + unstaged + '\n\n';
18331912
if (untracked) diff += '=== Untracked Files ===\n' + untracked + '\n';
@@ -1909,13 +1988,13 @@ async function main() {
19091988
} else if (args.includes('--reject')) {
19101989
console.log('\n[Review] Rejected. Rolling back changes...');
19111990
try {
1912-
execSync('git checkout -- .', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER });
1991+
execSync('git checkout -- .', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER, windowsHide: true });
19131992
// Preserve user state on reject: .env files, node_modules, runtime
19141993
// PID files, and a dedicated workspace/ dir (if one exists) MUST NOT
19151994
// be wiped by an automated rollback. Users have reported losing
19161995
// secrets and runtime caches to an aggressive git clean.
19171996
execSync('git clean -fd -e node_modules -e workspace -e .env -e ".env.*" -e "*.pid"', {
1918-
cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER,
1997+
cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER, windowsHide: true,
19191998
});
19201999
const evolDir = getEvolutionDir();
19212000
const sp = path.join(evolDir, 'evolution_solidify_state.json');
@@ -2922,10 +3001,40 @@ async function main() {
29223001
process.exit(1);
29233002
}
29243003

3004+
} else if (command === 'experiment') {
3005+
// Comparative experiment runner: run the SAME task twice -- a baseline arm
3006+
// and a variant arm that reuses a gene's strategy -- via a headless agent
3007+
// CLI, collect duration/rounds/tokens/pass-rate, and print a comparison
3008+
// JSON to stdout. Consumed by EvoMap Desktop's ExperimentsAPI.Run, which
3009+
// spawns `node index.js experiment --request-file=<json>` and parses stdout.
3010+
try {
3011+
const expCli = require('./src/experiment/cli');
3012+
const parsed = expCli.parseExperimentArgs(args.slice(1));
3013+
if (!parsed.ok) {
3014+
console.error('[Experiment] ' + parsed.error);
3015+
console.error(expCli.printExperimentUsage());
3016+
process.exit(2);
3017+
}
3018+
const res = await expCli.runExperiment(parsed.opts, { err: (...a) => console.error(...a) });
3019+
// stdout carries ONLY the structured JSON so the Go caller can JSON.parse
3020+
// it without log contamination; all logging above went to stderr. res.data
3021+
// is already secret-redacted by runExperiment (sanitizePayload).
3022+
if (res && res.data) process.stdout.write(JSON.stringify(res.data) + '\n');
3023+
process.exit(res && typeof res.exitCode === 'number' ? res.exitCode : (res && res.ok ? 0 : 1));
3024+
} catch (expErr) {
3025+
console.error('[Experiment] CLI error:', expErr && expErr.message || expErr);
3026+
process.exit(1);
3027+
}
3028+
29253029
} else {
2926-
console.log(`Usage: node index.js [run|/evolve|login|logout|solidify|review|distill|fetch|sync|asset-log|webui|setup-hooks|recipe|buy|orders|verify|atp|atp-complete] [--loop]
3030+
console.log(`Usage: node index.js [run|/evolve|login|logout|proxy-token|solidify|review|distill|fetch|sync|asset-log|webui|setup-hooks|recipe|buy|orders|verify|atp|atp-complete|experiment] [--loop]
29273031
- login (authorize this device via the hub, gh-auth-login style; stores an OAuth token used instead of node_secret)
29283032
- logout (remove the stored OAuth token)
3033+
- proxy-token (print the local proxy bearer token for command-backed client auth)
3034+
- experiment flags:
3035+
- --task="..." --metric="..." (required; same task, baseline vs variant)
3036+
- --gene=<geneId> (variant arm reuses this gene's strategy)
3037+
- --baseline="..." --variant="..." --validation="c1;;c2" --request-file=<json>
29293038
- recipe flags:
29303039
- build --title="..." --genes=<asset_id,...> [--description] [--price=N] [--publish]
29313040
(builds a DRAFT DNA blueprint; --publish is opt-in)

0 commit comments

Comments
 (0)