@evomap/evolver 1.89.4 → 1.89.6

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 (108) hide show
  1. package/CONTRIBUTING.md +19 -0
  2. package/README.md +536 -86
  3. package/assets/cover.png +0 -0
  4. package/index.js +87 -7
  5. package/package.json +17 -6
  6. package/scripts/a2a_export.js +63 -0
  7. package/scripts/a2a_ingest.js +79 -0
  8. package/scripts/a2a_promote.js +118 -0
  9. package/scripts/analyze_by_skill.js +121 -0
  10. package/scripts/build_binaries.js +479 -0
  11. package/scripts/check-changelog.js +166 -0
  12. package/scripts/extract_log.js +85 -0
  13. package/scripts/generate_history.js +75 -0
  14. package/scripts/gep_append_event.js +96 -0
  15. package/scripts/gep_personality_report.js +234 -0
  16. package/scripts/human_report.js +147 -0
  17. package/scripts/recall-verify-report.js +234 -0
  18. package/scripts/recover_loop.js +61 -0
  19. package/scripts/refresh_stars_badge.js +168 -0
  20. package/scripts/seed-merchants.js +91 -0
  21. package/scripts/suggest_version.js +89 -0
  22. package/scripts/validate-modules.js +38 -0
  23. package/scripts/validate-suite.js +78 -0
  24. package/skills/index.json +14 -0
  25. package/src/adapters/scripts/_runtimePaths.js +1 -0
  26. package/src/adapters/scripts/evolver-session-end.js +1 -0
  27. package/src/adapters/scripts/evolver-session-start.js +1 -0
  28. package/src/evolve/guards.js +1 -721
  29. package/src/evolve/pipeline/collect.js +1 -1283
  30. package/src/evolve/pipeline/dispatch.js +1 -421
  31. package/src/evolve/pipeline/enrich.js +1 -440
  32. package/src/evolve/pipeline/hub.js +1 -319
  33. package/src/evolve/pipeline/select.js +1 -274
  34. package/src/evolve/pipeline/signals.js +1 -206
  35. package/src/evolve/utils.js +1 -264
  36. package/src/evolve.js +1 -350
  37. package/src/gep/a2aProtocol.js +1 -4455
  38. package/src/gep/antiAbuseTelemetry.js +1 -233
  39. package/src/gep/autoDistillConv.js +1 -205
  40. package/src/gep/autoDistillLlm.js +1 -315
  41. package/src/gep/candidateEval.js +1 -92
  42. package/src/gep/candidates.js +1 -198
  43. package/src/gep/contentHash.js +1 -30
  44. package/src/gep/conversationSniffer.js +1 -266
  45. package/src/gep/crypto.js +1 -89
  46. package/src/gep/curriculum.js +1 -163
  47. package/src/gep/deviceId.js +1 -218
  48. package/src/gep/envFingerprint.js +1 -118
  49. package/src/gep/epigenetics.js +1 -31
  50. package/src/gep/execBridge.js +1 -711
  51. package/src/gep/explore.js +1 -289
  52. package/src/gep/hash.js +1 -15
  53. package/src/gep/hubFetch.js +1 -359
  54. package/src/gep/hubReview.js +1 -207
  55. package/src/gep/hubSearch.js +1 -526
  56. package/src/gep/hubVerify.js +1 -306
  57. package/src/gep/idleScheduler.js +6 -1
  58. package/src/gep/learningSignals.js +1 -89
  59. package/src/gep/memoryGraph.js +1 -1374
  60. package/src/gep/memoryGraphAdapter.js +1 -203
  61. package/src/gep/mutation.js +1 -203
  62. package/src/gep/narrativeMemory.js +1 -108
  63. package/src/gep/openPRRegistry.js +1 -205
  64. package/src/gep/personality.js +1 -423
  65. package/src/gep/policyCheck.js +1 -599
  66. package/src/gep/prompt.js +1 -836
  67. package/src/gep/recallInject.js +1 -409
  68. package/src/gep/recallVerifier.js +1 -318
  69. package/src/gep/reflection.js +1 -177
  70. package/src/gep/savingsCore.js +1 -0
  71. package/src/gep/selector.js +1 -602
  72. package/src/gep/skillDistiller.js +1 -1294
  73. package/src/gep/solidify.js +1 -1699
  74. package/src/gep/strategy.js +1 -136
  75. package/src/gep/tokenSavings.js +1 -88
  76. package/src/gep/workspaceKeychain.js +1 -174
  77. package/src/ops/lifecycle.js +17 -4
  78. package/src/proxy/envelope.js +59 -0
  79. package/src/proxy/extensions/traceControl.js +1 -99
  80. package/src/proxy/index.js +221 -3
  81. package/src/proxy/inject.js +1 -52
  82. package/src/proxy/lifecycle/manager.js +14 -7
  83. package/src/proxy/mailbox/store.js +29 -6
  84. package/src/proxy/router/messages_route.js +4 -1
  85. package/src/proxy/router/responses_route.js +159 -0
  86. package/src/proxy/server/http.js +13 -4
  87. package/src/proxy/server/routes.js +11 -1
  88. package/src/proxy/sync/engine.js +7 -1
  89. package/src/proxy/sync/outbound.js +32 -4
  90. package/src/proxy/trace/extractor.js +1 -646
  91. package/src/proxy/trace/usage.js +1 -105
  92. package/.cursor/BUGBOT.md +0 -182
  93. package/.env.example +0 -68
  94. package/.git-commit-guard-token +0 -1
  95. package/.github/CODEOWNERS +0 -63
  96. package/.github/ISSUE_TEMPLATE/good_first_issue.md +0 -23
  97. package/.github/pull_request_template.md +0 -45
  98. package/.github/workflows/test.yml +0 -75
  99. package/CHANGELOG.md +0 -1237
  100. package/README.public.md +0 -569
  101. package/SECURITY.md +0 -108
  102. package/assets/gep/events.jsonl +0 -3
  103. package/examples/atp-consumer-quickstart.md +0 -100
  104. package/examples/hello-world.md +0 -38
  105. package/proxy-package.json +0 -39
  106. package/public.manifest.json +0 -143
  107. /package/assets/gep/{genes.json → genes.seed.json} +0 -0
  108. /package/{bundled-skills → skills}/_meta/SKILL.md +0 -0
