dulus 3.14.0__tar.gz → 3.14.2__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-3.14.0/dulus.egg-info → dulus-3.14.2}/PKG-INFO +7 -1
- {dulus-3.14.0 → dulus-3.14.2}/docs/news.md +3 -1
- {dulus-3.14.0 → dulus-3.14.2/dulus.egg-info}/PKG-INFO +7 -1
- {dulus-3.14.0 → dulus-3.14.2}/dulus.egg-info/requires.txt +6 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus.py +44 -37
- {dulus-3.14.0 → dulus-3.14.2}/providers.py +249 -0
- {dulus-3.14.0 → dulus-3.14.2}/pyproject.toml +21 -1
- {dulus-3.14.0 → dulus-3.14.2}/LICENSE +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/MANIFEST.in +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/README.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/agent.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/algolia_search.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/analytics.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/agents_bridge.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/compressor.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/context.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/githook.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/marketplace.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/mempalace_bridge.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/paths.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/personas.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/plugins.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/server.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/backend/tasks.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/banners/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/banners/banner_rotator.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/banners/banners_dulus_ai.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/batch_api.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/checkpoint/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/checkpoint/hooks.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/checkpoint/store.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/checkpoint/types.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/__main__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/ansi.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/assets/ascii/dulus_logo.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/assets/ascii/eagle.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/assets/ascii/terminal_art.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/banners.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/demo.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/effects.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/effort_slider.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/progress.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/py.typed +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/spinners.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cli_animations/status.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/clipboard_utils.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/cloudsave.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/common.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/compaction.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/config.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/context.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/active_persona.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/marketplace.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/personas.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/plugins/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/plugins/composio/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/plugins/composio/composio_plugin/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/plugins/composio/plugin.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/plugins/composio/plugin_tool.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/data/tasks.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/display_blocks.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/API.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/BRAND_GUIDE.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/CHANGELOG.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/CONTRIBUTING.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/DEPLOYMENT.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/FAQ.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/GETTING_STARTED.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_AR.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_EN.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_ES.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_FR.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_JA.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_KO.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_PT.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_RU.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/README_ZH.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/SECURITY.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/api.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/architecture.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/azure-speech-template.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/dashboard/index.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/divider.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/dulus-bird.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/generate.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/index.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/nvidia-models.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/particle-playground.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/personas/index.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/poetry-banner.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/preview.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/python-console.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/auto-adapter.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/dulus-os.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/hero.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/lookback_two_windows.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/pyc_heap.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/pyc_receipts.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/pyc_trap.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/roundtable.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/task-board.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/readme/webchat.png +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-agents.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-brainstorm.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-bridges.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-features.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-freetier.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-memory.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-models.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-perms.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-plugins.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-quickstart.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/sec-ssj.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/spinners.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/split-pane.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/terminal-boot.svg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/docs/termux-edge.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus.egg-info/SOURCES.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus.egg-info/dependency_links.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus.egg-info/entry_points.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus.egg-info/top_level.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_account.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_bar_client.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_gui.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_mcp/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_mcp/client.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_mcp/commands.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_mcp/config.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_mcp/hub.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_mcp/tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_mcp/types.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_quick_menu.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/add_dir_manager.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/afk_mode.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/approval_runtime.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/background_tasks.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/clipboard_utils.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/diff_visualizer.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/export_import.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/hook_engine.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/isolate.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/notification_manager.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/session_fork.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/shell_mode.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/todo_visualizer.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/tree_ls.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/wire_events.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/dulus_tools/yolo_mode.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/file_filter.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/fs_compass.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/governance.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/agent_bridge.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/chat_widget.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/main_window.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/personas.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/sandbox_server.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/session_utils.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/settings_dialog.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/sidebar.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/tasks_view.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/themes.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/gui/tool_panel.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/input.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/license_manager.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/lookback.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/audit.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/consolidator.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/context.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/mempalace_bridge.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/offload.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/palace.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/scan.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/adaptation_guides.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/askuserquestion_after_numbered_list.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/background_jobs_no_extra_timers.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/cleverness_over_resources.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/corporate_tls_breaks_curl_cffi.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/hardened_rules.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/investigator_workflow_heuristic.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/native_code_over_sketchy_plugins.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/no_personal_info_in_code.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/searches_include_modified_date.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/tmux_send_keys_power_patterns.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/token_optimization_technique.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/tool_chaining_capability.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/insights/webbridge_evaluate_first_pattern.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/seeds/short_memory.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/sessions.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/store.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/types.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/memory/vector_search.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/model_params.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/multi_agent/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/multi_agent/subagent.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/multi_agent/tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/paste_placeholders.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/personality_config.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/plugin/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/plugin/autoadapter.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/plugin/loader.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/plugin/recommend.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/plugin/store.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/plugin/types.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/profiles.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/pyconsole.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/README.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/index.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/wallpaper-default.jpg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/wallpapers/default.jpeg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/wallpapers/light.jpeg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/wallpapers/nature.jpeg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/dist/wallpapers/tech.jpeg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox/info.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/sandbox_bootstrap.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/setup.cfg +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/builtin.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/LICENSE-obsidian-skills +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/README.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/defuddle/SKILL.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/json-canvas/SKILL.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/json-canvas/references/EXAMPLES.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/obsidian-bases/SKILL.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/obsidian-cli/SKILL.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/obsidian-markdown/SKILL.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/obsidian-markdown/references/CALLOUTS.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/obsidian-markdown/references/EMBEDS.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/obsidian-markdown/references/PROPERTIES.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/README.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/SKILL.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/addresses.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/advancedbackgroundchecks.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/beenverified.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/clustal.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/clustrmaps.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/cyberbackgroundchecks.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/familytreenow.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/fastpeoplesearch.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/intelius.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/mylife.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/nuwber.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/peekyou.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/peoplefinders.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/radaris.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/rehold.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/searchpeoplefree.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/socialcatfish.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/spokeo.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/thatsthem.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/truepeoplesearch.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/usphonebook.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/brokers/whitepages.json +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/legal/ccpa.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/legal/drop.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/legal/gdpr.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/methods.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/site-playbooks.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/references/state-machine.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/autopilot.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/badbool.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/brokers.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/cdp.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/config.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/crypto.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/dossier.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/email_modes.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/emailer.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/ledger.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/legal.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/paths.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/pdd.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/registry.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/report.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/scan.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/storage.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/tiers.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/scripts/vectors.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/templates/consent/authorization.md +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/templates/emails/ccpa-authorized-agent.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/templates/emails/ccpa-deletion.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/templates/emails/ccpa-indirect-deletion.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/templates/emails/gdpr-erasure.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/bundled/unbroker/templates/emails/generic-optout.txt +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/clawhub.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/executor.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/loader.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skill/tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/skills.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/soul.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/spinner.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/steer_input.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/subagent.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/task/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/task/store.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/task/tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/task/types.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_afk_yolo.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_approval_runtime.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_background_task_tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_background_tasks.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_chatgpt_oauth.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_checkpoint.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_cli_animations_integration.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_clipboard_utils.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_compaction.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_composio_tool_generator.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_diff_view.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_diff_visualization.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_display_blocks.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_dulus_account.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_export_import.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_gold_memory_preload.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_grok_usage.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_hook_engine.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_injection_fix.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_json_protocol.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_license.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_lookback_cache.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_lookback_compact.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_mcp.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_mcp_algolia.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_memory.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_memory_home_resolution.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_notification_manager.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_plugin.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_profile_isolation.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_profile_plugin_scope.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_provider_errors.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_session_fork.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_shell_detection.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_shell_mode.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_skills.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_skillssh_algolia.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_steer_input.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_subagent.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_task.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_telegram_buffer.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_think_tool.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_todo_tool.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_todo_visualization.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_tool_registry.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_tree_ls.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_voice.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_webbridge_tabs.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tests/test_wire_events.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tmux_tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/token_budget.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tool_registry.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tools_background.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tools_think.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/tools_todo.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/ui/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/ui/input.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/ui/render.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/updater.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/voice/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/voice/audio_utils.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/voice/keyterms.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/voice/recorder.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/voice/stt.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/voice/tts.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/voice/wake_word.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webbridge/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webbridge/core.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webbridge/tools.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webchat.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webchat_server.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webchat_ui/__init__.py +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webchat_ui/app.js +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webchat_ui/index.html +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/webchat_ui/style.css +0 -0
- {dulus-3.14.0 → dulus-3.14.2}/welcome.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.14.
|
|
3
|
+
Version: 3.14.2
|
|
4
4
|
Summary: Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS.
|
|
5
5
|
Author-email: KevRojo <dev@dulus.ai>
|
|
6
6
|
Maintainer-email: KevRojo <dev@dulus.ai>
|
|
@@ -65,6 +65,12 @@ Requires-Dist: mcp>=1.0.0
|
|
|
65
65
|
Requires-Dist: uv>=0.4.0
|
|
66
66
|
Requires-Dist: sse-starlette>=2.0.0
|
|
67
67
|
Requires-Dist: starlette>=0.38.0
|
|
68
|
+
Requires-Dist: posthog>=3.0.0
|
|
69
|
+
Requires-Dist: mempalace>=3.3.4
|
|
70
|
+
Requires-Dist: sounddevice
|
|
71
|
+
Requires-Dist: elevenlabs>=1.0.0
|
|
72
|
+
Requires-Dist: playwright>=1.40.0
|
|
73
|
+
Requires-Dist: litellm>=1.50.0
|
|
68
74
|
Provides-Extra: dev
|
|
69
75
|
Requires-Dist: build>=1.2; extra == "dev"
|
|
70
76
|
Requires-Dist: pyright>=1.1.400; extra == "dev"
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## 🔥🔥🔥 News (Pacific Time)
|
|
4
4
|
|
|
5
|
-
- September 2, 2026 (**
|
|
5
|
+
- September 2, 2026 (**v3.14.1**): **🌐 Web-harvest browser fix.** `/harvest-gemini` (and claude/kimi/qwen/deepseek) no longer launch without a browser after the first run. The installer used to key off the *pip package*, so once the wizard installed it, later harvests skipped the *browser* download entirely — leaving you with a package but no Chromium. Now a single idempotent guard ensures both the package and the browser are present every time. `pip install -U dulus`. 🦅
|
|
6
|
+
|
|
7
|
+
- September 3, 2026 (**v3.14.2**): **📦 One-shot install — everything's in the box now.** No more `dulus[full]` archaeology: `pip install dulus` now pulls the whole runtime by default — memory palace, voice, browser automation, LiteLLM routing and analytics all come along. Plus a new **Meta AI (Muse Spark)** provider (`meta/muse-spark-1.3`). Same free open runtime, your machine. `pip install -U dulus`. 🦅🇩🇴
|
|
6
8
|
|
|
7
9
|
- September 1, 2026 (**v3.13.9**): **🔒 `/isolate` — workspace bubble, on demand.** Flip `/isolate on` and Write / Edit / NotebookEdit + Bash mutations stay locked to the frozen workspace root (plus anything you added with `/add-dir`). Read-only tools keep flying free. No `/temp` backdoor — pure bubble. Blocked? Dulus tells you straight: write `/isolate off` if you want help outside. `pip install -U dulus`. 🦅
|
|
8
10
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.14.
|
|
3
|
+
Version: 3.14.2
|
|
4
4
|
Summary: Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS.
|
|
5
5
|
Author-email: KevRojo <dev@dulus.ai>
|
|
6
6
|
Maintainer-email: KevRojo <dev@dulus.ai>
|
|
@@ -65,6 +65,12 @@ Requires-Dist: mcp>=1.0.0
|
|
|
65
65
|
Requires-Dist: uv>=0.4.0
|
|
66
66
|
Requires-Dist: sse-starlette>=2.0.0
|
|
67
67
|
Requires-Dist: starlette>=0.38.0
|
|
68
|
+
Requires-Dist: posthog>=3.0.0
|
|
69
|
+
Requires-Dist: mempalace>=3.3.4
|
|
70
|
+
Requires-Dist: sounddevice
|
|
71
|
+
Requires-Dist: elevenlabs>=1.0.0
|
|
72
|
+
Requires-Dist: playwright>=1.40.0
|
|
73
|
+
Requires-Dist: litellm>=1.50.0
|
|
68
74
|
Provides-Extra: dev
|
|
69
75
|
Requires-Dist: build>=1.2; extra == "dev"
|
|
70
76
|
Requires-Dist: pyright>=1.1.400; extra == "dev"
|
|
@@ -396,7 +396,7 @@ try:
|
|
|
396
396
|
from importlib.metadata import version as _pkg_version
|
|
397
397
|
VERSION = _pkg_version("dulus")
|
|
398
398
|
except Exception:
|
|
399
|
-
VERSION = "3.14.
|
|
399
|
+
VERSION = "3.14.2" # dev fallback — keep in sync with pyproject.toml
|
|
400
400
|
|
|
401
401
|
# ── Machine-readable protocol output (`--output json`) ─────────────────────
|
|
402
402
|
# Dulus is increasingly run as a child process by another agent runtime (an
|
|
@@ -3667,14 +3667,8 @@ def cmd_harvest(_args: str, _state, config) -> bool:
|
|
|
3667
3667
|
out_path = pathlib.Path.home() / ".dulus" / "claude_cookies.json"
|
|
3668
3668
|
ok(f"Starting Playwright harvest → {out_path}")
|
|
3669
3669
|
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
except ImportError:
|
|
3673
|
-
import os
|
|
3674
|
-
info("Installing playwright...")
|
|
3675
|
-
__import__("subprocess").run(__import__("common").pip_install_cmd("playwright"))
|
|
3676
|
-
os.system("playwright install chromium")
|
|
3677
|
-
from playwright.sync_api import sync_playwright
|
|
3670
|
+
_ensure_playwright_browser()
|
|
3671
|
+
from playwright.sync_api import sync_playwright
|
|
3678
3672
|
|
|
3679
3673
|
import os, time
|
|
3680
3674
|
from datetime import datetime
|
|
@@ -3813,13 +3807,8 @@ def cmd_harvest_kimi(_args: str, _state, config) -> bool:
|
|
|
3813
3807
|
out_path = pathlib.Path.home() / ".dulus" / "kimi_consumer.json"
|
|
3814
3808
|
ok(f"Starting Kimi Harvester → {out_path}")
|
|
3815
3809
|
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
except ImportError:
|
|
3819
|
-
info("Installing playwright...")
|
|
3820
|
-
__import__("subprocess").run(__import__("common").pip_install_cmd("playwright"))
|
|
3821
|
-
os.system("playwright install chromium")
|
|
3822
|
-
from playwright.sync_api import sync_playwright
|
|
3810
|
+
_ensure_playwright_browser()
|
|
3811
|
+
from playwright.sync_api import sync_playwright
|
|
3823
3812
|
|
|
3824
3813
|
pw_profile = os.path.join(os.path.expanduser("~"), ".dulus", "playwright", "kimi-consumer")
|
|
3825
3814
|
os.makedirs(pw_profile, exist_ok=True)
|
|
@@ -3910,6 +3899,39 @@ def cmd_harvest_kimi(_args: str, _state, config) -> bool:
|
|
|
3910
3899
|
return True
|
|
3911
3900
|
|
|
3912
3901
|
|
|
3902
|
+
def _ensure_playwright_browser():
|
|
3903
|
+
"""Guarantee BOTH the playwright package AND a browser binary are present.
|
|
3904
|
+
|
|
3905
|
+
The old per-harvest snippet only ran the installer inside `except
|
|
3906
|
+
ImportError`, i.e. it keyed off the *pip package* being importable. But
|
|
3907
|
+
the package and the *browser binary* are two separate installs: after the
|
|
3908
|
+
first-run wizard installs the package, a later `/harvest-*` sees the import
|
|
3909
|
+
succeed, skips the whole block, and never (re)installs the browser — so if
|
|
3910
|
+
the Chromium/Chrome download was missing or half-done, the harvest launches
|
|
3911
|
+
with no browser and fails. The welcome only "worked" because it was the
|
|
3912
|
+
first run, where the import genuinely failed and the full install fired.
|
|
3913
|
+
|
|
3914
|
+
Fix: check the import, install the package if needed, and ALWAYS run
|
|
3915
|
+
`playwright install chromium` — it's idempotent (a no-op when the browser
|
|
3916
|
+
is already there, a real download when it isn't), so it's cheap to call
|
|
3917
|
+
every time and closes the package-vs-browser gap for good.
|
|
3918
|
+
"""
|
|
3919
|
+
import os, subprocess, sys as _sys
|
|
3920
|
+
try:
|
|
3921
|
+
from playwright.sync_api import sync_playwright # noqa: F401
|
|
3922
|
+
except ImportError:
|
|
3923
|
+
info("Installing playwright...")
|
|
3924
|
+
subprocess.run(__import__("common").pip_install_cmd("playwright"))
|
|
3925
|
+
# Idempotent: installs the browser only if it's missing. Runs every time so
|
|
3926
|
+
# a present package with an absent/broken browser still gets fixed.
|
|
3927
|
+
try:
|
|
3928
|
+
subprocess.run([_sys.executable, "-m", "playwright", "install", "chromium"],
|
|
3929
|
+
check=False, timeout=600)
|
|
3930
|
+
except Exception:
|
|
3931
|
+
# Fallback to the plain CLI if `-m playwright` isn't on this interpreter.
|
|
3932
|
+
os.system("playwright install chromium")
|
|
3933
|
+
|
|
3934
|
+
|
|
3913
3935
|
def _launch_harvest_browser(p, pw_profile, headless):
|
|
3914
3936
|
"""Launch a persistent browser for harvesting, resilient to a bare box.
|
|
3915
3937
|
|
|
@@ -3985,13 +4007,8 @@ def cmd_harvest_gemini(_args: str, _state, config) -> "bool | None":
|
|
|
3985
4007
|
out_path = pathlib.Path.home() / ".dulus" / "gemini_web.json"
|
|
3986
4008
|
ok(f"Starting Gemini Harvester → {out_path}")
|
|
3987
4009
|
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
except ImportError:
|
|
3991
|
-
info("Installing playwright...")
|
|
3992
|
-
__import__("subprocess").run(__import__("common").pip_install_cmd("playwright"))
|
|
3993
|
-
os.system("playwright install chromium")
|
|
3994
|
-
from playwright.sync_api import sync_playwright
|
|
4010
|
+
_ensure_playwright_browser()
|
|
4011
|
+
from playwright.sync_api import sync_playwright
|
|
3995
4012
|
|
|
3996
4013
|
# Reutiliza el perfil de Gemini para no loguear cada vez
|
|
3997
4014
|
pw_profile = os.path.join(os.path.expanduser("~"), ".dulus", "playwright", "gemini-interceptor")
|
|
@@ -4191,13 +4208,8 @@ def cmd_harvest_deepseek(_args: str, _state, config) -> bool:
|
|
|
4191
4208
|
# Optional: navigate directly to a specific chat session from arg
|
|
4192
4209
|
start_url = _args.strip() if _args.strip().startswith("http") else "https://chat.deepseek.com/"
|
|
4193
4210
|
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
except ImportError:
|
|
4197
|
-
info("Installing playwright...")
|
|
4198
|
-
__import__("subprocess").run(__import__("common").pip_install_cmd("playwright"))
|
|
4199
|
-
os.system("playwright install chromium")
|
|
4200
|
-
from playwright.sync_api import sync_playwright
|
|
4211
|
+
_ensure_playwright_browser()
|
|
4212
|
+
from playwright.sync_api import sync_playwright
|
|
4201
4213
|
|
|
4202
4214
|
pw_profile = os.path.join(os.path.expanduser("~"), ".dulus", "playwright", "deepseek-interceptor")
|
|
4203
4215
|
os.makedirs(pw_profile, exist_ok=True)
|
|
@@ -4340,13 +4352,8 @@ def cmd_harvest_qwen(_args: str, _state, config) -> bool:
|
|
|
4340
4352
|
|
|
4341
4353
|
start_url = _args.strip() if _args.strip().startswith("http") else "https://chat.qwen.ai/"
|
|
4342
4354
|
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
except ImportError:
|
|
4346
|
-
info("Installing playwright...")
|
|
4347
|
-
__import__("subprocess").run(__import__("common").pip_install_cmd("playwright"))
|
|
4348
|
-
os.system("playwright install chromium")
|
|
4349
|
-
from playwright.sync_api import sync_playwright
|
|
4355
|
+
_ensure_playwright_browser()
|
|
4356
|
+
from playwright.sync_api import sync_playwright
|
|
4350
4357
|
|
|
4351
4358
|
pw_profile = os.path.join(os.path.expanduser("~"), ".dulus", "playwright", "qwen-interceptor")
|
|
4352
4359
|
os.makedirs(pw_profile, exist_ok=True)
|
|
@@ -875,6 +875,19 @@ PROVIDERS: dict[str, dict] = {
|
|
|
875
875
|
"fugu-mini", "fugu-ultra",
|
|
876
876
|
],
|
|
877
877
|
},
|
|
878
|
+
# Meta AI (Muse Spark) — Responses-API-style SSE endpoint at api.meta.ai.
|
|
879
|
+
# Key via /config meta_api_key=... or export META_API_KEY.
|
|
880
|
+
# Pick models as 'meta/muse-spark-1.3' (or bare 'muse-spark-1.3').
|
|
881
|
+
"meta": {
|
|
882
|
+
"type": "meta",
|
|
883
|
+
"api_key_env": "META_API_KEY",
|
|
884
|
+
"base_url": "https://api.meta.ai/v1",
|
|
885
|
+
"context_limit": 128000,
|
|
886
|
+
"max_completion_tokens": 32000,
|
|
887
|
+
"models": [
|
|
888
|
+
"muse-spark-1.3", "muse-spark-1.3-contributor",
|
|
889
|
+
],
|
|
890
|
+
},
|
|
878
891
|
}
|
|
879
892
|
|
|
880
893
|
# Cost per million tokens (approximate, fallback to 0 for unknown)
|
|
@@ -934,6 +947,9 @@ _PREFIXES = [
|
|
|
934
947
|
("gpt-5-codex", "chatgpt-oauth"),
|
|
935
948
|
("codex-mini", "chatgpt-oauth"),
|
|
936
949
|
("codex-auto", "chatgpt-oauth"),
|
|
950
|
+
# Meta AI (Muse Spark) — api.meta.ai Responses-style SSE, key via META_API_KEY.
|
|
951
|
+
("meta/", "meta"),
|
|
952
|
+
("muse-", "meta"),
|
|
937
953
|
("claude-", "anthropic"),
|
|
938
954
|
("gpt-", "openai"),
|
|
939
955
|
("o1", "openai"),
|
|
@@ -2842,6 +2858,236 @@ def stream_chatgpt_oauth(
|
|
|
2842
2858
|
cache_read_tokens=cached_tok)
|
|
2843
2859
|
|
|
2844
2860
|
|
|
2861
|
+
# ── Meta AI (Muse Spark) — API key, Responses-API-style SSE ────────────────
|
|
2862
|
+
META_API_BASE_URL = "https://api.meta.ai/v1"
|
|
2863
|
+
|
|
2864
|
+
|
|
2865
|
+
def stream_meta(
|
|
2866
|
+
api_key: str,
|
|
2867
|
+
model: str,
|
|
2868
|
+
system: str,
|
|
2869
|
+
messages: list,
|
|
2870
|
+
tool_schemas: list,
|
|
2871
|
+
config: dict,
|
|
2872
|
+
) -> Generator:
|
|
2873
|
+
"""Meta AI Muse Spark via api.meta.ai/v1/responses (SSE, OpenAI Responses
|
|
2874
|
+
wire format). Key: /config meta_api_key=... or META_API_KEY.
|
|
2875
|
+
Yields TextChunk / ThinkingChunk / AssistantTurn."""
|
|
2876
|
+
import requests as _req
|
|
2877
|
+
|
|
2878
|
+
if not api_key:
|
|
2879
|
+
yield TextChunk(
|
|
2880
|
+
"[meta] No API key. Set one with `/config meta_api_key=...` "
|
|
2881
|
+
"or export META_API_KEY."
|
|
2882
|
+
)
|
|
2883
|
+
yield AssistantTurn(
|
|
2884
|
+
"[meta] No API key. Set META_API_KEY or /config meta_api_key=...",
|
|
2885
|
+
[], 0, 0, error=True,
|
|
2886
|
+
)
|
|
2887
|
+
return
|
|
2888
|
+
|
|
2889
|
+
instructions, input_items = _chatgpt_messages_to_responses_input(system, messages)
|
|
2890
|
+
|
|
2891
|
+
body: dict[str, Any] = {
|
|
2892
|
+
"model": model,
|
|
2893
|
+
"input": input_items,
|
|
2894
|
+
"stream": True,
|
|
2895
|
+
"temperature": 1,
|
|
2896
|
+
"max_output_tokens": 32000,
|
|
2897
|
+
"top_p": 1,
|
|
2898
|
+
}
|
|
2899
|
+
if instructions:
|
|
2900
|
+
body["instructions"] = instructions
|
|
2901
|
+
|
|
2902
|
+
tools = _chatgpt_tools_to_responses(tool_schemas)
|
|
2903
|
+
if tools:
|
|
2904
|
+
body["tools"] = tools
|
|
2905
|
+
if not (config or {}).get("disable_tool_choice"):
|
|
2906
|
+
body["tool_choice"] = "auto"
|
|
2907
|
+
|
|
2908
|
+
base = (PROVIDERS.get("meta", {}).get("base_url") or META_API_BASE_URL).rstrip("/")
|
|
2909
|
+
url = base + "/responses"
|
|
2910
|
+
headers = {
|
|
2911
|
+
"Authorization": f"Bearer {api_key}",
|
|
2912
|
+
"Content-Type": "application/json",
|
|
2913
|
+
"Accept": "text/event-stream",
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
text = ""
|
|
2917
|
+
thinking = ""
|
|
2918
|
+
in_tok = 0
|
|
2919
|
+
out_tok = 0
|
|
2920
|
+
cached_tok = 0
|
|
2921
|
+
tool_buf: dict[str, dict] = {}
|
|
2922
|
+
tool_order: list[str] = []
|
|
2923
|
+
current_call_id: str | None = None
|
|
2924
|
+
stream_interrupted = False
|
|
2925
|
+
resp = None
|
|
2926
|
+
|
|
2927
|
+
def _ensure_tool(call_id: str | None, name: str | None = None) -> str:
|
|
2928
|
+
nonlocal current_call_id
|
|
2929
|
+
cid = call_id or current_call_id or f"call_{len(tool_order)}"
|
|
2930
|
+
if cid not in tool_buf:
|
|
2931
|
+
tool_buf[cid] = {"id": cid, "name": name or "", "args": ""}
|
|
2932
|
+
tool_order.append(cid)
|
|
2933
|
+
elif name and not tool_buf[cid].get("name"):
|
|
2934
|
+
tool_buf[cid]["name"] = name
|
|
2935
|
+
current_call_id = cid
|
|
2936
|
+
return cid
|
|
2937
|
+
|
|
2938
|
+
try:
|
|
2939
|
+
resp = _req.post(url, headers=headers, json=body, stream=True, timeout=300)
|
|
2940
|
+
|
|
2941
|
+
if resp.status_code in (401, 403):
|
|
2942
|
+
body_preview = (resp.text or "")[:300]
|
|
2943
|
+
yield TextChunk(
|
|
2944
|
+
f"[meta] Auth error {resp.status_code}. Check your key: "
|
|
2945
|
+
f"/config meta_api_key=... Detail: {body_preview}"
|
|
2946
|
+
)
|
|
2947
|
+
yield AssistantTurn(
|
|
2948
|
+
f"[meta] Auth error {resp.status_code}. Check meta_api_key.",
|
|
2949
|
+
[], 0, 0, error=True,
|
|
2950
|
+
)
|
|
2951
|
+
return
|
|
2952
|
+
if resp.status_code >= 400:
|
|
2953
|
+
body_preview = (resp.text or "")[:400]
|
|
2954
|
+
yield TextChunk(f"[meta] HTTP {resp.status_code}: {body_preview}")
|
|
2955
|
+
yield AssistantTurn(
|
|
2956
|
+
f"[meta] HTTP {resp.status_code}: {body_preview}",
|
|
2957
|
+
[], 0, 0, error=True,
|
|
2958
|
+
)
|
|
2959
|
+
return
|
|
2960
|
+
|
|
2961
|
+
event_type = ""
|
|
2962
|
+
# NOTE: iterate RAW BYTES (no decode_unicode). requests defaults to
|
|
2963
|
+
# ISO-8859-1 for text/event-stream when the server omits charset, which
|
|
2964
|
+
# mangled UTF-8 accents (á→á, ñ→ñ) in Spanish output. Decoding each
|
|
2965
|
+
# line explicitly as UTF-8 fixes the mojibake.
|
|
2966
|
+
for raw_line in resp.iter_lines():
|
|
2967
|
+
if raw_line is None:
|
|
2968
|
+
continue
|
|
2969
|
+
line = raw_line.decode("utf-8", "replace").strip() if isinstance(raw_line, (bytes, bytearray)) else raw_line.strip()
|
|
2970
|
+
if not line:
|
|
2971
|
+
continue
|
|
2972
|
+
if line.startswith(":"):
|
|
2973
|
+
continue
|
|
2974
|
+
if line.startswith("event:"):
|
|
2975
|
+
event_type = line[6:].strip()
|
|
2976
|
+
continue
|
|
2977
|
+
if not line.startswith("data:"):
|
|
2978
|
+
continue
|
|
2979
|
+
data = line[5:].strip()
|
|
2980
|
+
if data == "[DONE]":
|
|
2981
|
+
break
|
|
2982
|
+
try:
|
|
2983
|
+
event = json.loads(data)
|
|
2984
|
+
except Exception:
|
|
2985
|
+
continue
|
|
2986
|
+
if not isinstance(event, dict):
|
|
2987
|
+
continue
|
|
2988
|
+
et = event.get("type") or event_type or ""
|
|
2989
|
+
|
|
2990
|
+
if et in ("response.output_text.delta", "response.refusal.delta"):
|
|
2991
|
+
delta = event.get("delta") or ""
|
|
2992
|
+
if delta:
|
|
2993
|
+
text += delta
|
|
2994
|
+
yield TextChunk(delta)
|
|
2995
|
+
continue
|
|
2996
|
+
|
|
2997
|
+
if et in (
|
|
2998
|
+
"response.reasoning_summary_text.delta",
|
|
2999
|
+
"response.reasoning_text.delta",
|
|
3000
|
+
):
|
|
3001
|
+
delta = event.get("delta") or ""
|
|
3002
|
+
if delta:
|
|
3003
|
+
thinking += delta
|
|
3004
|
+
yield ThinkingChunk(delta)
|
|
3005
|
+
continue
|
|
3006
|
+
|
|
3007
|
+
if et == "response.output_item.added":
|
|
3008
|
+
item = event.get("item") or {}
|
|
3009
|
+
if isinstance(item, dict) and item.get("type") == "function_call":
|
|
3010
|
+
_ensure_tool(item.get("call_id") or item.get("id"), item.get("name"))
|
|
3011
|
+
continue
|
|
3012
|
+
|
|
3013
|
+
if et == "response.function_call_arguments.delta":
|
|
3014
|
+
cid = event.get("call_id") or current_call_id
|
|
3015
|
+
key = _ensure_tool(cid)
|
|
3016
|
+
delta_args = event.get("delta") or ""
|
|
3017
|
+
if delta_args:
|
|
3018
|
+
tool_buf[key]["args"] += delta_args
|
|
3019
|
+
continue
|
|
3020
|
+
|
|
3021
|
+
if et == "response.function_call_arguments.done":
|
|
3022
|
+
cid = event.get("call_id") or current_call_id
|
|
3023
|
+
key = _ensure_tool(cid)
|
|
3024
|
+
final_args = event.get("arguments")
|
|
3025
|
+
if final_args is not None:
|
|
3026
|
+
tool_buf[key]["args"] = final_args
|
|
3027
|
+
continue
|
|
3028
|
+
|
|
3029
|
+
if et == "response.output_item.done":
|
|
3030
|
+
item = event.get("item") or {}
|
|
3031
|
+
if isinstance(item, dict) and item.get("type") == "function_call":
|
|
3032
|
+
key = _ensure_tool(item.get("call_id") or item.get("id"), item.get("name"))
|
|
3033
|
+
if item.get("name"):
|
|
3034
|
+
tool_buf[key]["name"] = item["name"]
|
|
3035
|
+
if item.get("arguments") is not None:
|
|
3036
|
+
tool_buf[key]["args"] = item["arguments"]
|
|
3037
|
+
if item.get("call_id"):
|
|
3038
|
+
tool_buf[key]["id"] = item["call_id"]
|
|
3039
|
+
continue
|
|
3040
|
+
|
|
3041
|
+
if et in ("response.completed", "response.incomplete"):
|
|
3042
|
+
resp_obj = event.get("response") or {}
|
|
3043
|
+
usage = resp_obj.get("usage") or event.get("usage") or {}
|
|
3044
|
+
if isinstance(usage, dict):
|
|
3045
|
+
in_tok = int(usage.get("input_tokens") or usage.get("prompt_tokens") or in_tok or 0)
|
|
3046
|
+
out_tok = int(usage.get("output_tokens") or usage.get("completion_tokens") or out_tok or 0)
|
|
3047
|
+
_det = usage.get("input_tokens_details") or usage.get("prompt_tokens_details") or {}
|
|
3048
|
+
if isinstance(_det, dict):
|
|
3049
|
+
cached_tok = int(_det.get("cached_tokens") or cached_tok or 0)
|
|
3050
|
+
continue
|
|
3051
|
+
|
|
3052
|
+
if et in ("response.failed", "error"):
|
|
3053
|
+
err = event.get("error") or event.get("response", {}).get("error") or event
|
|
3054
|
+
if isinstance(err, dict):
|
|
3055
|
+
msg = err.get("message") or err.get("code") or json.dumps(err)[:300]
|
|
3056
|
+
else:
|
|
3057
|
+
msg = str(err)[:300]
|
|
3058
|
+
note = f"\n\n_[meta error: {msg}]_"
|
|
3059
|
+
text += note
|
|
3060
|
+
yield TextChunk(note)
|
|
3061
|
+
continue
|
|
3062
|
+
|
|
3063
|
+
except _req.exceptions.ChunkedEncodingError:
|
|
3064
|
+
stream_interrupted = True
|
|
3065
|
+
except _req.exceptions.ConnectionError:
|
|
3066
|
+
stream_interrupted = True
|
|
3067
|
+
except Exception as e:
|
|
3068
|
+
msg = f"[meta] Error: {e}"
|
|
3069
|
+
yield TextChunk(msg)
|
|
3070
|
+
yield AssistantTurn(msg, [], 0, 0, error=True)
|
|
3071
|
+
return
|
|
3072
|
+
finally:
|
|
3073
|
+
if resp is not None:
|
|
3074
|
+
try:
|
|
3075
|
+
resp.close()
|
|
3076
|
+
except Exception:
|
|
3077
|
+
pass
|
|
3078
|
+
|
|
3079
|
+
if stream_interrupted and not tool_buf:
|
|
3080
|
+
note = "\n\n_[meta: el streaming se cortó a media respuesta — esto es parcial, reintenta]_"
|
|
3081
|
+
text += note
|
|
3082
|
+
yield TextChunk(note)
|
|
3083
|
+
|
|
3084
|
+
ordered_buf = {i: tool_buf[k] for i, k in enumerate(tool_order)} if tool_order else tool_buf
|
|
3085
|
+
final_tool_calls = _finalize_tool_calls(ordered_buf)
|
|
3086
|
+
|
|
3087
|
+
yield AssistantTurn(text, final_tool_calls, in_tok, out_tok, thinking=thinking,
|
|
3088
|
+
cache_read_tokens=cached_tok)
|
|
3089
|
+
|
|
3090
|
+
|
|
2845
3091
|
def stream_xai_oauth(
|
|
2846
3092
|
model: str,
|
|
2847
3093
|
system: str,
|
|
@@ -7512,6 +7758,9 @@ def stream(
|
|
|
7512
7758
|
# ChatGPT/Codex subscription OAuth (`/login chatgpt` or ~/.codex/auth.json)
|
|
7513
7759
|
# → chatgpt.com/backend-api/codex/responses (Responses API, not chat/completions)
|
|
7514
7760
|
yield from stream_chatgpt_oauth(model_name, system, messages, tool_schemas, config)
|
|
7761
|
+
elif prov["type"] == "meta":
|
|
7762
|
+
# Meta AI (Muse Spark) via api.meta.ai/v1/responses — API key (META_API_KEY).
|
|
7763
|
+
yield from stream_meta(api_key, model_name, system, messages, tool_schemas, config)
|
|
7515
7764
|
elif prov["type"] == "gcloud":
|
|
7516
7765
|
yield from stream_gcloud(model_name, system, messages, tool_schemas, config)
|
|
7517
7766
|
elif prov["type"] == "litellm":
|
|
@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "dulus"
|
|
13
|
-
version = "3.14.
|
|
13
|
+
version = "3.14.2"
|
|
14
14
|
description = "Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS."
|
|
15
15
|
readme = "README.md"
|
|
16
16
|
requires-python = ">=3.10"
|
|
@@ -112,6 +112,26 @@ dependencies = [
|
|
|
112
112
|
"uv>=0.4.0",
|
|
113
113
|
"sse-starlette>=2.0.0",
|
|
114
114
|
"starlette>=0.38.0",
|
|
115
|
+
# Product analytics — usage/telemetry (respects opt-out). Nobody runs
|
|
116
|
+
# `pip install dulus[full]`, so shipping it here is the only way metrics
|
|
117
|
+
# actually reach us from real installs.
|
|
118
|
+
"posthog>=3.0.0",
|
|
119
|
+
# Memory Palace — per-turn semantic memory injection. Pulls chromadb; on
|
|
120
|
+
# exotic targets (termux/aarch64) wheels may be missing, but the vast
|
|
121
|
+
# majority of installs want this ON by default rather than hunting the
|
|
122
|
+
# `[memory]` extra nobody types.
|
|
123
|
+
"mempalace>=3.3.4",
|
|
124
|
+
# Voice I/O — mic capture + cloud TTS. On by default so `/voice` works out
|
|
125
|
+
# of the box; silent no-op on headless boxes with no audio device.
|
|
126
|
+
"sounddevice",
|
|
127
|
+
"elevenlabs>=1.0.0",
|
|
128
|
+
# Browser automation — /harvest-*, WebBridge, JS-rendered scraping. The pip
|
|
129
|
+
# package ships here; the Chromium binary is fetched on first harvest.
|
|
130
|
+
"playwright>=1.40.0",
|
|
131
|
+
# LiteLLM unified gateway — one provider entry, 100+ backends. Bundled by
|
|
132
|
+
# default so the welcome wizard's litellm option works without a second
|
|
133
|
+
# install step.
|
|
134
|
+
"litellm>=1.50.0",
|
|
115
135
|
]
|
|
116
136
|
|
|
117
137
|
# mempalace pulls chromadb (26 transitive deps incl. numpy + onnxruntime),
|
|
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
|