@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.
- package/index.js +159 -3
- package/package.json +2 -1
- package/src/adapters/claudeCode.js +21 -1
- package/src/adapters/hookAdapter.js +4 -2
- package/src/adapters/scripts/_runtimePaths.js +160 -36
- package/src/adapters/scripts/evolver-session-start.js +14 -10
- package/src/adapters/scripts/evolver-task-recall.js +173 -0
- package/src/atp/atpExecute.js +20 -7
- package/src/atp/cli.js +17 -9
- package/src/atp/protocol.js +41 -0
- package/src/config.js +29 -0
- package/src/evolve/guards.js +1 -1
- package/src/evolve/pipeline/collect.js +1 -1
- package/src/evolve/pipeline/dispatch.js +1 -1
- package/src/evolve/pipeline/enrich.js +1 -1
- package/src/evolve/pipeline/hub.js +1 -1
- package/src/evolve/pipeline/select.js +1 -1
- package/src/evolve/pipeline/signals.js +1 -1
- package/src/evolve/utils.js +1 -1
- package/src/evolve.js +1 -1
- package/src/forceUpdate.js +108 -3
- package/src/gep/a2aProtocol.js +1 -1
- package/src/gep/assetCallLog.js +40 -1
- package/src/gep/autoDistillConv.js +1 -1
- package/src/gep/autoDistillLlm.js +1 -1
- package/src/gep/candidateEval.js +1 -1
- package/src/gep/candidates.js +1 -1
- package/src/gep/contentHash.js +1 -1
- package/src/gep/conversationSniffer.js +1 -1
- package/src/gep/crypto.js +1 -1
- package/src/gep/curriculum.js +1 -1
- package/src/gep/deviceId.js +1 -1
- package/src/gep/envFingerprint.js +1 -1
- package/src/gep/epigenetics.js +1 -1
- package/src/gep/execBridge.js +1 -1
- package/src/gep/explore.js +1 -1
- package/src/gep/hash.js +1 -1
- package/src/gep/hubFetch.js +1 -1
- package/src/gep/hubReview.js +1 -1
- package/src/gep/hubSearch.js +1 -1
- package/src/gep/hubVerify.js +1 -1
- package/src/gep/learningSignals.js +1 -1
- package/src/gep/memoryGraph.js +1 -1
- package/src/gep/memoryGraphAdapter.js +1 -1
- package/src/gep/mutation.js +1 -1
- package/src/gep/narrativeMemory.js +1 -1
- package/src/gep/openPRRegistry.js +1 -1
- package/src/gep/personality.js +1 -1
- package/src/gep/policyCheck.js +1 -1
- package/src/gep/prompt.js +1 -1
- package/src/gep/recallInject.js +1 -0
- package/src/gep/recallVerifier.js +1 -1
- package/src/gep/reflection.js +1 -1
- package/src/gep/sanitize.js +5 -0
- package/src/gep/selector.js +1 -1
- package/src/gep/skillDistiller.js +1 -1
- package/src/gep/solidify.js +1 -1
- package/src/gep/strategy.js +1 -1
- package/src/gep/workspaceKeychain.js +1 -1
- package/src/proxy/extensions/traceControl.js +1 -0
- package/src/proxy/index.js +46 -4
- package/src/proxy/inject.js +1 -0
- package/src/proxy/lifecycle/manager.js +457 -2
- package/src/proxy/mailbox/store.js +1 -0
- package/src/proxy/router/messages_route.js +57 -8
- 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 = {
|
|
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) {
|