@evomap/evolver 1.89.0 → 1.89.2

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.
Files changed (98) hide show
  1. package/CONTRIBUTING.md +19 -0
  2. package/README.ja-JP.md +9 -32
  3. package/README.ko-KR.md +9 -32
  4. package/README.md +530 -86
  5. package/README.zh-CN.md +4 -31
  6. package/SKILL.md +1 -1
  7. package/assets/cover.png +0 -0
  8. package/index.js +14 -1
  9. package/package.json +17 -6
  10. package/scripts/a2a_export.js +63 -0
  11. package/scripts/a2a_ingest.js +79 -0
  12. package/scripts/a2a_promote.js +118 -0
  13. package/scripts/analyze_by_skill.js +121 -0
  14. package/scripts/build_binaries.js +479 -0
  15. package/scripts/check-changelog.js +166 -0
  16. package/scripts/extract_log.js +85 -0
  17. package/scripts/generate_history.js +75 -0
  18. package/scripts/gep_append_event.js +96 -0
  19. package/scripts/gep_personality_report.js +234 -0
  20. package/scripts/human_report.js +147 -0
  21. package/scripts/recall-verify-report.js +234 -0
  22. package/scripts/recover_loop.js +61 -0
  23. package/scripts/seed-merchants.js +91 -0
  24. package/scripts/suggest_version.js +89 -0
  25. package/scripts/validate-modules.js +38 -0
  26. package/scripts/validate-suite.js +78 -0
  27. package/skills/index.json +14 -0
  28. package/src/evolve/guards.js +1 -721
  29. package/src/evolve/pipeline/collect.js +1 -1283
  30. package/src/evolve/pipeline/dispatch.js +1 -421
  31. package/src/evolve/pipeline/enrich.js +1 -434
  32. package/src/evolve/pipeline/hub.js +1 -319
  33. package/src/evolve/pipeline/select.js +1 -274
  34. package/src/evolve/pipeline/signals.js +1 -206
  35. package/src/evolve/utils.js +1 -264
  36. package/src/evolve.js +1 -350
  37. package/src/forceUpdate.js +105 -20
  38. package/src/gep/a2aProtocol.js +1 -4395
  39. package/src/gep/autoDistillConv.js +1 -205
  40. package/src/gep/autoDistillLlm.js +1 -315
  41. package/src/gep/candidateEval.js +1 -92
  42. package/src/gep/candidates.js +1 -198
  43. package/src/gep/contentHash.js +1 -30
  44. package/src/gep/conversationSniffer.js +1 -266
  45. package/src/gep/crypto.js +1 -89
  46. package/src/gep/curriculum.js +1 -163
  47. package/src/gep/deviceId.js +1 -218
  48. package/src/gep/envFingerprint.js +1 -118
  49. package/src/gep/epigenetics.js +1 -31
  50. package/src/gep/execBridge.js +1 -711
  51. package/src/gep/explore.js +1 -289
  52. package/src/gep/hash.js +1 -15
  53. package/src/gep/hubFetch.js +1 -359
  54. package/src/gep/hubReview.js +1 -207
  55. package/src/gep/hubSearch.js +1 -526
  56. package/src/gep/hubVerify.js +1 -306
  57. package/src/gep/learningSignals.js +1 -89
  58. package/src/gep/memoryGraph.js +1 -1374
  59. package/src/gep/memoryGraphAdapter.js +1 -203
  60. package/src/gep/mutation.js +1 -203
  61. package/src/gep/narrativeMemory.js +1 -108
  62. package/src/gep/oauthLogin.js +34 -0
  63. package/src/gep/openPRRegistry.js +1 -205
  64. package/src/gep/personality.js +1 -423
  65. package/src/gep/policyCheck.js +1 -599
  66. package/src/gep/prompt.js +1 -836
  67. package/src/gep/recallInject.js +1 -409
  68. package/src/gep/recallVerifier.js +1 -318
  69. package/src/gep/reflection.js +1 -177
  70. package/src/gep/selector.js +1 -602
  71. package/src/gep/skillDistiller.js +1 -1294
  72. package/src/gep/skillPublisher.js +1 -1
  73. package/src/gep/solidify.js +1 -1699
  74. package/src/gep/strategy.js +1 -136
  75. package/src/gep/tokenSavings.js +1 -88
  76. package/src/gep/workspaceKeychain.js +1 -174
  77. package/src/proxy/extensions/traceControl.js +1 -99
  78. package/src/proxy/inject.js +1 -52
  79. package/src/proxy/lifecycle/manager.js +2 -0
  80. package/src/proxy/trace/extractor.js +1 -534
  81. package/src/proxy/trace/usage.js +1 -105
  82. package/.cursor/BUGBOT.md +0 -182
  83. package/.env.example +0 -68
  84. package/.git-commit-guard-token +0 -1
  85. package/.github/CODEOWNERS +0 -63
  86. package/.github/ISSUE_TEMPLATE/good_first_issue.md +0 -23
  87. package/.github/pull_request_template.md +0 -45
  88. package/.github/workflows/test.yml +0 -75
  89. package/CHANGELOG.md +0 -1123
  90. package/README.public.md +0 -594
  91. package/SECURITY.md +0 -108
  92. package/assets/gep/events.jsonl +0 -3
  93. package/examples/atp-consumer-quickstart.md +0 -100
  94. package/examples/hello-world.md +0 -38
  95. package/proxy-package.json +0 -39
  96. package/public.manifest.json +0 -141
  97. /package/assets/gep/{genes.json → genes.seed.json} +0 -0
  98. /package/{bundled-skills → skills}/_meta/SKILL.md +0 -0
