@evomap/evolver 1.89.19 → 1.90.0

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 (68) hide show
  1. package/index.js +85 -1
  2. package/package.json +1 -1
  3. package/scripts/skill2recipes.js +118 -0
  4. package/src/adapters/claudeCode.js +3 -3
  5. package/src/adapters/codex.js +2 -2
  6. package/src/adapters/kiro.js +2 -2
  7. package/src/adapters/opencode.js +2 -2
  8. package/src/evolve/guards.js +1 -1
  9. package/src/evolve/pipeline/collect.js +1 -1
  10. package/src/evolve/pipeline/dispatch.js +1 -1
  11. package/src/evolve/pipeline/enrich.js +1 -1
  12. package/src/evolve/pipeline/hub.js +1 -1
  13. package/src/evolve/pipeline/select.js +1 -1
  14. package/src/evolve/pipeline/signals.js +1 -1
  15. package/src/evolve/utils.js +1 -1
  16. package/src/evolve.js +1 -1
  17. package/src/gep/a2aProtocol.js +1 -1
  18. package/src/gep/antiAbuseTelemetry.js +1 -1
  19. package/src/gep/autoDistillConv.js +1 -1
  20. package/src/gep/autoDistillLlm.js +1 -1
  21. package/src/gep/candidateEval.js +1 -1
  22. package/src/gep/candidates.js +1 -1
  23. package/src/gep/contentHash.js +1 -1
  24. package/src/gep/conversationDistiller.js +1 -1
  25. package/src/gep/conversationSniffer.js +1 -1
  26. package/src/gep/crypto.js +1 -1
  27. package/src/gep/curriculum.js +1 -1
  28. package/src/gep/deviceId.js +1 -1
  29. package/src/gep/envFingerprint.js +1 -1
  30. package/src/gep/epigenetics.js +1 -1
  31. package/src/gep/execBridge.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/recallInject.js +1 -1
  48. package/src/gep/recallVerifier.js +1 -1
  49. package/src/gep/reflection.js +1 -1
  50. package/src/gep/savingsCore.js +1 -1
  51. package/src/gep/selector.js +1 -1
  52. package/src/gep/skill2recipes.js +511 -0
  53. package/src/gep/skillDistiller.js +1 -1
  54. package/src/gep/solidify.js +1 -1
  55. package/src/gep/strategy.js +1 -1
  56. package/src/gep/tokenSavings.js +1 -1
  57. package/src/gep/trajectoryExport.js +1 -1
  58. package/src/gep/workspaceKeychain.js +1 -1
  59. package/src/proxy/extensions/traceControl.js +1 -1
  60. package/src/proxy/inject.js +1 -1
  61. package/src/proxy/mailbox/store.js +14 -2
  62. package/src/proxy/sync/outbound.js +44 -3
  63. package/src/proxy/trace/extractor.js +1 -1
  64. package/src/proxy/trace/usage.js +1 -1
  65. package/src/solo/breaker.js +25 -0
  66. package/src/solo/gitGuard.js +65 -0
  67. package/skills/_meta/SKILL.md +0 -41
  68. package/skills/index.json +0 -14
@@ -345,6 +345,7 @@ class MailboxStore {
345
345
  synced_at: null,
346
346
  expires_at: expiresAt || null,
347
347
  retry_count: 0,
348
+ next_retry_at: null,
348
349
  error: null,
349
350
  };
350
351
  this._appendMessage(msg);
@@ -372,6 +373,7 @@ class MailboxStore {
372
373
  synced_at: null,
373
374
  expires_at: expiresAt || null,
374
375
  retry_count: 0,
376
+ next_retry_at: null,
375
377
  error: null,
376
378
  };
377
379
  this._appendMessage(msg);
@@ -418,6 +420,7 @@ class MailboxStore {
418
420
  const msg = this._messages.get(id);
419
421
  if (!msg || msg.status !== 'pending') continue;
420
422
  if (msg.channel !== ch) continue;
423
+ if (Number.isFinite(Number(msg.next_retry_at)) && Number(msg.next_retry_at) > Date.now()) continue;
421
424
  candidates.push(msg);
422
425
  }
