@intrect/openswarm 0.2.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.md +544 -0
- package/config.example.yaml +107 -0
- package/dist/adapters/base.d.ts +8 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +104 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude.d.ts +13 -0
- package/dist/adapters/claude.d.ts.map +1 -0
- package/dist/adapters/claude.js +318 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +14 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +366 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/cryptoQuantAdapter.d.ts +85 -0
- package/dist/adapters/cryptoQuantAdapter.d.ts.map +1 -0
- package/dist/adapters/cryptoQuantAdapter.js +238 -0
- package/dist/adapters/cryptoQuantAdapter.js.map +1 -0
- package/dist/adapters/index.d.ts +17 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +47 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/processRegistry.d.ts +38 -0
- package/dist/adapters/processRegistry.d.ts.map +1 -0
- package/dist/adapters/processRegistry.js +147 -0
- package/dist/adapters/processRegistry.js.map +1 -0
- package/dist/adapters/streamBuffer.d.ts +59 -0
- package/dist/adapters/streamBuffer.d.ts.map +1 -0
- package/dist/adapters/streamBuffer.js +123 -0
- package/dist/adapters/streamBuffer.js.map +1 -0
- package/dist/adapters/types.d.ts +65 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +6 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/agents/agentBus.d.ts +160 -0
- package/dist/agents/agentBus.d.ts.map +1 -0
- package/dist/agents/agentBus.js +350 -0
- package/dist/agents/agentBus.js.map +1 -0
- package/dist/agents/agentPair.d.ts +210 -0
- package/dist/agents/agentPair.d.ts.map +1 -0
- package/dist/agents/agentPair.js +420 -0
- package/dist/agents/agentPair.js.map +1 -0
- package/dist/agents/auditor.d.ts +27 -0
- package/dist/agents/auditor.d.ts.map +1 -0
- package/dist/agents/auditor.js +237 -0
- package/dist/agents/auditor.js.map +1 -0
- package/dist/agents/cliStreamParser.d.ts +18 -0
- package/dist/agents/cliStreamParser.d.ts.map +1 -0
- package/dist/agents/cliStreamParser.js +156 -0
- package/dist/agents/cliStreamParser.js.map +1 -0
- package/dist/agents/documenter.d.ts +31 -0
- package/dist/agents/documenter.d.ts.map +1 -0
- package/dist/agents/documenter.js +285 -0
- package/dist/agents/documenter.js.map +1 -0
- package/dist/agents/index.d.ts +10 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +10 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/pairMetrics.d.ts +63 -0
- package/dist/agents/pairMetrics.d.ts.map +1 -0
- package/dist/agents/pairMetrics.js +231 -0
- package/dist/agents/pairMetrics.js.map +1 -0
- package/dist/agents/pairPipeline.d.ts +155 -0
- package/dist/agents/pairPipeline.d.ts.map +1 -0
- package/dist/agents/pairPipeline.js +793 -0
- package/dist/agents/pairPipeline.js.map +1 -0
- package/dist/agents/pairWebhook.d.ts +59 -0
- package/dist/agents/pairWebhook.d.ts.map +1 -0
- package/dist/agents/pairWebhook.js +242 -0
- package/dist/agents/pairWebhook.js.map +1 -0
- package/dist/agents/pipelineFormat.d.ts +11 -0
- package/dist/agents/pipelineFormat.d.ts.map +1 -0
- package/dist/agents/pipelineFormat.js +164 -0
- package/dist/agents/pipelineFormat.js.map +1 -0
- package/dist/agents/pipelineGuards.d.ts +23 -0
- package/dist/agents/pipelineGuards.d.ts.map +1 -0
- package/dist/agents/pipelineGuards.js +175 -0
- package/dist/agents/pipelineGuards.js.map +1 -0
- package/dist/agents/reviewer.d.ts +37 -0
- package/dist/agents/reviewer.d.ts.map +1 -0
- package/dist/agents/reviewer.js +213 -0
- package/dist/agents/reviewer.js.map +1 -0
- package/dist/agents/skillDocumenter.d.ts +23 -0
- package/dist/agents/skillDocumenter.d.ts.map +1 -0
- package/dist/agents/skillDocumenter.js +218 -0
- package/dist/agents/skillDocumenter.js.map +1 -0
- package/dist/agents/tester.d.ts +37 -0
- package/dist/agents/tester.d.ts.map +1 -0
- package/dist/agents/tester.js +308 -0
- package/dist/agents/tester.js.map +1 -0
- package/dist/agents/worker.d.ts +30 -0
- package/dist/agents/worker.d.ts.map +1 -0
- package/dist/agents/worker.js +128 -0
- package/dist/agents/worker.js.map +1 -0
- package/dist/automation/autonomousRunner.d.ts +123 -0
- package/dist/automation/autonomousRunner.d.ts.map +1 -0
- package/dist/automation/autonomousRunner.js +1082 -0
- package/dist/automation/autonomousRunner.js.map +1 -0
- package/dist/automation/ciWorker.d.ts +51 -0
- package/dist/automation/ciWorker.d.ts.map +1 -0
- package/dist/automation/ciWorker.js +282 -0
- package/dist/automation/ciWorker.js.map +1 -0
- package/dist/automation/conflictResolver.d.ts +29 -0
- package/dist/automation/conflictResolver.d.ts.map +1 -0
- package/dist/automation/conflictResolver.js +261 -0
- package/dist/automation/conflictResolver.js.map +1 -0
- package/dist/automation/dailyReporter.d.ts +26 -0
- package/dist/automation/dailyReporter.d.ts.map +1 -0
- package/dist/automation/dailyReporter.js +132 -0
- package/dist/automation/dailyReporter.js.map +1 -0
- package/dist/automation/index.d.ts +7 -0
- package/dist/automation/index.d.ts.map +1 -0
- package/dist/automation/index.js +7 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/longRunningMonitor.d.ts +26 -0
- package/dist/automation/longRunningMonitor.d.ts.map +1 -0
- package/dist/automation/longRunningMonitor.js +231 -0
- package/dist/automation/longRunningMonitor.js.map +1 -0
- package/dist/automation/prOwnership.d.ts +18 -0
- package/dist/automation/prOwnership.d.ts.map +1 -0
- package/dist/automation/prOwnership.js +61 -0
- package/dist/automation/prOwnership.js.map +1 -0
- package/dist/automation/prProcessor.d.ts +62 -0
- package/dist/automation/prProcessor.d.ts.map +1 -0
- package/dist/automation/prProcessor.js +700 -0
- package/dist/automation/prProcessor.js.map +1 -0
- package/dist/automation/runnerExecution.d.ts +49 -0
- package/dist/automation/runnerExecution.d.ts.map +1 -0
- package/dist/automation/runnerExecution.js +663 -0
- package/dist/automation/runnerExecution.js.map +1 -0
- package/dist/automation/runnerState.d.ts +170 -0
- package/dist/automation/runnerState.d.ts.map +1 -0
- package/dist/automation/runnerState.js +495 -0
- package/dist/automation/runnerState.js.map +1 -0
- package/dist/automation/runnerTypes.d.ts +46 -0
- package/dist/automation/runnerTypes.d.ts.map +1 -0
- package/dist/automation/runnerTypes.js +5 -0
- package/dist/automation/runnerTypes.js.map +1 -0
- package/dist/automation/scheduler.d.ts +75 -0
- package/dist/automation/scheduler.d.ts.map +1 -0
- package/dist/automation/scheduler.js +394 -0
- package/dist/automation/scheduler.js.map +1 -0
- package/dist/cli/promptHandler.d.ts +13 -0
- package/dist/cli/promptHandler.d.ts.map +1 -0
- package/dist/cli/promptHandler.js +189 -0
- package/dist/cli/promptHandler.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +138 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/config.d.ts +308 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +529 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/eventHub.d.ts +194 -0
- package/dist/core/eventHub.d.ts.map +1 -0
- package/dist/core/eventHub.js +136 -0
- package/dist/core/eventHub.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/service.d.ts +27 -0
- package/dist/core/service.d.ts.map +1 -0
- package/dist/core/service.js +438 -0
- package/dist/core/service.js.map +1 -0
- package/dist/core/traceCollector.d.ts +105 -0
- package/dist/core/traceCollector.d.ts.map +1 -0
- package/dist/core/traceCollector.js +141 -0
- package/dist/core/traceCollector.js.map +1 -0
- package/dist/core/types.d.ts +413 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -0
- package/dist/discord/discordCore.d.ts +104 -0
- package/dist/discord/discordCore.d.ts.map +1 -0
- package/dist/discord/discordCore.js +698 -0
- package/dist/discord/discordCore.js.map +1 -0
- package/dist/discord/discordHandlers.d.ts +86 -0
- package/dist/discord/discordHandlers.d.ts.map +1 -0
- package/dist/discord/discordHandlers.js +849 -0
- package/dist/discord/discordHandlers.js.map +1 -0
- package/dist/discord/discordPair.d.ts +6 -0
- package/dist/discord/discordPair.d.ts.map +1 -0
- package/dist/discord/discordPair.js +567 -0
- package/dist/discord/discordPair.js.map +1 -0
- package/dist/discord/index.d.ts +4 -0
- package/dist/discord/index.d.ts.map +1 -0
- package/dist/discord/index.js +11 -0
- package/dist/discord/index.js.map +1 -0
- package/dist/github/github.d.ts +236 -0
- package/dist/github/github.d.ts.map +1 -0
- package/dist/github/github.js +535 -0
- package/dist/github/github.js.map +1 -0
- package/dist/github/index.d.ts +2 -0
- package/dist/github/index.d.ts.map +1 -0
- package/dist/github/index.js +2 -0
- package/dist/github/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge/analyzer.d.ts +36 -0
- package/dist/knowledge/analyzer.d.ts.map +1 -0
- package/dist/knowledge/analyzer.js +170 -0
- package/dist/knowledge/analyzer.js.map +1 -0
- package/dist/knowledge/gitInfo.d.ts +10 -0
- package/dist/knowledge/gitInfo.d.ts.map +1 -0
- package/dist/knowledge/gitInfo.js +134 -0
- package/dist/knowledge/gitInfo.js.map +1 -0
- package/dist/knowledge/graph.d.ts +45 -0
- package/dist/knowledge/graph.d.ts.map +1 -0
- package/dist/knowledge/graph.js +262 -0
- package/dist/knowledge/graph.js.map +1 -0
- package/dist/knowledge/graphqlExporter.d.ts +64 -0
- package/dist/knowledge/graphqlExporter.d.ts.map +1 -0
- package/dist/knowledge/graphqlExporter.js +333 -0
- package/dist/knowledge/graphqlExporter.js.map +1 -0
- package/dist/knowledge/index.d.ts +58 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/index.js +212 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge/repository.d.ts +64 -0
- package/dist/knowledge/repository.d.ts.map +1 -0
- package/dist/knowledge/repository.js +250 -0
- package/dist/knowledge/repository.js.map +1 -0
- package/dist/knowledge/riskOnAnalyzer.d.ts +79 -0
- package/dist/knowledge/riskOnAnalyzer.d.ts.map +1 -0
- package/dist/knowledge/riskOnAnalyzer.js +243 -0
- package/dist/knowledge/riskOnAnalyzer.js.map +1 -0
- package/dist/knowledge/scanner.d.ts +14 -0
- package/dist/knowledge/scanner.d.ts.map +1 -0
- package/dist/knowledge/scanner.js +350 -0
- package/dist/knowledge/scanner.js.map +1 -0
- package/dist/knowledge/store.d.ts +23 -0
- package/dist/knowledge/store.d.ts.map +1 -0
- package/dist/knowledge/store.js +86 -0
- package/dist/knowledge/store.js.map +1 -0
- package/dist/knowledge/types.d.ts +288 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +111 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/linear/index.d.ts +3 -0
- package/dist/linear/index.d.ts.map +1 -0
- package/dist/linear/index.js +3 -0
- package/dist/linear/index.js.map +1 -0
- package/dist/linear/linear.d.ts +160 -0
- package/dist/linear/linear.d.ts.map +1 -0
- package/dist/linear/linear.js +983 -0
- package/dist/linear/linear.js.map +1 -0
- package/dist/linear/projectUpdater.d.ts +23 -0
- package/dist/linear/projectUpdater.d.ts.map +1 -0
- package/dist/linear/projectUpdater.js +347 -0
- package/dist/linear/projectUpdater.js.map +1 -0
- package/dist/locale/en.d.ts +3 -0
- package/dist/locale/en.d.ts.map +1 -0
- package/dist/locale/en.js +436 -0
- package/dist/locale/en.js.map +1 -0
- package/dist/locale/index.d.ts +28 -0
- package/dist/locale/index.d.ts.map +1 -0
- package/dist/locale/index.js +89 -0
- package/dist/locale/index.js.map +1 -0
- package/dist/locale/ko.d.ts +3 -0
- package/dist/locale/ko.d.ts.map +1 -0
- package/dist/locale/ko.js +436 -0
- package/dist/locale/ko.js.map +1 -0
- package/dist/locale/prompts/en.d.ts +3 -0
- package/dist/locale/prompts/en.d.ts.map +1 -0
- package/dist/locale/prompts/en.js +278 -0
- package/dist/locale/prompts/en.js.map +1 -0
- package/dist/locale/prompts/ko.d.ts +3 -0
- package/dist/locale/prompts/ko.d.ts.map +1 -0
- package/dist/locale/prompts/ko.js +279 -0
- package/dist/locale/prompts/ko.js.map +1 -0
- package/dist/locale/types.d.ts +407 -0
- package/dist/locale/types.d.ts.map +1 -0
- package/dist/locale/types.js +5 -0
- package/dist/locale/types.js.map +1 -0
- package/dist/memory/codex.d.ts +93 -0
- package/dist/memory/codex.d.ts.map +1 -0
- package/dist/memory/codex.js +366 -0
- package/dist/memory/codex.js.map +1 -0
- package/dist/memory/compaction.d.ts +21 -0
- package/dist/memory/compaction.d.ts.map +1 -0
- package/dist/memory/compaction.js +205 -0
- package/dist/memory/compaction.js.map +1 -0
- package/dist/memory/index.d.ts +13 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +13 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/memoryCore.d.ts +178 -0
- package/dist/memory/memoryCore.d.ts.map +1 -0
- package/dist/memory/memoryCore.js +623 -0
- package/dist/memory/memoryCore.js.map +1 -0
- package/dist/memory/memoryOps.d.ts +90 -0
- package/dist/memory/memoryOps.d.ts.map +1 -0
- package/dist/memory/memoryOps.js +606 -0
- package/dist/memory/memoryOps.js.map +1 -0
- package/dist/orchestration/conflictDetector.d.ts +15 -0
- package/dist/orchestration/conflictDetector.d.ts.map +1 -0
- package/dist/orchestration/conflictDetector.js +130 -0
- package/dist/orchestration/conflictDetector.js.map +1 -0
- package/dist/orchestration/decisionEngine.d.ts +177 -0
- package/dist/orchestration/decisionEngine.d.ts.map +1 -0
- package/dist/orchestration/decisionEngine.js +496 -0
- package/dist/orchestration/decisionEngine.js.map +1 -0
- package/dist/orchestration/index.d.ts +5 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +5 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/taskParser.d.ts +67 -0
- package/dist/orchestration/taskParser.d.ts.map +1 -0
- package/dist/orchestration/taskParser.js +542 -0
- package/dist/orchestration/taskParser.js.map +1 -0
- package/dist/orchestration/taskScheduler.d.ts +141 -0
- package/dist/orchestration/taskScheduler.d.ts.map +1 -0
- package/dist/orchestration/taskScheduler.js +317 -0
- package/dist/orchestration/taskScheduler.js.map +1 -0
- package/dist/orchestration/workflow.d.ts +145 -0
- package/dist/orchestration/workflow.d.ts.map +1 -0
- package/dist/orchestration/workflow.js +301 -0
- package/dist/orchestration/workflow.js.map +1 -0
- package/dist/runners/cliRunner.d.ts +11 -0
- package/dist/runners/cliRunner.d.ts.map +1 -0
- package/dist/runners/cliRunner.js +194 -0
- package/dist/runners/cliRunner.js.map +1 -0
- package/dist/support/apiCache.d.ts +85 -0
- package/dist/support/apiCache.d.ts.map +1 -0
- package/dist/support/apiCache.js +163 -0
- package/dist/support/apiCache.js.map +1 -0
- package/dist/support/chat.d.ts +3 -0
- package/dist/support/chat.d.ts.map +1 -0
- package/dist/support/chat.js +304 -0
- package/dist/support/chat.js.map +1 -0
- package/dist/support/chatBackend.d.ts +25 -0
- package/dist/support/chatBackend.d.ts.map +1 -0
- package/dist/support/chatBackend.js +235 -0
- package/dist/support/chatBackend.js.map +1 -0
- package/dist/support/chatMemory.d.ts +71 -0
- package/dist/support/chatMemory.d.ts.map +1 -0
- package/dist/support/chatMemory.js +119 -0
- package/dist/support/chatMemory.js.map +1 -0
- package/dist/support/chatTui.d.ts +3 -0
- package/dist/support/chatTui.d.ts.map +1 -0
- package/dist/support/chatTui.js +998 -0
- package/dist/support/chatTui.js.map +1 -0
- package/dist/support/costTracker.d.ts +29 -0
- package/dist/support/costTracker.d.ts.map +1 -0
- package/dist/support/costTracker.js +113 -0
- package/dist/support/costTracker.js.map +1 -0
- package/dist/support/dashboardHtml.d.ts +3 -0
- package/dist/support/dashboardHtml.d.ts.map +1 -0
- package/dist/support/dashboardHtml.js +2070 -0
- package/dist/support/dashboardHtml.js.map +1 -0
- package/dist/support/delete-beliefs.d.ts +2 -0
- package/dist/support/delete-beliefs.d.ts.map +1 -0
- package/dist/support/delete-beliefs.js +34 -0
- package/dist/support/delete-beliefs.js.map +1 -0
- package/dist/support/dev.d.ts +55 -0
- package/dist/support/dev.d.ts.map +1 -0
- package/dist/support/dev.js +298 -0
- package/dist/support/dev.js.map +1 -0
- package/dist/support/editParser.d.ts +37 -0
- package/dist/support/editParser.d.ts.map +1 -0
- package/dist/support/editParser.js +365 -0
- package/dist/support/editParser.js.map +1 -0
- package/dist/support/gitStatus.d.ts +21 -0
- package/dist/support/gitStatus.d.ts.map +1 -0
- package/dist/support/gitStatus.js +108 -0
- package/dist/support/gitStatus.js.map +1 -0
- package/dist/support/gitTracker.d.ts +30 -0
- package/dist/support/gitTracker.d.ts.map +1 -0
- package/dist/support/gitTracker.js +143 -0
- package/dist/support/gitTracker.js.map +1 -0
- package/dist/support/index.d.ts +13 -0
- package/dist/support/index.d.ts.map +1 -0
- package/dist/support/index.js +13 -0
- package/dist/support/index.js.map +1 -0
- package/dist/support/planner.d.ts +58 -0
- package/dist/support/planner.d.ts.map +1 -0
- package/dist/support/planner.js +395 -0
- package/dist/support/planner.js.map +1 -0
- package/dist/support/projectMapper.d.ts +46 -0
- package/dist/support/projectMapper.d.ts.map +1 -0
- package/dist/support/projectMapper.js +259 -0
- package/dist/support/projectMapper.js.map +1 -0
- package/dist/support/quotaTracker.d.ts +29 -0
- package/dist/support/quotaTracker.d.ts.map +1 -0
- package/dist/support/quotaTracker.js +89 -0
- package/dist/support/quotaTracker.js.map +1 -0
- package/dist/support/rateLimiter.d.ts +101 -0
- package/dist/support/rateLimiter.d.ts.map +1 -0
- package/dist/support/rateLimiter.js +219 -0
- package/dist/support/rateLimiter.js.map +1 -0
- package/dist/support/rollback.d.ts +61 -0
- package/dist/support/rollback.d.ts.map +1 -0
- package/dist/support/rollback.js +328 -0
- package/dist/support/rollback.js.map +1 -0
- package/dist/support/stuckDetector.d.ts +68 -0
- package/dist/support/stuckDetector.d.ts.map +1 -0
- package/dist/support/stuckDetector.js +174 -0
- package/dist/support/stuckDetector.js.map +1 -0
- package/dist/support/timeWindow.d.ts +60 -0
- package/dist/support/timeWindow.d.ts.map +1 -0
- package/dist/support/timeWindow.js +236 -0
- package/dist/support/timeWindow.js.map +1 -0
- package/dist/support/web.d.ts +11 -0
- package/dist/support/web.d.ts.map +1 -0
- package/dist/support/web.js +938 -0
- package/dist/support/web.js.map +1 -0
- package/dist/support/workflowLinear.d.ts +99 -0
- package/dist/support/workflowLinear.d.ts.map +1 -0
- package/dist/support/workflowLinear.js +257 -0
- package/dist/support/workflowLinear.js.map +1 -0
- package/dist/support/worktreeManager.d.ts +20 -0
- package/dist/support/worktreeManager.d.ts.map +1 -0
- package/dist/support/worktreeManager.js +144 -0
- package/dist/support/worktreeManager.js.map +1 -0
- package/dist/taskState/store.d.ts +101 -0
- package/dist/taskState/store.d.ts.map +1 -0
- package/dist/taskState/store.js +346 -0
- package/dist/taskState/store.js.map +1 -0
- package/package.json +70 -0
- package/templates/AGENTS.md +432 -0
- package/templates/BOOT.md +25 -0
- package/templates/BOOTSTRAP.md +50 -0
- package/templates/CHANGELOG_AUDIT.md +74 -0
- package/templates/HEARTBEAT.md +86 -0
- package/templates/IDENTITY.md +27 -0
- package/templates/ISSUE_ANALYSIS.md +31 -0
- package/templates/PR_LAND.md +75 -0
- package/templates/PR_REVIEW.md +97 -0
- package/templates/SOUL.dev.md +52 -0
- package/templates/SOUL.md +81 -0
- package/templates/TOOLS.md +52 -0
- package/templates/USER.md +22 -0
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
// ============================================
|
|
2
|
+
// OpenSwarm - Discord Command Handlers
|
|
3
|
+
//
|
|
4
|
+
// All command handlers (!status, !dev, etc.)
|
|
5
|
+
import { EmbedBuilder, } from 'discord.js';
|
|
6
|
+
import * as linear from '../linear/index.js';
|
|
7
|
+
import * as github from '../github/index.js';
|
|
8
|
+
import * as dev from '../support/dev.js';
|
|
9
|
+
import * as scheduler from '../automation/scheduler.js';
|
|
10
|
+
import * as codex from '../memory/codex.js';
|
|
11
|
+
import * as autonomous from '../automation/autonomousRunner.js';
|
|
12
|
+
import { linearIssueToTask } from '../orchestration/decisionEngine.js';
|
|
13
|
+
import { onPauseAgent, onResumeAgent, getAgentStatus, getGithubRepos, pairModeConfig, formatTimeAgo, } from './discordCore.js';
|
|
14
|
+
import { t, getDateLocale } from '../locale/index.js';
|
|
15
|
+
/**
|
|
16
|
+
* Helper: Reply with Embed for consistent Discord UI
|
|
17
|
+
*/
|
|
18
|
+
async function replyWithEmbed(msg, content, color = 0x00ff41) {
|
|
19
|
+
const embed = new EmbedBuilder()
|
|
20
|
+
.setDescription(content)
|
|
21
|
+
.setColor(color)
|
|
22
|
+
.setTimestamp();
|
|
23
|
+
await msg.reply({ embeds: [embed] });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* !status [session] - Check status
|
|
27
|
+
*/
|
|
28
|
+
export async function handleStatus(msg, sessionName) {
|
|
29
|
+
if (!getAgentStatus) {
|
|
30
|
+
await replyWithEmbed(msg, t('discord.errors.serviceNotInitialized'), 0xff0000);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const statuses = getAgentStatus(sessionName);
|
|
34
|
+
if (statuses.length === 0) {
|
|
35
|
+
await replyWithEmbed(msg, sessionName ? t('discord.errors.sessionNotFound', { name: sessionName || '' }) : t('discord.status.noAgents'), 0xffaa00);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const embed = new EmbedBuilder()
|
|
39
|
+
.setTitle(t('discord.status.title'))
|
|
40
|
+
.setColor(0x00ae86)
|
|
41
|
+
.setTimestamp();
|
|
42
|
+
for (const status of statuses) {
|
|
43
|
+
const stateEmoji = {
|
|
44
|
+
idle: '💤',
|
|
45
|
+
working: '⚙️',
|
|
46
|
+
blocked: '⚠️',
|
|
47
|
+
paused: '⏸️',
|
|
48
|
+
}[status.state];
|
|
49
|
+
const issueInfo = status.currentIssue
|
|
50
|
+
? `\n📋 ${status.currentIssue.identifier}: ${status.currentIssue.title}`
|
|
51
|
+
: `\n📋 ${t('discord.status.noIssueAssigned')}`;
|
|
52
|
+
const lastHB = status.lastHeartbeat
|
|
53
|
+
? `\n🕐 ${t('discord.status.lastHeartbeat', { time: formatTimeAgo(status.lastHeartbeat) })}`
|
|
54
|
+
: '';
|
|
55
|
+
embed.addFields({
|
|
56
|
+
name: `${stateEmoji} ${status.name}`,
|
|
57
|
+
value: `${t('discord.status.stateLabel', { state: status.state })}${issueInfo}${lastHB}`,
|
|
58
|
+
inline: false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
await msg.reply({ embeds: [embed] });
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* !list - (deprecated) tmux session list -> dashboard redirect
|
|
65
|
+
*/
|
|
66
|
+
export async function handleList(msg) {
|
|
67
|
+
await replyWithEmbed(msg, 'Use web dashboard at /dashboard for session management. tmux mode has been removed.', 0xffaa00);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* !run <session> "<task>" - (deprecated) tmux task execution -> !dev redirect
|
|
71
|
+
*/
|
|
72
|
+
export async function handleRun(msg, _args) {
|
|
73
|
+
await replyWithEmbed(msg, 'tmux mode has been removed. Use `!dev <repo> "<task>"` instead.', 0xffaa00);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* !pause <session> - Pause autonomous work
|
|
77
|
+
*/
|
|
78
|
+
export async function handlePause(msg, sessionName) {
|
|
79
|
+
if (!sessionName) {
|
|
80
|
+
await replyWithEmbed(msg, t('discord.pause.usage'), 0xffaa00);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (onPauseAgent) {
|
|
84
|
+
onPauseAgent(sessionName);
|
|
85
|
+
await replyWithEmbed(msg, `⏸️ ${t('discord.pause.paused', { name: sessionName })}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* !resume <session> - Resume autonomous work
|
|
90
|
+
*/
|
|
91
|
+
export async function handleResume(msg, sessionName) {
|
|
92
|
+
if (!sessionName) {
|
|
93
|
+
await replyWithEmbed(msg, t('discord.resume.usage'), 0xffaa00);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (onResumeAgent) {
|
|
97
|
+
onResumeAgent(sessionName);
|
|
98
|
+
await replyWithEmbed(msg, `▶️ ${t('discord.resume.resumed', { name: sessionName })}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* !issues [session] - List Linear issues
|
|
103
|
+
*/
|
|
104
|
+
export async function handleIssues(msg, sessionName) {
|
|
105
|
+
try {
|
|
106
|
+
// Validate session name
|
|
107
|
+
if (sessionName) {
|
|
108
|
+
const status = getAgentStatus?.(sessionName);
|
|
109
|
+
if (!status || status.length === 0) {
|
|
110
|
+
await replyWithEmbed(msg, t('discord.errors.sessionNotFound', { name: sessionName }), 0xff0000);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const agentLabel = sessionName || undefined;
|
|
115
|
+
const issues = await linear.getMyIssues(agentLabel ? { agentLabel, slim: true } : { slim: true });
|
|
116
|
+
if (issues.length === 0) {
|
|
117
|
+
await replyWithEmbed(msg, t('discord.issues.noIssues'), 0xffaa00);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// Priority emoji mapping (Linear: 0=None, 1=Urgent, 2=High, 3=Normal, 4=Low)
|
|
121
|
+
const priorityEmoji = {
|
|
122
|
+
0: '⚪',
|
|
123
|
+
1: '🔴',
|
|
124
|
+
2: '🟠',
|
|
125
|
+
3: '🟡',
|
|
126
|
+
4: '🟢',
|
|
127
|
+
};
|
|
128
|
+
// State color mapping
|
|
129
|
+
const stateColor = {
|
|
130
|
+
'Todo': 0x808080,
|
|
131
|
+
'In Progress': 0x3498db,
|
|
132
|
+
'In Review': 0x9b59b6,
|
|
133
|
+
'Done': 0x2ecc71,
|
|
134
|
+
'Backlog': 0x95a5a6,
|
|
135
|
+
};
|
|
136
|
+
// Pagination (max 10 per embed)
|
|
137
|
+
const ITEMS_PER_PAGE = 10;
|
|
138
|
+
const totalPages = Math.ceil(issues.length / ITEMS_PER_PAGE);
|
|
139
|
+
const embeds = [];
|
|
140
|
+
for (let page = 0; page < totalPages; page++) {
|
|
141
|
+
const startIdx = page * ITEMS_PER_PAGE;
|
|
142
|
+
const endIdx = Math.min(startIdx + ITEMS_PER_PAGE, issues.length);
|
|
143
|
+
const pageIssues = issues.slice(startIdx, endIdx);
|
|
144
|
+
const embed = new EmbedBuilder()
|
|
145
|
+
.setTitle(sessionName
|
|
146
|
+
? t('discord.issues.sessionIssues', { session: sessionName })
|
|
147
|
+
: t('discord.issues.myIssues'))
|
|
148
|
+
.setColor(stateColor[pageIssues[0]?.state] ?? 0x3498db)
|
|
149
|
+
.setTimestamp();
|
|
150
|
+
if (totalPages > 1) {
|
|
151
|
+
embed.setFooter({ text: t('discord.issues.page', { current: page + 1, total: totalPages }) });
|
|
152
|
+
}
|
|
153
|
+
const fields = pageIssues.map((issue) => {
|
|
154
|
+
const priority = priorityEmoji[issue.priority] ?? '⚪';
|
|
155
|
+
const stateEmoji = {
|
|
156
|
+
'Todo': '📝',
|
|
157
|
+
'In Progress': '⚙️',
|
|
158
|
+
'In Review': '👀',
|
|
159
|
+
'Done': '✅',
|
|
160
|
+
'Backlog': '📦',
|
|
161
|
+
}[issue.state] ?? '📋';
|
|
162
|
+
let value = `${priority} **${issue.identifier}**: ${issue.title}\n`;
|
|
163
|
+
value += `${stateEmoji} ${issue.state}`;
|
|
164
|
+
if (issue.project) {
|
|
165
|
+
value += ` · ${issue.project.name}`;
|
|
166
|
+
}
|
|
167
|
+
if (issue.labels && issue.labels.length > 0) {
|
|
168
|
+
value += `\n🏷️ ${issue.labels.join(', ')}`;
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
name: `\u200b`,
|
|
172
|
+
value,
|
|
173
|
+
inline: false,
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
embed.addFields(...fields);
|
|
177
|
+
embeds.push(embed);
|
|
178
|
+
}
|
|
179
|
+
// Send embeds (all at once or split)
|
|
180
|
+
if (embeds.length === 1) {
|
|
181
|
+
await msg.reply({ embeds });
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// First one as reply, rest as messages
|
|
185
|
+
await msg.reply({ embeds: [embeds[0]] });
|
|
186
|
+
// Send additional embeds (paging)
|
|
187
|
+
for (let i = 1; i < embeds.length; i++) {
|
|
188
|
+
const channel = msg.channel;
|
|
189
|
+
if (channel?.send) {
|
|
190
|
+
await channel.send({ embeds: [embeds[i]] });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
197
|
+
await replyWithEmbed(msg, t('discord.issues.fetchError', { error: errorMsg }), 0xff0000);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* !issue <ID> - View Linear issue details
|
|
202
|
+
*/
|
|
203
|
+
export async function handleIssue(msg, issueId) {
|
|
204
|
+
try {
|
|
205
|
+
if (!issueId) {
|
|
206
|
+
await replyWithEmbed(msg, t('discord.issues.usage'), 0xffaa00);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const issue = await linear.getIssue(issueId);
|
|
210
|
+
if (!issue) {
|
|
211
|
+
await replyWithEmbed(msg, t('discord.issue.notFound', { id: issueId }), 0xff0000);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// Priority labels
|
|
215
|
+
const priorityLabel = {
|
|
216
|
+
0: 'None',
|
|
217
|
+
1: 'Urgent',
|
|
218
|
+
2: 'High',
|
|
219
|
+
3: 'Normal',
|
|
220
|
+
4: 'Low',
|
|
221
|
+
};
|
|
222
|
+
// State color mapping
|
|
223
|
+
const stateColor = {
|
|
224
|
+
'Todo': 0x808080,
|
|
225
|
+
'In Progress': 0x3498db,
|
|
226
|
+
'In Review': 0x9b59b6,
|
|
227
|
+
'Done': 0x2ecc71,
|
|
228
|
+
'Backlog': 0x95a5a6,
|
|
229
|
+
};
|
|
230
|
+
const embed = new EmbedBuilder()
|
|
231
|
+
.setTitle(`${issue.identifier}: ${issue.title}`)
|
|
232
|
+
.setColor(stateColor[issue.state] ?? 0x3498db)
|
|
233
|
+
.setTimestamp();
|
|
234
|
+
// Description
|
|
235
|
+
if (issue.description) {
|
|
236
|
+
const desc = issue.description.length > 1024
|
|
237
|
+
? issue.description.slice(0, 1021) + '...'
|
|
238
|
+
: issue.description;
|
|
239
|
+
embed.addFields({
|
|
240
|
+
name: '📝 Description',
|
|
241
|
+
value: desc,
|
|
242
|
+
inline: false,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
// State, priority, project
|
|
246
|
+
const stateEmoji = {
|
|
247
|
+
'Todo': '📝',
|
|
248
|
+
'In Progress': '⚙️',
|
|
249
|
+
'In Review': '👀',
|
|
250
|
+
'Done': '✅',
|
|
251
|
+
'Backlog': '📦',
|
|
252
|
+
}[issue.state] ?? '📋';
|
|
253
|
+
let infoValue = `${stateEmoji} ${t('discord.issue.stateLabel', { state: issue.state })}`;
|
|
254
|
+
infoValue += `\n⭐ ${t('discord.issues.priorityLabel', { priority: priorityLabel[issue.priority] ?? 'Unknown' })}`;
|
|
255
|
+
if (issue.project) {
|
|
256
|
+
infoValue += `\n📦 ${t('discord.issues.projectLabel', { project: issue.project.name })}`;
|
|
257
|
+
}
|
|
258
|
+
if (issue.labels && issue.labels.length > 0) {
|
|
259
|
+
infoValue += `\n🏷️ ${t('discord.issues.labelsLabel', { labels: issue.labels.join(', ') })}`;
|
|
260
|
+
}
|
|
261
|
+
embed.addFields({
|
|
262
|
+
name: '📊 Details',
|
|
263
|
+
value: infoValue,
|
|
264
|
+
inline: false,
|
|
265
|
+
});
|
|
266
|
+
// Show comments
|
|
267
|
+
if (issue.comments && issue.comments.length > 0) {
|
|
268
|
+
const commentSummary = issue.comments.slice(0, 3).map((comment, idx) => {
|
|
269
|
+
const preview = comment.body.length > 100
|
|
270
|
+
? comment.body.slice(0, 97) + '...'
|
|
271
|
+
: comment.body;
|
|
272
|
+
const createdAt = new Date(comment.createdAt).toLocaleDateString(getDateLocale());
|
|
273
|
+
return `${idx + 1}. ${preview}\n _${createdAt}_`;
|
|
274
|
+
}).join('\n\n');
|
|
275
|
+
const commentValue = issue.comments.length > 3
|
|
276
|
+
? `${commentSummary}\n\n_+${issue.comments.length - 3} more..._`
|
|
277
|
+
: commentSummary;
|
|
278
|
+
embed.addFields({
|
|
279
|
+
name: `💬 ${t('discord.issues.commentsCount', { count: issue.comments.length })}`,
|
|
280
|
+
value: commentValue,
|
|
281
|
+
inline: false,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
embed.addFields({
|
|
286
|
+
name: '💬 Comments',
|
|
287
|
+
value: t('discord.issue.noComments'),
|
|
288
|
+
inline: false,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
await msg.reply({ embeds: [embed] });
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
295
|
+
await replyWithEmbed(msg, t('discord.issue.fetchError', { error: errorMsg }), 0xff0000);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* !log <session> [lines] - (deprecated) tmux logs -> dashboard redirect
|
|
300
|
+
*/
|
|
301
|
+
export async function handleLog(msg, _sessionName, _lines) {
|
|
302
|
+
await replyWithEmbed(msg, 'tmux mode has been removed. Use web dashboard at /dashboard for logs.', 0xffaa00);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* !ci - Check GitHub CI status
|
|
306
|
+
*/
|
|
307
|
+
export async function handleCI(msg) {
|
|
308
|
+
const repos = getGithubRepos?.() ?? [];
|
|
309
|
+
if (repos.length === 0) {
|
|
310
|
+
await replyWithEmbed(msg, t('discord.ci.noRepos'), 0xffaa00);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
await replyWithEmbed(msg, `🔍 ${t('discord.ci.checking')}`);
|
|
314
|
+
const summary = await github.summarizeCIFailures(repos);
|
|
315
|
+
await replyWithEmbed(msg, summary);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* !notifications - Check GitHub notifications
|
|
319
|
+
*/
|
|
320
|
+
export async function handleNotifications(msg) {
|
|
321
|
+
await replyWithEmbed(msg, `🔍 ${t('discord.notifications.checking')}`);
|
|
322
|
+
const summary = await github.summarizeNotifications();
|
|
323
|
+
await replyWithEmbed(msg, summary);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* !dev <repo> "<task>" - Run dev task in a specific repository
|
|
327
|
+
*/
|
|
328
|
+
export async function handleDev(msg, args) {
|
|
329
|
+
// !dev list - Known repo list (redirects to repos)
|
|
330
|
+
if (args[0] === 'list') {
|
|
331
|
+
await handleRepos(msg);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
// !dev scan - Scan ~/dev
|
|
335
|
+
if (args[0] === 'scan') {
|
|
336
|
+
const repos = dev.scanDevRepos();
|
|
337
|
+
if (repos.length === 0) {
|
|
338
|
+
await replyWithEmbed(msg, t('discord.dev.noRepos'), 0xffaa00);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
await replyWithEmbed(msg, `${t('discord.dev.repoList')}\n${repos.map(r => `- ${r}`).join('\n')}`);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
// !dev <repo> "<task>" parsing
|
|
345
|
+
const repo = args[0];
|
|
346
|
+
const taskMatch = msg.content.match(/!dev \S+ "(.+)"/s);
|
|
347
|
+
const task = taskMatch?.[1];
|
|
348
|
+
if (!repo || !task) {
|
|
349
|
+
await replyWithEmbed(msg, t('discord.dev.usage'), 0xffaa00);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
// Verify path
|
|
353
|
+
const resolvedPath = dev.resolveRepoPath(repo);
|
|
354
|
+
if (!resolvedPath) {
|
|
355
|
+
await replyWithEmbed(msg, t('discord.errors.repoNotFound', { repo }), 0xff0000);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// Task start notification
|
|
359
|
+
await replyWithEmbed(msg, `🚀 ${t('discord.dev.taskStarting', { repo, path: resolvedPath, task: task.slice(0, 100) + (task.length > 100 ? '...' : '') })}`);
|
|
360
|
+
// For collecting progress updates
|
|
361
|
+
let progressChunks = [];
|
|
362
|
+
let _lastProgressMsg = null;
|
|
363
|
+
let progressTimer = null;
|
|
364
|
+
// Execute task
|
|
365
|
+
const result = await dev.runDevTask(repo, task, msg.author.username,
|
|
366
|
+
// onProgress: intermediate progress notification every 10 seconds
|
|
367
|
+
(chunk) => {
|
|
368
|
+
progressChunks.push(chunk);
|
|
369
|
+
if (!progressTimer) {
|
|
370
|
+
progressTimer = setTimeout(async () => {
|
|
371
|
+
const combined = progressChunks.join('').slice(-500);
|
|
372
|
+
if (combined.trim()) {
|
|
373
|
+
try {
|
|
374
|
+
_lastProgressMsg = await msg.reply(`${t('discord.dev.inProgress', { repo })}\n\`\`\`\n${combined}\n\`\`\``);
|
|
375
|
+
}
|
|
376
|
+
catch { /* ignore */ }
|
|
377
|
+
}
|
|
378
|
+
progressChunks = [];
|
|
379
|
+
progressTimer = null;
|
|
380
|
+
}, 10000);
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
// onComplete: send result on completion
|
|
384
|
+
async (output, exitCode) => {
|
|
385
|
+
if (progressTimer) {
|
|
386
|
+
clearTimeout(progressTimer);
|
|
387
|
+
}
|
|
388
|
+
// Split result for sending (Discord 2000 char limit)
|
|
389
|
+
const MAX_LEN = 1800;
|
|
390
|
+
const truncated = output.length > MAX_LEN * 3
|
|
391
|
+
? `...(${output.length - MAX_LEN * 3} chars omitted)\n\n${output.slice(-MAX_LEN * 3)}`
|
|
392
|
+
: output;
|
|
393
|
+
const statusEmoji = exitCode === 0 ? '✅' : '⚠️';
|
|
394
|
+
const header = `${statusEmoji} ${t('discord.dev.completed', { repo, exitCode: exitCode ?? 'unknown' })}`;
|
|
395
|
+
// If result is short, send at once
|
|
396
|
+
if (truncated.length <= MAX_LEN) {
|
|
397
|
+
await msg.reply(`${header}\n\`\`\`\n${truncated || t('discord.dev.noOutput')}\n\`\`\``);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
// If result is long, split
|
|
401
|
+
await msg.reply(header);
|
|
402
|
+
const chunks = [];
|
|
403
|
+
for (let i = 0; i < truncated.length; i += MAX_LEN) {
|
|
404
|
+
chunks.push(truncated.slice(i, i + MAX_LEN));
|
|
405
|
+
}
|
|
406
|
+
for (let i = 0; i < Math.min(chunks.length, 3); i++) {
|
|
407
|
+
await msg.reply(`\`\`\`\n${chunks[i]}\n\`\`\``);
|
|
408
|
+
}
|
|
409
|
+
if (chunks.length > 3) {
|
|
410
|
+
await msg.reply(t('discord.dev.outputTooLong', { shown: 3, total: chunks.length }));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
if ('error' in result) {
|
|
415
|
+
await msg.reply(`❌ ${result.error}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* !repos - List known repositories
|
|
420
|
+
*/
|
|
421
|
+
export async function handleRepos(msg) {
|
|
422
|
+
const repos = dev.listKnownRepos();
|
|
423
|
+
const embed = new EmbedBuilder()
|
|
424
|
+
.setTitle(t('discord.repos.title'))
|
|
425
|
+
.setColor(0x00ae86)
|
|
426
|
+
.setDescription(t('discord.repos.description'));
|
|
427
|
+
const available = repos.filter(r => r.exists);
|
|
428
|
+
const unavailable = repos.filter(r => !r.exists);
|
|
429
|
+
if (available.length > 0) {
|
|
430
|
+
embed.addFields({
|
|
431
|
+
name: `✅ ${t('discord.repos.available')}`,
|
|
432
|
+
value: available.map(r => `\`${r.alias}\` → ${r.path}`).join('\n'),
|
|
433
|
+
inline: false,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
if (unavailable.length > 0) {
|
|
437
|
+
embed.addFields({
|
|
438
|
+
name: `❌ ${t('discord.repos.unavailable')}`,
|
|
439
|
+
value: unavailable.map(r => `\`${r.alias}\` → ${r.path}`).join('\n'),
|
|
440
|
+
inline: false,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
embed.addFields({
|
|
444
|
+
name: `💡 ${t('discord.repos.tip')}`,
|
|
445
|
+
value: t('discord.repos.tipContent'),
|
|
446
|
+
inline: false,
|
|
447
|
+
});
|
|
448
|
+
await msg.reply({ embeds: [embed] });
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* !tasks - List running dev tasks
|
|
452
|
+
*/
|
|
453
|
+
export async function handleTasks(msg) {
|
|
454
|
+
const tasks = dev.getActiveTasks();
|
|
455
|
+
if (tasks.length === 0) {
|
|
456
|
+
await msg.reply(t('discord.tasks.noTasks'));
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const embed = new EmbedBuilder()
|
|
460
|
+
.setTitle(t('discord.tasks.title'))
|
|
461
|
+
.setColor(0xffaa00);
|
|
462
|
+
for (const task of tasks) {
|
|
463
|
+
const elapsed = Math.floor((Date.now() - task.startedAt) / 1000);
|
|
464
|
+
embed.addFields({
|
|
465
|
+
name: `${task.repo}`,
|
|
466
|
+
value: `ID: \`${task.taskId}\`\n${t('discord.tasks.path', { path: task.path })}\n${t('discord.tasks.requester', { user: task.requestedBy })}\n${t('discord.tasks.elapsed', { seconds: elapsed })}`,
|
|
467
|
+
inline: false,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
embed.setFooter({ text: t('discord.tasks.cancelHint') });
|
|
471
|
+
await msg.reply({ embeds: [embed] });
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* !cancel <taskId> - Cancel task
|
|
475
|
+
*/
|
|
476
|
+
export async function handleCancel(msg, taskId) {
|
|
477
|
+
if (!taskId) {
|
|
478
|
+
await msg.reply(t('discord.cancel.usage'));
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const success = dev.cancelTask(taskId);
|
|
482
|
+
if (success) {
|
|
483
|
+
await msg.reply(`⏹️ ${t('discord.cancel.cancelled', { id: taskId })}`);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
await msg.reply(`❌ ${t('discord.cancel.notFound', { id: taskId })}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* !limits - Agent daily limit status
|
|
491
|
+
*/
|
|
492
|
+
export async function handleLimits(msg) {
|
|
493
|
+
const remaining = linear.getRemainingDailyIssues();
|
|
494
|
+
const used = linear.getDailyIssueCount();
|
|
495
|
+
const total = 10;
|
|
496
|
+
const progressBar = '█'.repeat(used) + '░'.repeat(remaining);
|
|
497
|
+
const embed = new EmbedBuilder()
|
|
498
|
+
.setTitle(t('discord.limits.title'))
|
|
499
|
+
.setColor(remaining > 3 ? 0x00ae86 : remaining > 0 ? 0xffaa00 : 0xff0000)
|
|
500
|
+
.addFields({
|
|
501
|
+
name: t('discord.limits.issueCreation'),
|
|
502
|
+
value: `${progressBar} ${used}/${total}\n${t('discord.limits.remaining', { n: remaining })}`,
|
|
503
|
+
inline: false,
|
|
504
|
+
})
|
|
505
|
+
.setFooter({ text: t('discord.limits.resetNote') })
|
|
506
|
+
.setTimestamp();
|
|
507
|
+
await msg.reply({ embeds: [embed] });
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* !schedule - Schedule management
|
|
511
|
+
*/
|
|
512
|
+
export async function handleSchedule(msg, args) {
|
|
513
|
+
const subCommand = args[0];
|
|
514
|
+
// !schedule list or !schedule (list)
|
|
515
|
+
if (!subCommand || subCommand === 'list') {
|
|
516
|
+
const schedules = await scheduler.listSchedules();
|
|
517
|
+
const formatted = scheduler.formatScheduleList(schedules);
|
|
518
|
+
const embed = new EmbedBuilder()
|
|
519
|
+
.setTitle(t('discord.schedule.title'))
|
|
520
|
+
.setDescription(formatted)
|
|
521
|
+
.setColor(0x00ae86)
|
|
522
|
+
.setTimestamp();
|
|
523
|
+
await msg.reply({ embeds: [embed] });
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
// !schedule run <name> - Run immediately
|
|
527
|
+
if (subCommand === 'run') {
|
|
528
|
+
const name = args[1];
|
|
529
|
+
if (!name) {
|
|
530
|
+
await msg.reply(t('discord.schedule.runUsage'));
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const success = await scheduler.runNow(name);
|
|
534
|
+
if (success) {
|
|
535
|
+
await msg.reply(`▶️ ${t('discord.schedule.runStarted', { name })}`);
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
await msg.reply(`❌ ${t('discord.schedule.notFound', { name })}`);
|
|
539
|
+
}
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
// !schedule toggle <name> - Enable/disable
|
|
543
|
+
if (subCommand === 'toggle') {
|
|
544
|
+
const name = args[1];
|
|
545
|
+
if (!name) {
|
|
546
|
+
await msg.reply(t('discord.schedule.toggleUsage'));
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const job = await scheduler.toggleSchedule(name);
|
|
550
|
+
if (job) {
|
|
551
|
+
const status = job.enabled ? t('discord.schedule.toggleEnabled', { name: job.name }) : t('discord.schedule.toggleDisabled', { name: job.name });
|
|
552
|
+
await msg.reply(status);
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
await msg.reply(`❌ ${t('discord.schedule.notFound', { name })}`);
|
|
556
|
+
}
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
// !schedule add <name> <project> <interval> "<prompt>"
|
|
560
|
+
if (subCommand === 'add') {
|
|
561
|
+
const name = args[1];
|
|
562
|
+
const projectPath = args[2];
|
|
563
|
+
const interval = args[3];
|
|
564
|
+
const promptMatch = msg.content.match(/!schedule add \S+ \S+ \S+ "(.+)"/s);
|
|
565
|
+
const prompt = promptMatch?.[1];
|
|
566
|
+
if (!name || !projectPath || !interval || !prompt) {
|
|
567
|
+
await msg.reply(t('discord.schedule.addUsage'));
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
try {
|
|
571
|
+
const job = await scheduler.addSchedule(name, projectPath, prompt, interval, msg.author.username);
|
|
572
|
+
await msg.reply(`✅ ${t('discord.schedule.addSuccess', { name: job.name, schedule: job.schedule })}`);
|
|
573
|
+
}
|
|
574
|
+
catch (err) {
|
|
575
|
+
await msg.reply(`❌ ${t('discord.schedule.addFailed', { error: err instanceof Error ? err.message : String(err) })}`);
|
|
576
|
+
}
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
// !schedule remove <name>
|
|
580
|
+
if (subCommand === 'remove' || subCommand === 'delete') {
|
|
581
|
+
const name = args[1];
|
|
582
|
+
if (!name) {
|
|
583
|
+
await msg.reply(t('discord.schedule.removeUsage'));
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
const success = await scheduler.removeSchedule(name);
|
|
587
|
+
if (success) {
|
|
588
|
+
await msg.reply(`🗑️ ${t('discord.schedule.removeSuccess', { name })}`);
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
await msg.reply(`❌ ${t('discord.schedule.notFound', { name })}`);
|
|
592
|
+
}
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
// Unknown subcommand
|
|
596
|
+
await msg.reply(t('discord.schedule.helpText'));
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* !codex - Session record management
|
|
600
|
+
*/
|
|
601
|
+
export async function handleCodex(msg, args) {
|
|
602
|
+
const subCommand = args[0];
|
|
603
|
+
// !codex or !codex list - Recent session list
|
|
604
|
+
if (!subCommand || subCommand === 'list') {
|
|
605
|
+
const recent = await codex.getRecentSessions(10);
|
|
606
|
+
if (recent.length === 0) {
|
|
607
|
+
await msg.reply(t('discord.codex.noSessions'));
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const embed = new EmbedBuilder()
|
|
611
|
+
.setTitle(t('discord.codex.title'))
|
|
612
|
+
.setDescription(recent.join('\n'))
|
|
613
|
+
.setColor(0x9b59b6)
|
|
614
|
+
.setFooter({ text: t('discord.codex.pathLabel', { path: codex.getCodexPath() }) })
|
|
615
|
+
.setTimestamp();
|
|
616
|
+
await msg.reply({ embeds: [embed] });
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
// !codex save "<title>" [tags...] - Save current session
|
|
620
|
+
if (subCommand === 'save') {
|
|
621
|
+
const titleMatch = msg.content.match(/!codex save "(.+?)"/);
|
|
622
|
+
const title = titleMatch?.[1];
|
|
623
|
+
if (!title) {
|
|
624
|
+
await msg.reply(t('discord.codex.saveUsage'));
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
// Extract tags (words after the title)
|
|
628
|
+
const afterTitle = msg.content.slice(msg.content.indexOf('"', msg.content.indexOf('"') + 1) + 1).trim();
|
|
629
|
+
const tags = afterTitle.split(/\s+/).filter(t => t.length > 0);
|
|
630
|
+
// Session save request message
|
|
631
|
+
await msg.reply(t('discord.codex.saving', { title, tags: tags.length > 0 ? tags.map(tag => `\`${tag}\``).join(' ') : t('discord.codex.noTags') }));
|
|
632
|
+
// Actual save should be called after Claude completes work
|
|
633
|
+
// Here we save an empty session (can be updated later)
|
|
634
|
+
try {
|
|
635
|
+
const { summaryPath } = await codex.quickSave({
|
|
636
|
+
title,
|
|
637
|
+
tags,
|
|
638
|
+
result: 'success',
|
|
639
|
+
});
|
|
640
|
+
await msg.reply(`✅ ${t('discord.codex.saveSuccess', { path: summaryPath })}`);
|
|
641
|
+
}
|
|
642
|
+
catch (err) {
|
|
643
|
+
await msg.reply(`❌ ${t('discord.codex.saveFailed', { error: err instanceof Error ? err.message : String(err) })}`);
|
|
644
|
+
}
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
// !codex path - Check path
|
|
648
|
+
if (subCommand === 'path') {
|
|
649
|
+
await msg.reply(`📁 ${t('discord.codex.pathLabel', { path: codex.getCodexPath() })}`);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
// Unknown subcommand
|
|
653
|
+
await msg.reply(t('discord.codex.helpText'));
|
|
654
|
+
}
|
|
655
|
+
// Autonomous Runner Commands
|
|
656
|
+
/**
|
|
657
|
+
* !auto - Autonomous execution mode management
|
|
658
|
+
*/
|
|
659
|
+
export async function handleAuto(msg, args) {
|
|
660
|
+
const subCommand = args[0];
|
|
661
|
+
// !auto status or !auto - Check status
|
|
662
|
+
if (!subCommand || subCommand === 'status') {
|
|
663
|
+
try {
|
|
664
|
+
const runner = autonomous.getRunner();
|
|
665
|
+
const stats = runner.getStats();
|
|
666
|
+
const embed = new EmbedBuilder()
|
|
667
|
+
.setTitle(t('discord.auto.title'))
|
|
668
|
+
.setColor(stats.isRunning ? 0x00AE86 : 0x95A5A6)
|
|
669
|
+
.addFields({ name: t('discord.auto.statusLabel'), value: stats.isRunning ? `✅ ${t('discord.auto.statusRunning')}` : `⏹️ ${t('discord.auto.statusStopped')}`, inline: true }, { name: t('discord.auto.completedFailed'), value: `${stats.engineStats.totalCompleted}/${stats.engineStats.totalFailed}`, inline: true }, { name: t('discord.auto.pendingApprovalLabel'), value: stats.pendingApproval ? `⏳ ${t('discord.auto.pendingApproval')}` : t('discord.auto.noPending'), inline: true })
|
|
670
|
+
.setTimestamp();
|
|
671
|
+
if (stats.lastHeartbeat > 0) {
|
|
672
|
+
embed.addFields({
|
|
673
|
+
name: t('discord.auto.lastHeartbeatLabel'),
|
|
674
|
+
value: new Date(stats.lastHeartbeat).toLocaleString(getDateLocale()),
|
|
675
|
+
inline: false,
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
await msg.reply({ embeds: [embed] });
|
|
679
|
+
}
|
|
680
|
+
catch {
|
|
681
|
+
await msg.reply(t('discord.auto.notInitialized'));
|
|
682
|
+
}
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
// !auto start [schedule] [--pair] - Start
|
|
686
|
+
if (subCommand === 'start') {
|
|
687
|
+
// Check --pair option
|
|
688
|
+
const hasPairFlag = args.includes('--pair') || args.includes('pair');
|
|
689
|
+
const scheduleArg = args.find(a => a !== 'start' && a !== '--pair' && a !== 'pair');
|
|
690
|
+
const schedule = scheduleArg || '*/30 * * * *'; // Default: every 30 minutes
|
|
691
|
+
const startingMsg = hasPairFlag ? t('discord.auto.startingPair') : t('discord.auto.startingSolo');
|
|
692
|
+
await msg.reply(`🚀 ${startingMsg}\nSchedule: \`${schedule}\``);
|
|
693
|
+
try {
|
|
694
|
+
// Register Discord reporter
|
|
695
|
+
autonomous.setDiscordReporter(async (content) => {
|
|
696
|
+
const channel = msg.channel;
|
|
697
|
+
if (typeof content === 'string') {
|
|
698
|
+
await channel.send(content);
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
await channel.send(content);
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
// Register Linear fetcher
|
|
705
|
+
autonomous.setLinearFetcher(async () => {
|
|
706
|
+
try {
|
|
707
|
+
const issues = await linear.getMyIssues({ slim: true, timeoutMs: 30000 });
|
|
708
|
+
return issues.map((issue) => linearIssueToTask({
|
|
709
|
+
id: issue.id,
|
|
710
|
+
identifier: issue.identifier,
|
|
711
|
+
title: issue.title,
|
|
712
|
+
description: issue.description,
|
|
713
|
+
priority: issue.priority || 3,
|
|
714
|
+
dueDate: issue.dueDate,
|
|
715
|
+
state: issue.state,
|
|
716
|
+
project: issue.project ? {
|
|
717
|
+
id: issue.project.id,
|
|
718
|
+
name: issue.project.name,
|
|
719
|
+
} : undefined,
|
|
720
|
+
}));
|
|
721
|
+
}
|
|
722
|
+
catch (err) {
|
|
723
|
+
console.error('Linear fetch error:', err);
|
|
724
|
+
return [];
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
// Start runner
|
|
728
|
+
console.log(`[Auto] Starting with pairMode: ${hasPairFlag}`);
|
|
729
|
+
await autonomous.startAutonomous({
|
|
730
|
+
linearTeamId: process.env.LINEAR_TEAM_ID || '',
|
|
731
|
+
allowedProjects: ['~/dev/OpenSwarm', '~/dev/tools/pykis', '~/dev'],
|
|
732
|
+
heartbeatSchedule: schedule,
|
|
733
|
+
autoExecute: true, // Auto-execute (no approval needed)
|
|
734
|
+
maxConsecutiveTasks: 3,
|
|
735
|
+
cooldownSeconds: 300,
|
|
736
|
+
dryRun: false,
|
|
737
|
+
pairMode: hasPairFlag,
|
|
738
|
+
pairMaxAttempts: pairModeConfig?.maxAttempts ?? 3,
|
|
739
|
+
maxConcurrentTasks: 4,
|
|
740
|
+
enableDecomposition: true,
|
|
741
|
+
decompositionThresholdMinutes: 30,
|
|
742
|
+
worktreeMode: true,
|
|
743
|
+
});
|
|
744
|
+
const startMsg = hasPairFlag
|
|
745
|
+
? `✅ ${t('discord.auto.startedPair')}`
|
|
746
|
+
: `✅ ${t('discord.auto.startedSolo')}`;
|
|
747
|
+
await msg.reply(startMsg);
|
|
748
|
+
}
|
|
749
|
+
catch (err) {
|
|
750
|
+
await msg.reply(`❌ ${t('discord.errors.startFailed', { error: err instanceof Error ? err.message : String(err) })}`);
|
|
751
|
+
}
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
// !auto stop - Stop
|
|
755
|
+
if (subCommand === 'stop') {
|
|
756
|
+
autonomous.stopAutonomous();
|
|
757
|
+
await msg.reply(`⏹️ ${t('discord.auto.stopped')}`);
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
// !auto run - Run heartbeat immediately
|
|
761
|
+
if (subCommand === 'run') {
|
|
762
|
+
try {
|
|
763
|
+
const runner = autonomous.getRunner();
|
|
764
|
+
await msg.reply(`🔄 ${t('discord.auto.runningHeartbeat')}`);
|
|
765
|
+
await runner.runNow();
|
|
766
|
+
}
|
|
767
|
+
catch {
|
|
768
|
+
await msg.reply(`❌ ${t('discord.errors.runnerNotStarted')}`);
|
|
769
|
+
}
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
// !auto approve on/off - Toggle auto-approval
|
|
773
|
+
if (subCommand === 'approve' && (args[1] === 'on' || args[1] === 'off')) {
|
|
774
|
+
const autoApprove = args[1] === 'on';
|
|
775
|
+
await msg.reply(`Restart required to switch to ${autoApprove ? '⚠️ auto-execute' : '✅ manual approval'} mode.`);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
// Help
|
|
779
|
+
await msg.reply(t('discord.auto.helpText'));
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* !approve - Approve pending task
|
|
783
|
+
*/
|
|
784
|
+
export async function handleApprove(msg) {
|
|
785
|
+
try {
|
|
786
|
+
const runner = autonomous.getRunner();
|
|
787
|
+
const approved = await runner.approve();
|
|
788
|
+
if (approved) {
|
|
789
|
+
await msg.reply(`✅ ${t('discord.auto.approved')}`);
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
await msg.reply(`⏳ ${t('discord.auto.noPendingApproval')}`);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
catch {
|
|
796
|
+
await msg.reply(`❌ ${t('discord.errors.runnerNotStarted')}`);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* !reject - Reject pending task
|
|
801
|
+
*/
|
|
802
|
+
export async function handleReject(msg) {
|
|
803
|
+
try {
|
|
804
|
+
const runner = autonomous.getRunner();
|
|
805
|
+
const rejected = runner.reject();
|
|
806
|
+
if (rejected) {
|
|
807
|
+
await msg.reply(`❌ ${t('discord.auto.rejected')}`);
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
await msg.reply(`⏳ ${t('discord.auto.noPendingApproval')}`);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
catch {
|
|
814
|
+
await msg.reply(`❌ ${t('discord.errors.runnerNotStarted')}`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* !turbo [on|off] - Toggle turbo mode
|
|
819
|
+
*/
|
|
820
|
+
export async function handleTurbo(msg, arg) {
|
|
821
|
+
try {
|
|
822
|
+
const runner = autonomous.getRunner();
|
|
823
|
+
if (!arg || arg === 'status') {
|
|
824
|
+
const stats = runner.getStats();
|
|
825
|
+
const isTurbo = stats.turboMode;
|
|
826
|
+
if (isTurbo && stats.turboExpiresAt) {
|
|
827
|
+
const remainMin = Math.max(0, Math.round((stats.turboExpiresAt - Date.now()) / 60000));
|
|
828
|
+
await replyWithEmbed(msg, `TURBO ON (${remainMin}min remaining)`, 0xff8800);
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
await replyWithEmbed(msg, 'TURBO OFF (normal pace)', 0x00ff41);
|
|
832
|
+
}
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
const enabled = arg === 'on';
|
|
836
|
+
if (arg !== 'on' && arg !== 'off') {
|
|
837
|
+
await replyWithEmbed(msg, 'Usage: `!turbo [on|off|status]`', 0xffaa00);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
runner.setTurboMode(enabled);
|
|
841
|
+
const emoji = enabled ? '🔥' : '🐢';
|
|
842
|
+
const label = enabled ? 'TURBO ON — 5min heartbeat, 20 daily cap, 4h auto-expire' : 'TURBO OFF — normal pace resumed';
|
|
843
|
+
await replyWithEmbed(msg, `${emoji} ${label}`, enabled ? 0xff8800 : 0x00ff41);
|
|
844
|
+
}
|
|
845
|
+
catch {
|
|
846
|
+
await msg.reply(`❌ Runner not started`);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
//# sourceMappingURL=discordHandlers.js.map
|