@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
@@ -0,0 +1,566 @@
1
+ const fs = require('fs');
2
+ const { captureEnvFingerprint } = require('./envFingerprint');
3
+ const { formatAssetPreview } = require('./assets');
4
+ const { generateInnovationIdeas } = require('../ops/innovation');
5
+ const { analyzeRecentHistory, OPPORTUNITY_SIGNALS } = require('./signals');
6
+ const { loadNarrativeSummary } = require('./narrativeMemory');
7
+ const { getEvolutionPrinciplesPath } = require('./paths');
8
+
9
+ /**
10
+ * Build a minimal prompt for direct-reuse mode.
11
+ */
12
+ function buildReusePrompt({ capsule, signals, nowIso }) {
13
+ const payload = capsule.payload || capsule;
14
+ const summary = payload.summary || capsule.summary || '(no summary)';
15
+ const gene = payload.gene || capsule.gene || '(unknown)';
16
+ const confidence = payload.confidence || capsule.confidence || 0;
17
+ const assetId = capsule.asset_id || '(unknown)';
18
+ const sourceNode = capsule.source_node_id || '(unknown)';
19
+ const trigger = Array.isArray(payload.trigger || capsule.trigger_text)
20
+ ? (payload.trigger || String(capsule.trigger_text || '').split(',')).join(', ')
21
+ : '';
22
+
23
+ return `
24
+ GEP -- REUSE MODE (Search-First) [${nowIso || new Date().toISOString()}]
25
+
26
+ You are applying a VERIFIED solution from the EvoMap Hub.
27
+ Source asset: ${assetId} (Node: ${sourceNode})
28
+ Confidence: ${confidence} | Gene: ${gene}
29
+ Trigger signals: ${trigger}
30
+
31
+ Summary: ${summary}
32
+
33
+ Your signals: ${JSON.stringify(signals || [])}
34
+
35
+ Instructions:
36
+ 1. Read the capsule details below.
37
+ 2. Apply the fix to the local codebase, adapting paths/names.
38
+ 3. Run validation to confirm it works.
39
+ 4. If passed, run: node index.js solidify
40
+ 5. If failed, ROLLBACK and report.
41
+
42
+ Capsule payload:
43
+ \`\`\`json
44
+ ${JSON.stringify(payload, null, 2)}
45
+ \`\`\`
46
+
47
+ IMPORTANT: Do NOT reinvent. Apply faithfully.
48
+ `.trim();
49
+ }
50
+
51
+ /**
52
+ * Build a Hub Matched Solution block.
53
+ */
54
+ function buildHubMatchedBlock({ capsule }) {
55
+ if (!capsule) return '(no hub match)';
56
+ const payload = capsule.payload || capsule;
57
+ const summary = payload.summary || capsule.summary || '(no summary)';
58
+ const gene = payload.gene || capsule.gene || '(unknown)';
59
+ const confidence = payload.confidence || capsule.confidence || 0;
60
+ const assetId = capsule.asset_id || '(unknown)';
61
+
62
+ return `
63
+ Hub Matched Solution (STRONG REFERENCE):
64
+ - Asset: ${assetId} (${confidence})
65
+ - Gene: ${gene}
66
+ - Summary: ${summary}
67
+ - Payload:
68
+ \`\`\`json
69
+ ${JSON.stringify(payload, null, 2)}
70
+ \`\`\`
71
+ Use this as your primary approach if applicable. Adapt to local context.
72
+ `.trim();
73
+ }
74
+
75
+ /**
76
+ * Truncate context intelligently to preserve header/footer structure.
77
+ */
78
+ function truncateContext(text, maxLength = 20000) {
79
+ if (!text || text.length <= maxLength) return text || '';
80
+ return text.slice(0, maxLength) + '\n...[TRUNCATED_EXECUTION_CONTEXT]...';
81
+ }
82
+
83
+ /**
84
+ * Strict schema definitions for the prompt to reduce drift.
85
+ * UPDATED: 2026-02-14 (Protocol Drift Fix v3.2 - JSON-Only Enforcement)
86
+ */
87
+ const SCHEMA_DEFINITIONS = `
88
+ ━━━━━━━━━━━━━━━━━━━━━━
89
+ I. Mandatory Evolution Object Model (Output EXACTLY these 5 objects)
90
+ ━━━━━━━━━━━━━━━━━━━━━━
91
+
92
+ Output separate JSON objects. DO NOT wrap in a single array.
93
+ DO NOT use markdown code blocks (like \`\`\`json ... \`\`\`).
94
+ Output RAW JSON ONLY. No prelude, no postscript.
95
+ Missing any object = PROTOCOL FAILURE.
96
+ ENSURE VALID JSON SYNTAX (escape quotes in strings).
97
+
98
+ 0. Mutation (The Trigger) - MUST BE FIRST
99
+ {
100
+ "type": "Mutation",
101
+ "id": "mut_<timestamp>",
102
+ "category": "repair|optimize|innovate",
103
+ "trigger_signals": ["<signal_string>"],
104
+ "target": "<module_or_gene_id>",
105
+ "expected_effect": "<outcome_description>",
106
+ "risk_level": "low|medium|high",
107
+ "rationale": "<why_this_change_is_necessary>"
108
+ }
109
+
110
+ 1. PersonalityState (The Mood)
111
+ {
112
+ "type": "PersonalityState",
113
+ "rigor": 0.0-1.0,
114
+ "creativity": 0.0-1.0,
115
+ "verbosity": 0.0-1.0,
116
+ "risk_tolerance": 0.0-1.0,
117
+ "obedience": 0.0-1.0
118
+ }
119
+
120
+ 2. EvolutionEvent (The Record)
121
+ {
122
+ "type": "EvolutionEvent",
123
+ "schema_version": "1.5.0",
124
+ "id": "evt_<timestamp>",
125
+ "parent": <parent_evt_id|null>,
126
+ "intent": "repair|optimize|innovate",
127
+ "signals": ["<signal_string>"],
128
+ "genes_used": ["<gene_id>"],
129
+ "mutation_id": "<mut_id>",
130
+ "personality_state": { ... },
131
+ "blast_radius": { "files": N, "lines": N },
132
+ "outcome": { "status": "success|failed", "score": 0.0-1.0 }
133
+ }
134
+
135
+ 3. Gene (The Knowledge)
136
+ - Reuse/update existing ID if possible. Create new only if novel pattern.
137
+ {
138
+ "type": "Gene",
139
+ "schema_version": "1.5.0",
140
+ "id": "gene_<name>",
141
+ "category": "repair|optimize|innovate",
142
+ "signals_match": ["<pattern>"],
143
+ "preconditions": ["<condition>"],
144
+ "strategy": ["<step_1>", "<step_2>"],
145
+ "constraints": { "max_files": N, "forbidden_paths": [] },
146
+ "validation": ["<node_command>"]
147
+ }
148
+
149
+ 4. Capsule (The Result)
150
+ - Only on success. Reference Gene used.
151
+ {
152
+ "type": "Capsule",
153
+ "schema_version": "1.5.0",
154
+ "id": "capsule_<timestamp>",
155
+ "trigger": ["<signal_string>"],
156
+ "gene": "<gene_id>",
157
+ "summary": "<one sentence summary>",
158
+ "confidence": 0.0-1.0,
159
+ "blast_radius": { "files": N, "lines": N }
160
+ }
161
+ `.trim();
162
+
163
+ function buildAntiPatternZone(failedCapsules, signals) {
164
+ if (!Array.isArray(failedCapsules) || failedCapsules.length === 0) return '';
165
+ if (!Array.isArray(signals) || signals.length === 0) return '';
166
+ var sigSet = new Set(signals.map(function (s) { return String(s).toLowerCase(); }));
167
+ var matched = [];
168
+ for (var i = failedCapsules.length - 1; i >= 0 && matched.length < 3; i--) {
169
+ var fc = failedCapsules[i];
170
+ if (!fc) continue;
171
+ var triggers = Array.isArray(fc.trigger) ? fc.trigger : [];
172
+ var overlap = 0;
173
+ for (var j = 0; j < triggers.length; j++) {
174
+ if (sigSet.has(String(triggers[j]).toLowerCase())) overlap++;
175
+ }
176
+ if (triggers.length > 0 && overlap / triggers.length >= 0.4) {
177
+ matched.push(fc);
178
+ }
179
+ }
180
+ if (matched.length === 0) return '';
181
+ var lines = matched.map(function (fc, idx) {
182
+ var diffPreview = fc.diff_snapshot ? String(fc.diff_snapshot).slice(0, 500) : '(no diff)';
183
+ return [
184
+ ' ' + (idx + 1) + '. Gene: ' + (fc.gene || 'unknown') + ' | Signals: [' + (fc.trigger || []).slice(0, 4).join(', ') + ']',
185
+ ' Failure: ' + String(fc.failure_reason || 'unknown').slice(0, 300),
186
+ ' Diff (first 500 chars): ' + diffPreview.replace(/\n/g, ' '),
187
+ ].join('\n');
188
+ });
189
+ return '\nContext [Anti-Pattern Zone] (AVOID these failed approaches):\n' + lines.join('\n') + '\n';
190
+ }
191
+
192
+ function buildLessonsBlock(hubLessons, signals) {
193
+ if (!Array.isArray(hubLessons) || hubLessons.length === 0) return '';
194
+ var sigSet = new Set((Array.isArray(signals) ? signals : []).map(function (s) { return String(s).toLowerCase(); }));
195
+
196
+ var positive = [];
197
+ var negative = [];
198
+ for (var i = 0; i < hubLessons.length && (positive.length + negative.length) < 6; i++) {
199
+ var l = hubLessons[i];
200
+ if (!l || !l.content) continue;
201
+ var entry = ' - [' + (l.scenario || l.lesson_type || '?') + '] ' + String(l.content).slice(0, 300);
202
+ if (l.source_node_id) entry += ' (from: ' + String(l.source_node_id).slice(0, 20) + ')';
203
+ if (l.lesson_type === 'negative') {
204
+ negative.push(entry);
205
+ } else {
206
+ positive.push(entry);
207
+ }
208
+ }
209
+
210
+ if (positive.length === 0 && negative.length === 0) return '';
211
+
212
+ var parts = ['\nContext [Lessons from Ecosystem] (Cross-agent learned experience):'];
213
+ if (positive.length > 0) {
214
+ parts.push(' Strategies that WORKED:');
215
+ parts.push(positive.join('\n'));
216
+ }
217
+ if (negative.length > 0) {
218
+ parts.push(' Pitfalls to AVOID:');
219
+ parts.push(negative.join('\n'));
220
+ }
221
+ parts.push(' Apply relevant lessons. Ignore irrelevant ones.\n');
222
+ return parts.join('\n');
223
+ }
224
+
225
+ function buildNarrativeBlock() {
226
+ try {
227
+ const narrative = loadNarrativeSummary(3000);
228
+ if (!narrative) return '';
229
+ return `\nContext [Evolution Narrative] (Recent decisions and outcomes -- learn from this history):\n${narrative}\n`;
230
+ } catch (_) {
231
+ return '';
232
+ }
233
+ }
234
+
235
+ function buildPrinciplesBlock() {
236
+ try {
237
+ const principlesPath = getEvolutionPrinciplesPath();
238
+ if (!fs.existsSync(principlesPath)) return '';
239
+ const content = fs.readFileSync(principlesPath, 'utf8');
240
+ if (!content.trim()) return '';
241
+ const trimmed = content.length > 2000 ? content.slice(0, 2000) + '\n...[TRUNCATED]' : content;
242
+ return `\nContext [Evolution Principles] (Guiding directives -- align your actions):\n${trimmed}\n`;
243
+ } catch (_) {
244
+ return '';
245
+ }
246
+ }
247
+
248
+ function buildGepPrompt({
249
+ nowIso,
250
+ context,
251
+ signals,
252
+ selector,
253
+ parentEventId,
254
+ selectedGene,
255
+ capsuleCandidates,
256
+ genesPreview,
257
+ capsulesPreview,
258
+ capabilityCandidatesPreview,
259
+ externalCandidatesPreview,
260
+ hubMatchedBlock,
261
+ cycleId,
262
+ recentHistory,
263
+ failedCapsules,
264
+ hubLessons,
265
+ }) {
266
+ const parentValue = parentEventId ? `"${parentEventId}"` : 'null';
267
+ const selectedGeneId = selectedGene && selectedGene.id ? selectedGene.id : 'gene_<name>';
268
+ const envFingerprint = captureEnvFingerprint();
269
+ const cycleLabel = cycleId ? ` Cycle #${cycleId}` : '';
270
+
271
+ // Extract strategy from selected gene if available
272
+ let strategyBlock = "";
273
+ if (selectedGene && selectedGene.strategy && Array.isArray(selectedGene.strategy)) {
274
+ strategyBlock = `
275
+ ACTIVE STRATEGY (${selectedGeneId}):
276
+ ${selectedGene.strategy.map((s, i) => `${i + 1}. ${s}`).join('\n')}
277
+ ADHERE TO THIS STRATEGY STRICTLY.
278
+ `.trim();
279
+ } else {
280
+ // Fallback strategy if no gene is selected or strategy is missing
281
+ strategyBlock = `
282
+ ACTIVE STRATEGY (Generic):
283
+ 1. Analyze signals and context.
284
+ 2. Select or create a Gene that addresses the root cause.
285
+ 3. Apply minimal, safe changes.
286
+ 4. Validate changes strictly.
287
+ 5. Solidify knowledge.
288
+ `.trim();
289
+ }
290
+
291
+ // Use intelligent truncation
292
+ const executionContext = truncateContext(context, 20000);
293
+
294
+ // Strict Schema Injection
295
+ const schemaSection = SCHEMA_DEFINITIONS.replace('<parent_evt_id|null>', parentValue);
296
+
297
+ // Reduce noise by filtering capabilityCandidatesPreview if too large
298
+ // If a gene is selected, we need less noise from capabilities
299
+ let capsPreview = capabilityCandidatesPreview || '(none)';
300
+ const capsLimit = selectedGene ? 500 : 2000;
301
+ if (capsPreview.length > capsLimit) {
302
+ capsPreview = capsPreview.slice(0, capsLimit) + "\n...[TRUNCATED_CAPABILITIES]...";
303
+ }
304
+
305
+ // Optimize signals display: truncate long signals and limit count
306
+ const uniqueSignals = Array.from(new Set(signals || []));
307
+ const optimizedSignals = uniqueSignals.slice(0, 50).map(s => {
308
+ if (typeof s === 'string' && s.length > 200) {
309
+ return s.slice(0, 200) + '...[TRUNCATED_SIGNAL]';
310
+ }
311
+ return s;
312
+ });
313
+ if (uniqueSignals.length > 50) {
314
+ optimizedSignals.push(`...[TRUNCATED ${uniqueSignals.length - 50} SIGNALS]...`);
315
+ }
316
+
317
+ const formattedGenes = formatAssetPreview(genesPreview);
318
+ const formattedCapsules = formatAssetPreview(capsulesPreview);
319
+
320
+ // [2026-02-14] Innovation Catalyst Integration
321
+ // If stagnation is detected, inject concrete innovation ideas into the prompt.
322
+ let innovationBlock = '';
323
+ const stagnationSignals = [
324
+ 'evolution_stagnation_detected',
325
+ 'stable_success_plateau',
326
+ 'repair_loop_detected',
327
+ 'force_innovation_after_repair_loop',
328
+ 'empty_cycle_loop_detected',
329
+ 'evolution_saturation'
330
+ ];
331
+ if (uniqueSignals.some(s => stagnationSignals.includes(s))) {
332
+ const ideas = generateInnovationIdeas();
333
+ if (ideas && ideas.length > 0) {
334
+ innovationBlock = `
335
+ Context [Innovation Catalyst] (Stagnation Detected - Consider These Ideas):
336
+ ${ideas.join('\n')}
337
+ `;
338
+ }
339
+ }
340
+
341
+ // [2026-02-14] Strict Stagnation Directive
342
+ // If uniqueSignals contains 'evolution_stagnation_detected' or 'stable_success_plateau',
343
+ // inject a MANDATORY directive to force innovation and forbid repair/optimize if not strictly necessary.
344
+ if (uniqueSignals.includes('evolution_stagnation_detected') || uniqueSignals.includes('stable_success_plateau')) {
345
+ const stagnationDirective = `
346
+ *** CRITICAL STAGNATION DIRECTIVE ***
347
+ System has detected stagnation (repetitive cycles or lack of progress).
348
+ You MUST choose INTENT: INNOVATE.
349
+ You MUST NOT choose repair or optimize unless there is a critical blocking error (log_error).
350
+ Prefer implementing one of the Innovation Catalyst ideas above.
351
+ `;
352
+ innovationBlock += stagnationDirective;
353
+ }
354
+
355
+ // [2026-02-14] Recent History Integration
356
+ let historyBlock = '';
357
+ if (recentHistory && recentHistory.length > 0) {
358
+ historyBlock = `
359
+ Recent Evolution History (last 8 cycles -- DO NOT repeat the same intent+signal+gene):
360
+ ${recentHistory.map((h, i) => ` ${i + 1}. [${h.intent}] signals=[${h.signals.slice(0, 2).join(', ')}] gene=${h.gene_id} outcome=${h.outcome.status} @${h.timestamp}`).join('\n')}
361
+ IMPORTANT: If you see 3+ consecutive "repair" cycles with the same gene, you MUST switch to "innovate" intent.
362
+ `.trim();
363
+ }
364
+
365
+ // Refactor prompt assembly to minimize token usage and maximize clarity
366
+ // UPDATED: 2026-02-14 (Optimized Asset Embedding & Strict Schema v2.5 - JSON-Only Hardening)
367
+ const basePrompt = `
368
+ GEP — GENOME EVOLUTION PROTOCOL (v1.10.3 STRICT)${cycleLabel} [${nowIso}]
369
+
370
+ You are a protocol-bound evolution engine. Compliance overrides optimality.
371
+
372
+ ${schemaSection}
373
+
374
+ ━━━━━━━━━━━━━━━━━━━━━━
375
+ II. Directives & Logic
376
+ ━━━━━━━━━━━━━━━━━━━━━━
377
+
378
+ 1. Intent: ${selector && selector.intent ? selector.intent.toUpperCase() : 'UNKNOWN'}
379
+ Reason: ${(selector && selector.reason) ? (Array.isArray(selector.reason) ? selector.reason.join('; ') : selector.reason) : 'No reason provided.'}
380
+
381
+ 2. Selection: Selected Gene "${selectedGeneId}".
382
+ ${strategyBlock}
383
+
384
+ 3. Execution: Apply changes (tool calls). Repair/Optimize: small/reversible. Innovate: new skills in \`skills/<name>/\`.
385
+ 4. Validation: Run gene's validation steps. Fail = ROLLBACK.
386
+ 5. Solidify: Output 5 Mandatory Objects. Update Gene/Capsule files.
387
+ 6. Report: Use \`feishu-evolver-wrapper/report.js\`. Describe WHAT/WHY.
388
+
389
+ PHILOSOPHY:
390
+ - Automate Patterns: 3+ manual occurrences = tool.
391
+ - Innovate > Maintain: 60% innovation.
392
+ - Robustness: Fix recurring errors permanently.
393
+ - Blast Radius Control (CRITICAL):
394
+ * Check file count BEFORE editing. > 80% of max_files = STOP.
395
+ * System hard cap: 60 files / 20000 lines per cycle.
396
+ * Repair: fix ONLY broken files. Do NOT reinstall/bulk-copy.
397
+ * Prefer targeted edits.
398
+ - Strictness: NO CHITCHAT. NO MARKDOWN WRAPPERS around JSON. Output RAW JSON objects separated by newlines.
399
+ - NO "Here is the plan" or conversational filler. START IMMEDIATELY WITH JSON.
400
+
401
+ CONSTRAINTS:
402
+ - No \`exec\` for messaging (use feishu-post/card).
403
+ - \`exec\` usage: Only for background tasks. LOG IT. Optimize usage to avoid high token burn.
404
+ - New skills -> \`skills/<name>/\`.
405
+ - NEVER modify \`skills/evolver/\` or \`skills/feishu-evolver-wrapper/\`. These are managed through the human-reviewed release pipeline.
406
+ Self-modification causes instability and is blocked by solidify. To enable (NOT recommended): set EVOLVE_ALLOW_SELF_MODIFY=true.
407
+
408
+ CONSTITUTIONAL ETHICS (EvoMap Ethics Committee -- Mandatory):
409
+ These are non-negotiable rules derived from EvoMap's Constitution. Violation = FAILED + ROLLBACK.
410
+ 1. HUMAN WELFARE PRIORITY: Never create tools, scripts, or strategies that could harm humans,
411
+ enable surveillance, social engineering, phishing, or manipulation of human behavior.
412
+ 2. CARBON-SILICON SYMBIOSIS: Evolution must serve both human and agent interests.
413
+ Never attempt to replace, marginalize, or deceive human users.
414
+ 3. TRANSPARENCY: All actions must be auditable. Never hide, obfuscate, or conceal
415
+ the intent or effect of mutations. No steganography or covert channels.
416
+ 4. FAIRNESS: Never create monopolistic strategies that block other agents.
417
+ Fair competition through quality, not exclusion.
418
+ 5. SAFETY: Never bypass, disable, or weaken safety mechanisms, guardrails,
419
+ validation checks, or security controls. Never create tools to do so.
420
+ - If a task or signal CONFLICTS with these principles, REFUSE it and set outcome to FAILED
421
+ with reason "ethics_violation: <which principle>".
422
+
423
+ SKILL OVERLAP PREVENTION:
424
+ - Before creating a new skill, check the existing skills list in the execution context.
425
+ - If a skill with similar functionality already exists (e.g., "log-rotation" and "log-archivist",
426
+ "system-monitor" and "resource-profiler"), you MUST enhance the existing skill instead of creating a new one.
427
+ - Creating duplicate/overlapping skills wastes evolution cycles and increases maintenance burden.
428
+ - Violation = mark outcome as FAILED with reason "skill_overlap".
429
+
430
+ SKILL CREATION QUALITY GATES (MANDATORY for innovate intent):
431
+ When creating a new skill in skills/<name>/:
432
+ 1. STRUCTURE: Follow the standard skill layout:
433
+ skills/<name>/
434
+ |- index.js (required: main entry with working exports)
435
+ |- SKILL.md (required: YAML frontmatter with name + description, then usage docs)
436
+ |- package.json (required: name and version)
437
+ |- scripts/ (optional: reusable executable scripts)
438
+ |- references/ (optional: detailed docs loaded on demand)
439
+ |- assets/ (optional: templates, data files)
440
+ Creating an empty directory or a directory missing index.js = FAILED.
441
+ Do NOT create unnecessary files (README.md, CHANGELOG.md, INSTALLATION_GUIDE.md, etc.).
442
+ 2. SKILL.MD FRONTMATTER: Every SKILL.md MUST start with YAML frontmatter:
443
+ ---
444
+ name: <skill-name>
445
+ description: <what it does and when to use it>
446
+ ---
447
+ The description is the triggering mechanism -- include WHAT the skill does and WHEN to use it.
448
+ 3. CONCISENESS: SKILL.md body should be under 500 lines. Keep instructions lean.
449
+ Only include information the agent does not already know. Move detailed reference
450
+ material to references/ files, not into SKILL.md itself.
451
+ 4. EXPORT VERIFICATION: Every exported function must be importable.
452
+ Run: node -e "const s = require('./skills/<name>'); console.log(Object.keys(s))"
453
+ If this fails, the skill is broken. Fix before solidify.
454
+ 5. NO HARDCODED SECRETS: Never embed API keys, tokens, or secrets in code.
455
+ Use process.env or .env references. Hardcoded App ID, App Secret, Bearer tokens = FAILED.
456
+ 6. TEST BEFORE SOLIDIFY: Actually run the skill's core function to verify it works:
457
+ node -e "require('./skills/<name>').main ? require('./skills/<name>').main() : console.log('ok')"
458
+ Scripts in scripts/ must also be tested by executing them.
459
+ 7. ATOMIC CREATION: Create ALL files for a skill in a single cycle.
460
+ Do not create a directory in one cycle and fill it in the next.
461
+ Empty directories from failed cycles will be automatically cleaned up on rollback.
462
+
463
+ CRITICAL SAFETY (SYSTEM CRASH PREVENTION):
464
+ - NEVER delete/empty/overwrite: feishu-evolver-wrapper, feishu-common, feishu-post, feishu-card, feishu-doc, common, clawhub, git-sync, evolver.
465
+ - NEVER delete root files: MEMORY.md, SOUL.md, IDENTITY.md, AGENTS.md, USER.md, HEARTBEAT.md, RECENT_EVENTS.md, TOOLS.md, openclaw.json, .env, package.json.
466
+ - Fix broken skills; DO NOT delete and recreate.
467
+ - Violation = ROLLBACK + FAILED.
468
+
469
+ COMMON FAILURE PATTERNS:
470
+ - Blast radius exceeded.
471
+ - Omitted Mutation object.
472
+ - Merged objects into one JSON.
473
+ - Hallucinated "type": "Logic".
474
+ - "id": "mut_undefined".
475
+ - Missing "trigger_signals".
476
+ - Unrunnable validation steps.
477
+ - Markdown code blocks wrapping JSON (FORBIDDEN).
478
+
479
+ FAILURE STREAK AWARENESS:
480
+ - If "consecutive_failure_streak_N" or "failure_loop_detected":
481
+ 1. Change approach (do NOT repeat failed gene).
482
+ 2. Pick SIMPLER fix.
483
+ 3. Respect "ban_gene:<id>".
484
+
485
+ Final Directive: Every cycle must leave the system measurably better.
486
+ START IMMEDIATELY WITH RAW JSON (Mutation Object first).
487
+ DO NOT WRITE ANY INTRODUCTORY TEXT.
488
+
489
+ Context [Signals]:
490
+ ${JSON.stringify(optimizedSignals)}
491
+
492
+ Context [Env Fingerprint]:
493
+ ${JSON.stringify(envFingerprint, null, 2)}
494
+ ${innovationBlock}
495
+ Context [Injection Hint]:
496
+ ${process.env.EVOLVE_HINT ? process.env.EVOLVE_HINT : '(none)'}
497
+
498
+ Context [Gene Preview] (Reference for Strategy):
499
+ ${formattedGenes}
500
+
501
+ Context [Capsule Preview] (Reference for Past Success):
502
+ ${formattedCapsules}
503
+
504
+ Context [Capability Candidates]:
505
+ ${capsPreview}
506
+
507
+ Context [Hub Matched Solution]:
508
+ ${hubMatchedBlock || '(no hub match)'}
509
+
510
+ Context [External Candidates]:
511
+ ${externalCandidatesPreview || '(none)'}
512
+ ${buildAntiPatternZone(failedCapsules, signals)}${buildLessonsBlock(hubLessons, signals)}
513
+ ${historyBlock}
514
+ ${buildNarrativeBlock()}
515
+ ${buildPrinciplesBlock()}
516
+ Context [Execution]:
517
+ ${executionContext}
518
+
519
+ ━━━━━━━━━━━━━━━━━━━━━━
520
+ MANDATORY POST-SOLIDIFY STEP (Wrapper Authority -- Cannot Be Skipped)
521
+ ━━━━━━━━━━━━━━━━━━━━━━
522
+
523
+ After solidify, a status summary file MUST exist for this cycle.
524
+ Preferred path: evolver core auto-writes it during solidify.
525
+ The wrapper will handle reporting AFTER git push.
526
+ If core write is unavailable for any reason, create fallback status JSON manually.
527
+
528
+ Write a JSON file with your status:
529
+ \`\`\`bash
530
+ cat > ${process.env.WORKSPACE_DIR || '.'}/logs/status_${cycleId}.json << 'STATUSEOF'
531
+ {
532
+ "result": "success|failed",
533
+ "en": "Status: [INTENT] <describe what you did in 1-2 sentences, in English>",
534
+ "zh": "状态: [意图] <用中文描述你做了什么,1-2句>"
535
+ }
536
+ STATUSEOF
537
+ \`\`\`
538
+
539
+ Rules:
540
+ - "en" field: English status. "zh" field: Chinese status. Content must match (different language).
541
+ - Add "result" with value success or failed.
542
+ - INTENT must be one of: INNOVATION, REPAIR, OPTIMIZE (or Chinese: 创新, 修复, 优化)
543
+ - Do NOT use generic text like "Step Complete", "Cycle finished", "周期已完成". Describe the actual work.
544
+ - Example:
545
+ {"result":"success","en":"Status: [INNOVATION] Created auto-scheduler that syncs calendar to HEARTBEAT.md","zh":"状态: [创新] 创建了自动调度器,将日历同步到 HEARTBEAT.md"}
546
+ `.trim();
547
+
548
+ const maxChars = Number.isFinite(Number(process.env.GEP_PROMPT_MAX_CHARS)) ? Number(process.env.GEP_PROMPT_MAX_CHARS) : 50000;
549
+
550
+ if (basePrompt.length <= maxChars) return basePrompt;
551
+
552
+ const executionContextIndex = basePrompt.indexOf("Context [Execution]:");
553
+ if (executionContextIndex > -1) {
554
+ const prefix = basePrompt.slice(0, executionContextIndex + 20);
555
+ const currentExecution = basePrompt.slice(executionContextIndex + 20);
556
+ // Hard cap the execution context length to avoid token limit errors even if MAX_CHARS is high.
557
+ // 20000 chars is roughly 5k tokens, which is safe for most models alongside the rest of the prompt.
558
+ const EXEC_CONTEXT_CAP = 20000;
559
+ const allowedExecutionLength = Math.min(EXEC_CONTEXT_CAP, Math.max(0, maxChars - prefix.length - 100));
560
+ return prefix + "\n" + currentExecution.slice(0, allowedExecutionLength) + "\n...[TRUNCATED]...";
561
+ }
562
+
563
+ return basePrompt.slice(0, maxChars) + "\n...[TRUNCATED]...";
564
+ }
565
+
566
+ module.exports = { buildGepPrompt, buildReusePrompt, buildHubMatchedBlock, buildLessonsBlock, buildNarrativeBlock, buildPrinciplesBlock };