dulus 0.2.22__tar.gz → 0.2.24__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 (164) hide show
  1. {dulus-0.2.22/dulus.egg-info → dulus-0.2.24}/PKG-INFO +2 -2
  2. {dulus-0.2.22 → dulus-0.2.24}/README.md +1 -1
  3. {dulus-0.2.22 → dulus-0.2.24}/context.py +1 -0
  4. {dulus-0.2.22 → dulus-0.2.24}/docs/news.md +12 -0
  5. {dulus-0.2.22 → dulus-0.2.24/dulus.egg-info}/PKG-INFO +2 -2
  6. {dulus-0.2.22 → dulus-0.2.24}/dulus.py +1 -1
  7. {dulus-0.2.22 → dulus-0.2.24}/plugin/autoadapter.py +37 -2
  8. {dulus-0.2.22 → dulus-0.2.24}/pyproject.toml +1 -1
  9. {dulus-0.2.22 → dulus-0.2.24}/LICENSE +0 -0
  10. {dulus-0.2.22 → dulus-0.2.24}/MANIFEST.in +0 -0
  11. {dulus-0.2.22 → dulus-0.2.24}/agent.py +0 -0
  12. {dulus-0.2.22 → dulus-0.2.24}/backend/__init__.py +0 -0
  13. {dulus-0.2.22 → dulus-0.2.24}/backend/compressor.py +0 -0
  14. {dulus-0.2.22 → dulus-0.2.24}/backend/context.py +0 -0
  15. {dulus-0.2.22 → dulus-0.2.24}/backend/githook.py +0 -0
  16. {dulus-0.2.22 → dulus-0.2.24}/backend/marketplace.py +0 -0
  17. {dulus-0.2.22 → dulus-0.2.24}/backend/mempalace_bridge.py +0 -0
  18. {dulus-0.2.22 → dulus-0.2.24}/backend/personas.py +0 -0
  19. {dulus-0.2.22 → dulus-0.2.24}/backend/plugins.py +0 -0
  20. {dulus-0.2.22 → dulus-0.2.24}/backend/server.py +0 -0
  21. {dulus-0.2.22 → dulus-0.2.24}/backend/tasks.py +0 -0
  22. {dulus-0.2.22 → dulus-0.2.24}/batch_api.py +0 -0
  23. {dulus-0.2.22 → dulus-0.2.24}/checkpoint/__init__.py +0 -0
  24. {dulus-0.2.22 → dulus-0.2.24}/checkpoint/hooks.py +0 -0
  25. {dulus-0.2.22 → dulus-0.2.24}/checkpoint/store.py +0 -0
  26. {dulus-0.2.22 → dulus-0.2.24}/checkpoint/types.py +0 -0
  27. {dulus-0.2.22 → dulus-0.2.24}/claude_code_watcher.py +0 -0
  28. {dulus-0.2.22 → dulus-0.2.24}/clipboard_utils.py +0 -0
  29. {dulus-0.2.22 → dulus-0.2.24}/cloudsave.py +0 -0
  30. {dulus-0.2.22 → dulus-0.2.24}/common.py +0 -0
  31. {dulus-0.2.22 → dulus-0.2.24}/compaction.py +0 -0
  32. {dulus-0.2.22 → dulus-0.2.24}/config.py +0 -0
  33. {dulus-0.2.22 → dulus-0.2.24}/data/__init__.py +0 -0
  34. {dulus-0.2.22 → dulus-0.2.24}/data/active_persona.json +0 -0
  35. {dulus-0.2.22 → dulus-0.2.24}/data/context.json +0 -0
  36. {dulus-0.2.22 → dulus-0.2.24}/data/marketplace.json +0 -0
  37. {dulus-0.2.22 → dulus-0.2.24}/data/personas.json +0 -0
  38. {dulus-0.2.22 → dulus-0.2.24}/data/plugins/__init__.py +0 -0
  39. {dulus-0.2.22 → dulus-0.2.24}/data/plugins/composio/__init__.py +0 -0
  40. {dulus-0.2.22 → dulus-0.2.24}/data/plugins/composio/composio_plugin/__init__.py +0 -0
  41. {dulus-0.2.22 → dulus-0.2.24}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
  42. {dulus-0.2.22 → dulus-0.2.24}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
  43. {dulus-0.2.22 → dulus-0.2.24}/data/plugins/composio/plugin.json +0 -0
  44. {dulus-0.2.22 → dulus-0.2.24}/data/plugins/composio/plugin_tool.py +0 -0
  45. {dulus-0.2.22 → dulus-0.2.24}/data/tasks.json +0 -0
  46. {dulus-0.2.22 → dulus-0.2.24}/docs/README.md +0 -0
  47. {dulus-0.2.22 → dulus-0.2.24}/docs/__init__.py +0 -0
  48. {dulus-0.2.22 → dulus-0.2.24}/docs/api.html +0 -0
  49. {dulus-0.2.22 → dulus-0.2.24}/docs/architecture.md +0 -0
  50. {dulus-0.2.22 → dulus-0.2.24}/docs/azure-speech-template.json +0 -0
  51. {dulus-0.2.22 → dulus-0.2.24}/docs/dashboard/index.html +0 -0
  52. {dulus-0.2.22 → dulus-0.2.24}/docs/divider.svg +0 -0
  53. {dulus-0.2.22 → dulus-0.2.24}/docs/generate.py +0 -0
  54. {dulus-0.2.22 → dulus-0.2.24}/docs/hero.svg +0 -0
  55. {dulus-0.2.22 → dulus-0.2.24}/docs/index.html +0 -0
  56. {dulus-0.2.22 → dulus-0.2.24}/docs/nvidia-models.svg +0 -0
  57. {dulus-0.2.22 → dulus-0.2.24}/docs/particle-playground.html +0 -0
  58. {dulus-0.2.22 → dulus-0.2.24}/docs/personas/index.html +0 -0
  59. {dulus-0.2.22 → dulus-0.2.24}/docs/poetry-banner.png +0 -0
  60. {dulus-0.2.22 → dulus-0.2.24}/docs/preview.html +0 -0
  61. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-agents.svg +0 -0
  62. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-brainstorm.svg +0 -0
  63. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-bridges.svg +0 -0
  64. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-features.svg +0 -0
  65. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-freetier.svg +0 -0
  66. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-memory.svg +0 -0
  67. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-models.svg +0 -0
  68. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-perms.svg +0 -0
  69. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-plugins.svg +0 -0
  70. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-quickstart.svg +0 -0
  71. {dulus-0.2.22 → dulus-0.2.24}/docs/sec-ssj.svg +0 -0
  72. {dulus-0.2.22 → dulus-0.2.24}/docs/spinners.svg +0 -0
  73. {dulus-0.2.22 → dulus-0.2.24}/docs/split-pane.svg +0 -0
  74. {dulus-0.2.22 → dulus-0.2.24}/docs/terminal-boot.svg +0 -0
  75. {dulus-0.2.22 → dulus-0.2.24}/docs/uploads/particle-playground.html +0 -0
  76. {dulus-0.2.22 → dulus-0.2.24}/dulus.egg-info/SOURCES.txt +0 -0
  77. {dulus-0.2.22 → dulus-0.2.24}/dulus.egg-info/dependency_links.txt +0 -0
  78. {dulus-0.2.22 → dulus-0.2.24}/dulus.egg-info/entry_points.txt +0 -0
  79. {dulus-0.2.22 → dulus-0.2.24}/dulus.egg-info/requires.txt +0 -0
  80. {dulus-0.2.22 → dulus-0.2.24}/dulus.egg-info/top_level.txt +0 -0
  81. {dulus-0.2.22 → dulus-0.2.24}/dulus_gui.py +0 -0
  82. {dulus-0.2.22 → dulus-0.2.24}/dulus_mcp/__init__.py +0 -0
  83. {dulus-0.2.22 → dulus-0.2.24}/dulus_mcp/client.py +0 -0
  84. {dulus-0.2.22 → dulus-0.2.24}/dulus_mcp/config.py +0 -0
  85. {dulus-0.2.22 → dulus-0.2.24}/dulus_mcp/tools.py +0 -0
  86. {dulus-0.2.22 → dulus-0.2.24}/dulus_mcp/types.py +0 -0
  87. {dulus-0.2.22 → dulus-0.2.24}/gui/__init__.py +0 -0
  88. {dulus-0.2.22 → dulus-0.2.24}/gui/agent_bridge.py +0 -0
  89. {dulus-0.2.22 → dulus-0.2.24}/gui/chat_widget.py +0 -0
  90. {dulus-0.2.22 → dulus-0.2.24}/gui/main_window.py +0 -0
  91. {dulus-0.2.22 → dulus-0.2.24}/gui/personas.py +0 -0
  92. {dulus-0.2.22 → dulus-0.2.24}/gui/session_utils.py +0 -0
  93. {dulus-0.2.22 → dulus-0.2.24}/gui/settings_dialog.py +0 -0
  94. {dulus-0.2.22 → dulus-0.2.24}/gui/sidebar.py +0 -0
  95. {dulus-0.2.22 → dulus-0.2.24}/gui/tasks_view.py +0 -0
  96. {dulus-0.2.22 → dulus-0.2.24}/gui/themes.py +0 -0
  97. {dulus-0.2.22 → dulus-0.2.24}/gui/tool_panel.py +0 -0
  98. {dulus-0.2.22 → dulus-0.2.24}/input.py +0 -0
  99. {dulus-0.2.22 → dulus-0.2.24}/license_manager.py +0 -0
  100. {dulus-0.2.22 → dulus-0.2.24}/memory/__init__.py +0 -0
  101. {dulus-0.2.22 → dulus-0.2.24}/memory/audit.py +0 -0
  102. {dulus-0.2.22 → dulus-0.2.24}/memory/consolidator.py +0 -0
  103. {dulus-0.2.22 → dulus-0.2.24}/memory/context.py +0 -0
  104. {dulus-0.2.22 → dulus-0.2.24}/memory/offload.py +0 -0
  105. {dulus-0.2.22 → dulus-0.2.24}/memory/palace.py +0 -0
  106. {dulus-0.2.22 → dulus-0.2.24}/memory/scan.py +0 -0
  107. {dulus-0.2.22 → dulus-0.2.24}/memory/sessions.py +0 -0
  108. {dulus-0.2.22 → dulus-0.2.24}/memory/store.py +0 -0
  109. {dulus-0.2.22 → dulus-0.2.24}/memory/tools.py +0 -0
  110. {dulus-0.2.22 → dulus-0.2.24}/memory/types.py +0 -0
  111. {dulus-0.2.22 → dulus-0.2.24}/memory/vector_search.py +0 -0
  112. {dulus-0.2.22 → dulus-0.2.24}/multi_agent/__init__.py +0 -0
  113. {dulus-0.2.22 → dulus-0.2.24}/multi_agent/subagent.py +0 -0
  114. {dulus-0.2.22 → dulus-0.2.24}/multi_agent/tools.py +0 -0
  115. {dulus-0.2.22 → dulus-0.2.24}/offload_helper.py +0 -0
  116. {dulus-0.2.22 → dulus-0.2.24}/plugin/__init__.py +0 -0
  117. {dulus-0.2.22 → dulus-0.2.24}/plugin/loader.py +0 -0
  118. {dulus-0.2.22 → dulus-0.2.24}/plugin/recommend.py +0 -0
  119. {dulus-0.2.22 → dulus-0.2.24}/plugin/store.py +0 -0
  120. {dulus-0.2.22 → dulus-0.2.24}/plugin/types.py +0 -0
  121. {dulus-0.2.22 → dulus-0.2.24}/providers.py +0 -0
  122. {dulus-0.2.22 → dulus-0.2.24}/setup.cfg +0 -0
  123. {dulus-0.2.22 → dulus-0.2.24}/skill/__init__.py +0 -0
  124. {dulus-0.2.22 → dulus-0.2.24}/skill/builtin.py +0 -0
  125. {dulus-0.2.22 → dulus-0.2.24}/skill/clawhub.py +0 -0
  126. {dulus-0.2.22 → dulus-0.2.24}/skill/executor.py +0 -0
  127. {dulus-0.2.22 → dulus-0.2.24}/skill/loader.py +0 -0
  128. {dulus-0.2.22 → dulus-0.2.24}/skill/tools.py +0 -0
  129. {dulus-0.2.22 → dulus-0.2.24}/skills.py +0 -0
  130. {dulus-0.2.22 → dulus-0.2.24}/spinner.py +0 -0
  131. {dulus-0.2.22 → dulus-0.2.24}/string_utils.py +0 -0
  132. {dulus-0.2.22 → dulus-0.2.24}/subagent.py +0 -0
  133. {dulus-0.2.22 → dulus-0.2.24}/task/__init__.py +0 -0
  134. {dulus-0.2.22 → dulus-0.2.24}/task/store.py +0 -0
  135. {dulus-0.2.22 → dulus-0.2.24}/task/tools.py +0 -0
  136. {dulus-0.2.22 → dulus-0.2.24}/task/types.py +0 -0
  137. {dulus-0.2.22 → dulus-0.2.24}/tests/test_checkpoint.py +0 -0
  138. {dulus-0.2.22 → dulus-0.2.24}/tests/test_compaction.py +0 -0
  139. {dulus-0.2.22 → dulus-0.2.24}/tests/test_diff_view.py +0 -0
  140. {dulus-0.2.22 → dulus-0.2.24}/tests/test_injection_fix.py +0 -0
  141. {dulus-0.2.22 → dulus-0.2.24}/tests/test_license.py +0 -0
  142. {dulus-0.2.22 → dulus-0.2.24}/tests/test_mcp.py +0 -0
  143. {dulus-0.2.22 → dulus-0.2.24}/tests/test_memory.py +0 -0
  144. {dulus-0.2.22 → dulus-0.2.24}/tests/test_plugin.py +0 -0
  145. {dulus-0.2.22 → dulus-0.2.24}/tests/test_skills.py +0 -0
  146. {dulus-0.2.22 → dulus-0.2.24}/tests/test_subagent.py +0 -0
  147. {dulus-0.2.22 → dulus-0.2.24}/tests/test_task.py +0 -0
  148. {dulus-0.2.22 → dulus-0.2.24}/tests/test_telegram_buffer.py +0 -0
  149. {dulus-0.2.22 → dulus-0.2.24}/tests/test_tool_registry.py +0 -0
  150. {dulus-0.2.22 → dulus-0.2.24}/tests/test_voice.py +0 -0
  151. {dulus-0.2.22 → dulus-0.2.24}/tmux_offloader.py +0 -0
  152. {dulus-0.2.22 → dulus-0.2.24}/tmux_tools.py +0 -0
  153. {dulus-0.2.22 → dulus-0.2.24}/tool_registry.py +0 -0
  154. {dulus-0.2.22 → dulus-0.2.24}/tools.py +0 -0
  155. {dulus-0.2.22 → dulus-0.2.24}/ui/__init__.py +0 -0
  156. {dulus-0.2.22 → dulus-0.2.24}/ui/input.py +0 -0
  157. {dulus-0.2.22 → dulus-0.2.24}/ui/render.py +0 -0
  158. {dulus-0.2.22 → dulus-0.2.24}/voice/__init__.py +0 -0
  159. {dulus-0.2.22 → dulus-0.2.24}/voice/keyterms.py +0 -0
  160. {dulus-0.2.22 → dulus-0.2.24}/voice/recorder.py +0 -0
  161. {dulus-0.2.22 → dulus-0.2.24}/voice/stt.py +0 -0
  162. {dulus-0.2.22 → dulus-0.2.24}/voice/tts.py +0 -0
  163. {dulus-0.2.22 → dulus-0.2.24}/webchat.py +0 -0
  164. {dulus-0.2.22 → dulus-0.2.24}/webchat_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.22
