klaude-code 2.0.0__tar.gz → 2.0.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-2.0.0 → klaude_code-2.0.1}/PKG-INFO +1 -1
- {klaude_code-2.0.0 → klaude_code-2.0.1}/pyproject.toml +1 -1
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/cost_cmd.py +1 -1
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/assets/builtin_config.yaml +4 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/const.py +4 -3
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/executor.py +0 -29
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/todo_write_tool.py +1 -2
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/model.py +1 -4
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/op.py +0 -13
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/op_handler.py +0 -5
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/event_handler.py +2 -5
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/key_bindings.py +135 -1
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/bash_syntax.py +36 -4
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/common.py +8 -6
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/tools.py +15 -20
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/theme.py +13 -13
- {klaude_code-2.0.0 → klaude_code-2.0.1}/README.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/base.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/exceptions.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/oauth.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/claude/token_manager.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/exceptions.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/oauth.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/auth/codex/token_manager.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/auth_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/config_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/debug.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/list_model.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/main.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/runtime.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/self_update.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/cli/session_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/clear_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/command_abc.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/debug_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/export_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/export_online_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/fork_session_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/help_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/model_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/model_select.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/prompt-commit.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/prompt-init.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/prompt_command.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/refresh_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/registry.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/release_notes_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/resume_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/status_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/terminal_setup_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/command/thinking_cmd.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/assets/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/builtin_config.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/config.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/select_model.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/config/thinking.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/agent.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/llm_clients.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompt.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent-image-gen.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/reminders.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/task.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/_utils.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/move_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/move_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/read_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/read_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/write_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/file/write_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/report_back_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/skill/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/skill/skill_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/skill/skill_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_abc.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_context.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_registry.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/tool_runner.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/truncation.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/core/turn.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/anthropic/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/anthropic/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/anthropic/input.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/bedrock/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/bedrock/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/claude/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/claude/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/codex/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/codex/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/google/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/google/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/google/input.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/image.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/input_common.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/input.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/stream.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/input.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/registry.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/responses/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/responses/client.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/responses/input.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/llm/usage.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/commands.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/events.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/llm_param.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/message.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/image_gen.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/task.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/sub_agent/web.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/protocol/tools.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/codec.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/export.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/selector.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/session.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/store.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/templates/export_session.html +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/session/templates/mermaid_viewer.html +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/dev-docs/SKILL.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/jj-workspace/SKILL.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/loader.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/manager.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/skill/system_skills.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/trace/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/trace/log.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/display.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/input.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/core/stage_manager.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/debug/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/debug/display.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/exec/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/exec/display.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/clipboard.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/completers.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/display.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/input_prompt_toolkit.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/modes/repl/renderer.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/assistant.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/developer.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/diffs.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/errors.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/mermaid_viewer.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/metadata.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/sub_agent.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/thinking.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/renderers/user_input.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/cjk_wrap.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/code_panel.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/live.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/markdown.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/quote.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/searchable_text.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/rich/status.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/color.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/control.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/image.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/notifier.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/progress_bar.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/terminal/selector.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/utils/__init__.py +0 -0
- {klaude_code-2.0.0 → klaude_code-2.0.1}/src/klaude_code/ui/utils/common.py +0 -0
|
@@ -122,13 +122,14 @@ TOOL_OUTPUT_TRUNCATION_DIR = "/tmp/klaude" # Directory for saving full truncate
|
|
|
122
122
|
TAB_EXPAND_WIDTH = 8 # Tab expansion width for text rendering
|
|
123
123
|
DIFF_PREFIX_WIDTH = 4 # Width of line number prefix in diff display
|
|
124
124
|
MAX_DIFF_LINES = 500 # Maximum lines to show in diff output
|
|
125
|
-
INVALID_TOOL_CALL_MAX_LENGTH =
|
|
126
|
-
TRUNCATE_DISPLAY_MAX_LINE_LENGTH =
|
|
127
|
-
TRUNCATE_DISPLAY_MAX_LINES =
|
|
125
|
+
INVALID_TOOL_CALL_MAX_LENGTH = 200 # Maximum length for invalid tool call display
|
|
126
|
+
TRUNCATE_DISPLAY_MAX_LINE_LENGTH = 200 # Maximum line length for truncated display
|
|
127
|
+
TRUNCATE_DISPLAY_MAX_LINES = 4 # Maximum lines for truncated display
|
|
128
128
|
MIN_HIDDEN_LINES_FOR_INDICATOR = 5 # Minimum hidden lines before showing truncation indicator
|
|
129
129
|
SUB_AGENT_RESULT_MAX_LINES = 10 # Maximum lines for sub-agent result display
|
|
130
130
|
TRUNCATE_HEAD_MAX_LINES = 2 # Maximum lines for sub-agent error display
|
|
131
131
|
BASH_OUTPUT_PANEL_THRESHOLD = 10 # Bash output line threshold for CodePanel display
|
|
132
|
+
BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES = 2 # Max lines shown for heredoc / multiline string tokens in bash tool calls
|
|
132
133
|
URL_TRUNCATE_MAX_LENGTH = 400 # Maximum length for URL truncation in display
|
|
133
134
|
QUERY_DISPLAY_TRUNCATE_LENGTH = 80 # Maximum length for search query display
|
|
134
135
|
NOTIFY_COMPACT_LIMIT = 160 # Maximum length for notification body text
|
|
@@ -176,35 +176,6 @@ class ExecutorContext:
|
|
|
176
176
|
"""Initialize an agent for a session and replay history to UI."""
|
|
177
177
|
await self._ensure_agent(operation.session_id)
|
|
178
178
|
|
|
179
|
-
async def handle_user_input(self, operation: op.UserInputOperation) -> None:
|
|
180
|
-
"""Handle a user input operation.
|
|
181
|
-
|
|
182
|
-
Core should not parse slash commands. The UI/CLI layer is responsible for
|
|
183
|
-
turning raw user input into one or more operations.
|
|
184
|
-
"""
|
|
185
|
-
|
|
186
|
-
if operation.session_id is None:
|
|
187
|
-
raise ValueError("session_id cannot be None")
|
|
188
|
-
|
|
189
|
-
session_id = operation.session_id
|
|
190
|
-
agent = await self._ensure_agent(session_id)
|
|
191
|
-
user_input = operation.input
|
|
192
|
-
|
|
193
|
-
await self.emit_event(
|
|
194
|
-
events.UserMessageEvent(content=user_input.text, session_id=session_id, images=user_input.images)
|
|
195
|
-
)
|
|
196
|
-
agent.session.append_history(
|
|
197
|
-
[message.UserMessage(parts=message.parts_from_text_and_images(user_input.text, user_input.images))]
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
await self.handle_run_agent(
|
|
201
|
-
op.RunAgentOperation(
|
|
202
|
-
id=operation.id,
|
|
203
|
-
session_id=session_id,
|
|
204
|
-
input=user_input,
|
|
205
|
-
)
|
|
206
|
-
)
|
|
207
|
-
|
|
208
179
|
async def handle_run_agent(self, operation: op.RunAgentOperation) -> None:
|
|
209
180
|
agent = await self._ensure_agent(operation.session_id)
|
|
210
181
|
existing_active = self.task_manager.get(operation.id)
|
|
@@ -63,9 +63,8 @@ class TodoWriteTool(ToolABC):
|
|
|
63
63
|
"type": "string",
|
|
64
64
|
"enum": ["pending", "in_progress", "completed"],
|
|
65
65
|
},
|
|
66
|
-
"activeForm": {"type": "string", "minLength": 1},
|
|
67
66
|
},
|
|
68
|
-
"required": ["content", "status"
|
|
67
|
+
"required": ["content", "status"],
|
|
69
68
|
"additionalProperties": False,
|
|
70
69
|
},
|
|
71
70
|
"description": "The updated todo list",
|
|
@@ -2,7 +2,7 @@ from datetime import datetime
|
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from typing import Annotated, Any, Literal
|
|
4
4
|
|
|
5
|
-
from pydantic import BaseModel,
|
|
5
|
+
from pydantic import BaseModel, Field, computed_field
|
|
6
6
|
|
|
7
7
|
from klaude_code.const import DEFAULT_MAX_TOKENS
|
|
8
8
|
from klaude_code.protocol.commands import CommandName
|
|
@@ -150,11 +150,8 @@ class TaskMetadataItem(BaseModel):
|
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
class TodoItem(BaseModel):
|
|
153
|
-
model_config = ConfigDict(populate_by_name=True)
|
|
154
|
-
|
|
155
153
|
content: str
|
|
156
154
|
status: TodoStatusType
|
|
157
|
-
active_form: str = Field(default="", alias="activeForm")
|
|
158
155
|
|
|
159
156
|
|
|
160
157
|
class FileStatus(BaseModel):
|
|
@@ -23,7 +23,6 @@ if TYPE_CHECKING:
|
|
|
23
23
|
class OperationType(Enum):
|
|
24
24
|
"""Enumeration of supported operation types."""
|
|
25
25
|
|
|
26
|
-
USER_INPUT = "user_input"
|
|
27
26
|
RUN_AGENT = "run_agent"
|
|
28
27
|
CHANGE_MODEL = "change_model"
|
|
29
28
|
CHANGE_THINKING = "change_thinking"
|
|
@@ -46,18 +45,6 @@ class Operation(BaseModel):
|
|
|
46
45
|
raise NotImplementedError("Subclasses must implement execute()")
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
class UserInputOperation(Operation):
|
|
50
|
-
"""Operation for handling user input (text and optional images) that should be processed by an agent."""
|
|
51
|
-
|
|
52
|
-
type: OperationType = OperationType.USER_INPUT
|
|
53
|
-
input: UserInputPayload
|
|
54
|
-
session_id: str | None = None
|
|
55
|
-
|
|
56
|
-
async def execute(self, handler: OperationHandler) -> None:
|
|
57
|
-
"""Execute user input by running it through an agent."""
|
|
58
|
-
await handler.handle_user_input(self)
|
|
59
|
-
|
|
60
|
-
|
|
61
48
|
class RunAgentOperation(Operation):
|
|
62
49
|
"""Operation for launching an agent task for a given session."""
|
|
63
50
|
|
|
@@ -18,17 +18,12 @@ if TYPE_CHECKING:
|
|
|
18
18
|
InterruptOperation,
|
|
19
19
|
ResumeSessionOperation,
|
|
20
20
|
RunAgentOperation,
|
|
21
|
-
UserInputOperation,
|
|
22
21
|
)
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
class OperationHandler(Protocol):
|
|
26
25
|
"""Protocol defining the interface for handling operations."""
|
|
27
26
|
|
|
28
|
-
async def handle_user_input(self, operation: UserInputOperation) -> None:
|
|
29
|
-
"""Handle a user input operation."""
|
|
30
|
-
...
|
|
31
|
-
|
|
32
27
|
async def handle_run_agent(self, operation: RunAgentOperation) -> None:
|
|
33
28
|
"""Handle a run agent operation."""
|
|
34
29
|
...
|
|
@@ -624,11 +624,8 @@ class DisplayEventHandler:
|
|
|
624
624
|
def _extract_active_form_text(self, todo_event: events.TodoChangeEvent) -> str | None:
|
|
625
625
|
status_text: str | None = None
|
|
626
626
|
for todo in todo_event.todos:
|
|
627
|
-
if todo.status == "in_progress":
|
|
628
|
-
|
|
629
|
-
status_text = todo.active_form
|
|
630
|
-
if len(todo.content) > 0:
|
|
631
|
-
status_text = todo.content
|
|
627
|
+
if todo.status == "in_progress" and len(todo.content) > 0:
|
|
628
|
+
status_text = todo.content
|
|
632
629
|
|
|
633
630
|
if status_text is None:
|
|
634
631
|
return None
|
|
@@ -11,8 +11,9 @@ import re
|
|
|
11
11
|
from collections.abc import Callable
|
|
12
12
|
from typing import cast
|
|
13
13
|
|
|
14
|
+
from prompt_toolkit.application.current import get_app
|
|
14
15
|
from prompt_toolkit.buffer import Buffer
|
|
15
|
-
from prompt_toolkit.filters import Always, Filter
|
|
16
|
+
from prompt_toolkit.filters import Always, Condition, Filter
|
|
16
17
|
from prompt_toolkit.filters.app import has_completions
|
|
17
18
|
from prompt_toolkit.key_binding import KeyBindings
|
|
18
19
|
from prompt_toolkit.key_binding.key_processor import KeyPressEvent
|
|
@@ -40,6 +41,119 @@ def create_key_bindings(
|
|
|
40
41
|
kb = KeyBindings()
|
|
41
42
|
enabled = input_enabled if input_enabled is not None else Always()
|
|
42
43
|
|
|
44
|
+
def _can_move_cursor_visually_within_wrapped_line(delta_visible_y: int) -> bool:
|
|
45
|
+
"""Return True when Up/Down should move within a wrapped visual line.
|
|
46
|
+
|
|
47
|
+
prompt_toolkit's default Up/Down behavior operates on logical lines
|
|
48
|
+
(split by '\n'). When a single logical line wraps across terminal
|
|
49
|
+
rows, pressing Up/Down should move within those wrapped rows instead of
|
|
50
|
+
triggering history navigation.
|
|
51
|
+
|
|
52
|
+
We only intercept when the cursor can move to an adjacent *visible*
|
|
53
|
+
line that maps to the same input line.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
app = get_app()
|
|
58
|
+
window = app.layout.current_window
|
|
59
|
+
ri = window.render_info
|
|
60
|
+
if ri is None:
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
current_visible_y = int(ri.cursor_position.y)
|
|
64
|
+
target_visible_y = current_visible_y + delta_visible_y
|
|
65
|
+
if target_visible_y < 0:
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
current_input_line = ri.visible_line_to_input_line.get(current_visible_y)
|
|
69
|
+
target_input_line = ri.visible_line_to_input_line.get(target_visible_y)
|
|
70
|
+
return current_input_line is not None and current_input_line == target_input_line
|
|
71
|
+
except Exception:
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
def _move_cursor_visually_within_wrapped_line(event: KeyPressEvent, *, delta_visible_y: int) -> None:
|
|
75
|
+
"""Move the cursor Up/Down by one wrapped screen row, keeping column."""
|
|
76
|
+
|
|
77
|
+
buf = event.current_buffer
|
|
78
|
+
try:
|
|
79
|
+
window = event.app.layout.current_window
|
|
80
|
+
ri = window.render_info
|
|
81
|
+
if ri is None:
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
rowcol_to_yx = getattr(ri, "_rowcol_to_yx", None)
|
|
85
|
+
x_offset = getattr(ri, "_x_offset", None)
|
|
86
|
+
y_offset = getattr(ri, "_y_offset", None)
|
|
87
|
+
if not isinstance(rowcol_to_yx, dict) or not isinstance(x_offset, int) or not isinstance(y_offset, int):
|
|
88
|
+
return
|
|
89
|
+
rowcol_to_yx_typed = cast(dict[tuple[int, int], tuple[int, int]], rowcol_to_yx)
|
|
90
|
+
|
|
91
|
+
current_visible_y = int(ri.cursor_position.y)
|
|
92
|
+
target_visible_y = current_visible_y + delta_visible_y
|
|
93
|
+
mapping = ri.visible_line_to_row_col
|
|
94
|
+
if current_visible_y not in mapping or target_visible_y not in mapping:
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
current_row, _ = mapping[current_visible_y]
|
|
98
|
+
target_row, _ = mapping[target_visible_y]
|
|
99
|
+
|
|
100
|
+
# Only handle wrapped rows within the same input line.
|
|
101
|
+
if current_row != target_row:
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
current_abs_y = y_offset + current_visible_y
|
|
105
|
+
target_abs_y = y_offset + target_visible_y
|
|
106
|
+
cursor_abs_x = x_offset + int(ri.cursor_position.x)
|
|
107
|
+
|
|
108
|
+
def _segment_start_abs_x(row: int, abs_y: int) -> int | None:
|
|
109
|
+
xs: list[int] = []
|
|
110
|
+
for (r, _col), (y, x) in rowcol_to_yx_typed.items():
|
|
111
|
+
if r == row and y == abs_y:
|
|
112
|
+
xs.append(x)
|
|
113
|
+
return min(xs) if xs else None
|
|
114
|
+
|
|
115
|
+
current_start_x = _segment_start_abs_x(current_row, current_abs_y)
|
|
116
|
+
target_start_x = _segment_start_abs_x(target_row, target_abs_y)
|
|
117
|
+
if current_start_x is None or target_start_x is None:
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
offset_in_segment_cells = max(0, cursor_abs_x - current_start_x)
|
|
121
|
+
desired_abs_x = target_start_x + offset_in_segment_cells
|
|
122
|
+
|
|
123
|
+
candidates: list[tuple[int, int]] = []
|
|
124
|
+
for (r, col), (y, x) in rowcol_to_yx_typed.items():
|
|
125
|
+
if r == target_row and y == target_abs_y:
|
|
126
|
+
candidates.append((col, x))
|
|
127
|
+
if not candidates:
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
# Pick the closest column at/before the desired X. If the desired
|
|
131
|
+
# position is before the first character, snap to the first.
|
|
132
|
+
candidates.sort(key=lambda t: t[1])
|
|
133
|
+
chosen_display_col = candidates[0][0]
|
|
134
|
+
for col, x in candidates:
|
|
135
|
+
if x <= desired_abs_x:
|
|
136
|
+
chosen_display_col = col
|
|
137
|
+
else:
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
control = event.app.layout.current_control
|
|
141
|
+
get_processed_line = getattr(control, "_last_get_processed_line", None)
|
|
142
|
+
target_source_col = chosen_display_col
|
|
143
|
+
if callable(get_processed_line):
|
|
144
|
+
processed_line = get_processed_line(target_row)
|
|
145
|
+
display_to_source = getattr(processed_line, "display_to_source", None)
|
|
146
|
+
if callable(display_to_source):
|
|
147
|
+
display_to_source_fn = cast(Callable[[int], int], display_to_source)
|
|
148
|
+
target_source_col = display_to_source_fn(chosen_display_col)
|
|
149
|
+
|
|
150
|
+
doc = buf.document # type: ignore[reportUnknownMemberType]
|
|
151
|
+
new_index = doc.translate_row_col_to_index(target_row, target_source_col) # type: ignore[reportUnknownMemberType]
|
|
152
|
+
buf.cursor_position = new_index # type: ignore[reportUnknownMemberType]
|
|
153
|
+
event.app.invalidate() # type: ignore[reportUnknownMemberType]
|
|
154
|
+
except Exception:
|
|
155
|
+
return
|
|
156
|
+
|
|
43
157
|
def _should_submit_instead_of_accepting_completion(buf: Buffer) -> bool:
|
|
44
158
|
"""Return True when Enter should submit even if completions are visible.
|
|
45
159
|
|
|
@@ -174,6 +288,26 @@ def create_key_bindings(
|
|
|
174
288
|
_cycle_completion(buf, delta=-1)
|
|
175
289
|
event.app.invalidate() # type: ignore[reportUnknownMemberType]
|
|
176
290
|
|
|
291
|
+
@kb.add(
|
|
292
|
+
"up",
|
|
293
|
+
filter=enabled
|
|
294
|
+
& ~has_completions
|
|
295
|
+
& Condition(lambda: _can_move_cursor_visually_within_wrapped_line(delta_visible_y=-1)),
|
|
296
|
+
eager=True,
|
|
297
|
+
)
|
|
298
|
+
def _(event: KeyPressEvent) -> None:
|
|
299
|
+
_move_cursor_visually_within_wrapped_line(event, delta_visible_y=-1)
|
|
300
|
+
|
|
301
|
+
@kb.add(
|
|
302
|
+
"down",
|
|
303
|
+
filter=enabled
|
|
304
|
+
& ~has_completions
|
|
305
|
+
& Condition(lambda: _can_move_cursor_visually_within_wrapped_line(delta_visible_y=1)),
|
|
306
|
+
eager=True,
|
|
307
|
+
)
|
|
308
|
+
def _(event: KeyPressEvent) -> None:
|
|
309
|
+
_move_cursor_visually_within_wrapped_line(event, delta_visible_y=1)
|
|
310
|
+
|
|
177
311
|
@kb.add("c-j", filter=enabled)
|
|
178
312
|
def _(event: KeyPressEvent) -> None:
|
|
179
313
|
event.current_buffer.insert_text("\n") # type: ignore
|
|
@@ -7,6 +7,8 @@ from pygments.lexers import BashLexer # pyright: ignore[reportUnknownVariableTy
|
|
|
7
7
|
from pygments.token import Token
|
|
8
8
|
from rich.text import Text
|
|
9
9
|
|
|
10
|
+
from klaude_code.const import BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES
|
|
11
|
+
from klaude_code.ui.renderers.common import truncate_head
|
|
10
12
|
from klaude_code.ui.rich.theme import ThemeKey
|
|
11
13
|
|
|
12
14
|
# Token types for bash syntax highlighting
|
|
@@ -110,13 +112,34 @@ def _append_heredoc(result: Text, token_value: str) -> None:
|
|
|
110
112
|
# Extra content on first line (e.g., "> file.py")
|
|
111
113
|
if extra:
|
|
112
114
|
result.append(extra, style=ThemeKey.BASH_ARGUMENT)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
|
|
116
|
+
# Body content (truncate to keep tool call rendering compact)
|
|
117
|
+
body_inner = body.strip("\n")
|
|
118
|
+
result.append("\n")
|
|
119
|
+
if body_inner:
|
|
120
|
+
body_text = truncate_head(
|
|
121
|
+
body_inner,
|
|
122
|
+
max_lines=BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES,
|
|
123
|
+
base_style=ThemeKey.BASH_STRING,
|
|
124
|
+
truncated_style=ThemeKey.TOOL_RESULT_TRUNCATED,
|
|
125
|
+
)
|
|
126
|
+
result.append_text(body_text)
|
|
127
|
+
result.append("\n")
|
|
128
|
+
|
|
115
129
|
# End delimiter
|
|
116
130
|
result.append(end_delimiter, style=ThemeKey.BASH_HEREDOC_DELIMITER)
|
|
117
131
|
else:
|
|
118
132
|
# Fallback: couldn't parse heredoc structure
|
|
119
|
-
|
|
133
|
+
if "\n" in token_value and len(token_value.splitlines()) > BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES:
|
|
134
|
+
truncated = truncate_head(
|
|
135
|
+
token_value,
|
|
136
|
+
max_lines=BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES,
|
|
137
|
+
base_style=ThemeKey.BASH_STRING,
|
|
138
|
+
truncated_style=ThemeKey.TOOL_RESULT_TRUNCATED,
|
|
139
|
+
)
|
|
140
|
+
result.append_text(truncated)
|
|
141
|
+
else:
|
|
142
|
+
result.append(token_value, style=ThemeKey.BASH_STRING)
|
|
120
143
|
|
|
121
144
|
|
|
122
145
|
def highlight_bash_command(command: str) -> Text:
|
|
@@ -145,7 +168,16 @@ def highlight_bash_command(command: str) -> Text:
|
|
|
145
168
|
if token_value.startswith("<<"):
|
|
146
169
|
_append_heredoc(result, token_value)
|
|
147
170
|
else:
|
|
148
|
-
|
|
171
|
+
if "\n" in token_value and len(token_value.splitlines()) > BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES:
|
|
172
|
+
truncated = truncate_head(
|
|
173
|
+
token_value,
|
|
174
|
+
max_lines=BASH_MULTILINE_STRING_TRUNCATE_MAX_LINES,
|
|
175
|
+
base_style=ThemeKey.BASH_STRING,
|
|
176
|
+
truncated_style=ThemeKey.TOOL_RESULT_TRUNCATED,
|
|
177
|
+
)
|
|
178
|
+
result.append_text(truncated)
|
|
179
|
+
else:
|
|
180
|
+
result.append(token_value, style=ThemeKey.BASH_STRING)
|
|
149
181
|
expect_subcommand = False
|
|
150
182
|
elif token_type in _OPERATOR_TOKENS:
|
|
151
183
|
result.append(token_value, style=ThemeKey.BASH_OPERATOR)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
1
3
|
from rich.style import Style
|
|
2
4
|
from rich.table import Table
|
|
3
5
|
from rich.text import Text
|
|
@@ -12,10 +14,10 @@ from klaude_code.const import (
|
|
|
12
14
|
from klaude_code.ui.rich.theme import ThemeKey
|
|
13
15
|
|
|
14
16
|
|
|
15
|
-
def create_grid() -> Table:
|
|
17
|
+
def create_grid(*, overflow: Literal["fold", "crop", "ellipsis", "ignore"] = "fold") -> Table:
|
|
16
18
|
grid = Table.grid(padding=(0, 1))
|
|
17
19
|
grid.add_column(no_wrap=True)
|
|
18
|
-
grid.add_column(overflow=
|
|
20
|
+
grid.add_column(overflow=overflow)
|
|
19
21
|
return grid
|
|
20
22
|
|
|
21
23
|
|
|
@@ -36,7 +38,7 @@ def truncate_middle(
|
|
|
36
38
|
if max_lines <= 0:
|
|
37
39
|
truncated_lines = text.split("\n")
|
|
38
40
|
remaining = max(0, len(truncated_lines))
|
|
39
|
-
return Text(f"… (more {remaining} lines)", style=ThemeKey.TOOL_RESULT_TRUNCATED)
|
|
41
|
+
return Text(f" … (more {remaining} lines)", style=ThemeKey.TOOL_RESULT_TRUNCATED)
|
|
40
42
|
|
|
41
43
|
lines = text.split("\n")
|
|
42
44
|
truncated_lines = 0
|
|
@@ -65,7 +67,7 @@ def truncate_middle(
|
|
|
65
67
|
out.append(line[:max_line_length])
|
|
66
68
|
out.append_text(
|
|
67
69
|
Text(
|
|
68
|
-
f"… (more {extra_chars} characters in this line)",
|
|
70
|
+
f" … (more {extra_chars} characters in this line)",
|
|
69
71
|
style=ThemeKey.TOOL_RESULT_TRUNCATED,
|
|
70
72
|
)
|
|
71
73
|
)
|
|
@@ -82,7 +84,7 @@ def truncate_middle(
|
|
|
82
84
|
out.append("\n")
|
|
83
85
|
|
|
84
86
|
if truncated_lines > 0:
|
|
85
|
-
out.append_text(Text(f"
|
|
87
|
+
out.append_text(Text(f" … (more {truncated_lines} lines)\n", style=ThemeKey.TOOL_RESULT_TRUNCATED))
|
|
86
88
|
|
|
87
89
|
for idx, line in enumerate(tail_lines):
|
|
88
90
|
append_line(out, line)
|
|
@@ -139,6 +141,6 @@ def truncate_head(
|
|
|
139
141
|
out.append("\n")
|
|
140
142
|
|
|
141
143
|
remaining = len(lines) - max_lines
|
|
142
|
-
out.append_text(Text(f"… more {remaining} lines", style=truncated_style or ThemeKey.TOOL_RESULT_TRUNCATED))
|
|
144
|
+
out.append_text(Text(f" … (more {remaining} lines)", style=truncated_style or ThemeKey.TOOL_RESULT_TRUNCATED))
|
|
143
145
|
|
|
144
146
|
return out
|
|
@@ -68,9 +68,7 @@ def _render_tool_call_tree(
|
|
|
68
68
|
tool_name: str,
|
|
69
69
|
details: RenderableType | None,
|
|
70
70
|
) -> RenderableType:
|
|
71
|
-
|
|
72
|
-
# but move the tool mark into the tree prefix so it can connect to the tool result.
|
|
73
|
-
grid = create_grid()
|
|
71
|
+
grid = create_grid(overflow="ellipsis")
|
|
74
72
|
grid.add_row(
|
|
75
73
|
Text(tool_name, style=ThemeKey.TOOL_NAME),
|
|
76
74
|
details if details is not None else Text(""),
|
|
@@ -138,15 +136,13 @@ def render_bash_tool_call(arguments: str) -> RenderableType:
|
|
|
138
136
|
command = payload.get("command")
|
|
139
137
|
timeout_ms = payload.get("timeout_ms")
|
|
140
138
|
|
|
141
|
-
# Build the command display with optional timeout suffix
|
|
142
139
|
if isinstance(command, str) and command.strip():
|
|
143
140
|
cmd_str = command.strip()
|
|
144
|
-
line_count = len(cmd_str.splitlines())
|
|
145
|
-
|
|
146
141
|
highlighted = highlight_bash_command(cmd_str)
|
|
147
142
|
|
|
148
|
-
|
|
149
|
-
|
|
143
|
+
display_line_count = len(highlighted.plain.splitlines())
|
|
144
|
+
|
|
145
|
+
if display_line_count > BASH_OUTPUT_PANEL_THRESHOLD:
|
|
150
146
|
code_panel = CodePanel(highlighted, border_style=ThemeKey.LINES)
|
|
151
147
|
if isinstance(timeout_ms, int):
|
|
152
148
|
if timeout_ms >= 1000 and timeout_ms % 1000 == 0:
|
|
@@ -298,7 +294,6 @@ def render_move_tool_call(arguments: str) -> RenderableType:
|
|
|
298
294
|
start_line = payload.get("start_line", "")
|
|
299
295
|
end_line = payload.get("end_line", "")
|
|
300
296
|
|
|
301
|
-
# Build display: source:start-end -> target
|
|
302
297
|
parts = Text()
|
|
303
298
|
if source_path:
|
|
304
299
|
parts.append_text(render_path(source_path, ThemeKey.TOOL_PARAM_FILE_PATH))
|
|
@@ -386,15 +381,17 @@ def render_todo(tr: events.ToolResultEvent) -> RenderableType:
|
|
|
386
381
|
def render_generic_tool_result(result: str, *, is_error: bool = False) -> RenderableType:
|
|
387
382
|
"""Render a generic tool result as truncated text."""
|
|
388
383
|
style = ThemeKey.ERROR if is_error else ThemeKey.TOOL_RESULT
|
|
389
|
-
|
|
384
|
+
text = truncate_middle(result, base_style=style)
|
|
385
|
+
# Tool results should not reflow/wrap; use ellipsis when exceeding terminal width.
|
|
386
|
+
text.no_wrap = True
|
|
387
|
+
text.overflow = "ellipsis"
|
|
388
|
+
return text
|
|
390
389
|
|
|
391
390
|
|
|
392
391
|
def _extract_mermaid_link(
|
|
393
392
|
ui_extra: model.ToolResultUIExtra | None,
|
|
394
393
|
) -> model.MermaidLinkUIExtra | None:
|
|
395
|
-
if isinstance(ui_extra, model.MermaidLinkUIExtra)
|
|
396
|
-
return ui_extra
|
|
397
|
-
return None
|
|
394
|
+
return ui_extra if isinstance(ui_extra, model.MermaidLinkUIExtra) else None
|
|
398
395
|
|
|
399
396
|
|
|
400
397
|
def render_mermaid_tool_call(arguments: str) -> RenderableType:
|
|
@@ -443,7 +440,7 @@ def _render_mermaid_viewer_link(
|
|
|
443
440
|
) -> RenderableType:
|
|
444
441
|
viewer_path = r_mermaid_viewer.build_viewer(code=link_info.code, link=link_info.link, tool_call_id=tr.tool_call_id)
|
|
445
442
|
if viewer_path is None:
|
|
446
|
-
return Text(link_info.link, style=ThemeKey.TOOL_RESULT_MERMAID, overflow="
|
|
443
|
+
return Text(link_info.link, style=ThemeKey.TOOL_RESULT_MERMAID, overflow="ellipsis", no_wrap=True)
|
|
447
444
|
|
|
448
445
|
display_path = str(viewer_path)
|
|
449
446
|
|
|
@@ -534,9 +531,7 @@ def render_mermaid_tool_result(
|
|
|
534
531
|
def _extract_truncation(
|
|
535
532
|
ui_extra: model.ToolResultUIExtra | None,
|
|
536
533
|
) -> model.TruncationUIExtra | None:
|
|
537
|
-
if isinstance(ui_extra, model.TruncationUIExtra)
|
|
538
|
-
return ui_extra
|
|
539
|
-
return None
|
|
534
|
+
return ui_extra if isinstance(ui_extra, model.TruncationUIExtra) else None
|
|
540
535
|
|
|
541
536
|
|
|
542
537
|
def render_truncation_info(ui_extra: model.TruncationUIExtra) -> RenderableType:
|
|
@@ -548,6 +543,8 @@ def render_truncation_info(ui_extra: model.TruncationUIExtra) -> RenderableType:
|
|
|
548
543
|
(ui_extra.saved_file_path, ThemeKey.TOOL_RESULT_TRUNCATED),
|
|
549
544
|
(f", {truncated_kb:.1f}KB truncated", ThemeKey.TOOL_RESULT_TRUNCATED),
|
|
550
545
|
)
|
|
546
|
+
text.no_wrap = True
|
|
547
|
+
text.overflow = "ellipsis"
|
|
551
548
|
return text
|
|
552
549
|
|
|
553
550
|
|
|
@@ -685,7 +682,7 @@ def render_tool_result(
|
|
|
685
682
|
|
|
686
683
|
# Handle error case
|
|
687
684
|
if e.status == "error" and e.ui_extra is None:
|
|
688
|
-
return wrap(
|
|
685
|
+
return wrap(render_generic_tool_result(e.result, is_error=True))
|
|
689
686
|
|
|
690
687
|
# Render multiple ui blocks if present
|
|
691
688
|
if isinstance(e.ui_extra, model.MultiUIExtra) and e.ui_extra.items:
|
|
@@ -737,8 +734,6 @@ def render_tool_result(
|
|
|
737
734
|
case tools.MERMAID:
|
|
738
735
|
return wrap(render_mermaid_tool_result(e, session_id=session_id))
|
|
739
736
|
case tools.BASH:
|
|
740
|
-
if e.result.startswith("diff --git"):
|
|
741
|
-
return wrap(r_diffs.render_diff_panel(e.result, show_file_name=True))
|
|
742
737
|
return _render_fallback()
|
|
743
738
|
case _:
|
|
744
739
|
return _render_fallback()
|
|
@@ -60,17 +60,17 @@ LIGHT_PALETTE = Palette(
|
|
|
60
60
|
diff_remove="#82071e on #ffecec",
|
|
61
61
|
diff_remove_char="#82071e on #ffcfcf",
|
|
62
62
|
code_theme="ansi_light",
|
|
63
|
-
code_background="#
|
|
64
|
-
green_background="#
|
|
65
|
-
blue_grey_background="#
|
|
66
|
-
cyan_background="#
|
|
67
|
-
green_sub_background="#
|
|
68
|
-
blue_sub_background="#
|
|
69
|
-
purple_background="#
|
|
70
|
-
orange_background="#
|
|
71
|
-
red_background="#
|
|
72
|
-
grey_background="#
|
|
73
|
-
yellow_background="#
|
|
63
|
+
code_background="#ebebeb",
|
|
64
|
+
green_background="#f0f7f1",
|
|
65
|
+
blue_grey_background="#f0f1f7",
|
|
66
|
+
cyan_background="#ecf7f7",
|
|
67
|
+
green_sub_background="#ecf7ec",
|
|
68
|
+
blue_sub_background="#ecf1f9",
|
|
69
|
+
purple_background="#f5ecf9",
|
|
70
|
+
orange_background="#f9f3ec",
|
|
71
|
+
red_background="#f9ecec",
|
|
72
|
+
grey_background="#f0f0f0",
|
|
73
|
+
yellow_background="#f9f9ec",
|
|
74
74
|
)
|
|
75
75
|
|
|
76
76
|
DARK_PALETTE = Palette(
|
|
@@ -270,11 +270,11 @@ def get_theme(theme: str | None = None) -> Themes:
|
|
|
270
270
|
ThemeKey.TOOL_RESULT.value: palette.grey_green,
|
|
271
271
|
ThemeKey.TOOL_RESULT_TREE_PREFIX.value: palette.grey_green + " dim",
|
|
272
272
|
ThemeKey.TOOL_RESULT_BOLD.value: "bold " + palette.grey_green,
|
|
273
|
-
ThemeKey.TOOL_RESULT_TRUNCATED.value: palette.
|
|
273
|
+
ThemeKey.TOOL_RESULT_TRUNCATED.value: palette.grey1,
|
|
274
274
|
ThemeKey.TOOL_MARK.value: "bold",
|
|
275
275
|
ThemeKey.TOOL_APPROVED.value: palette.green + " bold reverse",
|
|
276
276
|
ThemeKey.TOOL_REJECTED.value: palette.red + " bold reverse",
|
|
277
|
-
ThemeKey.TOOL_TIMEOUT.value: palette.
|
|
277
|
+
ThemeKey.TOOL_TIMEOUT.value: palette.grey2,
|
|
278
278
|
ThemeKey.TOOL_RESULT_MERMAID: palette.blue + " underline",
|
|
279
279
|
ThemeKey.SUB_AGENT_FOOTER.value: "dim " + palette.grey2,
|
|
280
280
|
# BASH SYNTAX
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|