package/README.zh-CN.md CHANGED
@@ -178,7 +178,7 @@ evolver --loop
178
178
  | 循环模式 (`evolver --loop`) | 在守护进程循环中重复上述流程,带自适应休眠 |
179
179
  | 在 OpenClaw 中 | 宿主运行时解释 stdout 中的指令(如 `sessions_spawn(...)`) |
180
180
 
181
- > **`--loop` 不是"实时辅助正在干活的 agent"的模式。** 循环模式用于后台自维护任务(validator 验证、worker 任务、ATP 商家自动交付、solidify),它的 stdout 是被 evolver 自己消费的,**不会**传给正在运行的 OpenClaw / Cursor / Claude Code agent——即使这些宿主已经安装,`sessions_spawn(...)` 指令在循环模式下也不会被它们接收。如果你想让 evolver 观察并辅助一次具体的 agent 会话,请在那个 agent 会话内部调用 `evolver run`(一次一轮),OpenClaw 会在这次运行中接管 stdout 指令。对 OpenClaw 用户还要特别注意:`AGENT_NAME`(或 `AGENT_SESSIONS_DIR`)必须指向真正在产生 session 的那个 agent 目录(`~/.openclaw/agents/<名字>/sessions/`),否则 evolver 会回退到读自己的日志,看上去就像在"空转"。
181
+ > **`--loop` 不是"实时辅助正在干活的 agent"的模式。** 循环模式用于后台自维护任务(validator 验证、worker 任务、ATP 商家自动交付、solidify),它的 stdout 是被 evolver 自己消费的,**不会**传给正在运行的 OpenClaw / Cursor / Claude Code agent——即使这些宿主已经安装,`sessions_spawn(...)` 指令在循环模式下也不会被它们接收。如果你想让 evolver 观察并辅助一次具体的 agent 会话,请在那个 agent 会话内部调用 `evolver`(一次一轮),OpenClaw 会在这次运行中接管 stdout 指令。对 OpenClaw 用户还要特别注意:`AGENT_NAME`(或 `AGENT_SESSIONS_DIR`)必须指向真正在产生 session 的那个 agent 目录(`~/.openclaw/agents/<名字>/sessions/`),否则 evolver 会回退到读自己的日志,看上去就像在"空转"。
182
182
 
183
183
  ## 适用 / 不适用场景
184
184
 
@@ -416,7 +416,7 @@ EVOLVE_REPORT_TOOL=feishu-card
416
416
  永久关闭:
417
417
 
418
418
  ```bash
419
- EVOLVER_VALIDATOR_ENABLED=0 evolver run --loop
419
+ EVOLVER_VALIDATOR_ENABLED=0 evolver --loop
420
420
  ```
421
421
 
422
422
  ### 自动 GitHub Issue 上报
@@ -426,7 +426,7 @@ EVOLVER_VALIDATOR_ENABLED=0 evolver run --loop
426
426
  | 变量 | 默认值 | 说明 |
427
427
  |------|--------|------|
428
428
  | `EVOLVER_AUTO_ISSUE` | `true` | 是否启用自动 issue 上报 |
429
- | `EVOLVER_ISSUE_REPO` | `autogame-17/capability-evolver` | 目标 GitHub 仓库(owner/repo) |
429
+ | `EVOLVER_ISSUE_REPO` | `EvoMap/evolver` | 目标 GitHub 仓库(owner/repo) |
430
430
  | `EVOLVER_ISSUE_COOLDOWN_MS` | `86400000`(24 小时) | 同类错误签名的冷却期 |
431
431
  | `EVOLVER_ISSUE_MIN_STREAK` | `5` | 触发上报所需的最低连续失败次数 |
432
432
 