423
426
  candidates.sort((a, b) => {
@@ -450,7 +453,7 @@ class MailboxStore {
450
453
 
451
454
  updateStatus(id, status, { error, syncedAt } = {}) {
452
455
  const TERMINAL = new Set(['synced', 'delivered', 'failed', 'rejected']);
453
- const fields = { status };
456
+ const fields = { status, next_retry_at: null };
454
457
  if (syncedAt) fields.synced_at = syncedAt;
455
458
  else if (status === 'synced') fields.synced_at = Date.now();
456
459
  if (error !== undefined) fields.error = error;
@@ -470,7 +473,16 @@ class MailboxStore {
470
473
  incrementRetry(id, error) {
471
474
  const msg = this._messages.get(id);
472
475
  const newCount = msg ? (msg.retry_count || 0) + 1 : 1;
473
- this._appendUpdate(id, { retry_count: newCount, error: error || null });
476
+ this._appendUpdate(id, { retry_count: newCount, next_retry_at: null, error: error || null });
477
+ }
478
+
479
+ deferRetry(id, error, retryAfterMs) {
480
+ const delay = Math.max(1_000, Number.isFinite(Number(retryAfterMs)) ? Number(retryAfterMs) : 60_000);
481
+ this._appendUpdate(id, {
482
+ status: 'pending',
483
+ next_retry_at: Date.now() + delay,
484
+ error: error || null,
485
+ });
474
486
  }
475
487
 
476
488
  list({ type, direction, status, limit, offset } = {}) {
@@ -120,6 +120,30 @@ function buildSizedOutboundBatch(senderId, messages, maxBodyBytes, hardMaxBodyBy
120
120
  return { selected, rejected, body, bodyBytes, maxBodyBytes };
121
121
  }
122
122
 
123
+ function numberField(row, keys) {
124
+ for (const key of keys) {
125
+ if (!row || row[key] === undefined || row[key] === null || row[key] === '') continue;
126
+ const n = Number(row[key]);
127
+ if (Number.isFinite(n)) return n;
128
+ }
129
+ return null;
130
+ }
131
+
132
+ function resultRetryAfterMs(row) {
133
+ const ms = numberField(row, ['retryAfterMs', 'retry_after_ms']);
134
+ if (ms !== null) return Math.max(1_000, ms);
135
+ const seconds = numberField(row, ['retryAfter', 'retry_after']);
136
+ return seconds !== null ? Math.max(1_000, seconds * 1000) : null;
137
+ }
138
+
139
+ function resultIsRetryable(row) {
140
+ return row && (row.retryable === true || row.retryable === 'true' || row.terminal === false || row.terminal === 'false');
141
+ }
142
+
143
+ function resultIsTerminal(row) {
144
+ return row && (row.terminal === true || row.terminal === 'true');
145
+ }
146
+
123
147
  class OutboundSync {
124
148
  constructor({ store, hubUrl, getHeaders, logger }) {
125
149
  this.store = store;
@@ -261,17 +285,33 @@ class OutboundSync {
261
285
 
262
286
  const updates = [];
263
287
  const inboundMessages = [];
288
+ let deferred = 0;
264
289
 
265
290
  for (const r of results) {
266
291
  if (r.status === 'accepted' || r.status === 'ok') {
267
292
  updates.push({ id: r.id, status: 'synced' });
268
293
  } else if (r.status === 'failed' || r.status === 'rejected') {
269
294
  const msg = pending.find(m => m.id === r.id);
270
- const error = sanitizeHubErrorMessage(r.error || 'rejected by hub');
271
- if (msg && msg.retry_count < MAX_RETRIES) {
295
+ const error = sanitizeHubErrorMessage(r.error || r.reason || 'rejected by hub');
296
+ const retryAfterMs = resultRetryAfterMs(r);
297
+ // A `terminal: true` hint from the Hub means "final, do not retry"
298
+ // and must win even when the same result also carries retryAfterMs
299
+ // or retryable (a contradictory but possible payload). Guard the
300
+ // defer branch with !resultIsTerminal so a terminal message is
301
+ // finalized as failed instead of being parked for retry and resent.
302
+ if (msg && !resultIsTerminal(r) && (retryAfterMs !== null || resultIsRetryable(r))) {
303
+ this.store.deferRetry(r.id, error, retryAfterMs || 60_000);
304
+ deferred++;
305
+ } else if (msg && !resultIsTerminal(r) && msg.retry_count < MAX_RETRIES) {
272
306
  this.store.incrementRetry(r.id, error);
273
307
  } else {
274
- updates.push({ id: r.id, status: 'failed', error: sanitizeHubErrorMessage(r.error || 'max retries') });
308
+ // Reuse the already-sanitized `error` (r.error / r.reason, else
309
+ // 'rejected by hub'). Only label 'max retries' for the genuine
310
+ // retry-exhaustion path (non-terminal, no explicit Hub error) so a
311
+ // terminal rejection without an error/reason is not mislabeled as
312
+ // retry exhaustion (Bugbot PR #301 Low).
313
+ const exhausted = !resultIsTerminal(r) && !(r.error || r.reason);
314
+ updates.push({ id: r.id, status: 'failed', error: exhausted ? sanitizeHubErrorMessage('max retries') : error });
275
315
  }
276
316
  }
277
317
 
@@ -290,6 +330,7 @@ class OutboundSync {
290
330
 
291
331
  this.store.setState('last_sync_at', new Date().toISOString());
292
332
  const result = { sent: pending.length, synced: updates.length, responses: inboundMessages.length };
333
+ if (deferred > 0) result.deferred = deferred;
293
334
  if (dropped > 0) result.dropped = dropped;
294
335
  return result;
295
336
  } catch (err) {