dulus 3.11.2__tar.gz → 3.11.3__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 (393) hide show
  1. {dulus-3.11.2/dulus.egg-info → dulus-3.11.3}/PKG-INFO +1 -1
  2. {dulus-3.11.2 → dulus-3.11.3/dulus.egg-info}/PKG-INFO +1 -1
  3. {dulus-3.11.2 → dulus-3.11.3}/dulus.egg-info/SOURCES.txt +1 -0
  4. {dulus-3.11.2 → dulus-3.11.3}/dulus.py +37 -6
  5. {dulus-3.11.2 → dulus-3.11.3}/providers.py +0 -25
  6. {dulus-3.11.2 → dulus-3.11.3}/pyproject.toml +247 -247
  7. dulus-3.11.3/tests/test_dulus_account.py +183 -0
  8. {dulus-3.11.2 → dulus-3.11.3}/tests/test_provider_errors.py +0 -52
  9. {dulus-3.11.2 → dulus-3.11.3}/LICENSE +0 -0
  10. {dulus-3.11.2 → dulus-3.11.3}/MANIFEST.in +0 -0
  11. {dulus-3.11.2 → dulus-3.11.3}/README.md +0 -0
  12. {dulus-3.11.2 → dulus-3.11.3}/agent.py +0 -0
  13. {dulus-3.11.2 → dulus-3.11.3}/algolia_search.py +0 -0
  14. {dulus-3.11.2 → dulus-3.11.3}/analytics.py +0 -0
  15. {dulus-3.11.2 → dulus-3.11.3}/backend/__init__.py +0 -0
  16. {dulus-3.11.2 → dulus-3.11.3}/backend/agents_bridge.py +0 -0
  17. {dulus-3.11.2 → dulus-3.11.3}/backend/compressor.py +0 -0
  18. {dulus-3.11.2 → dulus-3.11.3}/backend/context.py +0 -0
  19. {dulus-3.11.2 → dulus-3.11.3}/backend/githook.py +0 -0
  20. {dulus-3.11.2 → dulus-3.11.3}/backend/marketplace.py +0 -0
  21. {dulus-3.11.2 → dulus-3.11.3}/backend/mempalace_bridge.py +0 -0
  22. {dulus-3.11.2 → dulus-3.11.3}/backend/paths.py +0 -0
  23. {dulus-3.11.2 → dulus-3.11.3}/backend/personas.py +0 -0
  24. {dulus-3.11.2 → dulus-3.11.3}/backend/plugins.py +0 -0
  25. {dulus-3.11.2 → dulus-3.11.3}/backend/server.py +0 -0
  26. {dulus-3.11.2 → dulus-3.11.3}/backend/tasks.py +0 -0
  27. {dulus-3.11.2 → dulus-3.11.3}/banners/__init__.py +0 -0
  28. {dulus-3.11.2 → dulus-3.11.3}/banners/banner_rotator.py +0 -0
  29. {dulus-3.11.2 → dulus-3.11.3}/banners/banners_dulus_ai.txt +0 -0
  30. {dulus-3.11.2 → dulus-3.11.3}/batch_api.py +0 -0
  31. {dulus-3.11.2 → dulus-3.11.3}/checkpoint/__init__.py +0 -0
  32. {dulus-3.11.2 → dulus-3.11.3}/checkpoint/hooks.py +0 -0
  33. {dulus-3.11.2 → dulus-3.11.3}/checkpoint/store.py +0 -0
  34. {dulus-3.11.2 → dulus-3.11.3}/checkpoint/types.py +0 -0
  35. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/__init__.py +0 -0
  36. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/__main__.py +0 -0
  37. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/ansi.py +0 -0
  38. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/assets/ascii/dulus_logo.txt +0 -0
  39. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/assets/ascii/eagle.txt +0 -0
  40. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/assets/ascii/terminal_art.txt +0 -0
  41. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/banners.py +0 -0
  42. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/demo.py +0 -0
  43. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/effects.py +0 -0
  44. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/effort_slider.py +0 -0
  45. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/progress.py +0 -0
  46. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/py.typed +0 -0
  47. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/spinners.py +0 -0
  48. {dulus-3.11.2 → dulus-3.11.3}/cli_animations/status.py +0 -0
  49. {dulus-3.11.2 → dulus-3.11.3}/clipboard_utils.py +0 -0
  50. {dulus-3.11.2 → dulus-3.11.3}/cloudsave.py +0 -0
  51. {dulus-3.11.2 → dulus-3.11.3}/common.py +0 -0
  52. {dulus-3.11.2 → dulus-3.11.3}/compaction.py +0 -0
  53. {dulus-3.11.2 → dulus-3.11.3}/config.py +0 -0
  54. {dulus-3.11.2 → dulus-3.11.3}/context.py +0 -0
  55. {dulus-3.11.2 → dulus-3.11.3}/data/__init__.py +0 -0
  56. {dulus-3.11.2 → dulus-3.11.3}/data/active_persona.json +0 -0
  57. {dulus-3.11.2 → dulus-3.11.3}/data/marketplace.json +0 -0
  58. {dulus-3.11.2 → dulus-3.11.3}/data/personas.json +0 -0
  59. {dulus-3.11.2 → dulus-3.11.3}/data/plugins/__init__.py +0 -0
  60. {dulus-3.11.2 → dulus-3.11.3}/data/plugins/composio/__init__.py +0 -0
  61. {dulus-3.11.2 → dulus-3.11.3}/data/plugins/composio/composio_plugin/__init__.py +0 -0
  62. {dulus-3.11.2 → dulus-3.11.3}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
  63. {dulus-3.11.2 → dulus-3.11.3}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
  64. {dulus-3.11.2 → dulus-3.11.3}/data/plugins/composio/plugin.json +0 -0
  65. {dulus-3.11.2 → dulus-3.11.3}/data/plugins/composio/plugin_tool.py +0 -0
  66. {dulus-3.11.2 → dulus-3.11.3}/data/tasks.json +0 -0
  67. {dulus-3.11.2 → dulus-3.11.3}/display_blocks.py +0 -0
  68. {dulus-3.11.2 → dulus-3.11.3}/docs/API.md +0 -0
  69. {dulus-3.11.2 → dulus-3.11.3}/docs/BRAND_GUIDE.md +0 -0
  70. {dulus-3.11.2 → dulus-3.11.3}/docs/CHANGELOG.md +0 -0
  71. {dulus-3.11.2 → dulus-3.11.3}/docs/CONTRIBUTING.md +0 -0
  72. {dulus-3.11.2 → dulus-3.11.3}/docs/DEPLOYMENT.md +0 -0
  73. {dulus-3.11.2 → dulus-3.11.3}/docs/Dulus_AI_Whitepaper_(v2.0).pdf +0 -0
  74. {dulus-3.11.2 → dulus-3.11.3}/docs/Dulus_YC_Company_Overview_Aug_2026.pdf +0 -0
  75. {dulus-3.11.2 → dulus-3.11.3}/docs/FAQ.md +0 -0
  76. {dulus-3.11.2 → dulus-3.11.3}/docs/GETTING_STARTED.md +0 -0
  77. {dulus-3.11.2 → dulus-3.11.3}/docs/README.md +0 -0
  78. {dulus-3.11.2 → dulus-3.11.3}/docs/README_AR.md +0 -0
  79. {dulus-3.11.2 → dulus-3.11.3}/docs/README_EN.md +0 -0
  80. {dulus-3.11.2 → dulus-3.11.3}/docs/README_ES.md +0 -0
  81. {dulus-3.11.2 → dulus-3.11.3}/docs/README_FR.md +0 -0
  82. {dulus-3.11.2 → dulus-3.11.3}/docs/README_JA.md +0 -0
  83. {dulus-3.11.2 → dulus-3.11.3}/docs/README_KO.md +0 -0
  84. {dulus-3.11.2 → dulus-3.11.3}/docs/README_PT.md +0 -0
  85. {dulus-3.11.2 → dulus-3.11.3}/docs/README_RU.md +0 -0
  86. {dulus-3.11.2 → dulus-3.11.3}/docs/README_ZH.md +0 -0
  87. {dulus-3.11.2 → dulus-3.11.3}/docs/SECURITY.md +0 -0
  88. {dulus-3.11.2 → dulus-3.11.3}/docs/__init__.py +0 -0
  89. {dulus-3.11.2 → dulus-3.11.3}/docs/api.html +0 -0
  90. {dulus-3.11.2 → dulus-3.11.3}/docs/architecture.md +0 -0
  91. {dulus-3.11.2 → dulus-3.11.3}/docs/azure-speech-template.json +0 -0
  92. {dulus-3.11.2 → dulus-3.11.3}/docs/dashboard/index.html +0 -0
  93. {dulus-3.11.2 → dulus-3.11.3}/docs/divider.svg +0 -0
  94. {dulus-3.11.2 → dulus-3.11.3}/docs/dulus-bird.png +0 -0
  95. {dulus-3.11.2 → dulus-3.11.3}/docs/generate.py +0 -0
  96. {dulus-3.11.2 → dulus-3.11.3}/docs/index.html +0 -0
  97. {dulus-3.11.2 → dulus-3.11.3}/docs/news.md +0 -0
  98. {dulus-3.11.2 → dulus-3.11.3}/docs/nvidia-models.svg +0 -0
  99. {dulus-3.11.2 → dulus-3.11.3}/docs/particle-playground.html +0 -0
  100. {dulus-3.11.2 → dulus-3.11.3}/docs/personas/index.html +0 -0
  101. {dulus-3.11.2 → dulus-3.11.3}/docs/poetry-banner.png +0 -0
  102. {dulus-3.11.2 → dulus-3.11.3}/docs/preview.html +0 -0
  103. {dulus-3.11.2 → dulus-3.11.3}/docs/python-console.md +0 -0
  104. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/auto-adapter.png +0 -0
  105. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/dulus-os.png +0 -0
  106. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/hero.png +0 -0
  107. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/lookback_two_windows.png +0 -0
  108. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/pyc_heap.svg +0 -0
  109. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/pyc_receipts.svg +0 -0
  110. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/pyc_trap.svg +0 -0
  111. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/roundtable.png +0 -0
  112. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/task-board.png +0 -0
  113. {dulus-3.11.2 → dulus-3.11.3}/docs/readme/webchat.png +0 -0
  114. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-agents.svg +0 -0
  115. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-brainstorm.svg +0 -0
  116. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-bridges.svg +0 -0
  117. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-features.svg +0 -0
  118. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-freetier.svg +0 -0
  119. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-memory.svg +0 -0
  120. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-models.svg +0 -0
  121. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-perms.svg +0 -0
  122. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-plugins.svg +0 -0
  123. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-quickstart.svg +0 -0
  124. {dulus-3.11.2 → dulus-3.11.3}/docs/sec-ssj.svg +0 -0
  125. {dulus-3.11.2 → dulus-3.11.3}/docs/spinners.svg +0 -0
  126. {dulus-3.11.2 → dulus-3.11.3}/docs/split-pane.svg +0 -0
  127. {dulus-3.11.2 → dulus-3.11.3}/docs/terminal-boot.svg +0 -0
  128. {dulus-3.11.2 → dulus-3.11.3}/docs/termux-edge.md +0 -0
  129. {dulus-3.11.2 → dulus-3.11.3}/dulus.egg-info/dependency_links.txt +0 -0
  130. {dulus-3.11.2 → dulus-3.11.3}/dulus.egg-info/entry_points.txt +0 -0
  131. {dulus-3.11.2 → dulus-3.11.3}/dulus.egg-info/requires.txt +0 -0
  132. {dulus-3.11.2 → dulus-3.11.3}/dulus.egg-info/top_level.txt +0 -0
  133. {dulus-3.11.2 → dulus-3.11.3}/dulus_bar_client.py +0 -0
  134. {dulus-3.11.2 → dulus-3.11.3}/dulus_gui.py +0 -0
  135. {dulus-3.11.2 → dulus-3.11.3}/dulus_mcp/__init__.py +0 -0
  136. {dulus-3.11.2 → dulus-3.11.3}/dulus_mcp/client.py +0 -0
  137. {dulus-3.11.2 → dulus-3.11.3}/dulus_mcp/commands.py +0 -0
  138. {dulus-3.11.2 → dulus-3.11.3}/dulus_mcp/config.py +0 -0
  139. {dulus-3.11.2 → dulus-3.11.3}/dulus_mcp/hub.py +0 -0
  140. {dulus-3.11.2 → dulus-3.11.3}/dulus_mcp/tools.py +0 -0
  141. {dulus-3.11.2 → dulus-3.11.3}/dulus_mcp/types.py +0 -0
  142. {dulus-3.11.2 → dulus-3.11.3}/dulus_quick_menu.py +0 -0
  143. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/__init__.py +0 -0
  144. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/add_dir_manager.py +0 -0
  145. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/afk_mode.py +0 -0
  146. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/approval_runtime.py +0 -0
  147. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/background_tasks.py +0 -0
  148. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/clipboard_utils.py +0 -0
  149. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/diff_visualizer.py +0 -0
  150. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/export_import.py +0 -0
  151. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/hook_engine.py +0 -0
  152. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/notification_manager.py +0 -0
  153. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/session_fork.py +0 -0
  154. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/shell_mode.py +0 -0
  155. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/todo_visualizer.py +0 -0
  156. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/tree_ls.py +0 -0
  157. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/wire_events.py +0 -0
  158. {dulus-3.11.2 → dulus-3.11.3}/dulus_tools/yolo_mode.py +0 -0
  159. {dulus-3.11.2 → dulus-3.11.3}/file_filter.py +0 -0
  160. {dulus-3.11.2 → dulus-3.11.3}/fs_compass.py +0 -0
  161. {dulus-3.11.2 → dulus-3.11.3}/governance.py +0 -0
  162. {dulus-3.11.2 → dulus-3.11.3}/gui/__init__.py +0 -0
  163. {dulus-3.11.2 → dulus-3.11.3}/gui/agent_bridge.py +0 -0
  164. {dulus-3.11.2 → dulus-3.11.3}/gui/chat_widget.py +0 -0
  165. {dulus-3.11.2 → dulus-3.11.3}/gui/main_window.py +0 -0
  166. {dulus-3.11.2 → dulus-3.11.3}/gui/personas.py +0 -0
  167. {dulus-3.11.2 → dulus-3.11.3}/gui/sandbox_server.py +0 -0
  168. {dulus-3.11.2 → dulus-3.11.3}/gui/session_utils.py +0 -0
  169. {dulus-3.11.2 → dulus-3.11.3}/gui/settings_dialog.py +0 -0
  170. {dulus-3.11.2 → dulus-3.11.3}/gui/sidebar.py +0 -0
  171. {dulus-3.11.2 → dulus-3.11.3}/gui/tasks_view.py +0 -0
  172. {dulus-3.11.2 → dulus-3.11.3}/gui/themes.py +0 -0
  173. {dulus-3.11.2 → dulus-3.11.3}/gui/tool_panel.py +0 -0
  174. {dulus-3.11.2 → dulus-3.11.3}/input.py +0 -0
  175. {dulus-3.11.2 → dulus-3.11.3}/license_manager.py +0 -0
  176. {dulus-3.11.2 → dulus-3.11.3}/lookback.py +0 -0
  177. {dulus-3.11.2 → dulus-3.11.3}/memory/__init__.py +0 -0
  178. {dulus-3.11.2 → dulus-3.11.3}/memory/audit.py +0 -0
  179. {dulus-3.11.2 → dulus-3.11.3}/memory/consolidator.py +0 -0
  180. {dulus-3.11.2 → dulus-3.11.3}/memory/context.py +0 -0
  181. {dulus-3.11.2 → dulus-3.11.3}/memory/mempalace_bridge.py +0 -0
  182. {dulus-3.11.2 → dulus-3.11.3}/memory/offload.py +0 -0
  183. {dulus-3.11.2 → dulus-3.11.3}/memory/palace.py +0 -0
  184. {dulus-3.11.2 → dulus-3.11.3}/memory/scan.py +0 -0
  185. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/adaptation_guides.md +0 -0
  186. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/askuserquestion_after_numbered_list.md +0 -0
  187. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/background_jobs_no_extra_timers.md +0 -0
  188. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/cleverness_over_resources.md +0 -0
  189. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/corporate_tls_breaks_curl_cffi.md +0 -0
  190. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/hardened_rules.md +0 -0
  191. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/investigator_workflow_heuristic.md +0 -0
  192. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/native_code_over_sketchy_plugins.md +0 -0
  193. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/no_personal_info_in_code.md +0 -0
  194. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/searches_include_modified_date.md +0 -0
  195. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/tmux_send_keys_power_patterns.md +0 -0
  196. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/token_optimization_technique.md +0 -0
  197. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/tool_chaining_capability.md +0 -0
  198. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/insights/webbridge_evaluate_first_pattern.md +0 -0
  199. {dulus-3.11.2 → dulus-3.11.3}/memory/seeds/short_memory.md +0 -0
  200. {dulus-3.11.2 → dulus-3.11.3}/memory/sessions.py +0 -0
  201. {dulus-3.11.2 → dulus-3.11.3}/memory/store.py +0 -0
  202. {dulus-3.11.2 → dulus-3.11.3}/memory/tools.py +0 -0
  203. {dulus-3.11.2 → dulus-3.11.3}/memory/types.py +0 -0
  204. {dulus-3.11.2 → dulus-3.11.3}/memory/vector_search.py +0 -0
  205. {dulus-3.11.2 → dulus-3.11.3}/model_params.py +0 -0
  206. {dulus-3.11.2 → dulus-3.11.3}/multi_agent/__init__.py +0 -0
  207. {dulus-3.11.2 → dulus-3.11.3}/multi_agent/subagent.py +0 -0
  208. {dulus-3.11.2 → dulus-3.11.3}/multi_agent/tools.py +0 -0
  209. {dulus-3.11.2 → dulus-3.11.3}/paste_placeholders.py +0 -0
  210. {dulus-3.11.2 → dulus-3.11.3}/personality_config.py +0 -0
  211. {dulus-3.11.2 → dulus-3.11.3}/plugin/__init__.py +0 -0
  212. {dulus-3.11.2 → dulus-3.11.3}/plugin/autoadapter.py +0 -0
  213. {dulus-3.11.2 → dulus-3.11.3}/plugin/loader.py +0 -0
  214. {dulus-3.11.2 → dulus-3.11.3}/plugin/recommend.py +0 -0
  215. {dulus-3.11.2 → dulus-3.11.3}/plugin/store.py +0 -0
  216. {dulus-3.11.2 → dulus-3.11.3}/plugin/types.py +0 -0
  217. {dulus-3.11.2 → dulus-3.11.3}/profiles.py +0 -0
  218. {dulus-3.11.2 → dulus-3.11.3}/pyconsole.py +0 -0
  219. {dulus-3.11.2 → dulus-3.11.3}/sandbox/README.md +0 -0
  220. {dulus-3.11.2 → dulus-3.11.3}/sandbox/__init__.py +0 -0
  221. {dulus-3.11.2 → dulus-3.11.3}/sandbox/components.json +0 -0
  222. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
  223. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
  224. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/index.html +0 -0
  225. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/wallpaper-default.jpg +0 -0
  226. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/wallpapers/default.jpeg +0 -0
  227. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/wallpapers/light.jpeg +0 -0
  228. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/wallpapers/nature.jpeg +0 -0
  229. {dulus-3.11.2 → dulus-3.11.3}/sandbox/dist/wallpapers/tech.jpeg +0 -0
  230. {dulus-3.11.2 → dulus-3.11.3}/sandbox/eslint.config.js +0 -0
  231. {dulus-3.11.2 → dulus-3.11.3}/sandbox/index.html +0 -0
  232. {dulus-3.11.2 → dulus-3.11.3}/sandbox/info.md +0 -0
  233. {dulus-3.11.2 → dulus-3.11.3}/sandbox/package-lock.json +0 -0
  234. {dulus-3.11.2 → dulus-3.11.3}/sandbox/package.json +0 -0
  235. {dulus-3.11.2 → dulus-3.11.3}/sandbox/postcss.config.js +0 -0
  236. {dulus-3.11.2 → dulus-3.11.3}/sandbox/tailwind.config.js +0 -0
  237. {dulus-3.11.2 → dulus-3.11.3}/sandbox/tsconfig.app.json +0 -0
  238. {dulus-3.11.2 → dulus-3.11.3}/sandbox/tsconfig.json +0 -0
  239. {dulus-3.11.2 → dulus-3.11.3}/sandbox/tsconfig.node.json +0 -0
  240. {dulus-3.11.2 → dulus-3.11.3}/sandbox/vite.config.ts +0 -0
  241. {dulus-3.11.2 → dulus-3.11.3}/sandbox_bootstrap.py +0 -0
  242. {dulus-3.11.2 → dulus-3.11.3}/setup.cfg +0 -0
  243. {dulus-3.11.2 → dulus-3.11.3}/skill/__init__.py +0 -0
  244. {dulus-3.11.2 → dulus-3.11.3}/skill/builtin.py +0 -0
  245. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/LICENSE-obsidian-skills +0 -0
  246. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/README.md +0 -0
  247. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/defuddle/SKILL.md +0 -0
  248. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/json-canvas/SKILL.md +0 -0
  249. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/json-canvas/references/EXAMPLES.md +0 -0
  250. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/obsidian-bases/SKILL.md +0 -0
  251. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -0
  252. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/obsidian-cli/SKILL.md +0 -0
  253. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/obsidian-markdown/SKILL.md +0 -0
  254. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/obsidian-markdown/references/CALLOUTS.md +0 -0
  255. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/obsidian-markdown/references/EMBEDS.md +0 -0
  256. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/obsidian-markdown/references/PROPERTIES.md +0 -0
  257. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/README.md +0 -0
  258. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/SKILL.md +0 -0
  259. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/addresses.json +0 -0
  260. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/advancedbackgroundchecks.json +0 -0
  261. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/beenverified.json +0 -0
  262. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/clustal.json +0 -0
  263. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/clustrmaps.json +0 -0
  264. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/cyberbackgroundchecks.json +0 -0
  265. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/familytreenow.json +0 -0
  266. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/fastpeoplesearch.json +0 -0
  267. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/intelius.json +0 -0
  268. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/mylife.json +0 -0
  269. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/nuwber.json +0 -0
  270. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/peekyou.json +0 -0
  271. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/peoplefinders.json +0 -0
  272. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/radaris.json +0 -0
  273. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/rehold.json +0 -0
  274. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/searchpeoplefree.json +0 -0
  275. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/socialcatfish.json +0 -0
  276. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/spokeo.json +0 -0
  277. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/thatsthem.json +0 -0
  278. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/truepeoplesearch.json +0 -0
  279. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/usphonebook.json +0 -0
  280. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/brokers/whitepages.json +0 -0
  281. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/legal/ccpa.md +0 -0
  282. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/legal/drop.md +0 -0
  283. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/legal/gdpr.md +0 -0
  284. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/methods.md +0 -0
  285. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/site-playbooks.md +0 -0
  286. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/references/state-machine.md +0 -0
  287. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/autopilot.py +0 -0
  288. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/badbool.py +0 -0
  289. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/brokers.py +0 -0
  290. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/cdp.py +0 -0
  291. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/config.py +0 -0
  292. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/crypto.py +0 -0
  293. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/dossier.py +0 -0
  294. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/email_modes.py +0 -0
  295. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/emailer.py +0 -0
  296. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/ledger.py +0 -0
  297. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/legal.py +0 -0
  298. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/paths.py +0 -0
  299. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/pdd.py +0 -0
  300. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/registry.py +0 -0
  301. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/report.py +0 -0
  302. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/scan.py +0 -0
  303. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/storage.py +0 -0
  304. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/tiers.py +0 -0
  305. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/scripts/vectors.py +0 -0
  306. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/templates/consent/authorization.md +0 -0
  307. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/templates/emails/ccpa-authorized-agent.txt +0 -0
  308. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/templates/emails/ccpa-deletion.txt +0 -0
  309. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/templates/emails/ccpa-indirect-deletion.txt +0 -0
  310. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/templates/emails/gdpr-erasure.txt +0 -0
  311. {dulus-3.11.2 → dulus-3.11.3}/skill/bundled/unbroker/templates/emails/generic-optout.txt +0 -0
  312. {dulus-3.11.2 → dulus-3.11.3}/skill/clawhub.py +0 -0
  313. {dulus-3.11.2 → dulus-3.11.3}/skill/executor.py +0 -0
  314. {dulus-3.11.2 → dulus-3.11.3}/skill/loader.py +0 -0
  315. {dulus-3.11.2 → dulus-3.11.3}/skill/tools.py +0 -0
  316. {dulus-3.11.2 → dulus-3.11.3}/skills.py +0 -0
  317. {dulus-3.11.2 → dulus-3.11.3}/soul.py +0 -0
  318. {dulus-3.11.2 → dulus-3.11.3}/spinner.py +0 -0
  319. {dulus-3.11.2 → dulus-3.11.3}/steer_input.py +0 -0
  320. {dulus-3.11.2 → dulus-3.11.3}/subagent.py +0 -0
  321. {dulus-3.11.2 → dulus-3.11.3}/task/__init__.py +0 -0
  322. {dulus-3.11.2 → dulus-3.11.3}/task/store.py +0 -0
  323. {dulus-3.11.2 → dulus-3.11.3}/task/tools.py +0 -0
  324. {dulus-3.11.2 → dulus-3.11.3}/task/types.py +0 -0
  325. {dulus-3.11.2 → dulus-3.11.3}/tests/test_afk_yolo.py +0 -0
  326. {dulus-3.11.2 → dulus-3.11.3}/tests/test_approval_runtime.py +0 -0
  327. {dulus-3.11.2 → dulus-3.11.3}/tests/test_background_task_tools.py +0 -0
  328. {dulus-3.11.2 → dulus-3.11.3}/tests/test_background_tasks.py +0 -0
  329. {dulus-3.11.2 → dulus-3.11.3}/tests/test_chatgpt_oauth.py +0 -0
  330. {dulus-3.11.2 → dulus-3.11.3}/tests/test_checkpoint.py +0 -0
  331. {dulus-3.11.2 → dulus-3.11.3}/tests/test_cli_animations_integration.py +0 -0
  332. {dulus-3.11.2 → dulus-3.11.3}/tests/test_clipboard_utils.py +0 -0
  333. {dulus-3.11.2 → dulus-3.11.3}/tests/test_compaction.py +0 -0
  334. {dulus-3.11.2 → dulus-3.11.3}/tests/test_composio_tool_generator.py +0 -0
  335. {dulus-3.11.2 → dulus-3.11.3}/tests/test_diff_view.py +0 -0
  336. {dulus-3.11.2 → dulus-3.11.3}/tests/test_diff_visualization.py +0 -0
  337. {dulus-3.11.2 → dulus-3.11.3}/tests/test_display_blocks.py +0 -0
  338. {dulus-3.11.2 → dulus-3.11.3}/tests/test_export_import.py +0 -0
  339. {dulus-3.11.2 → dulus-3.11.3}/tests/test_grok_usage.py +0 -0
  340. {dulus-3.11.2 → dulus-3.11.3}/tests/test_hook_engine.py +0 -0
  341. {dulus-3.11.2 → dulus-3.11.3}/tests/test_injection_fix.py +0 -0
  342. {dulus-3.11.2 → dulus-3.11.3}/tests/test_license.py +0 -0
  343. {dulus-3.11.2 → dulus-3.11.3}/tests/test_lookback_cache.py +0 -0
  344. {dulus-3.11.2 → dulus-3.11.3}/tests/test_mcp.py +0 -0
  345. {dulus-3.11.2 → dulus-3.11.3}/tests/test_mcp_algolia.py +0 -0
  346. {dulus-3.11.2 → dulus-3.11.3}/tests/test_memory.py +0 -0
  347. {dulus-3.11.2 → dulus-3.11.3}/tests/test_memory_home_resolution.py +0 -0
  348. {dulus-3.11.2 → dulus-3.11.3}/tests/test_notification_manager.py +0 -0
  349. {dulus-3.11.2 → dulus-3.11.3}/tests/test_plugin.py +0 -0
  350. {dulus-3.11.2 → dulus-3.11.3}/tests/test_profile_isolation.py +0 -0
  351. {dulus-3.11.2 → dulus-3.11.3}/tests/test_session_fork.py +0 -0
  352. {dulus-3.11.2 → dulus-3.11.3}/tests/test_shell_mode.py +0 -0
  353. {dulus-3.11.2 → dulus-3.11.3}/tests/test_skills.py +0 -0
  354. {dulus-3.11.2 → dulus-3.11.3}/tests/test_skillssh_algolia.py +0 -0
  355. {dulus-3.11.2 → dulus-3.11.3}/tests/test_steer_input.py +0 -0
  356. {dulus-3.11.2 → dulus-3.11.3}/tests/test_subagent.py +0 -0
  357. {dulus-3.11.2 → dulus-3.11.3}/tests/test_task.py +0 -0
  358. {dulus-3.11.2 → dulus-3.11.3}/tests/test_telegram_buffer.py +0 -0
  359. {dulus-3.11.2 → dulus-3.11.3}/tests/test_think_tool.py +0 -0
  360. {dulus-3.11.2 → dulus-3.11.3}/tests/test_todo_tool.py +0 -0
  361. {dulus-3.11.2 → dulus-3.11.3}/tests/test_todo_visualization.py +0 -0
  362. {dulus-3.11.2 → dulus-3.11.3}/tests/test_tool_registry.py +0 -0
  363. {dulus-3.11.2 → dulus-3.11.3}/tests/test_tree_ls.py +0 -0
  364. {dulus-3.11.2 → dulus-3.11.3}/tests/test_voice.py +0 -0
  365. {dulus-3.11.2 → dulus-3.11.3}/tests/test_webbridge_tabs.py +0 -0
  366. {dulus-3.11.2 → dulus-3.11.3}/tests/test_wire_events.py +0 -0
  367. {dulus-3.11.2 → dulus-3.11.3}/tmux_tools.py +0 -0
  368. {dulus-3.11.2 → dulus-3.11.3}/tool_registry.py +0 -0
  369. {dulus-3.11.2 → dulus-3.11.3}/tools.py +0 -0
  370. {dulus-3.11.2 → dulus-3.11.3}/tools_background.py +0 -0
  371. {dulus-3.11.2 → dulus-3.11.3}/tools_think.py +0 -0
  372. {dulus-3.11.2 → dulus-3.11.3}/tools_todo.py +0 -0
  373. {dulus-3.11.2 → dulus-3.11.3}/ui/__init__.py +0 -0
  374. {dulus-3.11.2 → dulus-3.11.3}/ui/input.py +0 -0
  375. {dulus-3.11.2 → dulus-3.11.3}/ui/render.py +0 -0
  376. {dulus-3.11.2 → dulus-3.11.3}/updater.py +0 -0
  377. {dulus-3.11.2 → dulus-3.11.3}/voice/__init__.py +0 -0
  378. {dulus-3.11.2 → dulus-3.11.3}/voice/audio_utils.py +0 -0
  379. {dulus-3.11.2 → dulus-3.11.3}/voice/keyterms.py +0 -0
  380. {dulus-3.11.2 → dulus-3.11.3}/voice/recorder.py +0 -0
  381. {dulus-3.11.2 → dulus-3.11.3}/voice/stt.py +0 -0
  382. {dulus-3.11.2 → dulus-3.11.3}/voice/tts.py +0 -0
  383. {dulus-3.11.2 → dulus-3.11.3}/voice/wake_word.py +0 -0
  384. {dulus-3.11.2 → dulus-3.11.3}/webbridge/__init__.py +0 -0
  385. {dulus-3.11.2 → dulus-3.11.3}/webbridge/core.py +0 -0
  386. {dulus-3.11.2 → dulus-3.11.3}/webbridge/tools.py +0 -0
  387. {dulus-3.11.2 → dulus-3.11.3}/webchat.py +0 -0
  388. {dulus-3.11.2 → dulus-3.11.3}/webchat_server.py +0 -0
  389. {dulus-3.11.2 → dulus-3.11.3}/webchat_ui/__init__.py +0 -0
  390. {dulus-3.11.2 → dulus-3.11.3}/webchat_ui/app.js +0 -0
  391. {dulus-3.11.2 → dulus-3.11.3}/webchat_ui/index.html +0 -0
  392. {dulus-3.11.2 → dulus-3.11.3}/webchat_ui/style.css +0 -0
  393. {dulus-3.11.2 → dulus-3.11.3}/welcome.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: dulus
