patchwork-os 0.2.0-alpha.0

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 (721) hide show
  1. package/LICENSE +21 -0
  2. package/README.bridge.md +352 -0
  3. package/README.md +72 -0
  4. package/deploy/README.md +172 -0
  5. package/deploy/bootstrap-new-vps.sh +364 -0
  6. package/deploy/claude-ide-bridge.service.template +67 -0
  7. package/deploy/claude-ide-bridge@.service +31 -0
  8. package/deploy/ecosystem.config.js.example +36 -0
  9. package/deploy/install-vps-service.sh +240 -0
  10. package/deploy/nginx-claude-bridge.conf.template +129 -0
  11. package/dist/activityLog.d.ts +112 -0
  12. package/dist/activityLog.js +399 -0
  13. package/dist/activityLog.js.map +1 -0
  14. package/dist/activityTypes.d.ts +28 -0
  15. package/dist/activityTypes.js +9 -0
  16. package/dist/activityTypes.js.map +1 -0
  17. package/dist/adapters/base.d.ts +78 -0
  18. package/dist/adapters/base.js +14 -0
  19. package/dist/adapters/base.js.map +1 -0
  20. package/dist/adapters/claude.d.ts +18 -0
  21. package/dist/adapters/claude.js +276 -0
  22. package/dist/adapters/claude.js.map +1 -0
  23. package/dist/adapters/gemini.d.ts +17 -0
  24. package/dist/adapters/gemini.js +218 -0
  25. package/dist/adapters/gemini.js.map +1 -0
  26. package/dist/adapters/grok.d.ts +7 -0
  27. package/dist/adapters/grok.js +21 -0
  28. package/dist/adapters/grok.js.map +1 -0
  29. package/dist/adapters/index.d.ts +5 -0
  30. package/dist/adapters/index.js +37 -0
  31. package/dist/adapters/index.js.map +1 -0
  32. package/dist/adapters/local.d.ts +7 -0
  33. package/dist/adapters/local.js +22 -0
  34. package/dist/adapters/local.js.map +1 -0
  35. package/dist/adapters/openai.d.ts +22 -0
  36. package/dist/adapters/openai.js +284 -0
  37. package/dist/adapters/openai.js.map +1 -0
  38. package/dist/adapters/sse.d.ts +13 -0
  39. package/dist/adapters/sse.js +58 -0
  40. package/dist/adapters/sse.js.map +1 -0
  41. package/dist/analyticsAggregator.d.ts +28 -0
  42. package/dist/analyticsAggregator.js +133 -0
  43. package/dist/analyticsAggregator.js.map +1 -0
  44. package/dist/analyticsPrefs.d.ts +9 -0
  45. package/dist/analyticsPrefs.js +50 -0
  46. package/dist/analyticsPrefs.js.map +1 -0
  47. package/dist/analyticsSend.d.ts +12 -0
  48. package/dist/analyticsSend.js +34 -0
  49. package/dist/analyticsSend.js.map +1 -0
  50. package/dist/approvalHttp.d.ts +46 -0
  51. package/dist/approvalHttp.js +370 -0
  52. package/dist/approvalHttp.js.map +1 -0
  53. package/dist/approvalQueue.d.ts +49 -0
  54. package/dist/approvalQueue.js +84 -0
  55. package/dist/approvalQueue.js.map +1 -0
  56. package/dist/automation.d.ts +675 -0
  57. package/dist/automation.js +1038 -0
  58. package/dist/automation.js.map +1 -0
  59. package/dist/bridge.d.ts +85 -0
  60. package/dist/bridge.js +1535 -0
  61. package/dist/bridge.js.map +1 -0
  62. package/dist/bridgeLockDiscovery.d.ts +11 -0
  63. package/dist/bridgeLockDiscovery.js +49 -0
  64. package/dist/bridgeLockDiscovery.js.map +1 -0
  65. package/dist/bridgeToken.d.ts +22 -0
  66. package/dist/bridgeToken.js +114 -0
  67. package/dist/bridgeToken.js.map +1 -0
  68. package/dist/bridgeToolsRules.d.ts +20 -0
  69. package/dist/bridgeToolsRules.js +79 -0
  70. package/dist/bridgeToolsRules.js.map +1 -0
  71. package/dist/ccPermissions.d.ts +59 -0
  72. package/dist/ccPermissions.js +163 -0
  73. package/dist/ccPermissions.js.map +1 -0
  74. package/dist/claudeDriver.d.ts +129 -0
  75. package/dist/claudeDriver.js +459 -0
  76. package/dist/claudeDriver.js.map +1 -0
  77. package/dist/claudeMdPatch.d.ts +29 -0
  78. package/dist/claudeMdPatch.js +164 -0
  79. package/dist/claudeMdPatch.js.map +1 -0
  80. package/dist/claudeOrchestrator.d.ts +171 -0
  81. package/dist/claudeOrchestrator.js +591 -0
  82. package/dist/claudeOrchestrator.js.map +1 -0
  83. package/dist/commands/install.d.ts +1 -0
  84. package/dist/commands/install.js +158 -0
  85. package/dist/commands/install.js.map +1 -0
  86. package/dist/commands/marketplace.d.ts +11 -0
  87. package/dist/commands/marketplace.js +120 -0
  88. package/dist/commands/marketplace.js.map +1 -0
  89. package/dist/commands/patchworkInit.d.ts +14 -0
  90. package/dist/commands/patchworkInit.js +155 -0
  91. package/dist/commands/patchworkInit.js.map +1 -0
  92. package/dist/commands/task.d.ts +14 -0
  93. package/dist/commands/task.js +289 -0
  94. package/dist/commands/task.js.map +1 -0
  95. package/dist/commands/tokenEfficiency.d.ts +9 -0
  96. package/dist/commands/tokenEfficiency.js +211 -0
  97. package/dist/commands/tokenEfficiency.js.map +1 -0
  98. package/dist/commands/tools.d.ts +28 -0
  99. package/dist/commands/tools.js +326 -0
  100. package/dist/commands/tools.js.map +1 -0
  101. package/dist/commitIssueLinkLog.d.ts +77 -0
  102. package/dist/commitIssueLinkLog.js +142 -0
  103. package/dist/commitIssueLinkLog.js.map +1 -0
  104. package/dist/companions/registry.d.ts +12 -0
  105. package/dist/companions/registry.js +71 -0
  106. package/dist/companions/registry.js.map +1 -0
  107. package/dist/config.d.ts +105 -0
  108. package/dist/config.js +720 -0
  109. package/dist/config.js.map +1 -0
  110. package/dist/crypto.d.ts +16 -0
  111. package/dist/crypto.js +34 -0
  112. package/dist/crypto.js.map +1 -0
  113. package/dist/dashboard.d.ts +12 -0
  114. package/dist/dashboard.js +149 -0
  115. package/dist/dashboard.js.map +1 -0
  116. package/dist/decisionTraceLog.d.ts +77 -0
  117. package/dist/decisionTraceLog.js +147 -0
  118. package/dist/decisionTraceLog.js.map +1 -0
  119. package/dist/errors.d.ts +32 -0
  120. package/dist/errors.js +34 -0
  121. package/dist/errors.js.map +1 -0
  122. package/dist/extensionClient.d.ts +279 -0
  123. package/dist/extensionClient.js +1253 -0
  124. package/dist/extensionClient.js.map +1 -0
  125. package/dist/fileLock.d.ts +36 -0
  126. package/dist/fileLock.js +121 -0
  127. package/dist/fileLock.js.map +1 -0
  128. package/dist/fp/activityAnalytics.d.ts +39 -0
  129. package/dist/fp/activityAnalytics.js +111 -0
  130. package/dist/fp/activityAnalytics.js.map +1 -0
  131. package/dist/fp/async.d.ts +48 -0
  132. package/dist/fp/async.js +60 -0
  133. package/dist/fp/async.js.map +1 -0
  134. package/dist/fp/automationInterpreter.d.ts +37 -0
  135. package/dist/fp/automationInterpreter.js +523 -0
  136. package/dist/fp/automationInterpreter.js.map +1 -0
  137. package/dist/fp/automationProgram.d.ts +89 -0
  138. package/dist/fp/automationProgram.js +29 -0
  139. package/dist/fp/automationProgram.js.map +1 -0
  140. package/dist/fp/automationState.d.ts +135 -0
  141. package/dist/fp/automationState.js +206 -0
  142. package/dist/fp/automationState.js.map +1 -0
  143. package/dist/fp/automationUtils.d.ts +31 -0
  144. package/dist/fp/automationUtils.js +61 -0
  145. package/dist/fp/automationUtils.js.map +1 -0
  146. package/dist/fp/brandedTypes.d.ts +32 -0
  147. package/dist/fp/brandedTypes.js +41 -0
  148. package/dist/fp/brandedTypes.js.map +1 -0
  149. package/dist/fp/commandDescription.d.ts +18 -0
  150. package/dist/fp/commandDescription.js +125 -0
  151. package/dist/fp/commandDescription.js.map +1 -0
  152. package/dist/fp/extensionSnapshot.d.ts +10 -0
  153. package/dist/fp/extensionSnapshot.js +14 -0
  154. package/dist/fp/extensionSnapshot.js.map +1 -0
  155. package/dist/fp/index.d.ts +8 -0
  156. package/dist/fp/index.js +9 -0
  157. package/dist/fp/index.js.map +1 -0
  158. package/dist/fp/interpreterContext.d.ts +69 -0
  159. package/dist/fp/interpreterContext.js +56 -0
  160. package/dist/fp/interpreterContext.js.map +1 -0
  161. package/dist/fp/policyParser.d.ts +16 -0
  162. package/dist/fp/policyParser.js +334 -0
  163. package/dist/fp/policyParser.js.map +1 -0
  164. package/dist/fp/result.d.ts +38 -0
  165. package/dist/fp/result.js +57 -0
  166. package/dist/fp/result.js.map +1 -0
  167. package/dist/fp/tokenBucket.d.ts +27 -0
  168. package/dist/fp/tokenBucket.js +36 -0
  169. package/dist/fp/tokenBucket.js.map +1 -0
  170. package/dist/index.d.ts +2 -0
  171. package/dist/index.js +1465 -0
  172. package/dist/index.js.map +1 -0
  173. package/dist/instructionsUtils.d.ts +17 -0
  174. package/dist/instructionsUtils.js +38 -0
  175. package/dist/instructionsUtils.js.map +1 -0
  176. package/dist/lockfile.d.ts +16 -0
  177. package/dist/lockfile.js +172 -0
  178. package/dist/lockfile.js.map +1 -0
  179. package/dist/logger.d.ts +16 -0
  180. package/dist/logger.js +68 -0
  181. package/dist/logger.js.map +1 -0
  182. package/dist/oauth.d.ts +105 -0
  183. package/dist/oauth.js +880 -0
  184. package/dist/oauth.js.map +1 -0
  185. package/dist/orchestrator/childBridgeClient.d.ts +33 -0
  186. package/dist/orchestrator/childBridgeClient.js +321 -0
  187. package/dist/orchestrator/childBridgeClient.js.map +1 -0
  188. package/dist/orchestrator/childBridgeRegistry.d.ts +67 -0
  189. package/dist/orchestrator/childBridgeRegistry.js +297 -0
  190. package/dist/orchestrator/childBridgeRegistry.js.map +1 -0
  191. package/dist/orchestrator/index.d.ts +3 -0
  192. package/dist/orchestrator/index.js +3 -0
  193. package/dist/orchestrator/index.js.map +1 -0
  194. package/dist/orchestrator/orchestratorBridge.d.ts +32 -0
  195. package/dist/orchestrator/orchestratorBridge.js +412 -0
  196. package/dist/orchestrator/orchestratorBridge.js.map +1 -0
  197. package/dist/orchestrator/orchestratorConfig.d.ts +11 -0
  198. package/dist/orchestrator/orchestratorConfig.js +85 -0
  199. package/dist/orchestrator/orchestratorConfig.js.map +1 -0
  200. package/dist/orchestrator/orchestratorTools.d.ts +16 -0
  201. package/dist/orchestrator/orchestratorTools.js +272 -0
  202. package/dist/orchestrator/orchestratorTools.js.map +1 -0
  203. package/dist/patchworkCli.d.ts +15 -0
  204. package/dist/patchworkCli.js +41 -0
  205. package/dist/patchworkCli.js.map +1 -0
  206. package/dist/patchworkConfig.d.ts +28 -0
  207. package/dist/patchworkConfig.js +30 -0
  208. package/dist/patchworkConfig.js.map +1 -0
  209. package/dist/plugin.d.ts +106 -0
  210. package/dist/plugin.js +31 -0
  211. package/dist/plugin.js.map +1 -0
  212. package/dist/pluginLoader.d.ts +44 -0
  213. package/dist/pluginLoader.js +357 -0
  214. package/dist/pluginLoader.js.map +1 -0
  215. package/dist/pluginWatcher.d.ts +24 -0
  216. package/dist/pluginWatcher.js +139 -0
  217. package/dist/pluginWatcher.js.map +1 -0
  218. package/dist/preToolUseHook.d.ts +10 -0
  219. package/dist/preToolUseHook.js +57 -0
  220. package/dist/preToolUseHook.js.map +1 -0
  221. package/dist/probe.d.ts +35 -0
  222. package/dist/probe.js +143 -0
  223. package/dist/probe.js.map +1 -0
  224. package/dist/prompts.d.ts +27 -0
  225. package/dist/prompts.js +1680 -0
  226. package/dist/prompts.js.map +1 -0
  227. package/dist/quickTaskPresets.d.ts +64 -0
  228. package/dist/quickTaskPresets.js +156 -0
  229. package/dist/quickTaskPresets.js.map +1 -0
  230. package/dist/recipes/compiler.d.ts +44 -0
  231. package/dist/recipes/compiler.js +140 -0
  232. package/dist/recipes/compiler.js.map +1 -0
  233. package/dist/recipes/installer.d.ts +25 -0
  234. package/dist/recipes/installer.js +62 -0
  235. package/dist/recipes/installer.js.map +1 -0
  236. package/dist/recipes/parser.d.ts +18 -0
  237. package/dist/recipes/parser.js +160 -0
  238. package/dist/recipes/parser.js.map +1 -0
  239. package/dist/recipes/scheduler.d.ts +45 -0
  240. package/dist/recipes/scheduler.js +110 -0
  241. package/dist/recipes/scheduler.js.map +1 -0
  242. package/dist/recipes/schema.d.ts +71 -0
  243. package/dist/recipes/schema.js +11 -0
  244. package/dist/recipes/schema.js.map +1 -0
  245. package/dist/recipesHttp.d.ts +63 -0
  246. package/dist/recipesHttp.js +183 -0
  247. package/dist/recipesHttp.js.map +1 -0
  248. package/dist/resources.d.ts +33 -0
  249. package/dist/resources.js +266 -0
  250. package/dist/resources.js.map +1 -0
  251. package/dist/riskTier.d.ts +40 -0
  252. package/dist/riskTier.js +142 -0
  253. package/dist/riskTier.js.map +1 -0
  254. package/dist/runLog.d.ts +90 -0
  255. package/dist/runLog.js +143 -0
  256. package/dist/runLog.js.map +1 -0
  257. package/dist/server.d.ts +160 -0
  258. package/dist/server.js +1244 -0
  259. package/dist/server.js.map +1 -0
  260. package/dist/sessionCheckpoint.d.ts +37 -0
  261. package/dist/sessionCheckpoint.js +123 -0
  262. package/dist/sessionCheckpoint.js.map +1 -0
  263. package/dist/streamableHttp.d.ts +86 -0
  264. package/dist/streamableHttp.js +702 -0
  265. package/dist/streamableHttp.js.map +1 -0
  266. package/dist/telemetry.d.ts +18 -0
  267. package/dist/telemetry.js +95 -0
  268. package/dist/telemetry.js.map +1 -0
  269. package/dist/tools/activityLog.d.ts +140 -0
  270. package/dist/tools/activityLog.js +204 -0
  271. package/dist/tools/activityLog.js.map +1 -0
  272. package/dist/tools/auditDependencies.d.ts +67 -0
  273. package/dist/tools/auditDependencies.js +298 -0
  274. package/dist/tools/auditDependencies.js.map +1 -0
  275. package/dist/tools/batchLsp.d.ts +262 -0
  276. package/dist/tools/batchLsp.js +328 -0
  277. package/dist/tools/batchLsp.js.map +1 -0
  278. package/dist/tools/blame-utils.d.ts +30 -0
  279. package/dist/tools/blame-utils.js +60 -0
  280. package/dist/tools/blame-utils.js.map +1 -0
  281. package/dist/tools/bridgeDoctor.d.ts +78 -0
  282. package/dist/tools/bridgeDoctor.js +542 -0
  283. package/dist/tools/bridgeDoctor.js.map +1 -0
  284. package/dist/tools/bridgeStatus.d.ts +122 -0
  285. package/dist/tools/bridgeStatus.js +250 -0
  286. package/dist/tools/bridgeStatus.js.map +1 -0
  287. package/dist/tools/cancelClaudeTask.d.ts +48 -0
  288. package/dist/tools/cancelClaudeTask.js +56 -0
  289. package/dist/tools/cancelClaudeTask.js.map +1 -0
  290. package/dist/tools/checkDocumentDirty.d.ts +56 -0
  291. package/dist/tools/checkDocumentDirty.js +74 -0
  292. package/dist/tools/checkDocumentDirty.js.map +1 -0
  293. package/dist/tools/clipboard.d.ts +80 -0
  294. package/dist/tools/clipboard.js +211 -0
  295. package/dist/tools/clipboard.js.map +1 -0
  296. package/dist/tools/closeTabs.d.ts +84 -0
  297. package/dist/tools/closeTabs.js +97 -0
  298. package/dist/tools/closeTabs.js.map +1 -0
  299. package/dist/tools/codeLens.d.ts +50 -0
  300. package/dist/tools/codeLens.js +47 -0
  301. package/dist/tools/codeLens.js.map +1 -0
  302. package/dist/tools/contextBundle.d.ts +75 -0
  303. package/dist/tools/contextBundle.js +218 -0
  304. package/dist/tools/contextBundle.js.map +1 -0
  305. package/dist/tools/createIssueFromAIComment.d.ts +75 -0
  306. package/dist/tools/createIssueFromAIComment.js +119 -0
  307. package/dist/tools/createIssueFromAIComment.js.map +1 -0
  308. package/dist/tools/ctxGetTaskContext.d.ts +103 -0
  309. package/dist/tools/ctxGetTaskContext.js +274 -0
  310. package/dist/tools/ctxGetTaskContext.js.map +1 -0
  311. package/dist/tools/ctxQueryTraces.d.ts +142 -0
  312. package/dist/tools/ctxQueryTraces.js +194 -0
  313. package/dist/tools/ctxQueryTraces.js.map +1 -0
  314. package/dist/tools/ctxSaveTrace.d.ts +87 -0
  315. package/dist/tools/ctxSaveTrace.js +94 -0
  316. package/dist/tools/ctxSaveTrace.js.map +1 -0
  317. package/dist/tools/debug.d.ts +206 -0
  318. package/dist/tools/debug.js +234 -0
  319. package/dist/tools/debug.js.map +1 -0
  320. package/dist/tools/decorations.d.ts +130 -0
  321. package/dist/tools/decorations.js +160 -0
  322. package/dist/tools/decorations.js.map +1 -0
  323. package/dist/tools/detectUnusedCode.d.ts +78 -0
  324. package/dist/tools/detectUnusedCode.js +173 -0
  325. package/dist/tools/detectUnusedCode.js.map +1 -0
  326. package/dist/tools/documentLinks.d.ts +62 -0
  327. package/dist/tools/documentLinks.js +55 -0
  328. package/dist/tools/documentLinks.js.map +1 -0
  329. package/dist/tools/editText.d.ts +108 -0
  330. package/dist/tools/editText.js +318 -0
  331. package/dist/tools/editText.js.map +1 -0
  332. package/dist/tools/enrichCommit.d.ts +89 -0
  333. package/dist/tools/enrichCommit.js +201 -0
  334. package/dist/tools/enrichCommit.js.map +1 -0
  335. package/dist/tools/enrichStackTrace.d.ts +121 -0
  336. package/dist/tools/enrichStackTrace.js +194 -0
  337. package/dist/tools/enrichStackTrace.js.map +1 -0
  338. package/dist/tools/explainDiagnostic.d.ts +137 -0
  339. package/dist/tools/explainDiagnostic.js +230 -0
  340. package/dist/tools/explainDiagnostic.js.map +1 -0
  341. package/dist/tools/explainSymbol.d.ts +119 -0
  342. package/dist/tools/explainSymbol.js +177 -0
  343. package/dist/tools/explainSymbol.js.map +1 -0
  344. package/dist/tools/fileOperations.d.ts +186 -0
  345. package/dist/tools/fileOperations.js +330 -0
  346. package/dist/tools/fileOperations.js.map +1 -0
  347. package/dist/tools/fileWatcher.d.ts +107 -0
  348. package/dist/tools/fileWatcher.js +121 -0
  349. package/dist/tools/fileWatcher.js.map +1 -0
  350. package/dist/tools/findFiles.d.ts +65 -0
  351. package/dist/tools/findFiles.js +142 -0
  352. package/dist/tools/findFiles.js.map +1 -0
  353. package/dist/tools/findRelatedTests.d.ts +83 -0
  354. package/dist/tools/findRelatedTests.js +196 -0
  355. package/dist/tools/findRelatedTests.js.map +1 -0
  356. package/dist/tools/fixAllLintErrors.d.ts +66 -0
  357. package/dist/tools/fixAllLintErrors.js +128 -0
  358. package/dist/tools/fixAllLintErrors.js.map +1 -0
  359. package/dist/tools/foldingRanges.d.ts +50 -0
  360. package/dist/tools/foldingRanges.js +51 -0
  361. package/dist/tools/foldingRanges.js.map +1 -0
  362. package/dist/tools/formatAndSave.d.ts +57 -0
  363. package/dist/tools/formatAndSave.js +87 -0
  364. package/dist/tools/formatAndSave.js.map +1 -0
  365. package/dist/tools/formatDocument.d.ts +61 -0
  366. package/dist/tools/formatDocument.js +144 -0
  367. package/dist/tools/formatDocument.js.map +1 -0
  368. package/dist/tools/generateAPIDocumentation.d.ts +62 -0
  369. package/dist/tools/generateAPIDocumentation.js +249 -0
  370. package/dist/tools/generateAPIDocumentation.js.map +1 -0
  371. package/dist/tools/generateTests.d.ts +75 -0
  372. package/dist/tools/generateTests.js +226 -0
  373. package/dist/tools/generateTests.js.map +1 -0
  374. package/dist/tools/getAIComments.d.ts +79 -0
  375. package/dist/tools/getAIComments.js +93 -0
  376. package/dist/tools/getAIComments.js.map +1 -0
  377. package/dist/tools/getAnalyticsReport.d.ts +102 -0
  378. package/dist/tools/getAnalyticsReport.js +137 -0
  379. package/dist/tools/getAnalyticsReport.js.map +1 -0
  380. package/dist/tools/getArchitectureContext.d.ts +85 -0
  381. package/dist/tools/getArchitectureContext.js +135 -0
  382. package/dist/tools/getArchitectureContext.js.map +1 -0
  383. package/dist/tools/getBufferContent.d.ts +80 -0
  384. package/dist/tools/getBufferContent.js +207 -0
  385. package/dist/tools/getBufferContent.js.map +1 -0
  386. package/dist/tools/getChangeImpact.d.ts +76 -0
  387. package/dist/tools/getChangeImpact.js +184 -0
  388. package/dist/tools/getChangeImpact.js.map +1 -0
  389. package/dist/tools/getClaudeTaskStatus.d.ts +87 -0
  390. package/dist/tools/getClaudeTaskStatus.js +89 -0
  391. package/dist/tools/getClaudeTaskStatus.js.map +1 -0
  392. package/dist/tools/getCodeCoverage.d.ts +86 -0
  393. package/dist/tools/getCodeCoverage.js +237 -0
  394. package/dist/tools/getCodeCoverage.js.map +1 -0
  395. package/dist/tools/getCommitsForIssue.d.ts +98 -0
  396. package/dist/tools/getCommitsForIssue.js +106 -0
  397. package/dist/tools/getCommitsForIssue.js.map +1 -0
  398. package/dist/tools/getCurrentSelection.d.ts +123 -0
  399. package/dist/tools/getCurrentSelection.js +113 -0
  400. package/dist/tools/getCurrentSelection.js.map +1 -0
  401. package/dist/tools/getDebugState.d.ts +140 -0
  402. package/dist/tools/getDebugState.js +109 -0
  403. package/dist/tools/getDebugState.js.map +1 -0
  404. package/dist/tools/getDependencyTree.d.ts +59 -0
  405. package/dist/tools/getDependencyTree.js +207 -0
  406. package/dist/tools/getDependencyTree.js.map +1 -0
  407. package/dist/tools/getDiagnostics.d.ts +108 -0
  408. package/dist/tools/getDiagnostics.js +371 -0
  409. package/dist/tools/getDiagnostics.js.map +1 -0
  410. package/dist/tools/getDiffFromHandoff.d.ts +89 -0
  411. package/dist/tools/getDiffFromHandoff.js +163 -0
  412. package/dist/tools/getDiffFromHandoff.js.map +1 -0
  413. package/dist/tools/getDocumentSymbols.d.ts +74 -0
  414. package/dist/tools/getDocumentSymbols.js +177 -0
  415. package/dist/tools/getDocumentSymbols.js.map +1 -0
  416. package/dist/tools/getFileTree.d.ts +66 -0
  417. package/dist/tools/getFileTree.js +131 -0
  418. package/dist/tools/getFileTree.js.map +1 -0
  419. package/dist/tools/getGitDiff.d.ts +50 -0
  420. package/dist/tools/getGitDiff.js +73 -0
  421. package/dist/tools/getGitDiff.js.map +1 -0
  422. package/dist/tools/getGitHotspots.d.ts +88 -0
  423. package/dist/tools/getGitHotspots.js +145 -0
  424. package/dist/tools/getGitHotspots.js.map +1 -0
  425. package/dist/tools/getGitLog.d.ts +62 -0
  426. package/dist/tools/getGitLog.js +87 -0
  427. package/dist/tools/getGitLog.js.map +1 -0
  428. package/dist/tools/getGitStatus.d.ts +72 -0
  429. package/dist/tools/getGitStatus.js +126 -0
  430. package/dist/tools/getGitStatus.js.map +1 -0
  431. package/dist/tools/getImportTree.d.ts +73 -0
  432. package/dist/tools/getImportTree.js +223 -0
  433. package/dist/tools/getImportTree.js.map +1 -0
  434. package/dist/tools/getImportedSignatures.d.ts +62 -0
  435. package/dist/tools/getImportedSignatures.js +255 -0
  436. package/dist/tools/getImportedSignatures.js.map +1 -0
  437. package/dist/tools/getOpenEditors.d.ts +62 -0
  438. package/dist/tools/getOpenEditors.js +126 -0
  439. package/dist/tools/getOpenEditors.js.map +1 -0
  440. package/dist/tools/getPRTemplate.d.ts +68 -0
  441. package/dist/tools/getPRTemplate.js +187 -0
  442. package/dist/tools/getPRTemplate.js.map +1 -0
  443. package/dist/tools/getProjectContext.d.ts +114 -0
  444. package/dist/tools/getProjectContext.js +344 -0
  445. package/dist/tools/getProjectContext.js.map +1 -0
  446. package/dist/tools/getProjectInfo.d.ts +51 -0
  447. package/dist/tools/getProjectInfo.js +325 -0
  448. package/dist/tools/getProjectInfo.js.map +1 -0
  449. package/dist/tools/getSecurityAdvisories.d.ts +105 -0
  450. package/dist/tools/getSecurityAdvisories.js +472 -0
  451. package/dist/tools/getSecurityAdvisories.js.map +1 -0
  452. package/dist/tools/getSessionUsage.d.ts +58 -0
  453. package/dist/tools/getSessionUsage.js +57 -0
  454. package/dist/tools/getSessionUsage.js.map +1 -0
  455. package/dist/tools/getSymbolHistory.d.ts +157 -0
  456. package/dist/tools/getSymbolHistory.js +256 -0
  457. package/dist/tools/getSymbolHistory.js.map +1 -0
  458. package/dist/tools/getToolCapabilities.d.ts +69 -0
  459. package/dist/tools/getToolCapabilities.js +298 -0
  460. package/dist/tools/getToolCapabilities.js.map +1 -0
  461. package/dist/tools/getTypeSignature.d.ts +70 -0
  462. package/dist/tools/getTypeSignature.js +132 -0
  463. package/dist/tools/getTypeSignature.js.map +1 -0
  464. package/dist/tools/getWorkspaceFolders.d.ts +58 -0
  465. package/dist/tools/getWorkspaceFolders.js +69 -0
  466. package/dist/tools/getWorkspaceFolders.js.map +1 -0
  467. package/dist/tools/getWorkspaceSettings.d.ts +44 -0
  468. package/dist/tools/getWorkspaceSettings.js +70 -0
  469. package/dist/tools/getWorkspaceSettings.js.map +1 -0
  470. package/dist/tools/git-utils.d.ts +16 -0
  471. package/dist/tools/git-utils.js +46 -0
  472. package/dist/tools/git-utils.js.map +1 -0
  473. package/dist/tools/gitHistory.d.ts +110 -0
  474. package/dist/tools/gitHistory.js +167 -0
  475. package/dist/tools/gitHistory.js.map +1 -0
  476. package/dist/tools/gitWrite.d.ts +612 -0
  477. package/dist/tools/gitWrite.js +983 -0
  478. package/dist/tools/gitWrite.js.map +1 -0
  479. package/dist/tools/github/actions.d.ts +152 -0
  480. package/dist/tools/github/actions.js +195 -0
  481. package/dist/tools/github/actions.js.map +1 -0
  482. package/dist/tools/github/index.d.ts +3 -0
  483. package/dist/tools/github/index.js +4 -0
  484. package/dist/tools/github/index.js.map +1 -0
  485. package/dist/tools/github/issues.d.ts +281 -0
  486. package/dist/tools/github/issues.js +340 -0
  487. package/dist/tools/github/issues.js.map +1 -0
  488. package/dist/tools/github/pr.d.ts +433 -0
  489. package/dist/tools/github/pr.js +588 -0
  490. package/dist/tools/github/pr.js.map +1 -0
  491. package/dist/tools/github/shared.d.ts +4 -0
  492. package/dist/tools/github/shared.js +12 -0
  493. package/dist/tools/github/shared.js.map +1 -0
  494. package/dist/tools/handoffNote.d.ts +106 -0
  495. package/dist/tools/handoffNote.js +232 -0
  496. package/dist/tools/handoffNote.js.map +1 -0
  497. package/dist/tools/headless/lspClient.d.ts +26 -0
  498. package/dist/tools/headless/lspClient.js +221 -0
  499. package/dist/tools/headless/lspClient.js.map +1 -0
  500. package/dist/tools/headless/lspFallback.d.ts +28 -0
  501. package/dist/tools/headless/lspFallback.js +122 -0
  502. package/dist/tools/headless/lspFallback.js.map +1 -0
  503. package/dist/tools/hoverAtCursor.d.ts +54 -0
  504. package/dist/tools/hoverAtCursor.js +68 -0
  505. package/dist/tools/hoverAtCursor.js.map +1 -0
  506. package/dist/tools/httpClient.d.ts +141 -0
  507. package/dist/tools/httpClient.js +486 -0
  508. package/dist/tools/httpClient.js.map +1 -0
  509. package/dist/tools/index.d.ts +49 -0
  510. package/dist/tools/index.js +672 -0
  511. package/dist/tools/index.js.map +1 -0
  512. package/dist/tools/inlayHints.d.ts +81 -0
  513. package/dist/tools/inlayHints.js +76 -0
  514. package/dist/tools/inlayHints.js.map +1 -0
  515. package/dist/tools/issueRefs.d.ts +14 -0
  516. package/dist/tools/issueRefs.js +27 -0
  517. package/dist/tools/issueRefs.js.map +1 -0
  518. package/dist/tools/jumpToFirstError.d.ts +63 -0
  519. package/dist/tools/jumpToFirstError.js +124 -0
  520. package/dist/tools/jumpToFirstError.js.map +1 -0
  521. package/dist/tools/launchQuickTask.d.ts +76 -0
  522. package/dist/tools/launchQuickTask.js +170 -0
  523. package/dist/tools/launchQuickTask.js.map +1 -0
  524. package/dist/tools/linters/biome.d.ts +2 -0
  525. package/dist/tools/linters/biome.js +44 -0
  526. package/dist/tools/linters/biome.js.map +1 -0
  527. package/dist/tools/linters/cargo.d.ts +2 -0
  528. package/dist/tools/linters/cargo.js +45 -0
  529. package/dist/tools/linters/cargo.js.map +1 -0
  530. package/dist/tools/linters/eslint.d.ts +2 -0
  531. package/dist/tools/linters/eslint.js +59 -0
  532. package/dist/tools/linters/eslint.js.map +1 -0
  533. package/dist/tools/linters/govet.d.ts +2 -0
  534. package/dist/tools/linters/govet.js +37 -0
  535. package/dist/tools/linters/govet.js.map +1 -0
  536. package/dist/tools/linters/pyright.d.ts +2 -0
  537. package/dist/tools/linters/pyright.js +34 -0
  538. package/dist/tools/linters/pyright.js.map +1 -0
  539. package/dist/tools/linters/ruff.d.ts +2 -0
  540. package/dist/tools/linters/ruff.js +30 -0
  541. package/dist/tools/linters/ruff.js.map +1 -0
  542. package/dist/tools/linters/types.d.ts +16 -0
  543. package/dist/tools/linters/types.js +2 -0
  544. package/dist/tools/linters/types.js.map +1 -0
  545. package/dist/tools/linters/typescript.d.ts +2 -0
  546. package/dist/tools/linters/typescript.js +38 -0
  547. package/dist/tools/linters/typescript.js.map +1 -0
  548. package/dist/tools/listClaudeTasks.d.ts +84 -0
  549. package/dist/tools/listClaudeTasks.js +88 -0
  550. package/dist/tools/listClaudeTasks.js.map +1 -0
  551. package/dist/tools/listTerminals.d.ts +55 -0
  552. package/dist/tools/listTerminals.js +78 -0
  553. package/dist/tools/listTerminals.js.map +1 -0
  554. package/dist/tools/lsp.d.ts +1086 -0
  555. package/dist/tools/lsp.js +1339 -0
  556. package/dist/tools/lsp.js.map +1 -0
  557. package/dist/tools/navigateToSymbolByName.d.ts +56 -0
  558. package/dist/tools/navigateToSymbolByName.js +170 -0
  559. package/dist/tools/navigateToSymbolByName.js.map +1 -0
  560. package/dist/tools/openDiff.d.ts +66 -0
  561. package/dist/tools/openDiff.js +126 -0
  562. package/dist/tools/openDiff.js.map +1 -0
  563. package/dist/tools/openFile.d.ts +69 -0
  564. package/dist/tools/openFile.js +129 -0
  565. package/dist/tools/openFile.js.map +1 -0
  566. package/dist/tools/openInBrowser.d.ts +55 -0
  567. package/dist/tools/openInBrowser.js +129 -0
  568. package/dist/tools/openInBrowser.js.map +1 -0
  569. package/dist/tools/organizeImports.d.ts +56 -0
  570. package/dist/tools/organizeImports.js +115 -0
  571. package/dist/tools/organizeImports.js.map +1 -0
  572. package/dist/tools/performanceReport.d.ts +133 -0
  573. package/dist/tools/performanceReport.js +218 -0
  574. package/dist/tools/performanceReport.js.map +1 -0
  575. package/dist/tools/planPersistence.d.ts +306 -0
  576. package/dist/tools/planPersistence.js +485 -0
  577. package/dist/tools/planPersistence.js.map +1 -0
  578. package/dist/tools/previewEdit.d.ts +107 -0
  579. package/dist/tools/previewEdit.js +270 -0
  580. package/dist/tools/previewEdit.js.map +1 -0
  581. package/dist/tools/recentTracesDigest.d.ts +35 -0
  582. package/dist/tools/recentTracesDigest.js +98 -0
  583. package/dist/tools/recentTracesDigest.js.map +1 -0
  584. package/dist/tools/refactorAnalyze.d.ts +78 -0
  585. package/dist/tools/refactorAnalyze.js +141 -0
  586. package/dist/tools/refactorAnalyze.js.map +1 -0
  587. package/dist/tools/refactorExtractFunction.d.ts +52 -0
  588. package/dist/tools/refactorExtractFunction.js +121 -0
  589. package/dist/tools/refactorExtractFunction.js.map +1 -0
  590. package/dist/tools/refactorPreview.d.ts +75 -0
  591. package/dist/tools/refactorPreview.js +93 -0
  592. package/dist/tools/refactorPreview.js.map +1 -0
  593. package/dist/tools/replaceBlock.d.ts +62 -0
  594. package/dist/tools/replaceBlock.js +125 -0
  595. package/dist/tools/replaceBlock.js.map +1 -0
  596. package/dist/tools/resumeClaudeTask.d.ts +75 -0
  597. package/dist/tools/resumeClaudeTask.js +149 -0
  598. package/dist/tools/resumeClaudeTask.js.map +1 -0
  599. package/dist/tools/runClaudeTask.d.ts +97 -0
  600. package/dist/tools/runClaudeTask.js +224 -0
  601. package/dist/tools/runClaudeTask.js.map +1 -0
  602. package/dist/tools/runCommand.d.ts +82 -0
  603. package/dist/tools/runCommand.js +101 -0
  604. package/dist/tools/runCommand.js.map +1 -0
  605. package/dist/tools/runTests.d.ts +146 -0
  606. package/dist/tools/runTests.js +315 -0
  607. package/dist/tools/runTests.js.map +1 -0
  608. package/dist/tools/saveDocument.d.ts +50 -0
  609. package/dist/tools/saveDocument.js +73 -0
  610. package/dist/tools/saveDocument.js.map +1 -0
  611. package/dist/tools/screenshot.d.ts +23 -0
  612. package/dist/tools/screenshot.js +43 -0
  613. package/dist/tools/screenshot.js.map +1 -0
  614. package/dist/tools/screenshotAndAnnotate.d.ts +103 -0
  615. package/dist/tools/screenshotAndAnnotate.js +192 -0
  616. package/dist/tools/screenshotAndAnnotate.js.map +1 -0
  617. package/dist/tools/searchAndReplace.d.ts +108 -0
  618. package/dist/tools/searchAndReplace.js +281 -0
  619. package/dist/tools/searchAndReplace.js.map +1 -0
  620. package/dist/tools/searchTools.d.ts +61 -0
  621. package/dist/tools/searchTools.js +85 -0
  622. package/dist/tools/searchTools.js.map +1 -0
  623. package/dist/tools/searchWorkspace.d.ts +99 -0
  624. package/dist/tools/searchWorkspace.js +189 -0
  625. package/dist/tools/searchWorkspace.js.map +1 -0
  626. package/dist/tools/selectionRanges.d.ts +58 -0
  627. package/dist/tools/selectionRanges.js +61 -0
  628. package/dist/tools/selectionRanges.js.map +1 -0
  629. package/dist/tools/semanticTokens.d.ts +87 -0
  630. package/dist/tools/semanticTokens.js +86 -0
  631. package/dist/tools/semanticTokens.js.map +1 -0
  632. package/dist/tools/setActiveWorkspaceFolder.d.ts +41 -0
  633. package/dist/tools/setActiveWorkspaceFolder.js +38 -0
  634. package/dist/tools/setActiveWorkspaceFolder.js.map +1 -0
  635. package/dist/tools/signatureHelp.d.ts +86 -0
  636. package/dist/tools/signatureHelp.js +79 -0
  637. package/dist/tools/signatureHelp.js.map +1 -0
  638. package/dist/tools/spawnWorkspace.d.ts +103 -0
  639. package/dist/tools/spawnWorkspace.js +268 -0
  640. package/dist/tools/spawnWorkspace.js.map +1 -0
  641. package/dist/tools/stackTraceParser.d.ts +43 -0
  642. package/dist/tools/stackTraceParser.js +139 -0
  643. package/dist/tools/stackTraceParser.js.map +1 -0
  644. package/dist/tools/terminal.d.ts +352 -0
  645. package/dist/tools/terminal.js +670 -0
  646. package/dist/tools/terminal.js.map +1 -0
  647. package/dist/tools/testRunners/cargoTest.d.ts +2 -0
  648. package/dist/tools/testRunners/cargoTest.js +129 -0
  649. package/dist/tools/testRunners/cargoTest.js.map +1 -0
  650. package/dist/tools/testRunners/goTest.d.ts +2 -0
  651. package/dist/tools/testRunners/goTest.js +108 -0
  652. package/dist/tools/testRunners/goTest.js.map +1 -0
  653. package/dist/tools/testRunners/pytest.d.ts +2 -0
  654. package/dist/tools/testRunners/pytest.js +135 -0
  655. package/dist/tools/testRunners/pytest.js.map +1 -0
  656. package/dist/tools/testRunners/types.d.ts +18 -0
  657. package/dist/tools/testRunners/types.js +2 -0
  658. package/dist/tools/testRunners/types.js.map +1 -0
  659. package/dist/tools/testRunners/vitestJest.d.ts +3 -0
  660. package/dist/tools/testRunners/vitestJest.js +215 -0
  661. package/dist/tools/testRunners/vitestJest.js.map +1 -0
  662. package/dist/tools/testTraceToSource.d.ts +80 -0
  663. package/dist/tools/testTraceToSource.js +206 -0
  664. package/dist/tools/testTraceToSource.js.map +1 -0
  665. package/dist/tools/transaction.d.ts +243 -0
  666. package/dist/tools/transaction.js +309 -0
  667. package/dist/tools/transaction.js.map +1 -0
  668. package/dist/tools/typeHierarchy.d.ts +77 -0
  669. package/dist/tools/typeHierarchy.js +86 -0
  670. package/dist/tools/typeHierarchy.js.map +1 -0
  671. package/dist/tools/utils.d.ts +124 -0
  672. package/dist/tools/utils.js +566 -0
  673. package/dist/tools/utils.js.map +1 -0
  674. package/dist/tools/vscodeCommands.d.ts +90 -0
  675. package/dist/tools/vscodeCommands.js +112 -0
  676. package/dist/tools/vscodeCommands.js.map +1 -0
  677. package/dist/tools/vscodeTasks.d.ts +102 -0
  678. package/dist/tools/vscodeTasks.js +110 -0
  679. package/dist/tools/vscodeTasks.js.map +1 -0
  680. package/dist/tools/watchDiagnostics.d.ts +64 -0
  681. package/dist/tools/watchDiagnostics.js +270 -0
  682. package/dist/tools/watchDiagnostics.js.map +1 -0
  683. package/dist/tools/workspaceSettings.d.ts +57 -0
  684. package/dist/tools/workspaceSettings.js +80 -0
  685. package/dist/tools/workspaceSettings.js.map +1 -0
  686. package/dist/transport.d.ts +207 -0
  687. package/dist/transport.js +1272 -0
  688. package/dist/transport.js.map +1 -0
  689. package/dist/version.d.ts +13 -0
  690. package/dist/version.js +31 -0
  691. package/dist/version.js.map +1 -0
  692. package/dist/wsUtils.d.ts +8 -0
  693. package/dist/wsUtils.js +54 -0
  694. package/dist/wsUtils.js.map +1 -0
  695. package/package.json +118 -0
  696. package/scripts/gen-claude-desktop-config.sh +124 -0
  697. package/scripts/gen-mcp-config.sh +390 -0
  698. package/scripts/install-extension.sh +106 -0
  699. package/scripts/mcp-stdio-shim.cjs +482 -0
  700. package/scripts/postinstall.mjs +68 -0
  701. package/scripts/start-all.sh +502 -0
  702. package/scripts/start-orchestrator.sh +186 -0
  703. package/scripts/start-remote.sh +126 -0
  704. package/scripts/start-vps.sh +116 -0
  705. package/templates/CLAUDE.bridge.md +125 -0
  706. package/templates/automation-policies/security-first.json +46 -0
  707. package/templates/automation-policies/strict-lint.json +41 -0
  708. package/templates/automation-policies/test-driven.json +54 -0
  709. package/templates/automation-policy.example.json +105 -0
  710. package/templates/bridge-tools.md +111 -0
  711. package/templates/dispatch-context.md +33 -0
  712. package/templates/managed-agent/code-review-agent.md +50 -0
  713. package/templates/managed-agent/managed-agent-mcp.json +102 -0
  714. package/templates/recipes/ambient-journal.yaml +11 -0
  715. package/templates/recipes/daily-status.yaml +21 -0
  716. package/templates/recipes/lint-on-save.yaml +13 -0
  717. package/templates/recipes/stale-branches.yaml +18 -0
  718. package/templates/recipes/watch-failing-tests.yaml +15 -0
  719. package/templates/scheduled-tasks/dependency-audit/SKILL.md +77 -0
  720. package/templates/scheduled-tasks/health-check/SKILL.md +73 -0
  721. package/templates/scheduled-tasks/nightly-review/SKILL.md +69 -0
