comate-cli 0.12.7b1__tar.gz → 0.12.8__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.
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/CHANGELOG.md +2 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/CONTEXT.md +5 -1
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/PKG-INFO +1 -1
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/main.py +18 -13
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/side_install.py +2 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/update_check.py +160 -9
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/update_messages.py +11 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/update_cli.py +89 -3
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/pyproject.toml +1 -1
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_side_install.py +28 -7
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_update_check.py +59 -39
- comate_cli-0.12.8/tests/test_update_mirror.py +338 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/uv.lock +1 -1
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/.agent/scheduled_prompts.json +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/.gitignore +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/.python-version +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/README.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/bash_settle_diag.log +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/__main__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/device_identity.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/distribution.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/mcp_cli.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/animations.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/app.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/approval_bridge.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/approval_content_preview.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/assistant_render.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/announcements.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/client.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/feedback.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/provider_snapshot.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/rating.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/runtime.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/session_report.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/session_title.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/backend/tasks.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/bash_command_display.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/browser_open.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/builtin_commands/.keep +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/builtin_commands/commit.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/builtin_commands/implement-plan.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/builtin_commands/learn.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/builtin_commands/open-pr.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/clipboard_image.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/clipboard_text.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/codenames.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/config/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/config/edit_session.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/config/model.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/config/picker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/config/picker_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/config/store.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/config_check.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/console_profile.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/context_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/custom_slash_commands.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/effort_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/effort_ruler.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/effort_style.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/env_utils.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/error_display.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/event_renderer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/exit_confirm_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/exit_watchdog.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/figures.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/file_ref_hint.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/focus_events.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/fragment_utils.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/goal_edit_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/goal_resume_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/history_printer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/i18n/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/i18n/_en.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/i18n/_ja.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/i18n/_zh.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/i18n/message.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/image_chips.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/input_geometry.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/job_activity.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/job_indicator.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/jobs_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/jobs_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/layout_coordinator.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/locale.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/logging_adapter.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/logging_file_handler.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/logo.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/loop_freeze_watchdog.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/markdown_render.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/mcp_serve.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/mention_completer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/menu_panel.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/message_style.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/model_tier_style.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/models.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/output_style_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/auto_update_runner.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/auto_update_store.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/components/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/components/detail_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/components/plugin_list.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/components/search_box.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/components/tab_bar.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/marketplace_install_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/operation_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/plugin_picker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/tabs/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/tabs/discover_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/tabs/errors_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/tabs/installed_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/plugins/tabs/marketplaces_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/preflight.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/preflight_wizard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/preflight_wizard_ui.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/print_mode.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/question_broker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/question_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/recap/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/recap/controller.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/resume_picker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/resume_preview.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/resume_selector.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/rpc_commands.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/rpc_relay.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/rpc_stdio.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/rpc_ws.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/scm_request_status.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/selection_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/sigint_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/skill_slash_input.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/skills_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/slash_commands.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/startup.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/startup_profile.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/status_bar.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/statusline/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/statusline/model.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/statusline/picker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/statusline/picker_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/statusline/store.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/stream_pacer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/suggestion/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/suggestion/controller.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/synchronized_output.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/text_effects.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/theme.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tip_highlight.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tips.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_approval_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_fold.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_fold_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_result_formatters.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_result_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_result_store.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_result_viewer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tool_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/transcript_viewer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/approval_queue.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/btw_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/commands.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/history_sync.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/input_behavior.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/key_bindings.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/mcp_auth_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/mcp_connecting_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/render_panels.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/resize_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/run_clock.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/shell_mode.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/slash_command_registry.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/tui_parts/ui_mode.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/ultracode_keyword.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/workflows_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_agent/workflows_panel_model.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/comate_cli/terminal_title.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/docs/cli-rpc-stdio-guide.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/docs/release-notes/0.12.3.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/docs/startup-performance.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/docs/superpowers/plans/2026-07-07-tui-first-repaint-before-sdk-submit.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/docs/superpowers/plans/2026-07-07-windows-update-manual-rollback.md +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/_fake_anthropic_server.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/_rpc_ws_client.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_config_exit.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_edit_session.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_model.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_picker_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_picker_ui.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_roundtrip.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_runtime_settings.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_skills_denylist_migration.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_store_load.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/config/test_store_save.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/conftest.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/fixtures/exit_watchdog_child.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/fixtures/fake_mcp_misbehaving_stdout.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/fixtures/mcp_stub_stdio_server.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/recap/test_idle_recap_controller.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/recap/test_recap_history_rendering.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/recap/test_tui_idle_recap_integration.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/statusline/__init__.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/statusline/test_model.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/statusline/test_picker_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/statusline/test_store.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/suggestion/test_next_step_suggestion_controller.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/suggestion/test_next_step_suggestion_render.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/suggestion/test_tab_accepts_next_step_suggestion.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/suggestion/test_tui_next_step_suggestion_integration.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_animations_styles.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_animator_shuffle.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_config_check_gate.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_disallowed_tools.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_exit_lifecycle.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_mcp_needs_auth_hint.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_mcp_preload.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_mcp_preload_kick.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_preflight_gate.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_print_mode.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_profile_threading.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_pty_ctrl_b.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_pty_ctrl_c_exit.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_pty_live_tail.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_pty_shell_mode.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_pty_smoke.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_shutdown.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_startup_latency.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_startup_order.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_token_cost_config.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_app_usage_line.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_approval_bridge.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_approval_content_preview.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_backend_announcements.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_backend_client.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_backend_feedback.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_backend_provider_snapshot.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_backend_rating.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_backend_session_report.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_backend_tasks.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_btw_slash_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_builtin_marketplaces.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_busy_slash_gating.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_cli_project_root.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_clipboard_chip_restore.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_clipboard_image_reader.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_clipboard_text.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_commands_system_messages.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_compact_command_semantics.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_completion_context_activation.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_completion_status_panel.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_config_check.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_console_profile.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_context_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_context_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_context_view_tool_search.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ctrl_b_background.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ctrl_c_clear_input.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_custom_slash_commands.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_device_identity.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_discover_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_distribution_contract.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_drain_frame_atomicity.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_effort_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_effort_menu_frame_rate.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_effort_ruler.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_effort_slash_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_effort_style.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_errors_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_approval_wait.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_bash_background.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_boundary.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_budget_floor.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_e2e.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_fixed_overhead.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_idle_prune.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_jobs.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_log_boundary.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_log_queue.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_mcp_background.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_oversized_tools.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_provider_overflow.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_shell.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_stream_pacing.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_stream_staging.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_streaming.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_tool_args_progress.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_tool_fold.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_event_renderer_tool_search_notice.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_exit_confirm_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_exit_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_exit_watchdog.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_exit_watchdog_subprocess.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_file_ref_hint.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_focus_events.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_format_error.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_goal_edit_handlers.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_goal_edit_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_goal_paused_hint.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_goal_resume_tui.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_goal_resume_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_goal_slash_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_handle_error.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_drain_throttle.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_printer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_printer_log.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_printer_styles.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_printer_subtitle_position.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_printer_tool_fold.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_sync.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_history_sync_tool_fold.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_i18n.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_image_chip_deletion.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_image_chips.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_image_preprocess_offload_lag.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_import_weight.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_input_behavior.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_input_history.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_input_separator_counter.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_installed_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_interrupt_exit_semantics.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_job_activity.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_job_indicator.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_job_indicator_host.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_job_indicator_pty.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_jobs_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_jobs_menu_host.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_jobs_menu_pty.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_jobs_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_key_bindings_system_messages.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_layout_coordinator.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_live_output_tail.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_loading_line_fragments.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_loading_modal_suppression.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_loading_tip_picker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_logging_adapter.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_logging_file_handler.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_logo.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_loop_freeze_watchdog.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_main_args.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_main_args_yolo.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_main_profile_entry.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_markdown_render.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_marketplace_add_commands.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_marketplace_install_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_marketplaces_tab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_auth_panel_pty.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_cli.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_cli_auth.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_cli_scope_defaults.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_cli_stdout_encoding.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_jobs_pty.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_panel_auth.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_serve.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mcp_slash_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_mention_completer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_menu_cursor_unification.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_menu_panel.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_menu_panel_pty.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_message_style.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_modal_freeze_timing.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_modal_panel_visibility.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_model_switch_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_model_tier_style.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_no_raw_colors.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_output_style_slash_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_permission_mode_cycle.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_plugin_auto_update_runner.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_plugin_auto_update_store.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_plugin_auto_update_tui.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_plugin_mcp_keeps_disk_servers.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_plugin_operation_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_plugin_slash_commands.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_plugin_tui_components.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_preflight.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_preflight_copilot.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_preflight_wizard_ui.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_print_mode_monitor_cap.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_print_mode_stdout_encoding.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_pty_output_integrity.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_question_broker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_question_key_bindings.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_question_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_resize_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_resume_picker.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_resume_preview.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_resume_selector.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rewind_command_semantics.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rpc_mode_logging.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rpc_relay_dial_out.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rpc_relay_e2e_smoke.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rpc_relay_process_smoke.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rpc_v4_stdio_smoke.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rpc_v4_ws_smoke.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_rpc_ws_bind_failure.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_run_clock.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_running_tool_live_tail.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_running_tool_status_line.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_scm_request_status.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_scrollback_write_encoding.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_selection_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_session_auto_title.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_session_query_token_summary.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_settings_write_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_shell_mode.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_shutdown_noise_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_shutdown_noise_integration.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_sigint_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_sigint_key_binding.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_skill_slash_input.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_skills_slash_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_slash_add_dir.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_slash_argument_hint.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_slash_clear.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_slash_completer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_slash_registry.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_startup_import_budget.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_startup_profile.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_status_bar.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_status_bar_mid_turn_refresh.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_status_bar_request_status.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_status_bar_transient.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_stream_pacer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_stream_pacing_tick.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_stream_staging_panel.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_style_class_coverage.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_synchronized_output.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tab_title.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_task_panel_format.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_task_panel_key_bindings.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_task_panel_rendering.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_task_poll.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_terminal_title.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_theme.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tip_highlight.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tips.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_todo_panel_busy_gating.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_approval_key_bindings.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_approval_tui.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_approval_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_approval_view_workflow.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_call_protection.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_fold.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_fold_panel.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_fold_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_result_formatters.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_result_state.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_result_store.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_result_viewer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_result_viewer_key_bindings.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_view.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tool_view_styles.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_transcript_viewer.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_transcript_viewer_record_matching.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_transcript_viewer_tool_fold.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_builtin_slash_chain.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_deferred_prewarm.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_elapsed_status.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_esc_queue.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_exit_idempotence.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_exit_paced_tail.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_exit_pending_logs.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_hot_reload.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_image_chip_retention.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_image_chip_seed.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_image_paste.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_image_path_upgrade.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_image_restore.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_image_submit.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_interrupt_queue_recall.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_llm_retry_panel.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_loading_tip_rotation.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_local_interactive_barrier.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_mcp_init_gate.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_paste_history_persistence.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_paste_newline_guard.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_paste_placeholder.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_plugin_load.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_provider_error_shield.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_queue_pop_images.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_queue_preview.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_queue_sdk_source.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_replace_session_resume_hint.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_scheduled_fire_log.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_scratchpad_fold_wiring.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_send_undo_window.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_session_observers.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_shutdown_cancel_propagation.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_split_invariance.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_startup_latency.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_surrogate_repair.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_thinking_display.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_tool_result_registry_lifecycle.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_tui_window_too_small_fallback.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ui_mode_derivation.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ui_tick_exception_isolation.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ultracode_keyword.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ultracode_keyword_frame_rate.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ultracode_keyword_submit.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_ultracode_shimmer_render.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_update_cli.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_upstream_surrogate_merge_characterization.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_usage_command.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_wellformed_terminal_input.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_whitelabel_clear_logo.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_windows_sigint_console.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_workflows_menu.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_workflows_menu_host.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_workflows_menu_pty.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_workflows_panel_model.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_wrap_user_text.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tests/test_zipapp_launcher_path.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/diagnose_windows_shim_rename.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/logo_lab.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/nico_preview.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/probe_conhost_char_width.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/probe_conhost_render_replay.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/startup_bench.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/transcript_viewer_bench.py +0 -0
- {comate_cli-0.12.7b1 → comate_cli-0.12.8}/tools/verify_windows_self_update_semantics.py +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
6
|
|
|
7
|
+
- `update --mirror <tag|url>`:这一次更新改用指定的 PyPI 包索引,查版本和装包都用它,不写入设置。tag 不分大小写:`pypi`、`tuna`、`aliyun`、`tencent`、`huawei`、`ustc`;也可以直接写 `http://` 或 `https://` 开头的 simple 地址(例 `--mirror=https://pypi.corp.example/simple`)。查版本读该索引的 simple 页(PEP 691 JSON 或 PEP 503 HTML),不用 `/pypi/<包名>/json`——阿里云、腾讯云、华为云没有这个接口;yanked 版本和预发布规则与原来一致。装包时 macOS/Linux 重装、Windows 旁装、Windows 手动修复命令都带 `--default-index <地址>`,简中用户的手动命令不再追加清华。输出多一行「使用包索引:<地址>」,四种语言齐全。值缺失、tag 不认识(会列出全部 tag)、`--mirror` 重复时退出码 2,不开始更新。白牌发行版自己管理更新源(如 hico),带 `--mirror` 时退出码 2 并说明原因。不带 `--mirror` 时行为不变:简中 locale 用清华,其他用 pypi.org。只改包索引,Python 下载镜像仍用 `UV_PYTHON_INSTALL_MIRROR` 环境变量。
|
|
7
8
|
- `--disallowed-tools <names>` 启动参数:本次会话不把这些 tool 发给模型,子 agent 也拿不到(进入 SDK 的 `AgentConfig.disallowed_tools`)。名字逗号分隔,参数可重复,结果按出现顺序合并去重;只认精确名字,MCP tool 写 `mcp__<server>__<tool>`。TUI、`resume`、`--rpc-stdio`、`--rpc-ws`、`--rpc-relay` 都生效(RPC 下对整个进程生效);`-p` 下与它自带的 `SendMessage` 取并集。以下情况都在启动前报错退出:值为空、含 `*`、写了 `Agent` 或 `Skill`(这两个去掉后会话无法创建)、内置名拼错或大小写不对(`mcp__` 开头的名字不检查,MCP 在启动后才连接)。`comate mcp serve` 不支持。
|
|
8
9
|
- 运行中的 Bash 显示 Live Output Tail:模型调用的 Bash 运行时,底部 running-tool 面板每秒读取一次最近输出,在签名行与 Running 状态行之间显示最多 3 个非空行(第一行带 `⎿`),`\r` 覆写的进度条只显示最后一段;`!` 命令活动区从 5 行改为 3 行。两处共用同一套行处理:丢空行、长行按显示宽度截断加 `…` 不折行(中文 / emoji 占 2 列)。命令结束、ctrl+b 转后台或中断后尾部立即消失,不进滚动区;折叠的 Bash 与子 agent 的 Bash 不受影响。
|
|
9
10
|
- Interpreter Migration(macOS/Linux):CLI 不在 Python 3.12 上、并且没有待更新的新版本时,第一次启动在界面之前显示一行提示,之后的启动显示全屏提示,只有「立即迁移」和「跳过」。「立即迁移」把**当前版本**(`<包名>==<当前版本>`,带发行版的安装参数)用 `--python 3.12` 重装,成功后提示重启,本次启动停止;失败只显示一行原因(uv 输出的最后一行),继续在当前 Python 上进入界面。「跳过」不记住,下次启动再问。已经在 3.12、editable 安装、PATH 里没有 uv、Windows 都不提示;有待更新的新版本时只显示更新提示(接受更新会顺带迁移到 3.12)。文案四种语言齐全。
|
|
@@ -75,6 +76,7 @@
|
|
|
75
76
|
|
|
76
77
|
### Changed
|
|
77
78
|
|
|
79
|
+
- Self-Update 不再把用户换到 Python 3.12:`comate update`、启动时的「立即更新」、Windows 旁装,以及 Windows 手动修复命令,uv 命令里的 `--python` 改为当前解释器的 `主版本.次版本`(例如在 3.13 上运行就带 `--python 3.13`),更新后留在原来的 Python 上。命令仍然带 `--python`,否则 `--force` 重装会漂到 uv 默认找到的解释器上。不在 `requires-python` 范围内的解释器(例如 3.14)也照样保持。白牌发行版在 `install_args` 里自己指定了 `--python` 时仍以白牌为准,可以用它固定版本(例如 `"--python", "3.13.12"`)。决策见 ADR 0064。
|
|
78
80
|
- 状态栏的 Job Indicator 只统计正在运行的后台 job:后台 subagent 跑完一轮进入待命(idle)后,不再显示 `x agent`;1 个运行中、2 个待命时显示 `1 agent`。待命的 agent 仍可在 `/ps` 里查看和停止,退出确认仍会提示它们(ADR 0050 补充)。
|
|
79
81
|
- Self-Update 固定到 Python 3.12:`comate update`、启动时的「立即更新」、Windows 旁装,以及 Windows 自动路径不可用时显示的手动修复命令,都让新版本装在 Python 3.12 上(uv 命令带 `--python 3.12`;机器上没有 3.12 时 uv 会自动下载)。原因:uv 在读包之前就选好解释器,并且忽略 `requires-python` 的上限,所以以前用户会跑在 3.11 / 3.13 / 3.14 等不同版本上,而且不带 `--python` 的重装会把已经在 3.12 上的环境换成别的版本。白牌发行版在 `install_args` 里自己指定了 `--python` 时,以白牌的为准。`requires-python` 不变,3.11–3.13 继续支持。决策见 ADR 0055。
|
|
80
82
|
- 简中用户更新时,uv 需要下载的 Python 改走国内镜像(npmmirror 的 python-build-standalone),不再依赖 GitHub;进程内重装和 Windows 旁装都生效。你自己设置了 `UV_PYTHON_INSTALL_MIRROR` 时以你的为准;其他语言环境不变。
|
|
@@ -212,6 +212,10 @@ _Avoid_: update check, update detection (plugin term), has-update probe
|
|
|
212
212
|
Where a Version Check reads the newest version from: the public package index for the default distribution, or the whitelabel distribution's own index. It is derived from the distribution profile, never hard-coded.
|
|
213
213
|
_Avoid_: registry, mirror (a mirror is one way to reach the same source)
|
|
214
214
|
|
|
215
|
+
**Update Mirror**:
|
|
216
|
+
A PyPI package index the user names for one `update` run (`--mirror <tag|url>`). It replaces the default Release Source for both the Version Check (read from the index's simple page) and the install of that run, and is never saved. Distributions with their own Release Source refuse it.
|
|
217
|
+
_Avoid_: Python download mirror (that is `UV_PYTHON_INSTALL_MIRROR`), update source setting
|
|
218
|
+
|
|
215
219
|
**Side-Install**:
|
|
216
220
|
Installing a new CLI version into its own version-isolated location without touching the currently running installation. Used where the running installation cannot be rebuilt in place.
|
|
217
221
|
_Avoid_: in-place upgrade, reinstall, versioned install
|
|
@@ -389,7 +393,7 @@ _Avoid_: lag log, profiler output (the profiler records phase durations, not a s
|
|
|
389
393
|
- **Self-Update** and **Plugin Auto Update** are separate concepts with separate vocabularies: a **Version Check** orders versions, plugin **Update Detection** only compares for equality. Neither triggers the other.
|
|
390
394
|
- A **Side-Install** followed by an **Entrypoint Flip** is one Self-Update strategy; an in-process reinstall of the current installation is another. Which one applies is a property of the platform, not of the user's choice.
|
|
391
395
|
- **Restart-to-Apply** holds for every Self-Update strategy and mirrors the plugin **Update Effectiveness Boundary**: on-disk state changes, the running process does not.
|
|
392
|
-
- **Self-Update**
|
|
396
|
+
- **Self-Update** keeps the installation on the interpreter it runs on: every uv install command requests the running `major.minor` (ADR 0064), unless the distribution profile's `install_args` already pins `--python`. There is no target Python; a CLI moves to another interpreter only when a whitelabel pin asks for it.
|
|
393
397
|
|
|
394
398
|
- A **Session Title** is a fact of the session, not of the **Session Report**: it exists whether or not a report backend is configured, and the report only mirrors it. **Durable Title Completion** is therefore judged from the session's own metadata.
|
|
395
399
|
- A **Session Title** is generated from the session's earliest **Committed Title Input**, never from the latest one. A resumed session without a title is titled from its original first input, so the title does not change to whatever was typed after resume.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: comate-cli
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.8
|
|
4
4
|
Summary: Comate terminal CLI built on comate-agent-sdk
|
|
5
5
|
Project-URL: Homepage, https://github.com/AndyLee1024/agent-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/AndyLee1024/agent-sdk
|
|
@@ -317,6 +317,9 @@ class _ShutdownNoiseGuard:
|
|
|
317
317
|
|
|
318
318
|
|
|
319
319
|
def _usage_text(command_name: str = "comate") -> str:
|
|
320
|
+
# 懒导入:usage 只在 --help 与参数错误时生成,不让启动路径多 import 更新模块。
|
|
321
|
+
from comate_cli.update_cli import UPDATE_MIRROR_TAGS
|
|
322
|
+
|
|
320
323
|
return (
|
|
321
324
|
"Usage:\n"
|
|
322
325
|
f" {command_name} [--rpc-stdio] [--add-dir <path>]...\n"
|
|
@@ -326,7 +329,7 @@ def _usage_text(command_name: str = "comate") -> str:
|
|
|
326
329
|
f" {command_name} -p [--output-format text|json] <prompt>\n"
|
|
327
330
|
f" {command_name} resume [<session_id>]\n"
|
|
328
331
|
f" {command_name} mcp <subcommand> [options]\n"
|
|
329
|
-
f" {command_name} update [--pre]\n"
|
|
332
|
+
f" {command_name} update [--pre] [--mirror <tag|url>]\n"
|
|
330
333
|
"\n"
|
|
331
334
|
f'MCP subcommands (run "{command_name} mcp <subcommand> --help" for details):\n'
|
|
332
335
|
f" add Add an MCP server to {command_name}\n"
|
|
@@ -366,7 +369,10 @@ def _usage_text(command_name: str = "comate") -> str:
|
|
|
366
369
|
" bypassPermissions; refused by default\n"
|
|
367
370
|
" --yolo Start in bypassPermissions (YOLO) mode\n"
|
|
368
371
|
" --version, -V Print version and exit\n"
|
|
369
|
-
" --pre (update) Also consider pre-release versions"
|
|
372
|
+
" --pre (update) Also consider pre-release versions\n"
|
|
373
|
+
" --mirror <tag|url> (update) PyPI package index for this update only (not the Python\n"
|
|
374
|
+
" download mirror): an http(s):// URL or one of\n"
|
|
375
|
+
f" {', '.join(UPDATE_MIRROR_TAGS)}"
|
|
370
376
|
)
|
|
371
377
|
|
|
372
378
|
|
|
@@ -881,19 +887,18 @@ def main(argv: list[str] | None = None, *, profile=None) -> None:
|
|
|
881
887
|
return
|
|
882
888
|
|
|
883
889
|
if run_argv and run_argv[0] == "update":
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
)
|
|
892
|
-
raise SystemExit(2)
|
|
893
|
-
from comate_cli.update_cli import run_update_cli
|
|
890
|
+
from comate_cli.update_cli import UpdateArgumentError, parse_update_args, run_update_cli
|
|
891
|
+
|
|
892
|
+
try:
|
|
893
|
+
include_prereleases, index_url = parse_update_args(run_argv[1:])
|
|
894
|
+
except UpdateArgumentError as exc:
|
|
895
|
+
sys.stderr.write(f"update: {exc}\n{_usage_text(command_name=command_name)}\n")
|
|
896
|
+
raise SystemExit(2) from None
|
|
894
897
|
|
|
895
898
|
raise SystemExit(
|
|
896
|
-
run_update_cli(
|
|
899
|
+
run_update_cli(
|
|
900
|
+
profile=profile, include_prereleases=include_prereleases, index_url=index_url
|
|
901
|
+
)
|
|
897
902
|
)
|
|
898
903
|
|
|
899
904
|
if run_argv and run_argv[0] == "mcp":
|
|
@@ -398,6 +398,7 @@ async def stage_update(
|
|
|
398
398
|
_notify(progress, StagePhase.STAGING)
|
|
399
399
|
# 延迟导入理由同 _staging_env:顶层互导会成环。
|
|
400
400
|
from comate_cli.terminal_agent.update_check import (
|
|
401
|
+
default_index_args,
|
|
401
402
|
index_strategy_fallback_args,
|
|
402
403
|
python_request_args,
|
|
403
404
|
)
|
|
@@ -414,6 +415,7 @@ async def stage_update(
|
|
|
414
415
|
"--refresh",
|
|
415
416
|
*python_request_args(target.install_args),
|
|
416
417
|
*index_strategy_fallback_args(target.install_args),
|
|
418
|
+
*default_index_args(target.index_url),
|
|
417
419
|
*target.install_args,
|
|
418
420
|
)
|
|
419
421
|
code, output = await run(
|
|
@@ -190,6 +190,9 @@ class UpdateTarget:
|
|
|
190
190
|
install_args: tuple[str, ...] = ()
|
|
191
191
|
command_name: str = "comate"
|
|
192
192
|
python_install_mirror: str | None = None
|
|
193
|
+
# `<command> update --mirror` 指定的包索引(simple 地址);只在这一次运行里有效。
|
|
194
|
+
# 设置后 Version Check 读它的 simple 页,三条安装路径都带 --default-index。
|
|
195
|
+
index_url: str | None = None
|
|
193
196
|
|
|
194
197
|
def update_command(self, *, pin_version: str | None = None) -> tuple[str, ...]:
|
|
195
198
|
"""进程内重装命令(macOS/Linux 路径)。"""
|
|
@@ -205,6 +208,7 @@ class UpdateTarget:
|
|
|
205
208
|
"--refresh",
|
|
206
209
|
*python_request_args(self.install_args),
|
|
207
210
|
*index_strategy_fallback_args(self.install_args),
|
|
211
|
+
*default_index_args(self.index_url),
|
|
208
212
|
*self.install_args,
|
|
209
213
|
)
|
|
210
214
|
|
|
@@ -274,6 +278,17 @@ def _pins_default_index(install_args: tuple[str, ...]) -> bool:
|
|
|
274
278
|
return any(arg in _DEFAULT_INDEX_FLAGS for arg in install_args)
|
|
275
279
|
|
|
276
280
|
|
|
281
|
+
def has_own_update_source(target: UpdateTarget) -> bool:
|
|
282
|
+
"""白牌自己管理更新源(profile 查询源或 install_args 已设默认索引):此时拒绝 --mirror。
|
|
283
|
+
uv 对重复的 --default-index 直接报错(实测 2026-11-06)。"""
|
|
284
|
+
return target.fetch_latest is not None or _pins_default_index(target.install_args)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def default_index_args(index_url: str | None) -> tuple[str, ...]:
|
|
288
|
+
# 命令行的 --default-index 盖过子进程环境里注入的清华 UV_DEFAULT_INDEX(实测 2026-11-06)。
|
|
289
|
+
return ("--default-index", index_url) if index_url else ()
|
|
290
|
+
|
|
291
|
+
|
|
277
292
|
def _install_spec(package: str, pin_version: str | None) -> str:
|
|
278
293
|
"""正式版沿用 `@latest`;目标是预发布版时精确 pin `==<version>`:`@latest`
|
|
279
294
|
会解析到最新正式版,把 beta 用户降级(Q9 预发布规则的另一半)。
|
|
@@ -296,10 +311,15 @@ def index_strategy_fallback_args(install_args: tuple[str, ...]) -> tuple[str, ..
|
|
|
296
311
|
return () if "--index-strategy" in install_args else _INDEX_STRATEGY_FALLBACK
|
|
297
312
|
|
|
298
313
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
314
|
+
def _running_python() -> str:
|
|
315
|
+
"""当前进程解释器的 `主版本.次版本`:Self-Update 后保持在这个版本上(ADR 0064)。
|
|
316
|
+
|
|
317
|
+
uv 在读包之前就选好 tool 环境的解释器,且忽略 requires-python 上限,所以只有命令里的
|
|
318
|
+
--python 能定运行时;实测 2026-11-02:不带它的 `--force` 重装把 3.12 环境重建到了
|
|
319
|
+
uv 默认找到的 3.13 上。不带补丁号:当前解释器已在机器上,uv 不用下载。
|
|
320
|
+
"""
|
|
321
|
+
major, minor = sys.version_info[:2]
|
|
322
|
+
return f"{major}.{minor}"
|
|
303
323
|
|
|
304
324
|
|
|
305
325
|
def _pins_python(install_args: tuple[str, ...]) -> bool:
|
|
@@ -313,7 +333,7 @@ def _pins_python(install_args: tuple[str, ...]) -> bool:
|
|
|
313
333
|
|
|
314
334
|
|
|
315
335
|
def python_request_args(install_args: tuple[str, ...]) -> tuple[str, ...]:
|
|
316
|
-
return () if _pins_python(install_args) else ("--python",
|
|
336
|
+
return () if _pins_python(install_args) else ("--python", _running_python())
|
|
317
337
|
|
|
318
338
|
|
|
319
339
|
def windows_update_command(
|
|
@@ -336,9 +356,15 @@ def windows_update_command(
|
|
|
336
356
|
target.package,
|
|
337
357
|
*python_request_args(target.install_args),
|
|
338
358
|
*index_strategy_fallback_args(target.install_args),
|
|
359
|
+
*default_index_args(target.index_url),
|
|
339
360
|
*target.install_args,
|
|
340
361
|
]
|
|
341
|
-
|
|
362
|
+
# 用户用 --mirror 指定了索引时不追加清华:uv 对重复的 --default-index 直接报错。
|
|
363
|
+
if (
|
|
364
|
+
_is_chinese_locale()
|
|
365
|
+
and target.index_url is None
|
|
366
|
+
and not _pins_default_index(target.install_args)
|
|
367
|
+
):
|
|
342
368
|
command += ["--default-index", TUNA_PYPI_INDEX]
|
|
343
369
|
return tuple(command)
|
|
344
370
|
|
|
@@ -414,8 +440,9 @@ def _is_chinese_locale() -> bool:
|
|
|
414
440
|
def uv_default_index_env(*, python_install_mirror: str | None = None) -> dict[str, str]:
|
|
415
441
|
"""uv 安装子进程的镜像环境变量。
|
|
416
442
|
|
|
417
|
-
简中 locale:包索引(清华)与 Python 下载镜像(npmmirror
|
|
418
|
-
|
|
443
|
+
简中 locale:包索引(清华)与 Python 下载镜像(npmmirror)。安装命令请求的 Python
|
|
444
|
+
(白牌在 install_args 里指定的版本)机器上没有时,uv 默认从 GitHub 下载,国内可能慢或
|
|
445
|
+
失败(ADR 0055 取舍四)。
|
|
419
446
|
白牌镜像 `python_install_mirror` 不看 locale,并且盖过 npmmirror(ADR 0056)。
|
|
420
447
|
调用方以 setdefault 语义合并,用户已显式设置的同名变量不覆盖。
|
|
421
448
|
"""
|
|
@@ -462,6 +489,125 @@ def pypi_json_source(
|
|
|
462
489
|
return fetch
|
|
463
490
|
|
|
464
491
|
|
|
492
|
+
# PEP 691 JSON 优先,退回 PEP 503 HTML。实测 2026-11-06:pypi.org / 清华 / 中科大回 JSON,
|
|
493
|
+
# 阿里云 / 腾讯云 / 华为云只回 HTML;后三家的 `/pypi/<pkg>/json` 都是 404,所以 --mirror 不用 JSON API。
|
|
494
|
+
_SIMPLE_INDEX_ACCEPT = "application/vnd.pypi.simple.v1+json, text/html;q=0.1"
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def simple_index_source(
|
|
498
|
+
package: str,
|
|
499
|
+
index_url: str,
|
|
500
|
+
*,
|
|
501
|
+
include_prereleases: bool = False,
|
|
502
|
+
) -> LatestVersionFetcher:
|
|
503
|
+
"""`--mirror` 的 Version Check:读 `<index_url>/<package>/`,从文件名取版本。"""
|
|
504
|
+
|
|
505
|
+
async def fetch() -> LatestRelease | None:
|
|
506
|
+
from packaging.utils import canonicalize_name
|
|
507
|
+
|
|
508
|
+
url = f"{index_url}/{canonicalize_name(package)}/"
|
|
509
|
+
files = await _fetch_simple_index_files(url, trust_env=_update_check_trust_env())
|
|
510
|
+
payload = _simple_index_payload(files, package)
|
|
511
|
+
latest = _select_latest_version(
|
|
512
|
+
payload,
|
|
513
|
+
current=installed_version(package),
|
|
514
|
+
include_prereleases=include_prereleases,
|
|
515
|
+
)
|
|
516
|
+
return LatestRelease(version=latest)
|
|
517
|
+
|
|
518
|
+
return fetch
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
async def _fetch_simple_index_files(url: str, *, trust_env: bool) -> list[tuple[str, bool]]:
|
|
522
|
+
"""返回 (文件名, 是否 yanked) 列表。网络/解析失败直接抛,由 `<command> update` 报「连不上」。"""
|
|
523
|
+
import httpx
|
|
524
|
+
|
|
525
|
+
client_kwargs: dict[str, Any] = {"timeout": 3.0, "trust_env": trust_env}
|
|
526
|
+
if not trust_env:
|
|
527
|
+
ssl_context = await _get_update_check_ssl_context_off_loop()
|
|
528
|
+
if ssl_context is None:
|
|
529
|
+
raise _UpdateCheckTransportUnavailable("update check SSL context is unavailable")
|
|
530
|
+
client_kwargs["verify"] = ssl_context
|
|
531
|
+
async with httpx.AsyncClient(**client_kwargs) as client:
|
|
532
|
+
resp = await client.get(
|
|
533
|
+
url, headers={"Accept": _SIMPLE_INDEX_ACCEPT}, follow_redirects=True
|
|
534
|
+
)
|
|
535
|
+
resp.raise_for_status()
|
|
536
|
+
if "application/vnd.pypi.simple.v1+json" in resp.headers.get("content-type", ""):
|
|
537
|
+
return [
|
|
538
|
+
(str(item["filename"]), bool(item.get("yanked")))
|
|
539
|
+
for item in resp.json()["files"]
|
|
540
|
+
]
|
|
541
|
+
return _parse_simple_index_html(resp.text)
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def _parse_simple_index_html(text: str) -> list[tuple[str, bool]]:
|
|
545
|
+
"""PEP 503:每个 `<a>` 的文本是文件名;有 `data-yanked` 属性即 yanked(PEP 592)。"""
|
|
546
|
+
from html.parser import HTMLParser
|
|
547
|
+
|
|
548
|
+
class _Links(HTMLParser):
|
|
549
|
+
def __init__(self) -> None:
|
|
550
|
+
super().__init__()
|
|
551
|
+
self.files: list[tuple[str, bool]] = []
|
|
552
|
+
self._open: tuple[bool, list[str]] | None = None
|
|
553
|
+
|
|
554
|
+
def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
|
|
555
|
+
if tag == "a":
|
|
556
|
+
self._open = (any(name == "data-yanked" for name, _ in attrs), [])
|
|
557
|
+
|
|
558
|
+
def handle_data(self, data: str) -> None:
|
|
559
|
+
if self._open is not None:
|
|
560
|
+
self._open[1].append(data)
|
|
561
|
+
|
|
562
|
+
def handle_endtag(self, tag: str) -> None:
|
|
563
|
+
if tag == "a" and self._open is not None:
|
|
564
|
+
yanked, parts = self._open
|
|
565
|
+
self.files.append(("".join(parts).strip(), yanked))
|
|
566
|
+
self._open = None
|
|
567
|
+
|
|
568
|
+
parser = _Links()
|
|
569
|
+
parser.feed(text)
|
|
570
|
+
parser.close()
|
|
571
|
+
return parser.files
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def _simple_index_payload(files: list[tuple[str, bool]], package: str) -> dict[str, Any]:
|
|
575
|
+
"""把文件列表整理成 PyPI JSON 的形状,交给 _select_latest_version 套用同一套预发布规则。
|
|
576
|
+
|
|
577
|
+
`info.version` 取最大的未 yanked 正式版(没有正式版时取最大的未 yanked 版本);
|
|
578
|
+
一个版本的文件全部 yanked 才算 yanked,与 _select_latest_version 一致。
|
|
579
|
+
"""
|
|
580
|
+
from packaging.utils import canonicalize_name, parse_sdist_filename, parse_wheel_filename
|
|
581
|
+
from packaging.version import Version
|
|
582
|
+
|
|
583
|
+
wanted = canonicalize_name(package)
|
|
584
|
+
releases: dict[str, list[dict[str, bool]]] = {}
|
|
585
|
+
for filename, yanked in files:
|
|
586
|
+
try:
|
|
587
|
+
if filename.endswith(".whl"):
|
|
588
|
+
name, version, _build, _tags = parse_wheel_filename(filename)
|
|
589
|
+
elif filename.endswith((".tar.gz", ".zip")):
|
|
590
|
+
name, version = parse_sdist_filename(filename)
|
|
591
|
+
else:
|
|
592
|
+
continue
|
|
593
|
+
except ValueError:
|
|
594
|
+
logger.debug("skipping unparsable index file name: %s", filename)
|
|
595
|
+
continue
|
|
596
|
+
if name != wanted:
|
|
597
|
+
continue
|
|
598
|
+
releases.setdefault(str(version), []).append({"yanked": yanked})
|
|
599
|
+
|
|
600
|
+
available = [
|
|
601
|
+
Version(raw)
|
|
602
|
+
for raw, entries in releases.items()
|
|
603
|
+
if not all(entry["yanked"] for entry in entries)
|
|
604
|
+
]
|
|
605
|
+
if not available:
|
|
606
|
+
raise ValueError(f"no installable {package} versions on the index")
|
|
607
|
+
stable = [version for version in available if not version.is_prerelease]
|
|
608
|
+
return {"info": {"version": str(max(stable or available))}, "releases": releases}
|
|
609
|
+
|
|
610
|
+
|
|
465
611
|
def _select_latest_version(
|
|
466
612
|
payload: dict[str, Any],
|
|
467
613
|
*,
|
|
@@ -595,6 +741,10 @@ async def fetch_latest_release(
|
|
|
595
741
|
启动期 best-effort 语义。include_prereleases 只对 PyPI 源有意义:白牌
|
|
596
742
|
profile 源只回一个版本号,没有预发布的概念。
|
|
597
743
|
"""
|
|
744
|
+
if target.index_url is not None:
|
|
745
|
+
return await simple_index_source(
|
|
746
|
+
target.package, target.index_url, include_prereleases=include_prereleases
|
|
747
|
+
)()
|
|
598
748
|
profile_fetch_latest = target.fetch_latest
|
|
599
749
|
if profile_fetch_latest is not None:
|
|
600
750
|
return await _fetch_profile_latest_with_timeout(profile_fetch_latest)
|
|
@@ -673,6 +823,7 @@ def _target_for_info(info: UpdateInfo, target: UpdateTarget | None = None) -> Up
|
|
|
673
823
|
install_args=target.install_args,
|
|
674
824
|
command_name=target.command_name,
|
|
675
825
|
python_install_mirror=target.python_install_mirror,
|
|
826
|
+
index_url=target.index_url,
|
|
676
827
|
)
|
|
677
828
|
return UpdateTarget(
|
|
678
829
|
package=info.package,
|
|
@@ -1044,7 +1195,7 @@ async def run_update_command(
|
|
|
1044
1195
|
def _write_plain_after_reinstall(console: Console, text: str) -> None:
|
|
1045
1196
|
"""成功重装之后写终端:不经过 Rich。
|
|
1046
1197
|
|
|
1047
|
-
|
|
1198
|
+
换解释器的重装(例如白牌 install_args 指定了别的 --python)会删掉旧的
|
|
1048
1199
|
lib/python3.X/site-packages,之后任何懒 import 都会 ModuleNotFoundError。Rich 渲染
|
|
1049
1200
|
非 ASCII 字符时懒加载 rich._unicode_data:真机实测 2026-11-02,
|
|
1050
1201
|
`comate update`(3.13 → 3.12)在打印成功文案时崩溃。
|
|
@@ -44,6 +44,9 @@ class UpdateMessages:
|
|
|
44
44
|
update_cli_unreachable: str
|
|
45
45
|
update_cli_editable: str
|
|
46
46
|
update_cli_uv_missing: str
|
|
47
|
+
# `<command> update --mirror`:这次运行用的包索引;白牌自管更新源时拒绝
|
|
48
|
+
update_cli_using_mirror: str
|
|
49
|
+
update_cli_mirror_unsupported: str
|
|
47
50
|
|
|
48
51
|
|
|
49
52
|
_MESSAGES: dict[str, UpdateMessages] = {
|
|
@@ -107,6 +110,8 @@ _MESSAGES: dict[str, UpdateMessages] = {
|
|
|
107
110
|
"uv was not found on PATH, so {product} cannot update itself. "
|
|
108
111
|
"Install uv (https://docs.astral.sh/uv/) and run `{command}`."
|
|
109
112
|
),
|
|
113
|
+
update_cli_using_mirror="Using package index: {url}",
|
|
114
|
+
update_cli_mirror_unsupported="{product} uses its own update source, so --mirror is not supported.",
|
|
110
115
|
),
|
|
111
116
|
"zh_cn": UpdateMessages(
|
|
112
117
|
hint=(
|
|
@@ -163,6 +168,8 @@ _MESSAGES: dict[str, UpdateMessages] = {
|
|
|
163
168
|
"PATH 上找不到 uv,{product} 无法自更新。"
|
|
164
169
|
"请先安装 uv(https://docs.astral.sh/uv/),再运行 `{command}`。"
|
|
165
170
|
),
|
|
171
|
+
update_cli_using_mirror="使用包索引:{url}",
|
|
172
|
+
update_cli_mirror_unsupported="{product} 使用自己的更新源,不支持 --mirror。",
|
|
166
173
|
),
|
|
167
174
|
"zh_tw": UpdateMessages(
|
|
168
175
|
hint=(
|
|
@@ -219,6 +226,8 @@ _MESSAGES: dict[str, UpdateMessages] = {
|
|
|
219
226
|
"PATH 上找不到 uv,{product} 無法自我更新。"
|
|
220
227
|
"請先安裝 uv(https://docs.astral.sh/uv/),再執行 `{command}`。"
|
|
221
228
|
),
|
|
229
|
+
update_cli_using_mirror="使用套件索引:{url}",
|
|
230
|
+
update_cli_mirror_unsupported="{product} 使用自己的更新來源,不支援 --mirror。",
|
|
222
231
|
),
|
|
223
232
|
"ja": UpdateMessages(
|
|
224
233
|
hint=(
|
|
@@ -279,6 +288,8 @@ _MESSAGES: dict[str, UpdateMessages] = {
|
|
|
279
288
|
"PATH に uv が見つからないため、{product} は自己更新できません。"
|
|
280
289
|
"uv(https://docs.astral.sh/uv/)をインストールしてから `{command}` を実行してください。"
|
|
281
290
|
),
|
|
291
|
+
update_cli_using_mirror="使用するパッケージインデックス:{url}",
|
|
292
|
+
update_cli_mirror_unsupported="{product} は独自の更新元を使うため、--mirror は使えません。",
|
|
282
293
|
),
|
|
283
294
|
}
|
|
284
295
|
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
流程:安装方式探测 → Version Check → 打印结果 → 交给 update_check 的平台
|
|
4
4
|
升级路径(macOS/Linux 进程内 uv 重装;Windows Side-Install + Entrypoint Flip)。
|
|
5
|
-
退出码:0=成功或已最新,1=失败/无法检查/不支持,130=中断。
|
|
5
|
+
退出码:0=成功或已最新,1=失败/无法检查/不支持,2=白牌不支持 --mirror,130=中断。
|
|
6
6
|
所有用户可见文案来自 update_messages(四 locale),命令名/包名来自发行配置。
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import asyncio
|
|
12
|
+
import dataclasses
|
|
12
13
|
import logging
|
|
13
14
|
from typing import TYPE_CHECKING
|
|
14
15
|
|
|
@@ -16,10 +17,12 @@ from rich.console import Console
|
|
|
16
17
|
|
|
17
18
|
from comate_cli.terminal_agent import theme
|
|
18
19
|
from comate_cli.terminal_agent.update_check import (
|
|
20
|
+
TUNA_PYPI_INDEX,
|
|
19
21
|
InstallKind,
|
|
20
22
|
UpdateInfo,
|
|
21
23
|
detect_install_kind,
|
|
22
24
|
fetch_latest_release,
|
|
25
|
+
has_own_update_source,
|
|
23
26
|
installed_version,
|
|
24
27
|
run_update_command,
|
|
25
28
|
update_target_from_profile,
|
|
@@ -32,12 +35,82 @@ logger = logging.getLogger(__name__)
|
|
|
32
35
|
|
|
33
36
|
# InstallKind / detect_install_kind 已搬到 update_check(启动期提示也要用),这里保留导入。
|
|
34
37
|
|
|
38
|
+
# `--mirror <tag>` 可用的 PyPI 包索引(simple 地址)。2026-11-06 逐个实测都能返回 simple 页。
|
|
39
|
+
UPDATE_MIRROR_TAGS: dict[str, str] = {
|
|
40
|
+
"pypi": "https://pypi.org/simple",
|
|
41
|
+
"tuna": TUNA_PYPI_INDEX,
|
|
42
|
+
"aliyun": "https://mirrors.aliyun.com/pypi/simple",
|
|
43
|
+
"tencent": "https://mirrors.cloud.tencent.com/pypi/simple",
|
|
44
|
+
"huawei": "https://repo.huaweicloud.com/repository/pypi/simple",
|
|
45
|
+
"ustc": "https://mirrors.ustc.edu.cn/pypi/simple",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class UpdateArgumentError(ValueError):
|
|
50
|
+
"""`<command> update` 的参数不合法;main 打印原因与 usage 后以退出码 2 结束。"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def parse_update_args(args: list[str]) -> tuple[bool, str | None]:
|
|
54
|
+
"""解析 `update [--pre] [--mirror <tag|url>]`,返回 (include_prereleases, index_url)。"""
|
|
55
|
+
include_prereleases = False
|
|
56
|
+
mirror_values: list[str] = []
|
|
57
|
+
unknown: list[str] = []
|
|
58
|
+
index = 0
|
|
59
|
+
while index < len(args):
|
|
60
|
+
arg = args[index]
|
|
61
|
+
if arg == "--pre":
|
|
62
|
+
include_prereleases = True
|
|
63
|
+
elif arg == "--mirror":
|
|
64
|
+
# 下一个参数缺失或是另一个 flag(例:`--mirror --pre`)都算没给值。
|
|
65
|
+
if index + 1 >= len(args) or args[index + 1].startswith("-"):
|
|
66
|
+
raise UpdateArgumentError("--mirror requires a value")
|
|
67
|
+
index += 1
|
|
68
|
+
mirror_values.append(args[index])
|
|
69
|
+
elif arg.startswith("--mirror="):
|
|
70
|
+
value = arg.split("=", 1)[1]
|
|
71
|
+
if not value.strip():
|
|
72
|
+
raise UpdateArgumentError("--mirror requires a value")
|
|
73
|
+
mirror_values.append(value)
|
|
74
|
+
else:
|
|
75
|
+
unknown.append(arg)
|
|
76
|
+
index += 1
|
|
77
|
+
if unknown:
|
|
78
|
+
raise UpdateArgumentError(f"unknown arguments: {' '.join(unknown)}")
|
|
79
|
+
if len(mirror_values) > 1:
|
|
80
|
+
raise UpdateArgumentError("--mirror can only be given once")
|
|
81
|
+
index_url = resolve_update_mirror(mirror_values[0]) if mirror_values else None
|
|
82
|
+
return include_prereleases, index_url
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def resolve_update_mirror(value: str) -> str:
|
|
86
|
+
"""`http://` / `https://` 开头按 URL(去掉结尾 /),否则按 tag 查表(不分大小写)。"""
|
|
87
|
+
raw = value.strip()
|
|
88
|
+
if raw.lower().startswith(("http://", "https://")):
|
|
89
|
+
return raw.rstrip("/")
|
|
90
|
+
url = UPDATE_MIRROR_TAGS.get(raw.lower())
|
|
91
|
+
if url is None:
|
|
92
|
+
raise UpdateArgumentError(
|
|
93
|
+
f"unknown mirror {value!r}; use an http(s):// URL or one of: "
|
|
94
|
+
+ ", ".join(UPDATE_MIRROR_TAGS)
|
|
95
|
+
)
|
|
96
|
+
return url
|
|
97
|
+
|
|
35
98
|
|
|
36
|
-
def run_update_cli(
|
|
99
|
+
def run_update_cli(
|
|
100
|
+
*,
|
|
101
|
+
profile: "DistributionProfile",
|
|
102
|
+
include_prereleases: bool = False,
|
|
103
|
+
index_url: str | None = None,
|
|
104
|
+
) -> int:
|
|
37
105
|
console = Console()
|
|
38
106
|
try:
|
|
39
107
|
return asyncio.run(
|
|
40
|
-
_run_update(
|
|
108
|
+
_run_update(
|
|
109
|
+
profile=profile,
|
|
110
|
+
console=console,
|
|
111
|
+
include_prereleases=include_prereleases,
|
|
112
|
+
index_url=index_url,
|
|
113
|
+
)
|
|
41
114
|
)
|
|
42
115
|
except KeyboardInterrupt:
|
|
43
116
|
return 130
|
|
@@ -48,6 +121,7 @@ async def _run_update(
|
|
|
48
121
|
profile: "DistributionProfile",
|
|
49
122
|
console: Console,
|
|
50
123
|
include_prereleases: bool = False,
|
|
124
|
+
index_url: str | None = None,
|
|
51
125
|
) -> int:
|
|
52
126
|
from comate_cli.terminal_agent.update_messages import get_update_messages
|
|
53
127
|
from packaging.version import InvalidVersion, Version
|
|
@@ -55,6 +129,16 @@ async def _run_update(
|
|
|
55
129
|
target = update_target_from_profile(profile)
|
|
56
130
|
messages = get_update_messages()
|
|
57
131
|
|
|
132
|
+
if index_url is not None:
|
|
133
|
+
if has_own_update_source(target):
|
|
134
|
+
console.print(
|
|
135
|
+
messages.update_cli_mirror_unsupported.format(product=target.product_label),
|
|
136
|
+
style=theme.ERROR,
|
|
137
|
+
markup=False,
|
|
138
|
+
)
|
|
139
|
+
return 2
|
|
140
|
+
target = dataclasses.replace(target, index_url=index_url)
|
|
141
|
+
|
|
58
142
|
kind = detect_install_kind(target.package)
|
|
59
143
|
if kind is InstallKind.EDITABLE:
|
|
60
144
|
console.print(
|
|
@@ -74,6 +158,8 @@ async def _run_update(
|
|
|
74
158
|
)
|
|
75
159
|
return 1
|
|
76
160
|
|
|
161
|
+
if target.index_url is not None:
|
|
162
|
+
console.print(messages.update_cli_using_mirror.format(url=target.index_url), markup=False)
|
|
77
163
|
console.print(messages.update_cli_checking, markup=False)
|
|
78
164
|
current = installed_version(target.package)
|
|
79
165
|
try:
|
|
@@ -12,6 +12,7 @@ Windows 独有的 OS 文件锁行为不进单测,归 tools/verify_windows_self
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
14
|
import os
|
|
15
|
+
import sys
|
|
15
16
|
import time
|
|
16
17
|
import unittest
|
|
17
18
|
from pathlib import Path
|
|
@@ -21,6 +22,9 @@ from unittest.mock import patch
|
|
|
21
22
|
from comate_cli.terminal_agent import side_install as vi
|
|
22
23
|
from comate_cli.terminal_agent.update_check import UpdateInfo, UpdateTarget
|
|
23
24
|
|
|
25
|
+
# 旁装命令请求当前解释器的 主版本.次版本(ADR 0064)。
|
|
26
|
+
_RUNNING_PYTHON = f"{sys.version_info.major}.{sys.version_info.minor}"
|
|
27
|
+
|
|
24
28
|
|
|
25
29
|
def _target(**overrides) -> UpdateTarget:
|
|
26
30
|
base = dict(
|
|
@@ -255,19 +259,36 @@ class _FakeUv:
|
|
|
255
259
|
|
|
256
260
|
|
|
257
261
|
class TestStageUpdate(unittest.IsolatedAsyncioTestCase):
|
|
258
|
-
async def
|
|
259
|
-
"""Windows 的 Self-Update
|
|
260
|
-
tool 环境,不带 --python 时 uv
|
|
261
|
-
|
|
262
|
+
async def test_side_install_requests_running_python(self) -> None:
|
|
263
|
+
"""Windows 的 Self-Update 也要把新版本装在当前解释器的 主版本.次版本上(ADR 0064):
|
|
264
|
+
旁装是全新的 tool 环境,不带 --python 时 uv 用它默认找到的解释器,更新后就换了 Python。
|
|
265
|
+
伪造成 3.14(不在 requires-python 范围内):改回固定版本或加范围判断,这里会失败。"""
|
|
266
|
+
with TemporaryDirectory() as tmp, patch(
|
|
267
|
+
"comate_cli.terminal_agent.update_check.sys.version_info", (3, 14, 2, "final", 0)
|
|
268
|
+
):
|
|
262
269
|
base = Path(tmp)
|
|
263
270
|
fake = _FakeUv(base)
|
|
264
271
|
await vi.stage_update(_info(), _target(), layout=_layout_for(base), run_command=fake)
|
|
265
272
|
install_cmd, _ = fake.calls[0]
|
|
266
273
|
self.assertIn("--python", install_cmd)
|
|
267
|
-
self.assertEqual(install_cmd[install_cmd.index("--python") + 1], "3.
|
|
274
|
+
self.assertEqual(install_cmd[install_cmd.index("--python") + 1], "3.14")
|
|
275
|
+
|
|
276
|
+
async def test_side_install_installs_from_update_mirror(self) -> None:
|
|
277
|
+
"""`update --mirror`:Windows 旁装也要从查版本的那个索引装包,否则精确 pin 的版本
|
|
278
|
+
在 uv 的默认索引上可能还不存在(镜像落后时正是用户换镜像的原因)。"""
|
|
279
|
+
mirror = "https://mirrors.example/pypi/simple"
|
|
280
|
+
with TemporaryDirectory() as tmp:
|
|
281
|
+
base = Path(tmp)
|
|
282
|
+
fake = _FakeUv(base)
|
|
283
|
+
await vi.stage_update(
|
|
284
|
+
_info(), _target(install_args=(), index_url=mirror), layout=_layout_for(base), run_command=fake
|
|
285
|
+
)
|
|
286
|
+
install_cmd, _ = fake.calls[0]
|
|
287
|
+
defaults = [install_cmd[i + 1] for i, arg in enumerate(install_cmd) if arg == "--default-index"]
|
|
288
|
+
self.assertEqual(defaults, [mirror])
|
|
268
289
|
|
|
269
290
|
async def test_zh_cn_side_install_downloads_python_through_mirror(self) -> None:
|
|
270
|
-
"""
|
|
291
|
+
"""旁装请求的 Python 机器上没有时 uv 从 GitHub 下载,国内可能失败(ADR 0055 取舍四);
|
|
271
292
|
用户自己设置的镜像必须保留。"""
|
|
272
293
|
mirror = "https://registry.npmmirror.com/-/binary/python-build-standalone"
|
|
273
294
|
own = "https://mirror.corp.example/python-build-standalone"
|
|
@@ -329,7 +350,7 @@ class TestStageUpdate(unittest.IsolatedAsyncioTestCase):
|
|
|
329
350
|
"uv", "tool", "install", "acme-cli==1.1.0",
|
|
330
351
|
"--refresh",
|
|
331
352
|
"--python",
|
|
332
|
-
|
|
353
|
+
_RUNNING_PYTHON,
|
|
333
354
|
"--index-strategy", "unsafe-first-match",
|
|
334
355
|
"--default-index", "https://pypi.example.com/simple",
|
|
335
356
|
),
|