dulus 0.2.51__tar.gz → 0.2.53__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 (359) hide show
  1. {dulus-0.2.51/dulus.egg-info → dulus-0.2.53}/PKG-INFO +3 -2
  2. {dulus-0.2.51 → dulus-0.2.53}/README.md +2 -1
  3. {dulus-0.2.51 → dulus-0.2.53}/data/context.json +18 -26
  4. {dulus-0.2.51 → dulus-0.2.53/dulus.egg-info}/PKG-INFO +3 -2
  5. {dulus-0.2.51 → dulus-0.2.53}/dulus.py +92 -26
  6. {dulus-0.2.51 → dulus-0.2.53}/gui/session_utils.py +2 -1
  7. {dulus-0.2.51 → dulus-0.2.53}/pyproject.toml +1 -1
  8. {dulus-0.2.51 → dulus-0.2.53}/skill/clawhub.py +89 -1
  9. {dulus-0.2.51 → dulus-0.2.53}/LICENSE +0 -0
  10. {dulus-0.2.51 → dulus-0.2.53}/MANIFEST.in +0 -0
  11. {dulus-0.2.51 → dulus-0.2.53}/agent.py +0 -0
  12. {dulus-0.2.51 → dulus-0.2.53}/backend/__init__.py +0 -0
  13. {dulus-0.2.51 → dulus-0.2.53}/backend/agents_bridge.py +0 -0
  14. {dulus-0.2.51 → dulus-0.2.53}/backend/compressor.py +0 -0
  15. {dulus-0.2.51 → dulus-0.2.53}/backend/context.py +0 -0
  16. {dulus-0.2.51 → dulus-0.2.53}/backend/githook.py +0 -0
  17. {dulus-0.2.51 → dulus-0.2.53}/backend/marketplace.py +0 -0
  18. {dulus-0.2.51 → dulus-0.2.53}/backend/mempalace_bridge.py +0 -0
  19. {dulus-0.2.51 → dulus-0.2.53}/backend/personas.py +0 -0
  20. {dulus-0.2.51 → dulus-0.2.53}/backend/plugins.py +0 -0
  21. {dulus-0.2.51 → dulus-0.2.53}/backend/server.py +0 -0
  22. {dulus-0.2.51 → dulus-0.2.53}/backend/tasks.py +0 -0
  23. {dulus-0.2.51 → dulus-0.2.53}/batch_api.py +0 -0
  24. {dulus-0.2.51 → dulus-0.2.53}/checkpoint/__init__.py +0 -0
  25. {dulus-0.2.51 → dulus-0.2.53}/checkpoint/hooks.py +0 -0
  26. {dulus-0.2.51 → dulus-0.2.53}/checkpoint/store.py +0 -0
  27. {dulus-0.2.51 → dulus-0.2.53}/checkpoint/types.py +0 -0
  28. {dulus-0.2.51 → dulus-0.2.53}/claude_code_watcher.py +0 -0
  29. {dulus-0.2.51 → dulus-0.2.53}/clipboard_utils.py +0 -0
  30. {dulus-0.2.51 → dulus-0.2.53}/cloudsave.py +0 -0
  31. {dulus-0.2.51 → dulus-0.2.53}/common.py +0 -0
  32. {dulus-0.2.51 → dulus-0.2.53}/compaction.py +0 -0
  33. {dulus-0.2.51 → dulus-0.2.53}/config.py +0 -0
  34. {dulus-0.2.51 → dulus-0.2.53}/context.py +0 -0
  35. {dulus-0.2.51 → dulus-0.2.53}/data/__init__.py +0 -0
  36. {dulus-0.2.51 → dulus-0.2.53}/data/active_persona.json +0 -0
  37. {dulus-0.2.51 → dulus-0.2.53}/data/marketplace.json +0 -0
  38. {dulus-0.2.51 → dulus-0.2.53}/data/personas.json +0 -0
  39. {dulus-0.2.51 → dulus-0.2.53}/data/plugins/__init__.py +0 -0
  40. {dulus-0.2.51 → dulus-0.2.53}/data/plugins/composio/__init__.py +0 -0
  41. {dulus-0.2.51 → dulus-0.2.53}/data/plugins/composio/composio_plugin/__init__.py +0 -0
  42. {dulus-0.2.51 → dulus-0.2.53}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
  43. {dulus-0.2.51 → dulus-0.2.53}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
  44. {dulus-0.2.51 → dulus-0.2.53}/data/plugins/composio/plugin.json +0 -0
  45. {dulus-0.2.51 → dulus-0.2.53}/data/plugins/composio/plugin_tool.py +0 -0
  46. {dulus-0.2.51 → dulus-0.2.53}/data/tasks.json +0 -0
  47. {dulus-0.2.51 → dulus-0.2.53}/docs/README.md +0 -0
  48. {dulus-0.2.51 → dulus-0.2.53}/docs/__init__.py +0 -0
  49. {dulus-0.2.51 → dulus-0.2.53}/docs/api.html +0 -0
  50. {dulus-0.2.51 → dulus-0.2.53}/docs/architecture.md +0 -0
  51. {dulus-0.2.51 → dulus-0.2.53}/docs/azure-speech-template.json +0 -0
  52. {dulus-0.2.51 → dulus-0.2.53}/docs/dashboard/index.html +0 -0
  53. {dulus-0.2.51 → dulus-0.2.53}/docs/divider.svg +0 -0
  54. {dulus-0.2.51 → dulus-0.2.53}/docs/generate.py +0 -0
  55. {dulus-0.2.51 → dulus-0.2.53}/docs/hero.svg +0 -0
  56. {dulus-0.2.51 → dulus-0.2.53}/docs/index.html +0 -0
  57. {dulus-0.2.51 → dulus-0.2.53}/docs/news.md +0 -0
  58. {dulus-0.2.51 → dulus-0.2.53}/docs/nvidia-models.svg +0 -0
  59. {dulus-0.2.51 → dulus-0.2.53}/docs/particle-playground.html +0 -0
  60. {dulus-0.2.51 → dulus-0.2.53}/docs/personas/index.html +0 -0
  61. {dulus-0.2.51 → dulus-0.2.53}/docs/poetry-banner.png +0 -0
  62. {dulus-0.2.51 → dulus-0.2.53}/docs/preview.html +0 -0
  63. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-agents.svg +0 -0
  64. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-brainstorm.svg +0 -0
  65. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-bridges.svg +0 -0
  66. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-features.svg +0 -0
  67. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-freetier.svg +0 -0
  68. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-memory.svg +0 -0
  69. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-models.svg +0 -0
  70. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-perms.svg +0 -0
  71. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-plugins.svg +0 -0
  72. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-quickstart.svg +0 -0
  73. {dulus-0.2.51 → dulus-0.2.53}/docs/sec-ssj.svg +0 -0
  74. {dulus-0.2.51 → dulus-0.2.53}/docs/spinners.svg +0 -0
  75. {dulus-0.2.51 → dulus-0.2.53}/docs/split-pane.svg +0 -0
  76. {dulus-0.2.51 → dulus-0.2.53}/docs/terminal-boot.svg +0 -0
  77. {dulus-0.2.51 → dulus-0.2.53}/docs/uploads/particle-playground.html +0 -0
  78. {dulus-0.2.51 → dulus-0.2.53}/dulus.egg-info/SOURCES.txt +0 -0
  79. {dulus-0.2.51 → dulus-0.2.53}/dulus.egg-info/dependency_links.txt +0 -0
  80. {dulus-0.2.51 → dulus-0.2.53}/dulus.egg-info/entry_points.txt +0 -0
  81. {dulus-0.2.51 → dulus-0.2.53}/dulus.egg-info/requires.txt +0 -0
  82. {dulus-0.2.51 → dulus-0.2.53}/dulus.egg-info/top_level.txt +0 -0
  83. {dulus-0.2.51 → dulus-0.2.53}/dulus_gui.py +0 -0
  84. {dulus-0.2.51 → dulus-0.2.53}/dulus_mcp/__init__.py +0 -0
  85. {dulus-0.2.51 → dulus-0.2.53}/dulus_mcp/client.py +0 -0
  86. {dulus-0.2.51 → dulus-0.2.53}/dulus_mcp/config.py +0 -0
  87. {dulus-0.2.51 → dulus-0.2.53}/dulus_mcp/tools.py +0 -0
  88. {dulus-0.2.51 → dulus-0.2.53}/dulus_mcp/types.py +0 -0
  89. {dulus-0.2.51 → dulus-0.2.53}/gui/__init__.py +0 -0
  90. {dulus-0.2.51 → dulus-0.2.53}/gui/agent_bridge.py +0 -0
  91. {dulus-0.2.51 → dulus-0.2.53}/gui/chat_widget.py +0 -0
  92. {dulus-0.2.51 → dulus-0.2.53}/gui/main_window.py +0 -0
  93. {dulus-0.2.51 → dulus-0.2.53}/gui/personas.py +0 -0
  94. {dulus-0.2.51 → dulus-0.2.53}/gui/settings_dialog.py +0 -0
  95. {dulus-0.2.51 → dulus-0.2.53}/gui/sidebar.py +0 -0
  96. {dulus-0.2.51 → dulus-0.2.53}/gui/tasks_view.py +0 -0
  97. {dulus-0.2.51 → dulus-0.2.53}/gui/themes.py +0 -0
  98. {dulus-0.2.51 → dulus-0.2.53}/gui/tool_panel.py +0 -0
  99. {dulus-0.2.51 → dulus-0.2.53}/input.py +0 -0
  100. {dulus-0.2.51 → dulus-0.2.53}/license_manager.py +0 -0
  101. {dulus-0.2.51 → dulus-0.2.53}/memory/__init__.py +0 -0
  102. {dulus-0.2.51 → dulus-0.2.53}/memory/audit.py +0 -0
  103. {dulus-0.2.51 → dulus-0.2.53}/memory/consolidator.py +0 -0
  104. {dulus-0.2.51 → dulus-0.2.53}/memory/context.py +0 -0
  105. {dulus-0.2.51 → dulus-0.2.53}/memory/offload.py +0 -0
  106. {dulus-0.2.51 → dulus-0.2.53}/memory/palace.py +0 -0
  107. {dulus-0.2.51 → dulus-0.2.53}/memory/scan.py +0 -0
  108. {dulus-0.2.51 → dulus-0.2.53}/memory/sessions.py +0 -0
  109. {dulus-0.2.51 → dulus-0.2.53}/memory/store.py +0 -0
  110. {dulus-0.2.51 → dulus-0.2.53}/memory/tools.py +0 -0
  111. {dulus-0.2.51 → dulus-0.2.53}/memory/types.py +0 -0
  112. {dulus-0.2.51 → dulus-0.2.53}/memory/vector_search.py +0 -0
  113. {dulus-0.2.51 → dulus-0.2.53}/multi_agent/__init__.py +0 -0
  114. {dulus-0.2.51 → dulus-0.2.53}/multi_agent/subagent.py +0 -0
  115. {dulus-0.2.51 → dulus-0.2.53}/multi_agent/tools.py +0 -0
  116. {dulus-0.2.51 → dulus-0.2.53}/offload_helper.py +0 -0
  117. {dulus-0.2.51 → dulus-0.2.53}/plugin/__init__.py +0 -0
  118. {dulus-0.2.51 → dulus-0.2.53}/plugin/autoadapter.py +0 -0
  119. {dulus-0.2.51 → dulus-0.2.53}/plugin/loader.py +0 -0
  120. {dulus-0.2.51 → dulus-0.2.53}/plugin/recommend.py +0 -0
  121. {dulus-0.2.51 → dulus-0.2.53}/plugin/store.py +0 -0
  122. {dulus-0.2.51 → dulus-0.2.53}/plugin/types.py +0 -0
  123. {dulus-0.2.51 → dulus-0.2.53}/providers.py +0 -0
  124. {dulus-0.2.51 → dulus-0.2.53}/sandbox/README.md +0 -0
  125. {dulus-0.2.51 → dulus-0.2.53}/sandbox/__init__.py +0 -0
  126. {dulus-0.2.51 → dulus-0.2.53}/sandbox/components.json +0 -0
  127. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
  128. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
  129. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/index.html +0 -0
  130. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/wallpaper-default.jpg +0 -0
  131. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/wallpapers/default.jpeg +0 -0
  132. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/wallpapers/light.jpeg +0 -0
  133. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/wallpapers/nature.jpeg +0 -0
  134. {dulus-0.2.51 → dulus-0.2.53}/sandbox/dist/wallpapers/tech.jpeg +0 -0
  135. {dulus-0.2.51 → dulus-0.2.53}/sandbox/eslint.config.js +0 -0
  136. {dulus-0.2.51 → dulus-0.2.53}/sandbox/index.html +0 -0
  137. {dulus-0.2.51 → dulus-0.2.53}/sandbox/info.md +0 -0
  138. {dulus-0.2.51 → dulus-0.2.53}/sandbox/package-lock.json +0 -0
  139. {dulus-0.2.51 → dulus-0.2.53}/sandbox/package.json +0 -0
  140. {dulus-0.2.51 → dulus-0.2.53}/sandbox/postcss.config.js +0 -0
  141. {dulus-0.2.51 → dulus-0.2.53}/sandbox/public/wallpaper-default.jpg +0 -0
  142. {dulus-0.2.51 → dulus-0.2.53}/sandbox/public/wallpapers/default.jpeg +0 -0
  143. {dulus-0.2.51 → dulus-0.2.53}/sandbox/public/wallpapers/light.jpeg +0 -0
  144. {dulus-0.2.51 → dulus-0.2.53}/sandbox/public/wallpapers/nature.jpeg +0 -0
  145. {dulus-0.2.51 → dulus-0.2.53}/sandbox/public/wallpapers/tech.jpeg +0 -0
  146. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/App.tsx +0 -0
  147. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/AgentMonitor.tsx +0 -0
  148. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/ApiTester.tsx +0 -0
  149. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/AppRouter.tsx +0 -0
  150. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/ArchiveManager.tsx +0 -0
  151. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/AsciiArt.tsx +0 -0
  152. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Base64Tool.tsx +0 -0
  153. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Browser.tsx +0 -0
  154. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Calculator.tsx +0 -0
  155. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Calendar.tsx +0 -0
  156. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Chat.tsx +0 -0
  157. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Chess.tsx +0 -0
  158. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Clock.tsx +0 -0
  159. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/CodeEditor.tsx +0 -0
  160. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/ColorPalette.tsx +0 -0
  161. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/ColorPicker.tsx +0 -0
  162. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Contacts.tsx +0 -0
  163. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/DocumentViewer.tsx +0 -0
  164. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Drawing.tsx +0 -0
  165. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Email.tsx +0 -0
  166. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/FileManager.tsx +0 -0
  167. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/FlappyBird.tsx +0 -0
  168. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/FtpClient.tsx +0 -0
  169. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Game2048.tsx +0 -0
  170. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/GitClient.tsx +0 -0
  171. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/ImageGallery.tsx +0 -0
  172. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/ImageViewer.tsx +0 -0
  173. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/JsonFormatter.tsx +0 -0
  174. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/MarkdownPreview.tsx +0 -0
  175. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/MatrixRain.tsx +0 -0
  176. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/MediaConverter.tsx +0 -0
  177. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Memory.tsx +0 -0
  178. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/MemoryManager.tsx +0 -0
  179. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Minesweeper.tsx +0 -0
  180. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/MusicPlayer.tsx +0 -0
  181. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/NetworkTools.tsx +0 -0
  182. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Notes.tsx +0 -0
  183. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/PasswordManager.tsx +0 -0
  184. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/PhotoEditor.tsx +0 -0
  185. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Pong.tsx +0 -0
  186. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/RegexTester.tsx +0 -0
  187. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Reminders.tsx +0 -0
  188. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/RssReader.tsx +0 -0
  189. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/ScreenRecorder.tsx +0 -0
  190. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Settings.tsx +0 -0
  191. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/SkillsLauncher.tsx +0 -0
  192. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Snake.tsx +0 -0
  193. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Solitaire.tsx +0 -0
  194. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Spreadsheet.tsx +0 -0
  195. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Sudoku.tsx +0 -0
  196. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/SystemMonitor.tsx +0 -0
  197. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/TaskManager.tsx +0 -0
  198. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Terminal.tsx +0 -0
  199. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Tetris.tsx +0 -0
  200. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/TextEditor.tsx +0 -0
  201. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/TicTacToe.tsx +0 -0
  202. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Todo.tsx +0 -0
  203. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/VideoPlayer.tsx +0 -0
  204. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/VoiceRecorder.tsx +0 -0
  205. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Weather.tsx +0 -0
  206. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/Whiteboard.tsx +0 -0
  207. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/apps/registry.ts +0 -0
  208. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/AppContainer.tsx +0 -0
  209. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/AppLauncher.tsx +0 -0
  210. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/BootSequence.tsx +0 -0
  211. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ContextMenu.tsx +0 -0
  212. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/Desktop.tsx +0 -0
  213. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/Dock.tsx +0 -0
  214. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/LoginScreen.tsx +0 -0
  215. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/NotImplemented.tsx +0 -0
  216. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/NotificationCenter.tsx +0 -0
  217. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/NotificationSystem.tsx +0 -0
  218. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/TopPanel.tsx +0 -0
  219. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/WindowFrame.tsx +0 -0
  220. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/WindowManager.tsx +0 -0
  221. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/accordion.tsx +0 -0
  222. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/alert-dialog.tsx +0 -0
  223. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/alert.tsx +0 -0
  224. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/aspect-ratio.tsx +0 -0
  225. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/avatar.tsx +0 -0
  226. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/badge.tsx +0 -0
  227. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/breadcrumb.tsx +0 -0
  228. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/button-group.tsx +0 -0
  229. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/button.tsx +0 -0
  230. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/calendar.tsx +0 -0
  231. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/card.tsx +0 -0
  232. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/carousel.tsx +0 -0
  233. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/chart.tsx +0 -0
  234. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/checkbox.tsx +0 -0
  235. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/collapsible.tsx +0 -0
  236. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/command.tsx +0 -0
  237. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/context-menu.tsx +0 -0
  238. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/dialog.tsx +0 -0
  239. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/drawer.tsx +0 -0
  240. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/dropdown-menu.tsx +0 -0
  241. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/empty.tsx +0 -0
  242. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/field.tsx +0 -0
  243. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/form.tsx +0 -0
  244. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/hover-card.tsx +0 -0
  245. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/input-group.tsx +0 -0
  246. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/input-otp.tsx +0 -0
  247. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/input.tsx +0 -0
  248. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/item.tsx +0 -0
  249. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/kbd.tsx +0 -0
  250. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/label.tsx +0 -0
  251. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/menubar.tsx +0 -0
  252. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/navigation-menu.tsx +0 -0
  253. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/pagination.tsx +0 -0
  254. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/popover.tsx +0 -0
  255. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/progress.tsx +0 -0
  256. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/radio-group.tsx +0 -0
  257. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/resizable.tsx +0 -0
  258. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/scroll-area.tsx +0 -0
  259. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/select.tsx +0 -0
  260. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/separator.tsx +0 -0
  261. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/sheet.tsx +0 -0
  262. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/sidebar.tsx +0 -0
  263. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/skeleton.tsx +0 -0
  264. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/slider.tsx +0 -0
  265. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/sonner.tsx +0 -0
  266. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/spinner.tsx +0 -0
  267. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/switch.tsx +0 -0
  268. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/table.tsx +0 -0
  269. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/tabs.tsx +0 -0
  270. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/textarea.tsx +0 -0
  271. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/toggle-group.tsx +0 -0
  272. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/toggle.tsx +0 -0
  273. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/components/ui/tooltip.tsx +0 -0
  274. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/index.ts +0 -0
  275. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/use-mobile.ts +0 -0
  276. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useAutoOpenChat.ts +0 -0
  277. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useDulusAgents.ts +0 -0
  278. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useDulusChat.ts +0 -0
  279. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useDulusEvents.ts +0 -0
  280. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useDulusHealth.ts +0 -0
  281. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useDulusMemory.ts +0 -0
  282. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useDulusSkills.ts +0 -0
  283. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useDulusTasks.ts +0 -0
  284. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useFileSystem.ts +0 -0
  285. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useOSStore.tsx +0 -0
  286. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useSkillBridge.ts +0 -0
  287. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useSystemBattery.ts +0 -0
  288. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useSystemNetwork.ts +0 -0
  289. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/hooks/useSystemVolume.ts +0 -0
  290. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/index.css +0 -0
  291. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/lib/dulus-api.ts +0 -0
  292. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/lib/utils.ts +0 -0
  293. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/main.tsx +0 -0
  294. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/types/index.ts +0 -0
  295. {dulus-0.2.51 → dulus-0.2.53}/sandbox/src/utils/assets.ts +0 -0
  296. {dulus-0.2.51 → dulus-0.2.53}/sandbox/tailwind.config.js +0 -0
  297. {dulus-0.2.51 → dulus-0.2.53}/sandbox/tsconfig.app.json +0 -0
  298. {dulus-0.2.51 → dulus-0.2.53}/sandbox/tsconfig.json +0 -0
  299. {dulus-0.2.51 → dulus-0.2.53}/sandbox/tsconfig.node.json +0 -0
  300. {dulus-0.2.51 → dulus-0.2.53}/sandbox/vite.config.ts +0 -0
  301. {dulus-0.2.51 → dulus-0.2.53}/setup.cfg +0 -0
  302. {dulus-0.2.51 → dulus-0.2.53}/skill/__init__.py +0 -0
  303. {dulus-0.2.51 → dulus-0.2.53}/skill/builtin.py +0 -0
  304. {dulus-0.2.51 → dulus-0.2.53}/skill/executor.py +0 -0
  305. {dulus-0.2.51 → dulus-0.2.53}/skill/loader.py +0 -0
  306. {dulus-0.2.51 → dulus-0.2.53}/skill/tools.py +0 -0
  307. {dulus-0.2.51 → dulus-0.2.53}/skills.py +0 -0
  308. {dulus-0.2.51 → dulus-0.2.53}/spinner.py +0 -0
  309. {dulus-0.2.51 → dulus-0.2.53}/string_utils.py +0 -0
  310. {dulus-0.2.51 → dulus-0.2.53}/subagent.py +0 -0
  311. {dulus-0.2.51 → dulus-0.2.53}/task/__init__.py +0 -0
  312. {dulus-0.2.51 → dulus-0.2.53}/task/store.py +0 -0
  313. {dulus-0.2.51 → dulus-0.2.53}/task/tools.py +0 -0
  314. {dulus-0.2.51 → dulus-0.2.53}/task/types.py +0 -0
  315. {dulus-0.2.51 → dulus-0.2.53}/tests/test_afk_yolo.py +0 -0
  316. {dulus-0.2.51 → dulus-0.2.53}/tests/test_approval_runtime.py +0 -0
  317. {dulus-0.2.51 → dulus-0.2.53}/tests/test_background_task_tools.py +0 -0
  318. {dulus-0.2.51 → dulus-0.2.53}/tests/test_background_tasks.py +0 -0
  319. {dulus-0.2.51 → dulus-0.2.53}/tests/test_checkpoint.py +0 -0
  320. {dulus-0.2.51 → dulus-0.2.53}/tests/test_clipboard_utils.py +0 -0
  321. {dulus-0.2.51 → dulus-0.2.53}/tests/test_compaction.py +0 -0
  322. {dulus-0.2.51 → dulus-0.2.53}/tests/test_diff_view.py +0 -0
  323. {dulus-0.2.51 → dulus-0.2.53}/tests/test_diff_visualization.py +0 -0
  324. {dulus-0.2.51 → dulus-0.2.53}/tests/test_display_blocks.py +0 -0
  325. {dulus-0.2.51 → dulus-0.2.53}/tests/test_export_import.py +0 -0
  326. {dulus-0.2.51 → dulus-0.2.53}/tests/test_hook_engine.py +0 -0
  327. {dulus-0.2.51 → dulus-0.2.53}/tests/test_injection_fix.py +0 -0
  328. {dulus-0.2.51 → dulus-0.2.53}/tests/test_license.py +0 -0
  329. {dulus-0.2.51 → dulus-0.2.53}/tests/test_mcp.py +0 -0
  330. {dulus-0.2.51 → dulus-0.2.53}/tests/test_memory.py +0 -0
  331. {dulus-0.2.51 → dulus-0.2.53}/tests/test_notification_manager.py +0 -0
  332. {dulus-0.2.51 → dulus-0.2.53}/tests/test_plugin.py +0 -0
  333. {dulus-0.2.51 → dulus-0.2.53}/tests/test_session_fork.py +0 -0
  334. {dulus-0.2.51 → dulus-0.2.53}/tests/test_shell_mode.py +0 -0
  335. {dulus-0.2.51 → dulus-0.2.53}/tests/test_skills.py +0 -0
  336. {dulus-0.2.51 → dulus-0.2.53}/tests/test_steer_input.py +0 -0
  337. {dulus-0.2.51 → dulus-0.2.53}/tests/test_subagent.py +0 -0
  338. {dulus-0.2.51 → dulus-0.2.53}/tests/test_task.py +0 -0
  339. {dulus-0.2.51 → dulus-0.2.53}/tests/test_telegram_buffer.py +0 -0
  340. {dulus-0.2.51 → dulus-0.2.53}/tests/test_think_tool.py +0 -0
  341. {dulus-0.2.51 → dulus-0.2.53}/tests/test_todo_tool.py +0 -0
  342. {dulus-0.2.51 → dulus-0.2.53}/tests/test_todo_visualization.py +0 -0
  343. {dulus-0.2.51 → dulus-0.2.53}/tests/test_tool_registry.py +0 -0
  344. {dulus-0.2.51 → dulus-0.2.53}/tests/test_voice.py +0 -0
  345. {dulus-0.2.51 → dulus-0.2.53}/tests/test_wire_events.py +0 -0
  346. {dulus-0.2.51 → dulus-0.2.53}/tmux_offloader.py +0 -0
  347. {dulus-0.2.51 → dulus-0.2.53}/tmux_tools.py +0 -0
  348. {dulus-0.2.51 → dulus-0.2.53}/tool_registry.py +0 -0
  349. {dulus-0.2.51 → dulus-0.2.53}/tools.py +0 -0
  350. {dulus-0.2.51 → dulus-0.2.53}/ui/__init__.py +0 -0
  351. {dulus-0.2.51 → dulus-0.2.53}/ui/input.py +0 -0
  352. {dulus-0.2.51 → dulus-0.2.53}/ui/render.py +0 -0
  353. {dulus-0.2.51 → dulus-0.2.53}/voice/__init__.py +0 -0
  354. {dulus-0.2.51 → dulus-0.2.53}/voice/keyterms.py +0 -0
  355. {dulus-0.2.51 → dulus-0.2.53}/voice/recorder.py +0 -0
  356. {dulus-0.2.51 → dulus-0.2.53}/voice/stt.py +0 -0
  357. {dulus-0.2.51 → dulus-0.2.53}/voice/tts.py +0 -0
  358. {dulus-0.2.51 → dulus-0.2.53}/webchat.py +0 -0
  359. {dulus-0.2.51 → dulus-0.2.53}/webchat_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.51