@@ -474,33 +474,6 @@ EVOLVER_VALIDATOR_ENABLED=0 evolver run --loop
474
474
  2. **稳定性优先**:如果近期错误率较高,强制进入修复模式,暂停创新功能。
475
475
  3. **环境检测**:外部集成(如 Git 同步)仅在检测到相应插件存在时才会启用。
476
476
 
477
- ## Public 发布
478
-
479
- 本仓库为公开发行版本。
480
-
481
- - 构建公开产物:`npm run build`
482
- - 发布公开产物:`npm run publish:public`
483
- - 演练:`DRY_RUN=true npm run publish:public`
484
-
485
- 必填环境变量:
486
-
487
- - `PUBLIC_REMOTE`(默认:`public`)
488
- - `PUBLIC_REPO`(例如 `EvoMap/evolver`)
489
- - `PUBLIC_OUT_DIR`(默认:`dist-public`)
490
- - `PUBLIC_USE_BUILD_OUTPUT`(默认:`true`)
491
-
492
- 可选环境变量:
493
-
494
- - `SOURCE_BRANCH`(默认:`main`)
495
- - `PUBLIC_BRANCH`(默认:`main`)
496
- - `RELEASE_TAG`(例如 `v1.0.41`)
497
- - `RELEASE_TITLE`(例如 `v1.0.41 - GEP protocol`)
498
- - `RELEASE_NOTES` 或 `RELEASE_NOTES_FILE`
499
- - `GITHUB_TOKEN`(或 `GH_TOKEN` / `GITHUB_PAT`,用于创建 GitHub Release)
500
- - `RELEASE_SKIP`(`true` 则跳过创建 GitHub Release;默认会创建)
501
- - `RELEASE_USE_GH`(`true` 则使用 `gh` CLI,否则默认走 GitHub API)
502
- - `PUBLIC_RELEASE_ONLY`(`true` 则仅为已存在的 tag 创建 Release;不发布代码)
503
-
504
477
  ## 版本号规则(SemVer)
505
478
 
506
479
  MAJOR.MINOR.PATCH
@@ -557,4 +530,4 @@ MAJOR.MINOR.PATCH
557
530
 
558
531
  ## 许可证
559
532
 
560
- [MIT](https://opensource.org/licenses/MIT)
533
+ [GPL-3.0-or-later](https://opensource.org/licenses/GPL-3.0)
package/SKILL.md CHANGED
@@ -362,4 +362,4 @@ Local asset store:
362
362
 
363
363
  ## License
364
364
 
365
- MIT
365
+ GPL-3.0-or-later
Binary file
package/index.js CHANGED
@@ -1232,6 +1232,19 @@ async function main() {
1232
1232
  console.warn('[ValidatorDaemon] failed to start: ' + (vdErr && vdErr.message || vdErr));
1233
1233
  }
1234
1234
 
1235
+ // OAuth token auto-refresh: if a device-flow OAuth token is present,
1236
+ // keep it fresh in the background so long-running `evolver run` loops
1237
+ // never hit an expired a2a token mid-request. No-op for node_secret nodes.
1238
+ try {
1239
+ const { loadOAuthToken, startTokenAutoRefresh } = require('./src/gep/oauthLogin');
1240
+ if (loadOAuthToken()) {
1241
+ startTokenAutoRefresh();
1242
+ console.log('[OAuth] token auto-refresh scheduled.');
1243
+ }
1244
+ } catch (oauthRefreshErr) {
1245
+ console.warn('[OAuth] auto-refresh setup failed: ' + (oauthRefreshErr && oauthRefreshErr.message || oauthRefreshErr));
1246
+ }
1247
+
1235
1248
  // ATP: auto-start merchant agent if enabled
1236
1249
  try {
1237
1250
  const { defaultHandler, merchantAgent } = require('./src/atp');
@@ -2046,7 +2059,7 @@ async function main() {
2046
2059
  } else if (resp.status >= 500) {
2047
2060
  console.error(' Server error. The Hub may be temporarily unavailable.');
2048
2061
  console.error(' Try again in a few minutes. If the issue persists, report at:');
2049
- console.error(' https://github.com/autogame-17/evolver/issues');
2062
+ console.error(' https://github.com/EvoMap/evolver/issues');
2050
2063
  }
2051
2064
  if (isVerbose) {
2052
2065
  console.error('[Verbose] Endpoint: ' + endpoint);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evomap/evolver",
3
- "version": "1.89.0",
3
+ "version": "1.89.2",
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,18 @@
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
+ "README.md",
59
+ "README.zh-CN.md",
60
+ "README.ja-JP.md",
61
+ "SKILL.md",
62
+ "CONTRIBUTING.md",
63
+ "LICENSE"
64
+ ]
54
65
  }
@@ -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
+