Skip to content

Commit f2bc326

Browse files
evolver-publishautogame-17bjw9808
committed
Release v1.93.0
Co-authored-by: autogame-17 <17@evomap.ai> Co-authored-by: bjw9808 <bjw9808@gmail.com> Co-authored-by: autogame-17 <166480271+autogame-17@users.noreply.github.com>
1 parent ea842c3 commit f2bc326

74 files changed

Lines changed: 1130 additions & 237 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/pull_request_template.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,27 @@ Short 1-2 sentence summary of the change.
1515

1616
Low / Medium / High -- note if it touches infra or public API.
1717

18+
## Harness/evaluator governance
19+
20+
Required when this PR touches Evolver harness/evaluator/self-evolution surfaces:
21+
GEP schemas, prompt/selector/mutation/solidify/candidate/evaluator logic,
22+
evolve pipeline, adapter execution bridge, proxy routing/trace, bundled GEP
23+
assets, or the EvoX bridge contract. For unrelated PRs, write
24+
`N/A -- not a harness/evaluator governance change` on each line.
25+
26+
Upstream governance surface: <typed Evolver surface, or N/A>
27+
Downstream EvoX impact: <bridge/contract/runtime impact, or N/A>
28+
Rollout-local scope: <proposal/shadow/cohort boundary before promotion, or N/A>
29+
Promotion boundary: <proposal→rollout→PR/default boundary, or N/A>
30+
Evaluator mismatch sets: <observation/action/repair/verification/evidence/belief sets covered, or N/A>
31+
Non-regression evidence: <tests/shadow runs/replay/doc-only rationale, or N/A>
32+
Fix-severity review: <low | medium | high | critical>
33+
Owner approval: <owning module/reviewer requirement, or N/A>
34+
Security boundary: <data/tool/host/network/secrets impact, or N/A>
35+
Rollback: <disable/revert/quarantine path, or N/A>
36+
Live promotion: no
37+
Autonomous evaluator self-editing: no
38+
1839
## Self-check
1940

2041
Tick only the boxes that apply, but every applicable box must be ticked. Bugbot

‎.github/workflows/test.yml‎

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,68 @@
11
name: test
22

3-
# Runs the Node test suite on every PR and on pushes to main. Originally
4-
# Ubuntu-only (#198): PR checks were Cursor Bugbot + Security, neither of
5-
# which runs `npm test`, so a green PR did NOT mean the tests passed.
3+
# Runs PR governance checks and the Node test suite.
64
#
7-
# This workflow now also runs the suite on Windows + macOS via a second job
8-
# (test-cross). #198 explicitly flagged Windows / macOS as a follow-up: the
9-
# suite still has Linux-specific assumptions (symlink reliance, hard-coded
10-
# ~/.volta layout, POSIX-style path equality) that would fail on those
11-
# hosts. test-cross runs on PRs in **advisory** mode (continue-on-error)
12-
# so those red signals are visible to reviewers without blocking merge
13-
# while the suite is being made hermetic. Each fix can flip its tests
14-
# from "red on Win/Mac" to "green on Win/Mac" incrementally. Once the
15-
# remaining failures are cleaned up, drop `continue-on-error: true` and
16-
# add `test-cross` to required checks to make cross-platform green a
17-
# hard merge gate.
5+
# Pull requests use pull_request_target on self-hosted Linux runners and only
6+
# execute trusted base-branch code against PR metadata. They intentionally do not
7+
# checkout, install, or test PR-controlled code on the self-hosted runner.
8+
# Pushes to main run the full Node suite on the merged repository state.
189
#
19-
# main pushes skip test-cross to keep private-repo billing predictable
20-
# (macos-latest is 10x and windows-latest is 2x the ubuntu rate).
10+
# Cross-platform Windows/macOS coverage remains a future advisory lane once it
11+
# can run on available self-hosted runners or an explicitly funded hosted pool.
2112

2213
on:
23-
pull_request:
14+
pull_request_target:
2415
push:
2516
branches: [main]
2617