3
+ Version: 0.2.53
4
4
  Summary: Spanish-first multi-provider AI CLI — 14 NVIDIA models free, Mesa Redonda, voice, TTS, RTK token reducer, MemPalace
5
5
  Author: KevRojo
6
6
  License: GPL-3.0
@@ -69,7 +69,7 @@ SET /sticky_input ON since the first run for the best experience!
69
69
  <a href="https://pypi.org/project/dulus/"><img src="https://static.pepy.tech/badge/dulus?style=flat-square" alt="downloads"/></a>
70
70
  <img src="https://img.shields.io/badge/python-3.11+-ff6b1f?style=flat-square&labelColor=07070a" alt="python"/>
71
71
  <img src="https://img.shields.io/badge/license-GPLv3-ff6b1f?style=flat-square&labelColor=07070a" alt="license"/>
72
- <img src="https://img.shields.io/badge/version-v0.2.44-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
72
+ <img src="https://img.shields.io/badge/version-v0.2.52-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
73
73
  <img src="https://img.shields.io/badge/providers-11-ff6b1f?style=flat-square&labelColor=07070a" alt="providers"/>
74
74
  <img src="https://img.shields.io/badge/tools-27-ff6b1f?style=flat-square&labelColor=07070a" alt="tools"/>
75
75
  <img src="https://img.shields.io/badge/tests-263+-ff6b1f?style=flat-square&labelColor=07070a" alt="tests"/>
