klaude-code 2.8.0__tar.gz → 2.10.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.8.0 → klaude_code-2.10.1}/PKG-INFO +3 -6
- {klaude_code-2.8.0 → klaude_code-2.10.1}/README.md +1 -5
- {klaude_code-2.8.0 → klaude_code-2.10.1}/pyproject.toml +2 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/app/runtime.py +7 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/antigravity/oauth.py +33 -38
- klaude_code-2.10.1/src/klaude_code/auth/antigravity/token_manager.py +27 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/base.py +53 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/claude/oauth.py +34 -49
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/codex/exceptions.py +0 -4
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/codex/oauth.py +32 -28
- klaude_code-2.10.1/src/klaude_code/auth/codex/token_manager.py +26 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/cost_cmd.py +128 -39
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/list_model.py +28 -12
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/main.py +25 -4
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/assets/builtin_config.yaml +39 -37
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/config.py +47 -25
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/sub_agent_model_helper.py +18 -13
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/thinking.py +0 -8
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/const.py +6 -5
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/agent_profile.py +35 -57
- klaude_code-2.10.1/src/klaude_code/core/bash_mode.py +276 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/compaction/compaction.py +4 -6
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/compaction/overflow.py +0 -4
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/executor.py +91 -12
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/manager/llm_clients.py +10 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/manager/llm_clients_builder.py +2 -2
- klaude_code-2.10.1/src/klaude_code/core/memory.py +140 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-claude-code.md +4 -4
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-sub-agent-web.md +2 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/reminders.py +38 -112
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/task.py +1 -5
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/__init__.py +3 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/apply_patch.py +0 -27
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/edit_tool.py +1 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/read_tool.md +3 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/read_tool.py +27 -3
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/offload.py +4 -39
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/shell/bash_tool.py +1 -1
- klaude_code-2.10.1/src/klaude_code/core/tool/sub_agent/__init__.py +6 -0
- klaude_code-2.10.1/src/klaude_code/core/tool/sub_agent/image_gen.md +16 -0
- klaude_code-2.10.1/src/klaude_code/core/tool/sub_agent/image_gen.py +146 -0
- klaude_code-2.10.1/src/klaude_code/core/tool/sub_agent/task.md +20 -0
- klaude_code-2.10.1/src/klaude_code/core/tool/sub_agent/task.py +205 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/tool_registry.py +0 -16
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/web/web_fetch_tool.md +2 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/web/web_fetch_tool.py +1 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/turn.py +10 -5
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/anthropic/input.py +6 -5
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/antigravity/input.py +14 -7
- klaude_code-2.10.1/src/klaude_code/llm/bedrock_anthropic/__init__.py +3 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/google/client.py +8 -6
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/google/input.py +20 -12
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/image.py +18 -11
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/input_common.py +32 -6
- klaude_code-2.10.1/src/klaude_code/llm/json_stable.py +37 -0
- {klaude_code-2.8.0/src/klaude_code/llm/codex → klaude_code-2.10.1/src/klaude_code/llm/openai_codex}/__init__.py +1 -1
- {klaude_code-2.8.0/src/klaude_code/llm/codex → klaude_code-2.10.1/src/klaude_code/llm/openai_codex}/client.py +24 -2
- klaude_code-2.10.1/src/klaude_code/llm/openai_codex/prompt_sync.py +237 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openai_compatible/client.py +3 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openai_compatible/input.py +0 -10
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openai_compatible/stream.py +35 -10
- {klaude_code-2.8.0/src/klaude_code/llm/responses → klaude_code-2.10.1/src/klaude_code/llm/openai_responses}/client.py +1 -1
- {klaude_code-2.8.0/src/klaude_code/llm/responses → klaude_code-2.10.1/src/klaude_code/llm/openai_responses}/input.py +15 -5
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/registry.py +3 -8
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/stream_parts.py +3 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/usage.py +1 -9
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/commands.py +1 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/events.py +19 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/message.py +3 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/model.py +34 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/op.py +39 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/op_handler.py +15 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/sub_agent/AGENTS.md +5 -5
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/sub_agent/__init__.py +13 -34
- klaude_code-2.10.1/src/klaude_code/protocol/sub_agent/explore.py +21 -0
- klaude_code-2.10.1/src/klaude_code/protocol/sub_agent/image_gen.py +38 -0
- klaude_code-2.10.1/src/klaude_code/protocol/sub_agent/task.py +17 -0
- klaude_code-2.10.1/src/klaude_code/protocol/sub_agent/web.py +21 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/tools.py +2 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/export.py +308 -299
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/session.py +80 -22
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/store.py +0 -4
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/templates/export_session.html +430 -134
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/templates/mermaid_viewer.html +85 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/assets/deslop/SKILL.md +9 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/system_skills.py +0 -20
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/__init__.py +3 -0
- klaude_code-2.10.1/src/klaude_code/tui/command/continue_cmd.py +34 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/fork_session_cmd.py +5 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/resume_cmd.py +10 -3
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/sub_agent_model_cmd.py +85 -18
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/commands.py +15 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/bash_syntax.py +4 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/command_output.py +7 -6
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/developer.py +4 -3
- klaude_code-2.10.1/src/klaude_code/tui/components/diffs.py +91 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/errors.py +4 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/mermaid_viewer.py +2 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/metadata.py +28 -28
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/code_panel.py +31 -16
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/markdown.py +104 -88
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/status.py +2 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/theme.py +33 -18
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/sub_agent.py +2 -46
- klaude_code-2.10.1/src/klaude_code/tui/components/thinking.py +28 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/tools.py +69 -23
- klaude_code-2.10.1/src/klaude_code/tui/components/user_input.py +99 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/welcome.py +47 -2
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/display.py +14 -6
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/completers.py +8 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/images.py +21 -18
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/key_bindings.py +39 -3
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/prompt_toolkit.py +95 -69
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/machine.py +136 -74
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/renderer.py +164 -50
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/runner.py +24 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/terminal/image.py +27 -34
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/terminal/notifier.py +11 -12
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/terminal/selector.py +1 -1
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/common.py +0 -70
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/terminal/title.py +4 -2
- klaude_code-2.8.0/src/klaude_code/auth/antigravity/token_manager.py +0 -45
- klaude_code-2.8.0/src/klaude_code/auth/codex/token_manager.py +0 -44
- klaude_code-2.8.0/src/klaude_code/core/tool/sub_agent_tool.py +0 -126
- klaude_code-2.8.0/src/klaude_code/llm/bedrock/__init__.py +0 -3
- klaude_code-2.8.0/src/klaude_code/llm/openai_compatible/tool_call_accumulator.py +0 -108
- klaude_code-2.8.0/src/klaude_code/protocol/sub_agent/explore.py +0 -48
- klaude_code-2.8.0/src/klaude_code/protocol/sub_agent/image_gen.py +0 -109
- klaude_code-2.8.0/src/klaude_code/protocol/sub_agent/task.py +0 -61
- klaude_code-2.8.0/src/klaude_code/protocol/sub_agent/web.py +0 -65
- klaude_code-2.8.0/src/klaude_code/tui/components/assistant.py +0 -28
- klaude_code-2.8.0/src/klaude_code/tui/components/diffs.py +0 -296
- klaude_code-2.8.0/src/klaude_code/tui/components/rich/searchable_text.py +0 -68
- klaude_code-2.8.0/src/klaude_code/tui/components/thinking.py +0 -96
- klaude_code-2.8.0/src/klaude_code/tui/components/user_input.py +0 -107
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/.DS_Store +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/app/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/AGENTS.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/antigravity/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/antigravity/exceptions.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/antigravity/pkce.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/claude/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/claude/exceptions.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/claude/token_manager.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/codex/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/codex/jwt_utils.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/auth/env.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/auth_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/config_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/debug.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/cli/self_update.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/assets/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/builtin_config.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/config/model_matcher.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/agent.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/compaction/AGENTS.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/compaction/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/compaction/prompts.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/loaded_skills.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/manager/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/manager/sub_agent_manager.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-antigravity.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2-codex.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-codex-gpt-5-2.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-codex.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-gemini.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-minimal.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-sub-agent-explore.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-sub-agent-image-gen.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/prompts/prompt-sub-agent.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/context.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/_utils.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/apply_patch_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/apply_patch_tool.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/diff_builder.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/edit_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/write_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/file/write_tool.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/report_back_tool.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/shell/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/shell/bash_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/shell/command_safety.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/todo/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/todo/todo_write_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/todo/todo_write_tool.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/todo/todo_write_tool_raw.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/todo/update_plan_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/todo/update_plan_tool.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/tool_abc.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/tool_runner.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/web/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/web/mermaid_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/web/mermaid_tool.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/web/web_search_tool.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/core/tool/web/web_search_tool.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/anthropic/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/anthropic/client.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/antigravity/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/antigravity/client.py +0 -0
- {klaude_code-2.8.0/src/klaude_code/llm/bedrock → klaude_code-2.10.1/src/klaude_code/llm/bedrock_anthropic}/client.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/claude/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/claude/client.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/client.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/google/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openai_compatible/__init__.py +0 -0
- {klaude_code-2.8.0/src/klaude_code/llm/responses → klaude_code-2.10.1/src/klaude_code/llm/openai_responses}/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openrouter/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openrouter/client.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openrouter/input.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/openrouter/reasoning.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/llm/partial_message.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/log.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/protocol/llm_param.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/codec.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/session/selector.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/.DS_Store +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/assets/.DS_Store +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/assets/create-plan/SKILL.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/assets/handoff/SKILL.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/assets/skill-creator/SKILL.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/loader.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/skill/manager.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/clear_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/command_abc.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/compact_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/copy_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/debug_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/export_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/export_online_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/model_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/model_picker.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/prompt-init.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/prompt_command.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/refresh_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/registry.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/status_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/command/thinking_cmd.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/common.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/cjk_wrap.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/live.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/components/rich/quote.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/AGENTS.md +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/drag_drop.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/input/paste.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/terminal/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/terminal/color.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/terminal/control.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/tui/terminal/progress_bar.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/core/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/core/display.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/core/input.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/debug_mode.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/ui/terminal/__init__.py +0 -0
- {klaude_code-2.8.0 → klaude_code-2.10.1}/src/klaude_code/update.py +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: klaude-code
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.10.1
|
|
4
4
|
Summary: Minimal code agent CLI
|
|
5
5
|
Requires-Dist: anthropic>=0.66.0
|
|
6
6
|
Requires-Dist: chardet>=5.2.0
|
|
7
7
|
Requires-Dist: ddgs>=9.9.3
|
|
8
8
|
Requires-Dist: diff-match-patch>=20241021
|
|
9
|
+
Requires-Dist: filelock>=3.20.3
|
|
9
10
|
Requires-Dist: google-genai>=1.56.0
|
|
10
11
|
Requires-Dist: markdown-it-py>=4.0.0
|
|
11
12
|
Requires-Dist: openai>=1.102.0
|
|
@@ -23,7 +24,7 @@ Description-Content-Type: text/markdown
|
|
|
23
24
|
Minimal code agent CLI.
|
|
24
25
|
|
|
25
26
|
## Features
|
|
26
|
-
- **Multi-provider**: Anthropic Message API, OpenAI Responses API, OpenRouter,
|
|
27
|
+
- **Multi-provider**: Anthropic Message API, OpenAI Responses API, OpenRouter, ChatGPT Codex OAuth etc.
|
|
27
28
|
- **Keep reasoning item in context**: Interleaved thinking support
|
|
28
29
|
- **Model-aware tools**: Claude Code tool set for Opus, `apply_patch` for GPT-5/Codex
|
|
29
30
|
- **Reminders**: Cooldown-based todo tracking, instruction reinforcement and external file change reminder
|
|
@@ -107,7 +108,6 @@ On first run, you'll be prompted to select a model. Your choice is saved as `mai
|
|
|
107
108
|
| Provider | Env Variable | Models |
|
|
108
109
|
|-------------|-----------------------|-------------------------------------------------------------------------------|
|
|
109
110
|
| anthropic | `ANTHROPIC_API_KEY` | sonnet, opus |
|
|
110
|
-
| claude | N/A (OAuth) | sonnet@claude, opus@claude (requires Claude Pro/Max subscription) |
|
|
111
111
|
| openai | `OPENAI_API_KEY` | gpt-5.2 |
|
|
112
112
|
| openrouter | `OPENROUTER_API_KEY` | gpt-5.2, gpt-5.2-fast, gpt-5.1-codex-max, sonnet, opus, haiku, kimi, gemini-* |
|
|
113
113
|
| deepseek | `DEEPSEEK_API_KEY` | deepseek |
|
|
@@ -139,7 +139,6 @@ klaude auth login deepseek # Set DEEPSEEK_API_KEY
|
|
|
139
139
|
klaude auth login moonshot # Set MOONSHOT_API_KEY
|
|
140
140
|
|
|
141
141
|
# OAuth login for subscription-based providers
|
|
142
|
-
klaude auth login claude # Claude Pro/Max subscription
|
|
143
142
|
klaude auth login codex # ChatGPT Pro subscription
|
|
144
143
|
```
|
|
145
144
|
|
|
@@ -148,7 +147,6 @@ API keys are stored in `~/.klaude/klaude-auth.json` and used as fallback when en
|
|
|
148
147
|
To logout from OAuth providers:
|
|
149
148
|
|
|
150
149
|
```bash
|
|
151
|
-
klaude auth logout claude
|
|
152
150
|
klaude auth logout codex
|
|
153
151
|
```
|
|
154
152
|
|
|
@@ -201,7 +199,6 @@ provider_list:
|
|
|
201
199
|
##### Supported Protocols
|
|
202
200
|
|
|
203
201
|
- `anthropic` - Anthropic Messages API
|
|
204
|
-
- `claude_oauth` - Claude OAuth (for Claude Pro/Max subscribers)
|
|
205
202
|
- `openai` - OpenAI Chat Completion API
|
|
206
203
|
- `responses` - OpenAI Responses API (for o-series, GPT-5, Codex)
|
|
207
204
|
- `codex_oauth` - OpenAI Codex CLI (OAuth-based, for ChatGPT Pro subscribers)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Minimal code agent CLI.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
|
-
- **Multi-provider**: Anthropic Message API, OpenAI Responses API, OpenRouter,
|
|
6
|
+
- **Multi-provider**: Anthropic Message API, OpenAI Responses API, OpenRouter, ChatGPT Codex OAuth etc.
|
|
7
7
|
- **Keep reasoning item in context**: Interleaved thinking support
|
|
8
8
|
- **Model-aware tools**: Claude Code tool set for Opus, `apply_patch` for GPT-5/Codex
|
|
9
9
|
- **Reminders**: Cooldown-based todo tracking, instruction reinforcement and external file change reminder
|
|
@@ -87,7 +87,6 @@ On first run, you'll be prompted to select a model. Your choice is saved as `mai
|
|
|
87
87
|
| Provider | Env Variable | Models |
|
|
88
88
|
|-------------|-----------------------|-------------------------------------------------------------------------------|
|
|
89
89
|
| anthropic | `ANTHROPIC_API_KEY` | sonnet, opus |
|
|
90
|
-
| claude | N/A (OAuth) | sonnet@claude, opus@claude (requires Claude Pro/Max subscription) |
|
|
91
90
|
| openai | `OPENAI_API_KEY` | gpt-5.2 |
|
|
92
91
|
| openrouter | `OPENROUTER_API_KEY` | gpt-5.2, gpt-5.2-fast, gpt-5.1-codex-max, sonnet, opus, haiku, kimi, gemini-* |
|
|
93
92
|
| deepseek | `DEEPSEEK_API_KEY` | deepseek |
|
|
@@ -119,7 +118,6 @@ klaude auth login deepseek # Set DEEPSEEK_API_KEY
|
|
|
119
118
|
klaude auth login moonshot # Set MOONSHOT_API_KEY
|
|
120
119
|
|
|
121
120
|
# OAuth login for subscription-based providers
|
|
122
|
-
klaude auth login claude # Claude Pro/Max subscription
|
|
123
121
|
klaude auth login codex # ChatGPT Pro subscription
|
|
124
122
|
```
|
|
125
123
|
|
|
@@ -128,7 +126,6 @@ API keys are stored in `~/.klaude/klaude-auth.json` and used as fallback when en
|
|
|
128
126
|
To logout from OAuth providers:
|
|
129
127
|
|
|
130
128
|
```bash
|
|
131
|
-
klaude auth logout claude
|
|
132
129
|
klaude auth logout codex
|
|
133
130
|
```
|
|
134
131
|
|
|
@@ -181,7 +178,6 @@ provider_list:
|
|
|
181
178
|
##### Supported Protocols
|
|
182
179
|
|
|
183
180
|
- `anthropic` - Anthropic Messages API
|
|
184
|
-
- `claude_oauth` - Claude OAuth (for Claude Pro/Max subscribers)
|
|
185
181
|
- `openai` - OpenAI Chat Completion API
|
|
186
182
|
- `responses` - OpenAI Responses API (for o-series, GPT-5, Codex)
|
|
187
183
|
- `codex_oauth` - OpenAI Codex CLI (OAuth-based, for ChatGPT Pro subscribers)
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "klaude-code"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.10.1"
|
|
8
8
|
description = "Minimal code agent CLI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13"
|
|
@@ -13,6 +13,7 @@ dependencies = [
|
|
|
13
13
|
"chardet>=5.2.0",
|
|
14
14
|
"ddgs>=9.9.3",
|
|
15
15
|
"diff-match-patch>=20241021",
|
|
16
|
+
"filelock>=3.20.3",
|
|
16
17
|
"google-genai>=1.56.0",
|
|
17
18
|
"markdown-it-py>=4.0.0",
|
|
18
19
|
"openai>=1.102.0",
|
|
@@ -12,6 +12,7 @@ from klaude_code.core.agent import Agent
|
|
|
12
12
|
from klaude_code.core.agent_profile import (
|
|
13
13
|
DefaultModelProfileProvider,
|
|
14
14
|
VanillaModelProfileProvider,
|
|
15
|
+
WebModelProfileProvider,
|
|
15
16
|
)
|
|
16
17
|
from klaude_code.core.executor import Executor
|
|
17
18
|
from klaude_code.core.manager import build_llm_clients
|
|
@@ -27,6 +28,7 @@ class AppInitConfig:
|
|
|
27
28
|
model: str | None
|
|
28
29
|
debug: bool
|
|
29
30
|
vanilla: bool
|
|
31
|
+
web: bool = False
|
|
30
32
|
debug_filters: set[DebugType] | None = None
|
|
31
33
|
|
|
32
34
|
|
|
@@ -74,6 +76,8 @@ async def initialize_app_components(
|
|
|
74
76
|
|
|
75
77
|
if init_config.vanilla:
|
|
76
78
|
model_profile_provider = VanillaModelProfileProvider()
|
|
79
|
+
elif init_config.web:
|
|
80
|
+
model_profile_provider = WebModelProfileProvider(config=config)
|
|
77
81
|
else:
|
|
78
82
|
model_profile_provider = DefaultModelProfileProvider(config=config)
|
|
79
83
|
|
|
@@ -87,7 +91,7 @@ async def initialize_app_components(
|
|
|
87
91
|
)
|
|
88
92
|
|
|
89
93
|
if on_model_change is not None:
|
|
90
|
-
on_model_change(llm_clients.
|
|
94
|
+
on_model_change(llm_clients.main_model_alias)
|
|
91
95
|
|
|
92
96
|
executor_task = asyncio.create_task(executor.start())
|
|
93
97
|
|
|
@@ -178,6 +182,7 @@ async def handle_keyboard_interrupt(executor: Executor) -> None:
|
|
|
178
182
|
log("Bye!")
|
|
179
183
|
session_id = executor.context.current_session_id()
|
|
180
184
|
if session_id and Session.exists(session_id):
|
|
181
|
-
|
|
185
|
+
short_id = Session.shortest_unique_prefix(session_id)
|
|
186
|
+
log(("Resume with:", "dim"), (f"klaude -r {short_id}", "green"))
|
|
182
187
|
with contextlib.suppress(Exception):
|
|
183
188
|
await executor.submit(op.InterruptOperation(target_session_id=None))
|
|
@@ -258,42 +258,46 @@ class AntigravityOAuth:
|
|
|
258
258
|
)
|
|
259
259
|
|
|
260
260
|
def refresh(self) -> AntigravityAuthState:
|
|
261
|
-
"""Refresh the access token using refresh token.
|
|
262
|
-
state = self.token_manager.get_state()
|
|
263
|
-
if state is None:
|
|
264
|
-
raise AntigravityNotLoggedInError("Not logged in to Antigravity. Run 'klaude login antigravity' first.")
|
|
261
|
+
"""Refresh the access token using refresh token with file locking.
|
|
265
262
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
"refresh_token": state.refresh_token,
|
|
270
|
-
"grant_type": "refresh_token",
|
|
271
|
-
}
|
|
263
|
+
Uses file locking to prevent multiple instances from refreshing simultaneously.
|
|
264
|
+
If another instance has already refreshed, returns the updated state.
|
|
265
|
+
"""
|
|
272
266
|
|
|
273
|
-
|
|
274
|
-
|
|
267
|
+
def do_refresh(current_state: AntigravityAuthState) -> AntigravityAuthState:
|
|
268
|
+
data = {
|
|
269
|
+
"client_id": CLIENT_ID,
|
|
270
|
+
"client_secret": CLIENT_SECRET,
|
|
271
|
+
"refresh_token": current_state.refresh_token,
|
|
272
|
+
"grant_type": "refresh_token",
|
|
273
|
+
}
|
|
275
274
|
|
|
276
|
-
|
|
277
|
-
|
|
275
|
+
with httpx.Client() as client:
|
|
276
|
+
response = client.post(TOKEN_URL, data=data, timeout=30)
|
|
278
277
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
refresh_token = tokens.get("refresh_token", state.refresh_token)
|
|
282
|
-
expires_in = tokens.get("expires_in", 3600)
|
|
278
|
+
if response.status_code != 200:
|
|
279
|
+
raise AntigravityTokenExpiredError(f"Token refresh failed: {response.text}")
|
|
283
280
|
|
|
284
|
-
|
|
285
|
-
|
|
281
|
+
tokens = response.json()
|
|
282
|
+
access_token = tokens["access_token"]
|
|
283
|
+
refresh_token = tokens.get("refresh_token", current_state.refresh_token)
|
|
284
|
+
expires_in = tokens.get("expires_in", 3600)
|
|
286
285
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
refresh_token=refresh_token,
|
|
290
|
-
expires_at=expires_at,
|
|
291
|
-
project_id=state.project_id,
|
|
292
|
-
email=state.email,
|
|
293
|
-
)
|
|
286
|
+
# Calculate expiry time with 5 minute buffer
|
|
287
|
+
expires_at = int(time.time()) + expires_in - 300
|
|
294
288
|
|
|
295
|
-
|
|
296
|
-
|
|
289
|
+
return AntigravityAuthState(
|
|
290
|
+
access_token=access_token,
|
|
291
|
+
refresh_token=refresh_token,
|
|
292
|
+
expires_at=expires_at,
|
|
293
|
+
project_id=current_state.project_id,
|
|
294
|
+
email=current_state.email,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
return self.token_manager.refresh_with_lock(do_refresh)
|
|
299
|
+
except ValueError as e:
|
|
300
|
+
raise AntigravityNotLoggedInError(str(e)) from e
|
|
297
301
|
|
|
298
302
|
def ensure_valid_token(self) -> tuple[str, str]:
|
|
299
303
|
"""Ensure we have a valid access token, refreshing if needed.
|
|
@@ -309,12 +313,3 @@ class AntigravityOAuth:
|
|
|
309
313
|
state = self.refresh()
|
|
310
314
|
|
|
311
315
|
return state.access_token, state.project_id
|
|
312
|
-
|
|
313
|
-
def get_api_key_json(self) -> str:
|
|
314
|
-
"""Get API key as JSON string for LLM client.
|
|
315
|
-
|
|
316
|
-
Returns:
|
|
317
|
-
JSON string with token and projectId.
|
|
318
|
-
"""
|
|
319
|
-
access_token, project_id = self.ensure_valid_token()
|
|
320
|
-
return json.dumps({"token": access_token, "projectId": project_id})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Token storage and management for Antigravity authentication."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from klaude_code.auth.base import BaseAuthState, BaseTokenManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AntigravityAuthState(BaseAuthState):
|
|
10
|
+
"""Stored authentication state for Antigravity."""
|
|
11
|
+
|
|
12
|
+
project_id: str
|
|
13
|
+
email: str | None = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AntigravityTokenManager(BaseTokenManager[AntigravityAuthState]):
|
|
17
|
+
"""Manage Antigravity OAuth tokens."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, auth_file: Path | None = None):
|
|
20
|
+
super().__init__(auth_file)
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def storage_key(self) -> str:
|
|
24
|
+
return "antigravity"
|
|
25
|
+
|
|
26
|
+
def _create_state(self, data: dict[str, Any]) -> AntigravityAuthState:
|
|
27
|
+
return AntigravityAuthState.model_validate(data)
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
import json
|
|
4
4
|
import time
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
|
+
from collections.abc import Callable
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Any, cast
|
|
8
9
|
|
|
10
|
+
from filelock import FileLock, Timeout
|
|
9
11
|
from pydantic import BaseModel
|
|
10
12
|
|
|
11
13
|
KLAUDE_AUTH_FILE = Path.home() / ".klaude" / "klaude-auth.json"
|
|
14
|
+
LOCK_TIMEOUT_SECONDS = 30 # Maximum time to wait for lock acquisition
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class BaseAuthState(BaseModel):
|
|
@@ -99,3 +102,53 @@ class BaseTokenManager[T: BaseAuthState](ABC):
|
|
|
99
102
|
def clear_cached_state(self) -> None:
|
|
100
103
|
"""Clear in-memory cached state to force reload from file on next access."""
|
|
101
104
|
self._state = None
|
|
105
|
+
|
|
106
|
+
def _get_lock_file(self) -> Path:
|
|
107
|
+
"""Get the lock file path for this auth file."""
|
|
108
|
+
return self.auth_file.with_suffix(".lock")
|
|
109
|
+
|
|
110
|
+
def refresh_with_lock(self, refresh_fn: Callable[[T], T]) -> T:
|
|
111
|
+
"""Refresh token with file locking to prevent concurrent refresh.
|
|
112
|
+
|
|
113
|
+
This prevents multiple instances from simultaneously refreshing the same token.
|
|
114
|
+
If another instance has already refreshed, returns the updated state.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
refresh_fn: Function that takes current state and returns new state.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
The new or already-refreshed authentication state.
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
Timeout: If unable to acquire the lock within timeout.
|
|
124
|
+
ValueError: If not logged in.
|
|
125
|
+
"""
|
|
126
|
+
lock_file = self._get_lock_file()
|
|
127
|
+
lock = FileLock(lock_file, timeout=LOCK_TIMEOUT_SECONDS)
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
with lock:
|
|
131
|
+
# Re-read file after acquiring lock - another instance may have refreshed
|
|
132
|
+
self.clear_cached_state()
|
|
133
|
+
state = self.load()
|
|
134
|
+
|
|
135
|
+
if state is None:
|
|
136
|
+
raise ValueError(f"Not logged in to {self.storage_key}")
|
|
137
|
+
|
|
138
|
+
# Check if token is still expired after re-reading
|
|
139
|
+
if not state.is_expired():
|
|
140
|
+
# Another instance already refreshed, use their result
|
|
141
|
+
return state
|
|
142
|
+
|
|
143
|
+
# Token still expired, we need to refresh
|
|
144
|
+
new_state = refresh_fn(state)
|
|
145
|
+
self.save(new_state)
|
|
146
|
+
return new_state
|
|
147
|
+
|
|
148
|
+
except Timeout:
|
|
149
|
+
# Lock timeout - try to re-read file in case another instance succeeded
|
|
150
|
+
self.clear_cached_state()
|
|
151
|
+
state = self.load()
|
|
152
|
+
if state and not state.is_expired():
|
|
153
|
+
return state
|
|
154
|
+
raise
|
|
@@ -125,60 +125,45 @@ class ClaudeOAuth:
|
|
|
125
125
|
expires_at=int(time.time()) + int(expires_in),
|
|
126
126
|
)
|
|
127
127
|
|
|
128
|
-
def _do_refresh_request(self, refresh_token: str) -> httpx.Response:
|
|
129
|
-
"""Send token refresh request to OAuth server."""
|
|
130
|
-
payload = {
|
|
131
|
-
"grant_type": "refresh_token",
|
|
132
|
-
"client_id": CLIENT_ID,
|
|
133
|
-
"refresh_token": refresh_token,
|
|
134
|
-
}
|
|
135
|
-
with httpx.Client() as client:
|
|
136
|
-
return client.post(
|
|
137
|
-
TOKEN_URL,
|
|
138
|
-
json=payload,
|
|
139
|
-
headers={"Content-Type": "application/json"},
|
|
140
|
-
)
|
|
141
|
-
|
|
142
128
|
def refresh(self) -> ClaudeAuthState:
|
|
143
|
-
"""Refresh the access token using refresh token.
|
|
129
|
+
"""Refresh the access token using refresh token with file locking.
|
|
144
130
|
|
|
145
|
-
|
|
146
|
-
|
|
131
|
+
Uses file locking to prevent multiple instances from refreshing simultaneously.
|
|
132
|
+
If another instance has already refreshed, returns the updated state.
|
|
147
133
|
"""
|
|
148
|
-
state = self.token_manager.get_state()
|
|
149
|
-
if state is None:
|
|
150
|
-
raise ClaudeNotLoggedInError("Not logged in to Claude. Run 'klaude login claude' first.")
|
|
151
134
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
135
|
+
def do_refresh(current_state: ClaudeAuthState) -> ClaudeAuthState:
|
|
136
|
+
payload = {
|
|
137
|
+
"grant_type": "refresh_token",
|
|
138
|
+
"client_id": CLIENT_ID,
|
|
139
|
+
"refresh_token": current_state.refresh_token,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
with httpx.Client() as client:
|
|
143
|
+
response = client.post(
|
|
144
|
+
TOKEN_URL,
|
|
145
|
+
json=payload,
|
|
146
|
+
headers={"Content-Type": "application/json"},
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
if response.status_code != 200:
|
|
150
|
+
raise ClaudeAuthError(f"Token refresh failed: {response.text}")
|
|
151
|
+
|
|
152
|
+
tokens = response.json()
|
|
153
|
+
access_token = tokens["access_token"]
|
|
154
|
+
refresh_token = tokens.get("refresh_token", current_state.refresh_token)
|
|
155
|
+
expires_in = tokens.get("expires_in", 3600)
|
|
156
|
+
|
|
157
|
+
return ClaudeAuthState(
|
|
158
|
+
access_token=access_token,
|
|
159
|
+
refresh_token=refresh_token,
|
|
160
|
+
expires_at=int(time.time()) + int(expires_in),
|
|
161
|
+
)
|
|
174
162
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
)
|
|
180
|
-
self.token_manager.save(new_state)
|
|
181
|
-
return new_state
|
|
163
|
+
try:
|
|
164
|
+
return self.token_manager.refresh_with_lock(do_refresh)
|
|
165
|
+
except ValueError as e:
|
|
166
|
+
raise ClaudeNotLoggedInError(str(e)) from e
|
|
182
167
|
|
|
183
168
|
def ensure_valid_token(self) -> str:
|
|
184
169
|
"""Ensure we have a valid access token, refreshing if needed."""
|
|
@@ -177,43 +177,47 @@ class CodexOAuth:
|
|
|
177
177
|
)
|
|
178
178
|
|
|
179
179
|
def refresh(self) -> CodexAuthState:
|
|
180
|
-
"""Refresh the access token using refresh token.
|
|
181
|
-
state = self.token_manager.get_state()
|
|
182
|
-
if state is None:
|
|
183
|
-
from klaude_code.auth.codex.exceptions import CodexNotLoggedInError
|
|
180
|
+
"""Refresh the access token using refresh token with file locking.
|
|
184
181
|
|
|
185
|
-
|
|
182
|
+
Uses file locking to prevent multiple instances from refreshing simultaneously.
|
|
183
|
+
If another instance has already refreshed, returns the updated state.
|
|
184
|
+
"""
|
|
186
185
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
def do_refresh(current_state: CodexAuthState) -> CodexAuthState:
|
|
187
|
+
data = {
|
|
188
|
+
"grant_type": "refresh_token",
|
|
189
|
+
"client_id": CLIENT_ID,
|
|
190
|
+
"refresh_token": current_state.refresh_token,
|
|
191
|
+
}
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
with httpx.Client() as client:
|
|
194
|
+
response = client.post(TOKEN_URL, data=data)
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
if response.status_code != 200:
|
|
197
|
+
from klaude_code.auth.codex.exceptions import CodexTokenExpiredError
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
raise CodexTokenExpiredError(f"Token refresh failed: {response.text}")
|
|
200
200
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
tokens = response.json()
|
|
202
|
+
access_token = tokens["access_token"]
|
|
203
|
+
refresh_token = tokens.get("refresh_token", current_state.refresh_token)
|
|
204
|
+
expires_in = tokens.get("expires_in", 3600)
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
account_id = extract_account_id(access_token)
|
|
207
207
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
208
|
+
return CodexAuthState(
|
|
209
|
+
access_token=access_token,
|
|
210
|
+
refresh_token=refresh_token,
|
|
211
|
+
expires_at=int(time.time()) + expires_in,
|
|
212
|
+
account_id=account_id,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
return self.token_manager.refresh_with_lock(do_refresh)
|
|
217
|
+
except ValueError as e:
|
|
218
|
+
from klaude_code.auth.codex.exceptions import CodexNotLoggedInError
|
|
214
219
|
|
|
215
|
-
|
|
216
|
-
return new_state
|
|
220
|
+
raise CodexNotLoggedInError(str(e)) from e
|
|
217
221
|
|
|
218
222
|
def ensure_valid_token(self) -> str:
|
|
219
223
|
"""Ensure we have a valid access token, refreshing if needed."""
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Token storage and management for Codex authentication."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from klaude_code.auth.base import BaseAuthState, BaseTokenManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CodexAuthState(BaseAuthState):
|
|
10
|
+
"""Stored authentication state for Codex."""
|
|
11
|
+
|
|
12
|
+
account_id: str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CodexTokenManager(BaseTokenManager[CodexAuthState]):
|
|
16
|
+
"""Manage Codex OAuth tokens."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, auth_file: Path | None = None):
|
|
19
|
+
super().__init__(auth_file)
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def storage_key(self) -> str:
|
|
23
|
+
return "codex"
|
|
24
|
+
|
|
25
|
+
def _create_state(self, data: dict[str, Any]) -> CodexAuthState:
|
|
26
|
+
return CodexAuthState.model_validate(data)
|