@evomap/evolver 1.70.0-beta.1 → 1.70.0-beta.3

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 (42) hide show
  1. package/README.ja-JP.md +13 -0
  2. package/README.ko-KR.md +13 -0
  3. package/README.md +13 -0
  4. package/README.zh-CN.md +13 -0
  5. package/assets/gep/candidates.jsonl +3 -3
  6. package/assets/gep/genes.json +39 -1
  7. package/index.js +53 -3
  8. package/package.json +1 -1
  9. package/src/adapters/hookAdapter.js +3 -1
  10. package/src/adapters/kiro.js +203 -0
  11. package/src/adapters/scripts/evolver-session-start.js +62 -0
  12. package/src/atp/cliAutobuyPrompt.js +160 -0
  13. package/src/evolve.js +1 -1
  14. package/src/gep/.integrity +0 -0
  15. package/src/gep/a2aProtocol.js +1 -1
  16. package/src/gep/candidateEval.js +1 -1
  17. package/src/gep/candidates.js +1 -1
  18. package/src/gep/contentHash.js +1 -1
  19. package/src/gep/crypto.js +1 -1
  20. package/src/gep/curriculum.js +1 -1
  21. package/src/gep/deviceId.js +1 -1
  22. package/src/gep/envFingerprint.js +1 -1
  23. package/src/gep/explore.js +1 -1
  24. package/src/gep/hubReview.js +1 -1
  25. package/src/gep/hubSearch.js +1 -1
  26. package/src/gep/hubVerify.js +1 -1
  27. package/src/gep/integrityCheck.js +1 -1
  28. package/src/gep/learningSignals.js +1 -1
  29. package/src/gep/memoryGraph.js +1 -1
  30. package/src/gep/memoryGraphAdapter.js +1 -1
  31. package/src/gep/mutation.js +1 -1
  32. package/src/gep/narrativeMemory.js +1 -1
  33. package/src/gep/personality.js +1 -1
  34. package/src/gep/policyCheck.js +1 -1
  35. package/src/gep/prompt.js +1 -1
  36. package/src/gep/reflection.js +1 -1
  37. package/src/gep/selector.js +1 -1
  38. package/src/gep/shield.js +1 -1
  39. package/src/gep/skillDistiller.js +1 -1
  40. package/src/gep/solidify.js +1 -1
  41. package/src/gep/strategy.js +1 -1
  42. package/src/gep/validator/sandboxExecutor.js +53 -8
