tsugite-cli 0.12.2__tar.gz → 0.14.0__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 (436) hide show
  1. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/.github/copilot-instructions.md +3 -5
  2. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/.github/workflows/ci.yml +2 -2
  3. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/.github/workflows/docker-publish.yml +0 -1
  4. tsugite_cli-0.14.0/.github/workflows/pypi-publish.yml +49 -0
  5. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/.gitignore +2 -1
  6. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/AGENTS.md +144 -17
  7. tsugite_cli-0.14.0/CONTRIBUTING.md +54 -0
  8. tsugite_cli-0.14.0/Dockerfile +19 -0
  9. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/PKG-INFO +5 -7
  10. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/README.md +4 -5
  11. tsugite_cli-0.14.0/cliff.toml +44 -0
  12. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/docs/agents.md +70 -2
  13. tsugite_cli-0.14.0/docs/plugin-events.md +131 -0
  14. tsugite_cli-0.14.0/docs/plugin-hooks.md +110 -0
  15. tsugite_cli-0.14.0/docs/plugin-tools.md +109 -0
  16. tsugite_cli-0.14.0/docs/plugins.md +139 -0
  17. tsugite_cli-0.14.0/docs/release_notes/v0.13.0.md +51 -0
  18. tsugite_cli-0.14.0/docs/release_notes/v0.14.0.md +39 -0
  19. tsugite_cli-0.14.0/examples/tsugite-example-plugin/pyproject.toml +17 -0
  20. tsugite_cli-0.14.0/examples/tsugite-example-plugin/tsugite_example_plugin/__init__.py +41 -0
  21. tsugite_cli-0.14.0/plugins/tsugite-tmux/pyproject.toml +16 -0
  22. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0/plugins/tsugite-tmux}/tests/test_tmux_tools.py +43 -62
  23. tsugite_cli-0.12.2/tsugite/tools/tmux.py → tsugite_cli-0.14.0/plugins/tsugite-tmux/tsugite_tmux/__init__.py +11 -25
  24. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/pyproject.toml +10 -3
  25. tsugite_cli-0.14.0/scripts/bump_version.py +90 -0
  26. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/scripts/update_model_registry.py +11 -0
  27. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/README.md +12 -16
  28. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/conftest.py +76 -36
  29. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_agent.py +154 -79
  30. tsugite_cli-0.14.0/tests/core/test_agent_event_loop.py +310 -0
  31. tsugite_cli-0.14.0/tests/core/test_agent_parser_triple_quotes.py +70 -0
  32. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_agent_ui_events.py +91 -27
  33. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_content_blocks.py +12 -12
  34. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_executor.py +133 -25
  35. tsugite_cli-0.14.0/tests/core/test_executor_escape_tripwire.py +35 -0
  36. tsugite_cli-0.14.0/tests/core/test_state.py +85 -0
  37. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_subprocess_executor.py +40 -11
  38. tsugite_cli-0.14.0/tests/daemon/test_chat_reentrancy.py +399 -0
  39. tsugite_cli-0.14.0/tests/daemon/test_collect_events.py +106 -0
  40. tsugite_cli-0.14.0/tests/daemon/test_compaction_command.py +247 -0
  41. tsugite_cli-0.14.0/tests/daemon/test_event_broadcast_scope.py +64 -0
  42. tsugite_cli-0.14.0/tests/daemon/test_final_answer_delivery.py +75 -0
  43. tsugite_cli-0.14.0/tests/daemon/test_http_adapter.py +797 -0
  44. tsugite_cli-0.14.0/tests/daemon/test_message_context_session_started.py +152 -0
  45. tsugite_cli-0.14.0/tests/daemon/test_message_context_topic.py +207 -0
  46. tsugite_cli-0.14.0/tests/daemon/test_prompt_too_long_retry.py +239 -0
  47. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/daemon/test_session_metadata_api.py +28 -0
  48. tsugite_cli-0.14.0/tests/daemon/test_session_pinning_api.py +284 -0
  49. tsugite_cli-0.14.0/tests/daemon/test_session_primary_api.py +151 -0
  50. tsugite_cli-0.14.0/tests/daemon/test_session_store_named_route.py +91 -0
  51. tsugite_cli-0.14.0/tests/daemon/test_session_store_pinning.py +194 -0
  52. tsugite_cli-0.14.0/tests/daemon/test_session_store_primary.py +182 -0
  53. tsugite_cli-0.14.0/tests/daemon/test_skill_trigger_loading.py +154 -0
  54. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_history_code_rendering.py +103 -7
  55. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_markdown_rendering.py +6 -25
  56. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_message_actions.py +26 -33
  57. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_scroll_behavior.py +6 -12
  58. tsugite_cli-0.14.0/tests/events/test_filtered_subscriptions.py +261 -0
  59. tsugite_cli-0.14.0/tests/integration/test_concurrent_workspace_cwd.py +88 -0
  60. tsugite_cli-0.14.0/tests/integration/test_exec_directive_e2e.py +37 -0
  61. tsugite_cli-0.14.0/tests/integration/test_nested_session_spawn.py +103 -0
  62. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/smoke_test.sh +3 -3
  63. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_agent_inheritance.py +54 -20
  64. tsugite_cli-0.14.0/tests/test_agent_preparation.py +107 -0
  65. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_agent_sessions.py +198 -0
  66. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_agent_skills.py +10 -30
  67. tsugite_cli-0.14.0/tests/test_anthropic_extended_thinking.py +198 -0
  68. tsugite_cli-0.14.0/tests/test_attachments.py +1074 -0
  69. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_background_tasks.py +193 -0
  70. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_builtin_agent_paths.py +1 -1
  71. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_builtin_agents.py +1 -1
  72. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_claude_code_attachments.py +20 -0
  73. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_claude_code_provider.py +340 -3
  74. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_cli.py +47 -6
  75. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_cli_rendering.py +3 -4
  76. tsugite_cli-0.14.0/tests/test_cli_skills.py +85 -0
  77. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_cli_subcommands.py +0 -30
  78. tsugite_cli-0.14.0/tests/test_compaction_context_preservation.py +233 -0
  79. tsugite_cli-0.14.0/tests/test_compaction_event.py +160 -0
  80. tsugite_cli-0.14.0/tests/test_compaction_progress.py +162 -0
  81. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_daemon_unified_sessions.py +89 -24
  82. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_discord_progress.py +206 -4
  83. tsugite_cli-0.14.0/tests/test_event_storage.py +153 -0
  84. tsugite_cli-0.14.0/tests/test_events_to_messages.py +217 -0
  85. tsugite_cli-0.14.0/tests/test_exceptions.py +17 -0
  86. tsugite_cli-0.14.0/tests/test_exec_directives.py +309 -0
  87. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_file_tools.py +155 -9
  88. tsugite_cli-0.14.0/tests/test_fs_tool_workspace.py +89 -0
  89. tsugite_cli-0.14.0/tests/test_handle_message_flush.py +216 -0
  90. tsugite_cli-0.14.0/tests/test_history_migrate.py +274 -0
  91. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_hooks.py +89 -0
  92. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_http_tools.py +62 -16
  93. tsugite_cli-0.14.0/tests/test_interaction_backend_isolation.py +186 -0
  94. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_interactive_context.py +0 -1
  95. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_jsonl_ui.py +41 -0
  96. tsugite_cli-0.14.0/tests/test_live_event_recording.py +130 -0
  97. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_md_agents_json.py +1 -3
  98. tsugite_cli-0.14.0/tests/test_memory_sanitize.py +288 -0
  99. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_model_registry.py +11 -0
  100. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_multistep_agents.py +102 -0
  101. tsugite_cli-0.14.0/tests/test_multistep_retry_side_effects.py +108 -0
  102. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_plugins.py +169 -1
  103. tsugite_cli-0.14.0/tests/test_post_compaction_counters.py +255 -0
  104. tsugite_cli-0.14.0/tests/test_provider_turn_heartbeat.py +142 -0
  105. tsugite_cli-0.14.0/tests/test_reasoning_models.py +127 -0
  106. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_renderer.py +88 -1
  107. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_rendering_scenarios.py +103 -0
  108. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_schedule_model_override.py +39 -0
  109. tsugite_cli-0.14.0/tests/test_scheduler_history_injection.py +363 -0
  110. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_schema.py +4 -3
  111. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_secrets.py +37 -0
  112. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_security_phase1.py +50 -0
  113. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_session_metadata.py +34 -0
  114. tsugite_cli-0.14.0/tests/test_session_progress_cache.py +139 -0
  115. tsugite_cli-0.14.0/tests/test_shell_tool_cwd.py +82 -0
  116. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_skill_discovery.py +172 -4
  117. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_skill_tools.py +103 -0
  118. tsugite_cli-0.14.0/tests/test_step_render_framework_flags.py +108 -0
  119. tsugite_cli-0.14.0/tests/test_time_tool.py +47 -0
  120. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_tool_registry.py +13 -0
  121. tsugite_cli-0.14.0/tests/test_unified_event_log.py +185 -0
  122. tsugite_cli-0.14.0/tests/test_user_agent.py +99 -0
  123. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/__init__.py +6 -1
  124. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_inheritance.py +16 -20
  125. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_preparation.py +382 -62
  126. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_runner/__init__.py +5 -0
  127. tsugite_cli-0.14.0/tsugite/agent_runner/exec_directives.py +124 -0
  128. tsugite_cli-0.14.0/tsugite/agent_runner/exec_runner.py +222 -0
  129. tsugite_cli-0.14.0/tsugite/agent_runner/history_integration.py +245 -0
  130. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_runner/models.py +1 -0
  131. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_runner/runner.py +226 -80
  132. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/base.py +16 -1
  133. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/url.py +6 -5
  134. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_agents/default.md +48 -20
  135. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_agents/file_searcher.md +1 -1
  136. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_agents/onboard.md +1 -1
  137. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/tsugite-agent-basics/SKILL.md +22 -6
  138. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/__init__.py +2 -4
  139. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/daemon.py +66 -0
  140. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/helpers.py +28 -2
  141. tsugite_cli-0.14.0/tsugite/cli/history.py +715 -0
  142. tsugite_cli-0.14.0/tsugite/cli/plugins.py +237 -0
  143. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/render.py +12 -4
  144. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/run.py +43 -21
  145. tsugite_cli-0.14.0/tsugite/cli/skills.py +77 -0
  146. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/config.py +1 -1
  147. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/agent.py +453 -366
  148. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/claude_code.py +28 -3
  149. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/executor.py +162 -94
  150. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/memory.py +3 -0
  151. tsugite_cli-0.14.0/tsugite/core/state.py +76 -0
  152. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/subprocess_executor.py +142 -110
  153. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/tools.py +0 -1
  154. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/adapters/base.py +421 -185
  155. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/adapters/discord.py +170 -58
  156. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/adapters/http.py +501 -285
  157. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/adapters/scheduler_adapter.py +99 -33
  158. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/commands.py +7 -5
  159. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/compaction_scheduler.py +10 -2
  160. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/config.py +5 -0
  161. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/gateway.py +9 -2
  162. tsugite_cli-0.14.0/tsugite/daemon/memory.py +507 -0
  163. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/scheduler.py +21 -0
  164. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/session_runner.py +44 -1
  165. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/session_store.py +524 -41
  166. tsugite_cli-0.14.0/tsugite/daemon/web/css/console.css +1720 -0
  167. tsugite_cli-0.14.0/tsugite/daemon/web/css/responsive.css +111 -0
  168. tsugite_cli-0.14.0/tsugite/daemon/web/css/styles.css +239 -0
  169. tsugite_cli-0.14.0/tsugite/daemon/web/css/theme.css +61 -0
  170. tsugite_cli-0.14.0/tsugite/daemon/web/index.html +1772 -0
  171. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/api.js +10 -2
  172. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/app.js +81 -0
  173. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/utils.js +20 -0
  174. tsugite_cli-0.14.0/tsugite/daemon/web/js/views/conversation/event_types.js +71 -0
  175. tsugite_cli-0.14.0/tsugite/daemon/web/js/views/conversation/history.js +425 -0
  176. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/conversation/input.js +1 -1
  177. tsugite_cli-0.14.0/tsugite/daemon/web/js/views/conversation/sessions.js +476 -0
  178. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/conversation/streaming.js +120 -47
  179. tsugite_cli-0.14.0/tsugite/daemon/web/js/views/conversations.js +687 -0
  180. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/file-editor.js +3 -0
  181. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/usage.js +2 -0
  182. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/manifest.json +1 -1
  183. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/events/__init__.py +5 -0
  184. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/events/base.py +14 -0
  185. tsugite_cli-0.14.0/tsugite/events/bus.py +114 -0
  186. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/events/events.py +40 -1
  187. tsugite_cli-0.14.0/tsugite/exceptions.py +66 -0
  188. tsugite_cli-0.14.0/tsugite/history/__init__.py +24 -0
  189. tsugite_cli-0.14.0/tsugite/history/models.py +46 -0
  190. tsugite_cli-0.14.0/tsugite/history/reconstruction.py +173 -0
  191. tsugite_cli-0.14.0/tsugite/history/storage.py +224 -0
  192. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/hooks.py +55 -1
  193. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/md_agents.py +173 -9
  194. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/models.py +59 -6
  195. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/options.py +1 -3
  196. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/plugins.py +91 -37
  197. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/anthropic.py +39 -14
  198. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/base.py +2 -0
  199. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/claude_code.py +37 -7
  200. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/model_registry.py +5 -0
  201. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/openai_compat.py +12 -8
  202. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/renderer.py +138 -21
  203. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/schemas/__init__.py +6 -3
  204. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/schemas/agent.schema.json +80 -24
  205. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/registry.py +21 -0
  206. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/skill_discovery.py +92 -24
  207. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/__init__.py +22 -8
  208. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/agents.py +27 -17
  209. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/fs.py +139 -27
  210. tsugite_cli-0.14.0/tsugite/tools/history.py +240 -0
  211. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/http.py +25 -16
  212. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/interactive.py +8 -10
  213. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/schedule.py +22 -0
  214. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/secrets.py +10 -0
  215. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/shell.py +11 -2
  216. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/skills.py +64 -2
  217. tsugite_cli-0.14.0/tsugite/tools/time.py +16 -0
  218. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/jsonl.py +23 -2
  219. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/repl_commands.py +23 -21
  220. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/user_agent.py +28 -3
  221. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/utils.py +32 -1
  222. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/workspace/models.py +10 -0
  223. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/workspace/session.py +9 -9
  224. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/uv.lock +666 -882
  225. tsugite_cli-0.12.2/.github/workflows/pypi-publish.yml +0 -37
  226. tsugite_cli-0.12.2/docs/plugin-hooks.md +0 -64
  227. tsugite_cli-0.12.2/tests/daemon/test_http_adapter.py +0 -534
  228. tsugite_cli-0.12.2/tests/test_attachments.py +0 -448
  229. tsugite_cli-0.12.2/tests/test_cache_control.py +0 -181
  230. tsugite_cli-0.12.2/tests/test_continuation.py +0 -453
  231. tsugite_cli-0.12.2/tests/test_daemon_history_persistence.py +0 -514
  232. tsugite_cli-0.12.2/tests/test_daemon_memory.py +0 -481
  233. tsugite_cli-0.12.2/tests/test_daemon_session_isolation.py +0 -265
  234. tsugite_cli-0.12.2/tests/test_history.py +0 -414
  235. tsugite_cli-0.12.2/tests/test_history_integration.py +0 -715
  236. tsugite_cli-0.12.2/tests/test_history_models.py +0 -517
  237. tsugite_cli-0.12.2/tests/test_history_performance.py +0 -202
  238. tsugite_cli-0.12.2/tests/test_history_tools.py +0 -286
  239. tsugite_cli-0.12.2/tests/test_mcp_client.py +0 -378
  240. tsugite_cli-0.12.2/tests/test_mcp_server.py +0 -109
  241. tsugite_cli-0.12.2/tests/test_reasoning_models.py +0 -62
  242. tsugite_cli-0.12.2/tests/test_scheduler_history_injection.py +0 -172
  243. tsugite_cli-0.12.2/tsugite/agent_runner/history_integration.py +0 -306
  244. tsugite_cli-0.12.2/tsugite/cli/history.py +0 -413
  245. tsugite_cli-0.12.2/tsugite/cli/mcp.py +0 -193
  246. tsugite_cli-0.12.2/tsugite/cli/plugins.py +0 -77
  247. tsugite_cli-0.12.2/tsugite/cli/serve.py +0 -41
  248. tsugite_cli-0.12.2/tsugite/daemon/memory.py +0 -333
  249. tsugite_cli-0.12.2/tsugite/daemon/web/css/responsive.css +0 -191
  250. tsugite_cli-0.12.2/tsugite/daemon/web/css/styles.css +0 -387
  251. tsugite_cli-0.12.2/tsugite/daemon/web/css/theme.css +0 -47
  252. tsugite_cli-0.12.2/tsugite/daemon/web/index.html +0 -1344
  253. tsugite_cli-0.12.2/tsugite/daemon/web/js/views/conversation/history.js +0 -184
  254. tsugite_cli-0.12.2/tsugite/daemon/web/js/views/conversation/sessions.js +0 -207
  255. tsugite_cli-0.12.2/tsugite/daemon/web/js/views/conversations.js +0 -345
  256. tsugite_cli-0.12.2/tsugite/events/bus.py +0 -62
  257. tsugite_cli-0.12.2/tsugite/exceptions.py +0 -33
  258. tsugite_cli-0.12.2/tsugite/history/__init__.py +0 -54
  259. tsugite_cli-0.12.2/tsugite/history/models.py +0 -147
  260. tsugite_cli-0.12.2/tsugite/history/reconstruction.py +0 -348
  261. tsugite_cli-0.12.2/tsugite/history/storage.py +0 -619
  262. tsugite_cli-0.12.2/tsugite/mcp_client.py +0 -221
  263. tsugite_cli-0.12.2/tsugite/mcp_config.py +0 -174
  264. tsugite_cli-0.12.2/tsugite/mcp_server.py +0 -144
  265. tsugite_cli-0.12.2/tsugite/tools/history.py +0 -190
  266. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/CLAUDE.md +0 -0
  267. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/LICENSE +0 -0
  268. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/docs/secrets.md +0 -0
  269. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/docs/test_agents/prefresh_readme.md +0 -0
  270. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/docs/test_agents/template_test.md +0 -0
  271. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/docs/test_agents/test_agent.md +0 -0
  272. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/docs/test_agents/test_steps.md +0 -0
  273. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/mise.toml +0 -0
  274. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/scripts/backfill_usage.py +0 -0
  275. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/scripts/regenerate_schema.py +0 -0
  276. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/__init__.py +0 -0
  277. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/__init__.py +0 -0
  278. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_agent_context_tokens.py +0 -0
  279. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_memory.py +0 -0
  280. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_proxy.py +0 -0
  281. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_sandbox.py +0 -0
  282. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/core/test_tools.py +0 -0
  283. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/daemon/__init__.py +0 -0
  284. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/__init__.py +0 -0
  285. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/conftest.py +0 -0
  286. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_auth.py +0 -0
  287. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_chat.py +0 -0
  288. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_context_bar.py +0 -0
  289. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_draft_persistence.py +0 -0
  290. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_history.py +0 -0
  291. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_page_load.py +0 -0
  292. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_prompt_inspector.py +0 -0
  293. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_sessions.py +0 -0
  294. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_sidebar_redesign.py +0 -0
  295. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/e2e/test_sse_metadata.py +0 -0
  296. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/events/test_event_consolidation.py +0 -0
  297. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_agent_file_hot_loading.py +0 -0
  298. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_agent_parser.py +0 -0
  299. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_agent_utils.py +0 -0
  300. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_agents_tool.py +0 -0
  301. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_attachment_deduplication.py +0 -0
  302. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_auto_context_handler.py +0 -0
  303. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_auto_discovery.py +0 -0
  304. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_background_task_status.py +0 -0
  305. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_chat_cli.py +0 -0
  306. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_chat_error_handling.py +0 -0
  307. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_cli_arguments.py +0 -0
  308. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_completion_callbacks.py +0 -0
  309. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_config.py +0 -0
  310. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_custom_shell_tools.py +0 -0
  311. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_custom_ui.py +0 -0
  312. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_daemon_auth.py +0 -0
  313. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_daemon_compaction_scheduler.py +0 -0
  314. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_daemon_config.py +0 -0
  315. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_daemon_push.py +0 -0
  316. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_daemon_scheduler.py +0 -0
  317. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_error_display.py +0 -0
  318. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_file_references.py +0 -0
  319. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_interaction_backends.py +0 -0
  320. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_interactive_tool.py +0 -0
  321. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_list_agents_tool.py +0 -0
  322. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_models.py +0 -0
  323. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_multi_agent.py +0 -0
  324. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_orchestrator_heartbeat.py +0 -0
  325. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_prompt_snapshot.py +0 -0
  326. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_provider_registry.py +0 -0
  327. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_repl_commands.py +0 -0
  328. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_repl_completer.py +0 -0
  329. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_repl_handler.py +0 -0
  330. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_retry_system.py +0 -0
  331. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_run_if.py +0 -0
  332. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_secret_access_event.py +0 -0
  333. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_send_message.py +0 -0
  334. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_session_orchestrator_tools.py +0 -0
  335. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_stdin.py +0 -0
  336. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_subagent_subprocess.py +0 -0
  337. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_tool_directives.py +0 -0
  338. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_workspace_auto_continue.py +0 -0
  339. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_workspace_cwd.py +0 -0
  340. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tests/test_workspace_discovery.py +0 -0
  341. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_runner/helpers.py +0 -0
  342. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_runner/metrics.py +0 -0
  343. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_runner/validation.py +0 -0
  344. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/agent_utils.py +0 -0
  345. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/__init__.py +0 -0
  346. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/auto_context.py +0 -0
  347. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/file.py +0 -0
  348. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/inline.py +0 -0
  349. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/storage.py +0 -0
  350. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/attachments/youtube.py +0 -0
  351. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_agents/.gitkeep +0 -0
  352. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_agents/code_searcher.md +0 -0
  353. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/.gitkeep +0 -0
  354. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/codebase-exploration/SKILL.md +0 -0
  355. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/python-math/SKILL.md +0 -0
  356. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/response-patterns/SKILL.md +0 -0
  357. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/scheduling/SKILL.md +0 -0
  358. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/skill-authoring/SKILL.md +0 -0
  359. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/tsugite-jinja-reference/SKILL.md +0 -0
  360. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/builtin_skills/tsugite-skill-basics/SKILL.md +0 -0
  361. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cache.py +0 -0
  362. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/agents.py +0 -0
  363. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/attachments.py +0 -0
  364. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/cache.py +0 -0
  365. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/chat.py +0 -0
  366. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/config.py +0 -0
  367. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/init.py +0 -0
  368. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/models.py +0 -0
  369. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/secrets.py +0 -0
  370. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/tools.py +0 -0
  371. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/usage.py +0 -0
  372. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/validate.py +0 -0
  373. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/cli/workspace.py +0 -0
  374. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/console.py +0 -0
  375. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/constants.py +0 -0
  376. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/__init__.py +0 -0
  377. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/content_blocks.py +0 -0
  378. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/proxy.py +0 -0
  379. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/core/sandbox.py +0 -0
  380. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/__init__.py +0 -0
  381. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/adapters/__init__.py +0 -0
  382. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/auth.py +0 -0
  383. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/push.py +0 -0
  384. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/icons/icon-192.png +0 -0
  385. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/icons/icon-512-maskable.png +0 -0
  386. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/icons/icon-512.png +0 -0
  387. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/icons/screenshot-narrow.png +0 -0
  388. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/icons/screenshot-wide.png +0 -0
  389. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/vendor/marked.LICENSE.md +0 -0
  390. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/vendor/marked.esm.min.js +0 -0
  391. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/conversation/attachments.js +0 -0
  392. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/schedules.js +0 -0
  393. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/webhooks.js +0 -0
  394. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/js/views/workspace.js +0 -0
  395. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/web/sw.js +0 -0
  396. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/daemon/webhook_store.py +0 -0
  397. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/events/helpers.py +0 -0
  398. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/interaction.py +0 -0
  399. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/__init__.py +0 -0
  400. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/model_cache.py +0 -0
  401. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/ollama.py +0 -0
  402. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/providers/openrouter.py +0 -0
  403. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/__init__.py +0 -0
  404. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/backend.py +0 -0
  405. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/env.py +0 -0
  406. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/exec.py +0 -0
  407. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/file.py +0 -0
  408. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/masking.py +0 -0
  409. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/secrets/sqlite.py +0 -0
  410. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/shell_tool_config.py +0 -0
  411. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/templates/AGENTS.md +0 -0
  412. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/templates/IDENTITY.md +0 -0
  413. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/templates/MEMORY.md +0 -0
  414. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/templates/USER.md +0 -0
  415. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/templates/personas/casual-technical.md +0 -0
  416. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/templates/personas/marvin.md +0 -0
  417. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/templates/personas/minimal.md +0 -0
  418. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/notify.py +0 -0
  419. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/scratchpad.py +0 -0
  420. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/sessions.py +0 -0
  421. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tools/shell_tools.py +0 -0
  422. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/tsugite.py +0 -0
  423. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/__init__.py +0 -0
  424. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/base.py +0 -0
  425. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/chat.py +0 -0
  426. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/helpers.py +0 -0
  427. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/plain.py +0 -0
  428. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/repl_chat.py +0 -0
  429. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/repl_completer.py +0 -0
  430. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui/repl_handler.py +0 -0
  431. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/ui_context.py +0 -0
  432. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/usage/__init__.py +0 -0
  433. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/usage/store.py +0 -0
  434. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/workspace/__init__.py +0 -0
  435. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/workspace/context.py +0 -0
  436. {tsugite_cli-0.12.2 → tsugite_cli-0.14.0}/tsugite/workspace/templates.py +0 -0
