@jshookmcp/jshook 0.2.9 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/README.md +25 -50
  2. package/README.zh.md +25 -48
  3. package/dist/AntiCheatDetector-CGVGNfy5.mjs +1 -0
  4. package/dist/CacheAdapters-CdAxBmVW.mjs +1 -0
  5. package/dist/CodeInjector-BlgyqTOk.mjs +1 -0
  6. package/dist/ConsoleMonitor-Dkqc0HNi.mjs +490 -0
  7. package/dist/DOMInspector-BYY_EJ0C.mjs +95 -0
  8. package/dist/DarwinAPI-DC4HGGLl.mjs +1 -0
  9. package/dist/DetailedDataManager-BniBJlVv.mjs +1 -0
  10. package/dist/EventBus-DgciURGg.mjs +1 -0
  11. package/dist/EvidenceGraphBridge-BIfgB7HP.mjs +1 -0
  12. package/dist/ExtensionManager-erMpqcLk.mjs +1 -0
  13. package/dist/FingerprintManager-N7BZqjxP.mjs +1 -0
  14. package/dist/HardwareBreakpoint-OcJqNFVc.mjs +1 -0
  15. package/dist/HeapAnalyzer-CqAxZzeS.mjs +1 -0
  16. package/dist/{HookGeneratorBuilders.core.generators.storage-CtcdK78Q.mjs → HookGeneratorBuilders.core.generators.storage-Bf1fbrNK.mjs} +66 -174
  17. package/dist/InstrumentationSession-DxXs0sCp.mjs +1 -0
  18. package/dist/MCPServer.search.handlers.domain-DVbWL1bT.mjs +1 -0
  19. package/dist/MemoryController-BaqstM5w.mjs +2 -0
  20. package/dist/MemoryScanSession-CaxAjZJf.mjs +1 -0
  21. package/dist/MemoryScanner-BLYnMJy6.mjs +1 -0
  22. package/dist/NativeMemoryManager.impl-CI554XbY.mjs +1 -0
  23. package/dist/NativeMemoryManager.utils-DM4NC3FE.mjs +1 -0
  24. package/dist/PEAnalyzer-DJyaJTQJ.mjs +1 -0
  25. package/dist/PageController-D9jVkH0i.mjs +1 -0
  26. package/dist/PointerChainEngine-5nF9eNlu.mjs +1 -0
  27. package/dist/PrerequisiteError-Bl3dK8XA.mjs +1 -0
  28. package/dist/ProcessRegistry-Hf12LlR9.mjs +1 -0
  29. package/dist/ResponseBuilder-B2lu4KEl.mjs +1 -0
  30. package/dist/ReverseEvidenceGraph-B931HeoW.mjs +2 -0
  31. package/dist/ScriptManager-fgqiALgj.mjs +7 -0
  32. package/dist/Speedhack-l6s8L2Qw.mjs +1 -0
  33. package/dist/StealthVerifier-Dhbj4B4P.mjs +1 -0
  34. package/dist/StructureAnalyzer-A-WamfYE.mjs +2 -0
  35. package/dist/ToolCatalog-D_IKl1Hu.mjs +1 -0
  36. package/dist/ToolError-DWU_z7gp.mjs +1 -0
  37. package/dist/ToolProbe-xsfALmN3.mjs +1 -0
  38. package/dist/ToolRegistry-B0Zs-phN.mjs +1 -0
  39. package/dist/ToolRouter.policy-CFHoN_Lw.mjs +4 -0
  40. package/dist/TraceRecorder-Dd8jLXpi.mjs +272 -0
  41. package/dist/VersionDetector-DMoUWyNm.mjs +9 -0
  42. package/dist/Win32API-Bhi5xFBe.mjs +1 -0
  43. package/dist/Win32Debug-CQteFL4F.mjs +1 -0
  44. package/dist/WorkflowEngine-CxEp2WXH.mjs +1 -0
  45. package/dist/analysis-BuR-NgX8.mjs +5 -0
  46. package/dist/{antidebug-CqDTB_uk.mjs → antidebug-BOTZH6-0.mjs} +8 -259
  47. package/dist/artifactRetention-NBdncOEW.mjs +1 -0
  48. package/dist/artifacts-B5xQuEa_.mjs +1 -0
  49. package/dist/authorization-schema-B40obG1A.mjs +1 -0
  50. package/dist/betterSqlite3-CGaxz4AX.mjs +1 -0
  51. package/dist/binary-instrument-Cf9qqLlM.mjs +7 -0
  52. package/dist/bind-helpers-BlAOQrFQ.mjs +1 -0
  53. package/dist/boringssl-inspector-BST5vtKx.mjs +2 -0
  54. package/dist/browser-C4Le3xqA.mjs +11 -0
  55. package/dist/capabilities-DbYCv-HF.mjs +1 -0
  56. package/dist/chunk-C_pMuVsO.mjs +1 -0
  57. package/dist/collector-CKO8RPK8.mjs +1 -0
  58. package/dist/concurrency-CcK46d0h.mjs +1 -0
  59. package/dist/constants-Cp6hBrrx.mjs +1 -0
  60. package/dist/coordination-BbijHEHH.mjs +1 -0
  61. package/dist/debugger-CRJq_krh.mjs +1 -0
  62. package/dist/definitions-BGobEDQa.mjs +1 -0
  63. package/dist/definitions-BGwNSkVm.mjs +1 -0
  64. package/dist/definitions-BbxOUiP-.mjs +1 -0
  65. package/dist/definitions-CCP9gphV.mjs +1 -0
  66. package/dist/definitions-CIO9O-Sw.mjs +1 -0
  67. package/dist/definitions-CYFbewnd.mjs +1 -0
  68. package/dist/definitions-CdWEuIkI.mjs +1 -0
  69. package/dist/definitions-CoQFbggH.mjs +1 -0
  70. package/dist/definitions-CuJRsJ6N.mjs +1 -0
  71. package/dist/definitions-DI9YXsJk.mjs +1 -0
  72. package/dist/definitions-DJklW2sS.mjs +1 -0
  73. package/dist/definitions-DZ8uKusP.mjs +1 -0
  74. package/dist/definitions-Dds_zrWx.mjs +1 -0
  75. package/dist/definitions-Dgrg7f3D.mjs +1 -0
  76. package/dist/definitions-DtE0XLrT.mjs +1 -0
  77. package/dist/definitions-LaYTuwQd.mjs +26 -0
  78. package/dist/definitions-NoVp_9Pm.mjs +1 -0
  79. package/dist/definitions-OvGsfxdt.mjs +1 -0
  80. package/dist/definitions-jXPaVy4P.mjs +1 -0
  81. package/dist/encoding-DGcr6Aj_.mjs +2 -0
  82. package/dist/ensure-browser-core-Buls24LQ.mjs +1 -0
  83. package/dist/evidence-graph-bridge-B0yhGPcs.mjs +1 -0
  84. package/dist/factory-Cx_1LorX.mjs +1 -0
  85. package/dist/flat-target-session-CO5g78k3.mjs +1 -0
  86. package/dist/formatAddress-C7j2fDlM.mjs +1 -0
  87. package/dist/graphql-HLf3MS8H.mjs +62 -0
  88. package/dist/handlers-BLMa4X7l.mjs +54 -0
  89. package/dist/handlers-BP12ZsWc.mjs +4 -0
  90. package/dist/handlers-BZoPla6E.mjs +1 -0
  91. package/dist/handlers-BggKiVx9.mjs +2 -0
  92. package/dist/handlers-D3iev8g1.mjs +1 -0
  93. package/dist/handlers-D49r1-1P.mjs +1 -0
  94. package/dist/handlers-DCE45Ww8.mjs +2 -0
  95. package/dist/handlers-DW5AbYs5.mjs +5 -0
  96. package/dist/handlers-De5u62Ga2.mjs +1 -0
  97. package/dist/handlers-DmQzIc44.mjs +31 -0
  98. package/dist/handlers-DnJRGp7t.mjs +302 -0
  99. package/dist/handlers-Dv_runVv.mjs +2 -0
  100. package/dist/handlers-S9Ws0IGy.mjs +2 -0
  101. package/dist/{handlers-Bl8zkwz1.mjs → handlers-pVNpaw4A.mjs} +144 -841
  102. package/dist/handlers.impl-CD2_kOcC.mjs +1 -0
  103. package/dist/hooks-DDKppogd.mjs +600 -0
  104. package/dist/index.mjs +12 -5225
  105. package/dist/logger-sBC6IdRT.mjs +1 -0
  106. package/dist/maintenance-CutEO84j.mjs +1 -0
  107. package/dist/manifest-BFGxlDRh.mjs +123 -0
  108. package/dist/manifest-BPuE6oH2.mjs +1 -0
  109. package/dist/manifest-BXry5N09.mjs +1 -0
  110. package/dist/manifest-BeP_zJGb2.mjs +1 -0
  111. package/dist/manifest-C0g67k6U.mjs +1 -0
  112. package/dist/manifest-C1nZkTkO.mjs +1 -0
  113. package/dist/manifest-C7qV1z7F.mjs +1 -0
  114. package/dist/manifest-CDeUZGUZ.mjs +1 -0
  115. package/dist/manifest-CDiCtaQT.mjs +1 -0
  116. package/dist/manifest-CFn0359q2.mjs +1 -0
  117. package/dist/manifest-CGq4NpqH2.mjs +1 -0
  118. package/dist/manifest-CJMGt7Qy.mjs +1 -0
  119. package/dist/manifest-CRIJq4Hs.mjs +1 -0
  120. package/dist/manifest-C_hEIjSx.mjs +1 -0
  121. package/dist/manifest-CeQmtQOY.mjs +1 -0
  122. package/dist/manifest-Cq0j7GZt.mjs +1 -0
  123. package/dist/manifest-CtPmHAdn.mjs +1 -0
  124. package/dist/manifest-Cx2IVMUY.mjs +1 -0
  125. package/dist/manifest-D16xPXro.mjs +1 -0
  126. package/dist/manifest-D44TaRJU.mjs +1 -0
  127. package/dist/manifest-D610kxZr.mjs +2 -0
  128. package/dist/manifest-DC-SMF6b.mjs +1 -0
  129. package/dist/manifest-DD3rtxvV.mjs +1 -0
  130. package/dist/manifest-DKUorv5M.mjs +1 -0
  131. package/dist/manifest-DMJlcsTR.mjs +1 -0
  132. package/dist/manifest-DWUUWBz0.mjs +1 -0
  133. package/dist/manifest-De-6Wf2R.mjs +1 -0
  134. package/dist/manifest-Dgh0uDW-.mjs +1 -0
  135. package/dist/manifest-Dm0o3i2U.mjs +1 -0
  136. package/dist/manifest-DsVh7Y4U.mjs +1 -0
  137. package/dist/manifest-DtEFSRaq.mjs +1 -0
  138. package/dist/manifest-H-EpAyZQ.mjs +1 -0
  139. package/dist/manifest-ais9Afrw.mjs +1 -0
  140. package/dist/manifest-tmb54wmA.mjs +1 -0
  141. package/dist/manifest-yu2xiQqe.mjs +1 -0
  142. package/dist/manifest-zrbrpKCC.mjs +1 -0
  143. package/dist/matchesWildcardPattern-BGqLSmEs.mjs +1 -0
  144. package/dist/modules-p-PUNv9r.mjs +332 -0
  145. package/dist/mojo-ipc-VGlv3Qyp.mjs +9 -0
  146. package/dist/network-BjZ1Y-GB.mjs +7 -0
  147. package/dist/outputPaths-BonGThuc.mjs +2 -0
  148. package/dist/parse-args-Cuk7-xUt.mjs +1 -0
  149. package/dist/platform-C446Lf97.mjs +93 -0
  150. package/dist/playwright-cdp-fallback-BwVR-_T3.mjs +1 -0
  151. package/dist/process-C9f2A5zk.mjs +962 -0
  152. package/dist/proxy-CvRepxgV.mjs +1 -0
  153. package/dist/registry-DUHIPE-v.mjs +1 -0
  154. package/dist/response-C7rKQst4.mjs +1 -0
  155. package/dist/search-defaults-D2bY-rzH.mjs +1 -0
  156. package/dist/server/plugin-api.mjs +1 -293
  157. package/dist/shared-state-board-Cyg-xh_k.mjs +1 -0
  158. package/dist/sourcemap-D6Q1UuAp.mjs +1 -0
  159. package/dist/ssrf-policy-T96MR3r6.mjs +1 -0
  160. package/dist/streaming-CTX58tbb.mjs +1 -0
  161. package/dist/tool-builder-CI9914Tf.mjs +1 -0
  162. package/dist/transform-Cv9P2vVD.mjs +103 -0
  163. package/dist/types-CuyefmGT.mjs +1 -0
  164. package/dist/types-DtThH00r.mjs +1 -0
  165. package/dist/wasm-DaJa8J0V.mjs +174 -0
  166. package/dist/webcrack-CsLLJIs9.mjs +46 -0
  167. package/dist/workflow-CYIXtrWD.mjs +101 -0
  168. package/package.json +12 -7
  169. package/dist/AntiCheatDetector-BNk-EoBt.mjs +0 -244
  170. package/dist/CacheAdapters-CDe5WPSV.mjs +0 -80
  171. package/dist/CodeInjector-Cq8q01kp.mjs +0 -150
  172. package/dist/ConsoleMonitor-CPVQW1Y-.mjs +0 -2201
  173. package/dist/DarwinAPI-BNPxu0RH.mjs +0 -363
  174. package/dist/DetailedDataManager-BQQcxh64.mjs +0 -217
  175. package/dist/EventBus-DgPmwpeu.mjs +0 -141
  176. package/dist/EvidenceGraphBridge-SFesNera.mjs +0 -153
  177. package/dist/ExtensionManager-CWYgw0YW.mjs +0 -714
  178. package/dist/FingerprintManager-gzWtkKuf.mjs +0 -96
  179. package/dist/HardwareBreakpoint-B9gZCdFP.mjs +0 -239
  180. package/dist/HeapAnalyzer-BLDH0dCv.mjs +0 -284
  181. package/dist/InstrumentationSession-CvPC7Jwy.mjs +0 -244
  182. package/dist/MemoryController-CbVdCIJF.mjs +0 -167
  183. package/dist/MemoryScanSession-BsDZbLYm.mjs +0 -278
  184. package/dist/MemoryScanner-Bcpml6II.mjs +0 -425
  185. package/dist/NativeMemoryManager.impl-dZtA1ZGn.mjs +0 -482
  186. package/dist/NativeMemoryManager.utils-B-FjA2mJ.mjs +0 -165
  187. package/dist/PEAnalyzer-D1lzJ_VG.mjs +0 -385
  188. package/dist/PageController-Bqm2kZ_X.mjs +0 -417
  189. package/dist/PointerChainEngine-BOhyVsjx.mjs +0 -322
  190. package/dist/PrerequisiteError-Dl33Svkz.mjs +0 -20
  191. package/dist/ResponseBuilder-D3iFYx2N.mjs +0 -143
  192. package/dist/ReverseEvidenceGraph-Dlsk94LC.mjs +0 -269
  193. package/dist/ScriptManager-aHHq0X7U.mjs +0 -3000
  194. package/dist/Speedhack-CqdIFlQl.mjs +0 -156
  195. package/dist/StealthVerifier-Bo4T3bz8.mjs +0 -135
  196. package/dist/StructureAnalyzer-DhFaPvRO.mjs +0 -426
  197. package/dist/ToolCatalog-C0JGZoOm.mjs +0 -582
  198. package/dist/ToolError-jh9whhMd.mjs +0 -15
  199. package/dist/ToolProbe-oC7aPrkv.mjs +0 -45
  200. package/dist/ToolRegistry-BjaF4oNz.mjs +0 -131
  201. package/dist/ToolRouter.policy-BWV67ZK-.mjs +0 -304
  202. package/dist/TraceRecorder-DgxyVbdQ.mjs +0 -519
  203. package/dist/VersionDetector-CwVLVdDM.mjs +0 -104
  204. package/dist/Win32API-CePkipZY.mjs +0 -340
  205. package/dist/Win32Debug-BvKs-gxc.mjs +0 -274
  206. package/dist/WorkflowEngine-CuvkZtWu.mjs +0 -598
  207. package/dist/analysis-CL9uACt9.mjs +0 -463
  208. package/dist/artifactRetention-CFEprwPw.mjs +0 -591
  209. package/dist/artifacts-Bk2-_uPq.mjs +0 -59
  210. package/dist/betterSqlite3-0pqusHHH.mjs +0 -74
  211. package/dist/binary-instrument-CXfpx6fT.mjs +0 -979
  212. package/dist/bind-helpers-xFfRF-qm.mjs +0 -22
  213. package/dist/boringssl-inspector-BH2D3VKc.mjs +0 -180
  214. package/dist/browser-BpOr5PEx.mjs +0 -4082
  215. package/dist/chunk-CjcI7cDX.mjs +0 -15
  216. package/dist/concurrency-Bt0yv1kJ.mjs +0 -41
  217. package/dist/constants-B0OANIBL.mjs +0 -519
  218. package/dist/coordination-qUbyF8KU.mjs +0 -259
  219. package/dist/debugger-gnKxRSN0.mjs +0 -1271
  220. package/dist/definitions-6M-eejaT.mjs +0 -53
  221. package/dist/definitions-B18eyf0B.mjs +0 -18
  222. package/dist/definitions-B3QdlrHv.mjs +0 -34
  223. package/dist/definitions-B4rAvHNZ.mjs +0 -63
  224. package/dist/definitions-BB_4jnmy.mjs +0 -37
  225. package/dist/definitions-BMfYXoNC.mjs +0 -43
  226. package/dist/definitions-Beid2EB3.mjs +0 -27
  227. package/dist/definitions-C1UvM5Iy.mjs +0 -126
  228. package/dist/definitions-CXEI7QC72.mjs +0 -216
  229. package/dist/definitions-C_4r7Fo-2.mjs +0 -14
  230. package/dist/definitions-CkFDALoa.mjs +0 -26
  231. package/dist/definitions-Cke7zEb8.mjs +0 -94
  232. package/dist/definitions-ClJLzsJQ.mjs +0 -25
  233. package/dist/definitions-Cq-zroAU.mjs +0 -28
  234. package/dist/definitions-Cy3Sl6gV.mjs +0 -34
  235. package/dist/definitions-D3VsGcvz.mjs +0 -47
  236. package/dist/definitions-DVGfrn7y.mjs +0 -96
  237. package/dist/definitions-LKpC3-nL.mjs +0 -9
  238. package/dist/definitions-bAhHQJq9.mjs +0 -359
  239. package/dist/encoding-Bvz5jLRv.mjs +0 -1065
  240. package/dist/evidence-graph-bridge-C_fv9PuC.mjs +0 -135
  241. package/dist/factory-DxlGh9Xf.mjs +0 -575
  242. package/dist/formatAddress-DVkj9kpI.mjs +0 -17
  243. package/dist/graphql-DYWzJ29s.mjs +0 -1026
  244. package/dist/handlers-9sAbfIg-.mjs +0 -2552
  245. package/dist/handlers-C67ktuRN.mjs +0 -710
  246. package/dist/handlers-C87g8oCe.mjs +0 -276
  247. package/dist/handlers-CTsDAO6p.mjs +0 -681
  248. package/dist/handlers-Cgyg6c0U.mjs +0 -645
  249. package/dist/handlers-D6j6yka7.mjs +0 -2124
  250. package/dist/handlers-DdFzXLvF.mjs +0 -446
  251. package/dist/handlers-DeLOCd5m.mjs +0 -799
  252. package/dist/handlers-DlCJN4Td.mjs +0 -757
  253. package/dist/handlers-DxGIq15_2.mjs +0 -917
  254. package/dist/handlers-U6L4xhuF.mjs +0 -585
  255. package/dist/handlers-tB9Mp9ZK.mjs +0 -84
  256. package/dist/handlers-tiy7EIBp.mjs +0 -572
  257. package/dist/handlers.impl-DS0d9fUw.mjs +0 -761
  258. package/dist/hooks-CzCWByww.mjs +0 -898
  259. package/dist/logger-Dh_xb7_2.mjs +0 -93
  260. package/dist/maintenance-P7ePRXQC.mjs +0 -830
  261. package/dist/manifest-2ToTpjv8.mjs +0 -106
  262. package/dist/manifest-3g71z6Bg.mjs +0 -79
  263. package/dist/manifest-82baTv4U.mjs +0 -45
  264. package/dist/manifest-B3QVVeBS.mjs +0 -82
  265. package/dist/manifest-BB2J8IMJ.mjs +0 -149
  266. package/dist/manifest-BKbgbSiY.mjs +0 -60
  267. package/dist/manifest-Bcf-TJzH.mjs +0 -848
  268. package/dist/manifest-BmtZzQiQ2.mjs +0 -45
  269. package/dist/manifest-Bnd7kqEY.mjs +0 -55
  270. package/dist/manifest-BqQX6OQC2.mjs +0 -65
  271. package/dist/manifest-BqrQ4Tpj.mjs +0 -81
  272. package/dist/manifest-Br4RPFt5.mjs +0 -370
  273. package/dist/manifest-C5qDjysN.mjs +0 -107
  274. package/dist/manifest-C9RT5nk32.mjs +0 -34
  275. package/dist/manifest-CAhOuvSl.mjs +0 -204
  276. package/dist/manifest-CBYWCUBJ.mjs +0 -51
  277. package/dist/manifest-CFADCRa1.mjs +0 -37
  278. package/dist/manifest-CQVhavRF.mjs +0 -114
  279. package/dist/manifest-CT7zZBV1.mjs +0 -48
  280. package/dist/manifest-CV12bcrF.mjs +0 -121
  281. package/dist/manifest-CXsRWjjI.mjs +0 -224
  282. package/dist/manifest-CZLUCfG02.mjs +0 -95
  283. package/dist/manifest-D6phHKFd.mjs +0 -131
  284. package/dist/manifest-DCyjf4n2.mjs +0 -294
  285. package/dist/manifest-DHsnKgP6.mjs +0 -60
  286. package/dist/manifest-Df_dliIe.mjs +0 -55
  287. package/dist/manifest-Dh8WBmEW.mjs +0 -129
  288. package/dist/manifest-DhKRAT8_.mjs +0 -92
  289. package/dist/manifest-DlpTj4ic2.mjs +0 -193
  290. package/dist/manifest-DrbmZcFl2.mjs +0 -253
  291. package/dist/manifest-DuwHjUa5.mjs +0 -70
  292. package/dist/manifest-DzwvxPJX.mjs +0 -38
  293. package/dist/manifest-NXctwWQq.mjs +0 -68
  294. package/dist/manifest-Sc_0JQ13.mjs +0 -418
  295. package/dist/manifest-gZ4s_UtG.mjs +0 -96
  296. package/dist/manifest-qSleDqdO.mjs +0 -1023
  297. package/dist/modules-C184v-S9.mjs +0 -11365
  298. package/dist/mojo-ipc-B_H61Afw.mjs +0 -525
  299. package/dist/network-671Cw6hV.mjs +0 -3346
  300. package/dist/outputPaths-B1uGmrWZ.mjs +0 -1145
  301. package/dist/parse-args-BlRjqlkL.mjs +0 -39
  302. package/dist/platform-WmNn8Sxb.mjs +0 -2070
  303. package/dist/process-QcbIy5Zq.mjs +0 -1401
  304. package/dist/proxy-DqNs0bAd.mjs +0 -170
  305. package/dist/registry-D-6e18lB.mjs +0 -34
  306. package/dist/response-BQVP-xUn.mjs +0 -28
  307. package/dist/shared-state-board-DV-dpHFJ.mjs +0 -586
  308. package/dist/sourcemap-Dq8ez8vS.mjs +0 -650
  309. package/dist/ssrf-policy-ZaUfvhq7.mjs +0 -166
  310. package/dist/streaming-BUQ0VJsg.mjs +0 -725
  311. package/dist/tool-builder-DCbIC5Eo.mjs +0 -186
  312. package/dist/transform-CiYJfNX0.mjs +0 -1007
  313. package/dist/types-Bx92KJfT.mjs +0 -4
  314. package/dist/types-CPhOReNX.mjs +0 -37
  315. package/dist/wasm-DQTnHDs4.mjs +0 -531
  316. package/dist/workflow-f3xJOcjx.mjs +0 -725
