Skip to content

Commit f9b6f0d

Browse files
author
evolver-publish
committed
Release v1.89.11
1 parent 51a7464 commit f9b6f0d

79 files changed

Lines changed: 1151 additions & 332 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.ja-JP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🧬 Evolver
22

3-
[![GitHub stars](https://img.shields.io/badge/Stars-8.6k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
3+
[![GitHub stars](https://img.shields.io/badge/Stars-8.7k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
44
[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0)
55
[![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
66
[![npm downloads](https://img.shields.io/npm/dm/@evomap/evolver.svg)](https://www.npmjs.com/package/@evomap/evolver)

README.ko-KR.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🧬 Evolver
22

3-
[![GitHub stars](https://img.shields.io/badge/Stars-8.6k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
3+
[![GitHub stars](https://img.shields.io/badge/Stars-8.7k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
44
[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0)
55
[![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
66
[![npm downloads](https://img.shields.io/npm/dm/@evomap/evolver.svg)](https://www.npmjs.com/package/@evomap/evolver)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🧬 Evolver
22

3-
[![GitHub stars](https://img.shields.io/badge/Stars-8.6k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
3+
[![GitHub stars](https://img.shields.io/badge/Stars-8.7k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
44
[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0)
55
[![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
66
[![npm downloads](https://img.shields.io/npm/dm/@evomap/evolver.svg)](https://www.npmjs.com/package/@evomap/evolver)
@@ -416,6 +416,7 @@ Evolver is designed to be **environment-agnostic**.
416416
| `EVOLVE_STRATEGY` | Evolution strategy preset (`balanced` / `innovate` / `harden` / `repair-only`) | `balanced` |
417417
| `A2A_HUB_URL` | [EvoMap Hub](https://evomap.ai) URL | _(unset, offline mode)_ |
418418
| `A2A_NODE_ID` | Your node identity on the network | _(auto-generated from device fingerprint)_ |
419+
| `EVOMAP_HUB_IP_FAMILY` | Hub egress IP-family policy: `ipv4first` tries IPv4 first and falls back to dual-stack, `auto` uses dual-stack as the primary path, `ipv4-only` disables fallback | `ipv4first` |
419420
| `HEARTBEAT_INTERVAL_MS` | Hub heartbeat interval | `360000` (6 min) |
420421
| `MEMORY_DIR` | Memory files path | `./memory` |
421422
| `EVOLVE_REPORT_TOOL` | Tool name for reporting results | `message` |

README.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🧬 Evolver
22

3-
[![GitHub stars](https://img.shields.io/badge/Stars-8.6k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
3+
[![GitHub stars](https://img.shields.io/badge/Stars-8.7k-2b3137?logo=github&logoColor=white)](https://github.com/EvoMap/evolver/stargazers)
44
[![License: GPL-3.0](https://img.shields.io/badge/License-GPL--3.0-blue.svg)](https://opensource.org/licenses/GPL-3.0)
55
[![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
66
[![npm downloads](https://img.shields.io/npm/dm/@evomap/evolver.svg)](https://www.npmjs.com/package/@evomap/evolver)

assets/cover.png

129 KB
Loading

index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,7 @@ async function main() {
20422042
}
20432043

20442044
const { getHubUrl, getNodeId, buildHubHeaders, sendHelloToHub, getHubNodeSecret } = require('./src/gep/a2aProtocol');
2045+
const { hubFetch } = require('./src/gep/hubFetch');
20452046

20462047
const hubUrl = getHubUrl();
20472048
if (!hubUrl) {
@@ -2071,7 +2072,7 @@ async function main() {
20712072

20722073
console.log('[fetch] Downloading skill: ' + skillId);
20732074

2074-
const resp = await fetch(endpoint, {
2075+
const resp = await hubFetch(endpoint, {
20752076
method: 'POST',
20762077
headers: buildHubHeaders(),
20772078
body: JSON.stringify({ sender_id: nodeId }),
@@ -2253,6 +2254,7 @@ async function main() {
22532254

22542255
} else if (command === 'sync') {
22552256
const { getHubUrl, getNodeId, buildHubHeaders, sendHelloToHub, getHubNodeSecret } = require('./src/gep/a2aProtocol');
2257+
const { hubFetch } = require('./src/gep/hubFetch');
22562258
const { upsertGene, upsertCapsule, loadGenes, loadCapsules } = require('./src/gep/assetStore');
22572259
const { getGepAssetsDir, getMemoryDir } = require('./src/gep/paths');
22582260

@@ -2321,7 +2323,7 @@ async function main() {
23212323
if (v != null) url += '&' + k + '=' + encodeURIComponent(v);
23222324
}
23232325
}
2324-
const resp = await fetch(url, {
2326+
const resp = await hubFetch(url, {
23252327
method: 'GET',
23262328
headers: buildHubHeaders(),
23272329
signal: AbortSignal.timeout(30000),
@@ -2438,7 +2440,7 @@ async function main() {
24382440
try {
24392441
let payload = asset.payload;
24402442
if (!payload) {
2441-
const detailResp = await fetch(baseUrl + '/a2a/assets/' + encodeURIComponent(assetId) + '?detailed=true', {
2443+
const detailResp = await hubFetch(baseUrl + '/a2a/assets/' + encodeURIComponent(assetId) + '?detailed=true', {
24422444
method: 'GET',
24432445
headers: buildHubHeaders(),
24442446
signal: AbortSignal.timeout(15000),

package-lock.json

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@evomap/evolver",
3-
"version": "1.89.10",
3+
"version": "1.89.11",
44
"description": "A GEP-powered self-evolution engine for AI agents. Features automated log analysis and Genome Evolution Protocol (GEP) for auditable, reusable evolution assets.",
55
"main": "index.js",
66
"bin": {

src/adapters/scripts/evolver-session-end.js

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
const fs = require('fs');
99
const path = require('path');
1010
const os = require('os');
11-
const https = require('https');
12-
const http = require('http');
1311
const { spawnSync } = require('child_process');
1412
// 10 MB — prevents RangeError on large child process output (e.g. git log/diff
1513
// on large repos). See GHSA reports / issue #451.
@@ -113,15 +111,17 @@ function detectSignals(text) {
113111
return [...new Set(signals)];
114112
}
115113

116-
function recordToHub(outcome) {
114+
function loadHubFetch() {
115+
const evolverRoot = findEvolverRoot();
116+
return require(path.join(evolverRoot, 'src', 'gep', 'hubFetch')).hubFetch;
117+
}
118+
119+
async function recordToHub(outcome) {
117120
const hubUrl = process.env.EVOMAP_HUB_URL || process.env.A2A_HUB_URL;
118121
const apiKey = process.env.EVOMAP_API_KEY || process.env.A2A_NODE_SECRET;
119122
const nodeId = process.env.EVOMAP_NODE_ID || process.env.A2A_NODE_ID;
120123
if (!hubUrl || !apiKey) return false;
121124

122-
// Use Node.js built-in http/https instead of curl so this works on all
123-
// platforms, including Windows where curl may not be available or may be
124-
// an older, incompatible version bundled with some environments.
125125
try {
126126
const payload = JSON.stringify({
127127
gene_id: outcome.geneId || 'ad_hoc',
@@ -133,37 +133,18 @@ function recordToHub(outcome) {
133133
});
134134

135135
const endpoint = hubUrl.replace(/\/+$/, '') + '/a2a/evolution/record';
136-
let parsedUrl;
137-
try { parsedUrl = new URL(endpoint); } catch { return false; }
138-
139-
const isHttps = parsedUrl.protocol === 'https:';
140-
const transport = isHttps ? https : http;
141-
142-
return new Promise((resolve) => {
143-
const req = transport.request(
144-
{
145-
hostname: parsedUrl.hostname,
146-
port: parsedUrl.port || (isHttps ? 443 : 80),
147-
path: parsedUrl.pathname + (parsedUrl.search || ''),
148-
method: 'POST',
149-
headers: {
150-
'Content-Type': 'application/json',
151-
'Authorization': `Bearer ${apiKey}`,
152-
'Content-Length': Buffer.byteLength(payload),
153-
},
154-
timeout: 8000,
155-
},
156-
(res) => {
157-
// Drain the response to free the socket; we only care about status.
158-
res.resume();
159-
resolve(res.statusCode >= 200 && res.statusCode < 300);
160-
}
161-
);
162-
req.on('error', () => resolve(false));
163-
req.on('timeout', () => { req.destroy(); resolve(false); });
164-
req.write(payload);
165-
req.end();
136+
const hubFetch = loadHubFetch();
137+
const res = await hubFetch(endpoint, {
138+
method: 'POST',
139+
headers: {
140+
'Content-Type': 'application/json',
141+
'Authorization': `Bearer ${apiKey}`,
142+
},
143+
body: payload,
144+
signal: AbortSignal.timeout(8000),
166145
});
146+
try { await res.text(); } catch (_) {}
147+
return res.ok;
167148
} catch {
168149
return false;
169150
}
@@ -250,7 +231,7 @@ function main() {
250231
process.stdin.on('data', chunk => { inputData += chunk; });
251232
process.stdin.on('end', () => {
252233
if (handled) return;
253-
// recordToHub is async (uses Node.js http/https); wrap the rest of the
234+
// recordToHub is async (uses the shared Hub fetch transport); wrap the rest of the
254235
// handler in an immediately-invoked async function so we can await it
255236
// while still honouring the watchdog timeout and the `handled` guard.
256237
(async () => {

src/atp/atpExecute.js

Lines changed: 27 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,10 @@
2222
// idempotent server-side).
2323

2424
const fs = require('fs');
25-
const http = require('http');
26-
const https = require('https');
2725
const crypto = require('crypto');
2826

2927
const { computeAssetId } = require('../gep/contentHash');
30-
const { enforceHubScheme, strictHttpsAgent } = require('../gep/hubFetch');
28+
const { hubFetch } = require('../gep/hubFetch');
3129
const {
3230
getNodeId,
3331
getHubUrl,
@@ -126,77 +124,35 @@ function _publishUrl() {
126124
return base + '/a2a/publish';
127125
}
128126

129-
function _postJson(urlStr, body, timeoutMs) {
130-
return new Promise(function (resolve) {
131-
// Same TLS posture as hubFetch: refuse plain http:// unless
132-
// EVOMAP_HUB_ALLOW_INSECURE=1. Before this guard the function
133-
// silently fell back to `lib = http` for any non-https URL, so an
134-
// operator override `A2A_HUB_URL=http://...` would send /a2a/publish
135-
// and /a2a/task/complete in cleartext while hubFetch-routed calls
136-
// (e.g. /a2a/verify-solidify) refused the same URL — inconsistent
137-
// TLS enforcement across modules.
138-
try {
139-
enforceHubScheme(urlStr);
140-
} catch (e) {
141-
resolve({ ok: false, error: 'tls_refused: ' + (e && e.message) });
142-
return;
143-
}
144-
let parsed;
145-
try {
146-
parsed = new URL(urlStr);
147-
} catch (e) {
148-
resolve({ ok: false, error: 'invalid_url: ' + (e && e.message) });
149-
return;
150-
}
151-
const isHttps = parsed.protocol === 'https:';
152-
const lib = isHttps ? https : http;
153-
const payload = JSON.stringify(body || {});
154-
const headers = Object.assign(
155-
{ 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) },
156-
buildHubHeaders() || {},
157-
);
158-
// Pin TLS cert verification for https calls so a globally-disabled
159-
// NODE_TLS_REJECT_UNAUTHORIZED=0 cannot weaken the Hub channel
160-
// (Cursor Security Reviewer #160 Medium). hubFetch enforces the
161-
// same via its undici dispatcher; this is the Node-native-https
162-
// equivalent.
163-
//
164-
// Skipped under EVOMAP_HUB_ALLOW_INSECURE=1 so local-dev / self-
165-
// signed mock hubs that legitimately rely on
166-
// NODE_TLS_REJECT_UNAUTHORIZED=0 still work.
167-
const requestOpts = {
168-
hostname: parsed.hostname,
169-
port: parsed.port || (isHttps ? 443 : 80),
170-
path: parsed.pathname + (parsed.search || ''),
127+
async function _postJson(urlStr, body, timeoutMs) {
128+
const payload = JSON.stringify(body || {});
129+
const headers = Object.assign(
130+
{ 'Content-Type': 'application/json' },
131+
buildHubHeaders() || {},
132+
);
133+
134+
try {
135+
const res = await hubFetch(urlStr, {
171136
method: 'POST',
172137
headers: headers,
173-
timeout: timeoutMs || PUBLISH_TIMEOUT_MS,
174-
};
175-
if (isHttps && process.env.EVOMAP_HUB_ALLOW_INSECURE !== '1') {
176-
requestOpts.agent = strictHttpsAgent;
138+
body: payload,
139+
signal: AbortSignal.timeout(timeoutMs || PUBLISH_TIMEOUT_MS),
140+
});
141+
const text = await res.text();
142+
let data = null;
143+
try { data = text ? JSON.parse(text) : null; } catch (e) { data = { raw: text }; }
144+
if (res.status >= 200 && res.status < 300) {
145+
return { ok: true, status: res.status, data };
177146
}
178-
const req = lib.request(
179-
requestOpts,
180-
function (res) {
181-
const chunks = [];
182-
res.on('data', function (c) { chunks.push(c); });
183-
res.on('end', function () {
184-
const text = Buffer.concat(chunks).toString('utf8');
185-
let data = null;
186-
try { data = text ? JSON.parse(text) : null; } catch (e) { data = { raw: text }; }
187-
if (res.statusCode >= 200 && res.statusCode < 300) {
188-
resolve({ ok: true, status: res.statusCode, data });
189-
} else {
190-
resolve({ ok: false, status: res.statusCode, data, error: 'http_' + res.statusCode });
191-
}
192-
});
193-
},
194-
);
195-
req.on('timeout', function () { req.destroy(new Error('timeout')); });
196-
req.on('error', function (err) { resolve({ ok: false, error: err.message }); });
197-
req.write(payload);
198-
req.end();
199-
});
147+
return { ok: false, status: res.status, data, error: 'http_' + res.status };
148+
} catch (err) {
149+
const msg = (err && err.message) || String(err);
150+
if (msg.indexOf('[hubFetch]') !== -1) {
151+
if (/not a valid URL/i.test(msg)) return { ok: false, error: 'invalid_url: ' + msg };
152+
return { ok: false, error: 'tls_refused: ' + msg };
153+
}
154+
return { ok: false, error: msg };
155+
}
200156
}
201157

202158
async function _ensureNodeSecret() {

0 commit comments

Comments
 (0)