@naarang/ccc 1.1.3 → 1.2.0-beta.10
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/README.md +69 -0
- package/dist/claude/manager.js +1 -1
- package/dist/claude/project-setup.js +1 -1
- package/dist/claude/session-manager.js +1 -0
- package/dist/claude/session-message-parser.js +1 -0
- package/dist/claude/session.js +1 -1
- package/dist/claude/stream-parser.js +1 -1
- package/dist/expo/client.js +1 -0
- package/dist/hooks/notification_hook.js +306 -0
- package/dist/hooks/permissions_hook.js +96 -26
- package/dist/index.js +1 -1
- package/dist/mdns/service.js +1 -0
- package/dist/mqtt/client.js +1 -1
- package/dist/mqtt-broker.js +1 -1
- package/dist/ngrok/manager.js +1 -1
- package/dist/notifications/handlers.js +1 -0
- package/dist/notifications/index.js +1 -0
- package/dist/notifications/manager.js +1 -0
- package/dist/notifications/preferences-manager.js +1 -0
- package/dist/notifications/preferences-storage.js +1 -0
- package/dist/notifications/receipt-checker.js +1 -0
- package/dist/notifications/sender.js +1 -0
- package/dist/notifications/storage.js +1 -0
- package/dist/notifications/types.js +1 -0
- package/dist/proxy/router.js +1 -1
- package/dist/qr/generator.js +1 -0
- package/dist/terminal/server.js +1 -1
- package/dist/types/index.js +1 -1
- package/dist/utils/auto-update.js +1 -1
- package/dist/utils/logger.js +1 -1
- package/dist/utils/version.js +1 -1
- package/package.json +9 -2
- package/scripts/check-pty.js +142 -0
- package/scripts/obfuscate.js +77 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function _0x5008e9(_0x3ed541,_0x118f7b,_0x559bc2,_0x5c2238){return _0x520f(_0x3ed541- -0x272,_0x559bc2);}(function(_0x584851,_0x492c73){const _0x308b87={_0x567c58:0x258,_0x105391:0x266,_0x2d72a7:0x253,_0x3e0d82:0x25f,_0x1fc554:0x257,_0x37046f:0x25d,_0xc52f5b:0x7f,_0x587611:0x73,_0xbc75de:0x6f,_0x397159:0x80,_0x17b57c:0x95,_0xf2ab91:0x63,_0x121804:0x259,_0x366ed5:0x24f,_0x39b5db:0x248,_0x52757f:0x24b,_0x2e9cbe:0x57,_0x4415e4:0x3e,_0x4fc4e6:0x55,_0x7848:0x47,_0x52ea02:0x277,_0x352cdd:0x26b,_0x77e2:0x261,_0xe6f4e3:0x272,_0x2c01e8:0x263,_0x2ab1a5:0x24a,_0x18bb4d:0x24b,_0x2e5620:0x249,_0x511314:0x262,_0x36a701:0x56,_0x3a834d:0x26f,_0x1ab34d:0x274,_0x26a3e1:0x26d},_0x3348c2={_0x33e540:0x184};function _0xde008a(_0x2e0faf,_0x3474fc,_0x352259,_0x313a5b){return _0x520f(_0x2e0faf-0x70,_0x313a5b);}function _0x5f41b7(_0x1261a4,_0x544835,_0x18155f,_0x3b2a63){return _0x520f(_0x18155f- -_0x3348c2._0x33e540,_0x3b2a63);}const _0x35f0aa=_0x584851();while(!![]){try{const _0x16c4ec=parseInt(_0xde008a(_0x308b87._0x567c58,0x244,_0x308b87._0x105391,0x25f))/(-0x174a+0x2268+-0xb1d)+parseInt(_0xde008a(_0x308b87._0x2d72a7,_0x308b87._0x3e0d82,_0x308b87._0x1fc554,_0x308b87._0x37046f))/(-0x9b4+-0x1*-0x11e7+-0x3*0x2bb)*(-parseInt(_0x5f41b7(0x87,_0x308b87._0xc52f5b,_0x308b87._0x587611,_0x308b87._0xbc75de))/(0x26d1+-0x441+-0x228d))+parseInt(_0x5f41b7(_0x308b87._0x397159,_0x308b87._0x17b57c,0x7d,_0x308b87._0xf2ab91))/(0x1*0x12b9+-0xc17*-0x1+-0xf66*0x2)+parseInt(_0xde008a(_0x308b87._0x121804,_0x308b87._0x366ed5,_0x308b87._0x39b5db,_0x308b87._0x52757f))/(-0x2*0xb44+-0x3*-0x68c+0x2e9)*(parseInt(_0x5f41b7(_0x308b87._0x2e9cbe,_0x308b87._0x4415e4,_0x308b87._0x4fc4e6,_0x308b87._0x7848))/(-0x20f3+0x1b39+0x20*0x2e))+parseInt(_0xde008a(_0x308b87._0x3e0d82,_0x308b87._0x52ea02,_0x308b87._0x352cdd,0x245))/(-0x1d96+0x1922+0x47b)+-parseInt(_0xde008a(_0x308b87._0x77e2,_0x308b87._0xe6f4e3,_0x308b87._0x2c01e8,0x25d))/(-0xc63+0x2*-0xa5e+0x2127)*(-parseInt(_0xde008a(_0x308b87._0x2ab1a5,_0x308b87._0x18bb4d,_0x308b87._0x2e5620,_0x308b87._0x511314))/(0x9fe+0x4b6+-0xeab))+-parseInt(_0x5f41b7(_0x308b87._0xbc75de,0x47,0x5a,_0x308b87._0x36a701))/(0x4*-0xfb+0x13*-0xfe+0x16d0)*(parseInt(_0xde008a(_0x308b87._0x3a834d,_0x308b87._0x1ab34d,_0x308b87._0x121804,_0x308b87._0x26a3e1))/(0x9b*-0x26+-0x1*0xc3d+0x234a));if(_0x16c4ec===_0x492c73)break;else _0x35f0aa['push'](_0x35f0aa['shift']());}catch(_0x504fc8){_0x35f0aa['push'](_0x35f0aa['shift']());}}}(_0x3af3,0x1*0xd15c3+0x39b34+-0x7be4c));function _0x3af3(){const _0x517737=['u19ut0TftG','Aw5PDgLHBgL6zq','z2v0rxHWB0nSAq','mtq0nJm5mgTiCxPiBG','B2DNzxi','mJeYmJe4ofDHq0v3zq','zMf1Bhq','DcbPBML0AwfSAq','EMvKihDPDgGGyq','AwfKCvK','r0z2qMe','s2PkrKG','rxHWBW','DhfiAxe','Aw5MBW','y2nLC3mGDg9Rzq','kcGOlISPkYKRkq','nJC5odG4mMvZzxrvCa','ntmXAhfWuKXY','ww9crLO','Dg9tDhjPBMC','rxHWBYbJBgLLBG','mtuWtMP5qwfh','De1UuxO','EMvKihDPDgHVDq','y29UC3rYDwn0BW','uu53Afe','mKLuwvLfCW','uvDgALK','B2TwtLy','zxHWBY1Zzxj2zq','DMfSDwu','mJyWndmXCNHuBLPI','nw15sKHIzq','C2vHCMnO','lI4VDxrPBhmVBa','zw52','q09XCeS','yvv2t3e','nZaZntK2nKjwvMTora','wM5mte0','mZeWndHpC3DzzfK','DcbHBhjLywr5ia','zw50','z05rsNu','DcbHy2nLC3mGDa','zgvMyxvSDa','mtC5odq0m2zzBKvnAG','we5QrNC','rvHqt19bq0nfuW','B2TLBG','x19LC01VzhvSzq'];_0x3af3=function(){return _0x517737;};return _0x3af3();}const _0x4aff8c=(function(){const _0x52daf1={_0x1248ce:0xc6,_0x41a337:0xd0,_0x38f478:0xe0,_0x5e8a6c:0xdd,_0x198382:0xd4,_0x51329e:0xc7,_0x5c4608:0x240,_0xcef38a:0x236,_0x1e263a:0x240,_0x161cc9:0x248,_0x13d40d:0x98,_0x403b6c:0xa2,_0x3596a8:0xb8,_0x148d73:0xe4,_0xa5bc1f:0xd2,_0x2e5b06:0xdb,_0x38f496:0xb8,_0x555d47:0xbd,_0x522367:0xd6,_0x56014f:0xc2,_0x3fcc42:0x25b,_0x4a390c:0x260,_0x259139:0x270,_0x4be798:0xc3,_0x53b0f2:0xb5},_0x164fcd={_0x398519:0x37e,_0x38bd9f:0x378,_0x46a558:0x37d,_0x27358e:0x388,_0x65f950:0x393,_0x48ba4b:0x3ab,_0x23eac4:0x395,_0x1b5771:0x381,_0x3b2012:0x392,_0x267675:0x387,_0x164089:0x371,_0x110070:0x313,_0x86fe3:0x314,_0x3f1d50:0x386,_0x3568f2:0x2de,_0xf2987c:0x2e7,_0x429bf0:0x2fd,_0x1cf6e8:0x38f,_0x51fb42:0x391,_0x3e627a:0x37b,_0x4c49ba:0x386},_0x5d4e69={_0x1ca623:0x49f,_0x4edef1:0x4b1,_0x58d721:0x4a7,_0x5323e2:0x1ca,_0xe7940e:0x1ce,_0x2fcfcd:0x1d6,_0xb64d4c:0x1c7,_0x2f5e4c:0x49a,_0x509777:0x4b4,_0x47d151:0x4ad,_0x2c9f50:0x1ad,_0x40a3ac:0x1b7,_0x29f3f5:0x1c3,_0x4ee16c:0x1c0,_0xa2331:0x1e7,_0x42c79c:0x1d3,_0x1dd931:0x1dd,_0x2721be:0x4c9,_0x3802ce:0x4d8,_0x57cd27:0x4de,_0x5dc458:0x4d9,_0x517ed6:0x1b5,_0x31c340:0x1ce,_0x4c7829:0x1da,_0x322dd6:0x1dc,_0x2d4209:0x1bc,_0x98207b:0x1a4,_0x5da313:0x1c1,_0x35794f:0x194},_0x35f8b7={_0x1225f7:0x96,_0x282e51:0x14c},_0x4a00d0={_0x223e0d:0x175,_0x46517f:0xa5},_0x5adfc9={_0x17be73:0x2af};function _0x31b304(_0x4baa80,_0x58a80f,_0x35b95f,_0x28ac3c){return _0x520f(_0x35b95f- -_0x5adfc9._0x17be73,_0x4baa80);}function _0x33f5a2(_0x264698,_0x537f98,_0x510479,_0x40b1b1){return _0x520f(_0x510479-0x6b,_0x40b1b1);}const _0x36b9b7={};_0x36b9b7[_0x31b304(-0xd6,-_0x52daf1._0x1248ce,-_0x52daf1._0x41a337,-_0x52daf1._0x38f478)]=function(_0x24760b,_0x5fbba){return _0x24760b!==_0x5fbba;},_0x36b9b7[_0x31b304(-0xe8,-_0x52daf1._0x5e8a6c,-_0x52daf1._0x198382,-_0x52daf1._0x51329e)]=_0x33f5a2(_0x52daf1._0x5c4608,_0x52daf1._0xcef38a,_0x52daf1._0x1e263a,_0x52daf1._0x161cc9),_0x36b9b7[_0x31b304(-_0x52daf1._0x13d40d,-_0x52daf1._0x403b6c,-0xa9,-0xc1)]=_0x31b304(-_0x52daf1._0x3596a8,-_0x52daf1._0x148d73,-_0x52daf1._0xa5bc1f,-_0x52daf1._0x2e5b06)+_0x31b304(-_0x52daf1._0x38f496,-_0x52daf1._0xa5bc1f,-_0x52daf1._0x555d47,-0xa4)+'initialize'+'d',_0x36b9b7['aUvOq']='Expo\x20clien'+'t\x20initiali'+_0x31b304(-0xe2,-_0x52daf1._0x522367,-0xcf,-_0x52daf1._0x56014f)+_0x33f5a2(0x25a,_0x52daf1._0x3fcc42,_0x52daf1._0x4a390c,_0x52daf1._0x259139)+_0x31b304(-_0x52daf1._0x4be798,-0xbd,-_0x52daf1._0x53b0f2,-0xaa);const _0xa84547=_0x36b9b7;let _0x728090=!![];return function(_0xce5b2e,_0x53da98){const _0x21b59d={_0x315bf0:0xa7},_0x547cc2={_0x289518:0x9f,_0x51bfe8:0x138,_0x5edd34:0x1c2},_0x4c5aec={};_0x4c5aec[_0x553a94(_0x164fcd._0x398519,0x38b,_0x164fcd._0x38bd9f,_0x164fcd._0x46a558)]=_0xa84547[_0x553a94(0x38d,_0x164fcd._0x27358e,_0x164fcd._0x65f950,0x393)],_0x4c5aec[_0x553a94(_0x164fcd._0x48ba4b,_0x164fcd._0x23eac4,_0x164fcd._0x1b5771,_0x164fcd._0x3b2012)]=function(_0x32d183,_0x33a305){return _0x32d183||_0x33a305;},_0x4c5aec[_0x553a94(0x373,_0x164fcd._0x267675,0x35e,_0x164fcd._0x164089)]='Expo\x20clien'+_0x1551a3(0x303,0x328,_0x164fcd._0x110070,_0x164fcd._0x86fe3)+_0x553a94(_0x164fcd._0x48ba4b,_0x164fcd._0x3f1d50,0x3a2,0x391)+_0x1551a3(0x2d8,_0x164fcd._0x3568f2,_0x164fcd._0xf2987c,_0x164fcd._0x429bf0)+'n';function _0x1551a3(_0x22002e,_0x190be1,_0x59b169,_0x195f6d){return _0x33f5a2(_0x22002e-0x120,_0x190be1-_0x4a00d0._0x223e0d,_0x59b169-_0x4a00d0._0x46517f,_0x22002e);}function _0x553a94(_0x3ecea7,_0xab30b0,_0x1b5f3e,_0x7e48d7){return _0x33f5a2(_0x3ecea7-_0x35f8b7._0x1225f7,_0xab30b0-_0x35f8b7._0x282e51,_0x7e48d7-0x122,_0x3ecea7);}_0x4c5aec[_0x553a94(0x38f,_0x164fcd._0x1cf6e8,_0x164fcd._0x51fb42,_0x164fcd._0x1b5771)]=_0xa84547[_0x553a94(_0x164fcd._0x3e627a,_0x164fcd._0x164089,_0x164fcd._0x4c49ba,_0x164fcd._0x3e627a)];const _0x31cc20=_0x4c5aec,_0x598d0e=_0x728090?function(){function _0x2abaa3(_0x402053,_0x1b8f53,_0x222649,_0xb32889){return _0x1551a3(_0xb32889,_0x1b8f53-_0x547cc2._0x289518,_0x1b8f53- -_0x547cc2._0x51bfe8,_0xb32889-_0x547cc2._0x5edd34);}function _0x2f30c0(_0x55c126,_0x24d6c1,_0x4dc0c8,_0x38afa1){return _0x1551a3(_0x24d6c1,_0x24d6c1-_0x21b59d._0x315bf0,_0x55c126-0x1b4,_0x38afa1-0x13);}if(_0xa84547['tMnQz'](_0xa84547[_0x2f30c0(_0x5d4e69._0x1ca623,_0x5d4e69._0x4edef1,_0x5d4e69._0x58d721,0x49b)],_0xa84547['YoBFZ'])){if(_0x4b6291)return _0x38195e[_0x2abaa3(_0x5d4e69._0x5323e2,_0x5d4e69._0xe7940e,_0x5d4e69._0x2fcfcd,_0x5d4e69._0xb64d4c)][_0x2f30c0(_0x5d4e69._0x2f5e4c,_0x5d4e69._0x509777,_0x5d4e69._0x47d151,0x4a5)](_0x31cc20[_0x2f30c0(_0x5d4e69._0x509777,_0x5d4e69._0x58d721,_0x5d4e69._0x58d721,0x4a5)]),_0x291c0b;const _0x841232=_0x2926a0[_0x2abaa3(_0x5d4e69._0x2c9f50,0x1c4,_0x5d4e69._0x40a3ac,_0x5d4e69._0x29f3f5)][_0x2abaa3(_0x5d4e69._0x4ee16c,0x1d1,_0x5d4e69._0xa2331,_0x5d4e69._0x42c79c)+_0x2abaa3(0x1c4,0x1d4,0x1e7,_0x5d4e69._0x1dd931)];return _0x605375=new _0x15f7ff['Expo']({'accessToken':_0x31cc20[_0x2f30c0(_0x5d4e69._0x2721be,_0x5d4e69._0x3802ce,_0x5d4e69._0x57cd27,_0x5d4e69._0x5dc458)](_0x841232,_0x497039),'useFcmV1':!![]}),_0x841232?_0x4937f6[_0x2abaa3(_0x5d4e69._0x517ed6,_0x5d4e69._0x31c340,_0x5d4e69._0x4c7829,_0x5d4e69._0x322dd6)]['info'](_0x31cc20[_0x2abaa3(0x1b8,_0x5d4e69._0x2d4209,0x1cd,_0x5d4e69._0x98207b)]):_0x2286d0['default'][_0x2abaa3(0x1a8,0x1ae,_0x5d4e69._0x5da313,_0x5d4e69._0x35794f)](_0x31cc20['gNQJu']),_0x25c1bc;}else{if(_0x53da98){const _0x12b926=_0x53da98['apply'](_0xce5b2e,arguments);return _0x53da98=null,_0x12b926;}}}:function(){};return _0x728090=![],_0x598d0e;};}()),_0x3e7307=_0x4aff8c(this,function(){const _0x49fc35={_0x525210:0x232,_0x2fabbc:0x242,_0x1fdc95:0x22d,_0xd4e980:0x225,_0x1a3c5a:0x223,_0x2f9612:0x44a,_0x5c3d27:0x231,_0x533357:0x21f,_0x5b735f:0x446,_0x211017:0x435,_0x20f268:0x444,_0xd33b57:0x44f,_0x2f33b8:0x440},_0x456f48={_0x52265b:0x265},_0x5f3d78={_0x2f123d:0x4d};function _0x394b01(_0x4f2e7a,_0x3736ad,_0x267d67,_0x302917){return _0x520f(_0x3736ad-_0x5f3d78._0x2f123d,_0x267d67);}const _0x24d9aa={};_0x24d9aa[_0x394b01(0x227,_0x49fc35._0x525210,_0x49fc35._0x2fabbc,_0x49fc35._0x1fdc95)]=_0x394b01(0x22f,_0x49fc35._0xd4e980,_0x49fc35._0x1a3c5a,_0x49fc35._0x1a3c5a)+'+$';function _0x533485(_0x54b422,_0x646ea7,_0x3d57d2,_0x3ec40c){return _0x520f(_0x54b422-_0x456f48._0x52265b,_0x646ea7);}const _0x148c4c=_0x24d9aa;return _0x3e7307['toString']()['search'](_0x148c4c[_0x533485(_0x49fc35._0x2f9612,0x44d,0x458,0x447)])[_0x394b01(_0x49fc35._0x5c3d27,0x229,_0x49fc35._0x533357,_0x49fc35._0x5c3d27)]()[_0x533485(_0x49fc35._0x5b735f,_0x49fc35._0x211017,0x438,_0x49fc35._0x20f268)+'r'](_0x3e7307)[_0x533485(_0x49fc35._0xd33b57,0x451,_0x49fc35._0xd33b57,_0x49fc35._0x2f33b8)](_0x148c4c['okVNV']);});_0x3e7307();'use strict';var __importDefault=this&&this['__importDe'+_0x5008e9(-0x70,-0x5f,-0x83,-0x76)]||function(_0x23c60c){const _0x46ee19={_0x1ea377:0x381,_0x52f6d1:0x388,_0x424b6f:0x398},_0x49d0cb={_0x52a0d1:0x3f8,_0x306a75:0x11f,_0x454531:0x2c};function _0x5e19a8(_0x32492c,_0x4bc2a4,_0x5098b9,_0x2f3ca4){return _0x5008e9(_0x32492c-_0x49d0cb._0x52a0d1,_0x4bc2a4-_0x49d0cb._0x306a75,_0x2f3ca4,_0x2f3ca4-_0x49d0cb._0x454531);}return _0x23c60c&&_0x23c60c[_0x5e19a8(_0x46ee19._0x1ea377,0x38c,_0x46ee19._0x52f6d1,_0x46ee19._0x424b6f)]?_0x23c60c:{'default':_0x23c60c};};const _0x9d96bb={};_0x9d96bb[_0x5008e9(-0x8b,-0x9f,-0x7a,-0x8f)]=!![];function _0x58fd3d(_0x288ff0,_0x504387,_0x5ab4d1,_0x518dd9){const _0x22354c={_0xa62bc5:0x3c2};return _0x520f(_0x288ff0-_0x22354c._0xa62bc5,_0x504387);}Object['defineProp'+'erty'](exports,_0x58fd3d(0x5bd,0x5d7,0x5d4,0x5c8),_0x9d96bb),exports[_0x5008e9(-0x74,-0x71,-0x67,-0x74)+_0x58fd3d(0x5b5,0x5b5,0x5a5,0x5a8)]=exports['initialize'+'Expo']=void(0x1f1f*0x1+0x2b*-0x3a+-0x1561);const expo_server_sdk_1=require(_0x58fd3d(0x5a8,0x5a2,0x5b3,0x595)+'r-sdk'),logger_1=__importDefault(require(_0x5008e9(-0x87,-0x99,-0x99,-0x9f)+_0x58fd3d(0x5c2,0x5ae,0x5db,0x5b1)));let expoClient=null;const initializeExpo=()=>{const _0x48936c={_0x146dce:0x51a,_0x2b4172:0x52f,_0x1fffa0:0x4f2,_0xb665d:0x4e8,_0x5df537:0x4fb,_0x545172:0x522,_0x21ee8c:0x1e6,_0x185ae8:0x1f1,_0x4da711:0x1e1,_0x1bb104:0x1de,_0x2da298:0x500,_0x3fc7e1:0x508,_0x4b6696:0x503,_0x35cb67:0x50b,_0x364453:0x208,_0x1da132:0x1fc,_0x251b40:0x213,_0x418756:0x4fe,_0x54ba77:0x4fd,_0x366084:0x504,_0x556e29:0x1e7,_0xe0ac21:0x1dd,_0x77a779:0x1d8,_0x396bb3:0x1d0,_0xd38620:0x1da,_0x1f8021:0x1e9,_0x4417f3:0x508,_0x4e7a05:0x4f3,_0x169b5f:0x4f5,_0xbcb523:0x1d4,_0x43f9b6:0x1d7,_0x37509c:0x1c5,_0x15779e:0x1dd,_0x5d1858:0x1e5,_0x5c3f45:0x1f5,_0x4e2a3b:0x1ea,_0x47a5c5:0x1fe,_0x41236d:0x20f,_0x41622e:0x501,_0x1e26bc:0x523,_0x231778:0x526,_0x769553:0x518,_0x25e34e:0x511,_0x918130:0x513,_0x4ae21a:0x50e,_0xa5e3b8:0x4f8,_0x2bf76b:0x50a,_0x194ea5:0x503,_0xa84215:0x4f9,_0x3402d7:0x4ff,_0x17e319:0x1d9,_0x50f17e:0x51b,_0x491beb:0x521,_0x2375c6:0x522,_0x5dc0c8:0x514,_0x257da0:0x201,_0x298d20:0x215,_0x287c8c:0x208,_0x58c66b:0x500,_0x21f257:0x1e8,_0x32aafb:0x1f8,_0xd72495:0x220,_0x3d56d2:0x21f,_0xe1c756:0x520,_0x200bec:0x515,_0x3620ff:0x526,_0x14346f:0x525},_0x3910bc={_0x50147b:0xa4,_0x480414:0x2b},_0x10ccb5={_0x20f46c:0x7a0},_0x2f0906={};function _0x805cb3(_0x5a251b,_0x173d6d,_0x35fb5d,_0x5688c4){return _0x58fd3d(_0x35fb5d- -_0x10ccb5._0x20f46c,_0x5688c4,_0x35fb5d-0xb5,_0x5688c4-0x173);}_0x2f0906[_0x55b6d7(0x521,_0x48936c._0x146dce,_0x48936c._0x2b4172,0x516)]=_0x55b6d7(0x4fd,_0x48936c._0x1fffa0,_0x48936c._0xb665d,_0x48936c._0x5df537)+_0x55b6d7(0x4ff,_0x48936c._0x545172,0x515,0x510)+_0x805cb3(-_0x48936c._0x21ee8c,-_0x48936c._0x185ae8,-_0x48936c._0x4da711,-_0x48936c._0x1bb104)+'d',_0x2f0906[_0x55b6d7(_0x48936c._0x2da298,_0x48936c._0x3fc7e1,_0x48936c._0x4b6696,_0x48936c._0x35cb67)]=function(_0x536e47,_0x8b97ff){return _0x536e47||_0x8b97ff;},_0x2f0906[_0x805cb3(-_0x48936c._0x364453,-0x205,-_0x48936c._0x1da132,-_0x48936c._0x251b40)]=_0x55b6d7(_0x48936c._0x418756,_0x48936c._0x54ba77,_0x48936c._0x366084,_0x48936c._0x5df537)+_0x805cb3(-_0x48936c._0x556e29,-_0x48936c._0xe0ac21,-0x1db,-_0x48936c._0x77a779)+_0x805cb3(-_0x48936c._0x396bb3,-0x1cd,-_0x48936c._0xd38620,-_0x48936c._0x1f8021)+_0x55b6d7(0x4ef,_0x48936c._0x4417f3,_0x48936c._0x4e7a05,_0x48936c._0x169b5f)+'n',_0x2f0906[_0x805cb3(-_0x48936c._0xbcb523,-0x1ea,-_0x48936c._0x43f9b6,-_0x48936c._0x37509c)]='Expo\x20clien'+_0x805cb3(-_0x48936c._0x15779e,-_0x48936c._0x5d1858,-0x1db,-_0x48936c._0x5d1858)+_0x805cb3(-_0x48936c._0x5c3f45,-_0x48936c._0x4e2a3b,-_0x48936c._0x47a5c5,-_0x48936c._0x41236d)+_0x55b6d7(_0x48936c._0x41622e,_0x48936c._0x1e26bc,_0x48936c._0x146dce,0x513)+_0x55b6d7(0x526,_0x48936c._0x231778,0x52e,_0x48936c._0x769553);function _0x55b6d7(_0x21bdeb,_0x59430c,_0x4b277b,_0x17d12e){return _0x58fd3d(_0x17d12e- -_0x3910bc._0x50147b,_0x21bdeb,_0x4b277b-0x195,_0x17d12e-_0x3910bc._0x480414);}const _0x2252d7=_0x2f0906;if(expoClient)return logger_1[_0x55b6d7(0x504,_0x48936c._0x25e34e,_0x48936c._0x918130,0x514)]['info'](_0x2252d7['XNjFw']),expoClient;const _0x50f0d9=process[_0x55b6d7(0x51c,_0x48936c._0x4ae21a,_0x48936c._0xa5e3b8,_0x48936c._0x2bf76b)]['EXPO_ACCES'+'S_TOKEN'];return expoClient=new expo_server_sdk_1[(_0x55b6d7(_0x48936c._0x194ea5,_0x48936c._0xa84215,_0x48936c._0x3402d7,0x4f2))]({'accessToken':_0x2252d7[_0x805cb3(-_0x48936c._0x17e319,-0x202,-_0x48936c._0x185ae8,-0x1ee)](_0x50f0d9,undefined),'useFcmV1':!![]}),_0x50f0d9?logger_1[_0x55b6d7(_0x48936c._0x50f17e,_0x48936c._0x491beb,_0x48936c._0x2375c6,_0x48936c._0x5dc0c8)][_0x805cb3(-_0x48936c._0x257da0,-_0x48936c._0x298d20,-_0x48936c._0x287c8c,-0x200)](_0x2252d7[_0x55b6d7(0x4e6,_0x48936c._0x2da298,0x515,_0x48936c._0x58c66b)]):logger_1[_0x805cb3(-_0x48936c._0x1da132,-0x1e9,-_0x48936c._0x21f257,-_0x48936c._0x32aafb)][_0x805cb3(-_0x48936c._0xd72495,-_0x48936c._0x3d56d2,-_0x48936c._0x287c8c,-0x20c)](_0x2252d7[_0x55b6d7(_0x48936c._0xe1c756,_0x48936c._0x200bec,_0x48936c._0x3620ff,_0x48936c._0x14346f)]),expoClient;};exports['initialize'+_0x58fd3d(0x596,0x5ac,0x588,0x5a0)]=initializeExpo;const getExpoClient=()=>{const _0x14de1c={_0x3e58f2:0x58d,_0x3e44c0:0x58e,_0x44b392:0x585,_0x39ba99:0x580,_0xa0a28c:0x59c,_0x526a7e:0x59d,_0x25147a:0x57d,_0x2c01a8:0x584},_0x29cb2={_0x26454f:0x11f,_0x55583a:0x189},_0x58abc3={_0x438a89:0x32,_0x5b81fb:0x160};function _0x5484e9(_0x2a23b1,_0x41212d,_0x41f29a,_0x33915b){return _0x58fd3d(_0x2a23b1- -_0x58abc3._0x438a89,_0x41212d,_0x41f29a-_0x58abc3._0x5b81fb,_0x33915b-0x187);}function _0x3cd554(_0x13349d,_0x1c9759,_0x565971,_0x10c5b5){return _0x5008e9(_0x10c5b5-0x622,_0x1c9759-_0x29cb2._0x26454f,_0x13349d,_0x10c5b5-_0x29cb2._0x55583a);}if(!expoClient)return(-0x1c62+0xb94+0x10ce,exports[_0x5484e9(_0x14de1c._0x3e58f2,_0x14de1c._0x3e44c0,_0x14de1c._0x44b392,_0x14de1c._0x39ba99)+_0x3cd554(_0x14de1c._0xa0a28c,_0x14de1c._0x526a7e,_0x14de1c._0x25147a,_0x14de1c._0x2c01a8)])();return expoClient;};function _0x520f(_0x5dbdbb,_0x1ebf1f){const _0x5bfa48=_0x3af3();return _0x520f=function(_0x1363a3,_0x1367cb){_0x1363a3=_0x1363a3-(0x1880+0x529*-0x4+0x41*-0x8);let _0x195103=_0x5bfa48[_0x1363a3];if(_0x520f['oIZrEd']===undefined){var _0x3e755f=function(_0x10f9dc){const _0x5d4391='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4fb3b0='',_0x2174e7='',_0x3959c1=_0x4fb3b0+_0x3e755f;for(let _0xb3dc50=-0x22da+0x25fc+0x2*-0x191,_0x48c876,_0x4e1235,_0x410e12=0x1499+-0x29*0x53+-0x74e;_0x4e1235=_0x10f9dc['charAt'](_0x410e12++);~_0x4e1235&&(_0x48c876=_0xb3dc50%(0x6b5+-0xe8+0x5c9*-0x1)?_0x48c876*(-0x2*0xf27+-0xb12+0x250*0x12)+_0x4e1235:_0x4e1235,_0xb3dc50++%(-0x149b+-0x2231+0x36d0))?_0x4fb3b0+=_0x3959c1['charCodeAt'](_0x410e12+(0x23a+0xa0a+-0xc3a))-(-0x173d+0x1a7e+-0x1*0x337)!==0xaa3*-0x1+0x22*0x83+-0x6c3?String['fromCharCode'](0x43*-0x95+0x689*0x4+0xdda&_0x48c876>>(-(0x1109+-0x34*-0x70+-0x27c7)*_0xb3dc50&0x1*0x992+0x2302+-0x2c8e)):_0xb3dc50:0x47*0x6b+0x16b1+-0x345e){_0x4e1235=_0x5d4391['indexOf'](_0x4e1235);}for(let _0x24fff8=-0x1513+0x1519+-0x6,_0x1f1e9f=_0x4fb3b0['length'];_0x24fff8<_0x1f1e9f;_0x24fff8++){_0x2174e7+='%'+('00'+_0x4fb3b0['charCodeAt'](_0x24fff8)['toString'](-0xc*-0x93+-0x24f8+-0xf12*-0x2))['slice'](-(-0xc6a+0x2cc+-0x9a*-0x10));}return decodeURIComponent(_0x2174e7);};_0x520f['rlzAnv']=_0x3e755f,_0x5dbdbb=arguments,_0x520f['oIZrEd']=!![];}const _0x4d86dc=_0x5bfa48[-0xa9*-0x2d+-0xc43*0x3+0x97*0xc],_0x58f3f6=_0x1363a3+_0x4d86dc,_0x3a3378=_0x5dbdbb[_0x58f3f6];if(!_0x3a3378){const _0x3a423e=function(_0x8fe7da){this['puMlzW']=_0x8fe7da,this['ZyyWdD']=[0x71a+0x1b10+-0x2229,0x1e30+-0x1e5*0x5+-0x14b7,-0x1c77+0xa65*0x1+0x303*0x6],this['QyAhtA']=function(){return'newState';},this['AevLGQ']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['EMmWyh']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x3a423e['prototype']['uyZLuD']=function(){const _0x3819b6=new RegExp(this['AevLGQ']+this['EMmWyh']),_0x461f3f=_0x3819b6['test'](this['QyAhtA']['toString']())?--this['ZyyWdD'][-0x5a3+-0xca7*0x1+-0x3*-0x619]:--this['ZyyWdD'][-0xf17+-0x1ca*-0x1+0x46f*0x3];return this['DDKWoJ'](_0x461f3f);},_0x3a423e['prototype']['DDKWoJ']=function(_0x14304e){if(!Boolean(~_0x14304e))return _0x14304e;return this['HRdDmX'](this['puMlzW']);},_0x3a423e['prototype']['HRdDmX']=function(_0x381de3){for(let _0x6bac4b=0x50b+-0x1108+-0x21*-0x5d,_0x5a0867=this['ZyyWdD']['length'];_0x6bac4b<_0x5a0867;_0x6bac4b++){this['ZyyWdD']['push'](Math['round'](Math['random']())),_0x5a0867=this['ZyyWdD']['length'];}return _0x381de3(this['ZyyWdD'][-0x3*-0x602+-0x272*-0x7+-0x2324]);},new _0x3a423e(_0x520f)['uyZLuD'](),_0x195103=_0x520f['rlzAnv'](_0x195103),_0x5dbdbb[_0x58f3f6]=_0x195103;}else _0x195103=_0x3a3378;return _0x195103;},_0x520f(_0x5dbdbb,_0x1ebf1f);}exports[_0x5008e9(-0x74,-0x82,-0x80,-0x89)+_0x58fd3d(0x5b5,0x5a9,0x5c5,0x5b6)]=getExpoClient;
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Notification Hook for Claude Code
|
|
5
|
+
*
|
|
6
|
+
* CURRENTLY DISABLED - Coming Soon
|
|
7
|
+
*
|
|
8
|
+
* This hook will send push notifications to mobile devices when Claude Code
|
|
9
|
+
* needs user attention (e.g., idle >60s, permission requests).
|
|
10
|
+
*
|
|
11
|
+
* Disabled due to FCM service account security concerns when distributing
|
|
12
|
+
* the backend as an npm package. Will be re-enabled once notification
|
|
13
|
+
* architecture is finalized (cloud relay, Expo push service, or MQTT-based).
|
|
14
|
+
*
|
|
15
|
+
* Communication Flow (when enabled):
|
|
16
|
+
* 1. Receives notification event from Claude via stdin
|
|
17
|
+
* 2. Reads session-to-project mapping from sessions.json
|
|
18
|
+
* 3. Gets all device tokens registered for that project
|
|
19
|
+
* 4. Sends "needs attention" notifications to devices via backend API
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// Exit immediately - feature disabled
|
|
23
|
+
process.exit(0);
|
|
24
|
+
|
|
25
|
+
/* DISABLED CODE BELOW - DO NOT USE UNTIL NOTIFICATION ARCHITECTURE IS FINALIZED
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// EVERYTHING BELOW THIS LINE IS COMMENTED OUT
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
|
|
33
|
+
const fs = require('fs');
|
|
34
|
+
const path = require('path');
|
|
35
|
+
|
|
36
|
+
// Load environment variables from .env file in hooks folder (silent mode)
|
|
37
|
+
require('dotenv').config({ path: path.join(__dirname, '.env'), quiet: true });
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Configuration
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
// Sessions.json is in .claude folder (same folder as hooks folder)
|
|
44
|
+
// Hook runs from $CLAUDE_PROJECT_DIR/.claude/hooks, so go up 1 level to .claude
|
|
45
|
+
const SESSION_MAPPING_FILE = path.join(__dirname, '..', 'sessions.json');
|
|
46
|
+
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Helper Functions
|
|
49
|
+
// ============================================================================
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Logs to stderr (so it doesn't interfere with stdout JSON output)
|
|
53
|
+
*/
|
|
54
|
+
function log(message, data = null) {
|
|
55
|
+
const timestamp = new Date().toISOString();
|
|
56
|
+
const logMsg = data
|
|
57
|
+
? `[${timestamp}] [NotificationHook] ${message}: ${JSON.stringify(data)}`
|
|
58
|
+
: `[${timestamp}] [NotificationHook] ${message}`;
|
|
59
|
+
console.error(logMsg);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Reads session-to-project mapping from sessions.json
|
|
64
|
+
* Returns projectId for given sessionId
|
|
65
|
+
*/
|
|
66
|
+
function getProjectIdFromSession(sessionId) {
|
|
67
|
+
try {
|
|
68
|
+
if (!fs.existsSync(SESSION_MAPPING_FILE)) {
|
|
69
|
+
log('Session mapping file not found', { path: SESSION_MAPPING_FILE });
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const data = fs.readFileSync(SESSION_MAPPING_FILE, 'utf8');
|
|
74
|
+
const mapping = JSON.parse(data);
|
|
75
|
+
|
|
76
|
+
if (mapping[sessionId]) {
|
|
77
|
+
log('Found project ID for session', { sessionId, projectId: mapping[sessionId] });
|
|
78
|
+
return mapping[sessionId];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
log('Session ID not found in mapping', { sessionId });
|
|
82
|
+
return null;
|
|
83
|
+
|
|
84
|
+
} catch (error) {
|
|
85
|
+
log('Error reading session mapping', { error: error.message });
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Reads JSON input from stdin
|
|
92
|
+
*/
|
|
93
|
+
function readStdin() {
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
let data = '';
|
|
96
|
+
|
|
97
|
+
process.stdin.setEncoding('utf8');
|
|
98
|
+
|
|
99
|
+
process.stdin.on('data', (chunk) => {
|
|
100
|
+
data += chunk;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
process.stdin.on('end', () => {
|
|
104
|
+
try {
|
|
105
|
+
const parsed = JSON.parse(data);
|
|
106
|
+
resolve(parsed);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
reject(new Error(`Failed to parse stdin JSON: ${error.message}`));
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
process.stdin.on('error', (error) => {
|
|
113
|
+
reject(new Error(`Error reading stdin: ${error.message}`));
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Sends notification to all devices registered for the project
|
|
120
|
+
* Uses the sendNotificationWithPreferenceCheck API from the backend
|
|
121
|
+
*/
|
|
122
|
+
async function sendNotificationsToDevices(projectId, notificationMessage) {
|
|
123
|
+
try {
|
|
124
|
+
// Import the backend notification module
|
|
125
|
+
// Path from hooks folder: ../src/notifications/sender.ts
|
|
126
|
+
const senderPath = path.join(__dirname, '..', 'src', 'notifications', 'sender.js');
|
|
127
|
+
const tokenManagerPath = path.join(__dirname, '..', 'src', 'notifications', 'token-manager.js');
|
|
128
|
+
|
|
129
|
+
// Check if compiled JS files exist (TypeScript backend needs to be compiled)
|
|
130
|
+
if (!fs.existsSync(senderPath) || !fs.existsSync(tokenManagerPath)) {
|
|
131
|
+
log('Backend notification modules not found - TypeScript may not be compiled', {
|
|
132
|
+
senderPath,
|
|
133
|
+
tokenManagerPath
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Try to require from dist folder if it exists
|
|
137
|
+
const distSenderPath = path.join(__dirname, '..', 'dist', 'notifications', 'sender.js');
|
|
138
|
+
const distTokenManagerPath = path.join(__dirname, '..', 'dist', 'notifications', 'token-manager.js');
|
|
139
|
+
|
|
140
|
+
if (!fs.existsSync(distSenderPath) || !fs.existsSync(distTokenManagerPath)) {
|
|
141
|
+
log('Compiled backend modules not found in dist folder either');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const { sendNotificationWithPreferenceCheck } = require(distSenderPath);
|
|
146
|
+
const { getDeviceTokensByProject } = require(distTokenManagerPath);
|
|
147
|
+
|
|
148
|
+
// Get all devices registered for this project
|
|
149
|
+
const deviceTokens = getDeviceTokensByProject(projectId);
|
|
150
|
+
|
|
151
|
+
if (!deviceTokens || deviceTokens.length === 0) {
|
|
152
|
+
log('No devices registered for project', { projectId });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
log('Sending notifications to devices', {
|
|
157
|
+
projectId,
|
|
158
|
+
deviceCount: deviceTokens.length
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Send notification to each device with preference check
|
|
162
|
+
const notificationPromises = deviceTokens.map(async (device) => {
|
|
163
|
+
return sendNotificationWithPreferenceCheck(
|
|
164
|
+
device.deviceId,
|
|
165
|
+
'needsAttention',
|
|
166
|
+
{
|
|
167
|
+
title: 'Claude Code Needs Attention',
|
|
168
|
+
body: notificationMessage || 'Claude is waiting for your input',
|
|
169
|
+
data: {
|
|
170
|
+
type: 'needsAttention',
|
|
171
|
+
projectId,
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{ priority: 'high' }
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const results = await Promise.allSettled(notificationPromises);
|
|
179
|
+
const successCount = results.filter(r => r.status === 'fulfilled' && r.value.success).length;
|
|
180
|
+
|
|
181
|
+
log('Notification sending completed', {
|
|
182
|
+
total: deviceTokens.length,
|
|
183
|
+
successful: successCount,
|
|
184
|
+
failed: deviceTokens.length - successCount
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Use regular path if compiled files exist
|
|
191
|
+
const { sendNotificationWithPreferenceCheck } = require(senderPath);
|
|
192
|
+
const { getDeviceTokensByProject } = require(tokenManagerPath);
|
|
193
|
+
|
|
194
|
+
// Get all devices registered for this project
|
|
195
|
+
const deviceTokens = getDeviceTokensByProject(projectId);
|
|
196
|
+
|
|
197
|
+
if (!deviceTokens || deviceTokens.length === 0) {
|
|
198
|
+
log('No devices registered for project', { projectId });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
log('Sending notifications to devices', {
|
|
203
|
+
projectId,
|
|
204
|
+
deviceCount: deviceTokens.length
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Send notification to each device with preference check
|
|
208
|
+
const notificationPromises = deviceTokens.map(async (device) => {
|
|
209
|
+
return sendNotificationWithPreferenceCheck(
|
|
210
|
+
device.deviceId,
|
|
211
|
+
'needsAttention',
|
|
212
|
+
{
|
|
213
|
+
title: 'Claude Code Needs Attention',
|
|
214
|
+
body: notificationMessage || 'Claude is waiting for your input',
|
|
215
|
+
data: {
|
|
216
|
+
type: 'needsAttention',
|
|
217
|
+
projectId,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{ priority: 'high' }
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const results = await Promise.allSettled(notificationPromises);
|
|
225
|
+
const successCount = results.filter(r => r.status === 'fulfilled' && r.value.success).length;
|
|
226
|
+
|
|
227
|
+
log('Notification sending completed', {
|
|
228
|
+
total: deviceTokens.length,
|
|
229
|
+
successful: successCount,
|
|
230
|
+
failed: deviceTokens.length - successCount
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
} catch (error) {
|
|
234
|
+
log('Error sending notifications', {
|
|
235
|
+
error: error.message,
|
|
236
|
+
stack: error.stack
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// Main Execution
|
|
243
|
+
// ============================================================================
|
|
244
|
+
|
|
245
|
+
async function main() {
|
|
246
|
+
try {
|
|
247
|
+
log('Notification hook started');
|
|
248
|
+
|
|
249
|
+
// Read hook input from stdin
|
|
250
|
+
const hookInput = await readStdin();
|
|
251
|
+
log('Received hook input', hookInput);
|
|
252
|
+
|
|
253
|
+
// Validate hook event
|
|
254
|
+
if (hookInput.hook_event_name !== 'Notification') {
|
|
255
|
+
log('Not a Notification event, ignoring', { event: hookInput.hook_event_name });
|
|
256
|
+
process.exit(0);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Validate required fields
|
|
260
|
+
if (!hookInput.session_id || !hookInput.message) {
|
|
261
|
+
throw new Error('Missing required fields in hook input (session_id or message)');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Get project ID from session mapping file
|
|
265
|
+
const projectId = getProjectIdFromSession(hookInput.session_id);
|
|
266
|
+
|
|
267
|
+
// If session is not in sessions.json, this is a native Claude Code session
|
|
268
|
+
// (not managed by CCC backend). Skip notification.
|
|
269
|
+
if (!projectId) {
|
|
270
|
+
log('Session not found in sessions.json - this is a native Claude Code session');
|
|
271
|
+
log('Skipping notification (no mobile devices registered)');
|
|
272
|
+
process.exit(0);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
log('Resolved project ID', { projectId });
|
|
276
|
+
|
|
277
|
+
// Send notifications to all devices
|
|
278
|
+
await sendNotificationsToDevices(projectId, hookInput.message);
|
|
279
|
+
|
|
280
|
+
// Exit successfully
|
|
281
|
+
log('Notification hook completed successfully');
|
|
282
|
+
process.exit(0);
|
|
283
|
+
|
|
284
|
+
} catch (error) {
|
|
285
|
+
log('Hook execution failed', { error: error.message, stack: error.stack });
|
|
286
|
+
|
|
287
|
+
// Exit with 0 even on error (don't block Claude Code execution)
|
|
288
|
+
process.exit(0);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Handle process signals
|
|
293
|
+
process.on('SIGINT', () => {
|
|
294
|
+
log('Received SIGINT, exiting');
|
|
295
|
+
process.exit(0);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
process.on('SIGTERM', () => {
|
|
299
|
+
log('Received SIGTERM, exiting');
|
|
300
|
+
process.exit(0);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Run the hook
|
|
304
|
+
main();
|
|
305
|
+
|
|
306
|
+
END OF DISABLED CODE */
|
|
@@ -326,10 +326,13 @@ async function requestPermission(hookInput, projectId) {
|
|
|
326
326
|
const client = mqtt.connect(connectUrl, connectOptions);
|
|
327
327
|
let resolved = false;
|
|
328
328
|
let timeoutHandle = null;
|
|
329
|
+
let ackTimeoutHandle = null;
|
|
330
|
+
let ackReceived = false;
|
|
329
331
|
|
|
330
332
|
// Topics for communication
|
|
331
333
|
const requestTopic = `permissions/${projectId}/request`;
|
|
332
334
|
const responseTopic = `permissions/${projectId}/response`;
|
|
335
|
+
const ackTopic = `permissions/${projectId}/ack`;
|
|
333
336
|
|
|
334
337
|
/**
|
|
335
338
|
* Cleanup and resolve/reject helper
|
|
@@ -342,6 +345,10 @@ async function requestPermission(hookInput, projectId) {
|
|
|
342
345
|
clearTimeout(timeoutHandle);
|
|
343
346
|
}
|
|
344
347
|
|
|
348
|
+
if (ackTimeoutHandle) {
|
|
349
|
+
clearTimeout(ackTimeoutHandle);
|
|
350
|
+
}
|
|
351
|
+
|
|
345
352
|
// Clean disconnect
|
|
346
353
|
client.end(true, {}, () => {
|
|
347
354
|
callback();
|
|
@@ -363,46 +370,108 @@ async function requestPermission(hookInput, projectId) {
|
|
|
363
370
|
client.on('connect', () => {
|
|
364
371
|
log('Connected to MQTT broker');
|
|
365
372
|
|
|
366
|
-
// Subscribe to
|
|
367
|
-
client.subscribe(
|
|
373
|
+
// Subscribe to ACK topic first
|
|
374
|
+
client.subscribe(ackTopic, { qos: MQTT_CONFIG.qos }, (err) => {
|
|
368
375
|
if (err) {
|
|
369
|
-
log('Failed to subscribe to
|
|
376
|
+
log('Failed to subscribe to ACK topic', { error: err.message });
|
|
370
377
|
cleanup(() => {
|
|
371
|
-
reject(new Error(`Failed to subscribe: ${err.message}`));
|
|
378
|
+
reject(new Error(`Failed to subscribe to ACK: ${err.message}`));
|
|
372
379
|
});
|
|
373
380
|
return;
|
|
374
381
|
}
|
|
375
382
|
|
|
376
|
-
log('Subscribed to
|
|
377
|
-
|
|
378
|
-
// Publish permission request
|
|
379
|
-
const permissionRequest = {
|
|
380
|
-
tool_name,
|
|
381
|
-
tool_input,
|
|
382
|
-
session_id,
|
|
383
|
-
cwd,
|
|
384
|
-
timestamp: Date.now(),
|
|
385
|
-
project_id: projectId,
|
|
386
|
-
};
|
|
383
|
+
log('Subscribed to ACK topic', { topic: ackTopic });
|
|
387
384
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
client.publish(requestTopic, payload, { qos: MQTT_CONFIG.qos, retain: false }, (err) => {
|
|
385
|
+
// Subscribe to response topic
|
|
386
|
+
client.subscribe(responseTopic, { qos: MQTT_CONFIG.qos }, (err) => {
|
|
391
387
|
if (err) {
|
|
392
|
-
log('Failed to
|
|
388
|
+
log('Failed to subscribe to response topic', { error: err.message });
|
|
393
389
|
cleanup(() => {
|
|
394
|
-
reject(new Error(`Failed to
|
|
390
|
+
reject(new Error(`Failed to subscribe: ${err.message}`));
|
|
395
391
|
});
|
|
396
392
|
return;
|
|
397
393
|
}
|
|
398
394
|
|
|
399
|
-
log('
|
|
395
|
+
log('Subscribed to response topic', { topic: responseTopic });
|
|
396
|
+
|
|
397
|
+
// Publish permission request
|
|
398
|
+
const permissionRequest = {
|
|
399
|
+
tool_name,
|
|
400
|
+
tool_input,
|
|
401
|
+
session_id,
|
|
402
|
+
cwd,
|
|
403
|
+
timestamp: Date.now(),
|
|
404
|
+
project_id: projectId,
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const payload = JSON.stringify(permissionRequest);
|
|
408
|
+
|
|
409
|
+
client.publish(requestTopic, payload, { qos: MQTT_CONFIG.qos, retain: false }, (err) => {
|
|
410
|
+
if (err) {
|
|
411
|
+
log('Failed to publish permission request', { error: err.message });
|
|
412
|
+
cleanup(() => {
|
|
413
|
+
reject(new Error(`Failed to publish: ${err.message}`));
|
|
414
|
+
});
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
log('Published permission request', { topic: requestTopic });
|
|
419
|
+
|
|
420
|
+
// Send notification to all devices
|
|
421
|
+
const notificationTopic = `notifications/${projectId}/permission`;
|
|
422
|
+
const notificationPayload = JSON.stringify({
|
|
423
|
+
type: 'permission_request',
|
|
424
|
+
tool_name,
|
|
425
|
+
tool_input,
|
|
426
|
+
timestamp: Date.now(),
|
|
427
|
+
project_id: projectId,
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
client.publish(notificationTopic, notificationPayload, { qos: MQTT_CONFIG.qos }, (notifErr) => {
|
|
431
|
+
if (notifErr) {
|
|
432
|
+
log('Failed to publish notification', { error: notifErr.message });
|
|
433
|
+
// Don't fail the whole request if notification fails
|
|
434
|
+
} else {
|
|
435
|
+
log('Published permission notification', { topic: notificationTopic });
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// Set ACK timeout (2 seconds)
|
|
440
|
+
ackTimeoutHandle = setTimeout(() => {
|
|
441
|
+
if (!ackReceived) {
|
|
442
|
+
log('ACK not received within 2 seconds - user likely not on mobile app');
|
|
443
|
+
cleanup(() => {
|
|
444
|
+
// Exit without response - Claude will continue without permission
|
|
445
|
+
process.exit(0);
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}, 2000);
|
|
449
|
+
});
|
|
400
450
|
});
|
|
401
451
|
});
|
|
402
452
|
});
|
|
403
453
|
|
|
404
|
-
// Handle incoming messages (response from frontend)
|
|
454
|
+
// Handle incoming messages (ACK and response from frontend)
|
|
405
455
|
client.on('message', (topic, payload) => {
|
|
456
|
+
// Handle ACK
|
|
457
|
+
if (topic === ackTopic) {
|
|
458
|
+
try {
|
|
459
|
+
const ack = JSON.parse(payload.toString());
|
|
460
|
+
log('Received ACK from mobile app', ack);
|
|
461
|
+
ackReceived = true;
|
|
462
|
+
|
|
463
|
+
// Clear ACK timeout since we received it
|
|
464
|
+
if (ackTimeoutHandle) {
|
|
465
|
+
clearTimeout(ackTimeoutHandle);
|
|
466
|
+
ackTimeoutHandle = null;
|
|
467
|
+
}
|
|
468
|
+
} catch (error) {
|
|
469
|
+
log('Failed to parse ACK', { error: error.message });
|
|
470
|
+
}
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Handle response
|
|
406
475
|
if (topic !== responseTopic) return;
|
|
407
476
|
|
|
408
477
|
try {
|
|
@@ -552,11 +621,12 @@ async function main() {
|
|
|
552
621
|
// Get project ID from session mapping file
|
|
553
622
|
let projectId = getProjectIdFromSession(hookInput.session_id);
|
|
554
623
|
|
|
555
|
-
//
|
|
556
|
-
//
|
|
624
|
+
// If no project ID found, we can't route the permission request via MQTT
|
|
625
|
+
// This could happen if the session was started from CLI without backend
|
|
626
|
+
// In this case, exit without blocking (allow the operation)
|
|
557
627
|
if (!projectId) {
|
|
558
|
-
log('Session not found in sessions.json -
|
|
559
|
-
|
|
628
|
+
log('Session not found in sessions.json - allowing operation without permission check');
|
|
629
|
+
outputDecision('allow', 'Session not managed by backend - bypassing permission check');
|
|
560
630
|
process.exit(0);
|
|
561
631
|
}
|
|
562
632
|
|