code-puppy-core-plugins 0.0.2__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 (313) hide show
  1. code_puppy_core_plugins/__init__.py +5 -0
  2. code_puppy_core_plugins/acp/README.md +266 -0
  3. code_puppy_core_plugins/acp/__init__.py +8 -0
  4. code_puppy_core_plugins/acp/agent.py +494 -0
  5. code_puppy_core_plugins/acp/bridge.py +309 -0
  6. code_puppy_core_plugins/acp/capabilities.py +73 -0
  7. code_puppy_core_plugins/acp/commands.py +116 -0
  8. code_puppy_core_plugins/acp/content.py +115 -0
  9. code_puppy_core_plugins/acp/io_delegation.py +231 -0
  10. code_puppy_core_plugins/acp/mcp_config.py +66 -0
  11. code_puppy_core_plugins/acp/permissions.py +159 -0
  12. code_puppy_core_plugins/acp/persistence.py +197 -0
  13. code_puppy_core_plugins/acp/register_callbacks.py +110 -0
  14. code_puppy_core_plugins/acp/replay.py +114 -0
  15. code_puppy_core_plugins/acp/session.py +329 -0
  16. code_puppy_core_plugins/acp/session_config.py +179 -0
  17. code_puppy_core_plugins/acp/state.py +135 -0
  18. code_puppy_core_plugins/agent_skills/__init__.py +22 -0
  19. code_puppy_core_plugins/agent_skills/config.py +208 -0
  20. code_puppy_core_plugins/agent_skills/discovery.py +337 -0
  21. code_puppy_core_plugins/agent_skills/downloader.py +392 -0
  22. code_puppy_core_plugins/agent_skills/enabled_skills.py +82 -0
  23. code_puppy_core_plugins/agent_skills/installer.py +22 -0
  24. code_puppy_core_plugins/agent_skills/metadata.py +219 -0
  25. code_puppy_core_plugins/agent_skills/prompt_builder.py +49 -0
  26. code_puppy_core_plugins/agent_skills/provider.py +52 -0
  27. code_puppy_core_plugins/agent_skills/register_callbacks.py +309 -0
  28. code_puppy_core_plugins/agent_skills/remote_catalog.py +322 -0
  29. code_puppy_core_plugins/agent_skills/skill_catalog.py +257 -0
  30. code_puppy_core_plugins/agent_skills/skill_commands.py +102 -0
  31. code_puppy_core_plugins/agent_skills/skills_install_menu.py +698 -0
  32. code_puppy_core_plugins/agent_skills/skills_menu.py +794 -0
  33. code_puppy_core_plugins/aws_bedrock/__init__.py +14 -0
  34. code_puppy_core_plugins/aws_bedrock/config.py +101 -0
  35. code_puppy_core_plugins/aws_bedrock/register_callbacks.py +243 -0
  36. code_puppy_core_plugins/aws_bedrock/utils.py +186 -0
  37. code_puppy_core_plugins/azure_foundry/README.md +238 -0
  38. code_puppy_core_plugins/azure_foundry/__init__.py +15 -0
  39. code_puppy_core_plugins/azure_foundry/config.py +126 -0
  40. code_puppy_core_plugins/azure_foundry/discovery.py +189 -0
  41. code_puppy_core_plugins/azure_foundry/register_callbacks.py +506 -0
  42. code_puppy_core_plugins/azure_foundry/token.py +182 -0
  43. code_puppy_core_plugins/azure_foundry/utils.py +375 -0
  44. code_puppy_core_plugins/btw/__init__.py +1 -0
  45. code_puppy_core_plugins/btw/inline_view.py +135 -0
  46. code_puppy_core_plugins/btw/register_callbacks.py +106 -0
  47. code_puppy_core_plugins/btw/side_query.py +91 -0
  48. code_puppy_core_plugins/chatgpt_oauth/IMAGEGEN_SKILL.md +83 -0
  49. code_puppy_core_plugins/chatgpt_oauth/__init__.py +8 -0
  50. code_puppy_core_plugins/chatgpt_oauth/config.py +52 -0
  51. code_puppy_core_plugins/chatgpt_oauth/image_generation.py +253 -0
  52. code_puppy_core_plugins/chatgpt_oauth/image_tool.py +70 -0
  53. code_puppy_core_plugins/chatgpt_oauth/oauth_flow.py +461 -0
  54. code_puppy_core_plugins/chatgpt_oauth/register_callbacks.py +288 -0
  55. code_puppy_core_plugins/chatgpt_oauth/test_plugin.py +663 -0
  56. code_puppy_core_plugins/chatgpt_oauth/usage.py +113 -0
  57. code_puppy_core_plugins/chatgpt_oauth/utils.py +534 -0
  58. code_puppy_core_plugins/claude_code_hooks/__init__.py +1 -0
  59. code_puppy_core_plugins/claude_code_hooks/config.py +137 -0
  60. code_puppy_core_plugins/claude_code_hooks/register_callbacks.py +383 -0
  61. code_puppy_core_plugins/claude_code_oauth/README.md +167 -0
  62. code_puppy_core_plugins/claude_code_oauth/SETUP.md +93 -0
  63. code_puppy_core_plugins/claude_code_oauth/__init__.py +25 -0
  64. code_puppy_core_plugins/claude_code_oauth/config.py +59 -0
  65. code_puppy_core_plugins/claude_code_oauth/fast_mode.py +122 -0
  66. code_puppy_core_plugins/claude_code_oauth/prompt_handler.py +64 -0
  67. code_puppy_core_plugins/claude_code_oauth/register_callbacks.py +719 -0
  68. code_puppy_core_plugins/claude_code_oauth/test_plugin.py +285 -0
  69. code_puppy_core_plugins/claude_code_oauth/token_refresh_heartbeat.py +240 -0
  70. code_puppy_core_plugins/claude_code_oauth/utils.py +663 -0
  71. code_puppy_core_plugins/code_puppy_agent/AGENTS_AND_TOOLS.md +155 -0
  72. code_puppy_core_plugins/code_puppy_agent/MODELS_AND_MCP.md +104 -0
  73. code_puppy_core_plugins/code_puppy_agent/PLUGINS_AND_CALLBACKS.md +147 -0
  74. code_puppy_core_plugins/code_puppy_agent/SESSIONS_AND_HISTORY.md +39 -0
  75. code_puppy_core_plugins/code_puppy_agent/SKILL.md +180 -0
  76. code_puppy_core_plugins/code_puppy_agent/SKILLS_SYSTEM.md +136 -0
  77. code_puppy_core_plugins/code_puppy_agent/SYSTEM_PROMPT_CONFIG_AND_I18N.md +160 -0
  78. code_puppy_core_plugins/code_puppy_agent/__init__.py +5 -0
  79. code_puppy_core_plugins/code_puppy_agent/register_callbacks.py +46 -0
  80. code_puppy_core_plugins/computer_use/NativeCapture.swift +123 -0
  81. code_puppy_core_plugins/computer_use/README.md +109 -0
  82. code_puppy_core_plugins/computer_use/__init__.py +1 -0
  83. code_puppy_core_plugins/computer_use/accessibility.py +163 -0
  84. code_puppy_core_plugins/computer_use/activation.py +75 -0
  85. code_puppy_core_plugins/computer_use/backend.py +584 -0
  86. code_puppy_core_plugins/computer_use/backend_types.py +5 -0
  87. code_puppy_core_plugins/computer_use/capture.py +110 -0
  88. code_puppy_core_plugins/computer_use/commands.py +62 -0
  89. code_puppy_core_plugins/computer_use/geometry.py +81 -0
  90. code_puppy_core_plugins/computer_use/inline_image.py +56 -0
  91. code_puppy_core_plugins/computer_use/keycodes.py +47 -0
  92. code_puppy_core_plugins/computer_use/policy.py +144 -0
  93. code_puppy_core_plugins/computer_use/register_callbacks.py +96 -0
  94. code_puppy_core_plugins/computer_use/safety.py +18 -0
  95. code_puppy_core_plugins/computer_use/settle.py +64 -0
  96. code_puppy_core_plugins/computer_use/state.py +86 -0
  97. code_puppy_core_plugins/computer_use/tools.py +469 -0
  98. code_puppy_core_plugins/context_indicator/__init__.py +14 -0
  99. code_puppy_core_plugins/context_indicator/register_callbacks.py +249 -0
  100. code_puppy_core_plugins/context_indicator/usage.py +40 -0
  101. code_puppy_core_plugins/copilot_auth/__init__.py +11 -0
  102. code_puppy_core_plugins/copilot_auth/config.py +93 -0
  103. code_puppy_core_plugins/copilot_auth/reasoning_client.py +409 -0
  104. code_puppy_core_plugins/copilot_auth/register_callbacks.py +460 -0
  105. code_puppy_core_plugins/copilot_auth/utils.py +587 -0
  106. code_puppy_core_plugins/customizable_commands/__init__.py +0 -0
  107. code_puppy_core_plugins/customizable_commands/register_callbacks.py +464 -0
  108. code_puppy_core_plugins/dbos_durable_exec/__init__.py +1 -0
  109. code_puppy_core_plugins/dbos_durable_exec/cancel.py +15 -0
  110. code_puppy_core_plugins/dbos_durable_exec/commands.py +31 -0
  111. code_puppy_core_plugins/dbos_durable_exec/config.py +31 -0
  112. code_puppy_core_plugins/dbos_durable_exec/lifecycle.py +83 -0
  113. code_puppy_core_plugins/dbos_durable_exec/register_callbacks.py +45 -0
  114. code_puppy_core_plugins/dbos_durable_exec/runtime.py +65 -0
  115. code_puppy_core_plugins/dbos_durable_exec/startup_lock.py +155 -0
  116. code_puppy_core_plugins/dbos_durable_exec/workflow_ids.py +16 -0
  117. code_puppy_core_plugins/dbos_durable_exec/wrapper.py +58 -0
  118. code_puppy_core_plugins/destructive_command_guard/AGENTS.md +79 -0
  119. code_puppy_core_plugins/destructive_command_guard/__init__.py +14 -0
  120. code_puppy_core_plugins/destructive_command_guard/detector.py +374 -0
  121. code_puppy_core_plugins/destructive_command_guard/register_callbacks.py +165 -0
  122. code_puppy_core_plugins/emoji_filter/__init__.py +12 -0
  123. code_puppy_core_plugins/emoji_filter/config.py +26 -0
  124. code_puppy_core_plugins/emoji_filter/register_callbacks.py +238 -0
  125. code_puppy_core_plugins/emoji_filter/stripper.py +45 -0
  126. code_puppy_core_plugins/empty_html_comment_filter/register_callbacks.py +116 -0
  127. code_puppy_core_plugins/example_custom_command/README.md +328 -0
  128. code_puppy_core_plugins/example_custom_command/register_callbacks.py +66 -0
  129. code_puppy_core_plugins/file_permission_handler/__init__.py +4 -0
  130. code_puppy_core_plugins/file_permission_handler/register_callbacks.py +575 -0
  131. code_puppy_core_plugins/flux_bootstrap/__init__.py +5 -0
  132. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/README.md +173 -0
  133. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/cheatsheet.md +86 -0
  134. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/pipeline.md +167 -0
  135. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/synopsis.md +392 -0
  136. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/about.md +51 -0
  137. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/address-feedback.md +129 -0
  138. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/ask.md +211 -0
  139. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/aug.md +181 -0
  140. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/auto-pilot.md +71 -0
  141. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/cheatsheet.md +16 -0
  142. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/commit.md +103 -0
  143. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/config.md +108 -0
  144. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/create-pr.md +195 -0
  145. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/exec.md +221 -0
  146. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/new.md +151 -0
  147. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/qa.md +208 -0
  148. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/rebase.md +180 -0
  149. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/review.md +304 -0
  150. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/split.md +120 -0
  151. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/squash-commits.md +179 -0
  152. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/status.md +46 -0
  153. code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/tests.md +155 -0
  154. code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_about.py +154 -0
  155. code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_cheatsheet.py +248 -0
  156. code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_status.py +345 -0
  157. code_puppy_core_plugins/flux_bootstrap/installer.py +256 -0
  158. code_puppy_core_plugins/flux_bootstrap/register_callbacks.py +71 -0
  159. code_puppy_core_plugins/force_push_guard/__init__.py +5 -0
  160. code_puppy_core_plugins/force_push_guard/detector.py +96 -0
  161. code_puppy_core_plugins/force_push_guard/register_callbacks.py +161 -0
  162. code_puppy_core_plugins/fork/__init__.py +7 -0
  163. code_puppy_core_plugins/fork/register_callbacks.py +445 -0
  164. code_puppy_core_plugins/frontend_emitter/__init__.py +25 -0
  165. code_puppy_core_plugins/frontend_emitter/emitter.py +249 -0
  166. code_puppy_core_plugins/frontend_emitter/register_callbacks.py +412 -0
  167. code_puppy_core_plugins/frontend_emitter/session_context.py +50 -0
  168. code_puppy_core_plugins/grok_oauth/__init__.py +6 -0
  169. code_puppy_core_plugins/grok_oauth/config.py +49 -0
  170. code_puppy_core_plugins/grok_oauth/oauth_flow.py +213 -0
  171. code_puppy_core_plugins/grok_oauth/register_callbacks.py +132 -0
  172. code_puppy_core_plugins/grok_oauth/utils.py +195 -0
  173. code_puppy_core_plugins/herdr/README.md +168 -0
  174. code_puppy_core_plugins/herdr/__init__.py +9 -0
  175. code_puppy_core_plugins/herdr/client.py +339 -0
  176. code_puppy_core_plugins/herdr/register_callbacks.py +140 -0
  177. code_puppy_core_plugins/herdr/reporter.py +212 -0
  178. code_puppy_core_plugins/herdr/smoke.py +143 -0
  179. code_puppy_core_plugins/herdr/sources.py +133 -0
  180. code_puppy_core_plugins/hook_creator/__init__.py +1 -0
  181. code_puppy_core_plugins/hook_creator/register_callbacks.py +33 -0
  182. code_puppy_core_plugins/hook_manager/__init__.py +1 -0
  183. code_puppy_core_plugins/hook_manager/config.py +290 -0
  184. code_puppy_core_plugins/hook_manager/hooks_menu.py +571 -0
  185. code_puppy_core_plugins/hook_manager/register_callbacks.py +227 -0
  186. code_puppy_core_plugins/meta_oauth/__init__.py +1 -0
  187. code_puppy_core_plugins/meta_oauth/config.py +55 -0
  188. code_puppy_core_plugins/meta_oauth/oauth_flow.py +109 -0
  189. code_puppy_core_plugins/meta_oauth/register_callbacks.py +154 -0
  190. code_puppy_core_plugins/meta_oauth/utils.py +252 -0
  191. code_puppy_core_plugins/namespace_skill_search/README.md +118 -0
  192. code_puppy_core_plugins/namespace_skill_search/__init__.py +15 -0
  193. code_puppy_core_plugins/namespace_skill_search/namespaces.py +125 -0
  194. code_puppy_core_plugins/namespace_skill_search/register_callbacks.py +99 -0
  195. code_puppy_core_plugins/namespace_skill_search/search_tool.py +158 -0
  196. code_puppy_core_plugins/no_tools/__init__.py +0 -0
  197. code_puppy_core_plugins/no_tools/register_callbacks.py +42 -0
  198. code_puppy_core_plugins/oauth_pasteback.py +110 -0
  199. code_puppy_core_plugins/oauth_puppy_html.py +194 -0
  200. code_puppy_core_plugins/obsidian_agent/README.md +52 -0
  201. code_puppy_core_plugins/obsidian_agent/__init__.py +8 -0
  202. code_puppy_core_plugins/obsidian_agent/agent_obsidian.py +147 -0
  203. code_puppy_core_plugins/obsidian_agent/register_callbacks.py +13 -0
  204. code_puppy_core_plugins/ollama/__init__.py +1 -0
  205. code_puppy_core_plugins/ollama/register_callbacks.py +127 -0
  206. code_puppy_core_plugins/ollama_setup/__init__.py +5 -0
  207. code_puppy_core_plugins/ollama_setup/completer.py +38 -0
  208. code_puppy_core_plugins/ollama_setup/register_callbacks.py +419 -0
  209. code_puppy_core_plugins/plugin_list/__init__.py +0 -0
  210. code_puppy_core_plugins/plugin_list/plugin_contributions.py +348 -0
  211. code_puppy_core_plugins/plugin_list/plugin_meta.py +67 -0
  212. code_puppy_core_plugins/plugin_list/plugin_text_utils.py +173 -0
  213. code_puppy_core_plugins/plugin_list/plugins_menu.py +455 -0
  214. code_puppy_core_plugins/plugin_list/plugins_menu_layout.py +194 -0
  215. code_puppy_core_plugins/plugin_list/plugins_menu_render.py +431 -0
  216. code_puppy_core_plugins/plugin_list/project_trust_flow.py +162 -0
  217. code_puppy_core_plugins/plugin_list/register_callbacks.py +281 -0
  218. code_puppy_core_plugins/pop_command/__init__.py +1 -0
  219. code_puppy_core_plugins/pop_command/register_callbacks.py +191 -0
  220. code_puppy_core_plugins/prompt_newline/__init__.py +13 -0
  221. code_puppy_core_plugins/prompt_newline/config.py +21 -0
  222. code_puppy_core_plugins/prompt_newline/register_callbacks.py +163 -0
  223. code_puppy_core_plugins/prune/__init__.py +1 -0
  224. code_puppy_core_plugins/prune/prune_menu.py +308 -0
  225. code_puppy_core_plugins/prune/prune_model.py +517 -0
  226. code_puppy_core_plugins/prune/prune_render.py +354 -0
  227. code_puppy_core_plugins/prune/register_callbacks.py +388 -0
  228. code_puppy_core_plugins/puppy_kennel/README.md +203 -0
  229. code_puppy_core_plugins/puppy_kennel/__init__.py +6 -0
  230. code_puppy_core_plugins/puppy_kennel/commands.py +206 -0
  231. code_puppy_core_plugins/puppy_kennel/config.py +36 -0
  232. code_puppy_core_plugins/puppy_kennel/kennel.py +368 -0
  233. code_puppy_core_plugins/puppy_kennel/packer.py +152 -0
  234. code_puppy_core_plugins/puppy_kennel/recorder.py +83 -0
  235. code_puppy_core_plugins/puppy_kennel/register_callbacks.py +109 -0
  236. code_puppy_core_plugins/puppy_kennel/retriever.py +28 -0
  237. code_puppy_core_plugins/puppy_kennel/schema.py +78 -0
  238. code_puppy_core_plugins/puppy_kennel/state.py +68 -0
  239. code_puppy_core_plugins/puppy_kennel/tools.py +449 -0
  240. code_puppy_core_plugins/puppy_kennel/wings.py +110 -0
  241. code_puppy_core_plugins/puppy_spinner/README.md +93 -0
  242. code_puppy_core_plugins/puppy_spinner/__init__.py +11 -0
  243. code_puppy_core_plugins/puppy_spinner/builtin_frames.py +172 -0
  244. code_puppy_core_plugins/puppy_spinner/commands.py +116 -0
  245. code_puppy_core_plugins/puppy_spinner/picker.py +379 -0
  246. code_puppy_core_plugins/puppy_spinner/register_callbacks.py +193 -0
  247. code_puppy_core_plugins/puppy_spinner/spinners.py +444 -0
  248. code_puppy_core_plugins/quick_resume/__init__.py +0 -0
  249. code_puppy_core_plugins/quick_resume/register_callbacks.py +77 -0
  250. code_puppy_core_plugins/review_pr/__init__.py +1 -0
  251. code_puppy_core_plugins/review_pr/register_callbacks.py +162 -0
  252. code_puppy_core_plugins/shell_safety/__init__.py +6 -0
  253. code_puppy_core_plugins/shell_safety/agent_shell_safety.py +69 -0
  254. code_puppy_core_plugins/shell_safety/command_cache.py +156 -0
  255. code_puppy_core_plugins/shell_safety/register_callbacks.py +203 -0
  256. code_puppy_core_plugins/stack_dump/__init__.py +1 -0
  257. code_puppy_core_plugins/stack_dump/register_callbacks.py +79 -0
  258. code_puppy_core_plugins/statusline/__init__.py +14 -0
  259. code_puppy_core_plugins/statusline/config.py +68 -0
  260. code_puppy_core_plugins/statusline/payload.py +138 -0
  261. code_puppy_core_plugins/statusline/prompt_patch.py +76 -0
  262. code_puppy_core_plugins/statusline/register_callbacks.py +45 -0
  263. code_puppy_core_plugins/statusline/runner.py +122 -0
  264. code_puppy_core_plugins/statusline/statusline_command.py +197 -0
  265. code_puppy_core_plugins/steer_queue/__init__.py +10 -0
  266. code_puppy_core_plugins/steer_queue/queue_menu.py +444 -0
  267. code_puppy_core_plugins/steer_queue/register_callbacks.py +138 -0
  268. code_puppy_core_plugins/subagent_panel/README.md +102 -0
  269. code_puppy_core_plugins/subagent_panel/__init__.py +24 -0
  270. code_puppy_core_plugins/subagent_panel/coalesce_patch.py +242 -0
  271. code_puppy_core_plugins/subagent_panel/panel_render.py +145 -0
  272. code_puppy_core_plugins/subagent_panel/register_callbacks.py +535 -0
  273. code_puppy_core_plugins/subagent_panel/resume_repaint.py +112 -0
  274. code_puppy_core_plugins/subagent_panel/state.py +231 -0
  275. code_puppy_core_plugins/switch_agent_resume/__init__.py +5 -0
  276. code_puppy_core_plugins/switch_agent_resume/register_callbacks.py +314 -0
  277. code_puppy_core_plugins/theme/README.md +86 -0
  278. code_puppy_core_plugins/theme/__init__.py +14 -0
  279. code_puppy_core_plugins/theme/bundled_palettes.py +346 -0
  280. code_puppy_core_plugins/theme/content_styles.py +146 -0
  281. code_puppy_core_plugins/theme/osc_palette.py +178 -0
  282. code_puppy_core_plugins/theme/picker.py +358 -0
  283. code_puppy_core_plugins/theme/prompt_toolkit_theme.py +113 -0
  284. code_puppy_core_plugins/theme/register_callbacks.py +348 -0
  285. code_puppy_core_plugins/theme/rich_themes.py +202 -0
  286. code_puppy_core_plugins/theme/themes.py +720 -0
  287. code_puppy_core_plugins/timestamp_heartbeat/__init__.py +1 -0
  288. code_puppy_core_plugins/timestamp_heartbeat/register_callbacks.py +114 -0
  289. code_puppy_core_plugins/token_ratio_learner/__init__.py +5 -0
  290. code_puppy_core_plugins/token_ratio_learner/ratios.py +208 -0
  291. code_puppy_core_plugins/token_ratio_learner/register_callbacks.py +213 -0
  292. code_puppy_core_plugins/universal_constructor/__init__.py +13 -0
  293. code_puppy_core_plugins/universal_constructor/models.py +138 -0
  294. code_puppy_core_plugins/universal_constructor/provider.py +62 -0
  295. code_puppy_core_plugins/universal_constructor/register_callbacks.py +75 -0
  296. code_puppy_core_plugins/universal_constructor/registry.py +302 -0
  297. code_puppy_core_plugins/universal_constructor/sandbox.py +584 -0
  298. code_puppy_core_plugins/wide_completion_menu/__init__.py +6 -0
  299. code_puppy_core_plugins/wide_completion_menu/register_callbacks.py +165 -0
  300. code_puppy_core_plugins/wiggum/__init__.py +1 -0
  301. code_puppy_core_plugins/wiggum/goal_runs.py +91 -0
  302. code_puppy_core_plugins/wiggum/judge.py +299 -0
  303. code_puppy_core_plugins/wiggum/judge_config.py +249 -0
  304. code_puppy_core_plugins/wiggum/judges_menu.py +814 -0
  305. code_puppy_core_plugins/wiggum/register_callbacks.py +569 -0
  306. code_puppy_core_plugins/wiggum/state.py +89 -0
  307. code_puppy_core_plugins/yolo_cli/__init__.py +1 -0
  308. code_puppy_core_plugins/yolo_cli/register_callbacks.py +41 -0
  309. code_puppy_core_plugins-0.0.2.dist-info/METADATA +64 -0
  310. code_puppy_core_plugins-0.0.2.dist-info/RECORD +313 -0
  311. code_puppy_core_plugins-0.0.2.dist-info/WHEEL +4 -0
  312. code_puppy_core_plugins-0.0.2.dist-info/entry_points.txt +55 -0
  313. code_puppy_core_plugins-0.0.2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,168 @@
