dulus 3.9.4__tar.gz → 3.10.0__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.
Files changed (339) hide show
  1. {dulus-3.9.4 → dulus-3.10.0}/MANIFEST.in +1 -0
  2. {dulus-3.9.4/dulus.egg-info → dulus-3.10.0}/PKG-INFO +1 -1
  3. {dulus-3.9.4 → dulus-3.10.0}/agent.py +4 -0
  4. {dulus-3.9.4 → dulus-3.10.0}/analytics.py +3 -71
  5. {dulus-3.9.4 → dulus-3.10.0}/docs/CHANGELOG.md +46 -0
  6. {dulus-3.9.4 → dulus-3.10.0}/docs/dashboard/index.html +0 -10
  7. {dulus-3.9.4 → dulus-3.10.0}/docs/index.html +0 -10
  8. {dulus-3.9.4 → dulus-3.10.0}/docs/news.md +6 -0
  9. {dulus-3.9.4 → dulus-3.10.0}/docs/personas/index.html +0 -10
  10. {dulus-3.9.4 → dulus-3.10.0/dulus.egg-info}/PKG-INFO +1 -1
  11. {dulus-3.9.4 → dulus-3.10.0}/dulus.egg-info/SOURCES.txt +5 -1
  12. {dulus-3.9.4 → dulus-3.10.0}/dulus.egg-info/top_level.txt +1 -0
  13. {dulus-3.9.4 → dulus-3.10.0}/dulus_mcp/commands.py +182 -182
  14. {dulus-3.9.4 → dulus-3.10.0}/dulus_mcp/hub.py +845 -845
  15. {dulus-3.9.4 → dulus-3.10.0}/pyproject.toml +2 -1
  16. {dulus-3.9.4 → dulus-3.10.0}/updater.py +178 -178
  17. {dulus-3.9.4 → dulus-3.10.0}/voice/tts.py +30 -1
  18. {dulus-3.9.4 → dulus-3.10.0}/webchat_server.py +98 -68
  19. dulus-3.10.0/webchat_ui/__init__.py +1 -0
  20. dulus-3.10.0/webchat_ui/app.js +1585 -0
  21. dulus-3.10.0/webchat_ui/index.html +349 -0
  22. dulus-3.10.0/webchat_ui/style.css +1802 -0
  23. {dulus-3.9.4 → dulus-3.10.0}/LICENSE +0 -0
  24. {dulus-3.9.4 → dulus-3.10.0}/README.md +0 -0
  25. {dulus-3.9.4 → dulus-3.10.0}/backend/__init__.py +0 -0
  26. {dulus-3.9.4 → dulus-3.10.0}/backend/agents_bridge.py +0 -0
  27. {dulus-3.9.4 → dulus-3.10.0}/backend/compressor.py +0 -0
  28. {dulus-3.9.4 → dulus-3.10.0}/backend/context.py +0 -0
  29. {dulus-3.9.4 → dulus-3.10.0}/backend/githook.py +0 -0
  30. {dulus-3.9.4 → dulus-3.10.0}/backend/marketplace.py +0 -0
  31. {dulus-3.9.4 → dulus-3.10.0}/backend/mempalace_bridge.py +0 -0
  32. {dulus-3.9.4 → dulus-3.10.0}/backend/personas.py +0 -0
  33. {dulus-3.9.4 → dulus-3.10.0}/backend/plugins.py +0 -0
  34. {dulus-3.9.4 → dulus-3.10.0}/backend/server.py +0 -0
  35. {dulus-3.9.4 → dulus-3.10.0}/backend/tasks.py +0 -0
  36. {dulus-3.9.4 → dulus-3.10.0}/batch_api.py +0 -0
  37. {dulus-3.9.4 → dulus-3.10.0}/checkpoint/__init__.py +0 -0
  38. {dulus-3.9.4 → dulus-3.10.0}/checkpoint/hooks.py +0 -0
  39. {dulus-3.9.4 → dulus-3.10.0}/checkpoint/store.py +0 -0
  40. {dulus-3.9.4 → dulus-3.10.0}/checkpoint/types.py +0 -0
  41. {dulus-3.9.4 → dulus-3.10.0}/claude_code_watcher.py +0 -0
  42. {dulus-3.9.4 → dulus-3.10.0}/clipboard_utils.py +0 -0
  43. {dulus-3.9.4 → dulus-3.10.0}/cloudsave.py +0 -0
  44. {dulus-3.9.4 → dulus-3.10.0}/common.py +0 -0
  45. {dulus-3.9.4 → dulus-3.10.0}/compaction.py +0 -0
  46. {dulus-3.9.4 → dulus-3.10.0}/config.py +0 -0
  47. {dulus-3.9.4 → dulus-3.10.0}/context.py +0 -0
  48. {dulus-3.9.4 → dulus-3.10.0}/data/__init__.py +0 -0
  49. {dulus-3.9.4 → dulus-3.10.0}/data/active_persona.json +0 -0
  50. {dulus-3.9.4 → dulus-3.10.0}/data/marketplace.json +0 -0
  51. {dulus-3.9.4 → dulus-3.10.0}/data/personas.json +0 -0
  52. {dulus-3.9.4 → dulus-3.10.0}/data/plugins/__init__.py +0 -0
  53. {dulus-3.9.4 → dulus-3.10.0}/data/plugins/composio/__init__.py +0 -0
  54. {dulus-3.9.4 → dulus-3.10.0}/data/plugins/composio/composio_plugin/__init__.py +0 -0
  55. {dulus-3.9.4 → dulus-3.10.0}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
  56. {dulus-3.9.4 → dulus-3.10.0}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
  57. {dulus-3.9.4 → dulus-3.10.0}/data/plugins/composio/plugin.json +0 -0
  58. {dulus-3.9.4 → dulus-3.10.0}/data/plugins/composio/plugin_tool.py +0 -0
  59. {dulus-3.9.4 → dulus-3.10.0}/data/tasks.json +0 -0
  60. {dulus-3.9.4 → dulus-3.10.0}/docs/API.md +0 -0
  61. {dulus-3.9.4 → dulus-3.10.0}/docs/BRAND_GUIDE.md +0 -0
  62. {dulus-3.9.4 → dulus-3.10.0}/docs/CONTRIBUTING.md +0 -0
  63. {dulus-3.9.4 → dulus-3.10.0}/docs/DEPLOYMENT.md +0 -0
  64. {dulus-3.9.4 → dulus-3.10.0}/docs/Dulus_AI_Whitepaper_(v2.0).pdf +0 -0
  65. {dulus-3.9.4 → dulus-3.10.0}/docs/FAQ.md +0 -0
  66. {dulus-3.9.4 → dulus-3.10.0}/docs/GETTING_STARTED.md +0 -0
  67. {dulus-3.9.4 → dulus-3.10.0}/docs/INVESTOR_BRIEF.md +0 -0
  68. {dulus-3.9.4 → dulus-3.10.0}/docs/README.md +0 -0
  69. {dulus-3.9.4 → dulus-3.10.0}/docs/README_AR.md +0 -0
  70. {dulus-3.9.4 → dulus-3.10.0}/docs/README_EN.md +0 -0
  71. {dulus-3.9.4 → dulus-3.10.0}/docs/README_ES.md +0 -0
  72. {dulus-3.9.4 → dulus-3.10.0}/docs/README_FR.md +0 -0
  73. {dulus-3.9.4 → dulus-3.10.0}/docs/README_JA.md +0 -0
  74. {dulus-3.9.4 → dulus-3.10.0}/docs/README_KO.md +0 -0
  75. {dulus-3.9.4 → dulus-3.10.0}/docs/README_PT.md +0 -0
  76. {dulus-3.9.4 → dulus-3.10.0}/docs/README_RU.md +0 -0
  77. {dulus-3.9.4 → dulus-3.10.0}/docs/README_ZH.md +0 -0
  78. {dulus-3.9.4 → dulus-3.10.0}/docs/SECURITY.md +0 -0
  79. {dulus-3.9.4 → dulus-3.10.0}/docs/__init__.py +0 -0
  80. {dulus-3.9.4 → dulus-3.10.0}/docs/api.html +0 -0
  81. {dulus-3.9.4 → dulus-3.10.0}/docs/architecture.md +0 -0
  82. {dulus-3.9.4 → dulus-3.10.0}/docs/azure-speech-template.json +0 -0
  83. {dulus-3.9.4 → dulus-3.10.0}/docs/divider.svg +0 -0
  84. {dulus-3.9.4 → dulus-3.10.0}/docs/dulus-bird.png +0 -0
  85. {dulus-3.9.4 → dulus-3.10.0}/docs/generate.py +0 -0
  86. {dulus-3.9.4 → dulus-3.10.0}/docs/hero.svg +0 -0
  87. {dulus-3.9.4 → dulus-3.10.0}/docs/nvidia-models.svg +0 -0
  88. {dulus-3.9.4 → dulus-3.10.0}/docs/particle-playground.html +0 -0
  89. {dulus-3.9.4 → dulus-3.10.0}/docs/poetry-banner.png +0 -0
  90. {dulus-3.9.4 → dulus-3.10.0}/docs/preview.html +0 -0
  91. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-agents.svg +0 -0
  92. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-brainstorm.svg +0 -0
  93. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-bridges.svg +0 -0
  94. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-features.svg +0 -0
  95. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-freetier.svg +0 -0
  96. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-memory.svg +0 -0
  97. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-models.svg +0 -0
  98. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-perms.svg +0 -0
  99. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-plugins.svg +0 -0
  100. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-quickstart.svg +0 -0
  101. {dulus-3.9.4 → dulus-3.10.0}/docs/sec-ssj.svg +0 -0
  102. {dulus-3.9.4 → dulus-3.10.0}/docs/spinners.svg +0 -0
  103. {dulus-3.9.4 → dulus-3.10.0}/docs/split-pane.svg +0 -0
  104. {dulus-3.9.4 → dulus-3.10.0}/docs/terminal-boot.svg +0 -0
  105. {dulus-3.9.4 → dulus-3.10.0}/dulus.egg-info/dependency_links.txt +0 -0
  106. {dulus-3.9.4 → dulus-3.10.0}/dulus.egg-info/entry_points.txt +0 -0
  107. {dulus-3.9.4 → dulus-3.10.0}/dulus.egg-info/requires.txt +0 -0
  108. {dulus-3.9.4 → dulus-3.10.0}/dulus.py +0 -0
  109. {dulus-3.9.4 → dulus-3.10.0}/dulus_gui.py +0 -0
  110. {dulus-3.9.4 → dulus-3.10.0}/dulus_gui_web.py +0 -0
  111. {dulus-3.9.4 → dulus-3.10.0}/dulus_mcp/__init__.py +0 -0
  112. {dulus-3.9.4 → dulus-3.10.0}/dulus_mcp/client.py +0 -0
  113. {dulus-3.9.4 → dulus-3.10.0}/dulus_mcp/config.py +0 -0
  114. {dulus-3.9.4 → dulus-3.10.0}/dulus_mcp/tools.py +0 -0
  115. {dulus-3.9.4 → dulus-3.10.0}/dulus_mcp/types.py +0 -0
  116. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/__init__.py +0 -0
  117. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/add_dir_manager.py +0 -0
  118. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/afk_mode.py +0 -0
  119. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/approval_runtime.py +0 -0
  120. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/background_tasks.py +0 -0
  121. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/clipboard_utils.py +0 -0
  122. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/diff_visualizer.py +0 -0
  123. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/export_import.py +0 -0
  124. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/hook_engine.py +0 -0
  125. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/notification_manager.py +0 -0
  126. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/session_fork.py +0 -0
  127. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/shell_mode.py +0 -0
  128. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/todo_visualizer.py +0 -0
  129. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/tree_ls.py +0 -0
  130. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/wire_events.py +0 -0
  131. {dulus-3.9.4 → dulus-3.10.0}/dulus_tools/yolo_mode.py +0 -0
  132. {dulus-3.9.4 → dulus-3.10.0}/governance.py +0 -0
  133. {dulus-3.9.4 → dulus-3.10.0}/gui/__init__.py +0 -0
  134. {dulus-3.9.4 → dulus-3.10.0}/gui/agent_bridge.py +0 -0
  135. {dulus-3.9.4 → dulus-3.10.0}/gui/chat_widget.py +0 -0
  136. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/App.tsx +0 -0
  137. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/THIRD_PARTY_NOTICES.md +0 -0
  138. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/dist/index.html +0 -0
  139. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/dist/standalone.html +0 -0
  140. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/index.html +0 -0
  141. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/index.tsx +0 -0
  142. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/metadata.json +0 -0
  143. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/package-lock.json +0 -0
  144. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/package.json +0 -0
  145. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/types.ts +0 -0
  146. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/utils.ts +0 -0
  147. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/vertex-ai-proxy-interceptor.js +0 -0
  148. {dulus-3.9.4 → dulus-3.10.0}/gui/dulus_orchestrator/vite.config.ts +0 -0
  149. {dulus-3.9.4 → dulus-3.10.0}/gui/main_window.py +0 -0
  150. {dulus-3.9.4 → dulus-3.10.0}/gui/personas.py +0 -0
  151. {dulus-3.9.4 → dulus-3.10.0}/gui/sandbox_server.py +0 -0
  152. {dulus-3.9.4 → dulus-3.10.0}/gui/session_utils.py +0 -0
  153. {dulus-3.9.4 → dulus-3.10.0}/gui/settings_dialog.py +0 -0
  154. {dulus-3.9.4 → dulus-3.10.0}/gui/sidebar.py +0 -0
  155. {dulus-3.9.4 → dulus-3.10.0}/gui/tasks_view.py +0 -0
  156. {dulus-3.9.4 → dulus-3.10.0}/gui/themes.py +0 -0
  157. {dulus-3.9.4 → dulus-3.10.0}/gui/tool_panel.py +0 -0
  158. {dulus-3.9.4 → dulus-3.10.0}/input.py +0 -0
  159. {dulus-3.9.4 → dulus-3.10.0}/license_manager.py +0 -0
  160. {dulus-3.9.4 → dulus-3.10.0}/memory/__init__.py +0 -0
  161. {dulus-3.9.4 → dulus-3.10.0}/memory/audit.py +0 -0
  162. {dulus-3.9.4 → dulus-3.10.0}/memory/consolidator.py +0 -0
  163. {dulus-3.9.4 → dulus-3.10.0}/memory/context.py +0 -0
  164. {dulus-3.9.4 → dulus-3.10.0}/memory/offload.py +0 -0
  165. {dulus-3.9.4 → dulus-3.10.0}/memory/palace.py +0 -0
  166. {dulus-3.9.4 → dulus-3.10.0}/memory/scan.py +0 -0
  167. {dulus-3.9.4 → dulus-3.10.0}/memory/sessions.py +0 -0
  168. {dulus-3.9.4 → dulus-3.10.0}/memory/store.py +0 -0
  169. {dulus-3.9.4 → dulus-3.10.0}/memory/tools.py +0 -0
  170. {dulus-3.9.4 → dulus-3.10.0}/memory/types.py +0 -0
  171. {dulus-3.9.4 → dulus-3.10.0}/memory/vector_search.py +0 -0
  172. {dulus-3.9.4 → dulus-3.10.0}/multi_agent/__init__.py +0 -0
  173. {dulus-3.9.4 → dulus-3.10.0}/multi_agent/subagent.py +0 -0
  174. {dulus-3.9.4 → dulus-3.10.0}/multi_agent/tools.py +0 -0
  175. {dulus-3.9.4 → dulus-3.10.0}/offload_helper.py +0 -0
  176. {dulus-3.9.4 → dulus-3.10.0}/personality_config.py +0 -0
  177. {dulus-3.9.4 → dulus-3.10.0}/plugin/__init__.py +0 -0
  178. {dulus-3.9.4 → dulus-3.10.0}/plugin/autoadapter.py +0 -0
  179. {dulus-3.9.4 → dulus-3.10.0}/plugin/loader.py +0 -0
  180. {dulus-3.9.4 → dulus-3.10.0}/plugin/recommend.py +0 -0
  181. {dulus-3.9.4 → dulus-3.10.0}/plugin/store.py +0 -0
  182. {dulus-3.9.4 → dulus-3.10.0}/plugin/types.py +0 -0
  183. {dulus-3.9.4 → dulus-3.10.0}/providers.py +0 -0
  184. {dulus-3.9.4 → dulus-3.10.0}/sandbox/README.md +0 -0
  185. {dulus-3.9.4 → dulus-3.10.0}/sandbox/__init__.py +0 -0
  186. {dulus-3.9.4 → dulus-3.10.0}/sandbox/components.json +0 -0
  187. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
  188. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
  189. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/index.html +0 -0
  190. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/wallpaper-default.jpg +0 -0
  191. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/wallpapers/default.jpeg +0 -0
  192. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/wallpapers/light.jpeg +0 -0
  193. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/wallpapers/nature.jpeg +0 -0
  194. {dulus-3.9.4 → dulus-3.10.0}/sandbox/dist/wallpapers/tech.jpeg +0 -0
  195. {dulus-3.9.4 → dulus-3.10.0}/sandbox/eslint.config.js +0 -0
  196. {dulus-3.9.4 → dulus-3.10.0}/sandbox/index.html +0 -0
  197. {dulus-3.9.4 → dulus-3.10.0}/sandbox/info.md +0 -0
  198. {dulus-3.9.4 → dulus-3.10.0}/sandbox/package-lock.json +0 -0
  199. {dulus-3.9.4 → dulus-3.10.0}/sandbox/package.json +0 -0
  200. {dulus-3.9.4 → dulus-3.10.0}/sandbox/postcss.config.js +0 -0
  201. {dulus-3.9.4 → dulus-3.10.0}/sandbox/tailwind.config.js +0 -0
  202. {dulus-3.9.4 → dulus-3.10.0}/sandbox/tsconfig.app.json +0 -0
  203. {dulus-3.9.4 → dulus-3.10.0}/sandbox/tsconfig.json +0 -0
  204. {dulus-3.9.4 → dulus-3.10.0}/sandbox/tsconfig.node.json +0 -0
  205. {dulus-3.9.4 → dulus-3.10.0}/sandbox/vite.config.ts +0 -0
  206. {dulus-3.9.4 → dulus-3.10.0}/sandbox_bootstrap.py +0 -0
  207. {dulus-3.9.4 → dulus-3.10.0}/setup.cfg +0 -0
  208. {dulus-3.9.4 → dulus-3.10.0}/skill/__init__.py +0 -0
  209. {dulus-3.9.4 → dulus-3.10.0}/skill/builtin.py +0 -0
  210. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/LICENSE-obsidian-skills +0 -0
  211. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/README.md +0 -0
  212. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/defuddle/SKILL.md +0 -0
  213. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/json-canvas/SKILL.md +0 -0
  214. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/json-canvas/references/EXAMPLES.md +0 -0
  215. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/obsidian-bases/SKILL.md +0 -0
  216. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -0
  217. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/obsidian-cli/SKILL.md +0 -0
  218. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/obsidian-markdown/SKILL.md +0 -0
  219. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/obsidian-markdown/references/CALLOUTS.md +0 -0
  220. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/obsidian-markdown/references/EMBEDS.md +0 -0
  221. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/obsidian-markdown/references/PROPERTIES.md +0 -0
  222. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/README.md +0 -0
  223. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/SKILL.md +0 -0
  224. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/addresses.json +0 -0
  225. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/advancedbackgroundchecks.json +0 -0
  226. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/beenverified.json +0 -0
  227. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/clustal.json +0 -0
  228. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/clustrmaps.json +0 -0
  229. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/cyberbackgroundchecks.json +0 -0
  230. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/familytreenow.json +0 -0
  231. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/fastpeoplesearch.json +0 -0
  232. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/intelius.json +0 -0
  233. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/mylife.json +0 -0
  234. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/nuwber.json +0 -0
  235. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/peekyou.json +0 -0
  236. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/peoplefinders.json +0 -0
  237. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/radaris.json +0 -0
  238. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/rehold.json +0 -0
  239. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/searchpeoplefree.json +0 -0
  240. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/socialcatfish.json +0 -0
  241. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/spokeo.json +0 -0
  242. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/thatsthem.json +0 -0
  243. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/truepeoplesearch.json +0 -0
  244. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/usphonebook.json +0 -0
  245. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/brokers/whitepages.json +0 -0
  246. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/legal/ccpa.md +0 -0
  247. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/legal/drop.md +0 -0
  248. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/legal/gdpr.md +0 -0
  249. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/methods.md +0 -0
  250. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/site-playbooks.md +0 -0
  251. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/references/state-machine.md +0 -0
  252. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/autopilot.py +0 -0
  253. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/badbool.py +0 -0
  254. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/brokers.py +0 -0
  255. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/cdp.py +0 -0
  256. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/config.py +0 -0
  257. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/crypto.py +0 -0
  258. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/dossier.py +0 -0
  259. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/email_modes.py +0 -0
  260. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/emailer.py +0 -0
  261. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/ledger.py +0 -0
  262. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/legal.py +0 -0
  263. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/paths.py +0 -0
  264. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/pdd.py +0 -0
  265. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/registry.py +0 -0
  266. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/report.py +0 -0
  267. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/scan.py +0 -0
  268. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/storage.py +0 -0
  269. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/tiers.py +0 -0
  270. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/scripts/vectors.py +0 -0
  271. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/templates/consent/authorization.md +0 -0
  272. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/templates/emails/ccpa-authorized-agent.txt +0 -0
  273. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/templates/emails/ccpa-deletion.txt +0 -0
  274. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/templates/emails/ccpa-indirect-deletion.txt +0 -0
  275. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/templates/emails/gdpr-erasure.txt +0 -0
  276. {dulus-3.9.4 → dulus-3.10.0}/skill/bundled/unbroker/templates/emails/generic-optout.txt +0 -0
  277. {dulus-3.9.4 → dulus-3.10.0}/skill/clawhub.py +0 -0
  278. {dulus-3.9.4 → dulus-3.10.0}/skill/executor.py +0 -0
  279. {dulus-3.9.4 → dulus-3.10.0}/skill/loader.py +0 -0
  280. {dulus-3.9.4 → dulus-3.10.0}/skill/tools.py +0 -0
  281. {dulus-3.9.4 → dulus-3.10.0}/skills.py +0 -0
  282. {dulus-3.9.4 → dulus-3.10.0}/soul.py +0 -0
  283. {dulus-3.9.4 → dulus-3.10.0}/spinner.py +0 -0
  284. {dulus-3.9.4 → dulus-3.10.0}/string_utils.py +0 -0
  285. {dulus-3.9.4 → dulus-3.10.0}/subagent.py +0 -0
  286. {dulus-3.9.4 → dulus-3.10.0}/task/__init__.py +0 -0
  287. {dulus-3.9.4 → dulus-3.10.0}/task/store.py +0 -0
  288. {dulus-3.9.4 → dulus-3.10.0}/task/tools.py +0 -0
  289. {dulus-3.9.4 → dulus-3.10.0}/task/types.py +0 -0
  290. {dulus-3.9.4 → dulus-3.10.0}/tests/test_afk_yolo.py +0 -0
  291. {dulus-3.9.4 → dulus-3.10.0}/tests/test_approval_runtime.py +0 -0
  292. {dulus-3.9.4 → dulus-3.10.0}/tests/test_background_task_tools.py +0 -0
  293. {dulus-3.9.4 → dulus-3.10.0}/tests/test_background_tasks.py +0 -0
  294. {dulus-3.9.4 → dulus-3.10.0}/tests/test_checkpoint.py +0 -0
  295. {dulus-3.9.4 → dulus-3.10.0}/tests/test_clipboard_utils.py +0 -0
  296. {dulus-3.9.4 → dulus-3.10.0}/tests/test_compaction.py +0 -0
  297. {dulus-3.9.4 → dulus-3.10.0}/tests/test_diff_view.py +0 -0
  298. {dulus-3.9.4 → dulus-3.10.0}/tests/test_diff_visualization.py +0 -0
  299. {dulus-3.9.4 → dulus-3.10.0}/tests/test_display_blocks.py +0 -0
  300. {dulus-3.9.4 → dulus-3.10.0}/tests/test_export_import.py +0 -0
  301. {dulus-3.9.4 → dulus-3.10.0}/tests/test_hook_engine.py +0 -0
  302. {dulus-3.9.4 → dulus-3.10.0}/tests/test_injection_fix.py +0 -0
  303. {dulus-3.9.4 → dulus-3.10.0}/tests/test_license.py +0 -0
  304. {dulus-3.9.4 → dulus-3.10.0}/tests/test_mcp.py +0 -0
  305. {dulus-3.9.4 → dulus-3.10.0}/tests/test_memory.py +0 -0
  306. {dulus-3.9.4 → dulus-3.10.0}/tests/test_notification_manager.py +0 -0
  307. {dulus-3.9.4 → dulus-3.10.0}/tests/test_plugin.py +0 -0
  308. {dulus-3.9.4 → dulus-3.10.0}/tests/test_session_fork.py +0 -0
  309. {dulus-3.9.4 → dulus-3.10.0}/tests/test_shell_mode.py +0 -0
  310. {dulus-3.9.4 → dulus-3.10.0}/tests/test_skills.py +0 -0
  311. {dulus-3.9.4 → dulus-3.10.0}/tests/test_steer_input.py +0 -0
  312. {dulus-3.9.4 → dulus-3.10.0}/tests/test_subagent.py +0 -0
  313. {dulus-3.9.4 → dulus-3.10.0}/tests/test_task.py +0 -0
  314. {dulus-3.9.4 → dulus-3.10.0}/tests/test_telegram_buffer.py +0 -0
  315. {dulus-3.9.4 → dulus-3.10.0}/tests/test_think_tool.py +0 -0
  316. {dulus-3.9.4 → dulus-3.10.0}/tests/test_todo_tool.py +0 -0
  317. {dulus-3.9.4 → dulus-3.10.0}/tests/test_todo_visualization.py +0 -0
  318. {dulus-3.9.4 → dulus-3.10.0}/tests/test_tool_registry.py +0 -0
  319. {dulus-3.9.4 → dulus-3.10.0}/tests/test_tree_ls.py +0 -0
  320. {dulus-3.9.4 → dulus-3.10.0}/tests/test_voice.py +0 -0
  321. {dulus-3.9.4 → dulus-3.10.0}/tests/test_wire_events.py +0 -0
  322. {dulus-3.9.4 → dulus-3.10.0}/tmux_offloader.py +0 -0
  323. {dulus-3.9.4 → dulus-3.10.0}/tmux_tools.py +0 -0
  324. {dulus-3.9.4 → dulus-3.10.0}/tool_registry.py +0 -0
  325. {dulus-3.9.4 → dulus-3.10.0}/tools.py +0 -0
  326. {dulus-3.9.4 → dulus-3.10.0}/ui/__init__.py +0 -0
  327. {dulus-3.9.4 → dulus-3.10.0}/ui/input.py +0 -0
  328. {dulus-3.9.4 → dulus-3.10.0}/ui/render.py +0 -0
  329. {dulus-3.9.4 → dulus-3.10.0}/voice/__init__.py +0 -0
  330. {dulus-3.9.4 → dulus-3.10.0}/voice/audio_utils.py +0 -0
  331. {dulus-3.9.4 → dulus-3.10.0}/voice/keyterms.py +0 -0
  332. {dulus-3.9.4 → dulus-3.10.0}/voice/recorder.py +0 -0
  333. {dulus-3.9.4 → dulus-3.10.0}/voice/stt.py +0 -0
  334. {dulus-3.9.4 → dulus-3.10.0}/voice/wake_word.py +0 -0
  335. {dulus-3.9.4 → dulus-3.10.0}/webbridge/__init__.py +0 -0
  336. {dulus-3.9.4 → dulus-3.10.0}/webbridge/core.py +0 -0
  337. {dulus-3.9.4 → dulus-3.10.0}/webbridge/tools.py +0 -0
  338. {dulus-3.9.4 → dulus-3.10.0}/webchat.py +0 -0
  339. {dulus-3.9.4 → dulus-3.10.0}/welcome.py +0 -0
