dulus 0.2.52__tar.gz → 0.2.53__tar.gz
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.
- {dulus-0.2.52/dulus.egg-info → dulus-0.2.53}/PKG-INFO +1 -1
- {dulus-0.2.52 → dulus-0.2.53/dulus.egg-info}/PKG-INFO +1 -1
- {dulus-0.2.52 → dulus-0.2.53}/dulus.py +92 -21
- {dulus-0.2.52 → dulus-0.2.53}/pyproject.toml +1 -1
- {dulus-0.2.52 → dulus-0.2.53}/skill/clawhub.py +89 -1
- {dulus-0.2.52 → dulus-0.2.53}/LICENSE +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/MANIFEST.in +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/README.md +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/agent.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/agents_bridge.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/compressor.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/context.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/githook.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/marketplace.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/mempalace_bridge.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/personas.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/plugins.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/server.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/backend/tasks.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/batch_api.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/checkpoint/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/checkpoint/hooks.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/checkpoint/store.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/checkpoint/types.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/claude_code_watcher.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/clipboard_utils.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/cloudsave.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/common.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/compaction.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/config.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/context.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/active_persona.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/context.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/marketplace.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/personas.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/plugins/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/plugins/composio/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/plugins/composio/composio_plugin/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/plugins/composio/plugin.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/plugins/composio/plugin_tool.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/data/tasks.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/README.md +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/api.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/architecture.md +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/azure-speech-template.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/dashboard/index.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/divider.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/generate.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/hero.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/index.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/news.md +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/nvidia-models.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/particle-playground.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/personas/index.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/poetry-banner.png +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/preview.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-agents.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-brainstorm.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-bridges.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-features.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-freetier.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-memory.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-models.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-perms.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-plugins.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-quickstart.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/sec-ssj.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/spinners.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/split-pane.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/terminal-boot.svg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/docs/uploads/particle-playground.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus.egg-info/SOURCES.txt +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus.egg-info/dependency_links.txt +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus.egg-info/entry_points.txt +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus.egg-info/requires.txt +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus.egg-info/top_level.txt +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus_gui.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus_mcp/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus_mcp/client.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus_mcp/config.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus_mcp/tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/dulus_mcp/types.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/agent_bridge.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/chat_widget.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/main_window.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/personas.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/session_utils.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/settings_dialog.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/sidebar.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/tasks_view.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/themes.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/gui/tool_panel.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/input.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/license_manager.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/audit.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/consolidator.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/context.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/offload.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/palace.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/scan.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/sessions.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/store.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/types.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/memory/vector_search.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/multi_agent/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/multi_agent/subagent.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/multi_agent/tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/offload_helper.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/plugin/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/plugin/autoadapter.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/plugin/loader.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/plugin/recommend.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/plugin/store.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/plugin/types.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/providers.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/README.md +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/components.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/index.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/wallpaper-default.jpg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/wallpapers/default.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/wallpapers/light.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/wallpapers/nature.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/dist/wallpapers/tech.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/eslint.config.js +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/index.html +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/info.md +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/package-lock.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/package.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/postcss.config.js +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/public/wallpaper-default.jpg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/public/wallpapers/default.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/public/wallpapers/light.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/public/wallpapers/nature.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/public/wallpapers/tech.jpeg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/App.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/AgentMonitor.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/ApiTester.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/AppRouter.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/ArchiveManager.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/AsciiArt.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Base64Tool.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Browser.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Calculator.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Calendar.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Chat.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Chess.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Clock.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/CodeEditor.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/ColorPalette.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/ColorPicker.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Contacts.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/DocumentViewer.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Drawing.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Email.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/FileManager.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/FlappyBird.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/FtpClient.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Game2048.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/GitClient.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/ImageGallery.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/ImageViewer.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/JsonFormatter.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/MarkdownPreview.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/MatrixRain.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/MediaConverter.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Memory.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/MemoryManager.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Minesweeper.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/MusicPlayer.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/NetworkTools.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Notes.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/PasswordManager.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/PhotoEditor.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Pong.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/RegexTester.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Reminders.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/RssReader.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/ScreenRecorder.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Settings.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/SkillsLauncher.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Snake.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Solitaire.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Spreadsheet.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Sudoku.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/SystemMonitor.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/TaskManager.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Terminal.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Tetris.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/TextEditor.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/TicTacToe.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Todo.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/VideoPlayer.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/VoiceRecorder.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Weather.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/Whiteboard.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/apps/registry.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/AppContainer.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/AppLauncher.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/BootSequence.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ContextMenu.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/Desktop.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/Dock.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/LoginScreen.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/NotImplemented.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/NotificationCenter.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/NotificationSystem.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/TopPanel.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/WindowFrame.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/WindowManager.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/accordion.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/alert-dialog.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/alert.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/aspect-ratio.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/avatar.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/badge.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/breadcrumb.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/button-group.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/button.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/calendar.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/card.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/carousel.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/chart.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/checkbox.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/collapsible.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/command.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/context-menu.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/dialog.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/drawer.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/dropdown-menu.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/empty.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/field.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/form.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/hover-card.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/input-group.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/input-otp.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/input.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/item.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/kbd.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/label.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/menubar.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/navigation-menu.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/pagination.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/popover.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/progress.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/radio-group.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/resizable.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/scroll-area.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/select.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/separator.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/sheet.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/sidebar.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/skeleton.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/slider.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/sonner.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/spinner.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/switch.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/table.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/tabs.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/textarea.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/toggle-group.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/toggle.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/components/ui/tooltip.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/index.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/use-mobile.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useAutoOpenChat.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useDulusAgents.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useDulusChat.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useDulusEvents.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useDulusHealth.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useDulusMemory.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useDulusSkills.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useDulusTasks.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useFileSystem.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useOSStore.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useSkillBridge.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useSystemBattery.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useSystemNetwork.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/hooks/useSystemVolume.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/index.css +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/lib/dulus-api.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/lib/utils.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/main.tsx +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/types/index.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/src/utils/assets.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/tailwind.config.js +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/tsconfig.app.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/tsconfig.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/tsconfig.node.json +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/sandbox/vite.config.ts +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/setup.cfg +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/skill/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/skill/builtin.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/skill/executor.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/skill/loader.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/skill/tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/skills.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/spinner.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/string_utils.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/subagent.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/task/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/task/store.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/task/tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/task/types.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_afk_yolo.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_approval_runtime.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_background_task_tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_background_tasks.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_checkpoint.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_clipboard_utils.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_compaction.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_diff_view.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_diff_visualization.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_display_blocks.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_export_import.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_hook_engine.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_injection_fix.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_license.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_mcp.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_memory.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_notification_manager.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_plugin.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_session_fork.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_shell_mode.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_skills.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_steer_input.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_subagent.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_task.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_telegram_buffer.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_think_tool.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_todo_tool.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_todo_visualization.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_tool_registry.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_voice.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tests/test_wire_events.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tmux_offloader.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tmux_tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tool_registry.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/tools.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/ui/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/ui/input.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/ui/render.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/voice/__init__.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/voice/keyterms.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/voice/recorder.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/voice/stt.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/voice/tts.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/webchat.py +0 -0
- {dulus-0.2.52 → dulus-0.2.53}/webchat_server.py +0 -0
|
@@ -4326,6 +4326,7 @@ def cmd_skill(args: str, state, config) -> bool:
|
|
|
4326
4326
|
list_local, list_installed, install_local, install_clawhub,
|
|
4327
4327
|
search_clawhub, read_skill,
|
|
4328
4328
|
list_awesome_remote, list_composio_toolkits,
|
|
4329
|
+
install_awesome_remote,
|
|
4329
4330
|
)
|
|
4330
4331
|
from pathlib import Path as _Path
|
|
4331
4332
|
|
|
@@ -4371,17 +4372,16 @@ def cmd_skill(args: str, state, config) -> bool:
|
|
|
4371
4372
|
|
|
4372
4373
|
if rest.startswith("awesome"):
|
|
4373
4374
|
query = rest[7:].strip()
|
|
4374
|
-
# `--
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
info("Fetching awesome skills + descriptions from GitHub (parallel, ~5s)...")
|
|
4375
|
+
# `--fast` skips descriptions for an instant list; default pulls them in parallel.
|
|
4376
|
+
fast = False
|
|
4377
|
+
if "--fast" in query.split():
|
|
4378
|
+
fast = True
|
|
4379
|
+
query = " ".join(t for t in query.split() if t != "--fast").strip()
|
|
4380
|
+
if fast:
|
|
4381
|
+
info("Fetching awesome skill list from GitHub (instant, no descriptions)...")
|
|
4382
4382
|
else:
|
|
4383
|
-
info("Fetching awesome
|
|
4384
|
-
skills = list_awesome_remote(query, with_descriptions=
|
|
4383
|
+
info("Fetching awesome skills + descriptions from GitHub (parallel, ~5s)...")
|
|
4384
|
+
skills = list_awesome_remote(query, with_descriptions=not fast)
|
|
4385
4385
|
if not skills:
|
|
4386
4386
|
err("Could not fetch awesome skills (network or rate-limit).")
|
|
4387
4387
|
return True
|
|
@@ -4390,7 +4390,7 @@ def cmd_skill(args: str, state, config) -> bool:
|
|
|
4390
4390
|
for s in skills
|
|
4391
4391
|
]
|
|
4392
4392
|
header = f"Awesome skills ({len(skills)})" + (f" matching '{query}'" if query else "")
|
|
4393
|
-
hint = "" if
|
|
4393
|
+
hint = "" if not fast else " — remove `--fast` for descriptions"
|
|
4394
4394
|
_pager(f"{header}{hint} — n=next q=quit", lines)
|
|
4395
4395
|
return True
|
|
4396
4396
|
|
|
@@ -4455,6 +4455,21 @@ def cmd_skill(args: str, state, config) -> bool:
|
|
|
4455
4455
|
print(f" {clr(r['slug'], 'cyan'):30s} {r.get('description','')[:60]}")
|
|
4456
4456
|
return True
|
|
4457
4457
|
|
|
4458
|
+
if rest.startswith("installed"):
|
|
4459
|
+
query = rest[9:].strip()
|
|
4460
|
+
skills = list_installed(query)
|
|
4461
|
+
if not skills:
|
|
4462
|
+
if query:
|
|
4463
|
+
info(f"No installed skills matching '{query}'.")
|
|
4464
|
+
else:
|
|
4465
|
+
info("No skills installed yet.")
|
|
4466
|
+
return True
|
|
4467
|
+
header = f"Installed skills ({len(skills)})" + (f" matching '{query}'" if query else "")
|
|
4468
|
+
info(header + ":")
|
|
4469
|
+
for s in skills:
|
|
4470
|
+
print(f" • {clr(s['name'], 'cyan'):22s} [{s['source']}] {s['description']}")
|
|
4471
|
+
return True
|
|
4472
|
+
|
|
4458
4473
|
# /skill info <name>
|
|
4459
4474
|
if subcmd == "info":
|
|
4460
4475
|
if not rest:
|
|
@@ -4494,27 +4509,83 @@ def cmd_skill(args: str, state, config) -> bool:
|
|
|
4494
4509
|
if rest.startswith("clawhub:"):
|
|
4495
4510
|
slug = rest[8:]
|
|
4496
4511
|
success, msg = install_clawhub(slug)
|
|
4512
|
+
elif rest.startswith("awesome/"):
|
|
4513
|
+
success, msg = install_awesome_remote(rest)
|
|
4497
4514
|
else:
|
|
4498
4515
|
success, msg = install_local(rest)
|
|
4516
|
+
# Fallback to awesome-remote if not found locally
|
|
4517
|
+
if not success:
|
|
4518
|
+
success, msg = install_awesome_remote(rest)
|
|
4499
4519
|
(ok if success else err)(msg)
|
|
4500
4520
|
return True
|
|
4501
4521
|
|
|
4502
4522
|
# ── /skill use ─────────────────────────────────────────────────────────
|
|
4503
4523
|
if subcmd == "use":
|
|
4524
|
+
from skill.clawhub import DULUS_SKILLS_DIR
|
|
4525
|
+
installed = list_installed()
|
|
4526
|
+
if not installed:
|
|
4527
|
+
err("No skills installed yet. Run /skill list to browse and install skills.")
|
|
4528
|
+
return True
|
|
4529
|
+
|
|
4530
|
+
# Interactive picker when no target is given
|
|
4504
4531
|
if not rest:
|
|
4505
|
-
|
|
4532
|
+
print(clr(" Select skill(s) to inject (active for this turn):", "cyan", "bold"))
|
|
4533
|
+
menu_buf = clr(" Select skill(s) to inject:", "cyan", "bold")
|
|
4534
|
+
for i, s in enumerate(installed):
|
|
4535
|
+
line = f" {clr(f'[{i+1:2d}]', 'yellow')} {clr(s['name'], 'white', 'bold'):<24} [{clr(s['source'], 'dim')}] {s['description'][:55]}"
|
|
4536
|
+
print(line)
|
|
4537
|
+
menu_buf += "\n" + line
|
|
4538
|
+
print()
|
|
4539
|
+
ans = ask_input_interactive(
|
|
4540
|
+
clr(" Enter number(s) (e.g. 1 or 1,2,3), name, or Enter to cancel > ", "cyan"),
|
|
4541
|
+
config, menu_buf,
|
|
4542
|
+
).strip()
|
|
4543
|
+
if not ans:
|
|
4544
|
+
info(" Cancelled.")
|
|
4545
|
+
return True
|
|
4546
|
+
rest = ans
|
|
4547
|
+
|
|
4548
|
+
# Resolve rest → list of skill names
|
|
4549
|
+
selected_names: list[str] = []
|
|
4550
|
+
tokens = [t.strip() for t in rest.replace(",", " ").split() if t.strip()]
|
|
4551
|
+
for tok in tokens:
|
|
4552
|
+
if tok.isdigit():
|
|
4553
|
+
idx = int(tok) - 1
|
|
4554
|
+
if 0 <= idx < len(installed):
|
|
4555
|
+
selected_names.append(installed[idx]["name"])
|
|
4556
|
+
else:
|
|
4557
|
+
warn(f"Index {tok} out of range (1-{len(installed)}). Skipping.")
|
|
4558
|
+
else:
|
|
4559
|
+
match = next((s["name"] for s in installed if s["name"].lower() == tok.lower()), None)
|
|
4560
|
+
if match is None:
|
|
4561
|
+
warn(f"No skill named '{tok}'. Skipping.")
|
|
4562
|
+
else:
|
|
4563
|
+
selected_names.append(match)
|
|
4564
|
+
|
|
4565
|
+
if not selected_names:
|
|
4566
|
+
err("No valid skill selected.")
|
|
4506
4567
|
return True
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4568
|
+
|
|
4569
|
+
# Inject selected skills into context
|
|
4570
|
+
blocks = []
|
|
4571
|
+
for name in selected_names:
|
|
4572
|
+
body = read_skill(name)
|
|
4573
|
+
if not body:
|
|
4574
|
+
warn(f"Skill '{name}' could not be read. Skipping.")
|
|
4575
|
+
continue
|
|
4576
|
+
skill_dir = DULUS_SKILLS_DIR / name
|
|
4577
|
+
path_hint = f"\n\n# NOTE: Skill '{name}' files are located at: {skill_dir}" if skill_dir.exists() else ""
|
|
4578
|
+
blocks.append(f"## Skill: {name}\n\n{body}{path_hint}")
|
|
4579
|
+
|
|
4580
|
+
if not blocks:
|
|
4581
|
+
err("No skills could be injected.")
|
|
4511
4582
|
return True
|
|
4512
|
-
|
|
4513
|
-
skill_dir = DULUS_SKILLS_DIR / rest
|
|
4514
|
-
path_hint = f"\n\n# NOTE: Skill '{rest}' files are located at: {skill_dir}" if skill_dir.exists() else ""
|
|
4583
|
+
|
|
4515
4584
|
existing = config.get("_skill_inject", "")
|
|
4516
|
-
|
|
4517
|
-
|
|
4585
|
+
new_inject = "\n\n---\n\n".join(blocks)
|
|
4586
|
+
config["_skill_inject"] = (existing + "\n\n" + new_inject).strip() if existing else new_inject
|
|
4587
|
+
names_txt = ", ".join(f"'{n}'" for n in selected_names)
|
|
4588
|
+
ok(f"Injected {len(blocks)} skill(s) — active for this turn: {names_txt}")
|
|
4518
4589
|
return True
|
|
4519
4590
|
|
|
4520
4591
|
# ── /skill remove ──────────────────────────────────────────────────────
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dulus"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.53"
|
|
8
8
|
description = "Spanish-first multi-provider AI CLI — 14 NVIDIA models free, Mesa Redonda, voice, TTS, RTK token reducer, MemPalace"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -198,10 +198,14 @@ def _fetch_awesome_remote(with_descriptions: bool = False) -> list[dict]:
|
|
|
198
198
|
if not path.endswith("/SKILL.md"):
|
|
199
199
|
continue
|
|
200
200
|
parts = path.split("/")
|
|
201
|
-
|
|
201
|
+
# Skip actual hidden scaffolding (.git, .github, .gitignore) but keep .gemini/skills/
|
|
202
|
+
if any(p in (".git", ".github", ".gitignore", ".gitattributes") for p in parts):
|
|
202
203
|
continue
|
|
203
204
|
if _AWESOME_EXCLUDE_REMOTE.intersection(parts):
|
|
204
205
|
continue
|
|
206
|
+
# Skip non-skill scaffold folders that happen to contain SKILL.md
|
|
207
|
+
if any(p.upper() in ("README", "TEMPLATE") for p in parts):
|
|
208
|
+
continue
|
|
205
209
|
skill_paths.append(path)
|
|
206
210
|
|
|
207
211
|
# Build the skill list from paths alone — instant, no per-file fetch.
|
|
@@ -287,6 +291,90 @@ def list_awesome_remote(query: Optional[str] = None, force_refresh: bool = False
|
|
|
287
291
|
return skills
|
|
288
292
|
|
|
289
293
|
|
|
294
|
+
def get_awesome_remote(slug: str) -> Optional[dict]:
|
|
295
|
+
"""Find an awesome-remote skill by its id (awesome/<dir>/<skill>) or skill name."""
|
|
296
|
+
for s in list_awesome_remote():
|
|
297
|
+
if s.get("id") == slug or s.get("skill") == slug:
|
|
298
|
+
return s
|
|
299
|
+
return None
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def install_awesome_remote(slug: str) -> tuple[bool, str]:
|
|
303
|
+
"""Download a skill from the awesome GitHub repo and install into ~/.dulus/skills/."""
|
|
304
|
+
import shutil
|
|
305
|
+
import urllib.request
|
|
306
|
+
|
|
307
|
+
entry = get_awesome_remote(slug)
|
|
308
|
+
if entry:
|
|
309
|
+
rel_dir = entry.get("_remote_dir", "")
|
|
310
|
+
skill_name = entry["skill"]
|
|
311
|
+
else:
|
|
312
|
+
# Derive from slug: awesome/<dir>/<skill> or <dir>/<skill>
|
|
313
|
+
parts = slug.replace("awesome/", "").strip("/").split("/")
|
|
314
|
+
if len(parts) < 1:
|
|
315
|
+
return False, f"Invalid awesome slug: '{slug}'. Expected awesome/<category>/<skill> or <category>/<skill>."
|
|
316
|
+
skill_name = parts[-1]
|
|
317
|
+
rel_dir = "/".join(parts)
|
|
318
|
+
|
|
319
|
+
dest_dir = DULUS_SKILLS_DIR / skill_name
|
|
320
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
321
|
+
|
|
322
|
+
# Try to discover sibling files via GitHub tree API for this directory.
|
|
323
|
+
tree_url = (
|
|
324
|
+
f"https://api.github.com/repos/{_AWESOME_REPO}/git/trees/"
|
|
325
|
+
f"{_AWESOME_BRANCH}?recursive=1"
|
|
326
|
+
)
|
|
327
|
+
sibling_paths: list[str] = []
|
|
328
|
+
try:
|
|
329
|
+
with urllib.request.urlopen(tree_url, timeout=15) as resp:
|
|
330
|
+
tree = json.loads(resp.read())
|
|
331
|
+
prefix = rel_dir.rstrip("/") + "/"
|
|
332
|
+
for item in tree.get("tree", []):
|
|
333
|
+
p = item.get("path", "")
|
|
334
|
+
if p.startswith(prefix) and item.get("type") == "blob":
|
|
335
|
+
sibling_paths.append(p)
|
|
336
|
+
except Exception:
|
|
337
|
+
sibling_paths = []
|
|
338
|
+
|
|
339
|
+
# If tree API failed or returned nothing, fall back to just SKILL.md
|
|
340
|
+
if not sibling_paths:
|
|
341
|
+
sibling_paths = [f"{rel_dir}/SKILL.md"]
|
|
342
|
+
|
|
343
|
+
raw_base = f"https://raw.githubusercontent.com/{_AWESOME_REPO}/{_AWESOME_BRANCH}"
|
|
344
|
+
downloaded = []
|
|
345
|
+
for p in sibling_paths:
|
|
346
|
+
url = f"{raw_base}/{p}"
|
|
347
|
+
rel = p[len(prefix):] if p.startswith(prefix) else p.split("/")[-1]
|
|
348
|
+
dst = dest_dir / rel
|
|
349
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
350
|
+
try:
|
|
351
|
+
with urllib.request.urlopen(url, timeout=15) as r:
|
|
352
|
+
data = r.read()
|
|
353
|
+
dst.write_bytes(data)
|
|
354
|
+
downloaded.append(rel)
|
|
355
|
+
except Exception:
|
|
356
|
+
pass # skip files we can't fetch
|
|
357
|
+
|
|
358
|
+
skill_md = dest_dir / "SKILL.md"
|
|
359
|
+
if not skill_md.exists():
|
|
360
|
+
return False, f"Could not download SKILL.md for '{skill_name}' from awesome repo."
|
|
361
|
+
|
|
362
|
+
# Rewrite SKILL.md frontmatter for Dulus
|
|
363
|
+
raw = skill_md.read_text(encoding="utf-8")
|
|
364
|
+
body = _strip_frontmatter(raw)
|
|
365
|
+
frontmatter = (
|
|
366
|
+
f"---\n"
|
|
367
|
+
f"name: {skill_name}\n"
|
|
368
|
+
f"description: {(entry or {}).get('description', '')}\n"
|
|
369
|
+
f"source: awesome-remote\n"
|
|
370
|
+
f"triggers: [/{skill_name}]\n"
|
|
371
|
+
f"---\n\n"
|
|
372
|
+
)
|
|
373
|
+
skill_md.write_text(frontmatter + body, encoding="utf-8")
|
|
374
|
+
|
|
375
|
+
return True, f"Installed '{skill_name}' → {dest_dir} ({len(downloaded)} files: {', '.join(downloaded[:5])}{'...' if len(downloaded)>5 else ''})"
|
|
376
|
+
|
|
377
|
+
|
|
290
378
|
# ── COMPOSIO (live API listing of toolkits) ───────────────────────────────
|
|
291
379
|
# The composio backend exposes a public toolkit list — we surface it as
|
|
292
380
|
# pseudo-skills so users can browse `gmail`, `slack`, etc. and create a
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|