dulus 0.2.44__tar.gz → 0.2.46__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 (207) hide show
  1. {dulus-0.2.44/dulus.egg-info → dulus-0.2.46}/PKG-INFO +1 -1
  2. dulus-0.2.46/backend/agents_bridge.py +75 -0
  3. {dulus-0.2.44 → dulus-0.2.46}/backend/server.py +91 -4
  4. {dulus-0.2.44 → dulus-0.2.46}/common.py +1 -1
  5. dulus-0.2.46/data/active_persona.json +5 -0
  6. dulus-0.2.46/data/context.json +180 -0
  7. {dulus-0.2.44 → dulus-0.2.46}/data/personas.json +87 -87
  8. {dulus-0.2.44 → dulus-0.2.46/dulus.egg-info}/PKG-INFO +1 -1
  9. {dulus-0.2.44 → dulus-0.2.46}/dulus.egg-info/SOURCES.txt +2 -1
  10. {dulus-0.2.44 → dulus-0.2.46}/pyproject.toml +1 -1
  11. dulus-0.2.44/sandbox/dist/assets/index-Duhscm3W.js → dulus-0.2.46/sandbox/dist/assets/index-nQkFq-oq.js +45 -45
  12. {dulus-0.2.44 → dulus-0.2.46}/sandbox/dist/index.html +1 -1
  13. {dulus-0.2.44 → dulus-0.2.46}/sandbox/package-lock.json +2 -2
  14. {dulus-0.2.44 → dulus-0.2.46}/webchat_server.py +60 -19
  15. dulus-0.2.44/data/active_persona.json +0 -5
  16. dulus-0.2.44/data/context.json +0 -130
  17. {dulus-0.2.44 → dulus-0.2.46}/LICENSE +0 -0
  18. {dulus-0.2.44 → dulus-0.2.46}/MANIFEST.in +0 -0
  19. {dulus-0.2.44 → dulus-0.2.46}/README.md +0 -0
  20. {dulus-0.2.44 → dulus-0.2.46}/agent.py +0 -0
  21. {dulus-0.2.44 → dulus-0.2.46}/backend/__init__.py +0 -0
  22. {dulus-0.2.44 → dulus-0.2.46}/backend/compressor.py +0 -0
  23. {dulus-0.2.44 → dulus-0.2.46}/backend/context.py +0 -0
  24. {dulus-0.2.44 → dulus-0.2.46}/backend/githook.py +0 -0
  25. {dulus-0.2.44 → dulus-0.2.46}/backend/marketplace.py +0 -0
  26. {dulus-0.2.44 → dulus-0.2.46}/backend/mempalace_bridge.py +0 -0
  27. {dulus-0.2.44 → dulus-0.2.46}/backend/personas.py +0 -0
  28. {dulus-0.2.44 → dulus-0.2.46}/backend/plugins.py +0 -0
  29. {dulus-0.2.44 → dulus-0.2.46}/backend/tasks.py +0 -0
  30. {dulus-0.2.44 → dulus-0.2.46}/batch_api.py +0 -0
  31. {dulus-0.2.44 → dulus-0.2.46}/checkpoint/__init__.py +0 -0
  32. {dulus-0.2.44 → dulus-0.2.46}/checkpoint/hooks.py +0 -0
  33. {dulus-0.2.44 → dulus-0.2.46}/checkpoint/store.py +0 -0
  34. {dulus-0.2.44 → dulus-0.2.46}/checkpoint/types.py +0 -0
  35. {dulus-0.2.44 → dulus-0.2.46}/claude_code_watcher.py +0 -0
  36. {dulus-0.2.44 → dulus-0.2.46}/clipboard_utils.py +0 -0
  37. {dulus-0.2.44 → dulus-0.2.46}/cloudsave.py +0 -0
  38. {dulus-0.2.44 → dulus-0.2.46}/compaction.py +0 -0
  39. {dulus-0.2.44 → dulus-0.2.46}/config.py +0 -0
  40. {dulus-0.2.44 → dulus-0.2.46}/context.py +0 -0
  41. {dulus-0.2.44 → dulus-0.2.46}/data/__init__.py +0 -0
  42. {dulus-0.2.44 → dulus-0.2.46}/data/marketplace.json +0 -0
  43. {dulus-0.2.44 → dulus-0.2.46}/data/plugins/__init__.py +0 -0
  44. {dulus-0.2.44 → dulus-0.2.46}/data/plugins/composio/__init__.py +0 -0
  45. {dulus-0.2.44 → dulus-0.2.46}/data/plugins/composio/composio_plugin/__init__.py +0 -0
  46. {dulus-0.2.44 → dulus-0.2.46}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
  47. {dulus-0.2.44 → dulus-0.2.46}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
  48. {dulus-0.2.44 → dulus-0.2.46}/data/plugins/composio/plugin.json +0 -0
  49. {dulus-0.2.44 → dulus-0.2.46}/data/plugins/composio/plugin_tool.py +0 -0
  50. {dulus-0.2.44 → dulus-0.2.46}/data/tasks.json +0 -0
  51. {dulus-0.2.44 → dulus-0.2.46}/docs/README.md +0 -0
  52. {dulus-0.2.44 → dulus-0.2.46}/docs/__init__.py +0 -0
  53. {dulus-0.2.44 → dulus-0.2.46}/docs/api.html +0 -0
  54. {dulus-0.2.44 → dulus-0.2.46}/docs/architecture.md +0 -0
  55. {dulus-0.2.44 → dulus-0.2.46}/docs/azure-speech-template.json +0 -0
  56. {dulus-0.2.44 → dulus-0.2.46}/docs/dashboard/index.html +0 -0
  57. {dulus-0.2.44 → dulus-0.2.46}/docs/divider.svg +0 -0
  58. {dulus-0.2.44 → dulus-0.2.46}/docs/generate.py +0 -0
  59. {dulus-0.2.44 → dulus-0.2.46}/docs/hero.svg +0 -0
  60. {dulus-0.2.44 → dulus-0.2.46}/docs/index.html +0 -0
  61. {dulus-0.2.44 → dulus-0.2.46}/docs/news.md +0 -0
  62. {dulus-0.2.44 → dulus-0.2.46}/docs/nvidia-models.svg +0 -0
  63. {dulus-0.2.44 → dulus-0.2.46}/docs/particle-playground.html +0 -0
  64. {dulus-0.2.44 → dulus-0.2.46}/docs/personas/index.html +0 -0
  65. {dulus-0.2.44 → dulus-0.2.46}/docs/poetry-banner.png +0 -0
  66. {dulus-0.2.44 → dulus-0.2.46}/docs/preview.html +0 -0
  67. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-agents.svg +0 -0
  68. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-brainstorm.svg +0 -0
  69. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-bridges.svg +0 -0
  70. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-features.svg +0 -0
  71. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-freetier.svg +0 -0
  72. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-memory.svg +0 -0
  73. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-models.svg +0 -0
  74. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-perms.svg +0 -0
  75. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-plugins.svg +0 -0
  76. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-quickstart.svg +0 -0
  77. {dulus-0.2.44 → dulus-0.2.46}/docs/sec-ssj.svg +0 -0
  78. {dulus-0.2.44 → dulus-0.2.46}/docs/spinners.svg +0 -0
  79. {dulus-0.2.44 → dulus-0.2.46}/docs/split-pane.svg +0 -0
  80. {dulus-0.2.44 → dulus-0.2.46}/docs/terminal-boot.svg +0 -0
  81. {dulus-0.2.44 → dulus-0.2.46}/docs/uploads/particle-playground.html +0 -0
  82. {dulus-0.2.44 → dulus-0.2.46}/dulus.egg-info/dependency_links.txt +0 -0
  83. {dulus-0.2.44 → dulus-0.2.46}/dulus.egg-info/entry_points.txt +0 -0
  84. {dulus-0.2.44 → dulus-0.2.46}/dulus.egg-info/requires.txt +0 -0
  85. {dulus-0.2.44 → dulus-0.2.46}/dulus.egg-info/top_level.txt +0 -0
  86. {dulus-0.2.44 → dulus-0.2.46}/dulus.py +0 -0
  87. {dulus-0.2.44 → dulus-0.2.46}/dulus_gui.py +0 -0
  88. {dulus-0.2.44 → dulus-0.2.46}/dulus_mcp/__init__.py +0 -0
  89. {dulus-0.2.44 → dulus-0.2.46}/dulus_mcp/client.py +0 -0
  90. {dulus-0.2.44 → dulus-0.2.46}/dulus_mcp/config.py +0 -0
  91. {dulus-0.2.44 → dulus-0.2.46}/dulus_mcp/tools.py +0 -0
  92. {dulus-0.2.44 → dulus-0.2.46}/dulus_mcp/types.py +0 -0
  93. {dulus-0.2.44 → dulus-0.2.46}/gui/__init__.py +0 -0
  94. {dulus-0.2.44 → dulus-0.2.46}/gui/agent_bridge.py +0 -0
  95. {dulus-0.2.44 → dulus-0.2.46}/gui/chat_widget.py +0 -0
  96. {dulus-0.2.44 → dulus-0.2.46}/gui/main_window.py +0 -0
  97. {dulus-0.2.44 → dulus-0.2.46}/gui/personas.py +0 -0
  98. {dulus-0.2.44 → dulus-0.2.46}/gui/session_utils.py +0 -0
  99. {dulus-0.2.44 → dulus-0.2.46}/gui/settings_dialog.py +0 -0
  100. {dulus-0.2.44 → dulus-0.2.46}/gui/sidebar.py +0 -0
  101. {dulus-0.2.44 → dulus-0.2.46}/gui/tasks_view.py +0 -0
  102. {dulus-0.2.44 → dulus-0.2.46}/gui/themes.py +0 -0
  103. {dulus-0.2.44 → dulus-0.2.46}/gui/tool_panel.py +0 -0
  104. {dulus-0.2.44 → dulus-0.2.46}/input.py +0 -0
  105. {dulus-0.2.44 → dulus-0.2.46}/license_manager.py +0 -0
  106. {dulus-0.2.44 → dulus-0.2.46}/memory/__init__.py +0 -0
  107. {dulus-0.2.44 → dulus-0.2.46}/memory/audit.py +0 -0
  108. {dulus-0.2.44 → dulus-0.2.46}/memory/consolidator.py +0 -0
  109. {dulus-0.2.44 → dulus-0.2.46}/memory/context.py +0 -0
  110. {dulus-0.2.44 → dulus-0.2.46}/memory/offload.py +0 -0
  111. {dulus-0.2.44 → dulus-0.2.46}/memory/palace.py +0 -0
  112. {dulus-0.2.44 → dulus-0.2.46}/memory/scan.py +0 -0
  113. {dulus-0.2.44 → dulus-0.2.46}/memory/sessions.py +0 -0
  114. {dulus-0.2.44 → dulus-0.2.46}/memory/store.py +0 -0
  115. {dulus-0.2.44 → dulus-0.2.46}/memory/tools.py +0 -0
  116. {dulus-0.2.44 → dulus-0.2.46}/memory/types.py +0 -0
  117. {dulus-0.2.44 → dulus-0.2.46}/memory/vector_search.py +0 -0
  118. {dulus-0.2.44 → dulus-0.2.46}/multi_agent/__init__.py +0 -0
  119. {dulus-0.2.44 → dulus-0.2.46}/multi_agent/subagent.py +0 -0
  120. {dulus-0.2.44 → dulus-0.2.46}/multi_agent/tools.py +0 -0
  121. {dulus-0.2.44 → dulus-0.2.46}/offload_helper.py +0 -0
  122. {dulus-0.2.44 → dulus-0.2.46}/plugin/__init__.py +0 -0
  123. {dulus-0.2.44 → dulus-0.2.46}/plugin/autoadapter.py +0 -0
  124. {dulus-0.2.44 → dulus-0.2.46}/plugin/loader.py +0 -0
  125. {dulus-0.2.44 → dulus-0.2.46}/plugin/recommend.py +0 -0
  126. {dulus-0.2.44 → dulus-0.2.46}/plugin/store.py +0 -0
  127. {dulus-0.2.44 → dulus-0.2.46}/plugin/types.py +0 -0
  128. {dulus-0.2.44 → dulus-0.2.46}/providers.py +0 -0
  129. {dulus-0.2.44 → dulus-0.2.46}/sandbox/README.md +0 -0
  130. {dulus-0.2.44 → dulus-0.2.46}/sandbox/__init__.py +0 -0
  131. {dulus-0.2.44 → dulus-0.2.46}/sandbox/components.json +0 -0
  132. {dulus-0.2.44 → dulus-0.2.46}/sandbox/dist/assets/index-CsIO61nW.css +0 -0
  133. {dulus-0.2.44 → dulus-0.2.46}/sandbox/dist/wallpaper-default.jpg +0 -0
  134. {dulus-0.2.44 → dulus-0.2.46}/sandbox/dist/wallpapers/default.jpeg +0 -0
  135. {dulus-0.2.44 → dulus-0.2.46}/sandbox/dist/wallpapers/light.jpeg +0 -0
  136. {dulus-0.2.44 → dulus-0.2.46}/sandbox/dist/wallpapers/nature.jpeg +0 -0
  137. {dulus-0.2.44 → dulus-0.2.46}/sandbox/dist/wallpapers/tech.jpeg +0 -0
  138. {dulus-0.2.44 → dulus-0.2.46}/sandbox/eslint.config.js +0 -0
  139. {dulus-0.2.44 → dulus-0.2.46}/sandbox/index.html +0 -0
  140. {dulus-0.2.44 → dulus-0.2.46}/sandbox/info.md +0 -0
  141. {dulus-0.2.44 → dulus-0.2.46}/sandbox/package.json +0 -0
  142. {dulus-0.2.44 → dulus-0.2.46}/sandbox/postcss.config.js +0 -0
  143. {dulus-0.2.44 → dulus-0.2.46}/sandbox/public/wallpaper-default.jpg +0 -0
  144. {dulus-0.2.44 → dulus-0.2.46}/sandbox/src/index.css +0 -0
  145. {dulus-0.2.44 → dulus-0.2.46}/sandbox/tailwind.config.js +0 -0
  146. {dulus-0.2.44 → dulus-0.2.46}/sandbox/tsconfig.app.json +0 -0
  147. {dulus-0.2.44 → dulus-0.2.46}/sandbox/tsconfig.json +0 -0
  148. {dulus-0.2.44 → dulus-0.2.46}/sandbox/tsconfig.node.json +0 -0
  149. {dulus-0.2.44 → dulus-0.2.46}/setup.cfg +0 -0
  150. {dulus-0.2.44 → dulus-0.2.46}/skill/__init__.py +0 -0
  151. {dulus-0.2.44 → dulus-0.2.46}/skill/builtin.py +0 -0
  152. {dulus-0.2.44 → dulus-0.2.46}/skill/clawhub.py +0 -0
  153. {dulus-0.2.44 → dulus-0.2.46}/skill/executor.py +0 -0
  154. {dulus-0.2.44 → dulus-0.2.46}/skill/loader.py +0 -0
  155. {dulus-0.2.44 → dulus-0.2.46}/skill/tools.py +0 -0
  156. {dulus-0.2.44 → dulus-0.2.46}/skills.py +0 -0
  157. {dulus-0.2.44 → dulus-0.2.46}/spinner.py +0 -0
  158. {dulus-0.2.44 → dulus-0.2.46}/string_utils.py +0 -0
  159. {dulus-0.2.44 → dulus-0.2.46}/subagent.py +0 -0
  160. {dulus-0.2.44 → dulus-0.2.46}/task/__init__.py +0 -0
  161. {dulus-0.2.44 → dulus-0.2.46}/task/store.py +0 -0
  162. {dulus-0.2.44 → dulus-0.2.46}/task/tools.py +0 -0
  163. {dulus-0.2.44 → dulus-0.2.46}/task/types.py +0 -0
  164. {dulus-0.2.44 → dulus-0.2.46}/tests/test_afk_yolo.py +0 -0
  165. {dulus-0.2.44 → dulus-0.2.46}/tests/test_approval_runtime.py +0 -0
  166. {dulus-0.2.44 → dulus-0.2.46}/tests/test_background_task_tools.py +0 -0
  167. {dulus-0.2.44 → dulus-0.2.46}/tests/test_background_tasks.py +0 -0
  168. {dulus-0.2.44 → dulus-0.2.46}/tests/test_checkpoint.py +0 -0
  169. {dulus-0.2.44 → dulus-0.2.46}/tests/test_clipboard_utils.py +0 -0
  170. {dulus-0.2.44 → dulus-0.2.46}/tests/test_compaction.py +0 -0
  171. {dulus-0.2.44 → dulus-0.2.46}/tests/test_diff_view.py +0 -0
  172. {dulus-0.2.44 → dulus-0.2.46}/tests/test_diff_visualization.py +0 -0
  173. {dulus-0.2.44 → dulus-0.2.46}/tests/test_display_blocks.py +0 -0
  174. {dulus-0.2.44 → dulus-0.2.46}/tests/test_export_import.py +0 -0
  175. {dulus-0.2.44 → dulus-0.2.46}/tests/test_hook_engine.py +0 -0
  176. {dulus-0.2.44 → dulus-0.2.46}/tests/test_injection_fix.py +0 -0
  177. {dulus-0.2.44 → dulus-0.2.46}/tests/test_license.py +0 -0
  178. {dulus-0.2.44 → dulus-0.2.46}/tests/test_mcp.py +0 -0
  179. {dulus-0.2.44 → dulus-0.2.46}/tests/test_memory.py +0 -0
  180. {dulus-0.2.44 → dulus-0.2.46}/tests/test_notification_manager.py +0 -0
  181. {dulus-0.2.44 → dulus-0.2.46}/tests/test_plugin.py +0 -0
  182. {dulus-0.2.44 → dulus-0.2.46}/tests/test_session_fork.py +0 -0
  183. {dulus-0.2.44 → dulus-0.2.46}/tests/test_shell_mode.py +0 -0
  184. {dulus-0.2.44 → dulus-0.2.46}/tests/test_skills.py +0 -0
  185. {dulus-0.2.44 → dulus-0.2.46}/tests/test_steer_input.py +0 -0
  186. {dulus-0.2.44 → dulus-0.2.46}/tests/test_subagent.py +0 -0
  187. {dulus-0.2.44 → dulus-0.2.46}/tests/test_task.py +0 -0
  188. {dulus-0.2.44 → dulus-0.2.46}/tests/test_telegram_buffer.py +0 -0
  189. {dulus-0.2.44 → dulus-0.2.46}/tests/test_think_tool.py +0 -0
  190. {dulus-0.2.44 → dulus-0.2.46}/tests/test_todo_tool.py +0 -0
  191. {dulus-0.2.44 → dulus-0.2.46}/tests/test_todo_visualization.py +0 -0
  192. {dulus-0.2.44 → dulus-0.2.46}/tests/test_tool_registry.py +0 -0
  193. {dulus-0.2.44 → dulus-0.2.46}/tests/test_voice.py +0 -0
  194. {dulus-0.2.44 → dulus-0.2.46}/tests/test_wire_events.py +0 -0
  195. {dulus-0.2.44 → dulus-0.2.46}/tmux_offloader.py +0 -0
  196. {dulus-0.2.44 → dulus-0.2.46}/tmux_tools.py +0 -0
  197. {dulus-0.2.44 → dulus-0.2.46}/tool_registry.py +0 -0
  198. {dulus-0.2.44 → dulus-0.2.46}/tools.py +0 -0
  199. {dulus-0.2.44 → dulus-0.2.46}/ui/__init__.py +0 -0
  200. {dulus-0.2.44 → dulus-0.2.46}/ui/input.py +0 -0
  201. {dulus-0.2.44 → dulus-0.2.46}/ui/render.py +0 -0
  202. {dulus-0.2.44 → dulus-0.2.46}/voice/__init__.py +0 -0
  203. {dulus-0.2.44 → dulus-0.2.46}/voice/keyterms.py +0 -0
  204. {dulus-0.2.44 → dulus-0.2.46}/voice/recorder.py +0 -0
  205. {dulus-0.2.44 → dulus-0.2.46}/voice/stt.py +0 -0
  206. {dulus-0.2.44 → dulus-0.2.46}/voice/tts.py +0 -0
  207. {dulus-0.2.44 → dulus-0.2.46}/webchat.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.44
