dulus 0.2.44__tar.gz → 0.2.47__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dulus-0.2.44/dulus.egg-info → dulus-0.2.47}/PKG-INFO +1 -1
- dulus-0.2.47/backend/agents_bridge.py +75 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/server.py +91 -4
- {dulus-0.2.44 → dulus-0.2.47}/common.py +1 -1
- dulus-0.2.47/data/active_persona.json +5 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/context.json +57 -45
- {dulus-0.2.44 → dulus-0.2.47}/data/personas.json +87 -87
- {dulus-0.2.44 → dulus-0.2.47/dulus.egg-info}/PKG-INFO +1 -1
- {dulus-0.2.44 → dulus-0.2.47}/dulus.egg-info/SOURCES.txt +2 -1
- {dulus-0.2.44 → dulus-0.2.47}/pyproject.toml +1 -1
- dulus-0.2.44/sandbox/dist/assets/index-Duhscm3W.js → dulus-0.2.47/sandbox/dist/assets/index-nQkFq-oq.js +45 -45
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/dist/index.html +1 -1
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/package-lock.json +2 -2
- {dulus-0.2.44 → dulus-0.2.47}/webchat_server.py +60 -19
- dulus-0.2.44/data/active_persona.json +0 -5
- {dulus-0.2.44 → dulus-0.2.47}/LICENSE +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/MANIFEST.in +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/README.md +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/agent.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/compressor.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/context.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/githook.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/marketplace.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/mempalace_bridge.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/personas.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/plugins.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/backend/tasks.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/batch_api.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/checkpoint/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/checkpoint/hooks.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/checkpoint/store.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/checkpoint/types.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/claude_code_watcher.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/clipboard_utils.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/cloudsave.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/compaction.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/config.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/context.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/marketplace.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/plugins/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/plugins/composio/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/plugins/composio/composio_plugin/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/plugins/composio/plugin.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/plugins/composio/plugin_tool.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/data/tasks.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/README.md +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/api.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/architecture.md +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/azure-speech-template.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/dashboard/index.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/divider.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/generate.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/hero.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/index.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/news.md +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/nvidia-models.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/particle-playground.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/personas/index.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/poetry-banner.png +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/preview.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-agents.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-brainstorm.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-bridges.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-features.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-freetier.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-memory.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-models.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-perms.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-plugins.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-quickstart.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/sec-ssj.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/spinners.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/split-pane.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/terminal-boot.svg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/docs/uploads/particle-playground.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus.egg-info/dependency_links.txt +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus.egg-info/entry_points.txt +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus.egg-info/requires.txt +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus.egg-info/top_level.txt +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus_gui.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus_mcp/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus_mcp/client.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus_mcp/config.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus_mcp/tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/dulus_mcp/types.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/agent_bridge.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/chat_widget.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/main_window.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/personas.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/session_utils.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/settings_dialog.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/sidebar.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/tasks_view.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/themes.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/gui/tool_panel.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/input.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/license_manager.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/audit.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/consolidator.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/context.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/offload.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/palace.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/scan.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/sessions.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/store.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/types.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/memory/vector_search.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/multi_agent/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/multi_agent/subagent.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/multi_agent/tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/offload_helper.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/plugin/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/plugin/autoadapter.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/plugin/loader.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/plugin/recommend.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/plugin/store.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/plugin/types.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/providers.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/README.md +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/components.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/dist/assets/index-CsIO61nW.css +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/dist/wallpaper-default.jpg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/dist/wallpapers/default.jpeg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/dist/wallpapers/light.jpeg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/dist/wallpapers/nature.jpeg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/dist/wallpapers/tech.jpeg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/eslint.config.js +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/index.html +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/info.md +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/package.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/postcss.config.js +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/public/wallpaper-default.jpg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/src/index.css +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/tailwind.config.js +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/tsconfig.app.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/tsconfig.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/sandbox/tsconfig.node.json +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/setup.cfg +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/skill/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/skill/builtin.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/skill/clawhub.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/skill/executor.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/skill/loader.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/skill/tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/skills.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/spinner.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/string_utils.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/subagent.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/task/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/task/store.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/task/tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/task/types.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_afk_yolo.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_approval_runtime.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_background_task_tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_background_tasks.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_checkpoint.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_clipboard_utils.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_compaction.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_diff_view.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_diff_visualization.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_display_blocks.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_export_import.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_hook_engine.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_injection_fix.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_license.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_mcp.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_memory.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_notification_manager.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_plugin.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_session_fork.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_shell_mode.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_skills.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_steer_input.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_subagent.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_task.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_telegram_buffer.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_think_tool.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_todo_tool.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_todo_visualization.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_tool_registry.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_voice.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tests/test_wire_events.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tmux_offloader.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tmux_tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tool_registry.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/tools.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/ui/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/ui/input.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/ui/render.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/voice/__init__.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/voice/keyterms.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/voice/recorder.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/voice/stt.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/voice/tts.py +0 -0
- {dulus-0.2.44 → dulus-0.2.47}/webchat.py +0 -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
|
-
|
|
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 =
|
|
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:
|
|
@@ -9,56 +9,68 @@
|
|
|
9
9
|
"project": {
|
|
10
10
|
"name": "Dulus Command Center",
|
|
11
11
|
"repo_stats": {
|
|
12
|
-
"files":
|
|
13
|
-
"lines":
|
|
12
|
+
"files": 591,
|
|
13
|
+
"lines": 283029,
|
|
14
14
|
"languages": {
|
|
15
15
|
".example": 5,
|
|
16
|
-
"no_ext":
|
|
17
|
-
".py":
|
|
18
|
-
".html":
|
|
19
|
-
".in":
|
|
20
|
-
".toml":
|
|
21
|
-
".md":
|
|
22
|
-
".txt":
|
|
23
|
-
".json":
|
|
24
|
-
".whl":
|
|
25
|
-
".gz":
|
|
26
|
-
".svg":
|
|
27
|
-
".png":
|
|
16
|
+
"no_ext": 1415,
|
|
17
|
+
".py": 103942,
|
|
18
|
+
".html": 25305,
|
|
19
|
+
".in": 3,
|
|
20
|
+
".toml": 131,
|
|
21
|
+
".md": 3295,
|
|
22
|
+
".txt": 309,
|
|
23
|
+
".json": 18761,
|
|
24
|
+
".whl": 32389,
|
|
25
|
+
".gz": 16269,
|
|
26
|
+
".svg": 2246,
|
|
27
|
+
".png": 34253,
|
|
28
28
|
".sh": 144,
|
|
29
|
-
".js":
|
|
30
|
-
".ts":
|
|
29
|
+
".js": 946,
|
|
30
|
+
".ts": 2304,
|
|
31
31
|
".log": 1,
|
|
32
|
-
".jpg":
|
|
33
|
-
".tsx":
|
|
34
|
-
".css":
|
|
35
|
-
".
|
|
36
|
-
".ps1": 784,
|
|
37
|
-
".tsbuildinfo": 2,
|
|
38
|
-
".mts": 29541,
|
|
39
|
-
".yml": 250,
|
|
40
|
-
".markdown": 763,
|
|
41
|
-
".flow": 21999,
|
|
42
|
-
".cjs": 150052,
|
|
43
|
-
".cts": 44618,
|
|
44
|
-
".map": 5059,
|
|
45
|
-
".mjs": 102525,
|
|
46
|
-
".BSD": 59,
|
|
47
|
-
".lock": 2598,
|
|
48
|
-
".nix": 20,
|
|
49
|
-
".bnf": 32,
|
|
50
|
-
".coffee": 1,
|
|
51
|
-
".1": 164,
|
|
52
|
-
".php": 156,
|
|
53
|
-
".jst": 1840,
|
|
54
|
-
".def": 534,
|
|
55
|
-
".node": 34828,
|
|
56
|
-
".snap": 4138,
|
|
57
|
-
".exe": 98693
|
|
32
|
+
".jpg": 2152,
|
|
33
|
+
".tsx": 31193,
|
|
34
|
+
".css": 340,
|
|
35
|
+
".jpeg": 7626
|
|
58
36
|
}
|
|
59
37
|
},
|
|
60
|
-
"recent_commits": [
|
|
61
|
-
|
|
38
|
+
"recent_commits": [
|
|
39
|
+
{
|
|
40
|
+
"hash": "cfa4e4e",
|
|
41
|
+
"subject": "bump: 0.2.45 → 0.2.46",
|
|
42
|
+
"author": "KevRojo",
|
|
43
|
+
"date": "2026-05-12"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"hash": "bc4cf5c",
|
|
47
|
+
"subject": "chore: pre-release sync — backend agents, sandbox updates, explorer HTML",
|
|
48
|
+
"author": "KevRojo",
|
|
49
|
+
"date": "2026-05-12"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"hash": "d68e870",
|
|
53
|
+
"subject": "chore(release): bump v0.2.45",
|
|
54
|
+
"author": "KevRojo",
|
|
55
|
+
"date": "2026-05-12"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"hash": "dfa9c49",
|
|
59
|
+
"subject": "fix(sandbox): wallpapers jpeg extension, SSE events hook, various OS improvements",
|
|
60
|
+
"author": "KevRojo",
|
|
61
|
+
"date": "2026-05-12"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"hash": "8c31a24",
|
|
65
|
+
"subject": "bump: 0.2.44",
|
|
66
|
+
"author": "KevRojo",
|
|
67
|
+
"date": "2026-05-12"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"recent_changes": [
|
|
71
|
+
"data/context.json",
|
|
72
|
+
"pyproject.toml"
|
|
73
|
+
]
|
|
62
74
|
},
|
|
63
75
|
"tasks": {
|
|
64
76
|
"active": [
|
|
@@ -84,7 +96,7 @@
|
|
|
84
96
|
"name": "Dulus",
|
|
85
97
|
"role": "primary",
|
|
86
98
|
"color": "#ff6b1f",
|
|
87
|
-
"status": "
|
|
99
|
+
"status": "active",
|
|
88
100
|
"avatar": "[F]",
|
|
89
101
|
"active": true
|
|
90
102
|
},
|
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"id": "dulus",
|
|
4
|
-
"name": "Dulus",
|
|
5
|
-
"avatar": "[F]",
|
|
6
|
-
"role": "primary",
|
|
7
|
-
"color": "#ff6b1f",
|
|
8
|
-
"status": "
|
|
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
|
]
|
|
@@ -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-
|
|
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.
|
|
7
|
+
version = "0.2.47"
|
|
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"
|