codepp 0.0.437__py3-none-any.whl

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 (288) hide show
  1. code_puppy/__init__.py +10 -0
  2. code_puppy/__main__.py +10 -0
  3. code_puppy/agents/__init__.py +31 -0
  4. code_puppy/agents/agent_c_reviewer.py +155 -0
  5. code_puppy/agents/agent_code_puppy.py +117 -0
  6. code_puppy/agents/agent_code_reviewer.py +90 -0
  7. code_puppy/agents/agent_cpp_reviewer.py +132 -0
  8. code_puppy/agents/agent_creator_agent.py +638 -0
  9. code_puppy/agents/agent_golang_reviewer.py +151 -0
  10. code_puppy/agents/agent_helios.py +124 -0
  11. code_puppy/agents/agent_javascript_reviewer.py +160 -0
  12. code_puppy/agents/agent_manager.py +742 -0
  13. code_puppy/agents/agent_pack_leader.py +385 -0
  14. code_puppy/agents/agent_planning.py +165 -0
  15. code_puppy/agents/agent_python_programmer.py +169 -0
  16. code_puppy/agents/agent_python_reviewer.py +90 -0
  17. code_puppy/agents/agent_qa_expert.py +163 -0
  18. code_puppy/agents/agent_qa_kitten.py +208 -0
  19. code_puppy/agents/agent_scheduler.py +121 -0
  20. code_puppy/agents/agent_security_auditor.py +181 -0
  21. code_puppy/agents/agent_terminal_qa.py +323 -0
  22. code_puppy/agents/agent_typescript_reviewer.py +166 -0
  23. code_puppy/agents/base_agent.py +2156 -0
  24. code_puppy/agents/event_stream_handler.py +348 -0
  25. code_puppy/agents/json_agent.py +202 -0
  26. code_puppy/agents/pack/__init__.py +34 -0
  27. code_puppy/agents/pack/bloodhound.py +304 -0
  28. code_puppy/agents/pack/husky.py +327 -0
  29. code_puppy/agents/pack/retriever.py +393 -0
  30. code_puppy/agents/pack/shepherd.py +348 -0
  31. code_puppy/agents/pack/terrier.py +287 -0
  32. code_puppy/agents/pack/watchdog.py +367 -0
  33. code_puppy/agents/prompt_reviewer.py +145 -0
  34. code_puppy/agents/subagent_stream_handler.py +276 -0
  35. code_puppy/api/__init__.py +13 -0
  36. code_puppy/api/app.py +169 -0
  37. code_puppy/api/main.py +21 -0
  38. code_puppy/api/pty_manager.py +453 -0
  39. code_puppy/api/routers/__init__.py +12 -0
  40. code_puppy/api/routers/agents.py +36 -0
  41. code_puppy/api/routers/commands.py +217 -0
  42. code_puppy/api/routers/config.py +75 -0
  43. code_puppy/api/routers/sessions.py +234 -0
  44. code_puppy/api/templates/terminal.html +361 -0
  45. code_puppy/api/websocket.py +154 -0
  46. code_puppy/callbacks.py +692 -0
  47. code_puppy/chatgpt_codex_client.py +338 -0
  48. code_puppy/claude_cache_client.py +672 -0
  49. code_puppy/cli_runner.py +1073 -0
  50. code_puppy/command_line/__init__.py +1 -0
  51. code_puppy/command_line/add_model_menu.py +1092 -0
  52. code_puppy/command_line/agent_menu.py +662 -0
  53. code_puppy/command_line/attachments.py +395 -0
  54. code_puppy/command_line/autosave_menu.py +704 -0
  55. code_puppy/command_line/clipboard.py +527 -0
  56. code_puppy/command_line/colors_menu.py +532 -0
  57. code_puppy/command_line/command_handler.py +293 -0
  58. code_puppy/command_line/command_registry.py +150 -0
  59. code_puppy/command_line/config_commands.py +719 -0
  60. code_puppy/command_line/core_commands.py +867 -0
  61. code_puppy/command_line/diff_menu.py +865 -0
  62. code_puppy/command_line/file_path_completion.py +73 -0
  63. code_puppy/command_line/load_context_completion.py +52 -0
  64. code_puppy/command_line/mcp/__init__.py +10 -0
  65. code_puppy/command_line/mcp/base.py +32 -0
  66. code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
  67. code_puppy/command_line/mcp/custom_server_form.py +688 -0
  68. code_puppy/command_line/mcp/custom_server_installer.py +195 -0
  69. code_puppy/command_line/mcp/edit_command.py +148 -0
  70. code_puppy/command_line/mcp/handler.py +138 -0
  71. code_puppy/command_line/mcp/help_command.py +147 -0
  72. code_puppy/command_line/mcp/install_command.py +214 -0
  73. code_puppy/command_line/mcp/install_menu.py +705 -0
  74. code_puppy/command_line/mcp/list_command.py +94 -0
  75. code_puppy/command_line/mcp/logs_command.py +235 -0
  76. code_puppy/command_line/mcp/remove_command.py +82 -0
  77. code_puppy/command_line/mcp/restart_command.py +100 -0
  78. code_puppy/command_line/mcp/search_command.py +123 -0
  79. code_puppy/command_line/mcp/start_all_command.py +135 -0
  80. code_puppy/command_line/mcp/start_command.py +117 -0
  81. code_puppy/command_line/mcp/status_command.py +184 -0
  82. code_puppy/command_line/mcp/stop_all_command.py +112 -0
  83. code_puppy/command_line/mcp/stop_command.py +80 -0
  84. code_puppy/command_line/mcp/test_command.py +107 -0
  85. code_puppy/command_line/mcp/utils.py +129 -0
  86. code_puppy/command_line/mcp/wizard_utils.py +334 -0
  87. code_puppy/command_line/mcp_completion.py +174 -0
  88. code_puppy/command_line/model_picker_completion.py +197 -0
  89. code_puppy/command_line/model_settings_menu.py +932 -0
  90. code_puppy/command_line/motd.py +96 -0
  91. code_puppy/command_line/onboarding_slides.py +179 -0
  92. code_puppy/command_line/onboarding_wizard.py +342 -0
  93. code_puppy/command_line/pin_command_completion.py +329 -0
  94. code_puppy/command_line/prompt_toolkit_completion.py +846 -0
  95. code_puppy/command_line/session_commands.py +302 -0
  96. code_puppy/command_line/shell_passthrough.py +145 -0
  97. code_puppy/command_line/skills_completion.py +160 -0
  98. code_puppy/command_line/uc_menu.py +893 -0
  99. code_puppy/command_line/utils.py +93 -0
  100. code_puppy/command_line/wiggum_state.py +78 -0
  101. code_puppy/config.py +1770 -0
  102. code_puppy/error_logging.py +134 -0
  103. code_puppy/gemini_code_assist.py +385 -0
  104. code_puppy/gemini_model.py +754 -0
  105. code_puppy/hook_engine/README.md +105 -0
  106. code_puppy/hook_engine/__init__.py +21 -0
  107. code_puppy/hook_engine/aliases.py +155 -0
  108. code_puppy/hook_engine/engine.py +221 -0
  109. code_puppy/hook_engine/executor.py +296 -0
  110. code_puppy/hook_engine/matcher.py +156 -0
  111. code_puppy/hook_engine/models.py +240 -0
  112. code_puppy/hook_engine/registry.py +106 -0
  113. code_puppy/hook_engine/validator.py +144 -0
  114. code_puppy/http_utils.py +361 -0
  115. code_puppy/keymap.py +128 -0
  116. code_puppy/main.py +10 -0
  117. code_puppy/mcp_/__init__.py +66 -0
  118. code_puppy/mcp_/async_lifecycle.py +286 -0
  119. code_puppy/mcp_/blocking_startup.py +469 -0
  120. code_puppy/mcp_/captured_stdio_server.py +275 -0
  121. code_puppy/mcp_/circuit_breaker.py +290 -0
  122. code_puppy/mcp_/config_wizard.py +507 -0
  123. code_puppy/mcp_/dashboard.py +308 -0
  124. code_puppy/mcp_/error_isolation.py +407 -0
  125. code_puppy/mcp_/examples/retry_example.py +226 -0
  126. code_puppy/mcp_/health_monitor.py +589 -0
  127. code_puppy/mcp_/managed_server.py +428 -0
  128. code_puppy/mcp_/manager.py +807 -0
  129. code_puppy/mcp_/mcp_logs.py +224 -0
  130. code_puppy/mcp_/registry.py +451 -0
  131. code_puppy/mcp_/retry_manager.py +337 -0
  132. code_puppy/mcp_/server_registry_catalog.py +1126 -0
  133. code_puppy/mcp_/status_tracker.py +355 -0
  134. code_puppy/mcp_/system_tools.py +209 -0
  135. code_puppy/mcp_prompts/__init__.py +1 -0
  136. code_puppy/mcp_prompts/hook_creator.py +103 -0
  137. code_puppy/messaging/__init__.py +255 -0
  138. code_puppy/messaging/bus.py +613 -0
  139. code_puppy/messaging/commands.py +167 -0
  140. code_puppy/messaging/markdown_patches.py +57 -0
  141. code_puppy/messaging/message_queue.py +361 -0
  142. code_puppy/messaging/messages.py +569 -0
  143. code_puppy/messaging/queue_console.py +271 -0
  144. code_puppy/messaging/renderers.py +311 -0
  145. code_puppy/messaging/rich_renderer.py +1158 -0
  146. code_puppy/messaging/spinner/__init__.py +83 -0
  147. code_puppy/messaging/spinner/console_spinner.py +240 -0
  148. code_puppy/messaging/spinner/spinner_base.py +95 -0
  149. code_puppy/messaging/subagent_console.py +460 -0
  150. code_puppy/model_factory.py +848 -0
  151. code_puppy/model_switching.py +63 -0
  152. code_puppy/model_utils.py +168 -0
  153. code_puppy/models.json +174 -0
  154. code_puppy/models_dev_api.json +1 -0
  155. code_puppy/models_dev_parser.py +592 -0
  156. code_puppy/plugins/__init__.py +186 -0
  157. code_puppy/plugins/agent_skills/__init__.py +22 -0
  158. code_puppy/plugins/agent_skills/config.py +175 -0
  159. code_puppy/plugins/agent_skills/discovery.py +136 -0
  160. code_puppy/plugins/agent_skills/downloader.py +392 -0
  161. code_puppy/plugins/agent_skills/installer.py +22 -0
  162. code_puppy/plugins/agent_skills/metadata.py +219 -0
  163. code_puppy/plugins/agent_skills/prompt_builder.py +60 -0
  164. code_puppy/plugins/agent_skills/register_callbacks.py +241 -0
  165. code_puppy/plugins/agent_skills/remote_catalog.py +322 -0
  166. code_puppy/plugins/agent_skills/skill_catalog.py +257 -0
  167. code_puppy/plugins/agent_skills/skills_install_menu.py +664 -0
  168. code_puppy/plugins/agent_skills/skills_menu.py +781 -0
  169. code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
  170. code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
  171. code_puppy/plugins/antigravity_oauth/antigravity_model.py +706 -0
  172. code_puppy/plugins/antigravity_oauth/config.py +42 -0
  173. code_puppy/plugins/antigravity_oauth/constants.py +133 -0
  174. code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
  175. code_puppy/plugins/antigravity_oauth/register_callbacks.py +518 -0
  176. code_puppy/plugins/antigravity_oauth/storage.py +288 -0
  177. code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
  178. code_puppy/plugins/antigravity_oauth/token.py +167 -0
  179. code_puppy/plugins/antigravity_oauth/transport.py +863 -0
  180. code_puppy/plugins/antigravity_oauth/utils.py +168 -0
  181. code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
  182. code_puppy/plugins/chatgpt_oauth/config.py +52 -0
  183. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +329 -0
  184. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +176 -0
  185. code_puppy/plugins/chatgpt_oauth/test_plugin.py +301 -0
  186. code_puppy/plugins/chatgpt_oauth/utils.py +523 -0
  187. code_puppy/plugins/claude_code_hooks/__init__.py +1 -0
  188. code_puppy/plugins/claude_code_hooks/config.py +137 -0
  189. code_puppy/plugins/claude_code_hooks/register_callbacks.py +175 -0
  190. code_puppy/plugins/claude_code_oauth/README.md +167 -0
  191. code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
  192. code_puppy/plugins/claude_code_oauth/__init__.py +25 -0
  193. code_puppy/plugins/claude_code_oauth/config.py +52 -0
  194. code_puppy/plugins/claude_code_oauth/register_callbacks.py +453 -0
  195. code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
  196. code_puppy/plugins/claude_code_oauth/token_refresh_heartbeat.py +241 -0
  197. code_puppy/plugins/claude_code_oauth/utils.py +640 -0
  198. code_puppy/plugins/customizable_commands/__init__.py +0 -0
  199. code_puppy/plugins/customizable_commands/register_callbacks.py +152 -0
  200. code_puppy/plugins/example_custom_command/README.md +280 -0
  201. code_puppy/plugins/example_custom_command/register_callbacks.py +51 -0
  202. code_puppy/plugins/file_permission_handler/__init__.py +4 -0
  203. code_puppy/plugins/file_permission_handler/register_callbacks.py +470 -0
  204. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  205. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  206. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  207. code_puppy/plugins/hook_creator/__init__.py +1 -0
  208. code_puppy/plugins/hook_creator/register_callbacks.py +33 -0
  209. code_puppy/plugins/hook_manager/__init__.py +1 -0
  210. code_puppy/plugins/hook_manager/config.py +290 -0
  211. code_puppy/plugins/hook_manager/hooks_menu.py +564 -0
  212. code_puppy/plugins/hook_manager/register_callbacks.py +227 -0
  213. code_puppy/plugins/oauth_puppy_html.py +228 -0
  214. code_puppy/plugins/scheduler/__init__.py +1 -0
  215. code_puppy/plugins/scheduler/register_callbacks.py +88 -0
  216. code_puppy/plugins/scheduler/scheduler_menu.py +522 -0
  217. code_puppy/plugins/scheduler/scheduler_wizard.py +341 -0
  218. code_puppy/plugins/shell_safety/__init__.py +6 -0
  219. code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
  220. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  221. code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
  222. code_puppy/plugins/synthetic_status/__init__.py +1 -0
  223. code_puppy/plugins/synthetic_status/register_callbacks.py +132 -0
  224. code_puppy/plugins/synthetic_status/status_api.py +147 -0
  225. code_puppy/plugins/universal_constructor/__init__.py +13 -0
  226. code_puppy/plugins/universal_constructor/models.py +138 -0
  227. code_puppy/plugins/universal_constructor/register_callbacks.py +47 -0
  228. code_puppy/plugins/universal_constructor/registry.py +302 -0
  229. code_puppy/plugins/universal_constructor/sandbox.py +584 -0
  230. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  231. code_puppy/pydantic_patches.py +356 -0
  232. code_puppy/reopenable_async_client.py +232 -0
  233. code_puppy/round_robin_model.py +150 -0
  234. code_puppy/scheduler/__init__.py +41 -0
  235. code_puppy/scheduler/__main__.py +9 -0
  236. code_puppy/scheduler/cli.py +118 -0
  237. code_puppy/scheduler/config.py +126 -0
  238. code_puppy/scheduler/daemon.py +280 -0
  239. code_puppy/scheduler/executor.py +155 -0
  240. code_puppy/scheduler/platform.py +19 -0
  241. code_puppy/scheduler/platform_unix.py +22 -0
  242. code_puppy/scheduler/platform_win.py +32 -0
  243. code_puppy/session_storage.py +338 -0
  244. code_puppy/status_display.py +257 -0
  245. code_puppy/summarization_agent.py +176 -0
  246. code_puppy/terminal_utils.py +418 -0
  247. code_puppy/tools/__init__.py +501 -0
  248. code_puppy/tools/agent_tools.py +603 -0
  249. code_puppy/tools/ask_user_question/__init__.py +26 -0
  250. code_puppy/tools/ask_user_question/constants.py +73 -0
  251. code_puppy/tools/ask_user_question/demo_tui.py +55 -0
  252. code_puppy/tools/ask_user_question/handler.py +232 -0
  253. code_puppy/tools/ask_user_question/models.py +304 -0
  254. code_puppy/tools/ask_user_question/registration.py +26 -0
  255. code_puppy/tools/ask_user_question/renderers.py +309 -0
  256. code_puppy/tools/ask_user_question/terminal_ui.py +329 -0
  257. code_puppy/tools/ask_user_question/theme.py +155 -0
  258. code_puppy/tools/ask_user_question/tui_loop.py +423 -0
  259. code_puppy/tools/browser/__init__.py +37 -0
  260. code_puppy/tools/browser/browser_control.py +289 -0
  261. code_puppy/tools/browser/browser_interactions.py +545 -0
  262. code_puppy/tools/browser/browser_locators.py +640 -0
  263. code_puppy/tools/browser/browser_manager.py +378 -0
  264. code_puppy/tools/browser/browser_navigation.py +251 -0
  265. code_puppy/tools/browser/browser_screenshot.py +179 -0
  266. code_puppy/tools/browser/browser_scripts.py +462 -0
  267. code_puppy/tools/browser/browser_workflows.py +221 -0
  268. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  269. code_puppy/tools/browser/terminal_command_tools.py +534 -0
  270. code_puppy/tools/browser/terminal_screenshot_tools.py +552 -0
  271. code_puppy/tools/browser/terminal_tools.py +525 -0
  272. code_puppy/tools/command_runner.py +1346 -0
  273. code_puppy/tools/common.py +1409 -0
  274. code_puppy/tools/display.py +84 -0
  275. code_puppy/tools/file_modifications.py +886 -0
  276. code_puppy/tools/file_operations.py +802 -0
  277. code_puppy/tools/scheduler_tools.py +412 -0
  278. code_puppy/tools/skills_tools.py +244 -0
  279. code_puppy/tools/subagent_context.py +158 -0
  280. code_puppy/tools/tools_content.py +51 -0
  281. code_puppy/tools/universal_constructor.py +889 -0
  282. code_puppy/uvx_detection.py +242 -0
  283. code_puppy/version_checker.py +82 -0
  284. codepp-0.0.437.dist-info/METADATA +766 -0
  285. codepp-0.0.437.dist-info/RECORD +288 -0
  286. codepp-0.0.437.dist-info/WHEEL +4 -0
  287. codepp-0.0.437.dist-info/entry_points.txt +3 -0
  288. codepp-0.0.437.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,175 @@
