@evomap/evolver 1.69.7 → 1.69.10
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 +11 -0
- package/assets/cover.png +0 -0
- package/assets/gep/candidates.jsonl +3 -3
- package/assets/gep/capsules.json +1 -4
- package/index.js +6 -5
- package/package.json +14 -2
- 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/check_wrapper_compat.js +113 -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/recover_loop.js +61 -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 +63 -0
- package/src/adapters/scripts/evolver-session-end.js +22 -9
- package/src/evolve.js +1 -1
- package/src/gep/.integrity +0 -0
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/assetStore.js +100 -21
- package/src/gep/candidateEval.js +1 -1
- package/src/gep/candidates.js +1 -1
- package/src/gep/contentHash.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/envFingerprint.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/gitOps.js +7 -2
- package/src/gep/hubReview.js +1 -1
- package/src/gep/hubSearch.js +1 -1
- package/src/gep/hubVerify.js +1 -1
- package/src/gep/idleScheduler.js +7 -3
- package/src/gep/integrityCheck.js +1 -1
- package/src/gep/issueReporter.js +18 -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/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/prompt.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/sanitize.js +22 -0
- package/src/gep/selector.js +1 -1
- package/src/gep/selfPR.js +10 -6
- package/src/gep/shield.js +1 -1
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/validator/index.js +12 -0
- package/src/gep/validator/sandboxExecutor.js +85 -2
- package/src/ops/lifecycle.js +5 -1
- package/src/ops/self_repair.js +9 -5
- package/src/ops/skills_monitor.js +5 -1
- package/.github/ISSUE_TEMPLATE/good_first_issue.md +0 -23
- package/.github/pull_request_template.md +0 -20
- package/examples/hello-world.md +0 -38
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for contributing. Please follow these rules:
|
|
4
|
+
|
|
5
|
+
- Do not use emoji (except the DNA emoji in documentation if needed).
|
|
6
|
+
- Keep changes small and reviewable.
|
|
7
|
+
- Update related documentation when you change behavior.
|
|
8
|
+
- Run `node index.js` for a quick sanity check.
|
|
9
|
+
|
|
10
|
+
Submit PRs with clear intent and scope.
|
|
11
|
+
|
package/assets/cover.png
ADDED
|
Binary file
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-
|
|
2
|
-
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-
|
|
3
|
-
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-
|
|
1
|
+
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-21T12:13:16.977Z","signals":["memory_missing","user_missing","session_logs_missing"],"tags":["memory_missing","user_missing","session_logs_missing","area:memory"],"shape":{"title":"Harden session log detection and fallback behavior","input":"Recent session transcript + memory snippets + user instructions","output":"A safe, auditable evolution patch guided by GEP assets","invariants":"Protocol order, small reversible patches, validation, append-only events","params":"Signals: memory_missing, user_missing, session_logs_missing","failure_points":"Missing signals, over-broad changes, skipped validation, missing knowledge solidification","evidence":"Signal present: session_logs_missing"}}
|
|
2
|
+
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-21T12:13:18.789Z","signals":["memory_missing","user_missing","session_logs_missing"],"tags":["memory_missing","user_missing","session_logs_missing","area:memory"],"shape":{"title":"Harden session log detection and fallback behavior","input":"Recent session transcript + memory snippets + user instructions","output":"A safe, auditable evolution patch guided by GEP assets","invariants":"Protocol order, small reversible patches, validation, append-only events","params":"Signals: memory_missing, user_missing, session_logs_missing","failure_points":"Missing signals, over-broad changes, skipped validation, missing knowledge solidification","evidence":"Signal present: session_logs_missing"}}
|
|
3
|
+
{"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-21T12:13:20.587Z","signals":["memory_missing","user_missing","session_logs_missing"],"tags":["memory_missing","user_missing","session_logs_missing","area:memory"],"shape":{"title":"Harden session log detection and fallback behavior","input":"Recent session transcript + memory snippets + user instructions","output":"A safe, auditable evolution patch guided by GEP assets","invariants":"Protocol order, small reversible patches, validation, append-only events","params":"Signals: memory_missing, user_missing, session_logs_missing","failure_points":"Missing signals, over-broad changes, skipped validation, missing knowledge solidification","evidence":"Signal present: session_logs_missing"}}
|
package/assets/gep/capsules.json
CHANGED
package/index.js
CHANGED
|
@@ -563,6 +563,7 @@ async function main() {
|
|
|
563
563
|
const { getEvolutionDir, getRepoRoot } = require('./src/gep/paths');
|
|
564
564
|
const { loadGenes } = require('./src/gep/assetStore');
|
|
565
565
|
const { execSync } = require('child_process');
|
|
566
|
+
const MAX_EXEC_BUFFER = 10 * 1024 * 1024; // 10MB; see GHSA reports / #451
|
|
566
567
|
|
|
567
568
|
const statePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
|
|
568
569
|
const state = readJsonSafe(statePath);
|
|
@@ -583,9 +584,9 @@ async function main() {
|
|
|
583
584
|
const repoRoot = getRepoRoot();
|
|
584
585
|
let diff = '';
|
|
585
586
|
try {
|
|
586
|
-
const unstaged = execSync('git diff', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 }).trim();
|
|
587
|
-
const staged = execSync('git diff --cached', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 }).trim();
|
|
588
|
-
const untracked = execSync('git ls-files --others --exclude-standard', { cwd: repoRoot, encoding: 'utf8', timeout: 10000 }).trim();
|
|
587
|
+
const unstaged = execSync('git diff', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER }).trim();
|
|
588
|
+
const staged = execSync('git diff --cached', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER }).trim();
|
|
589
|
+
const untracked = execSync('git ls-files --others --exclude-standard', { cwd: repoRoot, encoding: 'utf8', timeout: 10000, maxBuffer: MAX_EXEC_BUFFER }).trim();
|
|
589
590
|
if (staged) diff += '=== Staged Changes ===\n' + staged + '\n\n';
|
|
590
591
|
if (unstaged) diff += '=== Unstaged Changes ===\n' + unstaged + '\n\n';
|
|
591
592
|
if (untracked) diff += '=== Untracked Files ===\n' + untracked + '\n';
|
|
@@ -667,8 +668,8 @@ async function main() {
|
|
|
667
668
|
} else if (args.includes('--reject')) {
|
|
668
669
|
console.log('\n[Review] Rejected. Rolling back changes...');
|
|
669
670
|
try {
|
|
670
|
-
execSync('git checkout -- .', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 });
|
|
671
|
-
execSync('git clean -fd', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 });
|
|
671
|
+
execSync('git checkout -- .', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER });
|
|
672
|
+
execSync('git clean -fd', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER });
|
|
672
673
|
const evolDir = getEvolutionDir();
|
|
673
674
|
const sp = path.join(evolDir, 'evolution_solidify_state.json');
|
|
674
675
|
if (fs.existsSync(sp)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.69.
|
|
3
|
+
"version": "1.69.10",
|
|
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": {
|
|
@@ -37,5 +37,17 @@
|
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"javascript-obfuscator": "^5.4.1"
|
|
40
|
-
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"assets/",
|
|
43
|
+
"index.js",
|
|
44
|
+
"src/",
|
|
45
|
+
"scripts/",
|
|
46
|
+
"README.md",
|
|
47
|
+
"README.zh-CN.md",
|
|
48
|
+
"README.ja-JP.md",
|
|
49
|
+
"SKILL.md",
|
|
50
|
+
"CONTRIBUTING.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
]
|
|
41
53
|
}
|
|
@@ -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
|
+
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* check_wrapper_compat.js
|
|
4
|
+
*
|
|
5
|
+
* Checks whether recent evolver changes affect interfaces used by feishu-evolver-wrapper.
|
|
6
|
+
* Run manually or via cursor rule to detect breaking changes early.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node scripts/check_wrapper_compat.js # check all interfaces
|
|
10
|
+
* node scripts/check_wrapper_compat.js --diff # check only files in git diff
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const { execSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
18
|
+
|
|
19
|
+
const INTERFACE_CONTRACT = [
|
|
20
|
+
{
|
|
21
|
+
file: 'src/ops/self_repair.js',
|
|
22
|
+
requiredExports: ['repair'],
|
|
23
|
+
description: 'wrapper calls selfRepair.repair()',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
file: 'src/ops/commentary.js',
|
|
27
|
+
requiredExports: ['getComment'],
|
|
28
|
+
description: 'wrapper calls getComment(type, dur, ok, persona)',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
file: 'src/ops/cleanup.js',
|
|
32
|
+
requiredExports: ['run'],
|
|
33
|
+
description: 'wrapper calls cleanup.run()',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
file: 'src/ops/skills_monitor.js',
|
|
37
|
+
requiredExports: ['run'],
|
|
38
|
+
description: 'wrapper calls skills_monitor.run()',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
file: 'src/ops/health_check.js',
|
|
42
|
+
requiredExports: ['runHealthCheck'],
|
|
43
|
+
description: 'wrapper calls runHealthCheck()',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
file: 'src/gep/bridge.js',
|
|
47
|
+
requiredExports: ['renderSessionsSpawnCall'],
|
|
48
|
+
description: 'wrapper parses sessions_spawn() output from bridge',
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
function getChangedFiles() {
|
|
53
|
+
try {
|
|
54
|
+
const out = execSync('git diff --name-only HEAD~1', { cwd: ROOT, encoding: 'utf8' }).trim();
|
|
55
|
+
return out ? out.split('\n') : [];
|
|
56
|
+
} catch (e) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function checkInterface(spec) {
|
|
62
|
+
const fullPath = path.join(ROOT, spec.file);
|
|
63
|
+
if (!fs.existsSync(fullPath)) {
|
|
64
|
+
return { file: spec.file, status: 'MISSING', detail: 'file does not exist' };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const mod = require(fullPath);
|
|
69
|
+
const missing = spec.requiredExports.filter(name => typeof mod[name] !== 'function');
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
return {
|
|
72
|
+
file: spec.file,
|
|
73
|
+
status: 'BROKEN',
|
|
74
|
+
detail: `missing exports: ${missing.join(', ')} -- ${spec.description}`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return { file: spec.file, status: 'OK' };
|
|
78
|
+
} catch (e) {
|
|
79
|
+
return { file: spec.file, status: 'ERROR', detail: `require failed: ${e.message}` };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function main() {
|
|
84
|
+
const diffMode = process.argv.includes('--diff');
|
|
85
|
+
let contracts = INTERFACE_CONTRACT;
|
|
86
|
+
|
|
87
|
+
if (diffMode) {
|
|
88
|
+
const changed = getChangedFiles();
|
|
89
|
+
contracts = contracts.filter(c => changed.includes(c.file));
|
|
90
|
+
if (contracts.length === 0) {
|
|
91
|
+
process.stdout.write('No wrapper-affecting files changed.\n');
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const results = contracts.map(checkInterface);
|
|
97
|
+
const broken = results.filter(r => r.status !== 'OK');
|
|
98
|
+
|
|
99
|
+
for (const r of results) {
|
|
100
|
+
const icon = r.status === 'OK' ? '[OK]' : '[!!]';
|
|
101
|
+
process.stdout.write(`${icon} ${r.file}${r.detail ? ' -- ' + r.detail : ''}\n`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (broken.length > 0) {
|
|
105
|
+
process.stdout.write(`\n${broken.length} interface(s) broken. feishu-evolver-wrapper needs update.\n`);
|
|
106
|
+
process.stdout.write('Check the feishu-evolver-wrapper repo for required updates.\n');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
} else {
|
|
109
|
+
process.stdout.write(`\nAll ${results.length} interface(s) compatible.\n`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
main();
|