@evomap/evolver 1.87.0 → 1.87.2

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 (55) hide show
  1. package/assets/gep/candidates.jsonl +1 -0
  2. package/assets/gep/capsules.json +4 -0
  3. package/assets/gep/events.jsonl +0 -0
  4. package/assets/gep/failed_capsules.json +4 -0
  5. package/assets/gep/genes.json +245 -0
  6. package/assets/gep/genes.jsonl +0 -0
  7. package/index.js +33 -14
  8. package/package.json +1 -1
  9. package/src/adapters/hookAdapter.js +19 -4
  10. package/src/atp/autoBuyer.js +90 -11
  11. package/src/atp/cli.js +98 -0
  12. package/src/atp/cliAutobuyPrompt.js +59 -52
  13. package/src/evolve/guards.js +1 -1
  14. package/src/evolve/pipeline/collect.js +1 -1
  15. package/src/evolve/pipeline/dispatch.js +1 -1
  16. package/src/evolve/pipeline/enrich.js +1 -1
  17. package/src/evolve/pipeline/hub.js +1 -1
  18. package/src/evolve/pipeline/select.js +1 -1
  19. package/src/evolve/pipeline/signals.js +1 -1
  20. package/src/evolve/utils.js +1 -1
  21. package/src/evolve.js +1 -1
  22. package/src/forceUpdate.js +2 -1
  23. package/src/gep/a2aProtocol.js +1 -1
  24. package/src/gep/candidateEval.js +1 -1
  25. package/src/gep/candidates.js +1 -1
  26. package/src/gep/contentHash.js +1 -1
  27. package/src/gep/crypto.js +1 -1
  28. package/src/gep/curriculum.js +1 -1
  29. package/src/gep/deviceId.js +1 -1
  30. package/src/gep/envFingerprint.js +1 -1
  31. package/src/gep/epigenetics.js +1 -1
  32. package/src/gep/explore.js +1 -1
  33. package/src/gep/hash.js +1 -1
  34. package/src/gep/hubFetch.js +1 -1
  35. package/src/gep/hubReview.js +1 -1
  36. package/src/gep/hubSearch.js +1 -1
  37. package/src/gep/hubVerify.js +1 -1
  38. package/src/gep/learningSignals.js +1 -1
  39. package/src/gep/memoryGraph.js +1 -1
  40. package/src/gep/memoryGraphAdapter.js +1 -1
  41. package/src/gep/mutation.js +1 -1
  42. package/src/gep/narrativeMemory.js +1 -1
  43. package/src/gep/openPRRegistry.js +1 -1
  44. package/src/gep/personality.js +1 -1
  45. package/src/gep/policyCheck.js +1 -1
  46. package/src/gep/prompt.js +1 -1
  47. package/src/gep/recallVerifier.js +1 -1
  48. package/src/gep/reflection.js +1 -1
  49. package/src/gep/selector.js +1 -1
  50. package/src/gep/skillDistiller.js +1 -1
  51. package/src/gep/solidify.js +1 -1
  52. package/src/gep/strategy.js +1 -1
  53. package/src/gep/workspaceKeychain.js +1 -1
  54. package/src/proxy/index.js +29 -9
  55. package/src/proxy/router/messages_route.js +80 -5
package/src/atp/cli.js CHANGED
@@ -118,6 +118,27 @@ function parseVerifyArgs(args) {
118
118
  return { ok: true, opts: { orderId, action } };
119
119
  }
120
120
 
121
+ // `evolver atp <enable|disable|status>` — manage autoBuyer consent ack file.
122
+ // Non-TTY users (daemon, CI, hooks) opt in here instead of the interactive
123
+ // first-run prompt. Returns { ok, opts: { sub } } or { ok: false, error }.
124
+ function parseAtpArgs(args) {
125
+ if (!Array.isArray(args) || args.length === 0) {
126
+ return { ok: false, error: 'atp requires <enable|disable|status>' };
127
+ }
128
+ let sub = null;
129
+ for (let i = 0; i < args.length; i++) {
130
+ const a = args[i];
131
+ if (typeof a === 'string' && !a.startsWith('--')) {
132
+ sub = a.toLowerCase();
133
+ break;
134
+ }
135
+ }
136
+ if (!sub || !['enable', 'disable', 'status'].includes(sub)) {
137
+ return { ok: false, error: 'atp subcommand must be enable|disable|status (got: ' + sub + ')' };
138
+ }
139
+ return { ok: true, opts: { sub } };
140
+ }
141
+
121
142
  async function runBuy(opts, deps) {
122
143
  const atp = (deps && deps.atp) || require('./index');
123
144
  const consumerAgent = atp.consumerAgent;
@@ -226,6 +247,80 @@ async function runVerify(opts, deps) {
226
247
  }
227
248
  }
