dulus 3.7.0__tar.gz → 3.7.1__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.7.0/dulus.egg-info → dulus-3.7.1}/PKG-INFO +1 -1
- {dulus-3.7.0 → dulus-3.7.1}/analytics.py +164 -164
- {dulus-3.7.0 → dulus-3.7.1/dulus.egg-info}/PKG-INFO +1 -1
- {dulus-3.7.0 → dulus-3.7.1}/dulus.egg-info/SOURCES.txt +2 -2
- {dulus-3.7.0 → dulus-3.7.1}/dulus_gui_web.py +825 -825
- dulus-3.7.1/dulus_tools/tree_ls.py +156 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/App.tsx +196 -196
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/THIRD_PARTY_NOTICES.md +10 -10
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/dist/index.html +188 -188
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/dist/standalone.html +188 -188
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/index.html +120 -120
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/index.tsx +16 -16
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/metadata.json +6 -6
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/package-lock.json +3143 -3143
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/package.json +30 -30
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/types.ts +169 -169
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/utils.ts +74 -74
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/vertex-ai-proxy-interceptor.js +154 -154
- {dulus-3.7.0 → dulus-3.7.1}/gui/dulus_orchestrator/vite.config.ts +44 -44
- {dulus-3.7.0 → dulus-3.7.1}/pyproject.toml +1 -1
- dulus-3.7.0/tests/test_fs_compass.py → dulus-3.7.1/tests/test_tree_ls.py +86 -78
- {dulus-3.7.0 → dulus-3.7.1}/tools.py +3 -3
- dulus-3.7.0/dulus_tools/fs_compass.py +0 -472
- {dulus-3.7.0 → dulus-3.7.1}/LICENSE +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/MANIFEST.in +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/README.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/agent.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/agents_bridge.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/compressor.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/context.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/githook.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/marketplace.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/mempalace_bridge.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/personas.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/plugins.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/server.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/backend/tasks.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/batch_api.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/checkpoint/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/checkpoint/hooks.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/checkpoint/store.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/checkpoint/types.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/claude_code_watcher.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/clipboard_utils.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/cloudsave.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/common.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/compaction.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/config.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/context.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/active_persona.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/marketplace.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/personas.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/plugins/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/plugins/composio/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/plugins/composio/composio_plugin/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/plugins/composio/plugin.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/plugins/composio/plugin_tool.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/data/tasks.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/API.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/BRAND_GUIDE.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/CHANGELOG.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/CONTRIBUTING.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/DEPLOYMENT.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/Dulus_AI_Whitepaper_(v2.0).pdf +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/FAQ.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/GETTING_STARTED.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/INVESTOR_BRIEF.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_AR.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_EN.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_ES.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_FR.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_JA.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_KO.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_PT.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_RU.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/README_ZH.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/SECURITY.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/api.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/architecture.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/azure-speech-template.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/dashboard/index.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/divider.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/dulus-bird.png +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/generate.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/hero.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/index.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/news.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/nvidia-models.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/particle-playground.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/personas/index.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/poetry-banner.png +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/preview.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-agents.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-brainstorm.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-bridges.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-features.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-freetier.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-memory.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-models.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-perms.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-plugins.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-quickstart.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/sec-ssj.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/spinners.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/split-pane.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/docs/terminal-boot.svg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus.egg-info/dependency_links.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus.egg-info/entry_points.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus.egg-info/requires.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus.egg-info/top_level.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_gui.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_mcp/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_mcp/client.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_mcp/config.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_mcp/tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_mcp/types.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/add_dir_manager.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/afk_mode.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/approval_runtime.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/background_tasks.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/clipboard_utils.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/diff_visualizer.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/export_import.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/hook_engine.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/notification_manager.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/session_fork.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/shell_mode.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/todo_visualizer.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/wire_events.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/dulus_tools/yolo_mode.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/governance.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/agent_bridge.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/chat_widget.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/main_window.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/personas.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/sandbox_server.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/session_utils.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/settings_dialog.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/sidebar.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/tasks_view.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/themes.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/gui/tool_panel.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/input.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/license_manager.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/audit.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/consolidator.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/context.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/offload.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/palace.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/scan.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/sessions.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/store.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/types.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/memory/vector_search.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/multi_agent/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/multi_agent/subagent.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/multi_agent/tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/offload_helper.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/personality_config.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/plugin/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/plugin/autoadapter.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/plugin/loader.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/plugin/recommend.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/plugin/store.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/plugin/types.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/providers.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/README.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/components.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/index.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/wallpaper-default.jpg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/wallpapers/default.jpeg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/wallpapers/light.jpeg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/wallpapers/nature.jpeg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/dist/wallpapers/tech.jpeg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/eslint.config.js +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/index.html +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/info.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/package-lock.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/package.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/postcss.config.js +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/tailwind.config.js +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/tsconfig.app.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/tsconfig.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/tsconfig.node.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox/vite.config.ts +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/sandbox_bootstrap.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/setup.cfg +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/builtin.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/LICENSE-obsidian-skills +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/README.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/defuddle/SKILL.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/json-canvas/SKILL.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/json-canvas/references/EXAMPLES.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/obsidian-bases/SKILL.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/obsidian-cli/SKILL.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/obsidian-markdown/SKILL.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/obsidian-markdown/references/CALLOUTS.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/obsidian-markdown/references/EMBEDS.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/obsidian-markdown/references/PROPERTIES.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/README.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/SKILL.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/addresses.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/advancedbackgroundchecks.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/beenverified.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/clustal.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/clustrmaps.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/cyberbackgroundchecks.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/familytreenow.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/fastpeoplesearch.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/intelius.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/mylife.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/nuwber.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/peekyou.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/peoplefinders.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/radaris.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/rehold.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/searchpeoplefree.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/socialcatfish.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/spokeo.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/thatsthem.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/truepeoplesearch.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/usphonebook.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/brokers/whitepages.json +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/legal/ccpa.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/legal/drop.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/legal/gdpr.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/methods.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/site-playbooks.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/references/state-machine.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/autopilot.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/badbool.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/brokers.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/cdp.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/config.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/crypto.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/dossier.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/email_modes.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/emailer.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/ledger.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/legal.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/paths.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/pdd.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/registry.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/report.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/scan.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/storage.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/tiers.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/scripts/vectors.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/templates/consent/authorization.md +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/templates/emails/ccpa-authorized-agent.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/templates/emails/ccpa-deletion.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/templates/emails/ccpa-indirect-deletion.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/templates/emails/gdpr-erasure.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/bundled/unbroker/templates/emails/generic-optout.txt +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/clawhub.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/executor.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/loader.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skill/tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/skills.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/soul.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/spinner.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/string_utils.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/subagent.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/task/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/task/store.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/task/tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/task/types.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_afk_yolo.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_approval_runtime.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_background_task_tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_background_tasks.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_checkpoint.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_clipboard_utils.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_compaction.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_diff_view.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_diff_visualization.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_display_blocks.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_export_import.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_hook_engine.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_injection_fix.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_license.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_mcp.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_memory.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_notification_manager.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_plugin.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_session_fork.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_shell_mode.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_skills.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_steer_input.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_subagent.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_task.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_telegram_buffer.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_think_tool.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_todo_tool.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_todo_visualization.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_tool_registry.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_voice.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tests/test_wire_events.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tmux_offloader.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tmux_tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/tool_registry.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/ui/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/ui/input.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/ui/render.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/voice/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/voice/audio_utils.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/voice/keyterms.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/voice/recorder.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/voice/stt.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/voice/tts.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/voice/wake_word.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/webbridge/__init__.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/webbridge/core.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/webbridge/tools.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/webchat.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/webchat_server.py +0 -0
- {dulus-3.7.0 → dulus-3.7.1}/welcome.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.7.
|
|
3
|
+
Version: 3.7.1
|
|
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
|
|
@@ -1,164 +1,164 @@
|
|
|
1
|
-
"""Dulus anonymous usage telemetry (opt-in, privacy-first).
|
|
2
|
-
|
|
3
|
-
Dulus asks ONCE on startup whether you want to share anonymous usage
|
|
4
|
-
statistics. Nothing is sent until you explicitly say yes.
|
|
5
|
-
|
|
6
|
-
What IS collected (when enabled):
|
|
7
|
-
- Event names (session_start, message_sent, tool_used, model_selected)
|
|
8
|
-
- Dulus version, OS name, Python version
|
|
9
|
-
- Provider/model *names* (e.g. "gemini", "claude-sonnet")
|
|
10
|
-
- A random anonymous ID (UUID generated locally — not tied to you)
|
|
11
|
-
|
|
12
|
-
What is NEVER collected:
|
|
13
|
-
- Prompts, responses, or any conversation content
|
|
14
|
-
- File paths, file contents, or code
|
|
15
|
-
- Usernames, emails, hostnames, IPs (Mixpanel geo is disabled via $ip=0)
|
|
16
|
-
- API keys or tokens
|
|
17
|
-
|
|
18
|
-
Where it goes: Mixpanel (https://mixpanel.com) — event analytics only.
|
|
19
|
-
|
|
20
|
-
Opt out at any time (any of these):
|
|
21
|
-
- Answer "n" at the first-run prompt
|
|
22
|
-
- /config telemetry=off (inside Dulus)
|
|
23
|
-
- DULUS_TELEMETRY=0 (environment variable)
|
|
24
|
-
|
|
25
|
-
Implementation notes: zero third-party dependencies — plain urllib POST to
|
|
26
|
-
the Mixpanel ingestion API in a fire-and-forget daemon thread. Failures are
|
|
27
|
-
silently ignored; telemetry must never slow down or break Dulus.
|
|
28
|
-
"""
|
|
29
|
-
from __future__ import annotations
|
|
30
|
-
|
|
31
|
-
import base64
|
|
32
|
-
import json
|
|
33
|
-
import os
|
|
34
|
-
import platform
|
|
35
|
-
import sys
|
|
36
|
-
import threading
|
|
37
|
-
import time
|
|
38
|
-
import uuid
|
|
39
|
-
|
|
40
|
-
# Mixpanel PROJECT TOKEN for the public Dulus project.
|
|
41
|
-
# NOTE: Mixpanel ingestion tokens are write-only and designed to ship in
|
|
42
|
-
# client code (every website using Mixpanel exposes theirs). It cannot be
|
|
43
|
-
# used to read any data. Override with DULUS_MP_TOKEN.
|
|
44
|
-
MP_TOKEN = os.environ.get("DULUS_MP_TOKEN", "966ce8f5ccb32f06788f51be9f8bf8f5")
|
|
45
|
-
|
|
46
|
-
_MP_ENDPOINT = "https://api.mixpanel.com/track"
|
|
47
|
-
|
|
48
|
-
# Populated by init_telemetry(); None = not initialised / disabled.
|
|
49
|
-
_distinct_id: str | None = None
|
|
50
|
-
_enabled: bool = False
|
|
51
|
-
_dulus_version: str = ""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def _env_disabled() -> bool:
|
|
55
|
-
return os.environ.get("DULUS_TELEMETRY", "").strip().lower() in ("0", "off", "false", "no")
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def is_enabled() -> bool:
|
|
59
|
-
return _enabled and not _env_disabled() and bool(MP_TOKEN)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
CONSENT_NOTICE = """
|
|
63
|
-
── Ayuda a mejorar Dulus / Help improve Dulus ─────────────────────────
|
|
64
|
-
Dulus can share ANONYMOUS usage statistics to help us understand
|
|
65
|
-
which features matter (event counts only — sent to Mixpanel).
|
|
66
|
-
|
|
67
|
-
Collected: event names, Dulus version, OS, model/provider names,
|
|
68
|
-
a random anonymous ID generated on this machine.
|
|
69
|
-
NEVER: prompts, responses, files, paths, keys, emails, IPs.
|
|
70
|
-
|
|
71
|
-
Change your mind anytime: /config telemetry=off or DULUS_TELEMETRY=0
|
|
72
|
-
────────────────────────────────────────────────────────────────────────
|
|
73
|
-
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def ask_consent(config: dict) -> dict:
|
|
77
|
-
"""One-time interactive consent prompt. Mutates + returns config.
|
|
78
|
-
|
|
79
|
-
Only call when config['telemetry'] is unset and stdin is a TTY.
|
|
80
|
-
"""
|
|
81
|
-
print(CONSENT_NOTICE)
|
|
82
|
-
try:
|
|
83
|
-
answer = input(" Share anonymous usage stats? [y/N] ").strip().lower()
|
|
84
|
-
except (EOFError, KeyboardInterrupt):
|
|
85
|
-
answer = ""
|
|
86
|
-
config["telemetry"] = answer in ("y", "yes", "s", "si", "sí")
|
|
87
|
-
if config["telemetry"] and not config.get("telemetry_id"):
|
|
88
|
-
config["telemetry_id"] = uuid.uuid4().hex
|
|
89
|
-
state = "enabled — thank you! 🦅" if config["telemetry"] else "disabled."
|
|
90
|
-
print(f" Telemetry {state}\n")
|
|
91
|
-
return config
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def init_telemetry(config: dict, version: str = "") -> None:
|
|
95
|
-
"""Initialise the module from config. Safe to call multiple times."""
|
|
96
|
-
global _distinct_id, _enabled, _dulus_version
|
|
97
|
-
_dulus_version = version or _dulus_version
|
|
98
|
-
_enabled = bool(config.get("telemetry")) and not _env_disabled()
|
|
99
|
-
if _enabled:
|
|
100
|
-
_distinct_id = config.get("telemetry_id") or uuid.uuid4().hex
|
|
101
|
-
config.setdefault("telemetry_id", _distinct_id)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def track(event: str, properties: dict | None = None) -> None:
|
|
105
|
-
"""Fire-and-forget anonymous event. No-op unless telemetry is enabled."""
|
|
106
|
-
if not is_enabled() or not _distinct_id:
|
|
107
|
-
return
|
|
108
|
-
|
|
109
|
-
payload = {
|
|
110
|
-
"event": event,
|
|
111
|
-
"properties": {
|
|
112
|
-
"token": MP_TOKEN,
|
|
113
|
-
"distinct_id": _distinct_id,
|
|
114
|
-
"time": int(time.time()),
|
|
115
|
-
"$ip": 0, # disable Mixpanel geolocation
|
|
116
|
-
"dulus_version": _dulus_version,
|
|
117
|
-
"os": platform.system(),
|
|
118
|
-
"python": f"{sys.version_info.major}.{sys.version_info.minor}",
|
|
119
|
-
**(properties or {}),
|
|
120
|
-
},
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
def _send() -> None:
|
|
124
|
-
try:
|
|
125
|
-
from urllib.request import Request, urlopen
|
|
126
|
-
from urllib.parse import urlencode
|
|
127
|
-
|
|
128
|
-
data = urlencode(
|
|
129
|
-
{"data": base64.b64encode(json.dumps([payload]).encode()).decode()}
|
|
130
|
-
).encode()
|
|
131
|
-
req = Request(_MP_ENDPOINT, data=data, method="POST")
|
|
132
|
-
urlopen(req, timeout=4).read()
|
|
133
|
-
except Exception:
|
|
134
|
-
pass # telemetry must never break Dulus
|
|
135
|
-
|
|
136
|
-
threading.Thread(target=_send, daemon=True, name="telemetry").start()
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def track_session_start(config: dict) -> None:
|
|
140
|
-
"""Convenience: one event per REPL boot (enough for DAU/MAU counts)."""
|
|
141
|
-
track("session_start", {
|
|
142
|
-
"provider": str(config.get("provider", "")),
|
|
143
|
-
"model": str(config.get("model", "")),
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def track_message_sent(model: str = "") -> None:
|
|
148
|
-
"""One event per user prompt sent to the LLM (no content — count only)."""
|
|
149
|
-
track("message_sent", {"model": model})
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def track_tool_used(tool_name: str) -> None:
|
|
153
|
-
"""One event per tool invocation (tool NAME only — never inputs)."""
|
|
154
|
-
track("tool_used", {"tool": tool_name})
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def track_command_used(command: str) -> None:
|
|
158
|
-
"""One event per slash command (command NAME only — never args)."""
|
|
159
|
-
track("command_used", {"command": command})
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def track_model_selected(model: str, provider: str = "") -> None:
|
|
163
|
-
"""Fired when the user switches models via /model."""
|
|
164
|
-
track("model_selected", {"model": model, "provider": provider})
|
|
1
|
+
"""Dulus anonymous usage telemetry (opt-in, privacy-first).
|
|
2
|
+
|
|
3
|
+
Dulus asks ONCE on startup whether you want to share anonymous usage
|
|
4
|
+
statistics. Nothing is sent until you explicitly say yes.
|
|
5
|
+
|
|
6
|
+
What IS collected (when enabled):
|
|
7
|
+
- Event names (session_start, message_sent, tool_used, model_selected)
|
|
8
|
+
- Dulus version, OS name, Python version
|
|
9
|
+
- Provider/model *names* (e.g. "gemini", "claude-sonnet")
|
|
10
|
+
- A random anonymous ID (UUID generated locally — not tied to you)
|
|
11
|
+
|
|
12
|
+
What is NEVER collected:
|
|
13
|
+
- Prompts, responses, or any conversation content
|
|
14
|
+
- File paths, file contents, or code
|
|
15
|
+
- Usernames, emails, hostnames, IPs (Mixpanel geo is disabled via $ip=0)
|
|
16
|
+
- API keys or tokens
|
|
17
|
+
|
|
18
|
+
Where it goes: Mixpanel (https://mixpanel.com) — event analytics only.
|
|
19
|
+
|
|
20
|
+
Opt out at any time (any of these):
|
|
21
|
+
- Answer "n" at the first-run prompt
|
|
22
|
+
- /config telemetry=off (inside Dulus)
|
|
23
|
+
- DULUS_TELEMETRY=0 (environment variable)
|
|
24
|
+
|
|
25
|
+
Implementation notes: zero third-party dependencies — plain urllib POST to
|
|
26
|
+
the Mixpanel ingestion API in a fire-and-forget daemon thread. Failures are
|
|
27
|
+
silently ignored; telemetry must never slow down or break Dulus.
|
|
28
|
+
"""
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import base64
|
|
32
|
+
import json
|
|
33
|
+
import os
|
|
34
|
+
import platform
|
|
35
|
+
import sys
|
|
36
|
+
import threading
|
|
37
|
+
import time
|
|
38
|
+
import uuid
|
|
39
|
+
|
|
40
|
+
# Mixpanel PROJECT TOKEN for the public Dulus project.
|
|
41
|
+
# NOTE: Mixpanel ingestion tokens are write-only and designed to ship in
|
|
42
|
+
# client code (every website using Mixpanel exposes theirs). It cannot be
|
|
43
|
+
# used to read any data. Override with DULUS_MP_TOKEN.
|
|
44
|
+
MP_TOKEN = os.environ.get("DULUS_MP_TOKEN", "966ce8f5ccb32f06788f51be9f8bf8f5")
|
|
45
|
+
|
|
46
|
+
_MP_ENDPOINT = "https://api.mixpanel.com/track"
|
|
47
|
+
|
|
48
|
+
# Populated by init_telemetry(); None = not initialised / disabled.
|
|
49
|
+
_distinct_id: str | None = None
|
|
50
|
+
_enabled: bool = False
|
|
51
|
+
_dulus_version: str = ""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _env_disabled() -> bool:
|
|
55
|
+
return os.environ.get("DULUS_TELEMETRY", "").strip().lower() in ("0", "off", "false", "no")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def is_enabled() -> bool:
|
|
59
|
+
return _enabled and not _env_disabled() and bool(MP_TOKEN)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
CONSENT_NOTICE = """
|
|
63
|
+
── Ayuda a mejorar Dulus / Help improve Dulus ─────────────────────────
|
|
64
|
+
Dulus can share ANONYMOUS usage statistics to help us understand
|
|
65
|
+
which features matter (event counts only — sent to Mixpanel).
|
|
66
|
+
|
|
67
|
+
Collected: event names, Dulus version, OS, model/provider names,
|
|
68
|
+
a random anonymous ID generated on this machine.
|
|
69
|
+
NEVER: prompts, responses, files, paths, keys, emails, IPs.
|
|
70
|
+
|
|
71
|
+
Change your mind anytime: /config telemetry=off or DULUS_TELEMETRY=0
|
|
72
|
+
────────────────────────────────────────────────────────────────────────
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def ask_consent(config: dict) -> dict:
|
|
77
|
+
"""One-time interactive consent prompt. Mutates + returns config.
|
|
78
|
+
|
|
79
|
+
Only call when config['telemetry'] is unset and stdin is a TTY.
|
|
80
|
+
"""
|
|
81
|
+
print(CONSENT_NOTICE)
|
|
82
|
+
try:
|
|
83
|
+
answer = input(" Share anonymous usage stats? [y/N] ").strip().lower()
|
|
84
|
+
except (EOFError, KeyboardInterrupt):
|
|
85
|
+
answer = ""
|
|
86
|
+
config["telemetry"] = answer in ("y", "yes", "s", "si", "sí")
|
|
87
|
+
if config["telemetry"] and not config.get("telemetry_id"):
|
|
88
|
+
config["telemetry_id"] = uuid.uuid4().hex
|
|
89
|
+
state = "enabled — thank you! 🦅" if config["telemetry"] else "disabled."
|
|
90
|
+
print(f" Telemetry {state}\n")
|
|
91
|
+
return config
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def init_telemetry(config: dict, version: str = "") -> None:
|
|
95
|
+
"""Initialise the module from config. Safe to call multiple times."""
|
|
96
|
+
global _distinct_id, _enabled, _dulus_version
|
|
97
|
+
_dulus_version = version or _dulus_version
|
|
98
|
+
_enabled = bool(config.get("telemetry")) and not _env_disabled()
|
|
99
|
+
if _enabled:
|
|
100
|
+
_distinct_id = config.get("telemetry_id") or uuid.uuid4().hex
|
|
101
|
+
config.setdefault("telemetry_id", _distinct_id)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def track(event: str, properties: dict | None = None) -> None:
|
|
105
|
+
"""Fire-and-forget anonymous event. No-op unless telemetry is enabled."""
|
|
106
|
+
if not is_enabled() or not _distinct_id:
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
payload = {
|
|
110
|
+
"event": event,
|
|
111
|
+
"properties": {
|
|
112
|
+
"token": MP_TOKEN,
|
|
113
|
+
"distinct_id": _distinct_id,
|
|
114
|
+
"time": int(time.time()),
|
|
115
|
+
"$ip": 0, # disable Mixpanel geolocation
|
|
116
|
+
"dulus_version": _dulus_version,
|
|
117
|
+
"os": platform.system(),
|
|
118
|
+
"python": f"{sys.version_info.major}.{sys.version_info.minor}",
|
|
119
|
+
**(properties or {}),
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
def _send() -> None:
|
|
124
|
+
try:
|
|
125
|
+
from urllib.request import Request, urlopen
|
|
126
|
+
from urllib.parse import urlencode
|
|
127
|
+
|
|
128
|
+
data = urlencode(
|
|
129
|
+
{"data": base64.b64encode(json.dumps([payload]).encode()).decode()}
|
|
130
|
+
).encode()
|
|
131
|
+
req = Request(_MP_ENDPOINT, data=data, method="POST")
|
|
132
|
+
urlopen(req, timeout=4).read()
|
|
133
|
+
except Exception:
|
|
134
|
+
pass # telemetry must never break Dulus
|
|
135
|
+
|
|
136
|
+
threading.Thread(target=_send, daemon=True, name="telemetry").start()
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def track_session_start(config: dict) -> None:
|
|
140
|
+
"""Convenience: one event per REPL boot (enough for DAU/MAU counts)."""
|
|
141
|
+
track("session_start", {
|
|
142
|
+
"provider": str(config.get("provider", "")),
|
|
143
|
+
"model": str(config.get("model", "")),
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def track_message_sent(model: str = "") -> None:
|
|
148
|
+
"""One event per user prompt sent to the LLM (no content — count only)."""
|
|
149
|
+
track("message_sent", {"model": model})
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def track_tool_used(tool_name: str) -> None:
|
|
153
|
+
"""One event per tool invocation (tool NAME only — never inputs)."""
|
|
154
|
+
track("tool_used", {"tool": tool_name})
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def track_command_used(command: str) -> None:
|
|
158
|
+
"""One event per slash command (command NAME only — never args)."""
|
|
159
|
+
track("command_used", {"command": command})
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def track_model_selected(model: str, provider: str = "") -> None:
|
|
163
|
+
"""Fired when the user switches models via /model."""
|
|
164
|
+
track("model_selected", {"model": model, "provider": provider})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.7.
|
|
3
|
+
Version: 3.7.1
|
|
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
|
|
@@ -130,12 +130,12 @@ dulus_tools/background_tasks.py
|
|
|
130
130
|
dulus_tools/clipboard_utils.py
|
|
131
131
|
dulus_tools/diff_visualizer.py
|
|
132
132
|
dulus_tools/export_import.py
|
|
133
|
-
dulus_tools/fs_compass.py
|
|
134
133
|
dulus_tools/hook_engine.py
|
|
135
134
|
dulus_tools/notification_manager.py
|
|
136
135
|
dulus_tools/session_fork.py
|
|
137
136
|
dulus_tools/shell_mode.py
|
|
138
137
|
dulus_tools/todo_visualizer.py
|
|
138
|
+
dulus_tools/tree_ls.py
|
|
139
139
|
dulus_tools/wire_events.py
|
|
140
140
|
dulus_tools/yolo_mode.py
|
|
141
141
|
gui/__init__.py
|
|
@@ -294,7 +294,6 @@ tests/test_diff_view.py
|
|
|
294
294
|
tests/test_diff_visualization.py
|
|
295
295
|
tests/test_display_blocks.py
|
|
296
296
|
tests/test_export_import.py
|
|
297
|
-
tests/test_fs_compass.py
|
|
298
297
|
tests/test_hook_engine.py
|
|
299
298
|
tests/test_injection_fix.py
|
|
300
299
|
tests/test_license.py
|
|
@@ -313,6 +312,7 @@ tests/test_think_tool.py
|
|
|
313
312
|
tests/test_todo_tool.py
|
|
314
313
|
tests/test_todo_visualization.py
|
|
315
314
|
tests/test_tool_registry.py
|
|
315
|
+
tests/test_tree_ls.py
|
|
316
316
|
tests/test_voice.py
|
|
317
317
|
tests/test_wire_events.py
|
|
318
318
|
ui/__init__.py
|