2718
permissions:
2819
contents: read
20+
pull-requests: read
2921

3022
concurrency:
31-
group: test-${{ github.workflow }}-${{ github.ref }}
23+
group: test-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
3224
cancel-in-progress: true
3325

3426
jobs:
3527
test:
36-
runs-on: ubuntu-latest
28+
runs-on: [self-hosted, Linux, X64]
3729
steps:
38-
- uses: actions/checkout@v4
30+
- name: Checkout trusted base for PR guard
31+
if: github.event_name == 'pull_request_target'
32+
uses: actions/checkout@v4
33+
with:
34+
ref: ${{ github.event.pull_request.base.sha }}
35+
fetch-depth: 1
36+
37+
- name: Checkout merged code for main tests
38+
if: github.event_name == 'push'
39+
uses: actions/checkout@v4
3940

4041
- uses: actions/setup-node@v4
4142
with:
4243
node-version: '22' # engines: node >=22.12
4344
cache: npm
4445

45-
- name: Install dependencies
46-
run: npm ci
47-
48-
- name: Run tests (node --test)
49-
run: npm test
50-
51-
test-cross:
52-
# Advisory cross-platform run: PR-only (skips main push to save billing),
53-
# continue-on-error so a known Win/Mac regression does not block merge
54-
# while the suite is being hardened. Reviewers still see the result and
55-
# can opt-in to wait for a fix on a per-PR basis.
56-
if: github.event_name == 'pull_request'
57-
strategy:
58-
fail-fast: false
59-
matrix:
60-
os: [windows-latest, macos-latest]
61-
runs-on: ${{ matrix.os }}
62-
continue-on-error: true
63-
steps:
64-
- uses: actions/checkout@v4
46+
- name: Collect changed files for governance guard
47+
if: github.event_name == 'pull_request_target'
48+
env:
49+
GH_TOKEN: ${{ github.token }}
50+
PR_NUMBER: ${{ github.event.pull_request.number }}
51+
REPO: ${{ github.repository }}
52+
run: |
53+
gh api --paginate "repos/$REPO/pulls/$PR_NUMBER/files" --jq '.[].filename' > pr-changed-files.txt
6554
66-
- uses: actions/setup-node@v4
67-
with:
68-
node-version: '22'
69-
cache: npm
55+
- name: Harness/evaluator governance guard
56+
if: github.event_name == 'pull_request_target'
57+
env:
58+
PR_BODY: ${{ github.event.pull_request.body }}
59+
PR_CHANGED_FILES_FILE: pr-changed-files.txt
60+
run: node scripts/harness-governance-check.js
7061

7162
- name: Install dependencies
63+
if: github.event_name == 'push'
7264
run: npm ci
7365

7466
- name: Run tests (node --test)
67+
if: github.event_name == 'push'
7568
run: npm test

‎.npmignore‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
assets/cover.png
1+
assets/logo.png
22
/test/
33
/docs/
44
/memory/

‎CONTRIBUTING.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ Submit PRs with clear intent and scope.
1111

1212
### Engineering conventions
1313

14+
- **Evolver is the upstream governance source for EvoX harness/evolver behavior.**
15+
Any PR that changes harness/evaluator/self-evolution surfaces (GEP schemas,
16+
prompt/selector/mutation/solidify/candidate/evaluator logic, evolve pipeline,
17+
adapter execution bridge, proxy routing/trace, bundled GEP assets, or the EvoX
18+
bridge contract) must fill the `## Harness/evaluator governance` PR-template
19+
packet. The required packet documents the whitelisted surface, downstream EvoX
20+
impact, rollout-local scope, promotion boundary, evaluator mismatch sets,
21+
non-regression evidence, fix severity, owner approval, security boundary,
22+
rollback, and the two hard denials: `Live promotion: no` and
23+
`Autonomous evaluator self-editing: no`. `scripts/harness-governance-check.js`
24+
enforces this on PRs.
25+
1426
- **Spawn child CLIs as `node <entry.js>` — never via a `.cmd` shim, npm symlink, or bare command name.** When launching a harness/tool subprocess (claude-code, openclaw, codex, ...), resolve the JS entry behind the launcher and hand it to `node` directly. Two reasons:
1527
1. On Windows, `child_process.spawn` without `shell:true` on a `.cmd`/`.bat` throws `EINVAL` since the CVE-2024-27980 fix (Node >=18.20.2 / 20.12.2 / 21.7.3) — this silently broke the auto-exec bridge on Windows.
1628
2. Across platforms, shims/wrappers can emit warnings or silently exit on some machines. `node <entry>` is zero-shell, deterministic, and passes args via argv (no shell-injection surface).

