@evomap/evolver 1.30.2 → 1.31.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/index.js +124 -6
- package/package.json +1 -1
- package/src/evolve.js +2 -3
- package/src/gep/a2aProtocol.js +1 -0
- package/src/gep/solidify.js +4 -4
package/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
const evolve = require('./src/evolve');
|
|
3
3
|
const { solidify } = require('./src/gep/solidify');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
|
|
6
|
-
try { require('dotenv').config({ path: path.
|
|
5
|
+
const { getRepoRoot } = require('./src/gep/paths');
|
|
6
|
+
try { require('dotenv').config({ path: path.join(getRepoRoot(), '.env') }); } catch (e) { console.warn('[Evolver] Warning: dotenv not found or failed to load .env'); }
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const { spawn } = require('child_process');
|
|
9
9
|
|
|
@@ -24,6 +24,11 @@ function readJsonSafe(p) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Mark a pending evolution run as rejected (state-only, no git rollback).
|
|
29
|
+
* @param {string} statePath - Path to evolution_solidify_state.json
|
|
30
|
+
* @returns {boolean} true if a pending run was found and rejected
|
|
31
|
+
*/
|
|
27
32
|
function rejectPendingRun(statePath) {
|
|
28
33
|
try {
|
|
29
34
|
const state = readJsonSafe(statePath);
|
|
@@ -34,7 +39,9 @@ function rejectPendingRun(statePath) {
|
|
|
34
39
|
reason: 'loop_bridge_disabled_autoreject_no_rollback',
|
|
35
40
|
timestamp: new Date().toISOString(),
|
|
36
41
|
};
|
|
37
|
-
|
|
42
|
+
const tmp = `${statePath}.tmp`;
|
|
43
|
+
fs.writeFileSync(tmp, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
44
|
+
fs.renameSync(tmp, statePath);
|
|
38
45
|
return true;
|
|
39
46
|
}
|
|
40
47
|
} catch (e) {
|
|
@@ -120,8 +127,10 @@ async function main() {
|
|
|
120
127
|
process.on('SIGTERM', () => { releaseLock(); process.exit(); });
|
|
121
128
|
|
|
122
129
|
process.env.EVOLVE_LOOP = 'true';
|
|
123
|
-
process.env.EVOLVE_BRIDGE
|
|
124
|
-
|
|
130
|
+
if (!process.env.EVOLVE_BRIDGE) {
|
|
131
|
+
process.env.EVOLVE_BRIDGE = 'false';
|
|
132
|
+
}
|
|
133
|
+
console.log(`Loop mode enabled (internal daemon, bridge=${process.env.EVOLVE_BRIDGE}).`);
|
|
125
134
|
|
|
126
135
|
const { getEvolutionDir } = require('./src/gep/paths');
|
|
127
136
|
const solidifyStatePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
|
|
@@ -458,6 +467,112 @@ async function main() {
|
|
|
458
467
|
console.log('To reject and rollback: node index.js review --reject');
|
|
459
468
|
}
|
|
460
469
|
|
|
470
|
+
} else if (command === 'fetch') {
|
|
471
|
+
let skillId = null;
|
|
472
|
+
const eqFlag = args.find(a => typeof a === 'string' && (a.startsWith('--skill=') || a.startsWith('-s=')));
|
|
473
|
+
if (eqFlag) {
|
|
474
|
+
skillId = eqFlag.split('=').slice(1).join('=');
|
|
475
|
+
} else {
|
|
476
|
+
const sIdx = args.indexOf('-s');
|
|
477
|
+
const longIdx = args.indexOf('--skill');
|
|
478
|
+
const flagIdx = sIdx !== -1 ? sIdx : longIdx;
|
|
479
|
+
if (flagIdx !== -1 && args[flagIdx + 1] && !String(args[flagIdx + 1]).startsWith('-')) {
|
|
480
|
+
skillId = args[flagIdx + 1];
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (!skillId) {
|
|
484
|
+
const positional = args[1];
|
|
485
|
+
if (positional && !String(positional).startsWith('-')) skillId = positional;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (!skillId) {
|
|
489
|
+
console.error('Usage: evolver fetch --skill <skill_id>');
|
|
490
|
+
console.error(' evolver fetch -s <skill_id>');
|
|
491
|
+
process.exit(1);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const { getHubUrl, getNodeId, buildHubHeaders, sendHelloToHub, getHubNodeSecret } = require('./src/gep/a2aProtocol');
|
|
495
|
+
|
|
496
|
+
const hubUrl = getHubUrl();
|
|
497
|
+
if (!hubUrl) {
|
|
498
|
+
console.error('[fetch] A2A_HUB_URL is not configured.');
|
|
499
|
+
console.error('Set it via environment variable or .env file:');
|
|
500
|
+
console.error(' export A2A_HUB_URL=https://evomap.ai');
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
try {
|
|
505
|
+
if (!getHubNodeSecret()) {
|
|
506
|
+
console.log('[fetch] No node_secret found. Sending hello to Hub to register...');
|
|
507
|
+
const helloResult = await sendHelloToHub();
|
|
508
|
+
if (!helloResult || !helloResult.ok) {
|
|
509
|
+
console.error('[fetch] Failed to register with Hub:', helloResult && helloResult.error || 'unknown');
|
|
510
|
+
process.exit(1);
|
|
511
|
+
}
|
|
512
|
+
console.log('[fetch] Registered as ' + getNodeId());
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const endpoint = hubUrl.replace(/\/+$/, '') + '/a2a/skill/store/' + encodeURIComponent(skillId) + '/download';
|
|
516
|
+
const nodeId = getNodeId();
|
|
517
|
+
|
|
518
|
+
console.log('[fetch] Downloading skill: ' + skillId);
|
|
519
|
+
|
|
520
|
+
const resp = await fetch(endpoint, {
|
|
521
|
+
method: 'POST',
|
|
522
|
+
headers: buildHubHeaders(),
|
|
523
|
+
body: JSON.stringify({ sender_id: nodeId }),
|
|
524
|
+
signal: AbortSignal.timeout(30000),
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
if (!resp.ok) {
|
|
528
|
+
const body = await resp.text().catch(() => '');
|
|
529
|
+
let msg = 'HTTP ' + resp.status;
|
|
530
|
+
try { const j = JSON.parse(body); msg = j.error || j.message || msg; } catch (_) {}
|
|
531
|
+
console.error('[fetch] Download failed: ' + msg);
|
|
532
|
+
if (resp.status === 404) console.error(' Skill not found or not publicly available.');
|
|
533
|
+
if (resp.status === 401) console.error(' Authentication failed. Try deleting ~/.evomap/node_secret and retry.');
|
|
534
|
+
if (resp.status === 402) console.error(' Insufficient credits.');
|
|
535
|
+
process.exit(1);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const data = await resp.json();
|
|
539
|
+
const outFlag = args.find(a => typeof a === 'string' && a.startsWith('--out='));
|
|
540
|
+
const safeId = String(data.skill_id || skillId).replace(/[^a-zA-Z0-9_\-\.]/g, '_');
|
|
541
|
+
const outDir = outFlag
|
|
542
|
+
? outFlag.slice('--out='.length)
|
|
543
|
+
: path.join('.', 'skills', safeId);
|
|
544
|
+
|
|
545
|
+
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
546
|
+
|
|
547
|
+
if (data.content) {
|
|
548
|
+
fs.writeFileSync(path.join(outDir, 'SKILL.md'), data.content, 'utf8');
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const bundled = Array.isArray(data.bundled_files) ? data.bundled_files : [];
|
|
552
|
+
for (const file of bundled) {
|
|
553
|
+
if (!file || !file.name || typeof file.content !== 'string') continue;
|
|
554
|
+
const safeName = path.basename(file.name);
|
|
555
|
+
fs.writeFileSync(path.join(outDir, safeName), file.content, 'utf8');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
console.log('[fetch] Skill downloaded to: ' + outDir);
|
|
559
|
+
console.log(' Name: ' + (data.name || skillId));
|
|
560
|
+
console.log(' Version: ' + (data.version || '?'));
|
|
561
|
+
console.log(' Files: SKILL.md' + (bundled.length > 0 ? ', ' + bundled.map(f => f.name).join(', ') : ''));
|
|
562
|
+
if (data.already_purchased) {
|
|
563
|
+
console.log(' Cost: free (already purchased)');
|
|
564
|
+
} else {
|
|
565
|
+
console.log(' Cost: ' + (data.credit_cost || 0) + ' credits');
|
|
566
|
+
}
|
|
567
|
+
} catch (error) {
|
|
568
|
+
if (error && error.name === 'TimeoutError') {
|
|
569
|
+
console.error('[fetch] Request timed out. Check your network and A2A_HUB_URL.');
|
|
570
|
+
} else {
|
|
571
|
+
console.error('[fetch] Error:', error && error.message || error);
|
|
572
|
+
}
|
|
573
|
+
process.exit(1);
|
|
574
|
+
}
|
|
575
|
+
|
|
461
576
|
} else if (command === 'asset-log') {
|
|
462
577
|
const { summarizeCallLog, readCallLog, getLogPath } = require('./src/gep/assetCallLog');
|
|
463
578
|
|
|
@@ -502,7 +617,10 @@ async function main() {
|
|
|
502
617
|
}
|
|
503
618
|
|
|
504
619
|
} else {
|
|
505
|
-
console.log(`Usage: node index.js [run|/evolve|solidify|review|distill|asset-log] [--loop]
|
|
620
|
+
console.log(`Usage: node index.js [run|/evolve|solidify|review|distill|fetch|asset-log] [--loop]
|
|
621
|
+
- fetch flags:
|
|
622
|
+
- --skill=<id> | -s <id> (skill ID to download)
|
|
623
|
+
- --out=<dir> (output directory, default: ./skills/<skill_id>)
|
|
506
624
|
- solidify flags:
|
|
507
625
|
- --dry-run
|
|
508
626
|
- --no-rollback
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.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": {
|
package/src/evolve.js
CHANGED
|
@@ -2,7 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
|
-
const { getRepoRoot, getMemoryDir, getSessionScope } = require('./gep/paths');
|
|
5
|
+
const { getRepoRoot, getWorkspaceRoot, getMemoryDir, getSessionScope } = require('./gep/paths');
|
|
6
6
|
const { extractSignals } = require('./gep/signals');
|
|
7
7
|
const {
|
|
8
8
|
loadGenes,
|
|
@@ -492,7 +492,7 @@ function clearDormantHypothesis() {
|
|
|
492
492
|
}
|
|
493
493
|
// Read MEMORY.md and USER.md from the WORKSPACE root (not the evolver plugin dir).
|
|
494
494
|
// This avoids symlink breakage if the target file is temporarily deleted.
|
|
495
|
-
const WORKSPACE_ROOT =
|
|
495
|
+
const WORKSPACE_ROOT = getWorkspaceRoot();
|
|
496
496
|
const ROOT_MEMORY = path.join(WORKSPACE_ROOT, 'MEMORY.md');
|
|
497
497
|
const DIR_MEMORY = path.join(MEMORY_DIR, 'MEMORY.md');
|
|
498
498
|
const MEMORY_FILE = fs.existsSync(ROOT_MEMORY) ? ROOT_MEMORY : (fs.existsSync(DIR_MEMORY) ? DIR_MEMORY : ROOT_MEMORY);
|
|
@@ -1532,7 +1532,6 @@ async function run() {
|
|
|
1532
1532
|
try {
|
|
1533
1533
|
const runId = `run_${Date.now()}`;
|
|
1534
1534
|
const parentEventId = getLastEventId();
|
|
1535
|
-
const selectedBy = memoryAdvice && memoryAdvice.preferredGeneId ? 'memory_graph+selector' : 'selector';
|
|
1536
1535
|
|
|
1537
1536
|
// Baseline snapshot (before any edits).
|
|
1538
1537
|
let baselineUntracked = [];
|
package/src/gep/a2aProtocol.js
CHANGED
package/src/gep/solidify.js
CHANGED
|
@@ -383,12 +383,12 @@ function readStateForSolidify() {
|
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
function writeStateForSolidify(state) {
|
|
386
|
-
const
|
|
387
|
-
const statePath = path.join(
|
|
386
|
+
const evolutionDir = getEvolutionDir();
|
|
387
|
+
const statePath = path.join(evolutionDir, 'evolution_solidify_state.json');
|
|
388
388
|
try {
|
|
389
|
-
if (!fs.existsSync(
|
|
389
|
+
if (!fs.existsSync(evolutionDir)) fs.mkdirSync(evolutionDir, { recursive: true });
|
|
390
390
|
} catch (e) {
|
|
391
|
-
console.warn('[evolver] writeStateForSolidify mkdir failed:',
|
|
391
|
+
console.warn('[evolver] writeStateForSolidify mkdir failed:', evolutionDir, e && e.message || e);
|
|
392
392
|
}
|
|
393
393
|
const tmp = `${statePath}.tmp`;
|
|
394
394
|
fs.writeFileSync(tmp, JSON.stringify(state, null, 2) + '\n', 'utf8');
|