@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,1042 @@
|
|
|
1
|
+
import { BaseTool } from '../../base/BaseTool.js';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
import { buildReactArtifact } from './ReactArtifactBuilder.js';
|
|
7
|
+
import { watch } from 'fs';
|
|
8
|
+
import { exec } from 'child_process';
|
|
9
|
+
import { promisify } from 'util';
|
|
10
|
+
import { visualBridge } from './VisualFeedbackBridge.js';
|
|
11
|
+
import { broadcaster } from './SandboxEventBroadcaster.js';
|
|
12
|
+
import { viewServer, SandboxViewServer } from './SandboxViewServer.js';
|
|
13
|
+
import { SandboxRegistry } from '../../utils/SandboxRegistry.js';
|
|
14
|
+
import { ArtifactRegistry } from '../../utils/ArtifactRegistry.js';
|
|
15
|
+
import { TmuxManager } from '../../utils/TmuxManager.js';
|
|
16
|
+
import { SessionPersistence } from '../../utils/SessionPersistence.js';
|
|
17
|
+
const execAsync = promisify(exec);
|
|
18
|
+
/**
|
|
19
|
+
* Active artifactes registry
|
|
20
|
+
*/
|
|
21
|
+
const activeArtifactes = new Map();
|
|
22
|
+
/**
|
|
23
|
+
* CreateAddonToolEnhanced - Next-generation dynamic tool creation
|
|
24
|
+
*
|
|
25
|
+
* Features:
|
|
26
|
+
* - UV + NIX package manager support
|
|
27
|
+
* - Dev mode with hot reloading
|
|
28
|
+
* - Automatic UI display (browser popup)
|
|
29
|
+
* - Persistent artifact sessions
|
|
30
|
+
* - Live editing with file watching
|
|
31
|
+
* - Multi-step orchestration
|
|
32
|
+
* - WebSocket live updates
|
|
33
|
+
*
|
|
34
|
+
* Example: TradeStation Proxy
|
|
35
|
+
* ```
|
|
36
|
+
* Model creates:
|
|
37
|
+
* 1. Proxy server (Express.js)
|
|
38
|
+
* 2. Traffic monitor (captures inbound/outbound)
|
|
39
|
+
* 3. Real-time dashboard (React/Socket.io)
|
|
40
|
+
* 4. Auto-opens browser at localhost:3000
|
|
41
|
+
* 5. Hot reloads on code changes
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export class CreateArtifactToolExecutor extends BaseTool {
|
|
45
|
+
artifactDir;
|
|
46
|
+
workingDirectory;
|
|
47
|
+
constructor(config) {
|
|
48
|
+
const schema = {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {
|
|
51
|
+
name: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
description: 'Unique name for the addon tool'
|
|
54
|
+
},
|
|
55
|
+
description: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'What the tool does'
|
|
58
|
+
},
|
|
59
|
+
parameters: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
description: 'JSON Schema for tool parameters'
|
|
62
|
+
},
|
|
63
|
+
implementation: {
|
|
64
|
+
type: 'object',
|
|
65
|
+
properties: {
|
|
66
|
+
language: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
enum: ['javascript', 'python'],
|
|
69
|
+
description: 'Programming language'
|
|
70
|
+
},
|
|
71
|
+
code: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
description: 'Source code'
|
|
74
|
+
},
|
|
75
|
+
dependencies: {
|
|
76
|
+
type: 'array',
|
|
77
|
+
items: { type: 'string' },
|
|
78
|
+
description: 'Required packages'
|
|
79
|
+
},
|
|
80
|
+
packageManager: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
enum: ['npm', 'pip', 'uv', 'nix'],
|
|
83
|
+
description: 'Package manager (npm, pip, uv, nix)'
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
required: ['language', 'code']
|
|
87
|
+
},
|
|
88
|
+
mode: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
enum: ['oneshot', 'dev', 'persistent'],
|
|
91
|
+
description: 'Execution mode: oneshot (default), dev (hot reload), persistent (keep alive)'
|
|
92
|
+
},
|
|
93
|
+
enableVisualFeedback: {
|
|
94
|
+
type: 'boolean',
|
|
95
|
+
description: 'Enable comprehensive visual feedback system for you (the model) to see and iterate on your creations. Captures: (1) screenshots (base64 PNG) of actual UI rendering, (2) DOM structure (HTML), (3) console logs (runtime output), (4) network requests (API calls), (5) performance metrics. Visual data is included in response metadata, allowing you to analyze what you built, identify issues, and make improvements. Essential for iterative UI development.'
|
|
96
|
+
},
|
|
97
|
+
enableReactIntrospection: {
|
|
98
|
+
type: 'boolean',
|
|
99
|
+
description: 'Include a framework report (React/Vue/Svelte detection, React version, renderer count) in the initial visual snapshot. The sandbox_scan / sandbox_grab / sandbox_detect_framework tools work regardless of this flag (they enable introspection on first use). Default: false.'
|
|
100
|
+
},
|
|
101
|
+
devConfig: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
hotReload: {
|
|
105
|
+
type: 'boolean',
|
|
106
|
+
description: 'Enable hot reload on file changes'
|
|
107
|
+
},
|
|
108
|
+
watchFiles: {
|
|
109
|
+
type: 'array',
|
|
110
|
+
items: { type: 'string' },
|
|
111
|
+
description: 'Files to watch for changes'
|
|
112
|
+
},
|
|
113
|
+
openBrowser: {
|
|
114
|
+
type: 'boolean',
|
|
115
|
+
description: 'Auto-open browser on start'
|
|
116
|
+
},
|
|
117
|
+
liveBridge: {
|
|
118
|
+
type: 'boolean',
|
|
119
|
+
description: 'Enable WebSocket live updates'
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
uiConfig: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
type: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
enum: ['web', 'terminal', 'both'],
|
|
129
|
+
description: 'UI display type'
|
|
130
|
+
},
|
|
131
|
+
framework: {
|
|
132
|
+
type: 'string',
|
|
133
|
+
enum: ['express', 'fastapi', 'flask', 'nextjs', 'react'],
|
|
134
|
+
description: "Web framework. Use 'react' to build a React artifact from a component in implementation.code (define or default-export `App`). React artifacts are served statically and are introspectable via sandbox_scan/sandbox_grab/sandbox_detect_framework."
|
|
135
|
+
},
|
|
136
|
+
reactMode: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
enum: ['cdn', 'bundled'],
|
|
139
|
+
description: "React only. 'bundled' (default when esbuild is available): real source maps, sandbox_grab returns real src/App.tsx:line. 'cdn': zero-install in-browser Babel, faster to start."
|
|
140
|
+
},
|
|
141
|
+
additionalFiles: {
|
|
142
|
+
type: 'array',
|
|
143
|
+
items: {
|
|
144
|
+
type: 'object',
|
|
145
|
+
properties: {
|
|
146
|
+
path: { type: 'string', description: "Path under src/, e.g. 'components/Button.tsx'" },
|
|
147
|
+
code: { type: 'string', description: 'Module source' }
|
|
148
|
+
},
|
|
149
|
+
required: ['path', 'code']
|
|
150
|
+
},
|
|
151
|
+
description: 'React bundled mode only: extra source modules importable from App.'
|
|
152
|
+
},
|
|
153
|
+
autoStart: {
|
|
154
|
+
type: 'boolean',
|
|
155
|
+
description: 'Start UI server automatically'
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
artifactConfig: {
|
|
160
|
+
type: 'object',
|
|
161
|
+
properties: {
|
|
162
|
+
type: {
|
|
163
|
+
type: 'string',
|
|
164
|
+
enum: ['docker', 'local', 'nix'],
|
|
165
|
+
description: 'Artifact type'
|
|
166
|
+
},
|
|
167
|
+
nixConfig: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: {
|
|
170
|
+
packages: {
|
|
171
|
+
type: 'array',
|
|
172
|
+
items: { type: 'string' },
|
|
173
|
+
description: 'Nix packages to install'
|
|
174
|
+
},
|
|
175
|
+
shellHook: {
|
|
176
|
+
type: 'string',
|
|
177
|
+
description: 'Shell initialization script'
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
required: ['name', 'description', 'parameters', 'implementation']
|
|
185
|
+
};
|
|
186
|
+
super('CreateArtifactTool', 'CreateArtifactTool', 'Create persistent artifacts (web apps, tools, scripts) with hot reload, UV/NIX support, and auto UI display. Enable visual feedback to see your own creations: capture screenshots, DOM structure, console logs, network activity, and performance metrics. Use this data to iteratively improve and debug your work.', schema);
|
|
187
|
+
this.workingDirectory = config.workingDirectory;
|
|
188
|
+
// Use unified artifacts directory structure
|
|
189
|
+
this.artifactDir = join(config.workingDirectory, '.cortex', 'artifacts');
|
|
190
|
+
// Initialize unified artifact registry (singleton)
|
|
191
|
+
const registry = ArtifactRegistry.getInstance(config.workingDirectory);
|
|
192
|
+
registry.initialize().catch((error) => {
|
|
193
|
+
console.error(`⚠ Failed to initialize ArtifactRegistry: ${error.message}`);
|
|
194
|
+
});
|
|
195
|
+
// Also initialize sandbox registry for backwards compatibility
|
|
196
|
+
const sandboxRegistry = SandboxRegistry.getInstance(config.workingDirectory);
|
|
197
|
+
sandboxRegistry.initialize().catch((error) => {
|
|
198
|
+
console.error(`⚠ Failed to initialize SandboxRegistry: ${error.message}`);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Sanitize name to filesystem-safe format (kebab-case slug)
|
|
203
|
+
* Industry best practice: Accept human-friendly input, auto-convert to system-safe format
|
|
204
|
+
*/
|
|
205
|
+
sanitizeName(name) {
|
|
206
|
+
return name
|
|
207
|
+
.trim()
|
|
208
|
+
.toLowerCase()
|
|
209
|
+
.replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with hyphens
|
|
210
|
+
.replace(/^-+|-+$/g, '') // Remove leading/trailing hyphens
|
|
211
|
+
.replace(/-{2,}/g, '-') // Collapse multiple hyphens
|
|
212
|
+
|| 'unnamed-tool'; // Fallback if empty after sanitization
|
|
213
|
+
}
|
|
214
|
+
validateToolParams(params) {
|
|
215
|
+
// Basic validation
|
|
216
|
+
if (!params.name || params.name.trim().length === 0) {
|
|
217
|
+
return 'name must be a non-empty string';
|
|
218
|
+
}
|
|
219
|
+
// #18 — restore 64-char name cap (dropped during the CreateAddonTool →
|
|
220
|
+
// CreateArtifactTool rename refactor; unanimously diagnosed as a silent
|
|
221
|
+
// regression by the round-10 multi-agent audit). Checked BEFORE
|
|
222
|
+
// sanitization so callers see the same length contract they passed in;
|
|
223
|
+
// sanitization would only shrink a too-long name, masking the error.
|
|
224
|
+
if (params.name.length > 64) {
|
|
225
|
+
return 'name must be 64 characters or less';
|
|
226
|
+
}
|
|
227
|
+
// Auto-sanitize name instead of rejecting
|
|
228
|
+
// This accepts "Stock Chart App" and converts to "stock-chart-app"
|
|
229
|
+
const originalName = params.name;
|
|
230
|
+
params.name = this.sanitizeName(params.name);
|
|
231
|
+
if (params.name.length === 0 || params.name === 'unnamed-tool') {
|
|
232
|
+
return `name "${originalName}" contains no valid characters (letters, numbers)`;
|
|
233
|
+
}
|
|
234
|
+
if (!params.description || params.description.trim().length === 0) {
|
|
235
|
+
return 'description must be a non-empty string';
|
|
236
|
+
}
|
|
237
|
+
if (!params.implementation?.code) {
|
|
238
|
+
return 'implementation.code is required';
|
|
239
|
+
}
|
|
240
|
+
if (!['javascript', 'python'].includes(params.implementation.language)) {
|
|
241
|
+
return 'language must be javascript or python';
|
|
242
|
+
}
|
|
243
|
+
// Validate package manager
|
|
244
|
+
if (params.implementation.packageManager) {
|
|
245
|
+
const validManagers = ['npm', 'pip', 'uv', 'nix'];
|
|
246
|
+
if (!validManagers.includes(params.implementation.packageManager)) {
|
|
247
|
+
return `packageManager must be one of: ${validManagers.join(', ')}`;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Validate mode
|
|
251
|
+
if (params.mode && !['oneshot', 'dev', 'persistent'].includes(params.mode)) {
|
|
252
|
+
return 'mode must be oneshot, dev, or persistent';
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
async execute(params, signal) {
|
|
257
|
+
const startTime = Date.now();
|
|
258
|
+
const originalName = params.name; // Preserve original before sanitization
|
|
259
|
+
const validationError = this.validateToolParams(params);
|
|
260
|
+
if (validationError) {
|
|
261
|
+
return this.createErrorResult(validationError);
|
|
262
|
+
}
|
|
263
|
+
// Notify if name was sanitized
|
|
264
|
+
const nameSanitized = originalName !== params.name;
|
|
265
|
+
try {
|
|
266
|
+
await fs.mkdir(this.artifactDir, { recursive: true });
|
|
267
|
+
const mode = params.mode || 'oneshot';
|
|
268
|
+
const artifactId = randomUUID();
|
|
269
|
+
// Create artifact directory with workspace subdirectory
|
|
270
|
+
const artifactPath = join(this.artifactDir, artifactId);
|
|
271
|
+
const workspacePath = join(artifactPath, 'workspace');
|
|
272
|
+
await fs.mkdir(artifactPath, { recursive: true });
|
|
273
|
+
await fs.mkdir(workspacePath, { recursive: true });
|
|
274
|
+
await fs.mkdir(join(artifactPath, 'snapshots'), { recursive: true });
|
|
275
|
+
// React artifacts: introspection on by default so the initial snapshot (and the
|
|
276
|
+
// sandbox_scan/grab/detect tools) report the fiber tree. Opt out by passing false.
|
|
277
|
+
if (params.uiConfig?.framework === 'react' && params.enableReactIntrospection === undefined) {
|
|
278
|
+
params.enableReactIntrospection = true;
|
|
279
|
+
}
|
|
280
|
+
// Install dependencies in workspace
|
|
281
|
+
await this.installDependencies(params.implementation, workspacePath, signal);
|
|
282
|
+
// Write code files to workspace
|
|
283
|
+
await this.writeToolFiles(params.implementation, params.uiConfig, workspacePath);
|
|
284
|
+
// Launch artifact based on mode
|
|
285
|
+
let session = null;
|
|
286
|
+
if (mode === 'dev' || mode === 'persistent') {
|
|
287
|
+
session = await this.launchPersistentArtifact(artifactId, params, workspacePath, signal);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
// Oneshot execution
|
|
291
|
+
const result = await this.executeOneshot(params.implementation, workspacePath, signal);
|
|
292
|
+
await fs.rm(artifactPath, { recursive: true, force: true });
|
|
293
|
+
return {
|
|
294
|
+
...this.createSuccessResult(result.output),
|
|
295
|
+
metadata: {
|
|
296
|
+
executionTime: Date.now() - startTime,
|
|
297
|
+
toolName: params.name,
|
|
298
|
+
mode: 'oneshot',
|
|
299
|
+
success: result.success
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
// Format output for persistent/dev mode
|
|
304
|
+
const output = this.formatPersistentOutput(session, params, nameSanitized ? originalName : undefined);
|
|
305
|
+
return {
|
|
306
|
+
...this.createSuccessResult(output),
|
|
307
|
+
metadata: {
|
|
308
|
+
executionTime: Date.now() - startTime,
|
|
309
|
+
toolName: params.name,
|
|
310
|
+
originalName: nameSanitized ? originalName : undefined,
|
|
311
|
+
sanitized: nameSanitized,
|
|
312
|
+
mode,
|
|
313
|
+
artifactId: session.id,
|
|
314
|
+
url: session.url,
|
|
315
|
+
port: session.port,
|
|
316
|
+
status: 'running',
|
|
317
|
+
visualFeedbackEnabled: params.enableVisualFeedback || false,
|
|
318
|
+
hasVisualSnapshot: !!session.visualSnapshot
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
return this.createErrorResult(`Failed to create addon tool: ${error.message}`);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Install dependencies using specified package manager
|
|
328
|
+
*/
|
|
329
|
+
async installDependencies(implementation, artifactPath, signal) {
|
|
330
|
+
if (!implementation.dependencies || implementation.dependencies.length === 0) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const packageManager = implementation.packageManager ||
|
|
334
|
+
(implementation.language === 'javascript' ? 'npm' : 'pip');
|
|
335
|
+
switch (packageManager) {
|
|
336
|
+
case 'npm':
|
|
337
|
+
await this.installNpm(implementation.dependencies, artifactPath, signal);
|
|
338
|
+
break;
|
|
339
|
+
case 'pip':
|
|
340
|
+
await this.installPip(implementation.dependencies, artifactPath, signal);
|
|
341
|
+
break;
|
|
342
|
+
case 'uv':
|
|
343
|
+
await this.installUv(implementation.dependencies, artifactPath, signal);
|
|
344
|
+
break;
|
|
345
|
+
case 'nix':
|
|
346
|
+
// Nix handles dependencies declaratively in shell.nix
|
|
347
|
+
await this.setupNix(implementation.dependencies, artifactPath);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Install with npm
|
|
353
|
+
*/
|
|
354
|
+
async installNpm(deps, artifactPath, signal) {
|
|
355
|
+
const packageJson = {
|
|
356
|
+
name: 'addon-tool',
|
|
357
|
+
version: '1.0.0',
|
|
358
|
+
dependencies: Object.fromEntries(deps.map(d => [d, 'latest']))
|
|
359
|
+
};
|
|
360
|
+
await fs.writeFile(join(artifactPath, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
361
|
+
await this.runCommand('npm', ['install'], artifactPath, signal);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Install with pip
|
|
365
|
+
*/
|
|
366
|
+
async installPip(deps, artifactPath, signal) {
|
|
367
|
+
await fs.writeFile(join(artifactPath, 'requirements.txt'), deps.join('\n'));
|
|
368
|
+
await this.runCommand('pip3', ['install', '-r', 'requirements.txt'], artifactPath, signal);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Install with UV (fast Python package manager)
|
|
372
|
+
*/
|
|
373
|
+
async installUv(deps, artifactPath, signal) {
|
|
374
|
+
// Check if UV is installed
|
|
375
|
+
try {
|
|
376
|
+
await execAsync('uv --version');
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
throw new Error('UV is not installed. Install with: curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
380
|
+
}
|
|
381
|
+
await fs.writeFile(join(artifactPath, 'requirements.txt'), deps.join('\n'));
|
|
382
|
+
// UV is 10-100x faster than pip
|
|
383
|
+
await this.runCommand('uv', ['pip', 'install', '-r', 'requirements.txt'], artifactPath, signal);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Setup Nix environment
|
|
387
|
+
*/
|
|
388
|
+
async setupNix(deps, artifactPath) {
|
|
389
|
+
// Create shell.nix for declarative environment
|
|
390
|
+
const shellNix = `
|
|
391
|
+
{ pkgs ? import <nixpkgs> {} }:
|
|
392
|
+
|
|
393
|
+
pkgs.mkShell {
|
|
394
|
+
buildInputs = with pkgs; [
|
|
395
|
+
${deps.map(d => ` ${d}`).join('\n')}
|
|
396
|
+
];
|
|
397
|
+
|
|
398
|
+
shellHook = ''
|
|
399
|
+
echo "Nix environment activated"
|
|
400
|
+
echo "Packages: ${deps.join(', ')}"
|
|
401
|
+
'';
|
|
402
|
+
}
|
|
403
|
+
`;
|
|
404
|
+
await fs.writeFile(join(artifactPath, 'shell.nix'), shellNix);
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Write tool files to artifact
|
|
408
|
+
*/
|
|
409
|
+
async writeToolFiles(implementation, uiConfig, artifactPath) {
|
|
410
|
+
// React artifact: build a static dir (index.html [+ dist/bundle.js, src/*]) served by http-server.
|
|
411
|
+
if (uiConfig?.framework === 'react') {
|
|
412
|
+
const result = await buildReactArtifact(artifactPath, {
|
|
413
|
+
code: implementation.code,
|
|
414
|
+
reactMode: uiConfig.reactMode,
|
|
415
|
+
additionalFiles: uiConfig.additionalFiles
|
|
416
|
+
});
|
|
417
|
+
console.log(`[CreateArtifactTool] React artifact built (${result.mode} mode)` +
|
|
418
|
+
(result.warnings.length ? ` — ${result.warnings.join('; ')}` : ''));
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
// Detect if code is HTML (starts with <!DOCTYPE or <html)
|
|
422
|
+
const isHtml = implementation.code.trim().match(/^<!DOCTYPE|^<html/i);
|
|
423
|
+
let fileName;
|
|
424
|
+
let code = implementation.code;
|
|
425
|
+
if (isHtml) {
|
|
426
|
+
// HTML file - save as index.html
|
|
427
|
+
fileName = 'index.html';
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
// Regular script file
|
|
431
|
+
fileName = implementation.language === 'javascript' ? 'index.js' : 'main.py';
|
|
432
|
+
// If UI framework specified, wrap code with framework boilerplate
|
|
433
|
+
if (uiConfig?.framework) {
|
|
434
|
+
code = this.wrapWithFramework(implementation.code, uiConfig.framework, implementation.language);
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
// Post-process: Replace hardcoded ports with process.env.PORT for Node.js/Python servers
|
|
438
|
+
// This ensures artifacts use dynamically assigned ports instead of hardcoded values
|
|
439
|
+
if (implementation.language === 'javascript') {
|
|
440
|
+
// Replace common Node.js/Express server port patterns
|
|
441
|
+
code = code
|
|
442
|
+
// Match: server.listen(3000) or server.listen(3000, ...)
|
|
443
|
+
.replace(/\.listen\((\d{4,5})(\s*[,)])/g, '.listen(process.env.PORT || $1$2')
|
|
444
|
+
// Match: const PORT = 3000
|
|
445
|
+
.replace(/\b(const|let|var)\s+PORT\s*=\s*(\d{4,5})\b/g, '$1 PORT = process.env.PORT || $2')
|
|
446
|
+
// Match: app.listen(3000)
|
|
447
|
+
.replace(/app\.listen\((\d{4,5})(\s*[,)])/g, 'app.listen(process.env.PORT || $1$2');
|
|
448
|
+
console.log(`[CreateArtifactTool] Post-processed JavaScript code to use process.env.PORT`);
|
|
449
|
+
}
|
|
450
|
+
else if (implementation.language === 'python') {
|
|
451
|
+
// Replace common Flask/FastAPI port patterns
|
|
452
|
+
code = code
|
|
453
|
+
// Match: app.run(port=5000)
|
|
454
|
+
.replace(/\.run\((.*?)port\s*=\s*(\d{4,5})/g, (match, before, port) => {
|
|
455
|
+
return `.run(${before}port=int(os.getenv('PORT', ${port}))`;
|
|
456
|
+
})
|
|
457
|
+
// Match: uvicorn.run(..., port=8000)
|
|
458
|
+
.replace(/uvicorn\.run\((.*?)port\s*=\s*(\d{4,5})/g, (match, before, port) => {
|
|
459
|
+
return `uvicorn.run(${before}port=int(os.getenv('PORT', ${port}))`;
|
|
460
|
+
});
|
|
461
|
+
// Ensure os module is imported
|
|
462
|
+
if (!code.includes('import os')) {
|
|
463
|
+
code = 'import os\n' + code;
|
|
464
|
+
}
|
|
465
|
+
console.log(`[CreateArtifactTool] Post-processed Python code to use os.getenv('PORT')`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const filePath = join(artifactPath, fileName);
|
|
470
|
+
await fs.writeFile(filePath, code);
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Wrap user code with web framework boilerplate
|
|
474
|
+
*/
|
|
475
|
+
wrapWithFramework(code, framework, language) {
|
|
476
|
+
if (language === 'javascript') {
|
|
477
|
+
switch (framework) {
|
|
478
|
+
case 'express':
|
|
479
|
+
return `
|
|
480
|
+
const express = require('express');
|
|
481
|
+
const app = express();
|
|
482
|
+
const PORT = process.env.PORT || 3000;
|
|
483
|
+
|
|
484
|
+
app.use(express.json());
|
|
485
|
+
app.use(express.static('public'));
|
|
486
|
+
|
|
487
|
+
// User code
|
|
488
|
+
${code}
|
|
489
|
+
|
|
490
|
+
// Default route
|
|
491
|
+
app.get('/', (req, res) => {
|
|
492
|
+
res.send('<h1>Tool Running</h1><p>Port: ' + PORT + '</p>');
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
app.listen(PORT, () => {
|
|
496
|
+
console.log(\` Server running at http://localhost:\${PORT}\`);
|
|
497
|
+
});
|
|
498
|
+
`;
|
|
499
|
+
case 'nextjs':
|
|
500
|
+
return `
|
|
501
|
+
// Next.js API route wrapper
|
|
502
|
+
${code}
|
|
503
|
+
|
|
504
|
+
export default async function handler(req, res) {
|
|
505
|
+
const result = await main(req.body || req.query);
|
|
506
|
+
res.status(200).json(result);
|
|
507
|
+
}
|
|
508
|
+
`;
|
|
509
|
+
default:
|
|
510
|
+
return code;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
// Python
|
|
515
|
+
switch (framework) {
|
|
516
|
+
case 'fastapi':
|
|
517
|
+
return `
|
|
518
|
+
from fastapi import FastAPI
|
|
519
|
+
from fastapi.responses import HTMLResponse
|
|
520
|
+
import uvicorn
|
|
521
|
+
|
|
522
|
+
app = FastAPI()
|
|
523
|
+
|
|
524
|
+
# User code
|
|
525
|
+
${code}
|
|
526
|
+
|
|
527
|
+
@app.get("/", response_class=HTMLResponse)
|
|
528
|
+
async def root():
|
|
529
|
+
return "<h1>Tool Running</h1><p>Port: 8000</p>"
|
|
530
|
+
|
|
531
|
+
if __name__ == "__main__":
|
|
532
|
+
print(" Server running at http://localhost:8000")
|
|
533
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
534
|
+
`;
|
|
535
|
+
case 'flask':
|
|
536
|
+
return `
|
|
537
|
+
from flask import Flask, request, jsonify
|
|
538
|
+
app = Flask(__name__)
|
|
539
|
+
|
|
540
|
+
# User code
|
|
541
|
+
${code}
|
|
542
|
+
|
|
543
|
+
@app.route('/')
|
|
544
|
+
def index():
|
|
545
|
+
return '<h1>Tool Running</h1><p>Port: 5000</p>'
|
|
546
|
+
|
|
547
|
+
if __name__ == '__main__':
|
|
548
|
+
print(' Server running at http://localhost:5000')
|
|
549
|
+
app.run(host='0.0.0.0', port=5000, debug=True)
|
|
550
|
+
`;
|
|
551
|
+
default:
|
|
552
|
+
return code;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Find an available port starting from a base port
|
|
558
|
+
*/
|
|
559
|
+
async findAvailablePort(startPort = 3000) {
|
|
560
|
+
const net = await import('net');
|
|
561
|
+
const isPortAvailable = (port) => {
|
|
562
|
+
return new Promise((resolve) => {
|
|
563
|
+
const server = net.createServer();
|
|
564
|
+
server.once('error', () => resolve(false));
|
|
565
|
+
server.once('listening', () => {
|
|
566
|
+
server.close();
|
|
567
|
+
resolve(true);
|
|
568
|
+
});
|
|
569
|
+
server.listen(port);
|
|
570
|
+
});
|
|
571
|
+
};
|
|
572
|
+
let port = startPort;
|
|
573
|
+
while (port < startPort + 100) {
|
|
574
|
+
if (await isPortAvailable(port)) {
|
|
575
|
+
return port;
|
|
576
|
+
}
|
|
577
|
+
port++;
|
|
578
|
+
}
|
|
579
|
+
throw new Error(`No available ports found in range ${startPort}-${startPort + 99}`);
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Launch persistent artifact with tmux integration
|
|
583
|
+
* Supports arbitrary languages and custom commands
|
|
584
|
+
*/
|
|
585
|
+
async launchPersistentArtifact(artifactId, params, artifactPath, signal) {
|
|
586
|
+
let fileName;
|
|
587
|
+
let command;
|
|
588
|
+
let runtime;
|
|
589
|
+
// If user provides custom command, use it directly
|
|
590
|
+
if (params.implementation.command) {
|
|
591
|
+
command = params.implementation.command;
|
|
592
|
+
fileName = params.implementation.fileName || params.implementation.entryPoint || 'artifact';
|
|
593
|
+
runtime = `tmux+custom`;
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
// Auto-detect based on language or content
|
|
597
|
+
const isHtml = params.implementation.code.trim().match(/^<!DOCTYPE|^<html/i);
|
|
598
|
+
const isReact = params.uiConfig?.framework === 'react';
|
|
599
|
+
if (isReact || isHtml || params.implementation.language === 'html') {
|
|
600
|
+
// HTML file - serve with http-server
|
|
601
|
+
fileName = params.implementation.fileName || 'index.html';
|
|
602
|
+
command = `npx http-server -p ${params.artifactConfig?.ports?.[0] || 3000} -c-1 --silent`;
|
|
603
|
+
runtime = 'tmux+http-server';
|
|
604
|
+
}
|
|
605
|
+
else if (params.implementation.language === 'javascript') {
|
|
606
|
+
fileName = params.implementation.fileName || 'index.js';
|
|
607
|
+
command = `node ${fileName}`;
|
|
608
|
+
runtime = 'tmux+node';
|
|
609
|
+
}
|
|
610
|
+
else if (params.implementation.language === 'python') {
|
|
611
|
+
fileName = params.implementation.fileName || 'main.py';
|
|
612
|
+
command = `python3 ${fileName}`;
|
|
613
|
+
runtime = 'tmux+python';
|
|
614
|
+
}
|
|
615
|
+
else if (params.implementation.language === 'rust') {
|
|
616
|
+
fileName = params.implementation.fileName || 'main.rs';
|
|
617
|
+
command = params.implementation.buildCommand
|
|
618
|
+
? `${params.implementation.buildCommand} && cargo run --release`
|
|
619
|
+
: 'cargo run';
|
|
620
|
+
runtime = 'tmux+rust';
|
|
621
|
+
}
|
|
622
|
+
else if (params.implementation.language === 'go') {
|
|
623
|
+
fileName = params.implementation.fileName || 'main.go';
|
|
624
|
+
command = params.implementation.buildCommand
|
|
625
|
+
? `${params.implementation.buildCommand} && ./artifact`
|
|
626
|
+
: `go run ${fileName}`;
|
|
627
|
+
runtime = 'tmux+go';
|
|
628
|
+
}
|
|
629
|
+
else if (params.implementation.language === 'shell') {
|
|
630
|
+
fileName = params.implementation.fileName || 'run.sh';
|
|
631
|
+
command = `chmod +x ${fileName} && ./${fileName}`;
|
|
632
|
+
runtime = 'tmux+shell';
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
// Generic/other - use custom command or fail
|
|
636
|
+
fileName = params.implementation.fileName || 'artifact';
|
|
637
|
+
command = params.implementation.command || `echo "No command specified for language: ${params.implementation.language}"`;
|
|
638
|
+
runtime = 'tmux+other';
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
// Find an available port dynamically
|
|
642
|
+
// Port 4000 = API server, Port 4001 = Dashboard
|
|
643
|
+
// Artifacts start from port 3000 and increment (3000, 3001, 3002, etc.)
|
|
644
|
+
const requestedPort = params.artifactConfig?.ports?.[0] || 3000;
|
|
645
|
+
const port = await this.findAvailablePort(requestedPort);
|
|
646
|
+
const url = `http://localhost:${port}`;
|
|
647
|
+
// Update command with actual port if it's http-server or contains port reference
|
|
648
|
+
if (command.includes('http-server')) {
|
|
649
|
+
command = command.replace(/\-p \d+/, `-p ${port}`);
|
|
650
|
+
}
|
|
651
|
+
// For Node.js/JavaScript artifacts, inject PORT environment variable
|
|
652
|
+
if (runtime === 'tmux+node' || params.implementation.language === 'javascript') {
|
|
653
|
+
command = `PORT=${port} ${command}`;
|
|
654
|
+
}
|
|
655
|
+
// For Python artifacts, inject PORT environment variable
|
|
656
|
+
if (runtime === 'tmux+python' || params.implementation.language === 'python') {
|
|
657
|
+
command = `PORT=${port} ${command}`;
|
|
658
|
+
}
|
|
659
|
+
// Initialize tmux manager
|
|
660
|
+
const tmuxManager = TmuxManager.getInstance();
|
|
661
|
+
// Check if tmux is available
|
|
662
|
+
const tmuxAvailable = await tmuxManager.isAvailable();
|
|
663
|
+
if (!tmuxAvailable) {
|
|
664
|
+
throw new Error('tmux is not installed. Persistent mode requires tmux for session management.');
|
|
665
|
+
}
|
|
666
|
+
// Create tmux session with artifact ID as session name
|
|
667
|
+
const tmuxSessionId = `artifact-${artifactId.substring(0, 8)}`;
|
|
668
|
+
await tmuxManager.createSession(tmuxSessionId, artifactPath);
|
|
669
|
+
// Send command to tmux session
|
|
670
|
+
await tmuxManager.sendKeys(tmuxSessionId, command);
|
|
671
|
+
// Wait a moment for process to start
|
|
672
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
673
|
+
// Save tmux session metadata for dashboard
|
|
674
|
+
const sessionPersistence = new SessionPersistence(this.workingDirectory);
|
|
675
|
+
await sessionPersistence.saveSession({
|
|
676
|
+
sessionId: tmuxSessionId,
|
|
677
|
+
created: new Date(),
|
|
678
|
+
lastUsed: new Date(),
|
|
679
|
+
cwd: artifactPath,
|
|
680
|
+
env: {}
|
|
681
|
+
});
|
|
682
|
+
const session = {
|
|
683
|
+
id: artifactId,
|
|
684
|
+
name: params.name,
|
|
685
|
+
tmuxSessionId,
|
|
686
|
+
url,
|
|
687
|
+
port,
|
|
688
|
+
mode: params.mode || 'persistent',
|
|
689
|
+
startTime: new Date(),
|
|
690
|
+
lastActivity: new Date(),
|
|
691
|
+
watchers: [],
|
|
692
|
+
path: artifactPath // served/built dir (the workspace) — edits + rebuilds target this
|
|
693
|
+
};
|
|
694
|
+
// Store session in memory
|
|
695
|
+
activeArtifactes.set(artifactId, session);
|
|
696
|
+
// Store in unified artifact registry
|
|
697
|
+
const artifactRegistry = ArtifactRegistry.getInstance(this.workingDirectory);
|
|
698
|
+
await artifactRegistry.register({
|
|
699
|
+
id: artifactId,
|
|
700
|
+
name: params.name,
|
|
701
|
+
type: 'web-app',
|
|
702
|
+
runtime,
|
|
703
|
+
created: new Date().toISOString(),
|
|
704
|
+
lastUsed: new Date().toISOString(),
|
|
705
|
+
workspaceDir: artifactPath,
|
|
706
|
+
entryPoint: fileName,
|
|
707
|
+
mode: params.mode || 'persistent',
|
|
708
|
+
port,
|
|
709
|
+
url,
|
|
710
|
+
tmuxSession: tmuxSessionId,
|
|
711
|
+
description: params.description
|
|
712
|
+
});
|
|
713
|
+
// Also store in sandbox registry for backwards compatibility
|
|
714
|
+
const sandboxRegistry = SandboxRegistry.getInstance(this.workingDirectory);
|
|
715
|
+
await sandboxRegistry.register({
|
|
716
|
+
id: artifactId,
|
|
717
|
+
name: params.name,
|
|
718
|
+
port,
|
|
719
|
+
url,
|
|
720
|
+
pid: undefined, // No PID for tmux sessions, use tmux session ID instead
|
|
721
|
+
mode: params.mode || 'persistent',
|
|
722
|
+
startTime: new Date().toISOString(),
|
|
723
|
+
lastActivity: new Date().toISOString(),
|
|
724
|
+
path: artifactPath
|
|
725
|
+
});
|
|
726
|
+
// Emit artifact created event
|
|
727
|
+
broadcaster.emitSandboxEvent({
|
|
728
|
+
type: 'sandbox-created',
|
|
729
|
+
sandboxId: session.id,
|
|
730
|
+
timestamp: Date.now(),
|
|
731
|
+
data: {
|
|
732
|
+
name: session.name,
|
|
733
|
+
url: session.url,
|
|
734
|
+
mode: session.mode,
|
|
735
|
+
port: session.port,
|
|
736
|
+
tmuxSession: tmuxSessionId
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
// Start view server if not already running. ENABLE_DASHBOARD is the master
|
|
740
|
+
// switch for the dashboard system — when off, skip silently (the sandbox
|
|
741
|
+
// itself works; only the web viewer is unavailable).
|
|
742
|
+
if (SandboxViewServer.isEnabled() && !viewServer.isServerRunning()) {
|
|
743
|
+
await viewServer.start().catch(err => {
|
|
744
|
+
console.warn('Could not start view server:', err);
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
// Setup hot reload if dev mode
|
|
748
|
+
if (params.mode === 'dev' && params.devConfig?.hotReload) {
|
|
749
|
+
await this.setupHotReload(session, artifactPath, fileName, command, params.enableVisualFeedback);
|
|
750
|
+
}
|
|
751
|
+
// Open browser if requested
|
|
752
|
+
if (params.devConfig?.openBrowser) {
|
|
753
|
+
await this.openBrowser(url);
|
|
754
|
+
}
|
|
755
|
+
// Initialize visual feedback if requested
|
|
756
|
+
if (params.enableVisualFeedback) {
|
|
757
|
+
await this.initializeVisualFeedback(session, params);
|
|
758
|
+
}
|
|
759
|
+
// Log tmux session info
|
|
760
|
+
console.log(`[${params.name}] Running in tmux session: ${tmuxSessionId}`);
|
|
761
|
+
console.log(`[${params.name}] Access at: ${url}`);
|
|
762
|
+
console.log(`[${params.name}] View output: tmux attach -t ${tmuxSessionId}`);
|
|
763
|
+
return session;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Setup hot reload with file watching
|
|
767
|
+
*/
|
|
768
|
+
async setupHotReload(session, artifactPath, fileName, command, enableVisualFeedback) {
|
|
769
|
+
const filePath = join(artifactPath, fileName);
|
|
770
|
+
const watcher = watch(filePath, async (eventType) => {
|
|
771
|
+
if (eventType === 'change') {
|
|
772
|
+
console.log(` File changed, reloading ${session.name}...`);
|
|
773
|
+
// Emit file changed event
|
|
774
|
+
broadcaster.emitFileChange(session.id, fileName, 'modified');
|
|
775
|
+
// Emit hot reload triggered event
|
|
776
|
+
broadcaster.emitHotReload(session.id, fileName);
|
|
777
|
+
// Kill old process
|
|
778
|
+
session.process?.kill();
|
|
779
|
+
// Start new process
|
|
780
|
+
const newProcess = spawn(command, [fileName], {
|
|
781
|
+
cwd: artifactPath,
|
|
782
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
783
|
+
});
|
|
784
|
+
session.process = newProcess;
|
|
785
|
+
session.lastActivity = new Date();
|
|
786
|
+
console.log(`[OK] ${session.name} reloaded`);
|
|
787
|
+
// Emit process restarted event
|
|
788
|
+
broadcaster.emitProcessRestart(session.id, 'Hot reload triggered');
|
|
789
|
+
// Capture new visual snapshot after reload
|
|
790
|
+
if (enableVisualFeedback && session.url) {
|
|
791
|
+
// Wait for server to restart
|
|
792
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
793
|
+
try {
|
|
794
|
+
console.log(` Capturing updated visual snapshot...`);
|
|
795
|
+
session.visualSnapshot = await visualBridge.captureSnapshot(session.url);
|
|
796
|
+
console.log(`[OK] Visual snapshot updated`);
|
|
797
|
+
// Emit screenshot captured event
|
|
798
|
+
broadcaster.emitScreenshot(session.id, session.visualSnapshot.screenshot, session.url);
|
|
799
|
+
}
|
|
800
|
+
catch (error) {
|
|
801
|
+
console.warn(`⚠ Could not update visual snapshot: ${error}`);
|
|
802
|
+
broadcaster.emitError(session.id, error);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
session.watchers = [watcher];
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Initialize visual feedback bridge
|
|
811
|
+
*/
|
|
812
|
+
async initializeVisualFeedback(session, params) {
|
|
813
|
+
try {
|
|
814
|
+
// Initialize Playwright browser
|
|
815
|
+
await visualBridge.initialize();
|
|
816
|
+
// Opt-in React introspection: inject the fiber pre-load BEFORE the first
|
|
817
|
+
// navigation so the initial snapshot carries the framework report.
|
|
818
|
+
if (params.enableReactIntrospection) {
|
|
819
|
+
await visualBridge.enableReactIntrospection();
|
|
820
|
+
}
|
|
821
|
+
// Wait for server to be ready (give it 2 seconds)
|
|
822
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
823
|
+
// Capture initial snapshot
|
|
824
|
+
if (session.url) {
|
|
825
|
+
console.log(` Capturing visual snapshot of ${params.name}...`);
|
|
826
|
+
session.visualSnapshot = await visualBridge.captureSnapshot(session.url);
|
|
827
|
+
console.log(`[OK] Visual snapshot captured (${session.visualSnapshot.screenshot.length} bytes)`);
|
|
828
|
+
// Emit screenshot captured event
|
|
829
|
+
broadcaster.emitScreenshot(session.id, session.visualSnapshot.screenshot, session.url);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
catch (error) {
|
|
833
|
+
console.warn(`⚠ Could not capture visual snapshot: ${error}`);
|
|
834
|
+
broadcaster.emitError(session.id, error);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Open browser automatically
|
|
839
|
+
*/
|
|
840
|
+
async openBrowser(url) {
|
|
841
|
+
const platform = process.platform;
|
|
842
|
+
let command;
|
|
843
|
+
if (platform === 'darwin') {
|
|
844
|
+
command = `open ${url}`;
|
|
845
|
+
}
|
|
846
|
+
else if (platform === 'win32') {
|
|
847
|
+
command = `start ${url}`;
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
command = `xdg-open ${url}`;
|
|
851
|
+
}
|
|
852
|
+
try {
|
|
853
|
+
await execAsync(command);
|
|
854
|
+
console.log(` Opened browser at ${url}`);
|
|
855
|
+
}
|
|
856
|
+
catch (error) {
|
|
857
|
+
console.warn(`Could not open browser: ${error}`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Execute tool in oneshot mode
|
|
862
|
+
*/
|
|
863
|
+
async executeOneshot(implementation, artifactPath, signal) {
|
|
864
|
+
const fileName = implementation.language === 'javascript' ? 'index.js' : 'main.py';
|
|
865
|
+
const command = implementation.language === 'javascript' ? 'node' : 'python3';
|
|
866
|
+
const result = await this.runCommand(command, [fileName], artifactPath, signal);
|
|
867
|
+
return {
|
|
868
|
+
success: result.exitCode === 0,
|
|
869
|
+
output: result.stdout
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Run command and capture output
|
|
874
|
+
*/
|
|
875
|
+
async runCommand(command, args, cwd, signal) {
|
|
876
|
+
return new Promise((resolve) => {
|
|
877
|
+
const child = spawn(command, args, { cwd });
|
|
878
|
+
let stdout = '';
|
|
879
|
+
let stderr = '';
|
|
880
|
+
child.stdout?.on('data', (data) => {
|
|
881
|
+
stdout += data.toString();
|
|
882
|
+
});
|
|
883
|
+
child.stderr?.on('data', (data) => {
|
|
884
|
+
stderr += data.toString();
|
|
885
|
+
});
|
|
886
|
+
child.on('close', (exitCode) => {
|
|
887
|
+
resolve({ stdout, stderr, exitCode: exitCode || 0 });
|
|
888
|
+
});
|
|
889
|
+
signal.addEventListener('abort', () => {
|
|
890
|
+
child.kill();
|
|
891
|
+
});
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Format output for persistent/dev artifact
|
|
896
|
+
*/
|
|
897
|
+
formatPersistentOutput(session, params, originalName) {
|
|
898
|
+
const lines = [];
|
|
899
|
+
lines.push(`# ${params.name} - ${params.mode?.toUpperCase()} MODE`);
|
|
900
|
+
lines.push('');
|
|
901
|
+
// Notify if name was auto-sanitized
|
|
902
|
+
if (originalName && originalName !== params.name) {
|
|
903
|
+
lines.push(`_Note: Name auto-sanitized from "${originalName}" to "${params.name}" (filesystem-safe format)_`);
|
|
904
|
+
lines.push('');
|
|
905
|
+
}
|
|
906
|
+
lines.push(`**Status**: Running`);
|
|
907
|
+
lines.push(`**URL**: ${session.url}`);
|
|
908
|
+
lines.push(`**Port**: ${session.port}`);
|
|
909
|
+
lines.push(`**Artifact ID**: ${session.id}`);
|
|
910
|
+
lines.push('');
|
|
911
|
+
if (params.mode === 'dev') {
|
|
912
|
+
lines.push('## Dev Mode Features');
|
|
913
|
+
lines.push('');
|
|
914
|
+
if (params.devConfig?.hotReload) {
|
|
915
|
+
lines.push('[OK] Hot reload enabled');
|
|
916
|
+
}
|
|
917
|
+
if (params.devConfig?.openBrowser) {
|
|
918
|
+
lines.push('[OK] Browser auto-opened');
|
|
919
|
+
}
|
|
920
|
+
if (params.devConfig?.liveBridge) {
|
|
921
|
+
lines.push('[OK] Live WebSocket updates');
|
|
922
|
+
}
|
|
923
|
+
lines.push('');
|
|
924
|
+
}
|
|
925
|
+
lines.push('## Package Manager');
|
|
926
|
+
lines.push('');
|
|
927
|
+
lines.push(`**Manager**: ${params.implementation.packageManager || 'default'}`);
|
|
928
|
+
if (params.implementation.dependencies) {
|
|
929
|
+
lines.push(`**Dependencies**: ${params.implementation.dependencies.join(', ')}`);
|
|
930
|
+
}
|
|
931
|
+
lines.push('');
|
|
932
|
+
lines.push('## Access');
|
|
933
|
+
lines.push('');
|
|
934
|
+
lines.push(`**Artifact URL**: ${session.url}`);
|
|
935
|
+
lines.push(`**View Dashboard**: ${viewServer.getViewUrl(session.id)}`);
|
|
936
|
+
lines.push('');
|
|
937
|
+
lines.push('The dashboard provides:');
|
|
938
|
+
lines.push('- Live preview of artifact UI');
|
|
939
|
+
lines.push('- Real-time console logs');
|
|
940
|
+
lines.push('- Screenshot history');
|
|
941
|
+
lines.push('- Network request monitoring');
|
|
942
|
+
lines.push('');
|
|
943
|
+
if (params.mode === 'dev') {
|
|
944
|
+
lines.push('Edit files in the artifact to see live updates in both the artifact and dashboard!');
|
|
945
|
+
}
|
|
946
|
+
// Include visual snapshot if available
|
|
947
|
+
if (session.visualSnapshot) {
|
|
948
|
+
lines.push('');
|
|
949
|
+
lines.push('---');
|
|
950
|
+
lines.push('');
|
|
951
|
+
lines.push('## Visual Snapshot');
|
|
952
|
+
lines.push('');
|
|
953
|
+
lines.push('The model can now SEE its creation!');
|
|
954
|
+
lines.push('');
|
|
955
|
+
lines.push(visualBridge.formatForModel(session.visualSnapshot));
|
|
956
|
+
lines.push('');
|
|
957
|
+
lines.push('**Note**: The model can use this visual feedback to iterate and improve the tool.');
|
|
958
|
+
lines.push('');
|
|
959
|
+
}
|
|
960
|
+
return lines.join('\n');
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Get active artifact by ID
|
|
964
|
+
*/
|
|
965
|
+
static getActiveArtifact(id) {
|
|
966
|
+
return activeArtifactes.get(id);
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* List all active artifactes
|
|
970
|
+
*/
|
|
971
|
+
static listActiveArtifactes() {
|
|
972
|
+
return Array.from(activeArtifactes.values());
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Get all active artifactes (alias for listActiveArtifactes)
|
|
976
|
+
*/
|
|
977
|
+
static getActiveArtifactes() {
|
|
978
|
+
return Array.from(activeArtifactes.values());
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Stop a artifact
|
|
982
|
+
*/
|
|
983
|
+
static stopArtifact(id) {
|
|
984
|
+
const session = activeArtifactes.get(id);
|
|
985
|
+
if (!session)
|
|
986
|
+
return false;
|
|
987
|
+
session.process?.kill();
|
|
988
|
+
session.watchers?.forEach(w => w.close());
|
|
989
|
+
activeArtifactes.delete(id);
|
|
990
|
+
return true;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Get visual snapshot for a artifact
|
|
994
|
+
*/
|
|
995
|
+
static getVisualSnapshot(id) {
|
|
996
|
+
const session = activeArtifactes.get(id);
|
|
997
|
+
return session?.visualSnapshot;
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Capture fresh visual snapshot for a running artifact
|
|
1001
|
+
*/
|
|
1002
|
+
static async refreshVisualSnapshot(id) {
|
|
1003
|
+
const session = activeArtifactes.get(id);
|
|
1004
|
+
if (!session || !session.url)
|
|
1005
|
+
return null;
|
|
1006
|
+
try {
|
|
1007
|
+
await visualBridge.initialize();
|
|
1008
|
+
session.visualSnapshot = await visualBridge.captureSnapshot(session.url);
|
|
1009
|
+
return session.visualSnapshot;
|
|
1010
|
+
}
|
|
1011
|
+
catch (error) {
|
|
1012
|
+
console.error(`Failed to refresh visual snapshot: ${error}`);
|
|
1013
|
+
return null;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
// ===== BACKWARDS COMPATIBILITY ALIASES (for sandbox tools) =====
|
|
1017
|
+
/**
|
|
1018
|
+
* @deprecated Use getActiveArtifact instead
|
|
1019
|
+
*/
|
|
1020
|
+
static getActiveSandbox(id) {
|
|
1021
|
+
return this.getActiveArtifact(id);
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* @deprecated Use listActiveArtifactes instead
|
|
1025
|
+
*/
|
|
1026
|
+
static getActiveSandboxes() {
|
|
1027
|
+
return this.listActiveArtifactes();
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* @deprecated Use listActiveArtifactes instead
|
|
1031
|
+
*/
|
|
1032
|
+
static listActiveSandboxes() {
|
|
1033
|
+
return this.listActiveArtifactes();
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* @deprecated Use stopArtifact instead
|
|
1037
|
+
*/
|
|
1038
|
+
static stopSandbox(id) {
|
|
1039
|
+
return this.stopArtifact(id);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
//# sourceMappingURL=CreateArtifactTool.js.map
|