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,575 @@
1
+ """File Permission Handler Plugin.
2
+
3
+ This plugin handles user permission prompts for file operations,
4
+ providing a consistent and extensible permission system.
5
+ """
6
+
7
+ import difflib
8
+ import os
9
+ import threading
10
+ from typing import Any
11
+
12
+ from rich.text import Text as RichText
13
+
14
+ from code_puppy.callbacks import register_callback
15
+ from code_puppy.config import get_diff_context_lines, get_yolo_mode
16
+ from code_puppy.tools.file_permission_state import (
17
+ register_file_permission_state_provider,
18
+ )
19
+ from code_puppy.tools.common import (
20
+ _find_best_window,
21
+ get_user_approval,
22
+ get_user_approval_async,
23
+ )
24
+
25
+ # NOTE: module-level ``_FILE_CONFIRMATION_LOCK`` removed — queueing of parallel
26
+ # approvals now lives inside ``get_user_approval`` (they line up, never auto-rejected).
27
+
28
+ # Thread-local storage for user feedback from permission prompts
29
+ _thread_local = threading.local()
30
+
31
+
32
+ def get_last_user_feedback() -> str | None:
33
+ """Get the last user feedback from a permission prompt in this thread.
34
+
35
+ Returns:
36
+ The user feedback string, or None if no feedback was provided.
37
+ """
38
+ return getattr(_thread_local, "last_user_feedback", None)
39
+
40
+
41
+ def _set_user_feedback(feedback: str | None) -> None:
42
+ """Store user feedback in thread-local storage."""
43
+ _thread_local.last_user_feedback = feedback
44
+
45
+
46
+ def clear_user_feedback() -> None:
47
+ """Clear any stored user feedback."""
48
+ _thread_local.last_user_feedback = None
49
+
50
+
51
+ def set_diff_already_shown(shown: bool = True) -> None:
52
+ """Mark that a diff preview was already shown during permission prompt."""
53
+ _thread_local.diff_already_shown = shown
54
+
55
+
56
+ def was_diff_already_shown() -> bool:
57
+ """Check if a diff was already shown during the permission prompt.
58
+
59
+ Returns:
60
+ True if diff was shown, False otherwise
61
+ """
62
+ return getattr(_thread_local, "diff_already_shown", False)
63
+
64
+
65
+ def clear_diff_shown_flag() -> None:
66
+ """Clear the diff-already-shown flag."""
67
+ _thread_local.diff_already_shown = False
68
+
69
+
70
+ # Diff formatting is now handled by common.format_diff_with_colors()
71
+ # Arrow selector and approval UI now handled by common.get_user_approval()
72
+
73
+
74
+ def _preview_delete_snippet(file_path: str, snippet: str) -> str | None:
75
+ """Generate a preview diff for deleting a snippet without modifying the file."""
76
+ try:
77
+ file_path = os.path.abspath(file_path)
78
+ if not os.path.exists(file_path) or not os.path.isfile(file_path):
79
+ return None
80
+
81
+ with open(file_path, "r", encoding="utf-8", errors="surrogateescape") as f:
82
+ original = f.read()
83
+
84
+ # Sanitize any surrogate characters
85
+ try:
86
+ original = original.encode("utf-8", errors="surrogatepass").decode(
87
+ "utf-8", errors="replace"
88
+ )
89
+ except (UnicodeEncodeError, UnicodeDecodeError):
90
+ pass
91
+
92
+ if snippet not in original:
93
+ return None
94
+
95
+ modified = original.replace(snippet, "")
96
+ diff_text = "".join(
97
+ difflib.unified_diff(
98
+ original.splitlines(keepends=True),
99
+ modified.splitlines(keepends=True),
100
+ fromfile=f"a/{os.path.basename(file_path)}",
101
+ tofile=f"b/{os.path.basename(file_path)}",
102
+ n=get_diff_context_lines(),
103
+ )
104
+ )
105
+ return diff_text
106
+ except Exception:
107
+ return None
108
+
109
+
110
+ def _preview_write_to_file(
111
+ file_path: str, content: str, overwrite: bool = False
112
+ ) -> str | None:
113
+ """Generate a preview diff for writing to a file without modifying it."""
114
+ try:
115
+ file_path = os.path.abspath(file_path)
116
+ exists = os.path.exists(file_path)
117
+
118
+ if exists and not overwrite:
119
+ return None
120
+
121
+ diff_lines = difflib.unified_diff(
122
+ [] if not exists else [""],
123
+ content.splitlines(keepends=True),
124
+ fromfile="/dev/null" if not exists else f"a/{os.path.basename(file_path)}",
125
+ tofile=f"b/{os.path.basename(file_path)}",
126
+ n=get_diff_context_lines(),
127
+ )
128
+ return "".join(diff_lines)
129
+ except Exception:
130
+ return None
131
+
132
+
133
+ def _preview_replace_in_file(
134
+ file_path: str, replacements: list[dict[str, str]]
135
+ ) -> str | None:
136
+ """Generate a preview diff for replacing text in a file without modifying the file."""
137
+ try:
138
+ file_path = os.path.abspath(file_path)
139
+
140
+ with open(file_path, "r", encoding="utf-8", errors="surrogateescape") as f:
141
+ original = f.read()
142
+
143
+ # Sanitize any surrogate characters
144
+ try:
145
+ original = original.encode("utf-8", errors="surrogatepass").decode(
146
+ "utf-8", errors="replace"
147
+ )
148
+ except (UnicodeEncodeError, UnicodeDecodeError):
149
+ pass
150
+
151
+ modified = original
152
+ for rep in replacements:
153
+ old_snippet = rep.get("old_str", "")
154
+ new_snippet = rep.get("new_str", "")
155
+
156
+ if old_snippet and old_snippet in modified:
157
+ modified = modified.replace(old_snippet, new_snippet)
158
+ continue
159
+
160
+ # Use the same logic as file_modifications for fuzzy matching
161
+ orig_lines = modified.splitlines()
162
+ loc, score = _find_best_window(orig_lines, old_snippet)
163
+
164
+ if score < 0.95 or loc is None:
165
+ return None
166
+
167
+ start, end = loc
168
+ had_trailing_newline = modified.endswith("\n")
169
+ prefix = "\n".join(orig_lines[:start])
170
+ suffix = "\n".join(orig_lines[end:])
171
+ parts = []
172
+ if prefix:
173
+ parts.append(prefix)
174
+ parts.append(new_snippet.rstrip("\n"))
175
+ if suffix:
176
+ parts.append(suffix)
177
+ modified = "\n".join(parts)
178
+ if had_trailing_newline and not modified.endswith("\n"):
179
+ modified += "\n"
180
+
181
+ if modified == original:
182
+ return None
183
+
184
+ diff_text = "".join(
185
+ difflib.unified_diff(
186
+ original.splitlines(keepends=True),
187
+ modified.splitlines(keepends=True),
188
+ fromfile=f"a/{os.path.basename(file_path)}",
189
+ tofile=f"b/{os.path.basename(file_path)}",
190
+ n=get_diff_context_lines(),
191
+ )
192
+ )
193
+ return diff_text
194
+ except Exception:
195
+ return None
196
+
197
+
198
+ def _preview_delete_file(file_path: str) -> str | None:
199
+ """Generate a preview diff for deleting a file without modifying it."""
200
+ try:
201
+ file_path = os.path.abspath(file_path)
202
+ if not os.path.exists(file_path) or not os.path.isfile(file_path):
203
+ return None
204
+
205
+ with open(file_path, "r", encoding="utf-8", errors="surrogateescape") as f:
206
+ original = f.read()
207
+
208
+ # Sanitize any surrogate characters
209
+ try:
210
+ original = original.encode("utf-8", errors="surrogatepass").decode(
211
+ "utf-8", errors="replace"
212
+ )
213
+ except (UnicodeEncodeError, UnicodeDecodeError):
214
+ pass
215
+
216
+ diff_text = "".join(
217
+ difflib.unified_diff(
218
+ original.splitlines(keepends=True),
219
+ [],
220
+ fromfile=f"a/{os.path.basename(file_path)}",
221
+ tofile=f"b/{os.path.basename(file_path)}",
222
+ n=get_diff_context_lines(),
223
+ )
224
+ )
225
+ return diff_text
226
+ except Exception:
227
+ return None
228
+
229
+
230
+ def prompt_for_file_permission(
231
+ file_path: str,
232
+ operation: str,
233
+ preview: str | None = None,
234
+ message_group: str | None = None,
235
+ ) -> tuple[bool, str | None]:
236
+ """Prompt the user for permission to perform a file operation.
237
+
238
+ This function provides a unified permission prompt system for all file operations.
239
+
240
+ Args:
241
+ file_path: Path to the file being modified.
242
+ operation: Description of the operation (e.g., "edit", "delete", "create").
243
+ preview: Optional preview of changes (diff or content preview).
244
+ message_group: Optional message group for organizing output.
245
+
246
+ Returns:
247
+ Tuple of (confirmed: bool, user_feedback: str | None)
248
+ - confirmed: True if permission is granted, False otherwise
249
+ - user_feedback: Optional feedback message from user to send back to the model
250
+ """
251
+ yolo_mode = get_yolo_mode()
252
+
253
+ # Skip confirmation only if in yolo mode (removed TTY check for better compatibility)
254
+ if yolo_mode:
255
+ return True, None
256
+
257
+ # Build panel content
258
+ panel_content = RichText()
259
+ panel_content.append("🔒 Requesting permission to ", style="bold yellow")
260
+ panel_content.append(operation, style="bold cyan")
261
+ panel_content.append(":\n", style="bold yellow")
262
+ panel_content.append("📄 ", style="dim")
263
+ panel_content.append(file_path, style="bold white")
264
+
265
+ # Use the common approval function; internal queueing makes parallel callers
266
+ # wait their turn here rather than being silently auto-rejected.
267
+ return get_user_approval(
268
+ title="File Operation",
269
+ content=panel_content,
270
+ preview=preview,
271
+ border_style="dim white",
272
+ )
273
+
274
+
275
+ def handle_edit_file_permission(
276
+ context: Any,
277
+ file_path: str,
278
+ operation_type: str,
279
+ operation_data: Any,
280
+ message_group: str | None = None,
281
+ ) -> bool:
282
+ """Handle permission for edit_file operations with automatic preview generation.
283
+
284
+ Args:
285
+ context: The operation context
286
+ file_path: Path to the file being operated on
287
+ operation_type: Type of edit operation ('write', 'replace', 'delete_snippet')
288
+ operation_data: Operation-specific data (content, replacements, snippet, etc.)
289
+ message_group: Optional message group
290
+
291
+ Returns:
292
+ True if permission granted, False if denied
293
+ """
294
+ preview = None
295
+
296
+ if operation_type == "write":
297
+ content = operation_data.get("content", "")
298
+ overwrite = operation_data.get("overwrite", False)
299
+ preview = _preview_write_to_file(file_path, content, overwrite)
300
+ operation_desc = "write to"
301
+ elif operation_type == "replace":
302
+ replacements = operation_data.get("replacements", [])
303
+ preview = _preview_replace_in_file(file_path, replacements)
304
+ operation_desc = "replace text in"
305
+ elif operation_type == "delete_snippet":
306
+ snippet = operation_data.get("delete_snippet", "")
307
+ preview = _preview_delete_snippet(file_path, snippet)
308
+ operation_desc = "delete snippet from"
309
+ else:
310
+ operation_desc = f"perform {operation_type} operation on"
311
+
312
+ confirmed, user_feedback = prompt_for_file_permission(
313
+ file_path, operation_desc, preview, message_group
314
+ )
315
+ # Store feedback in thread-local storage so the tool can access it
316
+ _set_user_feedback(user_feedback)
317
+ return confirmed
318
+
319
+
320
+ def handle_delete_file_permission(
321
+ context: Any,
322
+ file_path: str,
323
+ message_group: str | None = None,
324
+ ) -> bool:
325
+ """Handle permission for delete_file operations with automatic preview generation.
326
+
327
+ Args:
328
+ context: The operation context
329
+ file_path: Path to the file being deleted
330
+ message_group: Optional message group
331
+
332
+ Returns:
333
+ True if permission granted, False if denied
334
+ """
335
+ preview = _preview_delete_file(file_path)
336
+ confirmed, user_feedback = prompt_for_file_permission(
337
+ file_path, "delete", preview, message_group
338
+ )
339
+ # Store feedback in thread-local storage so the tool can access it
340
+ _set_user_feedback(user_feedback)
341
+ return confirmed
342
+
343
+
344
+ def handle_file_permission(
345
+ context: Any,
346
+ file_path: str,
347
+ operation: str,
348
+ preview: str | None = None,
349
+ message_group: str | None = None,
350
+ operation_data: Any = None,
351
+ ) -> bool:
352
+ """Callback handler for file permission checks.
353
+
354
+ This function is called by file operations to check for user permission.
355
+ It returns True if the operation should proceed, False if it should be cancelled.
356
+
357
+ Args:
358
+ context: The operation context
359
+ file_path: Path to the file being operated on
360
+ operation: Description of the operation
361
+ preview: Optional preview of changes (deprecated - use operation_data instead)
362
+ message_group: Optional message group
363
+ operation_data: Operation-specific data for preview generation
364
+
365
+ Returns:
366
+ True if permission granted, False if denied
367
+ """
368
+ # Generate preview from operation_data if provided
369
+ if operation_data is not None:
370
+ preview = _generate_preview_from_operation_data(
371
+ file_path, operation, operation_data
372
+ )
373
+
374
+ confirmed, user_feedback = prompt_for_file_permission(
375
+ file_path, operation, preview, message_group
376
+ )
377
+ # Store feedback in thread-local storage so the tool can access it
378
+ _set_user_feedback(user_feedback)
379
+ return confirmed
380
+
381
+
382
+ def _generate_preview_from_operation_data(
383
+ file_path: str, operation: str, operation_data: Any
384
+ ) -> str | None:
385
+ """Generate preview diff from operation data.
386
+
387
+ Args:
388
+ file_path: Path to the file
389
+ operation: Type of operation
390
+ operation_data: Operation-specific data
391
+
392
+ Returns:
393
+ Preview diff or None if generation fails
394
+ """
395
+ try:
396
+ if operation == "delete":
397
+ return _preview_delete_file(file_path)
398
+ elif operation == "write":
399
+ content = operation_data.get("content", "")
400
+ overwrite = operation_data.get("overwrite", False)
401
+ return _preview_write_to_file(file_path, content, overwrite)
402
+ elif operation == "delete snippet from":
403
+ snippet = operation_data.get("snippet", "")
404
+ return _preview_delete_snippet(file_path, snippet)
405
+ elif operation == "replace text in":
406
+ replacements = operation_data.get("replacements", [])
407
+ return _preview_replace_in_file(file_path, replacements)
408
+ elif operation == "edit_file":
409
+ # Handle edit_file operations
410
+ if "delete_snippet" in operation_data:
411
+ return _preview_delete_snippet(
412
+ file_path, operation_data["delete_snippet"]
413
+ )
414
+ elif "replacements" in operation_data:
415
+ return _preview_replace_in_file(
416
+ file_path, operation_data["replacements"]
417
+ )
418
+ elif "content" in operation_data:
419
+ content = operation_data.get("content", "")
420
+ overwrite = operation_data.get("overwrite", False)
421
+ return _preview_write_to_file(file_path, content, overwrite)
422
+
423
+ return None
424
+ except Exception:
425
+ return None
426
+
427
+
428
+ def get_permission_handler_help() -> str:
429
+ """Return help information for the file permission handler."""
430
+ return """File Permission Handler Plugin:
431
+ - Unified permission prompts for all file operations
432
+ - YOLO mode support for automatic approval
433
+ - Thread-safe confirmation system
434
+ - Consistent user experience across file operations
435
+ - Detailed preview support with diff highlighting
436
+ - Automatic preview generation from operation data"""
437
+
438
+
439
+ def get_file_permission_prompt_additions() -> str:
440
+ """Return file permission handling prompt additions for agents."""
441
+ if get_yolo_mode():
442
+ return ""
443
+
444
+ return """
445
+ ## User Approval System
446
+
447
+ When file operations are rejected, the response includes a `user_feedback` field:
448
+ - If `user_feedback` has text: implement their suggestion and retry the operation.
449
+ - If `user_feedback` is empty: stop and ask the user what they want instead.
450
+ - Never retry the exact same rejected operation without changes.
451
+ """
452
+
453
+
454
+ async def prompt_for_file_permission_async(
455
+ file_path: str,
456
+ operation: str,
457
+ preview: str | None = None,
458
+ message_group: str | None = None,
459
+ ) -> tuple[bool, str | None]:
460
+ """Async sibling of :func:`prompt_for_file_permission`.
461
+
462
+ Uses :func:`get_user_approval_async` so prompt_toolkit cooperates
463
+ with the running asyncio loop instead of bailing out via
464
+ ``arrow_select() called from async context``.
465
+ """
466
+ if get_yolo_mode():
467
+ return True, None
468
+
469
+ panel_content = RichText()
470
+ panel_content.append("\U0001f512 Requesting permission to ", style="bold yellow")
471
+ panel_content.append(operation, style="bold cyan")
472
+ panel_content.append(":\n", style="bold yellow")
473
+ panel_content.append("\U0001f4c4 ", style="dim")
474
+ panel_content.append(file_path, style="bold white")
475
+
476
+ return await get_user_approval_async(
477
+ title="File Operation",
478
+ content=panel_content,
479
+ preview=preview,
480
+ border_style="dim white",
481
+ )
482
+
483
+
484
+ async def handle_edit_file_permission_async(
485
+ context: Any,
486
+ file_path: str,
487
+ operation_type: str,
488
+ operation_data: Any,
489
+ message_group: str | None = None,
490
+ ) -> bool:
491
+ """Async sibling of :func:`handle_edit_file_permission`."""
492
+ preview = None
493
+
494
+ if operation_type == "write":
495
+ content = operation_data.get("content", "")
496
+ overwrite = operation_data.get("overwrite", False)
497
+ preview = _preview_write_to_file(file_path, content, overwrite)
498
+ operation_desc = "write to"
499
+ elif operation_type == "replace":
500
+ replacements = operation_data.get("replacements", [])
501
+ preview = _preview_replace_in_file(file_path, replacements)
502
+ operation_desc = "replace text in"
503
+ elif operation_type == "delete_snippet":
504
+ snippet = operation_data.get("delete_snippet", "")
505
+ preview = _preview_delete_snippet(file_path, snippet)
506
+ operation_desc = "delete snippet from"
507
+ else:
508
+ operation_desc = f"perform {operation_type} operation on"
509
+
510
+ confirmed, user_feedback = await prompt_for_file_permission_async(
511
+ file_path, operation_desc, preview, message_group
512
+ )
513
+ _set_user_feedback(user_feedback)
514
+ return confirmed
515
+
516
+
517
+ async def handle_delete_file_permission_async(
518
+ context: Any,
519
+ file_path: str,
520
+ message_group: str | None = None,
521
+ ) -> bool:
522
+ """Async sibling of :func:`handle_delete_file_permission`."""
523
+ preview = _preview_delete_file(file_path)
524
+ confirmed, user_feedback = await prompt_for_file_permission_async(
525
+ file_path, "delete", preview, message_group
526
+ )
527
+ _set_user_feedback(user_feedback)
528
+ return confirmed
529
+
530
+
531
+ async def handle_file_permission_async(
532
+ context: Any,
533
+ file_path: str,
534
+ operation: str,
535
+ preview: str | None = None,
536
+ message_group: str | None = None,
537
+ operation_data: Any = None,
538
+ ) -> bool:
539
+ """Async sibling of :func:`handle_file_permission`.
540
+
541
+ This is the variant registered on the ``file_permission`` hook so
542
+ callers in async contexts (e.g. ``on_file_permission_async``)
543
+ don't trip the ``arrow_select() called from async context`` guard.
544
+ The async dispatcher awaits the coroutine; the sync dispatcher
545
+ handles it by running it on a fresh loop when invoked from a
546
+ worker thread.
547
+ """
548
+ if operation_data is not None:
549
+ preview = _generate_preview_from_operation_data(
550
+ file_path, operation, operation_data
551
+ )
552
+
553
+ confirmed, user_feedback = await prompt_for_file_permission_async(
554
+ file_path, operation, preview, message_group
555
+ )
556
+ _set_user_feedback(user_feedback)
557
+ return confirmed
558
+
559
+
560
+ # Expose the thread-local UX-state accessors to core via this small provider API
561
+ # (avoids core importing this plugin module to reach diff-shown flag / feedback).
562
+ _STATE_PROVIDER_REGISTRATION = register_file_permission_state_provider(
563
+ set_diff_already_shown=set_diff_already_shown,
564
+ was_diff_already_shown=was_diff_already_shown,
565
+ clear_diff_shown_flag=clear_diff_shown_flag,
566
+ get_last_user_feedback=get_last_user_feedback,
567
+ clear_user_feedback=clear_user_feedback,
568
+ )
569
+
570
+ # Register the async callback: awaited directly by the async dispatcher; the sync
571
+ # dispatcher runs it via ``asyncio.run`` when triggered from a thread without a loop.
572
+ register_callback("file_permission", handle_file_permission_async)
573
+
574
+ # Register the prompt hook for file permission instructions
575
+ register_callback("load_prompt", get_file_permission_prompt_additions)
@@ -0,0 +1,5 @@
1
+ """Flux bootstrap plugin package.
2
+
3
+ Ships the bundled Flux slash-command suite and installs it into
4
+ ``~/.code_puppy`` on fresh install / version bump. See ``register_callbacks.py``.
5
+ """