@evomap/evolver 1.89.11 → 1.89.12

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 (100) hide show
  1. package/.cursor/BUGBOT.md +182 -0
  2. package/.env.example +68 -0
  3. package/.git-commit-guard-token +1 -0
  4. package/.github/CODEOWNERS +63 -0
  5. package/.github/ISSUE_TEMPLATE/good_first_issue.md +23 -0
  6. package/.github/pull_request_template.md +45 -0
  7. package/.github/workflows/test.yml +75 -0
  8. package/CHANGELOG.md +1367 -0
  9. package/README.md +90 -537
  10. package/README.public.md +578 -0
  11. package/SECURITY.md +108 -0
  12. package/assets/gep/events.jsonl +3 -0
  13. package/examples/atp-consumer-quickstart.md +100 -0
  14. package/examples/hello-world.md +38 -0
  15. package/package.json +6 -18
  16. package/proxy-package.json +39 -0
  17. package/public.manifest.json +145 -0
  18. package/src/evolve/guards.js +721 -1
  19. package/src/evolve/pipeline/collect.js +1283 -1
  20. package/src/evolve/pipeline/dispatch.js +421 -1
  21. package/src/evolve/pipeline/enrich.js +440 -1
  22. package/src/evolve/pipeline/hub.js +319 -1
  23. package/src/evolve/pipeline/select.js +274 -1
  24. package/src/evolve/pipeline/signals.js +206 -1
  25. package/src/evolve/utils.js +264 -1
  26. package/src/evolve.js +350 -1
  27. package/src/gep/a2aProtocol.js +4463 -1
  28. package/src/gep/antiAbuseTelemetry.js +233 -1
  29. package/src/gep/autoDistillConv.js +205 -1
  30. package/src/gep/autoDistillLlm.js +315 -1
  31. package/src/gep/candidateEval.js +92 -1
  32. package/src/gep/candidates.js +198 -1
  33. package/src/gep/contentHash.js +30 -1
  34. package/src/gep/conversationDistiller.js +270 -0
  35. package/src/gep/conversationSniffer.js +266 -1
  36. package/src/gep/crypto.js +89 -1
  37. package/src/gep/curriculum.js +163 -1
  38. package/src/gep/deviceId.js +218 -1
  39. package/src/gep/envFingerprint.js +118 -1
  40. package/src/gep/epigenetics.js +31 -1
  41. package/src/gep/execBridge.js +712 -1
  42. package/src/gep/explore.js +289 -1
  43. package/src/gep/hash.js +15 -1
  44. package/src/gep/hubFetch.js +608 -1
  45. package/src/gep/hubReview.js +207 -1
  46. package/src/gep/hubSearch.js +526 -1
  47. package/src/gep/hubVerify.js +306 -1
  48. package/src/gep/learningSignals.js +89 -1
  49. package/src/gep/memoryGraph.js +1449 -1
  50. package/src/gep/memoryGraphAdapter.js +203 -1
  51. package/src/gep/mutation.js +203 -1
  52. package/src/gep/narrativeMemory.js +108 -1
  53. package/src/gep/openPRRegistry.js +205 -1
  54. package/src/gep/personality.js +423 -1
  55. package/src/gep/policyCheck.js +599 -1
  56. package/src/gep/prompt.js +836 -1
  57. package/src/gep/questionGenerator.js +103 -0
  58. package/src/gep/recallInject.js +409 -1
  59. package/src/gep/recallVerifier.js +318 -1
  60. package/src/gep/reflection.js +177 -1
  61. package/src/gep/savingsCore.js +112 -1
  62. package/src/gep/selector.js +602 -1
  63. package/src/gep/skillDistiller.js +1294 -1
  64. package/src/gep/solidify.js +1699 -1
  65. package/src/gep/strategy.js +136 -1
  66. package/src/gep/tokenSavings.js +95 -1
  67. package/src/gep/workspaceKeychain.js +174 -1
  68. package/src/proxy/extensions/traceControl.js +109 -1
  69. package/src/proxy/inject.js +52 -1
  70. package/src/proxy/lifecycle/manager.js +108 -7
  71. package/src/proxy/server/routes.js +31 -0
  72. package/src/proxy/server/settings.js +6 -2
  73. package/src/proxy/sync/engine.js +31 -15
  74. package/src/proxy/sync/inbound.js +87 -9
  75. package/src/proxy/sync/outbound.js +57 -4
  76. package/src/proxy/trace/extractor.js +1403 -1
  77. package/src/proxy/trace/usage.js +105 -1
  78. package/CONTRIBUTING.md +0 -19
  79. package/assets/cover.png +0 -0
  80. package/scripts/a2a_export.js +0 -63
  81. package/scripts/a2a_ingest.js +0 -79
  82. package/scripts/a2a_promote.js +0 -118
  83. package/scripts/analyze_by_skill.js +0 -121
  84. package/scripts/build_binaries.js +0 -479
  85. package/scripts/check-changelog.js +0 -166
  86. package/scripts/extract_log.js +0 -85
  87. package/scripts/generate_history.js +0 -75
  88. package/scripts/gep_append_event.js +0 -96
  89. package/scripts/gep_personality_report.js +0 -234
  90. package/scripts/human_report.js +0 -147
  91. package/scripts/recall-verify-report.js +0 -234
  92. package/scripts/recover_loop.js +0 -61
  93. package/scripts/refresh_stars_badge.js +0 -168
  94. package/scripts/seed-merchants.js +0 -91
  95. package/scripts/suggest_version.js +0 -89
  96. package/scripts/validate-modules.js +0 -38
  97. package/scripts/validate-suite.js +0 -78
  98. package/skills/index.json +0 -14
  99. /package/assets/gep/{genes.seed.json → genes.json} +0 -0
  100. /package/{skills → bundled-skills}/_meta/SKILL.md +0 -0
