klaude-code 1.3.0__tar.gz → 1.4.1__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.3.0 → klaude_code-1.4.1}/PKG-INFO +1 -2
- {klaude_code-1.3.0 → klaude_code-1.4.1}/pyproject.toml +1 -2
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/runtime.py +2 -2
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/session_cmd.py +24 -9
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/model_cmd.py +18 -13
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/thinking_cmd.py +28 -20
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/config/select_model.py +40 -30
- klaude_code-1.4.1/src/klaude_code/session/selector.py +98 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/event_handler.py +7 -1
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +1 -1
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/key_bindings.py +42 -1
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/developer.py +15 -6
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/errors.py +1 -1
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/tools.py +1 -1
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/searchable_text.py +4 -7
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/status.py +55 -2
- klaude_code-1.4.1/src/klaude_code/ui/terminal/selector.py +283 -0
- klaude_code-1.3.0/src/klaude_code/session/selector.py +0 -81
- {klaude_code-1.3.0 → klaude_code-1.4.1}/README.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/auth/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/auth/codex/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/auth/codex/exceptions.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/auth/codex/oauth.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/auth/codex/token_manager.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/auth_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/config_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/debug.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/list_model.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/main.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/cli/self_update.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/clear_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/command_abc.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/debug_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/export_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/export_online_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/fork_session_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/help_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/prompt-init.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/prompt-jj-describe.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/prompt_command.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/refresh_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/registry.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/release_notes_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/resume_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/status_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/config/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/config/assets/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/config/assets/builtin_config.yaml +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/config/builtin_config.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/config/config.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/const.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/agent.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/executor.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/manager/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/manager/llm_clients.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompt.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-sub-agent-oracle.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/reminders.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/task.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/__init__.py +2 -2
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/_utils.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/move_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/move_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/read_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/read_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/write_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/file/write_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/report_back_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/shell/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/skill/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/skill/skill_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/skill/skill_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/todo/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/tool_abc.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/tool_context.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/tool_registry.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/tool_runner.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/truncation.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/web/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/core/turn.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/anthropic/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/anthropic/client.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/anthropic/input.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/client.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/codex/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/codex/client.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/input_common.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openai_compatible/client.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openai_compatible/input.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openai_compatible/stream.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openrouter/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openrouter/client.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openrouter/input.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/registry.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/responses/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/responses/client.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/responses/input.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/llm/usage.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/commands.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/events.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/llm_param.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/model.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/op.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/op_handler.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/sub_agent/oracle.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/sub_agent/task.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/sub_agent/web.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/protocol/tools.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/session/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/session/codec.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/session/export.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/session/session.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/session/store.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/session/templates/export_session.html +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/session/templates/mermaid_viewer.html +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/assets/dev-docs/SKILL.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/assets/jj-workspace/SKILL.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/loader.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/manager.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/skill/system_skills.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/trace/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/trace/log.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/core/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/core/display.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/core/input.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/core/stage_manager.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/debug/display.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/exec/display.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/completers.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/display.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/renderer.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/assistant.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/bash_syntax.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/common.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/diffs.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/mermaid_viewer.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/metadata.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/thinking.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/renderers/user_input.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/cjk_wrap.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/code_panel.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/live.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/markdown.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/quote.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/rich/theme.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/terminal/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/terminal/color.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/terminal/control.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/terminal/notifier.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/utils/__init__.py +0 -0
- {klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/utils/common.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: klaude-code
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: Minimal code agent CLI
|
|
5
5
|
Requires-Dist: anthropic>=0.66.0
|
|
6
6
|
Requires-Dist: chardet>=5.2.0
|
|
@@ -12,7 +12,6 @@ Requires-Dist: pillow>=12.0.0
|
|
|
12
12
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
13
13
|
Requires-Dist: pydantic>=2.11.7
|
|
14
14
|
Requires-Dist: pyyaml>=6.0.2
|
|
15
|
-
Requires-Dist: questionary>=2.1.1
|
|
16
15
|
Requires-Dist: rich>=14.1.0
|
|
17
16
|
Requires-Dist: trafilatura>=2.0.0
|
|
18
17
|
Requires-Dist: typer>=0.17.3
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "klaude-code"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4.1"
|
|
8
8
|
description = "Minimal code agent CLI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13"
|
|
@@ -19,7 +19,6 @@ dependencies = [
|
|
|
19
19
|
"prompt-toolkit>=3.0.52",
|
|
20
20
|
"pydantic>=2.11.7",
|
|
21
21
|
"pyyaml>=6.0.2",
|
|
22
|
-
"questionary>=2.1.1",
|
|
23
22
|
"rich>=14.1.0",
|
|
24
23
|
"trafilatura>=2.0.0",
|
|
25
24
|
"typer>=0.17.3",
|
|
@@ -273,7 +273,7 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
|
|
|
273
273
|
display.wrapped_display.renderer.stop_bottom_live()
|
|
274
274
|
|
|
275
275
|
# Pass the pre-detected theme to avoid redundant TTY queries.
|
|
276
|
-
# Querying the terminal background again after
|
|
276
|
+
# Querying the terminal background again after an interactive selection
|
|
277
277
|
# can interfere with prompt_toolkit's terminal state and break history navigation.
|
|
278
278
|
is_light_background: bool | None = None
|
|
279
279
|
if components.theme == "light":
|
|
@@ -352,7 +352,7 @@ async def run_interactive(init_config: AppInitConfig, session_id: str | None = N
|
|
|
352
352
|
op.UserInputOperation(input=user_input, session_id=active_session_id)
|
|
353
353
|
)
|
|
354
354
|
# If it's an interactive command (e.g., /model), avoid starting the ESC monitor
|
|
355
|
-
# to prevent TTY conflicts with interactive
|
|
355
|
+
# to prevent TTY conflicts with interactive prompt_toolkit UIs.
|
|
356
356
|
if has_interactive_command(user_input.text):
|
|
357
357
|
await components.executor.wait_for(submission_id)
|
|
358
358
|
else:
|
|
@@ -7,8 +7,11 @@ from klaude_code.trace import log
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def _session_confirm(sessions: list[Session.SessionMetaBrief], message: str) -> bool:
|
|
10
|
-
"""Show session list and confirm deletion using
|
|
11
|
-
|
|
10
|
+
"""Show session list and confirm deletion using prompt_toolkit."""
|
|
11
|
+
|
|
12
|
+
from prompt_toolkit.styles import Style
|
|
13
|
+
|
|
14
|
+
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
12
15
|
|
|
13
16
|
def _fmt(ts: float) -> str:
|
|
14
17
|
try:
|
|
@@ -24,14 +27,26 @@ def _session_confirm(sessions: list[Session.SessionMetaBrief], message: str) ->
|
|
|
24
27
|
first_msg += "..."
|
|
25
28
|
log(f" {_fmt(s.updated_at)} {msg_count_display:>3} msgs {first_msg}")
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
items: list[SelectItem[bool]] = [
|
|
31
|
+
SelectItem(title=[("class:text", "No\n")], value=False, search_text="No"),
|
|
32
|
+
SelectItem(title=[("class:text", "Yes\n")], value=True, search_text="Yes"),
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
result = select_one(
|
|
36
|
+
message=message,
|
|
37
|
+
items=items,
|
|
38
|
+
pointer="→",
|
|
39
|
+
style=Style(
|
|
40
|
+
[
|
|
41
|
+
("question", "bold"),
|
|
42
|
+
("pointer", "ansigreen"),
|
|
43
|
+
("highlighted", "ansigreen"),
|
|
44
|
+
("text", ""),
|
|
45
|
+
]
|
|
46
|
+
),
|
|
47
|
+
use_search_filter=False,
|
|
34
48
|
)
|
|
49
|
+
return bool(result)
|
|
35
50
|
|
|
36
51
|
|
|
37
52
|
def session_clean(
|
|
@@ -1,38 +1,43 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from prompt_toolkit.styles import Style
|
|
4
4
|
|
|
5
5
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
6
|
from klaude_code.config.select_model import select_model_from_config
|
|
7
7
|
from klaude_code.protocol import commands, events, model, op
|
|
8
|
+
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
8
9
|
|
|
9
|
-
SELECT_STYLE =
|
|
10
|
+
SELECT_STYLE = Style(
|
|
10
11
|
[
|
|
11
12
|
("instruction", "ansibrightblack"),
|
|
12
|
-
("pointer", "
|
|
13
|
-
("highlighted", "
|
|
13
|
+
("pointer", "ansigreen"),
|
|
14
|
+
("highlighted", "ansigreen"),
|
|
14
15
|
("text", "ansibrightblack"),
|
|
16
|
+
("question", ""),
|
|
15
17
|
]
|
|
16
18
|
)
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
def _confirm_change_default_model_sync(selected_model: str) -> bool:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
items: list[SelectItem[bool]] = [
|
|
23
|
+
SelectItem(title=[("class:text", "No (session only)\n")], value=False, search_text="No"),
|
|
24
|
+
SelectItem(
|
|
25
|
+
title=[("class:text", "Yes (save as default main_model in ~/.klaude/klaude-config.yaml)\n")],
|
|
26
|
+
value=True,
|
|
27
|
+
search_text="Yes",
|
|
28
|
+
),
|
|
23
29
|
]
|
|
24
30
|
|
|
25
31
|
try:
|
|
26
32
|
# Add a blank line between the model selector and this confirmation prompt.
|
|
27
|
-
|
|
28
|
-
result =
|
|
33
|
+
print("")
|
|
34
|
+
result = select_one(
|
|
29
35
|
message=f"Save '{selected_model}' as default model?",
|
|
30
|
-
|
|
36
|
+
items=items,
|
|
31
37
|
pointer="→",
|
|
32
|
-
instruction="Use arrow keys to move, Enter to select",
|
|
33
|
-
use_jk_keys=False,
|
|
34
38
|
style=SELECT_STYLE,
|
|
35
|
-
|
|
39
|
+
use_search_filter=False,
|
|
40
|
+
)
|
|
36
41
|
except KeyboardInterrupt:
|
|
37
42
|
return False
|
|
38
43
|
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
from typing import Literal, cast
|
|
2
3
|
|
|
3
|
-
import
|
|
4
|
+
from prompt_toolkit.styles import Style
|
|
4
5
|
|
|
5
6
|
from klaude_code.command.command_abc import Agent, CommandABC, CommandResult
|
|
6
7
|
from klaude_code.protocol import commands, events, llm_param, model
|
|
8
|
+
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
9
|
+
|
|
10
|
+
ReasoningEffort = Literal["high", "medium", "low", "minimal", "none", "xhigh"]
|
|
7
11
|
|
|
8
12
|
# Thinking level options for different protocols
|
|
9
13
|
RESPONSES_LEVELS = ["low", "medium", "high"]
|
|
@@ -118,12 +122,13 @@ def format_current_thinking(config: llm_param.LLMConfigParameter) -> str:
|
|
|
118
122
|
return "unknown protocol"
|
|
119
123
|
|
|
120
124
|
|
|
121
|
-
SELECT_STYLE =
|
|
125
|
+
SELECT_STYLE = Style(
|
|
122
126
|
[
|
|
123
127
|
("instruction", "ansibrightblack"),
|
|
124
|
-
("pointer", "
|
|
125
|
-
("highlighted", "
|
|
128
|
+
("pointer", "ansigreen"),
|
|
129
|
+
("highlighted", "ansigreen"),
|
|
126
130
|
("text", "ansibrightblack"),
|
|
131
|
+
("question", ""),
|
|
127
132
|
]
|
|
128
133
|
)
|
|
129
134
|
|
|
@@ -131,43 +136,46 @@ SELECT_STYLE = questionary.Style(
|
|
|
131
136
|
def _select_responses_thinking_sync(model_name: str | None) -> llm_param.Thinking | None:
|
|
132
137
|
"""Select thinking level for responses/codex protocol (sync version)."""
|
|
133
138
|
levels = _get_levels_for_responses(model_name)
|
|
134
|
-
|
|
139
|
+
items: list[SelectItem[str]] = [
|
|
140
|
+
SelectItem(title=[("class:text", level + "\n")], value=level, search_text=level) for level in levels
|
|
141
|
+
]
|
|
135
142
|
|
|
136
143
|
try:
|
|
137
|
-
result =
|
|
144
|
+
result = select_one(
|
|
138
145
|
message="Select reasoning effort:",
|
|
139
|
-
|
|
146
|
+
items=items,
|
|
140
147
|
pointer="→",
|
|
141
|
-
instruction="Use arrow keys to move, Enter to select",
|
|
142
|
-
use_jk_keys=False,
|
|
143
148
|
style=SELECT_STYLE,
|
|
144
|
-
|
|
149
|
+
use_search_filter=False,
|
|
150
|
+
)
|
|
145
151
|
|
|
146
152
|
if result is None:
|
|
147
153
|
return None
|
|
148
|
-
return llm_param.Thinking(reasoning_effort=result)
|
|
154
|
+
return llm_param.Thinking(reasoning_effort=cast(ReasoningEffort, result))
|
|
149
155
|
except KeyboardInterrupt:
|
|
150
156
|
return None
|
|
151
157
|
|
|
152
158
|
|
|
153
159
|
def _select_anthropic_thinking_sync() -> llm_param.Thinking | None:
|
|
154
160
|
"""Select thinking level for anthropic/openai_compatible protocol (sync version)."""
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
items: list[SelectItem[int]] = [
|
|
162
|
+
SelectItem(title=[("class:text", label + "\n")], value=tokens or 0, search_text=label)
|
|
163
|
+
for label, tokens in ANTHROPIC_LEVELS
|
|
157
164
|
]
|
|
158
165
|
|
|
159
166
|
try:
|
|
160
|
-
result =
|
|
167
|
+
result = select_one(
|
|
161
168
|
message="Select thinking level:",
|
|
162
|
-
|
|
169
|
+
items=items,
|
|
163
170
|
pointer="→",
|
|
164
|
-
instruction="Use arrow keys to move, Enter to select",
|
|
165
|
-
use_jk_keys=False,
|
|
166
171
|
style=SELECT_STYLE,
|
|
167
|
-
|
|
168
|
-
|
|
172
|
+
use_search_filter=False,
|
|
173
|
+
)
|
|
174
|
+
if result is None:
|
|
175
|
+
return None
|
|
176
|
+
if result == 0:
|
|
169
177
|
return llm_param.Thinking(type="disabled", budget_tokens=0)
|
|
170
|
-
return llm_param.Thinking(type="enabled", budget_tokens=result
|
|
178
|
+
return llm_param.Thinking(type="enabled", budget_tokens=result)
|
|
171
179
|
except KeyboardInterrupt:
|
|
172
180
|
return None
|
|
173
181
|
|
|
@@ -108,60 +108,70 @@ def select_model_from_config(preferred: str | None = None) -> str | None:
|
|
|
108
108
|
return None
|
|
109
109
|
|
|
110
110
|
try:
|
|
111
|
-
import
|
|
111
|
+
from prompt_toolkit.styles import Style
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
114
114
|
|
|
115
115
|
max_model_name_length = max(len(m.model_name) for m in filtered_models)
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
def build_model_id_with_thinking(m: ModelEntry) -> str:
|
|
119
|
-
model_id = m.model_params.model or "N/A"
|
|
117
|
+
def _thinking_info(m: ModelEntry) -> str:
|
|
120
118
|
thinking = m.model_params.thinking
|
|
121
|
-
if thinking:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
119
|
+
if not thinking:
|
|
120
|
+
return ""
|
|
121
|
+
if thinking.reasoning_effort:
|
|
122
|
+
return f"reasoning {thinking.reasoning_effort}"
|
|
123
|
+
if thinking.budget_tokens:
|
|
124
|
+
return f"thinking budget {thinking.budget_tokens}"
|
|
125
|
+
return "thinking (configured)"
|
|
126
|
+
|
|
127
|
+
items: list[SelectItem[str]] = []
|
|
131
128
|
for m in filtered_models:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
model_id = m.model_params.model or "N/A"
|
|
130
|
+
first_line_prefix = f"{m.model_name:<{max_model_name_length}} → "
|
|
131
|
+
thinking_info = _thinking_info(m)
|
|
132
|
+
meta_parts: list[str] = [m.provider]
|
|
133
|
+
if thinking_info:
|
|
134
|
+
meta_parts.append(thinking_info)
|
|
135
|
+
if m.model_params.verbosity:
|
|
136
|
+
meta_parts.append(f"verbosity {m.model_params.verbosity}")
|
|
137
|
+
meta_str = " · ".join(meta_parts)
|
|
138
|
+
title = [
|
|
139
|
+
("class:msg", first_line_prefix),
|
|
140
|
+
("class:msg bold", model_id),
|
|
141
|
+
("class:meta", f" {meta_str}\n"),
|
|
142
|
+
]
|
|
143
|
+
search_text = f"{m.model_name} {model_id} {m.provider}"
|
|
144
|
+
items.append(SelectItem(title=title, value=m.model_name, search_text=search_text))
|
|
136
145
|
|
|
137
146
|
try:
|
|
138
147
|
message = f"Select a model (filtered by '{preferred}'):" if preferred else "Select a model:"
|
|
139
|
-
result =
|
|
148
|
+
result = select_one(
|
|
140
149
|
message=message,
|
|
141
|
-
|
|
150
|
+
items=items,
|
|
142
151
|
pointer="→",
|
|
143
|
-
instruction="↑↓ to move • Enter to select",
|
|
144
|
-
use_jk_keys=False,
|
|
145
152
|
use_search_filter=True,
|
|
146
|
-
|
|
153
|
+
initial_value=config.main_model,
|
|
154
|
+
style=Style(
|
|
147
155
|
[
|
|
148
|
-
("
|
|
149
|
-
("
|
|
150
|
-
("
|
|
156
|
+
("pointer", "ansigreen"),
|
|
157
|
+
("highlighted", "ansigreen"),
|
|
158
|
+
("msg", ""),
|
|
159
|
+
("meta", "fg:ansibrightblack"),
|
|
151
160
|
("text", "ansibrightblack"),
|
|
161
|
+
("question", "bold"),
|
|
162
|
+
("search_prefix", "ansibrightblack"),
|
|
152
163
|
# search filter colors at the bottom
|
|
153
164
|
("search_success", "noinherit fg:ansigreen"),
|
|
154
165
|
("search_none", "noinherit fg:ansired"),
|
|
155
|
-
("question-mark", "fg:ansigreen"),
|
|
156
166
|
]
|
|
157
167
|
),
|
|
158
|
-
)
|
|
168
|
+
)
|
|
159
169
|
if isinstance(result, str) and result in names:
|
|
160
170
|
return result
|
|
161
171
|
except KeyboardInterrupt:
|
|
162
172
|
return None
|
|
163
173
|
except Exception as e:
|
|
164
|
-
log((f"Failed to use
|
|
174
|
+
log((f"Failed to use prompt_toolkit for model selection: {e}", "yellow"))
|
|
165
175
|
# Never return an unvalidated model name here.
|
|
166
176
|
# If we can't interactively select, fall back to a known configured model.
|
|
167
177
|
if isinstance(preferred, str) and preferred in names:
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from klaude_code.trace import log, log_debug
|
|
4
|
+
from klaude_code.ui.terminal.selector import SelectItem, select_one
|
|
5
|
+
|
|
6
|
+
from .session import Session
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _relative_time(ts: float) -> str:
|
|
10
|
+
"""Format timestamp as relative time like '5 days ago'."""
|
|
11
|
+
now = time.time()
|
|
12
|
+
diff = now - ts
|
|
13
|
+
|
|
14
|
+
if diff < 60:
|
|
15
|
+
return "just now"
|
|
16
|
+
elif diff < 3600:
|
|
17
|
+
mins = int(diff / 60)
|
|
18
|
+
return f"{mins} minute{'s' if mins != 1 else ''} ago"
|
|
19
|
+
elif diff < 86400:
|
|
20
|
+
hours = int(diff / 3600)
|
|
21
|
+
return f"{hours} hour{'s' if hours != 1 else ''} ago"
|
|
22
|
+
elif diff < 604800:
|
|
23
|
+
days = int(diff / 86400)
|
|
24
|
+
return f"{days} day{'s' if days != 1 else ''} ago"
|
|
25
|
+
elif diff < 2592000:
|
|
26
|
+
weeks = int(diff / 604800)
|
|
27
|
+
return f"{weeks} week{'s' if weeks != 1 else ''} ago"
|
|
28
|
+
else:
|
|
29
|
+
months = int(diff / 2592000)
|
|
30
|
+
return f"{months} month{'s' if months != 1 else ''} ago"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def resume_select_session() -> str | None:
|
|
34
|
+
sessions = Session.list_sessions()
|
|
35
|
+
if not sessions:
|
|
36
|
+
log("No sessions found for this project.")
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
from prompt_toolkit.styles import Style
|
|
41
|
+
|
|
42
|
+
items: list[SelectItem[str]] = []
|
|
43
|
+
for s in sessions:
|
|
44
|
+
first_msg = s.first_user_message or "N/A"
|
|
45
|
+
first_msg = first_msg.strip().replace("\n", " ")
|
|
46
|
+
|
|
47
|
+
msg_count = "N/A" if s.messages_count == -1 else f"{s.messages_count} messages"
|
|
48
|
+
model = s.model_name or "N/A"
|
|
49
|
+
|
|
50
|
+
title = [
|
|
51
|
+
("class:msg", f"{first_msg}\n"),
|
|
52
|
+
("class:meta", f" {msg_count} · {_relative_time(s.updated_at)} · {model} · {s.id}\n\n"),
|
|
53
|
+
]
|
|
54
|
+
items.append(
|
|
55
|
+
SelectItem(
|
|
56
|
+
title=title,
|
|
57
|
+
value=str(s.id),
|
|
58
|
+
search_text=f"{first_msg} {model} {s.id}",
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return select_one(
|
|
63
|
+
message="Select a session to resume:",
|
|
64
|
+
items=items,
|
|
65
|
+
pointer="→",
|
|
66
|
+
style=Style(
|
|
67
|
+
[
|
|
68
|
+
("msg", ""),
|
|
69
|
+
("meta", "fg:ansibrightblack"),
|
|
70
|
+
("pointer", "bold fg:ansigreen"),
|
|
71
|
+
("highlighted", "fg:ansigreen"),
|
|
72
|
+
("search_prefix", "fg:ansibrightblack"),
|
|
73
|
+
("search_success", "noinherit fg:ansigreen"),
|
|
74
|
+
("search_none", "noinherit fg:ansired"),
|
|
75
|
+
("question", "bold"),
|
|
76
|
+
("text", ""),
|
|
77
|
+
]
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
except Exception as e:
|
|
81
|
+
log_debug(f"Failed to use prompt_toolkit for session select, {e}")
|
|
82
|
+
|
|
83
|
+
for i, s in enumerate(sessions, 1):
|
|
84
|
+
first_msg = (s.first_user_message or "N/A").strip().replace("\n", " ")
|
|
85
|
+
if len(first_msg) > 60:
|
|
86
|
+
first_msg = first_msg[:59] + "…"
|
|
87
|
+
msg_count = "N/A" if s.messages_count == -1 else f"{s.messages_count} msgs"
|
|
88
|
+
model = s.model_name or "N/A"
|
|
89
|
+
print(f"{i}. {first_msg}")
|
|
90
|
+
print(f" {_relative_time(s.updated_at)} · {msg_count} · {model}")
|
|
91
|
+
try:
|
|
92
|
+
raw = input("Select a session number: ").strip()
|
|
93
|
+
idx = int(raw)
|
|
94
|
+
if 1 <= idx <= len(sessions):
|
|
95
|
+
return str(sessions[idx - 1].id)
|
|
96
|
+
except (ValueError, EOFError):
|
|
97
|
+
return None
|
|
98
|
+
return None
|
|
@@ -12,6 +12,7 @@ from klaude_code.ui.core.stage_manager import Stage, StageManager
|
|
|
12
12
|
from klaude_code.ui.modes.repl.renderer import REPLRenderer
|
|
13
13
|
from klaude_code.ui.renderers.assistant import ASSISTANT_MESSAGE_MARK
|
|
14
14
|
from klaude_code.ui.renderers.thinking import THINKING_MESSAGE_MARK, normalize_thinking_content
|
|
15
|
+
from klaude_code.ui.rich import status as r_status
|
|
15
16
|
from klaude_code.ui.rich.markdown import MarkdownStream, ThinkingMarkdown
|
|
16
17
|
from klaude_code.ui.rich.theme import ThemeKey
|
|
17
18
|
from klaude_code.ui.terminal.notifier import Notification, NotificationType, TerminalNotifier
|
|
@@ -352,6 +353,8 @@ class DisplayEventHandler:
|
|
|
352
353
|
self.renderer.display_user_message(event)
|
|
353
354
|
|
|
354
355
|
def _on_task_start(self, event: events.TaskStartEvent) -> None:
|
|
356
|
+
if event.sub_agent_state is None:
|
|
357
|
+
r_status.set_task_start()
|
|
355
358
|
self.renderer.spinner_start()
|
|
356
359
|
self.renderer.display_task_start(event)
|
|
357
360
|
emit_osc94(OSC94States.INDETERMINATE)
|
|
@@ -501,6 +504,7 @@ class DisplayEventHandler:
|
|
|
501
504
|
async def _on_task_finish(self, event: events.TaskFinishEvent) -> None:
|
|
502
505
|
self.renderer.display_task_finish(event)
|
|
503
506
|
if not self.renderer.is_sub_agent_session(event.session_id):
|
|
507
|
+
r_status.clear_task_start()
|
|
504
508
|
emit_osc94(OSC94States.HIDDEN)
|
|
505
509
|
self.spinner_status.reset()
|
|
506
510
|
self.renderer.spinner_stop()
|
|
@@ -511,6 +515,7 @@ class DisplayEventHandler:
|
|
|
511
515
|
async def _on_interrupt(self, event: events.InterruptEvent) -> None:
|
|
512
516
|
self.renderer.spinner_stop()
|
|
513
517
|
self.spinner_status.reset()
|
|
518
|
+
r_status.clear_task_start()
|
|
514
519
|
await self.stage_manager.transition_to(Stage.WAITING)
|
|
515
520
|
emit_osc94(OSC94States.HIDDEN)
|
|
516
521
|
self.renderer.display_interrupt()
|
|
@@ -528,6 +533,7 @@ class DisplayEventHandler:
|
|
|
528
533
|
await self.stage_manager.transition_to(Stage.WAITING)
|
|
529
534
|
self.renderer.spinner_stop()
|
|
530
535
|
self.spinner_status.reset()
|
|
536
|
+
r_status.clear_task_start()
|
|
531
537
|
|
|
532
538
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
533
539
|
# Private helper methods
|
|
@@ -619,7 +625,7 @@ class DisplayEventHandler:
|
|
|
619
625
|
# 1 cell for glyph + 1 cell of padding between columns (collapsed).
|
|
620
626
|
spinner_prefix_cells = 2
|
|
621
627
|
|
|
622
|
-
hint_cells = cell_len(
|
|
628
|
+
hint_cells = cell_len(r_status.current_hint_text())
|
|
623
629
|
right_cells = cell_len(right_text.plain) if right_text is not None else 0
|
|
624
630
|
|
|
625
631
|
max_main_cells = terminal_width - spinner_prefix_cells - hint_cells - right_cells - 1
|
{klaude_code-1.3.0 → klaude_code-1.4.1}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py
RENAMED
|
@@ -55,7 +55,7 @@ class PromptToolkitInput(InputProviderABC):
|
|
|
55
55
|
self._pre_prompt = pre_prompt
|
|
56
56
|
self._post_prompt = post_prompt
|
|
57
57
|
# Use provided value if available to avoid redundant TTY queries that may interfere
|
|
58
|
-
# with prompt_toolkit's terminal state after
|
|
58
|
+
# with prompt_toolkit's terminal state after interactive UIs have been used.
|
|
59
59
|
self._is_light_terminal_background = (
|
|
60
60
|
is_light_background if is_light_background is not None else is_light_terminal_background(timeout=0.2)
|
|
61
61
|
)
|
|
@@ -34,6 +34,47 @@ def create_key_bindings(
|
|
|
34
34
|
"""
|
|
35
35
|
kb = KeyBindings()
|
|
36
36
|
|
|
37
|
+
def _should_submit_instead_of_accepting_completion(buf: Buffer) -> bool:
|
|
38
|
+
"""Return True when Enter should submit even if completions are visible.
|
|
39
|
+
|
|
40
|
+
We show completions proactively for contexts like `/`.
|
|
41
|
+
If the user already typed an exact candidate (e.g. `/clear`), accepting
|
|
42
|
+
a completion often only adds a trailing space and makes Enter require
|
|
43
|
+
two presses. In that case, prefer submitting.
|
|
44
|
+
"""
|
|
45
|
+
state = buf.complete_state
|
|
46
|
+
if state is None or not state.completions:
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
doc = buf.document # type: ignore[reportUnknownMemberType]
|
|
51
|
+
text = cast(str, doc.text) # type: ignore[reportUnknownMemberType]
|
|
52
|
+
cursor_pos = cast(int, doc.cursor_position) # type: ignore[reportUnknownMemberType]
|
|
53
|
+
except Exception:
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
# Only apply this heuristic when the caret is at the end of the buffer.
|
|
57
|
+
if cursor_pos != len(text):
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
for completion in state.completions:
|
|
61
|
+
try:
|
|
62
|
+
start = cursor_pos + completion.start_position
|
|
63
|
+
if start < 0 or start > cursor_pos:
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
replaced = text[start:cursor_pos]
|
|
67
|
+
inserted = completion.text
|
|
68
|
+
|
|
69
|
+
# If the user already typed an exact candidate, don't force
|
|
70
|
+
# accepting a completion (which often just adds a space).
|
|
71
|
+
if replaced == inserted or replaced == inserted.rstrip():
|
|
72
|
+
return True
|
|
73
|
+
except Exception:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
return False
|
|
77
|
+
|
|
37
78
|
def _select_first_completion_if_needed(buf: Buffer) -> None:
|
|
38
79
|
"""Ensure the completion menu has an active selection.
|
|
39
80
|
|
|
@@ -98,7 +139,7 @@ def create_key_bindings(
|
|
|
98
139
|
# When completions are visible, Enter accepts the current selection.
|
|
99
140
|
# This aligns with common TUI completion UX: navigation doesn't modify
|
|
100
141
|
# the buffer, and Enter/Tab inserts the selected option.
|
|
101
|
-
if _accept_current_completion(buf):
|
|
142
|
+
if not _should_submit_instead_of_accepting_completion(buf) and _accept_current_completion(buf):
|
|
102
143
|
return
|
|
103
144
|
|
|
104
145
|
# If the entire buffer is whitespace-only, insert a newline rather than submitting.
|
|
@@ -67,23 +67,32 @@ def render_developer_message(e: events.DeveloperMessageEvent) -> RenderableType:
|
|
|
67
67
|
|
|
68
68
|
if e.item.at_files:
|
|
69
69
|
grid = create_grid()
|
|
70
|
+
# Group at_files by (operation, mentioned_in)
|
|
71
|
+
grouped: dict[tuple[str, str | None], list[str]] = {}
|
|
70
72
|
for at_file in e.item.at_files:
|
|
71
|
-
|
|
73
|
+
key = (at_file.operation, at_file.mentioned_in)
|
|
74
|
+
if key not in grouped:
|
|
75
|
+
grouped[key] = []
|
|
76
|
+
grouped[key].append(at_file.path)
|
|
77
|
+
|
|
78
|
+
for (operation, mentioned_in), paths in grouped.items():
|
|
79
|
+
path_texts = Text(", ", ThemeKey.REMINDER).join(render_path(p, ThemeKey.REMINDER_BOLD) for p in paths)
|
|
80
|
+
if mentioned_in:
|
|
72
81
|
grid.add_row(
|
|
73
82
|
Text(REMINDER_BULLET, style=ThemeKey.REMINDER),
|
|
74
83
|
Text.assemble(
|
|
75
|
-
(f"{
|
|
76
|
-
|
|
84
|
+
(f"{operation} ", ThemeKey.REMINDER),
|
|
85
|
+
path_texts,
|
|
77
86
|
(" mentioned in ", ThemeKey.REMINDER),
|
|
78
|
-
render_path(
|
|
87
|
+
render_path(mentioned_in, ThemeKey.REMINDER_BOLD),
|
|
79
88
|
),
|
|
80
89
|
)
|
|
81
90
|
else:
|
|
82
91
|
grid.add_row(
|
|
83
92
|
Text(REMINDER_BULLET, style=ThemeKey.REMINDER),
|
|
84
93
|
Text.assemble(
|
|
85
|
-
(f"{
|
|
86
|
-
|
|
94
|
+
(f"{operation} ", ThemeKey.REMINDER),
|
|
95
|
+
path_texts,
|
|
87
96
|
),
|
|
88
97
|
)
|
|
89
98
|
parts.append(grid)
|