@@ -1,714 +0,0 @@
1
- import { t as __exportAll } from "./chunk-CjcI7cDX.mjs";
2
- import { t as logger } from "./logger-Dh_xb7_2.mjs";
3
- import { t as allTools } from "./ToolCatalog-C0JGZoOm.mjs";
4
- import { t as INSTALLED_EXTENSION_METADATA_FILENAME } from "./types-Bx92KJfT.mjs";
5
- import { createHash } from "node:crypto";
6
- import { existsSync, readFileSync } from "node:fs";
7
- import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
8
- import { fileURLToPath, pathToFileURL } from "node:url";
9
- import { readFile } from "node:fs/promises";
10
- import { glob } from "tinyglobby";
11
- //#region src/server/extensions/ExtensionManager.roots.ts
12
- /**
13
- * Extension path resolution — root directories for plugins and workflows.
14
- */
15
- /**
16
- * Walk up the directory tree from the given start to find the project root
17
- * (the nearest ancestor that contains a package.json).
18
- *
19
- * This is robust across both dev (`src/server/extensions/`) and production
20
- * (`dist/src/server/extensions/`) layouts — no hard-coded level count needed.
21
- */
22
- function findProjectRoot(startDir) {
23
- let dir = startDir;
24
- while (true) {
25
- if (existsSync(join(dir, "package.json"))) return dir;
26
- const parent = dirname(dir);
27
- if (parent === dir) break;
28
- dir = parent;
29
- }
30
- return resolve(startDir, "..", "..", "..", "..");
31
- }
32
- const EXTENSION_INSTALL_ROOT = findProjectRoot(fileURLToPath(new URL(".", import.meta.url)));
33
- const DEFAULT_PLUGIN_ROOTS = [join(EXTENSION_INSTALL_ROOT, "plugins")];
34
- const DEFAULT_WORKFLOW_ROOTS = [join(EXTENSION_INSTALL_ROOT, "workflows")];
35
- function parseRoots(raw, fallback) {
36
- const value = raw?.trim();
37
- if (!value) return fallback;
38
- const roots = value.split(",").map((item) => item.trim()).filter(Boolean);
39
- return roots.length > 0 ? [...new Set(roots)] : fallback;
40
- }
41
- function resolveRoots(roots, baseDir = EXTENSION_INSTALL_ROOT) {
42
- const resolved = roots.map((root) => isAbsolute(root) ? root : resolve(baseDir, root));
43
- return [...new Set(resolved)].toSorted((a, b) => a.localeCompare(b));
44
- }
45
- //#endregion
46
- //#region src/server/extensions/ExtensionManager.version.ts
47
- /**
48
- * Semver parsing and compatibility checks for extension version constraints.
49
- */
50
- function parseVersionParts(version) {
51
- const match = version.trim().match(/^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/);
52
- if (!match) return null;
53
- return [
54
- Number(match[1]),
55
- Number(match[2]),
56
- Number(match[3])
57
- ];
58
- }
59
- function compareVersion(a, b) {
60
- const aa = parseVersionParts(a);
61
- const bb = parseVersionParts(b);
62
- if (!aa || !bb) return null;
63
- const [aMajor, aMinor, aPatch] = aa;
64
- const [bMajor, bMinor, bPatch] = bb;
65
- if (aMajor > bMajor) return 1;
66
- if (aMajor < bMajor) return -1;
67
- if (aMinor > bMinor) return 1;
68
- if (aMinor < bMinor) return -1;
69
- if (aPatch > bPatch) return 1;
70
- if (aPatch < bPatch) return -1;
71
- return 0;
72
- }
73
- function isCompatibleVersion(range, currentVersion) {
74
- const input = range.trim();
75
- if (!input || input === "*") return true;
76
- if (input.startsWith(">=")) {
77
- const cmp = compareVersion(currentVersion, input.slice(2).trim());
78
- return cmp !== null && cmp >= 0;
79
- }
80
- if (input.startsWith("^")) {
81
- const base = input.slice(1).trim();
82
- const cc = parseVersionParts(currentVersion);
83
- const bb = parseVersionParts(base);
84
- if (!cc || !bb) return false;
85
- const cmp = compareVersion(currentVersion, base);
86
- return cmp !== null && cmp >= 0 && cc[0] === bb[0];
87
- }
88
- if (input.startsWith("~")) {
89
- const base = input.slice(1).trim();
90
- const cc = parseVersionParts(currentVersion);
91
- const bb = parseVersionParts(base);
92
- if (!cc || !bb) return false;
93
- const cmp = compareVersion(currentVersion, base);
94
- return cmp !== null && cmp >= 0 && cc[0] === bb[0] && cc[1] === bb[1];
95
- }
96
- const cmp = compareVersion(currentVersion, input);
97
- return cmp !== null && cmp === 0;
98
- }
99
- //#endregion
100
- //#region src/server/extensions/ExtensionManager.integrity.ts
101
- /**
102
- * Plugin integrity verification — digest allowlists, env guards, compatibility checks.
103
- */
104
- async function sha256Hex(filePath) {
105
- const content = await readFile(filePath);
106
- return createHash("sha256").update(content).digest("hex");
107
- }
108
- function normalizeHex(value) {
109
- return value.trim().toLowerCase().replace(/^0x/, "");
110
- }
111
- function isTruthyEnv(value) {
112
- return ["1", "true"].includes(value.toLowerCase());
113
- }
114
- function isPluginSignatureRequired() {
115
- const raw = process.env.MCP_PLUGIN_SIGNATURE_REQUIRED;
116
- if (raw === void 0 || raw.trim() === "") return process.env.NODE_ENV === "production";
117
- return isTruthyEnv(raw);
118
- }
119
- function isPluginStrictLoad() {
120
- const raw = process.env.MCP_PLUGIN_STRICT_LOAD;
121
- if (raw === void 0 || raw.trim() === "") return isPluginSignatureRequired();
122
- return isTruthyEnv(raw) || isPluginSignatureRequired();
123
- }
124
- function parseDigestAllowlist(raw) {
125
- const value = raw?.trim();
126
- if (!value) return /* @__PURE__ */ new Set();
127
- return new Set(value.split(",").map((item) => normalizeHex(item)).filter((item) => item.length > 0));
128
- }
129
- async function verifyPluginIntegrity(plugin, currentVersion) {
130
- const errors = [];
131
- const warnings = [];
132
- if (!isCompatibleVersion(plugin.compatibleCoreRange, currentVersion)) errors.push(`Plugin ${plugin.id} incompatible with core ${currentVersion}; requires ${plugin.compatibleCoreRange}`);
133
- return {
134
- ok: errors.length === 0,
135
- errors,
136
- warnings
137
- };
138
- }
139
- //#endregion
140
- //#region src/server/extensions/ExtensionManager.guards.ts
141
- function isExtensionBuilder(value) {
142
- if (!value || typeof value !== "object") return false;
143
- const candidate = value;
144
- return !!(typeof candidate.id === "string" && typeof candidate.version === "string" && Array.isArray(candidate.tools) && (candidate.workflows === void 0 || Array.isArray(candidate.workflows)));
145
- }
146
- function isWorkflowContract(value) {
147
- if (!value || typeof value !== "object") return false;
148
- const candidate = value;
149
- return !!(candidate.kind === "workflow-contract" && candidate.version === 1 && typeof candidate.id === "string" && typeof candidate.displayName === "string" && typeof candidate.build === "function");
150
- }
151
- //#endregion
152
- //#region src/server/extensions/ExtensionManager.discovery.ts
153
- /**
154
- * Extension file discovery — prefers installed registry metadata, then falls back
155
- * to scanning plugin/workflow roots for legacy manifest files.
156
- */
157
- async function collectMatchingFiles(roots, matcher) {
158
- const files = /* @__PURE__ */ new Set();
159
- for (const root of roots) {
160
- let matchedPaths;
161
- try {
162
- matchedPaths = await glob("**/*", {
163
- cwd: root,
164
- absolute: true,
165
- onlyFiles: true,
166
- ignore: [
167
- "**/node_modules/**",
168
- "**/.git/**",
169
- "**/.pnpm/**"
170
- ]
171
- });
172
- } catch {
173
- continue;
174
- }
175
- for (const file of matchedPaths) if (matcher(basename(file))) files.add(file);
176
- }
177
- return [...files].toSorted((a, b) => a.localeCompare(b));
178
- }
179
- function normalizeExtensionCandidateKey(root, file) {
180
- const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "").toLowerCase();
181
- const relDir = relative(root, dirname(file)).replace(/^[/\\]+/, "").replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "").toLowerCase();
182
- if (!relDir || relDir === "dist") return `${normalizedRoot}::`;
183
- return `${normalizedRoot}::${relDir.endsWith("/dist") ? relDir.slice(0, -5) : relDir}`;
184
- }
185
- function extensionRank(candidate) {
186
- if (candidate.isJs) return 0;
187
- if (candidate.isTs) return 1;
188
- return 2;
189
- }
190
- function isInstalledExtensionMetadata(value, kind) {
191
- if (!value || typeof value !== "object") return false;
192
- const record = value;
193
- if (record.version !== 1 || record.kind !== kind) return false;
194
- if (typeof record.slug !== "string" || typeof record.id !== "string") return false;
195
- if (!record.source || typeof record.source !== "object") return false;
196
- const source = record.source;
197
- return typeof source.type === "string" && typeof source.repo === "string" && typeof source.ref === "string" && typeof source.commit === "string" && typeof source.subpath === "string" && typeof source.entry === "string";
198
- }
199
- async function collectInstalledEntryCandidates(roots, kind) {
200
- const candidates = [];
201
- for (const [rootIndex, root] of roots.entries()) {
202
- const metadataFiles = await collectMatchingFiles([root], (filename) => filename === INSTALLED_EXTENSION_METADATA_FILENAME);
203
- for (const metadataFile of metadataFiles) {
204
- let metadataRaw;
205
- try {
206
- metadataRaw = JSON.parse(await readFile(metadataFile, "utf8"));
207
- } catch {
208
- continue;
209
- }
210
- if (!isInstalledExtensionMetadata(metadataRaw, kind)) continue;
211
- const entryPath = metadataRaw.source.entry.trim();
212
- if (!entryPath) continue;
213
- const file = resolve(dirname(metadataFile), entryPath);
214
- if (!existsSync(file)) continue;
215
- candidates.push({
216
- file,
217
- key: normalizeExtensionCandidateKey(root, file),
218
- isJs: file.endsWith(".js"),
219
- isTs: file.endsWith(".ts"),
220
- rootIndex,
221
- priority: 0
222
- });
223
- }
224
- }
225
- return candidates;
226
- }
227
- function deduplicateCandidates(candidates) {
228
- const byKey = /* @__PURE__ */ new Map();
229
- for (const candidate of candidates.toSorted((a, b) => a.file.localeCompare(b.file))) {
230
- const existing = byKey.get(candidate.key);
231
- if (!existing) {
232
- byKey.set(candidate.key, candidate);
233
- continue;
234
- }
235
- const existingRoot = existing.rootIndex;
236
- const candidateRoot = candidate.rootIndex;
237
- const existingPriority = existing.priority;
238
- const candidatePriority = candidate.priority;
239
- const existingExtRank = extensionRank(existing);
240
- const candidateExtRank = extensionRank(candidate);
241
- if (candidateRoot < existingRoot || candidateRoot === existingRoot && candidatePriority < existingPriority || candidateRoot === existingRoot && candidatePriority === existingPriority && candidateExtRank < existingExtRank || candidateRoot === existingRoot && candidatePriority === existingPriority && candidateExtRank === existingExtRank && candidate.file.localeCompare(existing.file) < 0) byKey.set(candidate.key, candidate);
242
- }
243
- return [...byKey.values()].map((item) => item.file).toSorted((a, b) => a.localeCompare(b));
244
- }
245
- async function discoverPluginFiles(pluginRoots) {
246
- const candidates = await collectInstalledEntryCandidates(pluginRoots, "plugin");
247
- for (const [rootIndex, root] of pluginRoots.entries()) {
248
- const files = await collectMatchingFiles([root], (filename) => filename === "manifest.js" || filename === "manifest.ts");
249
- for (const file of files) candidates.push({
250
- file,
251
- key: normalizeExtensionCandidateKey(root, file),
252
- isJs: file.endsWith(".js"),
253
- isTs: file.endsWith(".ts"),
254
- rootIndex,
255
- priority: 1
256
- });
257
- }
258
- return deduplicateCandidates(candidates);
259
- }
260
- async function discoverWorkflowFiles(workflowRoots) {
261
- const candidates = await collectInstalledEntryCandidates(workflowRoots, "workflow");
262
- for (const [rootIndex, root] of workflowRoots.entries()) {
263
- const files = await collectMatchingFiles([root], (filename) => filename.endsWith(".workflow.js") || filename.endsWith(".workflow.ts") || filename === "workflow.js" || filename === "workflow.ts");
264
- for (const file of files) candidates.push({
265
- file,
266
- key: normalizeExtensionCandidateKey(root, file),
267
- isJs: file.endsWith(".js"),
268
- isTs: file.endsWith(".ts"),
269
- rootIndex,
270
- priority: 1
271
- });
272
- }
273
- return deduplicateCandidates(candidates);
274
- }
275
- //#endregion
276
- //#region src/server/extensions/ExtensionManager.lifecycle.ts
277
- /**
278
- * Extension lifecycle helpers — import, cleanup, config extraction, list building.
279
- */
280
- function extractConfigValue(ctx, path, fallback) {
281
- const segments = path.split(".").filter(Boolean);
282
- let current = ctx.config;
283
- for (const segment of segments) {
284
- if (!current || typeof current !== "object") return fallback;
285
- current = current[segment];
286
- }
287
- return current ?? fallback;
288
- }
289
- function createFreshImportUrl(modulePath, kind) {
290
- const moduleUrl = new URL(pathToFileURL(modulePath).href);
291
- moduleUrl.searchParams.set("reloadTs", String(Date.now()));
292
- logger.debug(`[extensions] Loading fresh ${kind} module: ${modulePath}`);
293
- return moduleUrl.href;
294
- }
295
- async function clearLoadedExtensionTools(ctx) {
296
- let removed = 0;
297
- for (const [pluginId, runtime] of ctx.extensionPluginRuntimeById.entries()) {
298
- try {
299
- if (runtime.plugin.onDeactivateHandler && runtime.state === "activated") {
300
- await runtime.plugin.onDeactivateHandler(runtime.lifecycleContext);
301
- runtime.state = "deactivated";
302
- }
303
- } catch (error) {
304
- logger.warn(`Plugin onDeactivate failed for "${pluginId}":`, error);
305
- }
306
- try {
307
- if (runtime.plugin.onDeactivateHandler) runtime.state = "unloaded";
308
- } catch (error) {
309
- logger.warn(`Plugin onUnload failed for "${pluginId}":`, error);
310
- }
311
- }
312
- for (const record of ctx.extensionToolsByName.values()) {
313
- try {
314
- record.registeredTool?.remove();
315
- } catch (error) {
316
- logger.warn(`Failed to remove extension tool "${record.name}":`, error);
317
- }
318
- ctx.router.removeHandler(record.name);
319
- ctx.activatedToolNames.delete(record.name);
320
- ctx.activatedRegisteredTools.delete(record.name);
321
- removed++;
322
- }
323
- ctx.extensionToolsByName.clear();
324
- ctx.extensionPluginsById.clear();
325
- ctx.extensionPluginRuntimeById.clear();
326
- ctx.extensionWorkflowsById.clear();
327
- ctx.extensionWorkflowRuntimeById.clear();
328
- return removed;
329
- }
330
- function buildListResult(ctx, pluginRoots, workflowRoots) {
331
- return {
332
- pluginRoots,
333
- workflowRoots,
334
- pluginCount: ctx.extensionPluginsById.size,
335
- workflowCount: ctx.extensionWorkflowsById.size,
336
- toolCount: ctx.extensionToolsByName.size,
337
- lastReloadAt: ctx.lastExtensionReloadAt,
338
- plugins: [...ctx.extensionPluginsById.values()],
339
- workflows: [...ctx.extensionWorkflowsById.values()],
340
- tools: [...ctx.extensionToolsByName.values()].map((record) => ({
341
- name: record.name,
342
- domain: record.domain,
343
- source: record.source
344
- }))
345
- };
346
- }
347
- //#endregion
348
- //#region src/server/extensions/ExtensionManager.ts
349
- var ExtensionManager_exports = /* @__PURE__ */ __exportAll({
350
- ensureWorkflowsLoaded: () => ensureWorkflowsLoaded,
351
- listExtensions: () => listExtensions,
352
- reloadExtensions: () => reloadExtensions
353
- });
354
- function listExtensions(ctx) {
355
- return buildListResult(ctx, resolveRoots(parseRoots(process.env.MCP_PLUGIN_ROOTS, DEFAULT_PLUGIN_ROOTS)), resolveRoots(parseRoots(process.env.MCP_WORKFLOW_ROOTS, DEFAULT_WORKFLOW_ROOTS)));
356
- }
357
- /**
358
- * Parse a flat key: value YAML file (no nesting, no arrays).
359
- * Returns a Record<string, string> of trimmed key/value pairs.
360
- * Returns empty object on any error (file missing, malformed, etc.).
361
- */
362
- function parseSimpleYaml(filePath) {
363
- try {
364
- const text = readFileSync(filePath, "utf-8");
365
- const result = {};
366
- for (const line of text.split(/\r?\n/)) {
367
- const trimmed = line.trim();
368
- if (!trimmed || trimmed.startsWith("#")) continue;
369
- const colonIdx = trimmed.indexOf(":");
370
- if (colonIdx < 1) continue;
371
- const key = trimmed.slice(0, colonIdx).trim();
372
- const value = trimmed.slice(colonIdx + 1).trim();
373
- if (key) result[key] = value;
374
- }
375
- return result;
376
- } catch {
377
- return {};
378
- }
379
- }
380
- function findInstalledMetadataRoot(startDir) {
381
- let currentDir = startDir;
382
- while (true) {
383
- if (existsSync(join(currentDir, ".jshook-install.json"))) return currentDir;
384
- const parentDir = dirname(currentDir);
385
- if (parentDir === currentDir) return null;
386
- currentDir = parentDir;
387
- }
388
- }
389
- function resolvePluginProjectRoot(pluginFile) {
390
- const entryDir = dirname(pluginFile);
391
- const metadataRoot = findInstalledMetadataRoot(entryDir);
392
- if (metadataRoot) return metadataRoot;
393
- if (basename(entryDir).toLowerCase() === "dist") return dirname(entryDir);
394
- return entryDir;
395
- }
396
- let reloadMutex = Promise.resolve();
397
- const lazyWorkflowLoadAttempted = /* @__PURE__ */ new WeakSet();
398
- const STRICT_PLUGIN_ALLOWLIST_ERROR = "MCP_PLUGIN_ALLOWED_DIGESTS is required when MCP_PLUGIN_SIGNATURE_REQUIRED=true or MCP_PLUGIN_STRICT_LOAD=true. The digest allowlist is the only pre-import trust boundary — without it, plugin code executes before integrity verification. No plugins will be loaded.";
399
- const MISSING_PLUGIN_ALLOWLIST_WARNING = "[extensions] Loading plugins WITHOUT MCP_PLUGIN_ALLOWED_DIGESTS allowlist. Plugin code will execute on import() before post-load integrity checks. Set MCP_PLUGIN_STRICT_LOAD=true to enforce allowlist requirement.";
400
- async function withReloadMutex(operation) {
401
- const prev = reloadMutex;
402
- let resolve;
403
- reloadMutex = new Promise((r) => {
404
- resolve = r;
405
- });
406
- await prev;
407
- try {
408
- return await operation();
409
- } finally {
410
- resolve();
411
- }
412
- }
413
- async function reloadExtensions(ctx) {
414
- return withReloadMutex(() => reloadExtensionsInner(ctx));
415
- }
416
- async function ensureWorkflowsLoaded(ctx) {
417
- if (ctx.extensionWorkflowRuntimeById.size > 0 || lazyWorkflowLoadAttempted.has(ctx)) return;
418
- await withReloadMutex(async () => {
419
- if (ctx.extensionWorkflowRuntimeById.size > 0 || lazyWorkflowLoadAttempted.has(ctx)) return;
420
- lazyWorkflowLoadAttempted.add(ctx);
421
- const warnings = [];
422
- const errors = [];
423
- const pluginRoots = resolveRoots(parseRoots(process.env.MCP_PLUGIN_ROOTS, DEFAULT_PLUGIN_ROOTS));
424
- const workflowRoots = resolveRoots(parseRoots(process.env.MCP_WORKFLOW_ROOTS, DEFAULT_WORKFLOW_ROOTS));
425
- await loadPluginWorkflowContributions(ctx, pluginRoots, warnings, errors);
426
- await loadWorkflows(ctx, await discoverWorkflowFiles(workflowRoots), warnings, errors);
427
- for (const warning of warnings) logger.warn(`[extensions] ${warning}`);
428
- for (const error of errors) logger.error(`[extensions] ${error}`);
429
- });
430
- }
431
- async function loadWorkflows(ctx, workflowFiles, warnings, errors) {
432
- for (const workflowFile of workflowFiles) try {
433
- const mod = await import(createFreshImportUrl(workflowFile, "workflow"));
434
- const candidate = mod.default ?? mod;
435
- if (!isWorkflowContract(candidate)) {
436
- warnings.push(`Skip workflow file without valid WorkflowContract: ${workflowFile}`);
437
- continue;
438
- }
439
- registerWorkflowContract(ctx, candidate, workflowFile, warnings);
440
- } catch (error) {
441
- errors.push(`Failed to import workflow file ${workflowFile}: ${String(error)}`);
442
- }
443
- }
444
- function registerWorkflowContract(ctx, workflow, source, warnings) {
445
- if (ctx.extensionWorkflowsById.has(workflow.id)) {
446
- warnings.push(`Skip workflow "${workflow.id}" from ${source}: duplicate id`);
447
- return false;
448
- }
449
- const record = {
450
- id: workflow.id,
451
- displayName: workflow.displayName,
452
- source,
453
- description: workflow.description,
454
- tags: workflow.tags,
455
- timeoutMs: workflow.timeoutMs,
456
- defaultMaxConcurrency: workflow.defaultMaxConcurrency,
457
- route: workflow.route
458
- };
459
- ctx.extensionWorkflowsById.set(record.id, record);
460
- const runtimeRecord = {
461
- workflow,
462
- source,
463
- route: workflow.route
464
- };
465
- ctx.extensionWorkflowRuntimeById.set(record.id, runtimeRecord);
466
- return true;
467
- }
468
- function buildPluginRecord(plugin, pluginFile, loadedTools, loadedWorkflows) {
469
- return {
470
- id: plugin.id,
471
- name: plugin.pluginName,
472
- source: pluginFile,
473
- author: plugin.pluginAuthor || void 0,
474
- sourceRepo: plugin.pluginSourceRepo || void 0,
475
- domains: [],
476
- workflows: loadedWorkflows,
477
- tools: loadedTools
478
- };
479
- }
480
- async function loadPluginWorkflowContributions(ctx, pluginRoots, warnings, errors) {
481
- const allowedDigests = parseDigestAllowlist(process.env.MCP_PLUGIN_ALLOWED_DIGESTS);
482
- if (isPluginStrictLoad() && allowedDigests.size === 0) {
483
- errors.push(STRICT_PLUGIN_ALLOWLIST_ERROR);
484
- logger.error("[extensions] " + STRICT_PLUGIN_ALLOWLIST_ERROR);
485
- return;
486
- }
487
- if (allowedDigests.size === 0) logger.warn(MISSING_PLUGIN_ALLOWLIST_WARNING);
488
- const pluginFiles = await discoverPluginFiles(pluginRoots);
489
- const coreVersion = ctx.config?.mcp?.version ?? "0.0.0";
490
- for (const pluginFile of pluginFiles) {
491
- let fileDigest;
492
- try {
493
- fileDigest = normalizeHex(await sha256Hex(pluginFile));
494
- if (allowedDigests.size > 0 && !allowedDigests.has(fileDigest)) {
495
- warnings.push(`Skip plugin file not in MCP_PLUGIN_ALLOWED_DIGESTS allowlist: ${pluginFile}`);
496
- continue;
497
- }
498
- } catch (error) {
499
- errors.push(`Failed to hash plugin file ${pluginFile}: ${String(error)}`);
500
- continue;
501
- }
502
- let plugin;
503
- try {
504
- const mod = await import(createFreshImportUrl(pluginFile, "plugin"));
505
- const candidate = mod.default ?? mod;
506
- if (!isExtensionBuilder(candidate)) {
507
- warnings.push(`Skip plugin file without valid ExtensionBuilder: ${pluginFile}`);
508
- continue;
509
- }
510
- plugin = candidate;
511
- } catch (error) {
512
- errors.push(`Failed to import plugin file ${pluginFile}: ${String(error)}`);
513
- continue;
514
- }
515
- const meta = parseSimpleYaml(join(resolvePluginProjectRoot(pluginFile), "meta.yaml"));
516
- plugin.mergeMetadata(meta);
517
- if (ctx.extensionPluginsById.has(plugin.id)) {
518
- warnings.push(`Skip plugin "${plugin.id}" from ${pluginFile}: duplicate plugin id`);
519
- continue;
520
- }
521
- try {
522
- const verification = await verifyPluginIntegrity(plugin, coreVersion);
523
- warnings.push(...verification.warnings);
524
- if (!verification.ok) {
525
- errors.push(...verification.errors);
526
- continue;
527
- }
528
- } catch (error) {
529
- errors.push(`Failed to verify plugin ${plugin.id}: ${String(error)}`);
530
- continue;
531
- }
532
- const loadedWorkflows = [];
533
- const pluginWorkflows = Array.isArray(plugin.workflows) ? plugin.workflows : [];
534
- for (const candidate of pluginWorkflows) {
535
- if (!isWorkflowContract(candidate)) {
536
- warnings.push(`Skip invalid workflow contribution from plugin "${plugin.id}" in ${pluginFile}`);
537
- continue;
538
- }
539
- if (registerWorkflowContract(ctx, candidate, `${pluginFile}#workflow:${candidate.id}`, warnings)) loadedWorkflows.push(candidate.id);
540
- }
541
- if (loadedWorkflows.length === 0) continue;
542
- ctx.extensionPluginsById.set(plugin.id, buildPluginRecord(plugin, pluginFile, [], loadedWorkflows));
543
- }
544
- }
545
- async function reloadExtensionsInner(ctx) {
546
- const warnings = [];
547
- const errors = [];
548
- const removedTools = await clearLoadedExtensionTools(ctx);
549
- const pluginRoots = resolveRoots(parseRoots(process.env.MCP_PLUGIN_ROOTS, DEFAULT_PLUGIN_ROOTS));
550
- const workflowRoots = resolveRoots(parseRoots(process.env.MCP_WORKFLOW_ROOTS, DEFAULT_WORKFLOW_ROOTS));
551
- const allowedDigests = parseDigestAllowlist(process.env.MCP_PLUGIN_ALLOWED_DIGESTS);
552
- if (isPluginStrictLoad() && allowedDigests.size === 0) {
553
- const msg = STRICT_PLUGIN_ALLOWLIST_ERROR;
554
- errors.push(msg);
555
- logger.error("[extensions] " + msg);
556
- await loadWorkflows(ctx, await discoverWorkflowFiles(workflowRoots), warnings, errors);
557
- ctx.lastExtensionReloadAt = (/* @__PURE__ */ new Date()).toISOString();
558
- return {
559
- ...buildListResult(ctx, pluginRoots, workflowRoots),
560
- addedTools: 0,
561
- removedTools,
562
- warnings,
563
- errors
564
- };
565
- }
566
- if (allowedDigests.size === 0) logger.warn(MISSING_PLUGIN_ALLOWLIST_WARNING);
567
- const baseToolNames = new Set(allTools.map((tool) => tool.name));
568
- const pluginFiles = await discoverPluginFiles(pluginRoots);
569
- const coreVersion = ctx.config?.mcp?.version ?? "0.0.0";
570
- for (const pluginFile of pluginFiles) {
571
- let fileDigest;
572
- try {
573
- fileDigest = normalizeHex(await sha256Hex(pluginFile));
574
- if (allowedDigests.size > 0 && !allowedDigests.has(fileDigest)) {
575
- warnings.push(`Skip plugin file not in MCP_PLUGIN_ALLOWED_DIGESTS allowlist: ${pluginFile}`);
576
- continue;
577
- }
578
- } catch (error) {
579
- errors.push(`Failed to hash plugin file ${pluginFile}: ${String(error)}`);
580
- continue;
581
- }
582
- let plugin;
583
- try {
584
- const mod = await import(createFreshImportUrl(pluginFile, "plugin"));
585
- const candidate = mod.default ?? mod;
586
- if (!isExtensionBuilder(candidate)) {
587
- warnings.push(`Skip plugin file without valid ExtensionBuilder: ${pluginFile}`);
588
- continue;
589
- }
590
- plugin = candidate;
591
- } catch (error) {
592
- errors.push(`Failed to import plugin file ${pluginFile}: ${String(error)}`);
593
- continue;
594
- }
595
- const pluginProjectRoot = resolvePluginProjectRoot(pluginFile);
596
- const meta = parseSimpleYaml(join(pluginProjectRoot, "meta.yaml"));
597
- plugin.mergeMetadata(meta);
598
- if (ctx.extensionPluginsById.has(plugin.id)) {
599
- warnings.push(`Skip plugin "${plugin.id}" from ${pluginFile}: duplicate plugin id`);
600
- continue;
601
- }
602
- try {
603
- const verification = await verifyPluginIntegrity(plugin, coreVersion);
604
- warnings.push(...verification.warnings);
605
- if (!verification.ok) {
606
- errors.push(...verification.errors);
607
- continue;
608
- }
609
- } catch (error) {
610
- errors.push(`Failed to verify plugin ${plugin.id}: ${String(error)}`);
611
- continue;
612
- }
613
- const runtimeData = /* @__PURE__ */ new Map();
614
- const metrics = /* @__PURE__ */ new Set();
615
- let pluginState = "loaded";
616
- const allowInvokeAll = plugin.allowedTools.includes("*");
617
- const lifecycleContext = {
618
- pluginId: plugin.id,
619
- pluginRoot: pluginProjectRoot,
620
- config: ctx.config,
621
- get state() {
622
- return pluginState;
623
- },
624
- registerMetric(metricName) {
625
- metrics.add(metricName);
626
- },
627
- async invokeTool(name, args = {}) {
628
- if (typeof name !== "string" || name.length === 0) throw new Error("invokeTool requires a non-empty tool name");
629
- if (!allowInvokeAll && !plugin.allowedTools.includes(name)) throw new Error(`Plugin "${plugin.id}" is not allowed to invoke "${name}". Declare it in allowTool calls.`);
630
- if (!baseToolNames.has(name)) throw new Error(`Plugin "${plugin.id}" can only invoke built-in tools. "${name}" is not built-in.`);
631
- if (!ctx.router.has(name)) throw new Error(`Tool "${name}" is not available in the current active profile.`);
632
- return ctx.executeToolWithTracking(name, args ?? {});
633
- },
634
- hasPermission(_capability) {
635
- return true;
636
- },
637
- getConfig(path, fallback) {
638
- return extractConfigValue(ctx, path, fallback);
639
- },
640
- setRuntimeData(key, value) {
641
- runtimeData.set(key, value);
642
- },
643
- getRuntimeData(key) {
644
- return runtimeData.get(key);
645
- }
646
- };
647
- const runtimeRecord = {
648
- plugin,
649
- lifecycleContext,
650
- state: pluginState,
651
- source: pluginFile
652
- };
653
- try {
654
- if (plugin.onLoadHandler) await plugin.onLoadHandler(lifecycleContext);
655
- pluginState = "loaded";
656
- runtimeRecord.state = pluginState;
657
- if (plugin.onValidateHandler) {
658
- const validation = await plugin.onValidateHandler(lifecycleContext);
659
- if (!validation.valid) {
660
- warnings.push(`Plugin ${plugin.id} validation failed: ${validation.errors.join("; ")}`);
661
- continue;
662
- }
663
- pluginState = "validated";
664
- runtimeRecord.state = pluginState;
665
- }
666
- if (plugin.onActivateHandler) {
667
- await plugin.onActivateHandler(lifecycleContext);
668
- pluginState = "activated";
669
- runtimeRecord.state = pluginState;
670
- }
671
- ctx.extensionPluginRuntimeById.set(plugin.id, runtimeRecord);
672
- } catch (error) {
673
- try {
674
- if (plugin.onDeactivateHandler && pluginState === "activated") {
675
- await plugin.onDeactivateHandler(lifecycleContext);
676
- pluginState = "deactivated";
677
- runtimeRecord.state = pluginState;
678
- }
679
- } catch (deactivateError) {
680
- logger.warn(`Plugin onDeactivate failed during rollback for ${plugin.id}:`, deactivateError);
681
- }
682
- errors.push(`Plugin lifecycle failed for ${plugin.id}: ${String(error)}`);
683
- continue;
684
- }
685
- const loadedTools = plugin.tools.map((t) => t.name);
686
- const loadedWorkflows = [];
687
- const pluginWorkflows = Array.isArray(plugin.workflows) ? plugin.workflows : [];
688
- for (const candidate of pluginWorkflows) {
689
- if (!isWorkflowContract(candidate)) {
690
- warnings.push(`Skip invalid workflow contribution from plugin "${plugin.id}" in ${pluginFile}`);
691
- continue;
692
- }
693
- if (registerWorkflowContract(ctx, candidate, `${pluginFile}#workflow:${candidate.id}`, warnings)) loadedWorkflows.push(candidate.id);
694
- }
695
- const record = buildPluginRecord(plugin, pluginFile, loadedTools, loadedWorkflows);
696
- ctx.extensionPluginsById.set(record.id, record);
697
- }
698
- await loadWorkflows(ctx, await discoverWorkflowFiles(workflowRoots), warnings, errors);
699
- if (ctx.extensionToolsByName.size > 0 || removedTools > 0) try {
700
- await ctx.server.sendToolListChanged();
701
- } catch (error) {
702
- logger.warn("sendToolListChanged failed after extension reload:", error);
703
- }
704
- ctx.lastExtensionReloadAt = (/* @__PURE__ */ new Date()).toISOString();
705
- return {
706
- ...buildListResult(ctx, pluginRoots, workflowRoots),
707
- addedTools: ctx.extensionToolsByName.size,
708
- removedTools,
709
- warnings,
710
- errors
711
- };
712
- }
713
- //#endregion
714
- export { reloadExtensions as i, ensureWorkflowsLoaded as n, listExtensions as r, ExtensionManager_exports as t };