@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 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
- // Hardened Env Loading: Ensure .env is loaded before anything else
6
- try { require('dotenv').config({ path: path.resolve(__dirname, './.env') }); } catch (e) { console.warn('[Evolver] Warning: dotenv not found or failed to load .env'); }
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
- fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + '\n', 'utf8');
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 = 'false';
124
- console.log('Loop mode enabled (internal daemon).');
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.30.2",
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 = process.env.OPENCLAW_WORKSPACE || path.resolve(REPO_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 = [];
@@ -778,6 +778,7 @@ module.exports = {
778
778
  consumeOverdueTasks,
779
779
  getSkillStoreHint,
780
780
  queueCommitmentUpdate,
781
+ getHubUrl,
781
782
  getHubNodeSecret,
782
783
  buildHubHeaders,
783
784
  getNoveltyHint,
@@ -383,12 +383,12 @@ function readStateForSolidify() {
383
383
  }
384
384
 
385
385
  function writeStateForSolidify(state) {
386
- const memoryDir = getMemoryDir();
387
- const statePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
386
+ const evolutionDir = getEvolutionDir();
387
+ const statePath = path.join(evolutionDir, 'evolution_solidify_state.json');
388
388
  try {
389
- if (!fs.existsSync(memoryDir)) fs.mkdirSync(memoryDir, { recursive: true });
389
+ if (!fs.existsSync(evolutionDir)) fs.mkdirSync(evolutionDir, { recursive: true });
390
390
  } catch (e) {
391
- console.warn('[evolver] writeStateForSolidify mkdir failed:', memoryDir, e && e.message || e);
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');