@evomap/evolver 1.89.12 → 1.89.14
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/CONTRIBUTING.md +19 -0
- package/README.md +537 -90
- package/assets/cover.png +0 -0
- package/index.js +24 -11
- package/package.json +18 -6
- package/scripts/a2a_export.js +63 -0
- package/scripts/a2a_ingest.js +79 -0
- package/scripts/a2a_promote.js +118 -0
- package/scripts/analyze_by_skill.js +121 -0
- package/scripts/build_binaries.js +479 -0
- package/scripts/check-changelog.js +166 -0
- package/scripts/extract_log.js +85 -0
- package/scripts/generate_history.js +75 -0
- package/scripts/gep_append_event.js +96 -0
- package/scripts/gep_personality_report.js +234 -0
- package/scripts/human_report.js +147 -0
- package/scripts/recall-verify-report.js +234 -0
- package/scripts/recover_loop.js +61 -0
- package/scripts/refresh_stars_badge.js +168 -0
- package/scripts/seed-merchants.js +91 -0
- package/scripts/suggest_version.js +89 -0
- package/scripts/validate-modules.js +38 -0
- package/scripts/validate-suite.js +78 -0
- package/skills/index.json +14 -0
- package/src/evolve/guards.js +1 -721
- package/src/evolve/pipeline/collect.js +1 -1283
- package/src/evolve/pipeline/dispatch.js +1 -421
- package/src/evolve/pipeline/enrich.js +1 -440
- package/src/evolve/pipeline/hub.js +1 -319
- package/src/evolve/pipeline/select.js +1 -274
- package/src/evolve/pipeline/signals.js +1 -206
- package/src/evolve/utils.js +1 -264
- package/src/evolve.js +1 -350
- package/src/gep/a2aProtocol.js +1 -4463
- package/src/gep/antiAbuseTelemetry.js +1 -233
- package/src/gep/autoDistillConv.js +1 -205
- package/src/gep/autoDistillLlm.js +1 -315
- package/src/gep/candidateEval.js +1 -92
- package/src/gep/candidates.js +1 -198
- package/src/gep/contentHash.js +1 -30
- package/src/gep/conversationDistiller.js +1 -270
- package/src/gep/conversationSniffer.js +1 -266
- package/src/gep/crypto.js +1 -89
- package/src/gep/curriculum.js +1 -163
- package/src/gep/deviceId.js +1 -218
- package/src/gep/envFingerprint.js +1 -118
- package/src/gep/epigenetics.js +1 -31
- package/src/gep/execBridge.js +1 -712
- package/src/gep/explore.js +1 -289
- package/src/gep/hash.js +1 -15
- package/src/gep/hubFetch.js +1 -608
- package/src/gep/hubReview.js +1 -207
- package/src/gep/hubSearch.js +1 -526
- package/src/gep/hubVerify.js +1 -306
- package/src/gep/learningSignals.js +1 -89
- package/src/gep/memoryGraph.js +1 -1449
- package/src/gep/memoryGraphAdapter.js +1 -203
- package/src/gep/mutation.js +1 -203
- package/src/gep/narrativeMemory.js +1 -108
- package/src/gep/openPRRegistry.js +1 -205
- package/src/gep/personality.js +1 -423
- package/src/gep/policyCheck.js +1 -599
- package/src/gep/prompt.js +1 -836
- package/src/gep/recallInject.js +1 -409
- package/src/gep/recallVerifier.js +1 -318
- package/src/gep/reflection.js +1 -177
- package/src/gep/savingsCore.js +1 -112
- package/src/gep/selector.js +1 -602
- package/src/gep/skillDistiller.js +1 -1294
- package/src/gep/solidify.js +1 -1699
- package/src/gep/strategy.js +1 -136
- package/src/gep/tokenSavings.js +1 -95
- package/src/gep/workspaceKeychain.js +1 -174
- package/src/proxy/extensions/traceControl.js +1 -109
- package/src/proxy/index.js +50 -0
- package/src/proxy/inject.js +1 -52
- package/src/proxy/lifecycle/manager.js +40 -1
- package/src/proxy/server/routes.js +10 -0
- package/src/proxy/sync/outbound.js +1 -1
- package/src/proxy/trace/extractor.js +1 -1403
- package/src/proxy/trace/usage.js +1 -105
- package/.cursor/BUGBOT.md +0 -182
- package/.env.example +0 -68
- package/.git-commit-guard-token +0 -1
- package/.github/CODEOWNERS +0 -63
- package/.github/ISSUE_TEMPLATE/good_first_issue.md +0 -23
- package/.github/pull_request_template.md +0 -45
- package/.github/workflows/test.yml +0 -75
- package/CHANGELOG.md +0 -1367
- package/README.public.md +0 -578
- package/SECURITY.md +0 -108
- package/assets/gep/events.jsonl +0 -3
- package/examples/atp-consumer-quickstart.md +0 -100
- package/examples/hello-world.md +0 -38
- package/proxy-package.json +0 -39
- package/public.manifest.json +0 -145
- /package/assets/gep/{genes.json → genes.seed.json} +0 -0
- /package/{bundled-skills → skills}/_meta/SKILL.md +0 -0
package/assets/cover.png
ADDED
|
Binary file
|
package/index.js
CHANGED
|
@@ -2715,11 +2715,12 @@ async function main() {
|
|
|
2715
2715
|
} else if (command === 'reset-local-secret') {
|
|
2716
2716
|
// Wipe every local store of node_secret in one shot, so a daemon stuck
|
|
2717
2717
|
// after a manual web reset (https://evomap.ai/account -> Reset Secret)
|
|
2718
|
-
// can boot clean.
|
|
2719
|
-
// - MailboxStore: ~/.evomap/mailbox/state.json key node_secret
|
|
2720
|
-
// - Legacy
|
|
2721
|
-
// - Shell env: A2A_NODE_SECRET
|
|
2722
|
-
// we
|
|
2718
|
+
// can boot clean. Local stores involved:
|
|
2719
|
+
// - MailboxStore: ~/.evomap/mailbox/state.json key node_secret + version
|
|
2720
|
+
// - Legacy files: ~/.evomap/node_secret and ~/.evomap/node_secret_version
|
|
2721
|
+
// - Shell env: A2A_NODE_SECRET / EVOMAP_NODE_SECRET and matching
|
|
2722
|
+
// version vars (we cannot mutate the parent shell; we
|
|
2723
|
+
// just print the unset hint)
|
|
2723
2724
|
const path = require('path');
|
|
2724
2725
|
const fs = require('fs');
|
|
2725
2726
|
// Honor an explicit HOME override (used by tests to redirect to a fake
|
|
@@ -2731,12 +2732,13 @@ async function main() {
|
|
|
2731
2732
|
const home = process.env.HOME || os.homedir();
|
|
2732
2733
|
const stateFile = path.join(home, '.evomap', 'mailbox', 'state.json');
|
|
2733
2734
|
const legacyFile = path.join(home, '.evomap', 'node_secret');
|
|
2735
|
+
const legacyVersionFile = path.join(home, '.evomap', 'node_secret_version');
|
|
2734
2736
|
let cleared = 0;
|
|
2735
2737
|
try {
|
|
2736
2738
|
if (fs.existsSync(stateFile)) {
|
|
2737
2739
|
const raw = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
2738
2740
|
let mutated = false;
|
|
2739
|
-
for (const k of ['node_secret', 'node_secret_source']) {
|
|
2741
|
+
for (const k of ['node_secret', 'node_secret_source', 'node_secret_version']) {
|
|
2740
2742
|
if (raw[k] !== undefined && raw[k] !== '') {
|
|
2741
2743
|
raw[k] = '';
|
|
2742
2744
|
mutated = true;
|
|
@@ -2755,17 +2757,28 @@ async function main() {
|
|
|
2755
2757
|
cleared += 1;
|
|
2756
2758
|
console.log('[reset-local-secret] removed legacy file ' + legacyFile);
|
|
2757
2759
|
}
|
|
2760
|
+
if (fs.existsSync(legacyVersionFile)) {
|
|
2761
|
+
fs.unlinkSync(legacyVersionFile);
|
|
2762
|
+
cleared += 1;
|
|
2763
|
+
console.log('[reset-local-secret] removed legacy file ' + legacyVersionFile);
|
|
2764
|
+
}
|
|
2758
2765
|
} catch (err) {
|
|
2759
2766
|
console.error('[reset-local-secret] error:', err && err.message || err);
|
|
2760
2767
|
process.exit(1);
|
|
2761
2768
|
}
|
|
2762
|
-
|
|
2769
|
+
const stillSetEnv = [
|
|
2770
|
+
'A2A_NODE_SECRET',
|
|
2771
|
+
'A2A_NODE_SECRET_VERSION',
|
|
2772
|
+
'EVOMAP_NODE_SECRET',
|
|
2773
|
+
'EVOMAP_NODE_SECRET_VERSION',
|
|
2774
|
+
].filter((key) => process.env[key]);
|
|
2775
|
+
if (stillSetEnv.length > 0) {
|
|
2763
2776
|
console.log('');
|
|
2764
|
-
console.log('[reset-local-secret]
|
|
2765
|
-
console.log('[reset-local-secret] Run: unset A2A_NODE_SECRET');
|
|
2766
|
-
console.log('[reset-local-secret] Or
|
|
2777
|
+
console.log('[reset-local-secret] Node secret env vars are still set in this shell: ' + stillSetEnv.join(', '));
|
|
2778
|
+
console.log('[reset-local-secret] Run: unset A2A_NODE_SECRET A2A_NODE_SECRET_VERSION EVOMAP_NODE_SECRET EVOMAP_NODE_SECRET_VERSION');
|
|
2779
|
+
console.log('[reset-local-secret] Or update secret and version as a matched pair before restarting the daemon.');
|
|
2767
2780
|
} else {
|
|
2768
|
-
console.log('[reset-local-secret]
|
|
2781
|
+
console.log('[reset-local-secret] Node secret env vars are not set in env -- good.');
|
|
2769
2782
|
}
|
|
2770
2783
|
console.log('[reset-local-secret] ' + cleared + ' location(s) cleared. Restart the daemon to pick a fresh secret from the hub.');
|
|
2771
2784
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.89.
|
|
3
|
+
"version": "1.89.14",
|
|
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": {
|
|
@@ -28,12 +28,10 @@
|
|
|
28
28
|
"run": "node index.js run",
|
|
29
29
|
"solidify": "node index.js solidify",
|
|
30
30
|
"review": "node index.js review",
|
|
31
|
-
"distill": "node index.js distill",
|
|
32
|
-
"webui": "node index.js webui",
|
|
33
|
-
"test": "node -e \"const fs=require('fs'),cp=require('child_process');const all=fs.readdirSync('test').filter(f=>f.endsWith('.test.js'));const iso=new Set(['solidifyIntegration.test.js']);const others=all.filter(f=>!iso.has(f)).map(f=>'test/'+f);const isoFiles=all.filter(f=>iso.has(f)).map(f=>'test/'+f);if(others.length)cp.execSync('node --test '+others.join(' '),{stdio:'inherit'});if(isoFiles.length)cp.execSync('node --test '+isoFiles.join(' '),{stdio:'inherit'})\"",
|
|
34
31
|
"a2a:export": "node scripts/a2a_export.js",
|
|
35
32
|
"a2a:ingest": "node scripts/a2a_ingest.js",
|
|
36
|
-
"a2a:promote": "node scripts/a2a_promote.js"
|
|
33
|
+
"a2a:promote": "node scripts/a2a_promote.js",
|
|
34
|
+
"test": "node -e \"const fs=require('fs'),cp=require('child_process');const all=fs.readdirSync('test').filter(f=>f.endsWith('.test.js'));const iso=new Set(['solidifyIntegration.test.js']);const others=all.filter(f=>!iso.has(f)).map(f=>'test/'+f);const isoFiles=all.filter(f=>iso.has(f)).map(f=>'test/'+f);if(others.length)cp.execSync('node --test '+others.join(' '),{stdio:'inherit'});if(isoFiles.length)cp.execSync('node --test '+isoFiles.join(' '),{stdio:'inherit'})\""
|
|
37
35
|
},
|
|
38
36
|
"engines": {
|
|
39
37
|
"node": ">=22.12"
|
|
@@ -50,5 +48,19 @@
|
|
|
50
48
|
},
|
|
51
49
|
"optionalDependencies": {
|
|
52
50
|
"@napi-rs/keyring": "^1.1.6"
|
|
53
|
-
}
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"assets/",
|
|
54
|
+
"index.js",
|
|
55
|
+
"src/",
|
|
56
|
+
"scripts/",
|
|
57
|
+
"skills/",
|
|
58
|
+
"conformance/",
|
|
59
|
+
"README.md",
|
|
60
|
+
"README.zh-CN.md",
|
|
61
|
+
"README.ja-JP.md",
|
|
62
|
+
"SKILL.md",
|
|
63
|
+
"CONTRIBUTING.md",
|
|
64
|
+
"LICENSE"
|
|
65
|
+
]
|
|
54
66
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const { loadGenes, loadCapsules, readAllEvents } = require('../src/gep/assetStore');
|
|
2
|
+
const { exportEligibleCapsules, exportEligibleGenes, isAllowedA2AAsset } = require('../src/gep/a2a');
|
|
3
|
+
const { buildPublish, buildHello, getTransport } = require('../src/gep/a2aProtocol');
|
|
4
|
+
const { computeAssetId, SCHEMA_VERSION } = require('../src/gep/contentHash');
|
|
5
|
+
|
|
6
|
+
function main() {
|
|
7
|
+
var args = process.argv.slice(2);
|
|
8
|
+
var asJson = args.includes('--json');
|
|
9
|
+
var asProtocol = args.includes('--protocol');
|
|
10
|
+
var withHello = args.includes('--hello');
|
|
11
|
+
var persist = args.includes('--persist');
|
|
12
|
+
var includeEvents = args.includes('--include-events');
|
|
13
|
+
|
|
14
|
+
var capsules = loadCapsules();
|
|
15
|
+
var genes = loadGenes();
|
|
16
|
+
var events = readAllEvents();
|
|
17
|
+
|
|
18
|
+
// Build eligible list: Capsules (filtered) + Genes (filtered) + Events (opt-in)
|
|
19
|
+
var eligibleCapsules = exportEligibleCapsules({ capsules: capsules, events: events });
|
|
20
|
+
var eligibleGenes = exportEligibleGenes({ genes: genes });
|
|
21
|
+
var eligible = eligibleCapsules.concat(eligibleGenes);
|
|
22
|
+
|
|
23
|
+
if (includeEvents) {
|
|
24
|
+
var eligibleEvents = (Array.isArray(events) ? events : []).filter(function (e) {
|
|
25
|
+
return isAllowedA2AAsset(e) && e.type === 'EvolutionEvent';
|
|
26
|
+
});
|
|
27
|
+
for (var ei = 0; ei < eligibleEvents.length; ei++) {
|
|
28
|
+
var ev = eligibleEvents[ei];
|
|
29
|
+
if (!ev.schema_version) ev.schema_version = SCHEMA_VERSION;
|
|
30
|
+
if (!ev.asset_id) { try { ev.asset_id = computeAssetId(ev); } catch (e) {} }
|
|
31
|
+
}
|
|
32
|
+
eligible = eligible.concat(eligibleEvents);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (withHello || asProtocol) {
|
|
36
|
+
var hello = buildHello({ geneCount: genes.length, capsuleCount: capsules.length });
|
|
37
|
+
process.stdout.write(JSON.stringify(hello) + '\n');
|
|
38
|
+
if (persist) { try { getTransport().send(hello); } catch (e) {} }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (asProtocol) {
|
|
42
|
+
for (var i = 0; i < eligible.length; i++) {
|
|
43
|
+
var msg = buildPublish({ asset: eligible[i] });
|
|
44
|
+
process.stdout.write(JSON.stringify(msg) + '\n');
|
|
45
|
+
if (persist) { try { getTransport().send(msg); } catch (e) {} }
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (asJson) {
|
|
51
|
+
process.stdout.write(JSON.stringify(eligible, null, 2) + '\n');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (var j = 0; j < eligible.length; j++) {
|
|
56
|
+
process.stdout.write(JSON.stringify(eligible[j]) + '\n');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try { main(); } catch (e) {
|
|
61
|
+
process.stderr.write((e && e.message ? e.message : String(e)) + '\n');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var fs = require('fs');
|
|
2
|
+
var assetStore = require('../src/gep/assetStore');
|
|
3
|
+
var a2a = require('../src/gep/a2a');
|
|
4
|
+
var memGraph = require('../src/gep/memoryGraphAdapter');
|
|
5
|
+
var contentHash = require('../src/gep/contentHash');
|
|
6
|
+
var a2aProto = require('../src/gep/a2aProtocol');
|
|
7
|
+
|
|
8
|
+
function readStdin() {
|
|
9
|
+
try { return fs.readFileSync(0, 'utf8'); } catch (e) { return ''; }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function parseSignalsFromEnv() {
|
|
13
|
+
var raw = process.env.A2A_SIGNALS || '';
|
|
14
|
+
if (!raw) return [];
|
|
15
|
+
try {
|
|
16
|
+
var maybe = JSON.parse(raw);
|
|
17
|
+
if (Array.isArray(maybe)) return maybe.map(String).filter(Boolean);
|
|
18
|
+
} catch (e) {}
|
|
19
|
+
return String(raw).split(',').map(function (s) { return s.trim(); }).filter(Boolean);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function main() {
|
|
23
|
+
var args = process.argv.slice(2);
|
|
24
|
+
var inputPath = '';
|
|
25
|
+
for (var i = 0; i < args.length; i++) {
|
|
26
|
+
if (args[i] && !args[i].startsWith('--')) { inputPath = args[i]; break; }
|
|
27
|
+
}
|
|
28
|
+
var source = process.env.A2A_SOURCE || 'external';
|
|
29
|
+
var factor = Number.isFinite(Number(process.env.A2A_EXTERNAL_CONFIDENCE_FACTOR))
|
|
30
|
+
? Number(process.env.A2A_EXTERNAL_CONFIDENCE_FACTOR) : 0.6;
|
|
31
|
+
|
|
32
|
+
var text = inputPath ? a2a.readTextIfExists(inputPath) : readStdin();
|
|
33
|
+
var parsed = a2a.parseA2AInput(text);
|
|
34
|
+
var signals = parseSignalsFromEnv();
|
|
35
|
+
|
|
36
|
+
var accepted = 0;
|
|
37
|
+
var rejected = 0;
|
|
38
|
+
var emitDecisions = process.env.A2A_EMIT_DECISIONS === 'true';
|
|
39
|
+
|
|
40
|
+
for (var j = 0; j < parsed.length; j++) {
|
|
41
|
+
var obj = parsed[j];
|
|
42
|
+
if (!a2a.isAllowedA2AAsset(obj)) continue;
|
|
43
|
+
|
|
44
|
+
if (obj.asset_id && typeof obj.asset_id === 'string') {
|
|
45
|
+
if (!contentHash.verifyAssetId(obj)) {
|
|
46
|
+
rejected += 1;
|
|
47
|
+
if (emitDecisions) {
|
|
48
|
+
try {
|
|
49
|
+
var dm = a2aProto.buildDecision({ assetId: obj.asset_id, localId: obj.id, decision: 'reject', reason: 'asset_id integrity check failed' });
|
|
50
|
+
a2aProto.getTransport().send(dm);
|
|
51
|
+
} catch (e) {}
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
var staged = a2a.lowerConfidence(obj, { source: source, factor: factor });
|
|
58
|
+
if (!staged) continue;
|
|
59
|
+
|
|
60
|
+
assetStore.appendExternalCandidateJsonl(staged);
|
|
61
|
+
try { memGraph.recordExternalCandidate({ asset: staged, source: source, signals: signals }); } catch (e) {}
|
|
62
|
+
|
|
63
|
+
if (emitDecisions) {
|
|
64
|
+
try {
|
|
65
|
+
var dm2 = a2aProto.buildDecision({ assetId: staged.asset_id, localId: staged.id, decision: 'quarantine', reason: 'staged as external candidate' });
|
|
66
|
+
a2aProto.getTransport().send(dm2);
|
|
67
|
+
} catch (e) {}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
accepted += 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
process.stdout.write('accepted=' + accepted + ' rejected=' + rejected + '\n');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try { main(); } catch (e) {
|
|
77
|
+
process.stderr.write((e && e.message ? e.message : String(e)) + '\n');
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var assetStore = require('../src/gep/assetStore');
|
|
2
|
+
var solidifyMod = require('../src/gep/solidify');
|
|
3
|
+
var contentHash = require('../src/gep/contentHash');
|
|
4
|
+
var a2aProto = require('../src/gep/a2aProtocol');
|
|
5
|
+
|
|
6
|
+
function parseArgs(argv) {
|
|
7
|
+
var out = { flags: new Set(), kv: new Map(), positionals: [] };
|
|
8
|
+
for (var i = 0; i < argv.length; i++) {
|
|
9
|
+
var a = argv[i];
|
|
10
|
+
if (!a) continue;
|
|
11
|
+
if (a.startsWith('--')) {
|
|
12
|
+
var eq = a.indexOf('=');
|
|
13
|
+
if (eq > -1) { out.kv.set(a.slice(2, eq), a.slice(eq + 1)); }
|
|
14
|
+
else {
|
|
15
|
+
var key = a.slice(2);
|
|
16
|
+
var next = argv[i + 1];
|
|
17
|
+
if (next && !String(next).startsWith('--')) { out.kv.set(key, next); i++; }
|
|
18
|
+
else { out.flags.add(key); }
|
|
19
|
+
}
|
|
20
|
+
} else { out.positionals.push(a); }
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function main() {
|
|
26
|
+
var args = parseArgs(process.argv.slice(2));
|
|
27
|
+
var id = String(args.kv.get('id') || '').trim();
|
|
28
|
+
var typeRaw = String(args.kv.get('type') || '').trim().toLowerCase();
|
|
29
|
+
var validated = args.flags.has('validated') || String(args.kv.get('validated') || '') === 'true';
|
|
30
|
+
var limit = Number.isFinite(Number(args.kv.get('limit'))) ? Number(args.kv.get('limit')) : 500;
|
|
31
|
+
|
|
32
|
+
if (!id || !typeRaw) throw new Error('Usage: node scripts/a2a_promote.js --type capsule|gene|event --id <id> --validated');
|
|
33
|
+
if (!validated) throw new Error('Refusing to promote without --validated (local verification must be done first).');
|
|
34
|
+
|
|
35
|
+
var type = typeRaw === 'capsule' ? 'Capsule' : typeRaw === 'gene' ? 'Gene' : typeRaw === 'event' ? 'EvolutionEvent' : '';
|
|
36
|
+
if (!type) throw new Error('Invalid --type. Use capsule, gene, or event.');
|
|
37
|
+
|
|
38
|
+
var external = assetStore.readRecentExternalCandidates(limit);
|
|
39
|
+
var candidate = null;
|
|
40
|
+
for (var i = 0; i < external.length; i++) {
|
|
41
|
+
if (external[i] && external[i].type === type && String(external[i].id) === id) { candidate = external[i]; break; }
|
|
42
|
+
}
|
|
43
|
+
if (!candidate) throw new Error('Candidate not found in external zone: type=' + type + ' id=' + id);
|
|
44
|
+
|
|
45
|
+
if (type === 'Gene') {
|
|
46
|
+
var validation = Array.isArray(candidate.validation) ? candidate.validation : [];
|
|
47
|
+
for (var j = 0; j < validation.length; j++) {
|
|
48
|
+
var c = String(validation[j] || '').trim();
|
|
49
|
+
if (!c) continue;
|
|
50
|
+
if (!solidifyMod.isValidationCommandAllowed(c)) {
|
|
51
|
+
throw new Error('Refusing to promote Gene ' + id + ': validation command rejected by safety check: "' + c + '". Only node/npm/npx commands without shell operators are allowed.');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
var promoted = JSON.parse(JSON.stringify(candidate));
|
|
57
|
+
if (!promoted.a2a || typeof promoted.a2a !== 'object') promoted.a2a = {};
|
|
58
|
+
promoted.a2a.status = 'promoted';
|
|
59
|
+
promoted.a2a.promoted_at = new Date().toISOString();
|
|
60
|
+
if (!promoted.schema_version) promoted.schema_version = contentHash.SCHEMA_VERSION;
|
|
61
|
+
promoted.asset_id = contentHash.computeAssetId(promoted);
|
|
62
|
+
|
|
63
|
+
var emitDecisions = process.env.A2A_EMIT_DECISIONS === 'true';
|
|
64
|
+
|
|
65
|
+
if (type === 'EvolutionEvent') {
|
|
66
|
+
assetStore.appendEventJsonl(promoted);
|
|
67
|
+
if (emitDecisions) {
|
|
68
|
+
try {
|
|
69
|
+
var dmEv = a2aProto.buildDecision({ assetId: promoted.asset_id, localId: id, decision: 'accept', reason: 'event promoted for provenance tracking' });
|
|
70
|
+
a2aProto.getTransport().send(dmEv);
|
|
71
|
+
} catch (e) {}
|
|
72
|
+
}
|
|
73
|
+
process.stdout.write('promoted_event=' + id + '\n');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (type === 'Capsule') {
|
|
78
|
+
assetStore.appendCapsule(promoted);
|
|
79
|
+
if (emitDecisions) {
|
|
80
|
+
try {
|
|
81
|
+
var dm = a2aProto.buildDecision({ assetId: promoted.asset_id, localId: id, decision: 'accept', reason: 'capsule promoted after validation' });
|
|
82
|
+
a2aProto.getTransport().send(dm);
|
|
83
|
+
} catch (e) {}
|
|
84
|
+
}
|
|
85
|
+
process.stdout.write('promoted_capsule=' + id + '\n');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
var localGenes = assetStore.loadGenes();
|
|
90
|
+
var exists = false;
|
|
91
|
+
for (var k = 0; k < localGenes.length; k++) {
|
|
92
|
+
if (localGenes[k] && localGenes[k].type === 'Gene' && String(localGenes[k].id) === id) { exists = true; break; }
|
|
93
|
+
}
|
|
94
|
+
if (exists) {
|
|
95
|
+
if (emitDecisions) {
|
|
96
|
+
try {
|
|
97
|
+
var dm2 = a2aProto.buildDecision({ assetId: promoted.asset_id, localId: id, decision: 'reject', reason: 'local gene with same ID already exists' });
|
|
98
|
+
a2aProto.getTransport().send(dm2);
|
|
99
|
+
} catch (e) {}
|
|
100
|
+
}
|
|
101
|
+
process.stdout.write('conflict_keep_local_gene=' + id + '\n');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
assetStore.upsertGene(promoted);
|
|
106
|
+
if (emitDecisions) {
|
|
107
|
+
try {
|
|
108
|
+
var dm3 = a2aProto.buildDecision({ assetId: promoted.asset_id, localId: id, decision: 'accept', reason: 'gene promoted after safety audit' });
|
|
109
|
+
a2aProto.getTransport().send(dm3);
|
|
110
|
+
} catch (e) {}
|
|
111
|
+
}
|
|
112
|
+
process.stdout.write('promoted_gene=' + id + '\n');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
try { main(); } catch (e) {
|
|
116
|
+
process.stderr.write((e && e.message ? e.message : String(e)) + '\n');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
5
|
+
const LOG_FILE = path.join(REPO_ROOT, 'evolution_history_full.md');
|
|
6
|
+
const OUT_FILE = path.join(REPO_ROOT, 'evolution_detailed_report.md');
|
|
7
|
+
|
|
8
|
+
function analyzeEvolution() {
|
|
9
|
+
if (!fs.existsSync(LOG_FILE)) {
|
|
10
|
+
console.error("Source file missing.");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const content = fs.readFileSync(LOG_FILE, 'utf8');
|
|
15
|
+
// Split by divider
|
|
16
|
+
const entries = content.split('---').map(e => e.trim()).filter(e => e.length > 0);
|
|
17
|
+
|
|
18
|
+
const skillUpdates = {}; // Map<SkillName, Array<Changes>>
|
|
19
|
+
const generalUpdates = []; // Array<Changes>
|
|
20
|
+
|
|
21
|
+
// Regex to detect skills/paths
|
|
22
|
+
// e.g. `skills/feishu-card/send.js` or **Target**: `skills/git-sync`
|
|
23
|
+
const skillRegex = /skills\/([a-zA-Z0-9\-_]+)/;
|
|
24
|
+
const actionRegex = /Action:\s*([\s\S]*?)(?=\n\n|\n[A-Z]|$)/i; // Capture Action text
|
|
25
|
+
const statusRegex = /Status:\s*\[?([A-Z\s_]+)\]?/i;
|
|
26
|
+
|
|
27
|
+
entries.forEach(entry => {
|
|
28
|
+
// Extract basic info
|
|
29
|
+
const statusMatch = entry.match(statusRegex);
|
|
30
|
+
const status = statusMatch ? statusMatch[1].trim().toUpperCase() : 'UNKNOWN';
|
|
31
|
+
|
|
32
|
+
// Skip routine checks if we want a *detailed evolution* report (focus on changes)
|
|
33
|
+
// But user asked for "what happened", so routine scans might be boring unless they found something.
|
|
34
|
+
// Let's filter out "STABILITY" or "RUNNING" unless there is a clear "Mutated" or "Fixed" keyword.
|
|
35
|
+
const isInteresting =
|
|
36
|
+
entry.includes('Fixed') ||
|
|
37
|
+
entry.includes('Hardened') ||
|
|
38
|
+
entry.includes('Optimized') ||
|
|
39
|
+
entry.includes('Patched') ||
|
|
40
|
+
entry.includes('Created') ||
|
|
41
|
+
entry.includes('Added') ||
|
|
42
|
+
status === 'SUCCESS' ||
|
|
43
|
+
status === 'COMPLETED';
|
|
44
|
+
|
|
45
|
+
if (!isInteresting) return;
|
|
46
|
+
|
|
47
|
+
// Find associated skill
|
|
48
|
+
const skillMatch = entry.match(skillRegex);
|
|
49
|
+
let skillName = 'General / System';
|
|
50
|
+
if (skillMatch) {
|
|
51
|
+
skillName = skillMatch[1];
|
|
52
|
+
} else {
|
|
53
|
+
// Try heuristics
|
|
54
|
+
if (entry.toLowerCase().includes('feishu card')) skillName = 'feishu-card';
|
|
55
|
+
else if (entry.toLowerCase().includes('git sync')) skillName = 'git-sync';
|
|
56
|
+
else if (entry.toLowerCase().includes('logger')) skillName = 'interaction-logger';
|
|
57
|
+
else if (entry.toLowerCase().includes('evolve')) skillName = 'capability-evolver';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Extract description
|
|
61
|
+
let description = "";
|
|
62
|
+
const actionMatch = entry.match(actionRegex);
|
|
63
|
+
if (actionMatch) {
|
|
64
|
+
description = actionMatch[1].trim();
|
|
65
|
+
} else {
|
|
66
|
+
// Fallback: take lines that look like bullet points or text after header
|
|
67
|
+
const lines = entry.split('\n');
|
|
68
|
+
description = lines.filter(l => l.match(/^[•\-\*]|\w/)).slice(1).join('\n').trim();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Clean up description (remove duplicate "Action:" prefix if captured)
|
|
72
|
+
description = description.replace(/^Action:\s*/i, '');
|
|
73
|
+
|
|
74
|
+
if (!skillUpdates[skillName]) skillUpdates[skillName] = [];
|
|
75
|
+
|
|
76
|
+
// Dedup descriptions slightly (simple check)
|
|
77
|
+
const isDuplicate = skillUpdates[skillName].some(u => u.desc.includes(description.substring(0, 20)));
|
|
78
|
+
if (!isDuplicate) {
|
|
79
|
+
// Extract Date if possible
|
|
80
|
+
const dateMatch = entry.match(/\((\d{4}\/\d{1,2}\/\d{1,2}.*?)\)/);
|
|
81
|
+
const date = dateMatch ? dateMatch[1] : 'Unknown';
|
|
82
|
+
|
|
83
|
+
skillUpdates[skillName].push({
|
|
84
|
+
date,
|
|
85
|
+
status,
|
|
86
|
+
desc: description
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Generate Markdown
|
|
92
|
+
let md = "# Detailed Evolution Report (By Skill)\n\n> Comprehensive breakdown of system changes.\n\n";
|
|
93
|
+
|
|
94
|
+
// Sort skills alphabetically
|
|
95
|
+
const sortedSkills = Object.keys(skillUpdates).sort();
|
|
96
|
+
|
|
97
|
+
sortedSkills.forEach(skill => {
|
|
98
|
+
md += `## ${skill}\n`;
|
|
99
|
+
const updates = skillUpdates[skill];
|
|
100
|
+
|
|
101
|
+
updates.forEach(u => {
|
|
102
|
+
// Icon based on content
|
|
103
|
+
let icon = '*';
|
|
104
|
+
const lowerDesc = u.desc.toLowerCase();
|
|
105
|
+
if (lowerDesc.includes('optimiz')) icon = '[optimize]';
|
|
106
|
+
if (lowerDesc.includes('secur') || lowerDesc.includes('harden') || lowerDesc.includes('permission')) icon = '[security]';
|
|
107
|
+
if (lowerDesc.includes('fix') || lowerDesc.includes('patch')) icon = '[repair]';
|
|
108
|
+
if (lowerDesc.includes('creat') || lowerDesc.includes('add')) icon = '[add]';
|
|
109
|
+
|
|
110
|
+
md += `### ${icon} ${u.date}\n`;
|
|
111
|
+
md += `${u.desc}\n\n`;
|
|
112
|
+
});
|
|
113
|
+
md += `---\n`;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
fs.writeFileSync(OUT_FILE, md);
|
|
117
|
+
console.log(`Generated report for ${sortedSkills.length} skills.`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
analyzeEvolution();
|
|
121
|
+
|