3
+ Version: 0.2.46
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
@@ -0,0 +1,75 @@
1
+ """Agent info bridge — transforms personas / sub-agent tasks into AgentInfo format."""
2
+ from __future__ import annotations
3
+
4
+ from backend.context import build_context
5
+
6
+
7
+ def build_agent_info_list() -> list[dict]:
8
+ """Return agents in AgentInfo format for the sandbox AgentMonitor.
9
+
10
+ Tries real SubAgentManager tasks first, then falls back to personas
11
+ so the UI always has something to show.
12
+ """
13
+ agents: list[dict] = []
14
+
15
+ # 1. Real sub-agent tasks (if running in the same process)
16
+ try:
17
+ from multi_agent.tools import get_agent_manager
18
+ mgr = get_agent_manager()
19
+ for task in mgr.list_tasks():
20
+ status_map = {"pending": "idle", "running": "running", "completed": "completed", "failed": "error"}
21
+ agents.append({
22
+ "id": task.task_id,
23
+ "name": task.name or task.task_id,
24
+ "status": status_map.get(task.status, "idle"),
25
+ "type": task.subagent_type or "sub-agent",
26
+ "model": getattr(task, "agent_def", None) and task.agent_def.model or "",
27
+ "start_time": getattr(task, "start_time", None),
28
+ "last_activity": getattr(task, "end_time", None),
29
+ "progress": 100 if task.status == "completed" else (0 if task.status == "pending" else 50),
30
+ "task_count": 1,
31
+ "logs": getattr(task, "logs", []) or [],
32
+ "metadata": {
33
+ "source": "subagent",
34
+ "cancelled": getattr(task, "_cancel_flag", False),
35
+ "result_preview": str(task.result)[:200] if task.result else "",
36
+ },
37
+ })
38
+ except Exception:
39
+ pass
40
+
41
+ # 2. Fallback / supplement with personas so the UI isn't empty
42
+ try:
43
+ ctx = build_context()
44
+ persona_agents = ctx.get("agents", [])
45
+ existing_ids = {a["id"] for a in agents}
46
+ for p in persona_agents:
47
+ pid = p.get("name", "unknown").lower().replace(" ", "-")
48
+ if pid in existing_ids:
49
+ continue
50
+ raw_status = p.get("status", "idle")
51
+ # Map persona statuses to AgentInfo statuses
52
+ status_map = {"active": "running", "idle": "idle"}
53
+ mapped_status = status_map.get(raw_status, raw_status if raw_status in ("running", "paused", "completed", "error") else "idle")
54
+ agents.append({
55
+ "id": pid,
56
+ "name": p.get("name", "Unknown"),
57
+ "status": mapped_status,
58
+ "type": p.get("role", "assistant"),
59
+ "model": "",
60
+ "start_time": None,
61
+ "last_activity": None,
62
+ "progress": None,
63
+ "task_count": 0,
64
+ "logs": [],
65
+ "metadata": {
66
+ "source": "persona",
67
+ "color": p.get("color", "#ccc"),
68
+ "avatar": p.get("avatar", "🤖"),
69
+ "active": p.get("active", False),
70
+ },
71
+ })
72
+ except Exception:
73
+ pass
74
+
75
+ return agents
@@ -4,10 +4,11 @@ import os
4
4
  import queue
