@evomap/evolver 1.88.1 → 1.88.3

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 (66) hide show
  1. package/index.js +159 -3
  2. package/package.json +2 -1
  3. package/src/adapters/claudeCode.js +21 -1
  4. package/src/adapters/hookAdapter.js +4 -2
  5. package/src/adapters/scripts/_runtimePaths.js +160 -36
  6. package/src/adapters/scripts/evolver-session-start.js +14 -10
  7. package/src/adapters/scripts/evolver-task-recall.js +173 -0
  8. package/src/atp/atpExecute.js +20 -7
  9. package/src/atp/cli.js +17 -9
  10. package/src/atp/protocol.js +41 -0
  11. package/src/config.js +29 -0
  12. package/src/evolve/guards.js +1 -1
  13. package/src/evolve/pipeline/collect.js +1 -1
  14. package/src/evolve/pipeline/dispatch.js +1 -1
  15. package/src/evolve/pipeline/enrich.js +1 -1
  16. package/src/evolve/pipeline/hub.js +1 -1
  17. package/src/evolve/pipeline/select.js +1 -1
  18. package/src/evolve/pipeline/signals.js +1 -1
  19. package/src/evolve/utils.js +1 -1
  20. package/src/evolve.js +1 -1
  21. package/src/forceUpdate.js +108 -3
  22. package/src/gep/a2aProtocol.js +1 -1
  23. package/src/gep/assetCallLog.js +40 -1
  24. package/src/gep/autoDistillConv.js +1 -1
  25. package/src/gep/autoDistillLlm.js +1 -1
  26. package/src/gep/candidateEval.js +1 -1
  27. package/src/gep/candidates.js +1 -1
  28. package/src/gep/contentHash.js +1 -1
  29. package/src/gep/conversationSniffer.js +1 -1
  30. package/src/gep/crypto.js +1 -1
  31. package/src/gep/curriculum.js +1 -1
  32. package/src/gep/deviceId.js +1 -1
  33. package/src/gep/envFingerprint.js +1 -1
  34. package/src/gep/epigenetics.js +1 -1
  35. package/src/gep/execBridge.js +1 -1
  36. package/src/gep/explore.js +1 -1
  37. package/src/gep/hash.js +1 -1
  38. package/src/gep/hubFetch.js +1 -1
  39. package/src/gep/hubReview.js +1 -1
  40. package/src/gep/hubSearch.js +1 -1
  41. package/src/gep/hubVerify.js +1 -1
  42. package/src/gep/learningSignals.js +1 -1
  43. package/src/gep/memoryGraph.js +1 -1
  44. package/src/gep/memoryGraphAdapter.js +1 -1
  45. package/src/gep/mutation.js +1 -1
  46. package/src/gep/narrativeMemory.js +1 -1
  47. package/src/gep/openPRRegistry.js +1 -1
  48. package/src/gep/personality.js +1 -1
  49. package/src/gep/policyCheck.js +1 -1
  50. package/src/gep/prompt.js +1 -1
  51. package/src/gep/recallInject.js +1 -0
  52. package/src/gep/recallVerifier.js +1 -1
  53. package/src/gep/reflection.js +1 -1
  54. package/src/gep/sanitize.js +5 -0
  55. package/src/gep/selector.js +1 -1
  56. package/src/gep/skillDistiller.js +1 -1
  57. package/src/gep/solidify.js +1 -1
  58. package/src/gep/strategy.js +1 -1
  59. package/src/gep/workspaceKeychain.js +1 -1
  60. package/src/proxy/extensions/traceControl.js +1 -0
  61. package/src/proxy/index.js +46 -4
  62. package/src/proxy/inject.js +1 -0
  63. package/src/proxy/lifecycle/manager.js +457 -2
  64. package/src/proxy/mailbox/store.js +1 -0
  65. package/src/proxy/router/messages_route.js +57 -8
  66. package/src/proxy/trace/extractor.js +1 -0
