@evomap/evolver 1.78.9 → 1.79.0
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/index.js +177 -7
- 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/assets/gep/candidates.jsonl +0 -1
- package/assets/gep/capsules.json +0 -4
- package/assets/gep/events.jsonl +0 -0
- package/assets/gep/failed_capsules.json +0 -4
- package/assets/gep/genes.json +0 -201
- package/assets/gep/genes.jsonl +0 -0
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
|
|
package/index.js
CHANGED
|
@@ -104,6 +104,42 @@ 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
|
+
// Atomic write of the cycle_progress.json file. Wrapper polls this file every
|
|
128
|
+
// 60s; if updated_at goes stale beyond EVOLVE_INNER_STUCK_TIMEOUT_SEC the
|
|
129
|
+
// wrapper treats the inner core as zombie and SIGKILLs it. See Issue #19 (the
|
|
130
|
+
// 22-day stuck-cycle incident) and the cross-repo timeout plan for context.
|
|
131
|
+
function writeCycleProgressAtomic(progressPath, fields) {
|
|
132
|
+
try {
|
|
133
|
+
const data = Object.assign({}, fields, { updated_at: Date.now() });
|
|
134
|
+
const tmp = progressPath + '.tmp.' + process.pid;
|
|
135
|
+
fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
136
|
+
fs.renameSync(tmp, progressPath);
|
|
137
|
+
return true;
|
|
138
|
+
} catch (e) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
107
143
|
function getLastSignals(statePath) {
|
|
108
144
|
try {
|
|
109
145
|
const st = readJsonSafe(statePath);
|
|
@@ -255,6 +291,7 @@ async function main() {
|
|
|
255
291
|
|
|
256
292
|
const { getEvolutionDir, getEvolverLogPath } = require('./src/gep/paths');
|
|
257
293
|
const solidifyStatePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
|
|
294
|
+
const cycleProgressPath = path.join(getEvolutionDir(), 'cycle_progress.json');
|
|
258
295
|
|
|
259
296
|
const minSleepMs = parseMs(process.env.EVOLVER_MIN_SLEEP_MS, 2000);
|
|
260
297
|
const maxSleepMs = parseMs(process.env.EVOLVER_MAX_SLEEP_MS, 300000);
|
|
@@ -270,6 +307,15 @@ async function main() {
|
|
|
270
307
|
const maxRssMb = parseMs(process.env.EVOLVER_MAX_RSS_MB, 500) || 500;
|
|
271
308
|
const suicideEnabled = String(process.env.EVOLVER_SUICIDE || '').toLowerCase() !== 'false';
|
|
272
309
|
|
|
310
|
+
// Issue #19: hard timeout around evolve.run() to break out of zombie
|
|
311
|
+
// cycles (e.g. unclosed socket / stuck LLM call). On timeout we throw
|
|
312
|
+
// CycleTimeoutError, log diagnostic stderr, and force suicide-respawn
|
|
313
|
+
// so the wrapper sees a fresh PID + cycle. Also write cycle_progress
|
|
314
|
+
// every progressUpdateMs so the wrapper has a true heartbeat to poll.
|
|
315
|
+
const cycleTimeoutEnabled = parseBoolEnv(process.env.EVOLVER_CYCLE_TIMEOUT_ENABLED, true);
|
|
316
|
+
const cycleTimeoutMs = parseMs(process.env.EVOLVER_CYCLE_TIMEOUT_MS, 2700000); // 45 min default
|
|
317
|
+
const progressUpdateMs = parseMs(process.env.EVOLVER_PROGRESS_UPDATE_MS, 60000); // 1 min default
|
|
318
|
+
|
|
273
319
|
// Start hub heartbeat (keeps node alive independently of evolution cycles)
|
|
274
320
|
try {
|
|
275
321
|
if (process.env.EVOMAP_PROXY === '1' || process.env.A2A_TRANSPORT === 'mailbox') {
|
|
@@ -388,8 +434,46 @@ async function main() {
|
|
|
388
434
|
|
|
389
435
|
const t0 = Date.now();
|
|
390
436
|
let ok = false;
|
|
437
|
+
// Issue #19: write progress at cycle start, refresh it every
|
|
438
|
+
// progressUpdateMs (default 60s) while evolve.run() is active, and
|
|
439
|
+
// wrap evolve.run() with Promise.race(timeout) so a hung internal
|
|
440
|
+
// call cannot freeze the daemon for days.
|
|
441
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
442
|
+
pid: process.pid,
|
|
443
|
+
outer_cycle: cycleCount,
|
|
444
|
+
inner_cycle: cycleCount,
|
|
445
|
+
started_at: t0,
|
|
446
|
+
phase: 'evolve.run',
|
|
447
|
+
});
|
|
448
|
+
let progressTicker = null;
|
|
449
|
+
if (progressUpdateMs > 0) {
|
|
450
|
+
progressTicker = setInterval(function () {
|
|
451
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
452
|
+
pid: process.pid,
|
|
453
|
+
outer_cycle: cycleCount,
|
|
454
|
+
inner_cycle: cycleCount,
|
|
455
|
+
started_at: t0,
|
|
456
|
+
phase: 'evolve.run',
|
|
457
|
+
});
|
|
458
|
+
}, progressUpdateMs);
|
|
459
|
+
if (typeof progressTicker.unref === 'function') progressTicker.unref();
|
|
460
|
+
}
|
|
461
|
+
let cycleTimeoutHandle = null;
|
|
462
|
+
let cycleTimedOut = false;
|
|
391
463
|
try {
|
|
392
|
-
|
|
464
|
+
const evolvePromise = evolve.run();
|
|
465
|
+
if (cycleTimeoutEnabled && cycleTimeoutMs > 0) {
|
|
466
|
+
const timeoutPromise = new Promise(function (_, reject) {
|
|
467
|
+
cycleTimeoutHandle = setTimeout(function () {
|
|
468
|
+
cycleTimedOut = true;
|
|
469
|
+
reject(new CycleTimeoutError(cycleTimeoutMs, 'evolve.run', cycleCount));
|
|
470
|
+
}, cycleTimeoutMs);
|
|
471
|
+
if (cycleTimeoutHandle && typeof cycleTimeoutHandle.unref === 'function') cycleTimeoutHandle.unref();
|
|
472
|
+
});
|
|
473
|
+
await Promise.race([evolvePromise, timeoutPromise]);
|
|
474
|
+
} else {
|
|
475
|
+
await evolvePromise;
|
|
476
|
+
}
|
|
393
477
|
ok = true;
|
|
394
478
|
|
|
395
479
|
if (String(process.env.EVOLVE_BRIDGE || '').toLowerCase() === 'false') {
|
|
@@ -403,7 +487,37 @@ async function main() {
|
|
|
403
487
|
}
|
|
404
488
|
} catch (error) {
|
|
405
489
|
const msg = error && error.message ? String(error.message) : String(error);
|
|
490
|
+
if (error && error.code === 'CYCLE_TIMEOUT') {
|
|
491
|
+
console.error('[Daemon] ' + msg);
|
|
492
|
+
if (progressTicker) { clearInterval(progressTicker); progressTicker = null; }
|
|
493
|
+
if (cycleTimeoutHandle) { clearTimeout(cycleTimeoutHandle); cycleTimeoutHandle = null; }
|
|
494
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
495
|
+
pid: process.pid,
|
|
496
|
+
outer_cycle: cycleCount,
|
|
497
|
+
inner_cycle: cycleCount,
|
|
498
|
+
started_at: t0,
|
|
499
|
+
phase: 'cycle_timeout_respawn',
|
|
500
|
+
});
|
|
501
|
+
try {
|
|
502
|
+
const logFd = fs.openSync(getEvolverLogPath(), 'a');
|
|
503
|
+
const spawnOpts = {
|
|
504
|
+
detached: true,
|
|
505
|
+
stdio: ['ignore', logFd, logFd],
|
|
506
|
+
env: process.env,
|
|
507
|
+
windowsHide: true,
|
|
508
|
+
};
|
|
509
|
+
const child = spawn(process.execPath, [__filename, ...args], spawnOpts);
|
|
510
|
+
child.unref();
|
|
511
|
+
} catch (spawnErr) {
|
|
512
|
+
console.error('[Daemon] Force-restart spawn after cycle timeout failed: ' + (spawnErr && spawnErr.message || spawnErr));
|
|
513
|
+
}
|
|
514
|
+
releaseLock();
|
|
515
|
+
process.exit(1);
|
|
516
|
+
}
|
|
406
517
|
console.error(`Evolution cycle failed: ${msg}`);
|
|
518
|
+
} finally {
|
|
519
|
+
if (progressTicker) { clearInterval(progressTicker); progressTicker = null; }
|
|
520
|
+
if (cycleTimeoutHandle) { clearTimeout(cycleTimeoutHandle); cycleTimeoutHandle = null; }
|
|
407
521
|
}
|
|
408
522
|
const dt = Date.now() - t0;
|
|
409
523
|
|
|
@@ -496,6 +610,13 @@ async function main() {
|
|
|
496
610
|
const signals = getLastSignals(solidifyStatePath).join(',');
|
|
497
611
|
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
612
|
}
|
|
613
|
+
writeCycleProgressAtomic(cycleProgressPath, {
|
|
614
|
+
pid: process.pid,
|
|
615
|
+
outer_cycle: cycleCount,
|
|
616
|
+
inner_cycle: cycleCount,
|
|
617
|
+
started_at: t0,
|
|
618
|
+
phase: 'sleep',
|
|
619
|
+
});
|
|
499
620
|
await sleepMs(totalSleepMs);
|
|
500
621
|
|
|
501
622
|
} catch (loopErr) {
|
|
@@ -1097,6 +1218,7 @@ async function main() {
|
|
|
1097
1218
|
})();
|
|
1098
1219
|
const dryRun = args.includes('--dry-run');
|
|
1099
1220
|
const listUnpublished = !args.includes('--no-unpublished-list');
|
|
1221
|
+
const force = args.includes('--force');
|
|
1100
1222
|
const limitPerPage = 100;
|
|
1101
1223
|
|
|
1102
1224
|
const validScopes = new Set(['all', 'purchased', 'published']);
|
|
@@ -1173,11 +1295,25 @@ async function main() {
|
|
|
1173
1295
|
|
|
1174
1296
|
const existingGenes = loadGenes();
|
|
1175
1297
|
const existingCapsules = loadCapsules();
|
|
1298
|
+
// Dedup by Hub asset_id is the only safe key. Local-facing `id` (e.g.
|
|
1299
|
+
// `gene_gep_repair_from_errors`) collides between bundled default seed
|
|
1300
|
+
// genes and identically-named assets that the user later published, so
|
|
1301
|
+
// dedup-by-id silently skips legitimate Hub copies on first sync. Track
|
|
1302
|
+
// hub_asset_id (set by previous syncs / publishes) and only skip when
|
|
1303
|
+
// we've already seen the same Hub-side identity.
|
|
1304
|
+
const localHubAssetIds = new Set();
|
|
1305
|
+
for (const g of existingGenes) {
|
|
1306
|
+
if (g && g.hub_asset_id) localHubAssetIds.add(String(g.hub_asset_id));
|
|
1307
|
+
}
|
|
1308
|
+
for (const c of existingCapsules) {
|
|
1309
|
+
if (c && c.hub_asset_id) localHubAssetIds.add(String(c.hub_asset_id));
|
|
1310
|
+
}
|
|
1176
1311
|
const localGeneIds = new Set(existingGenes.filter(function (g) { return g && g.id; }).map(function (g) { return g.id; }));
|
|
1177
1312
|
const localCapsuleIds = new Set(existingCapsules.filter(function (c) { return c && c.id; }).map(function (c) { return c.id; }));
|
|
1178
1313
|
|
|
1179
1314
|
let synced = 0;
|
|
1180
|
-
let
|
|
1315
|
+
let skippedAlreadySynced = 0;
|
|
1316
|
+
let skippedIdCollision = 0;
|
|
1181
1317
|
let fetchErrors = 0;
|
|
1182
1318
|
|
|
1183
1319
|
for (const asset of allAssets) {
|
|
@@ -1186,14 +1322,37 @@ async function main() {
|
|
|
1186
1322
|
const localId = asset.local_id || assetId;
|
|
1187
1323
|
|
|
1188
1324
|
if (assetType !== 'Gene' && assetType !== 'Capsule') {
|
|
1189
|
-
|
|
1325
|
+
skippedAlreadySynced++;
|
|
1326
|
+
continue;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// Already-synced check: same Hub asset_id is already in our local
|
|
1330
|
+
// store. Idempotent skip; safe to no-op even with --force because
|
|
1331
|
+
// re-fetching the same payload would only rewrite identical bytes.
|
|
1332
|
+
if (!force && localHubAssetIds.has(String(assetId))) {
|
|
1333
|
+
skippedAlreadySynced++;
|
|
1190
1334
|
continue;
|
|
1191
1335
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1336
|
+
|
|
1337
|
+
// Local-id collision: a local entry with the same user-facing id
|
|
1338
|
+
// already exists but has no hub_asset_id (e.g. bundled default seed
|
|
1339
|
+
// gene, or a hand-edited entry). Without --force we keep the
|
|
1340
|
+
// user-owned entry and warn so the user can decide.
|
|
1341
|
+
if (!force) {
|
|
1342
|
+
if (assetType === 'Gene' && localGeneIds.has(localId)) {
|
|
1343
|
+
if (isVerbose) console.warn(' [sync] Skipping ' + localId + ' (local id collision; pass --force to overwrite with Hub copy)');
|
|
1344
|
+
skippedIdCollision++;
|
|
1345
|
+
continue;
|
|
1346
|
+
}
|
|
1347
|
+
if (assetType === 'Capsule' && localCapsuleIds.has(localId)) {
|
|
1348
|
+
if (isVerbose) console.warn(' [sync] Skipping ' + localId + ' (local id collision; pass --force to overwrite with Hub copy)');
|
|
1349
|
+
skippedIdCollision++;
|
|
1350
|
+
continue;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1194
1353
|
|
|
1195
1354
|
if (dryRun) {
|
|
1196
|
-
console.log(' [dry-run] Would sync: ' + assetType + ' ' + assetId);
|
|
1355
|
+
console.log(' [dry-run] Would sync: ' + assetType + ' ' + assetId + (force ? ' (force)' : ''));
|
|
1197
1356
|
synced++;
|
|
1198
1357
|
continue;
|
|
1199
1358
|
}
|
|
@@ -1230,6 +1389,7 @@ async function main() {
|
|
|
1230
1389
|
};
|
|
1231
1390
|
upsertGene(geneObj);
|
|
1232
1391
|
localGeneIds.add(geneObj.id);
|
|
1392
|
+
localHubAssetIds.add(String(assetId));
|
|
1233
1393
|
} else {
|
|
1234
1394
|
const capsuleObj = {
|
|
1235
1395
|
type: 'Capsule',
|
|
@@ -1244,6 +1404,7 @@ async function main() {
|
|
|
1244
1404
|
};
|
|
1245
1405
|
upsertCapsule(capsuleObj);
|
|
1246
1406
|
localCapsuleIds.add(capsuleObj.id);
|
|
1407
|
+
localHubAssetIds.add(String(assetId));
|
|
1247
1408
|
}
|
|
1248
1409
|
synced++;
|
|
1249
1410
|
} catch (fetchErr) {
|
|
@@ -1252,7 +1413,12 @@ async function main() {
|
|
|
1252
1413
|
}
|
|
1253
1414
|
}
|
|
1254
1415
|
|
|
1255
|
-
|
|
1416
|
+
const skippedTotal = skippedAlreadySynced + skippedIdCollision;
|
|
1417
|
+
console.log('[sync] Done. scope=' + scopeArg + ' synced=' + synced + ' skipped=' + skippedTotal + ' (already_synced=' + skippedAlreadySynced + ', id_collision=' + skippedIdCollision + ') errors=' + fetchErrors);
|
|
1418
|
+
if (skippedIdCollision > 0 && !force) {
|
|
1419
|
+
console.log('[sync] ' + skippedIdCollision + ' Hub asset(s) share a local id with an existing local entry that has no hub_asset_id.');
|
|
1420
|
+
console.log('[sync] Re-run with --force to overwrite those local entries with the Hub copies.');
|
|
1421
|
+
}
|
|
1256
1422
|
if (dryRun) console.log('[sync] (dry-run mode: no files were modified)');
|
|
1257
1423
|
|
|
1258
1424
|
if (listUnpublished && doPublished) {
|
|
@@ -1467,6 +1633,7 @@ async function main() {
|
|
|
1467
1633
|
- --status=draft,promoted,all (only for published scope; default promoted+draft)
|
|
1468
1634
|
- --export=<path.gepx> (also bundle local assets into a .gepx archive)
|
|
1469
1635
|
- --no-unpublished-list (suppress local-only asset list)
|
|
1636
|
+
- --force (overwrite local entries that share an id with a Hub asset; bypasses default-seed dedup)
|
|
1470
1637
|
- --dry-run (preview without writing to local store)
|
|
1471
1638
|
- solidify flags:
|
|
1472
1639
|
- --dry-run
|
|
@@ -1535,4 +1702,7 @@ module.exports = {
|
|
|
1535
1702
|
readJsonSafe,
|
|
1536
1703
|
rejectPendingRun,
|
|
1537
1704
|
isPendingSolidify,
|
|
1705
|
+
parseBoolEnv,
|
|
1706
|
+
CycleTimeoutError,
|
|
1707
|
+
writeCycleProgressAtomic,
|
|
1538
1708
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.79.0",
|
|
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": {
|