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,587 @@
1
+ """Utility helpers for the GitHub Copilot auth plugin.
2
+
3
+ Handles browser-based Device Flow authentication, session-token exchange /
4
+ caching, and model registration persistence.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ import time
12
+ from dataclasses import dataclass
13
+ from typing import Any, Dict, List, Optional
14
+
15
+ import requests
16
+
17
+ from .config import (
18
+ COPILOT_AUTH_CONFIG,
19
+ COPILOT_MODEL_CONTEXT_LENGTHS,
20
+ DEFAULT_COPILOT_MODELS,
21
+ DEVICE_FLOW_CONFIG,
22
+ get_copilot_models_path,
23
+ get_device_token_storage_path,
24
+ get_session_cache_path,
25
+ )
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # Token storage — persisted tokens obtained via the Device Flow
32
+ # ---------------------------------------------------------------------------
33
+
34
+
35
+ @dataclass
36
+ class CopilotToken:
37
+ """An OAuth token for a GitHub host."""
38
+
39
+ host: str # "github.com" or a GHE hostname
40
+ oauth_token: str
41
+ user: str = ""
42
+
43
+
44
+ def get_token_for_host(host: str) -> Optional[CopilotToken]:
45
+ """Return a stored Device Flow token whose host matches *host* exactly.
46
+
47
+ Returns ``None`` if no token for the given host is found.
48
+ """
49
+ tokens = load_device_tokens()
50
+ for t in tokens:
51
+ if t.host == host:
52
+ return t
53
+ return None
54
+
55
+
56
+ # ---------------------------------------------------------------------------
57
+ # Device Flow — browser-based GitHub OAuth (no IDE required)
58
+ # ---------------------------------------------------------------------------
59
+
60
+
61
+ def start_device_flow(host: str = "github.com") -> Optional[Dict[str, Any]]:
62
+ """Initiate the GitHub Device Flow and return the device code response.
63
+
64
+ Returns a dict with ``device_code``, ``user_code``, ``verification_uri``,
65
+ ``expires_in``, and ``interval`` on success, or ``None`` on failure.
66
+ """
67
+ url = DEVICE_FLOW_CONFIG["device_code_url"].format(host=host)
68
+ payload = {
69
+ "client_id": DEVICE_FLOW_CONFIG["client_id"],
70
+ "scope": DEVICE_FLOW_CONFIG["scope"],
71
+ }
72
+ headers = {"Accept": "application/json"}
73
+ try:
74
+ resp = requests.post(url, data=payload, headers=headers, timeout=30)
75
+ if resp.status_code == 200:
76
+ data = resp.json()
77
+ if data.get("device_code") and data.get("user_code"):
78
+ return data
79
+ logger.warning("Device flow response missing required fields: %s", data)
80
+ else:
81
+ logger.warning(
82
+ "Device flow initiation failed: %s %s",
83
+ resp.status_code,
84
+ resp.text[:300],
85
+ )
86
+ except Exception as exc:
87
+ logger.warning("Device flow error: %s", exc)
88
+ return None
89
+
90
+
91
+ def poll_for_token(
92
+ device_code: str,
93
+ host: str = "github.com",
94
+ interval: int = 5,
95
+ expires_in: int = 900,
96
+ ) -> Optional[str]:
97
+ """Poll GitHub until the user completes the Device Flow authorization.
98
+
99
+ Returns the OAuth ``access_token`` on success, or ``None`` on timeout/denial.
100
+ """
101
+ url = DEVICE_FLOW_CONFIG["access_token_url"].format(host=host)
102
+ payload = {
103
+ "client_id": DEVICE_FLOW_CONFIG["client_id"],
104
+ "device_code": device_code,
105
+ "grant_type": DEVICE_FLOW_CONFIG["grant_type"],
106
+ }
107
+ headers = {"Accept": "application/json"}
108
+
109
+ deadline = time.time() + expires_in
110
+ poll_interval = max(interval, DEVICE_FLOW_CONFIG["default_poll_interval"])
111
+
112
+ while time.time() < deadline:
113
+ time.sleep(poll_interval)
114
+ try:
115
+ resp = requests.post(url, data=payload, headers=headers, timeout=30)
116
+ data = resp.json() if resp.status_code == 200 else {}
117
+ except Exception as exc:
118
+ logger.warning("Device flow poll error: %s", exc)
119
+ continue
120
+
121
+ token = data.get("access_token")
122
+ if token:
123
+ return token
124
+
125
+ error = data.get("error", "")
126
+ if error == "authorization_pending":
127
+ continue
128
+ if error == "slow_down":
129
+ poll_interval += 5
130
+ continue
131
+ if error in ("expired_token", "access_denied", "unsupported_grant_type"):
132
+ logger.warning("Device flow denied or expired: %s", error)
133
+ return None
134
+ # Unknown error — keep trying until deadline
135
+ logger.debug("Device flow poll returned: %s", data)
136
+
137
+ return None
138
+
139
+
140
+ def save_device_token(host: str, oauth_token: str, user: str = "") -> bool:
141
+ """Persist a token obtained via the Device Flow to disk."""
142
+ try:
143
+ path = get_device_token_storage_path()
144
+ data: Dict[str, Any] = {}
145
+ if path.exists():
146
+ with open(path, "r", encoding="utf-8") as fh:
147
+ data = json.load(fh)
148
+ data[host] = {
149
+ "oauth_token": oauth_token,
150
+ "user": user,
151
+ "created_at": time.time(),
152
+ }
153
+ with open(path, "w", encoding="utf-8") as fh:
154
+ json.dump(data, fh, indent=2)
155
+ path.chmod(0o600)
156
+ return True
157
+ except Exception as exc:
158
+ logger.error("Failed to save device token: %s", exc)
159
+ return False
160
+
161
+
162
+ def load_device_tokens() -> List[CopilotToken]:
163
+ """Load tokens previously obtained via the Device Flow."""
164
+ tokens: List[CopilotToken] = []
165
+ try:
166
+ path = get_device_token_storage_path()
167
+ if not path.exists():
168
+ return tokens
169
+ with open(path, "r", encoding="utf-8") as fh:
170
+ data = json.load(fh)
171
+ if isinstance(data, dict):
172
+ for host, entry in data.items():
173
+ if not isinstance(entry, dict):
174
+ continue
175
+ oauth_token = entry.get("oauth_token")
176
+ if oauth_token:
177
+ tokens.append(
178
+ CopilotToken(
179
+ host=host,
180
+ oauth_token=oauth_token,
181
+ user=entry.get("user", ""),
182
+ )
183
+ )
184
+ except Exception as exc:
185
+ logger.warning("Failed to load device tokens: %s", exc)
186
+ return tokens
187
+
188
+
189
+ # ---------------------------------------------------------------------------
190
+ # Session token exchange — converts long-lived OAuth token → short-lived
191
+ # Copilot API bearer token (typically valid ~30 min).
192
+ # ---------------------------------------------------------------------------
193
+
194
+
195
+ @dataclass
196
+ class SessionToken:
197
+ """A short-lived Copilot API session token."""
198
+
199
+ token: str
200
+ expires_at: float # Unix timestamp
201
+ api_endpoint: str = (
202
+ "" # API base URL from the token response (may differ per region/host)
203
+ )
204
+
205
+
206
+ # Module-level cache keyed by (host, oauth_token[:16])
207
+ _session_cache: Dict[str, SessionToken] = {}
208
+
209
+ # Stores the API base URL returned by the most recent session-token exchange
210
+ # per host, so that model registration can use it.
211
+ _host_api_endpoints: Dict[str, str] = {}
212
+
213
+
214
+ def _cache_key(oauth_token: str, host: str) -> str:
215
+ return f"{host}:{oauth_token[:16]}"
216
+
217
+
218
+ def _token_endpoint(host: str) -> str:
219
+ """Return the Copilot session-token endpoint for the given host."""
220
+ if host == "github.com":
221
+ return COPILOT_AUTH_CONFIG["github_token_url"]
222
+ return COPILOT_AUTH_CONFIG["ghe_token_url_template"].format(host=host)
223
+
224
+
225
+ def exchange_for_session_token(
226
+ oauth_token: str, host: str = "github.com"
227
+ ) -> Optional[SessionToken]:
228
+ """Exchange a GitHub OAuth token for a short-lived Copilot session token.
229
+
230
+ The response ``endpoints.api`` value is the correct API base URL for this
231
+ token and may differ from the default (e.g. regional or GHE deployments).
232
+ """
233
+ url = _token_endpoint(host)
234
+ headers = {
235
+ "Authorization": f"token {oauth_token}",
236
+ "Accept": "application/json",
237
+ "Editor-Version": COPILOT_AUTH_CONFIG["editor_version"],
238
+ "Editor-Plugin-Version": COPILOT_AUTH_CONFIG["editor_plugin_version"],
239
+ "Copilot-Integration-Id": COPILOT_AUTH_CONFIG["copilot_integration_id"],
240
+ }
241
+ try:
242
+ resp = requests.get(url, headers=headers, timeout=30)
243
+ if resp.status_code == 200:
244
+ data = resp.json()
245
+ token_str = data.get("token")
246
+ expires_at = data.get("expires_at", 0)
247
+ if token_str:
248
+ # Extract the API endpoint — the token is only valid against
249
+ # this specific URL. Falls back to the default if missing.
250
+ endpoints = data.get("endpoints") or {}
251
+ api_endpoint = (
252
+ endpoints.get("api", "").rstrip("/")
253
+ or COPILOT_AUTH_CONFIG["api_base_url"]
254
+ )
255
+ # Remember this for model registration
256
+ _host_api_endpoints[host] = api_endpoint
257
+ logger.debug(
258
+ "Copilot session for %s: api_endpoint=%s", host, api_endpoint
259
+ )
260
+
261
+ st = SessionToken(
262
+ token=token_str,
263
+ expires_at=float(expires_at),
264
+ api_endpoint=api_endpoint,
265
+ )
266
+ # Persist to disk so we survive process restarts within the window
267
+ _persist_session(st, host, oauth_token)
268
+ return st
269
+ logger.warning("Token endpoint returned 200 but no 'token' field")
270
+ elif resp.status_code == 401:
271
+ logger.warning(
272
+ "Copilot token exchange returned 401 — OAuth token may be revoked."
273
+ )
274
+ else:
275
+ logger.warning(
276
+ "Copilot token exchange failed: %s %s",
277
+ resp.status_code,
278
+ resp.text[:200],
279
+ )
280
+ except requests.exceptions.Timeout:
281
+ logger.warning("Timeout exchanging Copilot token for host %s", host)
282
+ except Exception as exc:
283
+ logger.warning("Copilot token exchange error: %s", exc)
284
+ return None
285
+
286
+
287
+ def _persist_session(st: SessionToken, host: str, oauth_token: str = "") -> None:
288
+ """Write session token to disk for reuse after restarts.
289
+
290
+ Stores a fingerprint of the OAuth token so that a persisted session is
291
+ only reused when the same OAuth token is still active.
292
+ """
293
+ try:
294
+ path = get_session_cache_path()
295
+ data: Dict[str, Any] = {}
296
+ if path.exists():
297
+ with open(path, "r", encoding="utf-8") as fh:
298
+ data = json.load(fh)
299
+ data[host] = {
300
+ "token": st.token,
301
+ "expires_at": st.expires_at,
302
+ "api_endpoint": st.api_endpoint,
303
+ "oauth_fingerprint": oauth_token[:16] if oauth_token else "",
304
+ }
305
+ with open(path, "w", encoding="utf-8") as fh:
306
+ json.dump(data, fh, indent=2)
307
+ path.chmod(0o600)
308
+ except Exception as exc:
309
+ logger.debug("Could not persist session token: %s", exc)
310
+
311
+
312
+ def _load_persisted_session(host: str, oauth_token: str = "") -> Optional[SessionToken]:
313
+ """Load a previously persisted session token from disk.
314
+
315
+ If *oauth_token* is provided, the persisted entry is only returned when
316
+ its stored fingerprint matches ``oauth_token[:16]``, preventing
317
+ cross-account reuse after a re-login.
318
+ """
319
+ try:
320
+ path = get_session_cache_path()
321
+ if not path.exists():
322
+ return None
323
+ with open(path, "r", encoding="utf-8") as fh:
324
+ data = json.load(fh)
325
+ entry = data.get(host)
326
+ if entry:
327
+ # Verify the stored fingerprint matches the current OAuth token
328
+ stored_fp = entry.get("oauth_fingerprint", "")
329
+ if oauth_token and stored_fp and stored_fp != oauth_token[:16]:
330
+ logger.debug(
331
+ "Persisted session fingerprint mismatch for %s — skipping", host
332
+ )
333
+ return None
334
+
335
+ api_endpoint = entry.get(
336
+ "api_endpoint", COPILOT_AUTH_CONFIG["api_base_url"]
337
+ )
338
+ # Restore the host→endpoint mapping
339
+ if api_endpoint:
340
+ _host_api_endpoints[host] = api_endpoint
341
+ return SessionToken(
342
+ token=entry["token"],
343
+ expires_at=float(entry["expires_at"]),
344
+ api_endpoint=api_endpoint,
345
+ )
346
+ except Exception as exc:
347
+ logger.debug("Could not load persisted session: %s", exc)
348
+ return None
349
+
350
+
351
+ def get_valid_session_token(
352
+ oauth_token: str, host: str = "github.com"
353
+ ) -> Optional[str]:
354
+ """Return a valid Copilot session token, refreshing if needed.
355
+
356
+ Checks in-memory cache → on-disk cache → exchanges for a new one.
357
+ Returns the raw bearer token string or ``None``.
358
+ """
359
+ key = _cache_key(oauth_token, host)
360
+
361
+ # 1) In-memory cache
362
+ cached = _session_cache.get(key)
363
+ if cached and cached.expires_at > time.time() + 60:
364
+ # Ensure host→endpoint mapping is populated
365
+ if cached.api_endpoint:
366
+ _host_api_endpoints[host] = cached.api_endpoint
367
+ return cached.token
368
+
369
+ # 2) On-disk cache (with fingerprint verification)
370
+ persisted = _load_persisted_session(host, oauth_token)
371
+ if persisted and persisted.expires_at > time.time() + 60:
372
+ _session_cache[key] = persisted
373
+ return persisted.token
374
+
375
+ # 3) Exchange
376
+ new_token = exchange_for_session_token(oauth_token, host)
377
+ if new_token:
378
+ _session_cache[key] = new_token
379
+ return new_token.token
380
+
381
+ return None
382
+
383
+
384
+ def get_api_endpoint_for_host(host: str) -> str:
385
+ """Return the Copilot API base URL for the given host.
386
+
387
+ The correct endpoint is discovered during session-token exchange
388
+ (the ``endpoints.api`` field in the response). Falls back to the
389
+ default ``api.githubcopilot.com`` if no exchange has happened yet.
390
+ """
391
+ return _host_api_endpoints.get(host, COPILOT_AUTH_CONFIG["api_base_url"])
392
+
393
+
394
+ def clear_caches() -> None:
395
+ """Reset all in-memory session and endpoint caches.
396
+
397
+ Called by ``/copilot-logout`` to ensure no stale Copilot state remains.
398
+ """
399
+ _session_cache.clear()
400
+ _host_api_endpoints.clear()
401
+
402
+
403
+ # ---------------------------------------------------------------------------
404
+ # Model persistence — copilot_models.json
405
+ # ---------------------------------------------------------------------------
406
+
407
+
408
+ def load_copilot_models() -> Dict[str, Any]:
409
+ """Load registered Copilot models from copilot_models.json."""
410
+ try:
411
+ path = get_copilot_models_path()
412
+ if path.exists():
413
+ with open(path, "r", encoding="utf-8") as fh:
414
+ data = json.load(fh)
415
+ if isinstance(data, dict):
416
+ return data
417
+ logger.warning("copilot_models.json is not a JSON object — ignoring")
418
+ except Exception as exc:
419
+ logger.error("Failed to load Copilot models: %s", exc)
420
+ return {}
421
+
422
+
423
+ def save_copilot_models(models: Dict[str, Any]) -> bool:
424
+ """Persist Copilot models to copilot_models.json."""
425
+ try:
426
+ path = get_copilot_models_path()
427
+ with open(path, "w", encoding="utf-8") as fh:
428
+ json.dump(models, fh, indent=2)
429
+ return True
430
+ except Exception as exc:
431
+ logger.error("Failed to save Copilot models: %s", exc)
432
+ return False
433
+
434
+
435
+ def remove_copilot_models() -> int:
436
+ """Remove all Copilot-sourced models from copilot_models.json."""
437
+ try:
438
+ models = load_copilot_models()
439
+ to_remove = [
440
+ name
441
+ for name, cfg in models.items()
442
+ if cfg.get("oauth_source") == "copilot-auth-plugin"
443
+ ]
444
+ for name in to_remove:
445
+ models.pop(name, None)
446
+ if save_copilot_models(models):
447
+ return len(to_remove)
448
+ except Exception as exc:
449
+ logger.error("Error removing Copilot models: %s", exc)
450
+ return 0
451
+
452
+
453
+ def fetch_copilot_models(session_token: str, host: str = "github.com") -> List[str]:
454
+ """Try to fetch the model catalogue from the Copilot API.
455
+
456
+ Falls back to ``DEFAULT_COPILOT_MODELS`` if the endpoint is unavailable.
457
+ Uses the host-specific API endpoint discovered during token exchange.
458
+ """
459
+ api_base = get_api_endpoint_for_host(host)
460
+ url = f"{api_base}/models"
461
+ headers = {
462
+ "Authorization": f"Bearer {session_token}",
463
+ "Accept": "application/json",
464
+ "Editor-Version": COPILOT_AUTH_CONFIG["editor_version"],
465
+ "Editor-Plugin-Version": COPILOT_AUTH_CONFIG["editor_plugin_version"],
466
+ "Copilot-Integration-Id": COPILOT_AUTH_CONFIG["copilot_integration_id"],
467
+ "Openai-Intent": COPILOT_AUTH_CONFIG["openai_intent"],
468
+ }
469
+ try:
470
+ resp = requests.get(url, headers=headers, timeout=15)
471
+ if resp.status_code == 200:
472
+ data = resp.json()
473
+ model_list = data.get("data") or data.get("models") or []
474
+ if isinstance(model_list, list):
475
+ ids = []
476
+ for m in model_list:
477
+ if isinstance(m, dict):
478
+ mid = m.get("id") or m.get("name")
479
+ if mid:
480
+ ids.append(mid)
481
+ elif isinstance(m, str):
482
+ ids.append(m)
483
+ if ids:
484
+ logger.info("Fetched %d models from Copilot API", len(ids))
485
+ return ids
486
+ except Exception as exc:
487
+ logger.debug("Could not fetch Copilot model list: %s", exc)
488
+
489
+ logger.info("Using default Copilot model list")
490
+ return DEFAULT_COPILOT_MODELS
491
+
492
+
493
+ def _is_claude_model(model_name: str) -> bool:
494
+ """Check if a model name refers to a Claude/Anthropic model."""
495
+ return model_name.lower().startswith("claude-")
496
+
497
+
498
+ def _is_openai_model(model_name: str) -> bool:
499
+ """Check if a model name refers to an OpenAI/GPT model."""
500
+ lower = model_name.lower()
501
+ return lower.startswith("gpt-") or lower.startswith("o3") or lower.startswith("o4")
502
+
503
+
504
+ def _build_claude_model_settings(model_name: str) -> Dict[str, Any]:
505
+ """Build model_settings fields for a Claude model.
506
+
507
+ Mirrors the conventions in the claude_code_oauth plugin's
508
+ ``_build_model_entry``.
509
+ """
510
+ supported_settings = [
511
+ "temperature",
512
+ "extended_thinking",
513
+ "budget_tokens",
514
+ "interleaved_thinking",
515
+ ]
516
+
517
+ # Opus 4-6 (e.g. claude-opus-4.6) supports the effort setting,
518
+ # same as the claude_code_oauth plugin.
519
+ lower = model_name.lower()
520
+ if "opus-4.6" in lower or "opus-4-6" in lower or "4-6-opus" in lower:
521
+ supported_settings.append("effort")
522
+
523
+ return {"supported_settings": supported_settings}
524
+
525
+
526
+ def _build_openai_model_settings(model_name: str) -> Dict[str, Any]:
527
+ """Build model_settings fields for an OpenAI/GPT model behind Copilot.
528
+
529
+ The Copilot API only proxies a subset of OpenAI features. Currently
530
+ none of the GPT models exposed through Copilot support
531
+ ``reasoning_effort``, ``summary``, or ``verbosity`` — sending those
532
+ parameters results in a 400 Bad Request. Only basic ``temperature``
533
+ is safe.
534
+ """
535
+ return {"supported_settings": ["temperature"]}
536
+
537
+
538
+ def _model_settings_for(model_name: str) -> Dict[str, Any]:
539
+ """Return family-specific config fields for a Copilot model.
540
+
541
+ Claude models get extended_thinking/effort/etc.; OpenAI models get
542
+ reasoning_effort/summary/verbosity; everything else gets temperature.
543
+ """
544
+ if _is_claude_model(model_name):
545
+ return _build_claude_model_settings(model_name)
546
+ if _is_openai_model(model_name):
547
+ return _build_openai_model_settings(model_name)
548
+ # Fallback for other providers (Gemini, etc.)
549
+ return {"supported_settings": ["temperature"]}
550
+
551
+
552
+ def add_models_to_config(
553
+ models: List[str],
554
+ host: str = "github.com",
555
+ ) -> bool:
556
+ """Register Copilot models in copilot_models.json."""
557
+ try:
558
+ copilot_models = load_copilot_models()
559
+ added = 0
560
+ prefix = COPILOT_AUTH_CONFIG["prefix"]
561
+ # Use the API endpoint from session-token exchange (critical for GHE).
562
+ api_url = get_api_endpoint_for_host(host)
563
+ for model_name in models:
564
+ prefixed = f"{prefix}{model_name}"
565
+ entry: Dict[str, Any] = {
566
+ "type": "copilot",
567
+ "name": model_name,
568
+ "custom_endpoint": {
569
+ "url": api_url,
570
+ },
571
+ "context_length": COPILOT_MODEL_CONTEXT_LENGTHS.get(
572
+ model_name,
573
+ COPILOT_AUTH_CONFIG["default_context_length"],
574
+ ),
575
+ "copilot_host": host,
576
+ "oauth_source": "copilot-auth-plugin",
577
+ }
578
+ # Merge family-specific settings (supported_settings, etc.)
579
+ entry.update(_model_settings_for(model_name))
580
+ copilot_models[prefixed] = entry
581
+ added += 1
582
+ if save_copilot_models(copilot_models):
583
+ logger.info("Registered %d Copilot models (api: %s)", added, api_url)
584
+ return True
585
+ except Exception as exc:
586
+ logger.error("Error adding Copilot models to config: %s", exc)
587
+ return False