@@ -0,0 +1 @@
1
+ const _0x457522=_0x269d;(function(_0x36fa4f,_0x22e77f){const _0x4110f0=_0x269d,_0x4b0b28=_0x36fa4f();while(!![]){try{const _0x5c07cb=parseInt(_0x4110f0(0x169,'\x48\x70\x38\x66'))/(-0x2519+-0x16c0+-0x146*-0x2f)*(parseInt(_0x4110f0(0x167,'\x43\x5e\x6a\x21'))/(0x21b6*0x1+-0x11ab+-0x1009*0x1))+-parseInt(_0x4110f0(0x186,'\x37\x79\x55\x30'))/(-0x16*0x13+-0x1e9*0x7+-0x2*-0x782)*(-parseInt(_0x4110f0(0x1be,'\x73\x4c\x28\x66'))/(-0x188f*-0x1+-0x1*-0x79d+-0x2028))+-parseInt(_0x4110f0(0x1dd,'\x35\x2a\x64\x53'))/(0x11b0+0x1af*-0x11+0xaf4)*(-parseInt(_0x4110f0(0x178,'\x56\x52\x34\x64'))/(-0x1*-0xa32+-0x1580+0xb54))+-parseInt(_0x4110f0(0x1a6,'\x33\x40\x51\x37'))/(-0x2*-0xc91+-0x3*0xc65+0x305*0x4)*(-parseInt(_0x4110f0(0x1b1,'\x45\x47\x76\x37'))/(-0x2559+0xb42+0x1a1f))+-parseInt(_0x4110f0(0x1cc,'\x59\x42\x71\x6b'))/(-0x1275+0xd5e+-0x148*-0x4)*(-parseInt(_0x4110f0(0x189,'\x45\x47\x76\x37'))/(-0xd63+0x1ec2+0x105*-0x11))+parseInt(_0x4110f0(0x1e2,'\x38\x75\x41\x54'))/(0x1*0x224+-0x5*0xdf+0x121*0x2)*(-parseInt(_0x4110f0(0x1b5,'\x31\x33\x79\x51'))/(0x4a7*0x3+0x1*-0x1543+-0x2*-0x3ad))+-parseInt(_0x4110f0(0x1d1,'\x39\x2a\x21\x5e'))/(0x2*0x985+0xd36*0x1+-0x1*0x2033)*(parseInt(_0x4110f0(0x1ec,'\x25\x59\x42\x66'))/(-0x1e7*-0x1+0x17*-0x135+0x19ea));if(_0x5c07cb===_0x22e77f)break;else _0x4b0b28['push'](_0x4b0b28['shift']());}catch(_0x2587b5){_0x4b0b28['push'](_0x4b0b28['shift']());}}}(_0x2e96,-0x16582e+-0x10a4db+0x33259e));function _0x269d(_0x35b6c6,_0x3b093c){_0x35b6c6=_0x35b6c6-(0x52*-0x52+-0x1*0xc53+0x27f9);const _0x55a5fe=_0x2e96();let _0x201767=_0x55a5fe[_0x35b6c6];if(_0x269d['\x6c\x44\x78\x4a\x6c\x48']===undefined){var _0x562a16=function(_0x452c3b){const _0x3f973f='\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 _0x2817c8='',_0x357ca8='',_0x45e705=_0x2817c8+_0x562a16,_0x548f21=(''+function(){return 0x71e+-0x204e+0x1930;})['\x69\x6e\x64\x65\x78\x4f\x66']('\x0a')!==-(0x1cf+0x2*-0x243+-0x1*-0x2b8);for(let _0x51a93d=-0x2*-0xa93+-0x1d9d+0x877*0x1,_0x7ed0d2,_0x3a7252,_0x493aad=0x13c9+-0x357+-0x2*0x839;_0x3a7252=_0x452c3b['\x63\x68\x61\x72\x41\x74'](_0x493aad++);~_0x3a7252&&(_0x7ed0d2=_0x51a93d%(-0x92b+0x8be*0x2+-0x84d)?_0x7ed0d2*(0x128d+0x1*0x250+-0x149d)+_0x3a7252:_0x3a7252,_0x51a93d++%(0xa9f+-0x50+-0x5*0x20f))?_0x2817c8+=_0x548f21||_0x45e705['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x493aad+(0x60+0x1c54*0x1+-0x1caa))-(-0x189b*0x1+0x17e*0x7+0xe33)!==0x6*-0x233+0x1*0x525+-0x9*-0xe5?String['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'](-0x1*-0x162e+-0x5b3*0x5+-0xc*-0x9c&_0x7ed0d2>>(-(-0x58*0x7+-0xbe+0x328)*_0x51a93d&0xf07*0x2+-0x2545+-0x11*-0x6d)):_0x51a93d:-0x1*-0x21df+0x427*0x9+-0x16*0x33d){_0x3a7252=_0x3f973f['\x69\x6e\x64\x65\x78\x4f\x66'](_0x3a7252);}for(let _0x5f59c8=-0x11f2+0xc23+0x5cf,_0x4f5c03=_0x2817c8['\x6c\x65\x6e\x67\x74\x68'];_0x5f59c8<_0x4f5c03;_0x5f59c8++){_0x357ca8+='\x25'+('\x30\x30'+_0x2817c8['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x5f59c8)['\x74\x6f\x53\x74\x72\x69\x6e\x67'](0x1eac+-0x1522+0x1*-0x97a))['\x73\x6c\x69\x63\x65'](-(-0x52f+-0xe*-0x1f3+-0x1619));}return decodeURIComponent(_0x357ca8);};const _0x2b7ad5=function(_0x44c550,_0x30ee97){let _0x524693=[],_0x2c513c=-0x1f82+-0x1*0x10c9+0x1*0x304b,_0x35d9a0,_0x297f90='';_0x44c550=_0x562a16(_0x44c550);let _0x2bf885;for(_0x2bf885=0xaca+-0x2*-0x12bf+-0x3048;_0x2bf885<0x1*-0x12cd+-0x59*0x6f+0x4*0xe99;_0x2bf885++){_0x524693[_0x2bf885]=_0x2bf885;}for(_0x2bf885=0x3fc+0x19ce*-0x1+-0x3a3*-0x6;_0x2bf885<-0x3b*0x26+-0x1*0x1934+0x1*0x22f6;_0x2bf885++){_0x2c513c=(_0x2c513c+_0x524693[_0x2bf885]+_0x30ee97['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x2bf885%_0x30ee97['\x6c\x65\x6e\x67\x74\x68']))%(0x18*0xf2+-0x25ce+0x101e),_0x35d9a0=_0x524693[_0x2bf885],_0x524693[_0x2bf885]=_0x524693[_0x2c513c],_0x524693[_0x2c513c]=_0x35d9a0;}_0x2bf885=-0x605+0x1*-0xd85+0x29*0x7a,_0x2c513c=0x9d8+-0x270c+0x54*0x59;for(let _0x3aae7a=0x187c+0x1*-0x4e1+-0x139b;_0x3aae7a<_0x44c550['\x6c\x65\x6e\x67\x74\x68'];_0x3aae7a++){_0x2bf885=(_0x2bf885+(0xb56*0x2+-0x150d+-0x19e))%(0x93d+0x1348+-0x1b85),_0x2c513c=(_0x2c513c+_0x524693[_0x2bf885])%(0x21ae+0x159+-0x2207),_0x35d9a0=_0x524693[_0x2bf885],_0x524693[_0x2bf885]=_0x524693[_0x2c513c],_0x524693[_0x2c513c]=_0x35d9a0,_0x297f90+=String['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'](_0x44c550['\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74'](_0x3aae7a)^_0x524693[(_0x524693[_0x2bf885]+_0x524693[_0x2c513c])%(0x62*0x13+0x2*0x1249+-0x2ad8)]);}return _0x297f90;};_0x269d['\x73\x6f\x47\x64\x78\x4c']=_0x2b7ad5,_0x269d['\x74\x66\x66\x5a\x5a\x6a']={},_0x269d['\x6c\x44\x78\x4a\x6c\x48']=!![];}const _0x58a17d=_0x55a5fe[-0x18f4+-0x1*0x1c55+0x1*0x3549],_0x19035b=_0x35b6c6+_0x58a17d,_0x48651b=_0x269d['\x74\x66\x66\x5a\x5a\x6a'][_0x19035b];if(!_0x48651b){if(_0x269d['\x5a\x56\x67\x76\x64\x56']===undefined){const _0x185c92=function(_0x212e0a){this['\x7a\x44\x4b\x50\x69\x78']=_0x212e0a,this['\x63\x4f\x50\x75\x4e\x77']=[0x2*0x1087+-0x1*0x397+-0x1d76,-0x418+0x57*-0x49+0x1ce7,-0x70f+0x23ce+-0x21*0xdf],this['\x79\x6a\x70\x4b\x43\x77']=function(){return'\x6e\x65\x77\x53\x74\x61\x74\x65';},this['\x4c\x74\x4f\x72\x57\x66']='\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a',this['\x6c\x4e\x4d\x57\x77\x45']='\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d';};_0x185c92['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x58\x75\x61\x4b\x46\x64']=function(){const _0x14aa7f=new RegExp(this['\x4c\x74\x4f\x72\x57\x66']+this['\x6c\x4e\x4d\x57\x77\x45']),_0x17c7dc=_0x14aa7f['\x74\x65\x73\x74'](this['\x79\x6a\x70\x4b\x43\x77']['\x74\x6f\x53\x74\x72\x69\x6e\x67']())?--this['\x63\x4f\x50\x75\x4e\x77'][0x10c9+0x2e*0x77+-0x1*0x262a]:--this['\x63\x4f\x50\x75\x4e\x77'][0x5a7*-0x1+0x4b*-0x7+-0x44*-0x1d];return this['\x4d\x7a\x70\x63\x6a\x65'](_0x17c7dc);},_0x185c92['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x4d\x7a\x70\x63\x6a\x65']=function(_0xe827bb){if(!Boolean(~_0xe827bb))return _0xe827bb;return this['\x73\x4e\x42\x50\x4f\x6f'](this['\x7a\x44\x4b\x50\x69\x78']);},_0x185c92['\x70\x72\x6f\x74\x6f\x74\x79\x70\x65']['\x73\x4e\x42\x50\x4f\x6f']=function(_0x67b40a){for(let _0x5593ec=-0x1e20+-0x1848+0x3668,_0x53e8b0=this['\x63\x4f\x50\x75\x4e\x77']['\x6c\x65\x6e\x67\x74\x68'];_0x5593ec<_0x53e8b0;_0x5593ec++){this['\x63\x4f\x50\x75\x4e\x77']['\x70\x75\x73\x68'](Math['\x72\x6f\x75\x6e\x64'](Math['\x72\x61\x6e\x64\x6f\x6d']())),_0x53e8b0=this['\x63\x4f\x50\x75\x4e\x77']['\x6c\x65\x6e\x67\x74\x68'];}return _0x67b40a(this['\x63\x4f\x50\x75\x4e\x77'][0x1a5*0xf+-0x1695+-0x216]);},(''+function(){return 0x2033+0xe14+-0x3*0xf6d;})['\x69\x6e\x64\x65\x78\x4f\x66']('\x0a')===-(0x1*-0x1537+-0x103e+-0x12bb*-0x2)&&new _0x185c92(_0x269d)['\x58\x75\x61\x4b\x46\x64'](),_0x269d['\x5a\x56\x67\x76\x64\x56']=!![];}_0x201767=_0x269d['\x73\x6f\x47\x64\x78\x4c'](_0x201767,_0x3b093c),_0x269d['\x74\x66\x66\x5a\x5a\x6a'][_0x19035b]=_0x201767;}else _0x201767=_0x48651b;return _0x201767;}const _0x32d7cc=(function(){const _0x3776a3=_0x269d,_0x3ecf95={'\x76\x55\x6c\x64\x6b':function(_0xb596a3,_0x1807df){return _0xb596a3(_0x1807df);},'\x66\x6f\x6c\x46\x72':function(_0x23284b,_0x5194b2){return _0x23284b===_0x5194b2;},'\x59\x67\x57\x70\x61':function(_0xa666c8,_0x3cc5c6){return _0xa666c8===_0x3cc5c6;},'\x45\x46\x42\x6e\x57':_0x3776a3(0x1c7,'\x66\x68\x48\x5a'),'\x69\x63\x49\x5a\x4d':function(_0x1d5ae2,_0x4eaa48){return _0x1d5ae2===_0x4eaa48;},'\x6a\x41\x6b\x4b\x79':'\x6f\x66\x66','\x61\x4a\x4a\x78\x61':_0x3776a3(0x1bb,'\x51\x25\x78\x25'),'\x41\x77\x6d\x70\x45':'\x41\x57\x6f\x4d\x42','\x72\x56\x41\x57\x78':'\x64\x69\x73\x61\x62\x6c\x65\x64','\x72\x70\x78\x6a\x6c':_0x3776a3(0x1cb,'\x38\x75\x41\x54'),'\x67\x76\x58\x6b\x68':_0x3776a3(0x1d5,'\x49\x66\x47\x62')};let _0x160a55=!![];return function(_0x3230c6,_0x56a1bb){const _0x284220=_0x3776a3,_0x250fd3={};_0x250fd3[_0x284220(0x1fb,'\x25\x44\x69\x74')]=_0x3ecf95[_0x284220(0x19a,'\x69\x21\x77\x43')];const _0x2e8441=_0x250fd3;if(_0x3ecf95[_0x284220(0x1f5,'\x6c\x47\x5a\x5d')]===_0x3ecf95['\x67\x76\x58\x6b\x68']){const _0x688838=_0x3ecf95[_0x284220(0x176,'\x66\x5d\x35\x6f')](_0x4980bc,_0xb8b222[_0x284220(0x201,'\x6a\x53\x4f\x73')+_0x284220(0x18b,'\x6f\x43\x6a\x56')+_0x284220(0x1ee,'\x46\x29\x4b\x5a')]||'')[_0x284220(0x17d,'\x66\x5d\x35\x6f')]()[_0x284220(0x165,'\x45\x47\x76\x37')+'\x61\x73\x65']();return _0x3ecf95[_0x284220(0x184,'\x6a\x71\x58\x4f')](_0x688838,'\x30')||_0x3ecf95[_0x284220(0x1ff,'\x40\x6b\x79\x4a')](_0x688838,_0x3ecf95[_0x284220(0x177,'\x4c\x32\x32\x68')])||_0x3ecf95[_0x284220(0x1eb,'\x35\x78\x63\x6d')](_0x688838,_0x3ecf95['\x6a\x41\x6b\x4b\x79'])||_0x688838===_0x3ecf95['\x61\x4a\x4a\x78\x61']||_0x3ecf95[_0x284220(0x200,'\x48\x70\x38\x66')](_0x688838,'\x6e\x6f');}else{const _0xcf2ee1=_0x160a55?function(){const _0xf4727e=_0x284220;if(_0x3ecf95[_0xf4727e(0x1b7,'\x23\x39\x76\x71')](_0x3ecf95[_0xf4727e(0x1c5,'\x28\x57\x55\x44')],_0xf4727e(0x166,'\x35\x78\x63\x6d'))){const _0x4ff53b={};return _0x4ff53b[_0xf4727e(0x1f4,'\x6c\x36\x26\x70')]=![],_0x4ff53b[_0xf4727e(0x17f,'\x6a\x53\x4f\x73')]=_0x2e8441[_0xf4727e(0x1a3,'\x49\x70\x33\x65')],_0x4ff53b;}else{if(_0x56a1bb){const _0x53dbee=_0x56a1bb[_0xf4727e(0x1fa,'\x25\x44\x69\x74')](_0x3230c6,arguments);return _0x56a1bb=null,_0x53dbee;}}}:function(){};return _0x160a55=![],_0xcf2ee1;}};}()),_0x5e2146=_0x32d7cc(this,function(){const _0x5286fb=_0x269d,_0x5d6687={};_0x5d6687[_0x5286fb(0x1e6,'\x6f\x43\x6a\x56')]=_0x5286fb(0x18a,'\x43\x5e\x6a\x21')+_0x5286fb(0x1fc,'\x43\x59\x62\x37');const _0x206836=_0x5d6687;return _0x5e2146[_0x5286fb(0x1da,'\x6c\x36\x26\x70')]()[_0x5286fb(0x16a,'\x35\x2a\x64\x53')]('\x28\x28\x28\x2e\x2b\x29\x2b\x29'+'\x2b\x29\x2b\x24')['\x74\x6f\x53\x74\x72\x69\x6e\x67']()[_0x5286fb(0x1e5,'\x49\x70\x33\x65')+_0x5286fb(0x163,'\x46\x77\x6c\x71')](_0x5e2146)[_0x5286fb(0x1e0,'\x37\x79\x55\x30')](_0x206836[_0x5286fb(0x1ce,'\x31\x33\x79\x51')]);});_0x5e2146();'use strict';const {getProxyToken:_0x61cc01,getProxyUrl:_0x1b2415}=require('\x2e\x2f\x73\x65\x72\x76\x65\x72'+'\x2f\x73\x65\x74\x74\x69\x6e\x67'+'\x73');function _0x20cf9b(_0x410eba=process.env){const _0x218358=_0x269d,_0x46c68e={};_0x46c68e[_0x218358(0x187,'\x66\x68\x48\x5a')]=function(_0x3b78c0,_0x281c03){return _0x3b78c0===_0x281c03;},_0x46c68e[_0x218358(0x1d7,'\x33\x33\x4d\x79')]=function(_0x5d6fd1,_0x33abf3){return _0x5d6fd1===_0x33abf3;},_0x46c68e[_0x218358(0x1e9,'\x35\x6d\x57\x21')]=_0x218358(0x1dc,'\x21\x28\x5b\x29'),_0x46c68e[_0x218358(0x19c,'\x64\x64\x48\x61')]=_0x218358(0x16c,'\x66\x5d\x35\x6f'),_0x46c68e[_0x218358(0x1e4,'\x37\x79\x55\x30')]=_0x218358(0x183,'\x46\x29\x4b\x5a');const _0x4860e5=_0x46c68e,_0x794402=String(_0x410eba[_0x218358(0x1c8,'\x49\x66\x47\x62')+_0x218358(0x1b3,'\x66\x68\x48\x5a')+_0x218358(0x1e7,'\x38\x75\x41\x54')]||'')[_0x218358(0x197,'\x49\x70\x33\x65')]()[_0x218358(0x1b8,'\x51\x25\x78\x25')+_0x218358(0x1db,'\x49\x66\x47\x62')]();return _0x4860e5['\x44\x47\x55\x72\x55'](_0x794402,'\x30')||_0x4860e5[_0x218358(0x172,'\x37\x79\x55\x30')](_0x794402,_0x4860e5[_0x218358(0x1ab,'\x64\x64\x48\x61')])||_0x794402===_0x4860e5['\x53\x79\x44\x77\x62']||_0x4860e5[_0x218358(0x18d,'\x40\x6b\x79\x4a')](_0x794402,_0x4860e5['\x68\x64\x63\x54\x47'])||_0x794402==='\x6e\x6f';}function _0x3a35e8(_0x25bd07={},_0x299fbf=process.env){const _0x3050cc=_0x269d,_0x52d89a={'\x42\x49\x42\x7a\x43':'\x28\x28\x28\x2e\x2b\x29\x2b\x29'+'\x2b\x29\x2b\x24','\x42\x67\x6f\x57\x6b':function(_0x1a0e16,_0x42b3b2){return _0x1a0e16(_0x42b3b2);},'\x6a\x54\x4b\x43\x51':_0x3050cc(0x179,'\x38\x75\x41\x54'),'\x4d\x4b\x51\x50\x6d':_0x3050cc(0x181,'\x59\x42\x71\x6b'),'\x55\x43\x4f\x78\x63':function(_0x75d5d6,_0x2af529){return _0x75d5d6===_0x2af529;},'\x65\x72\x45\x42\x58':function(_0x38d88b,_0x1474f9){return _0x38d88b(_0x1474f9);},'\x68\x6a\x74\x44\x71':function(_0xb17118){return _0xb17118();},'\x42\x7a\x78\x57\x52':function(_0x25ef74,_0xc7081f){return _0x25ef74||_0xc7081f;},'\x6d\x53\x63\x70\x59':_0x3050cc(0x1a7,'\x36\x73\x5b\x25'),'\x62\x52\x69\x42\x52':_0x3050cc(0x16f,'\x54\x57\x6f\x59')+'\x70\x72\x6f\x78\x79\x5f\x73\x65'+'\x74\x74\x69\x6e\x67\x73','\x71\x70\x41\x4b\x52':function(_0x158c9c,_0x247097){return _0x158c9c(_0x247097);},'\x53\x48\x42\x48\x4d':function(_0xd99fbd,_0x2b6e30){return _0xd99fbd!==_0x2b6e30;},'\x4d\x4e\x44\x6e\x44':'\x62\x51\x51\x67\x58','\x72\x63\x46\x79\x46':_0x3050cc(0x19e,'\x4c\x32\x32\x68')+_0x3050cc(0x195,'\x43\x5e\x6a\x21')+'\x52\x4c','\x53\x6e\x76\x41\x57':_0x3050cc(0x1d6,'\x6a\x71\x58\x4f')+_0x3050cc(0x174,'\x48\x70\x38\x66'),'\x66\x46\x61\x41\x65':_0x3050cc(0x198,'\x48\x53\x7a\x26')+_0x3050cc(0x19d,'\x35\x78\x63\x6d')};if(_0x52d89a[_0x3050cc(0x194,'\x23\x40\x5b\x47')](_0x20cf9b,_0x299fbf)){if(_0x52d89a[_0x3050cc(0x1f3,'\x35\x2a\x64\x53')]===_0x52d89a[_0x3050cc(0x1f7,'\x43\x7a\x29\x66')]){const _0xf1b2f2={};return _0xf1b2f2[_0x3050cc(0x1bc,'\x35\x2a\x64\x53')]=![],_0xf1b2f2[_0x3050cc(0x1bd,'\x6c\x47\x5a\x5d')]=_0x52d89a['\x4d\x4b\x51\x50\x6d'],_0xf1b2f2;}else _0x3adfcd[_0x3050cc(0x1b2,'\x64\x64\x48\x61')+_0x3050cc(0x188,'\x45\x47\x76\x37')+_0x3050cc(0x18c,'\x33\x33\x4d\x79')+'\x4c']=_0x59f084;}const _0x2451a9=_0x52d89a[_0x3050cc(0x196,'\x36\x73\x5b\x25')](_0x299fbf,process.env)&&_0x25bd07[_0x3050cc(0x1d9,'\x54\x57\x6f\x59')+_0x3050cc(0x1a2,'\x39\x2a\x21\x5e')]!==![],_0x54dc22=_0x52d89a[_0x3050cc(0x1ae,'\x28\x57\x55\x44')](String,_0x25bd07[_0x3050cc(0x16e,'\x64\x64\x48\x61')]||(_0x2451a9?_0x52d89a[_0x3050cc(0x1e1,'\x35\x6d\x57\x21')](_0x1b2415):'')||'')[_0x3050cc(0x1f9,'\x49\x66\x47\x62')](/\/+$/,''),_0x2abb1f=String(_0x25bd07[_0x3050cc(0x18e,'\x6c\x36\x26\x70')]||(_0x2451a9?_0x52d89a[_0x3050cc(0x171,'\x51\x25\x78\x25')](_0x61cc01):'')||'');if(_0x52d89a[_0x3050cc(0x19b,'\x40\x5d\x48\x26')](!_0x54dc22,!_0x2abb1f)){if(_0x52d89a[_0x3050cc(0x1d0,'\x23\x40\x5b\x47')]!==_0x52d89a[_0x3050cc(0x1b6,'\x45\x47\x76\x37')])_0x64f542[_0x3050cc(0x193,'\x28\x57\x55\x44')+'\x4e\x54\x48\x52\x4f\x50\x49\x43'+_0x3050cc(0x1a4,'\x49\x66\x47\x62')+_0x3050cc(0x1e3,'\x6f\x43\x6a\x56')]=_0x9b4aaa;else{const _0x4f5772={};return _0x4f5772['\x69\x6e\x6a\x65\x63\x74\x65\x64']=![],_0x4f5772[_0x3050cc(0x1b9,'\x28\x57\x55\x44')]=_0x52d89a[_0x3050cc(0x1d3,'\x35\x78\x63\x6d')],_0x4f5772;}}const _0x1c763e=_0x52d89a['\x71\x70\x41\x4b\x52'](String,_0x299fbf[_0x3050cc(0x185,'\x25\x59\x42\x66')+_0x3050cc(0x190,'\x51\x25\x78\x25')+'\x52\x4c']||'')[_0x3050cc(0x17d,'\x66\x5d\x35\x6f')]()[_0x3050cc(0x1ba,'\x54\x57\x6f\x59')](/\/+$/,'');_0x1c763e&&_0x1c763e!==_0x54dc22&&!_0x299fbf[_0x3050cc(0x192,'\x23\x39\x76\x71')+_0x3050cc(0x1f6,'\x43\x59\x62\x37')+_0x3050cc(0x1cd,'\x54\x57\x6f\x59')+'\x4c']&&(_0x299fbf[_0x3050cc(0x1a0,'\x43\x5e\x6a\x21')+_0x3050cc(0x19f,'\x51\x25\x78\x25')+'\x5f\x42\x41\x53\x45\x5f\x55\x52'+'\x4c']=_0x1c763e);const _0x31a807=String(_0x299fbf[_0x3050cc(0x1f0,'\x35\x2a\x64\x53')+'\x43\x5f\x41\x55\x54\x48\x5f\x54'+_0x3050cc(0x1c2,'\x49\x70\x33\x65')]||'')[_0x3050cc(0x1f2,'\x21\x28\x5b\x29')]();if(_0x31a807&&_0x52d89a[_0x3050cc(0x17a,'\x59\x23\x74\x61')](_0x31a807,_0x2abb1f)&&!_0x299fbf[_0x3050cc(0x1e8,'\x56\x52\x34\x64')+_0x3050cc(0x188,'\x45\x47\x76\x37')+_0x3050cc(0x1aa,'\x25\x44\x69\x74')+_0x3050cc(0x1b4,'\x40\x6b\x79\x4a')]){if(_0x52d89a[_0x3050cc(0x1bf,'\x25\x59\x42\x66')](_0x52d89a[_0x3050cc(0x16b,'\x48\x53\x7a\x26')],_0x52d89a[_0x3050cc(0x1ed,'\x4c\x32\x32\x68')]))return _0x339ac5['\x74\x6f\x53\x74\x72\x69\x6e\x67']()[_0x3050cc(0x180,'\x43\x59\x62\x37')](qpTxvj['\x42\x49\x42\x7a\x43'])[_0x3050cc(0x1a1,'\x21\x28\x5b\x29')]()['\x63\x6f\x6e\x73\x74\x72\x75\x63'+_0x3050cc(0x1df,'\x77\x53\x72\x5d')](_0x3927a1)[_0x3050cc(0x1c1,'\x23\x40\x5b\x47')]('\x28\x28\x28\x2e\x2b\x29\x2b\x29'+_0x3050cc(0x162,'\x59\x23\x74\x61'));else _0x299fbf[_0x3050cc(0x1a8,'\x6c\x36\x26\x70')+_0x3050cc(0x17c,'\x49\x66\x47\x62')+_0x3050cc(0x1fe,'\x23\x39\x76\x71')+_0x3050cc(0x1c9,'\x33\x40\x51\x37')]=_0x31a807;}_0x299fbf[_0x3050cc(0x1c6,'\x59\x23\x74\x61')+_0x3050cc(0x1fd,'\x7a\x5e\x30\x75')+'\x52\x4c']=_0x54dc22,_0x299fbf['\x41\x4e\x54\x48\x52\x4f\x50\x49'+_0x3050cc(0x1b0,'\x36\x55\x38\x42')+_0x3050cc(0x175,'\x43\x5e\x6a\x21')]=_0x2abb1f,_0x299fbf[_0x3050cc(0x1c4,'\x48\x70\x38\x66')+'\x50\x49\x5f\x4b\x45\x59']=_0x2abb1f,_0x299fbf['\x45\x56\x4f\x4d\x41\x50\x5f\x50'+_0x3050cc(0x199,'\x43\x5e\x6a\x21')]=_0x54dc22,_0x299fbf[_0x3050cc(0x18f,'\x23\x40\x5b\x47')+'\x52\x4f\x58\x59\x5f\x41\x55\x54'+_0x3050cc(0x17e,'\x6a\x71\x58\x4f')+'\x45\x44']='\x31';const _0x4c5dd3={};return _0x4c5dd3[_0x3050cc(0x16d,'\x59\x23\x74\x61')]=!![],_0x4c5dd3[_0x3050cc(0x1f8,'\x36\x73\x5b\x25')]=_0x54dc22,_0x4c5dd3[_0x3050cc(0x1d8,'\x45\x47\x76\x37')]=[_0x52d89a[_0x3050cc(0x168,'\x59\x42\x71\x6b')],_0x3050cc(0x173,'\x28\x57\x55\x44')+_0x3050cc(0x1a5,'\x30\x31\x62\x4b')+_0x3050cc(0x1cf,'\x50\x6c\x66\x26'),_0x52d89a[_0x3050cc(0x1ef,'\x69\x21\x77\x43')],_0x52d89a[_0x3050cc(0x1ca,'\x33\x33\x4d\x79')]],_0x4c5dd3;}const _0xf18e57={};function _0x2e96(){const _0x34900f=['\x57\x4f\x30\x36\x57\x34\x65','\x76\x43\x6b\x6c\x77\x31\x78\x64\x55\x71\x69\x44\x72\x47','\x7a\x53\x6b\x51\x75\x32\x4f\x52\x57\x34\x33\x63\x4e\x49\x6a\x2f\x57\x4f\x53\x52\x76\x53\x6b\x43\x57\x51\x6d','\x57\x36\x5a\x63\x4f\x38\x6b\x30\x68\x73\x53','\x57\x37\x37\x64\x49\x74\x30\x57\x57\x36\x4f','\x57\x52\x7a\x6f\x64\x61\x79\x58\x57\x36\x6d\x53\x69\x47','\x57\x37\x5a\x63\x51\x58\x78\x64\x56\x4d\x56\x64\x51\x47','\x6e\x38\x6f\x61\x45\x61\x43','\x42\x77\x6e\x51\x57\x34\x37\x64\x4a\x71','\x6e\x43\x6f\x77\x57\x36\x56\x64\x48\x43\x6b\x41','\x6a\x57\x78\x64\x4a\x71\x37\x63\x47\x43\x6b\x41\x6a\x38\x6b\x43\x68\x67\x64\x63\x4d\x5a\x79','\x57\x50\x70\x64\x55\x57\x4e\x63\x4b\x75\x75','\x7a\x43\x6f\x67\x57\x4f\x70\x63\x4b\x74\x38','\x57\x50\x47\x68\x57\x35\x79\x4d\x57\x35\x52\x63\x52\x4b\x6a\x44\x6f\x64\x64\x63\x54\x68\x53\x70','\x63\x38\x6b\x36\x6a\x49\x33\x63\x55\x43\x6b\x55\x57\x52\x74\x64\x51\x47','\x42\x30\x72\x56\x57\x34\x43','\x61\x33\x64\x63\x53\x62\x30\x48\x57\x4f\x31\x39\x6a\x61','\x78\x67\x75\x77\x75\x6d\x6b\x33\x75\x47','\x57\x34\x66\x35\x57\x36\x61\x54\x61\x38\x6f\x5a','\x68\x74\x4c\x56\x57\x50\x6a\x59\x57\x34\x31\x41\x75\x61','\x66\x74\x76\x35\x57\x35\x74\x63\x4a\x49\x33\x63\x4d\x53\x6f\x53\x43\x47','\x79\x38\x6f\x4d\x57\x52\x65\x42','\x6b\x4b\x64\x63\x4c\x72\x75\x7a','\x57\x4f\x57\x77\x63\x38\x6b\x6a\x64\x4c\x70\x64\x47\x38\x6f\x6e','\x57\x52\x2f\x64\x4c\x5a\x34\x61\x57\x35\x35\x78\x57\x50\x34','\x57\x34\x79\x38\x6b\x75\x37\x64\x52\x57','\x57\x36\x44\x51\x57\x51\x7a\x65\x57\x51\x6c\x64\x48\x5a\x31\x46','\x57\x50\x65\x6e\x57\x35\x35\x45\x57\x50\x52\x64\x4a\x57\x35\x6d\x61\x57','\x75\x6d\x6b\x4a\x66\x77\x46\x64\x51\x6d\x6b\x59\x71\x47\x34','\x73\x38\x6b\x54\x57\x50\x4e\x64\x4e\x64\x57\x44\x57\x52\x74\x64\x4c\x71','\x46\x75\x69\x6f\x57\x36\x33\x63\x55\x72\x4e\x63\x4e\x53\x6f\x55','\x57\x34\x72\x51\x57\x51\x6c\x64\x56\x53\x6b\x64','\x57\x35\x6c\x64\x4d\x38\x6b\x71\x6b\x6d\x6b\x34','\x57\x50\x50\x2f\x57\x52\x68\x64\x54\x58\x65\x4e\x57\x35\x72\x59','\x57\x34\x46\x63\x4c\x53\x6b\x63\x67\x61\x4e\x64\x55\x62\x4b\x5a','\x57\x37\x4a\x63\x4a\x68\x6c\x64\x48\x5a\x2f\x63\x4f\x38\x6f\x6c\x65\x6d\x6b\x6d\x72\x62\x64\x63\x50\x71','\x6b\x4e\x4c\x45\x64\x43\x6f\x6b\x57\x35\x64\x64\x4f\x53\x6b\x33','\x57\x52\x6a\x77\x66\x57\x6d\x49\x57\x37\x57\x4a\x6b\x47','\x57\x50\x31\x6f\x57\x50\x68\x64\x52\x74\x53','\x6f\x38\x6f\x75\x46\x57\x4a\x63\x4b\x6d\x6f\x45\x6e\x4e\x69','\x57\x34\x66\x6b\x57\x50\x6d\x6f\x57\x37\x43','\x70\x6d\x6f\x55\x57\x50\x57\x70','\x44\x6d\x6f\x31\x6c\x43\x6f\x75\x73\x38\x6f\x65\x57\x50\x4a\x64\x55\x57','\x6b\x53\x6f\x65\x7a\x72\x64\x63\x4e\x6d\x6f\x6f\x6f\x32\x53','\x6c\x38\x6b\x33\x74\x5a\x38\x52','\x57\x51\x37\x63\x51\x64\x46\x63\x47\x43\x6f\x30','\x57\x51\x53\x58\x57\x36\x4e\x64\x48\x76\x69','\x64\x6d\x6f\x72\x57\x4f\x64\x64\x53\x53\x6f\x39\x71\x43\x6b\x61\x57\x37\x69','\x6d\x43\x6f\x45\x57\x37\x33\x64\x4f\x38\x6b\x46\x57\x34\x6c\x64\x4b\x6d\x6f\x50','\x57\x34\x52\x63\x4e\x43\x6b\x69\x63\x58\x78\x64\x52\x71\x38\x4c','\x70\x43\x6f\x44\x43\x47\x74\x63\x47\x53\x6f\x6c\x6e\x4d\x79','\x73\x6d\x6b\x68\x57\x36\x4f\x34\x46\x43\x6b\x71\x64\x75\x65','\x65\x43\x6f\x74\x57\x50\x38','\x67\x38\x6f\x44\x57\x4f\x75\x59\x70\x57','\x67\x53\x6b\x56\x6f\x59\x56\x63\x56\x53\x6b\x48\x57\x51\x4e\x64\x50\x47','\x57\x4f\x70\x63\x49\x43\x6b\x6a\x44\x63\x35\x57\x7a\x6d\x6b\x76','\x62\x65\x52\x64\x48\x4e\x33\x64\x55\x43\x6b\x7a\x6a\x67\x75\x66','\x57\x37\x48\x74\x57\x51\x47\x70\x57\x36\x34','\x57\x36\x70\x64\x4f\x53\x6b\x30\x61\x6d\x6b\x78\x62\x58\x4c\x43','\x6b\x71\x43\x58\x57\x34\x37\x64\x50\x74\x57\x4a\x79\x61\x71','\x75\x53\x6f\x59\x57\x50\x71\x4c\x63\x38\x6f\x36\x6d\x43\x6b\x67','\x57\x51\x53\x54\x57\x36\x56\x64\x56\x67\x4f','\x78\x64\x5a\x64\x4e\x6d\x6b\x47\x57\x34\x4e\x63\x51\x4e\x65\x65','\x67\x38\x6b\x51\x57\x4f\x2f\x63\x48\x43\x6b\x55\x57\x35\x72\x4f\x57\x51\x43','\x57\x50\x6a\x59\x68\x71\x57\x37','\x57\x37\x6c\x64\x50\x53\x6b\x7a\x73\x48\x39\x69\x71\x53\x6b\x52','\x57\x37\x4e\x64\x4b\x43\x6b\x72\x64\x68\x56\x64\x54\x43\x6b\x61\x57\x52\x57','\x57\x50\x53\x6b\x57\x35\x4f\x4a\x57\x35\x56\x63\x52\x5a\x44\x79\x6e\x61\x56\x63\x4a\x65\x30','\x57\x52\x30\x45\x57\x36\x6c\x64\x56\x33\x68\x63\x51\x53\x6f\x63\x79\x57','\x57\x35\x61\x30\x6a\x67\x78\x64\x50\x78\x6c\x63\x4f\x53\x6b\x31','\x57\x34\x54\x4f\x57\x52\x4b','\x57\x51\x46\x64\x4f\x53\x6b\x69\x57\x52\x71\x78\x6d\x33\x37\x63\x54\x61','\x57\x34\x72\x54\x57\x4f\x31\x4d\x57\x52\x71','\x63\x75\x62\x39\x62\x53\x6f\x35','\x57\x37\x64\x63\x50\x53\x6b\x6d\x6e\x49\x33\x64\x4d\x64\x71\x4c','\x57\x4f\x76\x4c\x6f\x74\x30\x6d\x57\x34\x69','\x73\x53\x6b\x68\x77\x65\x52\x64\x53\x71\x38\x46','\x57\x36\x52\x63\x50\x53\x6b\x55\x70\x61','\x67\x38\x6b\x51\x57\x4f\x2f\x63\x48\x43\x6b\x55\x57\x35\x72\x44\x57\x52\x65','\x6d\x4b\x6e\x49\x6b\x30\x6d\x65','\x6d\x67\x52\x63\x52\x72\x4a\x64\x53\x53\x6b\x6d\x57\x37\x79\x58\x76\x47\x64\x64\x4e\x65\x38\x54','\x57\x50\x34\x71\x68\x43\x6b\x6a\x65\x71','\x70\x6d\x6b\x37\x57\x50\x47\x38\x57\x52\x56\x64\x53\x6d\x6b\x46\x6e\x57','\x57\x51\x58\x6d\x57\x50\x2f\x64\x49\x64\x6d\x46','\x62\x38\x6f\x78\x57\x52\x61\x53','\x77\x43\x6b\x71\x57\x34\x4b\x4a\x46\x43\x6b\x6e\x65\x61','\x57\x36\x2f\x63\x54\x58\x4e\x64\x4f\x77\x68\x64\x56\x4d\x33\x63\x54\x57','\x57\x52\x7a\x33\x6e\x74\x34\x4d','\x44\x38\x6f\x61\x57\x50\x78\x63\x4b\x73\x64\x64\x47\x43\x6b\x36\x77\x61','\x57\x36\x71\x41\x65\x65\x2f\x64\x4e\x57','\x61\x6d\x6b\x34\x69\x74\x6c\x63\x54\x38\x6b\x55\x57\x51\x6c\x64\x55\x71','\x46\x74\x37\x63\x56\x57','\x72\x65\x79\x55\x57\x37\x2f\x63\x4d\x71','\x57\x4f\x4a\x64\x52\x59\x70\x63\x56\x31\x61','\x73\x67\x61\x51\x57\x34\x4f\x4c\x57\x50\x44\x58\x46\x64\x70\x64\x47\x33\x76\x32','\x7a\x38\x6b\x47\x41\x78\x78\x64\x4c\x74\x6d\x56\x73\x57','\x57\x37\x5a\x63\x53\x53\x6b\x33\x57\x50\x75\x54','\x57\x35\x79\x4e\x65\x38\x6f\x68','\x57\x52\x6a\x36\x57\x50\x33\x64\x49\x47\x4b','\x73\x43\x6b\x68\x57\x35\x5a\x64\x53\x75\x37\x63\x50\x43\x6b\x4f\x6c\x57\x62\x65\x43\x67\x53','\x57\x34\x2f\x64\x48\x38\x6b\x2f\x6a\x6d\x6b\x4c\x6e\x49\x72\x58','\x70\x6d\x6f\x6d\x57\x52\x68\x64\x51\x43\x6f\x57','\x57\x4f\x37\x63\x54\x53\x6f\x47\x42\x48\x4e\x63\x4a\x38\x6b\x35\x57\x52\x56\x63\x4e\x38\x6f\x53\x69\x53\x6b\x54','\x6a\x53\x6b\x65\x6b\x73\x46\x63\x4b\x71','\x64\x33\x52\x63\x51\x47\x43\x4b\x57\x4f\x76\x48\x6d\x71','\x77\x4b\x57\x67\x57\x34\x4a\x63\x55\x61','\x57\x35\x39\x46\x57\x50\x58\x4c','\x74\x43\x6b\x72\x74\x78\x78\x64\x54\x72\x47\x6f\x43\x61','\x57\x35\x6c\x64\x4d\x38\x6b\x4f\x6f\x43\x6b\x4b\x70\x49\x48\x36','\x6a\x6d\x6b\x44\x63\x57','\x77\x53\x6b\x6a\x57\x35\x75\x2f\x41\x47','\x71\x6d\x6f\x30\x57\x52\x74\x63\x49\x38\x6b\x4f\x57\x35\x62\x62\x57\x52\x38','\x6d\x43\x6b\x6b\x65\x43\x6b\x52\x63\x43\x6f\x59\x6a\x62\x6c\x64\x56\x47','\x46\x43\x6f\x77\x75\x57','\x57\x37\x78\x64\x4f\x62\x75\x30\x57\x34\x31\x36','\x46\x32\x68\x64\x48\x48\x37\x63\x4d\x47','\x57\x37\x4a\x63\x4a\x78\x5a\x64\x4a\x4a\x2f\x63\x50\x38\x6b\x58\x42\x6d\x6b\x73\x45\x5a\x42\x63\x56\x6d\x6f\x6a\x7a\x57','\x75\x53\x6b\x4e\x57\x4f\x38','\x57\x36\x37\x64\x4f\x72\x43\x73\x57\x36\x4b','\x6b\x38\x6f\x5a\x57\x50\x53\x72\x6a\x38\x6f\x61\x66\x74\x30','\x43\x38\x6b\x61\x57\x52\x4e\x64\x50\x4a\x69','\x57\x4f\x42\x64\x4f\x57\x33\x63\x53\x65\x64\x64\x4b\x6d\x6f\x67\x64\x61','\x76\x4d\x56\x63\x53\x4e\x74\x64\x54\x53\x6f\x34\x68\x53\x6b\x6f','\x72\x67\x37\x64\x54\x62\x74\x63\x53\x71','\x57\x51\x54\x79\x79\x53\x6b\x38\x76\x66\x64\x63\x4f\x38\x6f\x6b\x41\x74\x71\x35\x57\x51\x57','\x6e\x38\x6f\x39\x57\x50\x68\x64\x53\x43\x6f\x56','\x57\x37\x50\x54\x41\x43\x6b\x52\x6c\x4e\x46\x64\x47\x53\x6f\x75\x41\x71','\x70\x43\x6f\x45\x57\x36\x33\x64\x48\x43\x6b\x6a','\x71\x53\x6f\x77\x57\x50\x79\x57\x57\x50\x52\x64\x55\x53\x6b\x74\x63\x61','\x64\x53\x6b\x70\x45\x63\x4b\x65','\x6d\x38\x6b\x6b\x57\x52\x68\x63\x51\x6d\x6b\x46\x57\x36\x39\x4f\x57\x50\x57','\x57\x37\x42\x64\x50\x43\x6f\x34\x66\x30\x34\x6c\x75\x43\x6b\x64\x44\x78\x64\x63\x52\x62\x47','\x73\x6d\x6b\x41\x57\x35\x61\x48','\x67\x6d\x6b\x71\x57\x51\x37\x63\x4f\x38\x6b\x43','\x57\x34\x2f\x64\x4d\x53\x6b\x72\x6b\x6d\x6b\x31\x69\x59\x6e\x35','\x6d\x4c\x7a\x37\x6d\x4b\x61','\x57\x37\x58\x69\x57\x34\x4b\x6e\x6c\x38\x6f\x6c\x57\x35\x47\x78','\x70\x43\x6f\x70\x69\x62\x4c\x70','\x57\x36\x66\x37\x57\x52\x61','\x6e\x38\x6b\x6c\x68\x48\x70\x63\x4c\x38\x6b\x44\x57\x50\x47','\x42\x6d\x6f\x64\x57\x52\x65\x44\x6f\x47','\x78\x53\x6f\x59\x57\x52\x65\x48\x6c\x57','\x57\x50\x4b\x31\x57\x51\x50\x37','\x57\x50\x30\x65\x57\x50\x78\x63\x4a\x73\x70\x64\x4d\x43\x6b\x79\x57\x34\x71','\x6d\x67\x35\x65\x66\x6d\x6f\x64\x57\x35\x2f\x64\x51\x43\x6b\x35','\x57\x35\x4c\x6b\x57\x51\x64\x64\x56\x6d\x6b\x33','\x57\x34\x52\x63\x4a\x73\x42\x64\x53\x31\x57','\x41\x31\x79\x34\x42\x53\x6b\x7a\x42\x6d\x6f\x79\x70\x61','\x68\x43\x6b\x4e\x57\x36\x52\x64\x56\x71','\x57\x50\x79\x43\x44\x57','\x57\x34\x65\x41\x57\x36\x46\x64\x54\x65\x64\x63\x56\x38\x6f\x6c','\x57\x35\x31\x72\x57\x51\x6a\x35\x57\x50\x52\x64\x53\x47\x7a\x46','\x6a\x38\x6f\x67\x57\x50\x4e\x64\x49\x43\x6f\x51','\x73\x43\x6b\x34\x63\x33\x56\x64\x54\x43\x6b\x50\x65\x67\x53\x4f\x57\x35\x56\x64\x48\x78\x71','\x63\x5a\x6e\x41\x57\x4f\x50\x77','\x57\x50\x33\x64\x4b\x57\x4e\x64\x4d\x75\x5a\x64\x4d\x32\x42\x63\x4d\x71','\x61\x43\x6b\x48\x57\x4f\x74\x63\x4b\x53\x6b\x55\x57\x34\x47','\x46\x6d\x6f\x54\x6a\x53\x6f\x33\x74\x47','\x44\x66\x62\x47','\x78\x38\x6f\x47\x57\x51\x56\x63\x56\x62\x68\x64\x55\x53\x6b\x70\x44\x71'];_0x2e96=function(){return _0x34900f;};return _0x2e96();}_0xf18e57[_0x457522(0x1ad,'\x35\x2a\x64\x53')+'\x6f\x78\x79\x45\x6e\x76']=_0x3a35e8,_0xf18e57[_0x457522(0x1d2,'\x6c\x36\x26\x70')+'\x65\x64']=_0x20cf9b,module[_0x457522(0x1c3,'\x21\x28\x5b\x29')]=_0xf18e57;
@@ -6,6 +6,23 @@ const { PROXY_PROTOCOL_VERSION } = require('../mailbox/store');
6
6
  const crypto = require('crypto');
