code-puppy-core-plugins 0.0.16__tar.gz → 0.0.18__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_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/PKG-INFO +1 -1
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_hooks/config.py +20 -17
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_hooks/register_callbacks.py +34 -0
- code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/claude_code_hooks/trust.py +339 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_manager/config.py +31 -7
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_manager/register_callbacks.py +17 -1
- code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/hook_manager/trust_handler.py +185 -0
- code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/session_namer/__init__.py +1 -0
- code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/session_namer/namer.py +255 -0
- code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/session_namer/register_callbacks.py +86 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/pyproject.toml +2 -1
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/.gitignore +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/LICENSE +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/agent.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/bridge.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/capabilities.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/commands.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/content.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/io_delegation.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/mcp_config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/permissions.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/persistence.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/replay.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/session.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/session_config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/state.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_creator_skill/SKILL.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_creator_skill/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_creator_skill/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/discovery.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/downloader.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/enabled_skills.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/installer.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/metadata.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/prompt_builder.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/provider.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/remote_catalog.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/skill_catalog.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/skill_commands.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/skills_install_menu.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/skills_menu.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/aws_bedrock/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/aws_bedrock/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/aws_bedrock/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/aws_bedrock/utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/discovery.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/token.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/inline_view.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/side_query.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/IMAGEGEN_SKILL.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/image_generation.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/image_tool.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/model_catalog.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/oauth_flow.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/test_plugin.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/usage.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_hooks/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/SETUP.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/fast_mode.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/prompt_handler.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/test_plugin.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/claude_code_oauth/utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/AGENTS_AND_TOOLS.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/MODELS_AND_MCP.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/PLUGINS_AND_CALLBACKS.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/SESSIONS_AND_HISTORY.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/SKILL.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/SKILLS_SYSTEM.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/SYSTEM_PROMPT_CONFIG_AND_I18N.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/code_puppy_agent/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/NativeCapture.swift +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/accessibility.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/activation.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/backend.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/backend_types.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/capture.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/commands.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/geometry.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/inline_image.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/keycodes.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/policy.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/safety.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/settle.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/state.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/tools.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/context_indicator/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/context_indicator/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/context_indicator/usage.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/reasoning_client.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/customizable_commands/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/customizable_commands/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/cancel.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/commands.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/lifecycle.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/runtime.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/startup_lock.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/workflow_ids.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/dbos_durable_exec/wrapper.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/destructive_command_guard/AGENTS.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/destructive_command_guard/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/destructive_command_guard/detector.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/destructive_command_guard/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/emoji_filter/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/emoji_filter/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/emoji_filter/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/emoji_filter/stripper.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/empty_html_comment_filter/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/example_custom_command/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/file_permission_handler/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/file_permission_handler/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/cheatsheet.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/pipeline.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/synopsis.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/about.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/address-feedback.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/ask.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/aug.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/auto-pilot.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/cheatsheet.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/commit.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/config.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/create-pr.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/exec.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/new.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/qa.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/rebase.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/review.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/split.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/squash-commits.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/status.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/tests.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_about.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_cheatsheet.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_status.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/installer.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/force_push_guard/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/force_push_guard/detector.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/force_push_guard/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/fork/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/fork/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/frontend_emitter/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/frontend_emitter/emitter.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/frontend_emitter/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/frontend_emitter/session_context.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/oauth_flow.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/client.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/reporter.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/smoke.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/sources.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_creator/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_creator/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_manager/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_manager/hooks_menu.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_oauth/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_oauth/oauth.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_oauth/query_tool.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_oauth/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/mirror.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/query.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/sync.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/oauth_flow.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/namespace_skill_search/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/namespace_skill_search/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/namespace_skill_search/namespaces.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/namespace_skill_search/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/namespace_skill_search/search_tool.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/no_tools/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/no_tools/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/oauth_pasteback.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/oauth_puppy_html.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/obsidian_agent/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/obsidian_agent/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/obsidian_agent/agent_obsidian.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/obsidian_agent/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama_setup/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama_setup/completer.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama_setup/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/plugin_contributions.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/plugin_meta.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/plugin_text_utils.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/plugins_menu.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/plugins_menu_layout.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/plugins_menu_render.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/project_trust_flow.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/pop_command/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/pop_command/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prompt_newline/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prompt_newline/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prompt_newline/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/prune_menu.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/prune_model.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/prune_render.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/commands.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/kennel.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/packer.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/recorder.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/retriever.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/schema.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/state.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/tools.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/wings.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/builtin_frames.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/commands.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/picker.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/spinners.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/qa_kitten_skill/SKILL.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/qa_kitten_skill/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/qa_kitten_skill/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/quick_resume/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/quick_resume/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/review_pr/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/review_pr/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/shell_safety/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/shell_safety/agent_shell_safety.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/shell_safety/command_cache.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/shell_safety/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/LICENSE.deepseek +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/store.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/stack_dump/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/stack_dump/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/payload.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/prompt_patch.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/runner.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/statusline_command.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/steer_queue/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/steer_queue/queue_menu.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/steer_queue/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/coalesce_patch.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/panel_render.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/resume_repaint.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/state.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/switch_agent_resume/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/switch_agent_resume/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/README.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/bundled_palettes.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/content_styles.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/osc_palette.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/picker.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/prompt_toolkit_theme.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/rich_themes.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/themes.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/timestamp_heartbeat/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/timestamp_heartbeat/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/token_ratio_learner/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/token_ratio_learner/ratios.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/token_ratio_learner/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/models.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/provider.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/registry.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/sandbox.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/web_retriever_skill/SKILL.md +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/web_retriever_skill/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/web_retriever_skill/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wide_completion_menu/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wide_completion_menu/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/goal_runs.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/judge.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/judge_config.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/judges_menu.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/register_callbacks.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/state.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/yolo_cli/__init__.py +0 -0
- {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/yolo_cli/register_callbacks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: code-puppy-core-plugins
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.18
|
|
4
4
|
Summary: Official plugin bundle for Code Puppy
|
|
5
5
|
Project-URL: Repository, https://github.com/mpfaffenberger/code_puppy_core_plugins
|
|
6
6
|
Project-URL: Homepage, https://github.com/mpfaffenberger/code_puppy_core_plugins
|
|
@@ -15,6 +15,8 @@ import os
|
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
from typing import Any, Dict, Optional
|
|
17
17
|
|
|
18
|
+
from . import trust as _trust
|
|
19
|
+
|
|
18
20
|
logger = logging.getLogger(__name__)
|
|
19
21
|
|
|
20
22
|
PROJECT_HOOKS_FILE = ".claude/settings.json"
|
|
@@ -94,23 +96,24 @@ def load_hooks_config() -> Optional[Dict[str, Any]]:
|
|
|
94
96
|
except Exception as e:
|
|
95
97
|
logger.error(f"Failed to load {GLOBAL_HOOKS_FILE}: {e}", exc_info=True)
|
|
96
98
|
|
|
97
|
-
#
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
logger.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
99
|
+
# Hash the already-parsed subtree rather than re-reading the file — a
|
|
100
|
+
# second read is a TOCTOU foothold where an attacker could swap benign
|
|
101
|
+
# bytes for malicious ones between check and merge.
|
|
102
|
+
project_root = Path(os.getcwd())
|
|
103
|
+
project_settings_path = _trust.get_project_hooks_settings_file(project_root)
|
|
104
|
+
|
|
105
|
+
if project_settings_path is not None:
|
|
106
|
+
project_subtree = _trust._extract_hooks_subtree(project_settings_path)
|
|
107
|
+
if project_subtree is not None and _trust._has_effective_hooks(project_subtree):
|
|
108
|
+
current_hash = _trust.hash_subtree(project_subtree)
|
|
109
|
+
status = _trust.get_trust_status_for_hash(project_root, current_hash)
|
|
110
|
+
if status == _trust.TRUSTED:
|
|
111
|
+
logger.info(
|
|
112
|
+
f"Merging trusted hooks configuration from {project_settings_path}"
|
|
113
|
+
)
|
|
114
|
+
merged_config = _deep_merge_hooks(merged_config, project_subtree)
|
|
115
|
+
# The untrusted warning fires from the `startup` callback so it
|
|
116
|
+
# renders after boot rather than scrolling past above the banner.
|
|
114
117
|
|
|
115
118
|
if not merged_config:
|
|
116
119
|
logger.debug("No hooks configuration found")
|
|
@@ -27,6 +27,7 @@ from typing import Any, Dict, List, Optional
|
|
|
27
27
|
from code_puppy.callbacks import register_callback
|
|
28
28
|
from code_puppy.hook_engine import EventData, HookEngine
|
|
29
29
|
|
|
30
|
+
from . import trust as _trust
|
|
30
31
|
from .config import load_hooks_config
|
|
31
32
|
|
|
32
33
|
_SUBAGENT_NAMES = frozenset(
|
|
@@ -76,6 +77,28 @@ def _initialize_engine() -> Optional[HookEngine]:
|
|
|
76
77
|
_hook_engine = _initialize_engine()
|
|
77
78
|
|
|
78
79
|
|
|
80
|
+
def reload_hook_engine() -> None:
|
|
81
|
+
"""Rebuild ``_hook_engine`` from the current on-disk hooks config.
|
|
82
|
+
|
|
83
|
+
Called by the ``/hooks trust`` ceremony after accept/revoke so future
|
|
84
|
+
lifecycle events reflect the fresh trust state without a process
|
|
85
|
+
restart.
|
|
86
|
+
|
|
87
|
+
Intentionally does NOT re-fire ``SessionStart`` — that event's
|
|
88
|
+
semantics are "agent boot", and auto-firing mid-session would be a
|
|
89
|
+
surprise side-effect.
|
|
90
|
+
|
|
91
|
+
Also intentionally does NOT clear ``_pending_session_context`` on
|
|
92
|
+
revoke. The buffer only holds stdout produced by hooks that were
|
|
93
|
+
trusted at the moment they fired; honoring that stdout on the next
|
|
94
|
+
user prompt reflects the state that existed when the side-effect
|
|
95
|
+
already happened. The buffer is one-shot per session by design and
|
|
96
|
+
will drain on the next ``UserPromptSubmit`` regardless.
|
|
97
|
+
"""
|
|
98
|
+
global _hook_engine
|
|
99
|
+
_hook_engine = _initialize_engine()
|
|
100
|
+
|
|
101
|
+
|
|
79
102
|
def _collect_context_stdout(result: Any) -> List[str]:
|
|
80
103
|
"""Pull stdout from non-blocking, exit-0 hook results.
|
|
81
104
|
|
|
@@ -223,6 +246,17 @@ register_callback("startup", on_startup_hook)
|
|
|
223
246
|
register_callback("session_end", on_session_end_hook)
|
|
224
247
|
|
|
225
248
|
|
|
249
|
+
async def on_startup_emit_untrusted_warning() -> None:
|
|
250
|
+
"""Startup callback: emit the untrusted-hooks warning after boot."""
|
|
251
|
+
try:
|
|
252
|
+
_trust.emit_untrusted_project_hooks_warning_if_any()
|
|
253
|
+
except Exception as e: # pragma: no cover - defensive
|
|
254
|
+
logger.debug("emit_untrusted_project_hooks_warning_if_any failed: %s", e)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
register_callback("startup", on_startup_emit_untrusted_warning)
|
|
258
|
+
|
|
259
|
+
|
|
226
260
|
# ---------------------------------------------------------------------------
|
|
227
261
|
# UserPromptSubmit
|
|
228
262
|
# ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"""Content-hash trust store for project-level Claude Code hook configs.
|
|
2
|
+
|
|
3
|
+
Project ``.claude/settings.json`` files can declare hooks that run arbitrary
|
|
4
|
+
shell commands at lifecycle events. ``SessionStart`` fires during boot, so a
|
|
5
|
+
hostile repo is a workstation-compromise vector the moment the user runs
|
|
6
|
+
``cd <repo> && code-puppy``. The project ``hooks`` subtree is therefore
|
|
7
|
+
disabled until explicitly accepted via ``/hooks trust``.
|
|
8
|
+
|
|
9
|
+
The store lives user-side so a repo can never self-trust. Array order
|
|
10
|
+
survives canonicalization because hook execution order is semantic.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import hashlib
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import os
|
|
19
|
+
import tempfile
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Any, Dict, Optional
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
TRUST_STORE_FILE = Path.home() / ".code_puppy" / "trusted_hooks.json"
|
|
27
|
+
PROJECT_SETTINGS_RELPATH = Path(".claude") / "settings.json"
|
|
28
|
+
|
|
29
|
+
_STORE_VERSION = 1
|
|
30
|
+
|
|
31
|
+
TRUSTED = "trusted"
|
|
32
|
+
CHANGED = "changed"
|
|
33
|
+
UNTRUSTED = "untrusted"
|
|
34
|
+
|
|
35
|
+
REVOKED = "revoked"
|
|
36
|
+
NOT_TRUSTED = "not_trusted"
|
|
37
|
+
REVOKE_FAILED = "revoke_failed"
|
|
38
|
+
|
|
39
|
+
_WARNED: set[tuple[str, str]] = set()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ---------- discovery --------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_project_hooks_settings_file(
|
|
46
|
+
project_root: Optional[Path] = None,
|
|
47
|
+
) -> Optional[Path]:
|
|
48
|
+
"""Return ``<root>/.claude/settings.json`` if it exists, else ``None``.
|
|
49
|
+
|
|
50
|
+
Discovery is CWD-only — no ancestor walk — so the ceremony can't be
|
|
51
|
+
silently widened by a settings file in some parent directory.
|
|
52
|
+
"""
|
|
53
|
+
root = _resolved_root(project_root)
|
|
54
|
+
candidate = root / PROJECT_SETTINGS_RELPATH
|
|
55
|
+
try:
|
|
56
|
+
if not candidate.is_file():
|
|
57
|
+
return None
|
|
58
|
+
if candidate.is_symlink():
|
|
59
|
+
logger.warning(
|
|
60
|
+
"Refusing symlinked project hooks file %s — replace with a "
|
|
61
|
+
"real file to enable the trust ceremony.",
|
|
62
|
+
candidate,
|
|
63
|
+
)
|
|
64
|
+
return None
|
|
65
|
+
resolved = candidate.resolve()
|
|
66
|
+
if not _is_within(resolved, root):
|
|
67
|
+
logger.warning(
|
|
68
|
+
"Refusing project hooks file %s: resolves to %s, which is "
|
|
69
|
+
"outside the project root. A parent directory (typically "
|
|
70
|
+
"'.claude/') is likely a symlink. Replace with a real "
|
|
71
|
+
"in-project directory to enable the trust ceremony.",
|
|
72
|
+
candidate,
|
|
73
|
+
resolved,
|
|
74
|
+
)
|
|
75
|
+
return None
|
|
76
|
+
return candidate
|
|
77
|
+
except OSError: # pragma: no cover - exotic filesystem errors
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _is_within(path: Path, root: Path) -> bool:
|
|
82
|
+
"""True if *path* is *root* or lives beneath it. Both must be resolved."""
|
|
83
|
+
try:
|
|
84
|
+
return path.is_relative_to(root)
|
|
85
|
+
except AttributeError: # pragma: no cover - Python < 3.9
|
|
86
|
+
try:
|
|
87
|
+
path.relative_to(root)
|
|
88
|
+
return True
|
|
89
|
+
except ValueError:
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _resolved_root(project_root: Optional[Path]) -> Path:
|
|
94
|
+
"""Canonicalize the project root so a symlinked CWD and its real path
|
|
95
|
+
produce the same trust key."""
|
|
96
|
+
root = Path(project_root) if project_root is not None else Path.cwd()
|
|
97
|
+
try:
|
|
98
|
+
return root.resolve()
|
|
99
|
+
except OSError: # pragma: no cover - defensive
|
|
100
|
+
return root
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ---------- content hashing --------------------------------------------------
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _extract_hooks_subtree(settings_file: Path) -> Optional[Dict[str, Any]]:
|
|
107
|
+
"""Return the ``hooks`` subtree of *settings_file*, or ``None``. Never raises."""
|
|
108
|
+
try:
|
|
109
|
+
raw_bytes = Path(settings_file).read_bytes()
|
|
110
|
+
except OSError as exc:
|
|
111
|
+
logger.warning("Could not read project hooks file %s: %s", settings_file, exc)
|
|
112
|
+
return None
|
|
113
|
+
try:
|
|
114
|
+
raw = raw_bytes.decode("utf-8")
|
|
115
|
+
except UnicodeDecodeError as exc:
|
|
116
|
+
logger.warning("Non-UTF-8 project hooks file %s: %s", settings_file, exc)
|
|
117
|
+
return None
|
|
118
|
+
try:
|
|
119
|
+
data = json.loads(raw)
|
|
120
|
+
except json.JSONDecodeError as exc:
|
|
121
|
+
logger.warning("Invalid JSON in project hooks file %s: %s", settings_file, exc)
|
|
122
|
+
return None
|
|
123
|
+
if not isinstance(data, dict):
|
|
124
|
+
return None
|
|
125
|
+
subtree = data.get("hooks")
|
|
126
|
+
if not isinstance(subtree, dict):
|
|
127
|
+
return None
|
|
128
|
+
return subtree
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _has_effective_hooks(subtree: Dict[str, Any]) -> bool:
|
|
132
|
+
"""True iff *subtree* has a non-comment event entry.
|
|
133
|
+
|
|
134
|
+
``_``-prefixed keys are comments, matching the loader convention in
|
|
135
|
+
:mod:`.config`.
|
|
136
|
+
"""
|
|
137
|
+
return any(not key.startswith("_") for key in subtree)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def hash_subtree(subtree: Optional[Dict[str, Any]]) -> Optional[str]:
|
|
141
|
+
"""SHA-256 of the canonicalized subtree, or ``None`` if not effective.
|
|
142
|
+
|
|
143
|
+
Takes a pre-parsed subtree so the loader can hash the exact bytes it is
|
|
144
|
+
about to merge — re-reading the file would open a TOCTOU gap.
|
|
145
|
+
"""
|
|
146
|
+
if subtree is None or not _has_effective_hooks(subtree):
|
|
147
|
+
return None
|
|
148
|
+
canonical = json.dumps(subtree, sort_keys=True, separators=(",", ":"))
|
|
149
|
+
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def compute_hooks_config_hash(settings_file: Path) -> Optional[str]:
|
|
153
|
+
"""Hash the hooks subtree as it exists on disk right now.
|
|
154
|
+
|
|
155
|
+
Ceremony paths only. The loader must call :func:`hash_subtree` on an
|
|
156
|
+
already-parsed subtree to stay TOCTOU-safe.
|
|
157
|
+
"""
|
|
158
|
+
return hash_subtree(_extract_hooks_subtree(settings_file))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# ---------- trust store I/O --------------------------------------------------
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _project_key(project_root: Path) -> str:
|
|
165
|
+
return str(_resolved_root(project_root))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _load_store() -> dict:
|
|
169
|
+
"""Read the trust store, returning an empty store on any problem."""
|
|
170
|
+
try:
|
|
171
|
+
if TRUST_STORE_FILE.is_file():
|
|
172
|
+
data = json.loads(TRUST_STORE_FILE.read_text(encoding="utf-8"))
|
|
173
|
+
if isinstance(data, dict) and isinstance(data.get("projects"), dict):
|
|
174
|
+
return data
|
|
175
|
+
logger.warning(
|
|
176
|
+
"Malformed hooks trust store at %s — treating as empty",
|
|
177
|
+
TRUST_STORE_FILE,
|
|
178
|
+
)
|
|
179
|
+
except (OSError, json.JSONDecodeError, UnicodeDecodeError) as exc:
|
|
180
|
+
logger.warning("Could not read hooks trust store %s: %s", TRUST_STORE_FILE, exc)
|
|
181
|
+
return {"version": _STORE_VERSION, "projects": {}}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _save_store(store: dict) -> bool:
|
|
185
|
+
"""Persist the trust store atomically. Returns ``False`` on failure.
|
|
186
|
+
|
|
187
|
+
Written via tempfile + ``os.replace`` so a crash mid-write can't wipe
|
|
188
|
+
every project's trust.
|
|
189
|
+
"""
|
|
190
|
+
payload = json.dumps(store, indent=2, sort_keys=True)
|
|
191
|
+
tmp_path: Optional[str] = None
|
|
192
|
+
try:
|
|
193
|
+
TRUST_STORE_FILE.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
|
194
|
+
with tempfile.NamedTemporaryFile(
|
|
195
|
+
mode="w",
|
|
196
|
+
encoding="utf-8",
|
|
197
|
+
dir=str(TRUST_STORE_FILE.parent),
|
|
198
|
+
prefix=TRUST_STORE_FILE.name + ".",
|
|
199
|
+
suffix=".tmp",
|
|
200
|
+
delete=False,
|
|
201
|
+
) as handle:
|
|
202
|
+
handle.write(payload)
|
|
203
|
+
handle.flush()
|
|
204
|
+
os.fsync(handle.fileno())
|
|
205
|
+
tmp_path = handle.name
|
|
206
|
+
# This file decides whether shell commands run at boot, so keep it
|
|
207
|
+
# owner-only rather than whatever the umask allows.
|
|
208
|
+
os.chmod(tmp_path, 0o600)
|
|
209
|
+
os.replace(tmp_path, TRUST_STORE_FILE)
|
|
210
|
+
return True
|
|
211
|
+
except OSError as exc:
|
|
212
|
+
logger.error("Could not write hooks trust store %s: %s", TRUST_STORE_FILE, exc)
|
|
213
|
+
if tmp_path is not None:
|
|
214
|
+
try:
|
|
215
|
+
Path(tmp_path).unlink(missing_ok=True)
|
|
216
|
+
except OSError: # pragma: no cover - defensive
|
|
217
|
+
pass
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# ---------- trust queries / mutations ----------------------------------------
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def get_trust_status_for_hash(project_root: Path, current_hash: Optional[str]) -> str:
|
|
225
|
+
"""Compare a caller-provided hash to the store. TOCTOU-safe."""
|
|
226
|
+
store = _load_store()
|
|
227
|
+
entry = store["projects"].get(_project_key(project_root))
|
|
228
|
+
if not isinstance(entry, dict) or not entry.get("hash"):
|
|
229
|
+
return UNTRUSTED
|
|
230
|
+
if current_hash is not None and current_hash == entry["hash"]:
|
|
231
|
+
return TRUSTED
|
|
232
|
+
return CHANGED
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def get_trust_status(project_root: Path, settings_file: Path) -> str:
|
|
236
|
+
"""Trust status of *settings_file*, read from disk.
|
|
237
|
+
|
|
238
|
+
Ceremony paths only — the loader uses :func:`get_trust_status_for_hash`.
|
|
239
|
+
"""
|
|
240
|
+
return get_trust_status_for_hash(
|
|
241
|
+
project_root, compute_hooks_config_hash(settings_file)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def trust_project_hooks(project_root: Optional[Path] = None) -> bool:
|
|
246
|
+
"""Record acceptance of the current project's ``hooks`` subtree."""
|
|
247
|
+
root = _resolved_root(project_root)
|
|
248
|
+
settings_file = get_project_hooks_settings_file(root)
|
|
249
|
+
if settings_file is None:
|
|
250
|
+
return False
|
|
251
|
+
hooks_hash = compute_hooks_config_hash(settings_file)
|
|
252
|
+
if hooks_hash is None:
|
|
253
|
+
return False
|
|
254
|
+
store = _load_store()
|
|
255
|
+
store["projects"][_project_key(root)] = {
|
|
256
|
+
"hash": hooks_hash,
|
|
257
|
+
"accepted_at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
|
258
|
+
}
|
|
259
|
+
return _save_store(store)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def revoke_project_hooks(project_root: Optional[Path] = None) -> str:
|
|
263
|
+
"""Remove trust for the current project.
|
|
264
|
+
|
|
265
|
+
Returns :data:`REVOKED`, :data:`NOT_TRUSTED` (no entry to remove), or
|
|
266
|
+
:data:`REVOKE_FAILED` (entry exists but the store could not be written,
|
|
267
|
+
so the project is still trusted).
|
|
268
|
+
"""
|
|
269
|
+
root = _resolved_root(project_root)
|
|
270
|
+
store = _load_store()
|
|
271
|
+
key = _project_key(root)
|
|
272
|
+
if key not in store["projects"]:
|
|
273
|
+
return NOT_TRUSTED
|
|
274
|
+
del store["projects"][key]
|
|
275
|
+
return REVOKED if _save_store(store) else REVOKE_FAILED
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# ---------- boot / loader warning surface ------------------------------------
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def warn_untrusted_project_hooks(
|
|
282
|
+
project_root: Path, settings_file: Path, status: str
|
|
283
|
+
) -> None:
|
|
284
|
+
"""Emit a one-time warning about an unloaded project hooks file."""
|
|
285
|
+
key = (_project_key(project_root), status)
|
|
286
|
+
if key in _WARNED:
|
|
287
|
+
return
|
|
288
|
+
_WARNED.add(key)
|
|
289
|
+
|
|
290
|
+
# The legacy message_queue's startup buffer is never drained, so
|
|
291
|
+
# pre-renderer warnings emitted through it vanish silently.
|
|
292
|
+
try:
|
|
293
|
+
from code_puppy.messaging.bus import emit_warning
|
|
294
|
+
except Exception: # pragma: no cover - defensive during early boot
|
|
295
|
+
return
|
|
296
|
+
|
|
297
|
+
if status == CHANGED:
|
|
298
|
+
emit_warning(
|
|
299
|
+
f"Project hooks in '{settings_file}' have CHANGED since you "
|
|
300
|
+
"trusted them — they will NOT run. Review the changes and run "
|
|
301
|
+
"'/hooks trust accept' to re-enable."
|
|
302
|
+
)
|
|
303
|
+
else:
|
|
304
|
+
emit_warning(
|
|
305
|
+
f"Project hooks in '{settings_file}' are NOT trusted — they will "
|
|
306
|
+
"NOT run. Review them and run '/hooks trust accept' to enable "
|
|
307
|
+
"(project hooks can run arbitrary shell commands)."
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _reset_warning_cache() -> None:
|
|
312
|
+
"""Test hook."""
|
|
313
|
+
_WARNED.clear()
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def emit_untrusted_project_hooks_warning_if_any(
|
|
317
|
+
project_root: Optional[Path] = None,
|
|
318
|
+
) -> None:
|
|
319
|
+
"""Emit the untrusted-hooks warning, if any, for ``project_root``.
|
|
320
|
+
|
|
321
|
+
Called from the ``startup`` plugin callback rather than from
|
|
322
|
+
``load_hooks_config`` so the warning renders after boot output instead
|
|
323
|
+
of scrolling past above the banner.
|
|
324
|
+
"""
|
|
325
|
+
root = _resolved_root(project_root)
|
|
326
|
+
settings_file = get_project_hooks_settings_file(root)
|
|
327
|
+
if settings_file is None:
|
|
328
|
+
return
|
|
329
|
+
|
|
330
|
+
subtree = _extract_hooks_subtree(settings_file)
|
|
331
|
+
if subtree is None or not _has_effective_hooks(subtree):
|
|
332
|
+
return
|
|
333
|
+
|
|
334
|
+
current_hash = hash_subtree(subtree)
|
|
335
|
+
status = get_trust_status_for_hash(root, current_hash)
|
|
336
|
+
if status == TRUSTED:
|
|
337
|
+
return
|
|
338
|
+
|
|
339
|
+
warn_untrusted_project_hooks(root, settings_file, status)
|
|
@@ -24,13 +24,13 @@ HookSource = Literal["project", "global"]
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def _find_settings_path() -> Path:
|
|
27
|
-
"""Return the
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return cwd / _SETTINGS_FILENAME
|
|
27
|
+
"""Return the CWD's ``.claude/settings.json`` path.
|
|
28
|
+
|
|
29
|
+
Deliberately does not search ancestors. The executor only ever loads and
|
|
30
|
+
trust-gates the CWD's file, so returning a parent's settings here would
|
|
31
|
+
let the menu display and toggle hooks that can never actually run.
|
|
32
|
+
"""
|
|
33
|
+
return Path.cwd() / _SETTINGS_FILENAME
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def _load_global_hooks_config() -> Dict[str, Any]:
|
|
@@ -123,9 +123,33 @@ def save_hooks_config(hooks: Dict[str, Any]) -> Path:
|
|
|
123
123
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
124
124
|
path.write_text(json.dumps(existing, indent=2) + "\n", encoding="utf-8")
|
|
125
125
|
logger.debug("Saved hooks config to %s", path)
|
|
126
|
+
_reaccept_trust_after_user_write(path)
|
|
126
127
|
return path
|
|
127
128
|
|
|
128
129
|
|
|
130
|
+
def _reaccept_trust_after_user_write(path: Path) -> None:
|
|
131
|
+
"""Re-record trust after a user-initiated write to the project hooks file.
|
|
132
|
+
|
|
133
|
+
Menu actions like ``/hooks enable`` rewrite the hashed subtree (adding
|
|
134
|
+
``enabled`` keys), which would otherwise flip TRUSTED to CHANGED and
|
|
135
|
+
silently stop the very hooks the user just toggled. Only re-accepts a
|
|
136
|
+
project that was already trusted — an untrusted project stays untrusted,
|
|
137
|
+
so this can never grant trust the user did not give.
|
|
138
|
+
"""
|
|
139
|
+
from code_puppy_core_plugins.claude_code_hooks import trust as _trust
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
project_root = Path(os.getcwd()).resolve()
|
|
143
|
+
if path.resolve() != (project_root / _trust.PROJECT_SETTINGS_RELPATH):
|
|
144
|
+
return
|
|
145
|
+
store = _trust._load_store()
|
|
146
|
+
if _trust._project_key(project_root) not in store["projects"]:
|
|
147
|
+
return
|
|
148
|
+
_trust.trust_project_hooks(project_root)
|
|
149
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
150
|
+
logger.warning("Could not refresh hooks trust after save: %s", exc)
|
|
151
|
+
|
|
152
|
+
|
|
129
153
|
def save_global_hooks_config(hooks: Dict[str, Any]) -> Path:
|
|
130
154
|
"""Persist hooks config to ~/.code_puppy/hooks.json.
|
|
131
155
|
|
|
@@ -7,6 +7,7 @@ Provides:
|
|
|
7
7
|
/hooks enable – Enable all hooks (both global and project)
|
|
8
8
|
/hooks disable – Disable all hooks (both global and project)
|
|
9
9
|
/hooks status – Show summary counts per event type
|
|
10
|
+
/hooks trust – Preview / accept / revoke trust for project hooks
|
|
10
11
|
"""
|
|
11
12
|
|
|
12
13
|
import logging
|
|
@@ -32,6 +33,10 @@ def _hooks_command_help() -> List[Tuple[str, str]]:
|
|
|
32
33
|
"hooks",
|
|
33
34
|
"Manage Claude Code hooks (global + project) – browse, enable/disable, inspect",
|
|
34
35
|
),
|
|
36
|
+
(
|
|
37
|
+
"hooks trust",
|
|
38
|
+
"Preview / accept / revoke trust for project hooks from .claude/settings.json",
|
|
39
|
+
),
|
|
35
40
|
("hook", "Alias for /hooks"),
|
|
36
41
|
]
|
|
37
42
|
|
|
@@ -51,6 +56,7 @@ def _handle_hooks_command(command: str, name: str) -> Optional[Any]:
|
|
|
51
56
|
/hooks enable Enable every hook (both global and project)
|
|
52
57
|
/hooks disable Disable every hook (both global and project)
|
|
53
58
|
/hooks status Show counts per event type
|
|
59
|
+
/hooks trust Preview / accept / revoke trust for project hooks
|
|
54
60
|
"""
|
|
55
61
|
if name not in (_COMMAND_NAME, *_ALIASES):
|
|
56
62
|
return None # Not our command – pass through
|
|
@@ -69,6 +75,16 @@ def _handle_hooks_command(command: str, name: str) -> Optional[Any]:
|
|
|
69
75
|
tokens = command.split()
|
|
70
76
|
subcommand = tokens[1].lower() if len(tokens) > 1 else ""
|
|
71
77
|
|
|
78
|
+
# ----------------------------------------------------------------- trust
|
|
79
|
+
#
|
|
80
|
+
# Handled before the load/save-based branches below because the trust
|
|
81
|
+
# ceremony must work even when the project hooks file is currently
|
|
82
|
+
# untrusted (that is, in fact, its whole purpose).
|
|
83
|
+
if subcommand == "trust":
|
|
84
|
+
from .trust_handler import handle_trust_subcommand
|
|
85
|
+
|
|
86
|
+
return handle_trust_subcommand(tokens[2:])
|
|
87
|
+
|
|
72
88
|
# ------------------------------------------------------------------ list
|
|
73
89
|
if subcommand == "list":
|
|
74
90
|
entries = flatten_all_hooks()
|
|
@@ -208,7 +224,7 @@ def _handle_hooks_command(command: str, name: str) -> Optional[Any]:
|
|
|
208
224
|
# ----------------------------------------------- unknown sub-command
|
|
209
225
|
if subcommand and subcommand not in ("", "tui"):
|
|
210
226
|
emit_error(f"Unknown sub-command: {subcommand}")
|
|
211
|
-
emit_info("Usage: /hooks [list|enable|disable|status]")
|
|
227
|
+
emit_info("Usage: /hooks [list|enable|disable|status|trust]")
|
|
212
228
|
return True
|
|
213
229
|
# --------------------------------------------------- default: TUI menu
|
|
214
230
|
from .hooks_menu import show_hooks_menu
|