@@ -125,6 +125,7 @@ Dulus adapt any python repository <3
125
125
 
126
126
  Dulus is a **lightweight Python reimplementation of Claude Code** that isn't locked to Claude. It ships the whole loop — REPL, tool dispatch, streaming, context compaction, checkpoints, sub-agents, voice, Telegram bridge, MCP, plugins — in roughly **12K lines you can actually read**. Fork it. Bend it. Run it offline against Qwen on your M2.
127
127
 
128
+ > **v0.2.52 — May 12, 2026** — Session system overhaul: removed 50-session scan limit, metadata now includes message counts, eliminated daily prune from save path. **Recommendation:** wipe old sessions and start clean — only sessions, your memories stay intact.
128
129
  > **v0.2.22 — May 9, 2026** — `/bg start` spawns one detached Dulus daemon that serves CLI (IPC), Web (browser at `127.0.0.1:5000`), and Telegram simultaneously — all sharing the same session. WebChat now defaults to **loopback-only** (opt-in to LAN exposure with `/webchat lan on`).
129
130
  > **v0.2.21 — May 9, 2026** — Console-freeze fix: system prompt now tells the model SleepTimer is for user reminders only — pauses inside command pipelines must use `sleep N` inside the Bash command itself.
130
131
  > **v0.2.20 — May 9, 2026** — Windows IPC port-collision fix: switched to `SO_EXCLUSIVEADDRUSE` so a second Dulus instance correctly cedes the port and acts as client. End-to-end tested.
