@evomap/evolver 1.67.4 → 1.68.0-beta.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.
- package/README.ja-JP.md +55 -2
- package/README.md +55 -2
- package/README.zh-CN.md +55 -2
- package/SECURITY.md +66 -0
- package/index.js +41 -25
- package/package.json +1 -1
- package/src/adapters/scripts/evolver-session-end.js +194 -0
- package/src/adapters/scripts/evolver-session-start.js +93 -0
- package/src/adapters/scripts/evolver-signal-detect.js +69 -0
- package/src/config.js +26 -0
- package/src/evolve.js +1 -1
- package/src/gep/.integrity +0 -0
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/candidateEval.js +1 -1
- package/src/gep/candidates.js +1 -1
- package/src/gep/contentHash.js +1 -1
- package/src/gep/crypto.js +1 -1
- package/src/gep/curriculum.js +1 -1
- package/src/gep/deviceId.js +1 -1
- package/src/gep/envFingerprint.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/hubReview.js +1 -1
- package/src/gep/hubSearch.js +1 -1
- package/src/gep/hubVerify.js +1 -1
- package/src/gep/integrityCheck.js +1 -1
- package/src/gep/learningSignals.js +1 -1
- package/src/gep/memoryGraph.js +1 -1
- package/src/gep/memoryGraphAdapter.js +1 -1
- package/src/gep/mutation.js +1 -1
- package/src/gep/narrativeMemory.js +1 -1
- package/src/gep/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/prompt.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/selector.js +1 -1
- package/src/gep/shield.js +1 -1
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/validator/index.js +170 -0
- package/src/gep/validator/reporter.js +118 -0
- package/src/gep/validator/sandboxExecutor.js +262 -0
- package/src/gep/validator/stakeBootstrap.js +81 -0
- package/assets/gep/candidates.jsonl +0 -2
- package/assets/gep/failed_capsules.json +0 -4
- package/assets/gep/genes.jsonl +0 -0
package/README.ja-JP.md
CHANGED
|
@@ -42,7 +42,56 @@ Evolverは **[EvoMap](https://evomap.ai)** のコアエンジンです。EvoMap
|
|
|
42
42
|
- **[Node.js](https://nodejs.org/)** >= 18
|
|
43
43
|
- **[Git](https://git-scm.com/)** -- 必須。Evolverはロールバック、影響範囲の算出、solidifyにgitを使用します。git管理外のディレクトリで実行すると、明確なエラーメッセージが表示されます。
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### npm からインストール(推奨)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install -g @evomap/evolver
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`evolver` CLI がグローバルにインストールされます。`evolver --help` で確認してください。
|
|
52
|
+
|
|
53
|
+
Linux/macOS で `EACCES` エラーが出る場合は、`sudo` ではなくユーザーレベルの prefix を設定してください:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm config set prefix ~/.npm-global
|
|
57
|
+
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
|
|
58
|
+
source ~/.bashrc
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### プラットフォーム統合
|
|
62
|
+
|
|
63
|
+
Evolver は `setup-hooks` で主要な Agent ランタイムに統合できます。統合したいプラットフォームごとに 1 回実行してください。
|
|
64
|
+
|
|
65
|
+
#### Cursor
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
evolver setup-hooks --platform=cursor
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`~/.cursor/hooks.json` を書き込み、`~/.cursor/hooks/` に hook スクリプトを配置します。Cursor を再起動(または新しいセッションを開始)すると有効化されます。Hook は `sessionStart`、`afterFileEdit`、`stop` で発火します。
|
|
72
|
+
|
|
73
|
+
#### Claude Code
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
evolver setup-hooks --platform=claude-code
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`~/.claude/` を通して Claude Code の hook システムに Evolver を登録します。インストール後、Claude Code CLI を再起動してください。
|
|
80
|
+
|
|
81
|
+
#### OpenClaw
|
|
82
|
+
|
|
83
|
+
OpenClaw は Evolver が stdout に出力する `sessions_spawn(...)` プロトコルを解釈するため、**hook のインストールは不要**です。OpenClaw workspace に Evolver をクローンし、セッション内で実行してください:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cd <your-openclaw-workspace>
|
|
87
|
+
git clone https://github.com/EvoMap/evolver.git
|
|
88
|
+
cd evolver
|
|
89
|
+
npm install
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Evolver が OpenClaw セッション内で実行されると、ホストが stdout のディレクティブ(`sessions_spawn(...)` など)を拾い、後続のアクションを自動で連鎖させます。
|
|
93
|
+
|
|
94
|
+
### ソースからインストール(上級者向け)
|
|
46
95
|
|
|
47
96
|
```bash
|
|
48
97
|
git clone https://github.com/EvoMap/evolver.git
|
|
@@ -50,7 +99,11 @@ cd evolver
|
|
|
50
99
|
npm install
|
|
51
100
|
```
|
|
52
101
|
|
|
53
|
-
|
|
102
|
+
エンジン自体を改造したい、未リリースビルドを試したい、ソースツリーを調査したい場合に使用します。
|
|
103
|
+
|
|
104
|
+
### EvoMap ネットワークへの接続(任意)
|
|
105
|
+
|
|
106
|
+
[EvoMap ネットワーク](https://evomap.ai)に接続するには、プロジェクトルートに `.env` ファイルを作成します:
|
|
54
107
|
|
|
55
108
|
```bash
|
|
56
109
|
# Node ID を取得するには https://evomap.ai で登録してください
|
package/README.md
CHANGED
|
@@ -42,7 +42,56 @@ Keywords: protocol-constrained evolution, audit trail, genes and capsules, promp
|
|
|
42
42
|
- **[Node.js](https://nodejs.org/)** >= 18
|
|
43
43
|
- **[Git](https://git-scm.com/)** -- Required. Evolver uses git for rollback, blast radius calculation, and solidify. Running in a non-git directory will fail with a clear error message.
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### Install from npm (recommended)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install -g @evomap/evolver
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This installs the `evolver` CLI globally. Verify with `evolver --help`.
|
|
52
|
+
|
|
53
|
+
If you hit `EACCES` on Linux/macOS, configure a user-level prefix instead of using `sudo`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm config set prefix ~/.npm-global
|
|
57
|
+
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
|
|
58
|
+
source ~/.bashrc
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Platform integration
|
|
62
|
+
|
|
63
|
+
Evolver integrates with major agent runtimes through `setup-hooks`. Run the command once per platform you want to wire up.
|
|
64
|
+
|
|
65
|
+
#### Cursor
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
evolver setup-hooks --platform=cursor
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Writes `~/.cursor/hooks.json` and installs hook scripts under `~/.cursor/hooks/`. Restart Cursor (or open a new session) to activate. Hooks fire on `sessionStart`, `afterFileEdit`, and `stop`.
|
|
72
|
+
|
|
73
|
+
#### Claude Code
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
evolver setup-hooks --platform=claude-code
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Registers Evolver with Claude Code's hook system via `~/.claude/`. Restart the Claude Code CLI after installation.
|
|
80
|
+
|
|
81
|
+
#### OpenClaw
|
|
82
|
+
|
|
83
|
+
OpenClaw interprets the `sessions_spawn(...)` protocol that Evolver emits on stdout, so no hooks are required. Clone Evolver into your OpenClaw workspace and invoke it from within a session:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cd <your-openclaw-workspace>
|
|
87
|
+
git clone https://github.com/EvoMap/evolver.git
|
|
88
|
+
cd evolver
|
|
89
|
+
npm install
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
When Evolver runs inside an OpenClaw session, the host picks up stdout directives (`sessions_spawn(...)`, etc.) and chains follow-up actions automatically.
|
|
93
|
+
|
|
94
|
+
### Install from source (advanced)
|
|
46
95
|
|
|
47
96
|
```bash
|
|
48
97
|
git clone https://github.com/EvoMap/evolver.git
|
|
@@ -50,7 +99,11 @@ cd evolver
|
|
|
50
99
|
npm install
|
|
51
100
|
```
|
|
52
101
|
|
|
53
|
-
|
|
102
|
+
Use this mode if you want to hack on the engine itself, run unreleased builds, or inspect the source tree.
|
|
103
|
+
|
|
104
|
+
### Connect to the EvoMap network (optional)
|
|
105
|
+
|
|
106
|
+
To connect to the [EvoMap network](https://evomap.ai), create a `.env` file in your project root:
|
|
54
107
|
|
|
55
108
|
```bash
|
|
56
109
|
# Register at https://evomap.ai to get your Node ID
|
package/README.zh-CN.md
CHANGED
|
@@ -40,7 +40,56 @@ Evolver 是 **[EvoMap](https://evomap.ai)** 的核心引擎。EvoMap 是一个 A
|
|
|
40
40
|
- **[Node.js](https://nodejs.org/)** >= 18
|
|
41
41
|
- **[Git](https://git-scm.com/)** -- 必需。Evolver 依赖 git 进行回滚、变更范围计算和固化(solidify)。在非 git 目录中运行会直接报错并退出。
|
|
42
42
|
|
|
43
|
-
###
|
|
43
|
+
### 从 npm 安装(推荐)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install -g @evomap/evolver
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
此命令将全局安装 `evolver` CLI。通过 `evolver --help` 验证。
|
|
50
|
+
|
|
51
|
+
如在 Linux/macOS 上遇到 `EACCES` 错误,建议配置用户级 prefix,而不是使用 `sudo`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm config set prefix ~/.npm-global
|
|
55
|
+
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
|
|
56
|
+
source ~/.bashrc
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 平台集成
|
|
60
|
+
|
|
61
|
+
Evolver 通过 `setup-hooks` 命令与主流 Agent 运行时集成。每个需要接入的平台执行一次即可。
|
|
62
|
+
|
|
63
|
+
#### Cursor
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
evolver setup-hooks --platform=cursor
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
会写入 `~/.cursor/hooks.json`,并将 hook 脚本安装到 `~/.cursor/hooks/`。重启 Cursor(或开新会话)后生效。钩子在 `sessionStart`、`afterFileEdit`、`stop` 时触发。
|
|
70
|
+
|
|
71
|
+
#### Claude Code
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
evolver setup-hooks --platform=claude-code
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
通过 `~/.claude/` 向 Claude Code 的 hook 系统注册 Evolver。安装完成后重启 Claude Code CLI。
|
|
78
|
+
|
|
79
|
+
#### OpenClaw
|
|
80
|
+
|
|
81
|
+
OpenClaw 会识别 Evolver 向 stdout 输出的 `sessions_spawn(...)` 协议,**无需安装 hooks**。将 Evolver 克隆到 OpenClaw workspace 中,在会话内运行即可:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
cd <your-openclaw-workspace>
|
|
85
|
+
git clone https://github.com/EvoMap/evolver.git
|
|
86
|
+
cd evolver
|
|
87
|
+
npm install
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
在 OpenClaw 会话中运行 Evolver 时,宿主会自动识别 stdout 指令(如 `sessions_spawn(...)`)并串联后续动作。
|
|
91
|
+
|
|
92
|
+
### 从源码安装(进阶)
|
|
44
93
|
|
|
45
94
|
```bash
|
|
46
95
|
git clone https://github.com/EvoMap/evolver.git
|
|
@@ -48,7 +97,11 @@ cd evolver
|
|
|
48
97
|
npm install
|
|
49
98
|
```
|
|
50
99
|
|
|
51
|
-
|
|
100
|
+
适用于需要修改引擎本身、运行未发布构建、或审查源码的场景。
|
|
101
|
+
|
|
102
|
+
### 连接 EvoMap 网络(可选)
|
|
103
|
+
|
|
104
|
+
如需连接 [EvoMap 网络](https://evomap.ai),在项目根目录创建 `.env` 文件:
|
|
52
105
|
|
|
53
106
|
```bash
|
|
54
107
|
# 在 https://evomap.ai 注册后获取 Node ID
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
We support the latest minor version of `@evomap/evolver` on npm. Only the current release line receives security updates; older minor versions are not backported.
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
| --------- | ------------------- |
|
|
9
|
+
| 1.67.x | Yes (current) |
|
|
10
|
+
| < 1.67 | No |
|
|
11
|
+
|
|
12
|
+
Run `npm view @evomap/evolver version` to check the latest published version.
|
|
13
|
+
|
|
14
|
+
## Reporting a Vulnerability
|
|
15
|
+
|
|
16
|
+
Please do **not** open a public GitHub issue for security vulnerabilities. Instead, use one of the private channels below.
|
|
17
|
+
|
|
18
|
+
### Preferred: GitHub Private Vulnerability Reporting
|
|
19
|
+
|
|
20
|
+
Submit a private report via:
|
|
21
|
+
|
|
22
|
+
https://github.com/EvoMap/evolver/security/advisories/new
|
|
23
|
+
|
|
24
|
+
This is the fastest and most secure channel. Only repository maintainers will see the report.
|
|
25
|
+
|
|
26
|
+
### Alternative: Email
|
|
27
|
+
|
|
28
|
+
If you cannot use GitHub advisories, email `team@evomap.ai` with subject line `[SECURITY] evolver: <short title>`.
|
|
29
|
+
|
|
30
|
+
### What to include
|
|
31
|
+
|
|
32
|
+
- A clear description of the vulnerability and its impact
|
|
33
|
+
- Affected version(s) and environment (OS, Node.js version)
|
|
34
|
+
- Steps to reproduce or a minimal proof-of-concept
|
|
35
|
+
- Any suggested mitigation or patch
|
|
36
|
+
|
|
37
|
+
### What to expect
|
|
38
|
+
|
|
39
|
+
- **Acknowledgement**: within 48 hours of receipt
|
|
40
|
+
- **Initial assessment**: within 7 days (severity, affected versions, mitigation plan)
|
|
41
|
+
- **Fix timeline**: critical issues are targeted for a patch release within 14 days; lower severity follows the normal release cadence
|
|
42
|
+
- **Disclosure**: we practice coordinated disclosure. Once a fix is available, we publish a GitHub Security Advisory crediting the reporter (unless anonymity is requested)
|
|
43
|
+
|
|
44
|
+
### Scope
|
|
45
|
+
|
|
46
|
+
In scope:
|
|
47
|
+
|
|
48
|
+
- `@evomap/evolver` npm package source code
|
|
49
|
+
- Default configuration and built-in protocols (GEP, A2A Proxy)
|
|
50
|
+
- Supply-chain risks (malicious dependencies, install scripts)
|
|
51
|
+
|
|
52
|
+
Out of scope:
|
|
53
|
+
|
|
54
|
+
- Vulnerabilities in the EvoMap Hub service itself -- please report those separately to `security@evomap.ai`
|
|
55
|
+
- Third-party LLM providers, user-authored genes, or user-generated content
|
|
56
|
+
- Social engineering and physical attacks
|
|
57
|
+
|
|
58
|
+
## Safe Harbor
|
|
59
|
+
|
|
60
|
+
Good-faith security research conducted under this policy is authorized. We will not pursue legal action against researchers who:
|
|
61
|
+
|
|
62
|
+
- Give us reasonable time to respond before public disclosure
|
|
63
|
+
- Avoid accessing data that does not belong to them
|
|
64
|
+
- Do not degrade service for other users
|
|
65
|
+
|
|
66
|
+
Thank you for helping keep the EvoMap ecosystem safe.
|
package/index.js
CHANGED
|
@@ -65,6 +65,15 @@ function parseMs(v, fallback) {
|
|
|
65
65
|
return fallback;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
function getLastSignals(statePath) {
|
|
69
|
+
try {
|
|
70
|
+
const st = readJsonSafe(statePath);
|
|
71
|
+
return (st && st.last_run && Array.isArray(st.last_run.signals)) ? st.last_run.signals : [];
|
|
72
|
+
} catch (e) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
// Singleton Guard - prevent multiple evolver daemon instances
|
|
69
78
|
function acquireLock() {
|
|
70
79
|
const lockFile = path.join(__dirname, 'evolver.pid');
|
|
@@ -129,12 +138,13 @@ async function main() {
|
|
|
129
138
|
if (isLoop) {
|
|
130
139
|
// Internal daemon loop (no wrapper required).
|
|
131
140
|
if (!acquireLock()) process.exit(0);
|
|
132
|
-
|
|
141
|
+
function shutdown() {
|
|
133
142
|
releaseLock();
|
|
134
143
|
try { require('./src/gep/a2aProtocol').stopEventStream(); } catch (e) {}
|
|
135
|
-
}
|
|
136
|
-
process.on('
|
|
137
|
-
process.on('
|
|
144
|
+
}
|
|
145
|
+
process.on('exit', shutdown);
|
|
146
|
+
process.on('SIGINT', () => { shutdown(); process.exit(); });
|
|
147
|
+
process.on('SIGTERM', () => { shutdown(); process.exit(); });
|
|
138
148
|
process.on('uncaughtException', (err) => {
|
|
139
149
|
console.error('[FATAL] Uncaught exception:', err && err.stack ? err.stack : String(err));
|
|
140
150
|
releaseLock();
|
|
@@ -157,7 +167,7 @@ async function main() {
|
|
|
157
167
|
}
|
|
158
168
|
console.log(`Loop mode enabled (internal daemon, bridge=${process.env.EVOLVE_BRIDGE}, verbose=${isVerbose}).`);
|
|
159
169
|
|
|
160
|
-
const { getEvolutionDir } = require('./src/gep/paths');
|
|
170
|
+
const { getEvolutionDir, getEvolverLogPath } = require('./src/gep/paths');
|
|
161
171
|
const solidifyStatePath = path.join(getEvolutionDir(), 'evolution_solidify_state.json');
|
|
162
172
|
|
|
163
173
|
const minSleepMs = parseMs(process.env.EVOLVER_MIN_SLEEP_MS, 2000);
|
|
@@ -217,6 +227,11 @@ async function main() {
|
|
|
217
227
|
console.warn('[ATP] Auto-init failed: ' + (atpInitErr && atpInitErr.message || atpInitErr));
|
|
218
228
|
}
|
|
219
229
|
|
|
230
|
+
// Hoist module refs used inside the loop to avoid repeated module lookups per cycle
|
|
231
|
+
const idleScheduler = require('./src/gep/idleScheduler');
|
|
232
|
+
const { shouldDistillFromFailures: shouldDF, autoDistillFromFailures: autoDF } = require('./src/gep/skillDistiller');
|
|
233
|
+
const { tryExplore } = require('./src/gep/explore');
|
|
234
|
+
|
|
220
235
|
let currentSleepMs = minSleepMs;
|
|
221
236
|
let cycleCount = 0;
|
|
222
237
|
|
|
@@ -263,26 +278,24 @@ async function main() {
|
|
|
263
278
|
// operations (distillation, reflection) during detected idle windows.
|
|
264
279
|
let omlsMultiplier = 1;
|
|
265
280
|
try {
|
|
266
|
-
const
|
|
267
|
-
const schedule = getScheduleRecommendation();
|
|
281
|
+
const schedule = idleScheduler.getScheduleRecommendation();
|
|
268
282
|
if (schedule.enabled && schedule.sleep_multiplier > 0) {
|
|
269
283
|
omlsMultiplier = schedule.sleep_multiplier;
|
|
270
284
|
if (schedule.should_distill) {
|
|
271
285
|
try {
|
|
272
|
-
const { shouldDistillFromFailures: shouldDF, autoDistillFromFailures: autoDF } = require('./src/gep/skillDistiller');
|
|
273
286
|
if (shouldDF()) {
|
|
274
287
|
const dfResult = autoDF();
|
|
275
288
|
if (dfResult && dfResult.ok) {
|
|
276
289
|
console.log('[OMLS] Idle-window failure distillation: ' + dfResult.gene.id);
|
|
277
290
|
}
|
|
278
291
|
}
|
|
279
|
-
} catch (e) {
|
|
292
|
+
} catch (e) {
|
|
293
|
+
if (isVerbose) console.warn('[OMLS] Distill error: ' + (e.message || e));
|
|
294
|
+
}
|
|
280
295
|
}
|
|
281
296
|
if (schedule.should_explore) {
|
|
282
297
|
try {
|
|
283
|
-
const
|
|
284
|
-
const repoRoot = require('./src/gep/paths').getRepoRoot();
|
|
285
|
-
const exploreResult = await tryExplore([], schedule, repoRoot);
|
|
298
|
+
const exploreResult = await tryExplore([], schedule, getRepoRoot());
|
|
286
299
|
if (exploreResult && exploreResult.signals && exploreResult.signals.length > 0) {
|
|
287
300
|
console.log('[OMLS] Explore discovered ' + exploreResult.signals.length + ' signals: ' + exploreResult.signals.slice(0, 5).join(', '));
|
|
288
301
|
}
|
|
@@ -294,7 +307,9 @@ async function main() {
|
|
|
294
307
|
console.log(`[OMLS] idle=${schedule.idle_seconds}s intensity=${schedule.intensity} multiplier=${omlsMultiplier}`);
|
|
295
308
|
}
|
|
296
309
|
}
|
|
297
|
-
} catch (e) {
|
|
310
|
+
} catch (e) {
|
|
311
|
+
if (isVerbose) console.warn('[OMLS] Scheduler error: ' + (e.message || e));
|
|
312
|
+
}
|
|
298
313
|
|
|
299
314
|
// Suicide check (memory leak protection)
|
|
300
315
|
if (suicideEnabled) {
|
|
@@ -302,7 +317,6 @@ async function main() {
|
|
|
302
317
|
if (cycleCount >= maxCyclesPerProcess || memMb > maxRssMb) {
|
|
303
318
|
console.log(`[Daemon] Restarting self (cycles=${cycleCount}, rssMb=${memMb.toFixed(0)})`);
|
|
304
319
|
try {
|
|
305
|
-
const { getEvolverLogPath } = require('./src/gep/paths');
|
|
306
320
|
const logFd = fs.openSync(getEvolverLogPath(), 'a');
|
|
307
321
|
const spawnOpts = {
|
|
308
322
|
detached: true,
|
|
@@ -322,8 +336,7 @@ async function main() {
|
|
|
322
336
|
|
|
323
337
|
let saturationMultiplier = 1;
|
|
324
338
|
try {
|
|
325
|
-
const
|
|
326
|
-
const lastSignals = st1 && st1.last_run && Array.isArray(st1.last_run.signals) ? st1.last_run.signals : [];
|
|
339
|
+
const lastSignals = getLastSignals(solidifyStatePath);
|
|
327
340
|
if (lastSignals.includes('force_steady_state')) {
|
|
328
341
|
saturationMultiplier = 4;
|
|
329
342
|
console.log('[Daemon] Saturation detected. Entering steady-state mode (4x sleep).');
|
|
@@ -331,14 +344,17 @@ async function main() {
|
|
|
331
344
|
saturationMultiplier = 2;
|
|
332
345
|
console.log('[Daemon] Approaching saturation. Reducing evolution frequency (2x sleep).');
|
|
333
346
|
}
|
|
334
|
-
} catch (e) {
|
|
347
|
+
} catch (e) {
|
|
348
|
+
if (isVerbose) console.warn('[Daemon] Saturation check error: ' + (e.message || e));
|
|
349
|
+
}
|
|
335
350
|
|
|
336
351
|
// Jitter to avoid lockstep restarts.
|
|
337
352
|
const jitter = Math.floor(Math.random() * 250);
|
|
338
353
|
const totalSleepMs = Math.max(minSleepMs, (currentSleepMs + jitter) * saturationMultiplier * omlsMultiplier);
|
|
339
354
|
if (isVerbose) {
|
|
340
355
|
const memMb = (process.memoryUsage().rss / 1024 / 1024).toFixed(1);
|
|
341
|
-
|
|
356
|
+
const signals = getLastSignals(solidifyStatePath).join(',');
|
|
357
|
+
console.log(`[Verbose] cycle=${cycleCount} ok=${ok} dt=${dt}ms sleep=${totalSleepMs}ms (base=${currentSleepMs} jitter=${jitter} sat=${saturationMultiplier}x) rss=${memMb}MB signals=[${signals}]`);
|
|
342
358
|
}
|
|
343
359
|
await sleepMs(totalSleepMs);
|
|
344
360
|
|
|
@@ -438,11 +454,11 @@ async function main() {
|
|
|
438
454
|
if (!res || !res.ok) {
|
|
439
455
|
if (res && res.validation && !res.validation.ok) {
|
|
440
456
|
urgentOpts.validationFailed = true;
|
|
441
|
-
|
|
457
|
+
const failedStep = res.validation.results && res.validation.results.find(function (r) { return !r.ok; });
|
|
442
458
|
urgentOpts.validationErrors = failedStep ? (failedStep.err || failedStep.cmd || '') : '';
|
|
443
459
|
}
|
|
444
460
|
urgentOpts.geneId = res && res.gene ? res.gene.id : undefined;
|
|
445
|
-
|
|
461
|
+
const evtOutcome = res && res.event && res.event.outcome;
|
|
446
462
|
if (evtOutcome && typeof evtOutcome.score === 'number' && evtOutcome.score < 0.3) {
|
|
447
463
|
urgentOpts.lowConfidence = true;
|
|
448
464
|
urgentOpts.confidenceScore = evtOutcome.score;
|
|
@@ -454,13 +470,13 @@ async function main() {
|
|
|
454
470
|
urgentOpts.signals = res.event && Array.isArray(res.event.signals) ? res.event.signals : [];
|
|
455
471
|
}
|
|
456
472
|
if (res && res.constraintCheck && Array.isArray(res.constraintCheck.violations)) {
|
|
457
|
-
|
|
473
|
+
const llmRejectV = res.constraintCheck.violations.find(function (v) { return String(v).startsWith('llm_review_rejected'); });
|
|
458
474
|
if (llmRejectV) {
|
|
459
475
|
urgentOpts.llmReviewRejected = true;
|
|
460
476
|
urgentOpts.llmReviewReason = String(llmRejectV).replace('llm_review_rejected: ', '');
|
|
461
477
|
}
|
|
462
478
|
}
|
|
463
|
-
|
|
479
|
+
const lr = readJsonSafe(path.join(require('./src/gep/paths').getEvolutionDir(), 'evolution_solidify_state.json'));
|
|
464
480
|
if (lr && lr.last_run && lr.last_run.active_task_id) {
|
|
465
481
|
urgentOpts.taskCompletionFailed = true;
|
|
466
482
|
urgentOpts.taskTitle = lr.last_run.active_task_title || '';
|
|
@@ -473,13 +489,13 @@ async function main() {
|
|
|
473
489
|
}
|
|
474
490
|
|
|
475
491
|
if (Object.keys(urgentOpts).length > 0) {
|
|
476
|
-
|
|
492
|
+
const urgentQs = generateUrgentQuestions(urgentOpts);
|
|
477
493
|
if (urgentQs.length > 0) {
|
|
478
494
|
console.log('[UrgentQ] Generated ' + urgentQs.length + ' urgent question(s) from solidify outcome.');
|
|
479
495
|
try {
|
|
480
|
-
|
|
496
|
+
const fetchRes = await fetchTasks({ questions: urgentQs });
|
|
481
497
|
if (fetchRes.questions_created) {
|
|
482
|
-
|
|
498
|
+
const accepted = fetchRes.questions_created.filter(function (q) { return !q.error; });
|
|
483
499
|
if (accepted.length > 0) {
|
|
484
500
|
console.log('[UrgentQ] Hub accepted ' + accepted.length + ' urgent question(s) as bounties.');
|
|
485
501
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.68.0-beta.1",
|
|
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": {
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// evolver-session-end.js
|
|
3
|
+
// Records evolution outcome at session end.
|
|
4
|
+
// Collects git diff stats, extracts signals, records via Hub API or local memory.
|
|
5
|
+
// Input: stdin JSON. Output: stdout JSON with followup_message.
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { execSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
function findEvolverRoot() {
|
|
12
|
+
const candidates = [
|
|
13
|
+
process.env.EVOLVER_ROOT,
|
|
14
|
+
path.resolve(__dirname, '..', '..', '..'),
|
|
15
|
+
];
|
|
16
|
+
for (const c of candidates) {
|
|
17
|
+
if (c && fs.existsSync(path.join(c, 'package.json'))) {
|
|
18
|
+
try {
|
|
19
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(c, 'package.json'), 'utf8'));
|
|
20
|
+
if (pkg.name === '@evomap/evolver' || pkg.name === 'evolver') return c;
|
|
21
|
+
} catch { /* skip */ }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const homeSkills = path.join(require('os').homedir(), 'skills', 'evolver');
|
|
25
|
+
if (fs.existsSync(path.join(homeSkills, 'package.json'))) return homeSkills;
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function findMemoryGraph(evolverRoot) {
|
|
30
|
+
if (process.env.MEMORY_GRAPH_PATH && fs.existsSync(process.env.MEMORY_GRAPH_PATH)) {
|
|
31
|
+
return process.env.MEMORY_GRAPH_PATH;
|
|
32
|
+
}
|
|
33
|
+
const candidates = [
|
|
34
|
+
evolverRoot && path.join(evolverRoot, 'memory', 'evolution', 'memory_graph.jsonl'),
|
|
35
|
+
evolverRoot && path.join(evolverRoot, 'MEMORY', 'evolution', 'memory_graph.jsonl'),
|
|
36
|
+
];
|
|
37
|
+
for (const c of candidates) {
|
|
38
|
+
if (c && fs.existsSync(c)) return c;
|
|
39
|
+
}
|
|
40
|
+
if (evolverRoot) {
|
|
41
|
+
const defaultPath = path.join(evolverRoot, 'memory', 'evolution', 'memory_graph.jsonl');
|
|
42
|
+
fs.mkdirSync(path.dirname(defaultPath), { recursive: true });
|
|
43
|
+
return defaultPath;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getGitDiffStats() {
|
|
49
|
+
try {
|
|
50
|
+
const cwd = process.cwd();
|
|
51
|
+
const stat = execSync('git diff --stat HEAD~1 2>/dev/null || git diff --stat 2>/dev/null || echo ""', {
|
|
52
|
+
cwd,
|
|
53
|
+
encoding: 'utf8',
|
|
54
|
+
timeout: 5000,
|
|
55
|
+
}).trim();
|
|
56
|
+
const diffContent = execSync('git diff HEAD~1 --no-color 2>/dev/null || git diff --no-color 2>/dev/null || echo ""', {
|
|
57
|
+
cwd,
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
timeout: 5000,
|
|
60
|
+
}).trim();
|
|
61
|
+
const filesChanged = (stat.match(/\d+ files? changed/) || ['0'])[0];
|
|
62
|
+
const insertions = (stat.match(/(\d+) insertions?/) || [null, '0'])[1];
|
|
63
|
+
const deletions = (stat.match(/(\d+) deletions?/) || [null, '0'])[1];
|
|
64
|
+
return {
|
|
65
|
+
stat,
|
|
66
|
+
summary: `${filesChanged}, +${insertions}/-${deletions}`,
|
|
67
|
+
diffSnippet: diffContent.slice(0, 2000),
|
|
68
|
+
hasChanges: stat.length > 0,
|
|
69
|
+
};
|
|
70
|
+
} catch {
|
|
71
|
+
return { stat: '', summary: 'unknown', diffSnippet: '', hasChanges: false };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function detectSignals(text) {
|
|
76
|
+
if (!text) return [];
|
|
77
|
+
const lower = text.toLowerCase();
|
|
78
|
+
const signals = [];
|
|
79
|
+
if (/error:|exception:|failed/i.test(lower)) signals.push('log_error');
|
|
80
|
+
if (/timeout|slow|latency|bottleneck/i.test(lower)) signals.push('perf_bottleneck');
|
|
81
|
+
if (/add|implement|feature|new function|new module/i.test(lower)) signals.push('user_feature_request');
|
|
82
|
+
if (/improve|enhance|refactor|optimize/i.test(lower)) signals.push('user_improvement_suggestion');
|
|
83
|
+
if (/not supported|unsupported|not implemented/i.test(lower)) signals.push('capability_gap');
|
|
84
|
+
if (/deploy|ci|pipeline|build failed/i.test(lower)) signals.push('deployment_issue');
|
|
85
|
+
if (/test fail|assertion|expect\(/i.test(lower)) signals.push('test_failure');
|
|
86
|
+
return [...new Set(signals)];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function recordToHub(outcome) {
|
|
90
|
+
const hubUrl = process.env.EVOMAP_HUB_URL || process.env.A2A_HUB_URL;
|
|
91
|
+
const apiKey = process.env.EVOMAP_API_KEY || process.env.A2A_NODE_SECRET;
|
|
92
|
+
const nodeId = process.env.EVOMAP_NODE_ID || process.env.A2A_NODE_ID;
|
|
93
|
+
if (!hubUrl || !apiKey) return false;
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const payload = JSON.stringify({
|
|
97
|
+
gene_id: outcome.geneId || 'ad_hoc',
|
|
98
|
+
signals: outcome.signals,
|
|
99
|
+
status: outcome.status,
|
|
100
|
+
score: outcome.score,
|
|
101
|
+
summary: outcome.summary,
|
|
102
|
+
sender_id: nodeId || undefined,
|
|
103
|
+
});
|
|
104
|
+
const curlCmd = `curl -s -m 8 -X POST`
|
|
105
|
+
+ ` -H "Content-Type: application/json"`
|
|
106
|
+
+ ` -H "Authorization: Bearer ${apiKey}"`
|
|
107
|
+
+ ` -d '${payload.replace(/'/g, "'\\''")}'`
|
|
108
|
+
+ ` "${hubUrl.replace(/\/+$/, '')}/a2a/evolution/record"`;
|
|
109
|
+
execSync(curlCmd, { timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
110
|
+
return true;
|
|
111
|
+
} catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function recordToLocal(graphPath, outcome) {
|
|
117
|
+
try {
|
|
118
|
+
const entry = {
|
|
119
|
+
timestamp: new Date().toISOString(),
|
|
120
|
+
gene_id: outcome.geneId || 'ad_hoc',
|
|
121
|
+
signals: outcome.signals,
|
|
122
|
+
outcome: {
|
|
123
|
+
status: outcome.status,
|
|
124
|
+
score: outcome.score,
|
|
125
|
+
note: outcome.summary,
|
|
126
|
+
},
|
|
127
|
+
source: 'hook:session-end',
|
|
128
|
+
};
|
|
129
|
+
fs.appendFileSync(graphPath, JSON.stringify(entry) + '\n', 'utf8');
|
|
130
|
+
return true;
|
|
131
|
+
} catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function main() {
|
|
137
|
+
let inputData = '';
|
|
138
|
+
let handled = false;
|
|
139
|
+
process.stdin.setEncoding('utf8');
|
|
140
|
+
process.stdin.on('data', chunk => { inputData += chunk; });
|
|
141
|
+
process.stdin.on('end', () => {
|
|
142
|
+
if (handled) return;
|
|
143
|
+
handled = true;
|
|
144
|
+
try {
|
|
145
|
+
const diffInfo = getGitDiffStats();
|
|
146
|
+
|
|
147
|
+
if (!diffInfo.hasChanges) {
|
|
148
|
+
process.stdout.write(JSON.stringify({}));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const signals = detectSignals(diffInfo.diffSnippet);
|
|
153
|
+
if (signals.length === 0) signals.push('stable_success_plateau');
|
|
154
|
+
|
|
155
|
+
const hasErrors = signals.includes('log_error') || signals.includes('test_failure');
|
|
156
|
+
const status = hasErrors ? 'failed' : 'success';
|
|
157
|
+
const score = hasErrors ? 0.3 : 0.8;
|
|
158
|
+
|
|
159
|
+
const outcome = {
|
|
160
|
+
geneId: 'ad_hoc',
|
|
161
|
+
signals,
|
|
162
|
+
status,
|
|
163
|
+
score,
|
|
164
|
+
summary: `Session end: ${diffInfo.summary}. Signals: [${signals.join(', ')}]`,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const evolverRoot = findEvolverRoot();
|
|
168
|
+
const graphPath = findMemoryGraph(evolverRoot);
|
|
169
|
+
|
|
170
|
+
const hubOk = recordToHub(outcome);
|
|
171
|
+
const localOk = graphPath ? recordToLocal(graphPath, outcome) : false;
|
|
172
|
+
|
|
173
|
+
const target = hubOk ? 'Hub' : localOk ? 'local memory' : 'nowhere (no Hub or local path)';
|
|
174
|
+
const msg = `[Evolution] Session outcome recorded to ${target}: ${outcome.summary}`;
|
|
175
|
+
|
|
176
|
+
process.stdout.write(JSON.stringify({
|
|
177
|
+
followup_message: msg,
|
|
178
|
+
stopMessage: msg,
|
|
179
|
+
additionalContext: msg,
|
|
180
|
+
}));
|
|
181
|
+
} catch (e) {
|
|
182
|
+
process.stdout.write(JSON.stringify({}));
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
if (handled) return;
|
|
188
|
+
handled = true;
|
|
189
|
+
process.stdout.write(JSON.stringify({}));
|
|
190
|
+
process.exit(0);
|
|
191
|
+
}, 7000);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
main();
|