dulus 0.2.9__tar.gz → 0.2.11__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 (156) hide show
  1. {dulus-0.2.9/dulus.egg-info → dulus-0.2.11}/PKG-INFO +22 -5
  2. {dulus-0.2.9 → dulus-0.2.11}/README.md +16 -3
  3. {dulus-0.2.9 → dulus-0.2.11/dulus.egg-info}/PKG-INFO +22 -5
  4. {dulus-0.2.9 → dulus-0.2.11}/dulus.egg-info/requires.txt +7 -1
  5. {dulus-0.2.9 → dulus-0.2.11}/pyproject.toml +12 -2
  6. {dulus-0.2.9 → dulus-0.2.11}/LICENSE +0 -0
  7. {dulus-0.2.9 → dulus-0.2.11}/MANIFEST.in +0 -0
  8. {dulus-0.2.9 → dulus-0.2.11}/agent.py +0 -0
  9. {dulus-0.2.9 → dulus-0.2.11}/backend/__init__.py +0 -0
  10. {dulus-0.2.9 → dulus-0.2.11}/backend/compressor.py +0 -0
  11. {dulus-0.2.9 → dulus-0.2.11}/backend/context.py +0 -0
  12. {dulus-0.2.9 → dulus-0.2.11}/backend/githook.py +0 -0
  13. {dulus-0.2.9 → dulus-0.2.11}/backend/marketplace.py +0 -0
  14. {dulus-0.2.9 → dulus-0.2.11}/backend/mempalace_bridge.py +0 -0
  15. {dulus-0.2.9 → dulus-0.2.11}/backend/personas.py +0 -0
  16. {dulus-0.2.9 → dulus-0.2.11}/backend/plugins.py +0 -0
  17. {dulus-0.2.9 → dulus-0.2.11}/backend/server.py +0 -0
  18. {dulus-0.2.9 → dulus-0.2.11}/backend/tasks.py +0 -0
  19. {dulus-0.2.9 → dulus-0.2.11}/batch_api.py +0 -0
  20. {dulus-0.2.9 → dulus-0.2.11}/checkpoint/__init__.py +0 -0
  21. {dulus-0.2.9 → dulus-0.2.11}/checkpoint/hooks.py +0 -0
  22. {dulus-0.2.9 → dulus-0.2.11}/checkpoint/store.py +0 -0
  23. {dulus-0.2.9 → dulus-0.2.11}/checkpoint/types.py +0 -0
  24. {dulus-0.2.9 → dulus-0.2.11}/claude_code_watcher.py +0 -0
  25. {dulus-0.2.9 → dulus-0.2.11}/clipboard_utils.py +0 -0
  26. {dulus-0.2.9 → dulus-0.2.11}/cloudsave.py +0 -0
  27. {dulus-0.2.9 → dulus-0.2.11}/common.py +0 -0
  28. {dulus-0.2.9 → dulus-0.2.11}/compaction.py +0 -0
  29. {dulus-0.2.9 → dulus-0.2.11}/config.py +0 -0
  30. {dulus-0.2.9 → dulus-0.2.11}/context.py +0 -0
  31. {dulus-0.2.9 → dulus-0.2.11}/data/__init__.py +0 -0
  32. {dulus-0.2.9 → dulus-0.2.11}/data/active_persona.json +0 -0
  33. {dulus-0.2.9 → dulus-0.2.11}/data/context.json +0 -0
  34. {dulus-0.2.9 → dulus-0.2.11}/data/marketplace.json +0 -0
  35. {dulus-0.2.9 → dulus-0.2.11}/data/personas.json +0 -0
  36. {dulus-0.2.9 → dulus-0.2.11}/data/tasks.json +0 -0
  37. {dulus-0.2.9 → dulus-0.2.11}/docs/README.md +0 -0
  38. {dulus-0.2.9 → dulus-0.2.11}/docs/__init__.py +0 -0
  39. {dulus-0.2.9 → dulus-0.2.11}/docs/api.html +0 -0
  40. {dulus-0.2.9 → dulus-0.2.11}/docs/architecture.md +0 -0
  41. {dulus-0.2.9 → dulus-0.2.11}/docs/azure-speech-template.json +0 -0
  42. {dulus-0.2.9 → dulus-0.2.11}/docs/dashboard/index.html +0 -0
  43. {dulus-0.2.9 → dulus-0.2.11}/docs/divider.svg +0 -0
  44. {dulus-0.2.9 → dulus-0.2.11}/docs/generate.py +0 -0
  45. {dulus-0.2.9 → dulus-0.2.11}/docs/hero.svg +0 -0
  46. {dulus-0.2.9 → dulus-0.2.11}/docs/index.html +0 -0
  47. {dulus-0.2.9 → dulus-0.2.11}/docs/news.md +0 -0
  48. {dulus-0.2.9 → dulus-0.2.11}/docs/nvidia-models.svg +0 -0
  49. {dulus-0.2.9 → dulus-0.2.11}/docs/particle-playground.html +0 -0
  50. {dulus-0.2.9 → dulus-0.2.11}/docs/personas/index.html +0 -0
  51. {dulus-0.2.9 → dulus-0.2.11}/docs/preview.html +0 -0
  52. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-agents.svg +0 -0
  53. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-brainstorm.svg +0 -0
  54. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-bridges.svg +0 -0
  55. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-features.svg +0 -0
  56. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-freetier.svg +0 -0
  57. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-memory.svg +0 -0
  58. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-models.svg +0 -0
  59. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-perms.svg +0 -0
  60. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-plugins.svg +0 -0
  61. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-quickstart.svg +0 -0
  62. {dulus-0.2.9 → dulus-0.2.11}/docs/sec-ssj.svg +0 -0
  63. {dulus-0.2.9 → dulus-0.2.11}/docs/spinners.svg +0 -0
  64. {dulus-0.2.9 → dulus-0.2.11}/docs/split-pane.svg +0 -0
  65. {dulus-0.2.9 → dulus-0.2.11}/docs/terminal-boot.svg +0 -0
  66. {dulus-0.2.9 → dulus-0.2.11}/docs/uploads/particle-playground.html +0 -0
  67. {dulus-0.2.9 → dulus-0.2.11}/dulus.egg-info/SOURCES.txt +0 -0
  68. {dulus-0.2.9 → dulus-0.2.11}/dulus.egg-info/dependency_links.txt +0 -0
  69. {dulus-0.2.9 → dulus-0.2.11}/dulus.egg-info/entry_points.txt +0 -0
  70. {dulus-0.2.9 → dulus-0.2.11}/dulus.egg-info/top_level.txt +0 -0
  71. {dulus-0.2.9 → dulus-0.2.11}/dulus.py +0 -0
  72. {dulus-0.2.9 → dulus-0.2.11}/dulus_gui.py +0 -0
  73. {dulus-0.2.9 → dulus-0.2.11}/dulus_mcp/__init__.py +0 -0
  74. {dulus-0.2.9 → dulus-0.2.11}/dulus_mcp/client.py +0 -0
  75. {dulus-0.2.9 → dulus-0.2.11}/dulus_mcp/config.py +0 -0
  76. {dulus-0.2.9 → dulus-0.2.11}/dulus_mcp/tools.py +0 -0
  77. {dulus-0.2.9 → dulus-0.2.11}/dulus_mcp/types.py +0 -0
  78. {dulus-0.2.9 → dulus-0.2.11}/gui/__init__.py +0 -0
  79. {dulus-0.2.9 → dulus-0.2.11}/gui/agent_bridge.py +0 -0
  80. {dulus-0.2.9 → dulus-0.2.11}/gui/chat_widget.py +0 -0
  81. {dulus-0.2.9 → dulus-0.2.11}/gui/main_window.py +0 -0
  82. {dulus-0.2.9 → dulus-0.2.11}/gui/personas.py +0 -0
  83. {dulus-0.2.9 → dulus-0.2.11}/gui/session_utils.py +0 -0
  84. {dulus-0.2.9 → dulus-0.2.11}/gui/settings_dialog.py +0 -0
  85. {dulus-0.2.9 → dulus-0.2.11}/gui/sidebar.py +0 -0
  86. {dulus-0.2.9 → dulus-0.2.11}/gui/tasks_view.py +0 -0
  87. {dulus-0.2.9 → dulus-0.2.11}/gui/themes.py +0 -0
  88. {dulus-0.2.9 → dulus-0.2.11}/gui/tool_panel.py +0 -0
  89. {dulus-0.2.9 → dulus-0.2.11}/input.py +0 -0
  90. {dulus-0.2.9 → dulus-0.2.11}/license_manager.py +0 -0
  91. {dulus-0.2.9 → dulus-0.2.11}/memory/__init__.py +0 -0
  92. {dulus-0.2.9 → dulus-0.2.11}/memory/audit.py +0 -0
  93. {dulus-0.2.9 → dulus-0.2.11}/memory/consolidator.py +0 -0
  94. {dulus-0.2.9 → dulus-0.2.11}/memory/context.py +0 -0
  95. {dulus-0.2.9 → dulus-0.2.11}/memory/offload.py +0 -0
  96. {dulus-0.2.9 → dulus-0.2.11}/memory/palace.py +0 -0
  97. {dulus-0.2.9 → dulus-0.2.11}/memory/scan.py +0 -0
  98. {dulus-0.2.9 → dulus-0.2.11}/memory/sessions.py +0 -0
  99. {dulus-0.2.9 → dulus-0.2.11}/memory/store.py +0 -0
  100. {dulus-0.2.9 → dulus-0.2.11}/memory/tools.py +0 -0
  101. {dulus-0.2.9 → dulus-0.2.11}/memory/types.py +0 -0
  102. {dulus-0.2.9 → dulus-0.2.11}/memory/vector_search.py +0 -0
  103. {dulus-0.2.9 → dulus-0.2.11}/multi_agent/__init__.py +0 -0
  104. {dulus-0.2.9 → dulus-0.2.11}/multi_agent/subagent.py +0 -0
  105. {dulus-0.2.9 → dulus-0.2.11}/multi_agent/tools.py +0 -0
  106. {dulus-0.2.9 → dulus-0.2.11}/offload_helper.py +0 -0
  107. {dulus-0.2.9 → dulus-0.2.11}/plugin/__init__.py +0 -0
  108. {dulus-0.2.9 → dulus-0.2.11}/plugin/autoadapter.py +0 -0
  109. {dulus-0.2.9 → dulus-0.2.11}/plugin/loader.py +0 -0
  110. {dulus-0.2.9 → dulus-0.2.11}/plugin/recommend.py +0 -0
  111. {dulus-0.2.9 → dulus-0.2.11}/plugin/store.py +0 -0
  112. {dulus-0.2.9 → dulus-0.2.11}/plugin/types.py +0 -0
  113. {dulus-0.2.9 → dulus-0.2.11}/providers.py +0 -0
  114. {dulus-0.2.9 → dulus-0.2.11}/setup.cfg +0 -0
  115. {dulus-0.2.9 → dulus-0.2.11}/skill/__init__.py +0 -0
  116. {dulus-0.2.9 → dulus-0.2.11}/skill/builtin.py +0 -0
  117. {dulus-0.2.9 → dulus-0.2.11}/skill/clawhub.py +0 -0
  118. {dulus-0.2.9 → dulus-0.2.11}/skill/executor.py +0 -0
  119. {dulus-0.2.9 → dulus-0.2.11}/skill/loader.py +0 -0
  120. {dulus-0.2.9 → dulus-0.2.11}/skill/tools.py +0 -0
  121. {dulus-0.2.9 → dulus-0.2.11}/skills.py +0 -0
  122. {dulus-0.2.9 → dulus-0.2.11}/spinner.py +0 -0
  123. {dulus-0.2.9 → dulus-0.2.11}/string_utils.py +0 -0
  124. {dulus-0.2.9 → dulus-0.2.11}/subagent.py +0 -0
  125. {dulus-0.2.9 → dulus-0.2.11}/task/__init__.py +0 -0
  126. {dulus-0.2.9 → dulus-0.2.11}/task/store.py +0 -0
  127. {dulus-0.2.9 → dulus-0.2.11}/task/tools.py +0 -0
  128. {dulus-0.2.9 → dulus-0.2.11}/task/types.py +0 -0
  129. {dulus-0.2.9 → dulus-0.2.11}/tests/test_checkpoint.py +0 -0
  130. {dulus-0.2.9 → dulus-0.2.11}/tests/test_compaction.py +0 -0
  131. {dulus-0.2.9 → dulus-0.2.11}/tests/test_diff_view.py +0 -0
  132. {dulus-0.2.9 → dulus-0.2.11}/tests/test_injection_fix.py +0 -0
  133. {dulus-0.2.9 → dulus-0.2.11}/tests/test_license.py +0 -0
  134. {dulus-0.2.9 → dulus-0.2.11}/tests/test_mcp.py +0 -0
  135. {dulus-0.2.9 → dulus-0.2.11}/tests/test_memory.py +0 -0
  136. {dulus-0.2.9 → dulus-0.2.11}/tests/test_plugin.py +0 -0
  137. {dulus-0.2.9 → dulus-0.2.11}/tests/test_skills.py +0 -0
  138. {dulus-0.2.9 → dulus-0.2.11}/tests/test_subagent.py +0 -0
  139. {dulus-0.2.9 → dulus-0.2.11}/tests/test_task.py +0 -0
  140. {dulus-0.2.9 → dulus-0.2.11}/tests/test_telegram_buffer.py +0 -0
  141. {dulus-0.2.9 → dulus-0.2.11}/tests/test_tool_registry.py +0 -0
  142. {dulus-0.2.9 → dulus-0.2.11}/tests/test_voice.py +0 -0
  143. {dulus-0.2.9 → dulus-0.2.11}/tmux_offloader.py +0 -0
  144. {dulus-0.2.9 → dulus-0.2.11}/tmux_tools.py +0 -0
  145. {dulus-0.2.9 → dulus-0.2.11}/tool_registry.py +0 -0
  146. {dulus-0.2.9 → dulus-0.2.11}/tools.py +0 -0
  147. {dulus-0.2.9 → dulus-0.2.11}/ui/__init__.py +0 -0
  148. {dulus-0.2.9 → dulus-0.2.11}/ui/input.py +0 -0
  149. {dulus-0.2.9 → dulus-0.2.11}/ui/render.py +0 -0
  150. {dulus-0.2.9 → dulus-0.2.11}/voice/__init__.py +0 -0
  151. {dulus-0.2.9 → dulus-0.2.11}/voice/keyterms.py +0 -0
  152. {dulus-0.2.9 → dulus-0.2.11}/voice/recorder.py +0 -0
  153. {dulus-0.2.9 → dulus-0.2.11}/voice/stt.py +0 -0
  154. {dulus-0.2.9 → dulus-0.2.11}/voice/tts.py +0 -0
  155. {dulus-0.2.9 → dulus-0.2.11}/webchat.py +0 -0
  156. {dulus-0.2.9 → dulus-0.2.11}/webchat_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.9
