@evomap/evolver 1.89.2 → 1.89.4
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/.cursor/BUGBOT.md +182 -0
- package/.env.example +68 -0
- package/.git-commit-guard-token +1 -0
- package/.github/CODEOWNERS +63 -0
- package/.github/ISSUE_TEMPLATE/good_first_issue.md +23 -0
- package/.github/pull_request_template.md +45 -0
- package/.github/workflows/test.yml +75 -0
- package/CHANGELOG.md +1237 -0
- package/README.ja-JP.md +1 -3
- package/README.ko-KR.md +1 -3
- package/README.md +86 -530
- package/README.public.md +569 -0
- package/README.zh-CN.md +1 -3
- package/SECURITY.md +108 -0
- package/assets/gep/events.jsonl +3 -0
- package/assets/gep/genes.json +496 -0
- package/examples/atp-consumer-quickstart.md +100 -0
- package/examples/hello-world.md +38 -0
- package/index.js +44 -48
- package/package.json +6 -17
- package/proxy-package.json +39 -0
- package/public.manifest.json +143 -0
- package/src/adapters/hookAdapter.js +2 -0
- package/src/adapters/scripts/_lockPaths.js +74 -0
- package/src/adapters/scripts/evolver-session-start.js +19 -27
- package/src/config.js +23 -0
- package/src/evolve/guards.js +721 -1
- package/src/evolve/pipeline/collect.js +1283 -1
- package/src/evolve/pipeline/dispatch.js +421 -1
- package/src/evolve/pipeline/enrich.js +440 -1
- package/src/evolve/pipeline/hub.js +319 -1
- package/src/evolve/pipeline/select.js +274 -1
- package/src/evolve/pipeline/signals.js +206 -1
- package/src/evolve/utils.js +264 -1
- package/src/evolve.js +350 -1
- package/src/experiment/agentRunner.js +229 -0
- package/src/experiment/cli.js +159 -0
- package/src/experiment/comparison.js +233 -0
- package/src/experiment/metrics.js +75 -0
- package/src/forceUpdate.js +311 -30
- package/src/gep/a2aProtocol.js +4455 -1
- package/src/gep/antiAbuseTelemetry.js +233 -0
- package/src/gep/autoDistillConv.js +205 -1
- package/src/gep/autoDistillLlm.js +315 -1
- package/src/gep/candidateEval.js +92 -1
- package/src/gep/candidates.js +198 -1
- package/src/gep/contentHash.js +30 -1
- package/src/gep/conversationSniffer.js +266 -1
- package/src/gep/crypto.js +89 -1
- package/src/gep/curriculum.js +163 -1
- package/src/gep/deviceId.js +218 -1
- package/src/gep/envFingerprint.js +118 -1
- package/src/gep/epigenetics.js +31 -1
- package/src/gep/execBridge.js +711 -1
- package/src/gep/explore.js +289 -1
- package/src/gep/hash.js +15 -1
- package/src/gep/hubFetch.js +359 -1
- package/src/gep/hubReview.js +207 -1
- package/src/gep/hubSearch.js +526 -1
- package/src/gep/hubVerify.js +306 -1
- package/src/gep/learningSignals.js +89 -1
- package/src/gep/memoryGraph.js +1374 -1
- package/src/gep/memoryGraphAdapter.js +203 -1
- package/src/gep/mutation.js +203 -1
- package/src/gep/narrativeMemory.js +108 -1
- package/src/gep/openPRRegistry.js +205 -1
- package/src/gep/personality.js +423 -1
- package/src/gep/policyCheck.js +599 -1
- package/src/gep/prompt.js +836 -1
- package/src/gep/recallInject.js +409 -1
- package/src/gep/recallVerifier.js +318 -1
- package/src/gep/reflection.js +177 -1
- package/src/gep/sanitize.js +9 -0
- package/src/gep/selector.js +602 -1
- package/src/gep/skillDistiller.js +1294 -1
- package/src/gep/solidify.js +1699 -1
- package/src/gep/strategy.js +136 -1
- package/src/gep/tokenSavings.js +88 -1
- package/src/gep/validator/sandboxExecutor.js +29 -1
- package/src/gep/workspaceKeychain.js +174 -1
- package/src/proxy/extensions/traceControl.js +99 -1
- package/src/proxy/index.js +14 -5
- package/src/proxy/inject.js +52 -1
- package/src/proxy/lifecycle/manager.js +30 -0
- package/src/proxy/mailbox/store.js +2 -1
- package/src/proxy/router/messages_route.js +13 -2
- package/src/proxy/trace/extractor.js +646 -1
- package/src/proxy/trace/usage.js +105 -1
- package/CONTRIBUTING.md +0 -19
- package/assets/cover.png +0 -0
- package/assets/gep/genes.seed.json +0 -245
- package/scripts/a2a_export.js +0 -63
- package/scripts/a2a_ingest.js +0 -79
- package/scripts/a2a_promote.js +0 -118
- package/scripts/analyze_by_skill.js +0 -121
- package/scripts/build_binaries.js +0 -479
- package/scripts/check-changelog.js +0 -166
- package/scripts/extract_log.js +0 -85
- package/scripts/generate_history.js +0 -75
- package/scripts/gep_append_event.js +0 -96
- package/scripts/gep_personality_report.js +0 -234
- package/scripts/human_report.js +0 -147
- package/scripts/recall-verify-report.js +0 -234
- package/scripts/recover_loop.js +0 -61
- package/scripts/seed-merchants.js +0 -91
- package/scripts/suggest_version.js +0 -89
- package/scripts/validate-modules.js +0 -38
- package/scripts/validate-suite.js +0 -78
- package/skills/index.json +0 -14
- /package/{skills → bundled-skills}/_meta/SKILL.md +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const { captureEnvFingerprint, envFingerprintKey } = require('./envFingerprint');
|
|
9
|
+
|
|
10
|
+
const SCHEMA_VERSION = 'anti_abuse.v1';
|
|
11
|
+
const REDACTION_VERSION = 'anti_abuse_redaction.v1';
|
|
12
|
+
const DEFAULT_TTL_DAYS = 90;
|
|
13
|
+
const MAX_HASH_FILE_BYTES = 10 * 1024 * 1024;
|
|
14
|
+
|
|
15
|
+
function nowIso(now) {
|
|
16
|
+
if (now instanceof Date) return now.toISOString();
|
|
17
|
+
if (typeof now === 'string' && now) return now;
|
|
18
|
+
return new Date().toISOString();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function boolFromEnv(value) {
|
|
22
|
+
const v = String(value || '').trim().toLowerCase();
|
|
23
|
+
return v === '1' || v === 'true' || v === 'yes' || v === 'on';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function hmacPseudonym(value, opts) {
|
|
27
|
+
const raw = value == null ? '' : String(value);
|
|
28
|
+
const salt = opts && opts.salt ? String(opts.salt) : '';
|
|
29
|
+
const purpose = opts && opts.purpose ? String(opts.purpose) : 'anti_abuse';
|
|
30
|
+
if (!raw || !salt) return null;
|
|
31
|
+
return crypto.createHmac('sha256', salt).update(purpose).update('\0').update(raw).digest('hex').slice(0, 32);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function sha256File(filePath) {
|
|
35
|
+
let stat;
|
|
36
|
+
try {
|
|
37
|
+
stat = fs.statSync(filePath);
|
|
38
|
+
} catch (_) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (!stat.isFile() || stat.size > MAX_HASH_FILE_BYTES) return null;
|
|
42
|
+
const hash = crypto.createHash('sha256');
|
|
43
|
+
hash.update(fs.readFileSync(filePath));
|
|
44
|
+
return hash.digest('hex');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function safeJsonFile(filePath) {
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
50
|
+
} catch (_) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function filePermissionClass(filePath) {
|
|
56
|
+
let stat;
|
|
57
|
+
try {
|
|
58
|
+
stat = fs.statSync(filePath);
|
|
59
|
+
} catch (_) {
|
|
60
|
+
return 'missing';
|
|
61
|
+
}
|
|
62
|
+
if (!stat.isFile()) return 'not_file';
|
|
63
|
+
const mode = stat.mode & 0o777;
|
|
64
|
+
if ((mode & 0o077) === 0) return 'owner_only';
|
|
65
|
+
if ((mode & 0o007) !== 0) return 'world_accessible';
|
|
66
|
+
return 'group_accessible';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// The integrity envelope fingerprints the INSTALLED @evomap/evolver package
|
|
70
|
+
// — its package.json, CLI entry, and lockfiles — not the user's project.
|
|
71
|
+
// __dirname tracks this file inside the install (<pkg>/src/gep/), so two
|
|
72
|
+
// levels up is the package root in every install mode (dev clone, npm
|
|
73
|
+
// global, npx cache). Hashing getRepoRoot() (the user's project) here would
|
|
74
|
+
// make hub-side integrity checks compare workspace files against
|
|
75
|
+
// evolver_version, mismatching on every npm/global install.
|
|
76
|
+
function getEvolverPackageRoot() {
|
|
77
|
+
return path.resolve(__dirname, '..', '..');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Containment gate for EVERY file the integrity envelope reads: resolve the
|
|
81
|
+
// candidate through symlinks and require it to stay inside the package root.
|
|
82
|
+
// Default-on heartbeat collection must not grow an out-of-tree file-read
|
|
83
|
+
// side effect — not via a tampered bin.evolver, and not via a symlinked
|
|
84
|
+
// package.json / lockfile either (each read is up to MAX_HASH_FILE_BYTES).
|
|
85
|
+
// Returns the real path when contained, else null (missing files land here
|
|
86
|
+
// too, matching sha256File's old null-on-ENOENT behavior).
|
|
87
|
+
function containedRealPath(root, candidate) {
|
|
88
|
+
try {
|
|
89
|
+
const realRoot = fs.realpathSync(root);
|
|
90
|
+
const real = fs.realpathSync(candidate);
|
|
91
|
+
return real.startsWith(realRoot + path.sep) ? real : null;
|
|
92
|
+
} catch (_) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function collectIntegrityHashes(packageRoot) {
|
|
98
|
+
const root = packageRoot || getEvolverPackageRoot();
|
|
99
|
+
const pkgPath = containedRealPath(root, path.join(root, 'package.json'));
|
|
100
|
+
const pkg = (pkgPath && safeJsonFile(pkgPath)) || {};
|
|
101
|
+
const bin = pkg && pkg.bin && typeof pkg.bin.evolver === 'string' ? pkg.bin.evolver : null;
|
|
102
|
+
const binPath = bin ? containedRealPath(root, path.resolve(root, bin)) : null;
|
|
103
|
+
const lockfiles = ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'bun.lockb'];
|
|
104
|
+
const lockfile_hashes = {};
|
|
105
|
+
for (const name of lockfiles) {
|
|
106
|
+
const p = containedRealPath(root, path.join(root, name));
|
|
107
|
+
const digest = p ? sha256File(p) : null;
|
|
108
|
+
if (digest) lockfile_hashes[name] = digest;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
package_json_hash: pkgPath ? sha256File(pkgPath) : null,
|
|
112
|
+
cli_entry_hash: binPath ? sha256File(binPath) : null,
|
|
113
|
+
lockfile_hashes,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function settingsPermissionClass(env) {
|
|
118
|
+
const e = env || process.env;
|
|
119
|
+
const settingsDir = e.EVOLVER_SETTINGS_DIR || path.join(os.homedir(), '.evolver');
|
|
120
|
+
return filePermissionClass(path.join(settingsDir, 'settings.json'));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function normalizeTaskMetrics(taskMeta) {
|
|
124
|
+
const meta = taskMeta && typeof taskMeta === 'object' ? taskMeta : {};
|
|
125
|
+
const metrics = meta.task_metrics && typeof meta.task_metrics === 'object' ? meta.task_metrics : null;
|
|
126
|
+
if (!metrics) return null;
|
|
127
|
+
return {
|
|
128
|
+
pending: Number.isFinite(Number(metrics.pending)) ? Number(metrics.pending) : null,
|
|
129
|
+
claimed: Number.isFinite(Number(metrics.claimed)) ? Number(metrics.claimed) : null,
|
|
130
|
+
completed: Number.isFinite(Number(metrics.completed)) ? Number(metrics.completed) : null,
|
|
131
|
+
failed: Number.isFinite(Number(metrics.failed)) ? Number(metrics.failed) : null,
|
|
132
|
+
avg_completion_ms: Number.isFinite(Number(metrics.avg_completion_ms)) ? Number(metrics.avg_completion_ms) : null,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function ttlDays(env) {
|
|
137
|
+
const raw = Number(env && env.EVOLVER_ANTI_ABUSE_TTL_DAYS);
|
|
138
|
+
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : DEFAULT_TTL_DAYS;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function unavailable(field, reason, expectedSource) {
|
|
142
|
+
return {
|
|
143
|
+
field,
|
|
144
|
+
reason,
|
|
145
|
+
expected_source: expectedSource || 'hub_server',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function buildHeartbeatAntiAbuseTelemetry(opts) {
|
|
150
|
+
const options = opts || {};
|
|
151
|
+
const env = options.env || process.env;
|
|
152
|
+
const fp = options.envFingerprint || captureEnvFingerprint();
|
|
153
|
+
const salt = options.salt != null ? options.salt : env.EVOLVER_ANTI_ABUSE_SALT;
|
|
154
|
+
const saltId = options.saltId || env.EVOLVER_ANTI_ABUSE_SALT_ID || (salt ? 'env' : null);
|
|
155
|
+
const packageRoot = options.packageRoot || getEvolverPackageRoot();
|
|
156
|
+
const devicePseudonym = hmacPseudonym(fp && fp.device_id, { salt, purpose: 'device' });
|
|
157
|
+
const workspacePseudonym = hmacPseudonym(process.cwd(), { salt, purpose: 'workspace' });
|
|
158
|
+
const missing = [];
|
|
159
|
+
if (!devicePseudonym) missing.push(unavailable('device_pseudonym', 'anti_abuse_salt_missing', 'signed_policy_or_env'));
|
|
160
|
+
if (!workspacePseudonym) missing.push(unavailable('workspace_pseudonym', 'anti_abuse_salt_missing', 'signed_policy_or_env'));
|
|
161
|
+
missing.push(
|
|
162
|
+
unavailable('client_ip', 'server_observed_required', 'hub_edge'),
|
|
163
|
+
unavailable('asn', 'server_observed_required', 'hub_edge'),
|
|
164
|
+
unavailable('proxy_vpn_tor_datacenter_class', 'server_observed_required', 'hub_edge'),
|
|
165
|
+
unavailable('account_security', 'account_service_required', 'hub_account'),
|
|
166
|
+
unavailable('payout_method_token', 'payments_service_required', 'hub_payments'),
|
|
167
|
+
unavailable('risk_action_case', 'risk_engine_required', 'hub_risk')
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
schema_version: SCHEMA_VERSION,
|
|
172
|
+
event_type: 'node.heartbeat',
|
|
173
|
+
purpose: 'anti_abuse',
|
|
174
|
+
pii_class: 'medium',
|
|
175
|
+
consent_level: 'default',
|
|
176
|
+
retention_ttl_days: ttlDays(env),
|
|
177
|
+
policy_version: env.EVOLVER_ANTI_ABUSE_POLICY_VERSION || 'local-default',
|
|
178
|
+
redaction_version: REDACTION_VERSION,
|
|
179
|
+
source: options.source || 'evolver-client',
|
|
180
|
+
generated_at: nowIso(options.now),
|
|
181
|
+
source_confidence: {
|
|
182
|
+
node_identity: 'client_attested',
|
|
183
|
+
device_integrity: 'client_attested',
|
|
184
|
+
task_metrics: 'client_attested',
|
|
185
|
+
network_source: 'server_observed_required',
|
|
186
|
+
account_security: 'server_observed_required',
|
|
187
|
+
payout: 'server_observed_required',
|
|
188
|
+
risk_decision: 'server_observed_required',
|
|
189
|
+
},
|
|
190
|
+
identity: {
|
|
191
|
+
node_id: options.nodeId || null,
|
|
192
|
+
account_id: null,
|
|
193
|
+
org_id: null,
|
|
194
|
+
},
|
|
195
|
+
device: {
|
|
196
|
+
device_pseudonym: devicePseudonym,
|
|
197
|
+
workspace_pseudonym: workspacePseudonym,
|
|
198
|
+
pseudonym_salt_id: saltId,
|
|
199
|
+
env_fingerprint_key: envFingerprintKey(fp),
|
|
200
|
+
platform: fp.platform || null,
|
|
201
|
+
arch: fp.arch || null,
|
|
202
|
+
os_release: fp.os_release || null,
|
|
203
|
+
node_version: fp.node_version || null,
|
|
204
|
+
evolver_version: fp.evolver_version || null,
|
|
205
|
+
client: fp.client || null,
|
|
206
|
+
client_version: fp.client_version || null,
|
|
207
|
+
model: fp.model || null,
|
|
208
|
+
region: fp.region || null,
|
|
209
|
+
container: !!fp.container,
|
|
210
|
+
},
|
|
211
|
+
integrity: collectIntegrityHashes(packageRoot),
|
|
212
|
+
local_security_boundary: {
|
|
213
|
+
proxy_bind_address_class: 'loopback',
|
|
214
|
+
// Env sniffing is only a fallback for the client heartbeat: the proxy
|
|
215
|
+
// lifecycle heartbeat runs INSIDE the proxy process (which usually has
|
|
216
|
+
// neither env var set) and passes its ground truth explicitly.
|
|
217
|
+
proxy_port_configured: options.proxyPortConfigured != null
|
|
218
|
+
? !!options.proxyPortConfigured
|
|
219
|
+
: (boolFromEnv(env.EVOMAP_PROXY) || !!env.EVOMAP_PROXY_PORT),
|
|
220
|
+
settings_permission_class: settingsPermissionClass(env),
|
|
221
|
+
},
|
|
222
|
+
task_timing: normalizeTaskMetrics(options.taskMeta),
|
|
223
|
+
unavailable_fields: missing,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = {
|
|
228
|
+
SCHEMA_VERSION,
|
|
229
|
+
REDACTION_VERSION,
|
|
230
|
+
buildHeartbeatAntiAbuseTelemetry,
|
|
231
|
+
collectIntegrityHashes,
|
|
232
|
+
hmacPseudonym,
|
|
233
|
+
};
|