@@ -4,16 +4,16 @@ Tsugite is a micro-agent CLI: agents are Markdown + YAML frontmatter, rendered v
4
4
 
5
5
  ### Architecture
6
6
 
7
- **Flow:** `Agent.md` (YAML + Jinja2) → `renderer.py` → `TsugiteAgent` → LiteLLM → Tools
7
+ **Flow:** `Agent.md` (YAML + Jinja2) → `renderer.py` → `TsugiteAgent` → Provider → Tools
8
8
 
9
9
  **Key Modules:**
10
- - `cli/__init__.py` - Typer CLI (run, chat, render, config, mcp, tools, agents, attachments, cache)
10
+ - `cli/__init__.py` - Typer CLI (run, chat, render, config, tools, agents, attachments, cache)
11
11
  - `md_agents.py` - Parse frontmatter + agent resolution + directives
12
12
  - `builtin_agents/` - File-based built-in agent definitions (default.md, chat-assistant.md)
13
13
  - `agent_inheritance.py` - Agent resolution pipeline + inheritance chain
14
14
  - `chat.py` - Chat session management with history
15
15
  - `agent_runner.py` - Execution orchestration, prefetch, tool wiring, multi-step
16
- - `core/agent.py` - LiteLLM agent loop + streaming
16
+ - `core/agent.py` - agent loop + streaming
17
17
  - `renderer.py` - Jinja2 rendering + helpers (now, today, slugify, env, file_exists, read_text, is_file, is_dir)
