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,392 @@
1
+ """Remote skill downloader/installer.
2
+
3
+ Downloads a remote skill ZIP and installs it into the local skills directory.
4
+
5
+ Security notes:
6
+ - Defends against zip-slip path traversal.
7
+ - Defends (somewhat) against zip bombs by capping total uncompressed size.
8
+
9
+ This module never raises to callers; failures are returned as InstallResult.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ import shutil
16
+ import tempfile
17
+ import zipfile
18
+ from pathlib import Path
19
+ from typing import Optional
20
+
21
+ import httpx
22
+
23
+ from code_puppy_core_plugins.agent_skills.discovery import refresh_skill_cache
24
+ from code_puppy_core_plugins.agent_skills.installer import InstallResult
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ _DEFAULT_SKILLS_DIR = Path.home() / ".code_puppy" / "skills"
29
+ _MAX_UNCOMPRESSED_BYTES = 50 * 1024 * 1024 # 50MB
30
+
31
+
32
+ def _zip_entry_parts(name: str) -> list[str]:
33
+ """Return safe-ish path parts for a zip entry.
34
+
35
+ Zip files use POSIX-style separators, but malicious zips sometimes include
36
+ backslashes. We normalize to '/' then split.
37
+ """
38
+
39
+ normalized = name.replace("\\", "/")
40
+ return [part for part in normalized.split("/") if part not in {"", "."}]
41
+
42
+
43
+ def _safe_rmtree(path: Path) -> bool:
44
+ """Remove a directory tree, logging errors instead of raising."""
45
+
46
+ try:
47
+ if not path.exists():
48
+ return True
49
+ shutil.rmtree(path)
50
+ return True
51
+ except Exception as e:
52
+ logger.warning(f"Failed to remove directory {path}: {e}")
53
+ return False
54
+
55
+
56
+ def _download_to_file(url: str, dest: Path) -> bool:
57
+ """Download a URL to a local file path with streaming."""
58
+
59
+ headers = {
60
+ "Accept": "application/zip, application/octet-stream, */*",
61
+ "User-Agent": "code-puppy/skill-downloader",
62
+ }
63
+
64
+ try:
65
+ dest.parent.mkdir(parents=True, exist_ok=True)
66
+
67
+ with httpx.Client(timeout=30, headers=headers, follow_redirects=True) as client:
68
+ with client.stream("GET", url) as response:
69
+ response.raise_for_status()
70
+
71
+ with dest.open("wb") as f:
72
+ for chunk in response.iter_bytes():
73
+ if chunk:
74
+ f.write(chunk)
75
+
76
+ logger.info(f"Downloaded skill zip to {dest}")
77
+ return True
78
+
79
+ except httpx.HTTPStatusError as e:
80
+ logger.warning(
81
+ "Skill download failed with HTTP status: "
82
+ f"{e.response.status_code} {e.response.reason_phrase}"
83
+ )
84
+ return False
85
+ except (httpx.ConnectError, httpx.TimeoutException, httpx.NetworkError) as e:
86
+ logger.warning(f"Skill download network failure: {e}")
87
+ return False
88
+ except Exception as e:
89
+ logger.exception(f"Unexpected error downloading {url}: {e}")
90
+ return False
91
+
92
+
93
+ def _is_within_directory(base_dir: Path, candidate: Path) -> bool:
94
+ """Check that a path is safely contained within a directory."""
95
+
96
+ try:
97
+ base_resolved = base_dir.resolve()
98
+ candidate_resolved = candidate.resolve()
99
+ candidate_resolved.relative_to(base_resolved)
100
+ return True
101
+ except Exception:
102
+ return False
103
+
104
+
105
+ def _validate_zip_safety(zf: zipfile.ZipFile) -> Optional[str]:
106
+ """Return an error message if unsafe, otherwise None."""
107
+
108
+ total_uncompressed = 0
109
+
110
+ for info in zf.infolist():
111
+ # Directory entries are fine.
112
+ if info.is_dir():
113
+ continue
114
+
115
+ total_uncompressed += int(info.file_size or 0)
116
+ if total_uncompressed > _MAX_UNCOMPRESSED_BYTES:
117
+ return (
118
+ "ZIP appears too large when uncompressed "
119
+ f"(>{_MAX_UNCOMPRESSED_BYTES} bytes)"
120
+ )
121
+
122
+ # Basic zip-slip protection: reject absolute paths and parent traversals.
123
+ name = info.filename
124
+ normalized = name.replace("\\", "/")
125
+ if normalized.startswith("/"):
126
+ return f"Unsafe zip entry path (absolute): {name}"
127
+
128
+ parts = _zip_entry_parts(name)
129
+ if ".." in parts:
130
+ return f"Unsafe zip entry path (traversal): {name}"
131
+
132
+ return None
133
+
134
+
135
+ def _safe_extract_zip(zf: zipfile.ZipFile, extract_dir: Path) -> bool:
136
+ """Safely extract zip contents into extract_dir."""
137
+
138
+ try:
139
+ extract_dir.mkdir(parents=True, exist_ok=True)
140
+
141
+ for info in zf.infolist():
142
+ parts = _zip_entry_parts(info.filename)
143
+
144
+ # Skip weird metadata folders.
145
+ if parts and parts[0] == "__MACOSX":
146
+ continue
147
+
148
+ dest_path = extract_dir.joinpath(*parts)
149
+
150
+ if not _is_within_directory(extract_dir, dest_path):
151
+ logger.warning(
152
+ f"Blocked zip entry outside extraction dir: {info.filename}"
153
+ )
154
+ return False
155
+
156
+ if info.is_dir():
157
+ dest_path.mkdir(parents=True, exist_ok=True)
158
+ continue
159
+
160
+ dest_path.parent.mkdir(parents=True, exist_ok=True)
161
+
162
+ with zf.open(info, "r") as src, dest_path.open("wb") as dst:
163
+ shutil.copyfileobj(src, dst)
164
+
165
+ return True
166
+
167
+ except Exception as e:
168
+ logger.exception(f"Failed to extract zip safely: {e}")
169
+ return False
170
+
171
+
172
+ def _determine_extracted_root(extract_dir: Path) -> Optional[Path]:
173
+ """Determine where the skill files live inside an extracted zip.
174
+
175
+ Supports:
176
+ - Files at the zip root
177
+ - Files inside a single top-level folder
178
+
179
+ Returns:
180
+ Path to the directory containing SKILL.md, or None.
181
+ """
182
+
183
+ try:
184
+ if (extract_dir / "SKILL.md").is_file():
185
+ return extract_dir
186
+
187
+ children = [p for p in extract_dir.iterdir() if p.name != "__MACOSX"]
188
+ dirs = [p for p in children if p.is_dir()]
189
+ files = [p for p in children if p.is_file()]
190
+
191
+ # If it's root-level but SKILL.md missing, no good.
192
+ if files:
193
+ return None
194
+
195
+ if len(dirs) == 1:
196
+ candidate = dirs[0]
197
+ if (candidate / "SKILL.md").is_file():
198
+ return candidate
199
+
200
+ return None
201
+
202
+ except Exception as e:
203
+ logger.warning(f"Failed to inspect extracted zip directory {extract_dir}: {e}")
204
+ return None
205
+
206
+
207
+ def _stage_normalized_install(
208
+ extracted_root: Path, skill_name: str, staging_base: Path
209
+ ) -> Optional[Path]:
210
+ """Copy extracted content into staging_base/<skill_name>."""
211
+
212
+ try:
213
+ staged_skill_dir = staging_base / skill_name
214
+ if staged_skill_dir.exists():
215
+ _safe_rmtree(staged_skill_dir)
216
+
217
+ shutil.copytree(extracted_root, staged_skill_dir)
218
+
219
+ if not (staged_skill_dir / "SKILL.md").is_file():
220
+ logger.warning(
221
+ f"Staged skill is missing SKILL.md: {(staged_skill_dir / 'SKILL.md')}"
222
+ )
223
+ return None
224
+
225
+ return staged_skill_dir
226
+
227
+ except Exception as e:
228
+ logger.exception(f"Failed to stage normalized install for {skill_name}: {e}")
229
+ return None
230
+
231
+
232
+ def download_and_install_skill(
233
+ skill_name: str,
234
+ download_url: str,
235
+ target_dir: Optional[Path] = None,
236
+ force: bool = False,
237
+ ) -> InstallResult:
238
+ """Download and install a remote skill zip.
239
+
240
+ Args:
241
+ skill_name: Skill name (directory name under target_dir).
242
+ download_url: Absolute URL to the skill .zip.
243
+ target_dir: Base skills directory. Defaults to ~/.code_puppy/skills.
244
+ force: If True, delete any existing install first.
245
+
246
+ Returns:
247
+ InstallResult indicating success/failure.
248
+ """
249
+
250
+ skill_name = skill_name.strip()
251
+ if not skill_name:
252
+ return InstallResult(success=False, message="skill_name is required")
253
+
254
+ # Prevent path traversal via skill_name.
255
+ if Path(skill_name).name != skill_name or skill_name in {".", ".."}:
256
+ return InstallResult(
257
+ success=False, message="skill_name must be a simple directory name"
258
+ )
259
+
260
+ base_dir = target_dir or _DEFAULT_SKILLS_DIR
261
+ skill_dir = base_dir / skill_name
262
+
263
+ try:
264
+ if skill_dir.exists():
265
+ if not force:
266
+ return InstallResult(
267
+ success=False,
268
+ message=f"Skill already installed at {skill_dir} (use force=True to reinstall)",
269
+ installed_path=skill_dir,
270
+ )
271
+
272
+ logger.info(
273
+ f"Force reinstall enabled; removing existing skill at {skill_dir}"
274
+ )
275
+ if not _safe_rmtree(skill_dir):
276
+ return InstallResult(
277
+ success=False,
278
+ message=f"Failed to remove existing skill directory: {skill_dir}",
279
+ installed_path=skill_dir,
280
+ )
281
+
282
+ base_dir.mkdir(parents=True, exist_ok=True)
283
+
284
+ with tempfile.TemporaryDirectory(prefix="code_puppy_skill_") as tmp:
285
+ tmp_dir = Path(tmp)
286
+ tmp_zip = tmp_dir / f"{skill_name}.zip"
287
+ extract_dir = tmp_dir / "extracted"
288
+ staging_dir = tmp_dir / "staging"
289
+ staging_dir.mkdir(parents=True, exist_ok=True)
290
+
291
+ if not _download_to_file(download_url, tmp_zip):
292
+ return InstallResult(
293
+ success=False,
294
+ message=f"Failed to download skill zip from {download_url}",
295
+ )
296
+
297
+ try:
298
+ with zipfile.ZipFile(tmp_zip, "r") as zf:
299
+ unsafe_reason = _validate_zip_safety(zf)
300
+ if unsafe_reason:
301
+ logger.warning(
302
+ f"Rejected unsafe zip for {skill_name}: {unsafe_reason}"
303
+ )
304
+ return InstallResult(
305
+ success=False,
306
+ message=f"Rejected unsafe zip: {unsafe_reason}",
307
+ )
308
+
309
+ if not _safe_extract_zip(zf, extract_dir):
310
+ return InstallResult(
311
+ success=False,
312
+ message="Failed to extract skill zip safely",
313
+ )
314
+ except zipfile.BadZipFile:
315
+ logger.warning(f"Downloaded file is not a valid zip: {tmp_zip}")
316
+ return InstallResult(
317
+ success=False, message="Downloaded file is not a valid zip"
318
+ )
319
+ except Exception as e:
320
+ logger.exception(f"Failed to open/extract zip for {skill_name}: {e}")
321
+ return InstallResult(success=False, message="Failed to extract zip")
322
+
323
+ extracted_root = _determine_extracted_root(extract_dir)
324
+ if extracted_root is None:
325
+ logger.warning(
326
+ "Extracted zip layout not recognized or missing SKILL.md. "
327
+ f"extract_dir={extract_dir}"
328
+ )
329
+ return InstallResult(
330
+ success=False,
331
+ message="Extracted zip missing SKILL.md or has unexpected layout",
332
+ )
333
+
334
+ staged_skill_dir = _stage_normalized_install(
335
+ extracted_root=extracted_root,
336
+ skill_name=skill_name,
337
+ staging_base=staging_dir,
338
+ )
339
+ if staged_skill_dir is None:
340
+ return InstallResult(
341
+ success=False,
342
+ message="Failed to stage extracted skill (missing SKILL.md)",
343
+ )
344
+
345
+ # Move staged install into final destination.
346
+ try:
347
+ if skill_dir.exists():
348
+ # Shouldn't happen (handled earlier), but be safe.
349
+ if force:
350
+ _safe_rmtree(skill_dir)
351
+ else:
352
+ return InstallResult(
353
+ success=False,
354
+ message=f"Skill directory already exists: {skill_dir}",
355
+ installed_path=skill_dir,
356
+ )
357
+
358
+ shutil.move(str(staged_skill_dir), str(skill_dir))
359
+ except Exception as e:
360
+ logger.exception(f"Failed to install skill into {skill_dir}: {e}")
361
+ # Cleanup partial install.
362
+ _safe_rmtree(skill_dir)
363
+ return InstallResult(
364
+ success=False, message="Failed to move skill into place"
365
+ )
366
+
367
+ # Post-install verification.
368
+ if not (skill_dir / "SKILL.md").is_file():
369
+ logger.warning(f"Installed skill missing SKILL.md: {skill_dir}")
370
+ _safe_rmtree(skill_dir)
371
+ return InstallResult(
372
+ success=False,
373
+ message="Installed skill is missing SKILL.md",
374
+ installed_path=skill_dir,
375
+ )
376
+
377
+ try:
378
+ refresh_skill_cache()
379
+ except Exception as e:
380
+ # Cache refresh failure should not poison a successful install.
381
+ logger.warning(f"Skill installed but failed to refresh skill cache: {e}")
382
+
383
+ logger.info(f"Installed skill '{skill_name}' into {skill_dir}")
384
+ return InstallResult(
385
+ success=True,
386
+ message=f"Installed skill '{skill_name}'",
387
+ installed_path=skill_dir,
388
+ )
389
+
390
+ except Exception as e:
391
+ logger.exception(f"Unexpected error installing skill {skill_name}: {e}")
392
+ return InstallResult(success=False, message="Unexpected error installing skill")
@@ -0,0 +1,82 @@
1
+ """Single source of truth for `enabled skills with parsed frontmatter`.
2
+
3
+ Everywhere we want to surface skills to the model (prompt injection, the
4
+ ``list_or_search_skills`` tool, per-skill slash commands) we follow the same
5
+ three-step dance:
6
+
7
+ 1. discover skills on disk + plugin-registered ones,
8
+ 2. filter out disabled skills (and skills missing ``SKILL.md``),
9
+ 3. parse frontmatter for the survivors.
10
+
11
+ Centralising it here guarantees we **never** read frontmatter for a disabled
12
+ skill — and removes the temptation to reimplement the dance a fourth time.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from pathlib import Path
18
+ from typing import Iterator, List, Optional
19
+
20
+ # Import modules (not names) so monkeypatching at `<module>.attr` reaches us.
21
+ from . import config as _config
22
+ from . import discovery as _discovery
23
+ from . import metadata as _metadata
24
+ from .discovery import SkillInfo
25
+ from .metadata import SkillMetadata
26
+
27
+
28
+ def iter_enabled_skill_metadata(
29
+ *, directories: Optional[List[Path]] = None
30
+ ) -> Iterator[SkillMetadata]:
31
+ """Yield ``SkillMetadata`` for every enabled, valid skill.
32
+
33
+ Frontmatter is only read for skills that survive the disabled check —
34
+ so this function is also the cheapest way to ask "what's actually live?".
35
+
36
+ If skills integration is globally disabled, yields nothing.
37
+
38
+ Args:
39
+ directories: Optional explicit list of directories to scan. Defaults
40
+ to the configured + default skill directories (the standard path).
41
+ """
42
+ if not _config.get_skills_enabled():
43
+ return
44
+
45
+ disabled = _config.get_disabled_skills()
46
+
47
+ for info in _discovery.discover_skills(directories):
48
+ if not info.has_skill_md:
49
+ continue
50
+ if info.name in disabled:
51
+ continue
52
+ meta = _metadata.parse_skill_metadata(info.path)
53
+ if meta is not None:
54
+ yield meta
55
+
56
+
57
+ def list_enabled_skill_metadata(
58
+ *, directories: Optional[List[Path]] = None
59
+ ) -> List[SkillMetadata]:
60
+ """Materialised list version of :func:`iter_enabled_skill_metadata`."""
61
+ return list(iter_enabled_skill_metadata(directories=directories))
62
+
63
+
64
+ def iter_enabled_skills(
65
+ *, directories: Optional[List[Path]] = None
66
+ ) -> Iterator[SkillInfo]:
67
+ """Yield ``SkillInfo`` for enabled skills *without* parsing frontmatter.
68
+
69
+ Useful when a caller only needs the path/name (e.g. to load the full
70
+ ``SKILL.md`` body) and doesn't want to pay the YAML-parse cost.
71
+ """
72
+ if not _config.get_skills_enabled():
73
+ return
74
+
75
+ disabled = _config.get_disabled_skills()
76
+
77
+ for info in _discovery.discover_skills(directories):
78
+ if not info.has_skill_md:
79
+ continue
80
+ if info.name in disabled:
81
+ continue
82
+ yield info
@@ -0,0 +1,22 @@
1
+ """Agent skills installation helpers.
2
+
3
+ This module currently provides the shared InstallResult type used by skill
4
+ installers (e.g. local installers, remote zip downloaders).
5
+
6
+ It is intentionally small so other modules can depend on a stable result shape.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from dataclasses import dataclass
12
+ from pathlib import Path
13
+ from typing import Optional
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class InstallResult:
18
+ """Result of a skill install attempt."""
19
+
20
+ success: bool
21
+ message: str
22
+ installed_path: Optional[Path] = None