klaude-code 2.1.0__tar.gz → 2.1.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.
Files changed (235) hide show
  1. {klaude_code-2.1.0 → klaude_code-2.1.1}/PKG-INFO +1 -1
  2. {klaude_code-2.1.0 → klaude_code-2.1.1}/pyproject.toml +1 -1
  3. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/agent_profile.py +10 -3
  4. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/reminders.py +20 -4
  5. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/__init__.py +0 -2
  6. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/turn.py +1 -4
  7. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/commands.py +1 -0
  8. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/tools.py +5 -1
  9. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/tools.py +0 -1
  10. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/session.py +0 -2
  11. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/loader.py +31 -87
  12. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/manager.py +38 -0
  13. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/__init__.py +3 -0
  14. klaude_code-2.1.1/src/klaude_code/tui/command/copy_cmd.py +53 -0
  15. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/tools.py +4 -8
  16. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/machine.py +3 -1
  17. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/renderer.py +1 -1
  18. klaude_code-2.1.0/src/klaude_code/core/tool/skill/skill_tool.md +0 -24
  19. klaude_code-2.1.0/src/klaude_code/core/tool/skill/skill_tool.py +0 -89
  20. klaude_code-2.1.0/src/klaude_code/tui/components/__init__.py +0 -0
  21. {klaude_code-2.1.0 → klaude_code-2.1.1}/README.md +0 -0
  22. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/__init__.py +0 -0
  23. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/app/__init__.py +0 -0
  24. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/app/runtime.py +0 -0
  25. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/__init__.py +0 -0
  26. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/base.py +0 -0
  27. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/claude/__init__.py +0 -0
  28. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/claude/exceptions.py +0 -0
  29. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/claude/oauth.py +0 -0
  30. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/claude/token_manager.py +0 -0
  31. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/codex/__init__.py +0 -0
  32. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/codex/exceptions.py +0 -0
  33. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
  34. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/codex/oauth.py +0 -0
  35. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/auth/codex/token_manager.py +0 -0
  36. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/__init__.py +0 -0
  37. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/auth_cmd.py +0 -0
  38. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/config_cmd.py +0 -0
  39. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/cost_cmd.py +0 -0
  40. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/debug.py +0 -0
  41. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/list_model.py +0 -0
  42. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/main.py +0 -0
  43. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/self_update.py +0 -0
  44. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/cli/session_cmd.py +0 -0
  45. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/config/__init__.py +0 -0
  46. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/config/assets/__init__.py +0 -0
  47. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/config/assets/builtin_config.yaml +0 -0
  48. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/config/builtin_config.py +0 -0
  49. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/config/config.py +0 -0
  50. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/config/select_model.py +0 -0
  51. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/config/thinking.py +0 -0
  52. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/const.py +0 -0
  53. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/__init__.py +0 -0
  54. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/agent.py +0 -0
  55. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/executor.py +0 -0
  56. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/manager/__init__.py +0 -0
  57. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/manager/llm_clients.py +0 -0
  58. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/manager/llm_clients_builder.py +0 -0
  59. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
  60. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-claude-code.md +0 -0
  61. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-1-codex-max.md +0 -0
  62. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
  63. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
  64. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
  65. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
  66. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
  67. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-sub-agent-image-gen.md +0 -0
  68. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +0 -0
  69. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
  70. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/task.py +0 -0
  71. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/context.py +0 -0
  72. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/__init__.py +0 -0
  73. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/_utils.py +0 -0
  74. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/apply_patch.py +0 -0
  75. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
  76. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
  77. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
  78. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
  79. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/edit_tool.py +0 -0
  80. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/read_tool.md +0 -0
  81. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/read_tool.py +0 -0
  82. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/write_tool.md +0 -0
  83. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/file/write_tool.py +0 -0
  84. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/report_back_tool.py +0 -0
  85. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/shell/__init__.py +0 -0
  86. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
  87. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/shell/bash_tool.py +0 -0
  88. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
  89. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/sub_agent_tool.py +0 -0
  90. {klaude_code-2.1.0/src/klaude_code/core/tool/skill → klaude_code-2.1.1/src/klaude_code/core/tool/todo}/__init__.py +0 -0
  91. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
  92. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
  93. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
  94. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
  95. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
  96. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/tool_abc.py +0 -0
  97. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/tool_registry.py +0 -0
  98. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/tool_runner.py +0 -0
  99. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/truncation.py +0 -0
  100. {klaude_code-2.1.0/src/klaude_code/core/tool/todo → klaude_code-2.1.1/src/klaude_code/core/tool/web}/__init__.py +0 -0
  101. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
  102. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
  103. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/web/web_fetch_tool.md +0 -0
  104. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/web/web_fetch_tool.py +0 -0
  105. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
  106. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
  107. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/__init__.py +0 -0
  108. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/anthropic/__init__.py +0 -0
  109. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/anthropic/client.py +0 -0
  110. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/anthropic/input.py +0 -0
  111. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/bedrock/__init__.py +0 -0
  112. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/bedrock/client.py +0 -0
  113. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/claude/__init__.py +0 -0
  114. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/claude/client.py +0 -0
  115. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/client.py +0 -0
  116. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/codex/__init__.py +0 -0
  117. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/codex/client.py +0 -0
  118. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/google/__init__.py +0 -0
  119. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/google/client.py +0 -0
  120. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/google/input.py +0 -0
  121. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/image.py +0 -0
  122. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/input_common.py +0 -0
  123. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
  124. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openai_compatible/client.py +0 -0
  125. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openai_compatible/input.py +0 -0
  126. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openai_compatible/stream.py +0 -0
  127. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -0
  128. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openrouter/__init__.py +0 -0
  129. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openrouter/client.py +0 -0
  130. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openrouter/input.py +0 -0
  131. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
  132. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/registry.py +0 -0
  133. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/responses/__init__.py +0 -0
  134. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/responses/client.py +0 -0
  135. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/responses/input.py +0 -0
  136. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/llm/usage.py +0 -0
  137. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/log.py +0 -0
  138. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/__init__.py +0 -0
  139. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/__init__.py +0 -0
  140. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/base.py +0 -0
  141. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/chat.py +0 -0
  142. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/lifecycle.py +0 -0
  143. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/metadata.py +0 -0
  144. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/streaming.py +0 -0
  145. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/events/system.py +0 -0
  146. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/llm_param.py +0 -0
  147. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/message.py +0 -0
  148. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/model.py +0 -0
  149. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/op.py +0 -0
  150. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/op_handler.py +0 -0
  151. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/sub_agent/__init__.py +0 -0
  152. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/sub_agent/explore.py +0 -0
  153. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/sub_agent/image_gen.py +0 -0
  154. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/sub_agent/task.py +0 -0
  155. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/protocol/sub_agent/web.py +0 -0
  156. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/__init__.py +0 -0
  157. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/codec.py +0 -0
  158. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/export.py +0 -0
  159. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/selector.py +0 -0
  160. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/store.py +0 -0
  161. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/templates/export_session.html +0 -0
  162. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/session/templates/mermaid_viewer.html +0 -0
  163. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/__init__.py +0 -0
  164. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/assets/create-plan/SKILL.md +0 -0
  165. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/assets/deslop/SKILL.md +0 -0
  166. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
  167. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/assets/jj-workspace/SKILL.md +0 -0
  168. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
  169. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/skill/system_skills.py +0 -0
  170. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/__init__.py +0 -0
  171. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/clear_cmd.py +0 -0
  172. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/command_abc.py +0 -0
  173. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/debug_cmd.py +0 -0
  174. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/export_cmd.py +0 -0
  175. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/export_online_cmd.py +0 -0
  176. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/fork_session_cmd.py +0 -0
  177. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/help_cmd.py +0 -0
  178. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/model_cmd.py +0 -0
  179. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/model_select.py +0 -0
  180. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/prompt-commit.md +0 -0
  181. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/prompt-init.md +0 -0
  182. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/prompt_command.py +0 -0
  183. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/refresh_cmd.py +0 -0
  184. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/registry.py +0 -0
  185. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/release_notes_cmd.py +0 -0
  186. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/resume_cmd.py +0 -0
  187. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/status_cmd.py +0 -0
  188. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/terminal_setup_cmd.py +0 -0
  189. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/command/thinking_cmd.py +0 -0
  190. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/commands.py +0 -0
  191. {klaude_code-2.1.0/src/klaude_code/core/tool/web → klaude_code-2.1.1/src/klaude_code/tui/components}/__init__.py +0 -0
  192. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/assistant.py +0 -0
  193. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/bash_syntax.py +0 -0
  194. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/common.py +0 -0
  195. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/developer.py +0 -0
  196. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/diffs.py +0 -0
  197. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/errors.py +0 -0
  198. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/mermaid_viewer.py +0 -0
  199. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/metadata.py +0 -0
  200. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/__init__.py +0 -0
  201. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/cjk_wrap.py +0 -0
  202. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/code_panel.py +0 -0
  203. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/live.py +0 -0
  204. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/markdown.py +0 -0
  205. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/quote.py +0 -0
  206. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/searchable_text.py +0 -0
  207. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/status.py +0 -0
  208. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/rich/theme.py +0 -0
  209. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/sub_agent.py +0 -0
  210. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/thinking.py +0 -0
  211. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/components/user_input.py +0 -0
  212. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/display.py +0 -0
  213. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/input/__init__.py +0 -0
  214. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/input/clipboard.py +0 -0
  215. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/input/completers.py +0 -0
  216. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/input/key_bindings.py +0 -0
  217. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/input/prompt_toolkit.py +0 -0
  218. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/runner.py +0 -0
  219. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/terminal/__init__.py +0 -0
  220. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/terminal/color.py +0 -0
  221. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/terminal/control.py +0 -0
  222. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/terminal/image.py +0 -0
  223. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/terminal/notifier.py +0 -0
  224. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/terminal/progress_bar.py +0 -0
  225. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/tui/terminal/selector.py +0 -0
  226. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/__init__.py +0 -0
  227. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/common.py +0 -0
  228. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/core/__init__.py +0 -0
  229. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/core/display.py +0 -0
  230. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/core/input.py +0 -0
  231. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/debug_mode.py +0 -0
  232. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/exec_mode.py +0 -0
  233. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/terminal/__init__.py +0 -0
  234. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/ui/terminal/title.py +0 -0
  235. {klaude_code-2.1.0 → klaude_code-2.1.1}/src/klaude_code/update.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: klaude-code