1
+ # herdr integration
2
+
3
+ Makes code-puppy a first-class citizen in
4
+ [**herdr**](https://herdr.dev), a terminal workspace manager for coding
5
+ agents. When you run several agents at once, herdr's sidebar rolls each
6
+ one up to a single glanceable state -- who's **working**, who's
7
+ **blocked** waiting on you, and who's **done** -- so you always know
8
+ which pane needs attention.
9
+
10
+ This plugin teaches code-puppy to report that state authoritatively.
11
+
12
+ ## What it does
13
+
14
+ herdr injects three environment variables into every pane it owns:
15
+
16
+ | variable | meaning |
17
+ | ------------------- | ----------------------------------------- |
18
+ | `HERDR_ENV=1` | this shell is running inside a herdr pane |
19
+ | `HERDR_SOCKET_PATH` | herdr's local control socket |
20
+ | `HERDR_PANE_ID` | the pane this process owns (e.g. `w1:p1`) |
21
+
22
+ On startup the plugin checks for those. If they're absent it does
23
+ **nothing** -- zero overhead, zero output, no behaviour change, no socket,
24
+ no worker thread. If they're present it opens a background reporter that
25
+ reports code-puppy's state **authoritatively**: herdr never has to infer
26
+ it from the screen.
27
+
28
+ ## State is authoritative
29
+
30
+ State is a pure function of two facts the plugin observes directly:
31
+
32
+ ```text
33
+ blocked if awaiting the human
34
+ working elif a run is in flight (run_depth > 0)
35
+ idle otherwise
36
+ ```
37
+
38
+ * **run depth** comes from `agent_run_start` / `agent_run_end`, refcounted
39
+ so a finishing sub-agent doesn't flip the pane `idle` mid-turn (the same
40
+ pattern the `puppy_spinner` plugin uses).
41
+ * **awaiting** comes from the `awaiting_user_input` callback, which fires
42
+ from the single process-wide choke-point
43
+ (`command_runner.set_awaiting_user_input`) that *every* interactive wait
44
+ already passes through -- shell-command approval, file-permission
45
+ approval, `ask_user_question`, and every menu/picker. One hook captures
46
+ every block, so there is nothing left for herdr to guess.
47
+
48
+ User-initiated menus carry `notify=False`; the plugin suppresses their
49
+ `blocked` report entirely so quick pickers don't spam attention.
50
+
51
+ ## Activity text is best-effort
52
+
53
+ Alongside the authoritative state, the plugin attaches a short activity
54
+ `message` (`thinking`, `running <tool>`, `awaiting input`) driven by
55
+ `pre_tool_call` / `post_tool_call`. This is decorative: it rides a separate
56
+ lane, deduplicates on the `(state, message)` pair, and can **never** delay
57
+ or override the authoritative state, the session reference, or the final
58
+ release. If a hook-blocked tool misses its completion callback, the next
59
+ run / tool / wait / turn event corrects the message; state stays correct
60
+ regardless.
61
+
62
+ ## Pane metadata (model / context / tokens)
63
+
64
+ At the end of every interactive turn the plugin also reports pane
65
+ metadata via `pane.report_metadata`: the current model, context-window
66
+ fill percentage, and a compact token count. herdr stores these under the
67
+ pane with a 24h TTL (so stale numbers self-clear after an abrupt exit),
68
+ but it only *renders* them when your sidebar layout references the
69
+ matching `$name` fields. Add them to `rows_by_agent` in your herdr
70
+ config:
71
+
72
+ ```toml
73
+ [ui.sidebar.agents.rows_by_agent]
74
+ codepuppy = [
75
+ ["state_icon", "workspace", "tab"],
76
+ ["agent", "$model"],
77
+ ["$context", "$tokens"],
78
+ ]
79
+ ```
80
+
81
+ The payload uses static keys (`model`, `context`, `tokens`) with
82
+ string values and no indicator glyphs -- herdr rows already carry their
83
+ own state icons. If context usage can't be computed for a turn, no
84
+ metadata is sent and the pane keeps its last good values until the TTL
85
+ expires.
86
+
87
+ ## Session reference
88
+
89
+ On each prompt the plugin reports a **stable** session reference (the
90
+ durable autosave name and pickle path) via `pane.report_agent_session` --
91
+ not the per-run `group_id`, which changes every turn. It re-reports only
92
+ when the reference actually changes (after `/clear`, `/session new`,
93
+ `/autosave_load`, `/load_context`, a quick resume, or an agent switch).
94
+ This is a stable *reference*; automatic process restoration from it is
95
+ **unverified** and not claimed here.
96
+
97
+ ## Notifications are herdr's job
98
+
99
+ The plugin sends no notifications itself. herdr derives attention and
100
+ completion notifications from the agent-state transitions the plugin
101
+ reports, and herdr's own toast / sound settings control delivery. This
102
+ plugin's only job is to report accurate state.
103
+
104
+ ## Release on exit
105
+
106
+ On `session_end` / `shutdown` the plugin calls `pane.release_agent` once
107
+ (idempotent, bounded) so herdr knows code-puppy has let go of the pane --
108
+ no lingering stale `working`. There is no intermediate `idle` report on
109
+ shutdown; if herdr is unavailable the release is bounded and can never
110
+ delay process exit.
111
+
112
+ ## No install needed on the herdr side
113
+
114
+ Because this plugin ships with code-puppy and self-activates inside a
115
+ pane, there is nothing to run -- `herdr integration install` is **not**
116
+ required for code-puppy. Just start code-puppy inside herdr:
117
+
118
+ ```bash
119
+ herdr # start / attach herdr
120
+ code-puppy # (or: pup) -- herdr picks up its state automatically
121
+ ```
122
+
123
+ herdr also recognises the `code-puppy` / `pup` process on its own, so even
124
+ with this plugin disabled you still get basic detection. The plugin
125
+ upgrades that from screen-scraped guessing to authoritative, event-driven
126
+ state, metadata, and activity.
127
+
128
+ ## Design notes
129
+
130
+ * **Never disturbs the agent.** All socket I/O happens on a daemon
131
+ worker thread; the sync file-permission and tool hot-paths just enqueue
132
+ and return. The tool observers always return `None`, so they can never
133
+ block or transform a tool call.
134
+ * **Critical vs decorative.** State edges, session references, and the
135
+ release ride a critical lane that always overtakes decorative traffic
136
+ (activity messages, metadata). Decorative saturation can never displace
137
+ a critical report.
138
+ * **Edge-triggered + deduped.** Only genuine `(state, message)` changes
139
+ hit the socket.
140
+ * **Fail-soft.** A missing/closed socket, a departed herdr, an
141
+ unresolvable source -- all are swallowed to the debug log. Reporting
142
+ your state is never worth crashing your agent over.
143
+
144
+ ## Files
145
+
146
+ | file | responsibility |
147
+ | ----------------------- | ------------------------------------------- |
148
+ | `client.py` | herdr socket transport (JSON, worker thread)|
149
+ | `reporter.py` | event -> state machine (refcount + dedup) |
150
+ | `sources.py` | fail-soft adapters (tokens / session / msg) |
151
+ | `register_callbacks.py` | callback wiring + env activation guard |
152
+ | `smoke.py` | manual live smoke test (disposable pane) |
153
+
154
+ ## Live smoke test
155
+
156
+ The unit tests (`tests/plugins/test_herdr_*.py`) are the CI contract. For
157
+ an end-to-end check against a real herdr server, run the manual smoke test
158
+ from inside a herdr pane:
159
+
160
+ ```bash
161
+ python -m code_puppy_core_plugins.herdr.smoke
162
+ ```
163
+
164
+ It creates its **own** disposable pane, drives the real client through
165
+ every protocol-16 method (state edges, session reference, metadata,
166
+ release), reads each result back with `herdr pane get`, then closes the
167
+ disposable pane -- your working pane is never touched. Exits non-zero if
168
+ any check fails.
@@ -0,0 +1,9 @@
1
+ """herdr integration plugin for code-puppy.
2
+
3
+ Reports semantic agent state (working / blocked / idle) to a herdr pane
4
+ over herdr's local socket. Inert unless running inside herdr.
5
+
6
+ See ``register_callbacks.py`` for the wiring and ``README.md`` for docs.
7
+ """
8
+
9
+ __all__: list[str] = []
@@ -0,0 +1,339 @@
1
+ r"""Fire-and-forget client for the herdr pane socket.
2
+
3
+ herdr (https://herdr.dev) is a terminal workspace manager for coding
4
+ agents. When code-puppy runs inside a herdr pane, herdr injects three
5
+ environment variables:
6
+
7
+ * ``HERDR_ENV=1`` -- marks the pane as herdr-managed
8
+ * ``HERDR_SOCKET_PATH`` -- path to herdr's local control socket
9
+ * ``HERDR_PANE_ID`` -- the pane this process owns (e.g. ``w1:p1``)
10
+
11
+ This module speaks herdr's newline-delimited JSON socket protocol far
12
+ enough to call ``pane.report_agent`` / ``pane.report_agent_session`` /
13
+ ``pane.report_metadata`` / ``pane.release_agent``. It reads herdr's ack
14
+ (and retries a few times if it doesn't come) so an authoritative state
15
+ edge is never silently lost, but it never raises into the caller:
16
+ reporting agent state must never be able to disturb the agent itself.
17
+
18
+ Delivery runs on a single daemon worker thread fed by **coalescing
19
+ mailbox slots** rather than an unbounded queue:
20
+
21
+ * **Critical lane** -- state transitions, session references, and the
22
+ final release. The worker drains these first.
23
+ * **Decorative lane** -- message-only state refreshes and pane metadata.
24
+ These may be replaced by newer decorative work, and they are discarded
25
+ entirely once a release is scheduled.
26
+
27
+ Each slot keeps only its newest value, so memory is bounded and the pane
28
+ always converges on the latest authoritative facts. Request ``id`` and
29
+ ``seq`` are assigned immediately before the first wire attempt, so wire
30
+ order stays monotonic even when critical work overtakes decorative work;
31
+ retries reuse the same serialized envelope (herdr dedupes on ``seq``).
32
+
33
+ Transport is ``AF_UNIX`` everywhere it exists. On Windows (where CPython
34
+ still has no ``socket.AF_UNIX``), herdr's build -- via Rust's
35
+ ``interprocess`` crate -- maps the file-style ``HERDR_SOCKET_PATH`` onto a
36
+ named pipe whose name *is* the full path (``\\.\pipe\C:\...\herdr.sock``),
37
+ so plain stdlib file I/O on that pipe path gives the same bidirectional
38
+ byte stream. When neither transport is available the client is simply
39
+ inactive.
40
+ """
41
+
42
+ from __future__ import annotations
43
+
44
+ import json
45
+ import logging
46
+ import os
47
+ import socket
48
+ import threading
49
+ import time
50
+ from typing import Any, Dict, Optional, Tuple
51
+
52
+ logger = logging.getLogger(__name__)
53
+
54
+ #: source tag herdr attributes these reports to. The ``herdr:`` prefix is
55
+ #: the convention herdr uses for its own official integrations.
56
+ SOURCE = "herdr:codepuppy"
57
+ #: agent label; must match herdr's ``agent_label(Agent::CodePuppy)``.
58
+ AGENT = "codepuppy"
59
+
60
+ _CONNECT_TIMEOUT_S = 0.5
61
+
62
+ # Retry until herdr acks: a silently-dropped report strands the pane on a stale state.
63
+ # Retrying the *same* envelope is safe — herdr dedupes on ``seq``, so an already-applied
64
+ # report is harmlessly ignored.
65
+ _SEND_ATTEMPTS = 3
66
+ _SEND_BACKOFF_S = 0.05
67
+ _ACK_BYTES = 4096
68
+
69
+ #: Pane metadata TTL (24h) — bounds how long an abrupt process death can leave
70
+ #: stale token/model numbers on the sidebar.
71
+ _METADATA_TTL_MS = 86_400_000
72
+
73
+ # herdr request methods.
74
+ _M_STATE = "pane.report_agent"
75
+ _M_SESSION = "pane.report_agent_session"
76
+ _M_METADATA = "pane.report_metadata"
77
+ _M_RELEASE = "pane.release_agent"
78
+
79
+
80
+ class HerdrClient:
81
+ """Coalescing, two-lane reporter drained on a single worker thread."""
82
+
83
+ def __init__(
84
+ self,
85
+ socket_path: Optional[str] = None,
86
+ pane_id: Optional[str] = None,
87
+ ) -> None:
88
+ self._socket_path = socket_path or os.environ.get("HERDR_SOCKET_PATH")
89
+ self._pane_id = pane_id or os.environ.get("HERDR_PANE_ID")
90
+ self._active = bool(
91
+ os.environ.get("HERDR_ENV") == "1"
92
+ and self._socket_path
93
+ and self._pane_id
94
+ and (hasattr(socket, "AF_UNIX") or os.name == "nt")
95
+ )
96
+
97
+ # One condition guards every mailbox slot and the lifecycle flags.
98
+ self._cond = threading.Condition()
99
+ # Critical lane (latest-wins). ``None`` == empty.
100
+ self._state: Optional[Dict[str, Any]] = None
101
+ self._session: Optional[Dict[str, Any]] = None
102
+ # Decorative lane (latest-wins, discarded on release).
103
+ self._message: Optional[Dict[str, Any]] = None
104
+ self._metadata: Optional[Dict[str, Any]] = None
105
+ # Terminal release slot.
106
+ self._release: Optional[Dict[str, Any]] = None
107
+
108
+ self._closing = False
109
+ self._release_scheduled = False
110
+ self._released = threading.Event()
111
+
112
+ self._seq_lock = threading.Lock()
113
+ # Monotonic, process-unique sequence. herdr uses seq to discard
114
+ # out-of-order reports, so it must only ever increase.
115
+ self._seq = int(time.time() * 1000) * 1000
116
+ self._worker: Optional[threading.Thread] = None
117
+ if self._active:
118
+ self._start_worker()
119
+
120
+ @property
121
+ def active(self) -> bool:
122
+ return self._active
123
+
124
+ def _start_worker(self) -> None:
125
+ self._worker = threading.Thread(
126
+ target=self._run,
127
+ name="herdr-reporter",
128
+ daemon=True,
129
+ )
130
+ self._worker.start()
131
+
132
+ def _next_seq(self) -> int:
133
+ with self._seq_lock:
134
+ self._seq += 1
135
+ return self._seq
136
+
137
+ # -- public API ----------------------------------------------------
138
+
139
+ def report_state(
140
+ self,
141
+ state: str,
142
+ agent_session_id: Optional[str] = None,
143
+ *,
144
+ message: Optional[str] = None,
145
+ critical: bool = True,
146
+ ) -> None:
147
+ """Report a semantic state (``working`` / ``blocked`` / ``idle``).
148
+
149
+ A genuine state *edge* is ``critical`` (default) and jumps the queue.
150
+ A message-only refresh (same state, new activity text) should pass
151
+ ``critical=False`` so it rides the decorative lane and can never
152
+ delay an authoritative edge, session reference, or release.
153
+ """
154
+ params: Dict[str, Any] = {"state": state}
155
+ if agent_session_id:
156
+ params["agent_session_id"] = agent_session_id
157
+ if message:
158
+ params["message"] = message
159
+ self._put("_state" if critical else "_message", params)
160
+
161
+ def report_session(
162
+ self,
163
+ agent_session_id: Optional[str] = None,
164
+ session_path: Optional[str] = None,
165
+ ) -> None:
166
+ """Report a stable session reference (critical lane)."""
167
+ params: Dict[str, Any] = {}
168
+ if agent_session_id:
169
+ params["agent_session_id"] = agent_session_id
170
+ if session_path:
171
+ params["agent_session_path"] = session_path
172
+ if not params:
173
+ return
174
+ self._put("_session", params)
175
+
176
+ def report_metadata(self, tokens: Dict[str, Any]) -> None:
177
+ """Report pane metadata (model / context / tokens) on the decorative lane."""
178
+ if not tokens:
179
+ return
180
+ params: Dict[str, Any] = {
181
+ "applies_to_source": SOURCE,
182
+ "ttl_ms": _METADATA_TTL_MS,
183
+ "tokens": dict(tokens),
184
+ }
185
+ self._put("_metadata", params)
186
+
187
+ def _put(self, slot: str, params: Dict[str, Any]) -> None:
188
+ if not self._active:
189
+ return
190
+ with self._cond:
191
+ # Once a release is scheduled the pane is shutting down; refuse
192
+ # new work so the release stays the final wire event.
193
+ if self._closing:
194
+ return
195
+ setattr(self, slot, params)
196
+ self._cond.notify()
197
+
198
+ def release_and_close(self, timeout_s: float = 1.0) -> None:
199
+ """Schedule one ``pane.release_agent`` and wait up to ``timeout_s``.
200
+
201
+ Idempotent: repeated calls schedule a single release. Stops
202
+ decorative input, discards pending decorative work, lets any pending
203
+ critical work flush, then releases. The wait is bounded on the
204
+ caller side, so an unavailable herdr can never exceed ``timeout_s``.
205
+ """
206
+ if not self._active:
207
+ return
208
+ self._schedule_release()
209
+ self._released.wait(timeout=timeout_s)
210
+
211
+ def close(self) -> None:
212
+ """Best-effort, non-blocking shutdown: schedule the release and return."""
213
+ if not self._active:
214
+ return
215
+ self._schedule_release()
216
+
217
+ def _schedule_release(self) -> None:
218
+ with self._cond:
219
+ if self._release_scheduled:
220
+ return
221
+ self._release_scheduled = True
222
+ self._closing = True
223
+ # Decorative work is not worth delaying shutdown for.
224
+ self._message = None
225
+ self._metadata = None
226
+ self._release = {} # release_agent needs only the base params
227
+ self._cond.notify()
228
+
229
+ # -- worker --------------------------------------------------------
230
+
231
+ def _take_next_locked(self) -> Optional[Tuple[str, Dict[str, Any]]]:
232
+ """Pop the next job by priority. Caller holds ``self._cond``.
233
+
234
+ Order: critical state -> critical session -> (decorative message ->
235
+ decorative metadata, only while not closing) -> terminal release.
236
+ Critical work therefore always overtakes decorative work, and the
237
+ release is only taken once the critical lane is drained.
238
+ """
239
+ if self._state is not None:
240
+ params, self._state = self._state, None
241
+ return _M_STATE, params
242
+ if self._session is not None:
243
+ params, self._session = self._session, None
244
+ return _M_SESSION, params
245
+ if not self._closing:
246
+ if self._message is not None:
247
+ params, self._message = self._message, None
248
+ return _M_STATE, params
249
+ if self._metadata is not None:
250
+ params, self._metadata = self._metadata, None
251
+ return _M_METADATA, params
252
+ if self._closing and self._release is not None:
253
+ params, self._release = self._release, None
254
+ return _M_RELEASE, params
255
+ return None
256
+
257
+ def _run(self) -> None:
258
+ while True:
259
+ with self._cond:
260
+ job = self._take_next_locked()
261
+ while job is None:
262
+ if self._closing:
263
+ # Nothing left and shutting down -> unblock waiters.
264
+ self._released.set()
265
+ return
266
+ self._cond.wait()
267
+ job = self._take_next_locked()
268
+ method, params = job
269
+ self._send(method, params)
270
+ if method == _M_RELEASE:
271
+ self._released.set()
272
+ return
273
+
274
+ def _send(self, method: str, params: Dict[str, Any]) -> None:
275
+ # Assign id + seq at wire time so critical work that overtook
276
+ # decorative work still gets a higher (later) sequence number.
277
+ seq = self._next_seq()
278
+ envelope = {
279
+ "id": f"{SOURCE}:{seq}",
280
+ "method": method,
281
+ "params": {
282
+ "pane_id": self._pane_id,
283
+ "source": SOURCE,
284
+ "agent": AGENT,
285
+ "seq": seq,
286
+ **params,
287
+ },
288
+ }
289
+ payload = (json.dumps(envelope) + "\n").encode("utf-8")
290
+ last_exc: Optional[Exception] = None
291
+ for attempt in range(_SEND_ATTEMPTS):
292
+ try:
293
+ if self._deliver(payload):
294
+ return
295
+ except (OSError, ValueError) as exc:
296
+ last_exc = exc
297
+ if attempt + 1 < _SEND_ATTEMPTS:
298
+ time.sleep(_SEND_BACKOFF_S)
299
+ # herdr may have exited or the pane was closed. Nothing left to do but
300
+ # note it on the diagnostic channel -- never raise into the agent.
301
+ logger.debug(
302
+ "herdr %s undelivered after %d attempts: %s",
303
+ method,
304
+ _SEND_ATTEMPTS,
305
+ last_exc,
306
+ )
307
+
308
+ def _deliver(self, payload: bytes) -> bool:
309
+ """One wire attempt. ``True`` means herdr acked the report.
310
+
311
+ Any nonempty response is an ack: herdr already treats the report as
312
+ taken (even a busy ``shown:false`` reply). No bytes (closed /
313
+ timed-out) means it may not have applied -> caller retries the
314
+ identical envelope.
315
+ """
316
+ if os.name == "nt":
317
+ return self._deliver_pipe(payload)
318
+ return self._deliver_unix(payload)
319
+
320
+ def _deliver_unix(self, payload: bytes) -> bool:
321
+ with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
322
+ sock.settimeout(_CONNECT_TIMEOUT_S)
323
+ sock.connect(self._socket_path) # type: ignore[arg-type]
324
+ sock.sendall(payload)
325
+ return bool(sock.recv(_ACK_BYTES))
326
+
327
+ def _deliver_pipe(self, payload: bytes) -> bool:
328
+ # Windows herdr (Rust ``interprocess``) exposes ``\\.\pipe\<full path>``; the
329
+ # .sock file is just a pid marker. CreateFile fails fast when herdr's gone
330
+ # (OSError -> retry). The ack read has no timeout, but replies are immediate,
331
+ # the worker is a daemon thread, and release_and_close is bounded, so a wedged
332
+ # herdr can't hang the agent or its shutdown.
333
+ pipe_name = "\\\\.\\pipe\\" + str(self._socket_path)
334
+ with open(pipe_name, "r+b", buffering=0) as pipe:
335
+ pipe.write(payload)
336
+ return bool(pipe.readline(_ACK_BYTES))
337
+
338
+
339
+ __all__ = ["HerdrClient", "SOURCE", "AGENT"]
@@ -0,0 +1,140 @@
1
+ """herdr integration -- report code-puppy's state to a herdr pane.
2
+
3
+ This built-in plugin is a no-op unless code-puppy is running inside a
4
+ `herdr <https://herdr.dev>`_ pane (detected via the ``HERDR_ENV`` /
5
+ ``HERDR_SOCKET_PATH`` / ``HERDR_PANE_ID`` environment variables herdr
6
+ injects). When it is, it reports semantic agent state -- ``working`` /
7
+ ``blocked`` / ``idle`` -- over herdr's local socket so herdr's sidebar
8
+ can roll code-puppy up alongside every other agent in the fleet.
9
+
10
+ code-puppy reports its state **authoritatively**: herdr never infers it from
11
+ the screen. State is a pure function of two facts the plugin observes
12
+ directly (see reporter.py):
13
+
14
+ * run depth, from ``agent_run_start`` / ``agent_run_end`` -> ``working``
15
+ * awaiting-human, from the ``awaiting_user_input`` callback -> ``blocked``
16
+
17
+ The ``awaiting_user_input`` callback is the key: it fires from the single
18
+ process-wide choke-point (``command_runner.set_awaiting_user_input``) that
19
+ *every* interactive wait already passes through -- shell-command approval,
20
+ file-permission approval, ``ask_user_question``, and every menu/picker -- so
21
+ one hook captures every block. There is no per-prompt special-casing and
22
+ nothing for herdr to guess.
23
+
24
+ Callback -> effect:
25
+
26
+ * ``startup`` ......................................... resync (-> idle)
27
+ * ``session_end`` / ``shutdown`` ..................... release pane authority
28
+ * ``user_prompt_submit`` ............................. refresh durable session
29
+ * ``agent_run_start`` / ``agent_run_end`` ............ run-depth +/- 1
30
+ * ``pre_tool_call`` / ``post_tool_call`` ............. decorative activity msg
31
+ * ``agent_run_cancel`` / ``interactive_turn_end`` .... reset -> idle
32
+ * ``interactive_turn_cancel`` ........................ reset -> idle
33
+ * ``awaiting_user_input`` ............................ blocked <-> not
34
+
35
+ Session identity is the durable autosave (name, path) resolved by
36
+ ``sources.current_session_ref`` -- NOT the per-run ``group_id`` UUID, which
37
+ changes every turn. Pane metadata (model / context / tokens) and the
38
+ best-effort activity ``message`` are decorative: they never perturb the
39
+ authoritative state and never delay a state edge, session reference, or the
40
+ final ``pane.release_agent`` on exit.
41
+
42
+ Handlers are plain sync functions that swallow every argument: the callback
43
+ dispatcher passes hook args positionally and runs sync callbacks happily
44
+ from both async and worker-thread contexts, so ``*args`` is the robust
45
+ choice.
46
+ """
47
+
48
+ from __future__ import annotations
49
+
50
+ import logging
51
+
52
+ from code_puppy.callbacks import register_callback
53
+
54
+ from .client import HerdrClient
55
+ from .reporter import HerdrReporter
56
+
57
+ logger = logging.getLogger(__name__)
58
+
59
+ _client = HerdrClient()
60
+ _reporter = HerdrReporter(_client)
61
+
62
+
63
+ def _arg(args: tuple, index: int):
64
+ return args[index] if len(args) > index else None
65
+
66
+
67
+ def _on_startup(*_args, **_kw) -> None:
68
+ _reporter.on_startup()
69
+
70
+
71
+ def _on_user_prompt(*_args, **_kw) -> None:
72
+ # The callback's per-run group_id is ignored; the reporter resolves the
73
+ # durable session reference itself.
74
+ _reporter.on_user_prompt()
75
+
76
+
77
+ def _on_run_start(*_args, **_kw) -> None:
78
+ _reporter.on_run_start()
79
+
80
+
81
+ def _on_run_end(*_args, **_kw) -> None:
82
+ _reporter.on_run_end()
83
+
84
+
85
+ def _on_run_cancel(*_args, **_kw) -> None:
86
+ _reporter.on_run_cancel()
87
+
88
+
89
+ def _on_turn_end(*_args, **_kw) -> None:
90
+ _reporter.on_turn_end()
91
+
92
+
93
+ def _on_tool_start(*args, **kwargs):
94
+ # (tool_name, tool_args, context=None). Decorative only -> return None so
95
+ # the tool is never blocked or transformed.
96
+ tool_name = _arg(args, 0) if args else kwargs.get("tool_name")
97
+ _reporter.on_tool_start(str(tool_name) if tool_name is not None else "")
98
+ return None
99
+
100
+
101
+ def _on_tool_complete(*_args, **_kw):
102
+ # (tool_name, tool_args, result, duration_ms, context=None). Decorative.
103
+ _reporter.on_tool_complete()
104
+ return None
105
+
106
+
107
+ def _on_awaiting_user_input(*args, **_kw) -> None:
108
+ # Keep the public callback's historical one-argument signature. Notification
109
+ # intent is read synchronously from command_runner's current wait state.
110
+ from code_puppy.tools.command_runner import should_notify_awaiting_user_input
111
+
112
+ _reporter.on_awaiting_user_input(
113
+ bool(_arg(args, 0)),
114
+ notify=should_notify_awaiting_user_input(),
115
+ )
116
+
117
+
118
+ def _on_shutdown(*_args, **_kw) -> None:
119
+ _reporter.on_shutdown()
120
+
121
+
122
+ if _reporter.active:
123
+ register_callback("startup", _on_startup)
124
+ register_callback("user_prompt_submit", _on_user_prompt)
125
+ register_callback("agent_run_start", _on_run_start)
126
+ register_callback("agent_run_end", _on_run_end)
127
+ register_callback("agent_run_cancel", _on_run_cancel)
128
+ register_callback("interactive_turn_end", _on_turn_end)
129
+ register_callback("interactive_turn_cancel", _on_turn_end)
130
+ register_callback("pre_tool_call", _on_tool_start)
131
+ register_callback("post_tool_call", _on_tool_complete)
132
+ register_callback("awaiting_user_input", _on_awaiting_user_input)
133
+ register_callback("session_end", _on_shutdown)
134
+ register_callback("shutdown", _on_shutdown)
135
+ logger.debug("herdr plugin active for pane %s", _client._pane_id)
136
+ else:
137
+ logger.debug("herdr plugin inactive (not running inside a herdr pane)")
138
+
139
+
140
+ __all__ = ["HerdrClient", "HerdrReporter"]