1
+ """
2
+ Register callbacks for Claude Code hooks plugin.
3
+
4
+ Integrates the hook engine with code_puppy's callback system.
5
+ """
6
+
7
+ import logging
8
+ from typing import Any, Dict, Optional
9
+
10
+ from code_puppy.callbacks import register_callback
11
+ from code_puppy.hook_engine import EventData, HookEngine
12
+
13
+ from .config import load_hooks_config
14
+
15
+ _SUBAGENT_NAMES = frozenset(
16
+ {
17
+ "pack_leader",
18
+ "bloodhound",
19
+ "husky",
20
+ "retriever",
21
+ "shepherd",
22
+ "terrier",
23
+ "watchdog",
24
+ "subagent",
25
+ "sub_agent",
26
+ }
27
+ )
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+ _hook_engine: Optional[HookEngine] = None
32
+
33
+
34
+ def _initialize_engine() -> Optional[HookEngine]:
35
+ config = load_hooks_config()
36
+
37
+ if not config:
38
+ logger.info("No hooks configuration found - Claude Code hooks disabled")
39
+ return None
40
+
41
+ try:
42
+ engine = HookEngine(config, strict_validation=False)
43
+ stats = engine.get_stats()
44
+ logger.info(
45
+ f"Hook engine ready - Total: {stats['total_hooks']}, "
46
+ f"Enabled: {stats['enabled_hooks']}"
47
+ )
48
+ return engine
49
+ except Exception as e:
50
+ logger.error(f"Failed to initialize hook engine: {e}", exc_info=True)
51
+ return None
52
+
53
+
54
+ _hook_engine = _initialize_engine()
55
+
56
+
57
+ async def on_pre_tool_call_hook(
58
+ tool_name: str,
59
+ tool_args: Dict[str, Any],
60
+ context: Any = None,
61
+ ) -> Optional[Dict[str, Any]]:
62
+ """Pre-tool callback — executes hooks before tool runs. Can block."""
63
+ if not _hook_engine:
64
+ return None
65
+
66
+ event_data = EventData(
67
+ event_type="PreToolUse",
68
+ tool_name=tool_name,
69
+ tool_args=tool_args,
70
+ context={"context": context} if context else {},
71
+ )
72
+
73
+ try:
74
+ result = await _hook_engine.process_event("PreToolUse", event_data)
75
+
76
+ if result.blocked:
77
+ logger.debug(
78
+ f"Tool '{tool_name}' blocked by hook: {result.blocking_reason}"
79
+ )
80
+ return {
81
+ "blocked": True,
82
+ "reason": result.blocking_reason,
83
+ "error_message": result.blocking_reason,
84
+ }
85
+ return None
86
+ except Exception as e:
87
+ logger.error(f"Error in pre-tool hook: {e}", exc_info=True)
88
+ return None
89
+
90
+
91
+ async def on_post_tool_call_hook(
92
+ tool_name: str,
93
+ tool_args: Dict[str, Any],
94
+ result: Any,
95
+ duration_ms: float,
96
+ context: Any = None,
97
+ ) -> None:
98
+ """Post-tool callback — executes hooks after tool completes (observation only)."""
99
+ if not _hook_engine:
100
+ return
101
+
102
+ event_data = EventData(
103
+ event_type="PostToolUse",
104
+ tool_name=tool_name,
105
+ tool_args=tool_args,
106
+ context={"result": result, "duration_ms": duration_ms, "context": context},
107
+ )
108
+
109
+ try:
110
+ await _hook_engine.process_event("PostToolUse", event_data)
111
+ except Exception as e:
112
+ logger.error(f"Error in post-tool hook: {e}", exc_info=True)
113
+
114
+
115
+ register_callback("pre_tool_call", on_pre_tool_call_hook)
116
+ register_callback("post_tool_call", on_post_tool_call_hook)
117
+
118
+
119
+ async def on_startup_hook() -> None:
120
+ """Startup callback — fires SessionStart hooks when code_puppy boots."""
121
+ if not _hook_engine:
122
+ return
123
+
124
+ event_data = EventData(
125
+ event_type="SessionStart",
126
+ tool_name="session",
127
+ tool_args={},
128
+ )
129
+
130
+ try:
131
+ await _hook_engine.process_event("SessionStart", event_data)
132
+ except Exception as e:
133
+ logger.error(f"Error in SessionStart hook: {e}", exc_info=True)
134
+
135
+
136
+ async def on_agent_run_end_hook(
137
+ agent_name: str,
138
+ model_name: str,
139
+ session_id: str | None = None,
140
+ success: bool = True,
141
+ error: Exception | None = None,
142
+ response_text: str | None = None,
143
+ metadata: dict | None = None,
144
+ ) -> None:
145
+ """agent_run_end callback — fires Stop or SubagentStop hooks."""
146
+ if not _hook_engine:
147
+ return
148
+
149
+ agent_lower = (agent_name or "").lower()
150
+ is_subagent = any(name in agent_lower for name in _SUBAGENT_NAMES)
151
+ event_type = "SubagentStop" if is_subagent else "Stop"
152
+
153
+ event_data = EventData(
154
+ event_type=event_type,
155
+ tool_name=agent_name or "agent",
156
+ tool_args={},
157
+ context={
158
+ "agent_name": agent_name,
159
+ "model_name": model_name,
160
+ "session_id": session_id,
161
+ "success": success,
162
+ "error": str(error) if error else None,
163
+ },
164
+ )
165
+
166
+ try:
167
+ await _hook_engine.process_event(event_type, event_data)
168
+ except Exception as e:
169
+ logger.error(f"Error in {event_type} hook: {e}", exc_info=True)
170
+
171
+
172
+ register_callback("startup", on_startup_hook)
173
+ register_callback("agent_run_end", on_agent_run_end_hook)
174
+
175
+ logger.info("Claude Code hooks plugin registered")
@@ -0,0 +1,167 @@
1
+ # Claude Code OAuth Plugin
2
+
3
+ This plugin adds OAuth authentication for Claude Code to Code Puppy, automatically importing available models into your configuration.
4
+
5
+ ## Features
6
+
7
+ - **OAuth Authentication**: Secure OAuth flow for Claude Code using PKCE
8
+ - **Automatic Model Discovery**: Fetches available models from the Claude API once authenticated
9
+ - **Model Registration**: Automatically adds models to `extra_models.json` with the `claude-code-` prefix
10
+ - **Token Management**: Secure storage of OAuth tokens in the Code Puppy config directory
11
+ - **Browser Integration**: Launches the Claude OAuth consent flow automatically
12
+ - **Callback Capture**: Listens on localhost to receive and process the OAuth redirect
13
+
14
+ ## Commands
15
+
16
+ ### `/claude-code-auth`
17
+ Authenticate with Claude Code via OAuth and import available models.
18
+
19
+ This will:
20
+ 1. Launch the Claude OAuth consent flow in your browser
21
+ 2. Walk you through approving access for the shared `claude-cli` client
22
+ 3. Capture the redirect from Claude in a temporary local callback server
23
+ 4. Exchange the returned code for access tokens and store them securely
24
+ 5. Fetch available models from Claude Code and add them to your configuration
25
+
26
+ ### `/claude-code-status`
27
+ Check Claude Code OAuth authentication status and configured models.
28
+
29
+ Shows:
30
+ - Current authentication status
31
+ - Token expiry information (if available)
32
+ - Number and names of configured Claude Code models
33
+
34
+ ### `/claude-code-logout`
35
+ Remove Claude Code OAuth tokens and imported models.
36
+
37
+ This will:
38
+ 1. Remove stored OAuth tokens
39
+ 2. Remove all Claude Code models from `extra_models.json`
40
+
41
+ ## Setup
42
+
43
+ ### Prerequisites
44
+
45
+ 1. **Claude account** with access to the Claude Console developer settings
46
+ 2. **Browser access** to generate authorization codes
47
+
48
+ ### Configuration
49
+
50
+ The plugin ships with sensible defaults in `config.py`:
51
+
52
+ ```python
53
+ CLAUDE_CODE_OAUTH_CONFIG = {
54
+ "auth_url": "https://claude.ai/oauth/authorize",
55
+ "token_url": "https://console.anthropic.com/v1/oauth/token",
56
+ "api_base_url": "https://api.anthropic.com",
57
+ "client_id": "9d1c250a-e61b-44d9-88ed-5944d1962f5e",
58
+ "scope": "org:create_api_key user:profile user:inference",
59
+ "redirect_host": "http://localhost",
60
+ "redirect_path": "callback",
61
+ "callback_port_range": (8765, 8795),
62
+ "callback_timeout": 180,
63
+ "prefix": "claude-code-",
64
+ "default_context_length": 200000,
65
+ "api_key_env_var": "CLAUDE_CODE_ACCESS_TOKEN",
66
+ }
67
+ ```
68
+
69
+ These values mirror the public client used by llxprt-code. Adjust only if Anthropic changes their configuration.
70
+
71
+ ### Environment Variables
72
+
73
+ After authentication, the models will reference:
74
+ - `CLAUDE_CODE_ACCESS_TOKEN`: Automatically written by the plugin
75
+
76
+ ## Usage Example
77
+
78
+ ```bash
79
+ # Authenticate with Claude Code
80
+ /claude-code-auth
81
+
82
+ # Check status
83
+ /claude-code-status
84
+
85
+ # Use a Claude Code model
86
+ /set model claude-code-claude-3-5-sonnet-20241022
87
+
88
+ # When done, logout
89
+ /claude-code-logout
90
+ ```
91
+
92
+ ## Model Configuration
93
+
94
+ After authentication, models will be added to `~/.code_puppy/extra_models.json`:
95
+
96
+ ```json
97
+ {
98
+ "claude-code-claude-3-5-sonnet-20241022": {
99
+ "type": "anthropic",
100
+ "name": "claude-3-5-sonnet-20241022",
101
+ "custom_endpoint": {
102
+ "url": "https://api.anthropic.com",
103
+ "api_key": "$CLAUDE_CODE_ACCESS_TOKEN"
104
+ },
105
+ "context_length": 200000,
106
+ "oauth_source": "claude-code-plugin"
107
+ }
108
+ }
109
+ ```
110
+
111
+ ## Security
112
+
113
+ - **Token Storage**: Tokens are saved to `~/.code_puppy/claude_code_oauth.json` with `0o600` permissions
114
+ - **PKCE Support**: Uses Proof Key for Code Exchange for enhanced security
115
+ - **State Validation**: Checks the returned state (if provided) to guard against CSRF
116
+ - **HTTPS Only**: All OAuth communications use HTTPS endpoints
117
+
118
+ ## Troubleshooting
119
+
120
+ ### Browser doesn't open
121
+ - Manually visit the URL shown in the output
122
+ - Check that a default browser is configured
123
+
124
+ ### Authentication fails
125
+ - Ensure the browser completed the redirect back to Code Puppy (no pop-up blockers)
126
+ - Retry if the window shows an error; codes expire quickly
127
+ - Confirm network access to `claude.ai`
128
+
129
+ ### Models not showing up
130
+ - Claude may not return the model list for your account; verify access manually
131
+ - Check `/claude-code-status` to confirm authentication succeeded
132
+
133
+ ## Development
134
+
135
+ ### File Structure
136
+
137
+ ```
138
+ claude_code_oauth/
139
+ ├── __init__.py
140
+ ├── register_callbacks.py # Main plugin logic and command handlers
141
+ ├── config.py # Configuration settings
142
+ ├── utils.py # OAuth helpers and file operations
143
+ ├── README.md # This file
144
+ ├── SETUP.md # Quick setup guide
145
+ └── test_plugin.py # Manual test helper
146
+ ```
147
+
148
+ ### Key Components
149
+
150
+ - **OAuth Flow**: Authorization code flow with PKCE and automatic callback capture
151
+ - **Token Management**: Secure storage and retrieval helpers
152
+ - **Model Discovery**: API integration for model fetching
153
+ - **Plugin Registration**: Custom command handlers wired into Code Puppy
154
+
155
+ ## Notes
156
+
157
+ - The plugin assumes Anthropic continues to expose the shared `claude-cli` OAuth client
158
+ - Tokens are refreshed on subsequent API calls if the service returns refresh tokens
159
+ - Models are prefixed with `claude-code-` to avoid collisions with other Anthropic models
160
+
161
+ ## Contributing
162
+
163
+ When modifying this plugin:
164
+ 1. Maintain security best practices
165
+ 2. Test OAuth flow changes manually before shipping
166
+ 3. Update documentation for any configuration or UX changes
167
+ 4. Keep files under 600 lines; split into helpers when needed
@@ -0,0 +1,93 @@
1
+ # Claude Code OAuth Plugin Setup Guide
2
+
3
+ This guide walks you through using the Claude Code OAuth plugin inside Code Puppy.
4
+
5
+ ## Quick Start
6
+
7
+ 1. Ensure the plugin files live under `code_puppy/plugins/claude_code_oauth/`
8
+ 2. Restart Code Puppy so it loads the plugin
9
+ 3. Run `/claude-code-auth` and follow the prompts
10
+
11
+ ## Why No Client Registration?
12
+
13
+ Anthropic exposes a shared **public client** (`claude-cli`) for command-line tools. That means:
14
+ - No client secret is needed
15
+ - Everyone authenticates through Claude Console
16
+ - Security is enforced with PKCE and per-user tokens
17
+
18
+ ## Authentication Flow
19
+
20
+ 1. Call `/claude-code-auth`
21
+ 2. Your browser opens the Claude OAuth consent flow at `https://claude.ai/oauth/authorize`
22
+ 3. Sign in (or pick an account) and approve the "Claude CLI" access request
23
+ 4. The browser closes automatically after the redirect is captured
24
+ 5. Tokens are stored locally at `~/.code_puppy/claude_code_oauth.json`
25
+ 6. Available Claude Code models are fetched and added to `extra_models.json`
26
+
27
+ ## Commands Recap
28
+
29
+ - `/claude-code-auth` – Authenticate and sync models
30
+ - `/claude-code-status` – Show auth status, expiry, configured models
31
+ - `/claude-code-logout` – Remove tokens and any models added by the plugin
32
+
33
+ ## Configuration Defaults
34
+
35
+ `config.py` ships with values aligned to llxprt-code:
36
+
37
+ ```python
38
+ CLAUDE_CODE_OAUTH_CONFIG = {
39
+ "auth_url": "https://claude.ai/oauth/authorize",
40
+ "token_url": "https://console.anthropic.com/v1/oauth/token",
41
+ "api_base_url": "https://api.anthropic.com",
42
+ "client_id": "9d1c250a-e61b-44d9-88ed-5944d1962f5e",
43
+ "scope": "org:create_api_key user:profile user:inference",
44
+ "redirect_host": "http://localhost",
45
+ "redirect_path": "callback",
46
+ "callback_port_range": (8765, 8795),
47
+ "callback_timeout": 180,
48
+ "prefix": "claude-code-",
49
+ "default_context_length": 200000,
50
+ "api_key_env_var": "CLAUDE_CODE_ACCESS_TOKEN",
51
+ }
52
+ ```
53
+
54
+ Change these only if Anthropic updates their endpoints or scopes.
55
+
56
+ ## After Authentication
57
+
58
+ - Models appear in `~/.code_puppy/extra_models.json` with the `claude-code-` prefix
59
+ - The environment variable `CLAUDE_CODE_ACCESS_TOKEN` is used by those models
60
+ - `/claude-code-status` shows token expiry when the API provides it
61
+
62
+ ## Troubleshooting Tips
63
+
64
+ - **Browser did not open** – Copy the displayed URL into your browser manually
65
+ - **Invalid code** – The code expires quickly; generate a new one in Claude Console
66
+ - **State mismatch** – Rare, but rerun `/claude-code-auth` if the browser reports a mismatch
67
+ - **No models added** – Your account might lack Claude Code access; tokens are still stored for later use
68
+
69
+ ## Files Created
70
+
71
+ ```
72
+ ~/.code_puppy/
73
+ ├── claude_code_oauth.json # OAuth tokens (0600 permissions)
74
+ └── extra_models.json # Extended model registry
75
+ ```
76
+
77
+ ## Manual Testing
78
+
79
+ Run the helper script for sanity checks:
80
+
81
+ ```bash
82
+ python code_puppy/plugins/claude_code_oauth/test_plugin.py
83
+ ```
84
+
85
+ It verifies imports, configuration values, and filesystem expectations without hitting the Anthropic API.
86
+
87
+ ## Security Notes
88
+
89
+ - Tokens are stored locally and never transmitted elsewhere
90
+ - PKCE protects the flow even without a client secret
91
+ - HTTPS endpoints are enforced for all requests
92
+
93
+ Enjoy hacking with Claude Code straight from Code Puppy! 🐶💻
@@ -0,0 +1,25 @@
1
+ """
2
+ Claude Code OAuth Plugin for Code Puppy
3
+
4
+ This plugin provides OAuth authentication for Claude Code and automatically
5
+ adds available models to the extra_models.json configuration.
6
+
7
+ The plugin also includes a token refresh heartbeat for maintaining fresh
8
+ tokens during long-running agentic operations.
9
+ """
10
+
11
+ from .token_refresh_heartbeat import (
12
+ TokenRefreshHeartbeat,
13
+ force_token_refresh,
14
+ get_current_heartbeat,
15
+ is_heartbeat_running,
16
+ token_refresh_heartbeat_context,
17
+ )
18
+
19
+ __all__ = [
20
+ "TokenRefreshHeartbeat",
21
+ "token_refresh_heartbeat_context",
22
+ "is_heartbeat_running",
23
+ "get_current_heartbeat",
24
+ "force_token_refresh",
25
+ ]
@@ -0,0 +1,52 @@
1
+ from pathlib import Path
2
+ from typing import Any, Dict
3
+
4
+ from code_puppy import config
5
+
6
+ # Claude Code OAuth configuration
7
+ CLAUDE_CODE_OAUTH_CONFIG: Dict[str, Any] = {
8
+ # OAuth endpoints inferred from official Claude Code OAuth flow
9
+ "auth_url": "https://claude.ai/oauth/authorize",
10
+ "token_url": "https://console.anthropic.com/v1/oauth/token",
11
+ "api_base_url": "https://api.anthropic.com",
12
+ # OAuth client configuration observed in Claude Code CLI flow
13
+ "client_id": "9d1c250a-e61b-44d9-88ed-5944d1962f5e",
14
+ "scope": "org:create_api_key user:profile user:inference",
15
+ # Callback handling (we host a localhost callback to capture the redirect)
16
+ "redirect_host": "http://localhost",
17
+ "redirect_path": "callback",
18
+ "callback_port_range": (8765, 8795),
19
+ "callback_timeout": 180,
20
+ # Console redirect fallback (for manual flows, if needed)
21
+ "console_redirect_uri": "https://console.anthropic.com/oauth/code/callback",
22
+ # Local configuration (uses XDG_DATA_HOME)
23
+ "token_storage": None, # Set dynamically in get_token_storage_path()
24
+ # Model configuration
25
+ "prefix": "claude-code-",
26
+ "default_context_length": 200000,
27
+ "long_context_length": 1000000,
28
+ "long_context_models": ["claude-opus-4-6"],
29
+ "api_key_env_var": "CLAUDE_CODE_ACCESS_TOKEN",
30
+ "anthropic_version": "2023-06-01",
31
+ }
32
+
33
+
34
+ def get_token_storage_path() -> Path:
35
+ """Get the path for storing OAuth tokens (uses XDG_DATA_HOME)."""
36
+ data_dir = Path(config.DATA_DIR)
37
+ data_dir.mkdir(parents=True, exist_ok=True, mode=0o700)
38
+ return data_dir / "claude_code_oauth.json"
39
+
40
+
41
+ def get_config_dir() -> Path:
42
+ """Get the Code Puppy configuration directory (uses XDG_CONFIG_HOME)."""
43
+ config_dir = Path(config.CONFIG_DIR)
44
+ config_dir.mkdir(parents=True, exist_ok=True, mode=0o700)
45
+ return config_dir
46
+
47
+
48
+ def get_claude_models_path() -> Path:
49
+ """Get the path to the dedicated claude_models.json file (uses XDG_DATA_HOME)."""
50
+ data_dir = Path(config.DATA_DIR)
51
+ data_dir.mkdir(parents=True, exist_ok=True, mode=0o700)
52
+ return data_dir / "claude_models.json"