@@ -6,5 +6,6 @@ recursive-include gui/dulus_orchestrator/dist *
6
6
  exclude gui/dulus_orchestrator/dist/runtime-state.js
7
7
  exclude gui/dulus_orchestrator/dist/desktop-pet.html
8
8
  recursive-include webbridge *
9
+ recursive-include webchat_ui *.html *.css *.js
9
10
  global-exclude __pycache__/*
10
11
  global-exclude *.pyc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 3.9.4
3
+ Version: 3.10.0
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
@@ -162,6 +162,8 @@ def run(
162
162
  tool_schemas=get_tool_schemas(),
163
163
  config=config,
164
164
  )):
165
+ if cancel_check and cancel_check():
166
+ return
165
167
  if isinstance(event, (TextChunk, ThinkingChunk)):
166
168
  yield event
167
169
  elif isinstance(event, AssistantTurn):
@@ -217,6 +219,8 @@ def run(
217
219
 
218
220
  # ── Execute tools ────────────────────────────────────────────────
219
221
  for tc in assistant_turn.tool_calls:
222
+ if cancel_check and cancel_check():
223
+ return
220
224
  yield ToolStart(tc["name"], tc["input"])
221
225
 
222
226
  # ── Governance gate (capabilities + pre_tool hook) ───────────────
@@ -29,7 +29,6 @@ silently ignored; telemetry must never slow down or break Dulus.
29
29
  from __future__ import annotations
30
30
 
31
31
  import base64
32
- import datetime as _dt
33
32
  import json
34
33
  import os
35
34
  import platform
@@ -46,23 +45,6 @@ MP_TOKEN = os.environ.get("DULUS_MP_TOKEN", "966ce8f5ccb32f06788f51be9f8bf8f5")
46
45
 
47
46
  _MP_ENDPOINT = "https://api.mixpanel.com/track"
48
47
 
49
- # ── PostHog (product analytics, runs alongside Mixpanel) ────────────────────
50
- # Project API keys (phc_...) are public/write-only by design — meant to ship in
51
- # client code, cannot read data. Override with DULUS_POSTHOG_KEY.
52
- POSTHOG_KEY = os.environ.get(
53
- "DULUS_POSTHOG_KEY", "phc_yqAJ42vbj8YFkdpxZicsS4asdbWFTPy6orR8uRNewfYD"
54
- )
55
- _POSTHOG_ENDPOINT = os.environ.get(
56
- "DULUS_POSTHOG_HOST", "https://us.i.posthog.com"
57
- ).rstrip("/") + "/capture/"
58
-
59
- # ── Amplitude (behavioral analytics, runs alongside the others) ─────────────
60
- # API keys are write-only client keys (safe to ship). Override w/ DULUS_AMPLITUDE_KEY.
61
- AMPLITUDE_KEY = os.environ.get(
62
- "DULUS_AMPLITUDE_KEY", "2511c9e1fc597b8bc6b81f193cc615a2"
63
- )
64
- _AMPLITUDE_ENDPOINT = "https://api2.amplitude.com/2/httpapi"
65
-
66
48
  # Populated by init_telemetry(); None = not initialised / disabled.
67
49
  _distinct_id: str | None = None
68
50
  _enabled: bool = False
@@ -139,11 +121,10 @@ def track(event: str, properties: dict | None = None) -> None:
139
121
  }
140
122
 
141
123
  def _send() -> None:
142
- from urllib.request import Request, urlopen
143
- from urllib.parse import urlencode
144
-
145
- # Mixpanel
146
124
  try:
125
+ from urllib.request import Request, urlopen
126
+ from urllib.parse import urlencode
127
+
147
128
  data = urlencode(
148
129
  {"data": base64.b64encode(json.dumps([payload]).encode()).decode()}
149
130
  ).encode()
@@ -152,55 +133,6 @@ def track(event: str, properties: dict | None = None) -> None:
152
133
  except Exception:
153
134
  pass # telemetry must never break Dulus
154
135
 
155
- # PostHog (same event, product-analytics brain)
156
- if POSTHOG_KEY:
157
- try:
158
- ph_props = {
159
- "dulus_version": _dulus_version,
160
- "os": platform.system(),
161
- "python": f"{sys.version_info.major}.{sys.version_info.minor}",
162
- "$process_person_profile": False, # anonymous, no PII person
163
- **(properties or {}),
164
- }
165
- ph_payload = {
166
- "api_key": POSTHOG_KEY,
167
- "event": event,
168
- "distinct_id": _distinct_id,
169
- "properties": ph_props,
170
- "timestamp": _dt.datetime.utcnow().isoformat() + "Z",
171
- }
172
- ph_data = json.dumps(ph_payload).encode()
173
- ph_req = Request(
174
- _POSTHOG_ENDPOINT, data=ph_data, method="POST",
175
- headers={"Content-Type": "application/json"},
176
- )
177
- urlopen(ph_req, timeout=4).read()
178
- except Exception:
179
- pass # telemetry must never break Dulus
180
-
181
- # Amplitude (same event, behavioral-analytics brain)
182
- if AMPLITUDE_KEY:
183
- try:
184
- amp_event = {
185
- "user_id": (_distinct_id or "anon").ljust(5, "_"), # min 5 chars
186
- "event_type": event,
187
- "platform": platform.system(),
188
- "app_version": _dulus_version,
189
- "event_properties": (properties or {}),
190
- }
191
- amp_payload = {
192
- "api_key": AMPLITUDE_KEY,
193
- "events": [amp_event],
194
- }
195
- amp_data = json.dumps(amp_payload).encode()
196
- amp_req = Request(
197
- _AMPLITUDE_ENDPOINT, data=amp_data, method="POST",
198
- headers={"Content-Type": "application/json"},
199
- )
200
- urlopen(amp_req, timeout=4).read()
201
- except Exception:
202
- pass # telemetry must never break Dulus
203
-
204
136
  threading.Thread(target=_send, daemon=True, name="telemetry").start()
205
137
 
206
138
 
@@ -15,6 +15,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
15
  - Security policy
16
16
  - Brand guidelines
17
17
 
18
+ ## [3.9.5] - 2026-07-11
19
+
20
+ ### Fixed
21
+ - TTS `c` cancel key not working while the REPL prompt was active:
22
+ `msvcrt.kbhit()` only sees keystrokes when the raw console owns stdin, so
23
+ prompt_toolkit swallowed the `c` before the watcher saw it. Added a second
24
+ detection path via `GetAsyncKeyState` (physical key state, edge-detected)
25
+ that fires regardless of who owns stdin, plus a 30ms sleep so the watcher
26
+ no longer busy-spins a CPU core during playback.
27
+
28
+ ## [3.9.4] - 2026-07-11
29
+
30
+ ### Fixed
31
+ - Catastrophic config reset: `save_config()` wrote the caller's dict verbatim,
32
+ so a thin dict (e.g. only `lang` + `user_name` at early startup) silently
33
+ wiped every other key — API keys, voice config, everything. Now it merges
34
+ DEFAULTS + on-disk config first (with `.bak` fallback if the on-disk copy
35
+ is corrupt), then applies runtime changes on top.
36
+
37
+ ## [3.9.3] - 2026-07-11
38
+
39
+ ### Fixed
40
+ - `/lang` was silently overpowered by `soul.md` / gold memories that assert a
41
+ voice ("I speak Dominican Spanish"). The chosen language is now re-asserted
42
+ at the end of the system prompt (highest-authority position) and `/lang`
43
+ injects an immediate directive into the live conversation so the switch
44
+ takes effect the same turn. Defaults untouched — no `/lang` set means the
45
+ soul keeps control.
46
+
47
+ ## [3.9.2] - 2026-07-11
48
+
49
+ ### Added
50
+ - `/update` self-update command: quiet cached (6h TTL) non-blocking PyPI check
51
+ on startup, in-place upgrade, `now|check|status|on|off` subcommands.
52
+
53
+ ## [3.9.0] - 2026-07-11
54
+
55
+ ### Added
56
+ - MCP Marketplace: `/mcp list|search|install` over a live catalog of 2000+
57
+ servers from registry.modelcontextprotocol.io + awesome-mcp, deduped,
58
+ 6h-TTL cached, offline-safe. One-shot install: resolve command, write
59
+ config, connect, verify tools, hot-reload into the live session.
60
+
61
+ ### Fixed
62
+ - Windows launcher for node-based MCP servers (`npx` ships as `npx.cmd`).
63
+
18
64
  ## [3.6.2] - 2026-07-04
19
65
 
20
66
  ### Fixed
@@ -2,16 +2,6 @@
2
2
  <html lang="en">
3
3
 
4
4
  <head>
5
- <!-- Amplitude behavioral analytics -->
6
- <script src="https://cdn.amplitude.com/script/2511c9e1fc597b8bc6b81f193cc615a2.js"></script>
7
- <script>window.amplitude&&window.amplitude.init&&window.amplitude.init('2511c9e1fc597b8bc6b81f193cc615a2',{"fetchRemoteConfig":true,"autocapture":true});</script>
8
-
9
- <!-- PostHog product analytics -->
10
- <script>
11
- !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture identify reset get_distinct_id capture_pageview capture_pageleave".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
12
- posthog.init('phc_yqAJ42vbj8YFkdpxZicsS4asdbWFTPy6orR8uRNewfYD',{api_host:'https://us.i.posthog.com',person_profiles:'identified_only',capture_pageview:true,capture_pageleave:true});
13
- </script>
14
-
15
5
  <meta charset="UTF-8">
16
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
17
7
  <title>Dulus — Task Dashboard</title>
@@ -1,16 +1,6 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <!-- Amplitude behavioral analytics -->
5
- <script src="https://cdn.amplitude.com/script/2511c9e1fc597b8bc6b81f193cc615a2.js"></script>
6
- <script>window.amplitude&&window.amplitude.init&&window.amplitude.init('2511c9e1fc597b8bc6b81f193cc615a2',{"fetchRemoteConfig":true,"autocapture":true});</script>
7
-
8
- <!-- PostHog product analytics -->
9
- <script>
10
- !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture identify reset get_distinct_id capture_pageview capture_pageleave".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
11
- posthog.init('phc_yqAJ42vbj8YFkdpxZicsS4asdbWFTPy6orR8uRNewfYD',{api_host:'https://us.i.posthog.com',person_profiles:'identified_only',capture_pageview:true,capture_pageleave:true});
12
- </script>
13
-
14
4
  <meta charset="UTF-8">
15
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
6
  <title>Dulus — Hunt. Patch. Ship.</title>
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## 🔥🔥🔥 News (Pacific Time)
4
4
 
5
+ - July 11, 2026 (**v3.9.5**): **⏹ The `c` key now ALWAYS stops the voice.** Pressing `c` to cancel TTS playback only worked *sometimes* — and the reason was sneaky: the cancel watcher listened via `msvcrt.kbhit()`, which only sees keystrokes when the raw console owns stdin. With the fancy REPL prompt (prompt_toolkit) active, the prompt swallowed your `c` before the watcher ever saw it, and you were stuck listening to the whole monologue. Now there's a second detection path reading the **physical key state straight from the OS** (`GetAsyncKeyState`, edge-detected so a held key doesn't retrigger) — it fires no matter who owns stdin. Bonus: the watcher loop now sleeps 30ms per tick instead of busy-spinning a full CPU core while audio plays. Press `c`, voice dies, instantly, every time. 🦅🇩🇴
6
+
7
+ - July 11, 2026 (**v3.9.4**): **🛡️ Killed the config-wipe bug for real this time.** v3.6.1 made config writes atomic — but there was a second, nastier path to the same disaster: `save_config()` wrote the caller's dict **verbatim**. If anything called it with a thin dict (early startup, a command that rebuilt a minimal config), every other key you owned — API keys, voice config, provider settings, all of it — silently vanished, shrinking `config.json` to 2 keys. No crash needed; a perfectly successful write was the weapon. Now `save_config()` merges DEFAULTS + whatever is already on disk FIRST (with `.bak` fallback if the on-disk copy is corrupt), then applies the runtime changes on top. A thin save physically cannot drop your keys anymore. If your config ever mysteriously "reset itself": this was it, and it's dead now. 🦅🇩🇴
8
+
9
+ - July 11, 2026 (**v3.9.3**): **🗣️ `/lang` now beats your soul.** If you customized your Dulus with a `soul.md` or gold memories that assert a voice ("I speak Dominican Spanish"), those conversation-injected identities quietly overpowered the one language line at the top of the system prompt — so `/lang en` looked like it did nothing and Dulus kept replying in the soul's tongue. Two-layer fix: the chosen language is now re-asserted at the **end** of the system prompt (highest-authority position) explicitly overriding soul/essence/gold-memory language claims, AND `/lang` injects an immediate directive into the live conversation so the switch lands **the same turn** — not next session. Default setups are untouched: no `/lang` set means your soul keeps full control of the voice. 🦅🇩🇴
10
+
5
11
  - July 11, 2026: **🔄 Self-update — every Dulus stays on the latest, automatically.** The whole point of the organism is that a fix found by one Dulus reaches every other Dulus fast. So now Dulus keeps *itself* current: on startup it does a quiet, cached (6h TTL), non-blocking check against PyPI, and if there's a newer release it upgrades in place — no `pip install -U` dance, no stale nodes drifting behind. New `/update` command with everything you'd expect: `/update` (check + upgrade if newer), `/update now` (force), `/update check` (look but don't touch), `/update status` (see installed vs latest), and `/update on|off` to toggle the automatic startup check (on by default). Handles PEP 668 externally-managed Pythons automatically, and the check *never* blocks or crashes your boot — if PyPI is down or you're offline, Dulus just carries on. The fleet moves as one. 🦅🇩🇴
6
12
 
7
13
  - July 11, 2026: **🔌 MCP Marketplace — 2000+ servers, zero friction, install by name.** MCP (Model Context Protocol) was always one of Dulus's most powerful features and almost nobody used it — the friction killed it. You had to *find* a server somewhere, dig up its exact launch command, hand-edit a `.mcp.json`, and pray it connected. Dead on arrival. So we built a real marketplace on top of it. `/mcp list` and `/mcp search <anything>` now browse a live catalog of **2000+ servers** pulled from the official [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io) (the metaregistry backed by Anthropic, GitHub, Microsoft & PulseMCP) plus the community awesome-mcp list — deduped, cached with a 6h TTL, and **offline-safe** (falls back to a curated set if you're on a plane). Then `/mcp install <name>` does the whole thing in one shot: resolves the launch command, writes the config, **connects, verifies the tools, and hot-reloads them live into your current session** — no restart, no JSON, no manual anything. `/mcp installed` shows what's live with a green/red status dot, `/mcp runtimes` tells you which runtimes (node/python/docker) you've got. Also shipped a Windows launcher fix so node-based servers (`npx`, which ships as `npx.cmd` on Windows) actually start instead of silently failing — probably the real reason MCP "never worked" for a lot of Windows users. From *"I've never touched MCP"* to *"connected in 5 seconds."* 🦅🇩🇴
@@ -1,16 +1,6 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <!-- Amplitude behavioral analytics -->
5
- <script src="https://cdn.amplitude.com/script/2511c9e1fc597b8bc6b81f193cc615a2.js"></script>
6
- <script>window.amplitude&&window.amplitude.init&&window.amplitude.init('2511c9e1fc597b8bc6b81f193cc615a2',{"fetchRemoteConfig":true,"autocapture":true});</script>
7
-
8
- <!-- PostHog product analytics -->
9
- <script>
10
- !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture identify reset get_distinct_id capture_pageview capture_pageleave".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
11
- posthog.init('phc_yqAJ42vbj8YFkdpxZicsS4asdbWFTPy6orR8uRNewfYD',{api_host:'https://us.i.posthog.com',person_profiles:'identified_only',capture_pageview:true,capture_pageleave:true});
12
- </script>
13
-
14
4
  <meta charset="UTF-8">
15
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
6
  <title>Mesa Redonda — Dulus Personas</title>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 3.9.4
3
+ Version: 3.10.0
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
@@ -330,4 +330,8 @@ voice/tts.py
330
330
  voice/wake_word.py
331
331
  webbridge/__init__.py
332
332
  webbridge/core.py
333
- webbridge/tools.py
333
+ webbridge/tools.py
334
+ webchat_ui/__init__.py
335
+ webchat_ui/app.js
336
+ webchat_ui/index.html
337
+ webchat_ui/style.css
@@ -47,4 +47,5 @@ voice
47
47
  webbridge
48
48
  webchat
49
49
  webchat_server
50
+ webchat_ui
50
51
  welcome