@evomap/evolver 1.89.17 → 1.89.19
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 +272 -18
- package/package.json +7 -2
- package/src/adapters/claudeCode.js +16 -18
- package/src/adapters/hookAdapter.js +92 -5
- package/src/adapters/scripts/evolver-session-start.js +98 -0
- package/src/atp/atpExecute.js +3 -1
- package/src/atp/hubClient.js +5 -3
- package/src/atp/serviceHelper.js +3 -2
- 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/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/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/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/skill2gep.js +329 -43
- package/src/gep/skill2gepAudit.js +303 -0
- 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/trajectoryExport.js +1 -0
- 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/proxy/clientSettings.js +405 -0
- package/src/proxy/extensions/traceControl.js +1 -1
- package/src/proxy/index.js +13 -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 +56 -4
- package/src/proxy/server/http.js +40 -6
- package/src/proxy/sync/inbound.js +31 -12
- package/src/proxy/sync/outbound.js +164 -24
- 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; }
|
|
@@ -2748,6 +2817,165 @@ async function main() {
|
|
|
2748
2817
|
console.log('');
|
|
2749
2818
|
}
|
|
2750
2819
|
|
|
2820
|
+
} else if (command === 'trajectory-export') {
|
|
2821
|
+
const allowPartial = args.includes('--allow-partial');
|
|
2822
|
+
const runtimeSessions = args.includes('--runtime-sessions');
|
|
2823
|
+
// Strict-by-default marking gate (v1): runtime-session discovery only
|
|
2824
|
+
// collects sessions evolver actively marked (session-start hook), minus
|
|
2825
|
+
// those the gateway already captured. These flags open each gate back up.
|
|
2826
|
+
const includeUnmarked = args.includes('--include-unmarked');
|
|
2827
|
+
const includeGatewayCaptured = args.includes('--include-gateway-captured');
|
|
2828
|
+
try {
|
|
2829
|
+
const optionValue = (name) => {
|
|
2830
|
+
let value;
|
|
2831
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
2832
|
+
const arg = args[i];
|
|
2833
|
+
if (arg === name) {
|
|
2834
|
+
if (i + 1 >= args.length || String(args[i + 1]).startsWith('--')) {
|
|
2835
|
+
throw new Error('missing value for ' + name);
|
|
2836
|
+
}
|
|
2837
|
+
value = String(args[i + 1]);
|
|
2838
|
+
} else if (typeof arg === 'string' && arg.startsWith(name + '=')) {
|
|
2839
|
+
value = arg.slice(name.length + 1);
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
return value;
|
|
2843
|
+
};
|
|
2844
|
+
const optionValues = (name) => {
|
|
2845
|
+
const values = [];
|
|
2846
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
2847
|
+
const arg = args[i];
|
|
2848
|
+
if (arg === name) {
|
|
2849
|
+
if (i + 1 >= args.length || String(args[i + 1]).startsWith('--')) {
|
|
2850
|
+
throw new Error('missing value for ' + name);
|
|
2851
|
+
}
|
|
2852
|
+
values.push(String(args[i + 1]));
|
|
2853
|
+
} else if (typeof arg === 'string' && arg.startsWith(name + '=')) {
|
|
2854
|
+
values.push(arg.slice(name.length + 1));
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
return values;
|
|
2858
|
+
};
|
|
2859
|
+
const input = optionValue('--input');
|
|
2860
|
+
const output = optionValue('--output');
|
|
2861
|
+
const runtimeSessionDirs = optionValues('--runtime-session-dir');
|
|
2862
|
+
const nodeSecretInline = optionValue('--node-secret');
|
|
2863
|
+
const nodeSecretFile = optionValue('--node-secret-file');
|
|
2864
|
+
const nodeSecretEnv = optionValue('--node-secret-env');
|
|
2865
|
+
const hubPrivateKeyFile = optionValue('--hub-private-key');
|
|
2866
|
+
const nodeSecretKeyringFile = optionValue('--node-secret-keyring');
|
|
2867
|
+
const markedSessionsFile = optionValue('--marked-sessions-file');
|
|
2868
|
+
let nodeSecret;
|
|
2869
|
+
let hubPrivateKey;
|
|
2870
|
+
let nodeSecretKeyring;
|
|
2871
|
+
const nodeSecretSourceCount = [nodeSecretInline, nodeSecretFile, nodeSecretEnv]
|
|
2872
|
+
.filter((value) => value !== undefined).length;
|
|
2873
|
+
if (nodeSecretSourceCount > 1) {
|
|
2874
|
+
throw new Error('use only one node secret source');
|
|
2875
|
+
}
|
|
2876
|
+
if (nodeSecretInline !== undefined) {
|
|
2877
|
+
if (!nodeSecretInline) throw new Error('missing value for --node-secret');
|
|
2878
|
+
if (fs.existsSync(nodeSecretInline)) {
|
|
2879
|
+
try {
|
|
2880
|
+
nodeSecret = fs.readFileSync(nodeSecretInline, 'utf8').trim();
|
|
2881
|
+
} catch (readErr) {
|
|
2882
|
+
const err = new Error('node secret file is not readable: ' + nodeSecretInline);
|
|
2883
|
+
err.cause = readErr;
|
|
2884
|
+
throw err;
|
|
2885
|
+
}
|
|
2886
|
+
if (!nodeSecret) throw new Error('node secret file is empty');
|
|
2887
|
+
} else {
|
|
2888
|
+
nodeSecret = String(nodeSecretInline).trim();
|
|
2889
|
+
if (!nodeSecret) throw new Error('node secret is empty');
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
if (nodeSecretFile !== undefined) {
|
|
2893
|
+
if (!nodeSecretFile) throw new Error('missing path for --node-secret-file');
|
|
2894
|
+
try {
|
|
2895
|
+
nodeSecret = fs.readFileSync(nodeSecretFile, 'utf8').trim();
|
|
2896
|
+
} catch (readErr) {
|
|
2897
|
+
const err = new Error('node secret file is not readable: ' + nodeSecretFile);
|
|
2898
|
+
err.cause = readErr;
|
|
2899
|
+
throw err;
|
|
2900
|
+
}
|
|
2901
|
+
if (!nodeSecret) throw new Error('node secret file is empty');
|
|
2902
|
+
}
|
|
2903
|
+
if (nodeSecretEnv !== undefined) {
|
|
2904
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(nodeSecretEnv)) {
|
|
2905
|
+
throw new Error('invalid environment variable name for --node-secret-env');
|
|
2906
|
+
}
|
|
2907
|
+
nodeSecret = String(process.env[nodeSecretEnv] || '').trim();
|
|
2908
|
+
if (!nodeSecret) throw new Error('node secret environment variable is empty or unset');
|
|
2909
|
+
}
|
|
2910
|
+
if (hubPrivateKeyFile !== undefined) {
|
|
2911
|
+
if (!hubPrivateKeyFile) throw new Error('missing path for --hub-private-key');
|
|
2912
|
+
try {
|
|
2913
|
+
hubPrivateKey = fs.readFileSync(hubPrivateKeyFile, 'utf8');
|
|
2914
|
+
} catch (readErr) {
|
|
2915
|
+
const err = new Error('hub private key file is not readable: ' + hubPrivateKeyFile);
|
|
2916
|
+
err.cause = readErr;
|
|
2917
|
+
throw err;
|
|
2918
|
+
}
|
|
2919
|
+
if (!String(hubPrivateKey || '').trim()) throw new Error('hub private key file is empty');
|
|
2920
|
+
}
|
|
2921
|
+
if (nodeSecretKeyringFile !== undefined) {
|
|
2922
|
+
if (!nodeSecretKeyringFile) throw new Error('missing path for --node-secret-keyring');
|
|
2923
|
+
try {
|
|
2924
|
+
nodeSecretKeyring = JSON.parse(fs.readFileSync(nodeSecretKeyringFile, 'utf8'));
|
|
2925
|
+
} catch (readErr) {
|
|
2926
|
+
const err = new Error('node secret keyring file is not readable or invalid JSON: ' + nodeSecretKeyringFile);
|
|
2927
|
+
err.cause = readErr;
|
|
2928
|
+
throw err;
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
const { writeTrajectories } = require('./src/gep/trajectoryExport');
|
|
2932
|
+
const result = writeTrajectories({
|
|
2933
|
+
input,
|
|
2934
|
+
output,
|
|
2935
|
+
nodeSecret,
|
|
2936
|
+
nodeSecretKeyring,
|
|
2937
|
+
hubPrivateKey,
|
|
2938
|
+
allowPartial,
|
|
2939
|
+
runtimeSessions: runtimeSessions ? true : undefined,
|
|
2940
|
+
runtimeSessionDirs,
|
|
2941
|
+
markedSessionsFile,
|
|
2942
|
+
includeUnmarked: includeUnmarked ? true : undefined,
|
|
2943
|
+
includeGatewayCaptured: includeGatewayCaptured ? true : undefined,
|
|
2944
|
+
});
|
|
2945
|
+
console.log('[trajectory-export] Wrote ' + result.trajectories.length + ' trajector' + (result.trajectories.length === 1 ? 'y' : 'ies') + ' to ' + result.outputPath);
|
|
2946
|
+
console.log('[trajectory-export] Read ' + result.rowsRead + ' trace row(s) and ' + (result.sessionTurnsRead || 0) + ' session turn(s) from ' + (result.filesRead || 0) + ' file(s).');
|
|
2947
|
+
if (result.sessionFilesRead > 0) {
|
|
2948
|
+
console.log('[trajectory-export] Converted ' + result.sessionFilesRead + ' runtime session file(s).');
|
|
2949
|
+
}
|
|
2950
|
+
if (result.runtimeSessionDiscovery && result.runtimeSessionDiscovery.enabled) {
|
|
2951
|
+
console.log('[trajectory-export] Runtime session discovery is local-only; no Hub upload is performed.');
|
|
2952
|
+
console.log('[trajectory-export] Runtime discovery scanned '
|
|
2953
|
+
+ result.runtimeSessionDiscovery.dirsScanned + ' Codex/Claude dir(s), matched '
|
|
2954
|
+
+ result.runtimeSessionDiscovery.filesMatched + ' workspace session file(s).');
|
|
2955
|
+
const mg = result.runtimeSessionDiscovery.markGate;
|
|
2956
|
+
if (mg) {
|
|
2957
|
+
console.log('[trajectory-export] Marking gate: enforce_marked=' + mg.enforceMarked
|
|
2958
|
+
+ ', exclude_gateway_captured=' + mg.excludeGatewayCaptured
|
|
2959
|
+
+ '; marked_registry=' + mg.markedSessionCount
|
|
2960
|
+
+ ', gateway_captured=' + mg.gatewayCapturedCount
|
|
2961
|
+
+ ', excluded_unmarked=' + mg.excludedByMark
|
|
2962
|
+
+ ', excluded_gateway=' + mg.excludedByGateway + '.');
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
if (result.stats) {
|
|
2966
|
+
console.log('[trajectory-export] Scanned ' + result.stats.rowsScanned
|
|
2967
|
+
+ ' row(s); encrypted=' + result.stats.encryptedRows
|
|
2968
|
+
+ ', skipped_missing_secret=' + result.stats.skippedMissingSecret
|
|
2969
|
+
+ ', decrypt_failures=' + result.stats.decryptFailures
|
|
2970
|
+
+ ', invalid_json=' + result.stats.invalidJson
|
|
2971
|
+
+ ', session_invalid_json=' + (result.stats.sessionInvalidJson || 0)
|
|
2972
|
+
+ ', non_prism=' + result.stats.nonPrismSkipped + '.');
|
|
2973
|
+
}
|
|
2974
|
+
} catch (error) {
|
|
2975
|
+
console.error('[trajectory-export] Failed: ' + (error && error.message || error));
|
|
2976
|
+
process.exit(1);
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2751
2979
|
} else if (command === 'webui') {
|
|
2752
2980
|
const portFlag = args.find(a => typeof a === 'string' && a.startsWith('--port='));
|
|
2753
2981
|
const port = portFlag ? Number(portFlag.slice('--port='.length)) : undefined;
|
|
@@ -3227,7 +3455,7 @@ async function main() {
|
|
|
3227
3455
|
}
|
|
3228
3456
|
|
|
3229
3457
|
} else {
|
|
3230
|
-
console.log(`Usage: node index.js [run|/evolve|login|logout|proxy-token|solidify|review|distill|fetch|sync|asset-log|webui|setup-hooks|reuse|publish|recipe|buy|orders|verify|atp|atp-complete|experiment] [--loop]
|
|
3458
|
+
console.log(`Usage: node index.js [run|/evolve|login|logout|proxy-token|solidify|review|distill|fetch|sync|asset-log|trajectory-export|webui|setup-hooks|reuse|publish|recipe|buy|orders|verify|atp|atp-complete|experiment] [--loop]
|
|
3231
3459
|
- login (authorize this device via the hub, gh-auth-login style; stores an OAuth token used instead of node_secret)
|
|
3232
3460
|
- logout (remove the stored OAuth token)
|
|
3233
3461
|
- proxy-token (print the local proxy bearer token for command-backed client auth)
|
|
@@ -3276,6 +3504,29 @@ async function main() {
|
|
|
3276
3504
|
- --last=<N> (show last N entries)
|
|
3277
3505
|
- --since=<ISO_date> (entries after date)
|
|
3278
3506
|
- --json (raw JSON output)
|
|
3507
|
+
- trajectory-export flags:
|
|
3508
|
+
- --input=<path>|--input <path>
|
|
3509
|
+
(proxy trace JSONL, Claude/Codex/Cursor session JSONL, or directory; default: platform trace file)
|
|
3510
|
+
- --output=<path>|--output <path>
|
|
3511
|
+
(output JSONL; default: ./coding-trajectories.jsonl)
|
|
3512
|
+
- --runtime-sessions (local-only: also scan current-workspace Codex/Claude JSONL from ~/.codex/sessions and ~/.claude/projects; env: EVOLVER_TRAJECTORY_RUNTIME_SESSIONS=1)
|
|
3513
|
+
- --runtime-session-dir=<path>|--runtime-session-dir <path>
|
|
3514
|
+
(local-only: extra Codex/Claude runtime session directory; may be repeated)
|
|
3515
|
+
- --include-unmarked (collect runtime sessions even if evolver did not actively mark them; default: strict — only marked sessions are collected; env: EVOLVER_TRAJECTORY_INCLUDE_UNMARKED=1)
|
|
3516
|
+
- --include-gateway-captured (collect runtime sessions even if the proxy gateway already captured them; default: strict — gateway-captured sessions are skipped; env: EVOLVER_TRAJECTORY_INCLUDE_GATEWAY_CAPTURED=1)
|
|
3517
|
+
- --marked-sessions-file=<path>|--marked-sessions-file <path>
|
|
3518
|
+
(override the evolver-marked-sessions registry path; default: <trace-dir>/marked-sessions.jsonl; env: EVOLVER_MARKED_SESSIONS_FILE)
|
|
3519
|
+
- --allow-partial (skip unreadable encrypted rows instead of failing the whole export)
|
|
3520
|
+
- --node-secret=<hex|path>|--node-secret <hex|path>
|
|
3521
|
+
(read node secret from an existing local file, otherwise use the literal value)
|
|
3522
|
+
- --node-secret-file=<path>|--node-secret-file <path>
|
|
3523
|
+
(read node secret from a local file)
|
|
3524
|
+
- --node-secret-env=<name>|--node-secret-env <name>
|
|
3525
|
+
(read node secret from an environment variable)
|
|
3526
|
+
- --node-secret-keyring=<path>|--node-secret-keyring <path>
|
|
3527
|
+
(read versioned node secrets from a JSON file)
|
|
3528
|
+
- --hub-private-key=<path>|--hub-private-key <path>
|
|
3529
|
+
(decrypt hub_key_envelope trace rows with a local private key)
|
|
3279
3530
|
- webui flags:
|
|
3280
3531
|
- --port=<N> (local Web UI port, default 19821)
|
|
3281
3532
|
|
|
@@ -3328,5 +3579,8 @@ module.exports = {
|
|
|
3328
3579
|
parseBoolEnv,
|
|
3329
3580
|
CycleTimeoutError,
|
|
3330
3581
|
writeCycleProgressAtomic,
|
|
3582
|
+
handleCycleTimeout,
|
|
3583
|
+
observeTimedOutEvolvePromise,
|
|
3584
|
+
waitForTimedOutEvolvePromise,
|
|
3331
3585
|
spawnReplacementProcess,
|
|
3332
3586
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.89.
|
|
3
|
+
"version": "1.89.19",
|
|
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": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@evomap/atp-sdk": "^0.1.0",
|
|
42
42
|
"@evomap/gep-sdk": "^1.5.0",
|
|
43
43
|
"dotenv": "^16.4.7",
|
|
44
|
-
"undici": "^7.
|
|
44
|
+
"undici": "^7.28.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"javascript-obfuscator": "^5.4.1"
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"optionalDependencies": {
|
|
50
50
|
"@napi-rs/keyring": "^1.1.6"
|
|
51
51
|
},
|
|
52
|
+
"overrides": {
|
|
53
|
+
"@vercel/blob": {
|
|
54
|
+
"undici": "6.27.0"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
52
57
|
"files": [
|
|
53
58
|
"assets/",
|
|
54
59
|
"index.js",
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir, isEvolverHookCommand } = require('./hookAdapter');
|
|
3
|
+
const { mergeJsonFile, copyHookScripts, appendSectionToFile, removeHookScripts, removeMarkedSection, assertSafeConfigDir, isEvolverHookCommand, buildSafeNodeHookCommand } = require('./hookAdapter');
|
|
4
4
|
|
|
5
5
|
const HOOK_SCRIPTS_DIR_NAME = 'hooks';
|
|
6
6
|
const EVOLVER_MARKER = '<!-- evolver-evolution-memory -->';
|
|
7
7
|
|
|
8
|
-
function buildClaudeHooks(evolverRoot) {
|
|
9
|
-
|
|
8
|
+
function buildClaudeHooks(evolverRoot, configRoot) {
|
|
9
|
+
// Resolve hook scripts to an absolute path rooted at the real config dir so
|
|
10
|
+
// the command works regardless of the cwd Claude Code is launched from
|
|
11
|
+
// (#590). Falls back to the legacy relative base only when configRoot is
|
|
12
|
+
// absent (callers should always pass it).
|
|
13
|
+
const scriptsBase = configRoot
|
|
14
|
+
? path.resolve(configRoot, '.claude', 'hooks')
|
|
15
|
+
: path.join('.claude', 'hooks');
|
|
16
|
+
const hookCommand = (scriptName) =>
|
|
17
|
+
buildSafeNodeHookCommand(path.join(scriptsBase, scriptName));
|
|
10
18
|
return {
|
|
11
19
|
hooks: {
|
|
12
20
|
SessionStart: [
|
|
@@ -14,7 +22,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
14
22
|
hooks: [
|
|
15
23
|
{
|
|
16
24
|
type: 'command',
|
|
17
|
-
command:
|
|
25
|
+
command: hookCommand('evolver-session-start.js'),
|
|
18
26
|
timeout: 3,
|
|
19
27
|
},
|
|
20
28
|
],
|
|
@@ -32,7 +40,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
32
40
|
// ABOVE that watchdog, so the host never kills the script
|
|
33
41
|
// mid-write. A stuck/slow recall can never block or erase the
|
|
34
42
|
// user's prompt.
|
|
35
|
-
command:
|
|
43
|
+
command: hookCommand('evolver-task-recall.js'),
|
|
36
44
|
timeout: 5,
|
|
37
45
|
},
|
|
38
46
|
],
|
|
@@ -44,7 +52,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
44
52
|
hooks: [
|
|
45
53
|
{
|
|
46
54
|
type: 'command',
|
|
47
|
-
command:
|
|
55
|
+
command: hookCommand('evolver-signal-detect.js'),
|
|
48
56
|
timeout: 2,
|
|
49
57
|
},
|
|
50
58
|
],
|
|
@@ -55,7 +63,7 @@ function buildClaudeHooks(evolverRoot) {
|
|
|
55
63
|
hooks: [
|
|
56
64
|
{
|
|
57
65
|
type: 'command',
|
|
58
|
-
command:
|
|
66
|
+
command: hookCommand('evolver-session-end.js'),
|
|
59
67
|
timeout: 8,
|
|
60
68
|
},
|
|
61
69
|
],
|
|
@@ -87,19 +95,9 @@ function install({ configRoot, evolverRoot, force }) {
|
|
|
87
95
|
const claudeMdPath = path.join(configRoot, 'CLAUDE.md');
|
|
88
96
|
assertSafeConfigDir(claudeDir, '.claude', { subdirs: [HOOK_SCRIPTS_DIR_NAME] });
|
|
89
97
|
|
|
90
|
-
if (!force && fs.existsSync(settingsPath)) {
|
|
91
|
-
try {
|
|
92
|
-
const existing = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
93
|
-
if (existing._evolver_managed) {
|
|
94
|
-
console.log('[claude-code] Evolver hooks already installed. Use --force to overwrite.');
|
|
95
|
-
return { ok: true, skipped: true };
|
|
96
|
-
}
|
|
97
|
-
} catch { /* proceed */ }
|
|
98
|
-
}
|
|
99
|
-
|
|
100
98
|
fs.mkdirSync(claudeDir, { recursive: true });
|
|
101
99
|
|
|
102
|
-
const hooksCfg = buildClaudeHooks(evolverRoot);
|
|
100
|
+
const hooksCfg = buildClaudeHooks(evolverRoot, configRoot);
|
|
103
101
|
mergeJsonFile(settingsPath, hooksCfg);
|
|
104
102
|
console.log('[claude-code] Wrote ' + settingsPath);
|
|
105
103
|
|
|
@@ -10,7 +10,47 @@ const PLATFORMS = {
|
|
|
10
10
|
opencode: { name: 'opencode', configDir: '.opencode', detector: '.opencode' },
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
// Detect the host agent from runtime environment signals, which are far more
|
|
14
|
+
// reliable than scanning for `.claude` / `.cursor` directories when both exist
|
|
15
|
+
// on disk (e.g. under $HOME). Precedence when signals conflict (#590):
|
|
16
|
+
// 1. strong Claude Code signals (set only by the Claude Code runtime)
|
|
17
|
+
// 2. Cursor signals
|
|
18
|
+
// 3. Codex signals
|
|
19
|
+
// 4. CLAUDE_PROJECT_DIR — a weak Claude alias some hosts (incl. Cursor's
|
|
20
|
+
// Claude integration) export, so it loses to explicit Cursor signals.
|
|
21
|
+
function detectPlatformFromEnv(env = process.env) {
|
|
22
|
+
const hasStrongClaudeSignal = env.CLAUDECODE || env.CLAUDE_CODE_ENTRYPOINT;
|
|
23
|
+
if (hasStrongClaudeSignal) {
|
|
24
|
+
return 'claude-code';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const hasCursorSignal =
|
|
28
|
+
env.CURSOR_TRACE_ID ||
|
|
29
|
+
env.CURSOR_SESSION_ID ||
|
|
30
|
+
env.CURSOR_PROJECT_DIR ||
|
|
31
|
+
env.CURSOR_AGENT ||
|
|
32
|
+
String(env.TERM_PROGRAM || '').toLowerCase() === 'cursor';
|
|
33
|
+
if (hasCursorSignal) {
|
|
34
|
+
return 'cursor';
|
|
35
|
+
}
|
|
36
|
+
const hasCodexSignal =
|
|
37
|
+
env.CODEX_THREAD_ID ||
|
|
38
|
+
env.CODEX_SHELL ||
|
|
39
|
+
env.CODEX_CI ||
|
|
40
|
+
env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE;
|
|
41
|
+
if (hasCodexSignal) {
|
|
42
|
+
return 'codex';
|
|
43
|
+
}
|
|
44
|
+
if (env.CLAUDE_PROJECT_DIR) {
|
|
45
|
+
return 'claude-code';
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
13
50
|
function detectPlatform(cwd) {
|
|
51
|
+
const envPlatform = detectPlatformFromEnv();
|
|
52
|
+
if (envPlatform) return envPlatform;
|
|
53
|
+
|
|
14
54
|
const root = cwd || process.cwd();
|
|
15
55
|
const home = os.homedir();
|
|
16
56
|
for (const [id, meta] of Object.entries(PLATFORMS)) {
|
|
@@ -22,6 +62,37 @@ function detectPlatform(cwd) {
|
|
|
22
62
|
return null;
|
|
23
63
|
}
|
|
24
64
|
|
|
65
|
+
// Quote `value` as a single shell argument for the host that runs hook
|
|
66
|
+
// `command` strings (POSIX sh, or cmd.exe on Windows).
|
|
67
|
+
function shellQuoteForHost(value) {
|
|
68
|
+
const raw = String(value);
|
|
69
|
+
if (process.platform === 'win32') {
|
|
70
|
+
return `"${raw.replace(/"/g, '\\"')}"`;
|
|
71
|
+
}
|
|
72
|
+
return `'${raw.replace(/'/g, "'\\''")}'`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Build a hook `command` that runs `scriptPath` with node WITHOUT exposing the
|
|
76
|
+
// path bytes to the shell. The absolute path is base64-encoded into a `node -e`
|
|
77
|
+
// wrapper that decodes it and spawns the real script with `shell:false`, so
|
|
78
|
+
// spaces / `$()` / backticks / `%VAR%` in the path can never be expanded by sh
|
|
79
|
+
// or cmd.exe (#590). The plaintext basename is appended as a final, inert arg
|
|
80
|
+
// so uninstall/reinstall can still match evolver-owned hooks by command
|
|
81
|
+
// substring (see isEvolverHookCommand) even though the path itself is encoded.
|
|
82
|
+
//
|
|
83
|
+
// Shared across adapters so there is exactly one implementation to audit.
|
|
84
|
+
function buildSafeNodeHookCommand(scriptPath) {
|
|
85
|
+
const encodedPath = Buffer.from(String(scriptPath), 'utf8').toString('base64');
|
|
86
|
+
const js = [
|
|
87
|
+
"const{spawnSync}=require('child_process')",
|
|
88
|
+
`const p=Buffer.from('${encodedPath}','base64').toString('utf8')`,
|
|
89
|
+
"const r=spawnSync(process.execPath,[p],{stdio:'inherit',shell:false})",
|
|
90
|
+
"if(r.error){console.error(r.error.message||String(r.error));process.exit(1)}",
|
|
91
|
+
"process.exit(r.status==null?1:r.status)",
|
|
92
|
+
].join(';');
|
|
93
|
+
return `node -e ${shellQuoteForHost(js)} ${path.basename(scriptPath)}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
25
96
|
function resolveConfigRoot(platformId, cwd) {
|
|
26
97
|
const root = cwd || process.cwd();
|
|
27
98
|
const home = os.homedir();
|
|
@@ -74,11 +145,9 @@ function mergeWithHooksUnion(target, source) {
|
|
|
74
145
|
const tArr = Array.isArray(target.hooks[event]) ? target.hooks[event] : null;
|
|
75
146
|
const sArr = Array.isArray(source.hooks[event]) ? source.hooks[event] : null;
|
|
76
147
|
if (tArr && sArr) {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
};
|
|
81
|
-
const userEntries = tArr.filter(e => !isEvolverOwned(e));
|
|
148
|
+
const userEntries = tArr
|
|
149
|
+
.map(stripEvolverCommands)
|
|
150
|
+
.filter(Boolean);
|
|
82
151
|
result.hooks[event] = [...userEntries, ...sArr];
|
|
83
152
|
}
|
|
84
153
|
}
|
|
@@ -86,6 +155,22 @@ function mergeWithHooksUnion(target, source) {
|
|
|
86
155
|
return result;
|
|
87
156
|
}
|
|
88
157
|
|
|
158
|
+
function stripEvolverCommands(entry) {
|
|
159
|
+
if (!entry || typeof entry !== 'object') return entry;
|
|
160
|
+
if (typeof entry.command === 'string' && isEvolverHookCommand(entry.command)) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
if (!Array.isArray(entry.hooks)) return entry;
|
|
164
|
+
|
|
165
|
+
const hooks = entry.hooks.filter(h => {
|
|
166
|
+
const cmd = h && h.command;
|
|
167
|
+
return !(typeof cmd === 'string' && isEvolverHookCommand(cmd));
|
|
168
|
+
});
|
|
169
|
+
if (hooks.length === 0) return null;
|
|
170
|
+
if (hooks.length === entry.hooks.length) return entry;
|
|
171
|
+
return { ...entry, hooks };
|
|
172
|
+
}
|
|
173
|
+
|
|
89
174
|
// Pull all `command` strings out of an event entry, supporting both flat
|
|
90
175
|
// shape (Codex: `{type, command}`) and Claude Code matcher shape
|
|
91
176
|
// (`{matcher, hooks: [{type, command}]}`). Returns [] when neither applies.
|
|
@@ -362,7 +447,9 @@ async function setupHooks({ platform, cwd, force, uninstall, evolverRoot } = {})
|
|
|
362
447
|
}
|
|
363
448
|
|
|
364
449
|
module.exports = {
|
|
450
|
+
detectPlatformFromEnv,
|
|
365
451
|
detectPlatform,
|
|
452
|
+
buildSafeNodeHookCommand,
|
|
366
453
|
resolveConfigRoot,
|
|
367
454
|
loadAdapter,
|
|
368
455
|
mergeJsonFile,
|