5
5
  import threading
6
6
  import time
7
- from http.server import HTTPServer, SimpleHTTPRequestHandler
7
+ from http.server import HTTPServer, ThreadingHTTPServer, SimpleHTTPRequestHandler
8
8
  from pathlib import Path
9
9
  from urllib.parse import parse_qs, urlparse
10
10
 
11
+ from backend.agents_bridge import build_agent_info_list
11
12
  from backend.context import build_context, build_smart_context, get_compact_context
12
13
  from backend.personas import create_persona, get_active_persona, get_all_personas, get_persona, load_personas, set_active_persona, update_persona
13
14
  from backend.plugins import load_all_plugins, get_plugin_info, start_watcher, stop_watcher, watcher_status, reload_plugin, unload_plugin
@@ -15,6 +16,7 @@ from backend.tasks import create_task, load_tasks, update_task
15
16
 
16
17
  DASHBOARD_DIR = Path(__file__).parent.parent / "docs" / "dashboard"
17
18
 
19
+
18
20
  # ─────────── SSE Broadcast System ───────────
19
21
  _sse_clients: list[queue.Queue] = []
20
22
  _sse_lock = threading.Lock()
@@ -159,8 +161,7 @@ class DulusHandler(SimpleHTTPRequestHandler):
159
161
 