@@ -22,7 +22,7 @@ SET /sticky_input ON since the first run for the best experience!
22
22
  <a href="https://pypi.org/project/dulus/"><img src="https://static.pepy.tech/badge/dulus?style=flat-square" alt="downloads"/></a>
23
23
  <img src="https://img.shields.io/badge/python-3.11+-ff6b1f?style=flat-square&labelColor=07070a" alt="python"/>
24
24
  <img src="https://img.shields.io/badge/license-GPLv3-ff6b1f?style=flat-square&labelColor=07070a" alt="license"/>
25
- <img src="https://img.shields.io/badge/version-v0.2.44-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
25
+ <img src="https://img.shields.io/badge/version-v0.2.52-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
26
26
  <img src="https://img.shields.io/badge/providers-11-ff6b1f?style=flat-square&labelColor=07070a" alt="providers"/>
27
27
  <img src="https://img.shields.io/badge/tools-27-ff6b1f?style=flat-square&labelColor=07070a" alt="tools"/>
28
28
  <img src="https://img.shields.io/badge/tests-263+-ff6b1f?style=flat-square&labelColor=07070a" alt="tests"/>
@@ -78,6 +78,7 @@ Dulus adapt any python repository <3
78
78
 
79
79
  Dulus is a **lightweight Python reimplementation of Claude Code** that isn't locked to Claude. It ships the whole loop — REPL, tool dispatch, streaming, context compaction, checkpoints, sub-agents, voice, Telegram bridge, MCP, plugins — in roughly **12K lines you can actually read**. Fork it. Bend it. Run it offline against Qwen on your M2.