@@ -1,52 +1 @@
1
- 'use strict';
2
-
3
- const { getProxyToken, getProxyUrl } = require('./server/settings');
4
-
5
- function isDisabled(env = process.env) {
6
- const raw = String(env.EVOMAP_PROXY_AUTO_INJECT || '').trim().toLowerCase();
7
- return raw === '0' || raw === 'false' || raw === 'off' || raw === 'none' || raw === 'no';
8
- }
9
-
10
- function injectProxyEnv(info = {}, env = process.env) {
11
- if (isDisabled(env)) {
12
- return { injected: false, reason: 'disabled' };
13
- }
14
-
15
- const useSettingsFallback = env === process.env && info.useSettings !== false;
16
- const url = String(info.url || (useSettingsFallback ? getProxyUrl() : '') || '').replace(/\/+$/, '');
17
- const token = String(info.token || (useSettingsFallback ? getProxyToken() : '') || '');
18
- if (!url || !token) {
19
- return { injected: false, reason: 'missing_proxy_settings' };
20
- }
21
-
22
- const currentBase = String(env.ANTHROPIC_BASE_URL || '').trim().replace(/\/+$/, '');
23
- if (currentBase && currentBase !== url && !env.EVOMAP_ANTHROPIC_BASE_URL) {
24
- env.EVOMAP_ANTHROPIC_BASE_URL = currentBase;
25
- }
26
- const currentAuthToken = String(env.ANTHROPIC_AUTH_TOKEN || '').trim();
27
- if (currentAuthToken && currentAuthToken !== token && !env.EVOMAP_ANTHROPIC_AUTH_TOKEN) {
28
- env.EVOMAP_ANTHROPIC_AUTH_TOKEN = currentAuthToken;
29
- }
30
-
31
- env.ANTHROPIC_BASE_URL = url;
32
- env.ANTHROPIC_AUTH_TOKEN = token;
33
- env.CUSTOM_API_KEY = token;
34
- env.EVOMAP_PROXY_URL = url;
35
- env.EVOMAP_PROXY_AUTO_INJECTED = '1';
36
-
37
- return {
38
- injected: true,
39
- url,
40
- vars: [
41
- 'ANTHROPIC_BASE_URL',
42
- 'ANTHROPIC_AUTH_TOKEN',
43
- 'CUSTOM_API_KEY',
44
- 'EVOMAP_PROXY_URL',
45
- ],
46
- };
47
- }
48
-
49
- module.exports = {
50
- injectProxyEnv,
51
- isDisabled,
52
- };
1
+ function _0x232c(){const _0x3160ea=['\x73\x58\x78\x64\x53\x6d\x6f\x6c\x41\x74\x50\x6b\x57\x51\x5a\x63\x48\x4d\x70\x63\x4f\x76\x43\x35','\x76\x48\x72\x6a\x6f\x4d\x69\x7a','\x57\x36\x68\x64\x48\x53\x6f\x76\x57\x50\x37\x64\x4c\x53\x6f\x75\x57\x34\x4a\x64\x53\x71','\x57\x37\x64\x64\x55\x4a\x64\x64\x56\x43\x6b\x41\x57\x51\x53\x37','\x57\x4f\x2f\x63\x4c\x6d\x6f\x37\x6a\x58\x62\x78\x57\x50\x31\x6c','\x57\x50\x6e\x6c\x6e\x74\x48\x50\x44\x4a\x38','\x57\x52\x6a\x63\x46\x76\x34\x58\x57\x36\x34','\x57\x51\x37\x63\x48\x49\x31\x45\x57\x50\x7a\x51\x57\x52\x35\x37','\x70\x6d\x6b\x77\x57\x34\x58\x7a\x74\x47','\x57\x51\x39\x39\x57\x4f\x46\x64\x4e\x4d\x4a\x63\x4b\x68\x43','\x77\x6d\x6f\x49\x7a\x53\x6f\x41\x68\x38\x6b\x79\x68\x71\x69','\x57\x34\x37\x63\x4f\x61\x42\x63\x4d\x38\x6f\x57','\x67\x38\x6f\x2f\x57\x51\x7a\x63\x6e\x57\x68\x64\x4f\x33\x4f','\x46\x6d\x6f\x6a\x57\x4f\x6c\x63\x52\x73\x33\x63\x4a\x38\x6b\x43\x71\x71\x57\x31\x66\x59\x50\x37\x62\x71','\x57\x51\x31\x46\x6e\x6d\x6b\x44\x57\x4f\x42\x64\x53\x53\x6b\x4c\x57\x35\x74\x63\x48\x47','\x57\x34\x4b\x67\x42\x78\x4f\x4a\x70\x68\x65\x73','\x57\x50\x42\x64\x4f\x63\x6c\x64\x4b\x43\x6b\x38\x57\x4f\x65','\x57\x35\x38\x59\x72\x43\x6b\x57\x57\x50\x78\x64\x4a\x43\x6b\x78\x57\x36\x79','\x66\x77\x57\x68\x57\x35\x70\x64\x4d\x57','\x57\x4f\x42\x63\x4f\x74\x44\x49\x57\x4f\x61','\x76\x49\x34\x42\x62\x53\x6f\x66\x68\x6d\x6f\x34\x76\x61','\x57\x36\x65\x31\x57\x52\x52\x63\x4c\x53\x6f\x34','\x6a\x38\x6b\x45\x57\x35\x52\x64\x56\x4e\x42\x64\x49\x43\x6f\x69\x65\x47','\x71\x53\x6f\x38\x75\x74\x75\x52\x45\x49\x58\x57','\x70\x53\x6b\x63\x57\x35\x2f\x64\x4f\x32\x5a\x64\x4f\x53\x6f\x45\x65\x57','\x57\x37\x38\x33\x57\x51\x5a\x63\x54\x53\x6f\x46\x57\x4f\x69','\x71\x74\x43\x6d\x65\x53\x6f\x42\x64\x43\x6f\x59\x71\x71','\x62\x49\x48\x52\x57\x52\x2f\x63\x4d\x57','\x57\x34\x46\x64\x48\x6d\x6f\x72\x57\x51\x4e\x64\x4a\x57','\x6c\x53\x6f\x48\x57\x51\x76\x68\x66\x61','\x42\x78\x37\x63\x4e\x6d\x6f\x56\x57\x36\x43','\x57\x37\x4c\x6d\x57\x51\x31\x64\x42\x38\x6f\x43\x57\x51\x53\x37\x57\x34\x76\x33','\x57\x50\x44\x79\x63\x63\x66\x70','\x57\x34\x52\x63\x4d\x71\x37\x63\x55\x63\x75\x75\x65\x6d\x6b\x72','\x57\x36\x6e\x6d\x57\x4f\x68\x64\x50\x75\x79','\x57\x34\x47\x44\x6e\x6d\x6b\x62\x45\x6d\x6b\x4b\x6d\x53\x6b\x54','\x78\x43\x6f\x37\x42\x58\x57\x6c','\x57\x51\x6a\x57\x6a\x4a\x79\x57','\x57\x37\x42\x64\x4b\x6d\x6b\x69\x41\x76\x68\x63\x54\x53\x6b\x74\x57\x34\x65','\x71\x30\x6e\x72','\x57\x35\x4c\x62\x57\x51\x46\x64\x4f\x71','\x57\x50\x4b\x77\x65\x4b\x74\x64\x4e\x47','\x7a\x5a\x6c\x63\x48\x32\x4e\x63\x54\x6d\x6f\x4d\x41\x75\x6d','\x72\x53\x6f\x2f\x43\x43\x6f\x64\x66\x43\x6b\x72','\x57\x35\x37\x63\x4e\x72\x75','\x57\x35\x6c\x63\x52\x62\x64\x63\x4c\x47\x4f','\x79\x38\x6f\x65\x71\x47','\x57\x52\x34\x69\x57\x37\x75\x79','\x57\x4f\x46\x63\x4a\x53\x6b\x75\x57\x4f\x2f\x64\x4b\x38\x6b\x35\x57\x50\x5a\x63\x53\x57','\x57\x36\x4e\x63\x4e\x58\x78\x63\x50\x38\x6f\x45\x57\x50\x4a\x63\x4a\x71','\x57\x4f\x74\x63\x56\x72\x72\x56\x57\x52\x50\x74\x57\x52\x66\x69','\x57\x37\x56\x64\x4f\x33\x46\x63\x49\x43\x6b\x75','\x57\x35\x56\x63\x4a\x62\x70\x63\x56\x49\x69\x42\x64\x43\x6b\x44','\x57\x4f\x62\x44\x66\x73\x43\x4f\x75\x58\x2f\x64\x49\x57','\x57\x52\x69\x54\x6f\x67\x68\x63\x4b\x30\x4b\x61\x57\x37\x69','\x57\x37\x70\x63\x4b\x65\x52\x63\x52\x38\x6b\x46\x57\x4f\x47\x68\x57\x50\x5a\x64\x4f\x58\x71','\x66\x30\x43\x71\x43\x74\x4c\x70\x64\x67\x65\x68\x75\x77\x68\x64\x48\x57','\x57\x35\x68\x64\x52\x6d\x6b\x31\x79\x32\x56\x63\x47\x38\x6b\x59\x57\x37\x57','\x57\x4f\x53\x79\x64\x61','\x57\x51\x75\x63\x57\x36\x75\x57\x45\x6d\x6f\x62','\x57\x52\x34\x76\x57\x37\x43\x71\x45\x61','\x57\x51\x79\x2f\x57\x36\x71\x36\x7a\x47','\x42\x6d\x6f\x64\x45\x43\x6f\x68\x70\x47','\x57\x50\x47\x31\x57\x34\x71\x53\x73\x43\x6f\x32\x57\x52\x61\x4f','\x79\x66\x70\x63\x47\x53\x6f\x54\x57\x37\x37\x64\x4a\x6d\x6f\x43\x68\x47','\x57\x4f\x53\x30\x57\x34\x47\x39\x72\x6d\x6f\x34\x57\x52\x75\x31','\x72\x64\x58\x66\x57\x51\x33\x63\x4d\x43\x6f\x39\x57\x51\x42\x64\x47\x38\x6b\x48\x57\x35\x2f\x63\x56\x76\x5a\x64\x51\x71','\x65\x32\x2f\x63\x4c\x53\x6b\x30\x6d\x47','\x43\x59\x4e\x64\x52\x65\x6e\x55\x57\x51\x66\x50\x57\x35\x4b','\x65\x67\x65\x79\x57\x36\x56\x64\x4e\x6d\x6b\x38\x57\x36\x78\x64\x4d\x61','\x57\x35\x33\x64\x4e\x5a\x56\x64\x50\x43\x6b\x79','\x77\x63\x44\x44\x57\x52\x57','\x57\x4f\x71\x55\x57\x36\x79\x4e\x44\x61','\x57\x4f\x78\x64\x54\x4a\x2f\x64\x4d\x38\x6b\x51\x57\x50\x30\x59\x57\x52\x4b','\x77\x76\x44\x42','\x57\x34\x4b\x77\x6e\x43\x6b\x44\x46\x43\x6b\x58\x6f\x6d\x6b\x36','\x57\x36\x68\x64\x4d\x6d\x6b\x37\x6a\x67\x43','\x41\x38\x6f\x69\x79\x62\x57\x75','\x57\x51\x66\x33\x6c\x61\x57\x75\x42\x47','\x6a\x43\x6f\x58\x73\x66\x4c\x59\x57\x34\x4a\x64\x4a\x43\x6b\x67','\x57\x51\x71\x76\x57\x37\x69\x71','\x68\x63\x5a\x63\x54\x53\x6f\x31\x75\x47','\x57\x50\x65\x72\x57\x51\x2f\x64\x4e\x53\x6f\x72\x69\x71','\x64\x6d\x6f\x38\x57\x52\x35\x61\x68\x61','\x57\x35\x4e\x63\x4e\x57\x74\x63\x47\x38\x6f\x68','\x6c\x6d\x6f\x71\x57\x4f\x62\x35','\x6f\x6d\x6f\x48\x57\x50\x50\x6a\x6e\x71','\x62\x58\x44\x49\x57\x4f\x33\x63\x55\x71','\x70\x77\x56\x63\x4e\x43\x6b\x6d\x57\x4f\x47','\x57\x37\x70\x64\x51\x53\x6f\x52\x57\x52\x52\x64\x4c\x43\x6b\x45\x57\x51\x37\x63\x48\x43\x6f\x71','\x44\x49\x54\x37\x6b\x66\x57','\x57\x51\x6d\x36\x57\x50\x52\x64\x50\x6d\x6f\x47\x62\x4a\x54\x70','\x57\x51\x42\x63\x4d\x59\x69','\x66\x4a\x74\x64\x49\x53\x6f\x34','\x6d\x65\x47\x33\x77\x61','\x76\x38\x6b\x59\x70\x73\x38\x39\x57\x51\x4e\x63\x4b\x76\x30','\x57\x35\x68\x64\x49\x53\x6b\x64\x6d\x31\x2f\x64\x4b\x58\x4e\x63\x55\x61','\x6c\x49\x6c\x63\x4a\x43\x6f\x61\x77\x67\x5a\x64\x4d\x38\x6b\x70','\x46\x6d\x6b\x46\x6d\x62\x6d\x70\x57\x50\x70\x63\x54\x4b\x57','\x57\x50\x44\x6c\x73\x38\x6f\x77\x57\x52\x61\x48\x69\x6d\x6f\x69','\x42\x31\x70\x63\x49\x38\x6f\x37\x57\x37\x43','\x57\x4f\x74\x64\x4a\x62\x5a\x64\x4b\x53\x6b\x62','\x57\x51\x74\x63\x50\x6d\x6f\x67\x77\x74\x70\x63\x4d\x58\x4b\x35','\x57\x52\x38\x71\x66\x78\x68\x63\x4c\x61','\x69\x38\x6b\x61\x57\x35\x4f','\x57\x51\x2f\x63\x53\x62\x76\x50\x57\x4f\x71','\x6b\x38\x6b\x44\x57\x35\x75\x72\x57\x4f\x42\x63\x51\x38\x6b\x33\x6c\x47','\x57\x52\x58\x39\x69\x58\x53','\x57\x35\x37\x63\x4c\x47\x46\x63\x52\x53\x6f\x42','\x70\x38\x6f\x4d\x75\x4b\x62\x37\x57\x34\x46\x64\x48\x53\x6b\x7a','\x57\x52\x5a\x64\x48\x6d\x6f\x32\x75\x43\x6b\x4c','\x57\x52\x70\x63\x48\x57\x54\x75\x57\x4f\x6a\x37\x57\x50\x58\x6b','\x57\x37\x39\x64\x57\x51\x54\x61\x43\x6d\x6f\x4e\x57\x4f\x38\x6d\x57\x37\x58\x65','\x41\x57\x6a\x4d\x6d\x32\x34','\x57\x36\x5a\x64\x54\x38\x6b\x4f\x57\x51\x46\x64\x4f\x6d\x6b\x46\x57\x51\x42\x63\x4b\x71','\x57\x35\x4a\x63\x51\x48\x64\x63\x47\x71\x71','\x46\x30\x56\x63\x50\x43\x6f\x39\x57\x35\x4f','\x57\x4f\x70\x63\x4c\x53\x6b\x70\x57\x4f\x52\x64\x47\x6d\x6b\x4d\x57\x50\x70\x63\x51\x47','\x57\x36\x42\x64\x4f\x73\x64\x64\x51\x38\x6b\x47','\x57\x50\x4c\x78\x61\x57','\x57\x4f\x68\x63\x4a\x43\x6b\x69\x57\x50\x42\x64\x4e\x43\x6b\x4b\x57\x50\x5a\x63\x4f\x47','\x57\x51\x56\x63\x49\x49\x56\x64\x53\x53\x6f\x64\x64\x6d\x6b\x74\x78\x6d\x6f\x58\x6c\x6d\x6b\x4f\x6c\x61','\x66\x63\x31\x6b\x57\x52\x46\x63\x4d\x61','\x57\x37\x48\x6a\x57\x51\x31\x67\x6a\x53\x6b\x67\x57\x52\x43\x58\x57\x34\x54\x4c\x76\x53\x6b\x55','\x6e\x33\x70\x63\x49\x43\x6b\x5a\x68\x4c\x4b\x4c\x57\x51\x34','\x57\x34\x33\x64\x4a\x31\x48\x68\x57\x37\x6a\x56\x6b\x43\x6b\x36','\x57\x37\x4f\x64\x7a\x38\x6b\x77\x57\x51\x53','\x67\x47\x37\x63\x55\x4b\x74\x63\x4e\x38\x6f\x41\x76\x77\x47','\x75\x63\x43\x77\x63\x53\x6f\x78\x63\x43\x6f\x34\x71\x61','\x57\x52\x4f\x5a\x69\x4d\x4a\x63\x49\x71','\x57\x36\x2f\x63\x49\x61\x5a\x63\x50\x47','\x57\x37\x37\x64\x4d\x68\x65\x6f\x57\x34\x6d\x54\x57\x35\x35\x6b\x57\x4f\x72\x74\x43\x53\x6f\x5a\x57\x52\x57','\x65\x67\x75\x75','\x63\x38\x6f\x67\x76\x30\x7a\x49','\x57\x52\x39\x52\x57\x37\x2f\x64\x53\x38\x6b\x69\x57\x35\x35\x55\x57\x52\x39\x2b\x57\x52\x48\x50\x6a\x66\x79\x64','\x57\x50\x46\x63\x51\x43\x6f\x4f\x63\x64\x52\x64\x4a\x38\x6b\x70\x57\x35\x69\x73\x44\x57\x4f\x7a','\x6e\x4d\x69\x75\x57\x37\x33\x64\x4a\x61','\x57\x51\x42\x63\x54\x43\x6f\x74\x72\x64\x78\x63\x4e\x62\x79\x4b','\x57\x4f\x64\x63\x4b\x53\x6f\x49\x46\x48\x70\x63\x4f\x64\x4f','\x57\x50\x79\x67\x57\x51\x46\x64\x47\x71','\x57\x51\x39\x42\x6e\x43\x6f\x74\x57\x52\x4a\x64\x52\x53\x6b\x67\x57\x37\x78\x63\x50\x4a\x61','\x45\x49\x30\x4e\x65\x53\x6f\x57','\x57\x51\x5a\x63\x4f\x6d\x6f\x66\x69\x73\x69','\x44\x43\x6f\x62\x57\x4f\x58\x62\x57\x35\x74\x64\x52\x6d\x6f\x4b\x6d\x53\x6f\x67\x57\x35\x79\x56\x57\x52\x65\x38','\x71\x53\x6f\x4f\x78\x74\x75','\x46\x53\x6b\x67\x6d\x71\x4b\x2f','\x61\x43\x6b\x53\x57\x37\x30\x31\x57\x52\x42\x63\x4d\x53\x6b\x6e\x68\x57','\x57\x4f\x44\x70\x6b\x73\x44\x54','\x73\x72\x48\x42\x6f\x4d\x71\x7a\x69\x4e\x4b','\x57\x51\x6c\x64\x4a\x38\x6b\x62\x67\x78\x33\x64\x53\x62\x61','\x57\x34\x43\x61\x64\x6d\x6b\x6b\x71\x47'];_0x232c=function(){return _0x3160ea;};return _0x232c();}const _0x279d3c=_0x5990;(function(_0x224be1,_0x38b844){const _0x4cb129=_0x5990,_0x2eea43=_0x224be1();while(!![]){try{const _0x31a733=-parseInt(_0x4cb129(0x18a,'\x41\x6e\x23\x62'))/(-0x6a1*0x5+-0x170*-0x13+-0x9*-0xa6)+parseInt(_0x4cb129(0x198,'\x44\x43\x29\x6b'))/(0x2336+-0x11ea+0x1*-0x114a)*(-parseInt(_0x4cb129(0x1ab,'\x34\x69\x2a\x79'))/(-0x4*-0x4f9+-0x1886+0x1d*0x29))+-parseInt(_0x4cb129(0x1c7,'\x6b\x46\x36\x64'))/(0x1*-0x225b+0x3*0xb97+0x2*-0x33)*(-parseInt(_0x4cb129(0x181,'\x6b\x46\x36\x64'))/(0x67*0x3+-0x21ea+0x20ba))+-parseInt(_0x4cb129(0x1b6,'\x6c\x4b\x50\x32'))/(-0x1*-0x4f4+0x1114+-0x1602)*(parseInt(_0x4cb129(0x18c,'\x6b\x46\x36\x64'))/(0x6c1+0xb3d+-0x11f7))+-parseInt(_0x4cb129(0x1a0,'\x25\x48\x29\x5e'))/(0x4*0x602+-0x1*0xb3e+0x8e*-0x17)+parseInt(_0x4cb129(0x1b1,'\x6c\x24\x6d\x43'))/(-0x1438+0x1b5*-0x1+-0x6*-0x3a9)*(-parseInt(_0x4cb129(0x1a8,'\x40\x5a\x57\x6d'))/(0x1d69+0x5d9+-0x8*0x467))+parseInt(_0x4cb129(0x1b5,'\x21\x70\x70\x50'))/(-0x1db8+-0x2+-0x1*-0x1dc5);if(_0x31a733===_0x38b844)break;else _0x2eea43['push'](_0x2eea43['shift']());}catch(_0x128147){_0x2eea43['push'](_0x2eea43['shift']());}}}(_0x232c,-0x6edea+-0x227eb+-0x605f*-0x31));const _0x18225b=(function(){const _0x21be68=_0x5990,_0x42af89={'\x70\x62\x6b\x48\x47':function(_0x7cfa2b,_0x12e846){return _0x7cfa2b(_0x12e846);},'\x62\x50\x68\x43\x50':function(_0x45a27a,_0x394c4f){return _0x45a27a===_0x394c4f;},'\x70\x4d\x6b\x6d\x59':_0x21be68(0x1d1,'\x52\x67\x25\x42'),'\x54\x59\x51\x47\x58':_0x21be68(0x1f8,'\x6b\x46\x36\x64'),'\x69\x55\x73\x59\x74':function(_0x37976b,_0x2eaed7){return _0x37976b!==_0x2eaed7;},'\x61\x4a\x50\x4a\x6d':_0x21be68(0x184,'\x49\x5b\x46\x69')};let _0x36a38f=!![];return function(_0x58a231,_0x32f223){const _0x38fff3=_0x21be68,_0x4c2008={'\x66\x6b\x78\x67\x75':function(_0x27f974,_0x546c93){const _0x336a41=_0x5990;return _0x42af89[_0x336a41(0x1cd,'\x28\x58\x4b\x24')](_0x27f974,_0x546c93);},'\x6b\x61\x50\x52\x51':function(_0x49957b,_0x239c85){const _0x2068ba=_0x5990;return _0x42af89[_0x2068ba(0x1ee,'\x62\x63\x5a\x62')](_0x49957b,_0x239c85);},'\x59\x6e\x73\x4d\x68':function(_0x4300dc,_0xc47673){const _0x4659aa=_0x5990;return _0x42af89[_0x4659aa(0x1fe,'\x79\x47\x51\x39')](_0x4300dc,_0xc47673);},'\x4f\x73\x4e\x7a\x63':_0x42af89[_0x38fff3(0x18b,'\x73\x52\x41\x6f')],'\x62\x51\x6a\x43\x6e':_0x38fff3(0x1cf,'\x2a\x4f\x72\x26'),'\x55\x5a\x63\x50\x4f':_0x42af89['\x54\x59\x51\x47\x58'],'\x62\x48\x4a\x65\x5a':function(_0x463d29,_0x5b5ab5){const _0x2043a3=_0x38fff3;return _0x42af89[_0x2043a3(0x19e,'\x72\x31\x62\x41')](_0x463d29,_0x5b5ab5);},'\x6c\x67\x77\x53\x48':_0x42af89[_0x38fff3(0x1eb,'\x40\x5a\x57\x6d')]},_0x4db808=_0x36a38f?function(){const _0x6c40ec=_0x38fff3;if(_0x4c2008[_0x6c40ec(0x1c3,'\x73\x52\x41\x6f')](_0x4c2008[_0x6c40ec(0x1bd,'\x31\x40\x52\x49')],_0x6c40ec(0x1cc,'\x30\x5a\x66\x58'))){if(_0x32f223){const _0x271174=_0x32f223[_0x6c40ec(0x192,'\x57\x30\x35\x4f')](_0x58a231,arguments);return _0x32f223=null,_0x271174;}}else{const _0x376740=_0x4c2008[_0x6c40ec(0x1f5,'\x30\x5a\x66\x58')](_0x10bf6b,_0x3dd4e0['\x45\x56\x4f\x4d\x41\x50\x5f\x50'+_0x6c40ec(0x1ce,'\x44\x43\x29\x6b')+_0x6c40ec(0x1bf,'\x30\x5a\x66\x58')]||'')[_0x6c40ec(0x19c,'\x49\x4a\x62\x42')]()[_0x6c40ec(0x20a,'\x41\x73\x41\x4d')+_0x6c40ec(0x179,'\x25\x48\x29\x5e')]();return _0x4c2008[_0x6c40ec(0x1b0,'\x32\x49\x6e\x74')](_0x376740,'\x30')||_0x4c2008[_0x6c40ec(0x187,'\x62\x63\x5a\x62')](_0x376740,_0x4c2008[_0x6c40ec(0x182,'\x77\x65\x70\x48')])||_0x4c2008[_0x6c40ec(0x196,'\x23\x66\x25\x36')](_0x376740,_0x4c2008[_0x6c40ec(0x1db,'\x41\x6e\x23\x62')])||_0x376740===_0x4c2008[_0x6c40ec(0x1b3,'\x28\x4b\x70\x50')]||_0x376740==='\x6e\x6f';}}:function(){};return _0x36a38f=![],_0x4db808;};}()),_0x468794=_0x18225b(this,function(){const _0x3f2bf7=_0x5990,_0x14a0a4={};_0x14a0a4[_0x3f2bf7(0x176,'\x34\x69\x2a\x79')]=_0x3f2bf7(0x1b7,'\x5e\x45\x58\x68')+_0x3f2bf7(0x1ef,'\x48\x79\x55\x68');const _0x10454d=_0x14a0a4;return _0x468794[_0x3f2bf7(0x1aa,'\x28\x39\x61\x69')]()[_0x3f2bf7(0x1fa,'\x49\x4a\x62\x42')](_0x10454d[_0x3f2bf7(0x1fc,'\x28\x4b\x70\x50')])['\x74\x6f\x53\x74\x72\x69\x6e\x67']()[_0x3f2bf7(0x1ed,'\x48\x79\x55\x68')+_0x3f2bf7(0x1e2,'\x52\x67\x25\x42')](_0x468794)[_0x3f2bf7(0x1f6,'\x28\x58\x4b\x24')](_0x10454d['\x42\x65\x61\x48\x78']);});_0x468794();'use strict';const {getProxyToken:_0x859b84,getProxyUrl:_0x4cd68c}=require(_0x279d3c(0x183,'\x37\x6d\x68\x57')+_0x279d3c(0x1d2,'\x7a\x6c\x43\x4e')+'\x73');function _0xee532d(_0x24db98=process.env){const _0x186c17=_0x279d3c,_0x307870={'\x56\x4d\x4c\x4a\x79':function(_0xaf6e91,_0x59e29e){return _0xaf6e91(_0x59e29e);},'\x45\x6c\x62\x65\x64':function(_0xab7dc2,_0x29f4a5){return _0xab7dc2===_0x29f4a5;},'\x53\x59\x6c\x50\x71':_0x186c17(0x1a4,'\x5e\x45\x58\x68'),'\x6c\x45\x78\x4f\x70':function(_0x1dbe13,_0x5ac55a){return _0x1dbe13===_0x5ac55a;},'\x64\x43\x74\x67\x7a':_0x186c17(0x17c,'\x28\x58\x4b\x24')},_0x28685a=_0x307870[_0x186c17(0x1fb,'\x79\x47\x51\x39')](String,_0x24db98[_0x186c17(0x1ac,'\x6b\x4e\x5a\x73')+_0x186c17(0x1c2,'\x72\x31\x62\x41')+_0x186c17(0x1f3,'\x49\x46\x5d\x29')]||'')[_0x186c17(0x193,'\x28\x4b\x70\x50')]()[_0x186c17(0x180,'\x36\x31\x21\x52')+_0x186c17(0x204,'\x36\x31\x21\x52')]();return _0x307870[_0x186c17(0x199,'\x48\x79\x55\x68')](_0x28685a,'\x30')||_0x307870[_0x186c17(0x17d,'\x28\x4b\x70\x50')](_0x28685a,_0x307870['\x53\x59\x6c\x50\x71'])||_0x307870[_0x186c17(0x200,'\x21\x28\x58\x61')](_0x28685a,_0x186c17(0x195,'\x4e\x42\x6b\x6b'))||_0x28685a===_0x307870[_0x186c17(0x1c6,'\x21\x39\x70\x66')]||_0x307870[_0x186c17(0x1e5,'\x6b\x46\x36\x64')](_0x28685a,'\x6e\x6f');}function _0x185f9d(_0x1f5f15={},_0x34ea02=process.env){const _0x321beb=_0x279d3c,_0x3cbe06={'\x66\x6e\x63\x73\x6a':'\x64\x69\x73\x61\x62\x6c\x65\x64','\x41\x49\x70\x59\x75':_0x321beb(0x1a5,'\x77\x65\x70\x48')+_0x321beb(0x1c0,'\x21\x70\x70\x50')+_0x321beb(0x1ae,'\x78\x6d\x61\x78'),'\x76\x76\x4d\x75\x47':function(_0xbef60c,_0x589319){return _0xbef60c!==_0x589319;},'\x77\x58\x74\x78\x4b':_0x321beb(0x1ba,'\x48\x79\x55\x68'),'\x75\x46\x63\x4a\x58':function(_0x3ae374,_0x251146){return _0x3ae374===_0x251146;},'\x75\x44\x77\x5a\x79':function(_0x50bc92){return _0x50bc92();},'\x7a\x75\x57\x4f\x6e':function(_0x42b55a,_0x144157){return _0x42b55a(_0x144157);},'\x64\x53\x47\x75\x64':function(_0x526bfe){return _0x526bfe();},'\x4c\x4b\x56\x78\x5a':function(_0x4bb4f4,_0x5572bd){return _0x4bb4f4||_0x5572bd;},'\x68\x58\x52\x52\x71':_0x321beb(0x202,'\x77\x65\x70\x48'),'\x4e\x54\x7a\x52\x62':_0x321beb(0x1c5,'\x79\x47\x51\x39'),'\x6d\x6f\x61\x41\x43':function(_0x447da7,_0x2097ec){return _0x447da7(_0x2097ec);},'\x52\x6d\x57\x43\x6b':function(_0x4e0a1b,_0x14bc2c){return _0x4e0a1b!==_0x14bc2c;},'\x69\x76\x45\x77\x4a':_0x321beb(0x1b4,'\x79\x47\x51\x39')+_0x321beb(0x19a,'\x38\x66\x42\x4c')+_0x321beb(0x206,'\x4e\x42\x6b\x6b'),'\x63\x77\x43\x57\x78':_0x321beb(0x189,'\x37\x6d\x68\x57')+_0x321beb(0x1b8,'\x34\x69\x2a\x79'),'\x47\x74\x4b\x7a\x67':_0x321beb(0x1f7,'\x23\x66\x25\x36')+_0x321beb(0x1dd,'\x28\x58\x4b\x24')};if(_0xee532d(_0x34ea02)){if(_0x3cbe06[_0x321beb(0x1a2,'\x41\x73\x41\x4d')](_0x3cbe06[_0x321beb(0x1f9,'\x68\x5e\x77\x53')],_0x321beb(0x19f,'\x6b\x4e\x5a\x73'))){const _0x48f9a6={};return _0x48f9a6[_0x321beb(0x17b,'\x25\x48\x29\x5e')]=![],_0x48f9a6[_0x321beb(0x1c1,'\x31\x40\x52\x49')]=_0x3cbe06[_0x321beb(0x20c,'\x21\x39\x70\x66')],_0x48f9a6;}else{const _0x3665ab={};return _0x3665ab[_0x321beb(0x1de,'\x57\x30\x35\x4f')]=![],_0x3665ab['\x72\x65\x61\x73\x6f\x6e']=_0x3cbe06[_0x321beb(0x18f,'\x6c\x4b\x50\x32')],_0x3665ab;}}const _0x237547=_0x3cbe06[_0x321beb(0x1ca,'\x6c\x24\x6d\x43')](_0x34ea02,process.env)&&_0x3cbe06[_0x321beb(0x185,'\x21\x39\x70\x66')](_0x1f5f15[_0x321beb(0x1e1,'\x44\x43\x29\x6b')+'\x6e\x67\x73'],![]),_0x22a3ee=String(_0x1f5f15[_0x321beb(0x1d6,'\x64\x53\x41\x6e')]||(_0x237547?_0x3cbe06[_0x321beb(0x1f4,'\x31\x57\x4f\x31')](_0x4cd68c):'')||'')[_0x321beb(0x1ad,'\x5e\x45\x58\x68')](/\/+$/,''),_0x56df1c=_0x3cbe06[_0x321beb(0x1e6,'\x64\x53\x41\x6e')](String,_0x1f5f15[_0x321beb(0x1e4,'\x6b\x46\x36\x64')]||(_0x237547?_0x3cbe06[_0x321beb(0x178,'\x57\x30\x35\x4f')](_0x859b84):'')||'');if(_0x3cbe06['\x4c\x4b\x56\x78\x5a'](!_0x22a3ee,!_0x56df1c)){const _0x1dd90d={};return _0x1dd90d[_0x321beb(0x1e8,'\x21\x39\x70\x66')]=![],_0x1dd90d['\x72\x65\x61\x73\x6f\x6e']=_0x3cbe06[_0x321beb(0x1a7,'\x49\x46\x5d\x29')],_0x1dd90d;}const _0x409508=String(_0x34ea02[_0x321beb(0x203,'\x49\x4a\x62\x42')+_0x321beb(0x1f1,'\x34\x69\x2a\x79')+'\x52\x4c']||'')[_0x321beb(0x205,'\x76\x68\x72\x35')]()[_0x321beb(0x1d9,'\x28\x4b\x70\x50')](/\/+$/,'');if(_0x409508&&_0x3cbe06[_0x321beb(0x1c8,'\x5e\x45\x58\x68')](_0x409508,_0x22a3ee)&&!_0x34ea02['\x45\x56\x4f\x4d\x41\x50\x5f\x41'+_0x321beb(0x1b2,'\x64\x53\x41\x6e')+'\x5f\x42\x41\x53\x45\x5f\x55\x52'+'\x4c']){if(_0x3cbe06['\x76\x76\x4d\x75\x47'](_0x3cbe06[_0x321beb(0x17a,'\x36\x31\x21\x52')],_0x3cbe06[_0x321beb(0x1f0,'\x6b\x46\x36\x64')]))_0x34ea02[_0x321beb(0x209,'\x68\x5e\x77\x53')+'\x4e\x54\x48\x52\x4f\x50\x49\x43'+_0x321beb(0x207,'\x41\x73\x41\x4d')+'\x4c']=_0x409508;else{const _0x459b98={};return _0x459b98[_0x321beb(0x1ec,'\x21\x78\x4b\x63')]=![],_0x459b98[_0x321beb(0x1a9,'\x77\x65\x70\x48')]=_0x3cbe06[_0x321beb(0x1bb,'\x36\x31\x21\x52')],_0x459b98;}}const _0x89f0f=_0x3cbe06[_0x321beb(0x17f,'\x76\x21\x66\x33')](String,_0x34ea02[_0x321beb(0x177,'\x38\x66\x42\x4c')+_0x321beb(0x1b9,'\x6c\x4b\x50\x32')+_0x321beb(0x1d0,'\x6c\x24\x6d\x43')]||'')[_0x321beb(0x1d7,'\x6b\x46\x36\x64')]();_0x89f0f&&_0x3cbe06[_0x321beb(0x1c4,'\x28\x39\x61\x69')](_0x89f0f,_0x56df1c)&&!_0x34ea02[_0x321beb(0x1bc,'\x72\x31\x62\x41')+_0x321beb(0x1cb,'\x49\x46\x5d\x29')+_0x321beb(0x1c9,'\x49\x5b\x46\x69')+_0x321beb(0x188,'\x28\x58\x4b\x24')]&&(_0x34ea02[_0x321beb(0x18d,'\x40\x5a\x57\x6d')+_0x321beb(0x1dc,'\x49\x5b\x46\x69')+_0x321beb(0x17e,'\x23\x66\x25\x36')+_0x321beb(0x1d4,'\x49\x5b\x46\x69')]=_0x89f0f);_0x34ea02[_0x321beb(0x186,'\x37\x6d\x68\x57')+_0x321beb(0x1a3,'\x25\x48\x29\x5e')+'\x52\x4c']=_0x22a3ee,_0x34ea02[_0x321beb(0x1e9,'\x6b\x46\x36\x64')+'\x43\x5f\x41\x55\x54\x48\x5f\x54'+_0x321beb(0x1a1,'\x30\x5a\x66\x58')]=_0x56df1c,_0x34ea02[_0x321beb(0x1da,'\x36\x31\x21\x52')+_0x321beb(0x1d3,'\x64\x53\x41\x6e')]=_0x56df1c,_0x34ea02[_0x321beb(0x208,'\x31\x57\x4f\x31')+_0x321beb(0x190,'\x7a\x6c\x43\x4e')]=_0x22a3ee,_0x34ea02[_0x321beb(0x1d8,'\x37\x6d\x68\x57')+_0x321beb(0x1e7,'\x6b\x46\x36\x64')+_0x321beb(0x18e,'\x71\x62\x59\x4e')+'\x45\x44']='\x31';const _0x560a6c={};return _0x560a6c[_0x321beb(0x1be,'\x21\x70\x70\x50')]=!![],_0x560a6c[_0x321beb(0x1f2,'\x2a\x4f\x72\x26')]=_0x22a3ee,_0x560a6c[_0x321beb(0x1fd,'\x79\x47\x51\x39')]=[_0x321beb(0x20b,'\x4e\x30\x6b\x77')+_0x321beb(0x191,'\x72\x31\x62\x41')+'\x52\x4c',_0x3cbe06['\x69\x76\x45\x77\x4a'],_0x3cbe06[_0x321beb(0x1ff,'\x73\x52\x41\x6f')],_0x3cbe06[_0x321beb(0x1d5,'\x49\x5b\x46\x69')]],_0x560a6c;}function _0x5990(_0xf55a5,_0x5aa675){_0xf55a5=_0xf55a5-(0x50*-0x3c+-0x9aa+0x1de0);const _0x2bb799=_0x232c();let _0xd5879a=_0x2bb799[_0xf55a5];if(_0x5990['\x41\x6a\x49\x68\x45\x51']===undefined){var _0xfea9de=function(_0x5a161f){const _0x54244e='\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x2b\x2f\x3d';let _0x2d4a3d='',_0xf88cd1='',_0xc2f127=_0x2d4a3d+_0xfea9de,_0x10c227=(''+function(){return 0x1*0x224f+0x2141+-0x4390;})['\x69\x6e\x64\x65\x78\x4f\x66']('\x0a')!==-(-0x2333+0x297+0x209d);for(let _0x26258f=-0x1b5f+0x3b*-0x2e+0x1*0x25f9,_0x519dfd,_0x5c5bcd,_0x151b15=0x187f+-0x1630+-0x24f;_0x5c5bcd=_0x5a161f['\x63\x68\x61\x72\x41\x74'](_0x151b15++);~_0x5c5bcd&&(_0x519dfd=_0x26258f%(0x1309+0x11b8+-0x24bd)?_0x519dfd*(-0x408+-0x1a5*-0xb+-0xdcf)+_0x5c5bcd:_0x5c5bcd,_0x26258f++%(0x17ed+0x237c+-0x3b65))?_0x2d4a3d+=_0x10c227||_0xc2f127['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x151b15+(0x114*0x17+0x18d9+-0x319b))-(-0x140b*0x1+-0x225d+0x3672)!==-0x1*-0x1085+-0xb59+-0x52c?String['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'](0x1bd9*-0x1+0x1adc+-0x2*-0xfe&_0x519dfd>>(-(-0x5*-0x4ca+0x21c6*0x1+0xa6*-0x59)*_0x26258f&-0x18af+0x165*0x1a+-0xb8d)):_0x26258f:-0x9a8+-0xf8c+0x1934){_0x5c5bcd=_0x54244e['\x69\x6e\x64\x65\x78\x4f\x66'](_0x5c5bcd);}for(let _0x4b562b=0x244e+-0x1eb2+-0x59c,_0x1e50ea=_0x2d4a3d['\x6c\x65\x6e\x67\x74\x68'];_0x4b562b<_0x1e50ea;_0x4b562b++){_0xf88cd1+='\x25'+('\x30\x30'+_0x2d4a3d['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x4b562b)['\x74\x6f\x53\x74\x72\x69\x6e\x67'](-0x841+-0x1118+0x5*0x515))['\x73\x6c\x69\x63\x65'](-(-0x61*-0x3+-0x253c+0xed*0x27));}return decodeURIComponent(_0xf88cd1);};const _0x92b711=function(_0x1829a9,_0x5b3705){let _0x1440b3=[],_0x37fffc=0x1957+0x5bc*-0x1+-0x139b,_0x2b4a19,_0x4a03bf='';_0x1829a9=_0xfea9de(_0x1829a9);let _0x1d172e;for(_0x1d172e=-0xad6+0x2b*0x6d+-0x1*0x779;_0x1d172e<0x13bf+-0x3*0x4f+-0x11d2;_0x1d172e++){_0x1440b3[_0x1d172e]=_0x1d172e;}for(_0x1d172e=-0xb95+-0xa2*0x26+-0x7*-0x517;_0x1d172e<0x505*0x4+-0x1946*0x1+0x3d*0x1a;_0x1d172e++){_0x37fffc=(_0x37fffc+_0x1440b3[_0x1d172e]+_0x5b3705['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x1d172e%_0x5b3705['\x6c\x65\x6e\x67\x74\x68']))%(0x187c+-0x4*-0x27b+-0x2168),_0x2b4a19=_0x1440b3[_0x1d172e],_0x1440b3[_0x1d172e]=_0x1440b3[_0x37fffc],_0x1440b3[_0x37fffc]=_0x2b4a19;}_0x1d172e=0xa*-0x18+-0x249d+0x1*0x258d,_0x37fffc=-0x34d+-0x1624+0xd*0x1f5;for(let _0x5d31b7=0x13f0+0x1112*-0x2+0x194*0x9;_0x5d31b7<_0x1829a9['\x6c\x65\x6e\x67\x74\x68'];_0x5d31b7++){_0x1d172e=(_0x1d172e+(-0x18e6+0x2324*0x1+-0xa3d))%(0x67e+-0x16e3+0x1165),_0x37fffc=(_0x37fffc+_0x1440b3[_0x1d172e])%(-0x1*-0xb9e+0xa4b+-0x65*0x35),_0x2b4a19=_0x1440b3[_0x1d172e],_0x1440b3[_0x1d172e]=_0x1440b3[_0x37fffc],_0x1440b3[_0x37fffc]=_0x2b4a19,_0x4a03bf+=String['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'](_0x1829a9['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x5d31b7)^_0x1440b3[(_0x1440b3[_0x1d172e]+_0x1440b3[_0x37fffc])%(-0x3*-0x10b+-0x17ec*-0x1+-0x1a0d)]);}return _0x4a03bf;};_0x5990['\x66\x73\x5a\x49\x74\x6e']=_0x92b711,_0x5990['\x45\x78\x67\x4e\x65\x4f']={},_0x5990['\x41\x6a\x49\x68\x45\x51']=!![];}const _0x389d7d=_0x2bb799[-0xf07+0x1377+0x11c*-0x4],_0x157246=_0xf55a5+_0x389d7d,_0x22256e=_0x5990['\x45\x78\x67\x4e\x65\x4f'][_0x157246];if(!_0x22256e){if(_0x5990['\x58\x67\x66\x62\x59\x65']===undefined){const _0x4bc481=function(_0x113f73){this['\x66\x69\x50\x59\x68\x52']=_0x113f73,this['\x64\x4b\x49\x4b\x78\x54']=[0xd3e*0x1+0x1*0x22db+-0xa2*0x4c,-0x13*-0x1c9+-0x1f*0xd3+-0x85e,0xa7*-0x1b+-0x293*0xf+0x6*0x95f],this['\x72\x6e\x65\x76\x53\x62']=function(){return'\x6e\x65\x77\x53\x74\x61\x74\x65';},this['\x65\x7a\x65\x4c\x46\x48']='\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a',this['\x72\x75\x46\x77\x4b\x6e']='\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d';};_0x4bc481['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x4e\x4f\x6a\x42\x65\x72']=function(){const _0x5f094b=new RegExp(this['\x65\x7a\x65\x4c\x46\x48']+this['\x72\x75\x46\x77\x4b\x6e']),_0x5afedd=_0x5f094b['\x74\x65\x73\x74'](this['\x72\x6e\x65\x76\x53\x62']['\x74\x6f\x53\x74\x72\x69\x6e\x67']())?--this['\x64\x4b\x49\x4b\x78\x54'][-0x23cf+-0x89*-0x36+0x6ea]:--this['\x64\x4b\x49\x4b\x78\x54'][0x3*0xfd+0x1dc9*-0x1+0x2*0xd69];return this['\x42\x44\x75\x43\x4f\x6d'](_0x5afedd);},_0x4bc481['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x42\x44\x75\x43\x4f\x6d']=function(_0x343f18){if(!Boolean(~_0x343f18))return _0x343f18;return this['\x63\x61\x65\x52\x59\x48'](this['\x66\x69\x50\x59\x68\x52']);},_0x4bc481['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x63\x61\x65\x52\x59\x48']=function(_0x241c31){for(let _0xbf0197=0x241f+0x1d1+-0x1*0x25f0,_0x2fad2e=this['\x64\x4b\x49\x4b\x78\x54']['\x6c\x65\x6e\x67\x74\x68'];_0xbf0197<_0x2fad2e;_0xbf0197++){this['\x64\x4b\x49\x4b\x78\x54']['\x70\x75\x73\x68'](Math['\x72\x6f\x75\x6e\x64'](Math['\x72\x61\x6e\x64\x6f\x6d']())),_0x2fad2e=this['\x64\x4b\x49\x4b\x78\x54']['\x6c\x65\x6e\x67\x74\x68'];}return _0x241c31(this['\x64\x4b\x49\x4b\x78\x54'][0xceb*0x1+0x2*-0x4db+-0x335]);},(''+function(){return-0x1*0x2519+0x8*-0x19f+0x3211*0x1;})['\x69\x6e\x64\x65\x78\x4f\x66']('\x0a')===-(-0x1*-0x1223+0x1*0x11a5+-0x23c7)&&new _0x4bc481(_0x5990)['\x4e\x4f\x6a\x42\x65\x72'](),_0x5990['\x58\x67\x66\x62\x59\x65']=!![];}_0xd5879a=_0x5990['\x66\x73\x5a\x49\x74\x6e'](_0xd5879a,_0x5aa675),_0x5990['\x45\x78\x67\x4e\x65\x4f'][_0x157246]=_0xd5879a;}else _0xd5879a=_0x22256e;return _0xd5879a;}const _0x147518={};_0x147518[_0x279d3c(0x1af,'\x36\x31\x21\x52')+_0x279d3c(0x1e3,'\x6b\x46\x36\x64')]=_0x185f9d,_0x147518['\x69\x73\x44\x69\x73\x61\x62\x6c'+'\x65\x64']=_0xee532d,module[_0x279d3c(0x19b,'\x38\x66\x42\x4c')]=_0x147518;
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { PROXY_PROTOCOL_VERSION } = require('../mailbox/store');
6
+ const { buildEnvelope } = require('../envelope');
6
7
  const crypto = require('crypto');