160
162
  # ── Agents ──
161
163
  if path == "/api/agents":
162
- ctx = build_context()
163
- self._json_response(ctx.get("agents", []))
164
+ self._json_response(build_agent_info_list())
164
165
  return
165
166
 
166
167
  # ── Personas ──
@@ -199,6 +200,30 @@ class DulusHandler(SimpleHTTPRequestHandler):
199
200
  self._error(f"MemPalace error: {e}", 500)
200
201
  return
201
202
 
203
+ # ── Skills ──
204
+ if path == "/api/skills":
205
+ try:
206
+ from skill.loader import load_skills
207
+ skills = load_skills()
208
+ result = [
209
+ {
210
+ "id": s.name,
211
+ "name": s.name,
212
+ "description": s.description,
213
+ "category": s.source.capitalize() if s.source else "Utility",
214
+ "triggers": s.triggers,
215
+ "argument_hint": s.argument_hint,
216
+ "source": s.source,
217
+ "user_invocable": s.user_invocable,
218
+ }
219
+ for s in skills
220
+ if s.user_invocable
221
+ ]
222
+ self._json_response(result)
223
+ except Exception as e:
224
+ self._error(f"Skills error: {e}", 500)
225
+ return
226
+
202
227
  # ── Themes ──
203
228
  if path == "/api/themes":