3
- Version: 2.1.0
3
+ Version: 2.1.1
4
4
  Summary: Minimal code agent CLI
5
5
  Requires-Dist: anthropic>=0.66.0
6
6
  Requires-Dist: chardet>=5.2.0
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "klaude-code"
7
- version = "2.1.0"
7
+ version = "2.1.1"
8
8
  description = "Minimal code agent CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -150,10 +150,17 @@ def load_system_prompt(
150
150
  base_prompt = _load_base_prompt(file_key)
151
151
 
152
152
  if protocol == llm_param.LLMClientProtocol.CODEX_OAUTH:
153
- # Do not append environment info for Codex protocol
153
+ # Do not append environment info or skills info for Codex protocol.
154
154
  return base_prompt
155
155
 
156
- return base_prompt + _build_env_info(model_name)
156
+ skills_prompt = ""
157
+ if sub_agent_type is None:
158
+ # Skills are progressive-disclosure: keep only metadata in the system prompt.
159
+ from klaude_code.skill.manager import format_available_skills_for_system_prompt
160
+
161
+ skills_prompt = format_available_skills_for_system_prompt()
162
+
163
+ return base_prompt + _build_env_info(model_name) + skills_prompt
157
164
 
158
165
 
159
166
  def load_agent_tools(
@@ -180,7 +187,7 @@ def load_agent_tools(
180
187
  tool_names = [tools.BASH, tools.READ, tools.EDIT, tools.WRITE, tools.TODO_WRITE]
181
188
 
182
189
  tool_names.extend(sub_agent_tool_names(enabled_only=True, model_name=model_name))
183
- tool_names.extend([tools.SKILL, tools.MERMAID])
190
+ tool_names.extend([tools.MERMAID])
184
191
  # tool_names.extend([tools.MEMORY])
185
192
  return get_tool_schemas(tool_names)
186
193
 
@@ -444,16 +444,32 @@ async def skill_reminder(session: Session) -> message.DeveloperMessage | None:
444
444
  if not skill:
445
445
  return None
446
446
 
447
- # Get base directory from skill_path
448
- base_dir = str(skill.skill_path.parent) if skill.skill_path else "unknown"
447
+ if not skill.skill_path.exists() or not skill.skill_path.is_file():
448
+ return None
449
+
450
+ tool_context = ToolContext(
451
+ file_tracker=session.file_tracker,
452
+ todo_context=build_todo_context(session),
453
+ session_id=session.id,
454
+ )
455
+ args = ReadTool.ReadArguments(file_path=str(skill.skill_path))
456
+ tool_result = await ReadTool.call_with_args(args, tool_context)
457
+
458
+ tool_args = args.model_dump_json(exclude_none=True)
459
+ skill_file_str = f"""Called the {tools.READ} tool with the following input: {tool_args}
460
+ Result of calling the {tools.READ} tool:
461
+ {tool_result.output_text}
462
+ """
449
463
 
450
- content = f"""<system-reminder>The user activated the "{skill.name}" skill. Here is the skill content:
464
+ base_dir = str(skill.base_dir)
465
+ content = f"""<system-reminder>The user activated the "{skill.name}" skill.
451
466
 
452
467
  <skill>
453
468
  <name>{skill.name}</name>
454
469
  <base_dir>{base_dir}</base_dir>
470
+ <location>{skill.skill_path}</location>
455
471
 
456
- {skill.to_prompt()}
472
+ {skill_file_str}
457
473
  </skill>
458
474
  </system-reminder>"""
459
475
 
@@ -7,7 +7,6 @@ from .file.write_tool import WriteTool
7
7
  from .report_back_tool import ReportBackTool
8
8
  from .shell.bash_tool import BashTool
9
9
  from .shell.command_safety import SafetyCheckResult, is_safe_command
10
- from .skill.skill_tool import SkillTool
11
10
  from .sub_agent_tool import SubAgentTool
12
11
  from .todo.todo_write_tool import TodoWriteTool
13
12
  from .todo.update_plan_tool import UpdatePlanTool
@@ -31,7 +30,6 @@ __all__ = [
31
30
  "RunSubtask",
32
31
  "SafetyCheckResult",
33
32
  "SimpleTruncationStrategy",
34
- "SkillTool",
35
33
  "SubAgentResumeClaims",
36
34
  "SubAgentTool",
37
35
  "TodoContext",
@@ -69,7 +69,6 @@ def build_events_from_tool_executor_event(session_id: str, event: ToolExecutorEv
69
69
  )
70
70
  )
71
71
  case ToolExecutionResult(tool_call=tool_call, tool_result=tool_result, is_last_in_turn=is_last_in_turn):
72
- status = "success" if tool_result.status == "success" else "error"
73
72
  ui_events.append(
74
73
  events.ToolResultEvent(
75
74
  session_id=session_id,
@@ -78,13 +77,11 @@ def build_events_from_tool_executor_event(session_id: str, event: ToolExecutorEv
78
77
  tool_name=tool_call.tool_name,
79
78
  result=tool_result.output_text,
80
79
  ui_extra=tool_result.ui_extra,
81
- status=status,
80
+ status=tool_result.status,
82
81
  task_metadata=tool_result.task_metadata,
83
82
  is_last_in_turn=is_last_in_turn,
84
83
  )
85
84
  )
86
- if tool_result.status == "aborted":
87
- ui_events.append(events.InterruptEvent(session_id=session_id))
88
85
  case ToolExecutionTodoChange(todos=todos):
89
86
  ui_events.append(
90
87
  events.TodoChangeEvent(
@@ -28,6 +28,7 @@ class CommandName(str, Enum):
28
28
  THINKING = "thinking"
29
29
  FORK_SESSION = "fork-session"
30
30
  RESUME = "resume"
31
+ COPY = "copy"
31
32
  # PLAN and DOC are dynamically registered now, but kept here if needed for reference
32
33
  # or we can remove them if no code explicitly imports them.
33
34
  # PLAN = "plan"
@@ -18,6 +18,10 @@ class ToolResultEvent(ResponseEvent):
18
18
  tool_name: str
19
19
  result: str
20
20
  ui_extra: model.ToolResultUIExtra | None = None
21
- status: Literal["success", "error"]
21
+ status: Literal["success", "error", "aborted"]
22
22
  task_metadata: model.TaskMetadata | None = None
23
23
  is_last_in_turn: bool = True
24
+
25
+ @property
26
+ def is_error(self) -> bool:
27
+ return self.status in ("error", "aborted")
@@ -6,7 +6,6 @@ READ = "Read"
6
6
  WRITE = "Write"
7
7
  TODO_WRITE = "TodoWrite"
8
8
  UPDATE_PLAN = "update_plan"
9
- SKILL = "Skill"
10
9
  MERMAID = "Mermaid"
11
10
  WEB_FETCH = "WebFetch"
12
11
  WEB_SEARCH = "WebSearch"
@@ -350,8 +350,6 @@ class Session(BaseModel):
350
350
  is_last_in_turn=is_last_in_turn,
351
351
  )
352
352
  yield from self._iter_sub_agent_history(tr, seen_sub_agent_sessions)
353
- if tr.status == "aborted":
354
- yield events.InterruptEvent(session_id=self.id)
355
353
  case message.UserMessage() as um:
356
354
  images = [part for part in um.parts if isinstance(part, message.ImageURLPart)]
357
355
  yield events.UserMessageEvent(
@@ -1,4 +1,3 @@
1
- import re
2
1
  from dataclasses import dataclass
3
2
  from pathlib import Path
4
3
  from typing import ClassVar
@@ -14,12 +13,12 @@ class Skill:
14
13
 
15
14
  name: str # Skill identifier (lowercase-hyphen)
16
15
  description: str # What the skill does and when to use it
17
- content: str # Full markdown instructions
18
- location: str # Skill location: 'system', 'user', or 'project'
16
+ location: str # Skill source: 'system', 'user', or 'project'
17
+ skill_path: Path
18
+ base_dir: Path
19
19
  license: str | None = None
20
20
  allowed_tools: list[str] | None = None
21
21
  metadata: dict[str, str] | None = None
22
- skill_path: Path | None = None
23
22
 
24
23
  @property
25
24
  def short_description(self) -> str:
@@ -31,17 +30,6 @@ class Skill:
31
30
  return self.metadata["short-description"]
32
31
  return self.description
33
32
 
34
- def to_prompt(self) -> str:
35
- """Convert skill to prompt format for agent consumption"""
36
- return f"""# Skill: {self.name}
37
-
38
- {self.description}
39
-
40
- ---
41
-
42
- {self.content}
43
- """
44
-
45
33
 
46
34
  class SkillLoader:
47
35
  """Load and manage Claude Skills from SKILL.md files"""
@@ -79,7 +67,6 @@ class SkillLoader:
79
67
 
80
68
  # Parse YAML frontmatter
81
69
  frontmatter: dict[str, object] = {}
82
- markdown_content = content
83
70
 
84
71
  if content.startswith("---"):
85
72
  parts = content.split("---", 2)
@@ -87,7 +74,6 @@ class SkillLoader:
87
74
  loaded: object = yaml.safe_load(parts[1])
88
75
  if isinstance(loaded, dict):
89
76
  frontmatter = dict(loaded) # type: ignore[arg-type]
90
- markdown_content = parts[2].strip()
91
77
 
92
78
  # Extract skill metadata
93
79
  name = str(frontmatter.get("name", ""))
@@ -96,10 +82,6 @@ class SkillLoader:
96
82
  if not name or not description:
97
83
  return None
98
84
 
99
- # Process relative paths in content
100
- skill_dir = skill_path.parent
101
- processed_content = self._process_skill_paths(markdown_content, skill_dir)
102
-
103
85
  # Create Skill object
104
86
  license_val = frontmatter.get("license")
105
87
  allowed_tools_val = frontmatter.get("allowed-tools")
@@ -118,12 +100,12 @@ class SkillLoader:
118
100
  skill = Skill(
119
101
  name=name,
120
102
  description=description,
121
- content=processed_content,
122
103
  location=location,
123
104
  license=str(license_val) if license_val is not None else None,
124
105
  allowed_tools=allowed_tools,
125
106
  metadata=metadata,
126
- skill_path=skill_path,
107
+ skill_path=skill_path.resolve(),
108
+ base_dir=skill_path.parent.resolve(),
127
109
  )
128
110
 
129
111
  return skill
@@ -144,6 +126,15 @@ class SkillLoader:
144
126
  List of successfully loaded Skill objects
145
127
  """
146
128
  skills: list[Skill] = []
129
+ priority = {"system": 0, "user": 1, "project": 2}
130
+
131
+ def register(skill: Skill) -> None:
132
+ existing = self.loaded_skills.get(skill.name)
133
+ if existing is None:
134
+ self.loaded_skills[skill.name] = skill
135
+ return
136
+ if priority.get(skill.location, -1) >= priority.get(existing.location, -1):
137
+ self.loaded_skills[skill.name] = skill
147
138
 
148
139
  # Load system-level skills first (lowest priority, can be overridden)
149
140
  system_dir = self.SYSTEM_SKILLS_DIR.expanduser()
@@ -152,7 +143,7 @@ class SkillLoader:
152
143
  skill = self.load_skill(skill_file, location="system")
153
144
  if skill:
154
145
  skills.append(skill)
155
- self.loaded_skills[skill.name] = skill
146
+ register(skill)
156
147
 
157
148
  # Load user-level skills (override system skills if same name)
158
149
  for user_dir in self.USER_SKILLS_DIRS:
@@ -165,7 +156,7 @@ class SkillLoader:
165
156
  skill = self.load_skill(skill_file, location="user")
166
157
  if skill:
167
158
  skills.append(skill)
168
- self.loaded_skills[skill.name] = skill
159
+ register(skill)
169
160
 
170
161
  # Load project-level skills (override user skills if same name)
171
162
  project_dir = self.PROJECT_SKILLS_DIR.resolve()
@@ -174,13 +165,14 @@ class SkillLoader:
174
165
  skill = self.load_skill(skill_file, location="project")
175
166
  if skill:
176
167
  skills.append(skill)
177
- self.loaded_skills[skill.name] = skill
168
+ register(skill)
178
169
 
179
170
  # Log discovery summary
180
- if skills:
181
- system_count = sum(1 for s in skills if s.location == "system")
182
- user_count = sum(1 for s in skills if s.location == "user")
183
- project_count = sum(1 for s in skills if s.location == "project")
171
+ if self.loaded_skills:
172
+ selected = list(self.loaded_skills.values())
173
+ system_count = sum(1 for s in selected if s.location == "system")
174
+ user_count = sum(1 for s in selected if s.location == "user")
175
+ project_count = sum(1 for s in selected if s.location == "project")
184
176
  parts: list[str] = []
185
177
  if system_count > 0:
186
178
  parts.append(f"{system_count} system")
@@ -188,7 +180,7 @@ class SkillLoader:
188
180
  parts.append(f"{user_count} user")
189
181
  if project_count > 0:
190
182
  parts.append(f"{project_count} project")
191
- log_debug(f"Discovered {len(skills)} Claude Skills ({', '.join(parts)})")
183
+ log_debug(f"Loaded {len(self.loaded_skills)} Claude Skills ({', '.join(parts)})")
192
184
 
193
185
  return skills
194
186
 
@@ -224,62 +216,14 @@ class SkillLoader:
224
216
  XML string with all skill metadata
225
217
  """
226
218
  xml_parts: list[str] = []
227
- for skill in self.loaded_skills.values():
228
- xml_parts.append(f"""<skill>
219
+ # Prefer showing higher-priority skills first (project > user > system).
220
+ location_order = {"project": 0, "user": 1, "system": 2}
221
+ for skill in sorted(self.loaded_skills.values(), key=lambda s: location_order.get(s.location, 3)):
222
+ xml_parts.append(
223
+ f"""<skill>
229
224
  <name>{skill.name}</name>
230
225
  <description>{skill.description}</description>
231
- <location>{skill.location}</location>
232
- </skill>""")
226
+ <location>{skill.skill_path}</location>
227
+ </skill>"""
228
+ )
233
229
  return "\n".join(xml_parts)
234
-
235
- def _process_skill_paths(self, content: str, skill_dir: Path) -> str:
236
- """Convert relative paths to absolute paths for Level 3+
237
-
238
- Supports:
239
- - scripts/, examples/, templates/, reference/ directories
240
- - Markdown document references
241
- - Markdown links [text](path)
242
-
243
- Args:
244
- content: Original skill content
245
- skill_dir: Directory containing the SKILL.md file
246
-
247
- Returns:
248
- Content with absolute paths
249
- """
250
- # Pattern 1: Directory-based paths (scripts/, examples/, etc.)
251
- # e.g., "python scripts/generate.py" -> "python /abs/path/to/scripts/generate.py"
252
- dir_pattern = r"\b(scripts|examples|templates|reference)/([^\s\)]+)"
253
-
254
- def replace_dir_path(match: re.Match[str]) -> str:
255
- directory = match.group(1)
256
- filename = match.group(2)
257
- abs_path = skill_dir / directory / filename
258
- return str(abs_path)
259
-
260
- content = re.sub(dir_pattern, replace_dir_path, content)
261
-
262
- # Pattern 2: Markdown links [text](./path or path)
263
- # e.g., "[Guide](./docs/guide.md)" -> "[Guide](`/abs/path/to/docs/guide.md`) (use the Read tool to access)"
264
- link_pattern = r"\[([^\]]+)\]\((\./)?([^\)]+\.md)\)"
265
-
266
- def replace_link(match: re.Match[str]) -> str:
267
- text = match.group(1)
268
- filename = match.group(3)
269
- abs_path = skill_dir / filename
270
- return f"[{text}](`{abs_path}`) (use the Read tool to access)"
271
-
272
- content = re.sub(link_pattern, replace_link, content)
273
-
274
- # Pattern 3: Standalone markdown references
275
- # e.g., "see reference.md" -> "see `/abs/path/to/reference.md` (use the Read tool to access)"
276
- standalone_pattern = r"(?<!\])\b(\w+\.md)\b(?!\))"
277
-
278
- def replace_standalone(match: re.Match[str]) -> str:
279
- filename = match.group(1)
280
- abs_path = skill_dir / filename
281
- return f"`{abs_path}` (use the Read tool to access)"
282
-
283
- content = re.sub(standalone_pattern, replace_standalone, content)
284
-
285
- return content
@@ -68,3 +68,41 @@ def list_skill_names() -> list[str]:
68
68
  List of skill names
69
69
  """
70
70
  return _ensure_initialized().list_skills()
71
+
72
+
73
+ def format_available_skills_for_system_prompt() -> str:
74
+ """Format skills metadata for inclusion in the system prompt.
75
+
76
+ This follows the progressive-disclosure approach:
77
+ - Keep only name/description + file location in the always-on system prompt
78
+ - Load the full SKILL.md content on demand via the Read tool when needed
79
+ """
80
+
81
+ try:
82
+ loader = _ensure_initialized()
83
+ skills_xml = loader.get_skills_xml().strip()
84
+ if not skills_xml:
85
+ return ""
86
+
87
+ return f"""\
88
+ # Skills
89
+
90
+ Skills are optional task-specific instructions stored as `SKILL.md` files.
91
+
92
+ How to use skills:
93
+ - Use the metadata in <available_skills> to decide whether a skill applies.
94
+ - When the task matches a skill's description, use the `Read` tool to load the `SKILL.md` at the given <location>.
95
+ - If the user explicitly activates a skill by starting their message with `$skill-name`, prioritize that skill.
96
+
97
+ Important:
98
+ - Only use skills listed in <available_skills> below.
99
+ - Keep context small: do NOT load skill files unless needed.
100
+
101
+ The list below is metadata only (name/description/location). The full instructions live in the referenced file.
102
+
103
+ <available_skills>
104
+ {skills_xml}
105
+ </available_skills>"""
106
+ except Exception:
107
+ # Skills are an optional enhancement; do not fail prompt construction if discovery breaks.
108
+ return ""
@@ -30,6 +30,7 @@ def ensure_commands_loaded() -> None:
30
30
 
31
31
  # Import and register commands in display order
32
32
  from .clear_cmd import ClearCommand
33
+ from .copy_cmd import CopyCommand
33
34
  from .debug_cmd import DebugCommand
34
35
  from .export_cmd import ExportCommand
35
36
  from .export_online_cmd import ExportOnlineCommand
@@ -49,6 +50,7 @@ def ensure_commands_loaded() -> None:
49
50
  register(RefreshTerminalCommand())
50
51
  register(ThinkingCommand())
51
52
  register(ModelCommand())
53
+ register(CopyCommand())
52
54
  register(ForkSessionCommand())
53
55
  register(ResumeCommand())
54
56
  load_prompt_commands()
@@ -66,6 +68,7 @@ def ensure_commands_loaded() -> None:
66
68
  def __getattr__(name: str) -> object:
67
69
  _commands_map = {
68
70
  "ClearCommand": "clear_cmd",
71
+ "CopyCommand": "copy_cmd",
69
72
  "DebugCommand": "debug_cmd",
70
73
  "ExportCommand": "export_cmd",
71
74
  "ExportOnlineCommand": "export_online_cmd",
@@ -0,0 +1,53 @@
1
+ from klaude_code.protocol import commands, events, message, model
2
+ from klaude_code.tui.input.clipboard import copy_to_clipboard
3
+
4
+ from .command_abc import Agent, CommandABC, CommandResult
5
+
6
+
7
+ class CopyCommand(CommandABC):
8
+ """Copy the last assistant message to system clipboard."""
9
+
10
+ @property
11
+ def name(self) -> commands.CommandName:
12
+ return commands.CommandName.COPY
13
+
14
+ @property
15
+ def summary(self) -> str:
16
+ return "Copy last assistant message to clipboard"
17
+
18
+ async def run(self, agent: Agent, user_input: message.UserInputPayload) -> CommandResult:
19
+ del user_input # unused
20
+
21
+ last = _get_last_assistant_text(agent.session.conversation_history)
22
+ if not last:
23
+ return _developer_message(agent, "(no assistant message to copy)", self.name)
24
+
25
+ copy_to_clipboard(last)
26
+ return _developer_message(agent, "Copied last assistant message to clipboard.", self.name)
27
+
28
+
29
+ def _get_last_assistant_text(history: list[message.HistoryEvent]) -> str:
30
+ for item in reversed(history):
31
+ if not isinstance(item, message.AssistantMessage):
32
+ continue
33
+ content = message.join_text_parts(item.parts)
34
+ images = [part for part in item.parts if isinstance(part, message.ImageFilePart)]
35
+ formatted = message.format_saved_images(images, content)
36
+ return formatted.strip()
37
+ return ""
38
+
39
+
40
+ def _developer_message(agent: Agent, content: str, command_name: commands.CommandName) -> CommandResult:
41
+ return CommandResult(
42
+ events=[
43
+ events.DeveloperMessageEvent(
44
+ session_id=agent.session.id,
45
+ item=message.DeveloperMessage(
46
+ parts=message.text_parts_from_str(content),
47
+ ui_extra=model.build_command_output_extra(command_name),
48
+ ),
49
+ )
50
+ ],
51
+ persist_user_input=False,
52
+ persist_events=False,
53
+ )
@@ -37,7 +37,6 @@ MARK_MERMAID = "⧉"
37
37
  MARK_WEB_FETCH = "→"
38
38
  MARK_WEB_SEARCH = "✱"
39
39
  MARK_DONE = "✔"
40
- MARK_SKILL = "✪"
41
40
 
42
41
  # Todo status markers
43
42
  MARK_TODO_PENDING = "▢"
@@ -491,7 +490,7 @@ def render_mermaid_tool_result(
491
490
 
492
491
  link_info = _extract_mermaid_link(tr.ui_extra)
493
492
  if link_info is None:
494
- return render_generic_tool_result(tr.result, is_error=tr.status == "error")
493
+ return render_generic_tool_result(tr.result, is_error=tr.is_error)
495
494
 
496
495
  use_osc8 = supports_osc8_hyperlinks()
497
496
  viewer = _render_mermaid_viewer_link(tr, link_info, use_osc8=use_osc8)
@@ -537,7 +536,6 @@ _TOOL_ACTIVE_FORM: dict[str, str] = {
537
536
  tools.WRITE: "Writing",
538
537
  tools.TODO_WRITE: "Planning",
539
538
  tools.UPDATE_PLAN: "Planning",
540
- tools.SKILL: "Skilling",
541
539
  tools.MERMAID: "Diagramming",
542
540
  tools.WEB_FETCH: "Fetching Web",
543
541
  tools.WEB_SEARCH: "Searching Web",
@@ -589,8 +587,6 @@ def render_tool_call(e: events.ToolCallEvent) -> RenderableType | None:
589
587
  return render_update_plan_tool_call(e.arguments)
590
588
  case tools.MERMAID:
591
589
  return render_mermaid_tool_call(e.arguments)
592
- case tools.SKILL:
593
- return render_generic_tool_call(e.tool_name, e.arguments, MARK_SKILL)
594
590
  case tools.REPORT_BACK:
595
591
  return render_report_back_tool_call()
596
592
  case tools.WEB_FETCH:
@@ -649,7 +645,7 @@ def render_tool_result(
649
645
  return TreeQuote.for_tool_result(content, is_last=e.is_last_in_turn)
650
646
 
651
647
  # Handle error case
652
- if e.status == "error" and e.ui_extra is None:
648
+ if e.is_error and e.ui_extra is None:
653
649
  return wrap(render_generic_tool_result(e.result, is_error=True))
654
650
 
655
651
  # Render multiple ui blocks if present
@@ -666,7 +662,7 @@ def render_tool_result(
666
662
  # Show truncation info if output was truncated and saved to file
667
663
  truncation_info = get_truncation_info(e)
668
664
  if truncation_info:
669
- result = render_generic_tool_result(e.result, is_error=e.status == "error")
665
+ result = render_generic_tool_result(e.result, is_error=e.is_error)
670
666
  return wrap(Group(render_truncation_info(truncation_info), result))
671
667
 
672
668
  diff_ui = _extract_diff(e.ui_extra)
@@ -675,7 +671,7 @@ def render_tool_result(
675
671
  def _render_fallback() -> TreeQuote:
676
672
  if len(e.result.strip()) == 0:
677
673
  return wrap(render_generic_tool_result("(no content)"))
678
- return wrap(render_generic_tool_result(e.result, is_error=e.status == "error"))
674
+ return wrap(render_generic_tool_result(e.result, is_error=e.is_error))
679
675
 
680
676
  match e.tool_name:
681
677
  case tools.READ:
@@ -521,13 +521,15 @@ class DisplayStateMachine:
521
521
  self._spinner.finish_sub_agent_tool_call(e.tool_call_id, get_tool_active_form(e.tool_name))
522
522
  cmds.extend(self._spinner_update_commands())
523
523
 
524
- if s.is_sub_agent and e.status == "success":
524
+ if s.is_sub_agent and not e.is_error:
525
525
  return cmds
526
526
 
527
527
  cmds.append(RenderToolResult(event=e, is_sub_agent_session=s.is_sub_agent))
528
528
  return cmds
529
529
 
530
530
  case events.TaskMetadataEvent() as e:
531
+ cmds.append(EndThinkingStream(e.session_id))
532
+ cmds.append(EndAssistantStream(e.session_id))
531
533
  cmds.append(RenderTaskMetadata(e))
532
534
  return cmds
533
535
 
@@ -396,7 +396,7 @@ class TUICommandRenderer:
396
396
  if c_tools.is_sub_agent_tool(e.tool_name):
397
397
  return
398
398
 
399
- if is_sub_agent and e.status == "error":
399
+ if is_sub_agent and e.is_error:
400
400
  error_msg = truncate_head(e.result)
401
401
  self.print(c_errors.render_tool_error(error_msg))
402
402
  return
@@ -1,24 +0,0 @@
1
- Execute a skill within the main conversation
2
-
3
- <skills_instructions>
4
- When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
5
-
6
- How to use skills:
7
- - Invoke skills using this tool with the skill name only (no arguments)
8
- - When you invoke a skill, you will see <command-message>The "{name}" skill is loading</command-message>
9
- - The skill's prompt will expand and provide detailed instructions on how to complete the task
10
-
11
- Examples:
12
- - command: "pdf" - invoke the pdf skill
13
- - command: "xlsx" - invoke the xlsx skill
14
- - command: "document-skills:pdf" - invoke using fully qualified name
15
-
16
- Important:
17
- - Only use skills listed in <available_skills> below
18
- - Do not invoke a skill that is already running
19
- - Do not use this tool for built-in CLI commands (like /help, /clear, etc.)
20
- </skills_instructions>
21
-
22
- <available_skills>
23
- $skills_xml
24
- </available_skills>