18
18
  - `tools/` - Tool registry + implementations
19
19
  - `shell_tool_config.py` + `tools/shell_tools.py` - Custom shell command wrappers
@@ -62,7 +62,6 @@ File-based agents distributed with the package in `tsugite/builtin_agents/` dire
62
62
  **Merge rules:**
63
63
  - Scalars (model, max_steps): Child overwrites
64
64
  - Lists (tools): Merge + deduplicate
65
- - Dicts (mcp_servers): Merge, child keys override
66
65
  - Strings (instructions): Concatenate with `\n\n`
67
66
 
68
67
  **Opt-out:** `extends: none` skips all inheritance.
@@ -236,7 +235,6 @@ assert tool is not None
236
235
 
237
236
  **Safety:**
238
237
  - Shell tool guard: Never relax dangerous patterns blocklist
239
- - MCP: Requires `--trust-mcp-code` flag
240
238
  - File ops: Use `Path.resolve()` to prevent traversal
241
239
 
242
240
  **Testing:** Test-first workflow. Add minimal failing test, run target, widen to full suite before merge.
@@ -28,7 +28,7 @@ jobs:
28
28
  enable-cache: true
29
29
 
30
30
  - name: Install dependencies
31
- run: uv sync --dev
31
+ run: uv sync --dev --all-extras
32
32
 
