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.
- code_puppy_core_plugins/__init__.py +5 -0
- code_puppy_core_plugins/acp/README.md +266 -0
- code_puppy_core_plugins/acp/__init__.py +8 -0
- code_puppy_core_plugins/acp/agent.py +494 -0
- code_puppy_core_plugins/acp/bridge.py +309 -0
- code_puppy_core_plugins/acp/capabilities.py +73 -0
- code_puppy_core_plugins/acp/commands.py +116 -0
- code_puppy_core_plugins/acp/content.py +115 -0
- code_puppy_core_plugins/acp/io_delegation.py +231 -0
- code_puppy_core_plugins/acp/mcp_config.py +66 -0
- code_puppy_core_plugins/acp/permissions.py +159 -0
- code_puppy_core_plugins/acp/persistence.py +197 -0
- code_puppy_core_plugins/acp/register_callbacks.py +110 -0
- code_puppy_core_plugins/acp/replay.py +114 -0
- code_puppy_core_plugins/acp/session.py +329 -0
- code_puppy_core_plugins/acp/session_config.py +179 -0
- code_puppy_core_plugins/acp/state.py +135 -0
- code_puppy_core_plugins/agent_skills/__init__.py +22 -0
- code_puppy_core_plugins/agent_skills/config.py +208 -0
- code_puppy_core_plugins/agent_skills/discovery.py +337 -0
- code_puppy_core_plugins/agent_skills/downloader.py +392 -0
- code_puppy_core_plugins/agent_skills/enabled_skills.py +82 -0
- code_puppy_core_plugins/agent_skills/installer.py +22 -0
- code_puppy_core_plugins/agent_skills/metadata.py +219 -0
- code_puppy_core_plugins/agent_skills/prompt_builder.py +49 -0
- code_puppy_core_plugins/agent_skills/provider.py +52 -0
- code_puppy_core_plugins/agent_skills/register_callbacks.py +309 -0
- code_puppy_core_plugins/agent_skills/remote_catalog.py +322 -0
- code_puppy_core_plugins/agent_skills/skill_catalog.py +257 -0
- code_puppy_core_plugins/agent_skills/skill_commands.py +102 -0
- code_puppy_core_plugins/agent_skills/skills_install_menu.py +698 -0
- code_puppy_core_plugins/agent_skills/skills_menu.py +794 -0
- code_puppy_core_plugins/aws_bedrock/__init__.py +14 -0
- code_puppy_core_plugins/aws_bedrock/config.py +101 -0
- code_puppy_core_plugins/aws_bedrock/register_callbacks.py +243 -0
- code_puppy_core_plugins/aws_bedrock/utils.py +186 -0
- code_puppy_core_plugins/azure_foundry/README.md +238 -0
- code_puppy_core_plugins/azure_foundry/__init__.py +15 -0
- code_puppy_core_plugins/azure_foundry/config.py +126 -0
- code_puppy_core_plugins/azure_foundry/discovery.py +189 -0
- code_puppy_core_plugins/azure_foundry/register_callbacks.py +506 -0
- code_puppy_core_plugins/azure_foundry/token.py +182 -0
- code_puppy_core_plugins/azure_foundry/utils.py +375 -0
- code_puppy_core_plugins/btw/__init__.py +1 -0
- code_puppy_core_plugins/btw/inline_view.py +135 -0
- code_puppy_core_plugins/btw/register_callbacks.py +106 -0
- code_puppy_core_plugins/btw/side_query.py +91 -0
- code_puppy_core_plugins/chatgpt_oauth/IMAGEGEN_SKILL.md +83 -0
- code_puppy_core_plugins/chatgpt_oauth/__init__.py +8 -0
- code_puppy_core_plugins/chatgpt_oauth/config.py +52 -0
- code_puppy_core_plugins/chatgpt_oauth/image_generation.py +253 -0
- code_puppy_core_plugins/chatgpt_oauth/image_tool.py +70 -0
- code_puppy_core_plugins/chatgpt_oauth/oauth_flow.py +461 -0
- code_puppy_core_plugins/chatgpt_oauth/register_callbacks.py +288 -0
- code_puppy_core_plugins/chatgpt_oauth/test_plugin.py +663 -0
- code_puppy_core_plugins/chatgpt_oauth/usage.py +113 -0
- code_puppy_core_plugins/chatgpt_oauth/utils.py +534 -0
- code_puppy_core_plugins/claude_code_hooks/__init__.py +1 -0
- code_puppy_core_plugins/claude_code_hooks/config.py +137 -0
- code_puppy_core_plugins/claude_code_hooks/register_callbacks.py +383 -0
- code_puppy_core_plugins/claude_code_oauth/README.md +167 -0
- code_puppy_core_plugins/claude_code_oauth/SETUP.md +93 -0
- code_puppy_core_plugins/claude_code_oauth/__init__.py +25 -0
- code_puppy_core_plugins/claude_code_oauth/config.py +59 -0
- code_puppy_core_plugins/claude_code_oauth/fast_mode.py +122 -0
- code_puppy_core_plugins/claude_code_oauth/prompt_handler.py +64 -0
- code_puppy_core_plugins/claude_code_oauth/register_callbacks.py +719 -0
- code_puppy_core_plugins/claude_code_oauth/test_plugin.py +285 -0
- code_puppy_core_plugins/claude_code_oauth/token_refresh_heartbeat.py +240 -0
- code_puppy_core_plugins/claude_code_oauth/utils.py +663 -0
- code_puppy_core_plugins/code_puppy_agent/AGENTS_AND_TOOLS.md +155 -0
- code_puppy_core_plugins/code_puppy_agent/MODELS_AND_MCP.md +104 -0
- code_puppy_core_plugins/code_puppy_agent/PLUGINS_AND_CALLBACKS.md +147 -0
- code_puppy_core_plugins/code_puppy_agent/SESSIONS_AND_HISTORY.md +39 -0
- code_puppy_core_plugins/code_puppy_agent/SKILL.md +180 -0
- code_puppy_core_plugins/code_puppy_agent/SKILLS_SYSTEM.md +136 -0
- code_puppy_core_plugins/code_puppy_agent/SYSTEM_PROMPT_CONFIG_AND_I18N.md +160 -0
- code_puppy_core_plugins/code_puppy_agent/__init__.py +5 -0
- code_puppy_core_plugins/code_puppy_agent/register_callbacks.py +46 -0
- code_puppy_core_plugins/computer_use/NativeCapture.swift +123 -0
- code_puppy_core_plugins/computer_use/README.md +109 -0
- code_puppy_core_plugins/computer_use/__init__.py +1 -0
- code_puppy_core_plugins/computer_use/accessibility.py +163 -0
- code_puppy_core_plugins/computer_use/activation.py +75 -0
- code_puppy_core_plugins/computer_use/backend.py +584 -0
- code_puppy_core_plugins/computer_use/backend_types.py +5 -0
- code_puppy_core_plugins/computer_use/capture.py +110 -0
- code_puppy_core_plugins/computer_use/commands.py +62 -0
- code_puppy_core_plugins/computer_use/geometry.py +81 -0
- code_puppy_core_plugins/computer_use/inline_image.py +56 -0
- code_puppy_core_plugins/computer_use/keycodes.py +47 -0
- code_puppy_core_plugins/computer_use/policy.py +144 -0
- code_puppy_core_plugins/computer_use/register_callbacks.py +96 -0
- code_puppy_core_plugins/computer_use/safety.py +18 -0
- code_puppy_core_plugins/computer_use/settle.py +64 -0
- code_puppy_core_plugins/computer_use/state.py +86 -0
- code_puppy_core_plugins/computer_use/tools.py +469 -0
- code_puppy_core_plugins/context_indicator/__init__.py +14 -0
- code_puppy_core_plugins/context_indicator/register_callbacks.py +249 -0
- code_puppy_core_plugins/context_indicator/usage.py +40 -0
- code_puppy_core_plugins/copilot_auth/__init__.py +11 -0
- code_puppy_core_plugins/copilot_auth/config.py +93 -0
- code_puppy_core_plugins/copilot_auth/reasoning_client.py +409 -0
- code_puppy_core_plugins/copilot_auth/register_callbacks.py +460 -0
- code_puppy_core_plugins/copilot_auth/utils.py +587 -0
- code_puppy_core_plugins/customizable_commands/__init__.py +0 -0
- code_puppy_core_plugins/customizable_commands/register_callbacks.py +464 -0
- code_puppy_core_plugins/dbos_durable_exec/__init__.py +1 -0
- code_puppy_core_plugins/dbos_durable_exec/cancel.py +15 -0
- code_puppy_core_plugins/dbos_durable_exec/commands.py +31 -0
- code_puppy_core_plugins/dbos_durable_exec/config.py +31 -0
- code_puppy_core_plugins/dbos_durable_exec/lifecycle.py +83 -0
- code_puppy_core_plugins/dbos_durable_exec/register_callbacks.py +45 -0
- code_puppy_core_plugins/dbos_durable_exec/runtime.py +65 -0
- code_puppy_core_plugins/dbos_durable_exec/startup_lock.py +155 -0
- code_puppy_core_plugins/dbos_durable_exec/workflow_ids.py +16 -0
- code_puppy_core_plugins/dbos_durable_exec/wrapper.py +58 -0
- code_puppy_core_plugins/destructive_command_guard/AGENTS.md +79 -0
- code_puppy_core_plugins/destructive_command_guard/__init__.py +14 -0
- code_puppy_core_plugins/destructive_command_guard/detector.py +374 -0
- code_puppy_core_plugins/destructive_command_guard/register_callbacks.py +165 -0
- code_puppy_core_plugins/emoji_filter/__init__.py +12 -0
- code_puppy_core_plugins/emoji_filter/config.py +26 -0
- code_puppy_core_plugins/emoji_filter/register_callbacks.py +238 -0
- code_puppy_core_plugins/emoji_filter/stripper.py +45 -0
- code_puppy_core_plugins/empty_html_comment_filter/register_callbacks.py +116 -0
- code_puppy_core_plugins/example_custom_command/README.md +328 -0
- code_puppy_core_plugins/example_custom_command/register_callbacks.py +66 -0
- code_puppy_core_plugins/file_permission_handler/__init__.py +4 -0
- code_puppy_core_plugins/file_permission_handler/register_callbacks.py +575 -0
- code_puppy_core_plugins/flux_bootstrap/__init__.py +5 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/README.md +173 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/cheatsheet.md +86 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/pipeline.md +167 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/synopsis.md +392 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/about.md +51 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/address-feedback.md +129 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/ask.md +211 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/aug.md +181 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/auto-pilot.md +71 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/cheatsheet.md +16 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/commit.md +103 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/config.md +108 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/create-pr.md +195 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/exec.md +221 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/new.md +151 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/qa.md +208 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/rebase.md +180 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/review.md +304 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/split.md +120 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/squash-commits.md +179 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/status.md +46 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/tests.md +155 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_about.py +154 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_cheatsheet.py +248 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_status.py +345 -0
- code_puppy_core_plugins/flux_bootstrap/installer.py +256 -0
- code_puppy_core_plugins/flux_bootstrap/register_callbacks.py +71 -0
- code_puppy_core_plugins/force_push_guard/__init__.py +5 -0
- code_puppy_core_plugins/force_push_guard/detector.py +96 -0
- code_puppy_core_plugins/force_push_guard/register_callbacks.py +161 -0
- code_puppy_core_plugins/fork/__init__.py +7 -0
- code_puppy_core_plugins/fork/register_callbacks.py +445 -0
- code_puppy_core_plugins/frontend_emitter/__init__.py +25 -0
- code_puppy_core_plugins/frontend_emitter/emitter.py +249 -0
- code_puppy_core_plugins/frontend_emitter/register_callbacks.py +412 -0
- code_puppy_core_plugins/frontend_emitter/session_context.py +50 -0
- code_puppy_core_plugins/grok_oauth/__init__.py +6 -0
- code_puppy_core_plugins/grok_oauth/config.py +49 -0
- code_puppy_core_plugins/grok_oauth/oauth_flow.py +213 -0
- code_puppy_core_plugins/grok_oauth/register_callbacks.py +132 -0
- code_puppy_core_plugins/grok_oauth/utils.py +195 -0
- code_puppy_core_plugins/herdr/README.md +168 -0
- code_puppy_core_plugins/herdr/__init__.py +9 -0
- code_puppy_core_plugins/herdr/client.py +339 -0
- code_puppy_core_plugins/herdr/register_callbacks.py +140 -0
- code_puppy_core_plugins/herdr/reporter.py +212 -0
- code_puppy_core_plugins/herdr/smoke.py +143 -0
- code_puppy_core_plugins/herdr/sources.py +133 -0
- code_puppy_core_plugins/hook_creator/__init__.py +1 -0
- code_puppy_core_plugins/hook_creator/register_callbacks.py +33 -0
- code_puppy_core_plugins/hook_manager/__init__.py +1 -0
- code_puppy_core_plugins/hook_manager/config.py +290 -0
- code_puppy_core_plugins/hook_manager/hooks_menu.py +571 -0
- code_puppy_core_plugins/hook_manager/register_callbacks.py +227 -0
- code_puppy_core_plugins/meta_oauth/__init__.py +1 -0
- code_puppy_core_plugins/meta_oauth/config.py +55 -0
- code_puppy_core_plugins/meta_oauth/oauth_flow.py +109 -0
- code_puppy_core_plugins/meta_oauth/register_callbacks.py +154 -0
- code_puppy_core_plugins/meta_oauth/utils.py +252 -0
- code_puppy_core_plugins/namespace_skill_search/README.md +118 -0
- code_puppy_core_plugins/namespace_skill_search/__init__.py +15 -0
- code_puppy_core_plugins/namespace_skill_search/namespaces.py +125 -0
- code_puppy_core_plugins/namespace_skill_search/register_callbacks.py +99 -0
- code_puppy_core_plugins/namespace_skill_search/search_tool.py +158 -0
- code_puppy_core_plugins/no_tools/__init__.py +0 -0
- code_puppy_core_plugins/no_tools/register_callbacks.py +42 -0
- code_puppy_core_plugins/oauth_pasteback.py +110 -0
- code_puppy_core_plugins/oauth_puppy_html.py +194 -0
- code_puppy_core_plugins/obsidian_agent/README.md +52 -0
- code_puppy_core_plugins/obsidian_agent/__init__.py +8 -0
- code_puppy_core_plugins/obsidian_agent/agent_obsidian.py +147 -0
- code_puppy_core_plugins/obsidian_agent/register_callbacks.py +13 -0
- code_puppy_core_plugins/ollama/__init__.py +1 -0
- code_puppy_core_plugins/ollama/register_callbacks.py +127 -0
- code_puppy_core_plugins/ollama_setup/__init__.py +5 -0
- code_puppy_core_plugins/ollama_setup/completer.py +38 -0
- code_puppy_core_plugins/ollama_setup/register_callbacks.py +419 -0
- code_puppy_core_plugins/plugin_list/__init__.py +0 -0
- code_puppy_core_plugins/plugin_list/plugin_contributions.py +348 -0
- code_puppy_core_plugins/plugin_list/plugin_meta.py +67 -0
- code_puppy_core_plugins/plugin_list/plugin_text_utils.py +173 -0
- code_puppy_core_plugins/plugin_list/plugins_menu.py +455 -0
- code_puppy_core_plugins/plugin_list/plugins_menu_layout.py +194 -0
- code_puppy_core_plugins/plugin_list/plugins_menu_render.py +431 -0
- code_puppy_core_plugins/plugin_list/project_trust_flow.py +162 -0
- code_puppy_core_plugins/plugin_list/register_callbacks.py +281 -0
- code_puppy_core_plugins/pop_command/__init__.py +1 -0
- code_puppy_core_plugins/pop_command/register_callbacks.py +191 -0
- code_puppy_core_plugins/prompt_newline/__init__.py +13 -0
- code_puppy_core_plugins/prompt_newline/config.py +21 -0
- code_puppy_core_plugins/prompt_newline/register_callbacks.py +163 -0
- code_puppy_core_plugins/prune/__init__.py +1 -0
- code_puppy_core_plugins/prune/prune_menu.py +308 -0
- code_puppy_core_plugins/prune/prune_model.py +517 -0
- code_puppy_core_plugins/prune/prune_render.py +354 -0
- code_puppy_core_plugins/prune/register_callbacks.py +388 -0
- code_puppy_core_plugins/puppy_kennel/README.md +203 -0
- code_puppy_core_plugins/puppy_kennel/__init__.py +6 -0
- code_puppy_core_plugins/puppy_kennel/commands.py +206 -0
- code_puppy_core_plugins/puppy_kennel/config.py +36 -0
- code_puppy_core_plugins/puppy_kennel/kennel.py +368 -0
- code_puppy_core_plugins/puppy_kennel/packer.py +152 -0
- code_puppy_core_plugins/puppy_kennel/recorder.py +83 -0
- code_puppy_core_plugins/puppy_kennel/register_callbacks.py +109 -0
- code_puppy_core_plugins/puppy_kennel/retriever.py +28 -0
- code_puppy_core_plugins/puppy_kennel/schema.py +78 -0
- code_puppy_core_plugins/puppy_kennel/state.py +68 -0
- code_puppy_core_plugins/puppy_kennel/tools.py +449 -0
- code_puppy_core_plugins/puppy_kennel/wings.py +110 -0
- code_puppy_core_plugins/puppy_spinner/README.md +93 -0
- code_puppy_core_plugins/puppy_spinner/__init__.py +11 -0
- code_puppy_core_plugins/puppy_spinner/builtin_frames.py +172 -0
- code_puppy_core_plugins/puppy_spinner/commands.py +116 -0
- code_puppy_core_plugins/puppy_spinner/picker.py +379 -0
- code_puppy_core_plugins/puppy_spinner/register_callbacks.py +193 -0
- code_puppy_core_plugins/puppy_spinner/spinners.py +444 -0
- code_puppy_core_plugins/quick_resume/__init__.py +0 -0
- code_puppy_core_plugins/quick_resume/register_callbacks.py +77 -0
- code_puppy_core_plugins/review_pr/__init__.py +1 -0
- code_puppy_core_plugins/review_pr/register_callbacks.py +162 -0
- code_puppy_core_plugins/shell_safety/__init__.py +6 -0
- code_puppy_core_plugins/shell_safety/agent_shell_safety.py +69 -0
- code_puppy_core_plugins/shell_safety/command_cache.py +156 -0
- code_puppy_core_plugins/shell_safety/register_callbacks.py +203 -0
- code_puppy_core_plugins/stack_dump/__init__.py +1 -0
- code_puppy_core_plugins/stack_dump/register_callbacks.py +79 -0
- code_puppy_core_plugins/statusline/__init__.py +14 -0
- code_puppy_core_plugins/statusline/config.py +68 -0
- code_puppy_core_plugins/statusline/payload.py +138 -0
- code_puppy_core_plugins/statusline/prompt_patch.py +76 -0
- code_puppy_core_plugins/statusline/register_callbacks.py +45 -0
- code_puppy_core_plugins/statusline/runner.py +122 -0
- code_puppy_core_plugins/statusline/statusline_command.py +197 -0
- code_puppy_core_plugins/steer_queue/__init__.py +10 -0
- code_puppy_core_plugins/steer_queue/queue_menu.py +444 -0
- code_puppy_core_plugins/steer_queue/register_callbacks.py +138 -0
- code_puppy_core_plugins/subagent_panel/README.md +102 -0
- code_puppy_core_plugins/subagent_panel/__init__.py +24 -0
- code_puppy_core_plugins/subagent_panel/coalesce_patch.py +242 -0
- code_puppy_core_plugins/subagent_panel/panel_render.py +145 -0
- code_puppy_core_plugins/subagent_panel/register_callbacks.py +535 -0
- code_puppy_core_plugins/subagent_panel/resume_repaint.py +112 -0
- code_puppy_core_plugins/subagent_panel/state.py +231 -0
- code_puppy_core_plugins/switch_agent_resume/__init__.py +5 -0
- code_puppy_core_plugins/switch_agent_resume/register_callbacks.py +314 -0
- code_puppy_core_plugins/theme/README.md +86 -0
- code_puppy_core_plugins/theme/__init__.py +14 -0
- code_puppy_core_plugins/theme/bundled_palettes.py +346 -0
- code_puppy_core_plugins/theme/content_styles.py +146 -0
- code_puppy_core_plugins/theme/osc_palette.py +178 -0
- code_puppy_core_plugins/theme/picker.py +358 -0
- code_puppy_core_plugins/theme/prompt_toolkit_theme.py +113 -0
- code_puppy_core_plugins/theme/register_callbacks.py +348 -0
- code_puppy_core_plugins/theme/rich_themes.py +202 -0
- code_puppy_core_plugins/theme/themes.py +720 -0
- code_puppy_core_plugins/timestamp_heartbeat/__init__.py +1 -0
- code_puppy_core_plugins/timestamp_heartbeat/register_callbacks.py +114 -0
- code_puppy_core_plugins/token_ratio_learner/__init__.py +5 -0
- code_puppy_core_plugins/token_ratio_learner/ratios.py +208 -0
- code_puppy_core_plugins/token_ratio_learner/register_callbacks.py +213 -0
- code_puppy_core_plugins/universal_constructor/__init__.py +13 -0
- code_puppy_core_plugins/universal_constructor/models.py +138 -0
- code_puppy_core_plugins/universal_constructor/provider.py +62 -0
- code_puppy_core_plugins/universal_constructor/register_callbacks.py +75 -0
- code_puppy_core_plugins/universal_constructor/registry.py +302 -0
- code_puppy_core_plugins/universal_constructor/sandbox.py +584 -0
- code_puppy_core_plugins/wide_completion_menu/__init__.py +6 -0
- code_puppy_core_plugins/wide_completion_menu/register_callbacks.py +165 -0
- code_puppy_core_plugins/wiggum/__init__.py +1 -0
- code_puppy_core_plugins/wiggum/goal_runs.py +91 -0
- code_puppy_core_plugins/wiggum/judge.py +299 -0
- code_puppy_core_plugins/wiggum/judge_config.py +249 -0
- code_puppy_core_plugins/wiggum/judges_menu.py +814 -0
- code_puppy_core_plugins/wiggum/register_callbacks.py +569 -0
- code_puppy_core_plugins/wiggum/state.py +89 -0
- code_puppy_core_plugins/yolo_cli/__init__.py +1 -0
- code_puppy_core_plugins/yolo_cli/register_callbacks.py +41 -0
- code_puppy_core_plugins-0.0.2.dist-info/METADATA +64 -0
- code_puppy_core_plugins-0.0.2.dist-info/RECORD +313 -0
- code_puppy_core_plugins-0.0.2.dist-info/WHEEL +4 -0
- code_puppy_core_plugins-0.0.2.dist-info/entry_points.txt +55 -0
- code_puppy_core_plugins-0.0.2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"""Skill discovery - scans directories for valid skills."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import shutil
|
|
5
|
+
import threading
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Iterable, List, Optional
|
|
9
|
+
|
|
10
|
+
from code_puppy.callbacks import get_callbacks, on_register_skills
|
|
11
|
+
from code_puppy.config import CACHE_DIR
|
|
12
|
+
from code_puppy_core_plugins.agent_skills.config import get_skill_directories
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
_PLUGIN_SKILLS_CACHE_DIR = Path(CACHE_DIR) / "plugin-skills"
|
|
17
|
+
|
|
18
|
+
# Serialises the wipe-and-rebuild of the shared plugin-skills cache dir: called from
|
|
19
|
+
# both the main loop and worker threads (anyio to_thread), so without the lock two
|
|
20
|
+
# threads race -- one rmtree's it while the other mkdir's/writes (macOS: OSError 22).
|
|
21
|
+
_PLUGIN_SKILLS_LOCK = threading.Lock()
|
|
22
|
+
|
|
23
|
+
# Memoised last successful build, keyed by a signature of the (process-deterministic)
|
|
24
|
+
# registrations, so the cache dir is rebuilt only when they change. Also stops a rebuild
|
|
25
|
+
# from tearing the dir out from under lock-free readers of returned SkillInfo.path.
|
|
26
|
+
_plugin_skills_cache: Optional[List["SkillInfo"]] = None
|
|
27
|
+
_plugin_skills_signature: Optional[tuple] = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class SkillInfo:
|
|
32
|
+
"""Basic skill information from discovery."""
|
|
33
|
+
|
|
34
|
+
name: str
|
|
35
|
+
path: Path
|
|
36
|
+
has_skill_md: bool
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Global cache for discovered skills
|
|
40
|
+
_skill_cache: Optional[List[SkillInfo]] = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_default_skill_directories() -> List[Path]:
|
|
44
|
+
"""Return default directories to scan for skills.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
- ~/.code_puppy/skills (user skills)
|
|
48
|
+
- ./.code_puppy/skills (project config skills)
|
|
49
|
+
- ./skills (project skills)
|
|
50
|
+
"""
|
|
51
|
+
return [
|
|
52
|
+
Path.home() / ".code_puppy" / "skills",
|
|
53
|
+
Path.cwd() / ".code_puppy" / "skills",
|
|
54
|
+
Path.cwd() / "skills",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def is_valid_skill_directory(path: Path) -> bool:
|
|
59
|
+
"""Check if a directory contains a valid SKILL.md file."""
|
|
60
|
+
if not path.is_dir():
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
skill_md_path = path / "SKILL.md"
|
|
64
|
+
return skill_md_path.is_file()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _sanitize_path_part(value: str) -> str:
|
|
68
|
+
cleaned = (value or "").strip().replace("/", "-").replace("\\", "-")
|
|
69
|
+
return cleaned or "unnamed"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _render_skill_markdown(entry: dict[str, Any]) -> str:
|
|
73
|
+
if "skill_md" in entry:
|
|
74
|
+
return str(entry["skill_md"])
|
|
75
|
+
|
|
76
|
+
if "skill_md_path" in entry:
|
|
77
|
+
return Path(entry["skill_md_path"]).read_text(encoding="utf-8")
|
|
78
|
+
|
|
79
|
+
if "frontmatter" in entry and "body" in entry:
|
|
80
|
+
frontmatter = dict(entry["frontmatter"] or {})
|
|
81
|
+
frontmatter.setdefault("name", entry["name"])
|
|
82
|
+
if entry.get("description") and "description" not in frontmatter:
|
|
83
|
+
frontmatter["description"] = entry["description"]
|
|
84
|
+
if entry.get("version") and "version" not in frontmatter:
|
|
85
|
+
frontmatter["version"] = entry["version"]
|
|
86
|
+
if entry.get("author") and "author" not in frontmatter:
|
|
87
|
+
frontmatter["author"] = entry["author"]
|
|
88
|
+
if entry.get("tags") and "tags" not in frontmatter:
|
|
89
|
+
frontmatter["tags"] = entry["tags"]
|
|
90
|
+
|
|
91
|
+
lines = ["---"]
|
|
92
|
+
for key, value in frontmatter.items():
|
|
93
|
+
if isinstance(value, list):
|
|
94
|
+
lines.append(f"{key}:")
|
|
95
|
+
for item in value:
|
|
96
|
+
lines.append(f" - {item}")
|
|
97
|
+
else:
|
|
98
|
+
lines.append(f"{key}: {value}")
|
|
99
|
+
lines.extend(["---", str(entry["body"])])
|
|
100
|
+
return "\n".join(lines).rstrip() + "\n"
|
|
101
|
+
|
|
102
|
+
raise ValueError(
|
|
103
|
+
"Skill entry must define either skill_md_path, skill_md, or frontmatter+body"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _copy_scripts_dir(source_dir: Path, target_dir: Path) -> None:
|
|
108
|
+
scripts_target = target_dir / "scripts"
|
|
109
|
+
if scripts_target.exists() or scripts_target.is_symlink():
|
|
110
|
+
if scripts_target.is_dir() and not scripts_target.is_symlink():
|
|
111
|
+
shutil.rmtree(scripts_target)
|
|
112
|
+
else:
|
|
113
|
+
scripts_target.unlink()
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
scripts_target.symlink_to(source_dir, target_is_directory=True)
|
|
117
|
+
except OSError:
|
|
118
|
+
shutil.copytree(source_dir, scripts_target)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _materialize_plugin_skill(
|
|
122
|
+
callback_module: str, callback_name: str, entry: dict[str, Any]
|
|
123
|
+
) -> SkillInfo | None:
|
|
124
|
+
skill_name = str(entry.get("name") or "").strip()
|
|
125
|
+
if not skill_name:
|
|
126
|
+
logger.warning(
|
|
127
|
+
"Plugin skill registration from %s.%s missing required 'name'",
|
|
128
|
+
callback_module,
|
|
129
|
+
callback_name,
|
|
130
|
+
)
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
skill_md = _render_skill_markdown(entry)
|
|
135
|
+
except Exception as exc:
|
|
136
|
+
logger.warning(
|
|
137
|
+
"Failed to render plugin skill %s from %s.%s: %s",
|
|
138
|
+
skill_name,
|
|
139
|
+
callback_module,
|
|
140
|
+
callback_name,
|
|
141
|
+
exc,
|
|
142
|
+
)
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
owner_dir = _PLUGIN_SKILLS_CACHE_DIR / _sanitize_path_part(callback_module)
|
|
146
|
+
skill_dir = owner_dir / _sanitize_path_part(skill_name)
|
|
147
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
148
|
+
(skill_dir / "SKILL.md").write_text(skill_md, encoding="utf-8")
|
|
149
|
+
|
|
150
|
+
scripts_dir = entry.get("scripts_dir")
|
|
151
|
+
if scripts_dir:
|
|
152
|
+
source_dir = Path(scripts_dir).expanduser().resolve()
|
|
153
|
+
if source_dir.is_dir():
|
|
154
|
+
_copy_scripts_dir(source_dir, skill_dir)
|
|
155
|
+
else:
|
|
156
|
+
logger.warning(
|
|
157
|
+
"Plugin skill %s from %s.%s provided invalid scripts_dir: %s",
|
|
158
|
+
skill_name,
|
|
159
|
+
callback_module,
|
|
160
|
+
callback_name,
|
|
161
|
+
source_dir,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return SkillInfo(name=skill_name, path=skill_dir, has_skill_md=True)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _iter_plugin_skill_registrations() -> Iterable[tuple[str, str, dict[str, Any]]]:
|
|
168
|
+
callbacks = get_callbacks("register_skills")
|
|
169
|
+
results = on_register_skills()
|
|
170
|
+
|
|
171
|
+
for callback, result in zip(callbacks, results):
|
|
172
|
+
if not result:
|
|
173
|
+
continue
|
|
174
|
+
if not isinstance(result, list):
|
|
175
|
+
logger.warning(
|
|
176
|
+
"register_skills callback %s.%s must return a list, got %s",
|
|
177
|
+
callback.__module__,
|
|
178
|
+
callback.__name__,
|
|
179
|
+
type(result).__name__,
|
|
180
|
+
)
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
for entry in result:
|
|
184
|
+
if not isinstance(entry, dict):
|
|
185
|
+
logger.warning(
|
|
186
|
+
"register_skills callback %s.%s returned non-dict entry: %r",
|
|
187
|
+
callback.__module__,
|
|
188
|
+
callback.__name__,
|
|
189
|
+
entry,
|
|
190
|
+
)
|
|
191
|
+
continue
|
|
192
|
+
# Provider registrations are consumed by core through the same
|
|
193
|
+
# hook; they are capabilities, not skills to materialize.
|
|
194
|
+
if "provider" in entry:
|
|
195
|
+
continue
|
|
196
|
+
yield callback.__module__, callback.__name__, entry
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _plugin_registration_signature(
|
|
200
|
+
registrations: List[tuple[str, str, dict[str, Any]]],
|
|
201
|
+
) -> tuple:
|
|
202
|
+
"""Deterministic signature of the plugin skill registrations.
|
|
203
|
+
|
|
204
|
+
Used to decide whether the on-disk cache still reflects the registered
|
|
205
|
+
skills. Sorting each entry's items by key keeps the signature stable
|
|
206
|
+
regardless of dict ordering.
|
|
207
|
+
"""
|
|
208
|
+
return tuple(
|
|
209
|
+
(module, name, repr(sorted(entry.items(), key=lambda kv: kv[0])))
|
|
210
|
+
for module, name, entry in registrations
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _collect_plugin_skills() -> List[SkillInfo]:
|
|
215
|
+
global _plugin_skills_cache, _plugin_skills_signature
|
|
216
|
+
|
|
217
|
+
with _PLUGIN_SKILLS_LOCK:
|
|
218
|
+
registrations = list(_iter_plugin_skill_registrations())
|
|
219
|
+
signature = _plugin_registration_signature(registrations)
|
|
220
|
+
|
|
221
|
+
# Reuse the materialised cache when registrations are unchanged and files are
|
|
222
|
+
# still on disk. Skipping the wipe prevents a concurrent rebuild from deleting
|
|
223
|
+
# a SKILL.md while a lock-free reader is consuming an earlier returned path.
|
|
224
|
+
if (
|
|
225
|
+
_plugin_skills_cache is not None
|
|
226
|
+
and signature == _plugin_skills_signature
|
|
227
|
+
and _PLUGIN_SKILLS_CACHE_DIR.exists()
|
|
228
|
+
):
|
|
229
|
+
return list(_plugin_skills_cache)
|
|
230
|
+
|
|
231
|
+
if _PLUGIN_SKILLS_CACHE_DIR.exists():
|
|
232
|
+
shutil.rmtree(_PLUGIN_SKILLS_CACHE_DIR, ignore_errors=True)
|
|
233
|
+
_PLUGIN_SKILLS_CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
234
|
+
|
|
235
|
+
plugin_skills: List[SkillInfo] = []
|
|
236
|
+
seen_names: set[str] = set()
|
|
237
|
+
|
|
238
|
+
for callback_module, callback_name, entry in registrations:
|
|
239
|
+
skill = _materialize_plugin_skill(callback_module, callback_name, entry)
|
|
240
|
+
if skill is None:
|
|
241
|
+
continue
|
|
242
|
+
if skill.name in seen_names:
|
|
243
|
+
logger.warning(
|
|
244
|
+
"Skipping duplicate plugin skill registration for '%s' from %s.%s",
|
|
245
|
+
skill.name,
|
|
246
|
+
callback_module,
|
|
247
|
+
callback_name,
|
|
248
|
+
)
|
|
249
|
+
continue
|
|
250
|
+
seen_names.add(skill.name)
|
|
251
|
+
plugin_skills.append(skill)
|
|
252
|
+
|
|
253
|
+
_plugin_skills_cache = plugin_skills
|
|
254
|
+
_plugin_skills_signature = signature
|
|
255
|
+
return list(plugin_skills)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def discover_skills(directories: Optional[List[Path]] = None) -> List[SkillInfo]:
|
|
259
|
+
"""Scan directories for valid skills."""
|
|
260
|
+
global _skill_cache
|
|
261
|
+
|
|
262
|
+
if directories is None:
|
|
263
|
+
configured = [Path(d) for d in get_skill_directories()]
|
|
264
|
+
defaults = get_default_skill_directories()
|
|
265
|
+
seen = {p.resolve() for p in configured}
|
|
266
|
+
directories = list(configured)
|
|
267
|
+
for d in defaults:
|
|
268
|
+
if d.resolve() not in seen:
|
|
269
|
+
directories.append(d)
|
|
270
|
+
|
|
271
|
+
discovered_skills: List[SkillInfo] = []
|
|
272
|
+
seen_skill_names: set[str] = set()
|
|
273
|
+
|
|
274
|
+
for directory in directories:
|
|
275
|
+
if not directory.exists():
|
|
276
|
+
logger.debug(f"Skill directory does not exist: {directory}")
|
|
277
|
+
continue
|
|
278
|
+
|
|
279
|
+
if not directory.is_dir():
|
|
280
|
+
logger.warning(f"Skill path is not a directory: {directory}")
|
|
281
|
+
continue
|
|
282
|
+
|
|
283
|
+
for skill_dir in directory.iterdir():
|
|
284
|
+
if not skill_dir.is_dir() or skill_dir.name.startswith("."):
|
|
285
|
+
continue
|
|
286
|
+
|
|
287
|
+
# First-discovered skill wins - skip duplicates from later directories
|
|
288
|
+
if skill_dir.name in seen_skill_names:
|
|
289
|
+
logger.debug(
|
|
290
|
+
"Skipping duplicate skill '%s' at %s (already discovered)",
|
|
291
|
+
skill_dir.name,
|
|
292
|
+
skill_dir,
|
|
293
|
+
)
|
|
294
|
+
continue
|
|
295
|
+
|
|
296
|
+
has_skill_md = is_valid_skill_directory(skill_dir)
|
|
297
|
+
skill_info = SkillInfo(
|
|
298
|
+
name=skill_dir.name,
|
|
299
|
+
path=skill_dir,
|
|
300
|
+
has_skill_md=has_skill_md,
|
|
301
|
+
)
|
|
302
|
+
discovered_skills.append(skill_info)
|
|
303
|
+
seen_skill_names.add(skill_info.name)
|
|
304
|
+
|
|
305
|
+
if has_skill_md:
|
|
306
|
+
logger.debug(
|
|
307
|
+
"Discovered valid skill: %s at %s", skill_dir.name, skill_dir
|
|
308
|
+
)
|
|
309
|
+
else:
|
|
310
|
+
logger.debug(
|
|
311
|
+
"Found skill directory without SKILL.md: %s", skill_dir.name
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
for plugin_skill in _collect_plugin_skills():
|
|
315
|
+
if plugin_skill.name in seen_skill_names:
|
|
316
|
+
logger.debug(
|
|
317
|
+
"Skipping plugin skill '%s' because a filesystem skill already exists",
|
|
318
|
+
plugin_skill.name,
|
|
319
|
+
)
|
|
320
|
+
continue
|
|
321
|
+
discovered_skills.append(plugin_skill)
|
|
322
|
+
seen_skill_names.add(plugin_skill.name)
|
|
323
|
+
|
|
324
|
+
_skill_cache = discovered_skills
|
|
325
|
+
logger.info(
|
|
326
|
+
"Discovered %s skills from %s directories",
|
|
327
|
+
len(discovered_skills),
|
|
328
|
+
len(directories),
|
|
329
|
+
)
|
|
330
|
+
return discovered_skills
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def refresh_skill_cache() -> List[SkillInfo]:
|
|
334
|
+
"""Force re-discovery of all skills."""
|
|
335
|
+
global _skill_cache
|
|
336
|
+
_skill_cache = None
|
|
337
|
+
return discover_skills()
|