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,110 @@
1
+ """Plugin registration: the ``--acp`` entry point.
2
+
3
+ This is the only place the ACP plugin touches Code Puppy's CLI. It:
4
+ 1. contributes a ``--acp`` flag via the ``register_cli_args`` hook, and
5
+ 2. in ``handle_cli_args``, when ``--acp`` is present, boots the ACP server
6
+ over stdio and returns the short-circuit sentinel so the normal
7
+ interactive TUI never starts.
8
+
9
+ Per the contributing guide, all of this rides on existing hooks — no edits to
10
+ ``code_puppy/command_line`` or the core CLI runner.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import asyncio
16
+ import logging
17
+ from typing import Any, Dict, Optional
18
+
19
+ from code_puppy.callbacks import register_callback
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ def _register_cli_args(parser: Any) -> None:
25
+ """Add the ``--acp`` flag to Code Puppy's argument parser."""
26
+ parser.add_argument(
27
+ "--acp",
28
+ action="store_true",
29
+ help="Run as a native agent over the Agent Client Protocol (ACP), speaking JSON-RPC over stdio.",
30
+ )
31
+
32
+
33
+ def _handle_cli_args(args: Any) -> Optional[Dict[str, Any]]:
34
+ """Boot the ACP server when ``--acp`` is set; otherwise stand down.
35
+
36
+ Returns the ``{"handled": True, "exit_code": ...}`` sentinel so the CLI
37
+ runner exits after the ACP session ends instead of falling through to the
38
+ interactive TUI. Any other invocation returns ``None`` (not ours).
39
+
40
+ This hook is invoked *synchronously from within* Code Puppy's already-
41
+ running ``asyncio.run(main())`` loop, so we cannot start a nested loop
42
+ here. Instead we run the server on its own event loop in a dedicated
43
+ thread and block until it finishes — which keeps ``main()`` parked so the
44
+ TUI never starts.
45
+ """
46
+ if not getattr(args, "acp", False):
47
+ return None
48
+
49
+ import threading
50
+
51
+ box: Dict[str, int] = {"exit_code": 0}
52
+
53
+ def _run() -> None:
54
+ try:
55
+ box["exit_code"] = asyncio.run(_serve())
56
+ except Exception: # noqa: BLE001 - never leak a traceback onto stdout
57
+ logger.exception("ACP server crashed")
58
+ box["exit_code"] = 1
59
+
60
+ thread = threading.Thread(target=_run, name="acp-server")
61
+ thread.start()
62
+ thread.join()
63
+ return {"handled": True, "exit_code": box["exit_code"]}
64
+
65
+
66
+ async def _serve() -> int:
67
+ """Bind stdio via the ACP SDK and run one connection to completion.
68
+
69
+ Before serving we protect stdout — the JSON-RPC channel — by pointing
70
+ Code Puppy's streaming console and the root logger at stderr. In ACP mode
71
+ the interactive path that normally calls ``set_streaming_console`` is
72
+ short-circuited, so without this the streaming console would fall back to a
73
+ plain ``Console()`` on stdout and corrupt the protocol.
74
+
75
+ ``acp.run_agent`` owns the wire (stdio binding, JSON-RPC framing, param
76
+ parsing); we hand it a ``CodePuppyAgent`` and tear down the approval + I/O
77
+ backends afterwards so the process leaves no global seams set.
78
+ """
79
+ import sys
80
+
81
+ from acp import run_agent
82
+ from rich.console import Console
83
+
84
+ from code_puppy.agents.event_stream_handler import set_streaming_console
85
+ from code_puppy_core_plugins.acp import io_delegation, permissions, state
86
+ from code_puppy_core_plugins.acp.agent import CodePuppyAgent
87
+
88
+ # Route all incidental console output to stderr; stdout is JSON-RPC only.
89
+ set_streaming_console(Console(file=sys.stderr))
90
+ logging.basicConfig(stream=sys.stderr, level=logging.WARNING)
91
+
92
+ agent = CodePuppyAgent()
93
+ try:
94
+ await run_agent(agent)
95
+ finally:
96
+ agent.shutdown()
97
+ permissions.uninstall()
98
+ io_delegation.uninstall()
99
+ state.set_connection(None, None)
100
+ return 0
101
+
102
+
103
+ def register() -> None:
104
+ """Register the ACP CLI hooks."""
105
+ register_callback("register_cli_args", _register_cli_args)
106
+ register_callback("handle_cli_args", _handle_cli_args)
107
+ logger.debug("ACP plugin callbacks registered")
108
+
109
+
110
+ register()
@@ -0,0 +1,114 @@
1
+ """Replay a rehydrated session's history back to the client on load/resume.
2
+
3
+ The ACP ``session/load`` (and ``session/resume``) contract is not just "rebuild
4
+ the agent's memory" -- the client rebuilds its *own* thread UI from the
5
+ ``session/update`` notifications the agent streams while handling the request.
6
+ An agent that only rehydrates its internal ``_message_history`` (and streams
7
+ nothing) leaves the client with an empty thread: the conversation looks gone,
8
+ and clients that treat an empty replayed thread as dead will discard it
9
+ outright.
10
+
11
+ So on load/resume we walk the rehydrated pydantic-ai message history and emit
12
+ one ``session/update`` per visible turn -- user prompts, assistant text,
13
+ assistant thinking, and past tool calls (as already-``completed`` entries) --
14
+ in order, before the load response returns. System prompts and tool-return
15
+ plumbing are intentionally skipped: they are model-plumbing, not conversation
16
+ the user needs to see re-rendered.
17
+
18
+ Everything here is best-effort: a replay hiccup must never fail the load, so
19
+ per-update send failures are logged and swallowed.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import logging
25
+ import uuid
26
+ from typing import Any, Iterable, List
27
+
28
+ from acp.helpers import (
29
+ start_tool_call,
30
+ update_agent_message_text,
31
+ update_agent_thought_text,
32
+ update_user_message_text,
33
+ )
34
+
35
+ from code_puppy_core_plugins.acp import state
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ async def replay_history(session_id: str, history: Iterable[Any]) -> None:
41
+ """Stream ``history`` back to the client as ordered ``session/update``s.
42
+
43
+ No-op when there is no connection or nothing to replay.
44
+ """
45
+ connection = state.get_connection()
46
+ if connection is None:
47
+ return
48
+ for message in history or []:
49
+ for update in _updates_for_message(message):
50
+ try:
51
+ await connection.session_update(session_id, update)
52
+ except Exception: # noqa: BLE001
53
+ logger.debug("ACP: history replay update failed", exc_info=True)
54
+
55
+
56
+ def _updates_for_message(message: Any) -> List[Any]:
57
+ """Map one pydantic-ai message to zero or more ACP updates.
58
+
59
+ Discriminates on each part's ``part_kind`` (stable across pydantic-ai
60
+ versions) rather than importing concrete part classes, so a version bump
61
+ that renames a class doesn't silently drop history.
62
+ """
63
+ updates: List[Any] = []
64
+ for part in getattr(message, "parts", None) or []:
65
+ kind = getattr(part, "part_kind", None)
66
+ if kind == "user-prompt":
67
+ text = _text_of(getattr(part, "content", None))
68
+ if text:
69
+ updates.append(update_user_message_text(text))
70
+ elif kind == "text":
71
+ text = _text_of(getattr(part, "content", None))
72
+ if text:
73
+ updates.append(update_agent_message_text(text))
74
+ elif kind == "thinking":
75
+ text = _text_of(getattr(part, "content", None))
76
+ if text:
77
+ updates.append(update_agent_thought_text(text))
78
+ elif kind == "tool-call":
79
+ updates.append(_tool_call_update(part))
80
+ # system-prompt / tool-return: model plumbing, not replayed.
81
+ return updates
82
+
83
+
84
+ def _tool_call_update(part: Any) -> Any:
85
+ """Render a past tool call as an already-``completed`` tool-call entry.
86
+
87
+ Replayed tool calls are historical, so they open and close in one update
88
+ (status ``completed``). A fresh id is minted -- the original call id isn't
89
+ needed since nothing will update this entry again.
90
+ """
91
+ tool_name = str(getattr(part, "tool_name", "") or "tool")
92
+ return start_tool_call(
93
+ f"tc_{uuid.uuid4().hex[:12]}",
94
+ tool_name,
95
+ kind="other",
96
+ status="completed",
97
+ )
98
+
99
+
100
+ def _text_of(content: Any) -> str:
101
+ """Flatten a part's content to plain text.
102
+
103
+ Handles the string case and pydantic-ai's multimodal list form (where a
104
+ user prompt is a list of str + binary/image blocks): string items are
105
+ kept, non-text blocks are dropped, since replay is a text reconstruction.
106
+ """
107
+ if content is None:
108
+ return ""
109
+ if isinstance(content, str):
110
+ return content.strip()
111
+ if isinstance(content, (list, tuple)):
112
+ parts = [item for item in content if isinstance(item, str)]
113
+ return "\n".join(p for p in parts if p).strip()
114
+ return str(content).strip()
@@ -0,0 +1,329 @@
1
+ """``ACPSession`` — one client thread bound to one Code Puppy agent.
2
+
3
+ Each ACP session id maps to a single ``BaseAgent`` instance whose
4
+ ``_message_history`` persists across ``session/prompt`` calls, giving native
5
+ multi-turn conversations. The session also carries the ``cwd`` the client
6
+ opened the thread in, so tools resolve paths relative to the right project.
7
+
8
+ Cancellation (``session/cancel``) is real: the prompt runs as an
9
+ ``asyncio.Task`` we hold a handle to, so a cancel notification cancels that
10
+ task. pydantic-ai surfaces the ``CancelledError``, which we translate into the
11
+ ``cancelled`` stop reason for the in-flight ``session/prompt`` reply.
12
+
13
+ Each turn also reports token usage (mapped from the pydantic-ai run result)
14
+ back on the ``PromptResponse`` so the client can show cost/usage.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+ import logging
21
+ from dataclasses import dataclass
22
+ from typing import TYPE_CHECKING, Any, List, Optional
23
+
24
+ from acp.schema import Usage
25
+
26
+ from code_puppy_core_plugins.acp import commands, content, persistence, state
27
+
28
+ if TYPE_CHECKING:
29
+ from code_puppy.agents.base_agent import BaseAgent
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+ # ACP stop reasons a ``session/prompt`` may resolve to.
34
+ STOP_END_TURN = "end_turn"
35
+ STOP_CANCELLED = "cancelled"
36
+ STOP_REFUSAL = "refusal"
37
+
38
+
39
+ @dataclass
40
+ class PromptResult:
41
+ """Outcome of one turn: an ACP stop reason plus optional token usage."""
42
+
43
+ stop_reason: str
44
+ usage: Optional[Usage] = None
45
+
46
+
47
+ class ACPSession:
48
+ """State + run lifecycle for a single client agent thread."""
49
+
50
+ def __init__(
51
+ self,
52
+ session_id: str,
53
+ agent: "BaseAgent",
54
+ cwd: Optional[str] = None,
55
+ additional_directories: Optional[List[str]] = None,
56
+ mcp_specs: Optional[List[Any]] = None,
57
+ ) -> None:
58
+ self.session_id = session_id
59
+ self.agent = agent
60
+ self.cwd = cwd
61
+ self.additional_directories = list(additional_directories or [])
62
+ # Raw client-injected ACP MCP specs, retained so they can be re-attached
63
+ # if the session's agent is rebuilt (e.g. on ``session/set_mode``).
64
+ self.mcp_specs = list(mcp_specs or [])
65
+ # Set while a ``session/prompt`` is in flight so ``cancel`` has a task
66
+ # to cancel. ``None`` means idle.
67
+ self._task: Optional["asyncio.Task[Any]"] = None
68
+
69
+ async def prompt(self, blocks: List[Any]) -> PromptResult:
70
+ """Run the agent on a user turn and return the stop reason + usage.
71
+
72
+ Flow:
73
+ 1. Flatten ACP content blocks into the user text.
74
+ 2. Point the messaging session context + run context at this session
75
+ so streamed deltas and tool calls are tagged/correlated.
76
+ 3. Run ``agent.run_with_mcp(text)`` as a cancellable task — history
77
+ stays on the agent instance, so the next turn continues.
78
+ 4. If nothing streamed (streaming disabled/empty), send the final
79
+ result text as one ``agent_message_chunk`` so the client sees it.
80
+ """
81
+ from code_puppy.messaging import set_session_context
82
+
83
+ parsed = content.parse_prompt(blocks)
84
+ text = parsed.text
85
+ if not text.strip() and not parsed.attachments and not parsed.link_attachments:
86
+ return PromptResult(STOP_END_TURN)
87
+ # A leading /slash command runs via Code Puppy's command handler (not the
88
+ # model); if it expands into a prompt (string result), run the model on it,
89
+ # exactly as cli_runner does with a string command result.
90
+ if (
91
+ not parsed.attachments
92
+ and not parsed.link_attachments
93
+ and commands.is_command(text)
94
+ ):
95
+ expanded = await commands.run(self.session_id, text)
96
+ if not expanded:
97
+ return PromptResult(STOP_END_TURN)
98
+ text = expanded
99
+ # Resolve relative paths against this session's own cwd -- no process-global
100
+ # os.chdir (would corrupt the SDK's I/O + any concurrent session).
101
+ from code_puppy.tools.common import (
102
+ reset_working_directory,
103
+ set_working_directory,
104
+ )
105
+ from code_puppy.tools.subagent_context import (
106
+ reset_conversation_root_id,
107
+ set_conversation_root_id,
108
+ )
109
+
110
+ cwd_token = set_working_directory(self.cwd) if self.cwd else None
111
+ # ContextVar, not set_session_context: conversation_scope reads it and needs
112
+ # real per-task isolation across concurrent ACP sessions, which the shared
113
+ # mutable attribute can't provide.
114
+ root_id_token = set_conversation_root_id(self.session_id)
115
+
116
+ set_session_context(self.session_id)
117
+ state.begin_run(self.session_id)
118
+ result: Any = None
119
+ error: Optional[BaseException] = None
120
+ try:
121
+ self._task = asyncio.ensure_future(
122
+ self.agent.run_with_mcp(
123
+ text,
124
+ attachments=parsed.attachments or None,
125
+ link_attachments=parsed.link_attachments or None,
126
+ )
127
+ )
128
+ result = await self._task
129
+ self._absorb_history(result)
130
+ stop_reason = STOP_END_TURN
131
+ except asyncio.CancelledError:
132
+ # Two ways here: our own cancel cancelled the inner task (report
133
+ # ``cancelled``), or THIS coroutine was cancelled (SDK teardown) while the
134
+ # task lives on -> cancel it so it can't outlive us, and propagate.
135
+ task = self._task
136
+ if task is not None and not task.cancelled():
137
+ task.cancel()
138
+ raise
139
+ stop_reason = STOP_CANCELLED
140
+ except Exception as exc: # noqa: BLE001
141
+ logger.exception("ACP: agent run failed")
142
+ error = exc
143
+ stop_reason = STOP_REFUSAL
144
+ finally:
145
+ streamed = state.streamed_text()
146
+ self._task = None
147
+ state.end_run()
148
+ set_session_context(None)
149
+ reset_conversation_root_id(root_id_token)
150
+ if cwd_token is not None:
151
+ reset_working_directory(cwd_token)
152
+
153
+ # Persist off the event loop so pickling a large history can't stall other
154
+ # sessions' streaming. Best-effort; never fails the turn.
155
+ try:
156
+ await asyncio.to_thread(
157
+ persistence.save,
158
+ self.session_id,
159
+ self.agent,
160
+ self.cwd,
161
+ self.additional_directories,
162
+ )
163
+ except Exception: # noqa: BLE001
164
+ logger.debug("ACP: async persist failed", exc_info=True)
165
+
166
+ if stop_reason == STOP_END_TURN and not streamed and result is not None:
167
+ await self._send_final_result(result)
168
+ elif stop_reason == STOP_REFUSAL:
169
+ await self._send_error_notice(error)
170
+ return PromptResult(stop_reason, _to_acp_usage(result))
171
+
172
+ def _absorb_history(self, result: Any) -> None:
173
+ """Fold a completed run's full message list back into the agent.
174
+
175
+ ``run_with_mcp`` (the shared runtime) does NOT write the turn's
176
+ request+response back onto ``agent._message_history`` on the normal
177
+ path -- the caller must, exactly as ``cli_runner`` does after each
178
+ interactive turn. Without this the agent forgets every turn the moment
179
+ it ends: the next prompt runs with empty history, and persistence saves
180
+ a history containing only the user's prompt (no assistant reply). So we
181
+ replace the agent's history with ``result.all_messages()`` here, which
182
+ is what makes ACP multi-turn memory *and* load/resume replay real.
183
+ """
184
+ if result is None:
185
+ return
186
+ try:
187
+ messages = result.all_messages()
188
+ except Exception: # noqa: BLE001
189
+ return
190
+ if messages:
191
+ self.agent.set_message_history(list(messages))
192
+
193
+ def cancel(self) -> None:
194
+ """Cancel the in-flight run, if any. No-op when idle.
195
+
196
+ Besides cancelling the asyncio task, force-kill any local shell
197
+ processes the run spawned so they don't orphan. (Shells delegated to
198
+ the client run client-side and are unaffected.)
199
+
200
+ Only *requests* cancellation -- delivery happens at the task's next
201
+ await point, whenever that is, not immediately. Callers that need
202
+ the run to have actually finished unwinding (its ``finally`` block
203
+ included) before they act should use :meth:`cancel_and_wait` instead.
204
+ """
205
+ task = self._task
206
+ if task is not None and not task.done():
207
+ task.cancel()
208
+ try:
209
+ from code_puppy.tools.command_runner import (
210
+ kill_all_running_shell_processes,
211
+ )
212
+
213
+ kill_all_running_shell_processes()
214
+ except Exception: # noqa: BLE001
215
+ logger.debug("ACP: shell kill on cancel failed", exc_info=True)
216
+
217
+ async def cancel_and_wait(self, timeout: float = 2.0) -> None:
218
+ """Cancel the in-flight run and wait for it to actually unwind.
219
+
220
+ ``cancel()`` alone only *requests* cancellation; asyncio only
221
+ delivers it at the task's next await point, with no guarantee of
222
+ when that is. A caller that needs the run's own cleanup to have
223
+ genuinely finished first -- notably ``close_session`` purging this
224
+ session's warn-dedup bucket, which would otherwise race a
225
+ still-in-flight ``_invoke_agent_impl`` synchronously writing into
226
+ that same bucket a moment later -- must await this instead of the
227
+ bare ``cancel()``.
228
+
229
+ Bounded by ``timeout`` so a run stuck ignoring cancellation (blocked
230
+ in genuinely non-cancellable I/O, say) can't hang session close
231
+ forever; on timeout we give up waiting and return anyway -- the task
232
+ is still cancelled, just not confirmed finished.
233
+ """
234
+ task = self._task
235
+ self.cancel()
236
+ if task is None:
237
+ return
238
+ try:
239
+ await asyncio.wait_for(task, timeout=timeout)
240
+ except (asyncio.CancelledError, asyncio.TimeoutError):
241
+ pass
242
+ except Exception: # noqa: BLE001
243
+ # prompt()'s own except block already logs/handles run failures;
244
+ # a close shouldn't raise because the run it interrupted failed.
245
+ logger.debug("ACP: cancel_and_wait observed run failure", exc_info=True)
246
+
247
+ async def _send_error_notice(self, error: Optional[BaseException]) -> None:
248
+ """Tell the client a turn failed, so it isn't a silent empty response.
249
+
250
+ A ``refusal`` stop reason alone renders as nothing in most clients; a
251
+ short message chunk makes the failure visible without leaking a stack
252
+ trace (the full traceback is logged to stderr).
253
+ """
254
+ from acp.helpers import update_agent_message_text
255
+
256
+ connection = state.get_connection()
257
+ if connection is None:
258
+ return
259
+ detail = f": {error}" if error else "."
260
+ try:
261
+ await connection.session_update(
262
+ self.session_id,
263
+ update_agent_message_text(f"\u26a0\ufe0f The agent run failed{detail}"),
264
+ )
265
+ except Exception: # noqa: BLE001
266
+ logger.debug("ACP: failed to send error notice", exc_info=True)
267
+
268
+ async def _send_final_result(self, result: Any) -> None:
269
+ """Emit the run's final text when nothing streamed during the turn."""
270
+ from acp.helpers import update_agent_message_text
271
+
272
+ final_text = self._extract_result_text(result)
273
+ if not final_text:
274
+ return
275
+ connection = state.get_connection()
276
+ if connection is None:
277
+ return
278
+ try:
279
+ await connection.session_update(
280
+ self.session_id, update_agent_message_text(final_text)
281
+ )
282
+ except Exception: # noqa: BLE001
283
+ logger.exception("ACP: failed to send final result")
284
+
285
+ @staticmethod
286
+ def _extract_result_text(result: Any) -> str:
287
+ """Pull display text out of a pydantic-ai run result.
288
+
289
+ Mirrors ``_runtime``'s output extraction: prefer ``output``, then the
290
+ legacy ``data`` attribute, then ``str()``.
291
+ """
292
+ for attr in ("output", "data"):
293
+ value = getattr(result, attr, None)
294
+ if value:
295
+ return str(value)
296
+ return str(result) if result else ""
297
+
298
+
299
+ def _to_acp_usage(result: Any) -> Optional[Usage]:
300
+ """Map a pydantic-ai run result's usage onto ACP's ``Usage`` model.
301
+
302
+ Field names have drifted across pydantic-ai versions, so each ACP field is
303
+ resolved from a list of candidate attributes. Returns ``None`` when no
304
+ usage is available so we simply omit it from the response.
305
+ """
306
+ if result is None:
307
+ return None
308
+ try:
309
+ usage = result.usage()
310
+ except Exception: # noqa: BLE001
311
+ return None
312
+ if usage is None:
313
+ return None
314
+
315
+ def pick(*names: str) -> Optional[int]:
316
+ for name in names:
317
+ value = getattr(usage, name, None)
318
+ if value is not None:
319
+ return int(value)
320
+ return None
321
+
322
+ return Usage(
323
+ input_tokens=pick("input_tokens", "request_tokens", "prompt_tokens"),
324
+ output_tokens=pick("output_tokens", "response_tokens", "completion_tokens"),
325
+ total_tokens=pick("total_tokens"),
326
+ cached_read_tokens=pick("cache_read_tokens", "cached_read_tokens"),
327
+ cached_write_tokens=pick("cache_write_tokens", "cached_write_tokens"),
328
+ thought_tokens=pick("thinking_tokens", "thought_tokens", "reasoning_tokens"),
329
+ )