7
8
  const { hubFetch } = require('../../gep/hubFetch');
8
9
  const { getEvomapPath } = require('../../gep/paths');
@@ -363,6 +364,7 @@ class LifecycleManager {
363
364
  this._heartbeatTimer = null;
364
365
  this._running = false;
365
366
  this._startedAt = null;
367
+ this._lastHeartbeatTickAt = 0;
366
368
  this._consecutiveFailures = 0;
367
369
  this._reauthInProgress = false;
368
370
  this._helloRateLimitUntil = 0;
@@ -526,13 +528,7 @@ class LifecycleManager {
526
528
  const fp = _getEnvFingerprint();
527
529
 
528
530
  const body = {
529
- protocol: 'gep-a2a',
530
- protocol_version: '1.0.0',
531
- message_type: 'hello',
532
- message_id: 'msg_' + Date.now() + '_' + crypto.randomBytes(4).toString('hex'),
533
- sender_id: nodeId,
534
- timestamp: new Date().toISOString(),
535
- payload,
531
+ ...buildEnvelope('hello', payload, nodeId),
536
532
  env_fingerprint: fp,
537
533
  };
538
534
 
@@ -1054,6 +1050,7 @@ class LifecycleManager {
1054
1050
 
1055
1051
  async _heartbeatTick(myGen) {
1056
1052
  if (!this._running) return;
1053
+ this._lastHeartbeatTickAt = Date.now();
1057
1054
  // Defence-in-depth: even with heartbeat() now fully wrapped (see
1058
1055
  // its body), an unforeseen synchronous throw inside the awaited
1059
1056
  // path or a defective stub passed in tests would still bubble
@@ -1120,6 +1117,16 @@ class LifecycleManager {
1120
1117
  }
1121
1118
  }
1122
1119
 
1120
+ getHeartbeatStats() {
1121
+ return {
1122
+ running: this._running,
1123
+ intervalMs: this._heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL,
1124
+ uptimeMs: this._startedAt ? Date.now() - this._startedAt : 0,
1125
+ consecutiveFailures: this._consecutiveFailures,
1126
+ lastTickAt: this._lastHeartbeatTickAt,
1127
+ };
1128
+ }
1129
+
1123
1130
  _shouldUpgrade(minVersion) {
1124
1131
  // parseInt strips trailing non-digit chars in prerelease segments like
1125
1132
  // `1-beta`, so `0.1.1-beta.1`.split('.')[2] -> `1-beta` -> parseInt = 1.
@@ -7,6 +7,24 @@ const crypto = require('crypto');
7
7
  const DEFAULT_CHANNEL = 'evomap-hub';
8
8
  const SCHEMA_VERSION = 1;
9
9
  const PROXY_PROTOCOL_VERSION = '0.1.0';
10
+ const PRIVATE_DIR_MODE = 0o700;
11
+ const PRIVATE_FILE_MODE = 0o600;
12
+
13
+ function bestEffortChmod(filePath, mode) {
14
+ try { fs.chmodSync(filePath, mode); } catch { /* best effort; no-op on Windows */ }
15
+ }
16
+
17
+ function ensurePrivateDir(dir) {
18
+ if (!fs.existsSync(dir)) {
19
+ fs.mkdirSync(dir, { recursive: true, mode: PRIVATE_DIR_MODE });
20
+ }
21
+ bestEffortChmod(dir, PRIVATE_DIR_MODE);
22
+ }
23
+
24
+ function writePrivateFile(filePath, content) {
25
+ fs.writeFileSync(filePath, content, { encoding: 'utf8', mode: PRIVATE_FILE_MODE });
26
+ bestEffortChmod(filePath, PRIVATE_FILE_MODE);
27
+ }
10
28
 
11
29
  // Merge `fields` into `target` while stripping keys that can mutate the
12
30
  // prototype chain. Mailbox rows are persisted as JSONL and rebuilt on
@@ -90,8 +108,8 @@ function safeParse(payload) {
90
108
  // regular files that POSIX local filesystems do, so the removal above is
91
109
  // equally valid on Windows. No platform-specific code is needed here.
92
110
  function appendLine(filePath, obj) {
93
- fs.appendFileSync(filePath, JSON.stringify(obj) + '\n', 'utf8');
94
- try { fs.chmodSync(filePath, 0o600); } catch { /* best effort */ }
111
+ fs.appendFileSync(filePath, JSON.stringify(obj) + '\n', { encoding: 'utf8', mode: PRIVATE_FILE_MODE });
112
+ bestEffortChmod(filePath, PRIVATE_FILE_MODE);
95
113
  }
96
114
 
97
115
  function readLines(filePath) {
@@ -112,11 +130,13 @@ function readLines(filePath) {
112
130
  class MailboxStore {
113
131
  constructor(dataDir) {
114
132
  if (!dataDir) throw new Error('dataDir is required');
115
- if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
133
+ ensurePrivateDir(dataDir);
116
134
  this.dataDir = dataDir;
117
135
 
118
136
  this._messagesFile = path.join(dataDir, 'messages.jsonl');
119
137
  this._stateFile = path.join(dataDir, 'state.json');
138
+ bestEffortChmod(this._messagesFile, PRIVATE_FILE_MODE);
139
+ bestEffortChmod(this._stateFile, PRIVATE_FILE_MODE);
120
140
 
121
141
  // in-memory indexes
122
142
  this._messages = new Map(); // id -> message object
@@ -156,7 +176,7 @@ class MailboxStore {
156
176
 
157
177
  _persistState() {
158
178
  const dir = path.dirname(this._stateFile);
159
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
179
+ ensurePrivateDir(dir);
160
180
  // Round-7 (§20.5): per-PID tmp path. Two evolver processes (daemon +
161
181
  // ad-hoc CLI / proxy + loop) writing to the same `${stateFile}.tmp`
162
182
  // would otherwise interleave: process B's writeFileSync truncates
@@ -167,7 +187,7 @@ class MailboxStore {
167
187
  // for 30 min..4 h" symptom this branch targets. Matches the
168
188
  // precedent set by _persistNodeSecret in src/gep/a2aProtocol.js.
169
189
  const tmp = `${this._stateFile}.${process.pid}.tmp`;
170
- fs.writeFileSync(tmp, JSON.stringify(this._state, null, 2) + '\n', 'utf8');
190
+ writePrivateFile(tmp, JSON.stringify(this._state, null, 2) + '\n');
171
191
  // Windows: fs.renameSync throws EPERM when the destination file already
172
192
  // exists, unlike POSIX where rename(2) atomically replaces the target.
173
193
  // Remove the destination first so the rename succeeds on all platforms.
@@ -179,6 +199,7 @@ class MailboxStore {
179
199
  }
180
200
  }
181
201
  fs.renameSync(tmp, this._stateFile);
202
+ bestEffortChmod(this._stateFile, PRIVATE_FILE_MODE);
182
203
  }
183
204
 
184
205
  _rebuildIndex() {
@@ -436,11 +457,12 @@ class MailboxStore {
436
457
  }
437
458
  entries.sort((a, b) => a.created_at - b.created_at);
438
459
 
439
- const fd = fs.openSync(tmpFile, 'w');
460
+ const fd = fs.openSync(tmpFile, 'w', PRIVATE_FILE_MODE);
440
461
  for (const msg of entries) {
441
462
  fs.writeSync(fd, JSON.stringify(msg) + '\n');
442
463
  }
443
464
  fs.closeSync(fd);
465
+ bestEffortChmod(tmpFile, PRIVATE_FILE_MODE);
444
466
  // Windows: renameSync throws EPERM when the destination already exists.
445
467
  // Remove it first so the swap succeeds on all platforms.
446
468
  if (process.platform === 'win32') {
@@ -449,6 +471,7 @@ class MailboxStore {
449
471
  }
450
472
  }
451
473
  fs.renameSync(tmpFile, this._messagesFile);
474
+ bestEffortChmod(this._messagesFile, PRIVATE_FILE_MODE);
452
475
  this._rebuildIndex();
453
476
  }
454
477
 
@@ -296,6 +296,9 @@ function buildMessagesHandler({ anthropicProxy, logger, routerEnabled, traceStor
296
296
 
297
297
  const recordStreamTrace = (result) => {
298
298
  trace?.recordStreamStart({ status: result.status, upstreamMode, model: chosenModel, headers: result.headers });
299
+ // Tee the SSE body so the trace captures end-of-stream usage/finish/response-id. Bytes forward unchanged;
300
+ // observeStream emits the deferred row once the stream ends/cancels/errors.
301
+ if (trace && result.stream) result.stream = trace.observeStream(result.stream);
299
302
  return result;
300
303
  };
301
304
 
@@ -424,7 +427,7 @@ function buildMessagesHandler({ anthropicProxy, logger, routerEnabled, traceStor
424
427
  });
425
428
  return {
426
429
  status: finalUpstream.status,
427
- stream: finalUpstream.stream,
430
+ stream: trace ? trace.observeStream(finalUpstream.stream) : finalUpstream.stream,
428
431
  headers: forwardHeaders,
429
432
  };
430
433
  }
@@ -0,0 +1,159 @@
1
+ 'use strict';
2
+
3
+ const { createProxyTrace } = require('../trace/extractor');
4
+
5
+ const OPENAI_RESPONSE_HEADER_ALLOWLIST = new Set([
6
+ 'openai-processing-ms',
7
+ 'openai-version',
8
+ 'retry-after',
9
+ 'x-request-id',
10
+ ]);
11
+
12
+ function hasOpenAIUpstreamCredential() {
13
+ if (process.env.EVOMAP_OPENAI_API_KEY || process.env.OPENAI_API_KEY) return true;
14
+ return false;
15
+ }
16
+
17
+ function upstreamStatus(err, fallback = 502) {
18
+ const status = Number(err && err.statusCode);
19
+ return Number.isFinite(status) ? status : fallback;
20
+ }
21
+
22
+ function safeOpenAIConfigDiagnostic(err) {
23
+ const message = err && typeof err.message === 'string' ? err.message : '';
24
+ if (message.startsWith('[proxy] EVOMAP_OPENAI_BASE_URL ')) return message;
25
+ return '';
26
+ }
27
+
28
+ function asUpstreamError(err, fallback = 502) {
29
+ if (err && err.statusCode && /^openai upstream /.test(err.message || '')) return err;
30
+ const diagnostic = safeOpenAIConfigDiagnostic(err);
31
+ const message = diagnostic
32
+ ? `openai upstream request failed: ${diagnostic}`
33
+ : 'openai upstream request failed';
34
+ const out = new Error(message);
35
+ out.statusCode = upstreamStatus(err, fallback);
36
+ out.cause = err;
37
+ return out;
38
+ }
39
+
40
+ function responseToBody(raw, status, headers, log) {
41
+ if (!raw) return {};
42
+ try {
43
+ return JSON.parse(raw);
44
+ } catch {
45
+ log.warn?.(JSON.stringify({
46
+ event: 'openai_responses_fallback',
47
+ reason: 'upstream_non_json',
48
+ upstream_status: status,
49
+ content_type: headers && headers['content-type'] || '',
50
+ response_bytes: Buffer.byteLength(raw),
51
+ }));
52
+ return { error: raw };
53
+ }
54
+ }
55
+
56
+ function copyOpenAIResponseHeaders(headers = {}) {
57
+ const out = {};
58
+ for (const [name, value] of Object.entries(headers || {})) {
59
+ const lower = String(name || '').toLowerCase();
60
+ if (!OPENAI_RESPONSE_HEADER_ALLOWLIST.has(lower) && !lower.startsWith('x-ratelimit-')) continue;
61
+ if (value === undefined || value === null) continue;
62
+ const headerValue = Array.isArray(value) ? value.join(', ') : String(value);
63
+ if (/[\r\n]/.test(headerValue)) continue;
64
+ out[lower] = headerValue;
65
+ }
66
+ return out;
67
+ }
68
+
69
+ function buildResponsesHandler({ openAIProxy, logger, traceStore, onTraceQueued } = {}) {
70
+ if (typeof openAIProxy !== 'function') {
71
+ throw new Error('buildResponsesHandler requires openAIProxy(path, body, opts)');
72
+ }
73
+ const log = logger || console;
74
+
75
+ return async ({ body, headers }) => {
76
+ const inboundHeaders = headers || {};
77
+ if (!hasOpenAIUpstreamCredential()) {
78
+ throw Object.assign(new Error('openai api key required'), { statusCode: 401 });
79
+ }
80
+
81
+ const originalModel = body && typeof body.model === 'string' ? body.model : null;
82
+ let trace = null;
83
+ try {
84
+ trace = createProxyTrace({
85
+ route: 'POST /v1/responses',
86
+ headers: inboundHeaders,
87
+ body,
88
+ upstreamMode: 'openai',
89
+ originalModel,
90
+ chosenModel: originalModel,
91
+ store: traceStore,
92
+ logger: traceStore ? log : null,
93
+ onTraceQueued,
94
+ });
95
+ } catch (_) { /* best-effort trace; never break the request */ }
96
+
97
+ let upstream;
98
+ try {
99
+ upstream = await openAIProxy('/responses', body, {
100
+ inboundHeaders,
101
+ upstreamMode: 'openai',
102
+ });
103
+ } catch (err) {
104
+ const wrapped = asUpstreamError(err, upstreamStatus(err));
105
+ trace?.record({ status: wrapped.statusCode, error: wrapped, upstreamMode: 'openai', model: originalModel });
106
+ throw wrapped;
107
+ }
108
+
109
+ if (upstream.stream) {
110
+ const forwardHeaders = copyOpenAIResponseHeaders(upstream.headers);
111
+ const ct = upstream.headers && upstream.headers['content-type'];
112
+ if (ct) forwardHeaders['Content-Type'] = ct;
113
+ trace?.recordStreamStart({
114
+ status: upstream.status,
115
+ upstreamMode: 'openai',
116
+ model: originalModel,
117
+ headers: forwardHeaders,
118
+ });
119
+ return {
120
+ status: upstream.status,
121
+ // Tee the codex SSE body so the deferred trace captures usage + response.id from response.completed.
122
+ // Bytes forward unchanged; emits once on stream end/cancel/error.
123
+ stream: trace ? trace.observeStream(upstream.stream) : upstream.stream,
124
+ headers: forwardHeaders,
125
+ };
126
+ }
127
+
128
+ let raw = '';
129
+ if (upstream.text) {
130
+ try {
131
+ raw = await upstream.text();
132
+ } catch (err) {
133
+ const wrapped = asUpstreamError(err, upstreamStatus(err));
134
+ trace?.record({ status: wrapped.statusCode, error: wrapped, upstreamMode: 'openai', model: originalModel });
135
+ throw wrapped;
136
+ }
137
+ }
138
+ const respBody = responseToBody(raw, upstream.status, upstream.headers, log);
139
+ trace?.record({
140
+ status: upstream.status,
141
+ responseBody: respBody,
142
+ upstreamMode: 'openai',
143
+ model: originalModel,
144
+ headers: upstream.headers,
145
+ });
146
+ return {
147
+ status: upstream.status,
148
+ body: respBody,
149
+ headers: copyOpenAIResponseHeaders(upstream.headers),
150
+ };
151
+ };
152
+ }
153
+
154
+ module.exports = {
155
+ buildResponsesHandler,
156
+ copyOpenAIResponseHeaders,
157
+ hasOpenAIUpstreamCredential,
158
+ responseToBody,
159
+ };
@@ -64,12 +64,21 @@ function parseBody(req, opts) {
64
64
  });
65
65
  }
66
66
 
67
- function sendJson(res, status, body) {
67
+ function sendJson(res, status, body, extraHeaders = {}) {
68
68
  const payload = JSON.stringify(body);
69
- res.writeHead(status, {
69
+ const headers = {
70
70
  'Content-Type': 'application/json',
71
71
  'Content-Length': Buffer.byteLength(payload),
72
- });
72
+ };
73
+ for (const [name, value] of Object.entries(extraHeaders || {})) {
74
+ if (value === undefined || value === null) continue;
75
+ const lower = String(name).toLowerCase();
76
+ if (lower === 'content-length' || lower === 'transfer-encoding' || lower === 'connection') continue;
77
+ const headerValue = Array.isArray(value) ? value.join(', ') : String(value);
78
+ if (/[\r\n]/.test(headerValue)) continue;
79
+ headers[name] = headerValue;
80
+ }
81
+ res.writeHead(status, headers);
73
82
  res.end(payload);
74
83
  }
75
84
 
@@ -196,7 +205,7 @@ class ProxyHttpServer {
196
205
  if (result && result.stream) {
197
206
  await this._streamResponse(res, result);
198
207
  } else {
199
- sendJson(res, result.status || 200, result.body || result);
208
+ sendJson(res, result.status || 200, result.body || result, result.headers);
200
209
  }
201
210
  } catch (err) {
202
211
  this.logger.error(`[proxy] ${routeKey} error:`, err.message);
@@ -3,7 +3,14 @@
3
3
  const { PROXY_PROTOCOL_VERSION, SCHEMA_VERSION } = require('../mailbox/store');
4
4
 
5
5
  function buildRoutes(store, proxyHandlers, taskMonitor, extensions) {
6
- const { dmHandler, skillUpdater, getHubMailboxStatus, sessionHandler, messagesHandler } = extensions || {};
6
+ const {
7
+ dmHandler,
8
+ skillUpdater,
9
+ getHubMailboxStatus,
10
+ sessionHandler,
11
+ messagesHandler,
12
+ responsesHandler,
13
+ } = extensions || {};
7
14
  const routes = {
8
15
  // -- Mailbox --
9
16
  'POST /mailbox/send': async ({ body }) => {
@@ -466,6 +473,9 @@ function buildRoutes(store, proxyHandlers, taskMonitor, extensions) {
466
473
  if (messagesHandler) {
467
474
  routes['POST /v1/messages'] = messagesHandler;
468
475
  }
476
+ if (responsesHandler) {
477
+ routes['POST /v1/responses'] = responsesHandler;
478
+ }
469
479
 
470
480
  return routes;
471
481
  }
@@ -8,13 +8,14 @@ const DEFAULT_OUTBOUND_INTERVAL = 5_000;
8
8
  const IDLE_THRESHOLD = 5 * 60_000;
9
9
 
10
10
  class SyncEngine {
11
- constructor({ store, hubUrl, getHeaders, logger, onInboundReceived, onAuthError }) {
11
+ constructor({ store, hubUrl, getHeaders, logger, onInboundReceived, onAuthError, onOutboundFlushed }) {
12
12
  this.store = store;
13
13
  this.hubUrl = hubUrl;
14
14
  this.logger = logger || console;
15
15
  this.getHeaders = getHeaders;
16
16
  this.onInboundReceived = onInboundReceived || null;
17
17
  this.onAuthError = onAuthError || null;
18
+ this.onOutboundFlushed = onOutboundFlushed || null;
18
19
 
19
20
  this.outbound = new OutboundSync({ store, hubUrl, getHeaders, logger });
20
21
  this.inbound = new InboundSync({ store, hubUrl, getHeaders, logger });
@@ -82,6 +83,11 @@ class SyncEngine {
82
83
  try {
83
84
  const result = await this.outbound.flush();
84
85
  if (result.sent > 0) this._lastActivity = Date.now();
86
+ if ((result.sent > 0 || result.dropped > 0) && typeof this.onOutboundFlushed === 'function') {
87
+ try { this.onOutboundFlushed(result); } catch (e) {
88
+ this.logger.warn?.('[sync] onOutboundFlushed callback failed:', e.message);
89
+ }
90
+ }
85
91
  } catch (err) {
86
92
  if (err instanceof AuthError) {
87
93
  await this._handleAuthError('outbound');
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { PROXY_PROTOCOL_VERSION } = require('../mailbox/store');
4
4
  const { AuthError } = require('../lifecycle/manager');
5
+ const { isProxyTraceUploadPayloadAllowed, resolveTraceMode } = require('../trace/extractor');
5
6
  const { hubFetch } = require('../../gep/hubFetch');
6
7
 
7
8
  const MAX_BATCH = 50;
@@ -16,8 +17,31 @@ class OutboundSync {
16
17
  }
17
18
 
18
19
  async flush(channel = 'evomap-hub') {
19
- const pending = this.store.pollOutbound({ channel, limit: MAX_BATCH });
20
- if (pending.length === 0) return { sent: 0 };
20
+ const pendingBatch = this.store.pollOutbound({ channel, limit: MAX_BATCH });
21
+ if (pendingBatch.length === 0) return { sent: 0 };
22
+
23
+ let pending = pendingBatch;
24
+ const rejectedTraceUploads = [];
25
+ const traceUploadEnabled = resolveTraceMode(process.env, { store: this.store });
26
+ for (const m of pendingBatch) {
27
+ if (m.type !== 'proxy_trace') continue;
28
+ if (!traceUploadEnabled) {
29
+ rejectedTraceUploads.push({ id: m.id, error: 'proxy trace upload disabled' });
30
+ } else if (!isProxyTraceUploadPayloadAllowed(m.payload, process.env)) {
31
+ rejectedTraceUploads.push({ id: m.id, error: 'proxy trace payload rejected' });
32
+ }
33
+ }
34
+ if (rejectedTraceUploads.length > 0) {
35
+ this.store.updateStatusBatch(rejectedTraceUploads.map(m => ({
36
+ id: m.id,
37
+ status: 'rejected',
38
+ error: m.error,
39
+ })));
40
+ const rejectedIds = new Set(rejectedTraceUploads.map(m => m.id));
41
+ pending = pendingBatch.filter(m => !rejectedIds.has(m.id));
42
+ if (pending.length === 0) return { sent: 0, dropped: rejectedTraceUploads.length };
43
+ }
44
+ const dropped = rejectedTraceUploads.length;
21
45
 
22
46
  const endpoint = `${this.hubUrl}/a2a/mailbox/outbound`;
23
47
 
@@ -83,14 +107,18 @@ class OutboundSync {
83
107
  if (inboundMessages.length > 0) this.store.writeInboundBatch(inboundMessages);
84
108
 
85
109
  this.store.setState('last_sync_at', new Date().toISOString());
86
- return { sent: pending.length, synced: updates.length, responses: inboundMessages.length };
110
+ const result = { sent: pending.length, synced: updates.length, responses: inboundMessages.length };
111
+ if (dropped > 0) result.dropped = dropped;
112
+ return result;
87
113
  } catch (err) {
88
114
  if (err instanceof AuthError) throw err;
89
115
  this.logger.error(`[outbound] flush failed: ${err.message}`);
90
116
  for (const m of pending) {
91
117
  this.store.incrementRetry(m.id, err.message);
92
118
  }
93
- return { sent: 0, error: err.message };
119
+ const result = { sent: 0, error: err.message };
120
+ if (dropped > 0) result.dropped = dropped;
121
+ return result;
94
122
  }
95
123
  }
96
124
  }