80
80
 
81
+ > **v0.2.52 — May 12, 2026** — Session system overhaul: removed 50-session scan limit, metadata now includes message counts, eliminated daily prune from save path. **Recommendation:** wipe old sessions and start clean — only sessions, your memories stay intact.
81
82
  > **v0.2.22 — May 9, 2026** — `/bg start` spawns one detached Dulus daemon that serves CLI (IPC), Web (browser at `127.0.0.1:5000`), and Telegram simultaneously — all sharing the same session. WebChat now defaults to **loopback-only** (opt-in to LAN exposure with `/webchat lan on`).
82
83
  > **v0.2.21 — May 9, 2026** — Console-freeze fix: system prompt now tells the model SleepTimer is for user reminders only — pauses inside command pipelines must use `sleep N` inside the Bash command itself.
83
84
  > **v0.2.20 — May 9, 2026** — Windows IPC port-collision fix: switched to `SO_EXCLUSIVEADDRUSE` so a second Dulus instance correctly cedes the port and acts as client. End-to-end tested.
@@ -10,20 +10,20 @@
10
10
  "name": "Dulus Command Center",
11
11
  "repo_stats": {
12
12
  "files": 432,
13
- "lines": 204971,
13
+ "lines": 205188,
14
14
  "languages": {
15
15
  ".example": 5,
16
16
  "no_ext": 1424,
17
- ".py": 60404,
17
+ ".py": 60473,
18
18
  ".html": 14944,
19
19
  ".in": 3,
20
20
  ".toml": 129,
21
21
  ".md": 2161,
22
22
  ".txt": 463,
23
23
  ".lock": 1,
24
- ".json": 9521,
25
- ".whl": 21605,
26
- ".gz": 20876,
24
+ ".json": 9513,
25
+ ".whl": 21729,
26
+ ".gz": 20908,
27
27
  ".svg": 1123,
28
28
  ".png": 31639,
29
29
  ".sh": 144,
@@ -38,49 +38,41 @@
38
38
  },
39
39
  "recent_commits": [
40
40
  {
41
- "hash": "fae4455",
42
- "subject": "feat: MemoryManager overhaul, skill bridge polish, server sync",
41
+ "hash": "7fc805e",
42
+ "subject": "chore: bump version 0.2.50 -> 0.2.51",
43
43
  "author": "KevRojo",
44
44
  "date": "2026-05-12"
45
45
  },
46
46
  {
47
- "hash": "bf6455f",
48
- "subject": "feat: skill-to-chat bridge, MemPalace search API, sandbox UX polish",
47
+ "hash": "360badc",
48
+ "subject": "fix: GUI session responsiveness, sidebar incremental diff, async scan, default session IDs",
49
49
  "author": "KevRojo",
50
50
  "date": "2026-05-12"
51
51
  },
52
52
  {
53
- "hash": "9803f97",
54
- "subject": "fix: include sandbox/src and sandbox/public in wheel",
53
+ "hash": "fae4455",
54
+ "subject": "feat: MemoryManager overhaul, skill bridge polish, server sync",
55
55
  "author": "KevRojo",
56
56
  "date": "2026-05-12"
57
57
  },
58
58
  {
59
- "hash": "a157622",
60
- "subject": "fix: include missing sandbox JS bundle and anchor dist/build ignore to root",
59
+ "hash": "bf6455f",
60
+ "subject": "feat: skill-to-chat bridge, MemPalace search API, sandbox UX polish",
61
61
  "author": "KevRojo",
62
62
  "date": "2026-05-12"
63
63
  },
64
64
  {
65
- "hash": "cfa4e4e",
66
- "subject": "bump: 0.2.45 → 0.2.46",
65
+ "hash": "9803f97",
66
+ "subject": "fix: include sandbox/src and sandbox/public in wheel",
67
67
  "author": "KevRojo",
68
68
  "date": "2026-05-12"
69
69
  }
70
70
  ],
71
71
  "recent_changes": [
72
- "backend/server.py",
73
72
  "data/context.json",
74
- "pyproject.toml",
75
- "sandbox/dist/assets/index-CsIO61nW.css",
76
- "sandbox/dist/assets/index-DE51D6wI.css",
77
- "sandbox/dist/assets/index-DMCCNE9Y.js",
78
- "sandbox/dist/index.html",
79
- "sandbox/src/apps/Chat.tsx",
80
- "sandbox/src/apps/MemoryManager.tsx",
81
- "sandbox/src/hooks/useSkillBridge.ts",
82
- "sandbox/src/lib/dulus-api.ts",
83
- "webchat_server.py"
73
+ "dulus.py",
74
+ "gui/session_utils.py",
75
+ "pyproject.toml"
84
76
  ]
85
77
  },