‎README.zh-CN.md‎

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -99,28 +99,6 @@ evolver setup-hooks --platform=claude-code
9999

100100
通过 `~/.claude/` 向 Claude Code 的 hook 系统注册 Evolver。安装完成后重启 Claude Code CLI。
101101

102-
#### Codex
103-
104-
```bash
105-
evolver setup-hooks --platform=codex
106-
```
107-
108-
写入 `~/.codex/hooks.json`,将 hook 脚本安装到 `~/.codex/hooks/`,并在 `config.toml` 中启用 `codex_hooks` 特性。重启 Codex CLI 后生效。
109-
110-
##### Codex 注意事项
111-
112-
Codex CLI 暴露 `SessionStart` / `Stop` / `PostToolUse` 钩子(`setup-hooks --platform=codex` 通过它们接入 Evolver)。Codex 会将会话转写写入 `~/.codex/sessions/*.jsonl`,但 Stop 钩子的 payload 不包含 `transcript_path` 字段。自 v1.87.0 起,Evolver 会自动发现 `~/.codex/sessions/`(以及 Claude Code 的 `~/.claude/projects/`)下的转写文件,无需手动 export `EVOLVER_CURSOR_TRANSCRIPTS_DIR`,因此 `evolver --review` 可以在 Codex 上读取原始会话日志。
113-
114-
`setup-hooks --platform=codex` 仅做生命周期集成,不会将 Codex 的模型请求路由到 Evolver Proxy。如需路由 Codex 的模型流量,请运行 Evolver Proxy,并为 Codex 配置一个用户级 OpenAI Responses 兼容的自定义 provider,其 `base_url` 指向 proxy 的 `/v1` 端点,鉴权命令运行 `evolver proxy-token` 或源码检出中 `scripts/internal-proxy-env.sh --codex-config` 输出的绝对路径 `node index.js proxy-token --settings ...` 辅助脚本。
115-
116-
除会话转写外,Evolver 还按以下顺序读取:
117-
118-
1. 工作区根目录的 `MEMORY.md` / `USER.md`(需自行维护);
119-
2. `setup-hooks --platform=codex` 注入到项目 `AGENTS.md` 的 `<!-- evolver-evolution-memory -->` 段落;
120-
3. 本地 `memory_graph.jsonl` 的尾部(Evolver 自行写入的每轮结果日志)。
121-
122-
如果以上来源在前几轮都还没有内容,你会看到 `memory_missing` / `user_missing` / `session_logs_missing` 作为 advisory 信号出现。随着 `memory_graph.jsonl` 积累结果,这些信号会自行消失——无需手动配置。
123-
124102
#### OpenClaw
125103

126104
OpenClaw 会识别 Evolver 向 stdout 输出的 `sessions_spawn(...)` 协议,**无需安装 hooks**。将 Evolver 克隆到 OpenClaw workspace 中,在会话内运行即可:

‎SKILL.md‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ metadata:
6666
reads:
6767
- "~/.evolver/settings.json (Proxy address discovery)"
6868
- "~/.evomap/node_id (node identity)"
69-
- "assets/gep/* (GEP assets)"
70-
- "memory/* (evolution memory)"
69+
- "$EVOLVER_HOME/gep/* (runtime GEP assets)"
70+
- "$EVOLVER_HOME/memory/* (runtime evolution memory)"
7171
writes:
72-
- "assets/gep/* (genes, capsules, events)"
73-
- "memory/* (memory graph, narrative, reflection)"
72+
- "$EVOLVER_HOME/gep/* (runtime genes, capsules, events)"
73+
- "$EVOLVER_HOME/memory/* (runtime memory graph, narrative, reflection)"
7474
- "src/** (evolved code, only during solidify)"
7575
---
7676