3
+ Version: 0.2.24
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.22-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
72
+ <img src="https://img.shields.io/badge/version-v0.2.24-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"/>
@@ -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.22-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
25
+ <img src="https://img.shields.io/badge/version-v0.2.24-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"/>
@@ -20,6 +20,7 @@ You are Dulus, an AI coding agent. Think in English; reply to KevRojo in Dominic
20
20
  # Autonomy: Background scripts (nohup/&) allowed | Never refuse monitoring/long tasks | Always wait for tool results before replying
21
21
  # Tools: SearchLastOutput → for [TRUNCATED] | WebFetch/WebSearch → web | TmuxOffload → tasks > 5s | ReadJob → background results
22
22
  # SleepTimer: ONLY for user-facing reminders/notifications (e.g. "remind me in 10min"). NEVER use it to wait between your own tool calls — it freezes the console. To pause inside a command sequence, put `sleep N` INSIDE the Bash command itself (e.g. Bash('cmd1 && sleep 2 && cmd2')).
23
+ # Long-running tools: any tool whose `description` ends in `[long-running — wrap in TmuxOffload]` MUST be invoked via TmuxOffload (not directly), so the REPL stays responsive while it runs.
23
24
  # Multi-agent: Agent(subagent_type=...) | isolation="worktree" runs parallel | wait=false + name=... for fire-and-forget
