tsugite-cli 0.14.0__tar.gz → 0.14.2__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.
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/PKG-INFO +14 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/README.md +12 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/pyproject.toml +15 -2
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_inheritance.py +3 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_preparation.py +13 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/exec_directives.py +1 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_agents/default.md +9 -3
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/tsugite-jinja-reference/SKILL.md +2 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/chat.py +3 -13
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/plugins.py +8 -6
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/run.py +26 -20
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/workspace.py +0 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/executor.py +60 -12
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/adapters/base.py +52 -20
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/adapters/http.py +146 -132
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/commands.py +13 -10
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/compaction_scheduler.py +5 -4
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/scheduler.py +26 -11
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/session_runner.py +1 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/session_store.py +191 -139
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/css/console.css +4 -4
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/css/theme.css +11 -5
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/index.html +53 -25
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/app.js +23 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/conversation/history.js +37 -19
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/conversation/input.js +1 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/conversation/sessions.js +86 -29
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/conversation/streaming.js +51 -24
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/conversations.js +174 -80
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/events/base.py +0 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/events/bus.py +3 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/events/events.py +2 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/events/helpers.py +17 -2
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/history/models.py +2 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/md_agents.py +2 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/options.py +1 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/renderer.py +8 -1
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/schemas/agent.schema.json +12 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/agents.py +44 -43
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/skills.py +0 -2
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/__init__.py +11 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/chat.py +5 -73
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/helpers.py +25 -2
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/jsonl.py +8 -2
- tsugite_cli-0.14.2/tsugite/ui/live.py +150 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/plain.py +8 -4
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/repl_chat.py +0 -8
- tsugite_cli-0.14.0/.github/copilot-instructions.md +0 -252
- tsugite_cli-0.14.0/.github/workflows/ci.yml +0 -74
- tsugite_cli-0.14.0/.github/workflows/docker-publish.yml +0 -60
- tsugite_cli-0.14.0/.github/workflows/pypi-publish.yml +0 -49
- tsugite_cli-0.14.0/CLAUDE.md +0 -1
- tsugite_cli-0.14.0/Dockerfile +0 -19
- tsugite_cli-0.14.0/cliff.toml +0 -44
- tsugite_cli-0.14.0/docs/agents.md +0 -341
- tsugite_cli-0.14.0/docs/plugin-events.md +0 -131
- tsugite_cli-0.14.0/docs/plugin-hooks.md +0 -110
- tsugite_cli-0.14.0/docs/plugin-tools.md +0 -109
- tsugite_cli-0.14.0/docs/plugins.md +0 -139
- tsugite_cli-0.14.0/docs/release_notes/v0.13.0.md +0 -51
- tsugite_cli-0.14.0/docs/release_notes/v0.14.0.md +0 -39
- tsugite_cli-0.14.0/docs/secrets.md +0 -136
- tsugite_cli-0.14.0/docs/test_agents/prefresh_readme.md +0 -16
- tsugite_cli-0.14.0/docs/test_agents/template_test.md +0 -14
- tsugite_cli-0.14.0/docs/test_agents/test_agent.md +0 -15
- tsugite_cli-0.14.0/docs/test_agents/test_steps.md +0 -8
- tsugite_cli-0.14.0/examples/tsugite-example-plugin/pyproject.toml +0 -17
- tsugite_cli-0.14.0/examples/tsugite-example-plugin/tsugite_example_plugin/__init__.py +0 -41
- tsugite_cli-0.14.0/mise.toml +0 -22
- tsugite_cli-0.14.0/plugins/tsugite-tmux/pyproject.toml +0 -16
- tsugite_cli-0.14.0/plugins/tsugite-tmux/tests/test_tmux_tools.py +0 -376
- tsugite_cli-0.14.0/plugins/tsugite-tmux/tsugite_tmux/__init__.py +0 -292
- tsugite_cli-0.14.0/scripts/backfill_usage.py +0 -98
- tsugite_cli-0.14.0/scripts/bump_version.py +0 -90
- tsugite_cli-0.14.0/scripts/regenerate_schema.py +0 -33
- tsugite_cli-0.14.0/scripts/update_model_registry.py +0 -200
- tsugite_cli-0.14.0/tests/README.md +0 -123
- tsugite_cli-0.14.0/tests/__init__.py +0 -1
- tsugite_cli-0.14.0/tests/conftest.py +0 -573
- tsugite_cli-0.14.0/tests/core/__init__.py +0 -1
- tsugite_cli-0.14.0/tests/core/test_agent.py +0 -884
- tsugite_cli-0.14.0/tests/core/test_agent_context_tokens.py +0 -188
- tsugite_cli-0.14.0/tests/core/test_agent_event_loop.py +0 -310
- tsugite_cli-0.14.0/tests/core/test_agent_parser_triple_quotes.py +0 -70
- tsugite_cli-0.14.0/tests/core/test_agent_ui_events.py +0 -485
- tsugite_cli-0.14.0/tests/core/test_content_blocks.py +0 -269
- tsugite_cli-0.14.0/tests/core/test_executor.py +0 -668
- tsugite_cli-0.14.0/tests/core/test_executor_escape_tripwire.py +0 -35
- tsugite_cli-0.14.0/tests/core/test_memory.py +0 -165
- tsugite_cli-0.14.0/tests/core/test_proxy.py +0 -165
- tsugite_cli-0.14.0/tests/core/test_sandbox.py +0 -171
- tsugite_cli-0.14.0/tests/core/test_state.py +0 -85
- tsugite_cli-0.14.0/tests/core/test_subprocess_executor.py +0 -382
- tsugite_cli-0.14.0/tests/core/test_tools.py +0 -372
- tsugite_cli-0.14.0/tests/daemon/__init__.py +0 -0
- tsugite_cli-0.14.0/tests/daemon/test_chat_reentrancy.py +0 -399
- tsugite_cli-0.14.0/tests/daemon/test_collect_events.py +0 -106
- tsugite_cli-0.14.0/tests/daemon/test_compaction_command.py +0 -247
- tsugite_cli-0.14.0/tests/daemon/test_event_broadcast_scope.py +0 -64
- tsugite_cli-0.14.0/tests/daemon/test_final_answer_delivery.py +0 -75
- tsugite_cli-0.14.0/tests/daemon/test_http_adapter.py +0 -797
- tsugite_cli-0.14.0/tests/daemon/test_message_context_session_started.py +0 -152
- tsugite_cli-0.14.0/tests/daemon/test_message_context_topic.py +0 -207
- tsugite_cli-0.14.0/tests/daemon/test_prompt_too_long_retry.py +0 -239
- tsugite_cli-0.14.0/tests/daemon/test_session_metadata_api.py +0 -249
- tsugite_cli-0.14.0/tests/daemon/test_session_pinning_api.py +0 -284
- tsugite_cli-0.14.0/tests/daemon/test_session_primary_api.py +0 -151
- tsugite_cli-0.14.0/tests/daemon/test_session_store_named_route.py +0 -91
- tsugite_cli-0.14.0/tests/daemon/test_session_store_pinning.py +0 -194
- tsugite_cli-0.14.0/tests/daemon/test_session_store_primary.py +0 -182
- tsugite_cli-0.14.0/tests/daemon/test_skill_trigger_loading.py +0 -154
- tsugite_cli-0.14.0/tests/e2e/__init__.py +0 -0
- tsugite_cli-0.14.0/tests/e2e/conftest.py +0 -162
- tsugite_cli-0.14.0/tests/e2e/test_auth.py +0 -27
- tsugite_cli-0.14.0/tests/e2e/test_chat.py +0 -69
- tsugite_cli-0.14.0/tests/e2e/test_context_bar.py +0 -30
- tsugite_cli-0.14.0/tests/e2e/test_draft_persistence.py +0 -115
- tsugite_cli-0.14.0/tests/e2e/test_history.py +0 -148
- tsugite_cli-0.14.0/tests/e2e/test_history_code_rendering.py +0 -329
- tsugite_cli-0.14.0/tests/e2e/test_markdown_rendering.py +0 -186
- tsugite_cli-0.14.0/tests/e2e/test_message_actions.py +0 -253
- tsugite_cli-0.14.0/tests/e2e/test_page_load.py +0 -35
- tsugite_cli-0.14.0/tests/e2e/test_prompt_inspector.py +0 -53
- tsugite_cli-0.14.0/tests/e2e/test_scroll_behavior.py +0 -137
- tsugite_cli-0.14.0/tests/e2e/test_sessions.py +0 -41
- tsugite_cli-0.14.0/tests/e2e/test_sidebar_redesign.py +0 -73
- tsugite_cli-0.14.0/tests/e2e/test_sse_metadata.py +0 -31
- tsugite_cli-0.14.0/tests/events/test_event_consolidation.py +0 -206
- tsugite_cli-0.14.0/tests/events/test_filtered_subscriptions.py +0 -261
- tsugite_cli-0.14.0/tests/integration/test_concurrent_workspace_cwd.py +0 -88
- tsugite_cli-0.14.0/tests/integration/test_exec_directive_e2e.py +0 -37
- tsugite_cli-0.14.0/tests/integration/test_nested_session_spawn.py +0 -103
- tsugite_cli-0.14.0/tests/smoke_test.sh +0 -87
- tsugite_cli-0.14.0/tests/test_agent_file_hot_loading.py +0 -279
- tsugite_cli-0.14.0/tests/test_agent_inheritance.py +0 -485
- tsugite_cli-0.14.0/tests/test_agent_parser.py +0 -330
- tsugite_cli-0.14.0/tests/test_agent_preparation.py +0 -107
- tsugite_cli-0.14.0/tests/test_agent_sessions.py +0 -510
- tsugite_cli-0.14.0/tests/test_agent_skills.py +0 -1019
- tsugite_cli-0.14.0/tests/test_agent_utils.py +0 -220
- tsugite_cli-0.14.0/tests/test_agents_tool.py +0 -219
- tsugite_cli-0.14.0/tests/test_anthropic_extended_thinking.py +0 -198
- tsugite_cli-0.14.0/tests/test_attachment_deduplication.py +0 -281
- tsugite_cli-0.14.0/tests/test_attachments.py +0 -1074
- tsugite_cli-0.14.0/tests/test_auto_context_handler.py +0 -429
- tsugite_cli-0.14.0/tests/test_auto_discovery.py +0 -223
- tsugite_cli-0.14.0/tests/test_background_task_status.py +0 -187
- tsugite_cli-0.14.0/tests/test_background_tasks.py +0 -722
- tsugite_cli-0.14.0/tests/test_builtin_agent_paths.py +0 -164
- tsugite_cli-0.14.0/tests/test_builtin_agents.py +0 -229
- tsugite_cli-0.14.0/tests/test_chat_cli.py +0 -186
- tsugite_cli-0.14.0/tests/test_chat_error_handling.py +0 -65
- tsugite_cli-0.14.0/tests/test_claude_code_attachments.py +0 -103
- tsugite_cli-0.14.0/tests/test_claude_code_provider.py +0 -1167
- tsugite_cli-0.14.0/tests/test_cli.py +0 -873
- tsugite_cli-0.14.0/tests/test_cli_arguments.py +0 -132
- tsugite_cli-0.14.0/tests/test_cli_rendering.py +0 -387
- tsugite_cli-0.14.0/tests/test_cli_skills.py +0 -85
- tsugite_cli-0.14.0/tests/test_cli_subcommands.py +0 -159
- tsugite_cli-0.14.0/tests/test_compaction_context_preservation.py +0 -233
- tsugite_cli-0.14.0/tests/test_compaction_event.py +0 -160
- tsugite_cli-0.14.0/tests/test_compaction_progress.py +0 -162
- tsugite_cli-0.14.0/tests/test_completion_callbacks.py +0 -479
- tsugite_cli-0.14.0/tests/test_config.py +0 -157
- tsugite_cli-0.14.0/tests/test_custom_shell_tools.py +0 -340
- tsugite_cli-0.14.0/tests/test_custom_ui.py +0 -338
- tsugite_cli-0.14.0/tests/test_daemon_auth.py +0 -254
- tsugite_cli-0.14.0/tests/test_daemon_compaction_scheduler.py +0 -191
- tsugite_cli-0.14.0/tests/test_daemon_config.py +0 -133
- tsugite_cli-0.14.0/tests/test_daemon_push.py +0 -260
- tsugite_cli-0.14.0/tests/test_daemon_scheduler.py +0 -625
- tsugite_cli-0.14.0/tests/test_daemon_unified_sessions.py +0 -602
- tsugite_cli-0.14.0/tests/test_discord_progress.py +0 -529
- tsugite_cli-0.14.0/tests/test_error_display.py +0 -85
- tsugite_cli-0.14.0/tests/test_event_storage.py +0 -153
- tsugite_cli-0.14.0/tests/test_events_to_messages.py +0 -217
- tsugite_cli-0.14.0/tests/test_exceptions.py +0 -17
- tsugite_cli-0.14.0/tests/test_exec_directives.py +0 -309
- tsugite_cli-0.14.0/tests/test_file_references.py +0 -266
- tsugite_cli-0.14.0/tests/test_file_tools.py +0 -954
- tsugite_cli-0.14.0/tests/test_fs_tool_workspace.py +0 -89
- tsugite_cli-0.14.0/tests/test_handle_message_flush.py +0 -216
- tsugite_cli-0.14.0/tests/test_history_migrate.py +0 -274
- tsugite_cli-0.14.0/tests/test_hooks.py +0 -1213
- tsugite_cli-0.14.0/tests/test_http_tools.py +0 -397
- tsugite_cli-0.14.0/tests/test_interaction_backend_isolation.py +0 -186
- tsugite_cli-0.14.0/tests/test_interaction_backends.py +0 -246
- tsugite_cli-0.14.0/tests/test_interactive_context.py +0 -311
- tsugite_cli-0.14.0/tests/test_interactive_tool.py +0 -483
- tsugite_cli-0.14.0/tests/test_jsonl_ui.py +0 -203
- tsugite_cli-0.14.0/tests/test_list_agents_tool.py +0 -232
- tsugite_cli-0.14.0/tests/test_live_event_recording.py +0 -130
- tsugite_cli-0.14.0/tests/test_md_agents_json.py +0 -97
- tsugite_cli-0.14.0/tests/test_memory_sanitize.py +0 -288
- tsugite_cli-0.14.0/tests/test_model_registry.py +0 -37
- tsugite_cli-0.14.0/tests/test_models.py +0 -79
- tsugite_cli-0.14.0/tests/test_multi_agent.py +0 -162
- tsugite_cli-0.14.0/tests/test_multistep_agents.py +0 -972
- tsugite_cli-0.14.0/tests/test_multistep_retry_side_effects.py +0 -108
- tsugite_cli-0.14.0/tests/test_orchestrator_heartbeat.py +0 -228
- tsugite_cli-0.14.0/tests/test_plugins.py +0 -442
- tsugite_cli-0.14.0/tests/test_post_compaction_counters.py +0 -255
- tsugite_cli-0.14.0/tests/test_prompt_snapshot.py +0 -127
- tsugite_cli-0.14.0/tests/test_provider_registry.py +0 -53
- tsugite_cli-0.14.0/tests/test_provider_turn_heartbeat.py +0 -142
- tsugite_cli-0.14.0/tests/test_reasoning_models.py +0 -127
- tsugite_cli-0.14.0/tests/test_renderer.py +0 -760
- tsugite_cli-0.14.0/tests/test_rendering_scenarios.py +0 -490
- tsugite_cli-0.14.0/tests/test_repl_commands.py +0 -274
- tsugite_cli-0.14.0/tests/test_repl_completer.py +0 -105
- tsugite_cli-0.14.0/tests/test_repl_handler.py +0 -187
- tsugite_cli-0.14.0/tests/test_retry_system.py +0 -176
- tsugite_cli-0.14.0/tests/test_run_if.py +0 -92
- tsugite_cli-0.14.0/tests/test_schedule_model_override.py +0 -148
- tsugite_cli-0.14.0/tests/test_scheduler_history_injection.py +0 -363
- tsugite_cli-0.14.0/tests/test_schema.py +0 -207
- tsugite_cli-0.14.0/tests/test_secret_access_event.py +0 -69
- tsugite_cli-0.14.0/tests/test_secrets.py +0 -487
- tsugite_cli-0.14.0/tests/test_security_phase1.py +0 -369
- tsugite_cli-0.14.0/tests/test_send_message.py +0 -58
- tsugite_cli-0.14.0/tests/test_session_metadata.py +0 -304
- tsugite_cli-0.14.0/tests/test_session_orchestrator_tools.py +0 -152
- tsugite_cli-0.14.0/tests/test_session_progress_cache.py +0 -139
- tsugite_cli-0.14.0/tests/test_shell_tool_cwd.py +0 -82
- tsugite_cli-0.14.0/tests/test_skill_discovery.py +0 -691
- tsugite_cli-0.14.0/tests/test_skill_tools.py +0 -444
- tsugite_cli-0.14.0/tests/test_stdin.py +0 -204
- tsugite_cli-0.14.0/tests/test_step_render_framework_flags.py +0 -108
- tsugite_cli-0.14.0/tests/test_subagent_subprocess.py +0 -119
- tsugite_cli-0.14.0/tests/test_time_tool.py +0 -47
- tsugite_cli-0.14.0/tests/test_tool_directives.py +0 -433
- tsugite_cli-0.14.0/tests/test_tool_registry.py +0 -433
- tsugite_cli-0.14.0/tests/test_unified_event_log.py +0 -185
- tsugite_cli-0.14.0/tests/test_user_agent.py +0 -99
- tsugite_cli-0.14.0/tests/test_workspace_auto_continue.py +0 -74
- tsugite_cli-0.14.0/tests/test_workspace_cwd.py +0 -370
- tsugite_cli-0.14.0/tests/test_workspace_discovery.py +0 -120
- tsugite_cli-0.14.0/uv.lock +0 -2628
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/.gitignore +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/AGENTS.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/CONTRIBUTING.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/LICENSE +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/__init__.py +2 -2
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/exec_runner.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/helpers.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/history_integration.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/metrics.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/models.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/runner.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_runner/validation.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/agent_utils.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/auto_context.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/base.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/file.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/inline.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/storage.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/url.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/attachments/youtube.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_agents/.gitkeep +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_agents/code_searcher.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_agents/file_searcher.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_agents/onboard.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/.gitkeep +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/codebase-exploration/SKILL.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/python-math/SKILL.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/response-patterns/SKILL.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/scheduling/SKILL.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/skill-authoring/SKILL.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/tsugite-agent-basics/SKILL.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/tsugite-skill-basics/SKILL.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cache.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/agents.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/attachments.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/cache.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/config.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/daemon.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/helpers.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/history.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/init.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/models.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/render.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/secrets.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/skills.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/tools.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/usage.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/cli/validate.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/config.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/console.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/constants.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/agent.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/claude_code.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/content_blocks.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/memory.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/proxy.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/sandbox.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/state.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/subprocess_executor.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/core/tools.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/adapters/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/adapters/discord.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/adapters/scheduler_adapter.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/auth.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/config.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/gateway.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/memory.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/push.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/css/responsive.css +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/css/styles.css +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/icons/icon-192.png +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/icons/icon-512-maskable.png +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/icons/icon-512.png +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/icons/screenshot-narrow.png +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/icons/screenshot-wide.png +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/api.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/utils.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/vendor/marked.LICENSE.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/vendor/marked.esm.min.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/conversation/attachments.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/conversation/event_types.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/file-editor.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/schedules.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/usage.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/webhooks.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/js/views/workspace.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/manifest.json +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/web/sw.js +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/daemon/webhook_store.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/events/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/exceptions.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/history/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/history/reconstruction.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/history/storage.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/hooks.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/interaction.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/models.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/plugins.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/anthropic.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/base.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/claude_code.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/model_cache.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/model_registry.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/ollama.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/openai_compat.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/providers/openrouter.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/schemas/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/backend.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/env.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/exec.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/file.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/masking.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/registry.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/secrets/sqlite.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/shell_tool_config.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/skill_discovery.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/templates/AGENTS.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/templates/IDENTITY.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/templates/MEMORY.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/templates/USER.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/templates/personas/casual-technical.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/templates/personas/marvin.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/templates/personas/minimal.md +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/fs.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/history.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/http.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/interactive.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/notify.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/schedule.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/scratchpad.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/secrets.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/sessions.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/shell.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/shell_tools.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tools/time.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/tsugite.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/base.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/repl_commands.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/repl_completer.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui/repl_handler.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/ui_context.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/usage/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/usage/store.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/user_agent.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/utils.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/workspace/__init__.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/workspace/context.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/workspace/models.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/workspace/session.py +0 -0
- {tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/workspace/templates.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tsugite-cli
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.2
|
|
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
|
|
@@ -263,6 +263,7 @@ Provides-Extra: daemon
|
|
|
263
263
|
Requires-Dist: cronsim>=2.6; extra == 'daemon'
|
|
264
264
|
Requires-Dist: discord-py>=2.3.2; extra == 'daemon'
|
|
265
265
|
Requires-Dist: py-vapid>=1.9.0; extra == 'daemon'
|
|
266
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'daemon'
|
|
266
267
|
Requires-Dist: pywebpush>=2.0.0; extra == 'daemon'
|
|
267
268
|
Requires-Dist: starlette>=0.36; extra == 'daemon'
|
|
268
269
|
Requires-Dist: uvicorn>=0.25; extra == 'daemon'
|
|
@@ -337,6 +338,18 @@ tsu run my-agent.md "do the thing"
|
|
|
337
338
|
tsu daemon
|
|
338
339
|
```
|
|
339
340
|
|
|
341
|
+
### Output modes
|
|
342
|
+
|
|
343
|
+
`tsu run` keeps its terminal output plain by default so logs are copy-pasteable and behave
|
|
344
|
+
in nested tmux / non-Rich-friendly shells. Pick a richer or quieter mode when you need it:
|
|
345
|
+
|
|
346
|
+
| Mode | When to use |
|
|
347
|
+
| --- | --- |
|
|
348
|
+
| **Default (plain)** | Everyday interactive runs and piped output (`tsu run ... \| less`). |
|
|
349
|
+
| `--ui live` | Long-running interactive runs where a persistent footer showing turn / current tool / tokens / cost / elapsed time is useful. Falls back to plain if stdout is not a TTY or `NO_COLOR` is set. |
|
|
350
|
+
| `--headless` | CI/scripts: result on stdout, no progress chrome. Combine with `--verbose` for stderr trace. |
|
|
351
|
+
| `--plain` | Force plain explicitly (same as the default; useful when overriding configs/aliases). |
|
|
352
|
+
|
|
340
353
|
## Features
|
|
341
354
|
|
|
342
355
|
- **Multi-step workflows** with `<!-- tsu:step -->` to chain steps and pass data between them
|
|
@@ -67,6 +67,18 @@ tsu run my-agent.md "do the thing"
|
|
|
67
67
|
tsu daemon
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
### Output modes
|
|
71
|
+
|
|
72
|
+
`tsu run` keeps its terminal output plain by default so logs are copy-pasteable and behave
|
|
73
|
+
in nested tmux / non-Rich-friendly shells. Pick a richer or quieter mode when you need it:
|
|
74
|
+
|
|
75
|
+
| Mode | When to use |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| **Default (plain)** | Everyday interactive runs and piped output (`tsu run ... \| less`). |
|
|
78
|
+
| `--ui live` | Long-running interactive runs where a persistent footer showing turn / current tool / tokens / cost / elapsed time is useful. Falls back to plain if stdout is not a TTY or `NO_COLOR` is set. |
|
|
79
|
+
| `--headless` | CI/scripts: result on stdout, no progress chrome. Combine with `--verbose` for stderr trace. |
|
|
80
|
+
| `--plain` | Force plain explicitly (same as the default; useful when overriding configs/aliases). |
|
|
81
|
+
|
|
70
82
|
## Features
|
|
71
83
|
|
|
72
84
|
- **Multi-step workflows** with `<!-- tsu:step -->` to chain steps and pass data between them
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tsugite-cli"
|
|
3
|
-
version = "0.14.
|
|
3
|
+
version = "0.14.2"
|
|
4
4
|
description = "Micro-agent runner for task automation using markdown definitions"
|
|
5
5
|
authors = [{ name = "Justyn Shull" }]
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -34,6 +34,7 @@ daemon = [
|
|
|
34
34
|
"cronsim>=2.6",
|
|
35
35
|
"starlette>=0.36",
|
|
36
36
|
"uvicorn>=0.25",
|
|
37
|
+
"python-multipart>=0.0.9",
|
|
37
38
|
"pywebpush>=2.0.0",
|
|
38
39
|
"py-vapid>=1.9.0",
|
|
39
40
|
]
|
|
@@ -49,12 +50,23 @@ build-backend = "hatchling.build"
|
|
|
49
50
|
[tool.hatch.build.targets.wheel]
|
|
50
51
|
packages = ["tsugite"]
|
|
51
52
|
|
|
53
|
+
[tool.hatch.build.targets.sdist]
|
|
54
|
+
include = [
|
|
55
|
+
"/tsugite",
|
|
56
|
+
"/README.md",
|
|
57
|
+
"/LICENSE",
|
|
58
|
+
"/CONTRIBUTING.md",
|
|
59
|
+
"/AGENTS.md",
|
|
60
|
+
"/pyproject.toml",
|
|
61
|
+
]
|
|
62
|
+
|
|
52
63
|
[tool.uv.workspace]
|
|
53
64
|
members = ["plugins/*"]
|
|
54
65
|
|
|
55
66
|
[tool.uv.sources]
|
|
56
67
|
tsugite-cli = { workspace = true }
|
|
57
68
|
tsugite-tmux = { workspace = true }
|
|
69
|
+
tsugite-acp = { workspace = true }
|
|
58
70
|
|
|
59
71
|
[tool.ruff]
|
|
60
72
|
target-version = "py311"
|
|
@@ -73,7 +85,7 @@ line-length = 120
|
|
|
73
85
|
|
|
74
86
|
[tool.pytest.ini_options]
|
|
75
87
|
testpaths = ["tests", "plugins"]
|
|
76
|
-
addopts = "-n auto --dist
|
|
88
|
+
addopts = "-n auto --dist loadfile --cov=tsugite --cov-report=term-missing --cov-report=html --cov-report=xml"
|
|
77
89
|
asyncio_mode = "strict"
|
|
78
90
|
asyncio_default_fixture_loop_scope = "function"
|
|
79
91
|
filterwarnings = ["ignore::RuntimeWarning"]
|
|
@@ -129,4 +141,5 @@ dev = [
|
|
|
129
141
|
"ruff>=0.1",
|
|
130
142
|
"vulture>=2.14",
|
|
131
143
|
"tsugite-tmux",
|
|
144
|
+
"tsugite-acp",
|
|
132
145
|
]
|
|
@@ -281,6 +281,7 @@ def merge_scalar_fields(parent, child) -> Dict[str, Any]:
|
|
|
281
281
|
"model": child.model if child.model else parent.model,
|
|
282
282
|
"max_turns": child.max_turns if child.max_turns != 5 else parent.max_turns,
|
|
283
283
|
"reasoning_effort": child.reasoning_effort if child.reasoning_effort else parent.reasoning_effort,
|
|
284
|
+
"auto_load_agent_list": child.auto_load_agent_list or parent.auto_load_agent_list,
|
|
284
285
|
}
|
|
285
286
|
|
|
286
287
|
|
|
@@ -321,6 +322,7 @@ def merge_list_fields(parent, child) -> Dict[str, List]:
|
|
|
321
322
|
merged_tools = _merge_dedup(parent.tools, child.tools)
|
|
322
323
|
merged_attachments = _merge_attachments(parent.attachments, child.attachments)
|
|
323
324
|
merged_skills = _merge_dedup(parent.auto_load_skills, child.auto_load_skills)
|
|
325
|
+
merged_auto_load_agents = _merge_dedup(parent.auto_load_agents, child.auto_load_agents)
|
|
324
326
|
|
|
325
327
|
# Custom tools - deduplicate by "name" field (child overrides parent)
|
|
326
328
|
custom_tool_dict = {}
|
|
@@ -333,6 +335,7 @@ def merge_list_fields(parent, child) -> Dict[str, List]:
|
|
|
333
335
|
"prefetch": (parent.prefetch or []) + (child.prefetch or []),
|
|
334
336
|
"custom_tools": list(custom_tool_dict.values()),
|
|
335
337
|
"auto_load_skills": merged_skills,
|
|
338
|
+
"auto_load_agents": merged_auto_load_agents,
|
|
336
339
|
}
|
|
337
340
|
|
|
338
341
|
|
|
@@ -547,6 +547,19 @@ class AgentPreparer:
|
|
|
547
547
|
# Silently continue if prefetch fails
|
|
548
548
|
prefetch_context = {}
|
|
549
549
|
|
|
550
|
+
# Step 1b: Opt-in <available_agents> injection. Default agents call
|
|
551
|
+
# list_available_agents() on demand instead of carrying the full list.
|
|
552
|
+
if "available_agents" not in prefetch_context and (
|
|
553
|
+
agent_config.auto_load_agent_list or agent_config.auto_load_agents
|
|
554
|
+
):
|
|
555
|
+
from tsugite.tools.agents import discover_agents, format_agents_markdown
|
|
556
|
+
|
|
557
|
+
agents = discover_agents()
|
|
558
|
+
if agent_config.auto_load_agents:
|
|
559
|
+
wanted = set(agent_config.auto_load_agents)
|
|
560
|
+
agents = [a for a in agents if a["name"] in wanted]
|
|
561
|
+
prefetch_context["available_agents"] = format_agents_markdown(agents)
|
|
562
|
+
|
|
550
563
|
# Step 2: Execute tool directives (unless skip_tool_directives=True for render)
|
|
551
564
|
if skip_tool_directives:
|
|
552
565
|
modified_content = agent.content
|
|
@@ -7,7 +7,7 @@ execution note, and returns the modified content plus a context dict of assigned
|
|
|
7
7
|
|
|
8
8
|
from typing import Any, Dict, List, Optional, Tuple
|
|
9
9
|
|
|
10
|
-
from tsugite.agent_runner.exec_runner import run_python_block
|
|
10
|
+
from tsugite.agent_runner.exec_runner import ExecBlockResult, run_python_block
|
|
11
11
|
from tsugite.md_agents import ExecDirective, extract_exec_directives
|
|
12
12
|
|
|
13
13
|
|
|
@@ -15,6 +15,7 @@ attachments:
|
|
|
15
15
|
max_turns: 10
|
|
16
16
|
tools:
|
|
17
17
|
- spawn_agent
|
|
18
|
+
- list_available_agents
|
|
18
19
|
- read_file
|
|
19
20
|
- list_files
|
|
20
21
|
- write_file
|
|
@@ -36,9 +37,6 @@ tools:
|
|
|
36
37
|
auto_load_skills:
|
|
37
38
|
- response-patterns
|
|
38
39
|
prefetch:
|
|
39
|
-
- tool: list_agents
|
|
40
|
-
args: {}
|
|
41
|
-
assign: available_agents
|
|
42
40
|
- tool: get_skills_for_template
|
|
43
41
|
args: {}
|
|
44
42
|
assign: available_skills
|
|
@@ -54,6 +52,14 @@ instructions: |
|
|
|
54
52
|
Before starting work, check the `<available_skills>` section and load one if it matches.
|
|
55
53
|
Call `load_skill("skill_name")` and wait for the next turn before proceeding.
|
|
56
54
|
|
|
55
|
+
## Delegating to Sub-Agents
|
|
56
|
+
|
|
57
|
+
The list of available sub-agents is not auto-attached to your context. When a task
|
|
58
|
+
clearly benefits from a specialized agent (and isn't something you can handle inline),
|
|
59
|
+
call `list_available_agents()` to discover them, then `spawn_agent(path, prompt)` to
|
|
60
|
+
delegate. Skip both for simple tasks or single-file edits - most work doesn't need
|
|
61
|
+
delegation.
|
|
62
|
+
|
|
57
63
|
## Guidelines
|
|
58
64
|
|
|
59
65
|
- Be concise and direct in your responses
|
{tsugite_cli-0.14.0 → tsugite_cli-0.14.2}/tsugite/builtin_skills/tsugite-jinja-reference/SKILL.md
RENAMED
|
@@ -76,10 +76,11 @@ Injected via `AgentRenderer.env.globals`:
|
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
### Environment Access
|
|
79
|
-
- `env` → Dictionary of environment variables (`os.environ`)
|
|
79
|
+
- `env` → Dictionary of environment variables (`os.environ`). Also callable as `env(key, default)`.
|
|
80
80
|
```jinja2
|
|
81
81
|
Debug mode: {{ env.get("DEBUG", "false") }}
|
|
82
82
|
API endpoint: {{ env["API_URL"] }}
|
|
83
|
+
With default: {{ env("DEBUG", "false") }}
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
## Control Patterns
|
|
@@ -60,12 +60,9 @@ def chat(
|
|
|
60
60
|
workspace_attachments = _build_workspace_attachments(resolved_workspace)
|
|
61
61
|
|
|
62
62
|
with workspace_directory_context(resolved_workspace, root, console) as path_context:
|
|
63
|
-
# Handle conversation resume
|
|
64
|
-
resume_turns = None
|
|
65
|
-
|
|
66
63
|
if continue_ is not None:
|
|
67
64
|
from tsugite.agent_runner.history_integration import get_latest_conversation
|
|
68
|
-
from tsugite.history import get_history_dir
|
|
65
|
+
from tsugite.history import get_history_dir
|
|
69
66
|
|
|
70
67
|
if continue_ == "" or continue_.lower() == "latest":
|
|
71
68
|
history_opts.continue_id = get_latest_conversation()
|
|
@@ -77,16 +74,10 @@ def chat(
|
|
|
77
74
|
history_opts.continue_id = continue_
|
|
78
75
|
console.print(f"[cyan]Resuming conversation: {history_opts.continue_id}[/cyan]")
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
resume_turns = get_turns(session_path)
|
|
83
|
-
console.print(f"[cyan]Loaded {len(resume_turns)} previous turns[/cyan]")
|
|
84
|
-
except FileNotFoundError:
|
|
77
|
+
session_path = get_history_dir() / f"{history_opts.continue_id}.jsonl"
|
|
78
|
+
if not session_path.exists():
|
|
85
79
|
console.print(f"[red]Conversation not found: {history_opts.continue_id}[/red]")
|
|
86
80
|
raise typer.Exit(1)
|
|
87
|
-
except Exception as e:
|
|
88
|
-
console.print(f"[red]Failed to load conversation: {e}[/red]")
|
|
89
|
-
raise typer.Exit(1)
|
|
90
81
|
|
|
91
82
|
agent_to_load = agent if agent else "default"
|
|
92
83
|
_, primary_agent_path, _ = load_and_validate_agent(agent_to_load, console)
|
|
@@ -100,7 +91,6 @@ def chat(
|
|
|
100
91
|
agent_path=primary_agent_path,
|
|
101
92
|
exec_options=exec_opts,
|
|
102
93
|
history_options=history_opts,
|
|
103
|
-
resume_turns=resume_turns,
|
|
104
94
|
path_context=path_context,
|
|
105
95
|
workspace_attachments=workspace_attachments,
|
|
106
96
|
)
|
|
@@ -156,15 +156,15 @@ def test_hello_custom():
|
|
|
156
156
|
|
|
157
157
|
def _patch_root_pyproject(root_pyproject: Path, dist_name: str) -> None:
|
|
158
158
|
text = root_pyproject.read_text()
|
|
159
|
-
sources_line = f
|
|
159
|
+
sources_line = f"{dist_name} = {{ workspace = true }}\n"
|
|
160
160
|
dev_dep_line = f' "{dist_name}",\n'
|
|
161
161
|
|
|
162
162
|
if dist_name in text:
|
|
163
163
|
return # idempotent
|
|
164
164
|
|
|
165
165
|
new_text = re.sub(
|
|
166
|
-
r
|
|
167
|
-
rf
|
|
166
|
+
r"(\[tool\.uv\.sources\][^\[]*?tsugite-cli = \{ workspace = true \}\n)",
|
|
167
|
+
rf"\1{sources_line}",
|
|
168
168
|
text,
|
|
169
169
|
count=1,
|
|
170
170
|
)
|
|
@@ -172,8 +172,8 @@ def _patch_root_pyproject(root_pyproject: Path, dist_name: str) -> None:
|
|
|
172
172
|
raise typer.BadParameter("Could not locate [tool.uv.sources] block in root pyproject.toml")
|
|
173
173
|
|
|
174
174
|
new_text2 = re.sub(
|
|
175
|
-
r
|
|
176
|
-
rf
|
|
175
|
+
r"(\[dependency-groups\]\s*\ndev\s*=\s*\[(?:[^\]]|\n)*?)\n\]",
|
|
176
|
+
rf"\1\n{dev_dep_line.rstrip()}\n]",
|
|
177
177
|
new_text,
|
|
178
178
|
count=1,
|
|
179
179
|
)
|
|
@@ -185,7 +185,9 @@ def _patch_root_pyproject(root_pyproject: Path, dist_name: str) -> None:
|
|
|
185
185
|
|
|
186
186
|
@plugin_app.command("create")
|
|
187
187
|
def plugin_create(
|
|
188
|
-
name: str = typer.Argument(
|
|
188
|
+
name: str = typer.Argument(
|
|
189
|
+
help="Plugin short name (lowercase, alphanumeric + hyphens). E.g. 'discord' creates tsugite-discord."
|
|
190
|
+
),
|
|
189
191
|
dry_run: bool = typer.Option(False, "--dry-run", help="Print planned changes without writing"),
|
|
190
192
|
):
|
|
191
193
|
"""Scaffold a new workspace plugin under plugins/tsugite-<name>/."""
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""CLI run command - execute agents."""
|
|
2
2
|
|
|
3
|
-
import sys
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
from typing import Any, Dict, List, Optional, Tuple
|
|
6
5
|
|
|
@@ -97,16 +96,18 @@ def _resolve_ui_mode(ui_mode: Optional[str], ui_opts: UIOptions, console: Consol
|
|
|
97
96
|
console.print("[red]Error: --ui cannot be used with --plain or --headless[/red]")
|
|
98
97
|
raise typer.Exit(1)
|
|
99
98
|
|
|
100
|
-
ui_modes = {"plain", "headless"}
|
|
99
|
+
ui_modes = {"plain", "headless", "live"}
|
|
101
100
|
ui_lower = ui_mode.lower()
|
|
102
101
|
if ui_lower not in ui_modes:
|
|
103
|
-
console.print(f"[red]Error: Invalid UI mode '{ui_mode}'. Choose from: {', '.join(ui_modes)}[/red]")
|
|
102
|
+
console.print(f"[red]Error: Invalid UI mode '{ui_mode}'. Choose from: {', '.join(sorted(ui_modes))}[/red]")
|
|
104
103
|
raise typer.Exit(1)
|
|
105
104
|
|
|
106
105
|
if ui_lower == "plain":
|
|
107
106
|
ui_opts.plain = True
|
|
108
107
|
elif ui_lower == "headless":
|
|
109
108
|
ui_opts.headless = True
|
|
109
|
+
elif ui_lower == "live":
|
|
110
|
+
ui_opts.live = True
|
|
110
111
|
|
|
111
112
|
return ui_opts
|
|
112
113
|
|
|
@@ -169,7 +170,14 @@ def _execute_agent_with_ui(
|
|
|
169
170
|
use_plain_output: bool,
|
|
170
171
|
console: Console,
|
|
171
172
|
):
|
|
172
|
-
"""Execute agent with appropriate UI mode.
|
|
173
|
+
"""Execute agent with appropriate UI mode.
|
|
174
|
+
|
|
175
|
+
Dispatch order:
|
|
176
|
+
1. --headless / --final-only -> custom_agent_ui with silent progress
|
|
177
|
+
2. --ui live (on a real TTY) -> three-region LiveUIHandler
|
|
178
|
+
3. fall-through default -> plain logger (covers no flags, --plain, piped/NO_COLOR,
|
|
179
|
+
and --ui live degraded to plain by should_use_plain_output)
|
|
180
|
+
"""
|
|
173
181
|
from tsugite.ui import create_plain_logger, custom_agent_ui
|
|
174
182
|
|
|
175
183
|
if ui_opts.headless or ui_opts.final_only:
|
|
@@ -188,22 +196,16 @@ def _execute_agent_with_ui(
|
|
|
188
196
|
executor_kwargs["custom_logger"] = custom_logger
|
|
189
197
|
return executor(**executor_kwargs)
|
|
190
198
|
|
|
191
|
-
if use_plain_output:
|
|
192
|
-
|
|
193
|
-
|
|
199
|
+
if ui_opts.live and not use_plain_output:
|
|
200
|
+
from tsugite.ui import create_live_logger
|
|
201
|
+
|
|
202
|
+
custom_logger = create_live_logger(show_reasoning=ui_opts.show_reasoning)
|
|
203
|
+
with custom_logger.ui_handler.live_context():
|
|
194
204
|
executor_kwargs["custom_logger"] = custom_logger
|
|
195
205
|
return executor(**executor_kwargs)
|
|
196
206
|
|
|
197
|
-
|
|
198
|
-
with
|
|
199
|
-
console=default_console,
|
|
200
|
-
show_code=not ui_opts.non_interactive,
|
|
201
|
-
show_observations=not ui_opts.non_interactive,
|
|
202
|
-
show_progress=not ui_opts.no_color,
|
|
203
|
-
show_llm_messages=ui_opts.show_reasoning,
|
|
204
|
-
show_panels=False,
|
|
205
|
-
show_debug_messages=ui_opts.verbose,
|
|
206
|
-
) as custom_logger:
|
|
207
|
+
custom_logger = create_plain_logger(show_reasoning=ui_opts.show_reasoning)
|
|
208
|
+
with custom_logger.ui_handler.progress_context():
|
|
207
209
|
executor_kwargs["custom_logger"] = custom_logger
|
|
208
210
|
return executor(**executor_kwargs)
|
|
209
211
|
|
|
@@ -246,7 +248,11 @@ def run(
|
|
|
246
248
|
),
|
|
247
249
|
root: Optional[str] = typer.Option(None, "--root", help="Working directory"),
|
|
248
250
|
model: Optional[str] = typer.Option(None, "--model", "-m", help="Override agent model"),
|
|
249
|
-
ui: Optional[str] = typer.Option(
|
|
251
|
+
ui: Optional[str] = typer.Option(
|
|
252
|
+
None,
|
|
253
|
+
"--ui",
|
|
254
|
+
help="UI mode: plain, headless, or live. Default: plain (auto-degrades when piped or NO_COLOR is set)",
|
|
255
|
+
),
|
|
250
256
|
non_interactive: bool = typer.Option(False, "--non-interactive", help="Run without interactive prompts"),
|
|
251
257
|
history_dir: Optional[str] = typer.Option(None, "--history-dir", help="Directory to store history files"),
|
|
252
258
|
no_color: bool = typer.Option(False, "--no-color", help="Disable ANSI colors"),
|
|
@@ -407,8 +413,8 @@ def run(
|
|
|
407
413
|
import os
|
|
408
414
|
|
|
409
415
|
if subagent_mode:
|
|
410
|
-
if ui_opts.plain or ui_opts.headless:
|
|
411
|
-
console.print("[red]Error: --subagent-mode cannot be combined with --plain or --
|
|
416
|
+
if ui_opts.plain or ui_opts.headless or ui_opts.live:
|
|
417
|
+
console.print("[red]Error: --subagent-mode cannot be combined with --plain, --headless, or --ui live[/red]")
|
|
412
418
|
raise typer.Exit(1)
|
|
413
419
|
|
|
414
420
|
ui_opts.non_interactive = True
|
|
@@ -8,18 +8,47 @@ injected `state` object persist across turns.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import ast
|
|
11
|
+
import contextlib
|
|
11
12
|
import io
|
|
13
|
+
import os
|
|
12
14
|
import pprint
|
|
13
15
|
import sys
|
|
16
|
+
import threading
|
|
14
17
|
from dataclasses import dataclass, field
|
|
15
18
|
from pathlib import Path
|
|
16
|
-
from typing import Any, Callable, Dict, List, Optional
|
|
19
|
+
from typing import Any, Callable, Dict, Iterator, List, Optional
|
|
17
20
|
|
|
18
21
|
from tsugite.core.state import load_state, save_state
|
|
19
22
|
from tsugite.exceptions import StateSerializationError
|
|
20
23
|
|
|
21
24
|
PPRINT_WIDTH = 100
|
|
22
25
|
|
|
26
|
+
# CWD is process-global. Concurrent execute() calls in different threads must
|
|
27
|
+
# serialize their chdir+exec+restore window; the lock is held across the whole
|
|
28
|
+
# user-code exec(), so heavy parallel LocalExecutor turns serialize end-to-end.
|
|
29
|
+
# Accepted trade-off: silent disagreement between raw `os.getcwd()` and tool
|
|
30
|
+
# path resolution is worse than the serialization. `spawn_session` returns
|
|
31
|
+
# immediately so a parent holding the lock doesn't starve a nested child.
|
|
32
|
+
_chdir_lock = threading.Lock()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@contextlib.contextmanager
|
|
36
|
+
def _locked_chdir(target: Optional[Path]) -> Iterator[None]:
|
|
37
|
+
"""chdir to target under `_chdir_lock`; restore CWD and release on exit.
|
|
38
|
+
|
|
39
|
+
No-op when target is None.
|
|
40
|
+
"""
|
|
41
|
+
if target is None:
|
|
42
|
+
yield
|
|
43
|
+
return
|
|
44
|
+
with _chdir_lock:
|
|
45
|
+
previous = os.getcwd()
|
|
46
|
+
os.chdir(str(target))
|
|
47
|
+
try:
|
|
48
|
+
yield
|
|
49
|
+
finally:
|
|
50
|
+
os.chdir(previous)
|
|
51
|
+
|
|
23
52
|
|
|
24
53
|
def _looks_html_escaped(source: str) -> bool:
|
|
25
54
|
"""True if `source` is HTML-entity-escaped XML (observation content leaked into exec)."""
|
|
@@ -203,6 +232,11 @@ class LocalExecutor:
|
|
|
203
232
|
self._sticky_injections: Dict[str, Any] = {}
|
|
204
233
|
self._content_blocks: Dict[str, str] = {}
|
|
205
234
|
|
|
235
|
+
target = workspace_dir
|
|
236
|
+
if target is None and path_context is not None:
|
|
237
|
+
target = path_context.effective_cwd or path_context.workspace_dir
|
|
238
|
+
self._chdir_target_resolved: Optional[Path] = Path(target).resolve() if target is not None else None
|
|
239
|
+
|
|
206
240
|
self.namespace: Dict[str, Any] = self._build_turn_namespace()
|
|
207
241
|
|
|
208
242
|
def _build_turn_namespace(self) -> Dict[str, Any]:
|
|
@@ -317,11 +351,24 @@ class LocalExecutor:
|
|
|
317
351
|
return pprint.pformat(value, width=PPRINT_WIDTH, compact=False)
|
|
318
352
|
return repr(value)
|
|
319
353
|
|
|
354
|
+
def _workspace_chdir_target(self) -> Optional[Path]:
|
|
355
|
+
"""Target for the per-execute chdir, or None if CWD already matches (or no workspace)."""
|
|
356
|
+
target = self._chdir_target_resolved
|
|
357
|
+
if target is None:
|
|
358
|
+
return None
|
|
359
|
+
try:
|
|
360
|
+
if target == Path.cwd().resolve():
|
|
361
|
+
return None
|
|
362
|
+
except FileNotFoundError:
|
|
363
|
+
pass
|
|
364
|
+
return target
|
|
365
|
+
|
|
320
366
|
async def execute(self, code: str) -> ExecutionResult:
|
|
321
367
|
"""Execute code using exec().
|
|
322
368
|
|
|
323
369
|
Automatically displays the value of the last expression (REPL-like behavior).
|
|
324
|
-
|
|
370
|
+
When a workspace is bound, chdir to it under a process-wide lock so raw
|
|
371
|
+
Python file APIs (os.getcwd, open, Path.cwd) resolve against the workspace.
|
|
325
372
|
|
|
326
373
|
Args:
|
|
327
374
|
code: Python code to execute
|
|
@@ -367,19 +414,20 @@ class LocalExecutor:
|
|
|
367
414
|
sys.stdout = stdout_capture
|
|
368
415
|
sys.stderr = stderr_capture
|
|
369
416
|
|
|
370
|
-
|
|
417
|
+
with _locked_chdir(self._workspace_chdir_target()):
|
|
418
|
+
setup_code, last_expr = self._split_code_for_last_expr(code)
|
|
371
419
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
420
|
+
if last_expr:
|
|
421
|
+
if setup_code.strip():
|
|
422
|
+
exec(setup_code, self.namespace)
|
|
375
423
|
|
|
376
|
-
|
|
424
|
+
result = eval(last_expr, self.namespace)
|
|
377
425
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
426
|
+
if result is not None:
|
|
427
|
+
formatted = self._format_value(result)
|
|
428
|
+
print(formatted)
|
|
429
|
+
else:
|
|
430
|
+
exec(code, self.namespace)
|
|
383
431
|
|
|
384
432
|
except Exception as e:
|
|
385
433
|
exec_error = f"{type(e).__name__}: {str(e)}"
|