33
33
  - name: Run ruff check
34
34
  run: uv run ruff check --show-fixes .
@@ -58,7 +58,7 @@ jobs:
58
58
  enable-cache: true
59
59
 
60
60
  - name: Install dependencies
61
- run: uv sync --dev
61
+ run: uv sync --dev --all-extras
62
62
 
63
63
  - name: Run tests
64
64
  run: uv run pytest -v
@@ -52,7 +52,6 @@ jobs:
52
52
  uses: docker/build-push-action@v5
53
53
  with:
54
54
  context: .
55
- file: ./Dockerfile.runtime
56
55
  platforms: linux/amd64,linux/arm64
57
56
  push: true
58
57
  tags: ${{ steps.meta.outputs.tags }}
@@ -0,0 +1,49 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ build-and-publish:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write # Required for creating GitHub releases
14
+ id-token: write # Required for PyPI trusted publishing
15
+
16
+ steps:
17
+ - name: Checkout repository
18
+ uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0 # Full history so auto-generated release notes can diff
21
+
22
+ - name: Set up Python
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: "3.12"
26
+
27
+ - name: Install uv
28
+ uses: astral-sh/setup-uv@v5
29
+
30
+ - name: Build all workspace packages
31
+ run: uv build --all-packages
32
+
33
+ - name: Publish to PyPI
34
+ # Trusted publishing: each package (tsugite-cli, tsugite-tmux, ...) must be
35
+ # registered separately on PyPI as a trusted publisher pointing at this workflow.
36
+ uses: pypa/gh-action-pypi-publish@release/v1
37
+
38
+ - name: Generate release notes from conventional commits
39
+ id: changelog
40
+ uses: orhun/git-cliff-action@v4
41
+ with:
42
+ config: cliff.toml
43
+ args: --latest --strip header
44
+
45
+ - name: Create GitHub release
46
+ uses: softprops/action-gh-release@v2
47
+ with:
48
+ body: ${{ steps.changelog.outputs.content }}
49
+ files: dist/*
@@ -173,7 +173,8 @@ secrets/*
173
173
 
174
174
  # TODO: temp - I need to clean up the docs
175
175
  docs-old/
176
- examples/
176
+ examples/*
177
+ !examples/tsugite-example-plugin/
177
178
  agents/
178
179
  .claude/
179
180
  .tsugite/
@@ -2,12 +2,14 @@
2
2
 
3
3
  This file provides guidance to AI agents (tsugite, Claude Code, etc.) when working with code in this repository.
4
4
 
5
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for commit message conventions and PR guidelines.
6
+
5
7
  ## Commands
6
8
 
7
9
  ### Development Setup
8
10
  ```bash
9
- # Install dependencies
10
- uv sync --dev
11
+ # Install dependencies (core + daemon extras + core plugins)
12
+ uv sync --all-extras
11
13
 
12
14
  # Run all tests
13
15
  uv run pytest
@@ -54,7 +56,7 @@ Tsugite is an agentic CLI that executes AI agents defined as markdown files with
54
56
  1. **CLI Entry** (`tsugite/cli/__init__.py`)
55
57
  - Typer-based CLI with subcommands
56
58
  - Main commands: `run` (single-shot), `chat` (interactive), `render` (preview)
57
- - Additional: `daemon`, `workspace`, `init`, `validate`, `mcp`, `serve`, `agents`, `config`, `attachments`, `cache`, `tools`, `history`
59
+ - Additional: `daemon`, `workspace`, `init`, `validate`, `agents`, `config`, `attachments`, `cache`, `tools`, `history`
58
60
 
59
61
  2. **Agent Resolution & Inheritance** (`tsugite/agent_inheritance.py`)
60
62
  - Resolves agent names to file paths using search order:
@@ -73,6 +75,7 @@ Tsugite is an agentic CLI that executes AI agents defined as markdown files with
73
75
  - `<!-- tsu:step -->` - Multi-step workflow stages
74
76
  - `<!-- tsu:ignore -->` - Documentation blocks (stripped before LLM)
75
77
  - `<!-- tsu:tool -->` - Execute tools during rendering
78
+ - `<!-- tsu:exec --> ... <!-- /tsu:exec -->` - Run arbitrary Python at render time, capture result into Jinja context
76
79
 
77
80
  4. **Agent Preparation** (`tsugite/agent_preparation.py`)
78
81
  - **Unified preparation pipeline** (used by both `run` and `render` commands)
@@ -102,22 +105,20 @@ Tsugite is an agentic CLI that executes AI agents defined as markdown files with
102
105
  - Integrates with history system for conversation continuity
103
106
 
104
107
  7. **LLM Agent Loop** (`tsugite/core/agent.py`)
105
- - `TsugiteAgent` - Custom agent using LiteLLM directly
108
+ - `TsugiteAgent` - Custom agent using tsugite's provider abstraction
106
109
  - Think-Code-Observation loop (max_turns iterations)
107
110
  - Supports reasoning models (o1, o3, Claude extended thinking)
108
111
  - Direct control over model parameters (temperature, reasoning_effort)
109
112
  - Code execution via `LocalExecutor`
110
113
 
111
114
  8. **Tool System** (`tsugite/tools/`)
112
- - Tool registry with built-in tools (fs, http, shell, tasks, agents, memory, skills, history, interactive)
113
- - Category system: `@fs`, `@http`, `@shell`, `@tasks`, `@agents`, `@memory`, `@skills`, `@history`, `@interactive`
114
- - Custom shell tools (config-based command wrappers)
115
- - MCP integration (`tsugite/mcp_client.py`)
116
- - Tool expansion supports globs (`*_search`) and exclusions (`-delete_file`)
115
+ - Tool registry with built-in tools (fs, http, shell, agents, skills, history, interactive) plus optional categories (notify, schedule, scratchpad, sessions, secrets, tmux — gated by `_OPTIONAL_CATEGORIES` in `tools/__init__.py`)
116
+ - Custom shell tools (config-based command wrappers in `tools/shell_tools.py`)
117
+ - Tool expansion supports globs (`*_search`), categories (`@fs`), and exclusions (`-delete_file`)
117
118
 
118
119
  9. **Event System** (`tsugite/events/`)
119
120
  - Event-driven architecture for UI decoupling
120
- - 20 event types: execution, LLM, meta, progress, skills
121
+ - 28 event types: execution, LLM, meta, progress, skills
121
122
  - `EventBus` dispatches to multiple handlers
122
123
  - Handlers: Rich console, plain text, JSONL, chat, REPL
123
124
 
@@ -131,17 +132,16 @@ Tsugite is an agentic CLI that executes AI agents defined as markdown files with
131
132
  - XDG-compliant paths: `~/.config/tsugite/` or `$XDG_CONFIG_HOME/tsugite/`
132
133
  - JSON config with model aliases, default settings
133
134
  - Attachment storage (reusable context)
134
- - MCP server registration
135
135
  - Auto-context discovery (CLAUDE.md, AGENTS.md, CONTEXT.md)
136
136
 
137
137
  ### Key Data Structures
138
138
 
139
- **AgentConfig** (`md_agents.py:43`)
139
+ **AgentConfig** (`md_agents.py:36`)
140
140
  - Pydantic model for agent frontmatter
141
141
  - Validates all fields (name, model, tools, max_turns, etc.)
142
142
  - Schema exported to `tsugite/schemas/agent.schema.json`
143
143
 
144
- **PreparedAgent** (`agent_preparation.py:17`)
144
+ **PreparedAgent** (`agent_preparation.py:69`)
145
145
  - Dataclass containing everything for execution/display
146
146
  - Ensures `render` shows exactly what `run` executes
147
147
  - Contains: agent, config, system_message, user_message, tools, context
@@ -180,6 +180,37 @@ Summarize findings
180
180
  - Safety: `max_iterations` (default 10) prevents infinite loops
181
181
  - Loop context: `{{ iteration }}`, `{{ max_iterations }}`, `{{ is_looping_step }}`
182
182
 
183
+ ### Exec Directives
184
+
185
+ `<!-- tsu:exec name="..." assign="..." -->...<!-- /tsu:exec -->` runs an arbitrary Python block at agent-prep time and binds the return value (or last expression) to a Jinja variable. Use it for deterministic dispatchers, preprocessing, and branching that don't justify an LLM round-trip.
186
+
187
+ ```markdown
188
+ <!-- tsu:exec name="dispatch" assign="targets" -->
189
+ import os, json
190
+ out = []
191
+ for p in sorted(os.listdir("inbox")):
192
+ if p.endswith(".json"):
193
+ out.append({"path": p, "source": json.loads(open(f"inbox/{p}").read())["source"]})
194
+ out
195
+ <!-- /tsu:exec -->
196
+
197
+ Inventory: {{ targets }}
198
+ ```
199
+
200
+ **Semantics:**
201
+ - Block body is opaque to Jinja; prior-directive vars (prefetch, tool, earlier exec) arrive as **Python locals**, not via `{{ }}` substitution. So `{{ }}` literals inside Python strings work.
202
+ - Return value: explicit `return_value(x)` or the last expression in the block (Jupyter-style). Explicit `return_value` wins.
203
+ - Plain Python is allowed (`open`, `os`, etc.) - the directive is for trusted preprocessing, distinct from LLM-emitted code in `tsugite/core/subprocess_executor.py`.
204
+ - Top-level only in v1: between/before/after `tsu:step` directives, never inside step content.
205
+
206
+ **Optional attributes:** `assign="var"`, `stdout_assign="var"`, `timeout=30`, `continue_on_error=true`.
207
+
208
+ **Render mode:** `tsu render` executes exec blocks by default. Pass `--no-exec` to substitute placeholders instead (e.g. when the block has side effects you want to inspect without running).
209
+
210
+ **Return-type policy:** values must JSON-serialize. `Path -> str`, `datetime -> isoformat()`, `set -> sorted list` are coerced automatically. Other non-serializable types raise (convert explicitly).
211
+
212
+ See `examples/exec_dispatcher.md` for a runnable inbox-watcher pattern.
213
+
183
214
  ### Event-Driven UI
184
215
 
185
216
  All UI output goes through the event system:
@@ -241,7 +272,7 @@ Tsugite supports vision (images), audio, and document understanding through the
241
272
  **How It Works:**
242
273
 
243
274
  1. **URL Attachments** (Images/Documents):
244
- - LiteLLM fetches the URL directly (no download overhead)
275
+ - The provider fetches the URL directly (no download overhead — support varies by provider and content type; see `tsugite/attachments/url.py`)
245
276
  - Example: `tsu run -f https://example.com/chart.png "Describe this chart"`
246
277
  - Automatically detected via HTTP HEAD request
247
278
 
@@ -286,6 +317,63 @@ tsu run -f image1.jpg -f image2.jpg "Compare these images"
286
317
  - YouTube handler: `tsugite/attachments/youtube.py` (fetches transcripts)
287
318
  - LLM formatting: `tsugite/core/agent.py:_format_attachment()`
288
319
 
320
+ #### Frontmatter Attachment Specs
321
+
322
+ The `attachments:` field accepts either plain string paths (legacy) or dict-form `AttachmentSpec` entries. Both forms can be mixed in the same list.
323
+
324
+ **String form** (existing): rendered through Jinja, then loaded as a single file. Prefix with `-` to remove a workspace default (e.g., `-MEMORY.md`).
325
+
326
+ ```yaml
327
+ attachments:
328
+ - MEMORY.md
329
+ - "{{ today() }}.md"
330
+ - -SKIP.md # remove a workspace default named SKIP.md
331
+ ```
332
+
333
+ **Dict form** (`AttachmentSpec`): adds `assign:`, `mode: index`, glob expansion, and other knobs.
334
+
335
+ ```yaml
336
+ attachments:
337
+ - path: MEMORY.md
338
+ assign: memory_content # bind file content as Jinja variable
339
+
340
+ - path: USER.md
341
+ assign: user_prefs
342
+ attach: false # bind variable but don't inject into prompt
343
+
344
+ - path: "memory/topics/*.md" # glob - one Attachment per matched file
345
+ assign: topic_files # bound as list[dict] of {path, content}
346
+
347
+ - path: "memory/topics/*.md"
348
+ mode: index # render path+heading list, not full content
349
+ name: topic_index # explicit attachment name (default derives from glob)
350
+ assign: topics # bound as list[dict] of {path, heading, size_bytes, mtime}
351
+ index_format: first_heading # path_only | first_line | first_heading | frontmatter
352
+ max_entries: 50 # cap, warns if exceeded
353
+ ```
354
+
355
+ **Variable shapes** (when `assign:` is set):
356
+
357
+ | Spec | Shape |
358
+ |---|---|
359
+ | `mode: full`, single concrete file | `str` (file content) |
360
+ | `mode: full`, glob | `list[dict]` of `{path, content}` (binaries skipped) |
361
+ | `mode: index` | `list[dict]` of `{path, heading, size_bytes, mtime}` |
362
+ | Single file, missing | `None` |
363
+ | Empty glob | `[]` |
364
+
365
+ **Constraints (validated at parse time):**
366
+ - `assign:` must be a valid Python identifier.
367
+ - Two specs can't share the same `assign` value.
368
+ - `attach: false` requires `assign:` (otherwise the attachment loads for nothing).
369
+ - `path:` cannot start with `-` (use string form for removal).
370
+
371
+ **Index mode rendering** wraps the formatted index in an existing `<attachment>` tag with a `mode="index"` attribute, e.g. `<attachment name="topic_index" mode="index">...</attachment>`. Agents are expected to call `read_file(path=...)` to fetch individual entries on demand.
372
+
373
+ **Collisions:** if an `assign:` name shadows a built-in or prefetch variable, the assignment wins and a warning is logged.
374
+
375
+ See `examples/attachment_assign_demo.md` and `examples/attachment_index_demo.md` for runnable references.
376
+
289
377
  ## Development Patterns
290
378
 
291
379
  ### Adding a New Built-in Agent
@@ -315,14 +403,31 @@ tsu run -f image1.jpg -f image2.jpg "Compare these images"
315
403
 
316
404
  1. Update `AgentConfig` Pydantic model (`md_agents.py`)
317
405
  2. Regenerate schema: `uv run python scripts/regenerate_schema.py`
318
- 3. Update documentation in CLAUDE.md (user guide section)
406
+ 3. Update relevant documentation in `AGENTS.md` and any user-facing doc under `docs/`
319
407
  4. Add validation tests in `tests/test_agent_parser.py`
320
408
 
321
409
  ## Testing Strategy
322
410
 
323
- - **TDD preferred**: Write tests first when building new features. Tests don't need to be elaborate — simple tests that verify the expected behavior are enough. This creates a fast feedback loop and catches integration issues early (e.g., contextvar propagation, tool registration) before manual testing.
411
+ ### TDD is the default
412
+
413
+ For any non-trivial bug fix or feature, write a failing test **first**. Exceptions: typo fixes, docs, pure refactors, and changes the user has explicitly scoped as exploratory.
414
+
415
+ The workflow:
416
+
417
+ 1. **Reproduce before fixing.** Write the smallest test that demonstrates the symptom as reported. Run it. If it passes on master, the hypothesis is wrong — do not write a fix. Investigate further, ask the user for more detail, or add logging.
418
+ 2. **Implement the fix.** Keep the change minimal. Do not refactor or add adjacent cleanup in the same diff.
419
+ 3. **Verify the test is load-bearing.** Temp-revert the production change and re-run. The test must go red again. If it still passes, the test isn't actually exercising the fix — rework it.
420
+ 4. **Cover adjacent cases before declaring done.** When touching a parser, protocol boundary, or state machine, enumerate at least two adjacent input shapes and add tests for them. Narrow tests let bugs sneak in through the cases you didn't think about.
421
+ 5. **Run the local regression suite.** At minimum, the test files next to the modules you changed. Faster than running everything, catches silent breakage of existing tests.
422
+ 6. **Honest uncertainty.** If a hypothesis doesn't reproduce, say so. Don't ship a "probably-this" fix with no failing test to anchor it — that's how placebo fixes get merged.
423
+
424
+ Reproducing tests don't need to be elaborate. A 10-line test that flips red→green is worth more than a 100-line one that nobody understands.
425
+
426
+ ### Test layers
427
+
324
428
  - **Unit tests**: Individual functions and classes
325
- - **Pipeline tests**: Mock only `TsugiteAgent`/`litellm.acompletion` but exercise the full pipeline (parsing → rendering → preparation → tool expansion → execution). Most tests in the suite are this style.
429
+ - **Pipeline tests**: Mock only `TsugiteAgent` / the provider's `acompletion` but exercise the full pipeline (parsing → rendering → preparation → tool expansion → execution). Most tests in the suite are this style.
430
+ - **Integration tests**: Live under `tests/integration/` (not collected by default — see `pyproject.toml` `norecursedirs`). Run explicitly with `uv run pytest tests/integration/`. Good for concurrency, cwd, and daemon-wiring tests that need real threading or a real workspace.
326
431
  - **Smoke tests**: `tests/smoke_test.sh` hits a real LLM API (requires `OPENAI_API_KEY`, not run in CI)
327
432
  - **Fixtures**: `conftest.py` provides shared test data
328
433
  - **Mocking**: Use `@pytest.fixture` for LLM responses
@@ -348,6 +453,28 @@ tsu run -f image1.jpg -f image2.jpg "Compare these images"
348
453
  6. **Test both sync and async paths**: Many tools support both execution modes
349
454
  7. **Don't embed prompts in adapters/code**: Use context variables + conditional blocks in `default.md` instead. Add new context vars in `_build_agent_context()` (base adapter) and default them in `agent_preparation.py`, then use `{% if var %}` in the agent template. This keeps all prompt content in one place and leverages the existing rendering pipeline.
350
455
 
456
+ ## Web UI
457
+
458
+ The daemon's web UI lives at `tsugite/daemon/web/`.
459
+
460
+ ### Stack
461
+
462
+ - **Alpine.js 3** loaded from CDN. No build step. No React. Don't port this to a framework - the design handoff explicitly said match visuals, not internal structure.
463
+ - **Starlette** serves `index.html` plus `/static/{css,js,icons}` and the `/api/*` routes (`tsugite/daemon/adapters/http.py`).
464
+ - CSS lives in three files. Read all three before adding rules: `theme.css` (Catppuccin tokens), `console.css` (Console redesign - the real stylesheet), `styles.css` (legacy modals/auth/forms; ~120 lines, pruned aggressively after the redesign).
465
+ - View modules under `js/views/`: `conversations.js` (orchestrator) + `conversation/{sessions,history,streaming,input,attachments,event_types}.js` mixins, plus `workspace.js`, `schedules.js`, `webhooks.js`, `usage.js`, `file-editor.js`. Shared helpers: `js/api.js` (REST + SSE), `js/utils.js` (markdown, formatters, toast).
466
+
467
+ ### Theme tokens
468
+
469
+ - Use **bare token names** - `var(--base)`, `var(--mantle)`, `var(--crust)`, `var(--surface0/1/2)`, `var(--text)`, `var(--lavender)`, `var(--blue)`, `var(--peach)`, etc. The legacy `--ctp-*` aliases were removed.
470
+ - **Visual depth is `crust < mantle < base`** (darker → lighter on Frappé/Mocha/Macchiato). For dark-on-dark panels, panels go `var(--mantle)` and inner cards `var(--surface0)` or `var(--crust)`. Don't put a brighter (`--bg`/`--base`) header over a `--mantle` panel - it inverts the depth on dark themes.
471
+ - Never hardcode hex colors. They won't theme-switch. Even in JS palette objects (e.g. `PI_COLORS` in `conversations.js`), use `var(--pink)` strings - they get embedded into `:style="background: ..."` and resolve through the CSS cascade.
472
+ - `<meta name="theme-color">` is synced to the active theme's `--crust` via an `Alpine.effect` in `app.js` so the PWA status bar / mobile chrome track the theme.
473
+
474
+ ### Verification
475
+
476
+ Browser verification on UI changes is mandatory. The smoketest recipe - daemon spinup, Playwright wiring, and the post-redesign DOM selectors - is captured in the agent's project memory file `project_daemon_ui_smoketest.md`. There's also a `project_webui_console_hotzones.md` memory listing the load-bearing assumptions in the new UI (pulse signal, mid-turn reload guards, theme depth, PWA resume, mobile back-buttons) that bit during the redesign and should be re-read before touching session lifecycle, theme tokens, or PWA behaviour.
477
+
351
478
  ## Code Review Policy
352
479
 
353
480
  - **Automatically run the `code-simplifier:code-simplifier` agent** (via the Task tool) after implementing any changes, without waiting for the user to ask. This catches duplication, unnecessary complexity, and keeps the codebase DRY.
@@ -0,0 +1,54 @@
1
+ # Contributing
2
+
3
+ Quick guide for contributors. See [AGENTS.md](AGENTS.md) for architecture and dev commands.
4
+
5
+ ## Commit messages
6
+
7
+ Use [Conventional Commits](https://www.conventionalcommits.org/). Format:
8
+
9
+ ```
10
+ <type>(<scope>): <subject>
11
+ ```
12
+
13
+ Keep the subject on one line, lowercase, no trailing period. Body is optional and rarely needed.
14
+
15
+ ### Allowed types
16
+
17
+ These match the groups in `cliff.toml` so release notes generate cleanly:
18
+
19
+ | Type | Use for |
20
+ |------------|--------------------------------------------------------------|
21
+ | `feat` | User-visible new capability |
22
+ | `fix` | Bug fix |
23
+ | `refactor` | Code restructure with no behavior change |
24
+ | `docs` | Documentation only |
25
+ | `test` | Tests only |
26
+ | `chore` | Deps, version bumps, formatting, tooling, lockfile |
27
+ | `ci` | CI/release pipeline only |
28
+ | `revert` | Reverts a prior commit |
29
+
30
+ Don't use other prefixes (`wip:`, `bump:`, `lint:`, `style:`, etc.). Squash WIP commits before merging. Roll lint/format/version bumps into `chore:`.
31
+
32
+ ### Breaking changes
33
+
34
+ Append `!` to the type or add a `BREAKING CHANGE:` footer:
35
+
36
+ ```
37
+ feat!: drop Python 3.10 support
38
+ ```
39
+
40
+ ### Scopes
41
+
42
+ Scopes are optional, but should be limited to one of these:
43
+
44
+ `webui`, `daemon`, `agent`, `cli`, `skills`, `history`, `sandbox`
45
+
46
+ ### Examples
47
+
48
+ ```
49
+ feat(webui): show session topic inline in sidebar
50
+ fix(agent): use ast.parse to locate code block close fence
51
+ refactor(history): per-event JSONL log replaces Turn aggregate
52
+ chore: bump lxml to 6.1.0 (CVE-2026-41066)
53
+ docs: add plugin docs
54
+ ```
@@ -0,0 +1,19 @@
1
+ FROM python:3.12-slim
2
+
3
+ RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
4
+ git \
5
+ ripgrep \
6
+ curl \
7
+ ca-certificates \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ COPY . /app
11
+ WORKDIR /app
12
+ RUN pip install --no-cache-dir ".[daemon]"
13
+
14
+ RUN useradd -m tsu && mkdir -p /workspace && chown tsu:tsu /workspace
15
+ USER tsu
16
+ WORKDIR /workspace
17
+
18
+ ENTRYPOINT ["tsu"]
19
+ CMD ["--help"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tsugite-cli
3
- Version: 0.12.2
3
+ Version: 0.14.0
4
4
  Summary: Micro-agent runner for task automation using markdown definitions
5
5
  Author: Justyn Shull
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -246,7 +246,6 @@ Requires-Dist: ddgs>=9.6.0
246
246
  Requires-Dist: html2text>=2020.1.16
247
247
  Requires-Dist: httpx>=0.25
248
248
  Requires-Dist: jinja2>=3.1
249
- Requires-Dist: mcp>=1.0
250
249
  Requires-Dist: nest-asyncio>=1.5.0
251
250
  Requires-Dist: pathspec>=0.11.0
252
251
  Requires-Dist: portalocker>=2.8.0
@@ -334,8 +333,8 @@ tsu run +default "summarize the files in this directory"
334
333
  # Run an agent file directly
335
334
  tsu run my-agent.md "do the thing"
336
335
 
337
- # Start the web UI
338
- tsu serve
336
+ # Start the daemon (web UI, Discord/Telegram bots)
337
+ tsu daemon
339
338
  ```
340
339
 
341
340
  ## Features
@@ -347,7 +346,6 @@ tsu serve
347
346
  - **Skills** directory-based knowledge modules (mostly) following the [agentskills.io](https://agentskills.io/) SKILL.md format
348
347
  - **Hooks** that fire shell commands on lifecycle events (post-tool, pre-message, pre/post-compact)
349
348
  - **Sandbox** (linux only) via bubblewrap with filesystem and network isolation
350
- - **MCP** integration for connecting to MCP servers
351
349
 
352
350
  ## Agents in more detail
353
351
 
@@ -395,7 +393,7 @@ All paths follow [XDG Base Directory](https://specifications.freedesktop.org/bas
395
393
 
396
394
  | Path | Default | Contents |
397
395
  |----------------------------------------|--------------------------------------|----------------------------------------------|
398
- | `$XDG_CONFIG_HOME/tsugite/` | `~/.config/tsugite/` | `config.json`, `mcp.json`, `daemon.yaml` |
396
+ | `$XDG_CONFIG_HOME/tsugite/` | `~/.config/tsugite/` | `config.json`, `daemon.yaml` |
399
397
  | `$XDG_DATA_HOME/tsugite/history/` | `~/.local/share/tsugite/history/` | Session history (JSONL per session) |
400
398
  | `$XDG_DATA_HOME/tsugite/daemon/` | `~/.local/share/tsugite/daemon/` | Daemon state |
401
399
  | `$XDG_DATA_HOME/tsugite/secrets/` | `~/.local/share/tsugite/secrets/` | Encrypted secrets (`secrets.db`) |
@@ -409,7 +407,7 @@ All paths follow [XDG Base Directory](https://specifications.freedesktop.org/bas
409
407
  ```bash
410
408
  git clone https://github.com/justyns/tsugite.git
411
409
  cd tsugite
412
- uv sync --dev
410
+ uv sync --all-extras
413
411
  ```
414
412
 
415
413
  ## Status
@@ -63,8 +63,8 @@ tsu run +default "summarize the files in this directory"
63
63
  # Run an agent file directly
64
64
  tsu run my-agent.md "do the thing"
65
65
 
66
- # Start the web UI
67
- tsu serve
66
+ # Start the daemon (web UI, Discord/Telegram bots)
67
+ tsu daemon
68
68
  ```
69
69
 
70
70
  ## Features
@@ -76,7 +76,6 @@ tsu serve
76
76
  - **Skills** directory-based knowledge modules (mostly) following the [agentskills.io](https://agentskills.io/) SKILL.md format
77
77
  - **Hooks** that fire shell commands on lifecycle events (post-tool, pre-message, pre/post-compact)
78
78
  - **Sandbox** (linux only) via bubblewrap with filesystem and network isolation
79
- - **MCP** integration for connecting to MCP servers
80
79
 
81
80
  ## Agents in more detail
82
81
 
@@ -124,7 +123,7 @@ All paths follow [XDG Base Directory](https://specifications.freedesktop.org/bas
124
123
 
125
124
  | Path | Default | Contents |
126
125
  |----------------------------------------|--------------------------------------|----------------------------------------------|
127
- | `$XDG_CONFIG_HOME/tsugite/` | `~/.config/tsugite/` | `config.json`, `mcp.json`, `daemon.yaml` |
126
+ | `$XDG_CONFIG_HOME/tsugite/` | `~/.config/tsugite/` | `config.json`, `daemon.yaml` |
128
127
  | `$XDG_DATA_HOME/tsugite/history/` | `~/.local/share/tsugite/history/` | Session history (JSONL per session) |
129
128
  | `$XDG_DATA_HOME/tsugite/daemon/` | `~/.local/share/tsugite/daemon/` | Daemon state |
130
129
  | `$XDG_DATA_HOME/tsugite/secrets/` | `~/.local/share/tsugite/secrets/` | Encrypted secrets (`secrets.db`) |
@@ -138,7 +137,7 @@ All paths follow [XDG Base Directory](https://specifications.freedesktop.org/bas
138
137
  ```bash
139
138
  git clone https://github.com/justyns/tsugite.git
140
139
  cd tsugite
141
- uv sync --dev
140
+ uv sync --all-extras
142
141
  ```
143
142
 
144
143
  ## Status
@@ -0,0 +1,44 @@
1
+ # git-cliff config for tsugite
2
+ # Generates release notes from conventional commit messages.
3
+ # https://git-cliff.org/docs/configuration
4
+
5
+ [changelog]
6
+ header = ""
7
+ body = """
8
+ {% if version %}\
9
+ ## {{ version | trim_start_matches(pat="v") }} ({{ timestamp | date(format="%Y-%m-%d") }})
10
+ {% else %}\
11
+ ## Unreleased
12
+ {% endif %}\
13
+ {% for group, commits in commits | group_by(attribute="group") %}
14
+ ### {{ group | upper_first }}
15
+ {% for commit in commits %}
16
+ - {{ commit.message | split(pat="\n") | first | trim }}{% if commit.id %} ({{ commit.id | truncate(length=7, end="") }}){% endif %}\
17
+ {% endfor %}
18
+ {% endfor %}\n
19
+ """
20
+ trim = true
21
+ footer = ""
22
+
23
+ [git]
24
+ conventional_commits = true
25
+ filter_unconventional = false
26
+ split_commits = false
27
+ commit_parsers = [
28
+ { message = "^feat", group = "Features" },
29
+ { message = "^fix", group = "Bug Fixes" },
30
+ { message = "^perf", group = "Performance" },
31
+ { message = "^refactor", group = "Refactor" },
32
+ { message = "^docs", group = "Documentation" },
33
+ { message = "^test", group = "Tests" },
34
+ { message = "^ci", group = "CI" },
35
+ { message = "^chore\\(release\\)", skip = true },
36
+ { message = "^chore", group = "Maintenance" },
37
+ { message = "^revert", group = "Reverts" },
38
+ { message = ".*", group = "Other" },
39
+ ]
40
+ filter_commits = false
41
+ tag_pattern = "v[0-9]*"
42
+ ignore_tags = ""
43
+ topo_order = false
44
+ sort_commits = "oldest"