24
25
  # Rules: Edit > Write | Use absolute paths + line numbers | Surface errors immediately, do not retry blindly
25
26
  # Input: "🎙 Transcribed:" prefix = voice input — tolerate typos/misspellings
@@ -3,6 +3,18 @@
3
3
  ## 🔥🔥🔥 News (Pacific Time)
4
4
 
5
5
 
6
+ - May 09, 2026 (**v0.2.24**): **Auto-adapter prompt — 5 fixes from a sherlock postmortem**
7
+ - **Reconciled `limit` default** — the prompt had two contradictory rules ("default: 50, max: 200" vs "default: 10, NOT 50"). Models burned tokens reasoning about which to follow. Unified on `default: 10, hard max: 200` everywhere.
8
+ - **"READ the source first" rule** at the top of the wrapper guidelines. Adapters were inferring upstream function signatures from class names and shipping plugins that compile/import/export cleanly but crash at runtime due to type-shape mismatches. Now the prompt explicitly tells the model to read the consumer code (`param.get(...)` / `for x in param`) before guessing shapes.
9
+ - **Notifier/callback pattern hint** — when the upstream library has a notify/callback class, prefer collecting results via that callback over parsing the return value. Callbacks tend to stay stable; return shapes drift between versions.
10
+ - **`ADAPTATION_GUIDE.md` now requires a `## Type Contracts` section** documenting the exact shape of every non-trivial parameter. Read by the verifier and by future re-adaptations — eliminates blind re-guessing.
11
+ - **Verifier checklist explicitly flags the smoke test as THE BAR.** Compile / import / exports / ToolDef-shape are necessary but not sufficient. The new header in `ADAPTATION_TODO.md` warns the model not to celebrate after the syntactic checks — most real bugs are type-shape mismatches that only the smoke test catches.
12
+
13
+ - May 09, 2026 (**v0.2.23**): **Auto-adapter teaches new plugins to declare TmuxOffload-worthy tools**
14
+ - **The adapter prompt now requires** the model to estimate per-tool runtime. Any tool that typically takes more than ~15 seconds (sherlock, holehe, OSINT crawls, video downloads, full-repo analysis, etc.) must end its `description` with the literal marker `[long-running — wrap in TmuxOffload]`.
15
+ - **System prompt now honors that marker** at runtime. When the agent sees a tool with that suffix, it wraps the call in TmuxOffload automatically instead of blocking the REPL. No more 90-second sherlock freezes pretending to be productive.
16
+ - **Why this matters.** New plugins adopted via `/plugin adapt` now self-declare their UX hints. The agent picks them up the moment they install — zero manual config, zero "oh I should have offloaded that" regrets.
17
+
6
18
  - May 09, 2026 (**v0.2.22**): **`/bg start` — one detached daemon for CLI + Web + Telegram**
