@naarang/ccc 1.2.0-beta.1 → 1.2.0-beta.11
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 -1
- package/dist/claude/session-message-parser.js +1 -1
- 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 +95 -26
- package/dist/index.js +1 -1
- package/dist/mdns/service.js +1 -1
- 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 -1
- 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 +6 -2
- package/scripts/check-pty.js +142 -0
- package/scripts/obfuscate.js +77 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function _0x356b6c(_0x5905e8,_0x1469d9,_0x53b157,_0x15da01){const _0x3f3e60={_0x5d03bd:0x65};return _0x3159(_0x53b157-_0x3f3e60._0x5d03bd,_0x1469d9);}(function(_0x3ddb8e,_0x3fa0b6){const _0xf17d3d={_0x441bd8:0x499,_0x4bd1cc:0x499,_0x589574:0x4a6,_0x147cbc:0x229,_0x3660ea:0x247,_0x16df8c:0x23c,_0x3b2279:0x226,_0x2a231d:0x22e,_0x4e60d7:0x24c,_0x22e435:0x263,_0xa57bb2:0x246,_0x467f51:0x23e,_0x3bafe5:0x243,_0x95afc8:0x23b,_0x57a533:0x257,_0x35913e:0x249,_0x4190e1:0x23d,_0x4a6e65:0x4e4,_0x936da4:0x4bc,_0x90e8a5:0x4c2,_0x507227:0x4ca,_0x549069:0x4a7,_0x44246a:0x4bc,_0x34f6e6:0x49f,_0x2945d4:0x4bf,_0x2e95e9:0x4d6,_0x46f7f0:0x4cb,_0x1a504d:0x4b6,_0x562f03:0x4a8,_0x247e8a:0x4ac,_0x1bbf54:0x4ad,_0x12c18c:0x4bb},_0x4f6559={_0x391cbd:0x7d},_0x1cf0c6={_0x52f52d:0x2eb},_0x56232b=_0x3ddb8e();function _0x19b2f8(_0x43ef8d,_0x101f7e,_0x184c8e,_0x57f912){return _0x3159(_0x57f912-_0x1cf0c6._0x52f52d,_0x101f7e);}function _0x38b502(_0x1a8f19,_0x3844ff,_0x383d3d,_0x5b72b5){return _0x3159(_0x5b72b5-_0x4f6559._0x391cbd,_0x1a8f19);}while(!![]){try{const _0x42c7ce=parseInt(_0x19b2f8(0x4b1,_0xf17d3d._0x441bd8,_0xf17d3d._0x4bd1cc,_0xf17d3d._0x589574))/(0x93d+0x4*-0x196+-0x1*0x2e4)*(-parseInt(_0x38b502(_0xf17d3d._0x147cbc,_0xf17d3d._0x3660ea,0x226,_0xf17d3d._0x16df8c))/(-0x22d6+-0x2184+-0x7*-0x9c4))+parseInt(_0x38b502(_0xf17d3d._0x3b2279,_0xf17d3d._0x2a231d,_0xf17d3d._0x3660ea,0x239))/(-0x4*0x8ad+-0x280+0x2537)*(parseInt(_0x38b502(_0xf17d3d._0x4e60d7,0x25b,0x261,_0xf17d3d._0x22e435))/(-0x121*-0x3+0x1723+-0x1a82))+parseInt(_0x38b502(_0xf17d3d._0xa57bb2,_0xf17d3d._0x467f51,_0xf17d3d._0x3bafe5,_0xf17d3d._0x95afc8))/(0x24ee+0x957+-0x2e40)+-parseInt(_0x38b502(0x23a,_0xf17d3d._0x57a533,_0xf17d3d._0x35913e,_0xf17d3d._0x4190e1))/(-0x1*0x2663+0x11b*0x8+-0x3*-0x9db)+parseInt(_0x19b2f8(_0xf17d3d._0x4a6e65,_0xf17d3d._0x936da4,_0xf17d3d._0x90e8a5,_0xf17d3d._0x507227))/(0x1*-0x82c+-0x15b0+0x1*0x1de3)*(parseInt(_0x19b2f8(_0xf17d3d._0x549069,_0xf17d3d._0x44246a,_0xf17d3d._0x34f6e6,0x4b8))/(0x2157+-0x17ff*-0x1+-0xb76*0x5))+parseInt(_0x19b2f8(_0xf17d3d._0x2945d4,_0xf17d3d._0x2e95e9,0x4cd,_0xf17d3d._0x46f7f0))/(0x1b2c+0xe2f+0x1*-0x2952)+parseInt(_0x19b2f8(_0xf17d3d._0x1a504d,_0xf17d3d._0x562f03,_0xf17d3d._0x247e8a,_0xf17d3d._0x1bbf54))/(0x1b06+-0xc7d+-0xe7f)*(-parseInt(_0x19b2f8(0x4c2,_0xf17d3d._0x90e8a5,_0xf17d3d._0x12c18c,0x4b2))/(0x639+0x421+0x7*-0x179));if(_0x42c7ce===_0x3fa0b6)break;else _0x56232b['push'](_0x56232b['shift']());}catch(_0x27eb1a){_0x56232b['push'](_0x56232b['shift']());}}}(_0x324f,-0x1060+-0xca*0x31e+0xc9fb5));const _0x496f65=(function(){const _0x17d42c={_0x4cdf03:0x1ac,_0x302e31:0x1bf,_0x32e4ae:0x1c0,_0x548268:0x1d4,_0x1e5563:0x194,_0x369f08:0x19a,_0x47024e:0x197,_0x5e63fe:0x18f,_0x4901e2:0x18f},_0x192347={_0x46c2d5:0x121,_0x429c8b:0x10e,_0x4ce261:0xf7,_0x1411af:0x107,_0x37cf1e:0x129,_0x35e148:0x106,_0x1206c9:0x34d,_0x55876d:0x344,_0x20b3f5:0x327,_0x416b90:0x333,_0x40a7fa:0x32a,_0x1bb62f:0x120,_0x33df9d:0x130,_0xe1e8a0:0x12e,_0x18fc24:0x11b,_0x468804:0x32c,_0x636a0f:0x33f,_0x46981d:0x334,_0x1849b5:0x111,_0x5865fb:0xfc,_0x3958c9:0x111,_0x5b8322:0x329,_0x5c360f:0x31b,_0x592d9c:0x33a,_0x174b9f:0x11a,_0x280d38:0x126,_0x1a7227:0x104,_0x53b843:0x348,_0x151add:0x344,_0x251349:0x35a},_0x28069c={_0x2d3048:0xe,_0x1b9762:0x2a,_0xbe212a:0x15,_0x1ce57a:0x1},_0x2c3fde={_0x3da957:0x16},_0x4299e0={_0x51c8cb:0x37f},_0x351975={};_0x351975[_0x2ae1cb(-_0x17d42c._0x4cdf03,-0x1ab,-0x1aa,-_0x17d42c._0x302e31)]=_0x18dfcf(_0x17d42c._0x32e4ae,_0x17d42c._0x32e4ae,0x1cb,_0x17d42c._0x548268)+'+$',_0x351975[_0x2ae1cb(-_0x17d42c._0x1e5563,-0x189,-0x17a,-_0x17d42c._0x369f08)]=function(_0x262ded,_0x3b9979){return _0x262ded===_0x3b9979;};function _0x2ae1cb(_0x2f819,_0x4b87c8,_0xb104e5,_0xedf7ba){return _0x3159(_0x2f819- -_0x4299e0._0x51c8cb,_0x4b87c8);}_0x351975['itZWx']=_0x2ae1cb(-_0x17d42c._0x47024e,-_0x17d42c._0x5e63fe,-_0x17d42c._0x4901e2,-0x195);function _0x18dfcf(_0x5391c8,_0x8148d2,_0x1488cf,_0x5f20a){return _0x3159(_0x1488cf- -_0x2c3fde._0x3da957,_0x5f20a);}const _0x2d74a2=_0x351975;let _0x3a8779=!![];return function(_0x2bf49a,_0x13767a){const _0x12b102={'poyLd':_0x2d74a2['IjhZq'],'aSBUK':function(_0x3753fa,_0x23dd9d){const _0x5d6cfe={_0x2462f6:0x1d6};function _0x21f863(_0x27da54,_0x578fee,_0x3afe2e,_0x1b713c){return _0x3159(_0x3afe2e- -_0x5d6cfe._0x2462f6,_0x27da54);}return _0x2d74a2[_0x21f863(_0x28069c._0x2d3048,_0x28069c._0x1b9762,_0x28069c._0xbe212a,_0x28069c._0x1ce57a)](_0x3753fa,_0x23dd9d);},'trVrP':_0x2d74a2['itZWx']},_0x127278=_0x3a8779?function(){const _0x5d65c0={_0x206f36:0x2f8};function _0x51dece(_0x24db21,_0x3598c4,_0x11b46f,_0x30feff){return _0x3159(_0x3598c4- -_0x5d65c0._0x206f36,_0x24db21);}function _0x4976e0(_0xc48ee5,_0x106c5c,_0x19e8e3,_0x59d60e){return _0x3159(_0x106c5c-0x161,_0x19e8e3);}if(_0x13767a){if(_0x12b102[_0x51dece(-_0x192347._0x46c2d5,-_0x192347._0x429c8b,-_0x192347._0x4ce261,-_0x192347._0x1411af)](_0x12b102[_0x51dece(-0x129,-0x115,-_0x192347._0x37cf1e,-_0x192347._0x35e148)],_0x12b102[_0x4976e0(_0x192347._0x1206c9,_0x192347._0x55876d,0x339,0x351)])){const _0x234b8d=_0x13767a[_0x4976e0(_0x192347._0x20b3f5,_0x192347._0x416b90,0x31f,_0x192347._0x40a7fa)](_0x2bf49a,arguments);return _0x13767a=null,_0x234b8d;}else return _0x76b536[_0x51dece(-_0x192347._0x1bb62f,-_0x192347._0x33df9d,-_0x192347._0xe1e8a0,-_0x192347._0x18fc24)]()[_0x4976e0(_0x192347._0x468804,_0x192347._0x636a0f,_0x192347._0x46981d,0x33a)](_0x12b102[_0x51dece(-0xff,-_0x192347._0x1849b5,-_0x192347._0x5865fb,-_0x192347._0x3958c9)])[_0x4976e0(0x337,_0x192347._0x5b8322,_0x192347._0x5c360f,_0x192347._0x592d9c)]()['constructo'+'r'](_0x4f39e3)[_0x51dece(-_0x192347._0x46c2d5,-_0x192347._0x174b9f,-_0x192347._0x280d38,-_0x192347._0x1a7227)](_0x12b102[_0x4976e0(0x33f,_0x192347._0x53b843,_0x192347._0x151add,_0x192347._0x251349)]);}}:function(){};return _0x3a8779=![],_0x127278;};}()),_0x4146b9=_0x496f65(this,function(){const _0x4060de={_0x439463:0x8d,_0x40b423:0xb2,_0x33de75:0xa7,_0xb809f1:0x438,_0x130209:0x426,_0x416676:0xaa,_0x4ab514:0xab,_0x29ac88:0xbd,_0x3edd93:0xac,_0xc68778:0xb8,_0x43d6c8:0x434,_0xb6d837:0x438,_0x2c6cb7:0x43d,_0x24c943:0xa8,_0x5c5530:0xbe},_0x6dfc07={_0xc4c1c8:0x289},_0x26ffc4={_0x1974d7:0x256},_0x1a60fb={};_0x1a60fb[_0x116f25(-_0x4060de._0x439463,-_0x4060de._0x40b423,-_0x4060de._0x33de75,-0xbc)]='(((.+)+)+)'+'+$';const _0x3983cb=_0x1a60fb;function _0x1d5a4f(_0x3a5a09,_0x14949e,_0x8048bf,_0x1dcde7){return _0x3159(_0x8048bf-_0x26ffc4._0x1974d7,_0x3a5a09);}function _0x116f25(_0x5037c0,_0x5a5ad8,_0x37899c,_0x389cbc){return _0x3159(_0x37899c- -_0x6dfc07._0xc4c1c8,_0x5037c0);}return _0x4146b9[_0x1d5a4f(_0x4060de._0xb809f1,0x416,0x41e,_0x4060de._0x130209)]()[_0x116f25(-0xa1,-_0x4060de._0x416676,-_0x4060de._0x4ab514,-_0x4060de._0x29ac88)](_0x3983cb['ySKEz'])['toString']()[_0x116f25(-_0x4060de._0x3edd93,-_0x4060de._0x4ab514,-_0x4060de._0xc68778,-_0x4060de._0x3edd93)+'r'](_0x4146b9)[_0x1d5a4f(_0x4060de._0x43d6c8,_0x4060de._0xb6d837,0x434,_0x4060de._0x2c6cb7)](_0x116f25(-0x9e,-0xaf,-_0x4060de._0x24c943,-_0x4060de._0x5c5530)+'+$');});_0x4146b9();'use strict';var __importDefault=this&&this[_0x356b6c(0x23c,0x247,0x242,0x25c)+_0x356b6c(0x243,0x259,0x240,0x25a)]||function(_0xf407f0){const _0x252b75={_0x2e00d5:0x235,_0x56de8e:0x23b},_0x49aee5={_0x356e8d:0xd0,_0x4f4464:0x301,_0x4e642d:0x1dc};function _0x563c65(_0x462e65,_0xc34dc2,_0x549fce,_0x291a3d){return _0x383f21(_0x462e65-_0x49aee5._0x356e8d,_0x462e65,_0x291a3d- -_0x49aee5._0x4f4464,_0x291a3d-_0x49aee5._0x4e642d);}return _0xf407f0&&_0xf407f0[_0x563c65(0x231,_0x252b75._0x2e00d5,_0x252b75._0x56de8e,_0x252b75._0x56de8e)]?_0xf407f0:{'default':_0xf407f0};};function _0x383f21(_0x568520,_0x3440bf,_0x379a35,_0x10ec00){const _0x223be9={_0x4e6953:0x365};return _0x3159(_0x379a35-_0x223be9._0x4e6953,_0x3440bf);}function _0x324f(){const _0x51fabd=['zxHWBY1Zzxj2zq','EMvKihDPDgGGyq','ntK2suL2sKvH','Cg95tgq','shDIrhi','B2DNzxi','yvncvuS','servCwu','u19ut0TftG','zxj0Eq','DxnLrMnTvJe','n3fpyurjvW','mJm4nxDlq3DuDW','lI4VDxrPBhmVBa','mtm4mJqWmeTqAMPvzW','mJK4nZy2qMfHCMnQ','mZa2ndu2mhDfDgHzAq','EMvKihDPDgHVDq','odGYmg1kqKf3zG','DMfSDwu','ywnJzxnZvg9Rzq','zgvMyxvSDa','v2vzDhy','nZG1ngLpsLfssW','Dg9tDhjPBMC','y3rOtKK','CI1ZzgS','rvHqt19bq0nfuW','rxHWBYbJBgLLBG','nde5oda4vxHyz0Pw','A3HmsMO','se1IDNu','whbYEeq','y29UC3rYDwn0BW','yxbWBhK','swPOwNe','Aw5MBW','z2v0rxHWB0nSAq','zw50','x19LC01VzhvSzq','Aw5PDgLHBgL6zq','Eg9Wt2y','uurtufK','zMf1Bhq','rxHWBW','x19PBxbVCNrezq','C2vHCMnO','mtu0CgrhAMzS','mte2odGZotLMwgjrqLu','kcGOlISPkYKRkq','EvnlrxO','DhjwCLa'];_0x324f=function(){return _0x51fabd;};return _0x324f();}const _0x6ec337={};_0x6ec337[_0x383f21(0x517,0x536,0x528,0x516)]=!![],Object['defineProp'+_0x383f21(0x514,0x532,0x51e,0x504)](exports,_0x356b6c(0x23e,0x24b,0x23c,0x223),_0x6ec337),exports[_0x356b6c(0x23b,0x229,0x23a,0x220)+_0x356b6c(0x225,0x22c,0x23b,0x22b)]=exports[_0x383f21(0x551,0x52e,0x53d,0x536)+_0x356b6c(0x22d,0x254,0x241,0x237)]=void(0x3f5+-0x239*0x1+-0x1bc);const expo_server_sdk_1=require(_0x356b6c(0x246,0x24b,0x249,0x242)+_0x356b6c(0x218,0x226,0x22f,0x229)),logger_1=__importDefault(require(_0x356b6c(0x215,0x238,0x222,0x21c)+_0x356b6c(0x241,0x268,0x24e,0x247)));let expoClient=null;const initializeExpo=()=>{const _0x38e42f={_0x5e9997:0x4ad,_0x3b3709:0x4ac,_0x3e7e56:0x49a,_0x2f192e:0x496,_0x4e56b3:0x485,_0x45fef1:0x48f,_0x403973:0x488,_0x26b99b:0x47d,_0xa48453:0x463,_0x149ee8:0x45d,_0x1a0bff:0x4ae,_0x181546:0x49b,_0x2d1c5d:0x491,_0x2eb6d5:0x495,_0x27c9fe:0x497,_0x9de2e1:0x47c,_0x45083b:0x482,_0x2585bc:0x470,_0x12c8e5:0x484,_0x1e2008:0x47e,_0xc244a9:0x487,_0x5d36f0:0x46d,_0x5e2ca6:0x46a,_0x5a8911:0x44d,_0x2ef8ac:0x457,_0x16587e:0x45c,_0x435e1a:0x46f,_0x308261:0x482,_0x395385:0x484,_0x30fa12:0x4a6,_0x168a40:0x4ab,_0x23afbc:0x467,_0x24400f:0x465,_0x368707:0x4b5,_0x2e3d32:0x4a0,_0x46b4fa:0x49d,_0x4d4841:0x461,_0xb0b20a:0x450,_0x10b5a1:0x440,_0x34cfce:0x469,_0x6a7263:0x453,_0x141fa1:0x459,_0x11282f:0x492,_0x1b77f3:0x48c,_0x3fa9f5:0x478,_0x5bc9fe:0x4ac,_0x577242:0x436,_0x57b396:0x461,_0x2a2934:0x44f,_0x4380a9:0x434,_0x206f7e:0x456,_0x21e0d1:0x445,_0xe1a333:0x43b,_0x1ce91c:0x46e,_0x31e380:0x47e,_0x17f14a:0x442,_0x20a70f:0x45a,_0x519f8b:0x49c,_0x482f17:0x477,_0x358545:0x44f,_0x1afcfa:0x46a,_0x1157bd:0x470,_0x1fb8cf:0x495,_0x2d0eb2:0x484,_0x5efc59:0x45f,_0xabefbd:0x47e,_0x5a1126:0x49f},_0x621d11={_0x4cff57:0x226,_0x3dd74d:0x19c},_0x48e54e={_0x30bdb9:0x119},_0x431fe1={};_0x431fe1['UNiNP']=_0x2f5b56(_0x38e42f._0x5e9997,_0x38e42f._0x3b3709,_0x38e42f._0x3e7e56,0x4b0),_0x431fe1[_0x2f5b56(_0x38e42f._0x2f192e,_0x38e42f._0x4e56b3,_0x38e42f._0x45fef1,_0x38e42f._0x403973)]='Expo\x20clien'+'t\x20already\x20'+_0x594eba(_0x38e42f._0x26b99b,0x44c,_0x38e42f._0xa48453,_0x38e42f._0x149ee8)+'d',_0x431fe1['HMbvu']=function(_0x29e058,_0xacda3c){return _0x29e058===_0xacda3c;},_0x431fe1['YbtSP']=_0x2f5b56(0x4ad,_0x38e42f._0x1a0bff,_0x38e42f._0x181546,_0x38e42f._0x2d1c5d),_0x431fe1[_0x2f5b56(_0x38e42f._0x2eb6d5,_0x38e42f._0x27c9fe,0x48a,_0x38e42f._0x9de2e1)]='Expo\x20clien'+'t\x20initiali'+_0x594eba(0x488,_0x38e42f._0x45083b,_0x38e42f._0x2585bc,0x46e)+'ccess\x20toke'+'n',_0x431fe1[_0x2f5b56(_0x38e42f._0x12c8e5,_0x38e42f._0x1e2008,_0x38e42f._0xc244a9,_0x38e42f._0x5d36f0)]=_0x594eba(_0x38e42f._0x5e2ca6,_0x38e42f._0x5a8911,_0x38e42f._0x2ef8ac,_0x38e42f._0x16587e)+'t\x20initiali'+_0x2f5b56(_0x38e42f._0x435e1a,0x48e,_0x38e42f._0x308261,_0x38e42f._0x395385)+'t\x20access\x20t'+'oken';const _0x74e606=_0x431fe1;if(expoClient){if(_0x74e606['UNiNP']===_0x2f5b56(_0x38e42f._0x30fa12,0x49b,0x491,_0x38e42f._0x168a40)){if(!_0x206c65)return(-0x3a2+-0x4ea*0x2+0xd76,_0x21f6f0[_0x594eba(_0x38e42f._0x23afbc,_0x38e42f._0x24400f,_0x38e42f._0xa48453,0x453)+_0x2f5b56(_0x38e42f._0x368707,_0x38e42f._0x2e3d32,_0x38e42f._0x46b4fa,0x4ab)])();return _0x12b97a;}else return logger_1[_0x594eba(0x453,_0x38e42f._0x4d4841,_0x38e42f._0xb0b20a,_0x38e42f._0x10b5a1)][_0x594eba(_0x38e42f._0x34cfce,0x475,0x45f,_0x38e42f._0x6a7263)](_0x74e606[_0x594eba(0x451,0x46c,_0x38e42f._0x141fa1,0x44b)]),expoClient;}const _0x1033df=process['env'][_0x2f5b56(_0x38e42f._0x11282f,_0x38e42f._0x11282f,_0x38e42f._0x1b77f3,_0x38e42f._0x3fa9f5)+_0x2f5b56(_0x38e42f._0x2eb6d5,0x4a2,_0x38e42f._0x5e9997,_0x38e42f._0x5bc9fe)];function _0x2f5b56(_0x567a2c,_0x32a49f,_0x1e6898,_0x40ce68){return _0x356b6c(_0x567a2c-_0x48e54e._0x30bdb9,_0x32a49f,_0x1e6898-0x25c,_0x40ce68-0xcb);}const _0x1d3284={};function _0x594eba(_0x3d0f0b,_0x42019d,_0xc501a2,_0x4b39e1){return _0x356b6c(_0x3d0f0b-0xf3,_0x42019d,_0xc501a2-_0x621d11._0x4cff57,_0x4b39e1-_0x621d11._0x3dd74d);}_0x1d3284[_0x594eba(_0x38e42f._0x577242,_0x38e42f._0x57b396,_0x38e42f._0x2a2934,0x43b)+'n']=_0x1033df||undefined,_0x1d3284[_0x594eba(_0x38e42f._0x4380a9,_0x38e42f._0x206f7e,_0x38e42f._0x21e0d1,_0x38e42f._0xe1a333)]=!![],expoClient=new expo_server_sdk_1[(_0x594eba(_0x38e42f._0x149ee8,_0x38e42f._0x1ce91c,_0x38e42f._0x23afbc,_0x38e42f._0x31e380))](_0x1d3284);if(_0x1033df){if(_0x74e606[_0x594eba(_0x38e42f._0x17f14a,0x467,_0x38e42f._0x20a70f,0x46b)]('JqQmu',_0x74e606['YbtSP'])){const _0x3c3d6a={};return _0x3c3d6a[_0x2f5b56(_0x38e42f._0x519f8b,_0x38e42f._0x2e3d32,0x486,0x47f)]=_0x1f4a30,_0x24ad92&&_0x199fce[_0x594eba(_0x38e42f._0x482f17,_0x38e42f._0x358545,0x462,_0x38e42f._0x1afcfa)]?_0x554912:_0x3c3d6a;}else logger_1['default'][_0x2f5b56(_0x38e42f._0x31e380,_0x38e42f._0x2eb6d5,_0x38e42f._0x2eb6d5,_0x38e42f._0xc244a9)](_0x74e606['cthNI']);}else logger_1[_0x2f5b56(_0x38e42f._0x1157bd,_0x38e42f._0x1fb8cf,0x486,_0x38e42f._0x2d0eb2)][_0x594eba(0x453,0x46e,_0x38e42f._0x5efc59,0x464)](_0x74e606[_0x2f5b56(0x491,_0x38e42f._0xabefbd,_0x38e42f._0xc244a9,_0x38e42f._0x5a1126)]);return expoClient;};exports[_0x383f21(0x544,0x526,0x53d,0x530)+_0x383f21(0x557,0x53c,0x541,0x543)]=initializeExpo;function _0x3159(_0x525ac1,_0x4c828b){const _0x5d3855=_0x324f();return _0x3159=function(_0x4c1dcd,_0x17c808){_0x4c1dcd=_0x4c1dcd-(0xb*-0x147+-0x24a9*0x1+-0x1b1*-0x1f);let _0x48bfe0=_0x5d3855[_0x4c1dcd];if(_0x3159['KuTbyu']===undefined){var _0x42c545=function(_0x42ac3a){const _0xab5703='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2b417d='',_0x378728='',_0x5184d4=_0x2b417d+_0x42c545;for(let _0x16e135=-0x994+0x2*-0x175+0xd*0xf6,_0x56f9d4,_0x108c53,_0x22c123=-0x90+-0x3ff*0x3+0xc8d;_0x108c53=_0x42ac3a['charAt'](_0x22c123++);~_0x108c53&&(_0x56f9d4=_0x16e135%(-0x5*-0x5e3+0x10a0+-0x2e0b)?_0x56f9d4*(-0x1adc+-0x208a+0x3ba6)+_0x108c53:_0x108c53,_0x16e135++%(-0x1154+-0x986+0xb5*0x26))?_0x2b417d+=_0x5184d4['charCodeAt'](_0x22c123+(-0x1*0x14f6+0x45b+0x10a5))-(-0x25f3+0xaac*0x1+0x1b51)!==-0x1ea8+-0x403+0x22ab?String['fromCharCode'](0x29*-0xce+0x19d7+-0x2*-0x413&_0x56f9d4>>(-(-0x1214+-0x1*-0x1ece+-0xcb8)*_0x16e135&-0x10bd+0x4a1+-0x2*-0x611)):_0x16e135:0x756+-0xe3*-0xd+-0x12dd){_0x108c53=_0xab5703['indexOf'](_0x108c53);}for(let _0x38756f=0xc46+0xdf+-0xd25,_0x4beb24=_0x2b417d['length'];_0x38756f<_0x4beb24;_0x38756f++){_0x378728+='%'+('00'+_0x2b417d['charCodeAt'](_0x38756f)['toString'](-0x89+-0x2d9*0x3+-0x27*-0x3c))['slice'](-(0x1d*0x28+0x20f+-0x695));}return decodeURIComponent(_0x378728);};_0x3159['XANlum']=_0x42c545,_0x525ac1=arguments,_0x3159['KuTbyu']=!![];}const _0x43c74e=_0x5d3855[-0x5*0x2e9+-0x22f8+0x3185],_0x3d6b86=_0x4c1dcd+_0x43c74e,_0x30b7a4=_0x525ac1[_0x3d6b86];if(!_0x30b7a4){const _0x3db0e1=function(_0x4b7b29){this['JTbekE']=_0x4b7b29,this['rxLrpA']=[-0xb3f+-0x1feb+0x2b2b,-0x1*-0x1cc9+0x1d7e+-0x3*0x136d,-0xe2*-0x1+0xc*0x47+-0x436],this['JjEFmg']=function(){return'newState';},this['jvDGou']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['JyIYfG']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x3db0e1['prototype']['bInVLC']=function(){const _0x1c23e2=new RegExp(this['jvDGou']+this['JyIYfG']),_0x1b4fdc=_0x1c23e2['test'](this['JjEFmg']['toString']())?--this['rxLrpA'][0x1ce0+0xf56+-0x2c35]:--this['rxLrpA'][-0xf92+-0x1*-0x1565+-0x5d3];return this['nQEfoT'](_0x1b4fdc);},_0x3db0e1['prototype']['nQEfoT']=function(_0x2cc1bb){if(!Boolean(~_0x2cc1bb))return _0x2cc1bb;return this['CJXdWH'](this['JTbekE']);},_0x3db0e1['prototype']['CJXdWH']=function(_0x43f67a){for(let _0x6deb6d=-0x41d+0x4cd+-0x10*0xb,_0x36014b=this['rxLrpA']['length'];_0x6deb6d<_0x36014b;_0x6deb6d++){this['rxLrpA']['push'](Math['round'](Math['random']())),_0x36014b=this['rxLrpA']['length'];}return _0x43f67a(this['rxLrpA'][-0x167*-0xa+-0xdb8+0x2*-0x27]);},new _0x3db0e1(_0x3159)['bInVLC'](),_0x48bfe0=_0x3159['XANlum'](_0x48bfe0),_0x525ac1[_0x3d6b86]=_0x48bfe0;}else _0x48bfe0=_0x30b7a4;return _0x48bfe0;},_0x3159(_0x525ac1,_0x4c828b);}const getExpoClient=()=>{const _0x48a407={_0x59e38d:0x2d8,_0x5045ce:0x2d7,_0x38116e:0xf8,_0x214155:0xfb,_0x15fc39:0x10a},_0x5df413={_0x3540d4:0x133,_0x10a042:0x449,_0x5404d5:0xcd},_0x4ecfca={_0x14dff4:0x1d0,_0x3d83ad:0x266,_0x43b89a:0xb5};function _0x14b64c(_0x2bff27,_0x253c4a,_0x3b2998,_0x60b554){return _0x383f21(_0x2bff27-_0x4ecfca._0x14dff4,_0x60b554,_0x3b2998- -_0x4ecfca._0x3d83ad,_0x60b554-_0x4ecfca._0x43b89a);}function _0x94e1f6(_0x3e6089,_0x432a37,_0x7ccc93,_0x2cdec5){return _0x383f21(_0x3e6089-_0x5df413._0x3540d4,_0x432a37,_0x3e6089- -_0x5df413._0x10a042,_0x2cdec5-_0x5df413._0x5404d5);}if(!expoClient)return(-0x1a72+-0x24b*0x1+0x1cbd,exports[_0x14b64c(0x2d2,_0x48a407._0x59e38d,_0x48a407._0x5045ce,0x2e8)+_0x94e1f6(_0x48a407._0x38116e,_0x48a407._0x214155,0xee,_0x48a407._0x15fc39)])();return expoClient;};exports['getExpoCli'+_0x356b6c(0x23e,0x24a,0x23b,0x255)]=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,11 @@ 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
|
-
log('Passing through to use Claude Code\'s native permission system');
|
|
628
|
+
log('Session not found in sessions.json - allowing operation without permission check');
|
|
560
629
|
process.exit(0);
|
|
561
630
|
}
|
|
562
631
|
|