@nexus-cortex/executors 4.26.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 +202 -0
- package/NOTICE +2 -0
- package/README.md +13 -0
- package/dist/ExecutorRegistry.d.ts +89 -0
- package/dist/ExecutorRegistry.d.ts.map +1 -0
- package/dist/ExecutorRegistry.js +219 -0
- package/dist/ExecutorRegistry.js.map +1 -0
- package/dist/base/BaseTool.d.ts +108 -0
- package/dist/base/BaseTool.d.ts.map +1 -0
- package/dist/base/BaseTool.js +111 -0
- package/dist/base/BaseTool.js.map +1 -0
- package/dist/base/ToolRegistry.d.ts +141 -0
- package/dist/base/ToolRegistry.d.ts.map +1 -0
- package/dist/base/ToolRegistry.js +241 -0
- package/dist/base/ToolRegistry.js.map +1 -0
- package/dist/base/ToolResult.d.ts +63 -0
- package/dist/base/ToolResult.d.ts.map +1 -0
- package/dist/base/ToolResult.js +8 -0
- package/dist/base/ToolResult.js.map +1 -0
- package/dist/base/index.d.ts +10 -0
- package/dist/base/index.d.ts.map +1 -0
- package/dist/base/index.js +8 -0
- package/dist/base/index.js.map +1 -0
- package/dist/implementations/addon/CreateArtifactTool.d.ts +221 -0
- package/dist/implementations/addon/CreateArtifactTool.d.ts.map +1 -0
- package/dist/implementations/addon/CreateArtifactTool.js +1042 -0
- package/dist/implementations/addon/CreateArtifactTool.js.map +1 -0
- package/dist/implementations/addon/FrameDiffCache.d.ts +166 -0
- package/dist/implementations/addon/FrameDiffCache.d.ts.map +1 -0
- package/dist/implementations/addon/FrameDiffCache.js +395 -0
- package/dist/implementations/addon/FrameDiffCache.js.map +1 -0
- package/dist/implementations/addon/H264StreamEncoder.d.ts +84 -0
- package/dist/implementations/addon/H264StreamEncoder.d.ts.map +1 -0
- package/dist/implementations/addon/H264StreamEncoder.js +203 -0
- package/dist/implementations/addon/H264StreamEncoder.js.map +1 -0
- package/dist/implementations/addon/HybridScreenshotManager.d.ts +197 -0
- package/dist/implementations/addon/HybridScreenshotManager.d.ts.map +1 -0
- package/dist/implementations/addon/HybridScreenshotManager.js +415 -0
- package/dist/implementations/addon/HybridScreenshotManager.js.map +1 -0
- package/dist/implementations/addon/InspectSandboxTool.d.ts +54 -0
- package/dist/implementations/addon/InspectSandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/InspectSandboxTool.js +226 -0
- package/dist/implementations/addon/InspectSandboxTool.js.map +1 -0
- package/dist/implementations/addon/InteractWithSandboxTool.d.ts +90 -0
- package/dist/implementations/addon/InteractWithSandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/InteractWithSandboxTool.js +367 -0
- package/dist/implementations/addon/InteractWithSandboxTool.js.map +1 -0
- package/dist/implementations/addon/KeyframeDetector.d.ts +140 -0
- package/dist/implementations/addon/KeyframeDetector.d.ts.map +1 -0
- package/dist/implementations/addon/KeyframeDetector.js +390 -0
- package/dist/implementations/addon/KeyframeDetector.js.map +1 -0
- package/dist/implementations/addon/ModifySandboxTool.d.ts +62 -0
- package/dist/implementations/addon/ModifySandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/ModifySandboxTool.js +266 -0
- package/dist/implementations/addon/ModifySandboxTool.js.map +1 -0
- package/dist/implementations/addon/ReactArtifactBuilder.d.ts +27 -0
- package/dist/implementations/addon/ReactArtifactBuilder.d.ts.map +1 -0
- package/dist/implementations/addon/ReactArtifactBuilder.js +198 -0
- package/dist/implementations/addon/ReactArtifactBuilder.js.map +1 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.d.ts +143 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.d.ts.map +1 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.js +258 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.js.map +1 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.d.ts +77 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.d.ts.map +1 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.js +292 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.js.map +1 -0
- package/dist/implementations/addon/SandboxViewServer.d.ts +127 -0
- package/dist/implementations/addon/SandboxViewServer.d.ts.map +1 -0
- package/dist/implementations/addon/SandboxViewServer.js +775 -0
- package/dist/implementations/addon/SandboxViewServer.js.map +1 -0
- package/dist/implementations/addon/ScreenStream.d.ts +149 -0
- package/dist/implementations/addon/ScreenStream.d.ts.map +1 -0
- package/dist/implementations/addon/ScreenStream.js +306 -0
- package/dist/implementations/addon/ScreenStream.js.map +1 -0
- package/dist/implementations/addon/StopSandboxTool.d.ts +61 -0
- package/dist/implementations/addon/StopSandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/StopSandboxTool.js +252 -0
- package/dist/implementations/addon/StopSandboxTool.js.map +1 -0
- package/dist/implementations/addon/TerminalSandbox.d.ts +111 -0
- package/dist/implementations/addon/TerminalSandbox.d.ts.map +1 -0
- package/dist/implementations/addon/TerminalSandbox.js +345 -0
- package/dist/implementations/addon/TerminalSandbox.js.map +1 -0
- package/dist/implementations/addon/VisualFeedbackBridge.d.ts +367 -0
- package/dist/implementations/addon/VisualFeedbackBridge.d.ts.map +1 -0
- package/dist/implementations/addon/VisualFeedbackBridge.js +888 -0
- package/dist/implementations/addon/VisualFeedbackBridge.js.map +1 -0
- package/dist/implementations/addon/WindowManager.d.ts +138 -0
- package/dist/implementations/addon/WindowManager.d.ts.map +1 -0
- package/dist/implementations/addon/WindowManager.js +276 -0
- package/dist/implementations/addon/WindowManager.js.map +1 -0
- package/dist/implementations/addon/index.d.ts +29 -0
- package/dist/implementations/addon/index.d.ts.map +1 -0
- package/dist/implementations/addon/index.js +29 -0
- package/dist/implementations/addon/index.js.map +1 -0
- package/dist/implementations/addon/injectables/reactIntrospection.d.ts +57 -0
- package/dist/implementations/addon/injectables/reactIntrospection.d.ts.map +1 -0
- package/dist/implementations/addon/injectables/reactIntrospection.js +480 -0
- package/dist/implementations/addon/injectables/reactIntrospection.js.map +1 -0
- package/dist/implementations/addon/terminal-client.html +253 -0
- package/dist/implementations/agent/PRAgentTool.d.ts +37 -0
- package/dist/implementations/agent/PRAgentTool.d.ts.map +1 -0
- package/dist/implementations/agent/PRAgentTool.js +257 -0
- package/dist/implementations/agent/PRAgentTool.js.map +1 -0
- package/dist/implementations/agent/TaskTool.d.ts +76 -0
- package/dist/implementations/agent/TaskTool.d.ts.map +1 -0
- package/dist/implementations/agent/TaskTool.js +424 -0
- package/dist/implementations/agent/TaskTool.js.map +1 -0
- package/dist/implementations/agent/index.d.ts +5 -0
- package/dist/implementations/agent/index.d.ts.map +1 -0
- package/dist/implementations/agent/index.js +3 -0
- package/dist/implementations/agent/index.js.map +1 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.d.ts +68 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.d.ts.map +1 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.js +146 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.js.map +1 -0
- package/dist/implementations/execution/BashOutputTool.d.ts +42 -0
- package/dist/implementations/execution/BashOutputTool.d.ts.map +1 -0
- package/dist/implementations/execution/BashOutputTool.js +168 -0
- package/dist/implementations/execution/BashOutputTool.js.map +1 -0
- package/dist/implementations/execution/CodeExecuteTool.d.ts +31 -0
- package/dist/implementations/execution/CodeExecuteTool.d.ts.map +1 -0
- package/dist/implementations/execution/CodeExecuteTool.js +127 -0
- package/dist/implementations/execution/CodeExecuteTool.js.map +1 -0
- package/dist/implementations/execution/KillShellTool.d.ts +37 -0
- package/dist/implementations/execution/KillShellTool.d.ts.map +1 -0
- package/dist/implementations/execution/KillShellTool.js +144 -0
- package/dist/implementations/execution/KillShellTool.js.map +1 -0
- package/dist/implementations/execution/SearchToolsTool.d.ts +32 -0
- package/dist/implementations/execution/SearchToolsTool.d.ts.map +1 -0
- package/dist/implementations/execution/SearchToolsTool.js +109 -0
- package/dist/implementations/execution/SearchToolsTool.js.map +1 -0
- package/dist/implementations/execution/ShellTool.d.ts +108 -0
- package/dist/implementations/execution/ShellTool.d.ts.map +1 -0
- package/dist/implementations/execution/ShellTool.js +546 -0
- package/dist/implementations/execution/ShellTool.js.map +1 -0
- package/dist/implementations/execution/WorkspaceManagerTool.d.ts +40 -0
- package/dist/implementations/execution/WorkspaceManagerTool.d.ts.map +1 -0
- package/dist/implementations/execution/WorkspaceManagerTool.js +370 -0
- package/dist/implementations/execution/WorkspaceManagerTool.js.map +1 -0
- package/dist/implementations/execution/index.d.ts +13 -0
- package/dist/implementations/execution/index.d.ts.map +1 -0
- package/dist/implementations/execution/index.js +13 -0
- package/dist/implementations/execution/index.js.map +1 -0
- package/dist/implementations/extensions/EndTurnTool.d.ts +62 -0
- package/dist/implementations/extensions/EndTurnTool.d.ts.map +1 -0
- package/dist/implementations/extensions/EndTurnTool.js +172 -0
- package/dist/implementations/extensions/EndTurnTool.js.map +1 -0
- package/dist/implementations/extensions/ResearchBacklogTool.d.ts +37 -0
- package/dist/implementations/extensions/ResearchBacklogTool.d.ts.map +1 -0
- package/dist/implementations/extensions/ResearchBacklogTool.js +102 -0
- package/dist/implementations/extensions/ResearchBacklogTool.js.map +1 -0
- package/dist/implementations/extensions/SkillTool.d.ts +108 -0
- package/dist/implementations/extensions/SkillTool.d.ts.map +1 -0
- package/dist/implementations/extensions/SkillTool.js +351 -0
- package/dist/implementations/extensions/SkillTool.js.map +1 -0
- package/dist/implementations/extensions/SlashCommandTool.d.ts +112 -0
- package/dist/implementations/extensions/SlashCommandTool.d.ts.map +1 -0
- package/dist/implementations/extensions/SlashCommandTool.js +315 -0
- package/dist/implementations/extensions/SlashCommandTool.js.map +1 -0
- package/dist/implementations/extensions/index.d.ts +14 -0
- package/dist/implementations/extensions/index.d.ts.map +1 -0
- package/dist/implementations/extensions/index.js +10 -0
- package/dist/implementations/extensions/index.js.map +1 -0
- package/dist/implementations/file/EditTool.d.ts +232 -0
- package/dist/implementations/file/EditTool.d.ts.map +1 -0
- package/dist/implementations/file/EditTool.js +707 -0
- package/dist/implementations/file/EditTool.js.map +1 -0
- package/dist/implementations/file/ReadFileTool.d.ts +49 -0
- package/dist/implementations/file/ReadFileTool.d.ts.map +1 -0
- package/dist/implementations/file/ReadFileTool.js +225 -0
- package/dist/implementations/file/ReadFileTool.js.map +1 -0
- package/dist/implementations/file/WriteBinaryTool.d.ts +21 -0
- package/dist/implementations/file/WriteBinaryTool.d.ts.map +1 -0
- package/dist/implementations/file/WriteBinaryTool.js +153 -0
- package/dist/implementations/file/WriteBinaryTool.js.map +1 -0
- package/dist/implementations/file/WriteFileTool.d.ts +41 -0
- package/dist/implementations/file/WriteFileTool.d.ts.map +1 -0
- package/dist/implementations/file/WriteFileTool.js +220 -0
- package/dist/implementations/file/WriteFileTool.js.map +1 -0
- package/dist/implementations/file/index.d.ts +8 -0
- package/dist/implementations/file/index.d.ts.map +1 -0
- package/dist/implementations/file/index.js +8 -0
- package/dist/implementations/file/index.js.map +1 -0
- package/dist/implementations/historical/GetConversationSegmentTool.d.ts +44 -0
- package/dist/implementations/historical/GetConversationSegmentTool.d.ts.map +1 -0
- package/dist/implementations/historical/GetConversationSegmentTool.js +220 -0
- package/dist/implementations/historical/GetConversationSegmentTool.js.map +1 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.d.ts +36 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.d.ts.map +1 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.js +174 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.js.map +1 -0
- package/dist/implementations/historical/ListSessionsTool.d.ts +38 -0
- package/dist/implementations/historical/ListSessionsTool.d.ts.map +1 -0
- package/dist/implementations/historical/ListSessionsTool.js +140 -0
- package/dist/implementations/historical/ListSessionsTool.js.map +1 -0
- package/dist/implementations/historical/LoadSessionTool.d.ts +39 -0
- package/dist/implementations/historical/LoadSessionTool.d.ts.map +1 -0
- package/dist/implementations/historical/LoadSessionTool.js +171 -0
- package/dist/implementations/historical/LoadSessionTool.js.map +1 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.d.ts +46 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.d.ts.map +1 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.js +224 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.js.map +1 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.d.ts +51 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.d.ts.map +1 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.js +306 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.js.map +1 -0
- package/dist/implementations/historical/index.d.ts +12 -0
- package/dist/implementations/historical/index.d.ts.map +1 -0
- package/dist/implementations/historical/index.js +12 -0
- package/dist/implementations/historical/index.js.map +1 -0
- package/dist/implementations/index.d.ts +16 -0
- package/dist/implementations/index.d.ts.map +1 -0
- package/dist/implementations/index.js +28 -0
- package/dist/implementations/index.js.map +1 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.d.ts +58 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.d.ts.map +1 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.js +269 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.js.map +1 -0
- package/dist/implementations/mcp/index.d.ts +9 -0
- package/dist/implementations/mcp/index.d.ts.map +1 -0
- package/dist/implementations/mcp/index.js +8 -0
- package/dist/implementations/mcp/index.js.map +1 -0
- package/dist/implementations/notebook/NotebookEditTool.d.ts +96 -0
- package/dist/implementations/notebook/NotebookEditTool.d.ts.map +1 -0
- package/dist/implementations/notebook/NotebookEditTool.js +390 -0
- package/dist/implementations/notebook/NotebookEditTool.js.map +1 -0
- package/dist/implementations/notebook/index.d.ts +7 -0
- package/dist/implementations/notebook/index.d.ts.map +1 -0
- package/dist/implementations/notebook/index.js +7 -0
- package/dist/implementations/notebook/index.js.map +1 -0
- package/dist/implementations/search/GlobTool.d.ts +73 -0
- package/dist/implementations/search/GlobTool.d.ts.map +1 -0
- package/dist/implementations/search/GlobTool.js +213 -0
- package/dist/implementations/search/GlobTool.js.map +1 -0
- package/dist/implementations/search/GrepTool.d.ts +102 -0
- package/dist/implementations/search/GrepTool.d.ts.map +1 -0
- package/dist/implementations/search/GrepTool.js +754 -0
- package/dist/implementations/search/GrepTool.js.map +1 -0
- package/dist/implementations/search/index.d.ts +6 -0
- package/dist/implementations/search/index.d.ts.map +1 -0
- package/dist/implementations/search/index.js +6 -0
- package/dist/implementations/search/index.js.map +1 -0
- package/dist/implementations/tmux/TmuxSessionTool.d.ts +82 -0
- package/dist/implementations/tmux/TmuxSessionTool.d.ts.map +1 -0
- package/dist/implementations/tmux/TmuxSessionTool.js +371 -0
- package/dist/implementations/tmux/TmuxSessionTool.js.map +1 -0
- package/dist/implementations/tmux/TmuxViewServer.d.ts +86 -0
- package/dist/implementations/tmux/TmuxViewServer.d.ts.map +1 -0
- package/dist/implementations/tmux/TmuxViewServer.js +480 -0
- package/dist/implementations/tmux/TmuxViewServer.js.map +1 -0
- package/dist/implementations/tmux/index.d.ts +6 -0
- package/dist/implementations/tmux/index.d.ts.map +1 -0
- package/dist/implementations/tmux/index.js +6 -0
- package/dist/implementations/tmux/index.js.map +1 -0
- package/dist/implementations/ui/AskUserQuestionTool.d.ts +77 -0
- package/dist/implementations/ui/AskUserQuestionTool.d.ts.map +1 -0
- package/dist/implementations/ui/AskUserQuestionTool.js +241 -0
- package/dist/implementations/ui/AskUserQuestionTool.js.map +1 -0
- package/dist/implementations/ui/ExitPlanModeTool.d.ts +44 -0
- package/dist/implementations/ui/ExitPlanModeTool.d.ts.map +1 -0
- package/dist/implementations/ui/ExitPlanModeTool.js +150 -0
- package/dist/implementations/ui/ExitPlanModeTool.js.map +1 -0
- package/dist/implementations/ui/TodoWriteTool.d.ts +59 -0
- package/dist/implementations/ui/TodoWriteTool.d.ts.map +1 -0
- package/dist/implementations/ui/TodoWriteTool.js +315 -0
- package/dist/implementations/ui/TodoWriteTool.js.map +1 -0
- package/dist/implementations/ui/index.d.ts +9 -0
- package/dist/implementations/ui/index.d.ts.map +1 -0
- package/dist/implementations/ui/index.js +9 -0
- package/dist/implementations/ui/index.js.map +1 -0
- package/dist/implementations/web/BrowseTool.d.ts +43 -0
- package/dist/implementations/web/BrowseTool.d.ts.map +1 -0
- package/dist/implementations/web/BrowseTool.js +181 -0
- package/dist/implementations/web/BrowseTool.js.map +1 -0
- package/dist/implementations/web/SandboxTransferTool.d.ts +30 -0
- package/dist/implementations/web/SandboxTransferTool.d.ts.map +1 -0
- package/dist/implementations/web/SandboxTransferTool.js +261 -0
- package/dist/implementations/web/SandboxTransferTool.js.map +1 -0
- package/dist/implementations/web/WebFetchTool.d.ts +93 -0
- package/dist/implementations/web/WebFetchTool.d.ts.map +1 -0
- package/dist/implementations/web/WebFetchTool.js +484 -0
- package/dist/implementations/web/WebFetchTool.js.map +1 -0
- package/dist/implementations/web/WebSearchTool.d.ts +53 -0
- package/dist/implementations/web/WebSearchTool.d.ts.map +1 -0
- package/dist/implementations/web/WebSearchTool.js +227 -0
- package/dist/implementations/web/WebSearchTool.js.map +1 -0
- package/dist/implementations/web/escalateDirective.d.ts +11 -0
- package/dist/implementations/web/escalateDirective.d.ts.map +1 -0
- package/dist/implementations/web/escalateDirective.js +20 -0
- package/dist/implementations/web/escalateDirective.js.map +1 -0
- package/dist/implementations/web/index.d.ts +10 -0
- package/dist/implementations/web/index.d.ts.map +1 -0
- package/dist/implementations/web/index.js +10 -0
- package/dist/implementations/web/index.js.map +1 -0
- package/dist/implementations/web/webBackends.d.ts +65 -0
- package/dist/implementations/web/webBackends.d.ts.map +1 -0
- package/dist/implementations/web/webBackends.js +430 -0
- package/dist/implementations/web/webBackends.js.map +1 -0
- package/dist/implementations/web/webFetchRequestInit.d.ts +9 -0
- package/dist/implementations/web/webFetchRequestInit.d.ts.map +1 -0
- package/dist/implementations/web/webFetchRequestInit.js +21 -0
- package/dist/implementations/web/webFetchRequestInit.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/ArtifactRegistry.d.ts +138 -0
- package/dist/utils/ArtifactRegistry.d.ts.map +1 -0
- package/dist/utils/ArtifactRegistry.js +259 -0
- package/dist/utils/ArtifactRegistry.js.map +1 -0
- package/dist/utils/ChromiumBrowserManager.d.ts +56 -0
- package/dist/utils/ChromiumBrowserManager.d.ts.map +1 -0
- package/dist/utils/ChromiumBrowserManager.js +243 -0
- package/dist/utils/ChromiumBrowserManager.js.map +1 -0
- package/dist/utils/FileUtils.d.ts +81 -0
- package/dist/utils/FileUtils.d.ts.map +1 -0
- package/dist/utils/FileUtils.js +148 -0
- package/dist/utils/FileUtils.js.map +1 -0
- package/dist/utils/GitPolicy.d.ts +70 -0
- package/dist/utils/GitPolicy.d.ts.map +1 -0
- package/dist/utils/GitPolicy.js +166 -0
- package/dist/utils/GitPolicy.js.map +1 -0
- package/dist/utils/GitUtils.d.ts +18 -0
- package/dist/utils/GitUtils.d.ts.map +1 -0
- package/dist/utils/GitUtils.js +62 -0
- package/dist/utils/GitUtils.js.map +1 -0
- package/dist/utils/SandboxRegistry.d.ts +110 -0
- package/dist/utils/SandboxRegistry.d.ts.map +1 -0
- package/dist/utils/SandboxRegistry.js +220 -0
- package/dist/utils/SandboxRegistry.js.map +1 -0
- package/dist/utils/SchemaValidator.d.ts +21 -0
- package/dist/utils/SchemaValidator.d.ts.map +1 -0
- package/dist/utils/SchemaValidator.js +67 -0
- package/dist/utils/SchemaValidator.js.map +1 -0
- package/dist/utils/SessionLock.d.ts +96 -0
- package/dist/utils/SessionLock.d.ts.map +1 -0
- package/dist/utils/SessionLock.js +276 -0
- package/dist/utils/SessionLock.js.map +1 -0
- package/dist/utils/SessionPersistence.d.ts +89 -0
- package/dist/utils/SessionPersistence.d.ts.map +1 -0
- package/dist/utils/SessionPersistence.js +244 -0
- package/dist/utils/SessionPersistence.js.map +1 -0
- package/dist/utils/TextUtils.d.ts +77 -0
- package/dist/utils/TextUtils.d.ts.map +1 -0
- package/dist/utils/TextUtils.js +112 -0
- package/dist/utils/TextUtils.js.map +1 -0
- package/dist/utils/TmuxCapture.d.ts +94 -0
- package/dist/utils/TmuxCapture.d.ts.map +1 -0
- package/dist/utils/TmuxCapture.js +131 -0
- package/dist/utils/TmuxCapture.js.map +1 -0
- package/dist/utils/TmuxManager.d.ts +65 -0
- package/dist/utils/TmuxManager.d.ts.map +1 -0
- package/dist/utils/TmuxManager.js +304 -0
- package/dist/utils/TmuxManager.js.map +1 -0
- package/dist/utils/autoResearchPlanGate.d.ts +10 -0
- package/dist/utils/autoResearchPlanGate.d.ts.map +1 -0
- package/dist/utils/autoResearchPlanGate.js +57 -0
- package/dist/utils/autoResearchPlanGate.js.map +1 -0
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +13 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { createServer } from 'http';
|
|
3
|
+
import { Server as SocketIOServer } from 'socket.io';
|
|
4
|
+
import { broadcaster } from './SandboxEventBroadcaster.js';
|
|
5
|
+
import { CreateArtifactToolExecutor } from './CreateArtifactTool.js';
|
|
6
|
+
import { ArtifactRegistry } from '../../utils/ArtifactRegistry.js';
|
|
7
|
+
/**
|
|
8
|
+
* SandboxViewServer - Real-time sandbox viewing server
|
|
9
|
+
*
|
|
10
|
+
* Provides a web-based dashboard for users to view sandbox operations in real-time.
|
|
11
|
+
* Features:
|
|
12
|
+
* - Embedded iframe showing sandbox UI
|
|
13
|
+
* - Live console logs via WebSocket
|
|
14
|
+
* - File change notifications
|
|
15
|
+
* - Screenshot gallery with timeline
|
|
16
|
+
* - Network request monitoring
|
|
17
|
+
* - Multi-sandbox management
|
|
18
|
+
*
|
|
19
|
+
* Architecture:
|
|
20
|
+
* - Express HTTP server serves HTML dashboard
|
|
21
|
+
* - Socket.io WebSocket server broadcasts events
|
|
22
|
+
* - SandboxEventBroadcaster provides events
|
|
23
|
+
* - Each sandbox gets a unique room for isolated events
|
|
24
|
+
*
|
|
25
|
+
* User Flow:
|
|
26
|
+
* 1. Model creates sandbox → Server auto-starts (if not running)
|
|
27
|
+
* 2. Server emits view URL: http://localhost:4001/sandbox/{sandboxId}
|
|
28
|
+
* 3. User opens URL in browser
|
|
29
|
+
* 4. Dashboard loads with embedded iframe of sandbox UI
|
|
30
|
+
* 5. WebSocket subscribes to sandbox events
|
|
31
|
+
* 6. As model interacts, user sees live updates:
|
|
32
|
+
* - Console logs appear in sidebar
|
|
33
|
+
* - Files changed trigger reload notifications
|
|
34
|
+
* - Screenshots appear in gallery
|
|
35
|
+
* - Network requests show in timeline
|
|
36
|
+
*
|
|
37
|
+
* Example Usage:
|
|
38
|
+
* ```
|
|
39
|
+
* // Start server
|
|
40
|
+
* const server = SandboxViewServer.getInstance();
|
|
41
|
+
* await server.start(4001);
|
|
42
|
+
*
|
|
43
|
+
* // View URL auto-included in CreateAddon output
|
|
44
|
+
* // User opens: http://localhost:4001/sandbox/abc-123
|
|
45
|
+
*
|
|
46
|
+
* // Server automatically streams events via WebSocket
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export class SandboxViewServer {
|
|
50
|
+
static instance;
|
|
51
|
+
app;
|
|
52
|
+
httpServer;
|
|
53
|
+
io;
|
|
54
|
+
port = Number(process.env.DASHBOARD_PORT) || 4001;
|
|
55
|
+
isRunning = false;
|
|
56
|
+
constructor() {
|
|
57
|
+
this.app = express();
|
|
58
|
+
this.httpServer = createServer(this.app);
|
|
59
|
+
this.io = new SocketIOServer(this.httpServer, {
|
|
60
|
+
cors: {
|
|
61
|
+
origin: '*',
|
|
62
|
+
methods: ['GET', 'POST']
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
this.setupRoutes();
|
|
66
|
+
this.setupWebSocket();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get singleton instance
|
|
70
|
+
*/
|
|
71
|
+
static getInstance() {
|
|
72
|
+
if (!SandboxViewServer.instance) {
|
|
73
|
+
SandboxViewServer.instance = new SandboxViewServer();
|
|
74
|
+
}
|
|
75
|
+
return SandboxViewServer.instance;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Master switch for the dashboard/view-server system (tmux viewer + sandbox
|
|
79
|
+
* viewer share this one server). When false, the dashboard NEVER binds a port —
|
|
80
|
+
* not at server boot and not via the tools' demand-start paths.
|
|
81
|
+
*/
|
|
82
|
+
static isEnabled() {
|
|
83
|
+
return process.env.ENABLE_DASHBOARD === 'true';
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Agent-facing guidance for when the dashboard is disabled or fails to start.
|
|
87
|
+
* Surfaced through tool results so the model knows exactly how to proceed.
|
|
88
|
+
*/
|
|
89
|
+
static DISABLED_NOTICE = 'Tmux/sandbox web dashboard is DISABLED (ENABLE_DASHBOARD is not "true"). ' +
|
|
90
|
+
'Live view URLs are unavailable. To use the dashboard: set ENABLE_DASHBOARD=true ' +
|
|
91
|
+
'in the .env (or environment) and restart the harness. If it still fails to start ' +
|
|
92
|
+
'after enabling, check for a port conflict on DASHBOARD_PORT (default 4001 — the ' +
|
|
93
|
+
'server retries up to 10 consecutive ports before giving up).';
|
|
94
|
+
/**
|
|
95
|
+
* Start the server with dynamic port conflict resolution
|
|
96
|
+
*/
|
|
97
|
+
async start(startPort) {
|
|
98
|
+
if (!SandboxViewServer.isEnabled()) {
|
|
99
|
+
throw new Error(SandboxViewServer.DISABLED_NOTICE);
|
|
100
|
+
}
|
|
101
|
+
if (this.isRunning) {
|
|
102
|
+
console.log(` View server already running on http://localhost:${this.port}`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Dashboard port: DASHBOARD_PORT env wins, then the caller's arg, then 4001.
|
|
106
|
+
// Try starting on that port, with automatic retry on next port if occupied.
|
|
107
|
+
let currentPort = Number(process.env.DASHBOARD_PORT) || startPort || 4001;
|
|
108
|
+
const maxAttempts = 10; // Try up to 10 ports
|
|
109
|
+
let lastError = null;
|
|
110
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
111
|
+
try {
|
|
112
|
+
await this.tryStartOnPort(currentPort);
|
|
113
|
+
// Success! Server started
|
|
114
|
+
this.port = currentPort;
|
|
115
|
+
this.isRunning = true;
|
|
116
|
+
console.log(` Sandbox View Server started on http://localhost:${currentPort}`);
|
|
117
|
+
console.log(` - Dashboard: http://localhost:${currentPort}/`);
|
|
118
|
+
console.log(` - Sandbox view: http://localhost:${currentPort}/sandbox/{sandboxId}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (error.code === 'EADDRINUSE') {
|
|
123
|
+
lastError = error;
|
|
124
|
+
console.log(`Port ${currentPort} in use, trying ${currentPort + 1}...`);
|
|
125
|
+
currentPort++;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Non-port-conflict error, throw immediately
|
|
129
|
+
console.error(`[ERROR] Failed to start view server:`, error);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// If we get here, we exhausted all attempts
|
|
135
|
+
const errorMsg = `Failed to start view server after ${maxAttempts} attempts (ports ${startPort}-${currentPort - 1})`;
|
|
136
|
+
console.error(`[ERROR] ${errorMsg}`);
|
|
137
|
+
throw new Error(errorMsg);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Try to start server on a specific port
|
|
141
|
+
*/
|
|
142
|
+
async tryStartOnPort(port) {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const onListening = () => {
|
|
145
|
+
cleanup();
|
|
146
|
+
resolve();
|
|
147
|
+
};
|
|
148
|
+
const onError = (error) => {
|
|
149
|
+
cleanup();
|
|
150
|
+
reject(error);
|
|
151
|
+
};
|
|
152
|
+
const cleanup = () => {
|
|
153
|
+
this.httpServer.removeListener('listening', onListening);
|
|
154
|
+
this.httpServer.removeListener('error', onError);
|
|
155
|
+
};
|
|
156
|
+
this.httpServer.once('listening', onListening);
|
|
157
|
+
this.httpServer.once('error', onError);
|
|
158
|
+
this.httpServer.listen(port, '0.0.0.0');
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Stop the server
|
|
163
|
+
*/
|
|
164
|
+
async stop() {
|
|
165
|
+
if (!this.isRunning) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
return new Promise((resolve) => {
|
|
169
|
+
this.io.close();
|
|
170
|
+
this.httpServer.close(() => {
|
|
171
|
+
this.isRunning = false;
|
|
172
|
+
console.log(` View server stopped`);
|
|
173
|
+
resolve();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get view URL for a sandbox
|
|
179
|
+
*/
|
|
180
|
+
getViewUrl(sandboxId) {
|
|
181
|
+
return `http://localhost:${this.port}/sandbox/${sandboxId}`;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Setup HTTP routes
|
|
185
|
+
*/
|
|
186
|
+
setupRoutes() {
|
|
187
|
+
// Serve dashboard homepage
|
|
188
|
+
this.app.get('/', (req, res) => {
|
|
189
|
+
res.send(this.generateDashboardHTML());
|
|
190
|
+
});
|
|
191
|
+
// Serve sandbox-specific view
|
|
192
|
+
this.app.get('/sandbox/:sandboxId', (req, res) => {
|
|
193
|
+
const sandboxId = req.params.sandboxId;
|
|
194
|
+
const session = CreateArtifactToolExecutor.getActiveSandbox(sandboxId);
|
|
195
|
+
if (!session) {
|
|
196
|
+
res.status(404).send(this.generate404HTML(sandboxId));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
res.send(this.generateSandboxViewHTML(session));
|
|
200
|
+
});
|
|
201
|
+
// API: Get sandbox list (from persistent registry)
|
|
202
|
+
this.app.get('/api/sandboxes', (req, res) => {
|
|
203
|
+
try {
|
|
204
|
+
const registry = ArtifactRegistry.getInstance(process.env.PROJECT_ROOT || process.cwd());
|
|
205
|
+
const artifacts = registry.getAll();
|
|
206
|
+
res.json({
|
|
207
|
+
sandboxes: artifacts.map(a => ({
|
|
208
|
+
id: a.id,
|
|
209
|
+
name: a.name,
|
|
210
|
+
url: a.url,
|
|
211
|
+
mode: a.mode,
|
|
212
|
+
status: 'running', // Assume running if in registry (could check PID)
|
|
213
|
+
createdAt: a.created,
|
|
214
|
+
lastActivity: a.lastUsed
|
|
215
|
+
}))
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
console.error('Failed to get artifacts from registry:', error);
|
|
220
|
+
// Fallback to in-memory
|
|
221
|
+
const sessions = CreateArtifactToolExecutor.getActiveSandboxes();
|
|
222
|
+
res.json({
|
|
223
|
+
sandboxes: sessions.map(s => ({
|
|
224
|
+
id: s.id,
|
|
225
|
+
name: s.name,
|
|
226
|
+
url: s.url,
|
|
227
|
+
mode: s.mode,
|
|
228
|
+
status: s.process ? 'running' : 'stopped',
|
|
229
|
+
createdAt: s.startTime,
|
|
230
|
+
lastActivity: s.lastActivity
|
|
231
|
+
}))
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
// API: Get event history
|
|
236
|
+
this.app.get('/api/sandbox/:sandboxId/events', (req, res) => {
|
|
237
|
+
const sandboxId = req.params.sandboxId;
|
|
238
|
+
const limitParam = req.query.limit;
|
|
239
|
+
const limit = limitParam ? parseInt(limitParam) : undefined;
|
|
240
|
+
const events = broadcaster.getHistory(sandboxId, limit);
|
|
241
|
+
res.json({ events });
|
|
242
|
+
});
|
|
243
|
+
// Artifact lifecycle API endpoints
|
|
244
|
+
this.app.post('/api/artifacts/:id/stop', async (req, res) => {
|
|
245
|
+
try {
|
|
246
|
+
const id = req.params.id;
|
|
247
|
+
if (!id) {
|
|
248
|
+
res.status(400).json({ success: false, message: 'Artifact ID is required' });
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const stopped = CreateArtifactToolExecutor.stopSandbox(id);
|
|
252
|
+
if (stopped) {
|
|
253
|
+
res.json({ success: true, message: 'Artifact stopped successfully' });
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
res.status(404).json({ success: false, message: 'Artifact not found or already stopped' });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
res.status(500).json({ success: false, message: error.message });
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
this.app.post('/api/artifacts/:id/restart', async (req, res) => {
|
|
264
|
+
try {
|
|
265
|
+
const id = req.params.id;
|
|
266
|
+
if (!id) {
|
|
267
|
+
res.status(400).json({ success: false, message: 'Artifact ID is required' });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Get artifact metadata from registry
|
|
271
|
+
const registry = ArtifactRegistry.getInstance(process.env.PROJECT_ROOT || process.cwd());
|
|
272
|
+
await registry.initialize();
|
|
273
|
+
const metadata = await registry.get(id);
|
|
274
|
+
if (!metadata) {
|
|
275
|
+
res.status(404).json({ success: false, message: 'Artifact not found in registry' });
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
// Stop the artifact first
|
|
279
|
+
const stopped = CreateArtifactToolExecutor.stopSandbox(id);
|
|
280
|
+
if (!stopped) {
|
|
281
|
+
console.warn(`Artifact ${id} was not running, proceeding with restart anyway`);
|
|
282
|
+
}
|
|
283
|
+
// Wait a moment for cleanup
|
|
284
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
285
|
+
// Find a new available port dynamically by checking registry
|
|
286
|
+
// Use only ports that have external mappings in .replit configuration
|
|
287
|
+
// Infrastructure ports (reserved): 4000 (server), 4001 (dashboard)
|
|
288
|
+
// Available artifact ports with external mappings:
|
|
289
|
+
const ACCESSIBLE_PORTS = [
|
|
290
|
+
3001, // → 6800
|
|
291
|
+
3004, // → 4200
|
|
292
|
+
3005, // → 8081
|
|
293
|
+
3011, // → 9000
|
|
294
|
+
4002, // → 3002
|
|
295
|
+
4003, // → 3003
|
|
296
|
+
4004, // → 5173
|
|
297
|
+
4005, // → 5000
|
|
298
|
+
5000, // → 80
|
|
299
|
+
8000, // → 8008
|
|
300
|
+
8080, // → 8080
|
|
301
|
+
24678, // → 8000
|
|
302
|
+
36655, // → 6000
|
|
303
|
+
46323 // → 8099
|
|
304
|
+
];
|
|
305
|
+
const usedPorts = new Set(registry.getUsedPorts());
|
|
306
|
+
let newPort = null;
|
|
307
|
+
for (const port of ACCESSIBLE_PORTS) {
|
|
308
|
+
if (!usedPorts.has(port)) {
|
|
309
|
+
newPort = port;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (newPort === null) {
|
|
314
|
+
res.status(500).json({
|
|
315
|
+
success: false,
|
|
316
|
+
message: `All ${ACCESSIBLE_PORTS.length} accessible ports are currently in use. Stop an artifact first to free up a port.`
|
|
317
|
+
});
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
console.log(` Restarting artifact ${id} on port ${newPort} (was ${metadata.port})`);
|
|
321
|
+
// Restart based on runtime type
|
|
322
|
+
const TmuxManager = (await import('../../utils/TmuxManager.js')).TmuxManager;
|
|
323
|
+
const tmux = TmuxManager.getInstance();
|
|
324
|
+
if (metadata.tmuxSession) {
|
|
325
|
+
console.log(`[Restart] Processing tmux artifact ${id}`);
|
|
326
|
+
console.log(`[Restart] Session name: ${metadata.tmuxSession}`);
|
|
327
|
+
console.log(`[Restart] Workspace: ${metadata.workspaceDir}`);
|
|
328
|
+
console.log(`[Restart] Runtime: ${metadata.runtime}`);
|
|
329
|
+
console.log(`[Restart] Entry point: ${metadata.entryPoint}`);
|
|
330
|
+
// Kill old tmux session if it exists
|
|
331
|
+
const exists = await tmux.sessionExists(metadata.tmuxSession);
|
|
332
|
+
console.log(`[Restart] Session exists: ${exists}`);
|
|
333
|
+
if (exists) {
|
|
334
|
+
console.log(`[Restart] Killing existing session...`);
|
|
335
|
+
await tmux.killSession(metadata.tmuxSession);
|
|
336
|
+
console.log(`[Restart] Session killed`);
|
|
337
|
+
}
|
|
338
|
+
// Create new tmux session
|
|
339
|
+
console.log(`[Restart] Creating new tmux session...`);
|
|
340
|
+
try {
|
|
341
|
+
await tmux.createSession(metadata.tmuxSession, metadata.workspaceDir);
|
|
342
|
+
console.log(`[Restart] [OK] Tmux session created successfully`);
|
|
343
|
+
}
|
|
344
|
+
catch (err) {
|
|
345
|
+
console.error(`[Restart] [ERROR] Failed to create tmux session:`, err.message);
|
|
346
|
+
throw new Error(`Tmux session creation failed: ${err.message}`);
|
|
347
|
+
}
|
|
348
|
+
// Verify session was created
|
|
349
|
+
const sessionCreated = await tmux.sessionExists(metadata.tmuxSession);
|
|
350
|
+
console.log(`[Restart] Session verification: ${sessionCreated}`);
|
|
351
|
+
if (!sessionCreated) {
|
|
352
|
+
throw new Error('Tmux session was not created successfully');
|
|
353
|
+
}
|
|
354
|
+
// Start the appropriate server based on runtime with NEW PORT
|
|
355
|
+
let startCommand = '';
|
|
356
|
+
if (metadata.runtime === 'tmux+http-server') {
|
|
357
|
+
startCommand = `npx http-server -p ${newPort}`;
|
|
358
|
+
}
|
|
359
|
+
else if (metadata.runtime === 'tmux+node') {
|
|
360
|
+
startCommand = `PORT=${newPort} node ${metadata.entryPoint}`;
|
|
361
|
+
}
|
|
362
|
+
else if (metadata.runtime === 'tmux+python') {
|
|
363
|
+
startCommand = `PORT=${newPort} python ${metadata.entryPoint}`;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
// For tmux+custom, tmux+shell, etc., just start a shell
|
|
367
|
+
startCommand = 'bash';
|
|
368
|
+
}
|
|
369
|
+
console.log(`[Restart] Start command: ${startCommand}`);
|
|
370
|
+
console.log(`[Restart] Sending keys to tmux session...`);
|
|
371
|
+
try {
|
|
372
|
+
await tmux.sendKeys(metadata.tmuxSession, `cd ${metadata.workspaceDir} && ${startCommand}`);
|
|
373
|
+
console.log(`[Restart] [OK] Command sent to tmux`);
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
console.error(`[Restart] [ERROR] Failed to send keys:`, err.message);
|
|
377
|
+
throw new Error(`Failed to send command to tmux: ${err.message}`);
|
|
378
|
+
}
|
|
379
|
+
// Wait a moment for the process to start
|
|
380
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
381
|
+
// Update registry with new port and URL
|
|
382
|
+
await registry.update(id, {
|
|
383
|
+
port: newPort,
|
|
384
|
+
url: `http://localhost:${newPort}`,
|
|
385
|
+
lastUsed: new Date().toISOString()
|
|
386
|
+
});
|
|
387
|
+
res.json({
|
|
388
|
+
success: true,
|
|
389
|
+
message: `Artifact "${metadata.name}" restarted on NEW PORT ${newPort} (was ${metadata.port})`
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
// Non-tmux artifacts (process, docker) - spawn new process
|
|
394
|
+
const { exec } = await import('child_process');
|
|
395
|
+
const { promisify } = await import('util');
|
|
396
|
+
const execAsync = promisify(exec);
|
|
397
|
+
const command = `npx http-server ${metadata.workspaceDir} -p ${newPort} &`;
|
|
398
|
+
await execAsync(command, { cwd: metadata.workspaceDir });
|
|
399
|
+
// Update registry with new port and URL
|
|
400
|
+
await registry.update(id, {
|
|
401
|
+
port: newPort,
|
|
402
|
+
url: `http://localhost:${newPort}`,
|
|
403
|
+
lastUsed: new Date().toISOString()
|
|
404
|
+
});
|
|
405
|
+
res.json({
|
|
406
|
+
success: true,
|
|
407
|
+
message: `Artifact "${metadata.name}" restarted on NEW PORT ${newPort} (was ${metadata.port})`
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
catch (error) {
|
|
412
|
+
console.error('Restart error:', error);
|
|
413
|
+
res.status(500).json({ success: false, message: error.message });
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
// Health check
|
|
417
|
+
this.app.get('/health', (req, res) => {
|
|
418
|
+
res.json({ status: 'ok', uptime: process.uptime() });
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Setup WebSocket event streaming
|
|
423
|
+
*/
|
|
424
|
+
setupWebSocket() {
|
|
425
|
+
this.io.on('connection', (socket) => {
|
|
426
|
+
console.log(` Client connected: ${socket.id}`);
|
|
427
|
+
// Client subscribes to a specific sandbox
|
|
428
|
+
socket.on('subscribe', (sandboxId) => {
|
|
429
|
+
console.log(` Client ${socket.id} subscribed to sandbox: ${sandboxId}`);
|
|
430
|
+
socket.join(sandboxId);
|
|
431
|
+
// Send recent event history
|
|
432
|
+
const history = broadcaster.getHistory(sandboxId, 50);
|
|
433
|
+
socket.emit('history', { events: history });
|
|
434
|
+
});
|
|
435
|
+
// Client unsubscribes
|
|
436
|
+
socket.on('unsubscribe', (sandboxId) => {
|
|
437
|
+
console.log(` Client ${socket.id} unsubscribed from sandbox: ${sandboxId}`);
|
|
438
|
+
socket.leave(sandboxId);
|
|
439
|
+
});
|
|
440
|
+
// Disconnect
|
|
441
|
+
socket.on('disconnect', () => {
|
|
442
|
+
console.log(` Client disconnected: ${socket.id}`);
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
// Listen to broadcaster events and forward to WebSocket clients
|
|
446
|
+
broadcaster.subscribeToAll((event) => {
|
|
447
|
+
// Emit to all clients in the sandbox's room
|
|
448
|
+
this.io.to(event.sandboxId).emit(event.type, event);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Generate multi-sandbox dashboard HTML
|
|
453
|
+
*/
|
|
454
|
+
generateDashboardHTML() {
|
|
455
|
+
return `
|
|
456
|
+
<!DOCTYPE html>
|
|
457
|
+
<html lang="en">
|
|
458
|
+
<head>
|
|
459
|
+
<meta charset="UTF-8">
|
|
460
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
461
|
+
<title>Cortex Intelligence // Sandboxes</title>
|
|
462
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
463
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
464
|
+
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700&family=Oxygen+Mono&display=swap" rel="stylesheet">
|
|
465
|
+
<style>
|
|
466
|
+
:root {
|
|
467
|
+
--cx-primary: #4a90d9; --cx-primary-rgb: 74, 144, 217;
|
|
468
|
+
--cx-positive: #4ade80; --cx-positive-rgb: 74, 222, 128;
|
|
469
|
+
--cx-negative: #f87171; --cx-negative-rgb: 248, 113, 113;
|
|
470
|
+
--cx-warning: #fbbf24;
|
|
471
|
+
--cx-bg: #0f172a; --cx-bg2: #1e293b; --cx-bg3: #253347; --cx-bg4: #2d3d53;
|
|
472
|
+
--cx-text: #e2e8f0; --cx-text2: #b0b8c4; --cx-muted: #94a3b8; --cx-heading: #f8fafc;
|
|
473
|
+
--cx-border: #334155; --cx-border2: #283548;
|
|
474
|
+
--cx-radius: 6px;
|
|
475
|
+
--cx-font: 'Oxygen Mono', monospace;
|
|
476
|
+
}
|
|
477
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
478
|
+
body { font-family: var(--cx-font); font-size: 12px; line-height: 1.5; color: var(--cx-text); background: var(--cx-bg); padding: 24px 20px; min-height: 100vh; }
|
|
479
|
+
body::before { content: ''; position: fixed; inset: 0; background: radial-gradient(ellipse at 20% 50%, rgba(var(--cx-primary-rgb), 0.04) 0%, transparent 60%), linear-gradient(180deg, var(--cx-bg) 0%, #080818 100%); pointer-events: none; z-index: 0; }
|
|
480
|
+
.shell { position: relative; z-index: 1; max-width: 1440px; margin: 0 auto; }
|
|
481
|
+
.header-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: var(--cx-bg2); border: 1px solid var(--cx-border); border-radius: var(--cx-radius); margin-bottom: 20px; }
|
|
482
|
+
.header-bar h1 { font-family: 'Orbitron', var(--cx-font); font-size: 14px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase; color: var(--cx-heading); }
|
|
483
|
+
.header-bar .badge { font-size: 10px; color: var(--cx-muted); padding: 2px 8px; border: 1px solid var(--cx-border2); border-radius: var(--cx-radius); }
|
|
484
|
+
.subtitle { font-size: 11px; color: var(--cx-muted); letter-spacing: 0.04em; }
|
|
485
|
+
.sandbox-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 12px; margin-top: 16px; }
|
|
486
|
+
.sandbox-card { background: var(--cx-bg2); border: 1px solid var(--cx-border); border-radius: var(--cx-radius); padding: 16px; transition: all 200ms ease; }
|
|
487
|
+
.sandbox-card:hover { border-color: rgba(var(--cx-primary-rgb), 0.5); box-shadow: 0 0 16px rgba(var(--cx-primary-rgb), 0.1); }
|
|
488
|
+
.sandbox-name { font-size: 13px; font-weight: 400; color: var(--cx-heading); margin-bottom: 10px; letter-spacing: 0.04em; }
|
|
489
|
+
.sandbox-actions { display: flex; gap: 6px; margin-bottom: 10px; }
|
|
490
|
+
.sandbox-btn { flex: 1; padding: 7px 10px; border-radius: var(--cx-radius); font-family: var(--cx-font); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; text-align: center; text-decoration: none; cursor: pointer; transition: all 200ms ease; border: 1px solid var(--cx-border); background: transparent; color: var(--cx-text2); }
|
|
491
|
+
.sandbox-btn.primary { color: var(--cx-positive); border-color: rgba(var(--cx-positive-rgb), 0.3); }
|
|
492
|
+
.sandbox-btn.primary:hover { background: rgba(var(--cx-positive-rgb), 0.08); border-color: rgba(var(--cx-positive-rgb), 0.5); }
|
|
493
|
+
.sandbox-btn.secondary { color: var(--cx-primary); border-color: rgba(var(--cx-primary-rgb), 0.3); }
|
|
494
|
+
.sandbox-btn.secondary:hover { background: rgba(var(--cx-primary-rgb), 0.08); border-color: rgba(var(--cx-primary-rgb), 0.5); }
|
|
495
|
+
.sandbox-btn.danger { color: var(--cx-negative); border-color: rgba(var(--cx-negative-rgb), 0.3); flex: 0.5; }
|
|
496
|
+
.sandbox-btn.danger:hover { background: rgba(var(--cx-negative-rgb), 0.08); }
|
|
497
|
+
.sandbox-btn.warning { color: var(--cx-warning); border-color: rgba(255, 187, 36, 0.3); flex: 0.5; }
|
|
498
|
+
.sandbox-btn.warning:hover { background: rgba(255, 187, 36, 0.08); }
|
|
499
|
+
.sandbox-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
|
500
|
+
.sandbox-meta { display: flex; gap: 12px; font-size: 10px; color: var(--cx-muted); letter-spacing: 0.04em; }
|
|
501
|
+
.status { display: inline-flex; align-items: center; gap: 5px; }
|
|
502
|
+
.status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--cx-positive); box-shadow: 0 0 6px rgba(var(--cx-positive-rgb), 0.5); }
|
|
503
|
+
.status-dot.stopped { background: var(--cx-negative); box-shadow: 0 0 6px rgba(var(--cx-negative-rgb), 0.5); }
|
|
504
|
+
.empty-state { text-align: center; padding: 60px 20px; color: var(--cx-muted); }
|
|
505
|
+
.empty-state h2 { font-size: 14px; font-weight: 400; color: var(--cx-text2); margin-bottom: 8px; letter-spacing: 0.06em; }
|
|
506
|
+
.empty-state p { font-size: 11px; }
|
|
507
|
+
.refresh-btn { font-family: var(--cx-font); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--cx-primary); background: var(--cx-bg2); border: 1px solid rgba(var(--cx-primary-rgb), 0.3); border-radius: var(--cx-radius); padding: 8px 16px; cursor: pointer; transition: all 200ms ease; margin-top: 12px; }
|
|
508
|
+
.refresh-btn:hover { background: rgba(var(--cx-primary-rgb), 0.08); border-color: rgba(var(--cx-primary-rgb), 0.5); }
|
|
509
|
+
.nav-link { font-size: 10px; color: var(--cx-primary); text-decoration: none; letter-spacing: 0.04em; transition: color 200ms; }
|
|
510
|
+
.nav-link:hover { color: var(--cx-heading); }
|
|
511
|
+
@keyframes fade-up { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
|
|
512
|
+
.anim-in { animation: fade-up 400ms ease both; }
|
|
513
|
+
</style>
|
|
514
|
+
</head>
|
|
515
|
+
<body>
|
|
516
|
+
<div class="shell">
|
|
517
|
+
<div class="header-bar anim-in">
|
|
518
|
+
<div style="display: flex; align-items: center; gap: 12px;">
|
|
519
|
+
<h1>Cortex Intelligence // Sandboxes</h1>
|
|
520
|
+
<span class="badge">ARTIFACTS</span>
|
|
521
|
+
</div>
|
|
522
|
+
<div style="display: flex; align-items: center; gap: 16px;">
|
|
523
|
+
<a href="/tmux" class="nav-link">Tmux Sessions</a>
|
|
524
|
+
<span class="subtitle">Real-time artifact monitoring</span>
|
|
525
|
+
</div>
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
<div id="sandbox-list" class="sandbox-grid"></div>
|
|
529
|
+
</div>
|
|
530
|
+
|
|
531
|
+
<script>
|
|
532
|
+
async function loadSandboxes() {
|
|
533
|
+
try {
|
|
534
|
+
const response = await fetch('/api/sandboxes');
|
|
535
|
+
const data = await response.json();
|
|
536
|
+
const container = document.getElementById('sandbox-list');
|
|
537
|
+
|
|
538
|
+
if (data.sandboxes.length === 0) {
|
|
539
|
+
container.innerHTML = \`
|
|
540
|
+
<div class="empty-state anim-in">
|
|
541
|
+
<h2>No Active Sandboxes</h2>
|
|
542
|
+
<p>Create a sandbox using CreateArtifactTool to see it here</p>
|
|
543
|
+
<button class="refresh-btn" onclick="loadSandboxes()">Refresh</button>
|
|
544
|
+
</div>
|
|
545
|
+
\`;
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
container.innerHTML = data.sandboxes.map((sandbox, i) => \`
|
|
550
|
+
<div class="sandbox-card anim-in" style="animation-delay: \${i * 60}ms">
|
|
551
|
+
<div class="sandbox-name">\${sandbox.name}</div>
|
|
552
|
+
<div class="sandbox-actions">
|
|
553
|
+
<a class="sandbox-btn primary" href="\${sandbox.url}" target="_blank">View Artifact</a>
|
|
554
|
+
<a class="sandbox-btn secondary" href="/sandbox/\${sandbox.id}">Console</a>
|
|
555
|
+
</div>
|
|
556
|
+
<div class="sandbox-actions">
|
|
557
|
+
<button class="sandbox-btn danger" onclick="stopArtifact('\${sandbox.id}', '\${sandbox.name}')" \${sandbox.status !== 'running' ? 'disabled' : ''}>Stop</button>
|
|
558
|
+
<button class="sandbox-btn warning" onclick="restartArtifact('\${sandbox.id}', '\${sandbox.name}')" \${sandbox.status !== 'running' ? 'disabled' : ''}>Restart</button>
|
|
559
|
+
</div>
|
|
560
|
+
<div class="sandbox-meta">
|
|
561
|
+
<span class="status">
|
|
562
|
+
<span class="status-dot \${sandbox.status === 'running' ? '' : 'stopped'}"></span>
|
|
563
|
+
\${sandbox.status}
|
|
564
|
+
</span>
|
|
565
|
+
<span>Mode: \${sandbox.mode}</span>
|
|
566
|
+
</div>
|
|
567
|
+
</div>
|
|
568
|
+
\`).join('');
|
|
569
|
+
} catch (error) {
|
|
570
|
+
console.error('Failed to load sandboxes:', error);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
async function stopArtifact(id, name) {
|
|
575
|
+
if (!confirm('Stop artifact "' + name + '"?')) return;
|
|
576
|
+
try {
|
|
577
|
+
const r = await fetch('/api/artifacts/' + id + '/stop', { method: 'POST' });
|
|
578
|
+
const result = await r.json();
|
|
579
|
+
if (result.success) loadSandboxes();
|
|
580
|
+
else alert('Failed: ' + result.message);
|
|
581
|
+
} catch (e) { alert('Error: ' + e.message); }
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
async function restartArtifact(id, name) {
|
|
585
|
+
if (!confirm('Restart artifact "' + name + '"?')) return;
|
|
586
|
+
try {
|
|
587
|
+
const r = await fetch('/api/artifacts/' + id + '/restart', { method: 'POST' });
|
|
588
|
+
const result = await r.json();
|
|
589
|
+
if (result.success) loadSandboxes();
|
|
590
|
+
else alert('Failed: ' + result.message);
|
|
591
|
+
} catch (e) { alert('Error: ' + e.message); }
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
loadSandboxes();
|
|
595
|
+
setInterval(loadSandboxes, 5000);
|
|
596
|
+
</script>
|
|
597
|
+
</body>
|
|
598
|
+
</html>
|
|
599
|
+
`;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Generate sandbox-specific view HTML
|
|
603
|
+
*/
|
|
604
|
+
generateSandboxViewHTML(session) {
|
|
605
|
+
return `
|
|
606
|
+
<!DOCTYPE html>
|
|
607
|
+
<html lang="en">
|
|
608
|
+
<head>
|
|
609
|
+
<meta charset="UTF-8">
|
|
610
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
611
|
+
<title>Cortex Intelligence // ${session.name}</title>
|
|
612
|
+
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700&family=Oxygen+Mono&display=swap" rel="stylesheet">
|
|
613
|
+
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
|
|
614
|
+
<style>
|
|
615
|
+
:root {
|
|
616
|
+
--cx-primary: #4a90d9; --cx-primary-rgb: 74, 144, 217;
|
|
617
|
+
--cx-positive: #4ade80; --cx-positive-rgb: 74, 222, 128;
|
|
618
|
+
--cx-negative: #f87171; --cx-warning: #fbbf24;
|
|
619
|
+
--cx-bg: #0f172a; --cx-bg2: #1e293b; --cx-bg3: #253347;
|
|
620
|
+
--cx-text: #e2e8f0; --cx-text2: #b0b8c4; --cx-muted: #94a3b8; --cx-heading: #f8fafc;
|
|
621
|
+
--cx-border: #334155; --cx-border2: #283548;
|
|
622
|
+
--cx-radius: 6px;
|
|
623
|
+
--cx-font: 'Oxygen Mono', monospace;
|
|
624
|
+
}
|
|
625
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
626
|
+
body { font-family: var(--cx-font); font-size: 12px; color: var(--cx-text); background: var(--cx-bg); overflow: hidden; }
|
|
627
|
+
.container { display: grid; grid-template-rows: 48px 1fr; height: 100vh; }
|
|
628
|
+
.header { background: var(--cx-bg2); border-bottom: 1px solid var(--cx-border); padding: 0 16px; display: flex; align-items: center; justify-content: space-between; }
|
|
629
|
+
.header .title { font-family: 'Orbitron', var(--cx-font); font-size: 13px; font-weight: 500; color: var(--cx-heading); letter-spacing: 0.1em; text-transform: uppercase; }
|
|
630
|
+
.header .nav-link { font-size: 10px; color: var(--cx-primary); text-decoration: none; letter-spacing: 0.04em; }
|
|
631
|
+
.header .nav-link:hover { color: var(--cx-heading); }
|
|
632
|
+
.status { display: flex; align-items: center; gap: 6px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--cx-positive); }
|
|
633
|
+
.status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--cx-positive); box-shadow: 0 0 8px rgba(var(--cx-positive-rgb), 0.6); animation: pulse 2s ease-in-out infinite; }
|
|
634
|
+
@keyframes pulse { 0%, 100% { box-shadow: 0 0 8px rgba(var(--cx-positive-rgb), 0.6); } 50% { box-shadow: 0 0 14px rgba(var(--cx-positive-rgb), 0.9); } }
|
|
635
|
+
.main-content { display: grid; grid-template-columns: 1fr 360px; height: 100%; }
|
|
636
|
+
.preview-pane { background: #fff; position: relative; }
|
|
637
|
+
.preview-pane iframe { width: 100%; height: 100%; border: none; }
|
|
638
|
+
.sidebar { background: var(--cx-bg); border-left: 1px solid var(--cx-border); display: flex; flex-direction: column; }
|
|
639
|
+
.tabs { display: flex; background: var(--cx-bg2); border-bottom: 1px solid var(--cx-border); }
|
|
640
|
+
.tab { flex: 1; padding: 10px; text-align: center; cursor: pointer; border-bottom: 2px solid transparent; transition: all 200ms; font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--cx-muted); font-family: var(--cx-font); }
|
|
641
|
+
.tab:hover { background: var(--cx-bg3); color: var(--cx-text2); }
|
|
642
|
+
.tab.active { border-bottom-color: var(--cx-primary); color: var(--cx-primary); }
|
|
643
|
+
.tab-content { flex: 1; overflow-y: auto; padding: 10px; scrollbar-width: thin; scrollbar-color: var(--cx-border) var(--cx-bg); }
|
|
644
|
+
.console-line { font-size: 11px; padding: 3px 8px; border-left: 2px solid transparent; margin-bottom: 1px; }
|
|
645
|
+
.console-log { color: var(--cx-text); border-left-color: var(--cx-primary); }
|
|
646
|
+
.console-error { color: var(--cx-negative); border-left-color: var(--cx-negative); }
|
|
647
|
+
.console-warn { color: var(--cx-warning); border-left-color: var(--cx-warning); }
|
|
648
|
+
.timestamp { color: var(--cx-muted); margin-right: 8px; font-size: 10px; }
|
|
649
|
+
.screenshot-item { margin-bottom: 12px; }
|
|
650
|
+
.screenshot-item img { width: 100%; border-radius: var(--cx-radius); border: 1px solid var(--cx-border); }
|
|
651
|
+
.screenshot-meta { font-size: 10px; color: var(--cx-muted); margin-top: 4px; }
|
|
652
|
+
.network-item { padding: 6px 8px; margin-bottom: 2px; background: var(--cx-bg2); border-radius: var(--cx-radius); font-size: 11px; }
|
|
653
|
+
.network-method { color: var(--cx-primary); font-weight: 400; margin-right: 8px; }
|
|
654
|
+
.network-url { color: var(--cx-text2); }
|
|
655
|
+
.network-status { float: right; color: var(--cx-positive); }
|
|
656
|
+
.reload-notification { position: absolute; top: 16px; left: 50%; transform: translateX(-50%); background: var(--cx-bg2); color: var(--cx-primary); padding: 8px 20px; border-radius: var(--cx-radius); border: 1px solid rgba(var(--cx-primary-rgb), 0.3); box-shadow: 0 4px 12px rgba(0,0,0,0.4); z-index: 1000; display: none; font-family: var(--cx-font); font-size: 11px; letter-spacing: 0.04em; }
|
|
657
|
+
.reload-notification.show { display: block; animation: slideDown 0.3s; }
|
|
658
|
+
@keyframes slideDown { from { transform: translateX(-50%) translateY(-12px); opacity: 0; } to { transform: translateX(-50%) translateY(0); opacity: 1; } }
|
|
659
|
+
</style>
|
|
660
|
+
</head>
|
|
661
|
+
<body>
|
|
662
|
+
<div class="container">
|
|
663
|
+
<div class="header">
|
|
664
|
+
<div style="display: flex; align-items: center; gap: 16px;">
|
|
665
|
+
<a href="/" class="nav-link">← Dashboard</a>
|
|
666
|
+
<span class="title">${session.name}</span>
|
|
667
|
+
</div>
|
|
668
|
+
<div class="status"><span class="status-dot"></span> Running</div>
|
|
669
|
+
</div>
|
|
670
|
+
<div class="main-content">
|
|
671
|
+
<div class="preview-pane">
|
|
672
|
+
<div class="reload-notification" id="reload-notification">Reloading...</div>
|
|
673
|
+
<iframe id="sandbox-iframe" src="${session.url}"></iframe>
|
|
674
|
+
</div>
|
|
675
|
+
<div class="sidebar">
|
|
676
|
+
<div class="tabs">
|
|
677
|
+
<div class="tab active" onclick="switchTab('console')">Console</div>
|
|
678
|
+
<div class="tab" onclick="switchTab('screenshots')">Screenshots</div>
|
|
679
|
+
<div class="tab" onclick="switchTab('network')">Network</div>
|
|
680
|
+
</div>
|
|
681
|
+
<div class="tab-content" id="console-content"></div>
|
|
682
|
+
<div class="tab-content" id="screenshots-content" style="display:none;"></div>
|
|
683
|
+
<div class="tab-content" id="network-content" style="display:none;"></div>
|
|
684
|
+
</div>
|
|
685
|
+
</div>
|
|
686
|
+
</div>
|
|
687
|
+
<script>
|
|
688
|
+
const socket = io();
|
|
689
|
+
const sandboxId = '${session.id}';
|
|
690
|
+
socket.emit('subscribe', sandboxId);
|
|
691
|
+
socket.on('console-log', (e) => addConsoleLog('log', e.data.message));
|
|
692
|
+
socket.on('console-error', (e) => addConsoleLog('error', e.data.message));
|
|
693
|
+
socket.on('console-warn', (e) => addConsoleLog('warn', e.data.message));
|
|
694
|
+
socket.on('file-changed', () => { showReloadNotification(); setTimeout(() => { document.getElementById('sandbox-iframe').src = '${session.url}?' + Date.now(); }, 1000); });
|
|
695
|
+
socket.on('screenshot-captured', (e) => addScreenshot(e.data.screenshot, e.data.url));
|
|
696
|
+
socket.on('network-request', (e) => addNetworkRequest(e.data.method, e.data.url, e.data.status));
|
|
697
|
+
socket.on('network-response', (e) => addNetworkRequest(e.data.method, e.data.url, e.data.status));
|
|
698
|
+
socket.on('history', (data) => { data.events.forEach(e => { if (e.type.startsWith('console-')) addConsoleLog(e.data.level, e.data.message); else if (e.type === 'screenshot-captured') addScreenshot(e.data.screenshot, e.data.url); else if (e.type.startsWith('network-')) addNetworkRequest(e.data.method, e.data.url, e.data.status); }); });
|
|
699
|
+
function addConsoleLog(level, message) { const c = document.getElementById('console-content'); const l = document.createElement('div'); l.className = 'console-line console-' + level; l.innerHTML = '<span class="timestamp">' + new Date().toLocaleTimeString() + '</span>' + message; c.appendChild(l); c.scrollTop = c.scrollHeight; }
|
|
700
|
+
function addScreenshot(base64, url) { const c = document.getElementById('screenshots-content'); const i = document.createElement('div'); i.className = 'screenshot-item'; i.innerHTML = '<img src="data:image/png;base64,' + base64 + '" alt="Screenshot"><div class="screenshot-meta">' + new Date().toLocaleString() + '</div>'; c.insertBefore(i, c.firstChild); }
|
|
701
|
+
function addNetworkRequest(method, url, status) { const c = document.getElementById('network-content'); const i = document.createElement('div'); i.className = 'network-item'; i.innerHTML = '<span class="network-method">' + method + '</span><span class="network-url">' + url + '</span>' + (status ? '<span class="network-status">' + status + '</span>' : ''); c.insertBefore(i, c.firstChild); }
|
|
702
|
+
function showReloadNotification() { const n = document.getElementById('reload-notification'); n.classList.add('show'); setTimeout(() => n.classList.remove('show'), 2000); }
|
|
703
|
+
function switchTab(tab) { document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); event.target.classList.add('active'); ['console','screenshots','network'].forEach(t => { document.getElementById(t + '-content').style.display = t === tab ? 'block' : 'none'; }); }
|
|
704
|
+
addConsoleLog('log', 'Sandbox viewer connected');
|
|
705
|
+
</script>
|
|
706
|
+
</body>
|
|
707
|
+
</html>
|
|
708
|
+
`;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Generate 404 page
|
|
712
|
+
*/
|
|
713
|
+
generate404HTML(sandboxId) {
|
|
714
|
+
return `
|
|
715
|
+
<!DOCTYPE html>
|
|
716
|
+
<html lang="en">
|
|
717
|
+
<head>
|
|
718
|
+
<meta charset="UTF-8">
|
|
719
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
720
|
+
<title>Cortex Intelligence // Not Found</title>
|
|
721
|
+
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700&family=Oxygen+Mono&display=swap" rel="stylesheet">
|
|
722
|
+
<style>
|
|
723
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
724
|
+
body { font-family: 'Oxygen Mono', monospace; font-size: 12px; background: #0f172a; color: #e2e8f0; display: flex; align-items: center; justify-content: center; height: 100vh; text-align: center; }
|
|
725
|
+
.error-container { max-width: 440px; padding: 40px; background: #1e293b; border: 1px solid #334155; border-radius: 6px; }
|
|
726
|
+
h1 { font-size: 14px; font-weight: 400; letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 12px; color: #f8fafc; }
|
|
727
|
+
p { color: #94a3b8; font-size: 11px; margin-bottom: 8px; }
|
|
728
|
+
.sandbox-id { background: #253347; padding: 8px 12px; border-radius: 6px; margin: 16px 0; color: #f87171; font-size: 11px; border: 1px solid #283548; }
|
|
729
|
+
a { color: #4a90d9; text-decoration: none; font-size: 11px; letter-spacing: 0.04em; }
|
|
730
|
+
a:hover { color: #f8fafc; }
|
|
731
|
+
</style>
|
|
732
|
+
</head>
|
|
733
|
+
<body>
|
|
734
|
+
<div class="error-container">
|
|
735
|
+
<h1>Sandbox Not Found</h1>
|
|
736
|
+
<p>The sandbox you're looking for doesn't exist or has been stopped.</p>
|
|
737
|
+
<div class="sandbox-id">${sandboxId}</div>
|
|
738
|
+
<p><a href="/">← Back to Dashboard</a></p>
|
|
739
|
+
</div>
|
|
740
|
+
</body>
|
|
741
|
+
</html>
|
|
742
|
+
`;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Check if server is running
|
|
746
|
+
*/
|
|
747
|
+
isServerRunning() {
|
|
748
|
+
return this.isRunning;
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Get current port
|
|
752
|
+
*/
|
|
753
|
+
getPort() {
|
|
754
|
+
return this.port;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Get Express app instance for route registration
|
|
758
|
+
* Allows other servers (like TmuxViewServer) to add routes
|
|
759
|
+
*/
|
|
760
|
+
getApp() {
|
|
761
|
+
return this.app;
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Get Socket.IO server instance for WebSocket handling
|
|
765
|
+
* Allows other servers to register WebSocket event handlers
|
|
766
|
+
*/
|
|
767
|
+
getIO() {
|
|
768
|
+
return this.io;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Export singleton instance
|
|
773
|
+
*/
|
|
774
|
+
export const viewServer = SandboxViewServer.getInstance();
|
|
775
|
+
//# sourceMappingURL=SandboxViewServer.js.map
|