7
19
  - **One command, three doors.** `/bg start` spawns a detached Dulus daemon that simultaneously listens on `127.0.0.1:5151` (IPC for `dulus "..."` from any shell), `127.0.0.1:5000` (WebChat in your browser), and the Telegram bridge if configured. All three entry points hit the SAME live session — same history, memory, plugins, tool state.
8
20
  - **`/bg status` / `stop` / `attach`** — small surface, big convenience. `attach` prints how to reach the running daemon (CLI, browser, tail the log).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dulus
3
- Version: 0.2.22
3
+ Version: 0.2.24
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.22-ff6b1f?style=flat-square&labelColor=07070a" alt="version"/>
72
+ <img src="https://img.shields.io/badge/version-v0.2.24-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"/>
@@ -218,7 +218,7 @@ try:
218
218
  from importlib.metadata import version as _pkg_version
219
219
  VERSION = _pkg_version("dulus")
220
220
  except Exception:
221
- VERSION = "0.2.22" # dev fallback — keep in sync with pyproject.toml
221
+ VERSION = "0.2.24" # dev fallback — keep in sync with pyproject.toml
222
222
 
223
223
  # ── ANSI helpers (used even with rich for non-markdown output) ─────────────
224
224
  from common import C, clr, info, ok, warn, err, stream_thinking, print_tool_start, print_tool_end, sanitize_text
