@evomap/evolver 1.28.1

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 (52) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +290 -0
  3. package/README.zh-CN.md +236 -0
  4. package/SKILL.md +132 -0
  5. package/assets/gep/capsules.json +79 -0
  6. package/assets/gep/events.jsonl +7 -0
  7. package/assets/gep/genes.json +108 -0
  8. package/index.js +530 -0
  9. package/package.json +38 -0
  10. package/src/canary.js +13 -0
  11. package/src/evolve.js +1704 -0
  12. package/src/gep/a2a.js +173 -0
  13. package/src/gep/a2aProtocol.js +736 -0
  14. package/src/gep/analyzer.js +35 -0
  15. package/src/gep/assetCallLog.js +130 -0
  16. package/src/gep/assetStore.js +297 -0
  17. package/src/gep/assets.js +36 -0
  18. package/src/gep/bridge.js +71 -0
  19. package/src/gep/candidates.js +142 -0
  20. package/src/gep/contentHash.js +65 -0
  21. package/src/gep/deviceId.js +209 -0
  22. package/src/gep/envFingerprint.js +83 -0
  23. package/src/gep/hubReview.js +206 -0
  24. package/src/gep/hubSearch.js +237 -0
  25. package/src/gep/issueReporter.js +262 -0
  26. package/src/gep/llmReview.js +92 -0
  27. package/src/gep/memoryGraph.js +771 -0
  28. package/src/gep/memoryGraphAdapter.js +203 -0
  29. package/src/gep/mutation.js +186 -0
  30. package/src/gep/narrativeMemory.js +108 -0
  31. package/src/gep/paths.js +113 -0
  32. package/src/gep/personality.js +355 -0
  33. package/src/gep/prompt.js +566 -0
  34. package/src/gep/questionGenerator.js +212 -0
  35. package/src/gep/reflection.js +127 -0
  36. package/src/gep/sanitize.js +67 -0
  37. package/src/gep/selector.js +250 -0
  38. package/src/gep/signals.js +417 -0
  39. package/src/gep/skillDistiller.js +499 -0
  40. package/src/gep/solidify.js +1681 -0
  41. package/src/gep/strategy.js +126 -0
  42. package/src/gep/taskReceiver.js +528 -0
  43. package/src/gep/validationReport.js +55 -0
  44. package/src/ops/cleanup.js +80 -0
  45. package/src/ops/commentary.js +60 -0
  46. package/src/ops/health_check.js +106 -0
  47. package/src/ops/index.js +11 -0
  48. package/src/ops/innovation.js +67 -0
  49. package/src/ops/lifecycle.js +168 -0
  50. package/src/ops/self_repair.js +72 -0
  51. package/src/ops/skills_monitor.js +143 -0
  52. package/src/ops/trigger.js +33 -0