3
- Version: 3.11.2
3
+ Version: 3.11.3
4
4
  Summary: Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS.
5
5
  Author-email: KevRojo <dev@dulus.ai>
6
6
  Maintainer-email: KevRojo <dev@dulus.ai>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: dulus
3
- Version: 3.11.2
3
+ Version: 3.11.3
4
4
  Summary: Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS.
5
5
  Author-email: KevRojo <dev@dulus.ai>
6
6
  Maintainer-email: KevRojo <dev@dulus.ai>
@@ -341,6 +341,7 @@ tests/test_composio_tool_generator.py
341
341
  tests/test_diff_view.py
342
342
  tests/test_diff_visualization.py
343
343
  tests/test_display_blocks.py
344
+ tests/test_dulus_account.py
344
345
  tests/test_export_import.py
345
346
  tests/test_grok_usage.py
346
347
  tests/test_hook_engine.py
@@ -380,7 +380,7 @@ try:
380
380
  from importlib.metadata import version as _pkg_version
381
381
  VERSION = _pkg_version("dulus")
382
382
  except Exception:
383
- VERSION = "3.11.2" # dev fallback — keep in sync with pyproject.toml
383
+ VERSION = "3.11.3" # dev fallback — keep in sync with pyproject.toml
384
384
 
385
385
  # ── ANSI helpers (used even with rich for non-markdown output) ─────────────
386
386
  from common import C, clr, info, ok, warn, err, stream_thinking, sanitize_text
@@ -3246,11 +3246,7 @@ def cmd_harvest(_args: str, _state, config) -> bool:
3246
3246
  info("Login page detected. Please log in manually, then press ENTER here...")
3247
3247
  input()
3248
3248
 
3249
- # claude.ai is a long-lived SPA that never reaches "networkidle"
3250
- # (it keeps streaming/websocket connections open), so that wait
3251
- # always burned the full 30s and timed out. Wait for the DOM
3252
- # instead and give it a real ceiling.
3253
- page.goto("https://claude.ai/new", wait_until="domcontentloaded", timeout=60000)
3249
+ page.goto("https://claude.ai/new", wait_until="networkidle")
3254
3250
  time.sleep(2)
3255
3251
 
3256
3252
  user_agent = page.evaluate("navigator.userAgent") if browser.pages else ""
@@ -9171,6 +9167,41 @@ def cmd_login(args: str, _state, config) -> bool:
9171
9167
  """
9172
9168
  sub = (args or "").strip().lower()
9173
9169
 
9170
+ # ── Dulus account (OAuth 2.0 + PKCE against Dulus's own API) ──
9171
+ # Unlike the provider logins below, this one authenticates you to Dulus
9172
+ # itself, so the CLI can reach the Dulus API without an API key pasted in
9173
+ # by hand. `/login dulus key` mints a dulus_sk_* key for CI and servers.
9174
+ if sub.split(" ")[0] in ("dulus", "account"):
9175
+ import dulus_account
9176
+
9177
+ rest = (args or "").strip().split()
9178
+ force = "force" in rest
9179
+ if len(rest) > 1 and rest[1] in ("key", "apikey", "api-key"):
9180
+ name = rest[2] if len(rest) > 2 else "cli"
9181
+ dulus_account.create_api_key(name, notify=lambda m: print(clr(m, "cyan")))
9182
+ return True
9183
+
9184
+ if not force:
9185
+ store = dulus_account.load_store()
9186
+ if store.get("access_token") and not dulus_account._token_expired(store):
9187
+ print(clr("✅ Dulus account already signed in.", "green"))
9188
+ print(clr("Use `/login dulus force` to sign in again, or `/login dulus key` to mint an API key.", "green"))
9189
+ return True
9190
+
9191
+ if force:
9192
+ dulus_account.clear_store()
9193
+ print(clr("Starting Dulus sign-in (OAuth 2.0 + PKCE)…", "cyan"))
9194
+ try:
9195
+ token = dulus_account.login(notify=lambda m: print(clr(m, "cyan")))
9196
+ except Exception as e:
9197
+ token = None
9198
+ print(clr(f"Sign-in error: {e}", "red"))
9199
+ if token:
9200
+ print(clr("✅ Signed in to your Dulus account.", "green"))
9201
+ return True
9202
+ print(clr("Could not sign in. Re-run `/login dulus`.", "yellow"))
9203
+ return True
9204
+
9174
9205
  # ── Claude / Anthropic subscription OAuth (no API key, no cookie webbridge) ──
9175
9206
  # Mirrors the Grok flow: opens claude.ai in the browser, you approve and paste
9176
9207
  # back the code, Dulus exchanges it for an OAuth token. claude-* models then run
@@ -91,15 +91,6 @@ class _ProviderRetry:
91
91
  # Rate limit / server overload
92
92
  if "429" in msg or "rate limit" in msg or "too many requests" in msg:
93
93
  return True
94
- # Capacity pushback. Anthropic answers 529 "overloaded_error" and other
95
- # providers say "overloaded"/"capacity"/"server is busy" with assorted
96
- # status codes; the next request usually succeeds, so this is exactly
97
- # the case worth absorbing silently instead of surfacing to the user.
98
- if ("529" in msg or "overloaded" in msg or "over capacity" in msg
99
- or "at capacity" in msg or "server is busy" in msg
100
- or "model is currently loading" in msg
101
- or type(exc).__name__ in ("OverloadedError", "InternalServerError")):
102
- return True
103
94
  # Server errors
104
95
  if "500" in msg or "502" in msg or "503" in msg or "504" in msg:
105
96
  return True
@@ -5532,13 +5523,6 @@ def stream_anthropic(
5532
5523
  yield AssistantTurn(text, tool_calls, 0, 0, thinking=thinking,
5533
5524
  thinking_signature=thinking_signature, error=False)
5534
5525
  return
5535
- # Nothing emitted yet and the failure is transient (529 overloaded, a
5536
- # blip, a rate limit): let it propagate so _ProviderRetry can quietly
5537
- # try again. Turning it into text here would strand the retry wrapper,
5538
- # which only ever sees a well-behaved generator. Once output has been
5539
- # emitted a retry would duplicate it, so those still report.
5540
- if not text and not tool_calls and _ProviderRetry.is_retryable(_e):
5541
- raise
5542
5526
  msg = friendly_api_error(_e)
5543
5527
  yield TextChunk(msg)
5544
5528
  yield AssistantTurn(msg, [], 0, 0, error=True)
@@ -6167,11 +6151,6 @@ def stream_openai_compat(
6167
6151
  {**config, "_modelstudio_remaining": _ms_remaining[1:]},
6168
6152
  )
6169
6153
  return
6170
- # Transient capacity pushback before the stream opened: propagate so
6171
- # _ProviderRetry absorbs it silently. This is the create() call, so
6172
- # nothing has been emitted yet and a retry cannot duplicate output.
6173
- if _ProviderRetry.is_retryable(e):
6174
- raise
6175
6154
  msg = friendly_api_error(e)
6176
6155
  yield TextChunk(msg)
6177
6156
  yield AssistantTurn(msg, [], 0, 0, error=True)
@@ -6187,10 +6166,6 @@ def stream_openai_compat(
6187
6166
  {**config, "_modelstudio_remaining": _ms_remaining[1:]},
6188
6167
  )
6189
6168
  return
6190
- # Same as above: still inside the create() call, so a transient failure
6191
- # can be retried without duplicating anything.
6192
- if _ProviderRetry.is_retryable(e):
6193
- raise
6194
6169
  msg = friendly_api_error(e)
6195
6170
  yield TextChunk(msg)
6196
6171
  yield AssistantTurn(msg, [], 0, 0, error=True)
@@ -1,247 +1,247 @@
1
- # setuptools is pinned <77 on purpose: 77+ implements PEP 639 (SPDX license
2
- # string + license-files) which emits Metadata-Version 2.4. pip < 24.1 — which
3
- # ships on Ubuntu 24.04 LTS (pip 24.0) and many other current distros — cannot
4
- # read Metadata 2.4 and silently skips the package, so `pip install dulus` fails
5
- # with "Could not find a version that satisfies the requirement dulus (from
6
- # versions: none)" on a fresh machine. Staying <77 keeps Metadata at 2.1/2.2.
7
- [build-system]
8
- requires = ["setuptools>=61,<77", "wheel"]
9
- build-backend = "setuptools.build_meta"
10
-
11
- [project]
12
- name = "dulus"
13
- version = "3.11.2"
14
- description = "Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS."
15
- readme = "README.md"
16
- requires-python = ">=3.10"
17
- # Legacy table form (not the PEP 639 SPDX string) so setuptools emits the older
18
- # `License:` metadata field and keeps Metadata-Version at 2.1/2.2 — see the
19
- # build-system note above. LICENSE ships via MANIFEST.in.
20
- license = {text = "GPL-3.0-only"}
21
- authors = [{name = "KevRojo", email = "dev@dulus.ai"}]
22
- maintainers = [{name = "KevRojo", email = "dev@dulus.ai"}]
23
- keywords = [
24
- # Providers and runtimes people actually search for.
25
- "ai", "cli", "llm", "claude", "gemini", "nvidia", "openai",
26
- "kimi", "deepseek", "qwen", "ollama", "local-llm", "openai-compatible",
27
- # What this thing IS. Without these the package never surfaces for the
28
- # queries its own users type.
29
- "agent", "ai-agent", "coding-agent", "autonomous-agent", "agentic",
30
- "mcp", "terminal", "tui", "repl", "developer-tools", "sub-agents",
31
- "tts", "voice",
32
- ]
33
- classifiers = [
34
- # 19K+ installs, a full test suite and a 3.11.x line in production. This
35
- # sat at "4 - Beta" long after that stopped being true, and the Beta badge
36
- # is the first thing anyone reads on the PyPI page.
37
- "Development Status :: 5 - Production/Stable",
38
- # Dulus is not console-only: it ships a desktop GUI (pywebview), a Qt
39
- # status bar, a Flask webchat and Dulus OS. Listing just Console hid every
40
- # one of those surfaces.
41
- "Environment :: Console",
42
- "Environment :: Web Environment",
43
- "Environment :: X11 Applications :: Qt",
44
- "Environment :: Win32 (MS Windows)",
45
- "Environment :: MacOS X",
46
- # "Agentic AI for everyone" — the README's own pitch — is not a
47
- # developers-only audience.
48
- "Intended Audience :: Developers",
49
- "Intended Audience :: End Users/Desktop",
50
- "Intended Audience :: System Administrators",
51
- "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
52
- "Natural Language :: English",
53
- "Natural Language :: Spanish",
54
- "Operating System :: OS Independent",
55
- "Programming Language :: Python :: 3",
56
- "Programming Language :: Python :: 3 :: Only",
57
- "Programming Language :: Python :: 3.10",
58
- "Programming Language :: Python :: 3.11",
59
- "Programming Language :: Python :: 3.12",
60
- "Programming Language :: Python :: 3.13",
61
- "Programming Language :: Python :: 3.14",
62
- # Topics decide which PyPI category listings this appears in. AI + Terminals
63
- # alone missed the shell, code-generation, chat and speech angles that
64
- # describe just as much of what Dulus does.
65
- "Topic :: Scientific/Engineering :: Artificial Intelligence",
66
- "Topic :: Terminals",
67
- "Topic :: Software Development :: Code Generators",
68
- "Topic :: System :: Shells",
69
- "Topic :: Communications :: Chat",
70
- "Topic :: Multimedia :: Sound/Audio :: Speech",
71
- "Topic :: Utilities",
72
- ]
73
- dependencies = [
74
- "anthropic>=0.40.0",
75
- "openai>=1.30.0",
76
- "httpx>=0.27.0",
77
- "requests>=2.31.0",
78
- 'tomli>=2.0; python_version < "3.11"', # stdlib tomllib is 3.11+; backport for 3.10
79
- "rich>=13.0.0",
80
- "prompt_toolkit>=3.0.0",
81
- "Flask>=3.1.3",
82
- "bubblewrap-cli>=1.0.0",
83
- "customtkinter>=5.2.0",
84
- "Pillow>=10.0.0",
85
- "typing-extensions>=4.10.0",
86
- "pyttsx3",
87
- # Composio Tool Router — bundled plugin needs this to talk to 1000+ apps
88
- # without going through MCP. Only ~1MB on the wheel; worth it as a default.
89
- "composio>=1.0.0rc2",
90
- # HTML parsing — used by web scraping flows, harvest commands,
91
- # and several plugins. Tiny dep; ship it by default.
92
- "beautifulsoup4>=4.12.0",
93
- "sentry-sdk>=2.0.0",
94
- # OS trust store — fixes CERTIFICATE_VERIFY_FAILED behind corporate TLS
95
- # interceptors (Cloudflare Zero Trust/WARP, Zscaler, Netskope). Tiny dep.
96
- "truststore>=0.9",
97
- # OCR — local text extraction from images/screenshots. pytesseract is
98
- # lightweight; Tesseract binary must be installed separately (see README).
99
- # Pillow already listed above — no duplicate needed.
100
- "pytesseract>=0.3.10",
101
- # Dulus Bar — the floating "Dynamic Island" (live model/ctx + Allow/Deny).
102
- # A normal library dep: pip pulls it (and its PyQt6) at install time; the
103
- # dulus wheel stays tiny — nothing is bundled. On by default so Dulus opens
104
- # with the island out of the box; a silent no-op on headless/no-display
105
- # boxes (Docker, servers, CI) since it never imports Qt without a screen.
106
- # Off switch for anyone who dislikes it: DULUS_BAR=0 or /config dulus_bar=0.
107
- "dulus-bar>=0.3.7",
108
- ]
109
-
110
- # mempalace pulls chromadb (26 transitive deps incl. numpy + onnxruntime),
111
- # which on termux/aarch64 has no wheels and on regular installs sends pip's
112
- # resolver into a backtracking loop trying to reconcile typing-extensions /
113
- # pydantic / httpx ranges. Keeping it optional lets `pip install dulus` succeed
114
- # in seconds everywhere; power users opt in with `pip install dulus[memory]`
115
- # (or `dulus[full]`) when they want MemPalace per-turn injection.
116
- [project.optional-dependencies]
117
- dev = [
118
- "build>=1.2",
119
- "pyright>=1.1.400",
120
- "pytest>=8.0",
121
- "pytest-asyncio>=0.23",
122
- "twine>=5.0",
123
- ]
124
- memory = ["mempalace>=3.3.4"]
125
- voice = ["sounddevice", "pyttsx3", "elevenlabs>=1.0.0"]
126
- webbridge = ["playwright>=1.40.0"]
127
- # LiteLLM unified gateway — one provider entry, 100+ backends (OpenRouter,
128
- # Groq, Together, Bedrock, Vertex, Cohere, Perplexity, xAI, Mistral, …).
129
- # Optional because it pulls a sizeable transitive dep tree (tokenizers,
130
- # tiktoken, click, importlib-metadata, etc.) most users won't need until
131
- # they pick litellm in the welcome wizard.
132
- litellm = ["litellm>=1.50.0"]
133
- # OCR — local text extraction from images, no vision model call. Cheaper
134
- # than /img for receipts, code screenshots, error stacks, dense tables.
135
- # pytesseract needs the Tesseract binary installed separately:
136
- # Windows: winget install -e --id UB-Mannheim.TesseractOCR
137
- # Linux: sudo apt-get install -y tesseract-ocr
138
- # macOS: brew install tesseract
139
- # easyocr is the pure-Python fallback but pulls ~1GB of PyTorch deps,
140
- # so we leave it out of the default extra; opt in with `dulus[ocr-deep]`.
141
- ocr = ["pytesseract>=0.3.10", "Pillow>=10.0.0"]
142
- ocr-deep = ["pytesseract>=0.3.10", "Pillow>=10.0.0", "easyocr>=1.7.0"]
143
- full = ["mempalace>=3.3.4", "sounddevice", "elevenlabs>=1.0.0", "playwright>=1.40.0", "litellm>=1.50.0", "pytesseract>=0.3.10"]
144
-
145
- [project.scripts]
146
- dulus = "dulus:main"
147
-
148
- [project.urls]
149
- Homepage = "https://github.com/KevRojo/Dulus"
150
- Repository = "https://github.com/KevRojo/Dulus"
151
- Documentation = "https://kevrojo.github.io/Dulus/"
152
- Changelog = "https://github.com/KevRojo/Dulus/blob/main/docs/news.md"
153
- Issues = "https://github.com/KevRojo/Dulus/issues"
154
-
155
- # ── Build config ────────────────────────────────────────────────────────────
156
- # Fast-path: ship every top-level .py as a module + every subpackage with
157
- # its __init__.py. Cleaner restructure can come later.
158
- [tool.setuptools]
159
- py-modules = [
160
- "agent",
161
- "algolia_search",
162
- "batch_api",
163
- "clipboard_utils",
164
- "cloudsave",
165
- "analytics",
166
- "common",
167
- "compaction",
168
- "config",
169
- "context",
170
- "display_blocks",
171
- "dulus",
172
- "dulus_bar_client",
173
- "dulus_gui",
174
- "dulus_quick_menu",
175
- "file_filter",
176
- "fs_compass",
177
- "governance",
178
- "input",
179
- "license_manager",
180
- "lookback",
181
- "model_params",
182
- "paste_placeholders",
183
- "personality_config",
184
- "profiles",
185
- "providers",
186
- "pyconsole",
187
- "sandbox_bootstrap",
188
- "skills",
189
- "soul",
190
- "spinner",
191
- "steer_input",
192
- "subagent",
193
- "tmux_tools",
194
- "tool_registry",
195
- "tools",
196
- "tools_background",
197
- "tools_think",
198
- "tools_todo",
199
- "updater",
200
- "webchat",
201
- "webchat_server",
202
- "welcome",
203
- ]
204
-
205
- [tool.setuptools.packages.find]
206
- where = ["."]
207
- include = [
208
- "backend*",
209
- "banners*",
210
- "checkpoint*",
211
- "cli_animations*",
212
- "data*",
213
- "docs*",
214
- "gui*",
215
- "dulus_mcp*",
216
- "dulus_tools*",
217
- "memory*",
218
- "multi_agent*",
219
- "plugin*",
220
- "skill*",
221
- "task*",
222
- "ui*",
223
- "voice*",
224
- "webbridge*",
225
- "webchat_ui*",
226
- # sandbox/dist/ ships in the wheel so webchat serves /sandbox/ directly
227
- # (back to the 0.2.81 layout — no tarball, no extract-on-first-run).
228
- # GitHub Linguist won't double-count: .gitattributes marks sandbox/**
229
- # as linguist-vendored=true.
230
- "sandbox*",
231
- ]
232
- exclude = [
233
- "tests*",
234
- "__pycache__*",
235
- # Don't ship sandbox sources / node_modules / vite cache — only dist/.
236
- "sandbox.src*",
237
- "sandbox.node_modules*",
238
- "sandbox.public*",
239
- ]
240
-
241
- [tool.setuptools.package-data]
242
- "*" = ["*.html", "*.css", "*.js", "*.jsx", "*.ts", "*.tsx", "*.svg", "*.json", "*.md", "*.png", "*.jpg", "*.jpeg", "*.txt", "*.py"]
243
- "sandbox" = ["dist/**/*", "dist/**/.*"]
244
- # Bundled Agent Skills shipped with Dulus (kepano's obsidian-skills suite,
245
- # etc.). Each lives at `skill/bundled/<name>/SKILL.md` with optional
246
- # `references/*.md` files the skill body links to.
247
- "skill" = ["bundled/**/*"]
1
+ # setuptools is pinned <77 on purpose: 77+ implements PEP 639 (SPDX license
2
+ # string + license-files) which emits Metadata-Version 2.4. pip < 24.1 — which
3
+ # ships on Ubuntu 24.04 LTS (pip 24.0) and many other current distros — cannot
4
+ # read Metadata 2.4 and silently skips the package, so `pip install dulus` fails
5
+ # with "Could not find a version that satisfies the requirement dulus (from
6
+ # versions: none)" on a fresh machine. Staying <77 keeps Metadata at 2.1/2.2.
7
+ [build-system]
8
+ requires = ["setuptools>=61,<77", "wheel"]
9
+ build-backend = "setuptools.build_meta"
10
+
11
+ [project]
12
+ name = "dulus"
13
+ version = "3.11.3"
14
+ description = "Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS."
15
+ readme = "README.md"
16
+ requires-python = ">=3.10"
17
+ # Legacy table form (not the PEP 639 SPDX string) so setuptools emits the older
18
+ # `License:` metadata field and keeps Metadata-Version at 2.1/2.2 — see the
19
+ # build-system note above. LICENSE ships via MANIFEST.in.
20
+ license = {text = "GPL-3.0-only"}
21
+ authors = [{name = "KevRojo", email = "dev@dulus.ai"}]
22
+ maintainers = [{name = "KevRojo", email = "dev@dulus.ai"}]
23
+ keywords = [
24
+ # Providers and runtimes people actually search for.
25
+ "ai", "cli", "llm", "claude", "gemini", "nvidia", "openai",
26
+ "kimi", "deepseek", "qwen", "ollama", "local-llm", "openai-compatible",
27
+ # What this thing IS. Without these the package never surfaces for the
28
+ # queries its own users type.
29
+ "agent", "ai-agent", "coding-agent", "autonomous-agent", "agentic",
30
+ "mcp", "terminal", "tui", "repl", "developer-tools", "sub-agents",
31
+ "tts", "voice",
32
+ ]
33
+ classifiers = [
34
+ # 19K+ installs, a full test suite and a 3.11.x line in production. This
35
+ # sat at "4 - Beta" long after that stopped being true, and the Beta badge
36
+ # is the first thing anyone reads on the PyPI page.
37
+ "Development Status :: 5 - Production/Stable",
38
+ # Dulus is not console-only: it ships a desktop GUI (pywebview), a Qt
39
+ # status bar, a Flask webchat and Dulus OS. Listing just Console hid every
40
+ # one of those surfaces.
41
+ "Environment :: Console",
42
+ "Environment :: Web Environment",
43
+ "Environment :: X11 Applications :: Qt",
44
+ "Environment :: Win32 (MS Windows)",
45
+ "Environment :: MacOS X",
46
+ # "Agentic AI for everyone" — the README's own pitch — is not a
47
+ # developers-only audience.
48
+ "Intended Audience :: Developers",
49
+ "Intended Audience :: End Users/Desktop",
50
+ "Intended Audience :: System Administrators",
51
+ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
52
+ "Natural Language :: English",
53
+ "Natural Language :: Spanish",
54
+ "Operating System :: OS Independent",
55
+ "Programming Language :: Python :: 3",
56
+ "Programming Language :: Python :: 3 :: Only",
57
+ "Programming Language :: Python :: 3.10",
58
+ "Programming Language :: Python :: 3.11",
59
+ "Programming Language :: Python :: 3.12",
60
+ "Programming Language :: Python :: 3.13",
61
+ "Programming Language :: Python :: 3.14",
62
+ # Topics decide which PyPI category listings this appears in. AI + Terminals
63
+ # alone missed the shell, code-generation, chat and speech angles that
64
+ # describe just as much of what Dulus does.
65
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
66
+ "Topic :: Terminals",
67
+ "Topic :: Software Development :: Code Generators",
68
+ "Topic :: System :: Shells",
69
+ "Topic :: Communications :: Chat",
70
+ "Topic :: Multimedia :: Sound/Audio :: Speech",
71
+ "Topic :: Utilities",
72
+ ]
73
+ dependencies = [
74
+ "anthropic>=0.40.0",
75
+ "openai>=1.30.0",
76
+ "httpx>=0.27.0",
77
+ "requests>=2.31.0",
78
+ 'tomli>=2.0; python_version < "3.11"', # stdlib tomllib is 3.11+; backport for 3.10
79
+ "rich>=13.0.0",
80
+ "prompt_toolkit>=3.0.0",
81
+ "Flask>=3.1.3",
82
+ "bubblewrap-cli>=1.0.0",
83
+ "customtkinter>=5.2.0",
84
+ "Pillow>=10.0.0",
85
+ "typing-extensions>=4.10.0",
86
+ "pyttsx3",
87
+ # Composio Tool Router — bundled plugin needs this to talk to 1000+ apps
88
+ # without going through MCP. Only ~1MB on the wheel; worth it as a default.
89
+ "composio>=1.0.0rc2",
90
+ # HTML parsing — used by web scraping flows, harvest commands,
91
+ # and several plugins. Tiny dep; ship it by default.
92
+ "beautifulsoup4>=4.12.0",
93
+ "sentry-sdk>=2.0.0",
94
+ # OS trust store — fixes CERTIFICATE_VERIFY_FAILED behind corporate TLS
95
+ # interceptors (Cloudflare Zero Trust/WARP, Zscaler, Netskope). Tiny dep.
96
+ "truststore>=0.9",
97
+ # OCR — local text extraction from images/screenshots. pytesseract is
98
+ # lightweight; Tesseract binary must be installed separately (see README).
99
+ # Pillow already listed above — no duplicate needed.
100
+ "pytesseract>=0.3.10",
101
+ # Dulus Bar — the floating "Dynamic Island" (live model/ctx + Allow/Deny).
102
+ # A normal library dep: pip pulls it (and its PyQt6) at install time; the
103
+ # dulus wheel stays tiny — nothing is bundled. On by default so Dulus opens
104
+ # with the island out of the box; a silent no-op on headless/no-display
105
+ # boxes (Docker, servers, CI) since it never imports Qt without a screen.
106
+ # Off switch for anyone who dislikes it: DULUS_BAR=0 or /config dulus_bar=0.
107
+ "dulus-bar>=0.3.7",
108
+ ]
109
+
110
+ # mempalace pulls chromadb (26 transitive deps incl. numpy + onnxruntime),
111
+ # which on termux/aarch64 has no wheels and on regular installs sends pip's
112
+ # resolver into a backtracking loop trying to reconcile typing-extensions /
113
+ # pydantic / httpx ranges. Keeping it optional lets `pip install dulus` succeed
114
+ # in seconds everywhere; power users opt in with `pip install dulus[memory]`
115
+ # (or `dulus[full]`) when they want MemPalace per-turn injection.
116
+ [project.optional-dependencies]
117
+ dev = [
118
+ "build>=1.2",
119
+ "pyright>=1.1.400",
120
+ "pytest>=8.0",
121
+ "pytest-asyncio>=0.23",
122
+ "twine>=5.0",
123
+ ]
124
+ memory = ["mempalace>=3.3.4"]
125
+ voice = ["sounddevice", "pyttsx3", "elevenlabs>=1.0.0"]
126
+ webbridge = ["playwright>=1.40.0"]
127
+ # LiteLLM unified gateway — one provider entry, 100+ backends (OpenRouter,
128
+ # Groq, Together, Bedrock, Vertex, Cohere, Perplexity, xAI, Mistral, …).
129
+ # Optional because it pulls a sizeable transitive dep tree (tokenizers,
130
+ # tiktoken, click, importlib-metadata, etc.) most users won't need until
131
+ # they pick litellm in the welcome wizard.
132
+ litellm = ["litellm>=1.50.0"]
133
+ # OCR — local text extraction from images, no vision model call. Cheaper
134
+ # than /img for receipts, code screenshots, error stacks, dense tables.
135
+ # pytesseract needs the Tesseract binary installed separately:
136
+ # Windows: winget install -e --id UB-Mannheim.TesseractOCR
137
+ # Linux: sudo apt-get install -y tesseract-ocr
138
+ # macOS: brew install tesseract
139
+ # easyocr is the pure-Python fallback but pulls ~1GB of PyTorch deps,
140
+ # so we leave it out of the default extra; opt in with `dulus[ocr-deep]`.
141
+ ocr = ["pytesseract>=0.3.10", "Pillow>=10.0.0"]
142
+ ocr-deep = ["pytesseract>=0.3.10", "Pillow>=10.0.0", "easyocr>=1.7.0"]
143
+ full = ["mempalace>=3.3.4", "sounddevice", "elevenlabs>=1.0.0", "playwright>=1.40.0", "litellm>=1.50.0", "pytesseract>=0.3.10"]
144
+
145
+ [project.scripts]
146
+ dulus = "dulus:main"
147
+
148
+ [project.urls]
149
+ Homepage = "https://github.com/KevRojo/Dulus"
150
+ Repository = "https://github.com/KevRojo/Dulus"
151
+ Documentation = "https://kevrojo.github.io/Dulus/"
152
+ Changelog = "https://github.com/KevRojo/Dulus/blob/main/docs/news.md"
153
+ Issues = "https://github.com/KevRojo/Dulus/issues"
154
+
155
+ # ── Build config ────────────────────────────────────────────────────────────
156
+ # Fast-path: ship every top-level .py as a module + every subpackage with
157
+ # its __init__.py. Cleaner restructure can come later.
158
+ [tool.setuptools]
159
+ py-modules = [
160
+ "agent",
161
+ "algolia_search",
162
+ "batch_api",
163
+ "clipboard_utils",
164
+ "cloudsave",
165
+ "analytics",
166
+ "common",
167
+ "compaction",
168
+ "config",
169
+ "context",
170
+ "display_blocks",
171
+ "dulus",
172
+ "dulus_bar_client",
173
+ "dulus_gui",
174
+ "dulus_quick_menu",
175
+ "file_filter",
176
+ "fs_compass",
177
+ "governance",
178
+ "input",
179
+ "license_manager",
180
+ "lookback",
181
+ "model_params",
182
+ "paste_placeholders",
183
+ "personality_config",
184
+ "profiles",
185
+ "providers",
186
+ "pyconsole",
187
+ "sandbox_bootstrap",
188
+ "skills",
189
+ "soul",
190
+ "spinner",
191
+ "steer_input",
192
+ "subagent",
193
+ "tmux_tools",
194
+ "tool_registry",
195
+ "tools",
196
+ "tools_background",
197
+ "tools_think",
198
+ "tools_todo",
199
+ "updater",
200
+ "webchat",
201
+ "webchat_server",
202
+ "welcome",
203
+ ]
204
+
205
+ [tool.setuptools.packages.find]
206
+ where = ["."]
207
+ include = [
208
+ "backend*",
209
+ "banners*",
210
+ "checkpoint*",
211
+ "cli_animations*",
212
+ "data*",
213
+ "docs*",
214
+ "gui*",
215
+ "dulus_mcp*",
216
+ "dulus_tools*",
217
+ "memory*",
218
+ "multi_agent*",
219
+ "plugin*",
220
+ "skill*",
221
+ "task*",
222
+ "ui*",
223
+ "voice*",
224
+ "webbridge*",
225
+ "webchat_ui*",
226
+ # sandbox/dist/ ships in the wheel so webchat serves /sandbox/ directly
227
+ # (back to the 0.2.81 layout — no tarball, no extract-on-first-run).
228
+ # GitHub Linguist won't double-count: .gitattributes marks sandbox/**
229
+ # as linguist-vendored=true.
230
+ "sandbox*",
231
+ ]
232
+ exclude = [
233
+ "tests*",
234
+ "__pycache__*",
235
+ # Don't ship sandbox sources / node_modules / vite cache — only dist/.
236
+ "sandbox.src*",
237
+ "sandbox.node_modules*",
238
+ "sandbox.public*",
239
+ ]
240
+
241
+ [tool.setuptools.package-data]
242
+ "*" = ["*.html", "*.css", "*.js", "*.jsx", "*.ts", "*.tsx", "*.svg", "*.json", "*.md", "*.png", "*.jpg", "*.jpeg", "*.txt", "*.py"]
243
+ "sandbox" = ["dist/**/*", "dist/**/.*"]
244
+ # Bundled Agent Skills shipped with Dulus (kepano's obsidian-skills suite,
245
+ # etc.). Each lives at `skill/bundled/<name>/SKILL.md` with optional
246
+ # `references/*.md` files the skill body links to.
247
+ "skill" = ["bundled/**/*"]