@evomap/evolver 1.88.2 → 1.88.3
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/index.js +11 -0
- package/package.json +1 -1
- package/src/adapters/scripts/_runtimePaths.js +160 -36
- package/src/config.js +6 -0
- 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/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/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/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/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/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/sanitize.js +5 -0
- package/src/gep/selector.js +1 -1
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/workspaceKeychain.js +1 -1
- package/src/proxy/extensions/traceControl.js +1 -0
- package/src/proxy/index.js +24 -3
- package/src/proxy/inject.js +1 -0
- package/src/proxy/lifecycle/manager.js +1 -0
- package/src/proxy/mailbox/store.js +1 -0
- package/src/proxy/router/messages_route.js +57 -8
- package/src/proxy/trace/extractor.js +1 -0
package/index.js
CHANGED
|
@@ -1185,6 +1185,17 @@ async function main() {
|
|
|
1185
1185
|
hubUrl: process.env.A2A_HUB_URL,
|
|
1186
1186
|
});
|
|
1187
1187
|
console.log('[Proxy] Started on ' + proxyInfo.url);
|
|
1188
|
+
try {
|
|
1189
|
+
const { injectProxyEnv } = require('./src/proxy/inject');
|
|
1190
|
+
const injected = injectProxyEnv(proxyInfo);
|
|
1191
|
+
if (injected.injected) {
|
|
1192
|
+
console.log('[Proxy] Auto-injected client env for Claude Code/Codex/Cursor. Set EVOMAP_PROXY_AUTO_INJECT=off to disable.');
|
|
1193
|
+
} else {
|
|
1194
|
+
console.log('[Proxy] Auto-inject skipped: ' + injected.reason);
|
|
1195
|
+
}
|
|
1196
|
+
} catch (injectErr) {
|
|
1197
|
+
console.warn('[Proxy] Auto-inject failed: ' + (injectErr && injectErr.message || injectErr));
|
|
1198
|
+
}
|
|
1188
1199
|
const { registerMailboxTransport } = require('./src/gep/mailboxTransport');
|
|
1189
1200
|
registerMailboxTransport();
|
|
1190
1201
|
process.env.A2A_TRANSPORT = 'mailbox';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.88.
|
|
3
|
+
"version": "1.88.3",
|
|
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": {
|
|
@@ -31,6 +31,137 @@ function isEvolverPackageJson(filePath) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Scan a "versions dir" used by Node version managers (NVM, fnm, Volta, asdf)
|
|
35
|
+
// and append each `<versions-dir>/<version>/<subdir>/node_modules` to `out`.
|
|
36
|
+
// Skips silently when the versions dir does not exist (typical case — most
|
|
37
|
+
// users have at most one version manager). Most-recent-mtime first so the
|
|
38
|
+
// active version is preferred when a user has multiple Node versions
|
|
39
|
+
// installed.
|
|
40
|
+
function _scanVersionedNodeModules(versionsDir, subdir, out) {
|
|
41
|
+
let entries;
|
|
42
|
+
try {
|
|
43
|
+
entries = fs.readdirSync(versionsDir, { withFileTypes: true });
|
|
44
|
+
} catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const dirs = entries
|
|
48
|
+
.filter((e) => e.isDirectory && e.isDirectory())
|
|
49
|
+
.map((e) => {
|
|
50
|
+
const full = path.join(versionsDir, e.name);
|
|
51
|
+
let mtime = 0;
|
|
52
|
+
try { mtime = fs.statSync(full).mtimeMs; } catch {}
|
|
53
|
+
return { full, mtime };
|
|
54
|
+
})
|
|
55
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
56
|
+
for (const d of dirs) {
|
|
57
|
+
out.push(path.join(d.full, subdir, 'node_modules'));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Build the require.resolve paths array. All entries are user/system-scoped
|
|
62
|
+
// install roots — process.cwd() is intentionally excluded for the same
|
|
63
|
+
// prompt-injection reason as the original allowlist (see comment in
|
|
64
|
+
// findEvolverRoot below).
|
|
65
|
+
function _buildInstallSearchPaths() {
|
|
66
|
+
const home = os.homedir();
|
|
67
|
+
// Env-derived bases must be ABSOLUTE. A relative override (e.g. NVM_DIR='.nvm')
|
|
68
|
+
// or empty value would resolve against process.cwd() and let a hostile
|
|
69
|
+
// workspace plant a fake @evomap/evolver in the require.resolve allowlist —
|
|
70
|
+
// the prompt-injection surface PR #94 closed. isAbsolute is platform-matched
|
|
71
|
+
// (path.win32 recognises C:\ ...) so the guard holds on Windows too; a
|
|
72
|
+
// non-absolute override falls through to the trusted home/system default.
|
|
73
|
+
const _pathFlavor = process.platform === 'win32' ? path.win32 : path.posix;
|
|
74
|
+
const absEnv = (v) => (v && _pathFlavor.isAbsolute(v)) ? v : null;
|
|
75
|
+
const paths = [
|
|
76
|
+
// npm global with `npm config set prefix` overrides
|
|
77
|
+
path.join(home, '.npm-global', 'lib', 'node_modules'),
|
|
78
|
+
path.join(home, '.local', 'lib', 'node_modules'),
|
|
79
|
+
// System-wide (apt/yum nodejs, Intel Mac Homebrew)
|
|
80
|
+
'/usr/lib/node_modules',
|
|
81
|
+
'/usr/local/lib/node_modules',
|
|
82
|
+
// Apple Silicon Homebrew (default since macOS Big Sur on M1/M2/M3/M4 —
|
|
83
|
+
// the majority of Mac dev hardware sold since 2021). Without this
|
|
84
|
+
// entry, `npm install -g @evomap/evolver` on an Apple Silicon Mac
|
|
85
|
+
// lands at /opt/homebrew/lib/node_modules/@evomap/evolver and the
|
|
86
|
+
// hook scripts cannot find the package -> additionalContext is empty
|
|
87
|
+
// -> evolution memory never reaches the LLM.
|
|
88
|
+
'/opt/homebrew/lib/node_modules',
|
|
89
|
+
// Linuxbrew (Homebrew on Linux — niche but real).
|
|
90
|
+
'/home/linuxbrew/.linuxbrew/lib/node_modules',
|
|
91
|
+
];
|
|
92
|
+
// Per-user Node version managers. Each manager has its own on-disk layout
|
|
93
|
+
// and its own base-dir env override; the version subdirectory is dynamic
|
|
94
|
+
// (e.g. `~/.nvm/versions/node/v22.15.0`) so we scan and append each
|
|
95
|
+
// version's node_modules. These were missing from the original hard-coded
|
|
96
|
+
// list even though NVM in particular is extremely common across all OSes.
|
|
97
|
+
|
|
98
|
+
// NVM. Globals are per-version under `<NVM_DIR>/versions/node/<ver>/lib`.
|
|
99
|
+
// NVM_DIR defaults to ~/.nvm but is frequently relocated.
|
|
100
|
+
const nvmDir = absEnv(process.env.NVM_DIR) || path.join(home, '.nvm');
|
|
101
|
+
_scanVersionedNodeModules(path.join(nvmDir, 'versions', 'node'), 'lib', paths);
|
|
102
|
+
|
|
103
|
+
// fnm. Each version lives under `<base>/node-versions/<ver>/installation/`,
|
|
104
|
+
// and fnm does NOT override the npm prefix, so globals are at
|
|
105
|
+
// `installation/lib/node_modules`. The base dir is XDG-first
|
|
106
|
+
// (`$XDG_DATA_HOME/fnm`, i.e. ~/.local/share/fnm on Linux and
|
|
107
|
+
// ~/Library/Application Support/fnm on macOS); `~/.fnm` is only the legacy
|
|
108
|
+
// fallback. `$FNM_DIR` overrides everything. Scan all candidate bases;
|
|
109
|
+
// _scanVersionedNodeModules silently skips the ones that don't exist.
|
|
110
|
+
const fnmSub = path.join('installation', 'lib');
|
|
111
|
+
const fnmBases = [];
|
|
112
|
+
if (absEnv(process.env.FNM_DIR)) fnmBases.push(process.env.FNM_DIR);
|
|
113
|
+
if (absEnv(process.env.XDG_DATA_HOME)) fnmBases.push(path.join(process.env.XDG_DATA_HOME, 'fnm'));
|
|
114
|
+
fnmBases.push(path.join(home, '.local', 'share', 'fnm')); // Linux XDG default
|
|
115
|
+
fnmBases.push(path.join(home, 'Library', 'Application Support', 'fnm')); // macOS default
|
|
116
|
+
fnmBases.push(path.join(home, '.fnm')); // legacy
|
|
117
|
+
for (const base of fnmBases) {
|
|
118
|
+
_scanVersionedNodeModules(path.join(base, 'node-versions'), fnmSub, paths);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Volta does NOT store global packages alongside the Node image. It
|
|
122
|
+
// sandboxes each `npm install -g`'d package under
|
|
123
|
+
// `<VOLTA_HOME>/tools/image/packages/<name>/lib/node_modules` (the scope
|
|
124
|
+
// becomes a real nested directory). Because we know the package name, this
|
|
125
|
+
// is a single fixed path rather than a version scan. VOLTA_HOME defaults to
|
|
126
|
+
// ~/.volta on macOS/Linux but to %LOCALAPPDATA%\Volta on Windows (where the
|
|
127
|
+
// globals actually live, and hook processes often don't inherit VOLTA_HOME).
|
|
128
|
+
// Verified against volta-cli/volta `volta-layout` v4 (`package_image_dir`) +
|
|
129
|
+
// `package/manager.rs` (`source_dir` = lib/node_modules).
|
|
130
|
+
const voltaHome = absEnv(process.env.VOLTA_HOME)
|
|
131
|
+
|| (process.platform === 'win32'
|
|
132
|
+
? path.join(absEnv(process.env.LOCALAPPDATA) || path.join(home, 'AppData', 'Local'), 'Volta')
|
|
133
|
+
: path.join(home, '.volta'));
|
|
134
|
+
paths.push(path.join(voltaHome, 'tools', 'image', 'packages', '@evomap', 'evolver', 'lib', 'node_modules'));
|
|
135
|
+
|
|
136
|
+
// asdf. Globals are per-version under `<data>/installs/nodejs/<ver>/`.
|
|
137
|
+
// asdf-nodejs dropped the `.npm` prefix override in PR #228 (Sept 2022),
|
|
138
|
+
// so modern installs use plain `lib/node_modules`; older installs (never
|
|
139
|
+
// re-created) still use `.npm/lib/node_modules`. Scan both. `$ASDF_DATA_DIR`
|
|
140
|
+
// overrides the ~/.asdf default (asdf 0.16+ Go rewrite).
|
|
141
|
+
const asdfData = absEnv(process.env.ASDF_DATA_DIR) || path.join(home, '.asdf');
|
|
142
|
+
const asdfVersions = path.join(asdfData, 'installs', 'nodejs');
|
|
143
|
+
_scanVersionedNodeModules(asdfVersions, 'lib', paths); // modern (post-#228)
|
|
144
|
+
_scanVersionedNodeModules(asdfVersions, path.join('.npm', 'lib'), paths); // legacy (pre-#228)
|
|
145
|
+
|
|
146
|
+
// Windows: `npm install -g` puts packages under %APPDATA%\npm\node_modules
|
|
147
|
+
// (most common; same convention as `npm config get prefix` default on win32),
|
|
148
|
+
// %ProgramFiles%\nodejs\node_modules (system-wide installer), or
|
|
149
|
+
// %ProgramFiles(x86)%\nodejs\node_modules (32-bit Node on a 64-bit host).
|
|
150
|
+
// Conditional expansion keeps the POSIX base list untouched on Linux/macOS.
|
|
151
|
+
if (process.platform === 'win32') {
|
|
152
|
+
const appdata = absEnv(process.env.APPDATA) || path.join(home, 'AppData', 'Roaming');
|
|
153
|
+
paths.push(path.join(appdata, 'npm', 'node_modules'));
|
|
154
|
+
if (absEnv(process.env.ProgramFiles)) {
|
|
155
|
+
paths.push(path.join(process.env.ProgramFiles, 'nodejs', 'node_modules'));
|
|
156
|
+
}
|
|
157
|
+
if (absEnv(process.env['ProgramFiles(x86)'])) {
|
|
158
|
+
paths.push(path.join(process.env['ProgramFiles(x86)'], 'nodejs', 'node_modules'));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return paths;
|
|
163
|
+
}
|
|
164
|
+
|
|
34
165
|
function findEvolverRoot() {
|
|
35
166
|
if (process.env.EVOLVER_ROOT) {
|
|
36
167
|
const explicit = process.env.EVOLVER_ROOT;
|
|
@@ -57,39 +188,18 @@ function findEvolverRoot() {
|
|
|
57
188
|
// be selected here and control `findMemoryGraph()` -> the memory graph
|
|
58
189
|
// contents become attacker-controlled prompt-injection material in
|
|
59
190
|
// `evolver-session-start.js`'s `additionalContext`. Restrict to trusted,
|
|
60
|
-
// user/system-scoped install roots.
|
|
191
|
+
// user/system-scoped install roots (built in `_buildInstallSearchPaths`).
|
|
61
192
|
try {
|
|
62
|
-
//
|
|
63
|
-
// (
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
'npm', 'node_modules'
|
|
71
|
-
),
|
|
72
|
-
...(process.env.ProgramFiles
|
|
73
|
-
? [path.join(process.env.ProgramFiles, 'nodejs', 'node_modules')]
|
|
74
|
-
: []),
|
|
75
|
-
...(process.env['ProgramFiles(x86)']
|
|
76
|
-
? [path.join(process.env['ProgramFiles(x86)'], 'nodejs', 'node_modules')]
|
|
77
|
-
: []),
|
|
78
|
-
]
|
|
79
|
-
: [];
|
|
80
|
-
|
|
193
|
+
// Allowlist of trusted user/system-scoped install roots. Built by
|
|
194
|
+
// _buildInstallSearchPaths() above so the list is one source of truth
|
|
195
|
+
// (Apple Silicon Homebrew, Linuxbrew, NVM / fnm / Volta / asdf,
|
|
196
|
+
// and Windows %APPDATA%\npm + %ProgramFiles%\nodejs install layouts).
|
|
197
|
+
// process.cwd() is intentionally excluded: a hostile workspace can plant
|
|
198
|
+
// its own node_modules/@evomap/evolver/package.json which would then
|
|
199
|
+
// control findMemoryGraph() and feed attacker-controlled content into
|
|
200
|
+
// evolver-session-start.js's additionalContext.
|
|
81
201
|
const pkgJson = require.resolve('@evomap/evolver/package.json', {
|
|
82
|
-
|
|
83
|
-
// node_modules/@evomap/evolver to gain control over the memory graph path
|
|
84
|
-
// (prompt-injection surface: evolver-session-start.js additionalContext).
|
|
85
|
-
// Only trust user/system-scoped install roots.
|
|
86
|
-
paths: [
|
|
87
|
-
path.join(os.homedir(), '.npm-global', 'lib', 'node_modules'),
|
|
88
|
-
path.join(os.homedir(), '.local', 'lib', 'node_modules'),
|
|
89
|
-
'/usr/lib/node_modules',
|
|
90
|
-
'/usr/local/lib/node_modules',
|
|
91
|
-
..._winPaths,
|
|
92
|
-
],
|
|
202
|
+
paths: _buildInstallSearchPaths(),
|
|
93
203
|
});
|
|
94
204
|
if (pkgJson && isEvolverPackageJson(pkgJson)) {
|
|
95
205
|
return path.dirname(pkgJson);
|
|
@@ -293,10 +403,10 @@ function findMemoryGraph(evolverRoot) {
|
|
|
293
403
|
}
|
|
294
404
|
|
|
295
405
|
// Is `dir` inside a git work tree? Cheap, no-shell `git rev-parse`. Returns
|
|
296
|
-
// false on any error (git missing, not a repo, timeout) and never throws
|
|
297
|
-
// session-start hook uses this only to decide whether to surface a
|
|
298
|
-
// "evolver needs a git workspace" notice, so a false negative just
|
|
299
|
-
// the notice rather than breaking anything.
|
|
406
|
+
// false on any error (git missing, not a repo, timeout) and never throws.
|
|
407
|
+
// The session-start hook uses this only to decide whether to surface a
|
|
408
|
+
// one-line "evolver needs a git workspace" notice, so a false negative just
|
|
409
|
+
// suppresses the notice rather than breaking anything.
|
|
300
410
|
function isGitWorkspace(dir) {
|
|
301
411
|
try {
|
|
302
412
|
const res = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], {
|
|
@@ -312,4 +422,18 @@ function isGitWorkspace(dir) {
|
|
|
312
422
|
}
|
|
313
423
|
}
|
|
314
424
|
|
|
315
|
-
module.exports = {
|
|
425
|
+
module.exports = {
|
|
426
|
+
findEvolverRoot,
|
|
427
|
+
findMemoryGraph,
|
|
428
|
+
resolveProjectDir,
|
|
429
|
+
resolveWorkspaceId,
|
|
430
|
+
isGitWorkspace,
|
|
431
|
+
// Test-only: exposes the install-path builder so the test suite can
|
|
432
|
+
// verify Apple Silicon Homebrew + version-manager (NVM/fnm/Volta/asdf)
|
|
433
|
+
// + Windows %APPDATA%\npm paths are included without going through the
|
|
434
|
+
// full require.resolve chain (which depends on a real filesystem layout).
|
|
435
|
+
__internals: {
|
|
436
|
+
buildInstallSearchPaths: _buildInstallSearchPaths,
|
|
437
|
+
scanVersionedNodeModules: _scanVersionedNodeModules,
|
|
438
|
+
},
|
|
439
|
+
};
|
package/src/config.js
CHANGED
|
@@ -136,9 +136,14 @@ const REPAIR_LOOP_THRESHOLD = envInt('EVOLVER_REPAIR_LOOP_THRESHOLD', 3);
|
|
|
136
136
|
//
|
|
137
137
|
// GENE_BAN_PER_KEY_ATTEMPTS: minimum attempts on the same signal key
|
|
138
138
|
// GENE_BAN_BEST_THRESHOLD: best success rate at or below which the Gene is banned
|
|
139
|
+
// GENE_INERT_BAN_STREAK: consecutive inert (stable_no_error, zero-work) outcomes
|
|
140
|
+
// on a signal key after which a Gene with no real
|
|
141
|
+
// success is banned, so --loop selection explores
|
|
142
|
+
// instead of re-running a do-nothing gene (#562)
|
|
139
143
|
// GENE_EPIGENETIC_HARD_BOOST: epigenetic boost at or below which the Gene is hard-suppressed
|
|
140
144
|
const GENE_BAN_PER_KEY_ATTEMPTS = envInt('EVOLVER_GENE_BAN_PER_KEY_ATTEMPTS', 4);
|
|
141
145
|
const GENE_BAN_BEST_THRESHOLD = envFloat('EVOLVER_GENE_BAN_BEST_THRESHOLD', 0.15);
|
|
146
|
+
const GENE_INERT_BAN_STREAK = envInt('EVOLVER_GENE_INERT_BAN_STREAK', 8);
|
|
142
147
|
const GENE_EPIGENETIC_HARD_BOOST = envFloat('EVOLVER_GENE_EPIGENETIC_HARD_BOOST', -0.3);
|
|
143
148
|
const SESSION_ARCHIVE_TRIGGER = envInt('EVOLVER_SESSION_ARCHIVE_TRIGGER', 100);
|
|
144
149
|
const SESSION_ARCHIVE_KEEP = envInt('EVOLVER_SESSION_ARCHIVE_KEEP', 50);
|
|
@@ -243,6 +248,7 @@ module.exports = {
|
|
|
243
248
|
REPAIR_LOOP_THRESHOLD,
|
|
244
249
|
GENE_BAN_PER_KEY_ATTEMPTS,
|
|
245
250
|
GENE_BAN_BEST_THRESHOLD,
|
|
251
|
+
GENE_INERT_BAN_STREAK,
|
|
246
252
|
GENE_EPIGENETIC_HARD_BOOST,
|
|
247
253
|
SESSION_ARCHIVE_TRIGGER,
|
|
248
254
|
SESSION_ARCHIVE_KEEP,
|