package/index.js ADDED
@@ -0,0 +1,530 @@
1
+ #!/usr/bin/env node
2
+ const evolve = require('./src/evolve');
3
+ const { solidify } = require('./src/gep/solidify');
4
+ const path = require('path');
5
+ // Hardened Env Loading: Ensure .env is loaded before anything else
6
+ try { require('dotenv').config({ path: path.resolve(__dirname, './.env') }); } catch (e) { console.warn('[Evolver] Warning: dotenv not found or failed to load .env'); }
7
+ const fs = require('fs');
8
+ const { spawn } = require('child_process');
9
+
10
+ function sleepMs(ms) {
11
+ const n = parseInt(String(ms), 10);
12
+ const t = Number.isFinite(n) ? Math.max(0, n) : 0;
13
+ return new Promise(resolve => setTimeout(resolve, t));
14
+ }
15
+
16
+ function readJsonSafe(p) {
17
+ try {
18
+ if (!fs.existsSync(p)) return null;
19
+ const raw = fs.readFileSync(p, 'utf8');
20
+ if (!raw.trim()) return null;
21
+ return JSON.parse(raw);
22
+ } catch (e) {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ function rejectPendingRun(statePath) {
28
+ try {
29
+ const { getRepoRoot } = require('./src/gep/paths');
30
+ const { execSync } = require('child_process');
31
+ const repoRoot = getRepoRoot();
32
+
33
+ execSync('git checkout -- .', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 });
34
+ execSync('git clean -fd', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 });
35
+ } catch (e) {
36
+ console.warn('[Loop] Pending run rollback failed: ' + (e.message || e));
37
+ }
38
+
39
+ try {
40
+ const state = readJsonSafe(statePath);
41
+ if (state && state.last_run && state.last_run.run_id) {
42
+ state.last_solidify = {
43
+ run_id: state.last_run.run_id,
44
+ rejected: true,
45
+ reason: 'loop_bridge_disabled_autoreject',
46
+ timestamp: new Date().toISOString(),
47
+ };
48
+ fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + '\n', 'utf8');
49
+ return true;
50
+ }
51
+ } catch (e) {
52
+ console.warn('[Loop] Failed to clear pending run state: ' + (e.message || e));
53
+ }
54
+
55
+ return false;
56
+ }
57
+
58
+ function isPendingSolidify(state) {
59
+ const lastRun = state && state.last_run ? state.last_run : null;
60
+ const lastSolid = state && state.last_solidify ? state.last_solidify : null;
61
+ if (!lastRun || !lastRun.run_id) return false;
62
+ if (!lastSolid || !lastSolid.run_id) return true;
63
+ return String(lastSolid.run_id) !== String(lastRun.run_id);
64
+ }
65
+
66
+ function parseMs(v, fallback) {
67
+ const n = parseInt(String(v == null ? '' : v), 10);
68
+ if (Number.isFinite(n)) return Math.max(0, n);
69
+ return fallback;
70
+ }
71
+
72
+ // Singleton Guard - prevent multiple evolver daemon instances
73
+ function acquireLock() {
74
+ const lockFile = path.join(__dirname, 'evolver.pid');
75
+ try {
76
+ if (fs.existsSync(lockFile)) {
77
+ const pid = parseInt(fs.readFileSync(lockFile, 'utf8').trim(), 10);
78
+ if (!Number.isFinite(pid) || pid <= 0) {
79
+ console.log('[Singleton] Corrupt lock file (invalid PID). Taking over.');
80
+ } else {
81
+ try {
82
+ process.kill(pid, 0);
83
+ console.log(`[Singleton] Evolver loop already running (PID ${pid}). Exiting.`);
84
+ return false;
85
+ } catch (e) {
86
+ console.log(`[Singleton] Stale lock found (PID ${pid}). Taking over.`);
87
+ }
88
+ }
89
+ }
90
+ fs.writeFileSync(lockFile, String(process.pid));
91
+ return true;
92
+ } catch (err) {
93
+ console.error('[Singleton] Lock acquisition failed:', err);
94
+ return false;
95
+ }
96
+ }
97
+
98
+ function releaseLock() {
99
+ const lockFile = path.join(__dirname, 'evolver.pid');
100
+ try {
101
+ if (fs.existsSync(lockFile)) {
102
+ const pid = parseInt(fs.readFileSync(lockFile, 'utf8').trim(), 10);
103
+ if (pid === process.pid) fs.unlinkSync(lockFile);
104
+ }
105
+ } catch (e) { /* ignore */ }
106
+ }
107
+
108
+ async function main() {
109
+ const args = process.argv.slice(2);
110
+ const command = args[0];
111
+ const isLoop = args.includes('--loop') || args.includes('--mad-dog');
112
+
113
+ if (command === 'run' || command === '/evolve' || isLoop) {
114
+ if (isLoop) {
115
+ const originalLog = console.log;
116
+ const originalWarn = console.warn;
117
+ const originalError = console.error;
118
+ function ts() { return '[' + new Date().toISOString() + ']'; }
119
+ console.log = (...args) => { originalLog.call(console, ts(), ...args); };
120
+ console.warn = (...args) => { originalWarn.call(console, ts(), ...args); };
121
+ console.error = (...args) => { originalError.call(console, ts(), ...args); };
122
+ }
123
+
124
+ console.log('Starting capability evolver...');
125
+
126
+ if (isLoop) {
127
+ // Internal daemon loop (no wrapper required).
128
+ if (!acquireLock()) process.exit(0);
129
+ process.on('exit', releaseLock);
130
+ process.on('SIGINT', () => { releaseLock(); process.exit(); });
131
+ process.on('SIGTERM', () => { releaseLock(); process.exit(); });
132
+
133
+ process.env.EVOLVE_LOOP = 'true';
134
+ process.env.EVOLVE_BRIDGE = 'false';
135
+ console.log('Loop mode enabled (internal daemon).');
136
+
137
+ const { getEvolutionDir } = require('./src/gep/paths');
138
+ const solidifyStatePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
139
+
140
+ const minSleepMs = parseMs(process.env.EVOLVER_MIN_SLEEP_MS, 2000);
141
+ const maxSleepMs = parseMs(process.env.EVOLVER_MAX_SLEEP_MS, 300000);
142
+ const idleThresholdMs = parseMs(process.env.EVOLVER_IDLE_THRESHOLD_MS, 500);
143
+ const pendingSleepMs = parseMs(
144
+ process.env.EVOLVE_PENDING_SLEEP_MS ||
145
+ process.env.EVOLVE_MIN_INTERVAL ||
146
+ process.env.FEISHU_EVOLVER_INTERVAL,
147
+ 120000
148
+ );
149
+
150
+ const maxCyclesPerProcess = parseMs(process.env.EVOLVER_MAX_CYCLES_PER_PROCESS, 100) || 100;
151
+ const maxRssMb = parseMs(process.env.EVOLVER_MAX_RSS_MB, 500) || 500;
152
+ const suicideEnabled = String(process.env.EVOLVER_SUICIDE || '').toLowerCase() !== 'false';
153
+
154
+ // Start hub heartbeat (keeps node alive independently of evolution cycles)
155
+ try {
156
+ const { startHeartbeat } = require('./src/gep/a2aProtocol');
157
+ startHeartbeat();
158
+ } catch (e) {
159
+ console.warn('[Heartbeat] Failed to start: ' + (e.message || e));
160
+ }
161
+
162
+ let currentSleepMs = minSleepMs;
163
+ let cycleCount = 0;
164
+
165
+ while (true) {
166
+ try {
167
+ cycleCount += 1;
168
+
169
+ // Ralph-loop gating: do not run a new cycle while previous run is pending solidify.
170
+ const st0 = readJsonSafe(solidifyStatePath);
171
+ if (isPendingSolidify(st0)) {
172
+ await sleepMs(Math.max(pendingSleepMs, minSleepMs));
173
+ continue;
174
+ }
175
+
176
+ const t0 = Date.now();
177
+ let ok = false;
178
+ try {
179
+ await evolve.run();
180
+ ok = true;
181
+
182
+ if (String(process.env.EVOLVE_BRIDGE || '').toLowerCase() === 'false') {
183
+ const stAfterRun = readJsonSafe(solidifyStatePath);
184
+ if (isPendingSolidify(stAfterRun)) {
185
+ const cleared = rejectPendingRun(solidifyStatePath);
186
+ if (cleared) {
187
+ console.warn('[Loop] Auto-rejected pending run because bridge is disabled in loop mode.');
188
+ }
189
+ }
190
+ }
191
+ } catch (error) {
192
+ const msg = error && error.message ? String(error.message) : String(error);
193
+ console.error(`Evolution cycle failed: ${msg}`);
194
+ }
195
+ const dt = Date.now() - t0;
196
+
197
+ // Adaptive sleep: treat very fast cycles as "idle", backoff; otherwise reset to min.
198
+ if (!ok || dt < idleThresholdMs) {
199
+ currentSleepMs = Math.min(maxSleepMs, Math.max(minSleepMs, currentSleepMs * 2));
200
+ } else {
201
+ currentSleepMs = minSleepMs;
202
+ }
203
+
204
+ // Suicide check (memory leak protection)
205
+ if (suicideEnabled) {
206
+ const memMb = process.memoryUsage().rss / 1024 / 1024;
207
+ if (cycleCount >= maxCyclesPerProcess || memMb > maxRssMb) {
208
+ console.log(`[Daemon] Restarting self (cycles=${cycleCount}, rssMb=${memMb.toFixed(0)})`);
209
+ try {
210
+ const spawnOpts = {
211
+ detached: true,
212
+ stdio: 'ignore',
213
+ env: process.env,
214
+ windowsHide: true,
215
+ };
216
+ const child = spawn(process.execPath, [__filename, ...args], spawnOpts);
217
+ child.unref();
218
+ releaseLock();
219
+ process.exit(0);
220
+ } catch (spawnErr) {
221
+ console.error('[Daemon] Spawn failed, continuing current process:', spawnErr.message);
222
+ }
223
+ }
224
+ }
225
+
226
+ let saturationMultiplier = 1;
227
+ try {
228
+ const st1 = readJsonSafe(solidifyStatePath);
229
+ const lastSignals = st1 && st1.last_run && Array.isArray(st1.last_run.signals) ? st1.last_run.signals : [];
230
+ if (lastSignals.includes('force_steady_state')) {
231
+ saturationMultiplier = 10;
232
+ console.log('[Daemon] Saturation detected. Entering steady-state mode (10x sleep).');
233
+ } else if (lastSignals.includes('evolution_saturation')) {
234
+ saturationMultiplier = 5;
235
+ console.log('[Daemon] Approaching saturation. Reducing evolution frequency (5x sleep).');
236
+ }
237
+ } catch (e) {}
238
+
239
+ // Jitter to avoid lockstep restarts.
240
+ const jitter = Math.floor(Math.random() * 250);
241
+ await sleepMs((currentSleepMs + jitter) * saturationMultiplier);
242
+
243
+ } catch (loopErr) {
244
+ console.error('[Daemon] Unexpected loop error (recovering): ' + (loopErr && loopErr.message ? loopErr.message : String(loopErr)));
245
+ await sleepMs(Math.max(minSleepMs, 10000));
246
+ }
247
+ }
248
+ } else {
249
+ // Normal Single Run
250
+ try {
251
+ await evolve.run();
252
+ } catch (error) {
253
+ console.error('Evolution failed:', error);
254
+ process.exit(1);
255
+ }
256
+ }
257
+
258
+ // Post-run hint
259
+ console.log('\n' + '=======================================================');
260
+ console.log('Capability evolver finished. If you use this project, consider starring the upstream repository.');
261
+ console.log('Upstream: https://github.com/autogame-17/capability-evolver');
262
+ console.log('=======================================================\n');
263
+
264
+ } else if (command === 'solidify') {
265
+ const dryRun = args.includes('--dry-run');
266
+ const noRollback = args.includes('--no-rollback');
267
+ const intentFlag = args.find(a => typeof a === 'string' && a.startsWith('--intent='));
268
+ const summaryFlag = args.find(a => typeof a === 'string' && a.startsWith('--summary='));
269
+ const intent = intentFlag ? intentFlag.slice('--intent='.length) : null;
270
+ const summary = summaryFlag ? summaryFlag.slice('--summary='.length) : null;
271
+
272
+ try {
273
+ const res = solidify({
274
+ intent: intent || undefined,
275
+ summary: summary || undefined,
276
+ dryRun,
277
+ rollbackOnFailure: !noRollback,
278
+ });
279
+ const st = res && res.ok ? 'SUCCESS' : 'FAILED';
280
+ console.log(`[SOLIDIFY] ${st}`);
281
+ if (res && res.gene) console.log(JSON.stringify(res.gene, null, 2));
282
+ if (res && res.event) console.log(JSON.stringify(res.event, null, 2));
283
+ if (res && res.capsule) console.log(JSON.stringify(res.capsule, null, 2));
284
+
285
+ if (res && res.ok && !dryRun) {
286
+ try {
287
+ const { shouldDistill, prepareDistillation } = require('./src/gep/skillDistiller');
288
+ if (shouldDistill()) {
289
+ const dr = prepareDistillation();
290
+ if (dr && dr.ok && dr.promptPath) {
291
+ console.log('\n[DISTILL_REQUEST]');
292
+ console.log('Distillation prompt ready. Read the prompt file, process it with your LLM,');
293
+ console.log('save the LLM response to a file, then run:');
294
+ console.log(' node index.js distill --response-file=<path_to_llm_response>');
295
+ console.log('Prompt file: ' + dr.promptPath);
296
+ console.log('[/DISTILL_REQUEST]');
297
+ }
298
+ }
299
+ } catch (e) {
300
+ console.warn('[Distiller] Init failed (non-fatal): ' + (e.message || e));
301
+ }
302
+ }
303
+
304
+ if (res && res.hubReviewPromise) {
305
+ await res.hubReviewPromise;
306
+ }
307
+ process.exit(res && res.ok ? 0 : 2);
308
+ } catch (error) {
309
+ console.error('[SOLIDIFY] Error:', error);
310
+ process.exit(2);
311
+ }
312
+ } else if (command === 'distill') {
313
+ const responseFileFlag = args.find(a => typeof a === 'string' && a.startsWith('--response-file='));
314
+ if (!responseFileFlag) {
315
+ console.error('Usage: node index.js distill --response-file=<path>');
316
+ process.exit(1);
317
+ }
318
+ const responseFilePath = responseFileFlag.slice('--response-file='.length);
319
+ try {
320
+ const responseText = fs.readFileSync(responseFilePath, 'utf8');
321
+ const { completeDistillation } = require('./src/gep/skillDistiller');
322
+ const result = completeDistillation(responseText);
323
+ if (result && result.ok) {
324
+ console.log('[Distiller] Gene produced: ' + result.gene.id);
325
+ console.log(JSON.stringify(result.gene, null, 2));
326
+ } else {
327
+ console.warn('[Distiller] Distillation did not produce a gene: ' + (result && result.reason || 'unknown'));
328
+ }
329
+ process.exit(result && result.ok ? 0 : 2);
330
+ } catch (error) {
331
+ console.error('[DISTILL] Error:', error);
332
+ process.exit(2);
333
+ }
334
+
335
+ } else if (command === 'review' || command === '--review') {
336
+ const { getEvolutionDir, getRepoRoot } = require('./src/gep/paths');
337
+ const { loadGenes } = require('./src/gep/assetStore');
338
+ const { execSync } = require('child_process');
339
+
340
+ const statePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
341
+ const state = readJsonSafe(statePath);
342
+ const lastRun = state && state.last_run ? state.last_run : null;
343
+
344
+ if (!lastRun || !lastRun.run_id) {
345
+ console.log('[Review] No pending evolution run to review.');
346
+ console.log('Run "node index.js run" first to produce changes, then review before solidifying.');
347
+ process.exit(0);
348
+ }
349
+
350
+ const lastSolid = state && state.last_solidify ? state.last_solidify : null;
351
+ if (lastSolid && String(lastSolid.run_id) === String(lastRun.run_id)) {
352
+ console.log('[Review] Last run has already been solidified. Nothing to review.');
353
+ process.exit(0);
354
+ }
355
+
356
+ const repoRoot = getRepoRoot();
357
+ let diff = '';
358
+ try {
359
+ const unstaged = execSync('git diff', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 }).trim();
360
+ const staged = execSync('git diff --cached', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 }).trim();
361
+ const untracked = execSync('git ls-files --others --exclude-standard', { cwd: repoRoot, encoding: 'utf8', timeout: 10000 }).trim();
362
+ if (staged) diff += '=== Staged Changes ===\n' + staged + '\n\n';
363
+ if (unstaged) diff += '=== Unstaged Changes ===\n' + unstaged + '\n\n';
364
+ if (untracked) diff += '=== Untracked Files ===\n' + untracked + '\n';
365
+ } catch (e) {
366
+ diff = '(failed to capture diff: ' + (e.message || e) + ')';
367
+ }
368
+
369
+ const genes = loadGenes();
370
+ const geneId = lastRun.selected_gene_id ? String(lastRun.selected_gene_id) : null;
371
+ const gene = geneId ? genes.find(g => g && g.type === 'Gene' && g.id === geneId) : null;
372
+ const signals = Array.isArray(lastRun.signals) ? lastRun.signals : [];
373
+ const mutation = lastRun.mutation || null;
374
+
375
+ console.log('\n' + '='.repeat(60));
376
+ console.log('[Review] Pending evolution run: ' + lastRun.run_id);
377
+ console.log('='.repeat(60));
378
+ console.log('\n--- Gene ---');
379
+ if (gene) {
380
+ console.log(' ID: ' + gene.id);
381
+ console.log(' Category: ' + (gene.category || '?'));
382
+ console.log(' Summary: ' + (gene.summary || '?'));
383
+ if (Array.isArray(gene.strategy) && gene.strategy.length > 0) {
384
+ console.log(' Strategy:');
385
+ gene.strategy.forEach((s, i) => console.log(' ' + (i + 1) + '. ' + s));
386
+ }
387
+ } else {
388
+ console.log(' (no gene selected or gene not found: ' + (geneId || 'none') + ')');
389
+ }
390
+
391
+ console.log('\n--- Signals ---');
392
+ if (signals.length > 0) {
393
+ signals.forEach(s => console.log(' - ' + s));
394
+ } else {
395
+ console.log(' (no signals)');
396
+ }
397
+
398
+ console.log('\n--- Mutation ---');
399
+ if (mutation) {
400
+ console.log(' Category: ' + (mutation.category || '?'));
401
+ console.log(' Risk Level: ' + (mutation.risk_level || '?'));
402
+ if (mutation.rationale) console.log(' Rationale: ' + mutation.rationale);
403
+ } else {
404
+ console.log(' (no mutation data)');
405
+ }
406
+
407
+ if (lastRun.blast_radius_estimate) {
408
+ console.log('\n--- Blast Radius Estimate ---');
409
+ const br = lastRun.blast_radius_estimate;
410
+ console.log(' Files changed: ' + (br.files_changed || '?'));
411
+ console.log(' Lines changed: ' + (br.lines_changed || '?'));
412
+ }
413
+
414
+ console.log('\n--- Diff ---');
415
+ if (diff.trim()) {
416
+ console.log(diff.length > 5000 ? diff.slice(0, 5000) + '\n... (truncated, ' + diff.length + ' chars total)' : diff);
417
+ } else {
418
+ console.log(' (no changes detected)');
419
+ }
420
+ console.log('='.repeat(60));
421
+
422
+ if (args.includes('--approve')) {
423
+ console.log('\n[Review] Approved. Running solidify...\n');
424
+ try {
425
+ const res = solidify({
426
+ intent: lastRun.intent || undefined,
427
+ rollbackOnFailure: true,
428
+ });
429
+ const st = res && res.ok ? 'SUCCESS' : 'FAILED';
430
+ console.log(`[SOLIDIFY] ${st}`);
431
+ if (res && res.gene) console.log(JSON.stringify(res.gene, null, 2));
432
+ if (res && res.hubReviewPromise) {
433
+ await res.hubReviewPromise;
434
+ }
435
+ process.exit(res && res.ok ? 0 : 2);
436
+ } catch (error) {
437
+ console.error('[SOLIDIFY] Error:', error);
438
+ process.exit(2);
439
+ }
440
+ } else if (args.includes('--reject')) {
441
+ console.log('\n[Review] Rejected. Rolling back changes...');
442
+ try {
443
+ execSync('git checkout -- .', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 });
444
+ execSync('git clean -fd', { cwd: repoRoot, encoding: 'utf8', timeout: 30000 });
445
+ const evolDir = getEvolutionDir();
446
+ const sp = path.join(evolDir, 'evolution_solidify_state.json');
447
+ if (fs.existsSync(sp)) {
448
+ const s = readJsonSafe(sp);
449
+ if (s && s.last_run) {
450
+ s.last_solidify = { run_id: s.last_run.run_id, rejected: true, timestamp: new Date().toISOString() };
451
+ fs.writeFileSync(sp, JSON.stringify(s, null, 2));
452
+ }
453
+ }
454
+ console.log('[Review] Changes rolled back.');
455
+ } catch (e) {
456
+ console.error('[Review] Rollback failed:', e.message || e);
457
+ process.exit(2);
458
+ }
459
+ } else {
460
+ console.log('\nTo approve and solidify: node index.js review --approve');
461
+ console.log('To reject and rollback: node index.js review --reject');
462
+ }
463
+
464
+ } else if (command === 'asset-log') {
465
+ const { summarizeCallLog, readCallLog, getLogPath } = require('./src/gep/assetCallLog');
466
+
467
+ const runIdFlag = args.find(a => typeof a === 'string' && a.startsWith('--run='));
468
+ const actionFlag = args.find(a => typeof a === 'string' && a.startsWith('--action='));
469
+ const lastFlag = args.find(a => typeof a === 'string' && a.startsWith('--last='));
470
+ const sinceFlag = args.find(a => typeof a === 'string' && a.startsWith('--since='));
471
+ const jsonMode = args.includes('--json');
472
+
473
+ const opts = {};
474
+ if (runIdFlag) opts.run_id = runIdFlag.slice('--run='.length);
475
+ if (actionFlag) opts.action = actionFlag.slice('--action='.length);
476
+ if (lastFlag) opts.last = parseInt(lastFlag.slice('--last='.length), 10);
477
+ if (sinceFlag) opts.since = sinceFlag.slice('--since='.length);
478
+
479
+ if (jsonMode) {
480
+ const entries = readCallLog(opts);
481
+ console.log(JSON.stringify(entries, null, 2));
482
+ } else {
483
+ const summary = summarizeCallLog(opts);
484
+ console.log(`\n[Asset Call Log] ${getLogPath()}`);
485
+ console.log(` Total entries: ${summary.total_entries}`);
486
+ console.log(` Unique assets: ${summary.unique_assets}`);
487
+ console.log(` Unique runs: ${summary.unique_runs}`);
488
+ console.log(` By action:`);
489
+ for (const [action, count] of Object.entries(summary.by_action)) {
490
+ console.log(` ${action}: ${count}`);
491
+ }
492
+ if (summary.entries.length > 0) {
493
+ console.log(`\n Recent entries:`);
494
+ const show = summary.entries.slice(-10);
495
+ for (const e of show) {
496
+ const ts = e.timestamp ? e.timestamp.slice(0, 19) : '?';
497
+ const assetShort = e.asset_id ? e.asset_id.slice(0, 20) + '...' : '(none)';
498
+ const sigPreview = Array.isArray(e.signals) ? e.signals.slice(0, 3).join(', ') : '';
499
+ console.log(` [${ts}] ${e.action || '?'} asset=${assetShort} score=${e.score || '-'} mode=${e.mode || '-'} signals=[${sigPreview}] run=${e.run_id || '-'}`);
500
+ }
501
+ } else {
502
+ console.log('\n No entries found.');
503
+ }
504
+ console.log('');
505
+ }
506
+
507
+ } else {
508
+ console.log(`Usage: node index.js [run|/evolve|solidify|review|distill|asset-log] [--loop]
509
+ - solidify flags:
510
+ - --dry-run
511
+ - --no-rollback
512
+ - --intent=repair|optimize|innovate
513
+ - --summary=...
514
+ - review flags:
515
+ - --approve (approve and solidify the pending changes)
516
+ - --reject (reject and rollback the pending changes)
517
+ - distill flags:
518
+ - --response-file=<path> (LLM response file for skill distillation)
519
+ - asset-log flags:
520
+ - --run=<run_id> (filter by run ID)
521
+ - --action=<action> (filter: hub_search_hit, hub_search_miss, asset_reuse, asset_reference, asset_publish, asset_publish_skip)
522
+ - --last=<N> (show last N entries)
523
+ - --since=<ISO_date> (entries after date)
524
+ - --json (raw JSON output)`);
525
+ }
526
+ }
527
+
528
+ if (require.main === module) {
529
+ main();
530
+ }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@evomap/evolver",
3
+ "version": "1.28.1",
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
+ "main": "index.js",
6
+ "bin": {
7
+ "evolver": "index.js"
8
+ },
9
+ "keywords": [
10
+ "evomap",
11
+ "ai",
12
+ "evolution",
13
+ "gep",
14
+ "meta-learning",
15
+ "self-repair",
16
+ "automation",
17
+ "agent"
18
+ ],
19
+ "author": "EvoMap <team@evomap.ai>",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/EvoMap/evolver.git"
24
+ },
25
+ "homepage": "https://evomap.ai",
26
+ "scripts": {
27
+ "start": "node index.js",
28
+ "run": "node index.js run",
29
+ "solidify": "node index.js solidify",
30
+ "review": "node index.js review",
31
+ "a2a:export": "node scripts/a2a_export.js",
32
+ "a2a:ingest": "node scripts/a2a_ingest.js",
33
+ "a2a:promote": "node scripts/a2a_promote.js"
34
+ },
35
+ "dependencies": {
36
+ "dotenv": "^16.4.7"
37
+ }
38
+ }
package/src/canary.js ADDED
@@ -0,0 +1,13 @@
1
+ // Canary script: run in a forked child process to verify index.js loads
2
+ // without crashing. Exit 0 = safe, non-zero = broken.
3
+ //
4
+ // This is the last safety net before solidify commits an evolution.
5
+ // If a patch broke index.js (syntax error, missing require, etc.),
6
+ // the canary catches it BEFORE the daemon restarts with broken code.
7
+ try {
8
+ require('../index.js');
9
+ process.exit(0);
10
+ } catch (e) {
11
+ process.stderr.write(String(e.message || e).slice(0, 500));
12
+ process.exit(1);
13
+ }