code-puppy 0.0.613__tar.gz → 0.0.614__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.
- {code_puppy-0.0.613 → code_puppy-0.0.614}/PKG-INFO +1 -1
- code_puppy-0.0.614/code_puppy/plugins/grok_oauth/__init__.py +6 -0
- code_puppy-0.0.614/code_puppy/plugins/grok_oauth/config.py +49 -0
- code_puppy-0.0.614/code_puppy/plugins/grok_oauth/oauth_flow.py +213 -0
- code_puppy-0.0.614/code_puppy/plugins/grok_oauth/register_callbacks.py +132 -0
- code_puppy-0.0.614/code_puppy/plugins/grok_oauth/test_plugin.py +160 -0
- code_puppy-0.0.614/code_puppy/plugins/grok_oauth/utils.py +195 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/pyproject.toml +1 -1
- {code_puppy-0.0.613 → code_puppy-0.0.614}/.gitignore +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/LICENSE +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_builder.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_compaction.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_diagnostics.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_history.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_key_listeners.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_non_streaming_render.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_run_signals.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_runtime.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/_steer_processor.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/agent_helios.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/agent_planning.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/event_stream_handler.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/run_stats.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/smooth_stream.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/agents/subagent_stream_handler.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/chatgpt_codex_client.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/claude_cache_client.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/cli_runner.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/add_model_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/agent_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/attachments.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/autosave_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/autosave_search.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/clipboard.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/colors_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/command_registry.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/config_apply.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/config_commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/core_commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/diff_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/file_index.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/judges_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/edit_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/install_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/silence_warning_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp_binding_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/mcp_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/model_settings_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/onboarding_slides.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/onboarding_wizard.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/pagination.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/pin_command_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/session_commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/set_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/set_menu_catalog.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/set_menu_render.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/set_menu_schema.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/set_menu_settings.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/set_menu_shims.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/set_menu_values.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/shell_passthrough.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/skills_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/uc_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/command_line/wiggum_state.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/error_logging.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/gemini_code_assist.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/gemini_model.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/aliases.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/engine.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/executor.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/matcher.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/models.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/registry.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/hook_engine/validator.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/keymap.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/list_filtering.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/main.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/agent_bindings.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/mcp_logs.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_/tool_arg_coercion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_prompts/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/mcp_prompts/hook_creator.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/bar_painters.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/bar_rendering.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/bottom_bar.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/bus.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/editor_actions.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/editor_completion.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/editor_display.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/editor_history.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/editor_keys.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/editor_paste.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/line_editor.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/markdown_patches.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/messages.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/pause_controller.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/prompt_prefix_style.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/rich_renderer.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/run_ui.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/run_ui_wiring.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/subagent_console.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/messaging/transcript_guard.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/model_descriptions.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/model_switching.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/model_utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/models.json +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/models_dev_parser.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/discovery.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/downloader.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/enabled_skills.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/installer.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/metadata.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/prompt_builder.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/remote_catalog.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/skill_catalog.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/skill_commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/skills_install_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/agent_skills/skills_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/aws_bedrock/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/aws_bedrock/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/aws_bedrock/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/aws_bedrock/utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/azure_foundry/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/azure_foundry/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/azure_foundry/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/azure_foundry/discovery.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/azure_foundry/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/azure_foundry/token.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/azure_foundry/utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/btw/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/btw/inline_view.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/btw/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/btw/side_query.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_hooks/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_hooks/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_hooks/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/fast_mode.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/prompt_handler.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/test_fast_mode.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/code_puppy_agent/SKILL.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/code_puppy_agent/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/code_puppy_agent/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/context_indicator/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/context_indicator/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/context_indicator/usage.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/copilot_auth/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/copilot_auth/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/copilot_auth/reasoning_client.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/copilot_auth/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/copilot_auth/utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/cancel.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/lifecycle.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/runtime.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/startup_lock.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/workflow_ids.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/dbos_durable_exec/wrapper.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/destructive_command_guard/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/destructive_command_guard/detector.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/destructive_command_guard/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/emoji_filter/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/emoji_filter/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/emoji_filter/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/emoji_filter/stripper.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/example_custom_command/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/force_push_guard/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/force_push_guard/detector.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/force_push_guard/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/force_push_guard/test_detector.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/fork/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/fork/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/frontend_emitter/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/frontend_emitter/emitter.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/frontend_emitter/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/frontend_emitter/session_context.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/herdr/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/herdr/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/herdr/client.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/herdr/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/herdr/reporter.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/hook_creator/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/hook_creator/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/hook_manager/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/hook_manager/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/hook_manager/hooks_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/hook_manager/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/no_tools/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/no_tools/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/oauth_puppy_html.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/obsidian_agent/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/obsidian_agent/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/obsidian_agent/agent_obsidian.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/obsidian_agent/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/ollama/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/ollama/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/ollama_setup/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/ollama_setup/completer.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/ollama_setup/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/plugin_contributions.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/plugin_meta.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/plugin_text_utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/plugins_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/plugins_menu_layout.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/plugins_menu_render.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/project_trust_flow.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/plugin_list/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/pop_command/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/pop_command/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prompt_newline/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prompt_newline/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prompt_newline/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prune/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prune/prune_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prune/prune_model.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prune/prune_render.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/prune/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/kennel.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/packer.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/recorder.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/retriever.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/schema.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/state.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/tools.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_kennel/wings.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_spinner/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_spinner/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_spinner/builtin_frames.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_spinner/commands.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_spinner/picker.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_spinner/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/puppy_spinner/spinners.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/quick_resume/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/quick_resume/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/review_pr/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/review_pr/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/shell_safety/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/stack_dump/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/stack_dump/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/statusline/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/statusline/config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/statusline/payload.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/statusline/prompt_patch.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/statusline/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/statusline/runner.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/statusline/statusline_command.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/steer_queue/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/steer_queue/queue_menu.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/steer_queue/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/subagent_panel/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/subagent_panel/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/subagent_panel/coalesce_patch.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/subagent_panel/panel_render.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/subagent_panel/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/subagent_panel/resume_repaint.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/subagent_panel/state.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/switch_agent_resume/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/switch_agent_resume/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/README.md +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/bundled_palettes.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/content_styles.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/osc_palette.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/picker.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/rich_themes.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/theme/themes.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/token_ratio_learner/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/token_ratio_learner/ratios.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/token_ratio_learner/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/trust.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/trust_notice.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/universal_constructor/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/universal_constructor/models.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/universal_constructor/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/universal_constructor/registry.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/universal_constructor/sandbox.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/wide_completion_menu/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/wide_completion_menu/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/wiggum/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/wiggum/judge.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/wiggum/judge_config.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/wiggum/register_callbacks.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/plugins/wiggum/state.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/provider_credentials.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/provider_identity.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/pydantic_patches.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/session_lifecycle.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/session_migration.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/terminal_utils.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/constants.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/demo_tui.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/handler.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/models.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/registration.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/renderers.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/terminal_ui.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/theme.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/ask_user_question/tui_loop.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_locator_resolver.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_manager.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_page_snapshot.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_semantic_interactions.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/display.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/image_tools.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/model_tools.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/skills_tools.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/subagent_context.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/subagent_invocation.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/tools/universal_constructor.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/undo_manager.py +0 -0
- {code_puppy-0.0.613 → code_puppy-0.0.614}/code_puppy/version_checker.py +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Configuration for the Grok (x.ai) OAuth plugin.
|
|
2
|
+
|
|
3
|
+
Endpoints, client id, and scopes mirror the official Grok CLI OAuth flow
|
|
4
|
+
(as implemented by https://pi.dev/packages/pi-xai-oauth).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict
|
|
9
|
+
|
|
10
|
+
from code_puppy import config
|
|
11
|
+
|
|
12
|
+
GROK_OAUTH_CONFIG: Dict[str, Any] = {
|
|
13
|
+
# OIDC issuer + discovery. Authorization/token endpoints are resolved
|
|
14
|
+
# dynamically from the discovery document and validated against *.x.ai.
|
|
15
|
+
"issuer": "https://auth.x.ai",
|
|
16
|
+
"discovery_url": "https://auth.x.ai/.well-known/openid-configuration",
|
|
17
|
+
# Public OAuth client used by the official Grok CLI.
|
|
18
|
+
"client_id": "b1a00492-073a-47ea-816f-4c329264a828",
|
|
19
|
+
"scope": "openid profile email offline_access grok-cli:access api:access",
|
|
20
|
+
# Localhost callback. xAI allows an ephemeral-port fallback when the
|
|
21
|
+
# preferred port is busy.
|
|
22
|
+
"redirect_host": "127.0.0.1",
|
|
23
|
+
"redirect_port": 56121,
|
|
24
|
+
"redirect_path": "/callback",
|
|
25
|
+
"callback_timeout": 180,
|
|
26
|
+
# Refresh this many seconds before the token actually expires.
|
|
27
|
+
"refresh_skew_seconds": 120,
|
|
28
|
+
# Grok models are served from the regular xAI API with the OAuth
|
|
29
|
+
# access token as the bearer key.
|
|
30
|
+
"api_base_url": "https://api.x.ai/v1",
|
|
31
|
+
# Registered model names are prefixed to avoid catalogue collisions.
|
|
32
|
+
"prefix": "xai-",
|
|
33
|
+
"default_model": "grok-4.5",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Grok models made available after authentication.
|
|
37
|
+
GROK_MODELS: Dict[str, Dict[str, Any]] = {
|
|
38
|
+
"grok-4.5": {
|
|
39
|
+
"context_length": 500_000,
|
|
40
|
+
"supported_settings": ["reasoning_effort"],
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_token_storage_path() -> Path:
|
|
46
|
+
"""Path for storing OAuth tokens (uses XDG_DATA_HOME)."""
|
|
47
|
+
data_dir = Path(config.DATA_DIR)
|
|
48
|
+
data_dir.mkdir(parents=True, exist_ok=True, mode=0o700)
|
|
49
|
+
return data_dir / "grok_oauth.json"
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Grok (x.ai) OAuth flow matching the official Grok CLI / pi-xai-oauth."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import secrets
|
|
6
|
+
import threading
|
|
7
|
+
import time
|
|
8
|
+
import urllib.parse
|
|
9
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from code_puppy.messaging import emit_error, emit_info, emit_success, emit_warning
|
|
13
|
+
|
|
14
|
+
from ..oauth_puppy_html import oauth_failure_html, oauth_success_html
|
|
15
|
+
from .config import GROK_OAUTH_CONFIG
|
|
16
|
+
from .utils import (
|
|
17
|
+
exchange_token,
|
|
18
|
+
fetch_discovery,
|
|
19
|
+
generate_pkce_pair,
|
|
20
|
+
load_stored_tokens,
|
|
21
|
+
save_tokens,
|
|
22
|
+
tokens_from_payload,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
_ALLOWED_CORS_ORIGINS = ("https://accounts.x.ai", "https://auth.x.ai")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _OAuthServer(HTTPServer):
|
|
29
|
+
"""Localhost callback server holding the state for one OAuth attempt."""
|
|
30
|
+
|
|
31
|
+
def __init__(self) -> None:
|
|
32
|
+
host = GROK_OAUTH_CONFIG["redirect_host"]
|
|
33
|
+
preferred_port = GROK_OAUTH_CONFIG["redirect_port"]
|
|
34
|
+
try:
|
|
35
|
+
super().__init__((host, preferred_port), _CallbackHandler)
|
|
36
|
+
except OSError:
|
|
37
|
+
# Preferred port busy — xAI accepts ephemeral localhost ports.
|
|
38
|
+
super().__init__((host, 0), _CallbackHandler)
|
|
39
|
+
|
|
40
|
+
self.exit_code = 1
|
|
41
|
+
discovery = fetch_discovery()
|
|
42
|
+
self.authorization_endpoint = discovery["authorization_endpoint"]
|
|
43
|
+
self.token_endpoint = discovery["token_endpoint"]
|
|
44
|
+
self.state = secrets.token_hex(16)
|
|
45
|
+
self.nonce = secrets.token_hex(16)
|
|
46
|
+
self.code_verifier, self.code_challenge = generate_pkce_pair()
|
|
47
|
+
port = self.server_address[1]
|
|
48
|
+
self.redirect_uri = f"http://{host}:{port}{GROK_OAUTH_CONFIG['redirect_path']}"
|
|
49
|
+
|
|
50
|
+
def auth_url(self) -> str:
|
|
51
|
+
params = {
|
|
52
|
+
"response_type": "code",
|
|
53
|
+
"client_id": GROK_OAUTH_CONFIG["client_id"],
|
|
54
|
+
"redirect_uri": self.redirect_uri,
|
|
55
|
+
"scope": GROK_OAUTH_CONFIG["scope"],
|
|
56
|
+
"code_challenge": self.code_challenge,
|
|
57
|
+
"code_challenge_method": "S256",
|
|
58
|
+
"state": self.state,
|
|
59
|
+
"nonce": self.nonce,
|
|
60
|
+
}
|
|
61
|
+
return f"{self.authorization_endpoint}?{urllib.parse.urlencode(params)}"
|
|
62
|
+
|
|
63
|
+
def exchange_code(self, code: str) -> bool:
|
|
64
|
+
payload = exchange_token(
|
|
65
|
+
self.token_endpoint,
|
|
66
|
+
{
|
|
67
|
+
"grant_type": "authorization_code",
|
|
68
|
+
"code": code,
|
|
69
|
+
"redirect_uri": self.redirect_uri,
|
|
70
|
+
"client_id": GROK_OAUTH_CONFIG["client_id"],
|
|
71
|
+
"code_verifier": self.code_verifier,
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
return save_tokens(tokens_from_payload(payload, self.token_endpoint))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class _CallbackHandler(BaseHTTPRequestHandler):
|
|
78
|
+
server: "_OAuthServer"
|
|
79
|
+
|
|
80
|
+
def do_OPTIONS(self) -> None: # noqa: N802
|
|
81
|
+
self.send_response(204)
|
|
82
|
+
self._send_cors_headers()
|
|
83
|
+
self.end_headers()
|
|
84
|
+
|
|
85
|
+
def do_GET(self) -> None: # noqa: N802
|
|
86
|
+
parsed = urllib.parse.urlparse(self.path)
|
|
87
|
+
if parsed.path != GROK_OAUTH_CONFIG["redirect_path"]:
|
|
88
|
+
self._send_failure(404, "Callback endpoint not found for the puppy parade.")
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
params = urllib.parse.parse_qs(parsed.query)
|
|
92
|
+
error = params.get("error", [None])[0]
|
|
93
|
+
if error:
|
|
94
|
+
description = params.get("error_description", [error])[0]
|
|
95
|
+
self._send_failure(400, f"xAI authorization failed: {description}")
|
|
96
|
+
self._shutdown_after_delay()
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
if params.get("state", [None])[0] != self.server.state:
|
|
100
|
+
self._send_failure(
|
|
101
|
+
400, "OAuth state mismatch — a squirrel may have tampered with it."
|
|
102
|
+
)
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
code = params.get("code", [None])[0]
|
|
106
|
+
if not code:
|
|
107
|
+
self._send_failure(400, "Missing auth code — the token treat rolled away.")
|
|
108
|
+
self._shutdown_after_delay()
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
saved = self.server.exchange_code(code)
|
|
113
|
+
except Exception as exc: # noqa: BLE001
|
|
114
|
+
self._send_failure(500, f"Token exchange failed: {exc}")
|
|
115
|
+
self._shutdown_after_delay()
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
if saved:
|
|
119
|
+
self.server.exit_code = 0
|
|
120
|
+
self._send_html(
|
|
121
|
+
oauth_success_html(
|
|
122
|
+
"Grok",
|
|
123
|
+
"You can now close this window and return to Code Puppy.",
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
self._send_failure(
|
|
128
|
+
500, "Unable to persist auth file — a puppy probably chewed it."
|
|
129
|
+
)
|
|
130
|
+
self._shutdown_after_delay()
|
|
131
|
+
|
|
132
|
+
def log_message(self, fmt: str, *args: Any) -> None: # noqa: A003
|
|
133
|
+
pass
|
|
134
|
+
|
|
135
|
+
def _send_cors_headers(self) -> None:
|
|
136
|
+
origin = self.headers.get("Origin")
|
|
137
|
+
if origin not in _ALLOWED_CORS_ORIGINS:
|
|
138
|
+
return
|
|
139
|
+
self.send_header("Access-Control-Allow-Origin", origin)
|
|
140
|
+
self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS")
|
|
141
|
+
self.send_header("Access-Control-Allow-Headers", "Content-Type")
|
|
142
|
+
self.send_header("Access-Control-Allow-Private-Network", "true")
|
|
143
|
+
self.send_header("Vary", "Origin")
|
|
144
|
+
|
|
145
|
+
def _send_html(self, body: str, status: int = 200) -> None:
|
|
146
|
+
encoded = body.encode("utf-8")
|
|
147
|
+
self.send_response(status)
|
|
148
|
+
self._send_cors_headers()
|
|
149
|
+
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
150
|
+
self.send_header("Content-Length", str(len(encoded)))
|
|
151
|
+
self.end_headers()
|
|
152
|
+
self.wfile.write(encoded)
|
|
153
|
+
|
|
154
|
+
def _send_failure(self, status: int, reason: str) -> None:
|
|
155
|
+
self._send_html(oauth_failure_html("Grok", reason), status)
|
|
156
|
+
|
|
157
|
+
def _shutdown_after_delay(self, seconds: float = 2.0) -> None:
|
|
158
|
+
def _later() -> None:
|
|
159
|
+
time.sleep(seconds)
|
|
160
|
+
self.server.shutdown()
|
|
161
|
+
|
|
162
|
+
threading.Thread(target=_later, daemon=True).start()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def run_oauth_flow() -> bool:
|
|
166
|
+
"""Run the browser OAuth flow. Returns True when tokens were saved."""
|
|
167
|
+
existing_tokens = load_stored_tokens()
|
|
168
|
+
if existing_tokens and existing_tokens.get("access_token"):
|
|
169
|
+
emit_warning("Existing Grok tokens will be overwritten.")
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
server = _OAuthServer()
|
|
173
|
+
except Exception as exc: # noqa: BLE001
|
|
174
|
+
emit_error(f"Could not start Grok OAuth flow: {exc}")
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
auth_url = server.auth_url()
|
|
178
|
+
emit_info(f"Open this URL in your browser: {auth_url}")
|
|
179
|
+
|
|
180
|
+
server_thread = threading.Thread(target=server.serve_forever, daemon=True)
|
|
181
|
+
server_thread.start()
|
|
182
|
+
|
|
183
|
+
from code_puppy.tools.common import should_suppress_browser
|
|
184
|
+
|
|
185
|
+
if should_suppress_browser():
|
|
186
|
+
emit_info(f"[HEADLESS MODE] Would normally open: {auth_url}")
|
|
187
|
+
else:
|
|
188
|
+
try:
|
|
189
|
+
import webbrowser
|
|
190
|
+
|
|
191
|
+
if not webbrowser.open(auth_url):
|
|
192
|
+
emit_warning("Please open the URL manually — the browser stayed home.")
|
|
193
|
+
except Exception as exc: # noqa: BLE001
|
|
194
|
+
emit_warning(f"Could not open browser automatically: {exc}")
|
|
195
|
+
|
|
196
|
+
emit_info("Waiting for xAI authentication callback…")
|
|
197
|
+
|
|
198
|
+
elapsed = 0.0
|
|
199
|
+
timeout = GROK_OAUTH_CONFIG["callback_timeout"]
|
|
200
|
+
interval = 0.25
|
|
201
|
+
while elapsed < timeout and server.exit_code != 0:
|
|
202
|
+
time.sleep(interval)
|
|
203
|
+
elapsed += interval
|
|
204
|
+
|
|
205
|
+
server.shutdown()
|
|
206
|
+
server_thread.join(timeout=5)
|
|
207
|
+
|
|
208
|
+
if server.exit_code != 0:
|
|
209
|
+
emit_error("Grok authentication failed or timed out.")
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
emit_success("Grok OAuth complete — access token saved.")
|
|
213
|
+
return True
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Grok (x.ai) OAuth plugin callbacks.
|
|
2
|
+
|
|
3
|
+
Provides OAuth authentication for Grok models (SuperGrok / Grok CLI flow)
|
|
4
|
+
and registers the 'grok_oauth' model type handler plus the Grok model
|
|
5
|
+
catalogue (headlined by grok-4.5).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
11
|
+
|
|
12
|
+
from code_puppy.callbacks import register_callback
|
|
13
|
+
from code_puppy.messaging import emit_info, emit_success, emit_warning
|
|
14
|
+
from code_puppy.model_switching import set_model_and_reload_agent
|
|
15
|
+
|
|
16
|
+
from .config import GROK_MODELS, GROK_OAUTH_CONFIG, get_token_storage_path
|
|
17
|
+
from .oauth_flow import run_oauth_flow
|
|
18
|
+
from .utils import get_valid_access_token, load_stored_tokens
|
|
19
|
+
|
|
20
|
+
_PREFIX = GROK_OAUTH_CONFIG["prefix"]
|
|
21
|
+
_DEFAULT_MODEL = f"{_PREFIX}{GROK_OAUTH_CONFIG['default_model']}"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _custom_help() -> List[Tuple[str, str]]:
|
|
25
|
+
return [
|
|
26
|
+
(
|
|
27
|
+
"grok-auth",
|
|
28
|
+
"Authenticate with x.ai (Grok) via OAuth and register Grok models",
|
|
29
|
+
),
|
|
30
|
+
("grok-status", "Check Grok OAuth authentication status"),
|
|
31
|
+
("grok-logout", "Remove Grok OAuth tokens and registered models"),
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _handle_grok_status() -> None:
|
|
36
|
+
tokens = load_stored_tokens()
|
|
37
|
+
if tokens and tokens.get("access_token"):
|
|
38
|
+
emit_success(" Grok OAuth: Authenticated")
|
|
39
|
+
emit_info(f" Available Grok models: {', '.join(_grok_model_names())}")
|
|
40
|
+
else:
|
|
41
|
+
emit_warning(" Grok OAuth: Not authenticated")
|
|
42
|
+
emit_info(" Run /grok-auth to launch the browser sign-in flow.")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _handle_grok_logout() -> None:
|
|
46
|
+
token_path = get_token_storage_path()
|
|
47
|
+
if token_path.exists():
|
|
48
|
+
token_path.unlink()
|
|
49
|
+
emit_info("Removed Grok OAuth tokens")
|
|
50
|
+
emit_success("Grok logout complete")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _handle_custom_command(command: str, name: str) -> Optional[bool]:
|
|
54
|
+
if not name:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
if name == "grok-auth":
|
|
58
|
+
if run_oauth_flow():
|
|
59
|
+
emit_info(f"Registering Grok models: {', '.join(_grok_model_names())}")
|
|
60
|
+
set_model_and_reload_agent(_DEFAULT_MODEL)
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
if name == "grok-status":
|
|
64
|
+
_handle_grok_status()
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
if name == "grok-logout":
|
|
68
|
+
_handle_grok_logout()
|
|
69
|
+
return True
|
|
70
|
+
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _grok_model_names() -> List[str]:
|
|
75
|
+
return [f"{_PREFIX}{model_id}" for model_id in GROK_MODELS]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _load_grok_models() -> Dict[str, Any]:
|
|
79
|
+
"""Inject Grok models into the catalogue once authenticated."""
|
|
80
|
+
tokens = load_stored_tokens()
|
|
81
|
+
if not (tokens and tokens.get("access_token")):
|
|
82
|
+
return {}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
f"{_PREFIX}{model_id}": {
|
|
86
|
+
"type": "grok_oauth",
|
|
87
|
+
"name": model_id,
|
|
88
|
+
"context_length": spec["context_length"],
|
|
89
|
+
"supported_settings": spec.get("supported_settings", []),
|
|
90
|
+
"oauth_source": "grok-oauth-plugin",
|
|
91
|
+
}
|
|
92
|
+
for model_id, spec in GROK_MODELS.items()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _create_grok_oauth_model(model_name: str, model_config: Dict, config: Dict) -> Any:
|
|
97
|
+
"""Create a Grok OAuth model instance.
|
|
98
|
+
|
|
99
|
+
This handler is registered via the 'register_model_type' callback to
|
|
100
|
+
handle models with type='grok_oauth'. Grok models speak the OpenAI
|
|
101
|
+
Responses API on api.x.ai with the OAuth access token as bearer key.
|
|
102
|
+
"""
|
|
103
|
+
from pydantic_ai.models.openai import OpenAIResponsesModel
|
|
104
|
+
from pydantic_ai.providers.openai import OpenAIProvider
|
|
105
|
+
|
|
106
|
+
from code_puppy.http_utils import create_async_client
|
|
107
|
+
|
|
108
|
+
access_token = get_valid_access_token()
|
|
109
|
+
if not access_token:
|
|
110
|
+
emit_warning(
|
|
111
|
+
f"Failed to get valid Grok OAuth token; skipping model "
|
|
112
|
+
f"'{model_config.get('name')}'. Run /grok-auth to authenticate."
|
|
113
|
+
)
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
provider = OpenAIProvider(
|
|
117
|
+
api_key=access_token,
|
|
118
|
+
base_url=GROK_OAUTH_CONFIG["api_base_url"],
|
|
119
|
+
http_client=create_async_client(model_name=model_name),
|
|
120
|
+
)
|
|
121
|
+
return OpenAIResponsesModel(model_name=model_config["name"], provider=provider)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _register_model_types() -> List[Dict[str, Any]]:
|
|
125
|
+
"""Register the grok_oauth model type handler."""
|
|
126
|
+
return [{"type": "grok_oauth", "handler": _create_grok_oauth_model}]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
register_callback("custom_command_help", _custom_help)
|
|
130
|
+
register_callback("custom_command", _handle_custom_command)
|
|
131
|
+
register_callback("register_model_type", _register_model_types)
|
|
132
|
+
register_callback("load_models_config", _load_grok_models)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Tests for the Grok (x.ai) OAuth plugin."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from code_puppy.plugins.grok_oauth import config as grok_config
|
|
11
|
+
from code_puppy.plugins.grok_oauth import register_callbacks as rc
|
|
12
|
+
from code_puppy.plugins.grok_oauth import utils
|
|
13
|
+
from code_puppy.plugins.grok_oauth.config import GROK_OAUTH_CONFIG
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.fixture
|
|
17
|
+
def token_path(tmp_path):
|
|
18
|
+
path = tmp_path / "grok_oauth.json"
|
|
19
|
+
with (
|
|
20
|
+
patch.object(grok_config, "get_token_storage_path", return_value=path),
|
|
21
|
+
patch.object(utils, "get_token_storage_path", return_value=path),
|
|
22
|
+
patch.object(rc, "get_token_storage_path", return_value=path),
|
|
23
|
+
):
|
|
24
|
+
yield path
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _save_valid_tokens(**overrides):
|
|
28
|
+
tokens = {
|
|
29
|
+
"access_token": "fake-token",
|
|
30
|
+
"refresh_token": "fake-refresh",
|
|
31
|
+
"expires_at": time.time() + 3600,
|
|
32
|
+
"token_endpoint": "https://auth.x.ai/oauth2/token",
|
|
33
|
+
}
|
|
34
|
+
tokens.update(overrides)
|
|
35
|
+
assert utils.save_tokens(tokens)
|
|
36
|
+
return tokens
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_config_values():
|
|
40
|
+
assert GROK_OAUTH_CONFIG["issuer"] == "https://auth.x.ai"
|
|
41
|
+
assert "grok-cli:access" in GROK_OAUTH_CONFIG["scope"]
|
|
42
|
+
assert "api:access" in GROK_OAUTH_CONFIG["scope"]
|
|
43
|
+
assert GROK_OAUTH_CONFIG["api_base_url"] == "https://api.x.ai/v1"
|
|
44
|
+
assert GROK_OAUTH_CONFIG["default_model"] in grok_config.GROK_MODELS
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_pkce_pair_shape():
|
|
48
|
+
verifier, challenge = utils.generate_pkce_pair()
|
|
49
|
+
assert len(verifier) >= 43
|
|
50
|
+
assert "=" not in verifier and "=" not in challenge
|
|
51
|
+
# Deterministic: same verifier always hashes to the same challenge
|
|
52
|
+
import base64
|
|
53
|
+
import hashlib
|
|
54
|
+
|
|
55
|
+
digest = hashlib.sha256(verifier.encode()).digest()
|
|
56
|
+
expected = base64.urlsafe_b64encode(digest).decode().rstrip("=")
|
|
57
|
+
assert challenge == expected
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.parametrize(
|
|
61
|
+
"url",
|
|
62
|
+
[
|
|
63
|
+
"http://auth.x.ai/oauth2/token", # not https
|
|
64
|
+
"https://evil.com/oauth2/token", # wrong host
|
|
65
|
+
"https://notx.ai/oauth2/token", # suffix trickery
|
|
66
|
+
"https://x.ai.evil.com/token", # prefix trickery
|
|
67
|
+
],
|
|
68
|
+
)
|
|
69
|
+
def test_validate_xai_endpoint_rejects(url):
|
|
70
|
+
with pytest.raises(ValueError):
|
|
71
|
+
utils.validate_xai_endpoint(url)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_validate_xai_endpoint_accepts():
|
|
75
|
+
assert utils.validate_xai_endpoint("https://auth.x.ai/oauth2/token")
|
|
76
|
+
assert utils.validate_xai_endpoint("https://x.ai/oauth2/token")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_save_and_load_tokens(token_path):
|
|
80
|
+
_save_valid_tokens()
|
|
81
|
+
loaded = utils.load_stored_tokens()
|
|
82
|
+
assert loaded["access_token"] == "fake-token"
|
|
83
|
+
assert oct(token_path.stat().st_mode & 0o777) == oct(0o600)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_get_valid_access_token_fresh(token_path):
|
|
87
|
+
_save_valid_tokens()
|
|
88
|
+
assert utils.get_valid_access_token() == "fake-token"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_get_valid_access_token_refreshes_expired(token_path):
|
|
92
|
+
_save_valid_tokens(access_token="stale", expires_at=time.time() - 10)
|
|
93
|
+
payload = {
|
|
94
|
+
"access_token": "fresh-token",
|
|
95
|
+
"refresh_token": "new-refresh",
|
|
96
|
+
"expires_in": 3600,
|
|
97
|
+
}
|
|
98
|
+
with patch.object(utils, "exchange_token", return_value=payload) as exchange:
|
|
99
|
+
assert utils.get_valid_access_token() == "fresh-token"
|
|
100
|
+
|
|
101
|
+
body = exchange.call_args[0][1]
|
|
102
|
+
assert body["grant_type"] == "refresh_token"
|
|
103
|
+
assert body["client_id"] == GROK_OAUTH_CONFIG["client_id"]
|
|
104
|
+
assert utils.load_stored_tokens()["refresh_token"] == "new-refresh"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_get_valid_access_token_unauthenticated(token_path):
|
|
108
|
+
assert utils.get_valid_access_token() is None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_load_grok_models_requires_auth(token_path):
|
|
112
|
+
assert rc._load_grok_models() == {}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_load_grok_models_when_authenticated(token_path):
|
|
116
|
+
_save_valid_tokens()
|
|
117
|
+
models = rc._load_grok_models()
|
|
118
|
+
assert "xai-grok-4.5" in models
|
|
119
|
+
entry = models["xai-grok-4.5"]
|
|
120
|
+
assert entry["type"] == "grok_oauth"
|
|
121
|
+
assert entry["name"] == "grok-4.5"
|
|
122
|
+
assert entry["context_length"] == 500_000
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_model_type_registration():
|
|
126
|
+
handlers = rc._register_model_types()
|
|
127
|
+
assert handlers == [{"type": "grok_oauth", "handler": rc._create_grok_oauth_model}]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_create_model_returns_none_without_auth(token_path):
|
|
131
|
+
model = rc._create_grok_oauth_model("xai-grok-4.5", {"name": "grok-4.5"}, {})
|
|
132
|
+
assert model is None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_create_model_when_authenticated(token_path):
|
|
136
|
+
_save_valid_tokens()
|
|
137
|
+
model = rc._create_grok_oauth_model("xai-grok-4.5", {"name": "grok-4.5"}, {})
|
|
138
|
+
assert type(model).__name__ == "OpenAIResponsesModel"
|
|
139
|
+
assert model.model_name == "grok-4.5"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_custom_command_ignores_unknown():
|
|
143
|
+
assert rc._handle_custom_command("/other", "not-ours") is None
|
|
144
|
+
assert rc._handle_custom_command("/other", "") is None
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_custom_command_handles_status(token_path):
|
|
148
|
+
assert rc._handle_custom_command("/grok-status", "grok-status") is True
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_custom_command_logout(token_path):
|
|
152
|
+
_save_valid_tokens()
|
|
153
|
+
assert rc._handle_custom_command("/grok-logout", "grok-logout") is True
|
|
154
|
+
assert not token_path.exists()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_custom_help_entries():
|
|
158
|
+
entries = rc._custom_help()
|
|
159
|
+
names = [name for name, _ in entries]
|
|
160
|
+
assert names == ["grok-auth", "grok-status", "grok-logout"]
|