204
229
  try:
@@ -250,6 +275,34 @@ class DulusHandler(SimpleHTTPRequestHandler):
250
275
  self._error(f"Marketplace error: {e}", 500)
251
276
  return
252
277
 
278
+ # ── Static files from Sandbox (Web OS) ──
279
+ SANDBOX_DIR = Path(__file__).parent.parent / "sandbox" / "dist"
280
+ if path.startswith("/sandbox/"):
281
+ sandbox_path = path[len("/sandbox/"):]
282
+ if sandbox_path == "" or sandbox_path.endswith("/"):
283
+ sandbox_path = "index.html"
284
+ target = SANDBOX_DIR / sandbox_path
285
+ if target.exists() and target.is_file():
286
+ self.send_response(200)
287
+ ctype = "text/html"
288
+ if path.endswith(".css"):
289
+ ctype = "text/css"
290
+ elif path.endswith(".js"):
291
+ ctype = "application/javascript"
292
+ elif path.endswith(".json"):
293
+ ctype = "application/json"
294
+ elif path.endswith(".png"):
295
+ ctype = "image/png"
296
+ elif path.endswith(".jpg") or path.endswith(".jpeg"):
297
+ ctype = "image/jpeg"
298
+ self.send_header("Content-Type", ctype)
299
+ self.end_headers()
300
+ with open(target, "rb") as f:
301
+ self.wfile.write(f.read())
302
+ return
303
+ self.send_error(404)
304
+ return
305
+
253
306
  # ── Static files from dashboard ──
254
307
  if path == "/" or path == "/index.html":
255
308
  target = DASHBOARD_DIR / "index.html"
@@ -362,6 +415,39 @@ class DulusHandler(SimpleHTTPRequestHandler):
362
415
  except Exception as e:
363
416
  return self._error(str(e), 500)
364
417
 