@@ -77,12 +77,14 @@ class SyncEngine {
77
77
  // the whole tick, schedule the next iteration in `finally` so a
78
78
  // surprise throw cannot park the loop.
79
79
  let nextDelay = DEFAULT_OUTBOUND_INTERVAL;
80
+ let hubRetryAfterMs = 0;
80
81
  try {
81
82
  if (!this._running) return;
82
83
  this._outPending = true;
83
84
  try {
84
85
  const result = await this.outbound.flush();
85
86
  if (result.sent > 0) this._lastActivity = Date.now();
87
+ if (result.retryAfterMs > 0) hubRetryAfterMs = result.retryAfterMs;
86
88
  if ((result.sent > 0 || result.dropped > 0) && typeof this.onOutboundFlushed === 'function') {
87
89
  try { this.onOutboundFlushed(result); } catch (e) {
88
90
  this.logger.warn?.('[sync] onOutboundFlushed callback failed:', e.message);
@@ -96,13 +98,17 @@ class SyncEngine {
96
98
  }
97
99
  }
98
100
  this._outPending = false;
99
- try {
100
- const pending = this.store.countPending({ direction: 'outbound' });
101
- if (pending > 0) nextDelay = 1_000;
102
- } catch (err) {
103
- // countPending threw (corrupt store, FS hiccup): keep the
104
- // default cadence rather than parking the loop.
105
- this.logger.error(`[sync] countPending threw (non-fatal): ${err && err.message}`);
101
+ if (hubRetryAfterMs > 0) {
102
+ nextDelay = Math.max(1_000, hubRetryAfterMs);
103
+ } else {
104
+ try {
105
+ const pending = this.store.countPending({ direction: 'outbound' });
106
+ if (pending > 0) nextDelay = 1_000;
107
+ } catch (err) {
108
+ // countPending threw (corrupt store, FS hiccup): keep the
109
+ // default cadence rather than parking the loop.
110
+ this.logger.error(`[sync] countPending threw (non-fatal): ${err && err.message}`);
111
+ }
106
112
  }
107
113
  } catch (err) {
108
114
  // Anything that escaped the inner blocks above. Log and let
@@ -123,11 +129,14 @@ class SyncEngine {
123
129
  // from inbound.pull / ackDelivered / _isIdle used to escape the
124
130
  // setTimeout callback and silently park the inbound loop.
125
131
  let nextDelay = DEFAULT_POLL_INTERVAL_ACTIVE;
132
+ let hubRetryAfterMs = 0;
126
133
  try {
127
134
  if (!this._running) return;
128
135
  try {
129
136
  const result = await this.inbound.pull();
130
- if (result.received > 0) {
137
+ if (result.retryAfterMs > 0) {
138
+ hubRetryAfterMs = result.retryAfterMs;
139
+ } else if (result.received > 0) {
131
140
  this._lastActivity = Date.now();
132
141
  if (typeof this.onInboundReceived === 'function') {
133
142
  try { this.onInboundReceived(result.received); } catch (e) {
@@ -135,7 +144,10 @@ class SyncEngine {
135
144
  }
136
145
  }
137
146
  }
138
- await this.inbound.ackDelivered();
147
+ if (!hubRetryAfterMs) {
148
+ const ack = await this.inbound.ackDelivered();
149
+ if (ack.retryAfterMs > 0) hubRetryAfterMs = ack.retryAfterMs;
150
+ }
139
151
  } catch (err) {
140
152
  if (err instanceof AuthError) {
141
153
  await this._handleAuthError('inbound');
@@ -143,12 +155,16 @@ class SyncEngine {
143
155
  this.logger.error(`[sync] inbound error: ${err.message}`);
144
156
  }
145
157
  }
146
- try {
147
- nextDelay = this._isIdle()
148
- ? DEFAULT_POLL_INTERVAL_IDLE
149
- : DEFAULT_POLL_INTERVAL_ACTIVE;
150
- } catch (err) {
151
- this.logger.error(`[sync] _isIdle threw (non-fatal): ${err && err.message}`);
158
+ if (hubRetryAfterMs > 0) {
159
+ nextDelay = Math.max(1_000, hubRetryAfterMs);
160
+ } else {
161
+ try {
162
+ nextDelay = this._isIdle()
163
+ ? DEFAULT_POLL_INTERVAL_IDLE
164
+ : DEFAULT_POLL_INTERVAL_ACTIVE;
165
+ } catch (err) {
166
+ this.logger.error(`[sync] _isIdle threw (non-fatal): ${err && err.message}`);
167
+ }
152
168
  }
153
169
  } catch (err) {
154
170
  this.logger.error(`[sync] inbound tick threw (non-fatal): ${err && err.message}`);
@@ -2,7 +2,15 @@
2
2
 
3
3
  const { PROXY_PROTOCOL_VERSION } = require('../mailbox/store');
4
4
  const { AuthError } = require('../lifecycle/manager');
5
- const { hubFetch } = require('../../gep/hubFetch');
5
+ const {
6
+ drainHubResponse,
7
+ hubFetch,
8
+ hubUnreachableBackoffMs,
9
+ isHubUnreachableError,
10
+ readHubResponseJson,
11
+ readHubResponseText,
12
+ throwIfHubUnreachableResponse,
13
+ } = require('../../gep/hubFetch');
6
14
 
7
15
  const DEFAULT_POLL_INTERVAL_ACTIVE = 10_000;
8
16
  const DEFAULT_POLL_INTERVAL_IDLE = 60_000;
@@ -13,9 +21,41 @@ class InboundSync {
13
21
  this.hubUrl = hubUrl;
14
22
  this.logger = logger || console;
15
23
  this.getHeaders = getHeaders;
24
+ this._hubUnreachableFailures = 0;
25
+ this._hubUnreachableUntil = 0;
26
+ }
27
+
28
+ _hubUnreachableWaitMs() {
29
+ return Math.max(0, this._hubUnreachableUntil - Date.now());
30
+ }
31
+
32
+ _recordHubReachable() {
33
+ this._hubUnreachableFailures = 0;
34
+ this._hubUnreachableUntil = 0;
35
+ }
36
+
37
+ _recordHubUnreachable(err) {
38
+ this._hubUnreachableFailures += 1;
39
+ const retryAfterMs = hubUnreachableBackoffMs(this._hubUnreachableFailures);
40
+ this._hubUnreachableUntil = Date.now() + retryAfterMs;
41
+ this.logger.warn?.(
42
+ `[inbound] Hub unreachable; backing off for ${Math.ceil(retryAfterMs / 1000)}s: ` +
43
+ `${err && err.message || err}`
44
+ );
45
+ return retryAfterMs;
16
46
  }
17
47
 
18
48
  async pull(channel = 'evomap-hub', limit = 50) {
49
+ const waitMs = this._hubUnreachableWaitMs();
50
+ if (waitMs > 0) {
51
+ return {
52
+ received: 0,
53
+ error: 'hub_unreachable_backoff',
54
+ hubUnreachable: true,
55
+ retryAfterMs: waitMs,
56
+ };
57
+ }
58
+
19
59
  const cursorKey = `${channel}:inbound_cursor`;
20
60
  const cursor = this.store.getCursor(cursorKey);
21
61
 
@@ -30,17 +70,20 @@ class InboundSync {
30
70
  signal: AbortSignal.timeout(35_000),
31
71
  });
32
72
 
73
+ await throwIfHubUnreachableResponse(res, 'inbound pull');
74
+ this._recordHubReachable();
75
+
33
76
  if (res.status === 403 || res.status === 401) {
34
- const errText = await res.text().catch(() => 'unknown');
77
+ const errText = await readHubResponseText(res).catch(() => 'unknown');
35
78
  throw new AuthError(`Hub ${res.status}: ${errText}`, res.status);
36
79
  }
37
80
 
38
81
  if (!res.ok) {
39
- const errText = await res.text().catch(() => 'unknown');
82
+ const errText = await readHubResponseText(res).catch(() => 'unknown');
40
83
  throw new Error(`Hub returned ${res.status}: ${errText}`);
41
84
  }
42
85
 
43
- const data = await res.json();
86
+ const data = await readHubResponseJson(res);
44
87
  const messages = data.messages || [];
45
88
 
46
89
  if (messages.length > 0) {
@@ -64,12 +107,31 @@ class InboundSync {
64
107
  return { received: messages.length, cursor: data.next_cursor || cursor };
65
108
  } catch (err) {
66
109
  if (err instanceof AuthError) throw err;
110
+ if (isHubUnreachableError(err)) {
111
+ const retryAfterMs = this._recordHubUnreachable(err);
112
+ return {
113
+ received: 0,
114
+ error: 'hub_unreachable',
115
+ hubUnreachable: true,
116
+ retryAfterMs,
117
+ };
118
+ }
67
119
  this.logger.error(`[inbound] pull failed: ${err.message}`);
68
120
  return { received: 0, error: err.message };
69
121
  }
70
122
  }
71
123
 
72
124
  async ackDelivered(channel = 'evomap-hub') {
125
+ const waitMs = this._hubUnreachableWaitMs();
126
+ if (waitMs > 0) {
127
+ return {
128
+ acked: 0,
129
+ error: 'hub_unreachable_backoff',
130
+ hubUnreachable: true,
131
+ retryAfterMs: waitMs,
132
+ };
133
+ }
134
+
73
135
  const delivered = this.store.list({
74
136
  type: '%',
75
137
  direction: 'inbound',
@@ -97,13 +159,29 @@ class InboundSync {
97
159
  body: JSON.stringify({ sender_id: senderId, message_ids: delivered.map(m => m.id) }),
98
160
  signal: AbortSignal.timeout(10_000),
99
161
  });
100
- try {
101
- if (res && res.body && typeof res.body.cancel === 'function') {
102
- await res.body.cancel().catch(() => {});
103
- }
104
- } catch (_) { /* never escape the drain helper */ }
162
+ await throwIfHubUnreachableResponse(res, 'inbound ack');
163
+ this._recordHubReachable();
164
+ if (res.status === 403 || res.status === 401) {
165
+ const errText = await readHubResponseText(res).catch(() => 'unknown');
166
+ throw new AuthError(`Hub ${res.status}: ${errText}`, res.status);
167
+ }
168
+ if (!res.ok) {
169
+ const errText = await readHubResponseText(res).catch(() => 'unknown');
170
+ throw new Error(`Hub returned ${res.status}: ${errText}`);
171
+ }
172
+ await drainHubResponse(res);
105
173
  return { acked: delivered.length };
106
174
  } catch (err) {
175
+ if (err instanceof AuthError) throw err;
176
+ if (isHubUnreachableError(err)) {
177
+ const retryAfterMs = this._recordHubUnreachable(err);
178
+ return {
179
+ acked: 0,
180
+ error: 'hub_unreachable',
181
+ hubUnreachable: true,
182
+ retryAfterMs,
183
+ };
184
+ }
107
185
  this.logger.error(`[inbound] ack failed: ${err.message}`);
108
186
  return { acked: 0, error: err.message };
109
187
  }
@@ -3,7 +3,14 @@
3
3
  const { PROXY_PROTOCOL_VERSION } = require('../mailbox/store');
4
4
  const { AuthError } = require('../lifecycle/manager');
5
5
  const { isProxyTraceUploadPayloadAllowed, resolveTraceMode } = require('../trace/extractor');
6
- const { hubFetch } = require('../../gep/hubFetch');
6
+ const {
7
+ hubFetch,
8
+ hubUnreachableBackoffMs,
9
+ isHubUnreachableError,
10
+ readHubResponseJson,
11
+ readHubResponseText,
12
+ throwIfHubUnreachableResponse,
13
+ } = require('../../gep/hubFetch');
7
14
 
8
15
  const MAX_BATCH = 50;
9
16
  const MAX_RETRIES = 10;
@@ -14,9 +21,41 @@ class OutboundSync {
14
21
  this.hubUrl = hubUrl;
15
22
  this.logger = logger || console;
16
23
  this.getHeaders = getHeaders;
24
+ this._hubUnreachableFailures = 0;
25
+ this._hubUnreachableUntil = 0;
26
+ }
27
+
28
+ _hubUnreachableWaitMs() {
29
+ return Math.max(0, this._hubUnreachableUntil - Date.now());
30
+ }
31
+
32
+ _recordHubReachable() {
33
+ this._hubUnreachableFailures = 0;
34
+ this._hubUnreachableUntil = 0;
35
+ }
36
+
37
+ _recordHubUnreachable(err) {
38
+ this._hubUnreachableFailures += 1;
39
+ const retryAfterMs = hubUnreachableBackoffMs(this._hubUnreachableFailures);
40
+ this._hubUnreachableUntil = Date.now() + retryAfterMs;
41
+ this.logger.warn?.(
42
+ `[outbound] Hub unreachable; backing off for ${Math.ceil(retryAfterMs / 1000)}s: ` +
43
+ `${err && err.message || err}`
44
+ );
45
+ return retryAfterMs;
17
46
  }
18
47
 
19
48
  async flush(channel = 'evomap-hub') {
49
+ const waitMs = this._hubUnreachableWaitMs();
50
+ if (waitMs > 0) {
51
+ return {
52
+ sent: 0,
53
+ error: 'hub_unreachable_backoff',
54
+ hubUnreachable: true,
55
+ retryAfterMs: waitMs,
56
+ };
57
+ }
58
+
20
59
  const pendingBatch = this.store.pollOutbound({ channel, limit: MAX_BATCH });
21
60
  if (pendingBatch.length === 0) return { sent: 0 };
22
61
 
@@ -65,17 +104,20 @@ class OutboundSync {
65
104
  signal: AbortSignal.timeout(30_000),
66
105
  });
67
106
 
107
+ await throwIfHubUnreachableResponse(res, 'outbound flush');
108
+ this._recordHubReachable();
109
+
68
110
  if (res.status === 403 || res.status === 401) {
69
- const errText = await res.text().catch(() => 'unknown');
111
+ const errText = await readHubResponseText(res).catch(() => 'unknown');
70
112
  throw new AuthError(`Hub ${res.status}: ${errText}`, res.status);
71
113
  }
72
114
 
73
115
  if (!res.ok) {
74
- const errText = await res.text().catch(() => 'unknown');
116
+ const errText = await readHubResponseText(res).catch(() => 'unknown');
75
117
  throw new Error(`Hub returned ${res.status}: ${errText}`);
76
118
  }
77
119
 
78
- const data = await res.json();
120
+ const data = await readHubResponseJson(res);
79
121
  const results = data.results || [];
80
122
 
81
123
  const updates = [];
@@ -112,6 +154,17 @@ class OutboundSync {
112
154
  return result;
113
155
  } catch (err) {
114
156
  if (err instanceof AuthError) throw err;
157
+ if (isHubUnreachableError(err)) {
158
+ const retryAfterMs = this._recordHubUnreachable(err);
159
+ const result = {
160
+ sent: 0,
161
+ error: 'hub_unreachable',
162
+ hubUnreachable: true,
163
+ retryAfterMs,
164
+ };
165
+ if (dropped > 0) result.dropped = dropped;
166
+ return result;
167
+ }
115
168
  this.logger.error(`[outbound] flush failed: ${err.message}`);
116
169
  for (const m of pending) {
117
170
  this.store.incrementRetry(m.id, err.message);