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.
Files changed (341) hide show
  1. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/PKG-INFO +1 -1
  2. {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
  3. {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
  4. code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/claude_code_hooks/trust.py +339 -0
  5. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_manager/config.py +31 -7
  6. {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
  7. code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/hook_manager/trust_handler.py +185 -0
  8. code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/session_namer/__init__.py +1 -0
  9. code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/session_namer/namer.py +255 -0
  10. code_puppy_core_plugins-0.0.18/code_puppy_core_plugins/session_namer/register_callbacks.py +86 -0
  11. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/pyproject.toml +2 -1
  12. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/.gitignore +0 -0
  13. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/LICENSE +0 -0
  14. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/README.md +0 -0
  15. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/__init__.py +0 -0
  16. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/README.md +0 -0
  17. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/__init__.py +0 -0
  18. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/agent.py +0 -0
  19. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/bridge.py +0 -0
  20. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/capabilities.py +0 -0
  21. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/commands.py +0 -0
  22. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/content.py +0 -0
  23. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/io_delegation.py +0 -0
  24. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/mcp_config.py +0 -0
  25. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/permissions.py +0 -0
  26. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/persistence.py +0 -0
  27. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/register_callbacks.py +0 -0
  28. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/replay.py +0 -0
  29. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/session.py +0 -0
  30. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/session_config.py +0 -0
  31. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/acp/state.py +0 -0
  32. {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
  33. {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
  34. {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
  35. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/__init__.py +0 -0
  36. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/config.py +0 -0
  37. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/discovery.py +0 -0
  38. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/downloader.py +0 -0
  39. {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
  40. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/installer.py +0 -0
  41. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/metadata.py +0 -0
  42. {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
  43. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/agent_skills/provider.py +0 -0
  44. {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
  45. {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
  46. {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
  47. {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
  48. {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
  49. {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
  50. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/aws_bedrock/__init__.py +0 -0
  51. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/aws_bedrock/config.py +0 -0
  52. {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
  53. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/aws_bedrock/utils.py +0 -0
  54. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/README.md +0 -0
  55. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/__init__.py +0 -0
  56. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/config.py +0 -0
  57. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/discovery.py +0 -0
  58. {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
  59. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/token.py +0 -0
  60. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/azure_foundry/utils.py +0 -0
  61. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/__init__.py +0 -0
  62. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/inline_view.py +0 -0
  63. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/register_callbacks.py +0 -0
  64. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/btw/side_query.py +0 -0
  65. {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
  66. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/__init__.py +0 -0
  67. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/config.py +0 -0
  68. {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
  69. {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
  70. {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
  71. {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
  72. {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
  73. {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
  74. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/usage.py +0 -0
  75. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/chatgpt_oauth/utils.py +0 -0
  76. {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
  77. {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
  78. {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
  79. {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
  80. {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
  81. {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
  82. {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
  83. {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
  84. {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
  85. {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
  86. {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
  87. {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
  88. {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
  89. {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
  90. {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
  91. {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
  92. {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
  93. {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
  94. {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
  95. {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
  96. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/NativeCapture.swift +0 -0
  97. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/README.md +0 -0
  98. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/__init__.py +0 -0
  99. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/accessibility.py +0 -0
  100. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/activation.py +0 -0
  101. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/backend.py +0 -0
  102. {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
  103. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/capture.py +0 -0
  104. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/commands.py +0 -0
  105. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/geometry.py +0 -0
  106. {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
  107. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/keycodes.py +0 -0
  108. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/policy.py +0 -0
  109. {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
  110. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/safety.py +0 -0
  111. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/settle.py +0 -0
  112. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/state.py +0 -0
  113. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/computer_use/tools.py +0 -0
  114. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/context_indicator/__init__.py +0 -0
  115. {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
  116. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/context_indicator/usage.py +0 -0
  117. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/__init__.py +0 -0
  118. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/config.py +0 -0
  119. {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
  120. {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
  121. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/copilot_auth/utils.py +0 -0
  122. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/customizable_commands/__init__.py +0 -0
  123. {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
  124. {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
  125. {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
  126. {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
  127. {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
  128. {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
  129. {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
  130. {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
  131. {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
  132. {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
  133. {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
  134. {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
  135. {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
  136. {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
  137. {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
  138. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/emoji_filter/__init__.py +0 -0
  139. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/emoji_filter/config.py +0 -0
  140. {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
  141. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/emoji_filter/stripper.py +0 -0
  142. {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
  143. {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
  144. {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
  145. {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
  146. {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
  147. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/__init__.py +0 -0
  148. {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
  149. {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
  150. {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
  151. {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
  152. {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
  153. {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
  154. {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
  155. {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
  156. {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
  157. {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
  158. {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
  159. {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
  160. {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
  161. {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
  162. {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
  163. {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
  164. {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
  165. {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
  166. {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
  167. {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
  168. {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
  169. {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
  170. {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
  171. {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
  172. {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
  173. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/flux_bootstrap/installer.py +0 -0
  174. {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
  175. {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
  176. {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
  177. {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
  178. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/fork/__init__.py +0 -0
  179. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/fork/register_callbacks.py +0 -0
  180. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/frontend_emitter/__init__.py +0 -0
  181. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/frontend_emitter/emitter.py +0 -0
  182. {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
  183. {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
  184. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/__init__.py +0 -0
  185. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/config.py +0 -0
  186. {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
  187. {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
  188. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/grok_oauth/utils.py +0 -0
  189. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/README.md +0 -0
  190. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/__init__.py +0 -0
  191. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/client.py +0 -0
  192. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/register_callbacks.py +0 -0
  193. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/reporter.py +0 -0
  194. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/smoke.py +0 -0
  195. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/herdr/sources.py +0 -0
  196. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_creator/__init__.py +0 -0
  197. {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
  198. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/hook_manager/__init__.py +0 -0
  199. {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
  200. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_oauth/__init__.py +0 -0
  201. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_oauth/oauth.py +0 -0
  202. {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
  203. {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
  204. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/__init__.py +0 -0
  205. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/mirror.py +0 -0
  206. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/query.py +0 -0
  207. {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
  208. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/logfire_sessions/sync.py +0 -0
  209. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/__init__.py +0 -0
  210. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/config.py +0 -0
  211. {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
  212. {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
  213. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/meta_oauth/utils.py +0 -0
  214. {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
  215. {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
  216. {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
  217. {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
  218. {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
  219. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/no_tools/__init__.py +0 -0
  220. {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
  221. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/oauth_pasteback.py +0 -0
  222. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/oauth_puppy_html.py +0 -0
  223. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/obsidian_agent/README.md +0 -0
  224. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/obsidian_agent/__init__.py +0 -0
  225. {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
  226. {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
  227. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama/__init__.py +0 -0
  228. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama/register_callbacks.py +0 -0
  229. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama_setup/__init__.py +0 -0
  230. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/ollama_setup/completer.py +0 -0
  231. {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
  232. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/plugin_list/__init__.py +0 -0
  233. {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
  234. {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
  235. {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
  236. {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
  237. {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
  238. {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
  239. {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
  240. {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
  241. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/pop_command/__init__.py +0 -0
  242. {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
  243. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prompt_newline/__init__.py +0 -0
  244. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prompt_newline/config.py +0 -0
  245. {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
  246. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/__init__.py +0 -0
  247. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/prune_menu.py +0 -0
  248. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/prune_model.py +0 -0
  249. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/prune_render.py +0 -0
  250. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/prune/register_callbacks.py +0 -0
  251. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/README.md +0 -0
  252. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/__init__.py +0 -0
  253. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/commands.py +0 -0
  254. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/config.py +0 -0
  255. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/kennel.py +0 -0
  256. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/packer.py +0 -0
  257. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/recorder.py +0 -0
  258. {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
  259. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/retriever.py +0 -0
  260. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/schema.py +0 -0
  261. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/state.py +0 -0
  262. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/tools.py +0 -0
  263. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_kennel/wings.py +0 -0
  264. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/README.md +0 -0
  265. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/__init__.py +0 -0
  266. {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
  267. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/commands.py +0 -0
  268. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/picker.py +0 -0
  269. {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
  270. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/puppy_spinner/spinners.py +0 -0
  271. {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
  272. {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
  273. {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
  274. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/quick_resume/__init__.py +0 -0
  275. {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
  276. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/review_pr/__init__.py +0 -0
  277. {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
  278. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/shell_safety/__init__.py +0 -0
  279. {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
  280. {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
  281. {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
  282. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/LICENSE.deepseek +0 -0
  283. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/__init__.py +0 -0
  284. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/register_callbacks.py +0 -0
  285. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/spill/store.py +0 -0
  286. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/stack_dump/__init__.py +0 -0
  287. {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
  288. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/__init__.py +0 -0
  289. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/config.py +0 -0
  290. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/payload.py +0 -0
  291. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/prompt_patch.py +0 -0
  292. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/register_callbacks.py +0 -0
  293. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/runner.py +0 -0
  294. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/statusline/statusline_command.py +0 -0
  295. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/steer_queue/__init__.py +0 -0
  296. {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
  297. {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
  298. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/README.md +0 -0
  299. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/__init__.py +0 -0
  300. {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
  301. {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
  302. {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
  303. {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
  304. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/subagent_panel/state.py +0 -0
  305. {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
  306. {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
  307. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/README.md +0 -0
  308. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/__init__.py +0 -0
  309. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/bundled_palettes.py +0 -0
  310. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/content_styles.py +0 -0
  311. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/osc_palette.py +0 -0
  312. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/picker.py +0 -0
  313. {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
  314. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/register_callbacks.py +0 -0
  315. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/rich_themes.py +0 -0
  316. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/theme/themes.py +0 -0
  317. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/timestamp_heartbeat/__init__.py +0 -0
  318. {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
  319. {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
  320. {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
  321. {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
  322. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/__init__.py +0 -0
  323. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/models.py +0 -0
  324. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/provider.py +0 -0
  325. {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
  326. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/registry.py +0 -0
  327. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/universal_constructor/sandbox.py +0 -0
  328. {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
  329. {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
  330. {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
  331. {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
  332. {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
  333. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/__init__.py +0 -0
  334. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/goal_runs.py +0 -0
  335. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/judge.py +0 -0
  336. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/judge_config.py +0 -0
  337. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/judges_menu.py +0 -0
  338. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/register_callbacks.py +0 -0
  339. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/wiggum/state.py +0 -0
  340. {code_puppy_core_plugins-0.0.16 → code_puppy_core_plugins-0.0.18}/code_puppy_core_plugins/yolo_cli/__init__.py +0 -0
  341. {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.16
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
- # Load and merge project-level hooks
98
- project_config_path = Path(os.getcwd()) / PROJECT_HOOKS_FILE
99
-
100
- if project_config_path.exists():
101
- try:
102
- with open(project_config_path, "r", encoding="utf-8") as f:
103
- config = json.load(f)
104
- hooks_config = config.get("hooks")
105
- if hooks_config:
106
- logger.info(f"Merging hooks configuration from {project_config_path}")
107
- merged_config = _deep_merge_hooks(merged_config, hooks_config)
108
- else:
109
- logger.debug(f"No 'hooks' section found in {project_config_path}")
110
- except json.JSONDecodeError as e:
111
- logger.error(f"Invalid JSON in {project_config_path}: {e}")
112
- except Exception as e:
113
- logger.error(f"Failed to load {project_config_path}: {e}", exc_info=True)
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 path to .claude/settings.json, searching from cwd upward."""
28
- cwd = Path.cwd()
29
- for parent in [cwd, *cwd.parents]:
30
- candidate = parent / _SETTINGS_FILENAME
31
- if candidate.exists():
32
- return candidate
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