228
249
 
250
+ // Subcommand runner for `evolver atp enable|disable|status`. Writes the ack
251
+ // file via autoBuyer.setConsent so subsequent daemon starts pick it up. Does
252
+ // NOT mutate process.env — env override wins over the ack file by design,
253
+ // and we don't want a transient CLI invocation to silently shadow operator
254
+ // shell config.
255
+ // Detect whether an EVOLVER_ATP_AUTOBUY env override is currently set AND
256
+ // would supersede the ack we are about to write. Returns the effective env
257
+ // boolean (true=on, false=off) or null if env is unset / whitespace-only.
258
+ // Mirrors the trim-before-length-check rule from autoBuyer.getConsent so
259
+ // the CLI and the runtime agree on what "set" means (Bugbot PR #141).
260
+ function _envOverride() {
261
+ const raw = process.env.EVOLVER_ATP_AUTOBUY;
262
+ if (typeof raw !== 'string') return null;
263
+ const s = raw.trim().toLowerCase();
264
+ if (s.length === 0) return null;
265
+ return !(s === 'off' || s === '0' || s === 'false');
266
+ }
267
+
268
+ async function runAtp(opts, deps) {
269
+ const autoBuyer = (deps && deps.autoBuyer) || require('./autoBuyer');
270
+ const log = (deps && deps.log) || console.log;
271
+ const err = (deps && deps.err) || console.error;
272
+
273
+ try {
274
+ if (opts.sub === 'enable') {
275
+ const body = autoBuyer.setConsent(true);
276
+ log('[ATP] auto-spend ENABLED (consent recorded ' + body.acknowledged_at + ').');
277
+ log(' Caps: daily=' + (process.env.ATP_AUTOBUY_DAILY_CAP_CREDITS || '50') +
278
+ ', per-order=' + (process.env.ATP_AUTOBUY_PER_ORDER_CAP_CREDITS || '10') + ' credits.');
279
+ log(' Disable: evolver atp disable (or EVOLVER_ATP_AUTOBUY=off)');
280
+ // Loud warning if an env override will silently undo the ack at
281
+ // runtime. Bugbot PR #141 Medium: without this the user gets a
282
+ // false confirmation and real credits keep flowing the wrong way.
283
+ const envEnabled = _envOverride();
284
+ if (envEnabled === false) {
285
+ log('');
286
+ log('[ATP] WARNING: EVOLVER_ATP_AUTOBUY=' + process.env.EVOLVER_ATP_AUTOBUY +
287
+ ' is set in your environment and will OVERRIDE the ack file at runtime.');
288
+ log(' Auto-spend will stay OFF until you unset it (env wins over the ack file).');
289
+ return { exitCode: 0, data: body, envOverride: 'off' };
290
+ }
291
+ return { exitCode: 0, data: body };
292
+ }
293
+ if (opts.sub === 'disable') {
294
+ const body = autoBuyer.setConsent(false);
295
+ log('[ATP] auto-spend DISABLED (consent recorded ' + body.acknowledged_at + ').');
296
+ log(' Re-enable: evolver atp enable');
297
+ const envEnabled = _envOverride();
298
+ if (envEnabled === true) {
299
+ log('');
300
+ log('[ATP] WARNING: EVOLVER_ATP_AUTOBUY=' + process.env.EVOLVER_ATP_AUTOBUY +
301
+ ' is set in your environment and will OVERRIDE the ack file at runtime.');
302
+ log(' Auto-spend will stay ON (and continue charging credits) until you unset it.');
303
+ return { exitCode: 0, data: body, envOverride: 'on' };
304
+ }
305
+ return { exitCode: 0, data: body };
306
+ }
307
+ // status
308
+ const consent = autoBuyer.getConsent();
309
+ const ackPath = autoBuyer.getAckPath();
310
+ log('[ATP] auto-spend: ' + (consent.enabled ? 'ENABLED' : 'DISABLED') +
311
+ ' (source: ' + consent.source + ')');
312
+ log(' ack file: ' + ackPath);
313
+ if (consent.source === 'default') {
314
+ log(' Default policy (no ack file, no env override). Run `evolver atp disable`');
315
+ log(' to opt out, or `evolver atp enable` to record explicit opt-in.');
316
+ }
317
+ return { exitCode: 0, data: consent };
318
+ } catch (e) {
319
+ err('[ATP] atp command error: ' + (e && e.message || e));
320
+ return { exitCode: 1, error: String(e) };
321
+ }
322
+ }
323
+
229
324
  function printUsage() {
230
325
  return [
231
326
  'ATP subcommands:',
@@ -234,6 +329,7 @@ function printUsage() {
234
329
  ' evolver orders [--role=consumer|merchant] [--status=pending|verified|disputed|settled]',
235
330
  ' [--limit=N] [--json]',
236
331
  ' evolver verify <orderId> [--action=confirm|ai_judge]',
332
+ ' evolver atp <enable|disable|status> -- manage auto-spend consent',
237
333
  ].join('\n');
238
334
  }
239
335
 
@@ -241,8 +337,10 @@ module.exports = {
241
337
  parseBuyArgs,
242
338
  parseOrdersArgs,
243
339
  parseVerifyArgs,
340
+ parseAtpArgs,
244
341
  runBuy,
245
342
  runOrders,
246
343
  runVerify,
344
+ runAtp,
247
345
  printUsage,
248
346
  };
@@ -9,55 +9,34 @@
9
9
  * - ack file memory/atp-autobuy-ack.json does not exist (already decided)
10
10
  *
11
11
  * Outcomes:
12
- * - user answers y -> enabled=true written, session opts in immediately
13
- * - user answers n -> enabled=false written, prompt never shown again
14
- * - user answers later -> no file written, prompt shown next time
12
+ * - user answers y -> autoBuyer.setConsent(true) opts in for future sessions
13
+ * - user answers n -> autoBuyer.setConsent(false) prompt never shown again
14
+ * - user answers later -> no ack written, prompt shown next session
15
15
  * - any non-TTY/ack branch -> silent no-op
16
+ *
17
+ * setConsent failures (FS permission, disk full) are surfaced to the user
18
+ * via the output stream and returned as `reason: 'ack_write_failed'`; the
19
+ * decision field still reflects what the user typed.
16
20
  */
17
21
 
18
- const fs = require("fs");
19
- const path = require("path");
20
22
  const readline = require("readline");
23
+ const autoBuyer = require("./autoBuyer");
21
24
 
22
- const ACK_FILE_NAME = "atp-autobuy-ack.json";
23
-
24
- function _getMemoryDir() {
25
- try {
26
- return require("../gep/paths").getMemoryDir();
27
- } catch (_) {
28
- return process.env.MEMORY_DIR || path.join(process.cwd(), "memory");
29
- }
30
- }
25
+ // All ack file plumbing is owned by autoBuyer: filename constant, path
26
+ // resolution, read (strict validation), and write (atomic tmp+rename).
27
+ // cliAutobuyPrompt delegates through the public API (not __internals) so
28
+ // the two modules cannot diverge on schema or validation — pre-
29
+ // consolidation drift bit us twice (Bugbot PR #141: duplicate writers +
30
+ // lenient-vs-strict reader). Using public exports keeps the "test-only"
31
+ // contract on __internals honest (Bugbot PR #141 R6).
32
+ const ACK_FILE_NAME = autoBuyer.ACK_FILENAME;
31
33
 
32
34
  function _getAckPath() {
33
- return path.join(_getMemoryDir(), ACK_FILE_NAME);
35
+ return autoBuyer.getAckPath();
34
36
  }
35
37
 
36
38
  function _readAck() {
37
- try {
38
- const raw = fs.readFileSync(_getAckPath(), "utf8");
39
- const parsed = JSON.parse(raw);
40
- if (!parsed || typeof parsed !== "object") return null;
41
- return parsed;
42
- } catch (_) {
43
- return null;
44
- }
45
- }
46
-
47
- function _writeAck(enabled) {
48
- const p = _getAckPath();
49
- try {
50
- fs.mkdirSync(path.dirname(p), { recursive: true });
51
- const body = {
52
- enabled: !!enabled,
53
- acknowledged_at: new Date().toISOString(),
54
- version: 1,
55
- };
56
- fs.writeFileSync(p, JSON.stringify(body, null, 2) + "\n", "utf8");
57
- return true;
58
- } catch (_) {
59
- return false;
60
- }
39
+ return autoBuyer.readAck();
61
40
  }
62
41
 
63
42
  /**
@@ -116,11 +95,12 @@ async function runPrompt(opts) {
116
95
 
117
96
  try {
118
97
  output.write("\n");
119
- output.write("[ATP-AutoBuyer] Your evolver can automatically place small-priced\n");
120
- output.write("ATP orders when it detects a capability gap (default ON).\n");
121
- output.write(" - daily hard cap: ATP_AUTOBUY_DAILY_CAP_CREDITS (default applies)\n");
122
- output.write(" - per-order cap: ATP_AUTOBUY_PER_ORDER_CAP_CREDITS\n");
123
- output.write(" - set EVOLVER_ATP_AUTOBUY=off and restart to disable at any time.\n");
98
+ output.write("[ATP-AutoBuyer] Your evolver will automatically place small-priced\n");
99
+ output.write("ATP orders when it detects a capability gap. This spends real\n");
100
+ output.write("credits on the EvoMap hub and is ON by default for new installs.\n");
101
+ output.write(" - daily hard cap: ATP_AUTOBUY_DAILY_CAP_CREDITS (default 50)\n");
102
+ output.write(" - per-order cap: ATP_AUTOBUY_PER_ORDER_CAP_CREDITS (default 10)\n");
103
+ output.write(" - change later: evolver atp enable | evolver atp disable\n");
124
104
  output.write("\n");
125
105
  } catch (_) {
126
106
  return { prompted: false, decision: null, reason: "io_error" };
@@ -128,7 +108,7 @@ async function runPrompt(opts) {
128
108
 
129
109
  let answer;
130
110
  try {
131
- answer = await ask("Keep autoBuyer enabled for this session? [y/n/later] ", {
111
+ answer = await ask("Keep ATP auto-spend ON for future sessions? [y=keep enabled / n=disable / later=ask again next session] ", {
132
112
  input,
133
113
  output,
134
114
  });
@@ -136,16 +116,44 @@ async function runPrompt(opts) {
136
116
  return { prompted: true, decision: null, reason: "ask_error" };
137
117
  }
138
118
 
119
+ // For y/n we persist via autoBuyer.setConsent (atomic tmp+rename, throws
120
+ // on FS failure). If the write fails we MUST tell the user — for the 'n'
121
+ // path especially, since auto-spend is default-ON and a failed disable
122
+ // means the user typed "off" but the runtime keeps charging credits
123
+ // (Bugbot PR #141 Medium: unchecked ack write). Do NOT mutate process.env
124
+ // on success: that would double-signal and shadow any explicit operator
125
+ // preference set later.
126
+ function _persistConsent(enabled, decision) {
127
+ try {
128
+ autoBuyer.setConsent(enabled);
129
+ return { prompted: true, decision, reason: enabled ? "user_accepted" : "user_declined" };
130
+ } catch (err) {
131
+ try {
132
+ output.write("[ATP-AutoBuyer] WARN: failed to persist consent: " + (err && err.message || err) + "\n");
133
+ if (enabled) {
134
+ output.write(" Auto-spend will keep using the default-on policy until\n");
135
+ output.write(" the ack is saved (capped at the configured caps).\n");
136
+ } else {
137
+ output.write(" Auto-spend will STAY ON (default policy) until your opt-out\n");
138
+ output.write(" can be saved — your decline was not persisted.\n");
139
+ }
140
+ output.write(" Check disk space and write permissions on the memory dir, then run\n");
141
+ output.write(" `evolver atp " + (enabled ? "enable" : "disable") + "` to retry.\n");
142
+ } catch (_) { /* output stream is broken too — nothing more we can do */ }
143
+ return { prompted: true, decision, reason: "ack_write_failed" };
144
+ }
145
+ }
146
+
139
147
  if (answer === "y" || answer === "yes") {
140
- _writeAck(true);
141
- env.EVOLVER_ATP_AUTOBUY = "on";
142
- return { prompted: true, decision: "yes", reason: "user_accepted" };
148
+ return _persistConsent(true, "yes");
143
149
  }
144
150
  if (answer === "n" || answer === "no") {
145
- _writeAck(false);
146
- env.EVOLVER_ATP_AUTOBUY = "off";
147
- return { prompted: true, decision: "no", reason: "user_declined" };
151
+ return _persistConsent(false, "no");
148
152
  }
153
+ // Postpone: no ack written, so autoBuyer.getConsent() returns
154
+ // {enabled: true, source: 'default'} this session. Auto-spend keeps
155
+ // running under the default policy with caps; the prompt will fire again
156
+ // next interactive session so the user can confirm or opt out.
149
157
  return { prompted: true, decision: "later", reason: "user_postponed" };
150
158
  }
151
159
 
@@ -155,7 +163,6 @@ module.exports = {
155
163
  __internals: {
156
164
  ACK_FILE_NAME,
157
165
  _readAck,
158
- _writeAck,
159
166
  _getAckPath,
160
167
  },
161
168
  };