7
7
  const { hubFetch } = require('../../gep/hubFetch');
8
8
  const { getEvomapPath } = require('../../gep/paths');
9
+ // last_update transit (PR #188): proxy heartbeat ferries a pending
10
+ // force_update outcome to the hub, then clears the state file on 2xx.
11
+ // Proxy DOES run the upgrade now (PR #188 follow-up, HIGH bug): the
12
+ // original comment "Proxy itself never runs the upgrade — telemetry-only
13
+ // here" reflected pre-fix behaviour. Pure proxy-mode nodes (EVOMAP_PROXY=1,
14
+ // no evolve loop) never traversed a2aProtocol.js sendHeartbeat, so the
15
+ // canonical `_maybeTriggerForceUpdateFromHeartbeat` block at
16
+ // a2aProtocol.js:2304 never fired for them — Hub could push force_update
17
+ // forever with no upgrade attempt and no EvolverUpgradeAttempt row. The
18
+ // proxy heartbeat (200 with force_update, AND 426 with force_update in the
19
+ // error envelope) must mirror that logic. reportForceUpdateOutcome writes
20
+ // the state file the next heartbeat will pick up via body.last_update.
21
+ const {
22
+ readPendingLastUpdate,
23
+ clearLastUpdateOnAck,
24
+ reportForceUpdateOutcome,
25
+ } = require('../../gep/a2aProtocol');
9
26
 
