klaude-code 1.2.18__tar.gz → 1.2.19__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.
- {klaude_code-1.2.18 → klaude_code-1.2.19}/PKG-INFO +17 -2
- {klaude_code-1.2.18 → klaude_code-1.2.19}/README.md +16 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/pyproject.toml +1 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/main.py +42 -22
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/runtime.py +41 -2
- klaude_code-1.2.18/src/klaude_code/version.py → klaude_code-1.2.19/src/klaude_code/cli/self_update.py +110 -2
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/export_online_cmd.py +8 -3
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/registry.py +67 -22
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/thinking_cmd.py +4 -3
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/executor.py +21 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +14 -2
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/task.py +9 -7
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/read_tool.md +1 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/read_tool.py +3 -2
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/skill_loader.py +12 -10
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_registry.py +1 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/anthropic/client.py +25 -9
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/client.py +5 -2
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/client.py +7 -3
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/responses/client.py +6 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/session.py +33 -13
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/templates/export_session.html +43 -41
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/completers.py +212 -71
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/renderer.py +2 -2
- klaude_code-1.2.19/src/klaude_code/ui/renderers/common.py +62 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/developer.py +2 -3
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/errors.py +1 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/metadata.py +10 -1
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/tools.py +3 -4
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/utils/common.py +0 -18
- klaude_code-1.2.18/src/klaude_code/ui/renderers/common.py +0 -8
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/exceptions.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/oauth.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/auth/codex/token_manager.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/auth_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/config_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/debug.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/list_model.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/cli/session_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/clear_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/command_abc.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/debug_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/diff_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/export_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/help_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/model_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-deslop.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-dev-docs-update.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-dev-docs.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-handoff.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt-init.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/prompt_command.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/refresh_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/release_notes_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/status_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/config/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/config/config.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/config/select_model.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/const/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/agent.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/llm_clients.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompt.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/reminders.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/_utils.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/multi_edit_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/multi_edit_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/write_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/file/write_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/memory_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/memory_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/skill_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/memory/skill_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/report_back_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_abc.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_context.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/tool_runner.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/truncation.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/core/turn.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/anthropic/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/anthropic/input.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/client.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/codex/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/codex/client.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/input_common.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/input.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/stream_processor.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/input.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/openrouter/reasoning_handler.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/registry.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/responses/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/responses/input.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/llm/usage.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/commands.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/events.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/llm_param.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/model.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/op.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/op_handler.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/oracle.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/task.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/sub_agent/web.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/protocol/tools.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/export.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/session/selector.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/trace/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/trace/log.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/display.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/input.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/core/stage_manager.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/debug/display.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/exec/display.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/display.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/event_handler.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/modes/repl/key_bindings.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/assistant.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/diffs.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/thinking.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/renderers/user_input.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/code_panel.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/live.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/markdown.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/quote.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/searchable_text.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/status.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/rich/theme.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/color.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/control.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/notifier.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/utils/__init__.py +0 -0
- {klaude_code-1.2.18 → klaude_code-1.2.19}/src/klaude_code/ui/utils/debouncer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: klaude-code
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.19
|
|
4
4
|
Summary: Add your description here
|
|
5
5
|
Requires-Dist: anthropic>=0.66.0
|
|
6
6
|
Requires-Dist: ddgs>=9.9.3
|
|
@@ -41,6 +41,21 @@ To update:
|
|
|
41
41
|
uv tool upgrade klaude-code
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
Or use the built-in alias command:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
klaude update
|
|
48
|
+
klaude upgrade
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
To show version:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
klaude --version
|
|
55
|
+
klaude -v
|
|
56
|
+
klaude version
|
|
57
|
+
```
|
|
58
|
+
|
|
44
59
|
## Usage
|
|
45
60
|
|
|
46
61
|
### Interactive Mode
|
|
@@ -50,7 +65,7 @@ klaude [--model <name>] [--select-model]
|
|
|
50
65
|
```
|
|
51
66
|
|
|
52
67
|
**Options:**
|
|
53
|
-
- `--version`/`-V`: Show version and exit.
|
|
68
|
+
- `--version`/`-V`/`-v`: Show version and exit.
|
|
54
69
|
- `--model`/`-m`: Preferred model name (exact match picks immediately; otherwise opens the interactive selector filtered by this value).
|
|
55
70
|
- `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
|
|
56
71
|
- `--continue`/`-c`: Resume the most recent session.
|
|
@@ -23,6 +23,21 @@ To update:
|
|
|
23
23
|
uv tool upgrade klaude-code
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
Or use the built-in alias command:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
klaude update
|
|
30
|
+
klaude upgrade
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
To show version:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
klaude --version
|
|
37
|
+
klaude -v
|
|
38
|
+
klaude version
|
|
39
|
+
```
|
|
40
|
+
|
|
26
41
|
## Usage
|
|
27
42
|
|
|
28
43
|
### Interactive Mode
|
|
@@ -32,7 +47,7 @@ klaude [--model <name>] [--select-model]
|
|
|
32
47
|
```
|
|
33
48
|
|
|
34
49
|
**Options:**
|
|
35
|
-
- `--version`/`-V`: Show version and exit.
|
|
50
|
+
- `--version`/`-V`/`-v`: Show version and exit.
|
|
36
51
|
- `--model`/`-m`: Preferred model name (exact match picks immediately; otherwise opens the interactive selector filtered by this value).
|
|
37
52
|
- `--select-model`/`-s`: Open the interactive model selector at startup (shows all models unless `--model` is also provided).
|
|
38
53
|
- `--continue`/`-c`: Resume the most recent session.
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
|
-
from importlib.metadata import PackageNotFoundError
|
|
5
|
-
from importlib.metadata import version as pkg_version
|
|
6
4
|
from pathlib import Path
|
|
7
5
|
|
|
8
6
|
import typer
|
|
@@ -10,6 +8,7 @@ import typer
|
|
|
10
8
|
from klaude_code.cli.auth_cmd import register_auth_commands
|
|
11
9
|
from klaude_code.cli.config_cmd import register_config_commands
|
|
12
10
|
from klaude_code.cli.debug import DEBUG_FILTER_HELP, open_log_file_in_editor, resolve_debug_settings
|
|
11
|
+
from klaude_code.cli.self_update import register_self_update_commands, version_option_callback
|
|
13
12
|
from klaude_code.cli.session_cmd import register_session_commands
|
|
14
13
|
from klaude_code.session import Session, resume_select_session
|
|
15
14
|
from klaude_code.trace import DebugType, prepare_debug_log_file
|
|
@@ -21,10 +20,13 @@ def set_terminal_title(title: str) -> None:
|
|
|
21
20
|
sys.stdout.flush()
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
def
|
|
25
|
-
"""
|
|
23
|
+
def update_terminal_title(model_name: str | None = None) -> None:
|
|
24
|
+
"""Update terminal title with folder name and optional model name."""
|
|
26
25
|
folder_name = os.path.basename(os.getcwd())
|
|
27
|
-
|
|
26
|
+
if model_name:
|
|
27
|
+
set_terminal_title(f"{folder_name}: klaude ✳ {model_name}")
|
|
28
|
+
else:
|
|
29
|
+
set_terminal_title(f"{folder_name}: klaude")
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
def prepare_debug_logging(debug: bool, debug_filter: str | None) -> tuple[bool, set[DebugType] | None, Path | None]:
|
|
@@ -78,20 +80,6 @@ def read_input_content(cli_argument: str) -> str | None:
|
|
|
78
80
|
return content
|
|
79
81
|
|
|
80
82
|
|
|
81
|
-
def _version_callback(value: bool) -> None:
|
|
82
|
-
"""Show version and exit."""
|
|
83
|
-
if value:
|
|
84
|
-
try:
|
|
85
|
-
ver = pkg_version("klaude-code")
|
|
86
|
-
except PackageNotFoundError:
|
|
87
|
-
# Package is not installed or has no metadata; show a generic version string.
|
|
88
|
-
ver = "unknown"
|
|
89
|
-
except Exception:
|
|
90
|
-
ver = "unknown"
|
|
91
|
-
print(f"klaude-code {ver}")
|
|
92
|
-
raise typer.Exit(0)
|
|
93
|
-
|
|
94
|
-
|
|
95
83
|
app = typer.Typer(
|
|
96
84
|
add_completion=False,
|
|
97
85
|
pretty_exceptions_enable=False,
|
|
@@ -103,6 +91,8 @@ register_session_commands(app)
|
|
|
103
91
|
register_auth_commands(app)
|
|
104
92
|
register_config_commands(app)
|
|
105
93
|
|
|
94
|
+
register_self_update_commands(app)
|
|
95
|
+
|
|
106
96
|
|
|
107
97
|
@app.command("exec")
|
|
108
98
|
def exec_command(
|
|
@@ -146,7 +136,7 @@ def exec_command(
|
|
|
146
136
|
),
|
|
147
137
|
) -> None:
|
|
148
138
|
"""Execute non-interactively with provided input."""
|
|
149
|
-
|
|
139
|
+
update_terminal_title()
|
|
150
140
|
|
|
151
141
|
merged_input = read_input_content(input_content)
|
|
152
142
|
if merged_input is None:
|
|
@@ -190,8 +180,9 @@ def main_callback(
|
|
|
190
180
|
False,
|
|
191
181
|
"--version",
|
|
192
182
|
"-V",
|
|
183
|
+
"-v",
|
|
193
184
|
help="Show version and exit",
|
|
194
|
-
callback=
|
|
185
|
+
callback=version_option_callback,
|
|
195
186
|
is_eager=True,
|
|
196
187
|
),
|
|
197
188
|
model: str | None = typer.Option(
|
|
@@ -234,7 +225,7 @@ def main_callback(
|
|
|
234
225
|
from klaude_code.cli.runtime import AppInitConfig, run_interactive
|
|
235
226
|
from klaude_code.config.select_model import select_model_from_config
|
|
236
227
|
|
|
237
|
-
|
|
228
|
+
update_terminal_title()
|
|
238
229
|
|
|
239
230
|
chosen_model = model
|
|
240
231
|
if model or select_model:
|
|
@@ -254,6 +245,35 @@ def main_callback(
|
|
|
254
245
|
session_id = Session.most_recent_session_id()
|
|
255
246
|
# If still no session_id, leave as None to create a new session
|
|
256
247
|
|
|
248
|
+
if session_id is not None and chosen_model is None:
|
|
249
|
+
from klaude_code.config import load_config
|
|
250
|
+
from klaude_code.trace import log
|
|
251
|
+
|
|
252
|
+
session_meta = Session.load_meta(session_id)
|
|
253
|
+
cfg = load_config()
|
|
254
|
+
|
|
255
|
+
if cfg is not None and session_meta.model_config_name:
|
|
256
|
+
if any(m.model_name == session_meta.model_config_name for m in cfg.model_list):
|
|
257
|
+
chosen_model = session_meta.model_config_name
|
|
258
|
+
else:
|
|
259
|
+
log(
|
|
260
|
+
(
|
|
261
|
+
f"Warning: session model '{session_meta.model_config_name}' is not defined in config; falling back to default",
|
|
262
|
+
"yellow",
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if cfg is not None and chosen_model is None and session_meta.model_name:
|
|
267
|
+
raw_model = session_meta.model_name.strip()
|
|
268
|
+
if raw_model:
|
|
269
|
+
matches = [
|
|
270
|
+
m.model_name
|
|
271
|
+
for m in cfg.model_list
|
|
272
|
+
if (m.model_params.model or "").strip().lower() == raw_model.lower()
|
|
273
|
+
]
|
|
274
|
+
if len(matches) == 1:
|
|
275
|
+
chosen_model = matches[0]
|
|
276
|
+
|
|
257
277
|
debug_enabled, debug_filters, log_path = prepare_debug_logging(debug, debug_filter)
|
|
258
278
|
|
|
259
279
|
init_config = AppInitConfig(
|
|
@@ -8,9 +8,11 @@ import typer
|
|
|
8
8
|
from rich.text import Text
|
|
9
9
|
|
|
10
10
|
from klaude_code import ui
|
|
11
|
+
from klaude_code.cli.main import update_terminal_title
|
|
12
|
+
from klaude_code.cli.self_update import get_update_message
|
|
11
13
|
from klaude_code.command import has_interactive_command
|
|
12
14
|
from klaude_code.config import Config, load_config
|
|
13
|
-
from klaude_code.core.agent import DefaultModelProfileProvider, VanillaModelProfileProvider
|
|
15
|
+
from klaude_code.core.agent import Agent, DefaultModelProfileProvider, VanillaModelProfileProvider
|
|
14
16
|
from klaude_code.core.executor import Executor
|
|
15
17
|
from klaude_code.core.manager import build_llm_clients
|
|
16
18
|
from klaude_code.protocol import events, op
|
|
@@ -21,7 +23,6 @@ from klaude_code.ui.modes.repl.input_prompt_toolkit import REPLStatusSnapshot
|
|
|
21
23
|
from klaude_code.ui.terminal.color import is_light_terminal_background
|
|
22
24
|
from klaude_code.ui.terminal.control import install_sigint_double_press_exit, start_esc_interrupt_monitor
|
|
23
25
|
from klaude_code.ui.terminal.progress_bar import OSC94States, emit_osc94
|
|
24
|
-
from klaude_code.version import get_update_message
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class PrintCapable(Protocol):
|
|
@@ -92,8 +93,12 @@ async def initialize_app_components(init_config: AppInitConfig) -> AppComponents
|
|
|
92
93
|
event_queue,
|
|
93
94
|
llm_clients,
|
|
94
95
|
model_profile_provider=model_profile_provider,
|
|
96
|
+
on_model_change=update_terminal_title,
|
|
95
97
|
)
|
|
96
98
|
|
|
99
|
+
# Update terminal title with initial model name
|
|
100
|
+
update_terminal_title(llm_clients.main.model_name)
|
|
101
|
+
|
|
97
102
|
# Start executor in background
|
|
98
103
|
executor_task = asyncio.create_task(executor.start())
|
|
99
104
|
|
|
@@ -151,6 +156,28 @@ async def initialize_session(
|
|
|
151
156
|
return active_session_id or session_id
|
|
152
157
|
|
|
153
158
|
|
|
159
|
+
def _backfill_session_model_config(
|
|
160
|
+
agent: Agent | None,
|
|
161
|
+
model_override: str | None,
|
|
162
|
+
default_model: str,
|
|
163
|
+
is_new_session: bool,
|
|
164
|
+
) -> None:
|
|
165
|
+
"""Backfill model_config_name and model_thinking on newly created sessions."""
|
|
166
|
+
if agent is None or agent.session.model_config_name is not None:
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
if model_override is not None:
|
|
170
|
+
agent.session.model_config_name = model_override
|
|
171
|
+
elif is_new_session:
|
|
172
|
+
agent.session.model_config_name = default_model
|
|
173
|
+
else:
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
if agent.session.model_thinking is None and agent.profile:
|
|
177
|
+
agent.session.model_thinking = agent.profile.llm_client.get_llm_config().thinking
|
|
178
|
+
# Don't save here - session will be saved when first message is sent via append_history()
|
|
179
|
+
|
|
180
|
+
|
|
154
181
|
async def cleanup_app_components(components: AppComponents) -> None:
|
|
155
182
|
"""Clean up all application components."""
|
|
156
183
|
try:
|
|
@@ -192,6 +219,12 @@ async def run_exec(init_config: AppInitConfig, input_content: str) -> None:
|
|
|
192
219
|
|
|
193
220
|
try:
|
|
194
221
|
session_id = await initialize_session(components.executor, components.event_queue)
|
|
222
|
+
_backfill_session_model_config(
|
|
223
|
+
components.executor.context.current_agent,
|
|
224
|
+
init_config.model,
|
|
225
|
+
components.config.main_model,
|
|
226
|
+
is_new_session=True,
|
|
227
|
+
)
|
|
195
228
|
|
|
196
229
|
# Submit the input content directly
|
|
197
230
|
await components.executor.submit_and_wait(
|
|
@@ -260,6 +293,12 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
|
|
|
260
293
|
|
|
261
294
|
try:
|
|
262
295
|
await initialize_session(components.executor, components.event_queue, session_id=session_id)
|
|
296
|
+
_backfill_session_model_config(
|
|
297
|
+
components.executor.context.current_agent,
|
|
298
|
+
init_config.model,
|
|
299
|
+
components.config.main_model,
|
|
300
|
+
is_new_session=session_id is None,
|
|
301
|
+
)
|
|
263
302
|
|
|
264
303
|
def _get_active_session_id() -> str | None:
|
|
265
304
|
"""Get the current active session ID dynamically.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Self-update and version utilities for klaude-code."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -8,8 +8,14 @@ import subprocess
|
|
|
8
8
|
import threading
|
|
9
9
|
import time
|
|
10
10
|
import urllib.request
|
|
11
|
+
from importlib.metadata import PackageNotFoundError
|
|
12
|
+
from importlib.metadata import version as pkg_version
|
|
11
13
|
from typing import NamedTuple
|
|
12
14
|
|
|
15
|
+
import typer
|
|
16
|
+
|
|
17
|
+
from klaude_code.trace import log
|
|
18
|
+
|
|
13
19
|
PACKAGE_NAME = "klaude-code"
|
|
14
20
|
PYPI_URL = f"https://pypi.org/pypi/{PACKAGE_NAME}/json"
|
|
15
21
|
CHECK_INTERVAL_SECONDS = 3600 # Check at most once per hour
|
|
@@ -160,4 +166,106 @@ def get_update_message() -> str | None:
|
|
|
160
166
|
info = check_for_updates()
|
|
161
167
|
if info is None or not info.update_available:
|
|
162
168
|
return None
|
|
163
|
-
return f"New version available: {info.latest}. Please run `
|
|
169
|
+
return f"New version available: {info.latest}. Please run `klaude upgrade` to upgrade."
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _print_version() -> None:
|
|
173
|
+
try:
|
|
174
|
+
ver = pkg_version(PACKAGE_NAME)
|
|
175
|
+
except PackageNotFoundError:
|
|
176
|
+
ver = "unknown"
|
|
177
|
+
except Exception:
|
|
178
|
+
ver = "unknown"
|
|
179
|
+
print(f"{PACKAGE_NAME} {ver}")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def version_option_callback(value: bool) -> None:
|
|
183
|
+
"""Show version and exit."""
|
|
184
|
+
if value:
|
|
185
|
+
_print_version()
|
|
186
|
+
raise typer.Exit(0)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def version_command() -> None:
|
|
190
|
+
"""Show version and exit."""
|
|
191
|
+
|
|
192
|
+
_print_version()
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def update_command(
|
|
196
|
+
check: bool = typer.Option(
|
|
197
|
+
False,
|
|
198
|
+
"--check",
|
|
199
|
+
help="Check for updates and exit without upgrading",
|
|
200
|
+
),
|
|
201
|
+
) -> None:
|
|
202
|
+
"""Upgrade klaude-code when installed via `uv tool`."""
|
|
203
|
+
|
|
204
|
+
info = check_for_updates_blocking()
|
|
205
|
+
|
|
206
|
+
if check:
|
|
207
|
+
if info is None:
|
|
208
|
+
log(("Error: `uv` is not available; cannot check for updates.", "red"))
|
|
209
|
+
log(f"Install uv, then run `uv tool upgrade {PACKAGE_NAME}`.")
|
|
210
|
+
raise typer.Exit(1)
|
|
211
|
+
|
|
212
|
+
installed_display = info.installed or "unknown"
|
|
213
|
+
latest_display = info.latest or "unknown"
|
|
214
|
+
status = "update available" if info.update_available else "up to date"
|
|
215
|
+
|
|
216
|
+
log(f"{PACKAGE_NAME} installed: {installed_display}")
|
|
217
|
+
log(f"{PACKAGE_NAME} latest: {latest_display}")
|
|
218
|
+
log(f"Status: {status}")
|
|
219
|
+
|
|
220
|
+
if info.update_available:
|
|
221
|
+
log("Run `klaude upgrade` to upgrade.")
|
|
222
|
+
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
if shutil.which("uv") is None:
|
|
226
|
+
log(("Error: `uv` not found in PATH.", "red"))
|
|
227
|
+
log(f"To update, install uv and run `uv tool upgrade {PACKAGE_NAME}`.")
|
|
228
|
+
raise typer.Exit(1)
|
|
229
|
+
|
|
230
|
+
log(f"Running `uv tool upgrade {PACKAGE_NAME}`...")
|
|
231
|
+
result = subprocess.run(["uv", "tool", "upgrade", PACKAGE_NAME], check=False)
|
|
232
|
+
if result.returncode != 0:
|
|
233
|
+
log((f"Error: update failed (exit code {result.returncode}).", "red"))
|
|
234
|
+
raise typer.Exit(result.returncode or 1)
|
|
235
|
+
|
|
236
|
+
log("Update complete. Please re-run `klaude` to use the new version.")
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def register_self_update_commands(app: typer.Typer) -> None:
|
|
240
|
+
"""Register self-update and version subcommands to the given Typer app."""
|
|
241
|
+
|
|
242
|
+
app.command("update")(update_command)
|
|
243
|
+
app.command("upgrade", help="Alias for `klaude update`.")(update_command)
|
|
244
|
+
app.command("version", help="Alias for `klaude --version`.")(version_command)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def check_for_updates_blocking() -> VersionInfo | None:
|
|
248
|
+
"""Check for updates to klaude-code synchronously.
|
|
249
|
+
|
|
250
|
+
This is intended for CLI commands (e.g. `klaude update --check`) that need
|
|
251
|
+
a deterministic result instead of the async cached behavior.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
VersionInfo if uv is available, otherwise None.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
if not _has_uv():
|
|
258
|
+
return None
|
|
259
|
+
|
|
260
|
+
installed = _get_installed_version()
|
|
261
|
+
latest = _get_latest_version()
|
|
262
|
+
|
|
263
|
+
update_available = False
|
|
264
|
+
if installed and latest:
|
|
265
|
+
update_available = _compare_versions(installed, latest)
|
|
266
|
+
|
|
267
|
+
return VersionInfo(
|
|
268
|
+
installed=installed,
|
|
269
|
+
latest=latest,
|
|
270
|
+
update_available=update_available,
|
|
271
|
+
)
|
|
@@ -6,6 +6,9 @@ import subprocess
|
|
|
6
6
|
import tempfile
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.text import Text
|
|
11
|
+
|
|
9
12
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
10
13
|
from klaude_code.protocol import commands, events, model
|
|
11
14
|
from klaude_code.session.export import build_export_html
|
|
@@ -56,9 +59,11 @@ class ExportOnlineCommand(CommandABC):
|
|
|
56
59
|
return CommandResult(events=[event])
|
|
57
60
|
|
|
58
61
|
try:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
console = Console()
|
|
63
|
+
with console.status(Text("Deploying to surge.sh...", style="dim"), spinner_style="dim"):
|
|
64
|
+
html_doc = self._build_html(agent)
|
|
65
|
+
domain = self._generate_domain()
|
|
66
|
+
url = self._deploy_to_surge(surge_cmd, html_doc, domain)
|
|
62
67
|
|
|
63
68
|
event = events.DeveloperMessageEvent(
|
|
64
69
|
session_id=agent.session.id,
|
|
@@ -12,6 +12,68 @@ if TYPE_CHECKING:
|
|
|
12
12
|
_COMMANDS: dict[commands.CommandName | str, "CommandABC"] = {}
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
def _command_key_to_str(key: commands.CommandName | str) -> str:
|
|
16
|
+
if isinstance(key, commands.CommandName):
|
|
17
|
+
return key.value
|
|
18
|
+
return key
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _resolve_command_key(command_name_raw: str) -> commands.CommandName | str | None:
|
|
22
|
+
"""Resolve raw command token to a registered command key.
|
|
23
|
+
|
|
24
|
+
Resolution order:
|
|
25
|
+
1) Exact match
|
|
26
|
+
2) Enum conversion (for standard commands)
|
|
27
|
+
3) Prefix match (supports abbreviations like `exp` -> `export`)
|
|
28
|
+
|
|
29
|
+
Prefix match rules:
|
|
30
|
+
- If there's exactly one prefix match, use it.
|
|
31
|
+
- If multiple matches exist and one command name is a prefix of all others,
|
|
32
|
+
treat it as the base command and use it (e.g. `export` over `export-online`).
|
|
33
|
+
- Otherwise, consider it ambiguous and return None.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
if not command_name_raw:
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
# Exact string match (works for both Enum and str keys because CommandName is a str Enum)
|
|
40
|
+
if command_name_raw in _COMMANDS:
|
|
41
|
+
return command_name_raw
|
|
42
|
+
|
|
43
|
+
# Enum conversion for standard commands
|
|
44
|
+
try:
|
|
45
|
+
enum_key = commands.CommandName(command_name_raw)
|
|
46
|
+
except ValueError:
|
|
47
|
+
enum_key = None
|
|
48
|
+
else:
|
|
49
|
+
if enum_key in _COMMANDS:
|
|
50
|
+
return enum_key
|
|
51
|
+
|
|
52
|
+
# Prefix match across all registered names
|
|
53
|
+
matching_keys: list[commands.CommandName | str] = []
|
|
54
|
+
matching_names: list[str] = []
|
|
55
|
+
for key in _COMMANDS:
|
|
56
|
+
key_str = _command_key_to_str(key)
|
|
57
|
+
if key_str.startswith(command_name_raw):
|
|
58
|
+
matching_keys.append(key)
|
|
59
|
+
matching_names.append(key_str)
|
|
60
|
+
|
|
61
|
+
if len(matching_keys) == 1:
|
|
62
|
+
return matching_keys[0]
|
|
63
|
+
|
|
64
|
+
if len(matching_keys) > 1:
|
|
65
|
+
# Prefer the base command when one is a prefix of all other matches.
|
|
66
|
+
base_matches = [
|
|
67
|
+
key
|
|
68
|
+
for key, key_name in zip(matching_keys, matching_names, strict=True)
|
|
69
|
+
if all(other.startswith(key_name) for other in matching_names if other != key_name)
|
|
70
|
+
]
|
|
71
|
+
if len(base_matches) == 1:
|
|
72
|
+
return base_matches[0]
|
|
73
|
+
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
|
|
15
77
|
def register(cmd: "CommandABC") -> None:
|
|
16
78
|
"""Register a command instance. Order of registration determines display order."""
|
|
17
79
|
_COMMANDS[cmd.name] = cmd
|
|
@@ -45,7 +107,7 @@ def get_commands() -> dict[commands.CommandName | str, "CommandABC"]:
|
|
|
45
107
|
|
|
46
108
|
def is_slash_command_name(name: str) -> bool:
|
|
47
109
|
_ensure_commands_loaded()
|
|
48
|
-
return name
|
|
110
|
+
return _resolve_command_key(name) is not None
|
|
49
111
|
|
|
50
112
|
|
|
51
113
|
async def dispatch_command(raw: str, agent: Agent) -> CommandResult:
|
|
@@ -58,21 +120,7 @@ async def dispatch_command(raw: str, agent: Agent) -> CommandResult:
|
|
|
58
120
|
command_name_raw = splits[0][1:]
|
|
59
121
|
rest = " ".join(splits[1:]) if len(splits) > 1 else ""
|
|
60
122
|
|
|
61
|
-
|
|
62
|
-
command_key = None
|
|
63
|
-
|
|
64
|
-
# First try exact string match
|
|
65
|
-
if command_name_raw in _COMMANDS:
|
|
66
|
-
command_key = command_name_raw
|
|
67
|
-
else:
|
|
68
|
-
# Then try Enum conversion for standard commands
|
|
69
|
-
try:
|
|
70
|
-
enum_key = commands.CommandName(command_name_raw)
|
|
71
|
-
if enum_key in _COMMANDS:
|
|
72
|
-
command_key = enum_key
|
|
73
|
-
except ValueError:
|
|
74
|
-
pass
|
|
75
|
-
|
|
123
|
+
command_key = _resolve_command_key(command_name_raw)
|
|
76
124
|
if command_key is None:
|
|
77
125
|
return CommandResult(actions=[InputAction.run_agent(raw)])
|
|
78
126
|
|
|
@@ -106,11 +154,8 @@ def has_interactive_command(raw: str) -> bool:
|
|
|
106
154
|
return False
|
|
107
155
|
splits = raw.split(" ", maxsplit=1)
|
|
108
156
|
command_name_raw = splits[0][1:]
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
except ValueError:
|
|
112
|
-
return False
|
|
113
|
-
if command_name not in _COMMANDS:
|
|
157
|
+
command_key = _resolve_command_key(command_name_raw)
|
|
158
|
+
if command_key is None:
|
|
114
159
|
return False
|
|
115
|
-
command = _COMMANDS[
|
|
160
|
+
command = _COMMANDS[command_key]
|
|
116
161
|
return command.is_interactive
|
|
@@ -6,9 +6,9 @@ from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
|
6
6
|
from klaude_code.protocol import commands, events, llm_param, model
|
|
7
7
|
|
|
8
8
|
# Thinking level options for different protocols
|
|
9
|
-
RESPONSES_LEVELS = ["
|
|
10
|
-
RESPONSES_GPT51_LEVELS = ["none", "
|
|
11
|
-
RESPONSES_GPT52_LEVELS = ["none", "
|
|
9
|
+
RESPONSES_LEVELS = ["low", "medium", "high"]
|
|
10
|
+
RESPONSES_GPT51_LEVELS = ["none", "low", "medium", "high"]
|
|
11
|
+
RESPONSES_GPT52_LEVELS = ["none", "low", "medium", "high", "xhigh"]
|
|
12
12
|
RESPONSES_CODEX_MAX_LEVELS = ["medium", "high", "xhigh"]
|
|
13
13
|
|
|
14
14
|
ANTHROPIC_LEVELS: list[tuple[str, int | None]] = [
|
|
@@ -206,6 +206,7 @@ class ThinkingCommand(CommandABC):
|
|
|
206
206
|
|
|
207
207
|
# Apply the new thinking configuration
|
|
208
208
|
config.thinking = new_thinking
|
|
209
|
+
agent.session.model_thinking = new_thinking
|
|
209
210
|
new_status = _format_current_thinking(config)
|
|
210
211
|
|
|
211
212
|
return CommandResult(
|
|
@@ -90,11 +90,13 @@ class InputActionExecutor:
|
|
|
90
90
|
sub_agent_manager: SubAgentManager,
|
|
91
91
|
model_profile_provider: ModelProfileProvider,
|
|
92
92
|
emit_event: Callable[[events.Event], Awaitable[None]],
|
|
93
|
+
on_model_change: Callable[[str], None] | None = None,
|
|
93
94
|
) -> None:
|
|
94
95
|
self._task_manager = task_manager
|
|
95
96
|
self._sub_agent_manager = sub_agent_manager
|
|
96
97
|
self._model_profile_provider = model_profile_provider
|
|
97
98
|
self._emit_event = emit_event
|
|
99
|
+
self._on_model_change = on_model_change
|
|
98
100
|
|
|
99
101
|
async def run(self, action: InputAction, operation: op.UserInputOperation, agent: Agent) -> None:
|
|
100
102
|
"""Dispatch and execute a single input action."""
|
|
@@ -208,6 +210,9 @@ class InputActionExecutor:
|
|
|
208
210
|
llm_client = create_llm_client(llm_config)
|
|
209
211
|
agent.set_model_profile(self._model_profile_provider.build_profile(llm_client))
|
|
210
212
|
|
|
213
|
+
agent.session.model_config_name = model_name
|
|
214
|
+
agent.session.model_thinking = llm_config.thinking
|
|
215
|
+
|
|
211
216
|
developer_item = model.DeveloperMessageItem(
|
|
212
217
|
content=f"switched to model: {model_name}",
|
|
213
218
|
command_output=model.CommandOutput(command_name=commands.CommandName.MODEL),
|
|
@@ -217,11 +222,16 @@ class InputActionExecutor:
|
|
|
217
222
|
await self._emit_event(events.DeveloperMessageEvent(session_id=agent.session.id, item=developer_item))
|
|
218
223
|
await self._emit_event(events.WelcomeEvent(llm_config=llm_config, work_dir=str(agent.session.work_dir)))
|
|
219
224
|
|
|
225
|
+
if self._on_model_change is not None:
|
|
226
|
+
self._on_model_change(llm_client.model_name)
|
|
227
|
+
|
|
220
228
|
async def _apply_clear(self, agent: Agent) -> None:
|
|
221
229
|
"""Start a new conversation for the agent and notify the UI."""
|
|
222
230
|
|
|
223
231
|
new_session = Session(work_dir=agent.session.work_dir)
|
|
224
232
|
new_session.model_name = agent.session.model_name
|
|
233
|
+
new_session.model_config_name = agent.session.model_config_name
|
|
234
|
+
new_session.model_thinking = agent.session.model_thinking
|
|
225
235
|
|
|
226
236
|
agent.session = new_session
|
|
227
237
|
agent.session.save()
|
|
@@ -249,6 +259,7 @@ class ExecutorContext:
|
|
|
249
259
|
event_queue: asyncio.Queue[events.Event],
|
|
250
260
|
llm_clients: LLMClients,
|
|
251
261
|
model_profile_provider: ModelProfileProvider | None = None,
|
|
262
|
+
on_model_change: Callable[[str], None] | None = None,
|
|
252
263
|
):
|
|
253
264
|
self.event_queue: asyncio.Queue[events.Event] = event_queue
|
|
254
265
|
self.llm_clients: LLMClients = llm_clients
|
|
@@ -263,6 +274,7 @@ class ExecutorContext:
|
|
|
263
274
|
sub_agent_manager=self.sub_agent_manager,
|
|
264
275
|
model_profile_provider=resolved_profile_provider,
|
|
265
276
|
emit_event=self.emit_event,
|
|
277
|
+
on_model_change=on_model_change,
|
|
266
278
|
)
|
|
267
279
|
self._agent: Agent | None = None
|
|
268
280
|
|
|
@@ -302,6 +314,13 @@ class ExecutorContext:
|
|
|
302
314
|
|
|
303
315
|
session = Session.create() if session_id is None else Session.load(session_id)
|
|
304
316
|
|
|
317
|
+
if (
|
|
318
|
+
session.model_thinking is not None
|
|
319
|
+
and session.model_name
|
|
320
|
+
and session.model_name == self.llm_clients.main.model_name
|
|
321
|
+
):
|
|
322
|
+
self.llm_clients.main.get_llm_config().thinking = session.model_thinking
|
|
323
|
+
|
|
305
324
|
profile = self.model_profile_provider.build_profile(self.llm_clients.main)
|
|
306
325
|
agent = Agent(session=session, profile=profile)
|
|
307
326
|
|
|
@@ -439,8 +458,9 @@ class Executor:
|
|
|
439
458
|
event_queue: asyncio.Queue[events.Event],
|
|
440
459
|
llm_clients: LLMClients,
|
|
441
460
|
model_profile_provider: ModelProfileProvider | None = None,
|
|
461
|
+
on_model_change: Callable[[str], None] | None = None,
|
|
442
462
|
):
|
|
443
|
-
self.context = ExecutorContext(event_queue, llm_clients, model_profile_provider)
|
|
463
|
+
self.context = ExecutorContext(event_queue, llm_clients, model_profile_provider, on_model_change)
|
|
444
464
|
self.submission_queue: asyncio.Queue[op.Submission] = asyncio.Queue()
|
|
445
465
|
# Track completion events for all submissions (not just those with ActiveTask)
|
|
446
466
|
self._completion_events: dict[str, asyncio.Event] = {}
|