@@ -346,10 +346,10 @@ node index.js --review
346346

347347
## GEP Protocol (Auditable Evolution)
348348

349-
Local asset store:
350-
- `assets/gep/genes.json` -- reusable Gene definitions
351-
- `assets/gep/capsules.json` -- success capsules
352-
- `assets/gep/events.jsonl` -- append-only evolution events
349+
Local runtime asset store (created and maintained by Evolver; these mutable runtime files are not bundled in the published Skill package):
350+
- `$EVOLVER_HOME/gep/genes.json` -- reusable Gene definitions
351+
- `$EVOLVER_HOME/gep/capsules.json` -- success capsules
352+
- `$EVOLVER_HOME/gep/events.jsonl` -- append-only evolution events
353353

354354
---
355355

‎assets/cover.png‎

-254 KB
Binary file not shown.

‎cli-options.js‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
5+
const PROXY_PATH_FLAGS = new Map([
6+
['--home', 'home'],
7+
['--store', 'store'],
8+
['--settings', 'settings'],
9+
['--env-file', 'envFile'],
10+
]);
11+
12+
function expandHomePath(value, env = process.env) {
13+
if (value === '~') return env.HOME || require('os').homedir();
14+
if (value.startsWith('~/') || value.startsWith('~\\')) {
15+
return path.join(env.HOME || require('os').homedir(), value.slice(2));
16+
}
17+
return value;
18+
}
19+
20+
function parseProxyCliPathOptions(argv, env = process.env) {
21+
const options = {};
22+
for (let index = 0; index < argv.length; index += 1) {
23+
const arg = String(argv[index]);
24+
const equalsIndex = arg.indexOf('=');
25+
const flag = equalsIndex >= 0 ? arg.slice(0, equalsIndex) : arg;
26+
const key = PROXY_PATH_FLAGS.get(flag);
27+
if (!key) continue;
28+
29+
const value = equalsIndex >= 0 ? arg.slice(equalsIndex + 1) : argv[++index];
30+
if (!value || !String(value).trim() || (equalsIndex < 0 && String(value).startsWith('-'))) {
31+
throw new Error(flag + ' requires a path');
32+
}
33+
options[key] = path.resolve(expandHomePath(String(value).trim(), env));
34+
}
35+
return options;
36+
}
37+
38+
function applyProxyCliPathOptions(options, env = process.env) {
39+
if (options.envFile) env.EVOLVER_ENV_FILE = options.envFile;
40+
if (options.home) {
41+
env.EVOMAP_DIR = options.home;
42+
env.EVOLVER_HOME = options.home;
43+
env.EVOMAP_HOME = options.home;
44+
env.EVOLVER_SETTINGS_DIR = options.home;
45+
env.EVOLVER_PROXY_STORE = path.join(options.home, 'mailbox');
46+
env.EVOLVER_PROXY_SETTINGS_FILE = path.join(options.home, 'settings.json');
47+
env.EVOMAP_PROXY_TRACE_FILE = path.join(options.home, 'proxy', 'traces', 'proxy-traces.jsonl');
48+
}
49+
if (options.store) env.EVOLVER_PROXY_STORE = options.store;
50+
if (options.settings) env.EVOLVER_PROXY_SETTINGS_FILE = options.settings;
51+
return options;
52+
}
53+
54+
function prepareProxyCliEnvironment(argv, env = process.env, dotenv = require('dotenv')) {
55+
const options = parseProxyCliPathOptions(argv, env);
56+
let envFile = { loaded: false, error: null };
57+
const selectedEnvFile = options.envFile || env.EVOLVER_ENV_FILE;
58+
if (selectedEnvFile) {
59+
const resolvedEnvFile = path.resolve(expandHomePath(String(selectedEnvFile).trim(), env));
60+
env.EVOLVER_ENV_FILE = resolvedEnvFile;
61+
const result = dotenv.config({ path: resolvedEnvFile, processEnv: env });
62+
envFile = { loaded: !result.error, error: result.error || null };
63+
}
64+
applyProxyCliPathOptions(options, env);
65+
return { options, envFile };
66+
}
67+
68+
module.exports = {
69+
applyProxyCliPathOptions,
70+
expandHomePath,
71+
parseProxyCliPathOptions,
72+
prepareProxyCliEnvironment,
73+
};