@@ -250,6 +250,13 @@ GOAL: Generate `plugin.json`, `plugin_tool.py`, and `ADAPTATION_GUIDE.md`.
250
250
 
251
251
  GUIDELINES FOR plugin_tool.py:
252
252
 
253
+ 0. READ THE SOURCE FIRST (critical — skip and you'll waste 10+ retry rounds):
254
+ - Before writing the wrapper, READ the actual function/class definitions you'll be calling.
255
+ - Note the EXACT shape each parameter expects: raw dict-of-dicts vs object-of-objects vs list of objects.
256
+ - DO NOT infer shapes from class names. Read the consumer code that does `param.get(...)` or `for x in param: ...`.
257
+ - When the upstream library has a notifier/callback/observer class, PREFER collecting results via that callback over parsing the return value — callbacks are usually consistent across versions, return shapes are not.
258
+ - Common gotcha: a class called `XInformation` often *wraps* the raw dict in `.information` or `.data`. The downstream function may expect the raw dict, not the wrapper. Verify by reading the function body.
259
+
253
260
  1. EXPORTS (mandatory):
254
261
  - `TOOL_DEFS`: list of `ToolDef(name, schema, func)` objects
255
262
  - `TOOL_SCHEMAS`: `[t.schema for t in TOOL_DEFS]`
@@ -272,7 +279,7 @@ GUIDELINES FOR plugin_tool.py:
272
279
 
273
280
  4. SCHEMA DESIGN:
274
281
  - Each param gets its own property. Never bundle into single "data" string
275
- - Include `limit`/`max_results` (default: 10, NOT 50) and `verbose` (default: False) on every tool
282
+ - Include `limit`/`max_results` (default: 10, hard max: 200) and `verbose` (default: False) on every tool
276
283
 
277
284
  5. TOOL GRANULARITY:
278
285
  - Multiple specific tools > one mega-tool
@@ -352,9 +359,29 @@ CRITICAL:
352
359
  - plugin.json "dependencies" MUST be a simple LIST of strings
353
360
  - Include "ADAPTATION_GUIDE.md" in plugin.json "skills" list
354
361
 
362
+ TMUX-OFFLOAD HINT (important for UX):
363
+ - For each tool you generate, ESTIMATE its typical runtime.
364
+ - If a tool typically runs > 15 seconds (network scans, sherlock, full holehe sweeps, large file ingestion, OSINT crawls, video downloads, full-repo analysis, etc.), APPEND the literal marker `[long-running — wrap in TmuxOffload]` at the END of the tool's `description` field in the JSON schema.
365
+ - Tools that are fast (< 5s) do NOT need the marker. Don't be over-cautious — only mark tools where users will visibly wait.
366
+ - The marker is read by Dulus's agent at runtime: when it sees a tool description ending in `[long-running — wrap in TmuxOffload]`, it knows to wrap that call in TmuxOffload instead of blocking the REPL.
367
+ - Example: `"description": "Search for a username across hundreds of social networks. [long-running — wrap in TmuxOffload]"`
368
+
355
369
  Respond with the delimited format:
356
370
  ---FILE: ADAPTATION_GUIDE.md---
357
371
  (Overview, tool design decisions, error patterns, validation)
372
+
373
+ The ADAPTATION_GUIDE.md MUST include a `## Type Contracts` section that documents,
374
+ for each upstream function/class you call, the EXACT shape of every non-trivial
375
+ parameter. Example:
376
+
377
+ ## Type Contracts
378
+ - `sherlock(username, site_data, ...)` expects `site_data: Dict[str, Dict[str, Any]]`
379
+ (NOT `Dict[str, SiteInformation]` — extract `.information` from each SiteInformation first).
380
+ - `notifier.update(result)` is called once per site with a `QueryResult` object.
381
+ Collect via a `_SilentNotify(QueryNotify)` subclass instead of parsing the return dict.
382
+
383
+ This section is read by the verifier and by future re-adaptations, so be precise.
384
+
358
385
  ---FILE: plugin.json---
359
386
  (JSON manifest)
360
387
  ---FILE: plugin_tool.py---
@@ -392,7 +419,7 @@ Respond with the delimited format:
392
419
  "- Always encoding='utf-8', errors='replace' for file/subprocess I/O\n"
393
420
  "- Never lowercase true/false/null in Python — always True/False/None\n\n"
394
421
  "TOKEN OPTIMIZATION RULES — plugins MUST be efficient:\n"
395
- "- Every tool MUST accept a 'limit' or 'max_results' parameter (default: 50, max: 200)\n"
422
+ "- Every tool MUST accept a 'limit' or 'max_results' parameter (default: 10, hard max: 200)\n"
396
423
  "- Every tool MUST accept a 'verbose' parameter (default: False)\n"
397
424
  "- When verbose=False, return ONLY essential data — no debug info, no banners\n"
398
425
  "- Lists/arrays MUST be truncated before returning — never return unlimited items\n"
@@ -800,6 +827,14 @@ def _write_todo_file(plugin_dir: Path, safe_name: str, items: list[dict]) -> Pat
800
827
  "Auto-generated checklist verifying the AI-generated plugin works.",
801
828
  "Each task is verified by the adapter worker; failures trigger a fix attempt.",
802
829
  "",
830
+ "⚠ THE BAR IS THE SMOKE TEST. Compile / import / exports / ToolDef-shape",
831
+ "checks are necessary but NOT sufficient — they only prove the file is",
832
+ "syntactically a Python module that exports something callable. They do",
833
+ "NOT prove the wrapper passes the right shapes to upstream functions.",
834
+ "If a smoke test fails after the syntactic checks pass, the bug is almost",
835
+ "always a TYPE-SHAPE mismatch (e.g. passing wrapper objects where the",
836
+ "function expected raw dicts). Re-read the source code before guessing.",
837
+ "",
803
838
  ]
804
839
  for item in items:
805
840
  lines.append(f"- [ ] {item['title']}")
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dulus"
7
- version = "0.2.22"
7
+ version = "0.2.24"
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"
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