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,502 @@
1
+ #!/usr/bin/env bash
2
+ # Full orchestrator for bridge + claude + remote-control.
3
+ # Manages all three in tmux panes with health monitoring.
4
+ #
5
+ # Pane layout:
6
+ # 0 — health monitor (orchestrator)
7
+ # 1 — bridge (claude-ide-bridge MCP server)
8
+ # 2 — claude --ide (Claude Code CLI, connects to bridge for IDE tools)
9
+ # 3 — claude remote-control --spawn=session (exposes the workspace to claude.ai;
10
+ # spawned sessions auto-discover the bridge via ~/.claude/ide/*.lock)
11
+ # 4 — SSH reverse tunnel to VPS (optional, enabled with --vps <user@host:port>)
12
+ # Forwards VPS_PORT on the remote host back to the local bridge port.
13
+ # Allows claude.ai integrations to use a static VPS URL instead of a
14
+ # rotating remote-control session URL.
15
+ #
16
+ # Usage:
17
+ # ./scripts/start-all.sh [--workspace <path>] [--notify <ntfy-topic>] [--vps <user@host:port>] [--full]
18
+ # npm run start-all -- --workspace /path/to/project
19
+ #
20
+ # Options:
21
+ # --workspace <path> Directory to open in Claude (default: current directory)
22
+ # --full Register all ~95 bridge tools (git, terminal, file ops, HTTP, GitHub).
23
+ # Default is slim mode (27 IDE-exclusive tools). Add --full if your
24
+ # workflow requires git/terminal/file tools.
25
+ # --notify <topic> Push notifications via ntfy.sh when remote-control connects or
26
+ # the bridge restarts. Free, no account needed — pick any topic
27
+ # name and subscribe at ntfy.sh/<topic> or in the ntfy mobile app.
28
+ # Example: --notify my-claude-alerts
29
+ # The session URL is pushed automatically on each (re)connect,
30
+ # so Dispatch always has the current link without manual copy/paste.
31
+ # --vps <user@host> SSH reverse tunnel: forward a VPS port back to the local bridge,
32
+ # enabling a stable public URL for claude.ai integrations.
33
+ #
34
+ # Controls:
35
+ # Ctrl+C in any pane — stops that process only
36
+ # Ctrl+B then D (press Ctrl+B, release, then press D) — detach (everything keeps running)
37
+ # tmux kill-session -t claude-all — stop everything
38
+
39
+ set -uo pipefail
40
+
41
+ trap 'echo "[orchestrator] Caught signal, stopping all panes..."; tmux kill-session -t "${SESSION:-claude-all}" 2>/dev/null; exit 0' SIGINT SIGTERM
42
+
43
+ SESSION="claude-all"
44
+ SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
45
+ BRIDGE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
46
+ WORKSPACE="."
47
+ NTFY_TOPIC=""
48
+ IDE_NAME=""
49
+ VPS=""
50
+ FULL_MODE=""
51
+ AUTOMATION_POLICY=""
52
+ CLAUDE_DRIVER="subprocess"
53
+ BRIDGE_READY_TIMEOUT="${BRIDGE_READY_TIMEOUT:-30}"
54
+ LAST_CLAUDE_RESTART=0
55
+ RESTART_COUNT=0
56
+ RESTART_DELAY=5
57
+ LAST_START_TIME=0
58
+
59
+ # --- Parse args ---
60
+ while [[ $# -gt 0 ]]; do
61
+ case "$1" in
62
+ --workspace) WORKSPACE="$2"; shift 2 ;;
63
+ --notify) NTFY_TOPIC="$2"; shift 2 ;;
64
+ --ide) IDE_NAME="$2"; shift 2 ;;
65
+ --vps) VPS="$2"; shift 2 ;;
66
+ --full) FULL_MODE="--full"; shift ;;
67
+ --automation-policy) AUTOMATION_POLICY="$2"; shift 2 ;;
68
+ --claude-driver) CLAUDE_DRIVER="$2"; shift 2 ;;
69
+ *) echo "Unknown option: $1" >&2; exit 1 ;;
70
+ esac
71
+ done
72
+ WORKSPACE="$(cd "$WORKSPACE" && pwd)" || { echo "Error: workspace directory not found" >&2; exit 1; }
73
+ if [ ! -d "$WORKSPACE" ]; then
74
+ echo "Error: workspace directory does not exist: $WORKSPACE" >&2
75
+ exit 1
76
+ fi
77
+
78
+ # Validate automation policy path if provided
79
+ if [[ -n "$AUTOMATION_POLICY" ]]; then
80
+ AUTOMATION_POLICY="$(cd "$(dirname "$AUTOMATION_POLICY")" && pwd)/$(basename "$AUTOMATION_POLICY")" || {
81
+ echo "Error: automation-policy directory not found: $AUTOMATION_POLICY" >&2; exit 1
82
+ }
83
+ [[ -f "$AUTOMATION_POLICY" ]] || {
84
+ echo "Error: automation-policy file not found: $AUTOMATION_POLICY" >&2; exit 1
85
+ }
86
+ if ! python3 -c "import json,sys; json.load(open(sys.argv[1]))" "$AUTOMATION_POLICY" 2>/dev/null; then
87
+ echo "Error: automation-policy is not valid JSON: $AUTOMATION_POLICY" >&2; exit 1
88
+ fi
89
+ fi
90
+
91
+ # --- Bridge conflict check ---
92
+ # Detect an already-running bridge instance and abort early with a clear message.
93
+ # Iterates lock files safely (no xargs injection); filters to isBridge:true + live PID.
94
+ while IFS= read -r lock; do
95
+ [[ -f "$lock" ]] || continue
96
+ bridge_pid=$(python3 -c "
97
+ import json, sys
98
+ try:
99
+ d = json.load(open(sys.argv[1]))
100
+ if d.get('isBridge') is True:
101
+ print(d.get('pid', ''))
102
+ except Exception:
103
+ pass
104
+ " "$lock" 2>/dev/null || true)
105
+ if [[ -n "$bridge_pid" ]] && kill -0 "$bridge_pid" 2>/dev/null; then
106
+ echo "Error: bridge already running (PID $bridge_pid, lock: $(basename "$lock"))." >&2
107
+ echo " Stop it first: kill $bridge_pid" >&2
108
+ echo " Or kill the tmux session: tmux kill-session -t claude-all" >&2
109
+ exit 1
110
+ fi
111
+ done < <(ls ~/.claude/ide/*.lock 2>/dev/null)
112
+
113
+ # --- Dependency checks ---
114
+ command -v tmux >/dev/null 2>&1 || {
115
+ echo "Error: tmux is required. Install with: brew install tmux" >&2
116
+ exit 1
117
+ }
118
+ command -v claude >/dev/null 2>&1 || {
119
+ echo "Error: claude CLI not found on PATH." >&2
120
+ exit 1
121
+ }
122
+ command -v node >/dev/null 2>&1 || {
123
+ echo "Error: node is required." >&2
124
+ exit 1
125
+ }
126
+
127
+ # --- tmux session management ---
128
+ if [[ -z "${TMUX:-}" ]]; then
129
+ if tmux has-session -t "$SESSION" 2>/dev/null; then
130
+ echo "Session '$SESSION' already running. Attaching..."
131
+ exec tmux attach -t "$SESSION"
132
+ fi
133
+ # Create session detached, re-run this script inside it, then attach
134
+ tmux new-session -d -s "$SESSION" -x 200 -y 50
135
+ tmux send-keys -t "$SESSION" "\"$SCRIPT_PATH\" --workspace \"$WORKSPACE\"$([ -n "$NTFY_TOPIC" ] && echo " --notify \"$NTFY_TOPIC\"")$([ -n "$IDE_NAME" ] && echo " --ide \"$IDE_NAME\"")$([ -n "$VPS" ] && echo " --vps \"$VPS\"")$([ -n "$FULL_MODE" ] && echo " --full")" Enter
136
+ exec tmux attach -t "$SESSION"
137
+ fi
138
+
139
+ # --- We're inside tmux now (running in pane 0) ---
140
+ echo "=== Claude IDE Bridge Full Orchestrator ==="
141
+ echo " Ctrl+C in any pane — stops that process"
142
+ echo " Ctrl+B then D (press Ctrl+B, release, then press D) — detach (keeps running)"
143
+ echo " tmux kill-session -t $SESSION — stop everything"
144
+ [[ -n "$NTFY_TOPIC" ]] && echo " Push notifications: ntfy.sh/$NTFY_TOPIC"
145
+ if [[ -z "$FULL_MODE" ]]; then
146
+ echo ""
147
+ echo " ⚠ Slim mode: 27 IDE tools (LSP, debugger, editor state)."
148
+ echo " Git, terminal, file ops, HTTP, GitHub NOT registered."
149
+ echo " Add --full to restore all ~95 tools."
150
+ fi
151
+ if [[ -n "$AUTOMATION_POLICY" ]]; then
152
+ echo ""
153
+ echo " ⚡ Automation: enabled (driver: $CLAUDE_DRIVER)"
154
+ echo " Policy: $AUTOMATION_POLICY"
155
+ fi
156
+ echo ""
157
+
158
+ # Detect caffeinate (macOS-only)
159
+ caffeinate_cmd=""
160
+ command -v caffeinate >/dev/null 2>&1 && caffeinate_cmd="caffeinate -i"
161
+
162
+ # --- Notification helper (with 60s cooldown for non-critical notifications) ---
163
+ LAST_NOTIFY_TIME=0
164
+ NOTIFY_COOLDOWN=60
165
+
166
+ notify() {
167
+ local msg="$1"
168
+ local priority="${2:-default}"
169
+ echo "[$(date '+%H:%M:%S')] $msg"
170
+ if [[ -n "$NTFY_TOPIC" ]]; then
171
+ local now
172
+ now=$(date +%s)
173
+ # Skip cooldown for high-priority notifications
174
+ if [[ "$priority" != "high" ]] && (( now - LAST_NOTIFY_TIME < NOTIFY_COOLDOWN )); then
175
+ return
176
+ fi
177
+ LAST_NOTIFY_TIME=$now
178
+ curl -s --max-time 10 --connect-timeout 5 \
179
+ -H "Title: Claude IDE Bridge" -H "Priority: $priority" \
180
+ -d "$msg" "https://ntfy.sh/$NTFY_TOPIC" >/dev/null 2>&1 &
181
+ fi
182
+ }
183
+
184
+ # --- Reusable command strings ---
185
+ BRIDGE_IDE_FLAGS=""
186
+ if [[ -n "$IDE_NAME" ]]; then
187
+ _ide_lower="$(echo "$IDE_NAME" | tr '[:upper:]' '[:lower:]')"
188
+ BRIDGE_IDE_FLAGS="--ide-name $(printf '%q' "$IDE_NAME") --editor $(printf '%q' "$_ide_lower")"
189
+ fi
190
+ BRIDGE_AUTOMATION_FLAGS=""
191
+ if [[ -n "$AUTOMATION_POLICY" ]]; then
192
+ BRIDGE_AUTOMATION_FLAGS="--automation --automation-policy $(printf '%q' "$AUTOMATION_POLICY") --claude-driver $(printf '%q' "$CLAUDE_DRIVER")"
193
+ fi
194
+ # Use compiled dist when src/ is absent (npm install), tsx during local development
195
+ if [[ -f "$BRIDGE_DIR/src/index.ts" ]]; then
196
+ BRIDGE_BIN="npx tsx src/index.ts"
197
+ else
198
+ BRIDGE_BIN="node dist/index.js"
199
+ fi
200
+ BRIDGE_CMD="cd $(printf '%q' "$BRIDGE_DIR") && $BRIDGE_BIN --workspace $(printf '%q' "$WORKSPACE")${BRIDGE_IDE_FLAGS:+ $BRIDGE_IDE_FLAGS}${FULL_MODE:+ $FULL_MODE}${BRIDGE_AUTOMATION_FLAGS:+ $BRIDGE_AUTOMATION_FLAGS}"
201
+ # Derive a short display name for the Claude session from the workspace directory name.
202
+ # This appears in Claude Code's session list, making multi-workspace tmux setups identifiable.
203
+ WS_BASENAME=$(basename "$WORKSPACE")
204
+ SESSION_DISPLAY_NAME="bridge:${WS_BASENAME}"
205
+ # Give SessionEnd hooks up to 10 seconds to complete before the bridge exits.
206
+ # Ensures PostToolUse/SessionEnd hook payloads are delivered even during graceful shutdown.
207
+ CLAUDE_CMD="cd $(printf '%q' "$WORKSPACE") && unset CLAUDECODE && CLAUDE_CODE_IDE_SKIP_VALID_CHECK=true CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=10000 claude --ide --name $(printf '%q' "$SESSION_DISPLAY_NAME")"
208
+
209
+ # --- SSH reverse tunnel command (pane 4, only when --vps is set) ---
210
+ # Format: --vps user@host:remote_port (e.g. root@185.220.204.65:9000)
211
+ # The tunnel forwards remote_port on the VPS back to the local bridge port,
212
+ # so a static MCP URL on the VPS proxies directly to the local bridge.
213
+ TUNNEL_CMD=""
214
+ if [[ -n "$VPS" ]]; then
215
+ VPS_HOST="${VPS%:*}" # everything before the last colon
216
+ VPS_PORT="${VPS##*:}" # everything after the last colon
217
+ # Derive local bridge port from lock file at startup time (resolved later after bridge starts)
218
+ # We use a wrapper that reads the port dynamically so restarts pick up new ports automatically.
219
+ TUNNEL_CMD="bash -c '
220
+ delay=5; max_delay=60; failures=0
221
+ while true; do
222
+ # Read current bridge port from the newest lock file
223
+ LOCAL_PORT=\$(ls -t ~/.claude/ide/*.lock 2>/dev/null | head -1 | xargs -I{} python3 -c \"import json,sys; d=json.load(open(sys.argv[1])); print(d.get(\\\"port\\\", \\\"\\\"))\" {} 2>/dev/null || echo \"\")
224
+ # Fall back to basename of lock file (port is the filename)
225
+ if [[ -z \"\$LOCAL_PORT\" ]]; then
226
+ LOCAL_PORT=\$(ls -t ~/.claude/ide/*.lock 2>/dev/null | head -1 | xargs basename 2>/dev/null | sed \"s/.lock//\")
227
+ fi
228
+ if [[ -z \"\$LOCAL_PORT\" ]]; then
229
+ echo \"[\$(date +%H:%M:%S)] No bridge lock file found, retrying in \${delay}s...\"
230
+ sleep \$delay; continue
231
+ fi
232
+ echo \"[\$(date +%H:%M:%S)] Opening SSH tunnel: ${VPS_HOST} port ${VPS_PORT} -> localhost:\$LOCAL_PORT\"
233
+ ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
234
+ -o ExitOnForwardFailure=yes -o BatchMode=yes \
235
+ -R 0.0.0.0:${VPS_PORT}:localhost:\$LOCAL_PORT -N ${VPS_HOST}
236
+ code=\$?
237
+ [ \$code -eq 130 ] && { echo \"Exited by Ctrl+C.\"; exit 0; }
238
+ failures=\$((failures+1))
239
+ [ \$failures -ge 20 ] && { echo \"Too many tunnel failures. Giving up.\"; exit 1; }
240
+ echo \"[\$(date +%H:%M:%S)] Tunnel disconnected (exit \$code). Reconnecting in \${delay}s...\"
241
+ sleep \$delay
242
+ [ \$delay -lt \$max_delay ] && delay=\$((delay*2))
243
+ done'"
244
+ fi
245
+
246
+ # Export for subshell access
247
+ export NTFY_TOPIC
248
+
249
+ REMOTE_CMD="cd $(printf '%q' "$WORKSPACE") && unset CLAUDECODE && $caffeinate_cmd bash -c '
250
+ delay=1; max_delay=300; failures=0
251
+ while true; do
252
+ start=\$(date +%s)
253
+ claude remote-control --spawn=session
254
+ code=\$?
255
+ elapsed=\$(( \$(date +%s) - start ))
256
+ [ \$code -eq 130 ] && { echo \"Exited by Ctrl+C.\"; exit 0; }
257
+ if [ \$elapsed -ge 60 ]; then failures=0; delay=1
258
+ else
259
+ failures=\$((failures+1))
260
+ exp=\$((failures>6?6:failures-1)); p=1; for _ in \$(seq 1 \$exp); do p=\$((p*2)); done; delay=\$((5*p))
261
+ [ \$delay -gt \$max_delay ] && delay=\$max_delay
262
+ fi
263
+ if [ \$failures -ge 50 ]; then
264
+ echo \"Too many failures. Giving up.\"
265
+ if [ -n \"\$NTFY_TOPIC\" ]; then
266
+ curl -s --max-time 10 --connect-timeout 5 -H \"Title: Claude Remote\" -H \"Priority: high\" \
267
+ -d \"Circuit breaker: too many failures. Giving up.\" \"https://ntfy.sh/\$NTFY_TOPIC\" >/dev/null 2>&1 &
268
+ fi
269
+ exit 1
270
+ fi
271
+ echo \"[\$(date +%H:%M:%S)] Disconnected (exit \$code). Restarting in \${delay}s...\"
272
+ if [ -n \"\$NTFY_TOPIC\" ]; then
273
+ curl -s --max-time 10 --connect-timeout 5 -H \"Title: Claude Remote\" \
274
+ -d \"Disconnected (exit \$code). Restarting in \${delay}s...\" \"https://ntfy.sh/\$NTFY_TOPIC\" >/dev/null 2>&1 &
275
+ fi
276
+ sleep \$delay
277
+ done'"
278
+
279
+ # --- Create additional panes (pane 0 = orchestrator, 1 = bridge, 2 = claude, 3 = remote-control, 4 = ssh tunnel) ---
280
+ tmux split-window -v -t "$SESSION" # pane 1 for bridge
281
+ tmux split-window -v -t "$SESSION" # pane 2 for claude --ide
282
+ tmux split-window -v -t "$SESSION" # pane 3 for claude remote-control
283
+ [[ -n "$TUNNEL_CMD" ]] && tmux split-window -v -t "$SESSION" # pane 4 for ssh tunnel (optional)
284
+ tmux select-layout -t "$SESSION" even-vertical
285
+
286
+ # --- Helper: wait for a NEW lock file (ignores pre-existing ones) ---
287
+ wait_for_new_lock() {
288
+ local existing_locks="$1"
289
+ local timeout="$2"
290
+ local new_lock=""
291
+ for _ in $(seq 1 "$timeout"); do
292
+ # Find lock files that weren't in the pre-existing set
293
+ while IFS= read -r lock; do
294
+ if [[ -n "$lock" ]] && ! echo "$existing_locks" | grep -qF "$lock"; then
295
+ # Validate: readable JSON with a running PID (path passed as argv to avoid injection)
296
+ lock_pid=$(python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(d.get('pid',''))" "$lock" 2>/dev/null || true)
297
+ if [[ -n "$lock_pid" ]] && kill -0 "$lock_pid" 2>/dev/null; then
298
+ new_lock="$lock"
299
+ break 2
300
+ fi
301
+ fi
302
+ done < <(ls -t ~/.claude/ide/*.lock 2>/dev/null)
303
+ sleep 1
304
+ done
305
+ echo "$new_lock"
306
+ }
307
+
308
+ # Snapshot existing lock files before starting bridge
309
+ EXISTING_LOCKS=$(ls ~/.claude/ide/*.lock 2>/dev/null | sort)
310
+
311
+ # Pane 1: Bridge
312
+ tmux send-keys -t "${SESSION}:0.1" "$BRIDGE_CMD" Enter
313
+
314
+ # Wait for bridge readiness by detecting a NEW lock file
315
+ echo "Waiting for bridge to start..."
316
+ LOCK_FILE=$(wait_for_new_lock "$EXISTING_LOCKS" "$BRIDGE_READY_TIMEOUT")
317
+
318
+ if [[ -z "$LOCK_FILE" ]]; then
319
+ notify "Bridge failed to start within ${BRIDGE_READY_TIMEOUT}s" "high"
320
+ echo "Check pane 1 for errors."
321
+ # Don't exit — keep orchestrator running so user can debug
322
+ echo "Press Ctrl+C to exit orchestrator."
323
+ while true; do sleep 60; done
324
+ fi
325
+ notify "Bridge started (lock: $(basename "$LOCK_FILE"))"
326
+
327
+ # Prune stale lock files so --ide finds exactly one valid IDE (the one we just started).
328
+ # A lock is stale if its PID is dead. Paths passed as argv to avoid shell injection.
329
+ for stale in ~/.claude/ide/*.lock; do
330
+ [[ -f "$stale" ]] || continue
331
+ [[ "$stale" == "$LOCK_FILE" ]] && continue
332
+ stale_pid=$(python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(d.get('pid',''))" "$stale" 2>/dev/null || true)
333
+ if [[ -z "$stale_pid" ]] || ! kill -0 "$stale_pid" 2>/dev/null; then
334
+ rm -f "$stale"
335
+ echo "Removed stale lock: $(basename "$stale")"
336
+ fi
337
+ done
338
+
339
+ # Pane 2: Claude CLI with session ID for resume support
340
+ # Workspace-specific UUID file (hash workspace path to avoid collisions)
341
+ WS_HASH=$(echo -n "$WORKSPACE" | shasum -a 256 | cut -c1-12)
342
+ mkdir -p "$HOME/.claude"
343
+ SESSION_UUID_FILE="$HOME/.claude/claude-all-session-${WS_HASH}"
344
+ if command -v uuidgen >/dev/null 2>&1; then
345
+ SESSION_UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
346
+ elif [[ -f /proc/sys/kernel/random/uuid ]]; then
347
+ SESSION_UUID=$(cat /proc/sys/kernel/random/uuid)
348
+ else
349
+ SESSION_UUID=$(python3 -c "import uuid; print(uuid.uuid4())" 2>/dev/null || date +%s%N | sha256sum | head -c 32)
350
+ fi
351
+ echo "$SESSION_UUID" > "$SESSION_UUID_FILE"
352
+ chmod 600 "$SESSION_UUID_FILE"
353
+
354
+ tmux send-keys -t "${SESSION}:0.2" "$CLAUDE_CMD --session-id $SESSION_UUID" Enter
355
+
356
+ # Give claude a moment to start, then launch remote-control
357
+ sleep 3
358
+
359
+ # Pane 3: Remote control with auto-restart loop
360
+ tmux send-keys -t "${SESSION}:0.3" "$REMOTE_CMD" Enter
361
+
362
+ # Pane 4: SSH reverse tunnel (only if --vps was set)
363
+ if [[ -n "$TUNNEL_CMD" ]]; then
364
+ notify "Starting SSH tunnel to ${VPS}..."
365
+ tmux send-keys -t "${SESSION}:0.4" "$TUNNEL_CMD" Enter
366
+ fi
367
+
368
+ # --- Health monitor (runs in pane 0 — the orchestrator pane) ---
369
+ echo ""
370
+ echo "Health monitor active. Watching: $(basename "$LOCK_FILE")"
371
+ echo "---"
372
+
373
+ # Clean up child panes on exit — send SIGINT, wait, then escalate to kill-pane
374
+ cleanup() {
375
+ echo ""
376
+ echo "Orchestrator shutting down..."
377
+ tmux send-keys -t "${SESSION}:0.1" C-c 2>/dev/null
378
+ tmux send-keys -t "${SESSION}:0.2" C-c 2>/dev/null
379
+ tmux send-keys -t "${SESSION}:0.3" C-c 2>/dev/null
380
+ [[ -n "$TUNNEL_CMD" ]] && tmux send-keys -t "${SESSION}:0.4" C-c 2>/dev/null
381
+ # Wait up to 5s for panes to exit gracefully, then force-kill
382
+ local panes=(1 2 3)
383
+ [[ -n "$TUNNEL_CMD" ]] && panes=(1 2 3 4)
384
+ for _ in $(seq 1 5); do
385
+ sleep 1
386
+ all_idle=true
387
+ for pane in "${panes[@]}"; do
388
+ cmd=$(tmux display-message -t "${SESSION}:0.${pane}" -p '#{pane_current_command}' 2>/dev/null || echo "")
389
+ [[ "$cmd" != "bash" && "$cmd" != "zsh" && -n "$cmd" ]] && { all_idle=false; break; }
390
+ done
391
+ $all_idle && break
392
+ done
393
+ # Force-kill any remaining panes
394
+ for pane in "${panes[@]}"; do
395
+ tmux send-keys -t "${SESSION}:0.${pane}" C-c 2>/dev/null || true
396
+ done
397
+ sleep 1
398
+ local rpanes=(3 2 1)
399
+ [[ -n "$TUNNEL_CMD" ]] && rpanes=(4 3 2 1)
400
+ for pane in "${rpanes[@]}"; do
401
+ tmux kill-pane -t "${SESSION}:0.${pane}" 2>/dev/null || true
402
+ done
403
+ }
404
+ trap cleanup EXIT
405
+
406
+ while true; do
407
+ sleep 10
408
+ if [[ ! -f "$LOCK_FILE" ]]; then
409
+ notify "Bridge died! Restarting all processes..." "high"
410
+ # Kill any stale caffeinate processes before restart to prevent accumulation
411
+ pkill -f "caffeinate -i" 2>/dev/null || true
412
+ # Send Ctrl+C to all process panes (including bridge in case it's still alive)
413
+ tmux send-keys -t "${SESSION}:0.1" C-c
414
+ tmux send-keys -t "${SESSION}:0.2" C-c
415
+ tmux send-keys -t "${SESSION}:0.3" C-c
416
+ [[ -n "$TUNNEL_CMD" ]] && tmux send-keys -t "${SESSION}:0.4" C-c
417
+ # Wait for bridge (pane 1) and claude (pane 2) to actually stop
418
+ for _ in $(seq 1 10); do
419
+ pane1_cmd=$(tmux display-message -t "${SESSION}:0.1" -p '#{pane_current_command}' 2>/dev/null || echo "")
420
+ pane2_cmd=$(tmux display-message -t "${SESSION}:0.2" -p '#{pane_current_command}' 2>/dev/null || echo "")
421
+ pane1_idle=false; pane2_idle=false
422
+ [[ "$pane1_cmd" == "bash" || "$pane1_cmd" == "zsh" || -z "$pane1_cmd" ]] && pane1_idle=true
423
+ [[ "$pane2_cmd" == "bash" || "$pane2_cmd" == "zsh" || -z "$pane2_cmd" ]] && pane2_idle=true
424
+ $pane1_idle && $pane2_idle && break
425
+ sleep 1
426
+ done
427
+
428
+ # Verify old bridge process is truly dead using the lock file PID before it disappears
429
+ if [[ -f "$LOCK_FILE" ]]; then
430
+ old_pid=$(python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(d.get('pid',''))" "$LOCK_FILE" 2>/dev/null || echo "")
431
+ if [[ -n "$old_pid" ]]; then
432
+ for _ in $(seq 1 10); do
433
+ kill -0 "$old_pid" 2>/dev/null || break
434
+ sleep 1
435
+ done
436
+ fi
437
+ fi
438
+
439
+ # Give bridge time to clean up lock file after exiting
440
+ sleep 2
441
+
442
+ # Snapshot locks again before restarting bridge
443
+ EXISTING_LOCKS=$(ls ~/.claude/ide/*.lock 2>/dev/null | sort)
444
+
445
+ # Exponential backoff on rapid restarts
446
+ NOW=$(date +%s)
447
+ if [ $((NOW - LAST_START_TIME)) -lt 60 ]; then
448
+ echo "[health] Bridge crashed quickly, backing off ${RESTART_DELAY}s (restart #${RESTART_COUNT})"
449
+ sleep $RESTART_DELAY
450
+ RESTART_DELAY=$((RESTART_DELAY * 2))
451
+ [ $RESTART_DELAY -gt 300 ] && RESTART_DELAY=300
452
+ RESTART_COUNT=$((RESTART_COUNT + 1))
453
+ else
454
+ # Ran for a while, reset backoff
455
+ RESTART_DELAY=5
456
+ RESTART_COUNT=0
457
+ fi
458
+ LAST_START_TIME=$(date +%s)
459
+
460
+ # Restart bridge in pane 1
461
+ tmux send-keys -t "${SESSION}:0.1" "$BRIDGE_CMD" Enter
462
+
463
+ # Wait for new lock file (don't update LOCK_FILE on failure to avoid
464
+ # empty-string bug where [[ ! -f "" ]] is always true → infinite restart loop)
465
+ NEW_LOCK=$(wait_for_new_lock "$EXISTING_LOCKS" "$BRIDGE_READY_TIMEOUT")
466
+ if [[ -z "$NEW_LOCK" ]]; then
467
+ notify "Bridge failed to restart!" "high"
468
+ continue
469
+ fi
470
+ LOCK_FILE="$NEW_LOCK"
471
+
472
+ echo "Health monitor now watching: $(basename "$LOCK_FILE")"
473
+
474
+ # Restart claude with --resume to pick up same session
475
+ tmux send-keys -t "${SESSION}:0.2" "$CLAUDE_CMD --resume $SESSION_UUID" Enter
476
+ sleep 3
477
+ # Restart remote-control
478
+ tmux send-keys -t "${SESSION}:0.3" "$REMOTE_CMD" Enter
479
+ # Restart SSH tunnel (port may have changed — tunnel cmd reads lock file dynamically)
480
+ if [[ -n "$TUNNEL_CMD" ]]; then
481
+ tmux send-keys -t "${SESSION}:0.4" "$TUNNEL_CMD" Enter
482
+ fi
483
+ notify "All processes restarted"
484
+ else
485
+ # Bridge is alive — check if Claude CLI (pane 2) has exited
486
+ pane2_cmd=$(tmux display-message -t "${SESSION}:0.2" -p '#{pane_current_command}' 2>/dev/null || echo "")
487
+ if [[ "$pane2_cmd" == "bash" || "$pane2_cmd" == "zsh" || -z "$pane2_cmd" ]]; then
488
+ # Verify bridge is actually healthy before restarting just the CLI
489
+ BRIDGE_PORT=$(basename "$LOCK_FILE" .lock)
490
+ if curl -sf --max-time 5 "http://127.0.0.1:${BRIDGE_PORT}/health" >/dev/null 2>&1; then
491
+ # Cooldown: don't restart more than once per 30s
492
+ now=$(date +%s)
493
+ if [[ $(( now - LAST_CLAUDE_RESTART )) -ge 30 ]]; then
494
+ LAST_CLAUDE_RESTART=$now
495
+ echo "[$(date +%H:%M:%S)] Claude CLI died. Restarting with --resume..."
496
+ notify "Claude CLI died. Restarting with --resume..."
497
+ tmux send-keys -t "${SESSION}:0.2" "$CLAUDE_CMD --resume $SESSION_UUID" Enter
498
+ fi
499
+ fi
500
+ fi
501
+ fi
502
+ done
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env bash
2
+ # Orchestrator launcher: starts the meta-bridge that coordinates multiple IDE windows.
3
+ #
4
+ # Use this instead of start-all.sh when you have several IDE windows open simultaneously
5
+ # and want Claude to be able to work across all of them. Each IDE window must already
6
+ # have the claude-ide-bridge extension running — this script connects to them all.
7
+ #
8
+ # Pane layout:
9
+ # 0 — health monitor (this script)
10
+ # 1 — orchestrator bridge (port 4746 by default)
11
+ # 2 — claude --ide (connects to the orchestrator, sees all workspaces)
12
+ #
13
+ # Usage:
14
+ # ./scripts/start-orchestrator.sh [--port N] [--notify <ntfy-topic>]
15
+ # npm run start-orchestrator
16
+ #
17
+ # Options:
18
+ # --port <N> Orchestrator port (default: 4746)
19
+ # --notify <topic> Push notifications via ntfy.sh
20
+ # --verbose Enable verbose orchestrator logging
21
+
22
+ set -uo pipefail
23
+
24
+ trap 'echo "[monitor] Caught signal, stopping..."; tmux kill-session -t "${SESSION:-claude-orch}" 2>/dev/null; exit 0' SIGINT SIGTERM
25
+
26
+ SESSION="claude-orch"
27
+ SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
28
+ BRIDGE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
29
+ ORCH_PORT=4746
30
+ NTFY_TOPIC=""
31
+ VERBOSE_FLAG=""
32
+ ORCH_READY_TIMEOUT="${ORCH_READY_TIMEOUT:-20}"
33
+
34
+ # --- Parse args ---
35
+ while [[ $# -gt 0 ]]; do
36
+ case "$1" in
37
+ --port) ORCH_PORT="$2"; shift 2 ;;
38
+ --notify) NTFY_TOPIC="$2"; shift 2 ;;
39
+ --verbose) VERBOSE_FLAG="--verbose"; shift ;;
40
+ *) echo "Unknown option: $1" >&2; exit 1 ;;
41
+ esac
42
+ done
43
+
44
+ # --- Dependency checks ---
45
+ command -v tmux >/dev/null 2>&1 || { echo "Error: tmux is required (brew install tmux)" >&2; exit 1; }
46
+ command -v claude >/dev/null 2>&1 || { echo "Error: claude CLI not found on PATH" >&2; exit 1; }
47
+ command -v node >/dev/null 2>&1 || { echo "Error: node is required" >&2; exit 1; }
48
+
49
+ # --- tmux session management ---
50
+ if [[ -z "${TMUX:-}" ]]; then
51
+ if tmux has-session -t "$SESSION" 2>/dev/null; then
52
+ echo "Session '$SESSION' already running. Attaching..."
53
+ exec tmux attach -t "$SESSION"
54
+ fi
55
+ tmux new-session -d -s "$SESSION" -x 200 -y 50
56
+ tmux send-keys -t "$SESSION" \
57
+ "\"$SCRIPT_PATH\" --port \"$ORCH_PORT\"$([ -n "$NTFY_TOPIC" ] && echo " --notify \"$NTFY_TOPIC\"")$([ -n "$VERBOSE_FLAG" ] && echo " --verbose")" \
58
+ Enter
59
+ exec tmux attach -t "$SESSION"
60
+ fi
61
+
62
+ # --- Inside tmux ---
63
+ echo "=== Claude IDE Bridge Orchestrator ==="
64
+ echo " Port: $ORCH_PORT"
65
+ echo " Ctrl+C in any pane — stops that process"
66
+ echo " Ctrl+B then D — detach (keeps running)"
67
+ echo " tmux kill-session -t $SESSION — stop everything"
68
+ [[ -n "$NTFY_TOPIC" ]] && echo " Push notifications: ntfy.sh/$NTFY_TOPIC"
69
+ echo ""
70
+
71
+ # Use compiled dist when src/ is absent (npm install), tsx during local dev
72
+ if [[ -f "$BRIDGE_DIR/src/index.ts" ]]; then
73
+ BRIDGE_BIN="npx tsx src/index.ts"
74
+ else
75
+ BRIDGE_BIN="node dist/index.js"
76
+ fi
77
+
78
+ ORCH_CMD="cd $(printf '%q' "$BRIDGE_DIR") && $BRIDGE_BIN orchestrator --port $ORCH_PORT${VERBOSE_FLAG:+ $VERBOSE_FLAG}"
79
+ CLAUDE_CMD="unset CLAUDECODE && CLAUDE_CODE_IDE_SKIP_VALID_CHECK=true claude --ide"
80
+
81
+ export NTFY_TOPIC
82
+
83
+ # --- Notification helper ---
84
+ LAST_NOTIFY_TIME=0
85
+ NOTIFY_COOLDOWN=60
86
+
87
+ notify() {
88
+ local msg="$1"
89
+ local priority="${2:-default}"
90
+ echo "[$(date '+%H:%M:%S')] $msg"
91
+ if [[ -n "$NTFY_TOPIC" ]]; then
92
+ local now; now=$(date +%s)
93
+ if [[ "$priority" != "high" ]] && (( now - LAST_NOTIFY_TIME < NOTIFY_COOLDOWN )); then
94
+ return
95
+ fi
96
+ LAST_NOTIFY_TIME=$now
97
+ curl -s --max-time 10 --connect-timeout 5 \
98
+ -H "Title: Claude IDE Orchestrator" -H "Priority: $priority" \
99
+ -d "$msg" "https://ntfy.sh/$NTFY_TOPIC" >/dev/null 2>&1 &
100
+ fi
101
+ }
102
+
103
+ # --- Wait for orchestrator to be ready (polls /ping) ---
104
+ wait_for_orchestrator() {
105
+ local port="$1"
106
+ local timeout="$2"
107
+ for _ in $(seq 1 "$timeout"); do
108
+ if curl -sf --max-time 2 "http://127.0.0.1:${port}/ping" >/dev/null 2>&1; then
109
+ return 0
110
+ fi
111
+ sleep 1
112
+ done
113
+ return 1
114
+ }
115
+
116
+ # --- Create panes ---
117
+ tmux split-window -v -t "$SESSION" # pane 1: orchestrator
118
+ tmux split-window -v -t "$SESSION" # pane 2: claude
119
+ tmux select-layout -t "$SESSION" even-vertical
120
+
121
+ # Pane 1: Orchestrator
122
+ tmux send-keys -t "${SESSION}:0.1" "$ORCH_CMD" Enter
123
+
124
+ echo "Waiting for orchestrator to start on port $ORCH_PORT..."
125
+ if ! wait_for_orchestrator "$ORCH_PORT" "$ORCH_READY_TIMEOUT"; then
126
+ notify "Orchestrator failed to start within ${ORCH_READY_TIMEOUT}s" "high"
127
+ echo "Check pane 1 for errors. Press Ctrl+C to exit."
128
+ while true; do sleep 60; done
129
+ fi
130
+ notify "Orchestrator ready on port $ORCH_PORT"
131
+
132
+ # Pane 2: Claude connected to orchestrator
133
+ tmux send-keys -t "${SESSION}:0.2" "$CLAUDE_CMD" Enter
134
+
135
+ # --- Cleanup on exit ---
136
+ cleanup() {
137
+ echo ""
138
+ echo "Shutting down..."
139
+ tmux send-keys -t "${SESSION}:0.1" C-c 2>/dev/null
140
+ tmux send-keys -t "${SESSION}:0.2" C-c 2>/dev/null
141
+ sleep 2
142
+ tmux kill-pane -t "${SESSION}:0.2" 2>/dev/null || true
143
+ tmux kill-pane -t "${SESSION}:0.1" 2>/dev/null || true
144
+ }
145
+ trap cleanup EXIT
146
+
147
+ # --- Health monitor ---
148
+ echo ""
149
+ echo "Health monitor active. Watching orchestrator on port $ORCH_PORT"
150
+ echo "---"
151
+
152
+ LAST_CLAUDE_RESTART=0
153
+
154
+ while true; do
155
+ sleep 10
156
+
157
+ if ! curl -sf --max-time 3 "http://127.0.0.1:${ORCH_PORT}/ping" >/dev/null 2>&1; then
158
+ notify "Orchestrator on port $ORCH_PORT unreachable — restarting..." "high"
159
+
160
+ tmux send-keys -t "${SESSION}:0.1" C-c
161
+ tmux send-keys -t "${SESSION}:0.2" C-c
162
+ sleep 3
163
+
164
+ tmux send-keys -t "${SESSION}:0.1" "$ORCH_CMD" Enter
165
+
166
+ if ! wait_for_orchestrator "$ORCH_PORT" "$ORCH_READY_TIMEOUT"; then
167
+ notify "Orchestrator failed to restart!" "high"
168
+ continue
169
+ fi
170
+ notify "Orchestrator restarted"
171
+
172
+ tmux send-keys -t "${SESSION}:0.2" "$CLAUDE_CMD" Enter
173
+ else
174
+ # Orchestrator healthy — check if Claude exited
175
+ pane2_cmd=$(tmux display-message -t "${SESSION}:0.2" -p '#{pane_current_command}' 2>/dev/null || echo "")
176
+ if [[ "$pane2_cmd" == "bash" || "$pane2_cmd" == "zsh" || -z "$pane2_cmd" ]]; then
177
+ now=$(date +%s)
178
+ if (( now - LAST_CLAUDE_RESTART >= 30 )); then
179
+ LAST_CLAUDE_RESTART=$now
180
+ echo "[$(date '+%H:%M:%S')] Claude exited. Restarting..."
181
+ notify "Claude exited. Restarting..."
182
+ tmux send-keys -t "${SESSION}:0.2" "$CLAUDE_CMD" Enter
183
+ fi
184
+ fi
185
+ fi
186
+ done