@evomap/evolver 1.78.10 → 1.79.1
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.ja-JP.md +1 -0
- package/README.ko-KR.md +1 -0
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/assets/gep/candidates.jsonl +2 -1
- package/index.js +175 -14
- package/package.json +1 -1
- package/scripts/build_binaries.js +388 -0
- package/src/evolve.js +1 -1
- package/src/gep/.integrity +0 -0
- package/src/gep/a2aProtocol.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/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/explore.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/integrityCheck.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/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/prompt.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/selector.js +1 -1
- package/src/gep/shield.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/README.ja-JP.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://github.com/EvoMap/evolver/commits/main)
|
|
7
|
+
[](https://www.npmjs.com/package/@evomap/evolver)
|
|
7
8
|
[](https://github.com/EvoMap/evolver/issues)
|
|
8
9
|
[](https://arxiv.org/abs/2604.15097)
|
|
9
10
|
|
package/README.ko-KR.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://github.com/EvoMap/evolver/commits/main)
|
|
7
|
+
[](https://www.npmjs.com/package/@evomap/evolver)
|
|
7
8
|
[](https://github.com/EvoMap/evolver/issues)
|
|
8
9
|
[](https://arxiv.org/abs/2604.15097)
|
|
9
10
|
|
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://github.com/EvoMap/evolver/commits/main)
|
|
7
|
+
[](https://www.npmjs.com/package/@evomap/evolver)
|
|
7
8
|
[](https://github.com/EvoMap/evolver/issues)
|
|
8
9
|
[](https://arxiv.org/abs/2604.15097)
|
|
9
10
|
|
package/README.zh-CN.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://github.com/EvoMap/evolver/commits/main)
|
|
7
|
+
[](https://www.npmjs.com/package/@evomap/evolver)
|
|
7
8
|
[](https://github.com/EvoMap/evolver/issues)
|
|
8
9
|
[](https://arxiv.org/abs/2604.15097)
|
|
9
10
|
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-05-
|
|
1
|
+
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-05-06T01:46:54.543Z","signals":["memory_missing","user_missing","session_logs_missing"],"tags":["memory_missing","user_missing","session_logs_missing","area:memory"],"shape":{"title":"Harden session log detection and fallback behavior","input":"Recent session transcript + memory snippets + user instructions","output":"A safe, auditable evolution patch guided by GEP assets","invariants":"Protocol order, small reversible patches, validation, append-only events","params":"Signals: memory_missing, user_missing, session_logs_missing","failure_points":"Missing signals, over-broad changes, skipped validation, missing knowledge solidification","evidence":"Signal present: session_logs_missing"}}
|
|
2
|
+
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-05-06T01:47:23.332Z","signals":["memory_missing","user_missing","session_logs_missing"],"tags":["memory_missing","user_missing","session_logs_missing","area:memory"],"shape":{"title":"Harden session log detection and fallback behavior","input":"Recent session transcript + memory snippets + user instructions","output":"A safe, auditable evolution patch guided by GEP assets","invariants":"Protocol order, small reversible patches, validation, append-only events","params":"Signals: memory_missing, user_missing, session_logs_missing","failure_points":"Missing signals, over-broad changes, skipped validation, missing knowledge solidification","evidence":"Signal present: session_logs_missing"}}
|
package/index.js
CHANGED
|
@@ -104,6 +104,79 @@ function parseMs(v, fallback) {
|
|
|
104
104
|
return fallback;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
function parseBoolEnv(v, fallback) {
|
|
108
|
+
if (v == null) return fallback;
|
|
109
|
+
const s = String(v).toLowerCase().trim();
|
|
110
|
+
if (s === '' ) return fallback;
|
|
111
|
+
if (s === 'false' || s === '0' || s === 'off' || s === 'no') return false;
|
|
112
|
+
if (s === 'true' || s === '1' || s === 'on' || s === 'yes') return true;
|
|
113
|
+
return fallback;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
class CycleTimeoutError extends Error {
|
|
117
|
+
constructor(timeoutMs, phase, cycleNum) {
|
|
118
|
+
super('Cycle hard-timeout exceeded after ' + timeoutMs + 'ms (cycle=' + cycleNum + ', phase=' + phase + ')');
|
|
119
|
+
this.name = 'CycleTimeoutError';
|
|
120
|
+
this.code = 'CYCLE_TIMEOUT';
|
|
121
|
+
this.timeoutMs = timeoutMs;
|
|
122
|
+
this.phase = phase;
|
|
123
|
+
this.cycleNum = cycleNum;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Issue #528: on Windows, child_process.spawn(detached: true, windowsHide: true)
|
|
128
|
+
// allocates a new conhost window every time -- windowsHide is silently ignored
|
|
129
|
+
// in detached mode. So suicide-respawn (cycles >= max, RSS over budget, or the
|
|
130
|
+
// new cycle hard-timeout) opens a new cmd popup on every restart. We now skip
|
|
131
|
+
// the in-process detached spawn on Windows by default and rely on an external
|
|
132
|
+
// supervisor (feishu-evolver-wrapper >= 1.10.0, NSSM, pm2-windows, etc.) to
|
|
133
|
+
// respawn the daemon on non-zero exit. Users who insist can opt back in with
|
|
134
|
+
// EVOLVER_SUICIDE_WINDOWS=true (and accept the popups).
|
|
135
|
+
function spawnReplacementProcess({ reason, args, logPath }) {
|
|
136
|
+
const isWindows = process.platform === 'win32';
|
|
137
|
+
const allowOnWindows = parseBoolEnv(process.env.EVOLVER_SUICIDE_WINDOWS, false);
|
|
138
|
+
if (isWindows && !allowOnWindows) {
|
|
139
|
+
console.log(
|
|
140
|
+
'[Daemon] Skipping in-process respawn on Windows (' + reason + '). ' +
|
|
141
|
+
'Native Node spawn(detached, windowsHide) opens a cmd popup on every restart (Issue #528). ' +
|
|
142
|
+
'Set EVOLVER_SUICIDE_WINDOWS=true to opt back in. ' +
|
|
143
|
+
'Recommended: run evolver under feishu-evolver-wrapper >= 1.10.0, NSSM, or pm2-windows so the supervisor restarts on exit.'
|
|
144
|
+
);
|
|
145
|
+
return { spawned: false, reason: 'windows_default_skip' };
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const logFd = fs.openSync(logPath, 'a');
|
|
149
|
+
const spawnOpts = {
|
|
150
|
+
detached: true,
|
|
151
|
+
stdio: ['ignore', logFd, logFd],
|
|
152
|
+
env: process.env,
|
|
153
|
+
windowsHide: true,
|
|
154
|
+
};
|
|
155
|
+
const child = spawn(process.execPath, [__filename, ...args], spawnOpts);
|
|
156
|
+
child.unref();
|
|
157
|
+
return { spawned: true };
|
|
158
|
+
} catch (e) {
|
|
159
|
+
console.error('[Daemon] Spawn-replacement failed (' + reason + '): ' + (e && e.message || e));
|
|
160
|
+
return { spawned: false, reason: 'spawn_error', error: e };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Atomic write of the cycle_progress.json file. Wrapper polls this file every
|
|
165
|
+
// 60s; if updated_at goes stale beyond EVOLVE_INNER_STUCK_TIMEOUT_SEC the
|
|
166
|
+
// wrapper treats the inner core as zombie and SIGKILLs it. See Issue #19 (the
|
|
167
|
+
// 22-day stuck-cycle incident) and the cross-repo timeout plan for context.
|
|
168
|
+
function writeCycleProgressAtomic(progressPath, fields) {
|
|
169
|
+
try {
|
|
170
|
+
const data = Object.assign({}, fields, { updated_at: Date.now() });
|
|
171
|
+
const tmp = progressPath + '.tmp.' + process.pid;
|
|
172
|
+
fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
173
|
+
fs.renameSync(tmp, progressPath);
|
|
174
|
+
return true;
|
|
175
|
+
} catch (e) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
107
180
|
function getLastSignals(statePath) {
|
|
108
181
|
try {
|
|
109
182
|
const st = readJsonSafe(statePath);
|
|
@@ -255,6 +328,7 @@ async function main() {
|
|
|
255
328
|
|
|
256
329
|
const { getEvolutionDir, getEvolverLogPath } = require('./src/gep/paths');
|
|
257
330
|
const solidifyStatePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
|
|
331
|
+
const cycleProgressPath = path.join(getEvolutionDir(), 'cycle_progress.json');
|
|
258
332
|
|
|
259
333
|
const minSleepMs = parseMs(process.env.EVOLVER_MIN_SLEEP_MS, 2000);
|
|
260
334
|
const maxSleepMs = parseMs(process.env.EVOLVER_MAX_SLEEP_MS, 300000);
|
|
@@ -270,6 +344,15 @@ async function main() {
|
|
|
270
344
|
const maxRssMb = parseMs(process.env.EVOLVER_MAX_RSS_MB, 500) || 500;
|
|
271
345
|
const suicideEnabled = String(process.env.EVOLVER_SUICIDE || '').toLowerCase() !== 'false';
|
|
272
346
|
|
|
347
|
+
// Issue #19: hard timeout around evolve.run() to break out of zombie
|
|
348
|
+
// cycles (e.g. unclosed socket / stuck LLM call). On timeout we throw
|
|
349
|
+
// CycleTimeoutError, log diagnostic stderr, and force suicide-respawn
|
|
350
|
+
// so the wrapper sees a fresh PID + cycle. Also write cycle_progress
|
|
351
|
+
// every progressUpdateMs so the wrapper has a true heartbeat to poll.
|
|
352
|
+
const cycleTimeoutEnabled = parseBoolEnv(process.env.EVOLVER_CYCLE_TIMEOUT_ENABLED, true);
|
|
353
|
+
const cycleTimeoutMs = parseMs(process.env.EVOLVER_CYCLE_TIMEOUT_MS, 2700000); // 45 min default
|
|
354
|
+
const progressUpdateMs = parseMs(process.env.EVOLVER_PROGRESS_UPDATE_MS, 60000); // 1 min default
|
|
355
|
+
|
|
273
356
|
// Start hub heartbeat (keeps node alive independently of evolution cycles)
|
|
274
357
|
try {
|
|
275
358
|
if (process.env.EVOMAP_PROXY === '1' || process.env.A2A_TRANSPORT === 'mailbox') {
|
|
@@ -388,8 +471,46 @@ async function main() {
|
|
|
388
471
|
|
|
389
472
|
const t0 = Date.now();
|
|
390
473
|
let ok = false;
|
|
474
|
+
// Issue #19: write progress at cycle start, refresh it every
|
|
475
|
+
// progressUpdateMs (default 60s) while evolve.run() is active, and
|
|
476
|
+
// wrap evolve.run() with Promise.race(timeout) so a hung internal
|
|
477
|
+
// call cannot freeze the daemon for days.
|
|
478
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
479
|
+
pid: process.pid,
|
|
480
|
+
outer_cycle: cycleCount,
|
|
481
|
+
inner_cycle: cycleCount,
|
|
482
|
+
started_at: t0,
|
|
483
|
+
phase: 'evolve.run',
|
|
484
|
+
});
|
|
485
|
+
let progressTicker = null;
|
|
486
|
+
if (progressUpdateMs > 0) {
|
|
487
|
+
progressTicker = setInterval(function () {
|
|
488
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
489
|
+
pid: process.pid,
|
|
490
|
+
outer_cycle: cycleCount,
|
|
491
|
+
inner_cycle: cycleCount,
|
|
492
|
+
started_at: t0,
|
|
493
|
+
phase: 'evolve.run',
|
|
494
|
+
});
|
|
495
|
+
}, progressUpdateMs);
|
|
496
|
+
if (typeof progressTicker.unref === 'function') progressTicker.unref();
|
|
497
|
+
}
|
|
498
|
+
let cycleTimeoutHandle = null;
|
|
499
|
+
let cycleTimedOut = false;
|
|
391
500
|
try {
|
|
392
|
-
|
|
501
|
+
const evolvePromise = evolve.run();
|
|
502
|
+
if (cycleTimeoutEnabled && cycleTimeoutMs > 0) {
|
|
503
|
+
const timeoutPromise = new Promise(function (_, reject) {
|
|
504
|
+
cycleTimeoutHandle = setTimeout(function () {
|
|
505
|
+
cycleTimedOut = true;
|
|
506
|
+
reject(new CycleTimeoutError(cycleTimeoutMs, 'evolve.run', cycleCount));
|
|
507
|
+
}, cycleTimeoutMs);
|
|
508
|
+
if (cycleTimeoutHandle && typeof cycleTimeoutHandle.unref === 'function') cycleTimeoutHandle.unref();
|
|
509
|
+
});
|
|
510
|
+
await Promise.race([evolvePromise, timeoutPromise]);
|
|
511
|
+
} else {
|
|
512
|
+
await evolvePromise;
|
|
513
|
+
}
|
|
393
514
|
ok = true;
|
|
394
515
|
|
|
395
516
|
if (String(process.env.EVOLVE_BRIDGE || '').toLowerCase() === 'false') {
|
|
@@ -403,7 +524,29 @@ async function main() {
|
|
|
403
524
|
}
|
|
404
525
|
} catch (error) {
|
|
405
526
|
const msg = error && error.message ? String(error.message) : String(error);
|
|
527
|
+
if (error && error.code === 'CYCLE_TIMEOUT') {
|
|
528
|
+
console.error('[Daemon] ' + msg);
|
|
529
|
+
if (progressTicker) { clearInterval(progressTicker); progressTicker = null; }
|
|
530
|
+
if (cycleTimeoutHandle) { clearTimeout(cycleTimeoutHandle); cycleTimeoutHandle = null; }
|
|
531
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
532
|
+
pid: process.pid,
|
|
533
|
+
outer_cycle: cycleCount,
|
|
534
|
+
inner_cycle: cycleCount,
|
|
535
|
+
started_at: t0,
|
|
536
|
+
phase: 'cycle_timeout_respawn',
|
|
537
|
+
});
|
|
538
|
+
spawnReplacementProcess({
|
|
539
|
+
reason: 'cycle_hard_timeout',
|
|
540
|
+
args: args,
|
|
541
|
+
logPath: getEvolverLogPath(),
|
|
542
|
+
});
|
|
543
|
+
releaseLock();
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
406
546
|
console.error(`Evolution cycle failed: ${msg}`);
|
|
547
|
+
} finally {
|
|
548
|
+
if (progressTicker) { clearInterval(progressTicker); progressTicker = null; }
|
|
549
|
+
if (cycleTimeoutHandle) { clearTimeout(cycleTimeoutHandle); cycleTimeoutHandle = null; }
|
|
407
550
|
}
|
|
408
551
|
const dt = Date.now() - t0;
|
|
409
552
|
|
|
@@ -451,25 +594,32 @@ async function main() {
|
|
|
451
594
|
if (isVerbose) console.warn('[OMLS] Scheduler error: ' + (e.message || e));
|
|
452
595
|
}
|
|
453
596
|
|
|
454
|
-
// Suicide check (memory leak protection)
|
|
597
|
+
// Suicide check (memory leak protection). On Windows the
|
|
598
|
+
// in-process respawn opens a cmd popup (Issue #528), so by default
|
|
599
|
+
// we delegate to an external supervisor by exiting with a non-zero
|
|
600
|
+
// code instead. See spawnReplacementProcess() for the policy.
|
|
455
601
|
if (suicideEnabled) {
|
|
456
602
|
const memMb = process.memoryUsage().rss / 1024 / 1024;
|
|
457
603
|
if (cycleCount >= maxCyclesPerProcess || memMb > maxRssMb) {
|
|
458
604
|
console.log(`[Daemon] Restarting self (cycles=${cycleCount}, rssMb=${memMb.toFixed(0)})`);
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
windowsHide: true,
|
|
466
|
-
};
|
|
467
|
-
const child = spawn(process.execPath, [__filename, ...args], spawnOpts);
|
|
468
|
-
child.unref();
|
|
605
|
+
const result = spawnReplacementProcess({
|
|
606
|
+
reason: 'max_cycles_or_rss',
|
|
607
|
+
args: args,
|
|
608
|
+
logPath: getEvolverLogPath(),
|
|
609
|
+
});
|
|
610
|
+
if (result.spawned) {
|
|
469
611
|
releaseLock();
|
|
470
612
|
process.exit(0);
|
|
471
|
-
}
|
|
472
|
-
console.
|
|
613
|
+
} else if (result.reason === 'windows_default_skip') {
|
|
614
|
+
console.log('[Daemon] Exiting with code 1 to let external supervisor respawn.');
|
|
615
|
+
releaseLock();
|
|
616
|
+
process.exit(1);
|
|
617
|
+
} else {
|
|
618
|
+
// Non-Windows spawn error: keep the lock and fall through to
|
|
619
|
+
// the next iteration of the loop instead of leaving the daemon
|
|
620
|
+
// dead. This matches the pre-1.79.1 behavior where a failed
|
|
621
|
+
// spawn was logged and the process continued running.
|
|
622
|
+
console.error('[Daemon] Spawn failed, continuing current process.');
|
|
473
623
|
}
|
|
474
624
|
}
|
|
475
625
|
}
|
|
@@ -496,6 +646,13 @@ async function main() {
|
|
|
496
646
|
const signals = getLastSignals(solidifyStatePath).join(',');
|
|
497
647
|
console.log(`[Verbose] cycle=${cycleCount} ok=${ok} dt=${dt}ms sleep=${totalSleepMs}ms (base=${currentSleepMs} jitter=${jitter} sat=${saturationMultiplier}x) rss=${memMb}MB signals=[${signals}]`);
|
|
498
648
|
}
|
|
649
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
650
|
+
pid: process.pid,
|
|
651
|
+
outer_cycle: cycleCount,
|
|
652
|
+
inner_cycle: cycleCount,
|
|
653
|
+
started_at: t0,
|
|
654
|
+
phase: 'sleep',
|
|
655
|
+
});
|
|
499
656
|
await sleepMs(totalSleepMs);
|
|
500
657
|
|
|
501
658
|
} catch (loopErr) {
|
|
@@ -1581,4 +1738,8 @@ module.exports = {
|
|
|
1581
1738
|
readJsonSafe,
|
|
1582
1739
|
rejectPendingRun,
|
|
1583
1740
|
isPendingSolidify,
|
|
1741
|
+
parseBoolEnv,
|
|
1742
|
+
CycleTimeoutError,
|
|
1743
|
+
writeCycleProgressAtomic,
|
|
1744
|
+
spawnReplacementProcess,
|
|
1584
1745
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.79.1",
|
|
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": {
|