10
27
  // Hub's nodeId regex; mirror of src/gep/a2aProtocol.js so a malformed
11
28
  // legacy file can never feed garbage into the hello payload.
@@ -47,6 +64,28 @@ const DRIFT_CHECK_MS = 30 * 1000;
47
64
  const DRIFT_SLEEP_THRESHOLD_MS = 90 * 1000;
48
65
  const DRIFT_LONG_SLEEP_THRESHOLD_MS = 30 * 60_000;
49
66
 
67
+ // Heartbeat-driven force_update lifecycle tracking. Mirrors
68
+ // `_forceUpdateInFlight` / `_forceUpdateLastAttemptAt` /
69
+ // `_getForceUpdateRetryCooldownMs` in src/gep/a2aProtocol.js so the proxy
70
+ // path uses the same in-flight + cooldown contract as the canonical path.
71
+ // Module-level (not instance-level) so multiple LifecycleManager instances
72
+ // in the same process serialize through one upgrade attempt — matches
73
+ // a2aProtocol.js's module-level guard. Process-local is sufficient: the
74
+ // proxy daemon runs in a single process and any sibling process would
75
+ // have its own require-cached state; cross-process serialization is the
76
+ // hub's job via directive_id dedup, not the client's.
77
+ let _proxyForceUpdateInFlight = false;
78
+ let _proxyForceUpdateLastAttemptAt = 0;
79
+ function _getProxyForceUpdateRetryCooldownMs() {
80
+ // Share the env var with a2aProtocol.js: an operator who sets
81
+ // EVOLVER_FORCE_UPDATE_RETRY_COOLDOWN_MS=0 in a test or production tune
82
+ // expects BOTH code paths to honour it. Default 15min matches
83
+ // a2aProtocol.js exactly.
84
+ const v = Number(process.env.EVOLVER_FORCE_UPDATE_RETRY_COOLDOWN_MS);
85
+ if (Number.isFinite(v) && v >= 0) return v;
86
+ return 15 * 60 * 1000;
87
+ }
88
+
50
89
  let _cachedFingerprint = null;
