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,155 @@
1
+ ---
2
+ name: tests
3
+ description: Run the test suite, fix regressions introduced by this branch, and leave pre-existing failures untouched
4
+ argument-hint: additional_instructions
5
+ ---
6
+
7
+ # RUN & FIX TESTS
8
+
9
+ **Argument:** `$ARGUMENTS` (optional additional instructions, e.g. "address all failing tests including pre-existing")
10
+
11
+ Run the project's test suite, fix only regressions introduced by this branch, and leave pre-existing failures untouched.
12
+
13
+ If `$ARGUMENTS` contains additional instructions, apply them — they override default behavior (e.g. fix pre-existing failures too, focus on specific test files).
14
+
15
+ ## STEP 1: Setup
16
+
17
+ ```bash
18
+ FLUX_ROOT="${FLUX_ROOT:-$HOME/.flux}"
19
+ FLUX_DIR=$(printf '%s' "$(pwd -P)" | tr -cs 'a-zA-Z0-9' '-')
20
+ FLUX_BASE="$FLUX_ROOT/$FLUX_DIR"
21
+ CONFIG_FILE="$FLUX_BASE/config.env"
22
+ mkdir -p "$FLUX_BASE/todo" "$FLUX_BASE/done" "$FLUX_BASE/review" "$FLUX_BASE/research"
23
+ ```
24
+
25
+ Source config to get `TEST_CMD`:
26
+
27
+ ```bash
28
+ source "$CONFIG_FILE" 2>/dev/null
29
+ echo "TEST_CMD: ${TEST_CMD:-<not set>}"
30
+ ```
31
+
32
+ If `TEST_CMD` is empty or config file is missing:
33
+
34
+ ```
35
+ Error: TEST_CMD is not configured.
36
+ Run /flux/config to set your test command.
37
+ ```
38
+
39
+ Stop.
40
+
41
+ ## STEP 2: Establish baseline (pre-existing failures)
42
+
43
+ Find the merge base with the default branch to identify which tests were already failing before this branch's changes:
44
+
45
+ ```bash
46
+ DEFAULT_BRANCH=$(git remote show origin 2>/dev/null | grep 'HEAD branch' | awk '{print $NF}' || echo "main")
47
+ MERGE_BASE=$(git merge-base HEAD "origin/$DEFAULT_BRANCH" 2>/dev/null)
48
+ echo "MERGE_BASE: $MERGE_BASE"
49
+ ```
50
+
51
+ Run the test suite against the merge base in a temporary worktree to record pre-existing failures:
52
+
53
+ ```bash
54
+ WORKTREE_DIR=$(mktemp -d)
55
+ git worktree add "$WORKTREE_DIR" "$MERGE_BASE" --detach 2>/dev/null
56
+ ```
57
+
58
+ If worktree creation fails (e.g. no network, shallow clone), skip baseline and assume all failures are regressions — note this clearly in output.
59
+
60
+ If worktree created: run `$TEST_CMD` inside it, capture failing test names → `BASELINE_FAILURES`. Then clean up:
61
+
62
+ ```bash
63
+ git worktree remove "$WORKTREE_DIR" --force 2>/dev/null
64
+ ```
65
+
66
+ ## STEP 3: Run tests on current branch
67
+
68
+ ```bash
69
+ eval "$TEST_CMD" 2>&1
70
+ ```
71
+
72
+ Capture exit code and full output.
73
+
74
+ - **All tests pass** → print `✅ All tests pass.` and skip to STEP 6.
75
+ - **Failures found** → continue to STEP 4.
76
+
77
+ ## STEP 4: Classify failures
78
+
79
+ For each failing test, classify it:
80
+
81
+ | Classification | Criteria | Action |
82
+ | ---------------- | ---------------------------------------------------------- | -------- |
83
+ | **Regression** | Was passing at merge base (not in `BASELINE_FAILURES`) | Fix it |
84
+ | **Pre-existing** | Was already failing at merge base (in `BASELINE_FAILURES`) | Leave it |
85
+ | **Unknown** | Baseline unavailable | Fix it |
86
+
87
+ Print a summary table:
88
+
89
+ ```
90
+ Test Results
91
+ ────────────────────────────────────────
92
+ Total failures: N
93
+ Regressions: R ← will fix
94
+ Pre-existing: P ← will skip
95
+ Unknown: U ← will fix
96
+ ────────────────────────────────────────
97
+ ```
98
+
99
+ If there are no regressions or unknowns → print `✅ No regressions introduced by this branch.` and skip to STEP 6.
100
+
101
+ ## STEP 5: Fix regressions
102
+
103
+ Fix regressions one at a time. For each:
104
+
105
+ 1. Read the failing test and the source it exercises
106
+ 2. Determine root cause: did the feature change break the test, or does the test need updating to match intentional new behavior?
107
+ 3. Apply the minimal fix — either in source or in the test file
108
+ 4. Do NOT expand test scope or add new test cases
109
+ 5. Do NOT touch pre-existing failures
110
+
111
+ After fixing all regressions, re-run:
112
+
113
+ ```bash
114
+ eval "$TEST_CMD" 2>&1
115
+ ```
116
+
117
+ Repeat fix → re-run cycle until all regressions pass (max 3 cycles). If still failing after 3 cycles, stop and report:
118
+
119
+ ```
120
+ ⚠️ Could not fix the following regressions after 3 attempts:
121
+ - <test name>: <last error>
122
+
123
+ Remaining pre-existing failures (not touched):
124
+ - <test name>
125
+
126
+ Please review manually.
127
+ ```
128
+
129
+ ## STEP 6: Final summary
130
+
131
+ Print:
132
+
133
+ ```
134
+ Test Suite Summary
135
+ ────────────────────────────────────────
136
+ ✅ Regressions fixed: R
137
+ ⏭ Pre-existing skipped: P
138
+ ❌ Unresolved: U
139
+ ────────────────────────────────────────
140
+ ```
141
+
142
+ If `U > 0`, recommend the user review those manually before committing.
143
+
144
+ ## HARD CONSTRAINT
145
+
146
+ `/flux/tests` MUST NOT use `git commit`, `git push`, `git stash`, `git checkout`, or `git branch`. Only `git merge-base`, `git worktree`, and `git remote` are permitted. MUST NOT modify source files beyond the minimal fix required to resolve a regression. MUST NOT touch pre-existing failures. MUST NOT add new test cases or expand test scope.
147
+
148
+ ## Propose next step
149
+
150
+ Then propose the next step: `/flux/commit` (include arguments if needed).
151
+
152
+ Valid `//flux` commands: `/flux/config`, `/flux/new`, `/flux/ask`, `/flux/split`, `/flux/aug`, `/flux/exec`, `/flux/qa`, `/flux/tests`, `/flux/commit`, `/flux/create-pr`, `/flux/review`, `/flux/address-feedback`, `/flux/status`, `/flux/auto-pilot`, `/flux/rebase`. Do NOT suggest any command not on this list.
153
+
154
+ =================
155
+ $ARGUMENTS
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env python3
2
+ """Render the /flux/about overview using Rich's markdown renderer.
3
+
4
+ This is the deterministic, AI-free renderer for /flux/about. The previous
5
+ hand-rolled ANSI version was rough on tables (column widths didn't account
6
+ for ANSI escapes around cell contents). Rich does the heavy lifting properly:
7
+ real tables, syntax-highlighted code fences, headings, bullets -- all aligned.
8
+
9
+ Single source of truth: the overview text lives in about.md. We read it at
10
+ runtime, strip the YAML frontmatter + the AI-only preamble, normalize the
11
+ wibey //cmd refs to /cmd, and hand the rest to ``rich.markdown.Markdown``.
12
+
13
+ Usage:
14
+ flux_about.py [--source PATH] [--width N] [--no-color]
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import argparse
20
+ import os
21
+ import re
22
+ import sys
23
+ from pathlib import Path
24
+
25
+ from rich.console import Console
26
+ from rich.markdown import Markdown
27
+
28
+
29
+ def _default_source() -> str:
30
+ """Resolve about.md under code-puppy's (XDG-aware) config dir.
31
+
32
+ Runs inside the code-puppy venv, so importing the canonical resolver is the
33
+ single source of truth for the config location -- honoring XDG overrides
34
+ instead of assuming a hard-coded ~/.code_puppy. Falls back to the legacy
35
+ layout only if that import fails (e.g. run standalone).
36
+ """
37
+ try:
38
+ from code_puppy.config import CONFIG_DIR
39
+
40
+ return os.path.join(CONFIG_DIR, "commands", "flux", "about.md")
41
+ except Exception:
42
+ return os.path.join(
43
+ os.path.expanduser("~"), ".code_puppy", "commands", "flux", "about.md"
44
+ )
45
+
46
+
47
+ DEFAULT_SOURCE = _default_source()
48
+ DEFAULT_WIDTH = 120 # most modern terminals are at least this wide
49
+
50
+ # YAML frontmatter block at the top of the file
51
+ FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
52
+ # Wibey //cmd -> /cmd, URL-safe (won't touch https://, example.com//, etc.)
53
+ SLASH_CMD_RE = re.compile(r"(?<![:\w/])//(?=\w)")
54
+ # The AI instruction preamble we skip when rendering directly
55
+ PREAMBLE_RE = re.compile(r"^Output the following overview exactly")
56
+
57
+
58
+ def extract_body(raw: str) -> str:
59
+ """Strip YAML frontmatter and normalize //cmd -> /cmd."""
60
+ body = FRONTMATTER_RE.sub("", raw, count=1).strip()
61
+ return SLASH_CMD_RE.sub("/", body)
62
+
63
+
64
+ def drop_ai_preamble(body: str) -> str:
65
+ """Skip the 'Output the following overview exactly...' block + its --- rule.
66
+
67
+ The preamble exists solely to instruct an LLM; when a script is doing the
68
+ rendering it's just noise. If the preamble isn't present (someone edited
69
+ it out) the body is returned unchanged.
70
+ """
71
+ lines = body.splitlines()
72
+ out: list[str] = []
73
+ skipping = False
74
+ for line in lines:
75
+ if not skipping and PREAMBLE_RE.match(line):
76
+ skipping = True
77
+ continue
78
+ if skipping:
79
+ # The preamble ends at the first standalone --- horizontal rule
80
+ if line.strip() == "---":
81
+ skipping = False
82
+ continue
83
+ out.append(line)
84
+ return "\n".join(out).strip()
85
+
86
+
87
+ def resolve_width(cli_width: int | None) -> int:
88
+ """CLI flag wins; else $COLUMNS; else our DEFAULT_WIDTH."""
89
+ if cli_width and cli_width > 0:
90
+ return cli_width
91
+ env_cols = os.environ.get("COLUMNS")
92
+ if env_cols and env_cols.isdigit() and int(env_cols) > 0:
93
+ return int(env_cols)
94
+ return DEFAULT_WIDTH
95
+
96
+
97
+ def force_utf8_stdout() -> None:
98
+ """Reconfigure stdout to UTF-8 so emoji survive legacy Windows codepages.
99
+
100
+ Under the exec runner the env already forces UTF-8 (PYTHONIOENCODING);
101
+ this covers standalone runs in a cp1252 console, where printing a single
102
+ emoji would otherwise raise UnicodeEncodeError. Best-effort by design --
103
+ these scripts must never crash on an IO quirk. (Duplicated across the
104
+ flux_* scripts on purpose: each is a standalone, dependency-free file.)
105
+ """
106
+ try:
107
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
108
+ except Exception:
109
+ pass
110
+
111
+
112
+ def main(argv: list[str] | None = None) -> int:
113
+ force_utf8_stdout()
114
+ parser = argparse.ArgumentParser(description="Render /flux/about overview")
115
+ parser.add_argument(
116
+ "--source",
117
+ default=DEFAULT_SOURCE,
118
+ help=f"Path to about.md (default: {DEFAULT_SOURCE})",
119
+ )
120
+ parser.add_argument(
121
+ "--width",
122
+ type=int,
123
+ default=None,
124
+ help=f"Render width in cols (default: $COLUMNS or {DEFAULT_WIDTH})",
125
+ )
126
+ parser.add_argument("--no-color", action="store_true", help="Disable ANSI color")
127
+ args = parser.parse_args(argv)
128
+
129
+ source = Path(args.source).expanduser()
130
+ if not source.is_file():
131
+ print(f"(about.md not found at {source})")
132
+ return 1
133
+
134
+ raw = source.read_text(encoding="utf-8", errors="replace")
135
+ cleaned = drop_ai_preamble(extract_body(raw))
136
+
137
+ # force_terminal=True makes Rich emit ANSI to our piped stdout (the exec runner
138
+ # captures it); legacy_windows=False stays off the win32 LegacyWindowsTerm path,
139
+ # which both loses that ANSI and crashes encoding emoji on cp1252.
140
+ console = Console(
141
+ force_terminal=True,
142
+ legacy_windows=False,
143
+ color_system=None if args.no_color else "truecolor",
144
+ width=resolve_width(args.width),
145
+ no_color=args.no_color,
146
+ # Avoid stripping the user's content when stdout isn't a real TTY.
147
+ soft_wrap=False,
148
+ )
149
+ console.print(Markdown(cleaned))
150
+ return 0
151
+
152
+
153
+ if __name__ == "__main__":
154
+ raise SystemExit(main())
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env python3
2
+ """Render the //flux cheatsheet (pipeline flows) colorized for the terminal.
3
+
4
+ This is the code-puppy equivalent of Wibey's native cheatsheet panel. Wibey
5
+ shows clickable PIPELINE A/B/C/D tabs; code-puppy can't host interactive tabs,
6
+ so this prints all pipelines stacked (or one, via --pipeline).
7
+
8
+ SINGLE SOURCE OF TRUTH: the pipeline definitions are parsed at runtime from
9
+ `pipeline.md` in the flux _docs directory. Editing that doc changes this output
10
+ automatically -- nothing is hardcoded here except presentation.
11
+
12
+ Wibey writes commands as `/flux/<cmd>`; code-puppy's namespaced slash commands
13
+ use a single leading slash, so every command is normalized to `/flux/<cmd>`
14
+ before display -- exactly what a code-puppy user types to run it.
15
+
16
+ The flux _docs directory defaults to code-puppy's config dir (XDG-aware) rather
17
+ than any hard-coded home path; ``--docs`` overrides it. The command wiring
18
+ passes it explicitly via a ``{command:flux/_docs}`` token.
19
+
20
+ Usage:
21
+ flux_cheatsheet.py [--docs DIR] [--pipeline A|B|C|D] [--no-color]
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import argparse
27
+ import os
28
+ import re
29
+ import sys
30
+ from pathlib import Path
31
+
32
+ # --- ANSI palette -----------------------------------------------------------
33
+ RESET = "\033[0m"
34
+ MAGENTA = "\033[1;35m"
35
+ CYAN = "\033[1;36m"
36
+ GREEN = "\033[32m"
37
+ WHITE = "\033[1;37m"
38
+ GREY = "\033[90m"
39
+
40
+ FRAKTUR_F = "\U0001d571" # mathematical bold fraktur capital F
41
+
42
+
43
+ def _default_docs() -> str:
44
+ """Resolve the flux _docs dir under code-puppy's (XDG-aware) config dir.
45
+
46
+ Runs inside the code-puppy venv, so importing the canonical resolver is the
47
+ single source of truth. Falls back to the legacy ~/.code_puppy layout only
48
+ if that import somehow fails (e.g. run standalone).
49
+ """
50
+ try:
51
+ from code_puppy.config import CONFIG_DIR
52
+
53
+ return os.path.join(CONFIG_DIR, "commands", "flux", "_docs")
54
+ except Exception:
55
+ return os.path.join(
56
+ os.path.expanduser("~"), ".code_puppy", "commands", "flux", "_docs"
57
+ )
58
+
59
+
60
+ DEFAULT_DOCS = _default_docs()
61
+
62
+ # matches `/flux/`, `/flux/`, etc. -> we normalize to `/flux/` (the single-slash
63
+ # namespaced command code-puppy users actually type).
64
+ SLASH_CMD = re.compile(r"/+flux/")
65
+ PIPELINE_HEADING = re.compile(r"^##\s+PIPELINE\s+([A-Za-z0-9]+)\s*:")
66
+
67
+
68
+ class Theme:
69
+ def __init__(self, enabled: bool) -> None:
70
+ self.enabled = enabled
71
+
72
+ def __call__(self, code: str, text: str) -> str:
73
+ return f"{code}{text}{RESET}" if self.enabled else text
74
+
75
+
76
+ def strip_slashes(line: str) -> str:
77
+ """`/flux/new` -> `/flux/new`, `/flux/review <PR#>` -> `/flux/review <PR#>`.
78
+
79
+ Collapses any run of leading slashes to the single-slash namespaced form
80
+ code-puppy dispatches (``/flux/<cmd>``).
81
+ """
82
+ return SLASH_CMD.sub("/flux/", line)
83
+
84
+
85
+ def parse_pipelines(md_text: str) -> list[tuple[str, str, list[str]]]:
86
+ """Return [(letter, description, [flow_line, ...]), ...] in document order."""
87
+ lines = md_text.splitlines()
88
+ pipelines: list[tuple[str, str, list[str]]] = []
89
+
90
+ i = 0
91
+ n = len(lines)
92
+ while i < n:
93
+ m = PIPELINE_HEADING.match(lines[i])
94
+ if not m:
95
+ i += 1
96
+ continue
97
+ letter = m.group(1).upper()
98
+ i += 1
99
+
100
+ # find the description: first meaningful line before the code fence
101
+ description = ""
102
+ while i < n and not PIPELINE_HEADING.match(lines[i]):
103
+ stripped = lines[i].strip()
104
+ if stripped.startswith("```"):
105
+ break
106
+ if stripped and stripped != "---" and not stripped.startswith("#"):
107
+ description = stripped
108
+ i += 1
109
+ break
110
+ i += 1
111
+
112
+ # find and capture the first fenced code block = the flow
113
+ flow: list[str] = []
114
+ while i < n and not PIPELINE_HEADING.match(lines[i]):
115
+ if lines[i].strip().startswith("```"):
116
+ i += 1 # enter the fence
117
+ while i < n and not lines[i].strip().startswith("```"):
118
+ flow.append(lines[i])
119
+ i += 1
120
+ i += 1 # exit the fence
121
+ break
122
+ i += 1
123
+
124
+ # trim leading/trailing blank lines inside the flow
125
+ while flow and not flow[0].strip():
126
+ flow.pop(0)
127
+ while flow and not flow[-1].strip():
128
+ flow.pop()
129
+
130
+ pipelines.append((letter, description, flow))
131
+ return pipelines
132
+
133
+
134
+ def render_flow_line(raw: str, theme: Theme) -> str:
135
+ """Colorize one flow line: comments dim, command flow green, slashes stripped."""
136
+ if not raw.strip():
137
+ return ""
138
+ if raw.strip().startswith("#"):
139
+ # keep the comment's indentation, dim the text
140
+ return theme(GREY, strip_slashes(raw))
141
+ return theme(GREEN, strip_slashes(raw))
142
+
143
+
144
+ def render(pipelines: list[tuple[str, str, list[str]]], theme: Theme) -> str:
145
+ width = 60
146
+ out: list[str] = []
147
+ out.append(theme(MAGENTA, f"{FRAKTUR_F} FLUX CHEATSHEET"))
148
+ out.append(theme(MAGENTA, "\u2550" * width))
149
+
150
+ for idx, (letter, desc, flow) in enumerate(pipelines):
151
+ if idx > 0:
152
+ out.append("")
153
+ out.append(theme(GREY, "\u2500" * width))
154
+ out.append("")
155
+ out.append(theme(CYAN, f"PIPELINE {letter}"))
156
+ if desc:
157
+ out.append(theme(WHITE, desc))
158
+ out.append("")
159
+ for line in flow:
160
+ out.append(render_flow_line(line, theme))
161
+
162
+ out.append("")
163
+ out.append(theme(MAGENTA, "\u2550" * width))
164
+ return "\n".join(out)
165
+
166
+
167
+ def force_utf8_stdout() -> None:
168
+ """Reconfigure stdout to UTF-8 so emoji survive legacy Windows codepages.
169
+
170
+ Under the exec runner the env already forces UTF-8 (PYTHONIOENCODING);
171
+ this covers standalone runs in a cp1252 console, where printing a single
172
+ emoji or box-drawing glyph would otherwise raise UnicodeEncodeError.
173
+ Best-effort by design -- these scripts must never crash on an IO quirk.
174
+ (Duplicated across the flux_* scripts on purpose: each is a standalone,
175
+ dependency-free file.)
176
+ """
177
+ try:
178
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
179
+ except Exception:
180
+ pass
181
+
182
+
183
+ def main(argv: list[str] | None = None) -> int:
184
+ force_utf8_stdout()
185
+ parser = argparse.ArgumentParser(description="Render //flux cheatsheet panel")
186
+ parser.add_argument("--docs", default=DEFAULT_DOCS, help="flux _docs directory")
187
+ parser.add_argument(
188
+ "--pipeline",
189
+ default=None,
190
+ help="Show only one pipeline (A, B, C, or D)",
191
+ )
192
+ parser.add_argument(
193
+ "pipeline_pos",
194
+ nargs="?",
195
+ default=None,
196
+ help="Optional positional pipeline filter (a/b/c/d); overrides --pipeline.",
197
+ )
198
+ parser.add_argument("--no-color", action="store_true", help="Disable ANSI color")
199
+ args = parser.parse_args(argv)
200
+
201
+ # Positional pipeline arg (e.g. `flux_cheatsheet.py a`) wins over --pipeline
202
+ # so command-line callers don't have to remember the flag name.
203
+ selected_pipeline = args.pipeline_pos or args.pipeline
204
+ if selected_pipeline is not None:
205
+ normalized = selected_pipeline.strip().upper()
206
+ if normalized not in {"A", "B", "C", "D"}:
207
+ parser.error(
208
+ f"invalid pipeline: {selected_pipeline!r} (choose from A, B, C, D)"
209
+ )
210
+ args.pipeline = normalized
211
+
212
+ docs_dir = Path(args.docs).expanduser()
213
+ pipeline_md = docs_dir / "pipeline.md"
214
+
215
+ # The exec runner pipes stdout + injects FORCE_COLOR=1 (see _run_exec_directive), so
216
+ # color stays on despite isatty()==False. Keep the FORCE_COLOR branch so the
217
+ # cheatsheet doesn't silently go monochrome under the runner.
218
+ color_on = not args.no_color and (
219
+ sys.stdout.isatty() or os.environ.get("FORCE_COLOR")
220
+ )
221
+ theme = Theme(bool(color_on))
222
+
223
+ if not pipeline_md.is_file():
224
+ print(theme(GREY, f"(pipeline doc not found at {pipeline_md})"))
225
+ return 1
226
+
227
+ pipelines = parse_pipelines(
228
+ pipeline_md.read_text(encoding="utf-8", errors="replace")
229
+ )
230
+
231
+ if args.pipeline:
232
+ # Already validated + normalized above
233
+ want = args.pipeline
234
+ pipelines = [p for p in pipelines if p[0] == want]
235
+ if not pipelines:
236
+ print(theme(GREY, f"(no PIPELINE {want} found)"))
237
+ return 1
238
+
239
+ if not pipelines:
240
+ print(theme(GREY, "(no pipelines found in pipeline.md)"))
241
+ return 1
242
+
243
+ print(render(pipelines, theme))
244
+ return 0
245
+
246
+
247
+ if __name__ == "__main__":
248
+ raise SystemExit(main())