3
+ Version: 0.2.11
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
@@ -29,12 +29,16 @@ Requires-Dist: httpx>=0.27.0
29
29
  Requires-Dist: requests>=2.31.0
30
30
  Requires-Dist: rich>=13.0.0
31
31
  Requires-Dist: prompt_toolkit>=3.0.0
32
- Requires-Dist: mempalace>=3.3.4
33
32
  Requires-Dist: Flask>=3.1.3
34
33
  Requires-Dist: bubblewrap-cli>=1.0.0
35
34
  Requires-Dist: sounddevice
36
35
  Requires-Dist: customtkinter>=5.2.0
37
36
  Requires-Dist: Pillow>=10.0.0
37
+ Requires-Dist: typing-extensions>=4.10.0
38
+ Provides-Extra: memory
39
+ Requires-Dist: mempalace>=3.3.4; extra == "memory"
40
+ Provides-Extra: full
41
+ Requires-Dist: mempalace>=3.3.4; extra == "full"
38
42
  Dynamic: license-file
39
43
 
40
44
  # ▲ DULUS
@@ -84,7 +88,7 @@ SET /sticky_input ON since the first run for the best experience!
84
88
 
85
89
  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.
86
90
 
87
- > **v0.2.9 — May 8, 2026** — Per-turn injection now queries the real MemPalace (`~/.mempalace/palace`) instead of the small local memory dir, so deep context (bond, soul, sessions) actually surfaces. `/theme` palette upgraded to 4 semantic roles (accent / ok / warn / err) with a live preview swatch in the listing. TmuxOffload accepts `tool_input` as alias of `tool_params`, sends an explicit second Enter on Windows so commands containing `&&`/`||`/`;` don't sit typed-but-unexecuted.
91
+ > **v0.2.11 — May 8, 2026** — `mempalace` moved to `[memory]` extra so `pip install dulus` is now fast and works on termux/Android out of the box (chromadb's 26 transitive deps were the resolver killer). MemPalace per-turn injection still loads at runtime when present; opt in with `pip install "dulus[memory]"`.
88
92
  > Type `/news` to see what changed.
89
93
 
90
94
  ---
@@ -120,10 +124,11 @@ Dulus is the first one meeting multiple models at the same time working for the
120
124
  ### One-liner
121
125
 
122
126
  ```bash
123
- pip install dulus && dulus
127
+ pip install dulus && dulus # core CLI — fast, no compile, works on termux
128
+ pip install "dulus[memory]" && dulus # +MemPalace per-turn memory (pulls chromadb)
124
129
  ```
125
130
 
126
- That's it. Dulus prompts you for a key on first run.
131
+ That's it. Dulus prompts you for a key on first run. The `[memory]` extra pulls in `mempalace` and its `chromadb` chain — skip it on Android/termux or anywhere wheels for `numpy`/`onnxruntime` aren't available; the CLI still boots and chats fine without it.
127
132
 
128
133
  ### From source (hacking on Dulus itself)
129
134
 
@@ -133,6 +138,18 @@ pip install -e . # editable install
133
138
  dulus
134
139
  ```
135
140
 
141
+ ### Termux / Android
142
+
143
+ The default install pulls `mempalace` and `sounddevice`, both of which need a NumPy that has no prebuilt wheel for `aarch64-android` — pip will try to build NumPy from source and fail. Install around it:
144
+
145
+ ```bash
146
+ pkg install python python-numpy python-pillow build-essential
147
+ pip install --no-deps dulus
148
+ pip install anthropic openai httpx requests rich prompt_toolkit Flask bubblewrap-cli mempalace
149
+ ```
150
+
151
+ Skip `sounddevice` (no usable PortAudio on Android — voice features won't work anyway). Dulus's runtime is graceful: voice / MemPalace just degrade if their deps aren't there, the CLI still boots and chats fine.
152
+
136
153
  ### Pick a model
137
154
 
138
155
  ```bash
@@ -45,7 +45,7 @@ SET /sticky_input ON since the first run for the best experience!
45
45
 
46
46
  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.
47
47
 
48
- > **v0.2.9 — May 8, 2026** — Per-turn injection now queries the real MemPalace (`~/.mempalace/palace`) instead of the small local memory dir, so deep context (bond, soul, sessions) actually surfaces. `/theme` palette upgraded to 4 semantic roles (accent / ok / warn / err) with a live preview swatch in the listing. TmuxOffload accepts `tool_input` as alias of `tool_params`, sends an explicit second Enter on Windows so commands containing `&&`/`||`/`;` don't sit typed-but-unexecuted.
48
+ > **v0.2.11 — May 8, 2026** — `mempalace` moved to `[memory]` extra so `pip install dulus` is now fast and works on termux/Android out of the box (chromadb's 26 transitive deps were the resolver killer). MemPalace per-turn injection still loads at runtime when present; opt in with `pip install "dulus[memory]"`.
49
49
  > Type `/news` to see what changed.
50
50
 
51
51
  ---
@@ -81,10 +81,11 @@ Dulus is the first one meeting multiple models at the same time working for the
81
81
  ### One-liner
82
82
 
83
83
  ```bash
84
- pip install dulus && dulus
84
+ pip install dulus && dulus # core CLI — fast, no compile, works on termux
85
+ pip install "dulus[memory]" && dulus # +MemPalace per-turn memory (pulls chromadb)
85
86
  ```
86
87
 
87
- That's it. Dulus prompts you for a key on first run.
88
+ That's it. Dulus prompts you for a key on first run. The `[memory]` extra pulls in `mempalace` and its `chromadb` chain — skip it on Android/termux or anywhere wheels for `numpy`/`onnxruntime` aren't available; the CLI still boots and chats fine without it.
88
89
 
89
90
  ### From source (hacking on Dulus itself)
90
91
 
@@ -94,6 +95,18 @@ pip install -e . # editable install
94
95
  dulus
95
96
  ```
96
97
 
98
+ ### Termux / Android
99
+
100
+ The default install pulls `mempalace` and `sounddevice`, both of which need a NumPy that has no prebuilt wheel for `aarch64-android` — pip will try to build NumPy from source and fail. Install around it:
101
+
102
+ ```bash
103
+ pkg install python python-numpy python-pillow build-essential
104
+ pip install --no-deps dulus
105
+ pip install anthropic openai httpx requests rich prompt_toolkit Flask bubblewrap-cli mempalace
106
+ ```
107
+
108
+ Skip `sounddevice` (no usable PortAudio on Android — voice features won't work anyway). Dulus's runtime is graceful: voice / MemPalace just degrade if their deps aren't there, the CLI still boots and chats fine.
109
+
97
110
  ### Pick a model
98
111
 
99
112
  ```bash
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.9
3
+ Version: 0.2.11
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
@@ -29,12 +29,16 @@ Requires-Dist: httpx>=0.27.0
29
29
  Requires-Dist: requests>=2.31.0
30
30
  Requires-Dist: rich>=13.0.0
31
31
  Requires-Dist: prompt_toolkit>=3.0.0
32
- Requires-Dist: mempalace>=3.3.4
33
32
  Requires-Dist: Flask>=3.1.3
34
33
  Requires-Dist: bubblewrap-cli>=1.0.0
35
34
  Requires-Dist: sounddevice
36
35
  Requires-Dist: customtkinter>=5.2.0
37
36
  Requires-Dist: Pillow>=10.0.0
37
+ Requires-Dist: typing-extensions>=4.10.0
38
+ Provides-Extra: memory
39
+ Requires-Dist: mempalace>=3.3.4; extra == "memory"
40
+ Provides-Extra: full
41
+ Requires-Dist: mempalace>=3.3.4; extra == "full"
38
42
  Dynamic: license-file
39
43
 
40
44
  # ▲ DULUS
@@ -84,7 +88,7 @@ SET /sticky_input ON since the first run for the best experience!
84
88
 
85
89
  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.
86
90
 
87
- > **v0.2.9 — May 8, 2026** — Per-turn injection now queries the real MemPalace (`~/.mempalace/palace`) instead of the small local memory dir, so deep context (bond, soul, sessions) actually surfaces. `/theme` palette upgraded to 4 semantic roles (accent / ok / warn / err) with a live preview swatch in the listing. TmuxOffload accepts `tool_input` as alias of `tool_params`, sends an explicit second Enter on Windows so commands containing `&&`/`||`/`;` don't sit typed-but-unexecuted.
91
+ > **v0.2.11 — May 8, 2026** — `mempalace` moved to `[memory]` extra so `pip install dulus` is now fast and works on termux/Android out of the box (chromadb's 26 transitive deps were the resolver killer). MemPalace per-turn injection still loads at runtime when present; opt in with `pip install "dulus[memory]"`.
88
92
  > Type `/news` to see what changed.
89
93
 
90
94
  ---
@@ -120,10 +124,11 @@ Dulus is the first one meeting multiple models at the same time working for the
120
124
  ### One-liner
121
125
 
122
126
  ```bash
123
- pip install dulus && dulus
127
+ pip install dulus && dulus # core CLI — fast, no compile, works on termux
128
+ pip install "dulus[memory]" && dulus # +MemPalace per-turn memory (pulls chromadb)
124
129
  ```
125
130
 
126
- That's it. Dulus prompts you for a key on first run.
131
+ That's it. Dulus prompts you for a key on first run. The `[memory]` extra pulls in `mempalace` and its `chromadb` chain — skip it on Android/termux or anywhere wheels for `numpy`/`onnxruntime` aren't available; the CLI still boots and chats fine without it.
127
132
 
128
133
  ### From source (hacking on Dulus itself)
129
134
 
@@ -133,6 +138,18 @@ pip install -e . # editable install
133
138
  dulus
134
139
  ```
135
140
 
141
+ ### Termux / Android
142
+
143
+ The default install pulls `mempalace` and `sounddevice`, both of which need a NumPy that has no prebuilt wheel for `aarch64-android` — pip will try to build NumPy from source and fail. Install around it:
144
+
145
+ ```bash
146
+ pkg install python python-numpy python-pillow build-essential
147
+ pip install --no-deps dulus
148
+ pip install anthropic openai httpx requests rich prompt_toolkit Flask bubblewrap-cli mempalace
149
+ ```
150
+
151
+ Skip `sounddevice` (no usable PortAudio on Android — voice features won't work anyway). Dulus's runtime is graceful: voice / MemPalace just degrade if their deps aren't there, the CLI still boots and chats fine.
152
+
136
153
  ### Pick a model
137
154
 
138
155
  ```bash
@@ -4,9 +4,15 @@ httpx>=0.27.0
4
4
  requests>=2.31.0
5
5
  rich>=13.0.0
6
6
  prompt_toolkit>=3.0.0
7
- mempalace>=3.3.4
8
7
  Flask>=3.1.3
9
8
  bubblewrap-cli>=1.0.0
10
9
  sounddevice
11
10
  customtkinter>=5.2.0
12
11
  Pillow>=10.0.0
12
+ typing-extensions>=4.10.0
13
+
14
+ [full]
15
+ mempalace>=3.3.4
16
+
17
+ [memory]
18
+ mempalace>=3.3.4
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dulus"
7
- version = "0.2.9"
7
+ version = "0.2.11"
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"
@@ -34,14 +34,24 @@ dependencies = [
34
34
  "requests>=2.31.0",
35
35
  "rich>=13.0.0",
36
36
  "prompt_toolkit>=3.0.0",
37
- "mempalace>=3.3.4",
38
37
  "Flask>=3.1.3",
39
38
  "bubblewrap-cli>=1.0.0",
40
39
  "sounddevice",
41
40
  "customtkinter>=5.2.0",
42
41
  "Pillow>=10.0.0",
42
+ "typing-extensions>=4.10.0",
43
43
  ]
44
44
 
45
+ # mempalace pulls chromadb (26 transitive deps incl. numpy + onnxruntime),
46
+ # which on termux/aarch64 has no wheels and on regular installs sends pip's
47
+ # resolver into a backtracking loop trying to reconcile typing-extensions /
48
+ # pydantic / httpx ranges. Keeping it optional lets `pip install dulus` succeed
49
+ # in seconds everywhere; power users opt in with `pip install dulus[memory]`
50
+ # (or `dulus[full]`) when they want MemPalace per-turn injection.
51
+ [project.optional-dependencies]
52
+ memory = ["mempalace>=3.3.4"]
53
+ full = ["mempalace>=3.3.4"]
54
+
45
55
  [project.scripts]
46
56
  dulus = "dulus:main"
47
57
 
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
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
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