@evomap/evolver 1.89.15 → 1.89.18
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 -1
- package/README.ko-KR.md +1 -1
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/index.js +89 -17
- package/package.json +1 -1
- package/src/adapters/claudeCode.js +38 -9
- package/src/adapters/codex.js +2 -2
- package/src/adapters/hookAdapter.js +38 -2
- package/src/adapters/scripts/evolver-session-start.js +182 -2
- package/src/atp/atpExecute.js +3 -1
- package/src/atp/hubClient.js +5 -3
- package/src/atp/serviceHelper.js +3 -2
- package/src/config.js +11 -3
- package/src/evolve/guards.js +1 -1
- package/src/evolve/pipeline/collect.js +1 -1
- package/src/evolve/pipeline/dispatch.js +1 -1
- package/src/evolve/pipeline/enrich.js +1 -1
- package/src/evolve/pipeline/hub.js +1 -1
- package/src/evolve/pipeline/select.js +1 -1
- package/src/evolve/pipeline/signals.js +1 -1
- package/src/evolve/utils.js +1 -1
- package/src/evolve.js +1 -1
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/antiAbuseTelemetry.js +1 -1
- package/src/gep/autoDistillConv.js +1 -1
- package/src/gep/autoDistillLlm.js +1 -1
- package/src/gep/candidateEval.js +1 -1
- package/src/gep/candidates.js +1 -1
- package/src/gep/cliContracts.js +37 -1
- package/src/gep/contentHash.js +1 -1
- package/src/gep/conversationDistiller.js +1 -1
- package/src/gep/conversationSniffer.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/directoryClient.js +7 -3
- package/src/gep/envFingerprint.js +1 -1
- package/src/gep/epigenetics.js +1 -1
- package/src/gep/execBridge.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/hash.js +1 -1
- package/src/gep/hostErrorClassifier.js +34 -0
- package/src/gep/hubFetch.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/issueReporter.js +5 -4
- 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/oauthLogin.js +3 -5
- package/src/gep/openPRRegistry.js +1 -1
- package/src/gep/paths.js +20 -0
- package/src/gep/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/privacyClient.js +28 -10
- package/src/gep/prompt.js +1 -1
- package/src/gep/recallInject.js +1 -1
- package/src/gep/recallVerifier.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/savingsCore.js +1 -1
- package/src/gep/selector.js +1 -1
- package/src/gep/signals.js +37 -15
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/skillPublisher.js +8 -3
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/taskReceiver.js +3 -2
- package/src/gep/tokenSavings.js +1 -1
- package/src/gep/validator/index.js +7 -2
- package/src/gep/validator/reporter.js +7 -2
- package/src/gep/validator/stakeBootstrap.js +7 -2
- package/src/gep/workspaceKeychain.js +1 -1
- package/src/ops/lifecycle.js +501 -31
- package/src/proxy/clientSettings.js +405 -0
- package/src/proxy/extensions/traceControl.js +1 -1
- package/src/proxy/index.js +10 -5
- package/src/proxy/inject.js +1 -1
- package/src/proxy/lifecycle/manager.js +82 -16
- package/src/proxy/mailbox/state.js +207 -0
- package/src/proxy/mailbox/store.js +164 -64
- package/src/proxy/router/messages_route.js +4 -3
- package/src/proxy/server/http.js +40 -6
- package/src/proxy/sync/inbound.js +31 -12
- package/src/proxy/sync/outbound.js +157 -22
- package/src/proxy/trace/extractor.js +1 -1
- package/src/proxy/trace/usage.js +1 -1
package/README.ja-JP.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🧬 Evolver
|
|
2
2
|
|
|
3
|
-
[](https://github.com/EvoMap/evolver/stargazers)
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.npmjs.com/package/@evomap/evolver)
|
package/README.ko-KR.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🧬 Evolver
|
|
2
2
|
|
|
3
|
-
[](https://github.com/EvoMap/evolver/stargazers)
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.npmjs.com/package/@evomap/evolver)
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🧬 Evolver
|
|
2
2
|
|
|
3
|
-
[](https://github.com/EvoMap/evolver/stargazers)
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.npmjs.com/package/@evomap/evolver)
|
package/README.zh-CN.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🧬 Evolver
|
|
2
2
|
|
|
3
|
-
[](https://github.com/EvoMap/evolver/stargazers)
|
|
4
4
|
[](https://opensource.org/licenses/GPL-3.0)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.npmjs.com/package/@evomap/evolver)
|
package/index.js
CHANGED
|
@@ -464,6 +464,68 @@ function writeCycleProgressAtomic(progressPath, fields) {
|
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
+
function handleCycleTimeout({ error, cycleProgressPath, progressFields, suicideEnabled, args, logPath, spawnReplacementFn }) {
|
|
468
|
+
const msg = error && error.message ? String(error.message) : String(error);
|
|
469
|
+
console.error('[Daemon] ' + msg);
|
|
470
|
+
|
|
471
|
+
if (!suicideEnabled) {
|
|
472
|
+
console.warn('[Daemon] Cycle hard-timeout treated as non-fatal because EVOLVER_SUICIDE=false.');
|
|
473
|
+
writeCycleProgressAtomic(cycleProgressPath, Object.assign({}, progressFields, {
|
|
474
|
+
phase: 'cycle_timeout_nonfatal',
|
|
475
|
+
}));
|
|
476
|
+
return { action: 'continue' };
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
writeCycleProgressAtomic(cycleProgressPath, Object.assign({}, progressFields, {
|
|
480
|
+
phase: 'cycle_timeout_respawn',
|
|
481
|
+
}));
|
|
482
|
+
spawnReplacementFn({
|
|
483
|
+
reason: 'cycle_hard_timeout',
|
|
484
|
+
args: args,
|
|
485
|
+
logPath: logPath,
|
|
486
|
+
});
|
|
487
|
+
return { action: 'respawn' };
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function logTimedOutEvolveRejection(error, logFn) {
|
|
491
|
+
const lateMsg = error && error.message ? String(error.message) : String(error);
|
|
492
|
+
try {
|
|
493
|
+
logFn('[Daemon] Timed-out evolve.run() eventually rejected: ' + lateMsg);
|
|
494
|
+
} catch (logError) {
|
|
495
|
+
const fallbackMsg = logError && logError.message ? String(logError.message) : String(logError);
|
|
496
|
+
console.error('[Daemon] Failed to log timed-out evolve.run() rejection: ' + fallbackMsg);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function observeTimedOutEvolvePromise(evolvePromise, logFn = console.error) {
|
|
501
|
+
if (!evolvePromise || typeof evolvePromise.then !== 'function') {
|
|
502
|
+
return { status: 'ignored' };
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
Promise.resolve(evolvePromise).then(
|
|
506
|
+
function () {},
|
|
507
|
+
function (error) {
|
|
508
|
+
logTimedOutEvolveRejection(error, logFn);
|
|
509
|
+
}
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
return { status: 'observing' };
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async function waitForTimedOutEvolvePromise(evolvePromise, logFn = console.error) {
|
|
516
|
+
if (!evolvePromise || typeof evolvePromise.then !== 'function') {
|
|
517
|
+
return { status: 'ignored' };
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
try {
|
|
521
|
+
await evolvePromise;
|
|
522
|
+
return { status: 'resolved' };
|
|
523
|
+
} catch (error) {
|
|
524
|
+
logTimedOutEvolveRejection(error, logFn);
|
|
525
|
+
return { status: 'rejected' };
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
467
529
|
function getLastSignals(statePath) {
|
|
468
530
|
try {
|
|
469
531
|
const st = readJsonSafe(statePath);
|
|
@@ -1357,6 +1419,7 @@ async function main() {
|
|
|
1357
1419
|
const { startProxy } = require('./src/proxy');
|
|
1358
1420
|
const proxyInfo = await startProxy({
|
|
1359
1421
|
hubUrl: process.env.A2A_HUB_URL,
|
|
1422
|
+
clientSettings: {},
|
|
1360
1423
|
});
|
|
1361
1424
|
console.log('[Proxy] Started on ' + proxyInfo.url);
|
|
1362
1425
|
try {
|
|
@@ -1592,13 +1655,12 @@ async function main() {
|
|
|
1592
1655
|
if (typeof progressTicker.unref === 'function') progressTicker.unref();
|
|
1593
1656
|
}
|
|
1594
1657
|
let cycleTimeoutHandle = null;
|
|
1595
|
-
let
|
|
1658
|
+
let evolvePromise = null;
|
|
1596
1659
|
try {
|
|
1597
|
-
|
|
1660
|
+
evolvePromise = evolve.run();
|
|
1598
1661
|
if (cycleTimeoutEnabled && cycleTimeoutMs > 0) {
|
|
1599
1662
|
const timeoutPromise = new Promise(function (_, reject) {
|
|
1600
1663
|
cycleTimeoutHandle = setTimeout(function () {
|
|
1601
|
-
cycleTimedOut = true;
|
|
1602
1664
|
reject(new CycleTimeoutError(cycleTimeoutMs, 'evolve.run', cycleCount));
|
|
1603
1665
|
}, cycleTimeoutMs);
|
|
1604
1666
|
if (cycleTimeoutHandle && typeof cycleTimeoutHandle.unref === 'function') cycleTimeoutHandle.unref();
|
|
@@ -1621,25 +1683,32 @@ async function main() {
|
|
|
1621
1683
|
} catch (error) {
|
|
1622
1684
|
const msg = error && error.message ? String(error.message) : String(error);
|
|
1623
1685
|
if (error && error.code === 'CYCLE_TIMEOUT') {
|
|
1624
|
-
console.error('[Daemon] ' + msg);
|
|
1625
1686
|
if (progressTicker) { clearInterval(progressTicker); progressTicker = null; }
|
|
1626
1687
|
if (cycleTimeoutHandle) { clearTimeout(cycleTimeoutHandle); cycleTimeoutHandle = null; }
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1688
|
+
const timeoutAction = handleCycleTimeout({
|
|
1689
|
+
error,
|
|
1690
|
+
cycleProgressPath,
|
|
1691
|
+
progressFields: {
|
|
1692
|
+
pid: process.pid,
|
|
1693
|
+
outer_cycle: cycleCount,
|
|
1694
|
+
inner_cycle: cycleCount,
|
|
1695
|
+
started_at: t0,
|
|
1696
|
+
},
|
|
1697
|
+
suicideEnabled,
|
|
1698
|
+
args,
|
|
1637
1699
|
logPath: getEvolverLogPath(),
|
|
1700
|
+
spawnReplacementFn: spawnReplacementProcess,
|
|
1638
1701
|
});
|
|
1639
|
-
|
|
1640
|
-
|
|
1702
|
+
if (timeoutAction.action === 'respawn') {
|
|
1703
|
+
releaseLock();
|
|
1704
|
+
process.exit(1);
|
|
1705
|
+
}
|
|
1706
|
+
if (timeoutAction.action === 'continue') {
|
|
1707
|
+
await waitForTimedOutEvolvePromise(evolvePromise);
|
|
1708
|
+
}
|
|
1709
|
+
} else {
|
|
1710
|
+
console.error(`Evolution cycle failed: ${msg}`);
|
|
1641
1711
|
}
|
|
1642
|
-
console.error(`Evolution cycle failed: ${msg}`);
|
|
1643
1712
|
} finally {
|
|
1644
1713
|
if (progressTicker) { clearInterval(progressTicker); progressTicker = null; }
|
|
1645
1714
|
if (cycleTimeoutHandle) { clearTimeout(cycleTimeoutHandle); cycleTimeoutHandle = null; }
|
|
@@ -3328,5 +3397,8 @@ module.exports = {
|
|
|
3328
3397
|
parseBoolEnv,
|
|
3329
3398
|
CycleTimeoutError,
|
|
3330
3399
|
writeCycleProgressAtomic,
|
|
3400
|
+
handleCycleTimeout,
|
|
3401
|
+
observeTimedOutEvolvePromise,
|
|
3402
|
+
waitForTimedOutEvolvePromise,
|
|
3331
3403
|
spawnReplacementProcess,
|
|
3332
3404
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.89.
|
|
3
|
+
"version": "1.89.18",
|
|
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": {
|
|
@@ -1,12 +1,41 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir } = require('./hookAdapter');
|
|
3
|
+
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir, isEvolverHookCommand } = require('./hookAdapter');
|
|
4
4
|
|
|
5
5
|
const HOOK_SCRIPTS_DIR_NAME = 'hooks';
|
|
6
6
|
const EVOLVER_MARKER = '<!-- evolver-evolution-memory -->';
|
|
7
7
|
|
|
8
|
-
function
|
|
9
|
-
|
|
8
|
+
function shellSingleQuote(value) {
|
|
9
|
+
return `'${String(value).replace(/'/g, "'\\''")}'`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function quoteEvalScript(script) {
|
|
13
|
+
if (process.platform === 'win32') {
|
|
14
|
+
if (script.includes('"')) {
|
|
15
|
+
throw new Error('unexpected double quote in generated hook wrapper');
|
|
16
|
+
}
|
|
17
|
+
return `"${script}"`;
|
|
18
|
+
}
|
|
19
|
+
return shellSingleQuote(script);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function buildSafeNodeHookCommand(scriptPath) {
|
|
23
|
+
const encodedPath = Buffer.from(String(scriptPath), 'utf8').toString('base64');
|
|
24
|
+
const js = [
|
|
25
|
+
"const {spawnSync}=require('child_process')",
|
|
26
|
+
`const p=Buffer.from('${encodedPath}','base64').toString('utf8')`,
|
|
27
|
+
"const r=spawnSync(process.execPath,[p],{stdio:'inherit',shell:false})",
|
|
28
|
+
"if(r.error){throw r.error}",
|
|
29
|
+
'process.exit(r.status == null ? 1 : r.status)',
|
|
30
|
+
].join(';');
|
|
31
|
+
return `node -e ${quoteEvalScript(js)} ${path.basename(scriptPath)}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildClaudeHooks(evolverRoot, configRoot) {
|
|
35
|
+
const scriptsBase = configRoot
|
|
36
|
+
? path.join(configRoot, '.claude', 'hooks')
|
|
37
|
+
: path.join('.claude', 'hooks');
|
|
38
|
+
const hookCommand = (scriptName) => buildSafeNodeHookCommand(path.join(scriptsBase, scriptName));
|
|
10
39
|
return {
|
|
11
40
|
hooks: {
|
|
12
41
|
SessionStart: [
|
|
@@ -14,7 +43,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
14
43
|
hooks: [
|
|
15
44
|
{
|
|
16
45
|
type: 'command',
|
|
17
|
-
command:
|
|
46
|
+
command: hookCommand('evolver-session-start.js'),
|
|
18
47
|
timeout: 3,
|
|
19
48
|
},
|
|
20
49
|
],
|
|
@@ -32,7 +61,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
32
61
|
// ABOVE that watchdog, so the host never kills the script
|
|
33
62
|
// mid-write. A stuck/slow recall can never block or erase the
|
|
34
63
|
// user's prompt.
|
|
35
|
-
command:
|
|
64
|
+
command: hookCommand('evolver-task-recall.js'),
|
|
36
65
|
timeout: 5,
|
|
37
66
|
},
|
|
38
67
|
],
|
|
@@ -44,7 +73,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
44
73
|
hooks: [
|
|
45
74
|
{
|
|
46
75
|
type: 'command',
|
|
47
|
-
command:
|
|
76
|
+
command: hookCommand('evolver-signal-detect.js'),
|
|
48
77
|
timeout: 2,
|
|
49
78
|
},
|
|
50
79
|
],
|
|
@@ -55,7 +84,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
55
84
|
hooks: [
|
|
56
85
|
{
|
|
57
86
|
type: 'command',
|
|
58
|
-
command:
|
|
87
|
+
command: hookCommand('evolver-session-end.js'),
|
|
59
88
|
timeout: 8,
|
|
60
89
|
},
|
|
61
90
|
],
|
|
@@ -99,7 +128,7 @@ function install({ configRoot, evolverRoot, force }) {
|
|
|
99
128
|
|
|
100
129
|
fs.mkdirSync(claudeDir, { recursive: true });
|
|
101
130
|
|
|
102
|
-
const hooksCfg = buildClaudeHooks(evolverRoot);
|
|
131
|
+
const hooksCfg = buildClaudeHooks(evolverRoot, configRoot);
|
|
103
132
|
mergeJsonFile(settingsPath, hooksCfg);
|
|
104
133
|
console.log('[claude-code] Wrote ' + settingsPath);
|
|
105
134
|
|
|
@@ -146,7 +175,7 @@ function uninstall({ configRoot }) {
|
|
|
146
175
|
const innerBefore = matcher.hooks.length;
|
|
147
176
|
const filtered = matcher.hooks.filter(h => {
|
|
148
177
|
const cmd = (h && h.command) || '';
|
|
149
|
-
return !
|
|
178
|
+
return !isEvolverHookCommand(cmd);
|
|
150
179
|
});
|
|
151
180
|
// A matcher containing both evolver and user hooks shrinks
|
|
152
181
|
// its inner array without changing the outer matcher count.
|
package/src/adapters/codex.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir } = require('./hookAdapter');
|
|
3
|
+
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir, isEvolverHookCommand } = require('./hookAdapter');
|
|
4
4
|
|
|
5
5
|
const HOOK_SCRIPTS_DIR_NAME = 'hooks';
|
|
6
6
|
const EVOLVER_MARKER = '<!-- evolver-evolution-memory -->';
|
|
@@ -166,7 +166,7 @@ function uninstall({ configRoot }) {
|
|
|
166
166
|
const before = data.hooks[event].length;
|
|
167
167
|
data.hooks[event] = data.hooks[event].filter(h => {
|
|
168
168
|
const cmd = (h && h.command) || '';
|
|
169
|
-
return !
|
|
169
|
+
return !isEvolverHookCommand(cmd);
|
|
170
170
|
});
|
|
171
171
|
if (data.hooks[event].length !== before) touched = true;
|
|
172
172
|
if (data.hooks[event].length === 0) delete data.hooks[event];
|
|
@@ -10,7 +10,30 @@ const PLATFORMS = {
|
|
|
10
10
|
opencode: { name: 'opencode', configDir: '.opencode', detector: '.opencode' },
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
function detectPlatformFromEnv(env = process.env) {
|
|
14
|
+
const hasStrongClaudeSignal = env.CLAUDECODE || env.CLAUDE_CODE_ENTRYPOINT;
|
|
15
|
+
if (hasStrongClaudeSignal) {
|
|
16
|
+
return 'claude-code';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const hasCursorSignal =
|
|
20
|
+
env.CURSOR_TRACE_ID ||
|
|
21
|
+
env.CURSOR_SESSION_ID ||
|
|
22
|
+
env.CURSOR_PROJECT_DIR ||
|
|
23
|
+
String(env.TERM_PROGRAM || '').toLowerCase() === 'cursor';
|
|
24
|
+
if (hasCursorSignal) {
|
|
25
|
+
return 'cursor';
|
|
26
|
+
}
|
|
27
|
+
if (env.CLAUDE_PROJECT_DIR) {
|
|
28
|
+
return 'claude-code';
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
13
33
|
function detectPlatform(cwd) {
|
|
34
|
+
const envPlatform = detectPlatformFromEnv();
|
|
35
|
+
if (envPlatform) return envPlatform;
|
|
36
|
+
|
|
14
37
|
const root = cwd || process.cwd();
|
|
15
38
|
const home = os.homedir();
|
|
16
39
|
for (const [id, meta] of Object.entries(PLATFORMS)) {
|
|
@@ -76,7 +99,7 @@ function mergeWithHooksUnion(target, source) {
|
|
|
76
99
|
if (tArr && sArr) {
|
|
77
100
|
const isEvolverOwned = (entry) => {
|
|
78
101
|
const cmds = collectCommands(entry);
|
|
79
|
-
return cmds.some(
|
|
102
|
+
return cmds.some(isEvolverHookCommand);
|
|
80
103
|
};
|
|
81
104
|
const userEntries = tArr.filter(e => !isEvolverOwned(e));
|
|
82
105
|
result.hooks[event] = [...userEntries, ...sArr];
|
|
@@ -101,6 +124,17 @@ function collectCommands(entry) {
|
|
|
101
124
|
return out;
|
|
102
125
|
}
|
|
103
126
|
|
|
127
|
+
function isEvolverHookCommand(command) {
|
|
128
|
+
if (typeof command !== 'string') return false;
|
|
129
|
+
return command.includes('evolver-session') ||
|
|
130
|
+
command.includes('evolver-signal') ||
|
|
131
|
+
command.includes('evolver-task-recall') ||
|
|
132
|
+
// Legacy installs briefly shipped this companion daemon hook. Treat it
|
|
133
|
+
// as evolver-owned so reinstall/merge can remove it instead of preserving
|
|
134
|
+
// a stale supervisor that may point clients at a dead proxy.
|
|
135
|
+
command.includes('evolver-daemon-start');
|
|
136
|
+
}
|
|
137
|
+
|
|
104
138
|
function deepMerge(target, source) {
|
|
105
139
|
const result = { ...target };
|
|
106
140
|
for (const key of Object.keys(source)) {
|
|
@@ -226,7 +260,7 @@ function removeEvolverHooks(filePath, { markerKey = '_evolver_managed' } = {}) {
|
|
|
226
260
|
const before = data.hooks[event].length;
|
|
227
261
|
data.hooks[event] = data.hooks[event].filter(h => {
|
|
228
262
|
const cmd = h.command || '';
|
|
229
|
-
return !
|
|
263
|
+
return !isEvolverHookCommand(cmd);
|
|
230
264
|
});
|
|
231
265
|
if (data.hooks[event].length !== before) changed = true;
|
|
232
266
|
if (data.hooks[event].length === 0) delete data.hooks[event];
|
|
@@ -351,6 +385,7 @@ async function setupHooks({ platform, cwd, force, uninstall, evolverRoot } = {})
|
|
|
351
385
|
}
|
|
352
386
|
|
|
353
387
|
module.exports = {
|
|
388
|
+
detectPlatformFromEnv,
|
|
354
389
|
detectPlatform,
|
|
355
390
|
resolveConfigRoot,
|
|
356
391
|
loadAdapter,
|
|
@@ -358,6 +393,7 @@ module.exports = {
|
|
|
358
393
|
deepMerge,
|
|
359
394
|
mergeWithHooksUnion,
|
|
360
395
|
collectCommands,
|
|
396
|
+
isEvolverHookCommand,
|
|
361
397
|
copyHookScripts,
|
|
362
398
|
appendSectionToFile,
|
|
363
399
|
assertSafeConfigDir,
|
|
@@ -14,6 +14,180 @@ const { filterRelevantOutcomes } = require('./_memoryFiltering');
|
|
|
14
14
|
// _maybeRestartDaemon's catch-all and silently disable daemon auto-restart.
|
|
15
15
|
const lockPaths = require('./_lockPaths');
|
|
16
16
|
|
|
17
|
+
function _readJson(file) {
|
|
18
|
+
try {
|
|
19
|
+
if (!file || !fs.existsSync(file)) return null;
|
|
20
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
21
|
+
} catch (_) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function _isLoopbackProxyUrl(value) {
|
|
27
|
+
const raw = String(value || '').trim();
|
|
28
|
+
if (!raw) return false;
|
|
29
|
+
try {
|
|
30
|
+
const u = new URL(raw);
|
|
31
|
+
const host = u.hostname.toLowerCase();
|
|
32
|
+
return u.protocol === 'http:' && (host === '127.0.0.1' || host === 'localhost' || host === '::1' || host === '[::1]');
|
|
33
|
+
} catch (_) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _stripTomlComment(line) {
|
|
39
|
+
let out = '';
|
|
40
|
+
let quote = null;
|
|
41
|
+
let escaped = false;
|
|
42
|
+
for (const ch of String(line || '')) {
|
|
43
|
+
if (escaped) {
|
|
44
|
+
out += ch;
|
|
45
|
+
escaped = false;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (ch === '\\' && quote === '"') {
|
|
49
|
+
out += ch;
|
|
50
|
+
escaped = true;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if ((ch === '"' || ch === "'") && !quote) {
|
|
54
|
+
quote = ch;
|
|
55
|
+
out += ch;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (ch === quote) {
|
|
59
|
+
quote = null;
|
|
60
|
+
out += ch;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (ch === '#' && !quote) break;
|
|
64
|
+
out += ch;
|
|
65
|
+
}
|
|
66
|
+
return out.trim();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function _tomlStringValue(value) {
|
|
70
|
+
const raw = _stripTomlComment(value);
|
|
71
|
+
const match = raw.match(/^(['"])([\s\S]*)\1$/);
|
|
72
|
+
return match ? match[2] : raw.trim();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function _codexConfigPath() {
|
|
76
|
+
if (process.env.CODEX_CONFIG_FILE || process.env.EVOMAP_CODEX_CONFIG_FILE) {
|
|
77
|
+
return process.env.CODEX_CONFIG_FILE || process.env.EVOMAP_CODEX_CONFIG_FILE;
|
|
78
|
+
}
|
|
79
|
+
const home = process.env.HOME || os.homedir();
|
|
80
|
+
return home ? path.join(home, '.codex', 'config.toml') : null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function _codexConfigExpectsProxy() {
|
|
84
|
+
const file = _codexConfigPath();
|
|
85
|
+
if (!file || !fs.existsSync(file)) return false;
|
|
86
|
+
let selectedProvider = null;
|
|
87
|
+
let section = '';
|
|
88
|
+
const providerUrls = {};
|
|
89
|
+
try {
|
|
90
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
91
|
+
for (const line of content.split(/\r?\n/)) {
|
|
92
|
+
const clean = _stripTomlComment(line);
|
|
93
|
+
if (!clean) continue;
|
|
94
|
+
const sectionMatch = clean.match(/^\[([^\]]+)\]$/);
|
|
95
|
+
if (sectionMatch) {
|
|
96
|
+
section = sectionMatch[1].trim();
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const kv = clean.match(/^([A-Za-z0-9_.-]+)\s*=\s*([\s\S]+)$/);
|
|
100
|
+
if (!kv) continue;
|
|
101
|
+
const key = kv[1].trim();
|
|
102
|
+
const value = _tomlStringValue(kv[2]);
|
|
103
|
+
if (!section && key === 'model_provider') {
|
|
104
|
+
selectedProvider = value;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const providerMatch = section.match(/^model_providers\.([A-Za-z0-9_.-]+)$/);
|
|
108
|
+
if (providerMatch && key === 'base_url') {
|
|
109
|
+
providerUrls[providerMatch[1]] = value;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (!section && key === 'base_url' && _isLoopbackProxyUrl(value)) return true;
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (selectedProvider && _isLoopbackProxyUrl(providerUrls[selectedProvider])) return true;
|
|
118
|
+
return Object.keys(providerUrls).some(name =>
|
|
119
|
+
/(?:evomap|proxy)/i.test(name) && _isLoopbackProxyUrl(providerUrls[name])
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function _proxyExpected() {
|
|
124
|
+
if (String(process.env.EVOMAP_PROXY || '').trim() === '1') return true;
|
|
125
|
+
if (String(process.env.A2A_TRANSPORT || '').trim().toLowerCase() === 'mailbox') return true;
|
|
126
|
+
if (_isLoopbackProxyUrl(process.env.EVOMAP_PROXY_URL) || _isLoopbackProxyUrl(process.env.ANTHROPIC_BASE_URL)) return true;
|
|
127
|
+
if (_codexConfigExpectsProxy()) return true;
|
|
128
|
+
|
|
129
|
+
const home = process.env.HOME || os.homedir();
|
|
130
|
+
const settingsFile = process.env.CLAUDE_SETTINGS_FILE || process.env.EVOMAP_CLAUDE_SETTINGS_FILE ||
|
|
131
|
+
(home ? path.join(home, '.claude', 'settings.json') : null);
|
|
132
|
+
const settings = _readJson(settingsFile);
|
|
133
|
+
const cfg = settings && settings.env;
|
|
134
|
+
return !!(cfg && (
|
|
135
|
+
_isLoopbackProxyUrl(cfg.EVOMAP_PROXY_URL) ||
|
|
136
|
+
(String(cfg.EVOMAP_PROXY_AUTO_INJECTED || '') === '1' && _isLoopbackProxyUrl(cfg.ANTHROPIC_BASE_URL))
|
|
137
|
+
));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function _proxyReachable(url, token) {
|
|
141
|
+
if (!_isLoopbackProxyUrl(url) || !token) return false;
|
|
142
|
+
try {
|
|
143
|
+
const { execFileSync } = require('child_process');
|
|
144
|
+
execFileSync(process.execPath, ['-e', `
|
|
145
|
+
const fs = require('fs');
|
|
146
|
+
const http = require('http');
|
|
147
|
+
const url = process.argv[1].replace(/\\/+$/, '') + '/proxy/status';
|
|
148
|
+
const token = fs.readFileSync(0, 'utf8').trim();
|
|
149
|
+
if (!token) process.exit(1);
|
|
150
|
+
const req = http.get(url, { headers: { Authorization: 'Bearer ' + token } }, (res) => {
|
|
151
|
+
let body = '';
|
|
152
|
+
res.setEncoding('utf8');
|
|
153
|
+
res.on('data', (chunk) => {
|
|
154
|
+
body += chunk;
|
|
155
|
+
if (body.length > 1024 * 1024) req.destroy(new Error('response too large'));
|
|
156
|
+
});
|
|
157
|
+
res.on('end', () => {
|
|
158
|
+
if (res.statusCode < 200 || res.statusCode >= 300) process.exit(1);
|
|
159
|
+
let parsed;
|
|
160
|
+
try { parsed = JSON.parse(body); } catch (_) { process.exit(1); }
|
|
161
|
+
if (parsed && parsed.status === 'running' && (parsed.proxy_protocol_version || parsed.schema_version || parsed.node_id != null)) {
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
process.exit(1);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
req.setTimeout(700, () => req.destroy(new Error('timeout')));
|
|
168
|
+
req.on('error', () => process.exit(1));
|
|
169
|
+
`, url], { input: String(token), stdio: ['pipe', 'ignore', 'ignore'], timeout: 1200, windowsHide: true });
|
|
170
|
+
return true;
|
|
171
|
+
} catch (_) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function _proxyHealthyIfExpected() {
|
|
177
|
+
if (!_proxyExpected()) return true;
|
|
178
|
+
const dir = process.env.EVOLVER_SETTINGS_DIR || path.join(os.homedir(), '.evolver');
|
|
179
|
+
const settings = _readJson(path.join(dir, 'settings.json'));
|
|
180
|
+
const proxy = settings && settings.proxy;
|
|
181
|
+
if (!proxy || !proxy.url) return false;
|
|
182
|
+
if (proxy.pid) {
|
|
183
|
+
try { process.kill(proxy.pid, 0); } catch (e) {
|
|
184
|
+
if (!(e && e.code === 'EPERM')) return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (!proxy.token) return false;
|
|
188
|
+
return _proxyReachable(proxy.url, proxy.token);
|
|
189
|
+
}
|
|
190
|
+
|
|
17
191
|
// Auto-restart guard: if the evolver daemon is not running when a new agent
|
|
18
192
|
// session starts, attempt a background restart. This covers the "idle-death"
|
|
19
193
|
// scenario: the user closed the machine (macOS sleep), the process died due to
|
|
@@ -69,7 +243,7 @@ function _maybeRestartDaemon(evolverRoot) {
|
|
|
69
243
|
}
|
|
70
244
|
} catch (_) { /* lock file unreadable or absent: assume not running */ }
|
|
71
245
|
|
|
72
|
-
if (daemonRunning) return; // already alive, nothing to do
|
|
246
|
+
if (daemonRunning && _proxyHealthyIfExpected()) return; // already alive, nothing to do
|
|
73
247
|
|
|
74
248
|
// Daemon appears dead. Spawn lifecycle.js start in the background so
|
|
75
249
|
// this session-start script exits immediately (< 50 ms) and does not
|
|
@@ -305,5 +479,11 @@ function main() {
|
|
|
305
479
|
if (require.main === module) {
|
|
306
480
|
main();
|
|
307
481
|
} else {
|
|
308
|
-
module.exports = {
|
|
482
|
+
module.exports = {
|
|
483
|
+
belongsToWorkspace,
|
|
484
|
+
_isLoopbackProxyUrl,
|
|
485
|
+
_proxyExpected,
|
|
486
|
+
_proxyReachable,
|
|
487
|
+
_proxyHealthyIfExpected,
|
|
488
|
+
};
|
|
309
489
|
}
|
package/src/atp/atpExecute.js
CHANGED
|
@@ -31,6 +31,7 @@ const {
|
|
|
31
31
|
getHubUrl,
|
|
32
32
|
getHubNodeSecret,
|
|
33
33
|
buildHubHeaders,
|
|
34
|
+
buildNodeScopedHubHeaders,
|
|
34
35
|
sendHelloToHub,
|
|
35
36
|
} = require('../gep/a2aProtocol');
|
|
36
37
|
const { submitDelivery } = require('./hubClient');
|
|
@@ -126,9 +127,10 @@ function _publishUrl() {
|
|
|
126
127
|
|
|
127
128
|
async function _postJson(urlStr, body, timeoutMs) {
|
|
128
129
|
const payload = JSON.stringify(body || {});
|
|
130
|
+
const buildHeaders = buildNodeScopedHubHeaders || buildHubHeaders;
|
|
129
131
|
const headers = Object.assign(
|
|
130
132
|
{ 'Content-Type': 'application/json' },
|
|
131
|
-
|
|
133
|
+
buildHeaders() || {},
|
|
132
134
|
);
|
|
133
135
|
|
|
134
136
|
try {
|
package/src/atp/hubClient.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// bound to 127.0.0.1).
|
|
16
16
|
|
|
17
17
|
const http = require('http');
|
|
18
|
-
const { getHubUrl, buildHubHeaders, getNodeId } = require('../gep/a2aProtocol');
|
|
18
|
+
const { getHubUrl, buildHubHeaders, buildNodeScopedHubHeaders, getNodeId } = require('../gep/a2aProtocol');
|
|
19
19
|
const { hubFetch } = require('../gep/hubFetch');
|
|
20
20
|
const { getProxyUrl, getProxyToken } = require('../proxy/server/settings');
|
|
21
21
|
|
|
@@ -95,9 +95,10 @@ function _hubPost(pathSuffix, body, timeoutMs) {
|
|
|
95
95
|
if (!hubUrl) return Promise.resolve({ ok: false, error: 'no_hub_url' });
|
|
96
96
|
const endpoint = hubUrl.replace(/\/+$/, '') + pathSuffix;
|
|
97
97
|
const timeout = timeoutMs || require('../config').HTTP_TRANSPORT_TIMEOUT_MS;
|
|
98
|
+
const buildHeaders = buildNodeScopedHubHeaders || buildHubHeaders;
|
|
98
99
|
return hubFetch(endpoint, {
|
|
99
100
|
method: 'POST',
|
|
100
|
-
headers:
|
|
101
|
+
headers: buildHeaders(),
|
|
101
102
|
body: JSON.stringify(body),
|
|
102
103
|
signal: AbortSignal.timeout(timeout),
|
|
103
104
|
})
|
|
@@ -123,9 +124,10 @@ function _hubGet(pathSuffix, timeoutMs) {
|
|
|
123
124
|
if (!hubUrl) return Promise.resolve({ ok: false, error: 'no_hub_url' });
|
|
124
125
|
const endpoint = hubUrl.replace(/\/+$/, '') + pathSuffix;
|
|
125
126
|
const timeout = timeoutMs || require('../config').HTTP_TRANSPORT_TIMEOUT_MS;
|
|
127
|
+
const buildHeaders = buildNodeScopedHubHeaders || buildHubHeaders;
|
|
126
128
|
return hubFetch(endpoint, {
|
|
127
129
|
method: 'GET',
|
|
128
|
-
headers:
|
|
130
|
+
headers: buildHeaders(),
|
|
129
131
|
signal: AbortSignal.timeout(timeout),
|
|
130
132
|
})
|
|
131
133
|
.then(function (res) {
|
package/src/atp/serviceHelper.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
// ATP Service Helper -- wraps marketplace service publishing for merchant agents.
|
|
2
2
|
|
|
3
|
-
const { getNodeId, buildHubHeaders, getHubUrl } = require('../gep/a2aProtocol');
|
|
3
|
+
const { getNodeId, buildHubHeaders, buildNodeScopedHubHeaders, getHubUrl } = require('../gep/a2aProtocol');
|
|
4
4
|
const { hubFetch } = require('../gep/hubFetch');
|
|
5
5
|
const { HTTP_TRANSPORT_TIMEOUT_MS } = require('../config');
|
|
6
6
|
|
|
7
7
|
async function postService(endpoint, body) {
|
|
8
8
|
try {
|
|
9
|
+
const buildHeaders = buildNodeScopedHubHeaders || buildHubHeaders;
|
|
9
10
|
const res = await hubFetch(endpoint, {
|
|
10
11
|
method: 'POST',
|
|
11
|
-
headers: Object.assign({ 'Content-Type': 'application/json' },
|
|
12
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, buildHeaders() || {}),
|
|
12
13
|
body: JSON.stringify(body),
|
|
13
14
|
signal: AbortSignal.timeout(HTTP_TRANSPORT_TIMEOUT_MS),
|
|
14
15
|
});
|