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.
- package/LICENSE +21 -0
- package/README.bridge.md +352 -0
- package/README.md +72 -0
- package/deploy/README.md +172 -0
- package/deploy/bootstrap-new-vps.sh +364 -0
- package/deploy/claude-ide-bridge.service.template +67 -0
- package/deploy/claude-ide-bridge@.service +31 -0
- package/deploy/ecosystem.config.js.example +36 -0
- package/deploy/install-vps-service.sh +240 -0
- package/deploy/nginx-claude-bridge.conf.template +129 -0
- package/dist/activityLog.d.ts +112 -0
- package/dist/activityLog.js +399 -0
- package/dist/activityLog.js.map +1 -0
- package/dist/activityTypes.d.ts +28 -0
- package/dist/activityTypes.js +9 -0
- package/dist/activityTypes.js.map +1 -0
- package/dist/adapters/base.d.ts +78 -0
- package/dist/adapters/base.js +14 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude.d.ts +18 -0
- package/dist/adapters/claude.js +276 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/gemini.d.ts +17 -0
- package/dist/adapters/gemini.js +218 -0
- package/dist/adapters/gemini.js.map +1 -0
- package/dist/adapters/grok.d.ts +7 -0
- package/dist/adapters/grok.js +21 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.js +37 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/local.d.ts +7 -0
- package/dist/adapters/local.js +22 -0
- package/dist/adapters/local.js.map +1 -0
- package/dist/adapters/openai.d.ts +22 -0
- package/dist/adapters/openai.js +284 -0
- package/dist/adapters/openai.js.map +1 -0
- package/dist/adapters/sse.d.ts +13 -0
- package/dist/adapters/sse.js +58 -0
- package/dist/adapters/sse.js.map +1 -0
- package/dist/analyticsAggregator.d.ts +28 -0
- package/dist/analyticsAggregator.js +133 -0
- package/dist/analyticsAggregator.js.map +1 -0
- package/dist/analyticsPrefs.d.ts +9 -0
- package/dist/analyticsPrefs.js +50 -0
- package/dist/analyticsPrefs.js.map +1 -0
- package/dist/analyticsSend.d.ts +12 -0
- package/dist/analyticsSend.js +34 -0
- package/dist/analyticsSend.js.map +1 -0
- package/dist/approvalHttp.d.ts +46 -0
- package/dist/approvalHttp.js +370 -0
- package/dist/approvalHttp.js.map +1 -0
- package/dist/approvalQueue.d.ts +49 -0
- package/dist/approvalQueue.js +84 -0
- package/dist/approvalQueue.js.map +1 -0
- package/dist/automation.d.ts +675 -0
- package/dist/automation.js +1038 -0
- package/dist/automation.js.map +1 -0
- package/dist/bridge.d.ts +85 -0
- package/dist/bridge.js +1535 -0
- package/dist/bridge.js.map +1 -0
- package/dist/bridgeLockDiscovery.d.ts +11 -0
- package/dist/bridgeLockDiscovery.js +49 -0
- package/dist/bridgeLockDiscovery.js.map +1 -0
- package/dist/bridgeToken.d.ts +22 -0
- package/dist/bridgeToken.js +114 -0
- package/dist/bridgeToken.js.map +1 -0
- package/dist/bridgeToolsRules.d.ts +20 -0
- package/dist/bridgeToolsRules.js +79 -0
- package/dist/bridgeToolsRules.js.map +1 -0
- package/dist/ccPermissions.d.ts +59 -0
- package/dist/ccPermissions.js +163 -0
- package/dist/ccPermissions.js.map +1 -0
- package/dist/claudeDriver.d.ts +129 -0
- package/dist/claudeDriver.js +459 -0
- package/dist/claudeDriver.js.map +1 -0
- package/dist/claudeMdPatch.d.ts +29 -0
- package/dist/claudeMdPatch.js +164 -0
- package/dist/claudeMdPatch.js.map +1 -0
- package/dist/claudeOrchestrator.d.ts +171 -0
- package/dist/claudeOrchestrator.js +591 -0
- package/dist/claudeOrchestrator.js.map +1 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +158 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/marketplace.d.ts +11 -0
- package/dist/commands/marketplace.js +120 -0
- package/dist/commands/marketplace.js.map +1 -0
- package/dist/commands/patchworkInit.d.ts +14 -0
- package/dist/commands/patchworkInit.js +155 -0
- package/dist/commands/patchworkInit.js.map +1 -0
- package/dist/commands/task.d.ts +14 -0
- package/dist/commands/task.js +289 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/tokenEfficiency.d.ts +9 -0
- package/dist/commands/tokenEfficiency.js +211 -0
- package/dist/commands/tokenEfficiency.js.map +1 -0
- package/dist/commands/tools.d.ts +28 -0
- package/dist/commands/tools.js +326 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commitIssueLinkLog.d.ts +77 -0
- package/dist/commitIssueLinkLog.js +142 -0
- package/dist/commitIssueLinkLog.js.map +1 -0
- package/dist/companions/registry.d.ts +12 -0
- package/dist/companions/registry.js +71 -0
- package/dist/companions/registry.js.map +1 -0
- package/dist/config.d.ts +105 -0
- package/dist/config.js +720 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto.d.ts +16 -0
- package/dist/crypto.js +34 -0
- package/dist/crypto.js.map +1 -0
- package/dist/dashboard.d.ts +12 -0
- package/dist/dashboard.js +149 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/decisionTraceLog.d.ts +77 -0
- package/dist/decisionTraceLog.js +147 -0
- package/dist/decisionTraceLog.js.map +1 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +34 -0
- package/dist/errors.js.map +1 -0
- package/dist/extensionClient.d.ts +279 -0
- package/dist/extensionClient.js +1253 -0
- package/dist/extensionClient.js.map +1 -0
- package/dist/fileLock.d.ts +36 -0
- package/dist/fileLock.js +121 -0
- package/dist/fileLock.js.map +1 -0
- package/dist/fp/activityAnalytics.d.ts +39 -0
- package/dist/fp/activityAnalytics.js +111 -0
- package/dist/fp/activityAnalytics.js.map +1 -0
- package/dist/fp/async.d.ts +48 -0
- package/dist/fp/async.js +60 -0
- package/dist/fp/async.js.map +1 -0
- package/dist/fp/automationInterpreter.d.ts +37 -0
- package/dist/fp/automationInterpreter.js +523 -0
- package/dist/fp/automationInterpreter.js.map +1 -0
- package/dist/fp/automationProgram.d.ts +89 -0
- package/dist/fp/automationProgram.js +29 -0
- package/dist/fp/automationProgram.js.map +1 -0
- package/dist/fp/automationState.d.ts +135 -0
- package/dist/fp/automationState.js +206 -0
- package/dist/fp/automationState.js.map +1 -0
- package/dist/fp/automationUtils.d.ts +31 -0
- package/dist/fp/automationUtils.js +61 -0
- package/dist/fp/automationUtils.js.map +1 -0
- package/dist/fp/brandedTypes.d.ts +32 -0
- package/dist/fp/brandedTypes.js +41 -0
- package/dist/fp/brandedTypes.js.map +1 -0
- package/dist/fp/commandDescription.d.ts +18 -0
- package/dist/fp/commandDescription.js +125 -0
- package/dist/fp/commandDescription.js.map +1 -0
- package/dist/fp/extensionSnapshot.d.ts +10 -0
- package/dist/fp/extensionSnapshot.js +14 -0
- package/dist/fp/extensionSnapshot.js.map +1 -0
- package/dist/fp/index.d.ts +8 -0
- package/dist/fp/index.js +9 -0
- package/dist/fp/index.js.map +1 -0
- package/dist/fp/interpreterContext.d.ts +69 -0
- package/dist/fp/interpreterContext.js +56 -0
- package/dist/fp/interpreterContext.js.map +1 -0
- package/dist/fp/policyParser.d.ts +16 -0
- package/dist/fp/policyParser.js +334 -0
- package/dist/fp/policyParser.js.map +1 -0
- package/dist/fp/result.d.ts +38 -0
- package/dist/fp/result.js +57 -0
- package/dist/fp/result.js.map +1 -0
- package/dist/fp/tokenBucket.d.ts +27 -0
- package/dist/fp/tokenBucket.js +36 -0
- package/dist/fp/tokenBucket.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1465 -0
- package/dist/index.js.map +1 -0
- package/dist/instructionsUtils.d.ts +17 -0
- package/dist/instructionsUtils.js +38 -0
- package/dist/instructionsUtils.js.map +1 -0
- package/dist/lockfile.d.ts +16 -0
- package/dist/lockfile.js +172 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +68 -0
- package/dist/logger.js.map +1 -0
- package/dist/oauth.d.ts +105 -0
- package/dist/oauth.js +880 -0
- package/dist/oauth.js.map +1 -0
- package/dist/orchestrator/childBridgeClient.d.ts +33 -0
- package/dist/orchestrator/childBridgeClient.js +321 -0
- package/dist/orchestrator/childBridgeClient.js.map +1 -0
- package/dist/orchestrator/childBridgeRegistry.d.ts +67 -0
- package/dist/orchestrator/childBridgeRegistry.js +297 -0
- package/dist/orchestrator/childBridgeRegistry.js.map +1 -0
- package/dist/orchestrator/index.d.ts +3 -0
- package/dist/orchestrator/index.js +3 -0
- package/dist/orchestrator/index.js.map +1 -0
- package/dist/orchestrator/orchestratorBridge.d.ts +32 -0
- package/dist/orchestrator/orchestratorBridge.js +412 -0
- package/dist/orchestrator/orchestratorBridge.js.map +1 -0
- package/dist/orchestrator/orchestratorConfig.d.ts +11 -0
- package/dist/orchestrator/orchestratorConfig.js +85 -0
- package/dist/orchestrator/orchestratorConfig.js.map +1 -0
- package/dist/orchestrator/orchestratorTools.d.ts +16 -0
- package/dist/orchestrator/orchestratorTools.js +272 -0
- package/dist/orchestrator/orchestratorTools.js.map +1 -0
- package/dist/patchworkCli.d.ts +15 -0
- package/dist/patchworkCli.js +41 -0
- package/dist/patchworkCli.js.map +1 -0
- package/dist/patchworkConfig.d.ts +28 -0
- package/dist/patchworkConfig.js +30 -0
- package/dist/patchworkConfig.js.map +1 -0
- package/dist/plugin.d.ts +106 -0
- package/dist/plugin.js +31 -0
- package/dist/plugin.js.map +1 -0
- package/dist/pluginLoader.d.ts +44 -0
- package/dist/pluginLoader.js +357 -0
- package/dist/pluginLoader.js.map +1 -0
- package/dist/pluginWatcher.d.ts +24 -0
- package/dist/pluginWatcher.js +139 -0
- package/dist/pluginWatcher.js.map +1 -0
- package/dist/preToolUseHook.d.ts +10 -0
- package/dist/preToolUseHook.js +57 -0
- package/dist/preToolUseHook.js.map +1 -0
- package/dist/probe.d.ts +35 -0
- package/dist/probe.js +143 -0
- package/dist/probe.js.map +1 -0
- package/dist/prompts.d.ts +27 -0
- package/dist/prompts.js +1680 -0
- package/dist/prompts.js.map +1 -0
- package/dist/quickTaskPresets.d.ts +64 -0
- package/dist/quickTaskPresets.js +156 -0
- package/dist/quickTaskPresets.js.map +1 -0
- package/dist/recipes/compiler.d.ts +44 -0
- package/dist/recipes/compiler.js +140 -0
- package/dist/recipes/compiler.js.map +1 -0
- package/dist/recipes/installer.d.ts +25 -0
- package/dist/recipes/installer.js +62 -0
- package/dist/recipes/installer.js.map +1 -0
- package/dist/recipes/parser.d.ts +18 -0
- package/dist/recipes/parser.js +160 -0
- package/dist/recipes/parser.js.map +1 -0
- package/dist/recipes/scheduler.d.ts +45 -0
- package/dist/recipes/scheduler.js +110 -0
- package/dist/recipes/scheduler.js.map +1 -0
- package/dist/recipes/schema.d.ts +71 -0
- package/dist/recipes/schema.js +11 -0
- package/dist/recipes/schema.js.map +1 -0
- package/dist/recipesHttp.d.ts +63 -0
- package/dist/recipesHttp.js +183 -0
- package/dist/recipesHttp.js.map +1 -0
- package/dist/resources.d.ts +33 -0
- package/dist/resources.js +266 -0
- package/dist/resources.js.map +1 -0
- package/dist/riskTier.d.ts +40 -0
- package/dist/riskTier.js +142 -0
- package/dist/riskTier.js.map +1 -0
- package/dist/runLog.d.ts +90 -0
- package/dist/runLog.js +143 -0
- package/dist/runLog.js.map +1 -0
- package/dist/server.d.ts +160 -0
- package/dist/server.js +1244 -0
- package/dist/server.js.map +1 -0
- package/dist/sessionCheckpoint.d.ts +37 -0
- package/dist/sessionCheckpoint.js +123 -0
- package/dist/sessionCheckpoint.js.map +1 -0
- package/dist/streamableHttp.d.ts +86 -0
- package/dist/streamableHttp.js +702 -0
- package/dist/streamableHttp.js.map +1 -0
- package/dist/telemetry.d.ts +18 -0
- package/dist/telemetry.js +95 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tools/activityLog.d.ts +140 -0
- package/dist/tools/activityLog.js +204 -0
- package/dist/tools/activityLog.js.map +1 -0
- package/dist/tools/auditDependencies.d.ts +67 -0
- package/dist/tools/auditDependencies.js +298 -0
- package/dist/tools/auditDependencies.js.map +1 -0
- package/dist/tools/batchLsp.d.ts +262 -0
- package/dist/tools/batchLsp.js +328 -0
- package/dist/tools/batchLsp.js.map +1 -0
- package/dist/tools/blame-utils.d.ts +30 -0
- package/dist/tools/blame-utils.js +60 -0
- package/dist/tools/blame-utils.js.map +1 -0
- package/dist/tools/bridgeDoctor.d.ts +78 -0
- package/dist/tools/bridgeDoctor.js +542 -0
- package/dist/tools/bridgeDoctor.js.map +1 -0
- package/dist/tools/bridgeStatus.d.ts +122 -0
- package/dist/tools/bridgeStatus.js +250 -0
- package/dist/tools/bridgeStatus.js.map +1 -0
- package/dist/tools/cancelClaudeTask.d.ts +48 -0
- package/dist/tools/cancelClaudeTask.js +56 -0
- package/dist/tools/cancelClaudeTask.js.map +1 -0
- package/dist/tools/checkDocumentDirty.d.ts +56 -0
- package/dist/tools/checkDocumentDirty.js +74 -0
- package/dist/tools/checkDocumentDirty.js.map +1 -0
- package/dist/tools/clipboard.d.ts +80 -0
- package/dist/tools/clipboard.js +211 -0
- package/dist/tools/clipboard.js.map +1 -0
- package/dist/tools/closeTabs.d.ts +84 -0
- package/dist/tools/closeTabs.js +97 -0
- package/dist/tools/closeTabs.js.map +1 -0
- package/dist/tools/codeLens.d.ts +50 -0
- package/dist/tools/codeLens.js +47 -0
- package/dist/tools/codeLens.js.map +1 -0
- package/dist/tools/contextBundle.d.ts +75 -0
- package/dist/tools/contextBundle.js +218 -0
- package/dist/tools/contextBundle.js.map +1 -0
- package/dist/tools/createIssueFromAIComment.d.ts +75 -0
- package/dist/tools/createIssueFromAIComment.js +119 -0
- package/dist/tools/createIssueFromAIComment.js.map +1 -0
- package/dist/tools/ctxGetTaskContext.d.ts +103 -0
- package/dist/tools/ctxGetTaskContext.js +274 -0
- package/dist/tools/ctxGetTaskContext.js.map +1 -0
- package/dist/tools/ctxQueryTraces.d.ts +142 -0
- package/dist/tools/ctxQueryTraces.js +194 -0
- package/dist/tools/ctxQueryTraces.js.map +1 -0
- package/dist/tools/ctxSaveTrace.d.ts +87 -0
- package/dist/tools/ctxSaveTrace.js +94 -0
- package/dist/tools/ctxSaveTrace.js.map +1 -0
- package/dist/tools/debug.d.ts +206 -0
- package/dist/tools/debug.js +234 -0
- package/dist/tools/debug.js.map +1 -0
- package/dist/tools/decorations.d.ts +130 -0
- package/dist/tools/decorations.js +160 -0
- package/dist/tools/decorations.js.map +1 -0
- package/dist/tools/detectUnusedCode.d.ts +78 -0
- package/dist/tools/detectUnusedCode.js +173 -0
- package/dist/tools/detectUnusedCode.js.map +1 -0
- package/dist/tools/documentLinks.d.ts +62 -0
- package/dist/tools/documentLinks.js +55 -0
- package/dist/tools/documentLinks.js.map +1 -0
- package/dist/tools/editText.d.ts +108 -0
- package/dist/tools/editText.js +318 -0
- package/dist/tools/editText.js.map +1 -0
- package/dist/tools/enrichCommit.d.ts +89 -0
- package/dist/tools/enrichCommit.js +201 -0
- package/dist/tools/enrichCommit.js.map +1 -0
- package/dist/tools/enrichStackTrace.d.ts +121 -0
- package/dist/tools/enrichStackTrace.js +194 -0
- package/dist/tools/enrichStackTrace.js.map +1 -0
- package/dist/tools/explainDiagnostic.d.ts +137 -0
- package/dist/tools/explainDiagnostic.js +230 -0
- package/dist/tools/explainDiagnostic.js.map +1 -0
- package/dist/tools/explainSymbol.d.ts +119 -0
- package/dist/tools/explainSymbol.js +177 -0
- package/dist/tools/explainSymbol.js.map +1 -0
- package/dist/tools/fileOperations.d.ts +186 -0
- package/dist/tools/fileOperations.js +330 -0
- package/dist/tools/fileOperations.js.map +1 -0
- package/dist/tools/fileWatcher.d.ts +107 -0
- package/dist/tools/fileWatcher.js +121 -0
- package/dist/tools/fileWatcher.js.map +1 -0
- package/dist/tools/findFiles.d.ts +65 -0
- package/dist/tools/findFiles.js +142 -0
- package/dist/tools/findFiles.js.map +1 -0
- package/dist/tools/findRelatedTests.d.ts +83 -0
- package/dist/tools/findRelatedTests.js +196 -0
- package/dist/tools/findRelatedTests.js.map +1 -0
- package/dist/tools/fixAllLintErrors.d.ts +66 -0
- package/dist/tools/fixAllLintErrors.js +128 -0
- package/dist/tools/fixAllLintErrors.js.map +1 -0
- package/dist/tools/foldingRanges.d.ts +50 -0
- package/dist/tools/foldingRanges.js +51 -0
- package/dist/tools/foldingRanges.js.map +1 -0
- package/dist/tools/formatAndSave.d.ts +57 -0
- package/dist/tools/formatAndSave.js +87 -0
- package/dist/tools/formatAndSave.js.map +1 -0
- package/dist/tools/formatDocument.d.ts +61 -0
- package/dist/tools/formatDocument.js +144 -0
- package/dist/tools/formatDocument.js.map +1 -0
- package/dist/tools/generateAPIDocumentation.d.ts +62 -0
- package/dist/tools/generateAPIDocumentation.js +249 -0
- package/dist/tools/generateAPIDocumentation.js.map +1 -0
- package/dist/tools/generateTests.d.ts +75 -0
- package/dist/tools/generateTests.js +226 -0
- package/dist/tools/generateTests.js.map +1 -0
- package/dist/tools/getAIComments.d.ts +79 -0
- package/dist/tools/getAIComments.js +93 -0
- package/dist/tools/getAIComments.js.map +1 -0
- package/dist/tools/getAnalyticsReport.d.ts +102 -0
- package/dist/tools/getAnalyticsReport.js +137 -0
- package/dist/tools/getAnalyticsReport.js.map +1 -0
- package/dist/tools/getArchitectureContext.d.ts +85 -0
- package/dist/tools/getArchitectureContext.js +135 -0
- package/dist/tools/getArchitectureContext.js.map +1 -0
- package/dist/tools/getBufferContent.d.ts +80 -0
- package/dist/tools/getBufferContent.js +207 -0
- package/dist/tools/getBufferContent.js.map +1 -0
- package/dist/tools/getChangeImpact.d.ts +76 -0
- package/dist/tools/getChangeImpact.js +184 -0
- package/dist/tools/getChangeImpact.js.map +1 -0
- package/dist/tools/getClaudeTaskStatus.d.ts +87 -0
- package/dist/tools/getClaudeTaskStatus.js +89 -0
- package/dist/tools/getClaudeTaskStatus.js.map +1 -0
- package/dist/tools/getCodeCoverage.d.ts +86 -0
- package/dist/tools/getCodeCoverage.js +237 -0
- package/dist/tools/getCodeCoverage.js.map +1 -0
- package/dist/tools/getCommitsForIssue.d.ts +98 -0
- package/dist/tools/getCommitsForIssue.js +106 -0
- package/dist/tools/getCommitsForIssue.js.map +1 -0
- package/dist/tools/getCurrentSelection.d.ts +123 -0
- package/dist/tools/getCurrentSelection.js +113 -0
- package/dist/tools/getCurrentSelection.js.map +1 -0
- package/dist/tools/getDebugState.d.ts +140 -0
- package/dist/tools/getDebugState.js +109 -0
- package/dist/tools/getDebugState.js.map +1 -0
- package/dist/tools/getDependencyTree.d.ts +59 -0
- package/dist/tools/getDependencyTree.js +207 -0
- package/dist/tools/getDependencyTree.js.map +1 -0
- package/dist/tools/getDiagnostics.d.ts +108 -0
- package/dist/tools/getDiagnostics.js +371 -0
- package/dist/tools/getDiagnostics.js.map +1 -0
- package/dist/tools/getDiffFromHandoff.d.ts +89 -0
- package/dist/tools/getDiffFromHandoff.js +163 -0
- package/dist/tools/getDiffFromHandoff.js.map +1 -0
- package/dist/tools/getDocumentSymbols.d.ts +74 -0
- package/dist/tools/getDocumentSymbols.js +177 -0
- package/dist/tools/getDocumentSymbols.js.map +1 -0
- package/dist/tools/getFileTree.d.ts +66 -0
- package/dist/tools/getFileTree.js +131 -0
- package/dist/tools/getFileTree.js.map +1 -0
- package/dist/tools/getGitDiff.d.ts +50 -0
- package/dist/tools/getGitDiff.js +73 -0
- package/dist/tools/getGitDiff.js.map +1 -0
- package/dist/tools/getGitHotspots.d.ts +88 -0
- package/dist/tools/getGitHotspots.js +145 -0
- package/dist/tools/getGitHotspots.js.map +1 -0
- package/dist/tools/getGitLog.d.ts +62 -0
- package/dist/tools/getGitLog.js +87 -0
- package/dist/tools/getGitLog.js.map +1 -0
- package/dist/tools/getGitStatus.d.ts +72 -0
- package/dist/tools/getGitStatus.js +126 -0
- package/dist/tools/getGitStatus.js.map +1 -0
- package/dist/tools/getImportTree.d.ts +73 -0
- package/dist/tools/getImportTree.js +223 -0
- package/dist/tools/getImportTree.js.map +1 -0
- package/dist/tools/getImportedSignatures.d.ts +62 -0
- package/dist/tools/getImportedSignatures.js +255 -0
- package/dist/tools/getImportedSignatures.js.map +1 -0
- package/dist/tools/getOpenEditors.d.ts +62 -0
- package/dist/tools/getOpenEditors.js +126 -0
- package/dist/tools/getOpenEditors.js.map +1 -0
- package/dist/tools/getPRTemplate.d.ts +68 -0
- package/dist/tools/getPRTemplate.js +187 -0
- package/dist/tools/getPRTemplate.js.map +1 -0
- package/dist/tools/getProjectContext.d.ts +114 -0
- package/dist/tools/getProjectContext.js +344 -0
- package/dist/tools/getProjectContext.js.map +1 -0
- package/dist/tools/getProjectInfo.d.ts +51 -0
- package/dist/tools/getProjectInfo.js +325 -0
- package/dist/tools/getProjectInfo.js.map +1 -0
- package/dist/tools/getSecurityAdvisories.d.ts +105 -0
- package/dist/tools/getSecurityAdvisories.js +472 -0
- package/dist/tools/getSecurityAdvisories.js.map +1 -0
- package/dist/tools/getSessionUsage.d.ts +58 -0
- package/dist/tools/getSessionUsage.js +57 -0
- package/dist/tools/getSessionUsage.js.map +1 -0
- package/dist/tools/getSymbolHistory.d.ts +157 -0
- package/dist/tools/getSymbolHistory.js +256 -0
- package/dist/tools/getSymbolHistory.js.map +1 -0
- package/dist/tools/getToolCapabilities.d.ts +69 -0
- package/dist/tools/getToolCapabilities.js +298 -0
- package/dist/tools/getToolCapabilities.js.map +1 -0
- package/dist/tools/getTypeSignature.d.ts +70 -0
- package/dist/tools/getTypeSignature.js +132 -0
- package/dist/tools/getTypeSignature.js.map +1 -0
- package/dist/tools/getWorkspaceFolders.d.ts +58 -0
- package/dist/tools/getWorkspaceFolders.js +69 -0
- package/dist/tools/getWorkspaceFolders.js.map +1 -0
- package/dist/tools/getWorkspaceSettings.d.ts +44 -0
- package/dist/tools/getWorkspaceSettings.js +70 -0
- package/dist/tools/getWorkspaceSettings.js.map +1 -0
- package/dist/tools/git-utils.d.ts +16 -0
- package/dist/tools/git-utils.js +46 -0
- package/dist/tools/git-utils.js.map +1 -0
- package/dist/tools/gitHistory.d.ts +110 -0
- package/dist/tools/gitHistory.js +167 -0
- package/dist/tools/gitHistory.js.map +1 -0
- package/dist/tools/gitWrite.d.ts +612 -0
- package/dist/tools/gitWrite.js +983 -0
- package/dist/tools/gitWrite.js.map +1 -0
- package/dist/tools/github/actions.d.ts +152 -0
- package/dist/tools/github/actions.js +195 -0
- package/dist/tools/github/actions.js.map +1 -0
- package/dist/tools/github/index.d.ts +3 -0
- package/dist/tools/github/index.js +4 -0
- package/dist/tools/github/index.js.map +1 -0
- package/dist/tools/github/issues.d.ts +281 -0
- package/dist/tools/github/issues.js +340 -0
- package/dist/tools/github/issues.js.map +1 -0
- package/dist/tools/github/pr.d.ts +433 -0
- package/dist/tools/github/pr.js +588 -0
- package/dist/tools/github/pr.js.map +1 -0
- package/dist/tools/github/shared.d.ts +4 -0
- package/dist/tools/github/shared.js +12 -0
- package/dist/tools/github/shared.js.map +1 -0
- package/dist/tools/handoffNote.d.ts +106 -0
- package/dist/tools/handoffNote.js +232 -0
- package/dist/tools/handoffNote.js.map +1 -0
- package/dist/tools/headless/lspClient.d.ts +26 -0
- package/dist/tools/headless/lspClient.js +221 -0
- package/dist/tools/headless/lspClient.js.map +1 -0
- package/dist/tools/headless/lspFallback.d.ts +28 -0
- package/dist/tools/headless/lspFallback.js +122 -0
- package/dist/tools/headless/lspFallback.js.map +1 -0
- package/dist/tools/hoverAtCursor.d.ts +54 -0
- package/dist/tools/hoverAtCursor.js +68 -0
- package/dist/tools/hoverAtCursor.js.map +1 -0
- package/dist/tools/httpClient.d.ts +141 -0
- package/dist/tools/httpClient.js +486 -0
- package/dist/tools/httpClient.js.map +1 -0
- package/dist/tools/index.d.ts +49 -0
- package/dist/tools/index.js +672 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/inlayHints.d.ts +81 -0
- package/dist/tools/inlayHints.js +76 -0
- package/dist/tools/inlayHints.js.map +1 -0
- package/dist/tools/issueRefs.d.ts +14 -0
- package/dist/tools/issueRefs.js +27 -0
- package/dist/tools/issueRefs.js.map +1 -0
- package/dist/tools/jumpToFirstError.d.ts +63 -0
- package/dist/tools/jumpToFirstError.js +124 -0
- package/dist/tools/jumpToFirstError.js.map +1 -0
- package/dist/tools/launchQuickTask.d.ts +76 -0
- package/dist/tools/launchQuickTask.js +170 -0
- package/dist/tools/launchQuickTask.js.map +1 -0
- package/dist/tools/linters/biome.d.ts +2 -0
- package/dist/tools/linters/biome.js +44 -0
- package/dist/tools/linters/biome.js.map +1 -0
- package/dist/tools/linters/cargo.d.ts +2 -0
- package/dist/tools/linters/cargo.js +45 -0
- package/dist/tools/linters/cargo.js.map +1 -0
- package/dist/tools/linters/eslint.d.ts +2 -0
- package/dist/tools/linters/eslint.js +59 -0
- package/dist/tools/linters/eslint.js.map +1 -0
- package/dist/tools/linters/govet.d.ts +2 -0
- package/dist/tools/linters/govet.js +37 -0
- package/dist/tools/linters/govet.js.map +1 -0
- package/dist/tools/linters/pyright.d.ts +2 -0
- package/dist/tools/linters/pyright.js +34 -0
- package/dist/tools/linters/pyright.js.map +1 -0
- package/dist/tools/linters/ruff.d.ts +2 -0
- package/dist/tools/linters/ruff.js +30 -0
- package/dist/tools/linters/ruff.js.map +1 -0
- package/dist/tools/linters/types.d.ts +16 -0
- package/dist/tools/linters/types.js +2 -0
- package/dist/tools/linters/types.js.map +1 -0
- package/dist/tools/linters/typescript.d.ts +2 -0
- package/dist/tools/linters/typescript.js +38 -0
- package/dist/tools/linters/typescript.js.map +1 -0
- package/dist/tools/listClaudeTasks.d.ts +84 -0
- package/dist/tools/listClaudeTasks.js +88 -0
- package/dist/tools/listClaudeTasks.js.map +1 -0
- package/dist/tools/listTerminals.d.ts +55 -0
- package/dist/tools/listTerminals.js +78 -0
- package/dist/tools/listTerminals.js.map +1 -0
- package/dist/tools/lsp.d.ts +1086 -0
- package/dist/tools/lsp.js +1339 -0
- package/dist/tools/lsp.js.map +1 -0
- package/dist/tools/navigateToSymbolByName.d.ts +56 -0
- package/dist/tools/navigateToSymbolByName.js +170 -0
- package/dist/tools/navigateToSymbolByName.js.map +1 -0
- package/dist/tools/openDiff.d.ts +66 -0
- package/dist/tools/openDiff.js +126 -0
- package/dist/tools/openDiff.js.map +1 -0
- package/dist/tools/openFile.d.ts +69 -0
- package/dist/tools/openFile.js +129 -0
- package/dist/tools/openFile.js.map +1 -0
- package/dist/tools/openInBrowser.d.ts +55 -0
- package/dist/tools/openInBrowser.js +129 -0
- package/dist/tools/openInBrowser.js.map +1 -0
- package/dist/tools/organizeImports.d.ts +56 -0
- package/dist/tools/organizeImports.js +115 -0
- package/dist/tools/organizeImports.js.map +1 -0
- package/dist/tools/performanceReport.d.ts +133 -0
- package/dist/tools/performanceReport.js +218 -0
- package/dist/tools/performanceReport.js.map +1 -0
- package/dist/tools/planPersistence.d.ts +306 -0
- package/dist/tools/planPersistence.js +485 -0
- package/dist/tools/planPersistence.js.map +1 -0
- package/dist/tools/previewEdit.d.ts +107 -0
- package/dist/tools/previewEdit.js +270 -0
- package/dist/tools/previewEdit.js.map +1 -0
- package/dist/tools/recentTracesDigest.d.ts +35 -0
- package/dist/tools/recentTracesDigest.js +98 -0
- package/dist/tools/recentTracesDigest.js.map +1 -0
- package/dist/tools/refactorAnalyze.d.ts +78 -0
- package/dist/tools/refactorAnalyze.js +141 -0
- package/dist/tools/refactorAnalyze.js.map +1 -0
- package/dist/tools/refactorExtractFunction.d.ts +52 -0
- package/dist/tools/refactorExtractFunction.js +121 -0
- package/dist/tools/refactorExtractFunction.js.map +1 -0
- package/dist/tools/refactorPreview.d.ts +75 -0
- package/dist/tools/refactorPreview.js +93 -0
- package/dist/tools/refactorPreview.js.map +1 -0
- package/dist/tools/replaceBlock.d.ts +62 -0
- package/dist/tools/replaceBlock.js +125 -0
- package/dist/tools/replaceBlock.js.map +1 -0
- package/dist/tools/resumeClaudeTask.d.ts +75 -0
- package/dist/tools/resumeClaudeTask.js +149 -0
- package/dist/tools/resumeClaudeTask.js.map +1 -0
- package/dist/tools/runClaudeTask.d.ts +97 -0
- package/dist/tools/runClaudeTask.js +224 -0
- package/dist/tools/runClaudeTask.js.map +1 -0
- package/dist/tools/runCommand.d.ts +82 -0
- package/dist/tools/runCommand.js +101 -0
- package/dist/tools/runCommand.js.map +1 -0
- package/dist/tools/runTests.d.ts +146 -0
- package/dist/tools/runTests.js +315 -0
- package/dist/tools/runTests.js.map +1 -0
- package/dist/tools/saveDocument.d.ts +50 -0
- package/dist/tools/saveDocument.js +73 -0
- package/dist/tools/saveDocument.js.map +1 -0
- package/dist/tools/screenshot.d.ts +23 -0
- package/dist/tools/screenshot.js +43 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/screenshotAndAnnotate.d.ts +103 -0
- package/dist/tools/screenshotAndAnnotate.js +192 -0
- package/dist/tools/screenshotAndAnnotate.js.map +1 -0
- package/dist/tools/searchAndReplace.d.ts +108 -0
- package/dist/tools/searchAndReplace.js +281 -0
- package/dist/tools/searchAndReplace.js.map +1 -0
- package/dist/tools/searchTools.d.ts +61 -0
- package/dist/tools/searchTools.js +85 -0
- package/dist/tools/searchTools.js.map +1 -0
- package/dist/tools/searchWorkspace.d.ts +99 -0
- package/dist/tools/searchWorkspace.js +189 -0
- package/dist/tools/searchWorkspace.js.map +1 -0
- package/dist/tools/selectionRanges.d.ts +58 -0
- package/dist/tools/selectionRanges.js +61 -0
- package/dist/tools/selectionRanges.js.map +1 -0
- package/dist/tools/semanticTokens.d.ts +87 -0
- package/dist/tools/semanticTokens.js +86 -0
- package/dist/tools/semanticTokens.js.map +1 -0
- package/dist/tools/setActiveWorkspaceFolder.d.ts +41 -0
- package/dist/tools/setActiveWorkspaceFolder.js +38 -0
- package/dist/tools/setActiveWorkspaceFolder.js.map +1 -0
- package/dist/tools/signatureHelp.d.ts +86 -0
- package/dist/tools/signatureHelp.js +79 -0
- package/dist/tools/signatureHelp.js.map +1 -0
- package/dist/tools/spawnWorkspace.d.ts +103 -0
- package/dist/tools/spawnWorkspace.js +268 -0
- package/dist/tools/spawnWorkspace.js.map +1 -0
- package/dist/tools/stackTraceParser.d.ts +43 -0
- package/dist/tools/stackTraceParser.js +139 -0
- package/dist/tools/stackTraceParser.js.map +1 -0
- package/dist/tools/terminal.d.ts +352 -0
- package/dist/tools/terminal.js +670 -0
- package/dist/tools/terminal.js.map +1 -0
- package/dist/tools/testRunners/cargoTest.d.ts +2 -0
- package/dist/tools/testRunners/cargoTest.js +129 -0
- package/dist/tools/testRunners/cargoTest.js.map +1 -0
- package/dist/tools/testRunners/goTest.d.ts +2 -0
- package/dist/tools/testRunners/goTest.js +108 -0
- package/dist/tools/testRunners/goTest.js.map +1 -0
- package/dist/tools/testRunners/pytest.d.ts +2 -0
- package/dist/tools/testRunners/pytest.js +135 -0
- package/dist/tools/testRunners/pytest.js.map +1 -0
- package/dist/tools/testRunners/types.d.ts +18 -0
- package/dist/tools/testRunners/types.js +2 -0
- package/dist/tools/testRunners/types.js.map +1 -0
- package/dist/tools/testRunners/vitestJest.d.ts +3 -0
- package/dist/tools/testRunners/vitestJest.js +215 -0
- package/dist/tools/testRunners/vitestJest.js.map +1 -0
- package/dist/tools/testTraceToSource.d.ts +80 -0
- package/dist/tools/testTraceToSource.js +206 -0
- package/dist/tools/testTraceToSource.js.map +1 -0
- package/dist/tools/transaction.d.ts +243 -0
- package/dist/tools/transaction.js +309 -0
- package/dist/tools/transaction.js.map +1 -0
- package/dist/tools/typeHierarchy.d.ts +77 -0
- package/dist/tools/typeHierarchy.js +86 -0
- package/dist/tools/typeHierarchy.js.map +1 -0
- package/dist/tools/utils.d.ts +124 -0
- package/dist/tools/utils.js +566 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/tools/vscodeCommands.d.ts +90 -0
- package/dist/tools/vscodeCommands.js +112 -0
- package/dist/tools/vscodeCommands.js.map +1 -0
- package/dist/tools/vscodeTasks.d.ts +102 -0
- package/dist/tools/vscodeTasks.js +110 -0
- package/dist/tools/vscodeTasks.js.map +1 -0
- package/dist/tools/watchDiagnostics.d.ts +64 -0
- package/dist/tools/watchDiagnostics.js +270 -0
- package/dist/tools/watchDiagnostics.js.map +1 -0
- package/dist/tools/workspaceSettings.d.ts +57 -0
- package/dist/tools/workspaceSettings.js +80 -0
- package/dist/tools/workspaceSettings.js.map +1 -0
- package/dist/transport.d.ts +207 -0
- package/dist/transport.js +1272 -0
- package/dist/transport.js.map +1 -0
- package/dist/version.d.ts +13 -0
- package/dist/version.js +31 -0
- package/dist/version.js.map +1 -0
- package/dist/wsUtils.d.ts +8 -0
- package/dist/wsUtils.js +54 -0
- package/dist/wsUtils.js.map +1 -0
- package/package.json +118 -0
- package/scripts/gen-claude-desktop-config.sh +124 -0
- package/scripts/gen-mcp-config.sh +390 -0
- package/scripts/install-extension.sh +106 -0
- package/scripts/mcp-stdio-shim.cjs +482 -0
- package/scripts/postinstall.mjs +68 -0
- package/scripts/start-all.sh +502 -0
- package/scripts/start-orchestrator.sh +186 -0
- package/scripts/start-remote.sh +126 -0
- package/scripts/start-vps.sh +116 -0
- package/templates/CLAUDE.bridge.md +125 -0
- package/templates/automation-policies/security-first.json +46 -0
- package/templates/automation-policies/strict-lint.json +41 -0
- package/templates/automation-policies/test-driven.json +54 -0
- package/templates/automation-policy.example.json +105 -0
- package/templates/bridge-tools.md +111 -0
- package/templates/dispatch-context.md +33 -0
- package/templates/managed-agent/code-review-agent.md +50 -0
- package/templates/managed-agent/managed-agent-mcp.json +102 -0
- package/templates/recipes/ambient-journal.yaml +11 -0
- package/templates/recipes/daily-status.yaml +21 -0
- package/templates/recipes/lint-on-save.yaml +13 -0
- package/templates/recipes/stale-branches.yaml +18 -0
- package/templates/recipes/watch-failing-tests.yaml +15 -0
- package/templates/scheduled-tasks/dependency-audit/SKILL.md +77 -0
- package/templates/scheduled-tasks/health-check/SKILL.md +73 -0
- 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
|