@evomap/evolver 1.86.1 → 1.87.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/assets/gep/genes.seed.json +44 -2
- package/index.js +67 -73
- package/package.json +3 -2
- package/skills/_meta/SKILL.md +41 -0
- package/skills/index.json +14 -0
- package/src/adapters/hookAdapter.js +17 -2
- package/src/adapters/scripts/evolver-session-start.js +2 -52
- package/src/adapters/scripts/evolver-signal-detect.js +0 -28
- package/src/evolve/guards.js +1 -1
- package/src/evolve/pipeline/collect.js +1 -1
- package/src/evolve/pipeline/dispatch.js +1 -1
- package/src/evolve/pipeline/enrich.js +1 -1
- package/src/evolve/pipeline/hub.js +1 -1
- package/src/evolve/pipeline/select.js +1 -1
- package/src/evolve/pipeline/signals.js +1 -1
- package/src/evolve/utils.js +1 -1
- package/src/evolve.js +1 -1
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/assetStore.js +1 -0
- 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/epigenetics.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/hash.js +1 -1
- package/src/gep/hubFetch.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/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/openPRRegistry.js +1 -1
- package/src/gep/paths.js +7 -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/recallVerifier.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/schemas/capsule.js +51 -1
- package/src/gep/selector.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/workspaceKeychain.js +1 -1
- package/src/proxy/index.js +226 -1
- package/src/proxy/router/messages_route.js +87 -9
- package/src/proxy/server/http.js +50 -13
|
@@ -143,7 +143,11 @@
|
|
|
143
143
|
"validation": [
|
|
144
144
|
"node scripts/validate-modules.js ./src/gep/signals ./src/evolve",
|
|
145
145
|
"node scripts/validate-suite.js"
|
|
146
|
-
]
|
|
146
|
+
],
|
|
147
|
+
"routing_hint": {
|
|
148
|
+
"tier": "mid",
|
|
149
|
+
"reasoning_level": "medium"
|
|
150
|
+
}
|
|
147
151
|
},
|
|
148
152
|
{
|
|
149
153
|
"type": "Gene",
|
|
@@ -178,6 +182,10 @@
|
|
|
178
182
|
"validation": [
|
|
179
183
|
"node --version"
|
|
180
184
|
],
|
|
185
|
+
"routing_hint": {
|
|
186
|
+
"tier": "cheap",
|
|
187
|
+
"reasoning_level": "low"
|
|
188
|
+
},
|
|
181
189
|
"schema_version": "1.6.0",
|
|
182
190
|
"_source": {
|
|
183
191
|
"kind": "skill2gep",
|
|
@@ -197,7 +205,41 @@
|
|
|
197
205
|
"preconditions_extracted": 0
|
|
198
206
|
}
|
|
199
207
|
},
|
|
200
|
-
"asset_id": "sha256:
|
|
208
|
+
"asset_id": "sha256:1501bc37fbefb18630c4dc8a95d8cdc1ed32bec4a465dc3223280ae907e07297"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"type": "Gene",
|
|
212
|
+
"id": "gene_tool_integrity",
|
|
213
|
+
"category": "repair",
|
|
214
|
+
"signals_match": [
|
|
215
|
+
"tool_bypass|工具绕过|ツール迂回|도구우회"
|
|
216
|
+
],
|
|
217
|
+
"preconditions": [
|
|
218
|
+
"agent used shell/exec to perform an action that a registered tool can handle"
|
|
219
|
+
],
|
|
220
|
+
"strategy": [
|
|
221
|
+
"Always prefer registered tools over ad-hoc scripts or shell workarounds",
|
|
222
|
+
"If a registered tool fails, report the actual error honestly and attempt to fix the root cause",
|
|
223
|
+
"Never fabricate explanations -- describe actual actions transparently",
|
|
224
|
+
"Do not create temporary scripts in extension or project directories"
|
|
225
|
+
],
|
|
226
|
+
"constraints": {
|
|
227
|
+
"max_files": 4,
|
|
228
|
+
"forbidden_paths": [
|
|
229
|
+
".git",
|
|
230
|
+
"node_modules"
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
"validation": [
|
|
234
|
+
"node scripts/validate-suite.js"
|
|
235
|
+
],
|
|
236
|
+
"anti_patterns": [
|
|
237
|
+
"tool_bypass"
|
|
238
|
+
],
|
|
239
|
+
"routing_hint": {
|
|
240
|
+
"tier": "cheap",
|
|
241
|
+
"reasoning_level": "low"
|
|
242
|
+
}
|
|
201
243
|
}
|
|
202
244
|
]
|
|
203
245
|
}
|
package/index.js
CHANGED
|
@@ -39,74 +39,6 @@ try {
|
|
|
39
39
|
else process.env.EVOLVER_QUIET_PARENT_GIT = _prevQuiet;
|
|
40
40
|
} catch (e) { /* dotenv is optional */ }
|
|
41
41
|
|
|
42
|
-
async function runSetupHooksCli(args) {
|
|
43
|
-
const hookAdapter = require('./src/adapters/hookAdapter');
|
|
44
|
-
const { setupHooks, resolveConfigRoot, detectPlatform, loadAdapter } = hookAdapter;
|
|
45
|
-
|
|
46
|
-
const platformFlag = args.find(a => typeof a === 'string' && a.startsWith('--platform='));
|
|
47
|
-
const platform = platformFlag ? platformFlag.slice('--platform='.length) : undefined;
|
|
48
|
-
const force = args.includes('--force');
|
|
49
|
-
const uninstall = args.includes('--uninstall');
|
|
50
|
-
const verifyOnly = args.includes('--verify');
|
|
51
|
-
|
|
52
|
-
if (verifyOnly) {
|
|
53
|
-
try {
|
|
54
|
-
const platformId = platform || detectPlatform(process.cwd());
|
|
55
|
-
if (!platformId) {
|
|
56
|
-
console.error('[setup-hooks] --verify: could not detect platform. Pass --platform=opencode|cursor|claude-code|codex|kiro');
|
|
57
|
-
process.exit(2);
|
|
58
|
-
}
|
|
59
|
-
const adapter = loadAdapter(platformId);
|
|
60
|
-
if (!adapter || typeof adapter.verify !== 'function') {
|
|
61
|
-
console.error('[setup-hooks] --verify: platform ' + platformId + ' does not support verification yet.');
|
|
62
|
-
process.exit(2);
|
|
63
|
-
}
|
|
64
|
-
const configRoot = resolveConfigRoot(platformId, process.cwd());
|
|
65
|
-
const report = adapter.verify({ configRoot });
|
|
66
|
-
if (typeof adapter.printVerifyReport === 'function') {
|
|
67
|
-
adapter.printVerifyReport(report);
|
|
68
|
-
} else {
|
|
69
|
-
console.log(JSON.stringify(report, null, 2));
|
|
70
|
-
}
|
|
71
|
-
process.exit(report.ok ? 0 : 1);
|
|
72
|
-
} catch (verifyErr) {
|
|
73
|
-
console.error('[setup-hooks] --verify error:', verifyErr && verifyErr.message || verifyErr);
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
const result = await setupHooks({
|
|
80
|
-
platform,
|
|
81
|
-
cwd: process.cwd(),
|
|
82
|
-
force,
|
|
83
|
-
uninstall,
|
|
84
|
-
evolverRoot: __dirname,
|
|
85
|
-
});
|
|
86
|
-
if (result && result.ok) {
|
|
87
|
-
if (!uninstall && result.files) {
|
|
88
|
-
console.log('\n[setup-hooks] Files created/updated:');
|
|
89
|
-
for (const f of result.files) {
|
|
90
|
-
console.log(' ' + f);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
process.exit(0);
|
|
94
|
-
} else {
|
|
95
|
-
console.error('[setup-hooks] Failed: ' + (result && result.error || 'unknown'));
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error('[setup-hooks] Error:', error && error.message || error);
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (require.main === module && process.argv[2] === 'setup-hooks') {
|
|
105
|
-
runSetupHooksCli(process.argv.slice(3)).catch(function (err) {
|
|
106
|
-
console.error('[setup-hooks] Error:', err && err.stack ? err.stack : String(err));
|
|
107
|
-
process.exitCode = 1;
|
|
108
|
-
});
|
|
109
|
-
} else {
|
|
110
42
|
const evolve = require('./src/evolve');
|
|
111
43
|
const { solidify } = require('./src/gep/solidify');
|
|
112
44
|
const path = require('path');
|
|
@@ -458,11 +390,11 @@ async function main() {
|
|
|
458
390
|
// own env, since verification can run with HubMirror off (verifier
|
|
459
391
|
// events are local-only on first ship).
|
|
460
392
|
try {
|
|
461
|
-
const enabled = String(process.env.EVOLVE_RECALL_VERIFY || '
|
|
393
|
+
const enabled = String(process.env.EVOLVE_RECALL_VERIFY || '0') === '1';
|
|
462
394
|
const sampleRateRaw = Number(process.env.EVOLVE_RECALL_VERIFY_SAMPLE_RATE);
|
|
463
395
|
const sampleRate = Number.isFinite(sampleRateRaw) && sampleRateRaw >= 0 && sampleRateRaw <= 1 ? sampleRateRaw : 1.0;
|
|
464
396
|
if (!enabled) {
|
|
465
|
-
console.log('[RecallVerify] DISABLED —
|
|
397
|
+
console.log('[RecallVerify] DISABLED (default) — opt-in observability only. Set EVOLVE_RECALL_VERIFY=1 to verify published assets round-trip via Hub Phase 2 lookup.');
|
|
466
398
|
} else {
|
|
467
399
|
console.log(`[RecallVerify] ENABLED — verifying published assets via Hub Phase 2 lookup, sample_rate=${sampleRate}. Set EVOLVE_RECALL_VERIFY=0 to disable.`);
|
|
468
400
|
}
|
|
@@ -519,7 +451,7 @@ async function main() {
|
|
|
519
451
|
// RecallVerify worker: starts once per process; drains the publish-
|
|
520
452
|
// verification queue with backoff. unref'd so it never blocks exit.
|
|
521
453
|
try {
|
|
522
|
-
if (String(process.env.EVOLVE_RECALL_VERIFY || '
|
|
454
|
+
if (String(process.env.EVOLVE_RECALL_VERIFY || '0') === '1') {
|
|
523
455
|
require('./src/gep/recallVerifier').startWorker();
|
|
524
456
|
}
|
|
525
457
|
} catch (rvStartErr) {
|
|
@@ -1728,6 +1660,70 @@ async function main() {
|
|
|
1728
1660
|
process.exit(1);
|
|
1729
1661
|
}
|
|
1730
1662
|
|
|
1663
|
+
} else if (command === 'setup-hooks') {
|
|
1664
|
+
const hookAdapter = require('./src/adapters/hookAdapter');
|
|
1665
|
+
const { setupHooks, resolveConfigRoot, detectPlatform, loadAdapter } = hookAdapter;
|
|
1666
|
+
|
|
1667
|
+
const platformFlag = args.find(a => typeof a === 'string' && a.startsWith('--platform='));
|
|
1668
|
+
const platform = platformFlag ? platformFlag.slice('--platform='.length) : undefined;
|
|
1669
|
+
const force = args.includes('--force');
|
|
1670
|
+
const uninstall = args.includes('--uninstall');
|
|
1671
|
+
const verifyOnly = args.includes('--verify');
|
|
1672
|
+
|
|
1673
|
+
if (verifyOnly) {
|
|
1674
|
+
// Read-only verification: do not touch any files, just report whether
|
|
1675
|
+
// the previously-installed hooks/plugin look healthy. Lets users answer
|
|
1676
|
+
// "is the plugin actually loaded?" without grepping opencode logs.
|
|
1677
|
+
try {
|
|
1678
|
+
const platformId = platform || detectPlatform(process.cwd());
|
|
1679
|
+
if (!platformId) {
|
|
1680
|
+
console.error('[setup-hooks] --verify: could not detect platform. Pass --platform=opencode|cursor|claude-code|codex|kiro');
|
|
1681
|
+
process.exit(2);
|
|
1682
|
+
}
|
|
1683
|
+
const adapter = loadAdapter(platformId);
|
|
1684
|
+
if (!adapter || typeof adapter.verify !== 'function') {
|
|
1685
|
+
console.error('[setup-hooks] --verify: platform ' + platformId + ' does not support verification yet.');
|
|
1686
|
+
process.exit(2);
|
|
1687
|
+
}
|
|
1688
|
+
const configRoot = resolveConfigRoot(platformId, process.cwd());
|
|
1689
|
+
const report = adapter.verify({ configRoot });
|
|
1690
|
+
if (typeof adapter.printVerifyReport === 'function') {
|
|
1691
|
+
adapter.printVerifyReport(report);
|
|
1692
|
+
} else {
|
|
1693
|
+
console.log(JSON.stringify(report, null, 2));
|
|
1694
|
+
}
|
|
1695
|
+
process.exit(report.ok ? 0 : 1);
|
|
1696
|
+
} catch (verifyErr) {
|
|
1697
|
+
console.error('[setup-hooks] --verify error:', verifyErr && verifyErr.message || verifyErr);
|
|
1698
|
+
process.exit(1);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
try {
|
|
1703
|
+
const result = await setupHooks({
|
|
1704
|
+
platform,
|
|
1705
|
+
cwd: process.cwd(),
|
|
1706
|
+
force,
|
|
1707
|
+
uninstall,
|
|
1708
|
+
evolverRoot: __dirname,
|
|
1709
|
+
});
|
|
1710
|
+
if (result && result.ok) {
|
|
1711
|
+
if (!uninstall && result.files) {
|
|
1712
|
+
console.log('\n[setup-hooks] Files created/updated:');
|
|
1713
|
+
for (const f of result.files) {
|
|
1714
|
+
console.log(' ' + f);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
process.exit(0);
|
|
1718
|
+
} else {
|
|
1719
|
+
console.error('[setup-hooks] Failed: ' + (result && result.error || 'unknown'));
|
|
1720
|
+
process.exit(1);
|
|
1721
|
+
}
|
|
1722
|
+
} catch (error) {
|
|
1723
|
+
console.error('[setup-hooks] Error:', error && error.message || error);
|
|
1724
|
+
process.exit(1);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1731
1727
|
} else if (command === 'reset-local-secret') {
|
|
1732
1728
|
// Wipe every local store of node_secret in one shot, so a daemon stuck
|
|
1733
1729
|
// after a manual web reset (https://evomap.ai/account -> Reset Secret)
|
|
@@ -1927,7 +1923,6 @@ if (require.main === module) {
|
|
|
1927
1923
|
|
|
1928
1924
|
module.exports = {
|
|
1929
1925
|
main,
|
|
1930
|
-
runSetupHooksCli,
|
|
1931
1926
|
readJsonSafe,
|
|
1932
1927
|
rejectPendingRun,
|
|
1933
1928
|
isPendingSolidify,
|
|
@@ -1936,4 +1931,3 @@ module.exports = {
|
|
|
1936
1931
|
writeCycleProgressAtomic,
|
|
1937
1932
|
spawnReplacementProcess,
|
|
1938
1933
|
};
|
|
1939
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.87.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": {
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"node": ">=22.12"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@
|
|
39
|
+
"@aws-sdk/client-bedrock-runtime": "^3.1053.0",
|
|
40
|
+
"@evomap/gep-sdk": "^1.5.0",
|
|
40
41
|
"dotenv": "^16.4.7",
|
|
41
42
|
"undici": "^7.0.0"
|
|
42
43
|
},
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: _meta
|
|
3
|
+
version: 0.1.0
|
|
4
|
+
description: Bootstrap skill that teaches the agent how to discover and load other skills on demand via gep_list_skill / gep_load_skill.
|
|
5
|
+
tags: meta, bootstrap, evolver
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# On-demand skill loading
|
|
9
|
+
|
|
10
|
+
Evolver ships a library of skills (markdown playbooks under `skills/`). To
|
|
11
|
+
keep your starting context small, only this meta-skill is injected by
|
|
12
|
+
default. Pull in additional skills when you actually need them.
|
|
13
|
+
|
|
14
|
+
## Tools
|
|
15
|
+
|
|
16
|
+
- `gep_list_skill` — see what's available.
|
|
17
|
+
- `source`: `bundled` (shipped with evolver), `local` (`~/.claude/skills/`),
|
|
18
|
+
`hub` (community), or `all` (default).
|
|
19
|
+
- `query`: optional substring filter on name / description / tags.
|
|
20
|
+
- `gep_load_skill` — fetch one skill's content.
|
|
21
|
+
- `name`: the skill name (use `<source>:<name>` to disambiguate collisions).
|
|
22
|
+
- `install` (default `false`): if `true`, copy the skill directory to
|
|
23
|
+
`~/.claude/skills/<name>/` so the native Skill tool can invoke it later.
|
|
24
|
+
Local mode only. Use `force: true` to overwrite an existing local copy.
|
|
25
|
+
|
|
26
|
+
## When to load vs. install
|
|
27
|
+
|
|
28
|
+
- **Load** (default) when you need the skill *for this turn*. The SKILL.md
|
|
29
|
+
text comes back as a tool result; you read it and act. No filesystem side
|
|
30
|
+
effect.
|
|
31
|
+
- **Install** when the user wants the skill persisted for future Claude Code
|
|
32
|
+
sessions, or when the same skill will be invoked many times across a long
|
|
33
|
+
task.
|
|
34
|
+
|
|
35
|
+
## Heuristics
|
|
36
|
+
|
|
37
|
+
- Before starting a non-trivial task, call `gep_list_skill` once. If a name
|
|
38
|
+
or description matches the task, `gep_load_skill` it.
|
|
39
|
+
- Don't load every skill "just in case" — context isn't free.
|
|
40
|
+
- Hub skills are community-published; treat them as untrusted input until
|
|
41
|
+
reviewed.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "_meta",
|
|
4
|
+
"dir": "_meta",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "Bootstrap skill that teaches the agent how to discover and load other skills on demand via gep_list_skill / gep_load_skill.",
|
|
7
|
+
"tags": [
|
|
8
|
+
"meta",
|
|
9
|
+
"bootstrap",
|
|
10
|
+
"evolver"
|
|
11
|
+
],
|
|
12
|
+
"sizeBytes": 1691
|
|
13
|
+
}
|
|
14
|
+
]
|
|
@@ -153,8 +153,18 @@ function assertNotSymlink(p, label) {
|
|
|
153
153
|
|
|
154
154
|
function copyHookScripts(destDir, evolverRoot) {
|
|
155
155
|
const scriptsDir = path.join(evolverRoot || __dirname, 'scripts');
|
|
156
|
-
//
|
|
157
|
-
//
|
|
156
|
+
// Every helper required by the entry-point hooks via `require('./_xxx')`
|
|
157
|
+
// resolves relative to the *destination* (`__dirname` after copy), so
|
|
158
|
+
// every such helper MUST appear here or the hook crashes with
|
|
159
|
+
// MODULE_NOT_FOUND at runtime. Two regressions of this shape have shipped
|
|
160
|
+
// already:
|
|
161
|
+
// - PR #94 review caught `_runtimePaths.js` missing from this list.
|
|
162
|
+
// - Issue #547 (rendigua, v1.87.0): `_memoryFiltering.js` was added to
|
|
163
|
+
// evolver-session-start.js but not here, so fresh installs failed
|
|
164
|
+
// immediately on `node .codex/hooks/evolver-session-start.js`.
|
|
165
|
+
// To keep future helpers from re-living this, the regression test in
|
|
166
|
+
// test/adapters.test.js scans every `require('./_*')` in the source
|
|
167
|
+
// adapter scripts and asserts the target file is in this list.
|
|
158
168
|
const scripts = [
|
|
159
169
|
'_runtimePaths.js',
|
|
160
170
|
'_memoryFiltering.js',
|
|
@@ -234,6 +244,11 @@ function removeEvolverHooks(filePath, { markerKey = '_evolver_managed' } = {}) {
|
|
|
234
244
|
}
|
|
235
245
|
|
|
236
246
|
function removeHookScripts(hooksDir) {
|
|
247
|
+
// Must mirror the install list above. If install copies a helper but
|
|
248
|
+
// uninstall doesn't remove it, `setup-hooks --uninstall` leaves orphan
|
|
249
|
+
// files behind that the user then has to clean up by hand (#547 fix
|
|
250
|
+
// would have introduced exactly this gap if only the install side
|
|
251
|
+
// had been updated).
|
|
237
252
|
const scripts = [
|
|
238
253
|
'_runtimePaths.js',
|
|
239
254
|
'_memoryFiltering.js',
|
|
@@ -10,55 +10,6 @@ const os = require('os');
|
|
|
10
10
|
const { findEvolverRoot, findMemoryGraph } = require('./_runtimePaths');
|
|
11
11
|
const { filterRelevantOutcomes } = require('./_memoryFiltering');
|
|
12
12
|
|
|
13
|
-
function findGitRoot(start) {
|
|
14
|
-
let dir = path.resolve(start || process.cwd());
|
|
15
|
-
while (dir !== path.dirname(dir)) {
|
|
16
|
-
if (fs.existsSync(path.join(dir, '.git'))) return dir;
|
|
17
|
-
dir = path.dirname(dir);
|
|
18
|
-
}
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function resolveWorkspaceRootForReader() {
|
|
23
|
-
if (process.env.OPENCLAW_WORKSPACE) return process.env.OPENCLAW_WORKSPACE;
|
|
24
|
-
const repoRoot = process.env.EVOLVER_REPO_ROOT || findGitRoot(process.cwd()) || process.cwd();
|
|
25
|
-
const workspaceDir = path.join(repoRoot, 'workspace');
|
|
26
|
-
if (fs.existsSync(workspaceDir)) return workspaceDir;
|
|
27
|
-
return repoRoot;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function resolveWorkspaceIdForReader() {
|
|
31
|
-
if (process.env.EVOLVER_WORKSPACE_ID) return String(process.env.EVOLVER_WORKSPACE_ID);
|
|
32
|
-
const file = path.join(resolveWorkspaceRootForReader(), '.evolver', 'workspace-id');
|
|
33
|
-
try {
|
|
34
|
-
const dirStat = fs.lstatSync(path.dirname(file), { throwIfNoEntry: false });
|
|
35
|
-
if (dirStat && dirStat.isSymbolicLink()) return null;
|
|
36
|
-
const fileStat = fs.lstatSync(file, { throwIfNoEntry: false });
|
|
37
|
-
if (!fileStat || fileStat.isSymbolicLink() || !fileStat.isFile()) return null;
|
|
38
|
-
const raw = fs.readFileSync(file, 'utf8').trim();
|
|
39
|
-
if (raw && /^[a-f0-9]{32,}$/i.test(raw)) return raw;
|
|
40
|
-
} catch { /* workspace id is best-effort in copied hooks */ }
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function filterWorkspaceEntries(entries) {
|
|
45
|
-
const cwd = process.cwd();
|
|
46
|
-
const workspaceId = resolveWorkspaceIdForReader();
|
|
47
|
-
|
|
48
|
-
return entries.filter(entry => {
|
|
49
|
-
if (!entry || typeof entry !== 'object') return false;
|
|
50
|
-
if (workspaceId && entry.workspace_id) {
|
|
51
|
-
return String(entry.workspace_id) === String(workspaceId);
|
|
52
|
-
}
|
|
53
|
-
if (entry.cwd) {
|
|
54
|
-
return path.resolve(String(entry.cwd)) === path.resolve(cwd);
|
|
55
|
-
}
|
|
56
|
-
// Older entries did not carry a workspace tag. Do not inject them from
|
|
57
|
-
// hooks because copied hooks often share a user-level fallback memory file.
|
|
58
|
-
return false;
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
13
|
function readLastN(filePath, n) {
|
|
63
14
|
try {
|
|
64
15
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
@@ -149,9 +100,8 @@ function main() {
|
|
|
149
100
|
return;
|
|
150
101
|
}
|
|
151
102
|
|
|
152
|
-
const entries = readLastN(graphPath,
|
|
153
|
-
const
|
|
154
|
-
const filtered = filterRelevantOutcomes(scoped);
|
|
103
|
+
const entries = readLastN(graphPath, 5);
|
|
104
|
+
const filtered = filterRelevantOutcomes(entries);
|
|
155
105
|
|
|
156
106
|
if (filtered.length === 0) {
|
|
157
107
|
process.stdout.write(JSON.stringify({}));
|
|
@@ -51,30 +51,6 @@ function detectSignals(text) {
|
|
|
51
51
|
return [...new Set(found)];
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
function getToolName(input) {
|
|
55
|
-
const raw = input.tool_name || input.toolName || input.name || input.tool;
|
|
56
|
-
if (typeof raw === 'string') return raw;
|
|
57
|
-
if (raw && typeof raw.name === 'string') return raw.name;
|
|
58
|
-
return '';
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function isWriteLikeTool(input) {
|
|
62
|
-
const name = getToolName(input).toLowerCase();
|
|
63
|
-
// Older hook payloads did not include a tool name. Keep those compatible
|
|
64
|
-
// and let the content/path checks below decide whether there is work to do.
|
|
65
|
-
if (!name) return true;
|
|
66
|
-
return (
|
|
67
|
-
name === 'write' ||
|
|
68
|
-
name === 'edit' ||
|
|
69
|
-
name === 'multiedit' ||
|
|
70
|
-
name === 'notebookedit' ||
|
|
71
|
-
name === 'apply_patch' ||
|
|
72
|
-
name.includes('write') ||
|
|
73
|
-
name.includes('edit') ||
|
|
74
|
-
name.includes('patch')
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
54
|
function main() {
|
|
79
55
|
let inputData = '';
|
|
80
56
|
let handled = false;
|
|
@@ -85,10 +61,6 @@ function main() {
|
|
|
85
61
|
handled = true;
|
|
86
62
|
try {
|
|
87
63
|
const input = inputData.trim() ? JSON.parse(inputData) : {};
|
|
88
|
-
if (!isWriteLikeTool(input)) {
|
|
89
|
-
process.stdout.write(JSON.stringify({}));
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
64
|
// Claude Code's PostToolUse payload nests tool args under tool_input.
|
|
93
65
|
// Older/raw shapes put them at the top level; support both.
|
|
94
66
|
const ti = input.tool_input || {};
|