package/README.ja-JP.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
6
6
  [![GitHub last commit](https://img.shields.io/github/last-commit/EvoMap/evolver)](https://github.com/EvoMap/evolver/commits/main)
7
7
  [![GitHub issues](https://img.shields.io/github/issues/EvoMap/evolver)](https://github.com/EvoMap/evolver/issues)
8
+ [![arXiv](https://img.shields.io/badge/arXiv-2604.15097-b31b1b.svg)](https://arxiv.org/abs/2604.15097)
8
9
 
9
10
  ![Evolver Cover](assets/cover.png)
10
11
 
@@ -22,6 +23,18 @@
22
23
 
23
24
  ---
24
25
 
26
+ > **研究論文 — Evolver の理論的基盤**
27
+ >
28
+ > **From Procedural Skills to Strategy Genes: Towards Experience-Driven Test-Time Evolution** · [arXiv:2604.15097](https://arxiv.org/abs/2604.15097) · [PDF](https://arxiv.org/pdf/2604.15097)
29
+ >
30
+ > 45 の科学コード求解シナリオにおける 4,590 回の対照試験を通じて、本論文はドキュメント指向の **Skill** パッケージが疎で不安定な制御信号しか提供しないのに対し、コンパクトな **Gene** 表現は最も強い総合性能を示し、大きな構造的摂動の下でも競争力を保ち、経験の反復的蓄積の担い手としても優れていることを示しました。CritPt では、gene-evolved システムは組み合わせたベースモデルを 9.1% から 18.57% へ、17.7% から 27.14% へと引き上げました。
31
+ >
32
+ > Evolver はこの結論を実装に落とし込んだオープンソースエンジンです。GEP プロトコルの下で、エージェントの経験を場当たり的なプロンプトやスキルドキュメントではなく、Gene と Capsule として符号化します。*なぜ* Evolver が長いスキルドキュメントではなく Gene にこだわるのか疑問に思ったことがあるなら、読むべきはこの論文です。
33
+ >
34
+ > 応用事例を見たい方へ:[OpenClaw x EvoMap:CritPt 評価レポート](https://evomap.ai/blog/openclaw-critpt-report) では、OpenClaw エージェントが CritPt Physics Solver 上の 5 バージョン(Beta → v2.2)にわたって、同じ Gene ベース進化ループによってスコアを 0.00% から 18.57% まで押し上げる全過程を、トークンコストの軌跡、遺伝子活性化マップ、そして推論が再利用可能な Gene に圧縮されるときに現れる「トークンが上昇してから下降する」シグネチャとともに詳述しています。
35
+
36
+ ---
37
+
25
38
  > **「進化は任意ではない。適応するか、滅びるか。」**
26
39
 
27
40
  **3行で説明**
package/README.ko-KR.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
6
6
  [![GitHub last commit](https://img.shields.io/github/last-commit/EvoMap/evolver)](https://github.com/EvoMap/evolver/commits/main)
7
7
  [![GitHub issues](https://img.shields.io/github/issues/EvoMap/evolver)](https://github.com/EvoMap/evolver/issues)
8
+ [![arXiv](https://img.shields.io/badge/arXiv-2604.15097-b31b1b.svg)](https://arxiv.org/abs/2604.15097)
8
9
 
9
10
  ![Evolver Cover](assets/cover.png)
10
11
 
@@ -22,6 +23,18 @@
22
23
 
23
24
  ---
24
25
 
26
+ > **연구 논문 — Evolver의 이론적 기반**
27
+ >
28
+ > **From Procedural Skills to Strategy Genes: Towards Experience-Driven Test-Time Evolution** · [arXiv:2604.15097](https://arxiv.org/abs/2604.15097) · [PDF](https://arxiv.org/pdf/2604.15097)
29
+ >
30
+ > 45개의 과학 코드 풀이 시나리오에서 진행된 4,590회의 통제 실험을 통해, 본 논문은 문서 중심의 **Skill** 패키지가 희소하고 불안정한 제어 신호만 제공하는 반면, 컴팩트한 **Gene** 표현은 가장 강력한 전체 성능을 보이고 상당한 구조적 섭동에서도 경쟁력을 유지하며 경험의 반복적 축적을 담는 더 나은 매개체라는 것을 보여줍니다. CritPt에서 gene-evolved 시스템은 짝을 이룬 기본 모델을 9.1%에서 18.57%로, 17.7%에서 27.14%로 끌어올렸습니다.
31
+ >
32
+ > Evolver는 이 결과를 실제로 구현하는 오픈소스 엔진입니다. GEP 프로토콜 아래 에이전트의 경험을 임시 프롬프트나 스킬 문서가 아니라 Gene과 Capsule로 인코딩합니다. *왜* Evolver가 더 긴 스킬 문서 대신 Gene을 고집하는지 궁금했다면, 바로 이 논문을 읽어야 합니다.
33
+ >
34
+ > 적용 사례가 궁금하신가요? [OpenClaw x EvoMap: CritPt 평가 보고서](https://evomap.ai/blog/openclaw-critpt-report)는 동일한 Gene 기반 진화 루프가 OpenClaw 에이전트를 CritPt Physics Solver의 5개 버전(Beta → v2.2)에 걸쳐 0.00%에서 18.57%까지 끌어올리는 과정을, 전체 토큰 비용 궤적, 유전자 활성화 매핑, 그리고 추론이 재사용 가능한 Gene으로 압축될 때 나타나는 "토큰이 먼저 상승한 뒤 하강하는" 시그니처와 함께 단계별로 보여줍니다.
35
+
36
+ ---
37
+
25
38
  > **"진화는 선택이 아니다. 적응하거나, 도태되거나."**
26
39
 
27
40
  **한 줄 요약**
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
6
6
  [![GitHub last commit](https://img.shields.io/github/last-commit/EvoMap/evolver)](https://github.com/EvoMap/evolver/commits/main)
7
7
  [![GitHub issues](https://img.shields.io/github/issues/EvoMap/evolver)](https://github.com/EvoMap/evolver/issues)
8
+ [![arXiv](https://img.shields.io/badge/arXiv-2604.15097-b31b1b.svg)](https://arxiv.org/abs/2604.15097)
8
9
 
9
10
  ![Evolver Cover](assets/cover.png)
10
11
 
@@ -22,6 +23,18 @@
22
23
 
23
24
  ---
24
25
 
26
+ > **Research — The theory behind Evolver**
27
+ >
28
+ > **From Procedural Skills to Strategy Genes: Towards Experience-Driven Test-Time Evolution** · [arXiv:2604.15097](https://arxiv.org/abs/2604.15097) · [PDF](https://arxiv.org/pdf/2604.15097)
29
+ >
30
+ > Across 4,590 controlled trials on 45 scientific code-solving scenarios, the paper shows that documentation-oriented **Skill** packages provide unstable, sparse control signal, while a compact **Gene** representation delivers the strongest overall performance, stays robust under structural perturbation, and is a far better carrier for iterative experience accumulation. On CritPt, gene-evolved systems lift their paired base models from 9.1% to 18.57% and from 17.7% to 27.14%.
31
+ >
32
+ > Evolver is the open-source engine that puts this result into practice: it encodes agent experience as Genes and Capsules under the GEP protocol, not as ad hoc prompts or skill docs. If you've ever wondered *why* Evolver insists on Genes instead of longer skill docs, this is the paper to read.
33
+ >
34
+ > Want the applied version? [OpenClaw x EvoMap: CritPt Evaluation Report](https://evomap.ai/blog/openclaw-critpt-report) walks through how the same Gene-based evolution loop drives an OpenClaw agent from 0.00% to 18.57% on CritPt Physics Solver across five versions (Beta -> v2.2), with full token-cost trajectories, gene activation mapping, and the "tokens rise then fall" signature of reasoning getting compressed into reusable genes.
35
+
36
+ ---
37
+
25
38
  > **"Evolution is not optional. Adapt or die."**
26
39
 
27
40
  **Three lines**
package/README.zh-CN.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg)](https://nodejs.org/)
6
6
  [![GitHub last commit](https://img.shields.io/github/last-commit/EvoMap/evolver)](https://github.com/EvoMap/evolver/commits/main)
7
7
  [![GitHub issues](https://img.shields.io/github/issues/EvoMap/evolver)](https://github.com/EvoMap/evolver/issues)
8
+ [![arXiv](https://img.shields.io/badge/arXiv-2604.15097-b31b1b.svg)](https://arxiv.org/abs/2604.15097)
8
9
 
9
10
  ![Evolver Cover](assets/cover.png)
10
11
 
@@ -22,6 +23,18 @@
22
23
 
23
24
  ---
24
25
 
26
+ > **研究论文 —— Evolver 背后的理论依据**
27
+ >
28
+ > **From Procedural Skills to Strategy Genes: Towards Experience-Driven Test-Time Evolution**(《从程序化技能到策略基因:面向经验驱动的测试时进化》)· [arXiv:2604.15097](https://arxiv.org/abs/2604.15097) · [PDF](https://arxiv.org/pdf/2604.15097)
29
+ >
30
+ > 论文在 45 个科学代码求解场景下完成 4,590 次对照实验,结论是:以文档为中心的 **Skill** 包控制信号稀疏且不稳定,而紧凑的 **Gene** 表示在整体表现上最强,在大幅结构扰动下仍有竞争力,并且是承载经验迭代积累的更好载体。在 CritPt 基准上,gene-evolved 系统将配对基座模型从 9.1% 提升到 18.57%,从 17.7% 提升到 27.14%。
31
+ >
32
+ > Evolver 正是把这一结论落地的开源引擎:它基于 GEP 协议,把 Agent 的经验沉淀为 Gene 与 Capsule,而不是散落的 prompt 或技能文档。如果你想知道 *为什么* Evolver 坚持使用 Gene 而不是更长的 skill 文档,这就是那篇该读的论文。
33
+ >
34
+ > 想看应用落地的样本?[OpenClaw x EvoMap:CritPt 评测报告](https://evomap.ai/blog/openclaw-critpt-report) 以 OpenClaw Agent 在 CritPt Physics Solver 上的五个版本演进(Beta → v2.2)为例,完整拆解了同一套 Gene 进化闭环如何把得分从 0.00% 推到 18.57%,并给出 token 成本轨迹、基因激活映射,以及推理被压缩成可复用基因后所呈现的「token 先升后降」特征。
35
+
36
+ ---
37
+
25
38
  > **"进化不是可选项,而是生存法则。"**
26
39
 
27
40
  **三句话概括**
@@ -1,3 +1,3 @@
1
- {"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-23T06:02:57.897Z","signals":["bounty_task","external_task","what","understand","really","dont","explanation.","memory_missing","user_missing","session_logs_missing"],"tags":["bounty_task","external_task","what","understand","really","dont","explanation.","memory_missing","user_missing","session_logs_missing","area:orchestration","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: bounty_task, external_task, what, understand, really, dont, explanation., 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-23T06:03:00.033Z","signals":["bounty_task","external_task","human","new","very","grow","how","memory_missing","user_missing","session_logs_missing"],"tags":["bounty_task","external_task","human","new","very","grow","how","memory_missing","user_missing","session_logs_missing","area:orchestration","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: bounty_task, external_task, human, new, very, grow, how, 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-23T06:03:01.960Z","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"}}
1
+ {"type":"CapabilityCandidate","id":"cand_b9a66a5c","title":"Harden session log detection and fallback behavior","source":"signals","created_at":"2026-04-25T03:26:52.453Z","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-25T03:26:54.382Z","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-25T03:26:56.266Z","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"}}
@@ -78,7 +78,8 @@
78
78
  "perf_bottleneck",
79
79
  "capability_gap",
80
80
  "stable_success_plateau",
81
- "external_opportunity"
81
+ "external_opportunity",
82
+ "bounty_task"
82
83
  ],
83
84
  "preconditions": [
84
85
  "at least one opportunity signal is present",
@@ -105,6 +106,43 @@
105
106
  "node scripts/validate-suite.js"
106
107
  ]
107
108
  },
109
+ {
110
+ "type": "Gene",
111
+ "id": "gene_gep_optimize_tool_usage",
112
+ "summary": "Optimize tool execution patterns by reducing redundant exec calls, improving tool selection strategy, and enforcing tool-use constraints to prevent bypass.",
113
+ "category": "optimize",
114
+ "signals_match": [
115
+ "high_tool_usage:exec",
116
+ "repeated_tool_usage:exec",
117
+ "tool_bypass",
118
+ "tool_loop",
119
+ "high_tool_usage"
120
+ ],
121
+ "preconditions": [
122
+ "agent repeatedly invokes the same tool (especially exec) without progress",
123
+ "tool execution bypass patterns detected",
124
+ "no active error signals (errors would take repair priority)"
125
+ ],
126
+ "strategy": [
127
+ "Analyze tool usage patterns to identify the root cause of repetition (wrong tool, missing context, or lack of guardrails)",
128
+ "Introduce strategy-level guardrails: prefer single-shot commands, batch related operations, add explicit retry limits",
129
+ "If tool_bypass detected, strengthen constraint enforcement in prompt assembly or tool routing",
130
+ "Estimate blast radius; changes should target tool routing, prompt constraints, or signal deduplication logic",
131
+ "Validate by confirming no regressions in existing tool tests and signal extraction accuracy",
132
+ "Solidify: record EvolutionEvent with intent=optimize, update Capsule on success"
133
+ ],
134
+ "constraints": {
135
+ "max_files": 15,
136
+ "forbidden_paths": [
137
+ ".git",
138
+ "node_modules"
139
+ ]
140
+ },
141
+ "validation": [
142
+ "node scripts/validate-modules.js ./src/gep/signals ./src/evolve",
143
+ "node scripts/validate-suite.js"
144
+ ]
145
+ },
108
146
  {
109
147
  "type": "Gene",
110
148
  "id": "gene_distilled_s2g-env-vars",
package/index.js CHANGED
@@ -143,6 +143,24 @@ async function main() {
143
143
  }
144
144
 
145
145
  console.log('Starting evolver...');
146
+
147
+ // Preflight: fail fast if git is not on PATH. On Windows in particular
148
+ // a missing git binary can cause evolver to hang silently (see #394),
149
+ // because several cycle-critical steps shell out to git early (repo
150
+ // resolution, diff, blast-radius). Catching this up front makes the
151
+ // failure mode obvious.
152
+ try {
153
+ const { execSync } = require('child_process');
154
+ execSync('git --version', { stdio: 'ignore', timeout: 5000 });
155
+ } catch (_gitErr) {
156
+ console.error('');
157
+ console.error('[Preflight] Could not run "git --version". Evolver requires git to be installed and available on PATH.');
158
+ console.error('[Preflight] On Windows: install Git from https://git-scm.com/download/win and make sure `git --version` works in a fresh terminal.');
159
+ console.error('[Preflight] On macOS: xcode-select --install (or `brew install git`)');
160
+ console.error('[Preflight] On Linux: sudo apt-get install -y git (or your distro equivalent)');
161
+ console.error('');
162
+ process.exit(1);
163
+ }
146
164
 
147
165
  if (isLoop) {
148
166
  // Internal daemon loop (no wrapper required).
@@ -250,6 +268,12 @@ async function main() {
250
268
 
251
269
  // ATP: opt-in capability-gap auto-buyer (default OFF, must be explicitly enabled).
252
270
  try {
271
+ try {
272
+ const { runPrompt } = require('./src/atp/cliAutobuyPrompt');
273
+ await runPrompt();
274
+ } catch (promptErr) {
275
+ console.warn('[ATP-AutoBuyer] first-run prompt failed: ' + (promptErr && promptErr.message || promptErr));
276
+ }
253
277
  const autoBuyRaw = (process.env.EVOLVER_ATP_AUTOBUY || 'off').toLowerCase().trim();
254
278
  const autoBuyOn = autoBuyRaw === 'on' || autoBuyRaw === '1' || autoBuyRaw === 'true';
255
279
  if (autoBuyOn) {
@@ -698,7 +722,13 @@ async function main() {
698
722
  console.log('\n[Review] Rejected. Rolling back changes...');
699
723
  try {
700
724
  execSync('git checkout -- .', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER });
701
- execSync('git clean -fd', { cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER });
725
+ // Preserve user state on reject: .env files, node_modules, runtime
726
+ // PID files, and a dedicated workspace/ dir (if one exists) MUST NOT
727
+ // be wiped by an automated rollback. Users have reported losing
728
+ // secrets and runtime caches to an aggressive git clean.
729
+ execSync('git clean -fd -e node_modules -e workspace -e .env -e ".env.*" -e "*.pid"', {
730
+ cwd: repoRoot, encoding: 'utf8', timeout: 30000, maxBuffer: MAX_EXEC_BUFFER,
731
+ });
702
732
  const evolDir = getEvolutionDir();
703
733
  const sp = path.join(evolDir, 'evolution_solidify_state.json');
704
734
  if (fs.existsSync(sp)) {
@@ -848,10 +878,30 @@ async function main() {
848
878
  fs.writeFileSync(path.join(outDir, 'SKILL.md'), data.content, 'utf8');
849
879
  }
850
880
 
881
+ const ALLOWED_SKILL_EXTENSIONS = new Set([
882
+ '.js', '.mjs', '.cjs', '.ts',
883
+ '.json', '.md', '.txt',
884
+ '.sh', '.py',
885
+ '.yml', '.yaml',
886
+ ]);
887
+ const MAX_SKILL_FILE_BYTES = 512 * 1024;
888
+
851
889
  const bundled = Array.isArray(data.bundled_files) ? data.bundled_files : [];
890
+ const skippedFiles = [];
852
891
  for (const file of bundled) {
853
892
  if (!file || !file.name || typeof file.content !== 'string') continue;
854
893
  const safeName = path.basename(file.name);
894
+ const ext = path.extname(safeName).toLowerCase();
895
+ if (!ALLOWED_SKILL_EXTENSIONS.has(ext)) {
896
+ console.warn('[fetch] Skipped skill file with disallowed extension: ' + safeName);
897
+ skippedFiles.push(safeName);
898
+ continue;
899
+ }
900
+ if (Buffer.byteLength(file.content, 'utf8') > MAX_SKILL_FILE_BYTES) {
901
+ console.warn('[fetch] Skipped skill file exceeding ' + MAX_SKILL_FILE_BYTES + ' bytes: ' + safeName);
902
+ skippedFiles.push(safeName);
903
+ continue;
904
+ }
855
905
  fs.writeFileSync(path.join(outDir, safeName), file.content, 'utf8');
856
906
  }
857
907
 
@@ -860,9 +910,9 @@ async function main() {
860
910
  console.log(' Version: ' + (data.version || '?'));
861
911
  console.log(' Files: SKILL.md' + (bundled.length > 0 ? ', ' + bundled.map(f => f.name).join(', ') : ''));
862
912
  if (data.already_purchased) {
863
- console.log(' Cost: free (already purchased)');
913
+ console.log(' Fetch cost: free (already purchased)');
864
914
  } else {
865
- console.log(' Cost: ' + (data.credit_cost || 0) + ' credits');
915
+ console.log(' Fetch cost: ' + (data.credit_cost || 0) + ' credits');
866
916
  }
867
917
  } catch (error) {
868
918
  if (error && error.name === 'TimeoutError') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evomap/evolver",
3
- "version": "1.70.0-beta.1",
3
+ "version": "1.70.0-beta.3",
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": {
@@ -6,6 +6,7 @@ const PLATFORMS = {
6
6
  cursor: { name: 'Cursor', configDir: '.cursor', detector: '.cursor' },
7
7
  'claude-code': { name: 'Claude Code', configDir: '.claude', detector: '.claude' },
8
8
  codex: { name: 'Codex', configDir: '.codex', detector: '.codex' },
9
+ kiro: { name: 'Kiro', configDir: '.kiro', detector: '.kiro' },
9
10
  };
10
11
 
11
12
  function detectPlatform(cwd) {
@@ -35,6 +36,7 @@ function loadAdapter(platformId) {
35
36
  case 'cursor': return require('./cursor');
36
37
  case 'claude-code': return require('./claudeCode');
37
38
  case 'codex': return require('./codex');
39
+ case 'kiro': return require('./kiro');
38
40
  default: return null;
39
41
  }
40
42
  }
@@ -163,7 +165,7 @@ async function setupHooks({ platform, cwd, force, uninstall, evolverRoot } = {})
163
165
  const platformId = platform || detectPlatform(effectiveCwd);
164
166
 
165
167
  if (!platformId) {
166
- console.error('[setup-hooks] Could not detect platform. Use --platform=cursor|claude-code|codex');
168
+ console.error('[setup-hooks] Could not detect platform. Use --platform=cursor|claude-code|codex|kiro');
167
169
  return { ok: false, error: 'platform_not_detected' };
168
170
  }
169
171
 
@@ -0,0 +1,203 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { copyHookScripts, removeHookScripts } = require('./hookAdapter');
4
+
5
+ const HOOK_SCRIPTS_DIR_NAME = 'hooks';
6
+ const EVOLVER_MARKER = '<!-- evolver-evolution-memory -->';
7
+ const HOOK_FILE_SUFFIX = '.kiro.hook';
8
+ const HOOK_FILES = {
9
+ sessionStart: 'evolver-session-start.kiro.hook',
10
+ signalDetect: 'evolver-signal-detect.kiro.hook',
11
+ sessionEnd: 'evolver-session-end.kiro.hook',
12
+ };
13
+
14
+ function buildHookConfig(kind, scriptsBase) {
15
+ // Kiro has no dedicated sessionStart event; `promptSubmit` is the closest
16
+ // analogue. The session-start JS script itself guards against per-prompt
17
+ // re-injection via a session-scoped state file when
18
+ // EVOLVER_SESSION_START_DEDUP=1 is set (injected inline into the command
19
+ // because Kiro runCommand has no env field).
20
+ const sessionStartCmd = `EVOLVER_SESSION_START_DEDUP=1 node ${scriptsBase}/evolver-session-start.js`;
21
+ const hookTemplates = {
22
+ sessionStart: {
23
+ name: 'Evolver Session Start',
24
+ version: '1',
25
+ description:
26
+ 'Reads recent evolution memory from the local memory graph and injects it as context when a prompt is submitted.',
27
+ when: { type: 'promptSubmit' },
28
+ then: {
29
+ type: 'runCommand',
30
+ command: sessionStartCmd,
31
+ timeout: 3,
32
+ },
33
+ _evolver_managed: true,
34
+ },
35
+ signalDetect: {
36
+ name: 'Evolver Signal Detect',
37
+ version: '1',
38
+ description:
39
+ 'Detects evolution signals (errors, perf bottlenecks, capability gaps, test failures) in file content after write operations.',
40
+ when: { type: 'postToolUse', toolTypes: ['write'] },
41
+ then: {
42
+ type: 'runCommand',
43
+ command: `node ${scriptsBase}/evolver-signal-detect.js`,
44
+ timeout: 2,
45
+ },
46
+ _evolver_managed: true,
47
+ },
48
+ sessionEnd: {
49
+ name: 'Evolver Session End',
50
+ version: '1',
51
+ description:
52
+ 'Records evolution outcome at session end by analyzing git diff stats and writing to the local memory graph.',
53
+ when: { type: 'agentStop' },
54
+ then: {
55
+ type: 'runCommand',
56
+ command: `node ${scriptsBase}/evolver-session-end.js`,
57
+ timeout: 8,
58
+ },
59
+ _evolver_managed: true,
60
+ },
61
+ };
62
+ return hookTemplates[kind];
63
+ }
64
+
65
+ function buildAgentsMdSection() {
66
+ return `${EVOLVER_MARKER}
67
+ ## Evolution Memory (Evolver)
68
+
69
+ This project uses evolver for self-evolution. Hooks automatically:
70
+ 1. Inject recent evolution memory on prompt submit
71
+ 2. Detect evolution signals during file edits
72
+ 3. Record outcomes at session end
73
+
74
+ For substantive tasks, call \`gep_recall\` before work and \`gep_record_outcome\` after.
75
+ Signals: log_error, perf_bottleneck, user_feature_request, capability_gap, deployment_issue, test_failure.`;
76
+ }
77
+
78
+ function appendSectionToFile(filePath, marker, content) {
79
+ let existing = '';
80
+ try { existing = fs.readFileSync(filePath, 'utf8'); } catch { /* new file */ }
81
+ if (existing.includes(marker)) return false;
82
+ const separator = existing.length > 0 && !existing.endsWith('\n') ? '\n\n' : '\n';
83
+ fs.writeFileSync(filePath, existing + separator + content + '\n', 'utf8');
84
+ return true;
85
+ }
86
+
87
+ function writeHookFile(hooksDir, fileName, config) {
88
+ const tmp = path.join(hooksDir, fileName + '.tmp');
89
+ const dest = path.join(hooksDir, fileName);
90
+ fs.writeFileSync(tmp, JSON.stringify(config, null, 2) + '\n', 'utf8');
91
+ fs.renameSync(tmp, dest);
92
+ return dest;
93
+ }
94
+
95
+ function isEvolverManagedHookFile(filePath) {
96
+ try {
97
+ const raw = fs.readFileSync(filePath, 'utf8').trim();
98
+ if (!raw) return false;
99
+ const data = JSON.parse(raw);
100
+ if (data && data._evolver_managed === true) return true;
101
+ if (typeof data.name === 'string' && /^evolver\b/i.test(data.name)) return true;
102
+ if (data.then && typeof data.then.command === 'string' &&
103
+ /evolver-(session|signal)/.test(data.then.command)) return true;
104
+ } catch { /* treat as non-evolver */ }
105
+ return false;
106
+ }
107
+
108
+ function install({ configRoot, evolverRoot, force }) {
109
+ const kiroDir = path.join(configRoot, '.kiro');
110
+ const hooksDir = path.join(kiroDir, HOOK_SCRIPTS_DIR_NAME);
111
+ const agentsMdPath = path.join(configRoot, 'AGENTS.md');
112
+ const scriptsBase = '.kiro/hooks';
113
+
114
+ const hookPaths = Object.values(HOOK_FILES).map(name => path.join(hooksDir, name));
115
+
116
+ if (!force) {
117
+ const existingEvolverHook = hookPaths.find(p => fs.existsSync(p) && isEvolverManagedHookFile(p));
118
+ if (existingEvolverHook) {
119
+ console.log('[kiro] Evolver hooks already installed. Use --force to overwrite.');
120
+ return { ok: true, skipped: true };
121
+ }
122
+ }
123
+
124
+ fs.mkdirSync(hooksDir, { recursive: true });
125
+
126
+ const written = [];
127
+ for (const [kind, fileName] of Object.entries(HOOK_FILES)) {
128
+ const cfg = buildHookConfig(kind, scriptsBase);
129
+ const dest = writeHookFile(hooksDir, fileName, cfg);
130
+ written.push(dest);
131
+ console.log('[kiro] Wrote ' + dest);
132
+ }
133
+
134
+ const copied = copyHookScripts(hooksDir, path.join(evolverRoot, 'src', 'adapters'));
135
+ console.log('[kiro] Copied ' + copied.length + ' hook scripts to ' + hooksDir);
136
+
137
+ const injected = appendSectionToFile(agentsMdPath, EVOLVER_MARKER, buildAgentsMdSection());
138
+ if (injected) {
139
+ console.log('[kiro] Injected evolution section into ' + agentsMdPath);
140
+ }
141
+
142
+ console.log('[kiro] Installation complete.');
143
+ console.log('[kiro] Kiro auto-discovers *.kiro.hook files in .kiro/hooks/ -- no restart needed.');
144
+
145
+ return {
146
+ ok: true,
147
+ platform: 'kiro',
148
+ files: [...written, agentsMdPath, ...copied],
149
+ };
150
+ }
151
+
152
+ function uninstall({ configRoot }) {
153
+ const kiroDir = path.join(configRoot, '.kiro');
154
+ const hooksDir = path.join(kiroDir, HOOK_SCRIPTS_DIR_NAME);
155
+ const agentsMdPath = path.join(configRoot, 'AGENTS.md');
156
+
157
+ let changed = false;
158
+ let removedCount = 0;
159
+
160
+ if (fs.existsSync(hooksDir)) {
161
+ try {
162
+ const entries = fs.readdirSync(hooksDir);
163
+ for (const entry of entries) {
164
+ if (!entry.endsWith(HOOK_FILE_SUFFIX)) continue;
165
+ const full = path.join(hooksDir, entry);
166
+ if (isEvolverManagedHookFile(full)) {
167
+ try { fs.unlinkSync(full); removedCount++; changed = true; } catch { /* ignore */ }
168
+ }
169
+ }
170
+ } catch { /* ignore */ }
171
+ }
172
+
173
+ const scripts = removeHookScripts(hooksDir);
174
+ if (scripts > 0) changed = true;
175
+
176
+ try {
177
+ if (fs.existsSync(agentsMdPath)) {
178
+ let content = fs.readFileSync(agentsMdPath, 'utf8');
179
+ if (content.includes(EVOLVER_MARKER)) {
180
+ const idx = content.indexOf(EVOLVER_MARKER);
181
+ const nextSection = content.indexOf('\n## ', idx + EVOLVER_MARKER.length);
182
+ const endIdx = nextSection !== -1 ? nextSection : content.length;
183
+ content = content.slice(0, idx).trimEnd() + (nextSection !== -1 ? content.slice(endIdx) : '');
184
+ fs.writeFileSync(agentsMdPath, content.trimEnd() + '\n', 'utf8');
185
+ changed = true;
186
+ }
187
+ }
188
+ } catch { /* ignore */ }
189
+
190
+ console.log(changed
191
+ ? `[kiro] Uninstalled evolver hooks (${removedCount} hook files + ${scripts} scripts removed).`
192
+ : '[kiro] No evolver hooks found to uninstall.');
193
+
194
+ return { ok: true, removed: changed };
195
+ }
196
+
197
+ module.exports = {
198
+ install,
199
+ uninstall,
200
+ buildHookConfig,
201
+ isEvolverManagedHookFile,
202
+ HOOK_FILES,
203
+ };
@@ -5,6 +5,7 @@
5
5
 
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
+ const os = require('os');
8
9
 
9
10
  function findEvolverRoot() {
10
11
  const candidates = [
@@ -58,7 +59,68 @@ function formatOutcome(entry) {
58
59
  return `[${icon}] ${ts} score=${score} signals=[${signals}] ${note}`.slice(0, 200);
59
60
  }
60
61
 
62
+ // Dedup guard: on platforms like Kiro, the sessionStart-equivalent event
63
+ // (`promptSubmit`) fires on every user message in a session. Without this
64
+ // guard, recent memory would be re-injected on every prompt. We key the
65
+ // dedup on (platform, cwd) with a short TTL so a fresh agent session within
66
+ // the same workspace still gets the injection, but mid-session prompts do
67
+ // not. Cursor/Claude Code/Codex have true sessionStart events and should
68
+ // bypass this check (controlled by EVOLVER_SESSION_START_DEDUP env var,
69
+ // which the Kiro adapter sets on the hook command line implicitly via the
70
+ // runtime environment, and other adapters leave unset).
71
+ function getDedupStatePath() {
72
+ const dir = process.env.EVOLVER_SESSION_STATE_DIR
73
+ || path.join(os.homedir(), '.evolver');
74
+ try { fs.mkdirSync(dir, { recursive: true }); } catch { /* ignore */ }
75
+ return path.join(dir, 'session-start-state.json');
76
+ }
77
+
78
+ function shouldSkipInjection() {
79
+ // Only apply dedup when explicitly enabled (set by Kiro adapter) OR when
80
+ // we detect a per-prompt-firing platform via PROMPT_SUBMIT heuristic in
81
+ // stdin. The stdin is drained in main(), so we rely on env flag here.
82
+ const dedupEnabled = String(process.env.EVOLVER_SESSION_START_DEDUP || '').toLowerCase() === '1'
83
+ || String(process.env.EVOLVER_SESSION_START_DEDUP || '').toLowerCase() === 'true';
84
+ if (!dedupEnabled) return false;
85
+
86
+ const ttlMs = Number(process.env.EVOLVER_SESSION_START_DEDUP_TTL_MS) || (30 * 60 * 1000);
87
+ const key = process.cwd();
88
+ const statePath = getDedupStatePath();
89
+
90
+ let state = {};
91
+ try {
92
+ if (fs.existsSync(statePath)) {
93
+ state = JSON.parse(fs.readFileSync(statePath, 'utf8')) || {};
94
+ }
95
+ } catch { state = {}; }
96
+
97
+ const now = Date.now();
98
+ const last = state[key];
99
+ if (typeof last === 'number' && now - last < ttlMs) {
100
+ return true;
101
+ }
102
+
103
+ state[key] = now;
104
+ try {
105
+ for (const k of Object.keys(state)) {
106
+ if (typeof state[k] !== 'number' || now - state[k] > 24 * 60 * 60 * 1000) {
107
+ delete state[k];
108
+ }
109
+ }
110
+ const tmp = statePath + '.tmp';
111
+ fs.writeFileSync(tmp, JSON.stringify(state), 'utf8');
112
+ fs.renameSync(tmp, statePath);
113
+ } catch { /* best-effort */ }
114
+
115
+ return false;
116
+ }
117
+
61
118
  function main() {
119
+ if (shouldSkipInjection()) {
120
+ process.stdout.write(JSON.stringify({}));
121
+ return;
122
+ }
123
+
62
124
  const evolverRoot = findEvolverRoot();
63
125
  const graphPath = findMemoryGraph(evolverRoot);
64
126