dulus 3.10.1__tar.gz → 3.10.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.10.1/dulus.egg-info → dulus-3.10.2}/PKG-INFO +1 -1
- dulus-3.10.2/display_blocks.py +529 -0
- {dulus-3.10.1 → dulus-3.10.2/dulus.egg-info}/PKG-INFO +1 -1
- {dulus-3.10.1 → dulus-3.10.2}/dulus.egg-info/SOURCES.txt +8 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus.egg-info/top_level.txt +8 -0
- dulus-3.10.2/file_filter.py +91 -0
- dulus-3.10.2/paste_placeholders.py +49 -0
- dulus-3.10.2/profiles.py +340 -0
- {dulus-3.10.1 → dulus-3.10.2}/pyproject.toml +9 -1
- dulus-3.10.2/steer_input.py +148 -0
- dulus-3.10.2/tools_background.py +416 -0
- dulus-3.10.2/tools_think.py +68 -0
- dulus-3.10.2/tools_todo.py +196 -0
- {dulus-3.10.1 → dulus-3.10.2}/LICENSE +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/MANIFEST.in +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/README.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/agent.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/analytics.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/agents_bridge.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/compressor.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/context.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/githook.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/marketplace.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/mempalace_bridge.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/personas.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/plugins.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/server.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/backend/tasks.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/batch_api.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/checkpoint/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/checkpoint/hooks.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/checkpoint/store.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/checkpoint/types.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/claude_code_watcher.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/clipboard_utils.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/cloudsave.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/common.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/compaction.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/config.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/context.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/active_persona.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/marketplace.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/personas.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/plugins/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/plugins/composio/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/plugins/composio/composio_plugin/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/plugins/composio/plugin.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/plugins/composio/plugin_tool.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/data/tasks.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/API.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/BRAND_GUIDE.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/CHANGELOG.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/CONTRIBUTING.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/DEPLOYMENT.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/Dulus_AI_Whitepaper_(v2.0).pdf +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/FAQ.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/GETTING_STARTED.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/INVESTOR_BRIEF.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_AR.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_EN.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_ES.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_FR.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_JA.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_KO.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_PT.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_RU.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/README_ZH.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/SECURITY.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/api.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/architecture.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/azure-speech-template.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/dashboard/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/divider.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/dulus-bird.png +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/generate.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/hero.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/news.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/nvidia-models.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/particle-playground.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/personas/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/poetry-banner.png +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/preview.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-agents.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-brainstorm.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-bridges.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-features.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-freetier.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-memory.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-models.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-perms.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-plugins.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-quickstart.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/sec-ssj.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/spinners.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/split-pane.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/docs/terminal-boot.svg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus.egg-info/dependency_links.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus.egg-info/entry_points.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus.egg-info/requires.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_gui.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_gui_web.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_mcp/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_mcp/client.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_mcp/commands.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_mcp/config.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_mcp/hub.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_mcp/tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_mcp/types.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/add_dir_manager.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/afk_mode.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/approval_runtime.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/background_tasks.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/clipboard_utils.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/diff_visualizer.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/export_import.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/hook_engine.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/notification_manager.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/session_fork.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/shell_mode.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/todo_visualizer.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/tree_ls.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/wire_events.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/dulus_tools/yolo_mode.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/governance.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/agent_bridge.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/chat_widget.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/App.tsx +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/THIRD_PARTY_NOTICES.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/dist/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/dist/standalone.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/index.tsx +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/metadata.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/package-lock.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/package.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/types.ts +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/utils.ts +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/vertex-ai-proxy-interceptor.js +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/dulus_orchestrator/vite.config.ts +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/main_window.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/personas.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/sandbox_server.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/session_utils.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/settings_dialog.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/sidebar.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/tasks_view.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/themes.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/gui/tool_panel.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/input.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/license_manager.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/audit.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/consolidator.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/context.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/offload.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/palace.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/scan.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/sessions.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/store.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/types.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/memory/vector_search.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/multi_agent/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/multi_agent/subagent.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/multi_agent/tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/offload_helper.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/personality_config.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/plugin/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/plugin/autoadapter.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/plugin/loader.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/plugin/recommend.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/plugin/store.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/plugin/types.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/providers.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/README.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/components.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/wallpaper-default.jpg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/wallpapers/default.jpeg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/wallpapers/light.jpeg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/wallpapers/nature.jpeg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/dist/wallpapers/tech.jpeg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/eslint.config.js +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/info.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/package-lock.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/package.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/postcss.config.js +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/tailwind.config.js +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/tsconfig.app.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/tsconfig.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/tsconfig.node.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox/vite.config.ts +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/sandbox_bootstrap.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/setup.cfg +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/builtin.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/LICENSE-obsidian-skills +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/README.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/defuddle/SKILL.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/json-canvas/SKILL.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/json-canvas/references/EXAMPLES.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/obsidian-bases/SKILL.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/obsidian-cli/SKILL.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/obsidian-markdown/SKILL.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/obsidian-markdown/references/CALLOUTS.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/obsidian-markdown/references/EMBEDS.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/obsidian-markdown/references/PROPERTIES.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/README.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/SKILL.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/addresses.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/advancedbackgroundchecks.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/beenverified.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/clustal.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/clustrmaps.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/cyberbackgroundchecks.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/familytreenow.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/fastpeoplesearch.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/intelius.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/mylife.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/nuwber.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/peekyou.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/peoplefinders.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/radaris.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/rehold.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/searchpeoplefree.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/socialcatfish.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/spokeo.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/thatsthem.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/truepeoplesearch.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/usphonebook.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/brokers/whitepages.json +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/legal/ccpa.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/legal/drop.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/legal/gdpr.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/methods.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/site-playbooks.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/references/state-machine.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/autopilot.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/badbool.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/brokers.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/cdp.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/config.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/crypto.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/dossier.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/email_modes.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/emailer.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/ledger.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/legal.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/paths.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/pdd.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/registry.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/report.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/scan.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/storage.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/tiers.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/scripts/vectors.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/templates/consent/authorization.md +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/templates/emails/ccpa-authorized-agent.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/templates/emails/ccpa-deletion.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/templates/emails/ccpa-indirect-deletion.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/templates/emails/gdpr-erasure.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/bundled/unbroker/templates/emails/generic-optout.txt +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/clawhub.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/executor.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/loader.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skill/tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/skills.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/soul.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/spinner.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/string_utils.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/subagent.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/task/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/task/store.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/task/tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/task/types.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_afk_yolo.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_approval_runtime.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_background_task_tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_background_tasks.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_checkpoint.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_clipboard_utils.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_compaction.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_diff_view.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_diff_visualization.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_display_blocks.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_export_import.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_hook_engine.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_injection_fix.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_license.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_mcp.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_memory.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_notification_manager.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_plugin.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_session_fork.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_shell_mode.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_skills.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_steer_input.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_subagent.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_task.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_telegram_buffer.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_think_tool.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_todo_tool.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_todo_visualization.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_tool_registry.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_tree_ls.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_voice.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tests/test_wire_events.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tmux_offloader.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tmux_tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tool_registry.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/ui/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/ui/input.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/ui/render.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/updater.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/voice/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/voice/audio_utils.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/voice/keyterms.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/voice/recorder.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/voice/stt.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/voice/tts.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/voice/wake_word.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webbridge/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webbridge/core.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webbridge/tools.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webchat.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webchat_server.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webchat_ui/__init__.py +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webchat_ui/app.js +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webchat_ui/index.html +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/webchat_ui/style.css +0 -0
- {dulus-3.10.1 → dulus-3.10.2}/welcome.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.10.
|
|
3
|
+
Version: 3.10.2
|
|
4
4
|
Summary: Use IA as an agent without an API key. $0. Harvest your browser session for Gemini (guest, no login), Claude.ai, Claude Code, Kimi.com, Qwen, DeepSeek — drive them like an API, no per-token billing. Plus LiteLLM (100+ paid providers), local models via Ollama, /lang in 34 languages, Mesa Redonda, voice, OCR, MemPalace, embedded sandbox OS.
|
|
5
5
|
Author: KevRojo
|
|
6
6
|
License: GPL-3.0
|
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
"""Display Blocks System - Visual representations of agent actions.
|
|
2
|
+
|
|
3
|
+
Provides a structured way to represent agent actions visually across multiple
|
|
4
|
+
frontends: CLI (dulus.py), WebChat (webchat_server.py), and Telegram.
|
|
5
|
+
|
|
6
|
+
Display blocks are dict-based and can be rendered in various formats.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import difflib
|
|
11
|
+
import html
|
|
12
|
+
from typing import Literal
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ── Display block type hints ─────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
# These are the supported display block types
|
|
18
|
+
DisplayBlockType = Literal[
|
|
19
|
+
"diff",
|
|
20
|
+
"todo",
|
|
21
|
+
"shell",
|
|
22
|
+
"background_task",
|
|
23
|
+
"think",
|
|
24
|
+
"code",
|
|
25
|
+
"table",
|
|
26
|
+
"error",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ── CLI Renderer ─────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class DisplayBlockRenderer:
|
|
34
|
+
"""Render display blocks in various formats for different frontends.
|
|
35
|
+
|
|
36
|
+
Supports CLI (terminal), HTML (WebChat), and Telegram (Markdown) output formats.
|
|
37
|
+
Each render method takes a display block dict and returns a formatted string.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# ── Public API ──────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def render_cli(block: dict) -> str:
|
|
44
|
+
"""Render a display block for CLI (terminal) output.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
block: Display block dict with at least a 'type' key.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Formatted string suitable for terminal display.
|
|
51
|
+
"""
|
|
52
|
+
block_type = block.get("type", "unknown")
|
|
53
|
+
renderer = _CLI_RENDERERS.get(block_type, _CLI_RENDERERS["unknown"])
|
|
54
|
+
return renderer(block)
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def render_html(block: dict) -> str:
|
|
58
|
+
"""Render a display block as HTML for WebChat.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
block: Display block dict with at least a 'type' key.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
HTML string suitable for web display.
|
|
65
|
+
"""
|
|
66
|
+
block_type = block.get("type", "unknown")
|
|
67
|
+
renderer = _HTML_RENDERERS.get(block_type, _HTML_RENDERERS["unknown"])
|
|
68
|
+
return renderer(block)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def render_telegram(block: dict) -> str:
|
|
72
|
+
"""Render a display block for Telegram (Markdown V2).
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
block: Display block dict with at least a 'type' key.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Formatted string using Telegram Markdown V2 syntax.
|
|
79
|
+
"""
|
|
80
|
+
block_type = block.get("type", "unknown")
|
|
81
|
+
renderer = _TG_RENDERERS.get(block_type, _TG_RENDERERS["unknown"])
|
|
82
|
+
return renderer(block)
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def render(block: dict, format: Literal["cli", "html", "telegram"] = "cli") -> str:
|
|
86
|
+
"""Render a display block in the specified format.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
block: Display block dict with at least a 'type' key.
|
|
90
|
+
format: Target format - "cli", "html", or "telegram".
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Formatted string in the requested format.
|
|
94
|
+
"""
|
|
95
|
+
if format == "cli":
|
|
96
|
+
return DisplayBlockRenderer.render_cli(block)
|
|
97
|
+
elif format == "html":
|
|
98
|
+
return DisplayBlockRenderer.render_html(block)
|
|
99
|
+
elif format == "telegram":
|
|
100
|
+
return DisplayBlockRenderer.render_telegram(block)
|
|
101
|
+
return str(block)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ── CLI Renderers ────────────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _render_diff_cli(block: dict) -> str:
|
|
108
|
+
"""Render a diff display block for CLI.
|
|
109
|
+
|
|
110
|
+
Shows a unified diff between old and new text.
|
|
111
|
+
"""
|
|
112
|
+
path = block.get("path", "<unknown>")
|
|
113
|
+
old_text = block.get("old_text", "")
|
|
114
|
+
new_text = block.get("new_text", "")
|
|
115
|
+
old_start = block.get("old_start", 1)
|
|
116
|
+
new_start = block.get("new_start", 1)
|
|
117
|
+
is_summary = block.get("is_summary", False)
|
|
118
|
+
|
|
119
|
+
if is_summary:
|
|
120
|
+
return f"[Diff: {path}] (summary)"
|
|
121
|
+
|
|
122
|
+
old_lines = old_text.splitlines(keepends=True)
|
|
123
|
+
new_lines = new_text.splitlines(keepends=True)
|
|
124
|
+
|
|
125
|
+
# Generate unified diff
|
|
126
|
+
diff = difflib.unified_diff(
|
|
127
|
+
old_lines,
|
|
128
|
+
new_lines,
|
|
129
|
+
fromfile=f"a/{path}",
|
|
130
|
+
tofile=f"b/{path}",
|
|
131
|
+
lineterm="",
|
|
132
|
+
)
|
|
133
|
+
diff_text = "\n".join(diff)
|
|
134
|
+
|
|
135
|
+
if not diff_text:
|
|
136
|
+
return f"[Diff: {path}] No changes"
|
|
137
|
+
|
|
138
|
+
return f"[Diff: {path}]\n{diff_text}"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _render_todo_cli(block: dict) -> str:
|
|
142
|
+
"""Render a todo display block for CLI."""
|
|
143
|
+
items = block.get("items", [])
|
|
144
|
+
if not items:
|
|
145
|
+
return "[Todo] No items"
|
|
146
|
+
|
|
147
|
+
lines = ["Todo List:"]
|
|
148
|
+
icons = {"pending": "[ ]", "in_progress": "[/]", "done": "[x]"}
|
|
149
|
+
for item in items:
|
|
150
|
+
status = item.get("status", "pending")
|
|
151
|
+
icon = icons.get(status, "[ ]")
|
|
152
|
+
lines.append(f" {icon} {item.get('title', '')}")
|
|
153
|
+
return "\n".join(lines)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _render_shell_cli(block: dict) -> str:
|
|
157
|
+
"""Render a shell command display block for CLI."""
|
|
158
|
+
command = block.get("command", "")
|
|
159
|
+
language = block.get("language", "bash")
|
|
160
|
+
return f"$ {command}"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _render_bg_task_cli(block: dict) -> str:
|
|
164
|
+
"""Render a background task display block for CLI."""
|
|
165
|
+
task_id = block.get("task_id", "?")
|
|
166
|
+
kind = block.get("kind", "?")
|
|
167
|
+
status = block.get("status", "?")
|
|
168
|
+
description = block.get("description", "")
|
|
169
|
+
|
|
170
|
+
icons = {
|
|
171
|
+
"running": "●",
|
|
172
|
+
"completed": "✓",
|
|
173
|
+
"failed": "✗",
|
|
174
|
+
"stopped": "■",
|
|
175
|
+
}
|
|
176
|
+
icon = icons.get(status, "?")
|
|
177
|
+
return f"{icon} [{task_id}] {description} ({kind}, {status})"
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _render_think_cli(block: dict) -> str:
|
|
181
|
+
"""Render a think display block for CLI."""
|
|
182
|
+
thought = block.get("thought", "")
|
|
183
|
+
lines = thought.splitlines()
|
|
184
|
+
# Indent thought content for visual distinction
|
|
185
|
+
indented = "\n".join(f" | {line}" for line in lines)
|
|
186
|
+
return f"[Thinking...]\n{indented}"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _render_code_cli(block: dict) -> str:
|
|
190
|
+
"""Render a code display block for CLI."""
|
|
191
|
+
code = block.get("code", "")
|
|
192
|
+
language = block.get("language", "")
|
|
193
|
+
header = f"```{language}" if language else "```"
|
|
194
|
+
return f"{header}\n{code}\n```"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _render_table_cli(block: dict) -> str:
|
|
198
|
+
"""Render a table display block for CLI."""
|
|
199
|
+
headers = block.get("headers", [])
|
|
200
|
+
rows = block.get("rows", [])
|
|
201
|
+
if not headers and not rows:
|
|
202
|
+
return "[Table] Empty"
|
|
203
|
+
|
|
204
|
+
# Simple text table rendering
|
|
205
|
+
all_rows = [headers] + rows if headers else rows
|
|
206
|
+
# Calculate column widths
|
|
207
|
+
col_count = max(len(r) for r in all_rows) if all_rows else 0
|
|
208
|
+
widths = [0] * col_count
|
|
209
|
+
for row in all_rows:
|
|
210
|
+
for i, cell in enumerate(row):
|
|
211
|
+
widths[i] = max(widths[i], len(str(cell)))
|
|
212
|
+
|
|
213
|
+
def _fmt_row(row: list) -> str:
|
|
214
|
+
cells = [str(cell).ljust(widths[i]) for i, cell in enumerate(row)]
|
|
215
|
+
return " | ".join(cells)
|
|
216
|
+
|
|
217
|
+
lines = []
|
|
218
|
+
if headers:
|
|
219
|
+
lines.append(_fmt_row(headers))
|
|
220
|
+
lines.append("-" * (sum(widths) + 3 * (col_count - 1)))
|
|
221
|
+
for row in rows:
|
|
222
|
+
lines.append(_fmt_row(row))
|
|
223
|
+
return "\n".join(lines)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _render_error_cli(block: dict) -> str:
|
|
227
|
+
"""Render an error display block for CLI."""
|
|
228
|
+
message = block.get("message", "Unknown error")
|
|
229
|
+
return f"[Error] {message}"
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _render_unknown_cli(block: dict) -> str:
|
|
233
|
+
"""Render an unknown display block type for CLI."""
|
|
234
|
+
return f"[Display Block: {block.get('type', 'unknown')}]\n{str(block)}"
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
_CLI_RENDERERS: dict[str, callable] = {
|
|
238
|
+
"diff": _render_diff_cli,
|
|
239
|
+
"todo": _render_todo_cli,
|
|
240
|
+
"shell": _render_shell_cli,
|
|
241
|
+
"background_task": _render_bg_task_cli,
|
|
242
|
+
"think": _render_think_cli,
|
|
243
|
+
"code": _render_code_cli,
|
|
244
|
+
"table": _render_table_cli,
|
|
245
|
+
"error": _render_error_cli,
|
|
246
|
+
"unknown": _render_unknown_cli,
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# ── HTML Renderers ───────────────────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _render_diff_html(block: dict) -> str:
|
|
254
|
+
"""Render a diff display block as HTML."""
|
|
255
|
+
path = html.escape(block.get("path", "<unknown>"))
|
|
256
|
+
old_text = html.escape(block.get("old_text", ""))
|
|
257
|
+
new_text = html.escape(block.get("new_text", ""))
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
f'<div class="display-block diff-block">\n'
|
|
261
|
+
f' <div class="diff-header">{path}</div>\n'
|
|
262
|
+
f' <pre class="diff-old"><code>{old_text}</code></pre>\n'
|
|
263
|
+
f' <pre class="diff-new"><code>{new_text}</code></pre>\n'
|
|
264
|
+
f"</div>"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _render_todo_html(block: dict) -> str:
|
|
269
|
+
"""Render a todo display block as HTML."""
|
|
270
|
+
items = block.get("items", [])
|
|
271
|
+
if not items:
|
|
272
|
+
return '<div class="display-block todo-block"><p>No items</p></div>'
|
|
273
|
+
|
|
274
|
+
lines = ['<div class="display-block todo-block"><ul>']
|
|
275
|
+
icons = {
|
|
276
|
+
"pending": "⬜",
|
|
277
|
+
"in_progress": "🔄",
|
|
278
|
+
"done": "✅",
|
|
279
|
+
}
|
|
280
|
+
for item in items:
|
|
281
|
+
status = item.get("status", "pending")
|
|
282
|
+
icon = icons.get(status, "⬜")
|
|
283
|
+
title = html.escape(item.get("title", ""))
|
|
284
|
+
css_class = f"todo-{status}"
|
|
285
|
+
lines.append(f' <li class="{css_class}">{icon} {title}</li>')
|
|
286
|
+
lines.append("</ul></div>")
|
|
287
|
+
return "\n".join(lines)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _render_shell_html(block: dict) -> str:
|
|
291
|
+
"""Render a shell command display block as HTML."""
|
|
292
|
+
command = html.escape(block.get("command", ""))
|
|
293
|
+
language = html.escape(block.get("language", "bash"))
|
|
294
|
+
return (
|
|
295
|
+
f'<div class="display-block shell-block">\n'
|
|
296
|
+
f' <pre><code class="language-{language}">${command}</code></pre>\n'
|
|
297
|
+
f"</div>"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _render_bg_task_html(block: dict) -> str:
|
|
302
|
+
"""Render a background task display block as HTML."""
|
|
303
|
+
task_id = html.escape(block.get("task_id", "?"))
|
|
304
|
+
kind = html.escape(block.get("kind", "?"))
|
|
305
|
+
status = html.escape(block.get("status", "?"))
|
|
306
|
+
description = html.escape(block.get("description", ""))
|
|
307
|
+
|
|
308
|
+
status_colors = {
|
|
309
|
+
"running": "#2196F3",
|
|
310
|
+
"completed": "#4CAF50",
|
|
311
|
+
"failed": "#f44336",
|
|
312
|
+
"stopped": "#FF9800",
|
|
313
|
+
}
|
|
314
|
+
color = status_colors.get(status, "#9E9E9E")
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
f'<div class="display-block bg-task-block">\n'
|
|
318
|
+
f' <span class="task-id">[{task_id}]</span>\n'
|
|
319
|
+
f' <span class="task-desc">{description}</span>\n'
|
|
320
|
+
f' <span class="task-kind">({kind})</span>\n'
|
|
321
|
+
f' <span class="task-status" style="color: {color};">{status}</span>\n'
|
|
322
|
+
f"</div>"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _render_think_html(block: dict) -> str:
|
|
327
|
+
"""Render a think display block as HTML."""
|
|
328
|
+
thought = html.escape(block.get("thought", ""))
|
|
329
|
+
return (
|
|
330
|
+
f'<div class="display-block think-block">\n'
|
|
331
|
+
f' <div class="think-header">💭 Thinking</div>\n'
|
|
332
|
+
f' <pre class="think-content">{thought}</pre>\n'
|
|
333
|
+
f"</div>"
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _render_code_html(block: dict) -> str:
|
|
338
|
+
"""Render a code display block as HTML."""
|
|
339
|
+
code = html.escape(block.get("code", ""))
|
|
340
|
+
language = html.escape(block.get("language", ""))
|
|
341
|
+
return (
|
|
342
|
+
f'<div class="display-block code-block">\n'
|
|
343
|
+
f' <pre><code class="language-{language}">{code}</code></pre>\n'
|
|
344
|
+
f"</div>"
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _render_table_html(block: dict) -> str:
|
|
349
|
+
"""Render a table display block as HTML."""
|
|
350
|
+
headers = block.get("headers", [])
|
|
351
|
+
rows = block.get("rows", [])
|
|
352
|
+
if not headers and not rows:
|
|
353
|
+
return '<div class="display-block table-block"><p>Empty table</p></div>'
|
|
354
|
+
|
|
355
|
+
lines = ['<div class="display-block table-block">', "<table>"]
|
|
356
|
+
if headers:
|
|
357
|
+
lines.append(" <tr>" + "".join(f"<th>{html.escape(str(h))}</th>" for h in headers) + "</tr>")
|
|
358
|
+
for row in rows:
|
|
359
|
+
lines.append(" <tr>" + "".join(f"<td>{html.escape(str(c))}</td>" for c in row) + "</tr>")
|
|
360
|
+
lines.extend(["</table>", "</div>"])
|
|
361
|
+
return "\n".join(lines)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _render_error_html(block: dict) -> str:
|
|
365
|
+
"""Render an error display block as HTML."""
|
|
366
|
+
message = html.escape(block.get("message", "Unknown error"))
|
|
367
|
+
return (
|
|
368
|
+
f'<div class="display-block error-block" style="color: #f44336;">\n'
|
|
369
|
+
f' <strong>Error:</strong> {message}\n'
|
|
370
|
+
f"</div>"
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def _render_unknown_html(block: dict) -> str:
|
|
375
|
+
"""Render an unknown display block type as HTML."""
|
|
376
|
+
content = html.escape(str(block))
|
|
377
|
+
return f'<div class="display-block unknown-block"><pre>{content}</pre></div>'
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
_HTML_RENDERERS: dict[str, callable] = {
|
|
381
|
+
"diff": _render_diff_html,
|
|
382
|
+
"todo": _render_todo_html,
|
|
383
|
+
"shell": _render_shell_html,
|
|
384
|
+
"background_task": _render_bg_task_html,
|
|
385
|
+
"think": _render_think_html,
|
|
386
|
+
"code": _render_code_html,
|
|
387
|
+
"table": _render_table_html,
|
|
388
|
+
"error": _render_error_html,
|
|
389
|
+
"unknown": _render_unknown_html,
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
# ── Telegram Renderers ───────────────────────────────────────────────────────
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _render_diff_telegram(block: dict) -> str:
|
|
397
|
+
"""Render a diff display block for Telegram (Markdown V2).
|
|
398
|
+
|
|
399
|
+
Note: Telegram has limited formatting for diffs, so we keep it simple.
|
|
400
|
+
"""
|
|
401
|
+
path = block.get("path", "<unknown>")
|
|
402
|
+
old_text = block.get("old_text", "")
|
|
403
|
+
new_text = block.get("new_text", "")
|
|
404
|
+
|
|
405
|
+
# Escape Telegram Markdown V2 special chars
|
|
406
|
+
def _esc(text: str) -> str:
|
|
407
|
+
for c in "_[]()~`>#+-=|{}.!":
|
|
408
|
+
text = text.replace(c, f"\\{c}")
|
|
409
|
+
return text
|
|
410
|
+
|
|
411
|
+
return f"📝 *{_esc(path)}*\n```diff\n- {_esc('Old')}\n+ {_esc('New')}\n```"
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def _render_todo_telegram(block: dict) -> str:
|
|
415
|
+
"""Render a todo display block for Telegram (Markdown V2)."""
|
|
416
|
+
items = block.get("items", [])
|
|
417
|
+
if not items:
|
|
418
|
+
return "📋 *Todo List:* Empty"
|
|
419
|
+
|
|
420
|
+
def _esc(text: str) -> str:
|
|
421
|
+
for c in "_[]()~`>#+-=|{}.!":
|
|
422
|
+
text = text.replace(c, f"\\{c}")
|
|
423
|
+
return text
|
|
424
|
+
|
|
425
|
+
icons = {
|
|
426
|
+
"pending": "⬜",
|
|
427
|
+
"in_progress": "🔄",
|
|
428
|
+
"done": "✅",
|
|
429
|
+
}
|
|
430
|
+
lines = ["📋 *Todo List:*"]
|
|
431
|
+
for item in items:
|
|
432
|
+
status = item.get("status", "pending")
|
|
433
|
+
icon = icons.get(status, "⬜")
|
|
434
|
+
title = _esc(item.get("title", ""))
|
|
435
|
+
lines.append(f"{icon} {title}")
|
|
436
|
+
return "\n".join(lines)
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def _render_shell_telegram(block: dict) -> str:
|
|
440
|
+
"""Render a shell command display block for Telegram."""
|
|
441
|
+
command = block.get("command", "")
|
|
442
|
+
return f"```bash\n$ {command}\n```"
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def _render_bg_task_telegram(block: dict) -> str:
|
|
446
|
+
"""Render a background task display block for Telegram."""
|
|
447
|
+
task_id = block.get("task_id", "?")
|
|
448
|
+
kind = block.get("kind", "?")
|
|
449
|
+
status = block.get("status", "?")
|
|
450
|
+
description = block.get("description", "")
|
|
451
|
+
|
|
452
|
+
icons = {
|
|
453
|
+
"running": "🔄",
|
|
454
|
+
"completed": "✅",
|
|
455
|
+
"failed": "❌",
|
|
456
|
+
"stopped": "🛑",
|
|
457
|
+
}
|
|
458
|
+
icon = icons.get(status, "❓")
|
|
459
|
+
|
|
460
|
+
def _esc(text: str) -> str:
|
|
461
|
+
for c in "_[]()~`>#+-=|{}.!":
|
|
462
|
+
text = text.replace(c, f"\\{c}")
|
|
463
|
+
return text
|
|
464
|
+
|
|
465
|
+
return f"{icon} *Task `{task_id}`*\n{_esc(description)}\n({_esc(kind)}, {_esc(status)})"
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def _render_think_telegram(block: dict) -> str:
|
|
469
|
+
"""Render a think display block for Telegram."""
|
|
470
|
+
thought = block.get("thought", "")
|
|
471
|
+
return f"💭 *Thinking*\n```\n{thought[:3000]}\n```"
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def _render_code_telegram(block: dict) -> str:
|
|
475
|
+
"""Render a code display block for Telegram."""
|
|
476
|
+
code = block.get("code", "")
|
|
477
|
+
language = block.get("language", "")
|
|
478
|
+
return f"```{language}\n{code[:3000]}\n```"
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def _render_table_telegram(block: dict) -> str:
|
|
482
|
+
"""Render a table display block for Telegram."""
|
|
483
|
+
headers = block.get("headers", [])
|
|
484
|
+
rows = block.get("rows", [])
|
|
485
|
+
if not headers and not rows:
|
|
486
|
+
return "📊 *Table:* Empty"
|
|
487
|
+
|
|
488
|
+
def _esc(text: str) -> str:
|
|
489
|
+
for c in "_[]()~`>#+-=|{}.!":
|
|
490
|
+
text = text.replace(c, f"\\{c}")
|
|
491
|
+
return text
|
|
492
|
+
|
|
493
|
+
lines = []
|
|
494
|
+
if headers:
|
|
495
|
+
lines.append(" | ".join(_esc(str(h)) for h in headers))
|
|
496
|
+
lines.append("—" * 20)
|
|
497
|
+
for row in rows:
|
|
498
|
+
lines.append(" | ".join(_esc(str(c)) for c in row))
|
|
499
|
+
return "\n".join(lines)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _render_error_telegram(block: dict) -> str:
|
|
503
|
+
"""Render an error display block for Telegram."""
|
|
504
|
+
message = block.get("message", "Unknown error")
|
|
505
|
+
|
|
506
|
+
def _esc(text: str) -> str:
|
|
507
|
+
for c in "_[]()~`>#+-=|{}.!":
|
|
508
|
+
text = text.replace(c, f"\\{c}")
|
|
509
|
+
return text
|
|
510
|
+
|
|
511
|
+
return f"❌ *Error:* {_esc(message)}"
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def _render_unknown_telegram(block: dict) -> str:
|
|
515
|
+
"""Render an unknown display block type for Telegram."""
|
|
516
|
+
return f"```\n{str(block)[:1000]}\n```"
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
_TG_RENDERERS: dict[str, callable] = {
|
|
520
|
+
"diff": _render_diff_telegram,
|
|
521
|
+
"todo": _render_todo_telegram,
|
|
522
|
+
"shell": _render_shell_telegram,
|
|
523
|
+
"background_task": _render_bg_task_telegram,
|
|
524
|
+
"think": _render_think_telegram,
|
|
525
|
+
"code": _render_code_telegram,
|
|
526
|
+
"table": _render_table_telegram,
|
|
527
|
+
"error": _render_error_telegram,
|
|
528
|
+
"unknown": _render_unknown_telegram,
|
|
529
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.10.
|
|
3
|
+
Version: 3.10.2
|
|
4
4
|
Summary: Use IA as an agent without an API key. $0. Harvest your browser session for Gemini (guest, no login), Claude.ai, Claude Code, Kimi.com, Qwen, DeepSeek — drive them like an API, no per-token billing. Plus LiteLLM (100+ paid providers), local models via Ollama, /lang in 34 languages, Mesa Redonda, voice, OCR, MemPalace, embedded sandbox OS.
|
|
5
5
|
Author: KevRojo
|
|
6
6
|
License: GPL-3.0
|
|
@@ -11,26 +11,34 @@ common.py
|
|
|
11
11
|
compaction.py
|
|
12
12
|
config.py
|
|
13
13
|
context.py
|
|
14
|
+
display_blocks.py
|
|
14
15
|
dulus.py
|
|
15
16
|
dulus_gui.py
|
|
16
17
|
dulus_gui_web.py
|
|
18
|
+
file_filter.py
|
|
17
19
|
governance.py
|
|
18
20
|
input.py
|
|
19
21
|
license_manager.py
|
|
20
22
|
offload_helper.py
|
|
23
|
+
paste_placeholders.py
|
|
21
24
|
personality_config.py
|
|
25
|
+
profiles.py
|
|
22
26
|
providers.py
|
|
23
27
|
pyproject.toml
|
|
24
28
|
sandbox_bootstrap.py
|
|
25
29
|
skills.py
|
|
26
30
|
soul.py
|
|
27
31
|
spinner.py
|
|
32
|
+
steer_input.py
|
|
28
33
|
string_utils.py
|
|
29
34
|
subagent.py
|
|
30
35
|
tmux_offloader.py
|
|
31
36
|
tmux_tools.py
|
|
32
37
|
tool_registry.py
|
|
33
38
|
tools.py
|
|
39
|
+
tools_background.py
|
|
40
|
+
tools_think.py
|
|
41
|
+
tools_todo.py
|
|
34
42
|
updater.py
|
|
35
43
|
webchat.py
|
|
36
44
|
webchat_server.py
|
|
@@ -11,12 +11,14 @@ compaction
|
|
|
11
11
|
config
|
|
12
12
|
context
|
|
13
13
|
data
|
|
14
|
+
display_blocks
|
|
14
15
|
docs
|
|
15
16
|
dulus
|
|
16
17
|
dulus_gui
|
|
17
18
|
dulus_gui_web
|
|
18
19
|
dulus_mcp
|
|
19
20
|
dulus_tools
|
|
21
|
+
file_filter
|
|
20
22
|
governance
|
|
21
23
|
gui
|
|
22
24
|
input
|
|
@@ -24,8 +26,10 @@ license_manager
|
|
|
24
26
|
memory
|
|
25
27
|
multi_agent
|
|
26
28
|
offload_helper
|
|
29
|
+
paste_placeholders
|
|
27
30
|
personality_config
|
|
28
31
|
plugin
|
|
32
|
+
profiles
|
|
29
33
|
providers
|
|
30
34
|
sandbox
|
|
31
35
|
sandbox_bootstrap
|
|
@@ -33,6 +37,7 @@ skill
|
|
|
33
37
|
skills
|
|
34
38
|
soul
|
|
35
39
|
spinner
|
|
40
|
+
steer_input
|
|
36
41
|
string_utils
|
|
37
42
|
subagent
|
|
38
43
|
task
|
|
@@ -40,6 +45,9 @@ tmux_offloader
|
|
|
40
45
|
tmux_tools
|
|
41
46
|
tool_registry
|
|
42
47
|
tools
|
|
48
|
+
tools_background
|
|
49
|
+
tools_think
|
|
50
|
+
tools_todo
|
|
43
51
|
ui
|
|
44
52
|
updater
|
|
45
53
|
voice
|