86
78
  "tasks": {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.51
3
+ Version: 0.2.53
4
4
  Summary: Spanish-first multi-provider AI CLI — 14 NVIDIA models free, Mesa Redonda, voice, TTS, RTK token reducer, MemPalace
5
5
  Author: KevRojo
6
6
  License: GPL-3.0
@@ -69,7 +69,7 @@ SET /sticky_input ON since the first run for the best experience!
69
69
  <a href="https://pypi.org/project/dulus/"><img src="https://static.pepy.tech/badge/dulus?style=flat-square" alt="downloads"/></a>
70
70
  <img src="https://img.shields.io/badge/python-3.11+-ff6b1f?style=flat-square&labelColor=07070a" alt="python"/>
71
71
  <img src="https://img.shields.io/badge/license-GPLv3-ff6b1f?style=flat-square&labelColor=07070a" alt="license"/>
72
- <img src="https://img.shields.io/badge/version-v0.2.44-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
72
+ <img src="https://img.shields.io/badge/version-v0.2.52-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
73
73
  <img src="https://img.shields.io/badge/providers-11-ff6b1f?style=flat-square&labelColor=07070a" alt="providers"/>
74
74
  <img src="https://img.shields.io/badge/tools-27-ff6b1f?style=flat-square&labelColor=07070a" alt="tools"/>
75
75
  <img src="https://img.shields.io/badge/tests-263+-ff6b1f?style=flat-square&labelColor=07070a" alt="tests"/>
@@ -125,6 +125,7 @@ Dulus adapt any python repository <3
125
125
 
126
126
  Dulus is a **lightweight Python reimplementation of Claude Code** that isn't locked to Claude. It ships the whole loop — REPL, tool dispatch, streaming, context compaction, checkpoints, sub-agents, voice, Telegram bridge, MCP, plugins — in roughly **12K lines you can actually read**. Fork it. Bend it. Run it offline against Qwen on your M2.
127
127
 
128
+ > **v0.2.52 — May 12, 2026** — Session system overhaul: removed 50-session scan limit, metadata now includes message counts, eliminated daily prune from save path. **Recommendation:** wipe old sessions and start clean — only sessions, your memories stay intact.
128
129
  > **v0.2.22 — May 9, 2026** — `/bg start` spawns one detached Dulus daemon that serves CLI (IPC), Web (browser at `127.0.0.1:5000`), and Telegram simultaneously — all sharing the same session. WebChat now defaults to **loopback-only** (opt-in to LAN exposure with `/webchat lan on`).
129
130
  > **v0.2.21 — May 9, 2026** — Console-freeze fix: system prompt now tells the model SleepTimer is for user reminders only — pauses inside command pipelines must use `sleep N` inside the Bash command itself.
130
131
  > **v0.2.20 — May 9, 2026** — Windows IPC port-collision fix: switched to `SO_EXCLUSIVEADDRUSE` so a second Dulus instance correctly cedes the port and acts as client. End-to-end tested.
@@ -1239,11 +1239,6 @@ def save_latest(args: str, state, config=None, mode: str = "full") -> bool:
1239
1239
  daily_path = day_dir / f"session_{ts}_{sid}.json"
1240
1240
  daily_path.write_text(payload)
1241
1241
 
1242
- # Prune daily folder: keep only the latest `daily_limit` files
1243
- daily_files = sorted(day_dir.glob("session_*.json"))
1244
- for old in daily_files[:-daily_limit]:
1245
- old.unlink(missing_ok=True)
1246
-
1247
1242
  # 3. Append to history.json (master file)
1248
1243
  if SESSION_HIST_FILE.exists():
1249
1244
  try:
@@ -4331,6 +4326,7 @@ def cmd_skill(args: str, state, config) -> bool:
4331
4326
  list_local, list_installed, install_local, install_clawhub,
4332
4327
  search_clawhub, read_skill,
4333
4328
  list_awesome_remote, list_composio_toolkits,
4329
+ install_awesome_remote,
4334
4330
  )
4335
4331
  from pathlib import Path as _Path
4336
4332
 
@@ -4376,17 +4372,16 @@ def cmd_skill(args: str, state, config) -> bool:
4376
4372
 
4377
4373
  if rest.startswith("awesome"):
4378
4374
  query = rest[7:].strip()