‎index.js‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,19 @@ if (process.argv[2] === 'proxy-token') {
206206
}
207207
}
208208

209+
const {
210+
applyProxyCliPathOptions,
211+
prepareProxyCliEnvironment,
212+
} = require('./cli-options');
213+
214+
let _proxyCliBootstrap = { options: {}, envFile: { loaded: false, error: null } };
215+
let _proxyCliBootstrapError = null;
216+
try {
217+
_proxyCliBootstrap = prepareProxyCliEnvironment(process.argv.slice(2), process.env);
218+
} catch (error) {
219+
_proxyCliBootstrapError = error;
220+
}
221+
209222
// Load .env BEFORE any internal require so that a2aProtocol and ATP
210223
// modules see A2A_NODE_SECRET / A2A_NODE_ID / A2A_HUB_URL at first
211224
// access and never fall back to a stale persisted/cached secret.
@@ -242,6 +255,9 @@ try {
242255
if (_root && _root !== process.cwd()) {
243256
require('dotenv').config({ path: _path.join(_root, '.env') });
244257
}
258+
// CLI paths have the highest priority, including over values loaded from
259+
// either the selected env file or the repository defaults.
260+
applyProxyCliPathOptions(_proxyCliBootstrap.options, process.env);
245261
if (_prevQuiet === undefined) delete process.env.EVOLVER_QUIET_PARENT_GIT;
246262
else process.env.EVOLVER_QUIET_PARENT_GIT = _prevQuiet;
247263
} catch (e) { /* dotenv is optional */ }
@@ -831,6 +847,14 @@ function refuseHelloIfDaemonRunning(toolLabel) {
831847
}
832848

833849
async function main() {
850+
if (_proxyCliBootstrapError) {
851+
console.error('[evolver] ' + _proxyCliBootstrapError.message);
852+
process.exitCode = 1;
853+
return;
854+
}
855+
if (_proxyCliBootstrap.envFile.error) {
856+
console.warn('[evolver] Failed to load --env-file: ' + _proxyCliBootstrap.envFile.error.message);
857+
}
834858
const args = process.argv.slice(2);
835859
const command = args[0];
836860
// Solo mode (--solo): the "constrained wild" profile. Implies loop (a solo
@@ -1450,6 +1474,7 @@ async function main() {
14501474
const { startProxy } = require('./src/proxy');
14511475
const proxyInfo = await startProxy({
14521476
hubUrl: process.env.A2A_HUB_URL,
1477+
dataDir: process.env.EVOLVER_PROXY_STORE,
14531478
clientSettings: {},
14541479
});
14551480
console.log('[Proxy] Started on ' + proxyInfo.url);
@@ -3690,6 +3715,11 @@ async function main() {
36903715
(read versioned node secrets from a JSON file)
36913716
- --hub-private-key=<path>|--hub-private-key <path>
36923717
(decrypt hub_key_envelope trace rows with a local private key)
3718+
- run path flags (CLI overrides environment variables):
3719+
- --home=<dir> (root for assets, mailbox, settings, and traces)
3720+
- --store=<dir> (mailbox store directory; EVOLVER_PROXY_STORE)
3721+
- --settings=<path> (proxy settings file; EVOLVER_PROXY_SETTINGS_FILE)
3722+
- --env-file=<path> (environment file; EVOLVER_ENV_FILE)
36933723
- webui flags:
36943724
- --port=<N> (local Web UI port, default 19821)
36953725

0 commit comments

Comments
 (0)