51
90
  function _getEnvFingerprint() {
52
91
  if (_cachedFingerprint) return _cachedFingerprint;
@@ -97,6 +136,203 @@ function _readLegacyNodeId() {
97
136
  return null;
98
137
  }
99
138
 
139
+ // Mirror of src/gep/a2aProtocol.js `_persistNodeId`. Pure-proxy daemons
140
+ // (EVOMAP_PROXY=1, no a2aProtocol heartbeat thread) mint their own
141
+ // node_id and ONLY persist it to MailboxStore state.json. The legacy
142
+ // `~/.evomap/node_id` file never gets written, so:
143
+ //
144
+ // 1. `_shortNodeIdForStatePath` in a2aProtocol.js (used by the proxy
145
+ // heartbeat to pick the per-node `force_update_last.<suffix>.json`
146
+ // path) falls all the way through to 'anon' — every proxy node on
147
+ // the same EVOLVER_HOME would collide on the same state file.
148
+ // 2. A mixed-mode install (legacy evolve loop ran once, then user
149
+ // switched to proxy mode) is even worse: the legacy file holds a
150
+ // DIFFERENT id than the one in MailboxStore. The proxy heartbeats
151
+ // with body.node_id = its OWN id while writing
152
+ // `force_update_last.<legacy-suffix>.json`. The hub-side upgrade
153
+ // attempt row gets attributed to the wrong node.
154
+ //
155
+ // Calling this helper from hello() after the nodeId is resolved unifies
156
+ // the two persistence paths onto a single identity. Atomic write
157
+ // (per-pid tmp + rename) mirrors `_persistNodeSecret` in a2aProtocol.js;
158
+ // 0o600 mode keeps the file owner-read-only on POSIX (silently ignored
159
+ // on Windows, where %USERPROFILE% isolation is the only protection).
160
+ //
161
+ // Idempotent: if the file already holds the same id, we skip the write
162
+ // to avoid an inode churn on every hello tick. If it holds a DIFFERENT
163
+ // valid id, we still overwrite — the proxy's MailboxStore wins because
164
+ // that is the id the hub already knows us by (any rotation away from
165
+ // the legacy id was a deliberate operator action). The only way to
166
+ // re-seed a legacy id back onto a proxy install is to clear
167
+ // MailboxStore state.json (`evolver reset-local-secret`).
168
+ function _persistLegacyNodeId(id) {
169
+ if (!id || !NODE_ID_RE.test(id)) return;
170
+ const targets = [
171
+ getEvomapPath('node_id'),
172
+ path.resolve(__dirname, '..', '..', '..', '.evomap_node_id'),
173
+ ];
174
+ // Try targets in order until one succeeds, matching the read order in
175
+ // _readLegacyNodeId. We only need ONE persistent copy; once the home
176
+ // path takes the write, the install-root path is unused.
177
+ for (const file of targets) {
178
+ try {
179
+ // Skip if the file already matches — common steady-state path,
180
+ // saves a syscall storm under heartbeat backoff doubling.
181
+ try {
182
+ if (fs.existsSync(file)) {
183
+ const existing = fs.readFileSync(file, 'utf8').trim();
184
+ if (existing === id) return;
185
+ }
186
+ } catch {
187
+ // Unreadable -- treat as missing and try to write.
188
+ }
189
+ const dir = path.dirname(file);
190
+ try {
191
+ if (!fs.existsSync(dir)) {
192
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
193
+ }
194
+ } catch (_) {
195
+ // mkdir failed (read-only fs, EPERM under sandboxing). Skip
196
+ // this candidate; the next one (install-root .evomap_node_id)
197
+ // may still work.
198
+ continue;
199
+ }
200
+ // Atomic write: a sibling evolver process (mixed-mode upgrade, two
201
+ // proxy daemons started by hand) could otherwise race on this
202
+ // path and leave a half-written file. Matches the pattern in
203
+ // a2aProtocol.js `_persistNodeSecret`.
204
+ const tmp = file + '.' + process.pid + '.tmp';
205
+ fs.writeFileSync(tmp, id, { encoding: 'utf8', mode: 0o600 });
206
+ fs.renameSync(tmp, file);
207
+ return;
208
+ } catch {
209
+ // Best-effort: continue to the next candidate. If both fail (no
210
+ // home, no writable install root) we accept the legacy file is
211
+ // unavailable — the proxy will still function, it just cannot
212
+ // unify state-file suffixes with a co-resident a2aProtocol path.
213
+ }
214
+ }
215
+ }
216
+
217
+ // Heartbeat-driven force_update trigger for proxy-mode nodes. Mirrors
218
+ // `_maybeTriggerForceUpdateFromHeartbeat` in src/gep/a2aProtocol.js
219
+ // (search there for that name to compare). Pure proxy-mode deployments
220
+ // (EVOMAP_PROXY=1) never run the evolve run() loop or sendHeartbeat, so
221
+ // without this trigger Hub can push force_update on every heartbeat
222
+ // forever and the node will keep heartbeating on the old version — which
223
+ // is exactly what shipped before PR #188's H1 fix.
224
+ //
225
+ // Drives `executeForceUpdate` directly, gated by an in-flight lock + a
226
+ // cooldown on failures so we do not hammer npm/degit on every tick. After
227
+ // the attempt, persists the outcome via `reportForceUpdateOutcome` so the
228
+ // next heartbeat carries it as body.last_update — that's the path that
229
+ // finally writes a row to the hub's EvolverUpgradeAttempt table.
230
+ //
231
+ // Logger is injected (not a console fallback) so tests can capture the
232
+ // upgrade-path stderr without polluting CI output. The logger contract
233
+ // matches what the LifecycleManager already uses.
234
+ function _maybeTriggerForceUpdateFromHeartbeat(forceUpdate, logger) {
235
+ if (!forceUpdate || typeof forceUpdate !== 'object') return;
236
+ if (_proxyForceUpdateInFlight) return;
237
+ const nowMs = Date.now();
238
+ if (
239
+ _proxyForceUpdateLastAttemptAt &&
240
+ (nowMs - _proxyForceUpdateLastAttemptAt) < _getProxyForceUpdateRetryCooldownMs()
241
+ ) {
242
+ // A recent attempt already ran and either succeeded (process exited
243
+ // and we wouldn't be here on the post-restart heartbeat — see the
244
+ // FORCE_UPDATE_NOOP path in forceUpdate.js / reportForceUpdateOutcome
245
+ // status="skipped") or failed. Back off.
246
+ return;
247
+ }
248
+ _proxyForceUpdateInFlight = true;
249
+ _proxyForceUpdateLastAttemptAt = nowMs;
250
+
251
+ // Capture from_version BEFORE executeForceUpdate runs. A successful
252
+ // upgrade calls process.exit(78); the post-restart heartbeat reads the
253
+ // state file from a fresh process where require('package.json').version
254
+ // is the NEW version — so snapshot the CURRENTLY running version now.
255
+ let fromVersion = '';
256
+ try {
257
+ fromVersion = String((require('../../../package.json') || {}).version || '');
258
+ } catch (_) { /* best-effort */ }
259
+
260
+ // Kick off in a microtask so the heartbeat promise chain can still
261
+ // complete (log + return {ok:true}) before the long-running upgrade
262
+ // takes over the process. Matches a2aProtocol.js exactly.
263
+ Promise.resolve().then(() => {
264
+ let updated = false;
265
+ let noop = false;
266
+ let busy = false;
267
+ let thrownErr = null;
268
+ try {
269
+ const mod = require('../../forceUpdate');
270
+ const result = mod.executeForceUpdate(forceUpdate);
271
+ // Sentinel === comparison: executeForceUpdate returns the
272
+ // FORCE_UPDATE_NOOP symbol when the install is already at the
273
+ // required version. We must NOT treat that as "success" — doing so
274
+ // would (a) write a phantom {status:"success", from==to} row to
275
+ // EvolverUpgradeAttempt, and (b) trigger an exit(78) restart with
276
+ // nothing to restart for. The hub schema accepts status="skipped".
277
+ noop = (result === mod.FORCE_UPDATE_NOOP);
278
+ // FORCE_UPDATE_BUSY: another caller (e.g. a2aProtocol heartbeat
279
+ // trigger or an evolve tick) already holds the module-level
280
+ // _inFlight mutex in forceUpdate.js. Defensive only — the
281
+ // instance-level _proxyForceUpdateInFlight gate above and the
282
+ // single-caller property of pure proxy mode make BUSY unreachable
283
+ // in practice. If it does fire (mixed-mode regression, future
284
+ // additional caller, etc.), the other caller owns the telemetry:
285
+ // we MUST NOT write a state file or exit(78). Mirrors
286
+ // src/gep/a2aProtocol.js (search FORCE_UPDATE_BUSY).
287
+ busy = (result === mod.FORCE_UPDATE_BUSY);
288
+ updated = (result === true);
289
+ } catch (e) {
290
+ thrownErr = e;
291
+ try {
292
+ logger.warn(`[ForceUpdate] proxy heartbeat-trigger failed (non-fatal): ${e && e.message || e}`);
293
+ } catch (_) { /* logger broken; non-fatal */ }
294
+ updated = false;
295
+ } finally {
296
+ _proxyForceUpdateInFlight = false;
297
+ }
298
+ if (busy) {
299
+ try {
300
+ logger.log('[ForceUpdate] proxy heartbeat-trigger observed BUSY (concurrent invocation). Skipping telemetry; in-flight caller owns the outcome.');
301
+ } catch (_) { /* logger broken; non-fatal */ }
302
+ return;
303
+ }
304
+ // Persist outcome via the shared helper so the heartbeat-thread
305
+ // trigger and the proxy trigger stay in lockstep on payload assembly
306
+ // + validation. The next heartbeat reads this file and ferries it as
307
+ // body.last_update — same contract as the canonical path.
308
+ try {
309
+ reportForceUpdateOutcome(forceUpdate, {
310
+ updated: updated,
311
+ noop: noop,
312
+ error: thrownErr,
313
+ fromVersion: fromVersion,
314
+ });
315
+ } catch (e) {
316
+ try {
317
+ logger.warn(`[ForceUpdate] proxy reportForceUpdateOutcome failed (non-fatal): ${e && e.message || e}`);
318
+ } catch (_) { /* logger broken; non-fatal */ }
319
+ }
320
+ if (updated) {
321
+ try { logger.log('[ForceUpdate] Update complete (proxy heartbeat-trigger). Exiting for restart...'); } catch (_) {}
322
+ try { process.exit(78); } catch (_) {}
323
+ } else if (noop) {
324
+ try {
325
+ logger.log('[ForceUpdate] No-op (proxy heartbeat-trigger): already at required version. Skipping restart.');
326
+ } catch (_) {}
327
+ } else {
328
+ try {
329
+ logger.warn('[ForceUpdate] proxy heartbeat-trigger failed. Will retry after cooldown (' +
330
+ Math.round(_getProxyForceUpdateRetryCooldownMs() / 60000) + 'min).');
331
+ } catch (_) {}
332
+ }
333
+ });
334
+ }
335
+
100
336
  class AuthError extends Error {
101
337
  constructor(message, statusCode) {
102
338
  super(message);
@@ -121,6 +357,48 @@ class LifecycleManager {
121
357
  this._consecutiveReauthFailures = 0;
122
358
  this._driftInterval = null;
123
359
  this._lastDriftCheckAt = 0;
360
+
361
+ // H4 fix: persist the legacy node_id file as soon as the in-memory
362
+ // node_id is known, NOT only after a successful hello(). The original
363
+ // code persisted only in hello() (see ~L390-398) — but proxy-mode boot
364
+ // can fire `reportForceUpdateOutcome` BEFORE hello() returns:
365
+ //
366
+ // - First-tick heartbeat hits 426 → executeForceUpdate() → exit(78)
367
+ // all happens BEFORE the hello() response is processed.
368
+ // - enrich.js force_update path can fire during the same window.
369
+ //
370
+ // `_shortNodeIdForStatePath` in a2aProtocol.js then picks the
371
+ // state-file suffix from `_cachedNodeId` (never set in proxy mode —
372
+ // only getNodeId() sets it, and proxy never calls getNodeId()) or the
373
+ // legacy ~/.evomap/node_id file. With both empty, it falls through
374
+ // to 'anon', and the outcome lands at `force_update_last.anon.json`.
375
+ // Next boot's hello() writes the real id, the heartbeat reads
376
+ // `force_update_last.<8hex>.json`, the anon file is orphaned and the
377
+ // outcome is silently lost.
378
+ //
379
+ // Persisting at construction closes the window. _persistLegacyNodeId
380
+ // early-returns on invalid input (NODE_ID_RE gate, same regex as the
381
+ // hello() path uses) so a malformed/empty store value is a no-op,
382
+ // and it is idempotent on matching content so the cost is one
383
+ // existsSync + one readFileSync per construction. We keep the
384
+ // existing post-hello call as a safety net in case hello() mints or
385
+ // mutates the id.
386
+ try {
387
+ const earlyNodeId = this.store && this.store.getState
388
+ ? this.store.getState('node_id')
389
+ : null;
390
+ if (earlyNodeId && NODE_ID_RE.test(earlyNodeId)) {
391
+ _persistLegacyNodeId(earlyNodeId);
392
+ }
393
+ } catch (e) {
394
+ // Best-effort: persistence failure must never break construction.
395
+ // Logger may not exist if tests passed undefined; guard the call.
396
+ try {
397
+ this.logger.warn(
398
+ `[lifecycle] early persist of legacy node_id failed (non-fatal): ${e && e.message || e}`
399
+ );
400
+ } catch (_) { /* logger broken; non-fatal */ }
401
+ }
124
402
  }
125
403
 
126
404
  get nodeId() {
@@ -293,6 +571,27 @@ class LifecycleManager {
293
571
  }
294
572
 
295
573
  this.store.setState('node_id', nodeId);
574
+ // Unify proxy node_id with the legacy GEP file. Without this, the
575
+ // proxy-only fast path (EVOMAP_PROXY=1) never seeds
576
+ // ~/.evomap/node_id and `_shortNodeIdForStatePath` in a2aProtocol
577
+ // (used to pick the per-node `force_update_last.<suffix>.json`
578
+ // path for upgrade telemetry) falls through to 'anon' — every
579
+ // proxy node under the same EVOLVER_HOME would collide on the
580
+ // same state file. In a mixed-mode install where the legacy file
581
+ // holds a DIFFERENT (stale) id, the helper overwrites it so the
582
+ // state-file suffix matches `this.nodeId` — the id the hub sees
583
+ // in body.node_id. We persist AFTER hello succeeds so a rejected
584
+ // first-boot mint never commits to disk; on a rejection the next
585
+ // tick will mint fresh again (existing behaviour).
586
+ try {
587
+ _persistLegacyNodeId(nodeId);
588
+ } catch (e) {
589
+ // Best-effort: persistence failure must never break hello. Log
590
+ // and move on — the proxy still functions, the state-file
591
+ // suffix just falls back to 'anon' until the next successful
592
+ // hello retries the write.
593
+ this.logger.warn(`[lifecycle] failed to persist legacy node_id (non-fatal): ${e && e.message || e}`);
594
+ }
296
595
  this.logger.log(`[lifecycle] hello OK, node_id=${nodeId}${rotateSecret ? ' (secret rotated)' : ''}`);
297
596
  return { ok: true, nodeId, response: data };
298
597
  } catch (err) {
@@ -392,6 +691,7 @@ class LifecycleManager {
392
691
  try { this.store.setState('node_secret', ''); } catch { /* best-effort */ }
393
692
  // Clear the source tag too -- nothing is stored, nothing to attribute.
394
693
  try { this.store.setState('node_secret_source', ''); } catch { /* best-effort */ }
694
+ try { this.store.setState('node_secret_env_suppressed', 'true'); } catch { /* best-effort */ }
395
695
  // Suppress the env override for this process so _resolveNodeSecret stops
396
696
  // re-seeding the store with the same stale env value next call.
397
697
  this._suppressEnvSecret = true;
@@ -448,6 +748,21 @@ class LifecycleManager {
448
748
  },
449
749
  };
450
750
 
751
+ // Attach any pending force_update outcome so the hub-side
752
+ // EvolverUpgradeAttempt table gets a row. Captured in a local so the
753
+ // post-2xx clear matches identity (rotation-safe — see
754
+ // _clearLastUpdateStateIfMatches). Never let telemetry throw.
755
+ let capturedLastUpdate = null;
756
+ try {
757
+ const pending = readPendingLastUpdate();
758
+ if (pending) {
759
+ body.last_update = pending;
760
+ capturedLastUpdate = pending;
761
+ }
762
+ } catch (e) {
763
+ this.logger.warn(`[lifecycle] readPendingLastUpdate failed (non-fatal): ${e && e.message || e}`);
764
+ }
765
+
451
766
  const res = await hubFetch(endpoint, {
452
767
  method: 'POST',
453
768
  headers: this._buildHeaders(),
@@ -470,8 +785,70 @@ class LifecycleManager {
470
785
  }
471
786
 
472
787
  if (!res.ok) {
473
- this._consecutiveFailures++;
474
788
  const errText = await res.text().catch(() => '');
789
+ // 426 Upgrade Required: hub emits this when our evolver_version is
790
+ // below the minimum version it requires. The body is JSON of shape
791
+ // `{ error: 'evolver_min_version_required', force_update: {...} }`
792
+ // (see hub `src/routes/a2a/_middleware.js`). Pre-fix this fell
793
+ // through to the generic `http_426` error and the proxy never
794
+ // attempted the upgrade — defeating the very mechanism that 426
795
+ // exists to drive. Mirror the 200+force_update path: parse the
796
+ // body, fire executeForceUpdate (which writes the state file via
797
+ // reportForceUpdateOutcome), and let the next heartbeat carry the
798
+ // attempt as body.last_update. Still return an error so the
799
+ // caller's failure counter ticks and the loop backs off.
800
+ if (res.status === 426) {
801
+ let parsed = null;
802
+ try { parsed = JSON.parse(errText); } catch (_) { /* body not JSON */ }
803
+ const fu = parsed && parsed.force_update;
804
+ if (fu && typeof fu === 'object') {
805
+ this.logger.warn(
806
+ `[lifecycle] heartbeat HTTP 426 with force_update directive (required=${
807
+ fu.required_version || '?'
808
+ }) — triggering executeForceUpdate`
809
+ );
810
+ _maybeTriggerForceUpdateFromHeartbeat(fu, this.logger);
811
+ } else {
812
+ this.logger.warn(
813
+ `[lifecycle] heartbeat HTTP 426 without parseable force_update payload: ${errText}`
814
+ );
815
+ }
816
+ }
817
+ // Hub 400 circuit breaker (mirrors a2aProtocol.js sendHeartbeat
818
+ // ~L2376-2411): if last_update was attached this tick and the hub
819
+ // rejected the body with 400 AND the rejection names the
820
+ // last_update field, the state file is poisoning every heartbeat
821
+ // (e.g. downgrade-then-upgrade left a payload the new hub schema
822
+ // rejects, or a manual edit corrupted the JSON shape). The proxy
823
+ // path used to lack this breaker entirely, so a single bad payload
824
+ // would block telemetry forever -- every retry re-sends the same
825
+ // poison and re-fails with 400. Single-strike (no counter): the
826
+ // 400 + last_update substring pair is unambiguous enough that
827
+ // waiting for repeats just delays recovery. Scope intentionally
828
+ // narrowed to 400-only (NOT any 4xx): 401/403 are auth errors
829
+ // (handled above), 404/405/409 etc. are hub-routing problems that
830
+ // are not the payload's fault. The existing _consecutiveFailures
831
+ // backoff is preserved -- the breaker runs BEFORE the early
832
+ // return so the file is cleared, and then the normal failure
833
+ // path continues unchanged.
834
+ if (res.status === 400 && capturedLastUpdate) {
835
+ const errorText = 'http_400: ' + errText;
836
+ if (/last[_-]?update/i.test(errorText)) {
837
+ // Bypass any rate-limited warn helper: this is a critical
838
+ // recovery signal that must surface even if other ForceUpdate
839
+ // warns fired recently.
840
+ this.logger.warn(
841
+ '[lifecycle] hub 400 with last_update attached (error names last_update); ' +
842
+ 'clearing poisoning state file.'
843
+ );
844
+ try {
845
+ clearLastUpdateOnAck(capturedLastUpdate);
846
+ } catch (e) {
847
+ this.logger.warn(`[lifecycle] clearLastUpdateOnAck failed (non-fatal): ${e && e.message || e}`);
848
+ }
849
+ }
850
+ }
851
+ this._consecutiveFailures++;
475
852
  this.logger.error(`[lifecycle] heartbeat HTTP ${res.status}: ${errText}`);
476
853
  return { ok: false, error: `http_${res.status}`, statusCode: res.status };
477
854
  }
@@ -481,11 +858,73 @@ class LifecycleManager {
481
858
  this._consecutiveFailures = 0;
482
859
  this.store.setState('last_heartbeat_at', new Date().toISOString());
483
860
 
861
+ // Semantic parity with a2aProtocol.js sendHeartbeat: a 2xx with
862
+ // `{ok:false}` or `status:'unknown_node'` is NOT a hub-side persist,
863
+ // so the state file must survive for the next heartbeat to retry
864
+ // (unknown_node triggers a re-hello below).
865
+ //
866
+ // PR #188 follow-up (HIGH H1-client): the hub now writes a top-level
867
+ // `last_update_ack: { ok, reason? }` whenever the request carried a
868
+ // last_update payload. Gate the clear on the ack so we do not unlink
869
+ // the only evidence of the upgrade attempt when the hub's
870
+ // fire-and-forget persist throws / dedup-misses / schema-rejects /
871
+ // bypass-path returns false. Backward compat: an old hub that has not
872
+ // yet rolled out the ack writer falls back to the original bare-2xx
873
+ // semantics so this client keeps working against pre-rollout hubs.
874
+ // See src/gep/a2aProtocol.js sendHeartbeat for the canonical comment.
875
+ const hubAccepted = !(data && data.ok === false) && data?.status !== 'unknown_node';
876
+ if (capturedLastUpdate) {
877
+ const ack = data && data.last_update_ack;
878
+ const hasAck = ack && typeof ack === 'object';
879
+ let shouldClear;
880
+ if (hasAck) {
881
+ shouldClear = ack.ok === true
882
+ || ack.reason === 'duplicate'
883
+ || ack.reason === 'invalid';
884
+ if (ack.reason === 'failed') {
885
+ this.logger.warn('[lifecycle] hub last_update_ack=failed; ' +
886
+ 'keeping state file for retry on next heartbeat.');
887
+ } else if (ack.reason === 'invalid') {
888
+ this.logger.warn('[lifecycle] hub last_update_ack=invalid; ' +
889
+ 'clearing state file (retry will not help).');
890
+ }
891
+ } else {
892
+ shouldClear = hubAccepted;
893
+ }
894
+ if (shouldClear) {
895
+ try {
896
+ clearLastUpdateOnAck(capturedLastUpdate);
897
+ } catch (e) {
898
+ this.logger.warn(`[lifecycle] clearLastUpdateOnAck failed (non-fatal): ${e && e.message || e}`);
899
+ }
900
+ }
901
+ }
902
+
484
903
  if (data?.status === 'unknown_node') {
485
904
  this.logger.warn('[lifecycle] Node unknown, re-registering...');
486
905
  await this.hello();
487
906
  }
488
907
 
908
+ // PR #188 H1 fix: 200 with a `force_update` directive must drive
909
+ // executeForceUpdate the same way a2aProtocol.js does for
910
+ // non-proxy nodes (see a2aProtocol.js:2292-2305 and
911
+ // _maybeTriggerForceUpdateFromHeartbeat). Pure proxy-mode nodes
912
+ // never enter the evolve run() loop, so the consumeForceUpdate
913
+ // path never fires for them — without this block the hub could
914
+ // push force_update forever with zero upgrade attempts and zero
915
+ // EvolverUpgradeAttempt rows. The helper is in-flight + cooldown
916
+ // gated; placing the call here (post-events, pre-min_version
917
+ // banner) means a single response carrying both events AND a
918
+ // force_update still processes the events first.
919
+ if (data && data.force_update && typeof data.force_update === 'object') {
920
+ this.logger.log(
921
+ '[ForceUpdate] Hub requires update to ' +
922
+ (data.force_update.required_version || '?') +
923
+ ' -- reason: ' + (data.force_update.reason || 'unspecified')
924
+ );
925
+ _maybeTriggerForceUpdateFromHeartbeat(data.force_update, this.logger);
926
+ }
927
+
489
928
  if (Array.isArray(data?.events) && data.events.length > 0) {
490
929
  this.store.writeInboundBatch(
491
930
  data.events.map(e => ({
@@ -665,4 +1104,20 @@ class LifecycleManager {
665
1104
  }
666
1105
  }
667
1106
 
668
- module.exports = { LifecycleManager, AuthError, DEFAULT_HEARTBEAT_INTERVAL, HEARTBEAT_BACKOFF_CAP_MS };
1107
+ module.exports = {
1108
+ LifecycleManager,
1109
+ AuthError,
1110
+ DEFAULT_HEARTBEAT_INTERVAL,
1111
+ HEARTBEAT_BACKOFF_CAP_MS,
1112
+ // Test hooks behind `_testing` to mirror the namespacing used by
1113
+ // a2aProtocol.js — production callers must not accidentally tweak the
1114
+ // proxy force_update lifecycle state.
1115
+ _testing: {
1116
+ // Reset proxy heartbeat-driven force_update state. Avoids cooldown
1117
+ // leakage between sibling tests that share one process.
1118
+ _resetProxyForceUpdateStateForTesting: function () {
1119
+ _proxyForceUpdateInFlight = false;
1120
+ _proxyForceUpdateLastAttemptAt = 0;
1121
+ },
1122
+ },
1123
+ };
@@ -91,6 +91,7 @@ function safeParse(payload) {
91
91
  // equally valid on Windows. No platform-specific code is needed here.
92
92
  function appendLine(filePath, obj) {
93
93
  fs.appendFileSync(filePath, JSON.stringify(obj) + '\n', 'utf8');
94
+ try { fs.chmodSync(filePath, 0o600); } catch { /* best effort */ }
94
95
  }
95
96
 
96
97
  function readLines(filePath) {