4379
- # `--full` flag pulls per-skill descriptions in parallel (slower but
4380
- # informative). Default lists names only — instant.
4381
- full = False
4382
- if "--full" in query.split():
4383
- full = True
4384
- query = " ".join(t for t in query.split() if t != "--full").strip()
4385
- if full:
4386
- info("Fetching awesome skills + descriptions from GitHub (parallel, ~5s)...")
4375
+ # `--fast` skips descriptions for an instant list; default pulls them in parallel.
4376
+ fast = False
4377
+ if "--fast" in query.split():
4378
+ fast = True
4379
+ query = " ".join(t for t in query.split() if t != "--fast").strip()
4380
+ if fast:
4381
+ info("Fetching awesome skill list from GitHub (instant, no descriptions)...")
4387
4382
  else:
4388
- info("Fetching awesome skill list from GitHub (instant)...")
4389
- skills = list_awesome_remote(query, with_descriptions=full)
4383
+ info("Fetching awesome skills + descriptions from GitHub (parallel, ~5s)...")
4384
+ skills = list_awesome_remote(query, with_descriptions=not fast)
4390
4385
  if not skills:
4391
4386
  err("Could not fetch awesome skills (network or rate-limit).")
4392
4387
  return True
@@ -4395,7 +4390,7 @@ def cmd_skill(args: str, state, config) -> bool:
4395
4390
  for s in skills
4396
4391
  ]
4397
4392
  header = f"Awesome skills ({len(skills)})" + (f" matching '{query}'" if query else "")
4398
- hint = "" if full else " — add `--full` for descriptions"
4393
+ hint = "" if not fast else " — remove `--fast` for descriptions"
4399
4394
  _pager(f"{header}{hint} — n=next q=quit", lines)
4400
4395
  return True
4401
4396
 
@@ -4460,6 +4455,21 @@ def cmd_skill(args: str, state, config) -> bool:
4460
4455
  print(f" {clr(r['slug'], 'cyan'):30s} {r.get('description','')[:60]}")
4461
4456
  return True
4462
4457
 
4458
+ if rest.startswith("installed"):
4459
+ query = rest[9:].strip()
4460
+ skills = list_installed(query)
4461
+ if not skills:
4462
+ if query:
4463
+ info(f"No installed skills matching '{query}'.")
4464
+ else:
4465
+ info("No skills installed yet.")
4466
+ return True
4467
+ header = f"Installed skills ({len(skills)})" + (f" matching '{query}'" if query else "")
4468
+ info(header + ":")
4469
+ for s in skills:
4470
+ print(f" • {clr(s['name'], 'cyan'):22s} [{s['source']}] {s['description']}")
4471
+ return True
4472
+
4463
4473
  # /skill info <name>
4464
4474
  if subcmd == "info":
4465
4475
  if not rest:
@@ -4499,27 +4509,83 @@ def cmd_skill(args: str, state, config) -> bool:
4499
4509
  if rest.startswith("clawhub:"):
4500
4510
  slug = rest[8:]
4501
4511
  success, msg = install_clawhub(slug)
4512
+ elif rest.startswith("awesome/"):
4513
+ success, msg = install_awesome_remote(rest)
4502
4514
  else:
4503
4515
  success, msg = install_local(rest)
4516
+ # Fallback to awesome-remote if not found locally
4517
+ if not success:
4518
+ success, msg = install_awesome_remote(rest)
4504
4519
  (ok if success else err)(msg)
4505
4520
  return True
4506
4521
 
4507
4522
  # ── /skill use ─────────────────────────────────────────────────────────
4508
4523
  if subcmd == "use":
4524
+ from skill.clawhub import DULUS_SKILLS_DIR
4525
+ installed = list_installed()
4526
+ if not installed:
4527
+ err("No skills installed yet. Run /skill list to browse and install skills.")
4528
+ return True
4529
+
4530
+ # Interactive picker when no target is given
4509
4531
  if not rest:
4510
- err("Usage: /skill use <name>")
4532
+ print(clr(" Select skill(s) to inject (active for this turn):", "cyan", "bold"))
4533
+ menu_buf = clr(" Select skill(s) to inject:", "cyan", "bold")
4534
+ for i, s in enumerate(installed):
4535
+ line = f" {clr(f'[{i+1:2d}]', 'yellow')} {clr(s['name'], 'white', 'bold'):<24} [{clr(s['source'], 'dim')}] {s['description'][:55]}"
4536
+ print(line)
4537
+ menu_buf += "\n" + line
4538
+ print()
4539
+ ans = ask_input_interactive(
4540
+ clr(" Enter number(s) (e.g. 1 or 1,2,3), name, or Enter to cancel > ", "cyan"),
4541
+ config, menu_buf,
4542
+ ).strip()
4543
+ if not ans:
4544
+ info(" Cancelled.")
4545
+ return True
4546
+ rest = ans
4547
+
4548
+ # Resolve rest → list of skill names
4549
+ selected_names: list[str] = []
4550
+ tokens = [t.strip() for t in rest.replace(",", " ").split() if t.strip()]
4551
+ for tok in tokens:
4552
+ if tok.isdigit():
4553
+ idx = int(tok) - 1
4554
+ if 0 <= idx < len(installed):
4555
+ selected_names.append(installed[idx]["name"])
4556
+ else:
4557
+ warn(f"Index {tok} out of range (1-{len(installed)}). Skipping.")
4558
+ else:
4559
+ match = next((s["name"] for s in installed if s["name"].lower() == tok.lower()), None)
4560
+ if match is None:
4561
+ warn(f"No skill named '{tok}'. Skipping.")
4562
+ else:
4563
+ selected_names.append(match)
4564
+
4565
+ if not selected_names:
4566
+ err("No valid skill selected.")
4511
4567
  return True
4512
- from skill.clawhub import DULUS_SKILLS_DIR
4513
- body = read_skill(rest)
4514
- if not body:
4515
- err(f"Skill '{rest}' not found. Run /skill list to see installed skills.")
4568
+
4569
+ # Inject selected skills into context
4570
+ blocks = []
4571
+ for name in selected_names:
4572
+ body = read_skill(name)
4573
+ if not body:
4574
+ warn(f"Skill '{name}' could not be read. Skipping.")
4575
+ continue
4576
+ skill_dir = DULUS_SKILLS_DIR / name
4577
+ path_hint = f"\n\n# NOTE: Skill '{name}' files are located at: {skill_dir}" if skill_dir.exists() else ""
4578
+ blocks.append(f"## Skill: {name}\n\n{body}{path_hint}")
4579
+
4580
+ if not blocks:
4581
+ err("No skills could be injected.")
4516
4582
  return True
4517
- # Inject as a user-side system message for this turn
4518
- skill_dir = DULUS_SKILLS_DIR / rest
4519
- path_hint = f"\n\n# NOTE: Skill '{rest}' files are located at: {skill_dir}" if skill_dir.exists() else ""
4583
+
4520
4584
  existing = config.get("_skill_inject", "")
