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,152 @@
|
|
|
1
|
+
"""Tiered budget-aware packing for the system-prompt recall block.
|
|
2
|
+
|
|
3
|
+
Three priority classes, fed from the kennel, sized to fit a configurable
|
|
4
|
+
token budget without ever calling an LLM or shipping a tokenizer:
|
|
5
|
+
|
|
6
|
+
* **P0 - user preferences**: every drawer in ``user:default``. Short,
|
|
7
|
+
durable, pervasive ("Mike hates emojis"). Capped at ~30% of budget.
|
|
8
|
+
* **P1 - sticky repo notes**: drawers in ``repo:<cwd>`` with ``role='note'``,
|
|
9
|
+
i.e. content written via the ``kennel_remember`` tool. Highest signal-to-
|
|
10
|
+
token ratio in the kennel. Capped at ~30% of budget.
|
|
11
|
+
* **P2 - recent assistant responses**: drawers in ``repo:<cwd>`` with
|
|
12
|
+
``role='assistant'``. Fills whatever budget remains after P0 + P1.
|
|
13
|
+
|
|
14
|
+
Token budget is enforced via the well-known 1-token approximate-4-chars
|
|
15
|
+
heuristic. Cheap, zero-dep, accurate to plus-or-minus 20% which is fine
|
|
16
|
+
for "do not blow the context."
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
|
|
23
|
+
from . import kennel
|
|
24
|
+
from .config import (
|
|
25
|
+
CHARS_PER_TOKEN,
|
|
26
|
+
MIN_DRAWER_CHARS,
|
|
27
|
+
PROMPT_BUDGET_CHARS,
|
|
28
|
+
PROMPT_BUDGET_TOKENS,
|
|
29
|
+
STICKY_QUOTA,
|
|
30
|
+
USER_PREFS_QUOTA,
|
|
31
|
+
)
|
|
32
|
+
from .kennel import Drawer
|
|
33
|
+
from .wings import USER_WING, detect_cwd, repo_wing
|
|
34
|
+
|
|
35
|
+
# Reserve ~50 tokens for rendered headers and section dividers.
|
|
36
|
+
_HEADER_SLACK_CHARS = 50 * CHARS_PER_TOKEN
|
|
37
|
+
|
|
38
|
+
# We over-fetch from SQLite then truncate to fit. Cheap, simple.
|
|
39
|
+
_FETCH_LIMIT = 50
|
|
40
|
+
|
|
41
|
+
# Below this remainder, a new drawer would be mostly "...truncated]".
|
|
42
|
+
_MIN_REMAINING_CHARS = 120
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(slots=True)
|
|
46
|
+
class PackSection:
|
|
47
|
+
title: str
|
|
48
|
+
lines: list[str]
|
|
49
|
+
used_chars: int
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _agent_label(d: Drawer) -> str:
|
|
53
|
+
meta = d.metadata or {}
|
|
54
|
+
return str(meta.get("agent") or d.role or "?")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _format_drawer(d: Drawer, max_chars: int) -> str:
|
|
58
|
+
"""Render one drawer to a markdown bullet, fitting within ``max_chars``.
|
|
59
|
+
|
|
60
|
+
The bullet looks like ``- [ts] _agent_ : content...`` with the content
|
|
61
|
+
truncated as needed. Returns an empty string if the bullet skeleton
|
|
62
|
+
alone wouldn't fit.
|
|
63
|
+
"""
|
|
64
|
+
head = f"- [{d.ts}] _{_agent_label(d)}_ : "
|
|
65
|
+
if max_chars <= len(head) + 20:
|
|
66
|
+
return ""
|
|
67
|
+
body_budget = max_chars - len(head)
|
|
68
|
+
body = d.content.strip().replace("\n", " ")
|
|
69
|
+
if len(body) > body_budget:
|
|
70
|
+
body = body[: body_budget - 1].rstrip() + "..."
|
|
71
|
+
return head + body
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _pack_class(
|
|
75
|
+
drawers: list[Drawer],
|
|
76
|
+
budget_chars: int,
|
|
77
|
+
min_chars: int = MIN_DRAWER_CHARS,
|
|
78
|
+
) -> PackSection:
|
|
79
|
+
"""Greedily pack drawers into ``budget_chars``, newest first.
|
|
80
|
+
|
|
81
|
+
Skips drawers smaller than ``min_chars`` (probably noise). Truncates
|
|
82
|
+
the last drawer if it would otherwise push us over. Stops once the
|
|
83
|
+
remaining budget gets too small to be useful.
|
|
84
|
+
"""
|
|
85
|
+
lines: list[str] = []
|
|
86
|
+
used = 0
|
|
87
|
+
for d in drawers:
|
|
88
|
+
if len(d.content.strip()) < min_chars:
|
|
89
|
+
continue
|
|
90
|
+
remaining = budget_chars - used
|
|
91
|
+
if remaining < _MIN_REMAINING_CHARS:
|
|
92
|
+
break
|
|
93
|
+
rendered = _format_drawer(d, max_chars=remaining)
|
|
94
|
+
if not rendered:
|
|
95
|
+
break
|
|
96
|
+
lines.append(rendered)
|
|
97
|
+
used += len(rendered) + 1 # +1 for the newline that joins them
|
|
98
|
+
return PackSection(title="", lines=lines, used_chars=used)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def pack(cwd_override: str | None = None) -> str | None:
|
|
102
|
+
"""Build the system-prompt recall block under the configured budget.
|
|
103
|
+
|
|
104
|
+
Returns ``None`` when there is nothing useful to surface (empty kennel,
|
|
105
|
+
every drawer too short, etc.) - the ``load_prompt`` callback contract
|
|
106
|
+
interprets ``None`` as "skip me".
|
|
107
|
+
"""
|
|
108
|
+
cwd = cwd_override if cwd_override is not None else detect_cwd()
|
|
109
|
+
repo_w = repo_wing(cwd)
|
|
110
|
+
|
|
111
|
+
total_budget = max(0, PROMPT_BUDGET_CHARS - _HEADER_SLACK_CHARS)
|
|
112
|
+
p0_budget = int(total_budget * USER_PREFS_QUOTA)
|
|
113
|
+
p1_budget = int(total_budget * STICKY_QUOTA)
|
|
114
|
+
|
|
115
|
+
# P0: user preferences; include every role because user notes may be assistant-authored.
|
|
116
|
+
user_drawers = kennel.recent_drawers(USER_WING, limit=_FETCH_LIMIT)
|
|
117
|
+
p0 = _pack_class(user_drawers, p0_budget)
|
|
118
|
+
p0.title = "User Preferences"
|
|
119
|
+
|
|
120
|
+
# P1: repo sticky notes (role='note' only).
|
|
121
|
+
sticky = kennel.recent_drawers(repo_w, limit=_FETCH_LIMIT, role="note")
|
|
122
|
+
p1 = _pack_class(sticky, p1_budget)
|
|
123
|
+
p1.title = "Project Decisions"
|
|
124
|
+
|
|
125
|
+
# P2: recent assistant responses fill the remainder.
|
|
126
|
+
p2_budget = total_budget - p0.used_chars - p1.used_chars
|
|
127
|
+
assistant = kennel.recent_drawers(repo_w, limit=_FETCH_LIMIT, role="assistant")
|
|
128
|
+
p2 = _pack_class(assistant, max(0, p2_budget))
|
|
129
|
+
p2.title = "Recent Context"
|
|
130
|
+
|
|
131
|
+
sections = [s for s in (p0, p1, p2) if s.lines]
|
|
132
|
+
if not sections:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
return _render(sections, repo_w)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _render(sections: list[PackSection], repo_w: str) -> str:
|
|
139
|
+
"""Render the packed sections into the final markdown block."""
|
|
140
|
+
out: list[str] = [
|
|
141
|
+
"## Puppy Kennel - Memory",
|
|
142
|
+
(
|
|
143
|
+
f"_Repo wing: `{repo_w}` | token budget: "
|
|
144
|
+
f"{PROMPT_BUDGET_TOKENS} (~{PROMPT_BUDGET_CHARS} chars)_"
|
|
145
|
+
),
|
|
146
|
+
"",
|
|
147
|
+
]
|
|
148
|
+
for s in sections:
|
|
149
|
+
out.append(f"### {s.title}")
|
|
150
|
+
out.extend(s.lines)
|
|
151
|
+
out.append("")
|
|
152
|
+
return "\n".join(out)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Recorder — captures agent runs into the kennel.
|
|
2
|
+
|
|
3
|
+
Fires on ``agent_run_end``. The recorder writes the agent's response to
|
|
4
|
+
**one** wing: the current repo wing. The autosave path treats every
|
|
5
|
+
response as "a conversation that happened in this project" — that's the
|
|
6
|
+
honest framing.
|
|
7
|
+
|
|
8
|
+
Cross-project agent reflections belong in ``agent:<name>`` and are an
|
|
9
|
+
opt-in concern handled by the ``kennel_remember`` tool, not autosave.
|
|
10
|
+
User preferences likewise live in ``user:default`` and only land there
|
|
11
|
+
via explicit ``kennel_remember`` calls.
|
|
12
|
+
|
|
13
|
+
Capturing user input is a phase-2 concern that will hook ``stream_event``
|
|
14
|
+
instead.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from code_puppy.messaging.bus import emit_debug
|
|
22
|
+
|
|
23
|
+
from . import kennel
|
|
24
|
+
from .state import is_enabled
|
|
25
|
+
from .wings import detect_cwd, repo_wing
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _room_name(session_id: str | None) -> str:
|
|
29
|
+
"""Rooms partition a wing by session. Keep the name human-scannable."""
|
|
30
|
+
if not session_id:
|
|
31
|
+
return "session-unknown"
|
|
32
|
+
short = session_id.split("-")[0][:12] if "-" in session_id else session_id[:12]
|
|
33
|
+
return f"session-{short}"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def record_run_end(
|
|
37
|
+
agent_name: str,
|
|
38
|
+
model_name: str,
|
|
39
|
+
session_id: str | None = None,
|
|
40
|
+
success: bool = True,
|
|
41
|
+
error: Exception | None = None,
|
|
42
|
+
response_text: str | None = None,
|
|
43
|
+
metadata: dict | None = None,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Persist the agent's final response into the kennel.
|
|
46
|
+
|
|
47
|
+
Writes a single drawer to the repo wing (shared project memory).
|
|
48
|
+
Failures here must never crash the host app — the kennel is best-
|
|
49
|
+
effort memory, not a transactional system of record.
|
|
50
|
+
"""
|
|
51
|
+
if not response_text or not response_text.strip():
|
|
52
|
+
return
|
|
53
|
+
if not success:
|
|
54
|
+
# Don't memorialize broken runs. The error log is the right place.
|
|
55
|
+
return
|
|
56
|
+
if not is_enabled():
|
|
57
|
+
# Memory is toggled off — silently skip. Slash commands surface state.
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
cwd = detect_cwd()
|
|
62
|
+
room = _room_name(session_id)
|
|
63
|
+
drawer_meta: dict[str, Any] = {
|
|
64
|
+
"agent": agent_name,
|
|
65
|
+
"model": model_name,
|
|
66
|
+
"cwd": str(cwd),
|
|
67
|
+
}
|
|
68
|
+
if metadata:
|
|
69
|
+
drawer_meta["run_metadata"] = metadata
|
|
70
|
+
|
|
71
|
+
# Shared project memory — the only autosave destination.
|
|
72
|
+
repo_w = repo_wing(cwd)
|
|
73
|
+
repo_wing_id = kennel.ensure_wing(repo_w)
|
|
74
|
+
repo_room_id = kennel.ensure_room(repo_wing_id, room)
|
|
75
|
+
kennel.add_drawer(
|
|
76
|
+
repo_room_id,
|
|
77
|
+
content=response_text,
|
|
78
|
+
role="assistant",
|
|
79
|
+
session_id=session_id,
|
|
80
|
+
metadata=drawer_meta,
|
|
81
|
+
)
|
|
82
|
+
except Exception as exc: # noqa: BLE001 — best-effort memory.
|
|
83
|
+
emit_debug(f"[puppy_kennel] recorder skipped: {exc!r}")
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Register puppy_kennel with Code Puppy's callback system.
|
|
2
|
+
|
|
3
|
+
Hooks wired:
|
|
4
|
+
* ``load_prompt`` -> passive recall block in the system prompt
|
|
5
|
+
* ``agent_run_end`` -> record the agent's response as a verbatim drawer
|
|
6
|
+
* ``register_tools`` -> defines kennel tools in ``TOOL_REGISTRY``
|
|
7
|
+
* ``register_agent_tools``-> advertises kennel tools to every agent's tool list
|
|
8
|
+
* ``custom_command`` -> handles ``/kennel`` and subcommands
|
|
9
|
+
* ``custom_command_help`` -> advertises ``/kennel`` in the /help menu
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from code_puppy.callbacks import register_callback
|
|
15
|
+
from code_puppy.messaging.bus import emit_debug
|
|
16
|
+
|
|
17
|
+
from . import commands, kennel, tools
|
|
18
|
+
from .recorder import record_run_end
|
|
19
|
+
from .retriever import build_recall_block
|
|
20
|
+
from .state import is_enabled
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _initialize_once() -> bool:
|
|
24
|
+
"""Create the SQLite schema on first import. Idempotent + fail-soft."""
|
|
25
|
+
try:
|
|
26
|
+
kennel.initialize()
|
|
27
|
+
return True
|
|
28
|
+
except Exception as exc: # noqa: BLE001 — plugin must never crash boot.
|
|
29
|
+
emit_debug(f"[puppy_kennel] init failed, disabling: {exc!r}")
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _on_load_prompt() -> str | None:
|
|
34
|
+
"""Sync hook — returns a text fragment or None."""
|
|
35
|
+
try:
|
|
36
|
+
return build_recall_block()
|
|
37
|
+
except Exception as exc: # noqa: BLE001
|
|
38
|
+
emit_debug(f"[puppy_kennel] load_prompt skipped: {exc!r}")
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _on_agent_run_end(
|
|
43
|
+
agent_name: str,
|
|
44
|
+
model_name: str,
|
|
45
|
+
session_id: str | None = None,
|
|
46
|
+
success: bool = True,
|
|
47
|
+
error: Exception | None = None,
|
|
48
|
+
response_text: str | None = None,
|
|
49
|
+
metadata: dict | None = None,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Async-compatible hook (sync body, runner accepts either)."""
|
|
52
|
+
record_run_end(
|
|
53
|
+
agent_name=agent_name,
|
|
54
|
+
model_name=model_name,
|
|
55
|
+
session_id=session_id,
|
|
56
|
+
success=success,
|
|
57
|
+
error=error,
|
|
58
|
+
response_text=response_text,
|
|
59
|
+
metadata=metadata,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
_KENNEL_TOOL_NAMES = (
|
|
64
|
+
"kennel_recall",
|
|
65
|
+
"kennel_remember",
|
|
66
|
+
"kennel_recent",
|
|
67
|
+
"kennel_list_wings",
|
|
68
|
+
"kennel_stats",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _register_kennel_memory():
|
|
73
|
+
"""Expose the recall block through the neutral provider seam.
|
|
74
|
+
|
|
75
|
+
Returned to core via the ``register_kennel_memory`` callback phase; core
|
|
76
|
+
consumes it through ``code_puppy.kennel_provider``. Disabling the kennel
|
|
77
|
+
makes ``build_recall_block`` return ``None``, so providers are resolved
|
|
78
|
+
per call and the stale-registration problem never appears.
|
|
79
|
+
"""
|
|
80
|
+
if not is_enabled():
|
|
81
|
+
return None
|
|
82
|
+
return build_recall_block
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _advertise_tools_to_agent(agent_name: str | None = None) -> list[str]:
|
|
86
|
+
"""``register_agent_tools`` callback — advertise kennel tools to every agent.
|
|
87
|
+
|
|
88
|
+
Agnostic to ``agent_name`` for now: memory is universally useful, no
|
|
89
|
+
agent currently has a reason to opt out. If that changes, branch here.
|
|
90
|
+
|
|
91
|
+
When the kennel is toggled off via ``/kennel disable``, we advertise
|
|
92
|
+
NO tools — the agent shouldn't see (and definitely shouldn't try to
|
|
93
|
+
call) memory tools that will just bounce with ``DISABLED_TOOL_ERROR``.
|
|
94
|
+
The slash command pairs this with an agent reload so the tool list
|
|
95
|
+
actually shrinks/grows live.
|
|
96
|
+
"""
|
|
97
|
+
if not is_enabled():
|
|
98
|
+
return []
|
|
99
|
+
return list(_KENNEL_TOOL_NAMES)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if _initialize_once():
|
|
103
|
+
register_callback("load_prompt", _on_load_prompt)
|
|
104
|
+
register_callback("agent_run_end", _on_agent_run_end)
|
|
105
|
+
register_callback("register_tools", tools.register_tools_callback)
|
|
106
|
+
register_callback("register_agent_tools", _advertise_tools_to_agent)
|
|
107
|
+
register_callback("register_kennel_memory", _register_kennel_memory)
|
|
108
|
+
register_callback("custom_command", commands.handle)
|
|
109
|
+
register_callback("custom_command_help", commands.help_entries)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Retriever - surfaces kennel context into the system prompt.
|
|
2
|
+
|
|
3
|
+
Fires on ``load_prompt``. The actual packing logic lives in ``packer.py``;
|
|
4
|
+
this module is a thin wrapper that enforces the enable/disable toggle and
|
|
5
|
+
swallows any storage-layer hiccups so the host app never breaks.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from . import packer
|
|
11
|
+
from .state import is_enabled
|
|
12
|
+
|
|
13
|
+
_EMPTY_RETURN = None # Returning None tells the callback system "skip me."
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def build_recall_block() -> str | None:
|
|
17
|
+
"""Return a system-prompt fragment built by the tiered packer.
|
|
18
|
+
|
|
19
|
+
Returns ``None`` when the kennel is disabled, empty, or otherwise has
|
|
20
|
+
nothing worth surfacing this turn.
|
|
21
|
+
"""
|
|
22
|
+
if not is_enabled():
|
|
23
|
+
return _EMPTY_RETURN
|
|
24
|
+
try:
|
|
25
|
+
return packer.pack()
|
|
26
|
+
except Exception:
|
|
27
|
+
# Storage isn't ready yet, or the kennel is unhappy. Stay quiet.
|
|
28
|
+
return _EMPTY_RETURN
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""SQLite schema for the puppy_kennel.
|
|
2
|
+
|
|
3
|
+
Three core tables mirror MemKennel's mental model:
|
|
4
|
+
|
|
5
|
+
* ``wings`` — top-level partitions (typically a repo / project / agent)
|
|
6
|
+
* ``rooms`` — topical sub-partitions within a wing (one per session, usually)
|
|
7
|
+
* ``drawers`` — verbatim content chunks (a message, a response, etc.)
|
|
8
|
+
|
|
9
|
+
An FTS5 virtual table indexes drawer content for BM25 keyword retrieval.
|
|
10
|
+
Triggers keep the FTS table in sync with the base table automatically.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
SCHEMA_SQL = """
|
|
16
|
+
CREATE TABLE IF NOT EXISTS wings (
|
|
17
|
+
id INTEGER PRIMARY KEY,
|
|
18
|
+
name TEXT NOT NULL UNIQUE,
|
|
19
|
+
created_at TEXT NOT NULL,
|
|
20
|
+
metadata TEXT
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE TABLE IF NOT EXISTS rooms (
|
|
24
|
+
id INTEGER PRIMARY KEY,
|
|
25
|
+
wing_id INTEGER NOT NULL REFERENCES wings(id) ON DELETE CASCADE,
|
|
26
|
+
name TEXT NOT NULL,
|
|
27
|
+
created_at TEXT NOT NULL,
|
|
28
|
+
metadata TEXT,
|
|
29
|
+
UNIQUE(wing_id, name)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
CREATE TABLE IF NOT EXISTS drawers (
|
|
33
|
+
id INTEGER PRIMARY KEY,
|
|
34
|
+
room_id INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
|
|
35
|
+
role TEXT,
|
|
36
|
+
content TEXT NOT NULL,
|
|
37
|
+
ts TEXT NOT NULL,
|
|
38
|
+
session_id TEXT,
|
|
39
|
+
metadata TEXT
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_drawers_room ON drawers(room_id);
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_drawers_session ON drawers(session_id);
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_drawers_ts ON drawers(ts);
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_rooms_wing ON rooms(wing_id);
|
|
46
|
+
|
|
47
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS drawers_fts USING fts5(
|
|
48
|
+
content,
|
|
49
|
+
content='drawers',
|
|
50
|
+
content_rowid='id',
|
|
51
|
+
tokenize='porter unicode61'
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
-- Keep FTS in sync with drawers. Triggers are the SQLite-blessed way.
|
|
55
|
+
CREATE TRIGGER IF NOT EXISTS drawers_ai AFTER INSERT ON drawers BEGIN
|
|
56
|
+
INSERT INTO drawers_fts(rowid, content) VALUES (new.id, new.content);
|
|
57
|
+
END;
|
|
58
|
+
|
|
59
|
+
CREATE TRIGGER IF NOT EXISTS drawers_ad AFTER DELETE ON drawers BEGIN
|
|
60
|
+
INSERT INTO drawers_fts(drawers_fts, rowid, content)
|
|
61
|
+
VALUES('delete', old.id, old.content);
|
|
62
|
+
END;
|
|
63
|
+
|
|
64
|
+
CREATE TRIGGER IF NOT EXISTS drawers_au AFTER UPDATE ON drawers BEGIN
|
|
65
|
+
INSERT INTO drawers_fts(drawers_fts, rowid, content)
|
|
66
|
+
VALUES('delete', old.id, old.content);
|
|
67
|
+
INSERT INTO drawers_fts(rowid, content) VALUES (new.id, new.content);
|
|
68
|
+
END;
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
# Apply PRAGMAs on every connection. Set busy_timeout first: WAL's exclusive
|
|
72
|
+
# lock can collide during concurrent initialization and otherwise raises immediately.
|
|
73
|
+
PRAGMAS = (
|
|
74
|
+
"PRAGMA busy_timeout=5000", # 5s grace for writers waiting on the lock.
|
|
75
|
+
"PRAGMA journal_mode=WAL",
|
|
76
|
+
"PRAGMA synchronous=NORMAL", # WAL durability is fine at NORMAL; faster.
|
|
77
|
+
"PRAGMA foreign_keys=ON",
|
|
78
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Runtime state for the puppy_kennel plugin.
|
|
2
|
+
|
|
3
|
+
Single source of truth for whether the kennel is on. Flipped by the
|
|
4
|
+
``/kennel enable`` and ``/kennel disable`` slash commands. Persisted in
|
|
5
|
+
``puppy.cfg`` under the key ``kennel_enabled`` so the front end can read
|
|
6
|
+
and write the same value.
|
|
7
|
+
|
|
8
|
+
Default is **disabled** -- a missing key, blank value, or garbage value
|
|
9
|
+
all leave the kennel off. Only the explicit-truthy tokens
|
|
10
|
+
``{"true", "1", "yes", "on"}`` (case-insensitive) turn it on. That
|
|
11
|
+
asymmetry is on purpose: on a default-off system, a typo like
|
|
12
|
+
``kennel_enabled = yeas`` must not silently enable memory. In the face
|
|
13
|
+
of ambiguity, refuse to guess.
|
|
14
|
+
|
|
15
|
+
Reads and writes go through ``code_puppy.config.get_value`` /
|
|
16
|
+
``set_config_value``, the same helpers every other plugin (statusline,
|
|
17
|
+
prompt_newline, ...) uses for puppy.cfg interop.
|
|
18
|
+
|
|
19
|
+
An environment override, ``PUPPY_KENNEL_ENABLED``, takes precedence over
|
|
20
|
+
the persisted cfg value. This mirrors ``PUPPY_KENNEL_ROOT`` in
|
|
21
|
+
``config.py`` and -- crucially -- is the only knob that survives a
|
|
22
|
+
``multiprocessing`` *spawn*. Spawned children start a fresh interpreter
|
|
23
|
+
and re-read the developer's REAL ``puppy.cfg`` (the test harness's config
|
|
24
|
+
isolation lives in the parent process only), so without an env override a
|
|
25
|
+
child silently inherits whatever the developer happens to have toggled.
|
|
26
|
+
Env vars, by contrast, are inherited across the spawn boundary.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import os
|
|
32
|
+
|
|
33
|
+
from code_puppy.config import get_value, set_config_value
|
|
34
|
+
|
|
35
|
+
_CFG_KEY = "kennel_enabled"
|
|
36
|
+
_ENV_KEY = "PUPPY_KENNEL_ENABLED"
|
|
37
|
+
_TRUTHY = frozenset({"true", "1", "yes", "on"})
|
|
38
|
+
|
|
39
|
+
DISABLED_TOOL_ERROR = (
|
|
40
|
+
"Puppy Kennel memory is currently disabled. "
|
|
41
|
+
"Ask the user to run `/kennel enable` to turn it back on."
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def is_enabled() -> bool:
|
|
46
|
+
"""Return True if the kennel is on.
|
|
47
|
+
|
|
48
|
+
Defaults to False when the key is missing, blank, or set to anything
|
|
49
|
+
that isn't one of the explicit-truthy tokens. Evaluated on every call
|
|
50
|
+
so flipping the toggle takes effect immediately -- no relaunch
|
|
51
|
+
required.
|
|
52
|
+
"""
|
|
53
|
+
raw = os.environ.get(_ENV_KEY)
|
|
54
|
+
if raw is None:
|
|
55
|
+
raw = get_value(_CFG_KEY)
|
|
56
|
+
if raw is None:
|
|
57
|
+
return False
|
|
58
|
+
return str(raw).strip().lower() in _TRUTHY
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def set_enabled(value: bool) -> None:
|
|
62
|
+
"""Persist the kennel enable flag to puppy.cfg (positive sense).
|
|
63
|
+
|
|
64
|
+
Writes the literal string ``"true"`` or ``"false"`` so the on-disk
|
|
65
|
+
representation is stable and any future FE consumer can parse the
|
|
66
|
+
cfg directly without going through this helper.
|
|
67
|
+
"""
|
|
68
|
+
set_config_value(_CFG_KEY, "true" if value else "false")
|