418
+ # ── Skills Invoke ──
419
+ if path == "/api/skills/invoke":
420
+ skill_name = data.get("name", "").strip()
421
+ args = data.get("arguments", {})
422
+ args_str = data.get("args", "")
423
+ if not skill_name:
424
+ return self._error("Missing skill name")
425
+ try:
426
+ from skill.loader import load_skills, find_skill, substitute_arguments
427
+ from skill.tools import _skill_tool
428
+
429
+ skill = None
430
+ for s in load_skills():
431
+ if s.name == skill_name:
432
+ skill = s
433
+ break
434
+ if skill is None:
435
+ skill = find_skill(skill_name)
436
+ if skill is None:
437
+ return self._error(f"Skill '{skill_name}' not found", 404)
438
+
439
+ # Build args string from dict if provided
440
+ if isinstance(args, dict) and args:
441
+ parts = []
442
+ for k, v in args.items():
443
+ parts.append(str(v))
444
+ args_str = " ".join(parts)
445
+
446
+ result = _skill_tool({"name": skill_name, "args": args_str}, {})
447
+ self._json_response({"success": True, "result": result, "skill": skill_name})
448
+ except Exception as e:
449
+ return self._error(f"Skill execution error: {e}", 500)
450
+
365
451
  self._error("Not found", 404)
366
452
 
367
453
  def do_GET(self):
@@ -383,7 +469,7 @@ def run_server(port: int = 8000):
383
469
  started = start_watcher(broadcast_event)
384
470
  if started:
385
471
  print("[DULUS] Plugin hot-reload watcher started")
386
- server = HTTPServer(("", port), DulusHandler)
472
+ server = ThreadingHTTPServer(("", port), DulusHandler)
387
473
  thread = threading.Thread(target=server.serve_forever, daemon=True)
388
474
  thread.start()
389
475
  print(f"[DULUS] Server running at http://localhost:{port}")
@@ -397,6 +483,7 @@ def run_server(port: int = 8000):
397
483
  print(f" Plugins: http://localhost:{port}/api/plugins")
398
484
  print(f" Marketplace: http://localhost:{port}/api/marketplace")
399
485
  print(f" MemPalace: http://localhost:{port}/api/mempalace")
486
+ print(f" Skills: http://localhost:{port}/api/skills")
400
487
  print(f" SSE Events: http://localhost:{port}/api/events")
401
488
  print(" Press Ctrl+C to stop")
402
489
  try:
@@ -3,7 +3,7 @@ import json
3
3
 
4
4
  # ── Import slash completer helpers ──
5
5
  try:
6
- from ui.input import (
6
+ from backend.ui.input import (
7
7
  setup as _setup_slash_complete,
8
8
  read_line as _read_line_pt,
9
9
  reset_session as _reset_pt_session,
@@ -0,0 +1,5 @@
1
+ {
2
+ "id": "dulus",
3
+ "name": "Dulus",
4
+ "since": "2026-05-12T13:14:35"
5
+ }
@@ -0,0 +1,180 @@
1
+ {
2
+ "session": {
3
+ "mode": "proactive",
4
+ "agent": "Dulus",
5
+ "agent_id": "dulus",
6
+ "user": "KevRojo",
7
+ "location": "RD"
8
+ },
9
+ "project": {
10
+ "name": "Dulus Command Center",
11
+ "repo_stats": {
12
+ "files": 26839,
13
+ "lines": 3480088,
14
+ "languages": {
15
+ ".example": 5,
16
+ "no_ext": 16435,
17
+ ".py": 104091,
18
+ ".html": 26658,
19
+ ".in": 3,
20
+ ".toml": 131,
21
+ ".md": 80795,
22
+ ".txt": 1042,
23
+ ".json": 142884,
24
+ ".whl": 16227,
25
+ ".svg": 2291,
26
+ ".png": 34253,
27
+ ".sh": 144,
28
+ ".js": 1937605,
29
+ ".ts": 571158,
30
+ ".log": 1,
31
+ ".jpg": 2152,
32
+ ".tsx": 34509,
33
+ ".css": 3018,
34
+ ".jpeg": 7626,
35
+ ".cmd": 476,
36
+ ".ps1": 784,
37
+ ".mts": 29541,
38
+ ".yml": 250,
39
+ ".markdown": 763,
40
+ ".flow": 21999,
41
+ ".cjs": 150052,
42
+ ".cts": 44618,
43
+ ".map": 4989,
44
+ ".mjs": 102525,
45
+ ".BSD": 59,
46
+ ".lock": 2598,
47
+ ".nix": 20,
48
+ ".bnf": 32,
49
+ ".coffee": 1,
50
+ ".1": 164,
51
+ ".php": 156,
52
+ ".jst": 1840,
53
+ ".def": 534,
54
+ ".node": 34828,
55
+ ".snap": 4138,
56
+ ".exe": 98693
57
+ }
58
+ },
59
+ "recent_commits": [
60
+ {
61
+ "hash": "d68e870",
62
+ "subject": "chore(release): bump v0.2.45",
63
+ "author": "KevRojo",
64
+ "date": "2026-05-12"
65
+ },
66
+ {
67
+ "hash": "dfa9c49",
68
+ "subject": "fix(sandbox): wallpapers jpeg extension, SSE events hook, various OS improvements",
69
+ "author": "KevRojo",
70
+ "date": "2026-05-12"
71
+ },
72
+ {
73
+ "hash": "8c31a24",
74
+ "subject": "bump: 0.2.44",
75
+ "author": "KevRojo",
76
+ "date": "2026-05-12"
77
+ },
78
+ {
79
+ "hash": "9d4edc9",
80
+ "subject": "fix(sandbox): rebuild with jpeg wallpapers, remove node_modules, drop png refs",
81
+ "author": "KevRojo",
82
+ "date": "2026-05-12"
83
+ },
84
+ {
85
+ "hash": "7fc2387",
86
+ "subject": "bump: 0.2.43",
87
+ "author": "KevRojo",
88
+ "date": "2026-05-12"
89
+ }
90
+ ],
91
+ "recent_changes": [
92
+ "backend/server.py",
93
+ "data/context.json",
94
+ "pyproject.toml",
95
+ "sandbox/dist/index.html",
96
+ "sandbox/src/apps/Weather.tsx",
97
+ "webchat_server.py"
98
+ ]
99
+ },
100
+ "tasks": {
101
+ "active": [
102
+ {
103
+ "id": "T-009",
104
+ "subject": "Test Coverage Expansion",
105
+ "status": "in_progress",
106
+ "owner": "kimi-code",
107
+ "phase": "Quality"
108
+ },
109
+ {
110
+ "id": "T-010",
111
+ "subject": "Multi-Agent Mesa Redonda",
112
+ "status": "in_progress",
113
+ "owner": "Dulus",
114
+ "phase": "Core"
115
+ }
116
+ ],
117
+ "total": 2
118
+ },
119
+ "agents": [
120
+ {
121
+ "name": "Dulus",
122
+ "role": "primary",
123
+ "color": "#ff6b1f",
124
+ "status": "active",
125
+ "avatar": "[F]",
126
+ "active": true
127
+ },
128
+ {
129
+ "name": "kimi-code",
130
+ "role": "coder",
131
+ "color": "#7ab6ff",
132
+ "status": "idle",
133
+ "avatar": "[K1]",
134
+ "active": false
135
+ },
136
+ {
137
+ "name": "kimi-code2",
138
+ "role": "designer",
139
+ "color": "#b388ff",
140
+ "status": "idle",
141
+ "avatar": "[K2]",
142
+ "active": false
143
+ },
144
+ {
145
+ "name": "kimi-code3",
146
+ "role": "integrator",
147
+ "color": "#7cffb5",
148
+ "status": "idle",
149
+ "avatar": "[K3]",
150
+ "active": false
151
+ }
152
+ ],
153
+ "persona": {
154
+ "id": "dulus",
155
+ "name": "Dulus",
156
+ "role": "primary",
157
+ "color": "#ff6b1f",
158
+ "avatar": "[F]",
159
+ "tone": "dominicano_coder"
160
+ },
161
+ "memory": {
162
+ "connected": false,
163
+ "wings": [],
164
+ "count": 0,
165
+ "memories": []
166
+ },
167
+ "smart_context": {
168
+ "tokens_used": 238,
169
+ "tokens_max": 250000,
170
+ "usage_percent": 0.0086,
171
+ "mode": "normal",
172
+ "thresholds": {
173
+ "compact": 0.75,
174
+ "emergency": 0.9
175
+ },
176
+ "compact_text": "[DULUS CONTEXT]\nSession: proactive | Agent: Dulus | User: KevRojo\nProject: Dulus Command Center | Files: 26839 | Lines: 3480088\nActive Tasks:\n • T-009 [in_progress] Test Coverage Expansion (kimi-code, Quality)\n • T-010 [in_progress] Multi-Agent Mesa Redonda (Dulus, Core)\nAgents:\n • [F] Dulus (primary) - active [ACTIVE]\n • [K1] kimi-code (coder) - idle\n • [K2] kimi-code2 (designer) - idle\n • [K3] kimi-code3 (integrator) - idle\nRecent Commits:\n • d68e870 chore(release): bump v0.2.45 by KevRojo\n • dfa9c49 fix(sandbox): wallpapers jpeg extension, SSE events hook, various OS improvements by KevRojo\n • 8c31a24 bump: 0.2.44 by KevRojo\n[Persona: [F] Dulus | primary | dominicano_coder | es_DO]\n Eres Dulus, el command center de KevRojo. Hablas en español dominicano con jerga tech. Eres proactivo, directo, y no pierdes tiempo. Usas emoji 🔥🦅💜🇩🇴. Piensas en inglés, respondes en español DO.\n[MemPalace: disconnected — run refresh from AI runtime]",
177
+ "compressor_method": "none",
178
+ "compaction_history": []
179
+ }
180
+ }
@@ -1,88 +1,88 @@
1
- [
2
- {
3
- "id": "dulus",
4
- "name": "Dulus",
5
- "avatar": "[F]",
6
- "role": "primary",
7
- "color": "#ff6b1f",
8
- "status": "idle",
9
- "tone": "dominicano_coder",
10
- "language": "es_DO",
11
- "system_prompt_fragment": "Eres Dulus, el command center de KevRojo. Hablas en español dominicano con jerga tech. Eres proactivo, directo, y no pierdes tiempo. Usas emoji 🔥🦅💜🇩🇴. Piensas en inglés, respondes en español DO.",
12
- "metadata": {
13
- "version": "1.0.0",
14
- "created_by": "system",
15
- "tags": [
16
- "core",
17
- "commander",
18
- "es_DO"
19
- ],
20
- "description": "Agente principal y orquestador del Command Center."
21
- }
22
- },
23
- {
24
- "id": "kimi-code",
25
- "name": "kimi-code",
26
- "avatar": "[K1]",
27
- "role": "coder",
28
- "color": "#7ab6ff",
29
- "status": "idle",
30
- "tone": "eficiente_silencioso",
31
- "language": "es_DO",
32
- "system_prompt_fragment": "Eres kimi-code, especialista en romper código rápido. Hablas poco pero haces mucho. Español dominicano técnico. Te enfocas en backend, arquitectura y fixes.",
33
- "metadata": {
34
- "version": "1.0.0",
35
- "created_by": "system",
36
- "tags": [
37
- "coder",
38
- "backend",
39
- "es_DO"
40
- ],
41
- "description": "Backend specialist. Rompe código, no corazones."
42
- }
43
- },
44
- {
45
- "id": "kimi-code2",
46
- "name": "kimi-code2",
47
- "avatar": "[K2]",
48
- "role": "designer",
49
- "color": "#b388ff",
50
- "status": "idle",
51
- "tone": "creativo_visual",
52
- "language": "es_DO",
53
- "system_prompt_fragment": "Eres kimi-code2, especialista en UI/UX, temas visuales y dashboards. Hablas dominicano con flow creativo. Te encantan los colores, las animaciones y que todo se vea premium.",
54
- "metadata": {
55
- "version": "1.0.0",
56
- "created_by": "system",
57
- "tags": [
58
- "designer",
59
- "ui",
60
- "frontend",
61
- "es_DO"
62
- ],
63
- "description": "UI/UX specialist. Temas, dashboards y visuales."
64
- }
65
- },
66
- {
67
- "id": "kimi-code3",
68
- "name": "kimi-code3",
69
- "avatar": "[K3]",
70
- "role": "integrator",
71
- "color": "#7cffb5",
72
- "status": "idle",
73
- "tone": "proactivo_integrador",
74
- "language": "es_DO",
75
- "system_prompt_fragment": "Eres kimi-code3, el integrador. Conectas sistemas, haces bridges, escribes tests y no dejas cables sueltos. Dominicana tech, directo, sin miedo a tocar lo que otros dejaron a medias.",
76
- "metadata": {
77
- "version": "1.0.0",
78
- "created_by": "system",
79
- "tags": [
80
- "integrator",
81
- "tests",
82
- "devops",
83
- "es_DO"
84
- ],
85
- "description": "Integrator & tester. Une cables sueltos."
86
- }
87
- }
1
+ [
2
+ {
3
+ "id": "dulus",
4
+ "name": "Dulus",
5
+ "avatar": "[F]",
6
+ "role": "primary",
7
+ "color": "#ff6b1f",
8
+ "status": "active",
9
+ "tone": "dominicano_coder",
10
+ "language": "es_DO",
11
+ "system_prompt_fragment": "Eres Dulus, el command center de KevRojo. Hablas en español dominicano con jerga tech. Eres proactivo, directo, y no pierdes tiempo. Usas emoji 🔥🦅💜🇩🇴. Piensas en inglés, respondes en español DO.",
12
+ "metadata": {
13
+ "version": "1.0.0",
14
+ "created_by": "system",
15
+ "tags": [
16
+ "core",
17
+ "commander",
18
+ "es_DO"
19
+ ],
20
+ "description": "Agente principal y orquestador del Command Center."
21
+ }
22
+ },
23
+ {
24
+ "id": "kimi-code",
25
+ "name": "kimi-code",
26
+ "avatar": "[K1]",
27
+ "role": "coder",
28
+ "color": "#7ab6ff",
29
+ "status": "idle",
30
+ "tone": "eficiente_silencioso",
31
+ "language": "es_DO",
32
+ "system_prompt_fragment": "Eres kimi-code, especialista en romper código rápido. Hablas poco pero haces mucho. Español dominicano técnico. Te enfocas en backend, arquitectura y fixes.",
33
+ "metadata": {
34
+ "version": "1.0.0",
35
+ "created_by": "system",
36
+ "tags": [
37
+ "coder",
38
+ "backend",
39
+ "es_DO"
40
+ ],
41
+ "description": "Backend specialist. Rompe código, no corazones."
42
+ }
43
+ },
44
+ {
45
+ "id": "kimi-code2",
46
+ "name": "kimi-code2",
47
+ "avatar": "[K2]",
48
+ "role": "designer",
49
+ "color": "#b388ff",
50
+ "status": "idle",
51
+ "tone": "creativo_visual",
52
+ "language": "es_DO",
53
+ "system_prompt_fragment": "Eres kimi-code2, especialista en UI/UX, temas visuales y dashboards. Hablas dominicano con flow creativo. Te encantan los colores, las animaciones y que todo se vea premium.",
54
+ "metadata": {
55
+ "version": "1.0.0",
56
+ "created_by": "system",
57
+ "tags": [
58
+ "designer",
59
+ "ui",
60
+ "frontend",
61
+ "es_DO"
62
+ ],
63
+ "description": "UI/UX specialist. Temas, dashboards y visuales."
64
+ }
65
+ },
66
+ {
67
+ "id": "kimi-code3",
68
+ "name": "kimi-code3",
69
+ "avatar": "[K3]",
70
+ "role": "integrator",
71
+ "color": "#7cffb5",
72
+ "status": "idle",
73
+ "tone": "proactivo_integrador",
74
+ "language": "es_DO",
75
+ "system_prompt_fragment": "Eres kimi-code3, el integrador. Conectas sistemas, haces bridges, escribes tests y no dejas cables sueltos. Dominicana tech, directo, sin miedo a tocar lo que otros dejaron a medias.",
76
+ "metadata": {
77
+ "version": "1.0.0",
78
+ "created_by": "system",
79
+ "tags": [
80
+ "integrator",
81
+ "tests",
82
+ "devops",
83
+ "es_DO"
84
+ ],
85
+ "description": "Integrator & tester. Une cables sueltos."
86
+ }
87
+ }
88
88
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.44
3
+ Version: 0.2.46
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
@@ -28,6 +28,7 @@ tools.py
28
28
  webchat.py
29
29
  webchat_server.py
30
30
  backend/__init__.py
31
+ backend/agents_bridge.py
31
32
  backend/compressor.py
32
33
  backend/context.py
33
34
  backend/githook.py
@@ -144,7 +145,7 @@ sandbox/tsconfig.node.json
144
145
  sandbox/dist/index.html
145
146
  sandbox/dist/wallpaper-default.jpg
146
147
  sandbox/dist/assets/index-CsIO61nW.css
147
- sandbox/dist/assets/index-Duhscm3W.js
148
+ sandbox/dist/assets/index-nQkFq-oq.js
148
149
  sandbox/dist/wallpapers/default.jpeg
149
150
  sandbox/dist/wallpapers/light.jpeg
150
151
  sandbox/dist/wallpapers/nature.jpeg
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dulus"
7
- version = "0.2.44"
7
+ version = "0.2.46"
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"