4521
- config["_skill_inject"] = (existing + "\n\n" + body + path_hint).strip()
4522
- ok(f"Skill '{rest}' injected active for this turn.")
4585
+ new_inject = "\n\n---\n\n".join(blocks)
4586
+ config["_skill_inject"] = (existing + "\n\n" + new_inject).strip() if existing else new_inject
4587
+ names_txt = ", ".join(f"'{n}'" for n in selected_names)
4588
+ ok(f"Injected {len(blocks)} skill(s) — active for this turn: {names_txt}")
4523
4589
  return True
4524
4590
 
4525
4591
  # ── /skill remove ──────────────────────────────────────────────────────
@@ -51,6 +51,7 @@ def _read_session_meta(path: Path) -> dict | None:
51
51
  "path": str(path),
52
52
  "saved_at": saved_at,
53
53
  "turn_count": data.get("turn_count", len(messages) // 2),
54
+ "messages": messages,
54
55
  }
55
56
  _scan_cache[key] = (mtime, result)
56
57
  return result
@@ -87,7 +88,7 @@ def scan_sessions() -> list[dict]:
87
88
 
88
89
  # Sort all found sessions by saved_at DESC
89
90
  sessions.sort(key=lambda x: x.get("saved_at", ""), reverse=True)
90
- return sessions[:50]
91
+ return sessions
91
92
 
92
93
  def save_session(state, config: dict, session_id: str | None = None) -> str:
93
94
  """Save AgentState to disk in standard Dulus format. Returns the session_id."""
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dulus"
7
- version = "0.2.51"
7
+ version = "0.2.53"
8
8
  description = "Spanish-first multi-provider AI CLI — 14 NVIDIA models free, Mesa Redonda, voice, TTS, RTK token reducer, MemPalace"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -198,10 +198,14 @@ def _fetch_awesome_remote(with_descriptions: bool = False) -> list[dict]:
198
198
  if not path.endswith("/SKILL.md"):
199
199
  continue
200
200
  parts = path.split("/")
201
- if any(p.startswith(".") for p in parts):
201
+ # Skip actual hidden scaffolding (.git, .github, .gitignore) but keep .gemini/skills/
202
+ if any(p in (".git", ".github", ".gitignore", ".gitattributes") for p in parts):
202
203
  continue
203
204
  if _AWESOME_EXCLUDE_REMOTE.intersection(parts):
204
205
  continue
206
+ # Skip non-skill scaffold folders that happen to contain SKILL.md
207
+ if any(p.upper() in ("README", "TEMPLATE") for p in parts):
208
+ continue
205
209
  skill_paths.append(path)
206
210
 
207
211
  # Build the skill list from paths alone — instant, no per-file fetch.
@@ -287,6 +291,90 @@ def list_awesome_remote(query: Optional[str] = None, force_refresh: bool = False
287
291
  return skills
288
292
 
289
293
 
294
+ def get_awesome_remote(slug: str) -> Optional[dict]:
295
+ """Find an awesome-remote skill by its id (awesome/<dir>/<skill>) or skill name."""
296
+ for s in list_awesome_remote():
297
+ if s.get("id") == slug or s.get("skill") == slug:
298
+ return s
299
+ return None
300
+
301
+
302
+ def install_awesome_remote(slug: str) -> tuple[bool, str]:
303
+ """Download a skill from the awesome GitHub repo and install into ~/.dulus/skills/."""
304
+ import shutil
305
+ import urllib.request
306
+
307
+ entry = get_awesome_remote(slug)
308
+ if entry:
309
+ rel_dir = entry.get("_remote_dir", "")
310
+ skill_name = entry["skill"]
311
+ else:
312
+ # Derive from slug: awesome/<dir>/<skill> or <dir>/<skill>
313
+ parts = slug.replace("awesome/", "").strip("/").split("/")
314
+ if len(parts) < 1:
315
+ return False, f"Invalid awesome slug: '{slug}'. Expected awesome/<category>/<skill> or <category>/<skill>."
316
+ skill_name = parts[-1]
317
+ rel_dir = "/".join(parts)
318
+
319
+ dest_dir = DULUS_SKILLS_DIR / skill_name
320
+ dest_dir.mkdir(parents=True, exist_ok=True)
321
+
322
+ # Try to discover sibling files via GitHub tree API for this directory.
323
+ tree_url = (
324
+ f"https://api.github.com/repos/{_AWESOME_REPO}/git/trees/"
325
+ f"{_AWESOME_BRANCH}?recursive=1"
326
+ )
327
+ sibling_paths: list[str] = []
328
+ try:
329
+ with urllib.request.urlopen(tree_url, timeout=15) as resp:
330
+ tree = json.loads(resp.read())
331
+ prefix = rel_dir.rstrip("/") + "/"
332
+ for item in tree.get("tree", []):
333
+ p = item.get("path", "")
334
+ if p.startswith(prefix) and item.get("type") == "blob":
335
+ sibling_paths.append(p)
336
+ except Exception:
337
+ sibling_paths = []
338
+
339
+ # If tree API failed or returned nothing, fall back to just SKILL.md
340
+ if not sibling_paths:
341
+ sibling_paths = [f"{rel_dir}/SKILL.md"]
342
+
343
+ raw_base = f"https://raw.githubusercontent.com/{_AWESOME_REPO}/{_AWESOME_BRANCH}"
344
+ downloaded = []
345
+ for p in sibling_paths:
346
+ url = f"{raw_base}/{p}"
347
+ rel = p[len(prefix):] if p.startswith(prefix) else p.split("/")[-1]
348
+ dst = dest_dir / rel
349
+ dst.parent.mkdir(parents=True, exist_ok=True)
350
+ try:
351
+ with urllib.request.urlopen(url, timeout=15) as r:
352
+ data = r.read()
353
+ dst.write_bytes(data)
354
+ downloaded.append(rel)
355
+ except Exception:
356
+ pass # skip files we can't fetch
357
+
358
+ skill_md = dest_dir / "SKILL.md"
359
+ if not skill_md.exists():
360
+ return False, f"Could not download SKILL.md for '{skill_name}' from awesome repo."
361
+
362
+ # Rewrite SKILL.md frontmatter for Dulus
363
+ raw = skill_md.read_text(encoding="utf-8")
364
+ body = _strip_frontmatter(raw)
365
+ frontmatter = (
366
+ f"---\n"
367
+ f"name: {skill_name}\n"
368
+ f"description: {(entry or {}).get('description', '')}\n"
369
+ f"source: awesome-remote\n"
370
+ f"triggers: [/{skill_name}]\n"
371
+ f"---\n\n"
372
+ )
373
+ skill_md.write_text(frontmatter + body, encoding="utf-8")
374
+
375
+ return True, f"Installed '{skill_name}' → {dest_dir} ({len(downloaded)} files: {', '.join(downloaded[:5])}{'...' if len(downloaded)>5 else ''})"
376
+
377
+
290
378
  # ── COMPOSIO (live API listing of toolkits) ───────────────────────────────
291
379
  # The composio backend exposes a public toolkit list — we surface it as
292
380
  # pseudo-skills so users can browse `gmail`, `slack`, etc. and create a
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes