@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 @@
|
|
|
1
|
+
{"version":3,"file":"chatTui.js","sourceRoot":"","sources":["../../src/support/chatTui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type CostInfo = {
|
|
2
|
+
costUsd: number;
|
|
3
|
+
inputTokens: number;
|
|
4
|
+
outputTokens: number;
|
|
5
|
+
cacheReadTokens: number;
|
|
6
|
+
cacheCreationTokens: number;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
model?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Extract cost from Claude CLI JSON array output (--output-format json)
|
|
12
|
+
* Format: [{ type: 'result', total_cost_usd, usage, duration_ms, ... }]
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractCostFromJson(output: string): CostInfo | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Extract cost from Claude CLI stream-json output (--output-format stream-json)
|
|
17
|
+
* Format: newline-delimited JSON, each line is { type: 'result', ... }
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractCostFromStreamJson(output: string): CostInfo | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Aggregate multiple CostInfo into a single total
|
|
22
|
+
*/
|
|
23
|
+
export declare function aggregateCosts(costs: (CostInfo | undefined)[]): CostInfo;
|
|
24
|
+
/**
|
|
25
|
+
* Format CostInfo as a human-readable log string
|
|
26
|
+
* Example: "$0.0432 | 1.2k in / 0.8k out | 12.3s"
|
|
27
|
+
*/
|
|
28
|
+
export declare function formatCost(cost: CostInfo): string;
|
|
29
|
+
//# sourceMappingURL=costTracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costTracker.d.ts","sourceRoot":"","sources":["../../src/support/costTracker.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAIF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAexE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAiB9E;AAqBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,CAAC,QAAQ,GAAG,SAAS,CAAC,EAAE,GAAG,QAAQ,CAqBxE;AAaD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAKjD"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// ============================================
|
|
2
|
+
// OpenSwarm - Cost Tracker
|
|
3
|
+
// Common cost extraction utilities for Claude CLI output
|
|
4
|
+
// ============================================
|
|
5
|
+
// Extraction
|
|
6
|
+
/**
|
|
7
|
+
* Extract cost from Claude CLI JSON array output (--output-format json)
|
|
8
|
+
* Format: [{ type: 'result', total_cost_usd, usage, duration_ms, ... }]
|
|
9
|
+
*/
|
|
10
|
+
export function extractCostFromJson(output) {
|
|
11
|
+
try {
|
|
12
|
+
const match = output.match(/\[[\s\S]*\]/);
|
|
13
|
+
if (!match)
|
|
14
|
+
return undefined;
|
|
15
|
+
const arr = JSON.parse(match[0]);
|
|
16
|
+
for (const item of arr) {
|
|
17
|
+
if (item.type === 'result') {
|
|
18
|
+
return extractFromResultEvent(item);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Parse failure
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract cost from Claude CLI stream-json output (--output-format stream-json)
|
|
29
|
+
* Format: newline-delimited JSON, each line is { type: 'result', ... }
|
|
30
|
+
*/
|
|
31
|
+
export function extractCostFromStreamJson(output) {
|
|
32
|
+
try {
|
|
33
|
+
const lines = output.split('\n').filter(Boolean);
|
|
34
|
+
for (const line of lines) {
|
|
35
|
+
try {
|
|
36
|
+
const event = JSON.parse(line);
|
|
37
|
+
if (event.type === 'result') {
|
|
38
|
+
return extractFromResultEvent(event);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Not a valid JSON line
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Parse failure
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extract CostInfo from a result event object
|
|
53
|
+
*/
|
|
54
|
+
function extractFromResultEvent(event) {
|
|
55
|
+
if (event.total_cost_usd == null && !event.usage)
|
|
56
|
+
return undefined;
|
|
57
|
+
return {
|
|
58
|
+
costUsd: event.total_cost_usd ?? 0,
|
|
59
|
+
inputTokens: event.usage?.input_tokens ?? 0,
|
|
60
|
+
outputTokens: event.usage?.output_tokens ?? 0,
|
|
61
|
+
cacheReadTokens: event.usage?.cache_read_input_tokens ?? 0,
|
|
62
|
+
cacheCreationTokens: event.usage?.cache_creation_input_tokens ?? 0,
|
|
63
|
+
durationMs: event.duration_ms ?? 0,
|
|
64
|
+
model: event.model,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Aggregation
|
|
68
|
+
/**
|
|
69
|
+
* Aggregate multiple CostInfo into a single total
|
|
70
|
+
*/
|
|
71
|
+
export function aggregateCosts(costs) {
|
|
72
|
+
const result = {
|
|
73
|
+
costUsd: 0,
|
|
74
|
+
inputTokens: 0,
|
|
75
|
+
outputTokens: 0,
|
|
76
|
+
cacheReadTokens: 0,
|
|
77
|
+
cacheCreationTokens: 0,
|
|
78
|
+
durationMs: 0,
|
|
79
|
+
};
|
|
80
|
+
for (const cost of costs) {
|
|
81
|
+
if (!cost)
|
|
82
|
+
continue;
|
|
83
|
+
result.costUsd += cost.costUsd;
|
|
84
|
+
result.inputTokens += cost.inputTokens;
|
|
85
|
+
result.outputTokens += cost.outputTokens;
|
|
86
|
+
result.cacheReadTokens += cost.cacheReadTokens;
|
|
87
|
+
result.cacheCreationTokens += cost.cacheCreationTokens;
|
|
88
|
+
result.durationMs += cost.durationMs;
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
// Formatting
|
|
93
|
+
/**
|
|
94
|
+
* Format token count with k/M suffix
|
|
95
|
+
*/
|
|
96
|
+
function formatTokens(n) {
|
|
97
|
+
if (n >= 1_000_000)
|
|
98
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
99
|
+
if (n >= 1_000)
|
|
100
|
+
return `${(n / 1_000).toFixed(1)}k`;
|
|
101
|
+
return String(n);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Format CostInfo as a human-readable log string
|
|
105
|
+
* Example: "$0.0432 | 1.2k in / 0.8k out | 12.3s"
|
|
106
|
+
*/
|
|
107
|
+
export function formatCost(cost) {
|
|
108
|
+
const usd = `$${cost.costUsd.toFixed(4)}`;
|
|
109
|
+
const tokens = `${formatTokens(cost.inputTokens)} in / ${formatTokens(cost.outputTokens)} out`;
|
|
110
|
+
const duration = `${(cost.durationMs / 1000).toFixed(1)}s`;
|
|
111
|
+
return `${usd} | ${tokens} | ${duration}`;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=costTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costTracker.js","sourceRoot":"","sources":["../../src/support/costTracker.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,2BAA2B;AAC3B,yDAAyD;AACzD,+CAA+C;AAc/C,aAAa;AAEb;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAE7B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;YACvB,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC3B,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAc;IACtD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC5B,OAAO,sBAAsB,CAAC,KAAK,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,KAAU;IACxC,IAAI,KAAK,CAAC,cAAc,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAEnE,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,cAAc,IAAI,CAAC;QAClC,WAAW,EAAE,KAAK,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC;QAC3C,YAAY,EAAE,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC;QAC7C,eAAe,EAAE,KAAK,CAAC,KAAK,EAAE,uBAAuB,IAAI,CAAC;QAC1D,mBAAmB,EAAE,KAAK,CAAC,KAAK,EAAE,2BAA2B,IAAI,CAAC;QAClE,UAAU,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC;QAClC,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC;AACJ,CAAC;AAED,cAAc;AAEd;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAA+B;IAC5D,MAAM,MAAM,GAAa;QACvB,OAAO,EAAE,CAAC;QACV,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,eAAe,EAAE,CAAC;QAClB,mBAAmB,EAAE,CAAC;QACtB,UAAU,EAAE,CAAC;KACd,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC;QAC/B,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC;QACvC,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC;QACzC,MAAM,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,CAAC;QAC/C,MAAM,CAAC,mBAAmB,IAAI,IAAI,CAAC,mBAAmB,CAAC;QACvD,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC;IACvC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,aAAa;AAEb;;GAEG;AACH,SAAS,YAAY,CAAC,CAAS;IAC7B,IAAI,CAAC,IAAI,SAAS;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5D,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IAC/F,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC3D,OAAO,GAAG,GAAG,MAAM,MAAM,MAAM,QAAQ,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const DASHBOARD_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>OpenSwarm :: Supervisor</title>\n <style>\n :root {\n --bg: #0a0c0a;\n --bg2: #0d100d;\n --bg3: #111411;\n --green: #00ff41;\n --green-dim: #003a00;\n --green-mid: #00aa00;\n --green-lo: #005500;\n --cyan: #00ccdd;\n --cyan-dim: #003344;\n --amber: #ffaa00;\n --red: #ff3333;\n --white: #ccddcc;\n --dim: #445544;\n --border: #1a2a1a;\n --border2: #0d1a0d;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n html, body { height: 100%; overflow: hidden; }\n body {\n font-family: 'Cascadia Code', 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;\n background: var(--bg);\n color: var(--white);\n font-size: 13px;\n line-height: 1.4;\n }\n\n /* ===== SCROLLBAR ===== */\n ::-webkit-scrollbar { width: 4px; }\n ::-webkit-scrollbar-track { background: var(--bg); }\n ::-webkit-scrollbar-thumb { background: var(--green-lo); border-radius: 2px; }\n\n /* ===== HEADER ===== */\n header {\n height: 38px;\n background: var(--bg2);\n border-bottom: 1px solid var(--border);\n display: flex;\n align-items: center;\n padding: 0 1rem;\n gap: 0.75rem;\n flex-shrink: 0;\n }\n .hdr-logo {\n color: var(--green);\n font-weight: bold;\n font-size: 14px;\n letter-spacing: 0.15em;\n }\n .hdr-fullname { color: var(--dim); font-size: 11px; letter-spacing: 0.05em; margin-left: 0.25rem; }\n .hdr-sep { color: var(--dim); margin-left: 0.5rem; }\n .hdr-sub { color: var(--dim); font-size: 11px; letter-spacing: 0.1em; }\n .hdr-right { margin-left: auto; display: flex; align-items: center; gap: 0.5rem; }\n #sse-status {\n font-size: 10px;\n padding: 1px 6px;\n border: 1px solid var(--dim);\n color: var(--dim);\n letter-spacing: 0.1em;\n }\n #sse-status.connected { border-color: var(--green); color: var(--green); }\n #sse-status.disconnected { border-color: var(--red); color: var(--red); }\n .btn {\n font-family: inherit;\n font-size: 10px;\n padding: 2px 10px;\n background: transparent;\n border: 1px solid var(--green-lo);\n color: var(--green-mid);\n cursor: pointer;\n letter-spacing: 0.1em;\n transition: all 0.15s;\n }\n .btn:hover:not(:disabled) { border-color: var(--green); color: var(--green); background: var(--green-dim); }\n .btn:disabled { opacity: 0.4; cursor: default; }\n .btn-active { border-color: var(--amber); color: var(--amber); }\n .btn-active:hover:not(:disabled) { background: #332200; border-color: var(--amber); }\n .btn-danger { border-color: #551111; color: var(--red); }\n .btn-danger:hover:not(:disabled) { background: #220000; border-color: var(--red); }\n #turbo-btn { border-color: #553300; color: #ff8800; transition: all 0.3s; }\n #turbo-btn:hover:not(:disabled) { background: #221100; border-color: #ff8800; }\n #turbo-btn.turbo-active { background: #331800; border-color: #ff8800; color: #ffaa00; box-shadow: 0 0 8px rgba(255,136,0,0.3); animation: turbo-pulse 2s infinite; }\n @keyframes turbo-pulse { 0%,100% { box-shadow: 0 0 4px rgba(255,136,0,0.2); } 50% { box-shadow: 0 0 12px rgba(255,136,0,0.5); } }\n .move-to-todo-btn {\n font-family: inherit;\n font-size: 9px;\n padding: 1px 6px;\n background: transparent;\n border: 1px solid var(--cyan-dim);\n color: var(--cyan);\n cursor: pointer;\n margin-left: auto;\n flex-shrink: 0;\n transition: all 0.15s;\n }\n .move-to-todo-btn:hover:not(:disabled) { border-color: var(--cyan); background: var(--cyan-dim); }\n .move-to-todo-btn:disabled { opacity: 0.4; cursor: default; }\n .svc-group { display: flex; align-items: center; gap: 4px; margin-right: 8px; }\n .svc-status {\n font-size: 9px; padding: 1px 6px;\n border: 1px solid var(--dim); color: var(--dim);\n letter-spacing: 0.1em; text-transform: uppercase;\n }\n .svc-status.active { border-color: var(--green); color: var(--green); }\n .svc-status.inactive { border-color: var(--red); color: var(--red); }\n .svc-sep { color: var(--border); margin: 0 2px; }\n\n /* ===== STATS BAR ===== */\n .stats-bar {\n height: 36px;\n background: var(--bg2);\n border-bottom: 1px solid var(--border2);\n display: flex;\n align-items: center;\n padding: 0 1rem;\n gap: 1.5rem;\n flex-shrink: 0;\n }\n .stat {\n display: flex;\n align-items: baseline;\n gap: 0.4rem;\n }\n .stat-label { font-size: 10px; color: var(--dim); text-transform: uppercase; letter-spacing: 0.1em; }\n .stat-val { font-size: 13px; font-weight: 500; color: var(--green); }\n .stat-val.amber { color: var(--amber); }\n .stat-val.cyan { color: var(--cyan); }\n .stat-val.red { color: #ff5555; }\n #stat-adapter, #stat-pair-adapters {\n font-size: 10px;\n font-weight: 400;\n letter-spacing: 0.02em;\n }\n .provider-toggle {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px;\n border: 1px solid var(--border);\n background: var(--bg3);\n }\n .provider-btn {\n font-family: inherit;\n font-size: 9px;\n line-height: 1;\n padding: 4px 8px;\n background: transparent;\n border: 1px solid transparent;\n color: var(--dim);\n cursor: pointer;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n }\n .provider-btn:hover:not(:disabled) {\n color: var(--white);\n border-color: var(--border);\n }\n .provider-btn.active {\n color: var(--green);\n border-color: var(--green-lo);\n background: var(--green-dim);\n }\n .stat-divider { color: var(--border); }\n\n /* ===== MAIN GRID ===== */\n .main-grid {\n display: grid;\n grid-template-columns: 290px 1fr 340px;\n height: calc(100vh - 74px);\n overflow: hidden;\n }\n .col {\n display: flex;\n flex-direction: column;\n border-right: 1px solid var(--border);\n overflow: hidden;\n }\n .col:last-child { border-right: none; }\n\n /* ===== PANEL ===== */\n .panel { display: flex; flex-direction: column; overflow: hidden; flex: 1; }\n .panel + .panel { border-top: 1px solid var(--border); }\n .panel-hdr {\n height: 28px;\n padding: 0 0.75rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n background: var(--bg3);\n border-bottom: 1px solid var(--border2);\n flex-shrink: 0;\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.12em;\n color: var(--dim);\n }\n .panel-hdr-title { color: var(--green-mid); }\n .panel-hdr-badge {\n margin-left: auto;\n font-size: 9px;\n color: var(--dim);\n }\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 0.5rem;\n }\n .empty { color: var(--dim); font-size: 11px; text-align: center; padding: 1.5rem 0.5rem; }\n\n /* ===== PROJECTS ===== */\n .proj-card {\n border: 1px solid var(--border);\n margin-bottom: 4px;\n background: var(--bg2);\n }\n .proj-card.disabled { opacity: 0.45; }\n .proj-hdr {\n display: flex;\n align-items: center;\n padding: 5px 7px;\n gap: 6px;\n cursor: pointer;\n user-select: none;\n }\n .proj-hdr:hover { background: var(--green-dim); }\n .proj-arrow { color: var(--dim); font-size: 9px; width: 10px; flex-shrink: 0; }\n .proj-card.expanded .proj-arrow::before { content: \"\u25BC\"; }\n .proj-card:not(.expanded) .proj-arrow::before { content: \"\u25B6\"; }\n .proj-info { flex: 1; min-width: 0; }\n .proj-name { color: var(--green); font-size: 12px; font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .proj-path { color: var(--dim); font-size: 9px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .proj-counts { display: flex; gap: 3px; }\n .cnt { font-size: 9px; padding: 1px 4px; font-weight: bold; }\n .cnt-run { color: var(--green); border: 1px solid var(--green-lo); }\n .cnt-que { color: var(--amber); border: 1px solid #332200; }\n .cnt-pnd { color: var(--cyan); border: 1px solid var(--cyan-dim); }\n .proj-toggle { flex-shrink: 0; }\n .toggle { position: relative; display: inline-block; width: 30px; height: 16px; }\n .toggle input { opacity: 0; width: 0; height: 0; }\n .slider {\n position: absolute; cursor: pointer;\n top: 0; left: 0; right: 0; bottom: 0;\n background: #111; border: 1px solid var(--dim);\n border-radius: 16px; transition: 0.2s;\n }\n .slider:before {\n position: absolute; content: \"\";\n height: 10px; width: 10px;\n left: 2px; bottom: 2px;\n background: var(--dim); border-radius: 50%; transition: 0.2s;\n }\n input:checked + .slider { background: var(--green-dim); border-color: var(--green-lo); }\n input:checked + .slider:before { background: var(--green); transform: translateX(14px); }\n .proj-issues { border-top: 1px solid var(--border2); padding: 4px 7px; }\n .issue-sec-label {\n font-size: 9px; color: var(--dim); text-transform: uppercase;\n letter-spacing: 0.1em; margin: 4px 0 2px;\n }\n .issue-row {\n display: flex; align-items: center; gap: 4px;\n padding: 2px 0; font-size: 11px;\n border-bottom: 1px solid var(--border2);\n }\n .issue-row:last-child { border-bottom: none; }\n .git-info { color: var(--dim); font-size: 9px; display: flex; gap: 6px; align-items: center; }\n .git-branch-name { color: var(--cyan); }\n .git-dirty { color: var(--amber); }\n .git-sync { color: var(--dim); }\n .pr-row { display: flex; align-items: center; gap: 4px; padding: 2px 0; font-size: 11px; border-bottom: 1px solid var(--border2); }\n .pr-row:last-child { border-bottom: none; }\n .pr-num { color: var(--cyan); font-size: 9px; min-width: 32px; }\n .pr-branch { color: var(--green-lo); font-size: 9px; max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .pr-title { flex: 1; color: var(--white); font-size: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .pr-age { color: var(--dim); font-size: 9px; flex-shrink: 0; }\n .idot { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }\n .idot-run { background: var(--green); }\n .idot-que { background: var(--amber); }\n .idot-pnd { background: var(--dim); }\n .prio { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }\n .prio-1 { background: var(--red); }\n .prio-2 { background: var(--amber); }\n .prio-3 { background: var(--green-mid); }\n .prio-4 { background: var(--dim); }\n .issue-id { color: var(--cyan); font-size: 9px; min-width: 50px; }\n .issue-title { flex: 1; color: var(--white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .issue-row.issue-backlog { opacity: 0.45; }\n\n /* ===== PROCESS ROW ===== */\n .proc-row {\n display: flex; align-items: center; gap: 6px;\n padding: 4px 6px; border-bottom: 1px solid var(--border2);\n font-size: 11px;\n }\n .proc-pid { color: var(--cyan); font-size: 10px; min-width: 42px; font-variant-numeric: tabular-nums; }\n .proc-stage { color: var(--green); min-width: 56px; font-weight: bold; text-transform: uppercase; font-size: 10px; }\n .proc-model { color: var(--dim); font-size: 9px; min-width: 56px; }\n .proc-dur { color: var(--amber); font-size: 9px; min-width: 42px; text-align: right; font-variant-numeric: tabular-nums; }\n .proc-activity { font-size: 10px; min-width: 16px; text-align: center; }\n .proc-kill {\n font-family: inherit; font-size: 9px; padding: 1px 5px;\n background: transparent; border: 1px solid #551111; color: var(--red);\n cursor: pointer; margin-left: auto;\n }\n .proc-kill:hover { background: #220000; border-color: var(--red); }\n\n /* ===== PIPELINE ===== */\n .stage-row {\n display: flex; align-items: center; gap: 6px;\n padding: 3px 0; border-bottom: 1px solid var(--border2);\n font-size: 11px;\n }\n .sdot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--dim); }\n .sdot.start { background: var(--amber); }\n .sdot.complete { background: var(--green); }\n .sdot.fail { background: var(--red); }\n .sname { color: var(--white); min-width: 70px; }\n .srepo { color: var(--green-lo); font-size: 9px; min-width: 50px; max-width: 90px; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .stask { color: var(--cyan); font-size: 10px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .selapsed { color: var(--amber); font-size: 9px; flex-shrink: 0; min-width: 36px; text-align: right; }\n .smodel { color: var(--dim); font-size: 9px; flex-shrink: 0; min-width: 56px; text-align: right; }\n .stokens { color: var(--amber); font-size: 9px; flex-shrink: 0; min-width: 80px; text-align: right; white-space: nowrap; }\n .sstatus { margin-left: auto; font-size: 9px; color: var(--dim); text-transform: uppercase; letter-spacing: 0.06em; flex-shrink: 0; }\n\n /* ===== LOG TAB BAR ===== */\n .log-tab-bar {\n display: flex; gap: 0; border-bottom: 1px solid #1a2a1a;\n padding: 0 4px; overflow-x: auto; flex-shrink: 0;\n }\n .log-tab {\n background: transparent; border: none; border-bottom: 2px solid transparent;\n color: var(--dim); font-family: inherit; font-size: 10px;\n padding: 4px 8px; cursor: pointer; white-space: nowrap;\n text-transform: uppercase; letter-spacing: .05em;\n }\n .log-tab:hover { color: var(--green-mid); }\n .log-tab.active { color: var(--green); border-bottom-color: var(--green); }\n\n /* ===== LOG ===== */\n .log-area { font-size: 11px; line-height: 1.5; padding: 4px 0; }\n .log-line { padding: 3px 8px; display: flex; gap: 6px; align-items: flex-start; border-radius: 2px; margin: 1px 0; }\n .log-line:hover { background: rgba(255,255,255,0.03); }\n .log-line.log-success .ltext { color: var(--green); }\n .log-line.log-fail .ltext { color: var(--red); }\n .log-line.log-warn .ltext { color: var(--amber); }\n .log-line.log-system { opacity: 0.6; }\n .log-line.log-heading { border-top: 1px solid var(--border2); margin-top: 6px; padding-top: 8px; }\n .ltime { color: var(--dim); font-size: 9px; flex-shrink: 0; min-width: 36px; opacity: 0.7; padding-top: 2px; font-variant-numeric: tabular-nums; }\n .licon { flex-shrink: 0; min-width: 14px; text-align: center; font-size: 11px; padding-top: 1px; }\n .ltag { color: var(--green-lo); min-width: 52px; flex-shrink: 0; padding-top: 1px; font-size: 10px; font-weight: 500; }\n .lstage { color: var(--cyan); min-width: 60px; flex-shrink: 0; font-size: 10px; padding-top: 1px; text-transform: uppercase; letter-spacing: 0.03em; opacity: 0.8; }\n .ltext { color: #99aa99; word-break: break-word; white-space: pre-wrap; flex: 1; min-width: 0; }\n .ltext .lhighlight { color: var(--white); font-weight: 500; }\n .ltext .lcost { color: var(--amber); font-size: 10px; }\n .ltext .lfiles { color: var(--cyan); font-size: 10px; }\n .log-line.log-spacer { height: 6px; padding: 0; margin: 0; min-height: 6px; }\n .log-line.log-separator { opacity: 0.2; padding: 0 8px; margin: 4px 0; }\n .log-line.log-separator .ltext { color: var(--dim); }\n .log-line.log-code .ltext { font-family: 'JetBrains Mono', 'Fira Code', monospace; color: var(--cyan); opacity: 0.8; font-size: 10px; }\n .log-line.log-heading2 .ltext { color: var(--white); font-weight: 600; font-size: 12px; }\n .log-line.log-tool .ltext { color: var(--dim); font-style: italic; font-size: 10px; }\n\n /* ===== CHAT ===== */\n .chat-col { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; }\n .chat-messages {\n flex: 1;\n overflow-y: auto;\n padding: 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n .chat-line { display: flex; gap: 6px; font-size: 12px; line-height: 1.5; }\n .chat-prefix {\n flex-shrink: 0;\n font-weight: bold;\n }\n .chat-user .chat-prefix { color: var(--amber); }\n .chat-agent .chat-prefix { color: var(--cyan); }\n .chat-text { color: var(--white); white-space: pre-wrap; word-break: break-word; flex: 1; }\n .chat-agent .chat-text { color: var(--white); }\n .chat-user .chat-text { color: var(--amber); }\n .chat-ts { color: var(--dim); font-size: 9px; flex-shrink: 0; align-self: flex-start; padding-top: 2px; }\n .chat-thinking { animation: blink 1s infinite; color: var(--cyan); }\n @keyframes blink { 0%,100% { opacity:1; } 50% { opacity:0.3; } }\n\n .chat-input-area {\n border-top: 1px solid var(--border);\n padding: 6px 8px;\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--bg3);\n flex-shrink: 0;\n }\n .chat-prompt { color: var(--green); font-size: 12px; flex-shrink: 0; }\n .chat-input {\n flex: 1;\n background: transparent;\n border: none;\n outline: none;\n font-family: inherit;\n font-size: 12px;\n color: var(--green);\n caret-color: var(--green);\n }\n .chat-input::placeholder { color: var(--dim); }\n .chat-send {\n font-family: inherit;\n font-size: 10px;\n padding: 2px 8px;\n background: transparent;\n border: 1px solid var(--green-lo);\n color: var(--green-mid);\n cursor: pointer;\n }\n .chat-send:hover { border-color: var(--green); color: var(--green); }\n .chat-send:disabled { opacity: 0.3; cursor: default; }\n\n /* ===== REPO PICKER ===== */\n .repo-item {\n display: flex; align-items: center; gap: 8px;\n padding: 5px 12px; cursor: pointer; font-size: 11px;\n }\n .repo-item:hover { background: var(--green-dim); }\n .repo-item-name { color: var(--green); font-weight: bold; }\n .repo-item-path { color: var(--dim); font-size: 10px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .repo-item-badge { font-size: 9px; padding: 1px 5px; border: 1px solid var(--green-lo); color: var(--green-mid); flex-shrink: 0; }\n\n .scan-path-row { display: flex; align-items: center; gap: 6px; padding: 3px 0; font-size: 11px; }\n .scan-path-row .path { color: var(--dim); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .scan-path-badge { font-size: 9px; padding: 1px 5px; border: 1px solid #333; color: #556655; flex-shrink: 0; }\n .scan-path-remove { background: transparent; border: none; color: #553333; cursor: pointer; font-size: 12px; padding: 0 2px; flex-shrink: 0; }\n .scan-path-remove:hover { color: var(--red); }\n\n /* ===== TAB BAR (hidden on desktop) ===== */\n .tab-bar { display: none; }\n\n /* ===== MOBILE RESPONSIVE ===== */\n @media (max-width: 768px) {\n html, body { overflow: auto; }\n\n /* Header */\n header {\n height: auto;\n min-height: 38px;\n flex-wrap: wrap;\n padding: 6px 0.75rem;\n gap: 4px;\n }\n .hdr-fullname { display: none; }\n .hdr-right { width: 100%; justify-content: flex-end; }\n .svc-group .btn { font-size: 0; padding: 4px 8px; min-height: 32px; }\n .svc-group #svc-stop-btn::after { content: \"\\23F8\"; font-size: 12px; }\n .svc-group #svc-restart-btn::after { content: \"\\21BB\"; font-size: 12px; }\n #hb-btn { min-height: 32px; }\n\n /* Stats bar */\n .stats-bar {\n height: auto;\n min-height: 32px;\n flex-wrap: wrap;\n padding: 4px 0.75rem;\n gap: 0.5rem;\n font-size: 11px;\n }\n .stat-divider { display: none; }\n\n /* Tab bar */\n .tab-bar {\n display: flex;\n background: var(--bg2);\n border-bottom: 1px solid var(--border);\n }\n .tab {\n flex: 1;\n font-family: inherit;\n font-size: 11px;\n letter-spacing: 0.1em;\n padding: 10px 0;\n min-height: 44px;\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n color: var(--dim);\n cursor: pointer;\n text-align: center;\n transition: all 0.15s;\n }\n .tab.active {\n color: var(--green);\n border-bottom-color: var(--green);\n }\n\n /* Main grid \u2192 single column */\n .main-grid {\n display: flex;\n flex-direction: column;\n height: auto;\n min-height: calc(100vh - 160px);\n overflow: visible;\n }\n .col {\n display: none;\n border-right: none;\n overflow: visible;\n min-height: calc(100vh - 200px);\n }\n .col.mob-active {\n display: flex;\n flex: 1;\n }\n\n /* Repo picker \u2192 fullscreen */\n #repo-picker > div {\n width: 100% !important;\n max-height: 90vh !important;\n margin: 5vh 0 0;\n }\n .repo-item { min-height: 44px; }\n\n /* Chat input \u2192 sticky bottom */\n .chat-input-area {\n position: sticky;\n bottom: 0;\n z-index: 10;\n min-height: 44px;\n }\n .chat-input { min-height: 32px; font-size: 14px; }\n .chat-send { min-height: 36px; padding: 4px 12px; }\n\n /* Touch targets */\n .btn { min-height: 36px; padding: 4px 10px; }\n .proj-hdr { min-height: 44px; padding: 8px 7px; }\n .toggle { width: 40px; height: 22px; }\n .slider:before { height: 14px; width: 14px; left: 3px; bottom: 3px; }\n input:checked + .slider:before { transform: translateX(18px); }\n }\n </style>\n</head>\n<body>\n <!-- HEADER -->\n <header>\n <span class=\"hdr-logo\">OpenSwarm</span>\n <span class=\"hdr-fullname\">: Vector-Encoded General Agent</span>\n <span class=\"hdr-sep\">::</span>\n <span class=\"hdr-sub\">SUPERVISOR</span>\n <div class=\"hdr-right\">\n <div class=\"svc-group\">\n <span class=\"svc-status\" id=\"svc-status\">...</span>\n <span class=\"svc-sep\">\u2502</span>\n <div class=\"provider-toggle\">\n <button class=\"provider-btn\" id=\"provider-claude\" onclick=\"switchProvider('claude')\">Claude</button>\n <button class=\"provider-btn\" id=\"provider-codex\" onclick=\"switchProvider('codex')\">Codex</button>\n </div>\n <span class=\"svc-sep\">\u2502</span>\n <button class=\"btn\" id=\"turbo-btn\" onclick=\"toggleTurbo()\" title=\"Turbo: 5min heartbeat, 20 daily cap, 4h auto-expire\">TURBO</button>\n <span class=\"svc-sep\">\u2502</span>\n <button class=\"btn btn-danger\" id=\"svc-stop-btn\" onclick=\"svcAction('stop')\">\u23F8 STOP</button>\n <button class=\"btn\" id=\"svc-restart-btn\" onclick=\"svcAction('restart')\">\u21BB RESTART</button>\n </div>\n <span id=\"sse-status\">CONNECTING</span>\n <button class=\"btn btn-active\" id=\"hb-btn\" onclick=\"triggerHeartbeat()\">\u25B6 HEARTBEAT</button>\n <button class=\"btn\" id=\"pr-proc-btn\" onclick=\"triggerPRProcessor()\">\u21BB PR REVIEW</button>\n </div>\n </header>\n\n <!-- STATS BAR -->\n <div class=\"stats-bar\">\n <div class=\"stat\"><span class=\"stat-label\">RUN</span><span class=\"stat-val\" id=\"stat-running\">0</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">QUEUE</span><span class=\"stat-val amber\" id=\"stat-queued\">0</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">DONE</span><span class=\"stat-val\" id=\"stat-completed\">0</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">PACE</span><span class=\"stat-val\" id=\"stat-pace\">-</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">SSE</span><span class=\"stat-val cyan\" id=\"stat-sse\">-</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">CLI</span><span class=\"stat-val cyan\" id=\"stat-adapter\">-</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">PAIR</span><span class=\"stat-val cyan\" id=\"stat-pair-adapters\">-</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">UPTIME</span><span class=\"stat-val\" id=\"stat-uptime\">-</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">COST</span><span class=\"stat-val cyan\" id=\"stat-cost\">$0.00</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">QUOTA 5h</span><span class=\"stat-val\" id=\"stat-quota-5h\">-</span></div>\n <span class=\"stat-divider\">\u2502</span>\n <div class=\"stat\"><span class=\"stat-label\">QUOTA 7d</span><span class=\"stat-val\" id=\"stat-quota-7d\">-</span></div>\n </div>\n\n <!-- TAB BAR (mobile only) -->\n <div class=\"tab-bar\">\n <button class=\"tab active\" data-tab=\"0\">REPOS</button>\n <button class=\"tab\" data-tab=\"1\">PIPELINE</button>\n <button class=\"tab\" data-tab=\"2\">CHAT</button>\n </div>\n\n <!-- MAIN GRID -->\n <div class=\"main-grid\">\n\n <!-- LEFT: REPOSITORIES -->\n <div class=\"col\">\n <div class=\"panel\">\n <div class=\"panel-hdr\">\n <span class=\"panel-hdr-title\">REPOSITORIES</span>\n <span class=\"panel-hdr-badge\" id=\"proj-summary\"></span>\n <button class=\"btn\" style=\"margin-left:auto;font-size:9px;padding:1px 6px\" onclick=\"openRepoPicker()\">+ ADD</button>\n </div>\n <div class=\"panel-body\" id=\"project-list\">\n <div class=\"empty\">loading...</div>\n </div>\n </div>\n <div class=\"panel\" id=\"monitor-panel\">\n <div class=\"panel-hdr\">\n <span class=\"panel-hdr-title\">MONITORS & PROCESSES</span>\n <span class=\"panel-hdr-badge\" id=\"monitor-count\"></span>\n </div>\n <div class=\"panel-body\" id=\"monitor-list\">\n <div class=\"empty\">no monitors or processes</div>\n </div>\n </div>\n </div>\n\n <!-- REPO PICKER OVERLAY -->\n <div id=\"repo-picker\" style=\"display:none;position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:100;align-items:center;justify-content:center\">\n <div style=\"background:#0d100d;border:1px solid #1a2a1a;width:500px;max-height:70vh;display:flex;flex-direction:column\">\n <div style=\"padding:8px 12px;border-bottom:1px solid #1a2a1a;display:flex;align-items:center;gap:8px\">\n <span style=\"color:#00aa00;font-size:11px;text-transform:uppercase;letter-spacing:.1em\">ADD REPOSITORY</span>\n <button onclick=\"closeRepoPicker()\" style=\"margin-left:auto;background:transparent;border:none;color:#445544;cursor:pointer;font-size:14px\">\u2715</button>\n </div>\n <div style=\"padding:6px 12px;border-bottom:1px solid #1a2a1a\">\n <input id=\"repo-search\" type=\"text\" placeholder=\"filter repositories...\"\n style=\"width:100%;background:transparent;border:none;outline:none;font-family:inherit;font-size:12px;color:#00ff41;caret-color:#00ff41\"\n oninput=\"filterRepos(this.value)\" onkeydown=\"if(event.key==='Escape')closeRepoPicker()\">\n </div>\n <div id=\"repo-picker-list\" style=\"overflow-y:auto;flex:1;padding:4px 0\"></div>\n <div id=\"scan-paths-section\" style=\"border-top:1px solid #1a2a1a;padding:8px 12px\">\n <div style=\"color:#00aa00;font-size:10px;text-transform:uppercase;letter-spacing:.1em;margin-bottom:6px\">SCAN PATHS</div>\n <div id=\"scan-paths-list\"></div>\n <div style=\"display:flex;gap:4px;margin-top:6px\">\n <input id=\"scan-path-input\" type=\"text\" placeholder=\"/path/to/scan\"\n style=\"flex:1;background:transparent;border:1px solid #1a2a1a;outline:none;font-family:inherit;font-size:11px;color:#00ff41;padding:3px 6px;caret-color:#00ff41\"\n onkeydown=\"if(event.key==='Enter')addScanPath()\">\n <button class=\"btn\" style=\"font-size:9px;padding:1px 6px\" onclick=\"addScanPath()\">+ ADD</button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- MIDDLE: PIPELINE + LOG -->\n <div class=\"col\">\n <div class=\"panel\" style=\"flex: 0 0 38%\">\n <div class=\"panel-hdr\">\n <span class=\"panel-hdr-title\">PIPELINE</span>\n <span class=\"panel-hdr-badge\" id=\"stage-count\"></span>\n </div>\n <div class=\"panel-body\" id=\"stage-list\">\n <div class=\"empty\">no pipeline events</div>\n </div>\n </div>\n <div class=\"panel\">\n <div class=\"panel-hdr\">\n <span class=\"panel-hdr-title\">LIVE LOG</span>\n <span class=\"panel-hdr-badge\" id=\"log-count\"></span>\n </div>\n <div class=\"log-tab-bar\" id=\"log-tab-bar\">\n <button class=\"log-tab active\" data-task=\"all\" onclick=\"selectLogTab(null)\">ALL</button>\n </div>\n <div class=\"panel-body log-area\" id=\"log-list\">\n <div class=\"empty\">no log output</div>\n </div>\n </div>\n </div>\n\n <!-- RIGHT: CHAT -->\n <div class=\"col\">\n <!-- PR PROCESSOR -->\n <div class=\"panel\" style=\"flex: 0 0 auto;\">\n <div class=\"panel-hdr\">\n <span class=\"panel-hdr-title\">PR PROCESSOR</span>\n <span class=\"panel-hdr-badge\" id=\"pr-proc-badge\"></span>\n </div>\n <div class=\"panel-body\" style=\"font-size: 11px; line-height: 1.5;\">\n <div id=\"pr-proc-body\" style=\"color: var(--dim);\">Loading...</div>\n </div>\n </div>\n\n <!-- STUCK/FAILED ISSUES -->\n <div class=\"panel\" style=\"flex: 0 0 auto; max-height: 200px;\">\n <div class=\"panel-hdr\">\n <span class=\"panel-hdr-title\">\u26A0 STUCK/FAILED</span>\n <span class=\"panel-hdr-badge\" id=\"stuck-badge\">0</span>\n <button class=\"btn\" style=\"margin-left: 0.5rem; font-size: 9px; padding: 1px 6px;\" onclick=\"restartStuckIssues()\" id=\"restart-stuck-btn\">\u21BB RESTART ALL</button>\n </div>\n <div class=\"panel-body\" style=\"font-size: 10px; line-height: 1.4; overflow-y: auto;\">\n <div id=\"stuck-list\" style=\"color: var(--dim);\">Loading...</div>\n </div>\n </div>\n\n <!-- AGENT CHAT -->\n <div class=\"panel-hdr\">\n <span class=\"panel-hdr-title\">AGENT CHAT</span>\n <span class=\"panel-hdr-badge\" id=\"chat-status\"></span>\n </div>\n <div class=\"chat-col\">\n <div class=\"chat-messages\" id=\"chat-messages\"></div>\n <div class=\"chat-input-area\">\n <span class=\"chat-prompt\">></span>\n <input\n class=\"chat-input\" id=\"chat-input\"\n type=\"text\" placeholder=\"message OpenSwarm...\"\n onkeydown=\"if(event.key==='Enter')sendChat()\"\n >\n <button class=\"chat-send\" id=\"chat-send\" onclick=\"sendChat()\">SEND</button>\n </div>\n </div>\n </div>\n\n </div>\n\n <script>\n const MAX_LOG = 200;\n const MAX_STAGE = 100;\n\n let projects = [];\n let expandedProjects = new Set();\n let knowledgeCache = {};\n let logLines = [];\n let selectedLogTaskId = null; // null = ALL, string = specific taskId\n let stageRows = [];\n let chatBusy = false;\n let totalCostUsd = 0;\n const taskProjectMap = new Map();\n // taskId \u2192 { title, issueIdentifier } for pipeline display\n const taskTitleMap = new Map();\n // taskId \u2192 start timestamp for elapsed time\n const taskStartMap = new Map();\n\n // ---- SSE ----\n function connectSSE(skipReplay) {\n const url = skipReplay ? \"/api/events?skipReplay=1\" : \"/api/events\";\n const es = new EventSource(url);\n const statusEl = document.getElementById(\"sse-status\");\n es.onopen = () => { statusEl.textContent = \"LIVE\"; statusEl.className = \"connected\"; };\n es.onmessage = e => {\n let ev; try { ev = JSON.parse(e.data); } catch { return; }\n handleEvent(ev);\n };\n es.onerror = () => {\n statusEl.textContent = \"RECONNECTING\"; statusEl.className = \"disconnected\";\n es.close(); setTimeout(function() { connectSSE(false); }, 3000);\n };\n }\n\n function handleEvent(ev) {\n switch (ev.type) {\n case \"stats\": updateStats(ev.data); break;\n case \"task:queued\":\n taskProjectMap.set(ev.data.taskId, ev.data.projectPath);\n taskTitleMap.set(ev.data.taskId, { title: ev.data.title, issueIdentifier: ev.data.issueIdentifier });\n updateProjectTask(ev.data.projectPath, ev.data.taskId, ev.data.title, ev.data.priority, \"queued\");\n break;\n case \"task:started\": {\n const p = taskProjectMap.get(ev.data.taskId);\n if (ev.data.title) taskTitleMap.set(ev.data.taskId, { title: ev.data.title, issueIdentifier: ev.data.issueIdentifier });\n taskStartMap.set(ev.data.taskId, Date.now());\n if (p) updateProjectTask(p, ev.data.taskId, ev.data.title, null, \"running\");\n break;\n }\n case \"task:completed\": {\n const p = taskProjectMap.get(ev.data.taskId);\n if (p) removeProjectTask(p, ev.data.taskId);\n break;\n }\n case \"pipeline:stage\": addStageRow(ev.data); break;\n case \"pipeline:iteration\":\n addStageRow({ taskId: ev.data.taskId, stage: \"iter #\" + ev.data.iteration, status: \"start\" });\n break;\n case \"log\": addLogLine(ev.data); break;\n case \"project:toggled\": {\n const p = projects.find(x => x.path === ev.data.projectPath);\n if (p) { p.enabled = ev.data.enabled; renderProjects(); }\n break;\n }\n case \"task:cost\": {\n totalCostUsd += ev.data.cost?.costUsd ?? 0;\n document.getElementById(\"stat-cost\").textContent = \"$\" + totalCostUsd.toFixed(2);\n break;\n }\n case \"chat:agent\": appendChatMsg(\"agent\", ev.data.text, null, ev.data.ts); break;\n case \"monitor:checked\":\n case \"monitor:stateChange\":\n fetchMonitors();\n break;\n case \"process:spawn\":\n fetchProcesses();\n addLogLine({ taskId: ev.data.taskId || \"system\", stage: ev.data.stage || \"spawn\", line: \"Process spawned PID=\" + ev.data.pid + \" stage=\" + ev.data.stage + (ev.data.model ? \" model=\" + ev.data.model : \"\") });\n break;\n case \"process:exit\":\n fetchProcesses();\n addLogLine({ taskId: \"system\", stage: \"exit\", line: \"Process exited PID=\" + ev.data.pid + \" code=\" + ev.data.exitCode + \" duration=\" + (ev.data.durationMs / 1000).toFixed(1) + \"s\" });\n break;\n case \"heartbeat\": {\n const btn = document.getElementById(\"hb-btn\");\n btn.disabled = false; btn.textContent = \"\u25B6 HEARTBEAT\";\n break;\n }\n case \"pr_processor_start\":\n case \"pr_processor_end\":\n case \"pr_processor_pr\":\n fetchPRProcessorStatus();\n break;\n }\n }\n\n // ---- Stats ----\n function updateStats(data) {\n function shortModel(model) {\n if (!model) return \"-\";\n return model.length > 18 ? model.slice(0, 15) + \"...\" : model;\n }\n\n document.getElementById(\"stat-running\").textContent = data.runningTasks ?? 0;\n document.getElementById(\"stat-queued\").textContent = data.queuedTasks ?? 0;\n document.getElementById(\"stat-completed\").textContent = data.completedToday ?? 0;\n const defaultAdapter = data.adapters?.defaultAdapter ?? \"-\";\n const workerAdapter = data.adapters?.worker?.adapter ?? \"-\";\n const workerModel = shortModel(data.adapters?.worker?.model);\n const reviewerAdapter = data.adapters?.reviewer?.adapter ?? \"-\";\n const reviewerModel = shortModel(data.adapters?.reviewer?.model);\n const chatModel = workerModel || \"-\";\n document.getElementById(\"stat-adapter\").textContent = defaultAdapter;\n document.getElementById(\"stat-pair-adapters\").textContent =\n \"W \" + workerAdapter + \":\" + workerModel + \" / R \" + reviewerAdapter + \":\" + reviewerModel;\n document.getElementById(\"chat-status\").textContent = defaultAdapter + \":\" + chatModel;\n document.getElementById(\"provider-claude\").classList.toggle(\"active\", defaultAdapter === \"claude\");\n document.getElementById(\"provider-codex\").classList.toggle(\"active\", defaultAdapter === \"codex\");\n if (data.uptime != null) {\n const s = Math.floor(data.uptime / 1000);\n const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), ss = s % 60;\n document.getElementById(\"stat-uptime\").textContent =\n (h ? h + \"h \" : \"\") + (m ? m + \"m \" : \"\") + ss + \"s\";\n }\n // Turbo mode\n const turboBtn = document.getElementById(\"turbo-btn\");\n if (turboBtn) {\n turboBtn.classList.toggle(\"turbo-active\", !!data.turboMode);\n if (data.turboMode && data.turboExpiresAt) {\n const remainMin = Math.max(0, Math.round((data.turboExpiresAt - Date.now()) / 60000));\n turboBtn.textContent = \"TURBO \" + remainMin + \"m\";\n } else {\n turboBtn.textContent = \"TURBO\";\n }\n }\n // Daily pace\n const paceEl = document.getElementById(\"stat-pace\");\n if (paceEl && data.dailyPace) {\n const cap = data.turboMode ? 20 : 6;\n paceEl.textContent = data.dailyPace.completedToday + \"/\" + cap;\n paceEl.className = \"stat-val\" + (data.turboMode ? \" amber\" : \"\");\n }\n }\n\n // ---- Service control ----\n async function fetchSvcStatus() {\n try {\n const res = await fetch(\"/api/service/status\");\n const data = await res.json();\n const el = document.getElementById(\"svc-status\");\n const status = data.status || \"unknown\";\n el.textContent = status;\n el.className = \"svc-status \" + (status === \"active\" ? \"active\" : \"inactive\");\n } catch {\n const el = document.getElementById(\"svc-status\");\n el.textContent = \"unknown\";\n el.className = \"svc-status inactive\";\n }\n }\n\n // ---- Stuck/Failed Issues ----\n async function fetchStuckIssues() {\n try {\n const res = await fetch(\"/api/stuck-issues\");\n const data = await res.json();\n const list = document.getElementById(\"stuck-list\");\n const badge = document.getElementById(\"stuck-badge\");\n\n const totalStuck = data.stuckIssues?.length ?? 0;\n const totalFailed = data.failedIssues?.length ?? 0;\n const total = totalStuck + totalFailed;\n\n badge.textContent = total;\n badge.style.color = total > 0 ? \"var(--red)\" : \"var(--dim)\";\n\n if (total === 0) {\n list.innerHTML = '<div style=\"color: var(--green-mid); padding: 4px;\">\u2713 All issues healthy</div>';\n return;\n }\n\n let html = '';\n\n // Stuck issues (In Progress for >7 days)\n if (totalStuck > 0) {\n html += '<div style=\"color: var(--amber); font-weight: bold; margin-bottom: 4px; font-size: 9px; text-transform: uppercase;\">\u23F1 Stuck (' + totalStuck + ')</div>';\n data.stuckIssues.forEach(issue => {\n const priorityColor = issue.priority === 1 ? 'var(--red)' : issue.priority === 2 ? 'var(--amber)' : 'var(--dim)';\n html += '<div style=\"margin-bottom: 6px; padding: 4px; border-left: 2px solid ' + priorityColor + '; background: rgba(255, 170, 0, 0.05);\">';\n html += '<div style=\"color: var(--white); font-size: 10px; margin-bottom: 2px;\">' + issue.identifier + ': ' + issue.title.substring(0, 40) + (issue.title.length > 40 ? '...' : '') + '</div>';\n html += '<div style=\"color: var(--amber); font-size: 9px;\">' + issue.reason + '</div>';\n if (issue.project?.name) {\n html += '<div style=\"color: var(--dim); font-size: 9px; margin-top: 2px;\">\uD83D\uDCC1 ' + issue.project.name + '</div>';\n }\n html += '</div>';\n });\n }\n\n // Failed issues (retry, failed, blocked labels)\n if (totalFailed > 0) {\n if (totalStuck > 0) html += '<div style=\"height: 8px;\"></div>';\n html += '<div style=\"color: var(--red); font-weight: bold; margin-bottom: 4px; font-size: 9px; text-transform: uppercase;\">\u2716 Failed (' + totalFailed + ')</div>';\n data.failedIssues.forEach(issue => {\n const priorityColor = issue.priority === 1 ? 'var(--red)' : issue.priority === 2 ? 'var(--amber)' : 'var(--dim)';\n html += '<div style=\"margin-bottom: 6px; padding: 4px; border-left: 2px solid ' + priorityColor + '; background: rgba(255, 51, 51, 0.05);\">';\n html += '<div style=\"color: var(--white); font-size: 10px; margin-bottom: 2px;\">' + issue.identifier + ': ' + issue.title.substring(0, 40) + (issue.title.length > 40 ? '...' : '') + '</div>';\n html += '<div style=\"color: var(--red); font-size: 9px;\">' + issue.reason + '</div>';\n if (issue.project?.name) {\n html += '<div style=\"color: var(--dim); font-size: 9px; margin-top: 2px;\">\uD83D\uDCC1 ' + issue.project.name + '</div>';\n }\n html += '</div>';\n });\n }\n\n list.innerHTML = html;\n } catch (err) {\n console.error(\"Failed to fetch stuck issues:\", err);\n document.getElementById(\"stuck-list\").innerHTML = '<div style=\"color: var(--red);\">Error loading</div>';\n }\n }\n\n // ---- PR Processor Status ----\n async function fetchPRProcessorStatus() {\n try {\n const res = await fetch(\"/api/pr-processor-status\");\n const data = await res.json();\n const body = document.getElementById(\"pr-proc-body\");\n const badge = document.getElementById(\"pr-proc-badge\");\n\n if (!data) {\n body.innerHTML = '<div style=\"color: var(--dim);\">Not configured</div>';\n badge.textContent = \"OFF\";\n badge.style.color = \"var(--dim)\";\n return;\n }\n\n const status = data.processing ? \"RUNNING\" : \"IDLE\";\n badge.textContent = status;\n badge.style.color = data.processing ? \"var(--green)\" : \"var(--cyan)\";\n\n const formatTime = (ts) => {\n if (!ts) return \"N/A\";\n const d = new Date(ts);\n return d.toLocaleTimeString(\"en-US\", { hour: \"2-digit\", minute: \"2-digit\" });\n };\n\n let html = '<div style=\"display: flex; flex-direction: column; gap: 6px;\">';\n html += '<div><span style=\"color: var(--dim);\">Schedule:</span> <span style=\"color: var(--text);\">' + (data.schedule || \"N/A\") + '</span></div>';\n html += '<div><span style=\"color: var(--dim);\">Repos:</span> <span style=\"color: var(--text);\">' + (data.repos?.length || 0) + '</span></div>';\n\n if (data.currentPR) {\n html += '<div><span style=\"color: var(--amber);\">Processing:</span> <span style=\"color: var(--text); font-family: monospace; font-size: 10px;\">' + data.currentPR + '</span></div>';\n }\n\n html += '<div><span style=\"color: var(--dim);\">Last run:</span> <span style=\"color: var(--text);\">' + formatTime(data.lastRun) + '</span></div>';\n html += '<div><span style=\"color: var(--dim);\">Next run:</span> <span style=\"color: var(--text);\">' + formatTime(data.nextRun) + '</span></div>';\n\n if (data.conflictResolverEnabled) {\n html += '<div style=\"color: var(--green); font-size: 10px; margin-top: 4px;\">\u2713 Conflict Resolver: ON</div>';\n }\n\n html += '</div>';\n body.innerHTML = html;\n } catch (e) {\n const body = document.getElementById(\"pr-proc-body\");\n body.innerHTML = '<div style=\"color: var(--red);\">Error: ' + e.message + '</div>';\n }\n }\n\n async function svcAction(action) {\n const label = action === \"stop\" ? \"STOP\" : \"RESTART\";\n if (!confirm(\"Are you sure you want to \" + label + \" the service?\")) return;\n const btnId = action === \"stop\" ? \"svc-stop-btn\" : \"svc-restart-btn\";\n const btn = document.getElementById(btnId);\n btn.disabled = true;\n try {\n await fetch(\"/api/service/\" + action, { method: \"POST\" });\n addLogLine({ taskId: \"system\", stage: \"service\", line: \"Service \" + action + \" requested\" });\n } catch(e) {\n addLogLine({ taskId: \"system\", stage: \"error\", line: \"Service \" + action + \" failed: \" + e.message });\n }\n btn.disabled = false;\n setTimeout(fetchSvcStatus, 2000);\n }\n\n // ---- Heartbeat trigger ----\n async function triggerHeartbeat() {\n const btn = document.getElementById(\"hb-btn\");\n btn.disabled = true; btn.textContent = \"\u27F3 RUNNING\";\n addLogLine({ taskId: \"system\", stage: \"manual\", line: \"Heartbeat triggered by user\" });\n try {\n await fetch(\"/api/heartbeat\", { method: \"POST\" });\n } catch(e) {\n addLogLine({ taskId: \"system\", stage: \"error\", line: \"Heartbeat failed: \" + e.message });\n btn.disabled = false; btn.textContent = \"\u25B6 HEARTBEAT\";\n }\n }\n\n async function toggleTurbo() {\n const btn = document.getElementById(\"turbo-btn\");\n const isActive = btn.classList.contains(\"turbo-active\");\n const newState = !isActive;\n if (newState && !confirm(\"Enable TURBO mode? (5min heartbeat, 20 daily cap, auto-expires in 4h)\")) return;\n btn.disabled = true;\n try {\n const res = await fetch(\"/api/turbo\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ enabled: newState })\n });\n if (!res.ok) throw new Error(\"Failed\");\n addLogLine({ taskId: \"system\", stage: \"turbo\", line: newState ? \"TURBO MODE ON\" : \"TURBO MODE OFF\" });\n const stats = await fetch(\"/api/stats\").then(r => r.json());\n updateStats(stats);\n } catch (e) {\n addLogLine({ taskId: \"system\", stage: \"error\", line: \"Turbo toggle failed: \" + e.message });\n }\n btn.disabled = false;\n }\n\n async function switchProvider(provider) {\n try {\n const res = await fetch(\"/api/provider\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ provider })\n });\n if (!res.ok) {\n const data = await res.json().catch(() => ({}));\n throw new Error(data.error || \"Failed to switch provider\");\n }\n addLogLine({ taskId: \"system\", stage: \"provider\", line: \"Provider switched to \" + provider });\n const stats = await fetch(\"/api/stats\").then(r => r.json());\n updateStats(stats);\n } catch (e) {\n addLogLine({ taskId: \"system\", stage: \"error\", line: \"Provider switch failed: \" + e.message });\n }\n }\n\n // ---- PR Processor trigger ----\n async function triggerPRProcessor() {\n const btn = document.getElementById(\"pr-proc-btn\");\n btn.disabled = true; btn.textContent = \"\u27F3 PROCESSING\";\n addLogLine({ taskId: \"system\", stage: \"manual\", line: \"PR Processor triggered by user\" });\n try {\n const res = await fetch(\"/api/trigger-pr-processor\", { method: \"POST\" });\n if (!res.ok) {\n const data = await res.json();\n throw new Error(data.error || \"Failed to trigger PR processor\");\n }\n addLogLine({ taskId: \"system\", stage: \"manual\", line: \"PR Processor started successfully\" });\n setTimeout(() => {\n btn.disabled = false;\n btn.textContent = \"\u21BB PR REVIEW\";\n }, 3000);\n } catch(e) {\n addLogLine({ taskId: \"system\", stage: \"error\", line: \"PR Processor failed: \" + e.message });\n btn.disabled = false; btn.textContent = \"\u21BB PR REVIEW\";\n }\n }\n\n // ---- Restart stuck issues ----\n async function restartStuckIssues() {\n if (!confirm(\"Move all stuck/failed issues to Todo?\")) return;\n const btn = document.getElementById(\"restart-stuck-btn\");\n btn.disabled = true;\n btn.textContent = \"\u27F3 PROCESSING...\";\n\n try {\n const res = await fetch(\"/api/stuck-issues\");\n const data = await res.json();\n const allIssues = [...data.stuckIssues, ...data.failedIssues];\n\n let success = 0;\n let failed = 0;\n\n for (const issue of allIssues) {\n try {\n const moveRes = await fetch(\"/api/issue/move-to-todo\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ issueId: issue.id })\n });\n\n if (moveRes.ok) {\n success++;\n addLogLine({ taskId: \"system\", stage: \"stuck\", line: \"Moved \" + issue.identifier + \" to Todo\" });\n } else {\n failed++;\n }\n } catch (e) {\n failed++;\n }\n }\n\n addLogLine({ taskId: \"system\", stage: \"stuck\", line: \"Restart complete: \" + success + \" moved, \" + failed + \" failed\" });\n setTimeout(fetchStuckIssues, 1000);\n } catch (e) {\n addLogLine({ taskId: \"system\", stage: \"error\", line: \"Failed to restart stuck issues: \" + e.message });\n }\n\n btn.disabled = false;\n btn.textContent = \"\u21BB RESTART ALL\";\n }\n\n // ---- Project task updates ----\n function updateProjectTask(projectPath, taskId, title, priority, status) {\n const p = projects.find(x => x.path === projectPath);\n if (!p) return;\n\n // Get issueIdentifier from taskTitleMap\n const taskInfo = taskTitleMap.get(taskId);\n const issueIdentifier = taskInfo?.issueIdentifier;\n\n if (status === \"running\") {\n p.queued = p.queued.filter(t => t.id !== taskId);\n if (!p.running.find(t => t.id === taskId)) {\n p.running.push({ id: taskId, title, priority, issueIdentifier });\n }\n } else {\n if (!p.queued.find(t => t.id === taskId)) {\n p.queued.push({ id: taskId, title, priority, issueIdentifier });\n }\n }\n renderProjects();\n }\n function removeProjectTask(projectPath, taskId) {\n const p = projects.find(x => x.path === projectPath);\n if (!p) return;\n p.running = p.running.filter(t => t.id !== taskId);\n p.queued = p.queued.filter(t => t.id !== taskId);\n renderProjects();\n }\n\n // ---- Toggle project ----\n async function toggleProject(projectPath, enabled) {\n const p = projects.find(x => x.path === projectPath);\n if (p) p.enabled = enabled;\n renderProjects();\n try {\n await fetch(\"/api/projects/toggle\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ projectPath, enabled }),\n });\n } catch(e) {\n if (p) p.enabled = !enabled;\n renderProjects();\n }\n }\n\n // ---- Render Projects ----\n function renderProjects() {\n const el = document.getElementById(\"project-list\");\n const sumEl = document.getElementById(\"proj-summary\");\n if (!projects.length) { el.innerHTML = \"<div class=\\\"empty\\\">no repositories</div>\"; return; }\n const on = projects.filter(p => p.enabled).length;\n if (sumEl) sumEl.textContent = on + \"/\" + projects.length;\n\n el.innerHTML = projects.map(p => {\n // Use path as key, fall back to __n:name for unmapped projects\n const key = p.path || (\"__n:\" + p.name);\n const expanded = expandedProjects.has(key);\n const checked = p.enabled ? \"checked\" : \"\";\n const dCls = p.enabled ? \"\" : \" disabled\";\n const eCls = expanded ? \" expanded\" : \"\";\n // PRs always visible (not gated by expand)\n let prsHtml = \"\";\n if (p.prs && p.prs.length) {\n prsHtml = \"<div class=\\\"proj-issues\\\">\" +\n \"<div class=\\\"issue-sec-label\\\">open PRs (\" + p.prs.length + \")</div>\" +\n p.prs.map(function(pr) {\n return \"<div class=\\\"pr-row\\\">\" +\n \"<span class=\\\"pr-num\\\">#\" + pr.number + \"</span>\" +\n \"<span class=\\\"pr-branch\\\" title=\\\"\" + escapeAttr(pr.branch) + \"\\\">\" + escapeHtml(pr.branch) + \"</span>\" +\n \"<span class=\\\"pr-title\\\" title=\\\"\" + escapeAttr(pr.title) + \"\\\">\" + escapeHtml(pr.title) + \"</span>\" +\n \"<span class=\\\"pr-age\\\">\" + fmtAge(pr.updatedAt) + \"</span>\" +\n \"</div>\";\n }).join(\"\") +\n \"</div>\";\n }\n let issuesHtml = \"\";\n if (expanded) {\n const secs = [];\n if (p.running.length) secs.push(\n \"<div class=\\\"issue-sec-label\\\">running</div>\" +\n p.running.map(t => issueRow(t, \"idot-run\")).join(\"\")\n );\n if (p.queued.length) secs.push(\n \"<div class=\\\"issue-sec-label\\\">queued</div>\" +\n p.queued.map(t => issueRow(t, \"idot-que\")).join(\"\")\n );\n if (p.pending.length) {\n var stateOrder = [\"In Review\", \"In Progress\", \"Todo\", \"Backlog\"];\n var byState = {};\n for (var ti = 0; ti < p.pending.length; ti++) {\n var st = p.pending[ti].linearState || \"Todo\";\n if (!byState[st]) byState[st] = [];\n byState[st].push(p.pending[ti]);\n }\n for (var si = 0; si < stateOrder.length; si++) {\n var sn = stateOrder[si];\n if (!byState[sn] || !byState[sn].length) continue;\n secs.push(\n \"<div class=\\\"issue-sec-label\\\">\" + sn.toLowerCase() + \" (\" + byState[sn].length + \")</div>\" +\n byState[sn].map(t => issueRow(t, \"idot-pnd\")).join(\"\")\n );\n }\n var otherKeys = Object.keys(byState);\n for (var oi = 0; oi < otherKeys.length; oi++) {\n if (stateOrder.indexOf(otherKeys[oi]) === -1) {\n secs.push(\n \"<div class=\\\"issue-sec-label\\\">\" + otherKeys[oi].toLowerCase() + \" (\" + byState[otherKeys[oi]].length + \")</div>\" +\n byState[otherKeys[oi]].map(t => issueRow(t, \"idot-pnd\")).join(\"\")\n );\n }\n }\n }\n if (!secs.length) secs.push(\"<div class=\\\"empty\\\" style=\\\"padding:4px\\\">no issues</div>\");\n // Knowledge graph health info (if cached)\n var kgData = knowledgeCache[p.name] || knowledgeCache[p.path];\n if (kgData && kgData.summary) {\n var s = kgData.summary;\n secs.push(\n \"<div class=\\\"issue-sec-label\\\">code health</div>\" +\n \"<div style=\\\"padding:2px 8px;font-size:10px;color:#88aa88\\\">\" +\n \"modules:\" + s.totalModules + \" tests:\" + s.totalTestFiles +\n \" untested:\" + s.untestedModules.length +\n \" churn:\" + (s.avgChurnScore || 0).toFixed(2) +\n (s.hotModules.length ? \" hot:\" + s.hotModules.slice(0,3).map(function(m){return m.split(\"/\").pop()}).join(\",\") : \"\") +\n \"</div>\"\n );\n }\n issuesHtml = \"<div class=\\\"proj-issues\\\">\" + secs.join(\"\") + \"</div>\";\n }\n\n return (\n \"<div class=\\\"proj-card\" + dCls + eCls + \"\\\" data-key=\\\"\" + escapeAttr(key) + \"\\\">\" +\n \"<div class=\\\"proj-hdr\\\" data-key=\\\"\" + escapeAttr(key) + \"\\\" onclick=\\\"handleToggleExpand(this)\\\">\" +\n \"<span class=\\\"proj-arrow\\\"></span>\" +\n \"<div class=\\\"proj-info\\\">\" +\n \"<div class=\\\"proj-name\\\">\" + escapeHtml(p.name) + \"</div>\" +\n \"<div class=\\\"proj-path\\\">\" + escapeHtml(p.path) + \"</div>\" +\n (p.git ? \"<div class=\\\"git-info\\\">\" +\n \"\\u2387 <span class=\\\"git-branch-name\\\">\" + escapeHtml(p.git.branch) + \"</span>\" +\n (p.git.hasChanges ? \" <span class=\\\"git-dirty\\\">\\u25CF \" + p.git.uncommittedFiles + \"</span>\" : \"\") +\n ((p.git.ahead || p.git.behind) ? \" <span class=\\\"git-sync\\\">\" +\n (p.git.ahead ? \"\\u2191\" + p.git.ahead : \"\") +\n (p.git.behind ? \" \\u2193\" + p.git.behind : \"\") +\n \"</span>\" : \"\") +\n \"</div>\" : \"\") +\n \"</div>\" +\n \"<div class=\\\"proj-counts\\\">\" +\n (p.running.length ? \"<span class=\\\"cnt cnt-run\\\">\" + p.running.length + \"r</span>\" : \"\") +\n (p.queued.length ? \"<span class=\\\"cnt cnt-que\\\">\" + p.queued.length + \"q</span>\" : \"\") +\n (p.pending.length ? \"<span class=\\\"cnt cnt-pnd\\\">\" + p.pending.length + \"p</span>\" : \"\") +\n \"</div>\" +\n \"<div class=\\\"proj-toggle\\\" onclick=\\\"event.stopPropagation()\\\" style=\\\"display:flex;align-items:center;gap:4px\\\">\" +\n \"<button class=\\\"btn\\\" style=\\\"font-size:8px;padding:1px 4px;opacity:.5\\\" data-path=\\\"\" + escapeAttr(p.path) + \"\\\" onclick=\\\"handleUnpin(this)\\\">\u2715</button>\" +\n \"<label class=\\\"toggle\\\">\" +\n \"<input type=\\\"checkbox\\\" \" + checked + \" data-path=\\\"\" + escapeAttr(p.path) + \"\\\" onchange=\\\"handleToggleProject(this)\\\">\" +\n \"<span class=\\\"slider\\\"></span>\" +\n \"</label>\" +\n \"</div>\" +\n \"</div>\" +\n prsHtml +\n issuesHtml +\n \"</div>\"\n );\n }).join(\"\");\n }\n\n function issueRow(t, dotClass) {\n const prio = t.priority || 3;\n const extraCls = t.linearState === \"Backlog\" ? \" issue-backlog\" : \"\";\n const moveBtn = t.linearState === \"Backlog\" && t.linearId\n ? \"<button class=\\\"move-to-todo-btn\\\" data-issue-id=\\\"\" + escapeAttr(t.linearId) + \"\\\" onclick=\\\"handleMoveToTodo(this)\\\">\u2192 Todo</button>\"\n : \"\";\n return (\n \"<div class=\\\"issue-row\" + extraCls + \"\\\">\" +\n \"<span class=\\\"idot \" + dotClass + \"\\\"></span>\" +\n \"<span class=\\\"prio prio-\" + Math.min(4, prio) + \"\\\"></span>\" +\n (t.issueIdentifier ? \"<span class=\\\"issue-id\\\">\" + escapeHtml(t.issueIdentifier) + \"</span>\" : \"\") +\n \"<span class=\\\"issue-title\\\" title=\\\"\" + escapeAttr(t.title) + \"\\\">\" + escapeHtml(t.title) + \"</span>\" +\n moveBtn +\n \"</div>\"\n );\n }\n\n function toggleExpand(key) {\n if (expandedProjects.has(key)) expandedProjects.delete(key);\n else expandedProjects.add(key);\n renderProjects();\n }\n function handleToggleExpand(el) {\n const key = el.getAttribute(\"data-key\");\n if (key) toggleExpand(key);\n }\n function handleToggleProject(el) {\n const path = el.getAttribute(\"data-path\");\n if (path) toggleProject(path, el.checked);\n }\n async function handleUnpin(el) {\n const path = el.getAttribute(\"data-path\");\n if (!path) return;\n el.disabled = true;\n try {\n await fetch(\"/api/projects/unpin\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ projectPath: path }),\n });\n const res = await fetch(\"/api/projects\");\n projects = await res.json();\n renderProjects();\n // Update picker state so re-adding works correctly\n const item = allLocalProjects.find(function(p) { return p.path === path; });\n if (item) item.pinned = false;\n } catch(e) { el.disabled = false; }\n }\n async function handleMoveToTodo(el) {\n const issueId = el.getAttribute(\"data-issue-id\");\n if (!issueId) return;\n\n const originalText = el.textContent;\n el.disabled = true;\n el.textContent = \"Moving...\";\n\n try {\n const response = await fetch(\"/api/issue/move-to-todo\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ issueId }),\n });\n\n if (!response.ok) {\n throw new Error(\"Failed to move issue\");\n }\n\n // Refresh projects to show updated state\n const res = await fetch(\"/api/projects\");\n projects = await res.json();\n renderProjects();\n } catch(e) {\n el.disabled = false;\n el.textContent = originalText;\n alert(\"Failed to move issue to Todo: \" + e.message);\n }\n }\n\n // ---- Pipeline Stages ----\n function addStageRow(data) {\n stageRows.push(data);\n if (stageRows.length > MAX_STAGE) stageRows = stageRows.slice(-MAX_STAGE);\n renderStages();\n }\n function shortModel(name) {\n if (!name) return \"\";\n if (name.includes(\"sonnet-4-5\")) return \"sonnet-4.5\";\n if (name.includes(\"haiku-4-5\")) return \"haiku-4.5\";\n if (name.includes(\"opus-4-6\")) return \"opus-4.6\";\n if (name.includes(\"opus-4\")) return \"opus-4\";\n if (name.includes(\"sonnet-4\")) return \"sonnet-4\";\n var parts = name.split(\"-\");\n return parts[parts.length - 1];\n }\n function fmtTokens(n) {\n if (n == null) return \"\";\n if (n >= 1000000) return (n / 1000000).toFixed(1) + \"M\";\n if (n >= 1000) return (n / 1000).toFixed(1) + \"k\";\n return String(n);\n }\n function renderStages() {\n const el = document.getElementById(\"stage-list\");\n const cnt = document.getElementById(\"stage-count\");\n if (!stageRows.length) { el.innerHTML = \"<div class=\\\"empty\\\">no pipeline events</div>\"; return; }\n if (cnt) cnt.textContent = stageRows.length + \"/\" + MAX_STAGE;\n el.innerHTML = stageRows.slice().reverse().map(r => {\n const info = r.taskId ? taskTitleMap.get(r.taskId) : null;\n let taskLabel = \"\";\n if (info) {\n taskLabel = info.issueIdentifier\n ? info.issueIdentifier + (info.title ? \" \" + info.title.slice(0, 22) : \"\")\n : (info.title ? info.title.slice(0, 30) : \"\");\n } else if (r.taskId) {\n taskLabel = r.taskId.slice(0, 8);\n }\n // repo name from projectPath\n const projPath = r.taskId ? taskProjectMap.get(r.taskId) : null;\n const repoName = projPath ? projPath.split(\"/\").pop() : \"\";\n // elapsed time\n const startTs = r.taskId ? taskStartMap.get(r.taskId) : null;\n let elapsed = \"\";\n if (startTs) {\n const sec = Math.floor((Date.now() - startTs) / 1000);\n if (sec < 60) elapsed = sec + \"s\";\n else if (sec < 3600) elapsed = Math.floor(sec / 60) + \"m\" + (sec % 60) + \"s\";\n else elapsed = Math.floor(sec / 3600) + \"h\" + Math.floor((sec % 3600) / 60) + \"m\";\n }\n // model/token info (only on complete)\n var modelStr = r.model ? shortModel(r.model) : \"\";\n var tokenStr = \"\";\n if (r.inputTokens || r.outputTokens) {\n tokenStr = fmtTokens(r.inputTokens) + \"/\" + fmtTokens(r.outputTokens);\n if (r.costUsd != null) tokenStr += \" $\" + r.costUsd.toFixed(2);\n }\n return (\n \"<div class=\\\"stage-row\\\">\" +\n \"<div class=\\\"sdot \" + (r.status || \"\") + \"\\\"></div>\" +\n \"<div class=\\\"srepo\\\">\" + escapeHtml(repoName) + \"</div>\" +\n \"<div class=\\\"sname\\\">\" + escapeHtml(r.stage) + \"</div>\" +\n \"<div class=\\\"stask\\\" title=\\\"\" + escapeAttr(r.taskId || \"\") + \"\\\">\" + escapeHtml(taskLabel) + \"</div>\" +\n \"<div class=\\\"smodel\\\">\" + escapeHtml(modelStr) + \"</div>\" +\n \"<div class=\\\"stokens\\\">\" + escapeHtml(tokenStr) + \"</div>\" +\n \"<div class=\\\"selapsed\\\">\" + elapsed + \"</div>\" +\n \"<div class=\\\"sstatus\\\">\" + (r.status || \"\") + \"</div>\" +\n \"</div>\"\n );\n }).join(\"\");\n el.scrollTop = 0;\n }\n\n // ---- Log Tab ----\n function selectLogTab(taskId) {\n selectedLogTaskId = taskId;\n document.querySelectorAll('.log-tab').forEach(t =>\n t.classList.toggle('active', t.dataset.task === (taskId ?? 'all'))\n );\n renderLog();\n }\n\n function updateLogTabs() {\n const bar = document.getElementById('log-tab-bar');\n const taskIds = [...new Set(logLines.map(l => l.taskId).filter(id => id && id !== 'system'))];\n // Sort by most recent start time\n taskIds.sort((a, b) => (taskStartMap.get(b) || 0) - (taskStartMap.get(a) || 0));\n\n let html = '<button class=\"log-tab' + (selectedLogTaskId === null ? ' active' : '')\n + '\" data-task=\"all\" onclick=\"selectLogTab(null)\">ALL</button>';\n\n for (const tid of taskIds) {\n const info = taskTitleMap.get(tid);\n const label = info?.issueIdentifier || tid.slice(0, 8);\n const isActive = selectedLogTaskId === tid;\n html += '<button class=\"log-tab' + (isActive ? ' active' : '')\n + '\" data-task=\"' + tid + '\" onclick=\"selectLogTab(\\'' + tid + '\\')\">'\n + escapeHtml(label) + '</button>';\n }\n bar.innerHTML = html;\n }\n\n // ---- Log ----\n function addLogLine(data) {\n data._ts = Date.now();\n logLines.push(data);\n if (logLines.length > MAX_LOG) logLines = logLines.slice(-MAX_LOG);\n updateLogTabs();\n renderLog();\n }\n\n function classifyLog(line) {\n if (!line) return { cls: \"log-spacer\", icon: \"\" };\n if (line === \"\u2500\u2500\u2500\") return { cls: \"log-separator\", icon: \"\" };\n if (/^\u25A0 /.test(line)) return { cls: \"log-heading2\", icon: \"\u25A0\" };\n if (/^[\u250C\u2514\u2502]/.test(line)) return { cls: \"log-code\", icon: \"\" };\n if (/^\u25B8 /.test(line)) return { cls: \"log-tool\", icon: \"\u25B8\" };\n if (/^\u25B6|Heartbeat started|Stage started|Iteration [0-9]/.test(line)) return { cls: \"log-heading\", icon: \"\u25B6\" };\n if (/^\u2713|success=true|approved|completed|Done|Created sub-issue/.test(line)) return { cls: \"log-success\", icon: \"\u2713\" };\n if (/^\u2717|success=false|failed|error|Error|rejected|exceeded/.test(line)) return { cls: \"log-fail\", icon: \"\u2717\" };\n if (/^\u27F3|Fetching|Decomposing|Running|Scheduling|Spawning/.test(line)) return { cls: \"\", icon: \"\u27F3\" };\n if (/^\u26D4|Blocked|Time window|blocked/.test(line)) return { cls: \"log-warn\", icon: \"\u26D4\" };\n if (/^\u2014|No task|already completed|no log/.test(line)) return { cls: \"log-system\", icon: \"\u2014\" };\n if (/Cost:|\\$[\\.0-9]/.test(line)) return { cls: \"\", icon: \"\uD83D\uDCB2\" };\n if (/Git detected|files changed|filesChanged/.test(line)) return { cls: \"\", icon: \"\uD83D\uDCC1\" };\n if (/Selected [0-9]+ tasks/.test(line)) return { cls: \"\", icon: \"\uD83C\uDFAF\" };\n if (/Enqueued|executePipeline/.test(line)) return { cls: \"\", icon: \"\uD83D\uDCCB\" };\n if (/Direct path|Project|path found/.test(line)) return { cls: \"log-system\", icon: \"\uD83D\uDCC2\" };\n return { cls: \"\", icon: \"\u00B7\" };\n }\n\n function formatLogText(raw) {\n if (!raw) return \"\";\n // Detect and humanize raw JSON that slipped through\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"{\") && trimmed.endsWith(\"}\")) {\n try {\n const obj = JSON.parse(trimmed);\n if (obj.needsDecomposition === false) {\n const r = obj.reason ? obj.reason.slice(0, 120) : \"\";\n raw = \"\\u2713 No decomposition needed (\" + (obj.totalEstimatedMinutes || \"?\") + \"min) \" + r;\n } else if (obj.needsDecomposition === true && obj.subTasks) {\n raw = \"\\uD83D\\uDD00 Decomposed into \" + obj.subTasks.length + \" sub-tasks (total \" + (obj.totalEstimatedMinutes || \"?\") + \"min)\";\n } else if (obj.success !== undefined) {\n raw = (obj.success ? \"\\u2713 \" : \"\\u2717 \") + (obj.summary || obj.error || JSON.stringify(obj).slice(0, 120));\n }\n } catch { /* not valid JSON */ }\n }\n let t = escapeHtml(raw);\n // inline bold: **text** \u2192 highlighted\n t = t.replace(/\\*\\*([^*]+)\\*\\*/g, '<span class=\"lhighlight\">$1</span>');\n // highlight cost figures\n t = t.replace(/(\\$[\\d.]+)/g, '<span class=\"lcost\">$1</span>');\n // highlight file counts\n t = t.replace(/(\\d+ files? changed)/g, '<span class=\"lfiles\">$1</span>');\n // highlight durations\n t = t.replace(/(\\d+\\.\\d+s|\\d+ms)/g, '<span class=\"lcost\">$1</span>');\n // highlight task titles in quotes\n t = t.replace(/("[^&]+")/g, '<span class=\"lhighlight\">$1</span>');\n // highlight issue identifiers\n t = t.replace(/(INT-\\d+)/g, '<span class=\"lhighlight\">$1</span>');\n return t;\n }\n\n function fmtLogTime(ts) {\n if (!ts) return \"\";\n const d = new Date(ts);\n return d.getHours().toString().padStart(2,\"0\") + \":\" +\n d.getMinutes().toString().padStart(2,\"0\") + \":\" +\n d.getSeconds().toString().padStart(2,\"0\");\n }\n\n function renderLog() {\n const el = document.getElementById(\"log-list\");\n const cnt = document.getElementById(\"log-count\");\n const filtered = selectedLogTaskId === null\n ? logLines\n : logLines.filter(l => l.taskId === selectedLogTaskId);\n if (!filtered.length) {\n el.innerHTML = \"<div class=\\\"empty\\\">\" + (selectedLogTaskId ? \"no logs for this task\" : \"no log output\") + \"</div>\";\n if (cnt) cnt.textContent = selectedLogTaskId ? filtered.length + \"/\" + logLines.length : \"\";\n return;\n }\n if (cnt) cnt.textContent = (selectedLogTaskId ? filtered.length + \"/\" : \"\") + logLines.length + \"/\" + MAX_LOG;\n const atBottom = el.scrollHeight - el.scrollTop <= el.clientHeight + 50;\n el.innerHTML = filtered.map(l => {\n const info = l.taskId ? taskTitleMap.get(l.taskId) : null;\n const tag = info?.issueIdentifier\n ? info.issueIdentifier\n : (l.taskId === \"system\" ? \"SYS\" : (l.taskId || \"\").slice(0, 8));\n const { cls, icon } = classifyLog(l.line);\n // spacer/separator use minimal rendering\n if (cls === \"log-spacer\") return \"<div class=\\\"log-line log-spacer\\\"></div>\";\n if (cls === \"log-separator\") return \"<div class=\\\"log-line log-separator\\\"><span class=\\\"ltext\\\">\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</span></div>\";\n const time = fmtLogTime(l._ts);\n const stage = l.stage && l.stage !== \"heartbeat\" ? l.stage : \"\";\n // heading2: strip \u25A0 prefix (icon handles it)\n const displayLine = cls === \"log-heading2\" ? (l.line || \"\").replace(/^\u25A0 /, \"\") : l.line;\n // tool: strip \u25B8 prefix\n const displayLine2 = cls === \"log-tool\" ? (displayLine || \"\").replace(/^\u25B8 /, \"\") : displayLine;\n return (\n \"<div class=\\\"log-line \" + cls + \"\\\">\" +\n \"<span class=\\\"ltime\\\">\" + time + \"</span>\" +\n \"<span class=\\\"licon\\\">\" + icon + \"</span>\" +\n \"<span class=\\\"ltag\\\" title=\\\"\" + escapeAttr(l.taskId || \"\") + \"\\\">\" + escapeHtml(tag) + \"</span>\" +\n (stage ? \"<span class=\\\"lstage\\\">\" + escapeHtml(stage) + \"</span>\" : \"\") +\n \"<span class=\\\"ltext\\\">\" + formatLogText(displayLine2) + \"</span>\" +\n \"</div>\"\n );\n }).join(\"\");\n if (atBottom) el.scrollTop = el.scrollHeight;\n }\n\n // ---- Chat ----\n function fmtTime(ts) {\n const d = new Date(ts);\n return d.getHours().toString().padStart(2,\"0\") + \":\" +\n d.getMinutes().toString().padStart(2,\"0\");\n }\n\n function appendChatMsg(role, text, id, ts) {\n const container = document.getElementById(\"chat-messages\");\n const line = document.createElement(\"div\");\n line.className = \"chat-line chat-\" + role;\n if (id) line.id = id;\n const prefix = role === \"user\"\n ? \"<span class=\\\"chat-prefix\\\">YOU ></span>\"\n : \"<span class=\\\"chat-prefix\\\">OpenSwarm></span>\";\n const tsStr = ts ? \"<span class=\\\"chat-ts\\\">\" + fmtTime(ts) + \"</span>\" : \"\";\n line.innerHTML = prefix + \" <span class=\\\"chat-text\\\">\" + escapeHtml(text) + \"</span>\" + tsStr;\n container.appendChild(line);\n container.scrollTop = container.scrollHeight;\n }\n\n async function sendChat() {\n if (chatBusy) return;\n const input = document.getElementById(\"chat-input\");\n const sendBtn = document.getElementById(\"chat-send\");\n const msg = input.value.trim();\n if (!msg) return;\n input.value = \"\";\n chatBusy = true;\n sendBtn.disabled = true;\n\n appendChatMsg(\"user\", msg, null, Date.now());\n\n const thinkId = \"think-\" + Date.now();\n const thinkEl = document.createElement(\"div\");\n thinkEl.id = thinkId;\n thinkEl.className = \"chat-line chat-agent\";\n thinkEl.innerHTML = \"<span class=\\\"chat-prefix\\\">OpenSwarm></span> <span class=\\\"chat-text chat-thinking\\\">thinking...</span>\";\n document.getElementById(\"chat-messages\").appendChild(thinkEl);\n document.getElementById(\"chat-messages\").scrollTop = 99999;\n\n try {\n const res = await fetch(\"/api/chat\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ message: msg }),\n });\n const data = await res.json();\n document.getElementById(thinkId)?.remove();\n appendChatMsg(\"agent\", data.response || data.error || \"(no response)\", null, Date.now());\n } catch(e) {\n document.getElementById(thinkId)?.remove();\n appendChatMsg(\"agent\", \"[ERROR] \" + e.message, null, Date.now());\n }\n\n chatBusy = false;\n sendBtn.disabled = false;\n input.focus();\n }\n\n // ---- Utils ----\n function fmtAge(isoDate) {\n if (!isoDate) return \"\";\n var diff = Math.max(0, Date.now() - new Date(isoDate).getTime());\n var sec = Math.floor(diff / 1000);\n if (sec < 60) return sec + \"s\";\n var min = Math.floor(sec / 60);\n if (min < 60) return min + \"m\";\n var hr = Math.floor(min / 60);\n if (hr < 24) return hr + \"h\";\n var day = Math.floor(hr / 24);\n if (day < 7) return day + \"d\";\n var wk = Math.floor(day / 7);\n return wk + \"w\";\n }\n function escapeHtml(text) {\n const d = document.createElement(\"div\"); d.textContent = String(text || \"\"); return d.innerHTML;\n }\n function escapeAttr(text) {\n return String(text || \"\").replace(/&/g, \"&\").replace(/\"/g, \""\");\n }\n\n // ---- Repo Picker ----\n let allLocalProjects = [];\n let pickerOpen = false;\n\n async function openRepoPicker() {\n if (pickerOpen) return;\n pickerOpen = true;\n const overlay = document.getElementById(\"repo-picker\");\n overlay.style.display = \"flex\";\n document.getElementById(\"repo-search\").value = \"\";\n document.getElementById(\"repo-picker-list\").innerHTML =\n \"<div class=\\\"empty\\\">loading...</div>\";\n document.getElementById(\"repo-search\").focus();\n\n try {\n fetchScanPaths();\n const res = await fetch(\"/api/local-projects\");\n allLocalProjects = await res.json();\n filterRepos(\"\");\n } catch(e) {\n document.getElementById(\"repo-picker-list\").innerHTML =\n \"<div class=\\\"empty\\\">failed to load: \" + escapeHtml(e.message) + \"</div>\";\n }\n }\n\n function closeRepoPicker() {\n pickerOpen = false;\n document.getElementById(\"repo-picker\").style.display = \"none\";\n }\n\n function filterRepos(q) {\n const list = document.getElementById(\"repo-picker-list\");\n const filtered = q\n ? allLocalProjects.filter(p =>\n p.name.toLowerCase().includes(q.toLowerCase()) ||\n p.path.toLowerCase().includes(q.toLowerCase()))\n : allLocalProjects;\n\n if (!filtered.length) {\n list.innerHTML = \"<div class=\\\"empty\\\">no results</div>\";\n return;\n }\n list.innerHTML = filtered.slice(0, 80).map(p => {\n const badge = p.pinned ? \"<span class=\\\"repo-item-badge\\\">pinned</span>\" : \"\";\n return (\n \"<div class=\\\"repo-item\\\" data-path=\\\"\" + escapeAttr(p.path) + \"\\\" onclick=\\\"pickRepo(this)\\\">\" +\n \"<div>\" +\n \"<div class=\\\"repo-item-name\\\">\" + escapeHtml(p.name) + \"</div>\" +\n \"<div class=\\\"repo-item-path\\\">\" + escapeHtml(p.path) + \"</div>\" +\n \"</div>\" +\n badge +\n \"</div>\"\n );\n }).join(\"\");\n }\n\n async function pickRepo(el) {\n const path = el.getAttribute(\"data-path\");\n if (!path) return;\n el.style.opacity = \"0.4\";\n try {\n await fetch(\"/api/projects/pin\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ projectPath: path }),\n });\n // Refresh project list\n const res = await fetch(\"/api/projects\");\n projects = await res.json();\n renderProjects();\n // Mark as pinned in local picker list\n const item = allLocalProjects.find(p => p.path === path);\n if (item) item.pinned = true;\n filterRepos(document.getElementById(\"repo-search\").value);\n } catch(e) {\n console.error(\"Pin failed:\", e);\n }\n el.style.opacity = \"1\";\n }\n\n // ---- Scan Paths ----\n async function fetchScanPaths() {\n try {\n const res = await fetch(\"/api/scan-paths\");\n if (res.ok) {\n const data = await res.json();\n renderScanPaths(data);\n }\n } catch(e) {\n console.error(\"fetchScanPaths error:\", e);\n }\n }\n\n function renderScanPaths(data) {\n const list = document.getElementById(\"scan-paths-list\");\n if (!list) return;\n const rows = [];\n for (const p of (data.configPaths || [])) {\n rows.push(\n \"<div class=\\\"scan-path-row\\\">\" +\n \"<span class=\\\"path\\\">\" + escapeHtml(p) + \"</span>\" +\n \"<button class=\\\"scan-path-remove\\\" title=\\\"remove\\\" onclick=\\\"removeScanPath('\" + escapeAttr(p) + \"')\\\">\u2715</button>\" +\n \"</div>\"\n );\n }\n for (const p of (data.customPaths || [])) {\n rows.push(\n \"<div class=\\\"scan-path-row\\\">\" +\n \"<span class=\\\"path\\\">\" + escapeHtml(p) + \"</span>\" +\n \"<button class=\\\"scan-path-remove\\\" onclick=\\\"removeScanPath('\" + escapeAttr(p) + \"')\\\">\u2715</button>\" +\n \"</div>\"\n );\n }\n list.innerHTML = rows.length > 0 ? rows.join(\"\") : \"<div style=\\\"color:#334433;font-size:10px\\\">no scan paths configured</div>\";\n }\n\n async function addScanPath() {\n const input = document.getElementById(\"scan-path-input\");\n const path = input.value.trim();\n if (!path) return;\n input.value = \"\";\n try {\n await fetch(\"/api/scan-paths\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ path }),\n });\n await fetchScanPaths();\n // Refresh project list in picker\n const res = await fetch(\"/api/local-projects\");\n allLocalProjects = await res.json();\n filterRepos(document.getElementById(\"repo-search\").value);\n } catch(e) {\n console.error(\"addScanPath error:\", e);\n }\n }\n\n async function removeScanPath(path) {\n try {\n await fetch(\"/api/scan-paths/\" + encodeURIComponent(path), {\n method: \"DELETE\",\n });\n await fetchScanPaths();\n // Refresh project list in picker\n const res = await fetch(\"/api/local-projects\");\n allLocalProjects = await res.json();\n filterRepos(document.getElementById(\"repo-search\").value);\n } catch(e) {\n console.error(\"removeScanPath error:\", e);\n }\n }\n\n // ---- Monitors ----\n var monitorsData = [];\n async function fetchMonitors() {\n try {\n const res = await fetch(\"/api/monitors\");\n if (res.ok) { monitorsData = await res.json(); renderMonitors(); }\n } catch {}\n }\n function renderMonitors() {\n renderMonitorsAndProcesses();\n }\n function fmtDur(ms) {\n var s = Math.floor(ms / 1000);\n var h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60);\n if (h >= 24) return Math.floor(h / 24) + \"d \" + (h % 24) + \"h\";\n if (h > 0) return h + \"h \" + m + \"m\";\n return m + \"m\";\n }\n\n // ---- Processes ----\n var processesData = [];\n async function fetchProcesses() {\n try {\n const res = await fetch(\"/api/processes\");\n if (res.ok) { processesData = await res.json(); renderMonitorsAndProcesses(); }\n } catch {}\n }\n async function killProcess(pid) {\n if (!confirm(\"Kill process PID \" + pid + \"?\")) return;\n try {\n await fetch(\"/api/processes/\" + pid, { method: \"DELETE\" });\n processesData = processesData.filter(p => p.pid !== pid);\n renderMonitorsAndProcesses();\n } catch(e) {\n addLogLine({ taskId: \"system\", stage: \"error\", line: \"Kill failed: \" + e.message });\n }\n }\n function procActivityIcon(lastActivityAt) {\n var ago = (Date.now() - lastActivityAt) / 1000;\n if (ago < 10) return \"\\u26A1\";\n if (ago < 60) return \"\\u23F8\";\n return \"\\u2757\";\n }\n function renderMonitorsAndProcesses() {\n var panel = document.getElementById(\"monitor-panel\");\n var el = document.getElementById(\"monitor-list\");\n var countEl = document.getElementById(\"monitor-count\");\n var hasMonitors = monitorsData.length > 0;\n var hasProcesses = processesData.length > 0;\n if (!hasMonitors && !hasProcesses) {\n el.innerHTML = \"<div class=\\\"empty\\\">no monitors or processes</div>\";\n var counts = [];\n if (countEl) countEl.textContent = \"\";\n return;\n }\n var parts = [];\n if (processesData.length) parts.push(processesData.length + \"p\");\n if (monitorsData.length) parts.push(monitorsData.length + \"m\");\n if (countEl) countEl.textContent = parts.join(\" \");\n var html = \"\";\n // Processes section\n if (hasProcesses) {\n html += \"<div class=\\\"issue-sec-label\\\">processes</div>\";\n html += processesData.map(function(p) {\n var dur = fmtDur(Date.now() - p.spawnedAt);\n var act = procActivityIcon(p.lastActivityAt);\n var modelStr = p.model ? shortModel(p.model) : \"\";\n var projName = p.projectPath ? p.projectPath.split(\"/\").pop() : \"\";\n return '<div class=\"proc-row\">' +\n '<span class=\"proc-pid\">' + p.pid + '</span>' +\n '<span class=\"proc-stage\">' + escapeHtml(p.stage) + '</span>' +\n '<span class=\"proc-model\">' + escapeHtml(modelStr) + '</span>' +\n '<span style=\"color:var(--dim);font-size:9px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\" title=\"' + escapeAttr(p.projectPath || \"\") + '\">' + escapeHtml(projName) + '</span>' +\n '<span class=\"proc-activity\">' + act + '</span>' +\n '<span class=\"proc-dur\">' + dur + '</span>' +\n '<button class=\"proc-kill\" onclick=\"killProcess(' + p.pid + ')\">KILL</button>' +\n '</div>';\n }).join(\"\");\n }\n // Monitors section\n if (hasMonitors) {\n html += \"<div class=\\\"issue-sec-label\\\">monitors</div>\";\n html += monitorsData.map(function(m) {\n var stateColor = m.state === \"running\" ? \"var(--green)\" : m.state === \"completed\" ? \"var(--cyan)\" : m.state === \"failed\" || m.state === \"timeout\" ? \"var(--red)\" : \"var(--dim)\";\n var elapsed = m.registeredAt ? fmtDur(Date.now() - m.registeredAt) : \"-\";\n var lastOut = m.lastOutput ? escapeHtml(m.lastOutput.slice(0, 80)) : \"-\";\n return '<div style=\"padding:4px 6px;border-bottom:1px solid var(--border);font-size:11px\">' +\n '<div style=\"display:flex;align-items:center;gap:6px\">' +\n '<span style=\"color:' + stateColor + ';font-weight:bold\">[' + m.state.toUpperCase() + ']</span>' +\n '<span style=\"color:var(--green)\">' + escapeHtml(m.name) + '</span>' +\n '<span style=\"margin-left:auto;color:var(--dim)\">' + elapsed + '</span>' +\n '</div>' +\n '<div style=\"color:var(--dim);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\" title=\"' + escapeAttr(m.lastOutput || \"\") + '\">' + lastOut + '</div>' +\n (m.issueId ? '<div style=\"color:var(--cyan-dim);font-size:10px;margin-top:1px\">' + escapeHtml(m.issueId) + ' | checks: ' + m.checkCount + '</div>' : '') +\n '</div>';\n }).join(\"\");\n }\n el.innerHTML = html;\n }\n\n // ---- Init ----\n async function loadInitial() {\n try {\n // 1\uB2E8\uACC4: \uD544\uC218 \uB370\uC774\uD130 \uBA3C\uC800 \uB85C\uB4DC (\uC131\uB2A5 \uAC1C\uC120)\n const [statsRes, projectsRes] = await Promise.all([\n fetch(\"/api/stats\"),\n fetch(\"/api/projects\"),\n ]);\n const stats = await statsRes.json();\n updateStats(stats);\n document.getElementById(\"stat-sse\").textContent = stats.sseClients ?? \"-\";\n\n projects = await projectsRes.json();\n renderProjects();\n\n // 2\uB2E8\uACC4: \uCD94\uAC00 \uB370\uC774\uD130\uB294 \uBE44\uB3D9\uAE30\uB85C \uC9C0\uC5F0 \uB85C\uB4DC (\uBE0C\uB77C\uC6B0\uC800 \uB80C\uB354\uB9C1 \uBE14\uB85C\uD0B9 \uC81C\uAC70)\n loadSupplementalData();\n } catch(e) {\n console.error(\"Init failed:\", e);\n }\n }\n\n // \uCD94\uAC00 \uB370\uC774\uD130 \uC9C0\uC5F0 \uB85C\uB4DC (\uCD08\uAE30 \uB80C\uB354\uB9C1\uC744 \uBC29\uD574\uD558\uC9C0 \uC54A\uC74C)\n async function loadSupplementalData() {\n try {\n const [chatRes, logsRes, stagesRes] = await Promise.all([\n fetch(\"/api/chat/history\"),\n fetch(\"/api/logs\"),\n fetch(\"/api/stages\"),\n ]);\n\n const history = await chatRes.json();\n for (const msg of history) appendChatMsg(msg.role, msg.text, null, msg.ts);\n\n // Restore logs\n const logs = await logsRes.json();\n for (const ev of logs) addLogLine(ev.data);\n\n // Restore pipeline/task events\n const stages = await stagesRes.json();\n for (const ev of stages) handleEvent(ev);\n } catch(e) {\n console.error(\"Supplemental data load failed:\", e);\n }\n }\n\n // \uC131\uB2A5 \uCD5C\uC801\uD654: stats + projects \uD3F4\uB9C1\uC744 60\uCD08\uB85C \uC99D\uAC00 (\uBCC0\uD654 \uBE48\uB3C4 \uB0AE\uC74C)\n setInterval(async () => {\n try {\n const [sRes, pRes] = await Promise.all([fetch(\"/api/stats\"), fetch(\"/api/projects\")]);\n const stats = await sRes.json();\n document.getElementById(\"stat-sse\").textContent = stats.sseClients ?? \"-\";\n updateStats(stats);\n const fresh = await pRes.json();\n fresh.forEach(p => {\n const local = projects.find(l => l.path === p.path);\n if (local) p.enabled = local.enabled;\n });\n projects = fresh;\n renderProjects();\n } catch {}\n }, 60000);\n\n // ---- Mobile Tab Navigation ----\n function switchTab(idx) {\n const cols = document.querySelectorAll(\".main-grid > .col\");\n const tabs = document.querySelectorAll(\".tab-bar .tab\");\n cols.forEach((c, i) => c.classList.toggle(\"mob-active\", i === idx));\n tabs.forEach((t, i) => t.classList.toggle(\"active\", i === idx));\n }\n document.querySelector(\".tab-bar\").addEventListener(\"click\", e => {\n const tab = e.target.closest(\".tab\");\n if (!tab) return;\n switchTab(parseInt(tab.dataset.tab, 10));\n });\n // Activate first tab on load\n switchTab(0);\n\n // Knowledge graph data fetcher\n async function fetchKnowledgeData() {\n try {\n const res = await fetch(\"/api/knowledge\");\n if (res.ok) {\n const data = await res.json();\n for (const item of data) {\n knowledgeCache[item.slug] = item;\n // Also cache by last segment for name-based lookup\n const parts = item.slug.split(\"-\");\n knowledgeCache[parts[parts.length - 1]] = item;\n }\n renderProjects();\n }\n } catch {}\n }\n\n // ---- Quota tracker ----\n async function fetchQuota() {\n try {\n var res = await fetch(\"/api/quota\");\n if (!res.ok) return;\n var q = await res.json();\n if (q.error) return;\n var el5h = document.getElementById(\"stat-quota-5h\");\n var el7d = document.getElementById(\"stat-quota-7d\");\n if (q.five_hour && el5h) {\n var u5 = Math.round(q.five_hour.utilization);\n el5h.textContent = u5 + \"%\";\n el5h.className = \"stat-val \" + (u5 >= 80 ? \"red\" : u5 >= 50 ? \"amber\" : \"cyan\");\n }\n if (q.seven_day && el7d) {\n var u7 = Math.round(q.seven_day.utilization);\n el7d.textContent = u7 + \"%\";\n el7d.className = \"stat-val \" + (u7 >= 80 ? \"red\" : u7 >= 50 ? \"amber\" : \"cyan\");\n }\n } catch {}\n }\n\n // \uC131\uB2A5 \uCD5C\uC801\uD654: \uCD08\uAE30 \uB85C\uB4DC \uD6C4 2\uB2E8\uACC4 \uD398\uCE6D (\uB80C\uB354\uB9C1 \uBE14\uB85C\uD0B9 \uBC29\uC9C0)\n loadInitial().then(function() { connectSSE(true); });\n\n // 1\uB2E8\uACC4: \uCD08\uAE30\uD654 \uD6C4 \uC989\uC2DC \uD544\uC218 \uD3F4\uB9C1\uB9CC \uC2DC\uC791\n setInterval(fetchSvcStatus, 15000);\n setInterval(fetchPRProcessorStatus, 60000); // \uC131\uB2A5 \uCD5C\uC801\uD654: 30\uCD08 \u2192 60\uCD08 (\uBCC0\uD654 \uBE48\uB3C4 \uB0AE\uC74C)\n setInterval(fetchStuckIssues, 60000); // \uC131\uB2A5 \uCD5C\uC801\uD654: 30\uCD08 \u2192 60\uCD08 (Linear API \uBD80\uD558 \uAC10\uC18C)\n setInterval(fetchKnowledgeData, 60000);\n setInterval(fetchMonitors, 60000);\n setInterval(fetchProcesses, 30000);\n setInterval(fetchQuota, 300000);\n\n // 2\uB2E8\uACC4: \uB80C\uB354\uB9C1 \uC548\uC815\uD654 \uD6C4 \uBE44\uD544\uC218 \uB370\uC774\uD130 \uB85C\uB4DC (3\uCD08 \uC9C0\uC5F0)\n setTimeout(function() {\n fetchSvcStatus();\n fetchPRProcessorStatus();\n fetchStuckIssues();\n fetchKnowledgeData();\n fetchMonitors();\n fetchProcesses();\n fetchQuota();\n }, 3000);\n\n // \uB80C\uB354\uB9C1 \uC131\uB2A5: \uC2A4\uD14C\uC774\uC9C0 \uC5C5\uB370\uC774\uD2B8 \uD3F4\uB9C1 \uC81C\uAC70 (SSE \uC774\uBCA4\uD2B8 \uD65C\uC6A9)\n // setInterval(() => { if (stageRows.length) renderStages(); }, 10000);\n </script>\n</body>\n</html>";
|
|
2
|
+
export { DASHBOARD_HTML };
|
|
3
|
+
//# sourceMappingURL=dashboardHtml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboardHtml.d.ts","sourceRoot":"","sources":["../../src/support/dashboardHtml.ts"],"names":[],"mappings":"AACA,QAAA,MAAM,cAAc,643FAkhEZ,CAAC;AAGT,OAAO,EAAE,cAAc,EAAE,CAAC"}
|