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,136 @@
1
+ # Skills System
2
+
3
+ > Part of the `code-puppy-agent` skill. Read this when working with
4
+ > skill discovery/activation, or extending how skills are presented to
5
+ > the model. See `SKILL.md` for the overview and the full reference map.
6
+
7
+ ---
8
+
9
+ ## How skills work
10
+
11
+ A skill is a directory containing a `SKILL.md` with YAML frontmatter
12
+ (`name`, `description`, optional `version`, `author`, `tags`) and
13
+ markdown body. The body is the instruction set loaded into context when
14
+ the skill is activated.
15
+
16
+ ## Skill discovery (`plugins/agent_skills/discovery.py`)
17
+
18
+ Scans these directories (first-discovered wins on name collision):
19
+ 1. `~/.code_puppy/skills/`
20
+ 2. `<CWD>/.code_puppy/skills/`
21
+ 3. `<CWD>/skills/`
22
+ 4. Plugin-registered skills (via `register_skills` callback)
23
+
24
+ ## Skill activation flow
25
+
26
+ 1. The model calls `activate_skill("skill-name")` or the user types
27
+ `/<skill-name>`
28
+ 2. The tool reads the full `SKILL.md` from disk
29
+ 3. Content is injected into the model's context as a tool result
30
+ 4. The model follows the instructions in its next response
31
+
32
+ Skills are **opt-in** — by default the model sees a one-line summary in
33
+ its system prompt (name + description) and must explicitly activate to
34
+ get full instructions. At small catalog sizes (a handful to a few dozen
35
+ skills) this flat list is fine. It stops scaling well before a few
36
+ hundred skills — see "Skill namespaces" below.
37
+
38
+ ### Bundled resource files: filesystem skills vs. plugin-registered skills
39
+
40
+ `activate_skill` returns a `resources: List[str]` field listing files
41
+ bundled alongside `SKILL.md` (via `get_skill_resources()`), which the
42
+ model can then `read_file()` on demand instead of everything being
43
+ force-loaded on activation. This works cleanly for a **filesystem**
44
+ skill (a real directory under one of the scanned paths above) — any
45
+ sibling file just shows up.
46
+
47
+ It does **not** work the same way for a skill registered via the
48
+ `register_skills` callback with `skill_md_path` (like this skill,
49
+ `code-puppy-agent`, and `namespace_skill_search` originally considered
50
+ before dropping the idea): the discovery loader materializes only
51
+ `SKILL.md` itself into a cache directory (plus an optional `scripts_dir`
52
+ entry, and even that isn't surfaced through `get_skill_resources` since
53
+ it lands as a subdirectory, not a file). **If you want a plugin-owned
54
+ skill to reference sibling docs, put real repo paths in the SKILL.md
55
+ prose and let the model `read_file()` them directly** — don't rely on
56
+ the `resources` field to surface them. This document you're reading
57
+ right now is exactly that pattern: `SKILL.md` names this file by its
58
+ real path in the repo rather than expecting it to appear as a
59
+ `resources` entry.
60
+
61
+ ## Managing skills
62
+
63
+ | Command | Effect |
64
+ |---------|--------|
65
+ | `/skills` | Interactive TUI menu |
66
+ | `/skills list` | Text list of all skills |
67
+ | `/skills enable` / `disable` | Toggle skills globally |
68
+ | `/skills frontmatter on/off` | Toggle skill summaries in system prompt |
69
+ | `/skills install` | Browse & install from remote catalog |
70
+
71
+ ---
72
+
73
+ ## Skill namespaces (large catalogs)
74
+
75
+ The **`namespace_skill_search`** builtin plugin
76
+ (`code_puppy/plugins/namespace_skill_search/`) addresses the
77
+ flat-list-doesn't-scale problem above. It's the reference
78
+ implementation to look at if you're extending how skills are surfaced
79
+ to the model, or building something in the same spirit for another
80
+ large catalog (tools, MCP servers, etc.).
81
+
82
+ **Shape:** groups skills into **namespaces** — each skill's namespace is
83
+ its first `tags:` entry (untagged skills fall back to a `General`
84
+ namespace) — and replaces the flat per-skill system-prompt list with a
85
+ compact namespace directory, plus a new `browse_skill_namespace` tool
86
+ with three modes (no-args directory listing, `namespace=` drill-down,
87
+ `query=` keyword search across everything). This mirrors OpenAI's
88
+ shipped `tool_search` + namespace-grouping pattern and Anthropic's
89
+ shipped Tool Search Tool, reimplemented in a model-agnostic way (no
90
+ provider-specific request fields) using only Code Puppy's existing
91
+ plugin hooks.
92
+
93
+ **User-facing docs:** `docs/AGENT_SKILLS.md` → "Skill Namespaces (Large
94
+ Catalogs)" section — what changes automatically, the tool's three
95
+ modes with examples, and how to opt back out
96
+ (`/plugins disable namespace_skill_search` + `/skills frontmatter on`).
97
+
98
+ **Design rationale + what was deliberately not built:**
99
+ `code_puppy/plugins/namespace_skill_search/README.md` — full writeup of
100
+ what was copied from OpenAI/Anthropic, why namespace-per-first-tag was
101
+ chosen over a vector DB or a deep multi-level tree, and the two hook-
102
+ system gotchas it was built to avoid (see `PLUGINS_AND_CALLBACKS.md` in
103
+ this reference set for those gotchas explained in general terms, not
104
+ tied to this one plugin).
105
+
106
+ **Implementation details worth knowing if you're extending it:**
107
+ - Namespace grouping is **case-insensitive at build time** — skills
108
+ tagged `finance`/`Finance`/`FINANCE` merge into one namespace, keyed
109
+ by first-seen casing. This isn't optional; the tool's `namespace=`
110
+ lookup is case-insensitive, so case-sensitive grouping would let two
111
+ namespaces silently fragment while looking like a single one from the
112
+ tool's perspective.
113
+ - A blank/whitespace-only `query` means "no filter," not "match
114
+ nothing" — a naive `any(term in haystack for term in
115
+ query.lower().split())` degrades to `any([])` (`False`) for every
116
+ skill on an empty query, which is a genuinely easy trap to fall into
117
+ with keyword-filter code in general, not specific to this plugin.
118
+ - Duplicate skill names across namespaces are flagged in the directory
119
+ output (not deduped or resolved) — `activate_skill(name)` has no way
120
+ to disambiguate between two skills sharing a name, and that's an
121
+ `agent_skills`-level gap this plugin surfaces more visibly rather than
122
+ causes.
123
+
124
+ ## When to reach for `list_or_search_skills` / `activate_skill` vs. `browse_skill_namespace`
125
+
126
+ Both exist simultaneously and are not mutually exclusive:
127
+ - `list_or_search_skills` — the original, flat, always-available tool.
128
+ Fine for small catalogs or when you already roughly know the skill
129
+ name.
130
+ - `browse_skill_namespace` — better when the catalog is large enough
131
+ that `namespace_skill_search` has replaced the flat prompt block with
132
+ a namespace directory, and you want to browse by domain or search
133
+ across everything without scanning a huge flat list yourself.
134
+
135
+ Either way, the terminal step is the same: `activate_skill(name)` to
136
+ load the full instructions.
@@ -0,0 +1,160 @@
1
+ # System Prompt Assembly, Configuration, Messaging & i18n
2
+
3
+ > Part of the `code-puppy-agent` skill. Read this when debugging what
4
+ > ends up in the system prompt (and in what order), working with
5
+ > `puppy.cfg`, emitting UI messages from a plugin, or wrapping
6
+ > user-facing strings for i18n. See `SKILL.md` for the overview and the
7
+ > full reference map.
8
+
9
+ ---
10
+
11
+ ## System Prompt Assembly
12
+
13
+ Assembled in two stages: `get_full_system_prompt()` builds the base
14
+ (`base_agent.py`), then `_assemble_instructions()` (`_builder.py`)
15
+ appends rules and runs the per-model patcher.
16
+
17
+ `get_full_system_prompt()` layers:
18
+
19
+ ```
20
+ 1. Authored prompt (agent.get_system_prompt())
21
+ 2. load_prompt fragments (plugin-injected: kennel memory, permission
22
+ rules, namespace_skill_search's namespace directory, …)
23
+ 3. Identity ID (agent name + UUID prefix)
24
+ ```
25
+
26
+ `_assemble_instructions()` then appends:
27
+
28
+ ```
29
+ 4. AGENTS.md puppy_rules (global ~/.code_puppy/AGENTS.md, then project
30
+ <CWD>/.code_puppy/AGENTS.md, then ./AGENTS.md fallback — concatenated,
31
+ not first-wins)
32
+ 5. Extended-thinking note (only if active for the resolved model)
33
+ 6. Per-model patches (get_model_system_prompt callbacks, via
34
+ prepare_prompt_for_model) — this is where the **skills block**
35
+ (available-skills summary) is appended, by the agent_skills plugin
36
+ ```
37
+
38
+ > The skills summary is **not** a `load_prompt` fragment — it's injected
39
+ > through `get_model_system_prompt`, so it lands *after* identity and
40
+ > rules. **This is exactly the phase `namespace_skill_search` avoids
41
+ > registering a second callback on** — see `PLUGINS_AND_CALLBACKS.md`
42
+ > for why (`get_model_system_prompt` is last-write-wins across plugins,
43
+ > not additive like `load_prompt`).
44
+
45
+ Layers 2–6 are **runtime-only** — recomputed every run, never persisted
46
+ into static agent definitions. This prevents stale timestamps, dead file
47
+ paths, and baked-in session IDs from leaking into cloned agents.
48
+
49
+ ---
50
+
51
+ ## Configuration System (`config.py`)
52
+
53
+ All settings live in `~/.code_puppy/puppy.cfg` (INI format) managed via:
54
+ - `get_value(key)` / `set_value(key, value)`
55
+ - `/set <key> <value>` slash command
56
+
57
+ Key directories:
58
+ - **Config root**: `~/.code_puppy/`
59
+ - **State/sessions**: `~/.code_puppy/state/` (or platform cache dir)
60
+ - **Cache**: `~/.code_puppy/cache/`
61
+ - **Agents**: `~/.code_puppy/agents/`
62
+ - **Skills**: `~/.code_puppy/skills/`
63
+ - **Plugins**: `~/.code_puppy/plugins/`
64
+ - **Extra models**: `~/.code_puppy/extra_models.json`
65
+
66
+ AGENTS.md rules files are loaded from `~/.code_puppy/AGENTS.md` (global),
67
+ `<CWD>/.code_puppy/AGENTS.md` (project), and `./AGENTS.md` (fallback).
68
+
69
+ ### Disabling a plugin
70
+
71
+ `/plugins disable <name>` writes to the `disabled_plugins` config key
72
+ (JSON list) via `code_puppy/plugins/config.py`. A disabled plugin's
73
+ callbacks are skipped entirely — but any *persisted config change* the
74
+ plugin already made before being disabled (e.g. `namespace_skill_search`
75
+ turning off `frontmatter_in_system_prompt` on its first run) does **not**
76
+ automatically revert. Disabling the plugin and undoing what it already
77
+ did to your config are two separate actions.
78
+
79
+ ---
80
+
81
+ ## Messaging & UI
82
+
83
+ ### Message bus (`messaging/`)
84
+
85
+ Plugins emit UI messages through the message bus rather than printing
86
+ directly:
87
+
88
+ ```python
89
+ from code_puppy.messaging import emit_info, emit_success, emit_warning, emit_error
90
+ emit_info("Something happened")
91
+ ```
92
+
93
+ These are rendered by the TUI's event handler, so they work in both
94
+ interactive and streaming contexts.
95
+
96
+ ### Event streaming (`agents/event_stream_handler.py`)
97
+
98
+ The agent's streaming response is handled by `event_stream_handler`,
99
+ which processes pydantic-ai streaming events (text deltas, tool calls,
100
+ tool returns) and emits UI messages. The `stream_event` callback lets
101
+ plugins observe these events.
102
+
103
+ ---
104
+
105
+ ## Internationalization (i18n)
106
+
107
+ User-facing CLI/TUI text is localizable via the `code_puppy/i18n/` package
108
+ (stdlib-only; no Babel). **Full guide: `docs/I18N.md`.** Epic: PUP-473.
109
+ This section is a quick-reference cheat sheet, not a replacement for that
110
+ doc.
111
+
112
+ ### Call sites
113
+
114
+ ```python
115
+ from code_puppy.i18n import t, ngettext, lazy
116
+ emit_info(t("startup.welcome", name=owner)) # simple, interpolated
117
+ emit_info(ngettext("files.deleted", count=n)) # plural-aware
118
+ emit_info(lazy("startup.ready")) # resolved at render time
119
+ ```
120
+
121
+ - Keys are dotted IDs; **interpolation uses `{name}` only** — no f-strings,
122
+ no `str.format` on catalog text (attribute/index access and format specs are
123
+ deliberately unsupported; catalogs are untrusted input).
124
+ - A missing key echoes the key back — resolution **never raises**.
125
+
126
+ ### Catalogs & locales
127
+
128
+ - JSON per locale: `i18n/locales/<locale>.json` (dotted-key → string, or a
129
+ plural dict `{"one": ..., "other": ...}`).
130
+ - Shipped: `en-US` (source), `es` (Latin American `es-419` folded in), and
131
+ `fr-CA`. Regional catalogs are added only when reviewed translations exist.
132
+ - **Fallback chain**: plain BCP-47 truncation, `es-AR → es → en-US` (see
133
+ `i18n.locale.fallback_chain`). `i18n.locale.PARENT_LOCALES` is a currently-
134
+ empty CLDR override seam for non-truncation parents. Plugins / the private
135
+ fork can register extra catalog dirs via `i18n.catalog.add_catalog_dir()`.
136
+
137
+ ### How it wires in
138
+
139
+ - **Choke point**: `messaging/message_queue.py::emit_message` resolves a
140
+ `LazyTranslation` to a string; plain strings pass through unchanged.
141
+ - **Locale**: `config.get_locale()` is the single source of truth (delegates
142
+ to the i18n translator), seeded `CODE_PUPPY_LOCALE` › `locale` config key ›
143
+ POSIX env › `en-US`. `/set locale <tag>` persists it.
144
+ - **Formatting**: `i18n.format_number` / `i18n.format_datetime` (locale-aware).
145
+
146
+ ### Rules
147
+
148
+ - **Model-facing system prompts are OUT of scope** — translating them changes
149
+ LLM behavior. Don't run them through the seam. (This is why
150
+ `namespace_skill_search`'s namespace-directory prompt fragment is plain,
151
+ un-wrapped English — it's model-facing content, not user-facing UI text.)
152
+ - Extraction goes behind the coverage/pseudolocale CI gate
153
+ (`tests/i18n/test_i18n_coverage.py`): every translated key must exist in the
154
+ `en-US` source, and a pseudolocale (`en-XA`) run must emit only bracketed
155
+ text (catches un-externalized strings).
156
+ - **Find what's left to extract** with the static audit:
157
+ `python -m code_puppy.i18n.audit --top 15` lists the worst files;
158
+ `--list` shows every raw `emit_*`/`console.print` site, `--json` is
159
+ machine-readable, and `--fail-under PCT` is a CI gate. Use it to pick the
160
+ next module, then the pseudolocale test above to prove it's fully migrated.
@@ -0,0 +1,5 @@
1
+ """Builtin skill: ``code-puppy-agent``.
2
+
3
+ Ships a SKILL.md that explains Code Puppy's internal architecture so the
4
+ LLM can navigate the codebase and extend the product correctly.
5
+ """
@@ -0,0 +1,46 @@
1
+ """Register the built-in ``code-puppy-agent`` skill.
2
+
3
+ The skill's SKILL.md lives alongside this file and is an *index* into a
4
+ set of topic-specific reference files (``AGENTS_AND_TOOLS.md``,
5
+ ``PLUGINS_AND_CALLBACKS.md``, ``MODELS_AND_MCP.md``,
6
+ ``SESSIONS_AND_HISTORY.md``, ``SKILLS_SYSTEM.md``,
7
+ ``SYSTEM_PROMPT_CONFIG_AND_I18N.md``) in the same directory. This keeps
8
+ any single activation cheap while still covering the full internals
9
+ surface -- see SKILL.md's "Reference Map" for which file answers which
10
+ question.
11
+
12
+ We register it via the ``register_skills`` callback so the agent_skills
13
+ plugin materializes it into the plugin-skill cache and it shows up in
14
+ ``/skills list``, ``activate_skill``, and the system-prompt skill block --
15
+ just like any user-installed skill.
16
+
17
+ Note: only ``skill_md_path`` is registered below, not the reference
18
+ files. Plugin-registered skills (``skill_md_path``/``skill_md``/
19
+ ``frontmatter``+``body``) only ever materialize ``SKILL.md`` itself into
20
+ the runtime cache -- sibling files are NOT auto-discovered as
21
+ ``resources`` the way they would be for a real filesystem skill
22
+ directory. That's why SKILL.md references the other files by their real
23
+ repo paths in prose (for the model to ``read_file`` on demand) rather
24
+ than relying on the ``resources`` field ``activate_skill`` returns.
25
+ """
26
+
27
+ from pathlib import Path
28
+
29
+ from code_puppy.callbacks import register_callback
30
+
31
+ _SKILL_DIR = Path(__file__).resolve().parent
32
+
33
+
34
+ def _register_builtin_skills() -> list[dict]:
35
+ # This "name" MUST match the SKILL.md frontmatter ``name:``: it drives dedup +
36
+ # the disable-set, while frontmatter name drives display; a mismatch would
37
+ # silently break ``/skills enable|disable`` and the alias.
38
+ return [
39
+ {
40
+ "name": "code-puppy-agent",
41
+ "skill_md_path": str(_SKILL_DIR / "SKILL.md"),
42
+ }
43
+ ]
44
+
45
+
46
+ register_callback("register_skills", _register_builtin_skills)
@@ -0,0 +1,123 @@
1
+ import AppKit
2
+ import CoreGraphics
3
+ import Foundation
4
+ import ScreenCaptureKit
5
+
6
+ enum CaptureFailure: LocalizedError {
7
+ case message(String)
8
+
9
+ var errorDescription: String? {
10
+ switch self {
11
+ case .message(let text): return text
12
+ }
13
+ }
14
+ }
15
+ @main
16
+ struct NativeCapture {
17
+ static func scale(for frame: CGRect) -> CGFloat {
18
+ let midpoint = CGPoint(x: frame.midX, y: frame.midY)
19
+ for screen in NSScreen.screens {
20
+ guard
21
+ let number = screen.deviceDescription[
22
+ NSDeviceDescriptionKey("NSScreenNumber")
23
+ ] as? NSNumber
24
+ else { continue }
25
+ let bounds = CGDisplayBounds(CGDirectDisplayID(number.uint32Value))
26
+ if bounds.contains(midpoint) {
27
+ return screen.backingScaleFactor
28
+ }
29
+ }
30
+ return NSScreen.main?.backingScaleFactor ?? 1
31
+ }
32
+
33
+ static func matchingApplication(_ query: String) throws -> NSRunningApplication {
34
+ let wanted = query.lowercased()
35
+ guard let app = NSWorkspace.shared.runningApplications.first(where: {
36
+ ($0.localizedName ?? "").lowercased() == wanted
37
+ || ($0.bundleIdentifier ?? "").lowercased() == wanted
38
+ }) else {
39
+ throw CaptureFailure.message("Running application not found: \(query)")
40
+ }
41
+ return app
42
+ }
43
+
44
+ static func run(appName: String, outputPath: String) async throws -> [String: Any] {
45
+ let app = try matchingApplication(appName)
46
+ let content = try await SCShareableContent.excludingDesktopWindows(
47
+ false,
48
+ onScreenWindowsOnly: false
49
+ )
50
+ let candidates = content.windows.filter {
51
+ guard $0.owningApplication?.processID == app.processIdentifier else {
52
+ return false
53
+ }
54
+ return $0.frame.width >= 200 && $0.frame.height >= 120
55
+ }
56
+ guard let window = candidates.max(by: {
57
+ $0.frame.width * $0.frame.height < $1.frame.width * $1.frame.height
58
+ }) else {
59
+ throw CaptureFailure.message("No capturable window found for \(appName).")
60
+ }
61
+
62
+ let scale = scale(for: window.frame)
63
+ let configuration = SCStreamConfiguration()
64
+ configuration.width = max(1, Int((window.frame.width * scale).rounded()))
65
+ configuration.height = max(1, Int((window.frame.height * scale).rounded()))
66
+ configuration.showsCursor = false
67
+ configuration.scalesToFit = false
68
+ let filter = SCContentFilter(desktopIndependentWindow: window)
69
+ let image = try await SCScreenshotManager.captureImage(
70
+ contentFilter: filter,
71
+ configuration: configuration
72
+ )
73
+ let representation = NSBitmapImageRep(cgImage: image)
74
+ guard let data = representation.representation(
75
+ using: .png,
76
+ properties: [:]
77
+ ) else {
78
+ throw CaptureFailure.message("Could not encode screenshot as PNG.")
79
+ }
80
+ try data.write(to: URL(fileURLWithPath: outputPath), options: .atomic)
81
+
82
+ return [
83
+ "application": app.localizedName ?? appName,
84
+ "bundle_id": app.bundleIdentifier ?? "",
85
+ "pid": Int(app.processIdentifier),
86
+ "window_id": Int(window.windowID),
87
+ "window_title": window.title ?? "",
88
+ "backing_scale": Double(scale),
89
+ "window_bounds_points": [
90
+ "x": Double(window.frame.origin.x),
91
+ "y": Double(window.frame.origin.y),
92
+ "width": Double(window.frame.width),
93
+ "height": Double(window.frame.height),
94
+ ],
95
+ "screenshot_size_pixels": [
96
+ "width": configuration.width,
97
+ "height": configuration.height,
98
+ ],
99
+ ]
100
+ }
101
+
102
+ static func main() async {
103
+ guard CommandLine.arguments.count == 3 else {
104
+ FileHandle.standardError.write(
105
+ Data("usage: native-capture APP OUTPUT.png\n".utf8)
106
+ )
107
+ exit(2)
108
+ }
109
+ do {
110
+ let payload = try await run(
111
+ appName: CommandLine.arguments[1],
112
+ outputPath: CommandLine.arguments[2]
113
+ )
114
+ let data = try JSONSerialization.data(withJSONObject: payload)
115
+ FileHandle.standardOutput.write(data)
116
+ } catch {
117
+ FileHandle.standardError.write(
118
+ Data("\(error.localizedDescription)\n".utf8)
119
+ )
120
+ exit(1)
121
+ }
122
+ }
123
+ }
@@ -0,0 +1,109 @@
1
+ # macOS Computer Use
2
+
3
+ This opt-in plugin lets Code Puppy inspect and operate the current macOS desktop
4
+ through Apple's Accessibility APIs. It is macOS-only and does not use a virtual
5
+ machine or copy any Codex implementation.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install "code-puppy[computer-use]"
11
+ ```
12
+
13
+ On first use, macOS requests permissions for the terminal or application that
14
+ runs Code Puppy:
15
+
16
+ 1. **Accessibility** for inspecting and operating controls.
17
+ 2. **Screen Recording** for screenshots.
18
+
19
+ Grant these under **System Settings → Privacy & Security**. Restart Code Puppy
20
+ after changing Screen Recording access.
21
+
22
+ Computer Use is off by default: its tools are not exposed to the model until
23
+ you explicitly opt in. On macOS, Code Puppy shows a launch reminder with the
24
+ enable command. The choice is stored in the normal Code Puppy settings directory:
25
+
26
+ ```text
27
+ /computer-use enable
28
+ /computer-use disable
29
+ /computer-use status
30
+ ```
31
+
32
+ You can change this setting at any time. Once enabled, Computer Use runs
33
+ without per-application approval prompts or an allowlist.
34
+
35
+ Use `/computer-use pause` as an emergency stop and `/computer-use resume` only
36
+ after confirming it is safe. `/computer-use deny BUNDLE_ID` persists an
37
+ exception, and `/computer-use allow BUNDLE_ID` removes that exception. Login,
38
+ authorization, Keychain, and System Settings processes are always blocked.
39
+
40
+ Snapshots, explicit screenshots, and successful batches display a compact
41
+ inline preview in Ghostty, Kitty, WezTerm, and iTerm2. The same PNG is attached
42
+ to the tool result so multimodal models can inspect it directly. App-targeted
43
+ snapshots capture that application's largest standard window even when another
44
+ application is in front.
45
+
46
+ ## Agent workflow
47
+
48
+ 1. Call `computer_get_app_state` with an application name.
49
+ 2. Use its screenshot, pruned focused-window accessibility tree, and
50
+ `state_revision` to choose an action. Prefer an element ID and one of the
51
+ element's advertised actions.
52
+ 3. Run one mutation, or one guarded batch of at most 20 mutations.
53
+ 4. Fetch fresh state. A completed batch does this automatically after waiting
54
+ for the accessibility tree to stabilize.
55
+
56
+ Before every mutation, the target process is activated and verified as the
57
+ frontmost application. This is required because ScreenCaptureKit can capture a
58
+ background window, while Quartz sends global clicks and keystrokes to whichever
59
+ application is actually frontmost. Use a guarded batch for click-then-type
60
+ workflows so focus is retained and the result is verified in one control loop.
61
+
62
+ Pixel clicks and drags use window-local screenshot pixels. The backend converts
63
+ them to global Quartz points using the captured window bounds, so Retina scaling,
64
+ negative display origins, and windows on secondary displays remain consistent.
65
+ Scrolling accepts `up`, `down`, `left`, or `right` and a fractional page count.
66
+ Text selection supports an exact match, optional prefix/suffix disambiguation,
67
+ and cursor placement before or after the match.
68
+
69
+ ## Safety
70
+
71
+ - Prefer accessibility element IDs over pixel coordinates.
72
+ - Persisted user consent is required before tools are exposed to the model;
73
+ disabling the feature removes them again and blocks future captures/actions.
74
+ - State revisions and element IDs are single-use and expire after 120 seconds.
75
+ - Physical keyboard and pointer input do not interrupt YOLO-mode execution.
76
+ - Every capture and mutation re-checks the application policy; the emergency
77
+ stop therefore also interrupts a batch at its next action boundary.
78
+ - Password-field values are never returned in snapshots.
79
+ - Batches stop at the first failed action, contain at most 20 steps, wait for
80
+ deterministic UI stability, and return updated screenshot/tree state.
81
+ - The plugin does not pause for consequential-action confirmations in YOLO
82
+ mode. Use `/computer-use pause` when autonomous interaction should stop.
83
+
84
+ ## Native capture and privacy
85
+
86
+ Application screenshots use ScreenCaptureKit through the bundled Swift helper.
87
+ The helper is compiled locally, cached with a source hash, and returns stable
88
+ window metadata: bundle ID, PID, window ID/title, bounds, pixel dimensions, and
89
+ backing scale. Screenshot PNGs are temporary local files. This plugin does not
90
+ add telemetry, persistent action history, lock-screen automation, or privileged
91
+ system interaction.
92
+
93
+ The first native capture requires Xcode Command Line Tools because the bundled
94
+ helper is compiled on the Mac:
95
+
96
+ ```bash
97
+ xcode-select --install
98
+ ```
99
+
100
+ ## Test
101
+
102
+ ```bash
103
+ uv run ruff check code_puppy/plugins/computer_use tests/plugins
104
+ uv run pytest tests/plugins/test_computer_use_*.py -q --no-cov
105
+ ```
106
+
107
+ For a live Ghostty smoke test, launch Code Puppy from Ghostty and ask for
108
+ `computer_get_app_state`. A compact image should appear inline; the tool result
109
+ still carries the PNG if the terminal protocol is unavailable.
@@ -0,0 +1 @@
1
+ """Opt-in macOS computer-use tools."""