@@ -0,0 +1,702 @@
1
+ /**
2
+ * MCP Streamable HTTP transport (spec 2025-03-26).
3
+ *
4
+ * Mounts POST/GET/DELETE on /mcp alongside the existing WebSocket server.
5
+ * This allows the Claude Desktop app "Custom Connectors" UI and claude.ai web
6
+ * to connect to the bridge without the stdio shim.
7
+ *
8
+ * Architecture:
9
+ * - Each HTTP session gets its own McpTransport instance (same as WebSocket sessions).
10
+ * - HttpAdapter mimics the WebSocket interface so McpTransport.attach() works unchanged.
11
+ * - POST /mcp — client→server JSON-RPC (notifications return 202, requests return JSON).
12
+ * - GET /mcp — optional SSE stream for server-initiated notifications.
13
+ * - DELETE /mcp — terminate session.
14
+ */
15
+ import crypto from "node:crypto";
16
+ import { EventEmitter } from "node:events";
17
+ import { WebSocket } from "ws";
18
+ import { getApprovalQueue } from "./approvalQueue.js";
19
+ import { classifyTool } from "./riskTier.js";
20
+ import { corsOrigin } from "./server.js";
21
+ import { registerAllTools } from "./tools/index.js";
22
+ import { McpTransport } from "./transport.js";
23
+ const SESSION_TTL_MS = 2 * 60 * 60 * 1000; // 2 hour idle TTL — reduced from 24h to limit captured-session-ID reuse window
24
+ const SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
25
+ const MAX_HTTP_SESSIONS = 5;
26
+ const BODY_SIZE_LIMIT = 1_048_576; // 1 MB
27
+ const MAX_PENDING_SENDS = 100; // per-session response queue cap
28
+ const SSE_HEARTBEAT_MS = 20_000; // keep SSE streams alive through proxies/firewalls
29
+ const SSE_BUFFER_MAX = 100; // max events retained per session for Last-Event-ID replay
30
+ const SSE_BUFFER_TTL_MS = 30_000; // events older than 30s are not replayed
31
+ /** Mimics the WebSocket interface so McpTransport works unchanged. */
32
+ class HttpAdapter extends EventEmitter {
33
+ warn;
34
+ onSseSend;
35
+ /** WebSocket.OPEN = 1; WebSocket.CLOSED = 3 */
36
+ readyState = WebSocket.OPEN;
37
+ constructor(warn = () => { },
38
+ /** Called when the adapter writes to the SSE stream so the session's
39
+ * lastActivity is refreshed even during long-idle SSE connections. */
40
+ onSseSend = () => { }) {
41
+ super();
42
+ this.warn = warn;
43
+ this.onSseSend = onSseSend;
44
+ }
45
+ /** Always 0 — no send buffer for HTTP (bypasses backpressure drain). */
46
+ bufferedAmount = 0;
47
+ /**
48
+ * Pending POST resolvers keyed by JSON-RPC request `id`.
49
+ * Keying by ID fixes the FIFO ordering race: if two concurrent tool calls arrive
50
+ * on the same HTTP session, each POST waits for *its own* response rather than
51
+ * the first response that arrives.
52
+ *
53
+ * Duplicate-ID guard: if a second POST arrives with the same id while the first
54
+ * is still pending (client bug per JSON-RPC spec), waitForSend() rejects it
55
+ * immediately with a 400 rather than silently overwriting the first waiter.
56
+ */
57
+ pendingSends = new Map();
58
+ sseRes = null;
59
+ sseHeartbeatTimer = null;
60
+ // Monotonic event ID counter and replay buffer for SSE Last-Event-ID resumption.
61
+ eventCounter = 0;
62
+ eventBuffer = [];
63
+ /**
64
+ * Called by safeSend() / McpTransport to deliver a message.
65
+ * Responses (JSON-RPC messages with `id`) go to the matching pending POST resolver.
66
+ * Notifications (no `id` — e.g. progress, list_changed) go to the SSE stream with
67
+ * a monotonic `id:` field and are buffered for Last-Event-ID replay on reconnect.
68
+ */
69
+ send(data, cb) {
70
+ const str = typeof data === "string" ? data : data.toString("utf-8");
71
+ // Parse response `id` to route it to the correct waiting POST handler.
72
+ let responseId = null;
73
+ try {
74
+ const parsed = JSON.parse(str);
75
+ if (parsed.id !== undefined && parsed.id !== null) {
76
+ responseId = parsed.id;
77
+ }
78
+ }
79
+ catch {
80
+ // Unparseable — treat as notification
81
+ }
82
+ if (responseId !== null) {
83
+ // Response path: deliver to the waiting POST handler.
84
+ const resolve = this.pendingSends.get(responseId);
85
+ if (resolve) {
86
+ this.pendingSends.delete(responseId);
87
+ resolve(str);
88
+ cb?.();
89
+ return;
90
+ }
91
+ // Orphaned response (waiter timed out): try SSE as fallback.
92
+ if (this.sseRes && !this.sseRes.writableEnded) {
93
+ this.sseRes.write(`data: ${str}\n\n`);
94
+ this.onSseSend();
95
+ cb?.();
96
+ return;
97
+ }
98
+ this.warn(`HTTP: dropped response id=${responseId} — no pending waiter or active SSE stream`);
99
+ cb?.();
100
+ return;
101
+ }
102
+ // Notification path: assign monotonic event ID, buffer for replay, send to SSE.
103
+ const eventId = this.eventCounter++;
104
+ this.bufferEvent(eventId, str);
105
+ if (this.sseRes && !this.sseRes.writableEnded) {
106
+ this.sseRes.write(`id: ${eventId}\ndata: ${str}\n\n`);
107
+ this.onSseSend(); // refresh lastActivity so idle pruner doesn't kill open SSE connections
108
+ }
109
+ // If no SSE stream: buffered above for replay when the client reconnects.
110
+ cb?.();
111
+ }
112
+ /** Buffer a notification event, pruning expired entries and capping at MAX. */
113
+ bufferEvent(id, data) {
114
+ const now = Date.now();
115
+ // Prune expired events from the front (buffer is append-only so oldest are first).
116
+ let i = 0;
117
+ while (i < this.eventBuffer.length &&
118
+ now - (this.eventBuffer[i]?.ts ?? 0) > SSE_BUFFER_TTL_MS) {
119
+ i++;
120
+ }
121
+ if (i > 0)
122
+ this.eventBuffer.splice(0, i);
123
+ // Cap BEFORE pushing so the buffer never transiently exceeds SSE_BUFFER_MAX.
124
+ if (this.eventBuffer.length >= SSE_BUFFER_MAX) {
125
+ this.eventBuffer.shift(); // drop oldest to make room
126
+ }
127
+ this.eventBuffer.push({ id, data, ts: now });
128
+ }
129
+ /**
130
+ * Returns buffered events with id > lastId whose timestamps are within the TTL.
131
+ * Called by handleGet to replay missed notifications on SSE reconnect.
132
+ */
133
+ getEventsAfter(lastId) {
134
+ const now = Date.now();
135
+ return this.eventBuffer
136
+ .filter((e) => e.id > lastId && now - e.ts <= SSE_BUFFER_TTL_MS)
137
+ .map((e) => ({ id: e.id, data: e.data }));
138
+ }
139
+ /** Attach (or detach, when null) a GET /mcp SSE response for server-initiated notifications. */
140
+ attachSSE(res) {
141
+ if (this.sseHeartbeatTimer) {
142
+ clearInterval(this.sseHeartbeatTimer);
143
+ this.sseHeartbeatTimer = null;
144
+ }
145
+ this.sseRes = res;
146
+ if (res) {
147
+ const timer = setInterval(() => {
148
+ if (res.writableEnded) {
149
+ clearInterval(timer);
150
+ this.sseHeartbeatTimer = null;
151
+ }
152
+ else {
153
+ try {
154
+ res.write(": heartbeat\n\n");
155
+ }
156
+ catch {
157
+ // Client disconnected between the writableEnded check and the write
158
+ // (TOCTOU). Swallow the error — the req "close" listener will call
159
+ // attachSSE(null) which clears this timer on its next tick.
160
+ }
161
+ }
162
+ }, SSE_HEARTBEAT_MS);
163
+ this.sseHeartbeatTimer = timer;
164
+ timer.unref();
165
+ }
166
+ }
167
+ /** Returns a promise that resolves with the response for the given request ID.
168
+ * Rejects if the session is closed or the timeout fires. */
169
+ waitForSend(requestId, timeoutMs = 90_000) {
170
+ return new Promise((resolve, reject) => {
171
+ if (this.pendingSends.size >= MAX_PENDING_SENDS) {
172
+ reject(new Error("HTTP session send queue full"));
173
+ return;
174
+ }
175
+ // Reject duplicate in-flight IDs — reusing the same id while a request
176
+ // is pending is a client-side JSON-RPC spec violation.
177
+ if (this.pendingSends.has(requestId)) {
178
+ reject(new Error(`Duplicate request id=${requestId} — already in flight`));
179
+ return;
180
+ }
181
+ const timer = setTimeout(() => {
182
+ this.pendingSends.delete(requestId);
183
+ reject(new Error("HTTP session send timeout"));
184
+ }, timeoutMs);
185
+ this.pendingSends.set(requestId, (data) => {
186
+ clearTimeout(timer);
187
+ if (data === null) {
188
+ reject(new Error("Session closed"));
189
+ }
190
+ else {
191
+ resolve(data);
192
+ }
193
+ });
194
+ });
195
+ }
196
+ /** Feed an incoming POST body to the McpTransport's message listener. */
197
+ receive(data) {
198
+ this.emit("message", Buffer.from(data, "utf-8"));
199
+ }
200
+ /** Closes the adapter and any attached SSE stream. */
201
+ close() {
202
+ this.readyState = WebSocket.CLOSED;
203
+ if (this.sseHeartbeatTimer) {
204
+ clearInterval(this.sseHeartbeatTimer);
205
+ this.sseHeartbeatTimer = null;
206
+ }
207
+ if (this.sseRes && !this.sseRes.writableEnded) {
208
+ this.sseRes.end();
209
+ }
210
+ this.sseRes = null;
211
+ // Reject any pending sends so callers get a 504, not a 200 with error body
212
+ for (const resolve of this.pendingSends.values()) {
213
+ resolve(null);
214
+ }
215
+ this.pendingSends.clear();
216
+ }
217
+ }
218
+ /** Handles POST/GET/DELETE /mcp for all HTTP sessions. */
219
+ export class StreamableHttpHandler {
220
+ config;
221
+ probes;
222
+ extensionClient;
223
+ activityLog;
224
+ fileLock;
225
+ allSessions;
226
+ orchestrator;
227
+ logger;
228
+ getPluginTools;
229
+ getPluginWatcher;
230
+ resolveScopeFn;
231
+ instructionsProvider;
232
+ sessions = new Map();
233
+ cleanupTimer;
234
+ /**
235
+ * Shared token-bucket for all HTTP sessions.
236
+ * Prevents rate-limit bypass via session cycling: a client that repeatedly
237
+ * creates new sessions would otherwise get a fresh full bucket each time.
238
+ * Initialised lazily on first session creation using the configured limit.
239
+ */
240
+ sharedHttpRateLimitBucket = null;
241
+ constructor(config, probes, extensionClient, activityLog, fileLock, allSessions, // bridge sessions — for capacity guard
242
+ orchestrator, logger, getPluginTools = () => [], getPluginWatcher = () => null,
243
+ /** Optional: resolves the OAuth scope string for a bearer token, or null for full access. */
244
+ resolveScopeFn = null,
245
+ /**
246
+ * Optional: provider for the instructions string injected into the
247
+ * MCP initialize response. Called per session so digests stay fresh
248
+ * across sessions without restarting the bridge.
249
+ */
250
+ instructionsProvider = null) {
251
+ this.config = config;
252
+ this.probes = probes;
253
+ this.extensionClient = extensionClient;
254
+ this.activityLog = activityLog;
255
+ this.fileLock = fileLock;
256
+ this.allSessions = allSessions;
257
+ this.orchestrator = orchestrator;
258
+ this.logger = logger;
259
+ this.getPluginTools = getPluginTools;
260
+ this.getPluginWatcher = getPluginWatcher;
261
+ this.resolveScopeFn = resolveScopeFn;
262
+ this.instructionsProvider = instructionsProvider;
263
+ // Prune idle sessions every 2 minutes.
264
+ // .unref() prevents this timer from keeping the Node process alive when
265
+ // all other work is done — avoids test hangs and clean process exit.
266
+ this.cleanupTimer = setInterval(() => this.pruneIdle(), 2 * 60 * 1000).unref();
267
+ }
268
+ /** Handle an incoming HTTP request to /mcp */
269
+ async handle(req, res) {
270
+ const origin = corsOrigin(req.headers.origin, this.config.corsOrigins);
271
+ if (origin) {
272
+ res.setHeader("Access-Control-Allow-Origin", origin);
273
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
274
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Mcp-Session-Id");
275
+ res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
276
+ }
277
+ // OPTIONS is handled by server.ts before auth — this handler only sees POST/GET/DELETE.
278
+ if (req.method === "POST") {
279
+ await this.handlePost(req, res);
280
+ }
281
+ else if (req.method === "GET") {
282
+ this.handleGet(req, res);
283
+ }
284
+ else if (req.method === "DELETE") {
285
+ this.handleDelete(req, res);
286
+ }
287
+ else {
288
+ res.writeHead(405, { "Content-Type": "text/plain" });
289
+ res.end("Method Not Allowed");
290
+ }
291
+ }
292
+ async handlePost(req, res) {
293
+ // Read body with size limit
294
+ let body;
295
+ try {
296
+ body = await readBody(req, BODY_SIZE_LIMIT);
297
+ }
298
+ catch {
299
+ res.writeHead(413, { "Content-Type": "application/json" });
300
+ res.end(JSON.stringify({ error: "Request body too large" }));
301
+ return;
302
+ }
303
+ // Parse JSON-RPC
304
+ let msg;
305
+ try {
306
+ const parsed = JSON.parse(body);
307
+ // Batch requests (arrays) are not supported — reject early with a clear error
308
+ // rather than letting the request silently fall through as a notification.
309
+ if (Array.isArray(parsed)) {
310
+ res.writeHead(400, { "Content-Type": "application/json" });
311
+ res.end(JSON.stringify({
312
+ jsonrpc: "2.0",
313
+ id: null,
314
+ error: {
315
+ code: -32600,
316
+ message: "Batch requests are not supported",
317
+ },
318
+ }));
319
+ return;
320
+ }
321
+ msg = parsed;
322
+ }
323
+ catch {
324
+ res.writeHead(400, { "Content-Type": "application/json" });
325
+ res.end(JSON.stringify({
326
+ jsonrpc: "2.0",
327
+ id: null,
328
+ error: { code: -32700, message: "Parse error" },
329
+ }));
330
+ return;
331
+ }
332
+ // Resolve session
333
+ const sessionId = req.headers["mcp-session-id"];
334
+ let session = null;
335
+ let sessionIsNew = false;
336
+ if (msg.method === "initialize") {
337
+ // Capacity guard — try to evict the oldest idle session before rejecting.
338
+ // If a client crashed without sending DELETE, its session lingers until
339
+ // the TTL prune fires. Eviction here gives new connections a seat without
340
+ // waiting up to 10 minutes for the idle sweep.
341
+ if (this.sessions.size >= MAX_HTTP_SESSIONS) {
342
+ if (!this.evictOldestIdleSession()) {
343
+ res.writeHead(503, { "Content-Type": "application/json" });
344
+ res.end(JSON.stringify({
345
+ jsonrpc: "2.0",
346
+ id: msg.id ?? null,
347
+ error: { code: -32000, message: "HTTP session capacity reached" },
348
+ }));
349
+ return;
350
+ }
351
+ }
352
+ // Resolve OAuth scope from bearer token (if a resolver is configured)
353
+ let sessionScope = null;
354
+ if (this.resolveScopeFn) {
355
+ const authHeader = req.headers.authorization ?? "";
356
+ const bearer = authHeader.startsWith("Bearer ")
357
+ ? authHeader.slice(7)
358
+ : "";
359
+ if (bearer)
360
+ sessionScope = this.resolveScopeFn(bearer);
361
+ }
362
+ // Parse X-Bridge-Deny-Tools header: comma-separated tool names to block for this session.
363
+ const denyHeader = req.headers["x-bridge-deny-tools"];
364
+ const denyTools = new Set();
365
+ if (typeof denyHeader === "string" && denyHeader.trim().length > 0) {
366
+ const TOOL_NAME_RE = /^[a-zA-Z0-9_]+$/;
367
+ for (const name of denyHeader.split(",")) {
368
+ const trimmed = name.trim();
369
+ if (TOOL_NAME_RE.test(trimmed)) {
370
+ denyTools.add(trimmed);
371
+ }
372
+ else if (trimmed.length > 0) {
373
+ this.logger.warn(`[http] ignoring invalid X-Bridge-Deny-Tools entry: "${trimmed}"`);
374
+ }
375
+ }
376
+ }
377
+ session = await this.createSession(sessionScope, denyTools);
378
+ sessionIsNew = true;
379
+ const ccSessionId = req.headers["x-claude-code-session-id"];
380
+ if (typeof ccSessionId === "string" && SESSION_ID_RE.test(ccSessionId)) {
381
+ session.claudeCodeSessionId = ccSessionId;
382
+ session.transport.claudeCodeSessionId = ccSessionId;
383
+ }
384
+ res.setHeader("Mcp-Session-Id", session.id);
385
+ }
386
+ else {
387
+ if (typeof sessionId !== "string") {
388
+ res.writeHead(400, { "Content-Type": "application/json" });
389
+ res.end(JSON.stringify({
390
+ jsonrpc: "2.0",
391
+ id: msg.id ?? null,
392
+ error: { code: -32000, message: "Missing Mcp-Session-Id header" },
393
+ }));
394
+ return;
395
+ }
396
+ session = this.sessions.get(sessionId) ?? null;
397
+ if (!session) {
398
+ res.writeHead(404, { "Content-Type": "application/json" });
399
+ res.end(JSON.stringify({
400
+ jsonrpc: "2.0",
401
+ id: msg.id ?? null,
402
+ error: {
403
+ code: -32000,
404
+ message: "Session not found or expired — re-initialize",
405
+ },
406
+ }));
407
+ return;
408
+ }
409
+ }
410
+ session.lastActivity = Date.now();
411
+ // Notifications have no `id` field at all per JSON-RPC 2.0.
412
+ // id:null is technically a malformed request but treat it as a notification
413
+ // to prevent two null-id requests from colliding in the pendingSends Map.
414
+ const isNotification = !Object.hasOwn(msg, "id") || msg.id === null;
415
+ if (isNotification) {
416
+ session.adapter.receive(body);
417
+ res.writeHead(202);
418
+ res.end();
419
+ return;
420
+ }
421
+ // Request → feed to adapter, wait for transport's response keyed by request ID
422
+ const requestId = msg.id ?? 0;
423
+ let responsePromise;
424
+ try {
425
+ responsePromise = session.adapter.waitForSend(requestId);
426
+ }
427
+ catch (err) {
428
+ // Duplicate in-flight id — reject before feeding to transport so the
429
+ // transport never sees a second message with the same id.
430
+ res.writeHead(400, { "Content-Type": "application/json" });
431
+ res.end(JSON.stringify({
432
+ jsonrpc: "2.0",
433
+ id: msg.id ?? null,
434
+ error: {
435
+ code: -32600,
436
+ message: err instanceof Error ? err.message : "Invalid request",
437
+ },
438
+ }));
439
+ return;
440
+ }
441
+ session.inFlight++;
442
+ session.adapter.receive(body);
443
+ let responseData;
444
+ try {
445
+ responseData = await responsePromise;
446
+ }
447
+ catch {
448
+ // Destroy newly-created sessions that timed out and strip the session ID
449
+ // header so the client doesn't attempt to reuse a session that no longer
450
+ // exists (setHeader is in-memory until writeHead; removeHeader undoes it).
451
+ if (sessionIsNew) {
452
+ this.destroySession(session.id);
453
+ res.removeHeader("Mcp-Session-Id");
454
+ }
455
+ session.inFlight = Math.max(0, session.inFlight - 1);
456
+ res.writeHead(504, { "Content-Type": "application/json" });
457
+ res.end(JSON.stringify({
458
+ jsonrpc: "2.0",
459
+ id: msg.id ?? null,
460
+ error: { code: -32000, message: "Response timeout" },
461
+ }));
462
+ return;
463
+ }
464
+ session.inFlight = Math.max(0, session.inFlight - 1);
465
+ res.writeHead(200, { "Content-Type": "application/json" });
466
+ res.end(responseData);
467
+ }
468
+ handleGet(req, res) {
469
+ const sessionId = req.headers["mcp-session-id"];
470
+ if (typeof sessionId !== "string") {
471
+ res.writeHead(400, { "Content-Type": "text/plain" });
472
+ res.end("Missing Mcp-Session-Id header");
473
+ return;
474
+ }
475
+ const session = this.sessions.get(sessionId);
476
+ if (!session) {
477
+ res.writeHead(404, { "Content-Type": "text/plain" });
478
+ res.end("Session not found");
479
+ return;
480
+ }
481
+ // Establish SSE stream for server→client notifications.
482
+ // Disable the per-request timeout for this long-lived stream only.
483
+ res.socket?.setTimeout(0);
484
+ res.writeHead(200, {
485
+ "Content-Type": "text/event-stream",
486
+ "Cache-Control": "no-cache",
487
+ Connection: "keep-alive",
488
+ "X-Accel-Buffering": "no", // prevent nginx from buffering SSE heartbeats
489
+ });
490
+ res.write(": connected\n\n"); // SSE comment to flush headers
491
+ // Replay missed events if the client supplies a Last-Event-ID header.
492
+ // This satisfies the MCP spec's stream recovery mechanism for dropped connections.
493
+ const lastEventIdHeader = req.headers["last-event-id"];
494
+ if (typeof lastEventIdHeader === "string") {
495
+ const lastId = Number.parseInt(lastEventIdHeader, 10);
496
+ if (!Number.isNaN(lastId)) {
497
+ for (const event of session.adapter.getEventsAfter(lastId)) {
498
+ res.write(`id: ${event.id}\ndata: ${event.data}\n\n`);
499
+ }
500
+ }
501
+ }
502
+ session.adapter.attachSSE(res);
503
+ session.lastActivity = Date.now();
504
+ req.on("close", () => {
505
+ session.adapter.attachSSE(null); // detach SSE stream on client disconnect
506
+ });
507
+ }
508
+ handleDelete(req, res) {
509
+ const sessionId = req.headers["mcp-session-id"];
510
+ if (typeof sessionId !== "string") {
511
+ res.writeHead(400, { "Content-Type": "text/plain" });
512
+ res.end("Missing Mcp-Session-Id header");
513
+ return;
514
+ }
515
+ if (!this.sessions.has(sessionId)) {
516
+ res.writeHead(404, { "Content-Type": "text/plain" });
517
+ res.end("Session not found");
518
+ return;
519
+ }
520
+ const session = this.sessions.get(sessionId);
521
+ if (session && session.inFlight > 0) {
522
+ res.writeHead(409, { "Content-Type": "application/json" });
523
+ res.end(JSON.stringify({ error: "request in progress" }));
524
+ return;
525
+ }
526
+ this.destroySession(sessionId);
527
+ res.writeHead(204);
528
+ res.end();
529
+ }
530
+ async createSession(scope = null, denyTools = new Set()) {
531
+ const id = crypto.randomUUID();
532
+ const session = {
533
+ id,
534
+ adapter: null,
535
+ transport: null,
536
+ openedFiles: new Set(),
537
+ terminalPrefix: `http-${id.slice(0, 8)}`,
538
+ lastActivity: Date.now(),
539
+ inFlight: 0,
540
+ claudeCodeSessionId: null,
541
+ };
542
+ const adapter = new HttpAdapter((msg) => this.logger.warn(msg), () => {
543
+ session.lastActivity = Date.now();
544
+ });
545
+ const transport = new McpTransport(this.logger);
546
+ transport.workspace = this.config.workspace;
547
+ transport.sessionId = id;
548
+ transport.onActivity = () => {
549
+ session.lastActivity = Date.now();
550
+ };
551
+ transport.setActivityLog(this.activityLog);
552
+ transport.setToolRateLimit(this.config.toolRateLimit);
553
+ // Share one rate-limit bucket across all HTTP sessions to prevent bypass via cycling.
554
+ if (this.config.toolRateLimit > 0) {
555
+ if (!this.sharedHttpRateLimitBucket) {
556
+ this.sharedHttpRateLimitBucket = {
557
+ tokens: this.config.toolRateLimit,
558
+ lastRefill: Date.now(),
559
+ };
560
+ }
561
+ transport.setSharedToolRateLimitBucket(this.sharedHttpRateLimitBucket);
562
+ }
563
+ transport.setExtensionConnectedFn(() => this.extensionClient.isConnected());
564
+ if (this.instructionsProvider !== null) {
565
+ transport.setInstructions(await this.instructionsProvider());
566
+ }
567
+ if (scope)
568
+ transport.setSessionScope(scope);
569
+ if (denyTools.size > 0)
570
+ transport.setDenyTools(denyTools);
571
+ if (this.config.approvalGate !== "off") {
572
+ const gateAll = this.config.approvalGate === "all";
573
+ transport.setApprovalGate(async ({ toolName, params, sessionId }) => {
574
+ const tier = classifyTool(toolName);
575
+ if (!gateAll && tier !== "high")
576
+ return "bypass";
577
+ const queue = getApprovalQueue();
578
+ const { promise } = queue.request({
579
+ toolName,
580
+ params,
581
+ tier,
582
+ sessionId: sessionId ?? undefined,
583
+ riskSignals: [],
584
+ });
585
+ return promise;
586
+ });
587
+ }
588
+ const terminalPrefix = `h${id.slice(0, 8)}-`; // "h" prefix distinguishes HTTP sessions
589
+ // Populate the early session stub so onSseSend callback can reference it.
590
+ session.adapter = adapter;
591
+ session.transport = transport;
592
+ session.terminalPrefix = terminalPrefix;
593
+ // Join the plugin watcher BEFORE registerAllTools so that if a reload fires
594
+ // between the two, this transport is already tracked and will receive fresh tools.
595
+ this.getPluginWatcher()?.addTransport(transport);
596
+ const pluginTools = this.getPluginTools();
597
+ registerAllTools(transport, this.config, session.openedFiles, this.probes, this.extensionClient, this.activityLog, terminalPrefix, this.fileLock, this.allSessions, this.orchestrator, id, pluginTools);
598
+ transport.attach(adapter);
599
+ this.sessions.set(id, session);
600
+ this.logger.info(`HTTP session created (${id.slice(0, 8)}) — ${this.sessions.size} HTTP sessions`);
601
+ return session;
602
+ }
603
+ destroySession(id) {
604
+ const session = this.sessions.get(id);
605
+ if (!session)
606
+ return;
607
+ // Abort in-flight tool calls before closing the response channel so handlers
608
+ // receive their cancellation signal while they can still observe it.
609
+ this.getPluginWatcher()?.removeTransport(session.transport);
610
+ session.transport.detach();
611
+ session.adapter.close();
612
+ this.sessions.delete(id);
613
+ this.logger.info(`HTTP session closed (${id.slice(0, 8)}) — ${this.sessions.size} HTTP sessions`);
614
+ }
615
+ pruneIdle() {
616
+ const now = Date.now();
617
+ for (const [id, session] of this.sessions) {
618
+ if (now - session.lastActivity > SESSION_TTL_MS) {
619
+ this.logger.info(`Pruning idle HTTP session ${id.slice(0, 8)}`);
620
+ this.destroySession(id);
621
+ }
622
+ }
623
+ }
624
+ /**
625
+ * Evict the oldest idle HTTP session to make room for a new connection.
626
+ * Only evicts if the oldest session has been idle for more than 60 seconds,
627
+ * which indicates the client is gone (crashed, network dropped, no DELETE sent).
628
+ * Returns true if a slot was freed, false if all sessions are actively in use.
629
+ */
630
+ evictOldestIdleSession() {
631
+ const IDLE_THRESHOLD_MS = 60_000;
632
+ const now = Date.now();
633
+ let oldestId = null;
634
+ let oldestActivity = now;
635
+ for (const [id, session] of this.sessions) {
636
+ if (session.inFlight > 0)
637
+ continue; // skip sessions with in-flight tool calls
638
+ if (session.lastActivity < oldestActivity) {
639
+ oldestActivity = session.lastActivity;
640
+ oldestId = id;
641
+ }
642
+ }
643
+ if (oldestId && now - oldestActivity > IDLE_THRESHOLD_MS) {
644
+ this.logger.warn(`Evicting idle HTTP session ${oldestId.slice(0, 8)} (idle ${Math.round((now - oldestActivity) / 1000)}s) to make room`);
645
+ this.destroySession(oldestId);
646
+ return true;
647
+ }
648
+ return false;
649
+ }
650
+ /**
651
+ * Broadcast notifications/tools/list_changed to all HTTP sessions that have
652
+ * an open SSE stream. Called by bridge.ts sendListChanged() so HTTP clients
653
+ * learn about plugin reloads alongside WebSocket clients.
654
+ */
655
+ broadcastListChanged() {
656
+ for (const session of this.sessions.values()) {
657
+ if (session.adapter.readyState === WebSocket.OPEN) {
658
+ McpTransport.sendNotification(session.adapter, "notifications/tools/list_changed", undefined, this.logger);
659
+ }
660
+ }
661
+ }
662
+ /** Call on bridge shutdown to clean up all sessions and the prune timer. */
663
+ close() {
664
+ clearInterval(this.cleanupTimer);
665
+ for (const id of [...this.sessions.keys()]) {
666
+ this.destroySession(id);
667
+ }
668
+ }
669
+ }
670
+ /** Read the full request body, enforcing a size limit. */
671
+ function readBody(req, limit) {
672
+ return new Promise((resolve, reject) => {
673
+ const chunks = [];
674
+ let size = 0;
675
+ let settled = false;
676
+ req.on("data", (chunk) => {
677
+ size += chunk.length;
678
+ if (size > limit) {
679
+ req.destroy();
680
+ if (!settled) {
681
+ settled = true;
682
+ reject(new Error("Body too large"));
683
+ }
684
+ return;
685
+ }
686
+ chunks.push(chunk);
687
+ });
688
+ req.on("end", () => {
689
+ if (!settled) {
690
+ settled = true;
691
+ resolve(Buffer.concat(chunks).toString("utf-8"));
692
+ }
693
+ });
694
+ req.on("error", (err) => {
695
+ if (!settled) {
696
+ settled = true;
697
+ reject(err);
698
+ }
699
+ });
700
+ });
701
+ }
702
+ //# sourceMappingURL=streamableHttp.js.map