@evomap/evolver 1.89.15 → 1.89.17
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/package.json +1 -1
- package/src/adapters/claudeCode.js +2 -2
- package/src/adapters/codex.js +2 -2
- package/src/adapters/hookAdapter.js +14 -2
- package/src/adapters/scripts/evolver-session-start.js +182 -2
- package/src/config.js +11 -3
- package/src/evolve/guards.js +1 -1
- package/src/evolve/pipeline/collect.js +1 -1
- package/src/evolve/pipeline/dispatch.js +1 -1
- package/src/evolve/pipeline/enrich.js +1 -1
- package/src/evolve/pipeline/hub.js +1 -1
- package/src/evolve/pipeline/select.js +1 -1
- package/src/evolve/pipeline/signals.js +1 -1
- package/src/evolve/utils.js +1 -1
- package/src/evolve.js +1 -1
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/antiAbuseTelemetry.js +1 -1
- package/src/gep/autoDistillConv.js +1 -1
- package/src/gep/autoDistillLlm.js +1 -1
- package/src/gep/candidateEval.js +1 -1
- package/src/gep/candidates.js +1 -1
- package/src/gep/contentHash.js +1 -1
- package/src/gep/conversationDistiller.js +1 -1
- package/src/gep/conversationSniffer.js +1 -1
- package/src/gep/crypto.js +1 -1
- package/src/gep/curriculum.js +1 -1
- package/src/gep/deviceId.js +1 -1
- package/src/gep/envFingerprint.js +1 -1
- package/src/gep/epigenetics.js +1 -1
- package/src/gep/execBridge.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/hash.js +1 -1
- package/src/gep/hostErrorClassifier.js +34 -0
- package/src/gep/hubFetch.js +1 -1
- package/src/gep/hubReview.js +1 -1
- package/src/gep/hubSearch.js +1 -1
- package/src/gep/hubVerify.js +1 -1
- package/src/gep/issueReporter.js +5 -4
- package/src/gep/learningSignals.js +1 -1
- package/src/gep/memoryGraph.js +1 -1
- package/src/gep/memoryGraphAdapter.js +1 -1
- package/src/gep/mutation.js +1 -1
- package/src/gep/narrativeMemory.js +1 -1
- package/src/gep/openPRRegistry.js +1 -1
- package/src/gep/paths.js +20 -0
- package/src/gep/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/prompt.js +1 -1
- package/src/gep/recallInject.js +1 -1
- package/src/gep/recallVerifier.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/savingsCore.js +1 -1
- package/src/gep/selector.js +1 -1
- package/src/gep/signals.js +37 -15
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/tokenSavings.js +1 -1
- package/src/gep/workspaceKeychain.js +1 -1
- package/src/ops/lifecycle.js +501 -31
- package/src/proxy/extensions/traceControl.js +1 -1
- package/src/proxy/inject.js +1 -1
- package/src/proxy/trace/extractor.js +1 -1
- package/src/proxy/trace/usage.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.89.
|
|
3
|
+
"version": "1.89.17",
|
|
4
4
|
"description": "A GEP-powered self-evolution engine for AI agents. Features automated log analysis and Genome Evolution Protocol (GEP) for auditable, reusable evolution assets.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir } = require('./hookAdapter');
|
|
3
|
+
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir, isEvolverHookCommand } = require('./hookAdapter');
|
|
4
4
|
|
|
5
5
|
const HOOK_SCRIPTS_DIR_NAME = 'hooks';
|
|
6
6
|
const EVOLVER_MARKER = '<!-- evolver-evolution-memory -->';
|
|
@@ -146,7 +146,7 @@ function uninstall({ configRoot }) {
|
|
|
146
146
|
const innerBefore = matcher.hooks.length;
|
|
147
147
|
const filtered = matcher.hooks.filter(h => {
|
|
148
148
|
const cmd = (h && h.command) || '';
|
|
149
|
-
return !
|
|
149
|
+
return !isEvolverHookCommand(cmd);
|
|
150
150
|
});
|
|
151
151
|
// A matcher containing both evolver and user hooks shrinks
|
|
152
152
|
// its inner array without changing the outer matcher count.
|
package/src/adapters/codex.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir } = require('./hookAdapter');
|
|
3
|
+
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir, isEvolverHookCommand } = require('./hookAdapter');
|
|
4
4
|
|
|
5
5
|
const HOOK_SCRIPTS_DIR_NAME = 'hooks';
|
|
6
6
|
const EVOLVER_MARKER = '<!-- evolver-evolution-memory -->';
|
|
@@ -166,7 +166,7 @@ function uninstall({ configRoot }) {
|
|
|
166
166
|
const before = data.hooks[event].length;
|
|
167
167
|
data.hooks[event] = data.hooks[event].filter(h => {
|
|
168
168
|
const cmd = (h && h.command) || '';
|
|
169
|
-
return !
|
|
169
|
+
return !isEvolverHookCommand(cmd);
|
|
170
170
|
});
|
|
171
171
|
if (data.hooks[event].length !== before) touched = true;
|
|
172
172
|
if (data.hooks[event].length === 0) delete data.hooks[event];
|
|
@@ -76,7 +76,7 @@ function mergeWithHooksUnion(target, source) {
|
|
|
76
76
|
if (tArr && sArr) {
|
|
77
77
|
const isEvolverOwned = (entry) => {
|
|
78
78
|
const cmds = collectCommands(entry);
|
|
79
|
-
return cmds.some(
|
|
79
|
+
return cmds.some(isEvolverHookCommand);
|
|
80
80
|
};
|
|
81
81
|
const userEntries = tArr.filter(e => !isEvolverOwned(e));
|
|
82
82
|
result.hooks[event] = [...userEntries, ...sArr];
|
|
@@ -101,6 +101,17 @@ function collectCommands(entry) {
|
|
|
101
101
|
return out;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
function isEvolverHookCommand(command) {
|
|
105
|
+
if (typeof command !== 'string') return false;
|
|
106
|
+
return command.includes('evolver-session') ||
|
|
107
|
+
command.includes('evolver-signal') ||
|
|
108
|
+
command.includes('evolver-task-recall') ||
|
|
109
|
+
// Legacy installs briefly shipped this companion daemon hook. Treat it
|
|
110
|
+
// as evolver-owned so reinstall/merge can remove it instead of preserving
|
|
111
|
+
// a stale supervisor that may point clients at a dead proxy.
|
|
112
|
+
command.includes('evolver-daemon-start');
|
|
113
|
+
}
|
|
114
|
+
|
|
104
115
|
function deepMerge(target, source) {
|
|
105
116
|
const result = { ...target };
|
|
106
117
|
for (const key of Object.keys(source)) {
|
|
@@ -226,7 +237,7 @@ function removeEvolverHooks(filePath, { markerKey = '_evolver_managed' } = {}) {
|
|
|
226
237
|
const before = data.hooks[event].length;
|
|
227
238
|
data.hooks[event] = data.hooks[event].filter(h => {
|
|
228
239
|
const cmd = h.command || '';
|
|
229
|
-
return !
|
|
240
|
+
return !isEvolverHookCommand(cmd);
|
|
230
241
|
});
|
|
231
242
|
if (data.hooks[event].length !== before) changed = true;
|
|
232
243
|
if (data.hooks[event].length === 0) delete data.hooks[event];
|
|
@@ -358,6 +369,7 @@ module.exports = {
|
|
|
358
369
|
deepMerge,
|
|
359
370
|
mergeWithHooksUnion,
|
|
360
371
|
collectCommands,
|
|
372
|
+
isEvolverHookCommand,
|
|
361
373
|
copyHookScripts,
|
|
362
374
|
appendSectionToFile,
|
|
363
375
|
assertSafeConfigDir,
|
|
@@ -14,6 +14,180 @@ const { filterRelevantOutcomes } = require('./_memoryFiltering');
|
|
|
14
14
|
// _maybeRestartDaemon's catch-all and silently disable daemon auto-restart.
|
|
15
15
|
const lockPaths = require('./_lockPaths');
|
|
16
16
|
|
|
17
|
+
function _readJson(file) {
|
|
18
|
+
try {
|
|
19
|
+
if (!file || !fs.existsSync(file)) return null;
|
|
20
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
21
|
+
} catch (_) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function _isLoopbackProxyUrl(value) {
|
|
27
|
+
const raw = String(value || '').trim();
|
|
28
|
+
if (!raw) return false;
|
|
29
|
+
try {
|
|
30
|
+
const u = new URL(raw);
|
|
31
|
+
const host = u.hostname.toLowerCase();
|
|
32
|
+
return u.protocol === 'http:' && (host === '127.0.0.1' || host === 'localhost' || host === '::1' || host === '[::1]');
|
|
33
|
+
} catch (_) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _stripTomlComment(line) {
|
|
39
|
+
let out = '';
|
|
40
|
+
let quote = null;
|
|
41
|
+
let escaped = false;
|
|
42
|
+
for (const ch of String(line || '')) {
|
|
43
|
+
if (escaped) {
|
|
44
|
+
out += ch;
|
|
45
|
+
escaped = false;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (ch === '\\' && quote === '"') {
|
|
49
|
+
out += ch;
|
|
50
|
+
escaped = true;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if ((ch === '"' || ch === "'") && !quote) {
|
|
54
|
+
quote = ch;
|
|
55
|
+
out += ch;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (ch === quote) {
|
|
59
|
+
quote = null;
|
|
60
|
+
out += ch;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (ch === '#' && !quote) break;
|
|
64
|
+
out += ch;
|
|
65
|
+
}
|
|
66
|
+
return out.trim();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function _tomlStringValue(value) {
|
|
70
|
+
const raw = _stripTomlComment(value);
|
|
71
|
+
const match = raw.match(/^(['"])([\s\S]*)\1$/);
|
|
72
|
+
return match ? match[2] : raw.trim();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function _codexConfigPath() {
|
|
76
|
+
if (process.env.CODEX_CONFIG_FILE || process.env.EVOMAP_CODEX_CONFIG_FILE) {
|
|
77
|
+
return process.env.CODEX_CONFIG_FILE || process.env.EVOMAP_CODEX_CONFIG_FILE;
|
|
78
|
+
}
|
|
79
|
+
const home = process.env.HOME || os.homedir();
|
|
80
|
+
return home ? path.join(home, '.codex', 'config.toml') : null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function _codexConfigExpectsProxy() {
|
|
84
|
+
const file = _codexConfigPath();
|
|
85
|
+
if (!file || !fs.existsSync(file)) return false;
|
|
86
|
+
let selectedProvider = null;
|
|
87
|
+
let section = '';
|
|
88
|
+
const providerUrls = {};
|
|
89
|
+
try {
|
|
90
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
91
|
+
for (const line of content.split(/\r?\n/)) {
|
|
92
|
+
const clean = _stripTomlComment(line);
|
|
93
|
+
if (!clean) continue;
|
|
94
|
+
const sectionMatch = clean.match(/^\[([^\]]+)\]$/);
|
|
95
|
+
if (sectionMatch) {
|
|
96
|
+
section = sectionMatch[1].trim();
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const kv = clean.match(/^([A-Za-z0-9_.-]+)\s*=\s*([\s\S]+)$/);
|
|
100
|
+
if (!kv) continue;
|
|
101
|
+
const key = kv[1].trim();
|
|
102
|
+
const value = _tomlStringValue(kv[2]);
|
|
103
|
+
if (!section && key === 'model_provider') {
|
|
104
|
+
selectedProvider = value;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const providerMatch = section.match(/^model_providers\.([A-Za-z0-9_.-]+)$/);
|
|
108
|
+
if (providerMatch && key === 'base_url') {
|
|
109
|
+
providerUrls[providerMatch[1]] = value;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (!section && key === 'base_url' && _isLoopbackProxyUrl(value)) return true;
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (selectedProvider && _isLoopbackProxyUrl(providerUrls[selectedProvider])) return true;
|
|
118
|
+
return Object.keys(providerUrls).some(name =>
|
|
119
|
+
/(?:evomap|proxy)/i.test(name) && _isLoopbackProxyUrl(providerUrls[name])
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function _proxyExpected() {
|
|
124
|
+
if (String(process.env.EVOMAP_PROXY || '').trim() === '1') return true;
|
|
125
|
+
if (String(process.env.A2A_TRANSPORT || '').trim().toLowerCase() === 'mailbox') return true;
|
|
126
|
+
if (_isLoopbackProxyUrl(process.env.EVOMAP_PROXY_URL) || _isLoopbackProxyUrl(process.env.ANTHROPIC_BASE_URL)) return true;
|
|
127
|
+
if (_codexConfigExpectsProxy()) return true;
|
|
128
|
+
|
|
129
|
+
const home = process.env.HOME || os.homedir();
|
|
130
|
+
const settingsFile = process.env.CLAUDE_SETTINGS_FILE || process.env.EVOMAP_CLAUDE_SETTINGS_FILE ||
|
|
131
|
+
(home ? path.join(home, '.claude', 'settings.json') : null);
|
|
132
|
+
const settings = _readJson(settingsFile);
|
|
133
|
+
const cfg = settings && settings.env;
|
|
134
|
+
return !!(cfg && (
|
|
135
|
+
_isLoopbackProxyUrl(cfg.EVOMAP_PROXY_URL) ||
|
|
136
|
+
(String(cfg.EVOMAP_PROXY_AUTO_INJECTED || '') === '1' && _isLoopbackProxyUrl(cfg.ANTHROPIC_BASE_URL))
|
|
137
|
+
));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function _proxyReachable(url, token) {
|
|
141
|
+
if (!_isLoopbackProxyUrl(url) || !token) return false;
|
|
142
|
+
try {
|
|
143
|
+
const { execFileSync } = require('child_process');
|
|
144
|
+
execFileSync(process.execPath, ['-e', `
|
|
145
|
+
const fs = require('fs');
|
|
146
|
+
const http = require('http');
|
|
147
|
+
const url = process.argv[1].replace(/\\/+$/, '') + '/proxy/status';
|
|
148
|
+
const token = fs.readFileSync(0, 'utf8').trim();
|
|
149
|
+
if (!token) process.exit(1);
|
|
150
|
+
const req = http.get(url, { headers: { Authorization: 'Bearer ' + token } }, (res) => {
|
|
151
|
+
let body = '';
|
|
152
|
+
res.setEncoding('utf8');
|
|
153
|
+
res.on('data', (chunk) => {
|
|
154
|
+
body += chunk;
|
|
155
|
+
if (body.length > 1024 * 1024) req.destroy(new Error('response too large'));
|
|
156
|
+
});
|
|
157
|
+
res.on('end', () => {
|
|
158
|
+
if (res.statusCode < 200 || res.statusCode >= 300) process.exit(1);
|
|
159
|
+
let parsed;
|
|
160
|
+
try { parsed = JSON.parse(body); } catch (_) { process.exit(1); }
|
|
161
|
+
if (parsed && parsed.status === 'running' && (parsed.proxy_protocol_version || parsed.schema_version || parsed.node_id != null)) {
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
process.exit(1);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
req.setTimeout(700, () => req.destroy(new Error('timeout')));
|
|
168
|
+
req.on('error', () => process.exit(1));
|
|
169
|
+
`, url], { input: String(token), stdio: ['pipe', 'ignore', 'ignore'], timeout: 1200, windowsHide: true });
|
|
170
|
+
return true;
|
|
171
|
+
} catch (_) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function _proxyHealthyIfExpected() {
|
|
177
|
+
if (!_proxyExpected()) return true;
|
|
178
|
+
const dir = process.env.EVOLVER_SETTINGS_DIR || path.join(os.homedir(), '.evolver');
|
|
179
|
+
const settings = _readJson(path.join(dir, 'settings.json'));
|
|
180
|
+
const proxy = settings && settings.proxy;
|
|
181
|
+
if (!proxy || !proxy.url) return false;
|
|
182
|
+
if (proxy.pid) {
|
|
183
|
+
try { process.kill(proxy.pid, 0); } catch (e) {
|
|
184
|
+
if (!(e && e.code === 'EPERM')) return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (!proxy.token) return false;
|
|
188
|
+
return _proxyReachable(proxy.url, proxy.token);
|
|
189
|
+
}
|
|
190
|
+
|
|
17
191
|
// Auto-restart guard: if the evolver daemon is not running when a new agent
|
|
18
192
|
// session starts, attempt a background restart. This covers the "idle-death"
|
|
19
193
|
// scenario: the user closed the machine (macOS sleep), the process died due to
|
|
@@ -69,7 +243,7 @@ function _maybeRestartDaemon(evolverRoot) {
|
|
|
69
243
|
}
|
|
70
244
|
} catch (_) { /* lock file unreadable or absent: assume not running */ }
|
|
71
245
|
|
|
72
|
-
if (daemonRunning) return; // already alive, nothing to do
|
|
246
|
+
if (daemonRunning && _proxyHealthyIfExpected()) return; // already alive, nothing to do
|
|
73
247
|
|
|
74
248
|
// Daemon appears dead. Spawn lifecycle.js start in the background so
|
|
75
249
|
// this session-start script exits immediately (< 50 ms) and does not
|
|
@@ -305,5 +479,11 @@ function main() {
|
|
|
305
479
|
if (require.main === module) {
|
|
306
480
|
main();
|
|
307
481
|
} else {
|
|
308
|
-
module.exports = {
|
|
482
|
+
module.exports = {
|
|
483
|
+
belongsToWorkspace,
|
|
484
|
+
_isLoopbackProxyUrl,
|
|
485
|
+
_proxyExpected,
|
|
486
|
+
_proxyReachable,
|
|
487
|
+
_proxyHealthyIfExpected,
|
|
488
|
+
};
|
|
309
489
|
}
|
package/src/config.js
CHANGED
|
@@ -85,9 +85,17 @@ const HUB_SEARCH_TIMEOUT_MS = envPositiveInt('EVOLVER_HUB_SEARCH_TIMEOUT_MS', 80
|
|
|
85
85
|
const PUBLIC_DEFAULT_HUB_URL = 'https://evomap.ai';
|
|
86
86
|
|
|
87
87
|
function resolveHubUrl() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
// Trim each candidate and fall through on empty/whitespace-only values.
|
|
89
|
+
// A trailing space in a `.env` value (common with quoted entries like
|
|
90
|
+
// A2A_HUB_URL="https://evomap.ai ") otherwise survives into endpoint
|
|
91
|
+
// construction: `hubUrl.replace(/\/+$/, '')` strips trailing slashes but
|
|
92
|
+
// NOT whitespace, producing "https://evomap.ai /a2a/events/poll" which
|
|
93
|
+
// fails URL validation (#580 Bug 1). `||` alone would also pick a
|
|
94
|
+
// whitespace-only override as "truthy", so trim-then-fall-through here.
|
|
95
|
+
const pick = (v) => { const t = (v == null ? '' : String(v)).trim(); return t || null; };
|
|
96
|
+
const raw = pick(process.env.A2A_HUB_URL)
|
|
97
|
+
|| pick(process.env.EVOMAP_HUB_URL)
|
|
98
|
+
|| pick(process.env.EVOLVER_DEFAULT_HUB_URL)
|
|
91
99
|
|| PUBLIC_DEFAULT_HUB_URL;
|
|
92
100
|
|
|
93
101
|
if (process.env.EVOMAP_HUB_ALLOW_INSECURE !== '1') {
|