code-puppy 0.0.169__py3-none-any.whl → 0.0.366__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 (243) hide show
  1. code_puppy/__init__.py +7 -1
  2. code_puppy/agents/__init__.py +8 -8
  3. code_puppy/agents/agent_c_reviewer.py +155 -0
  4. code_puppy/agents/agent_code_puppy.py +9 -2
  5. code_puppy/agents/agent_code_reviewer.py +90 -0
  6. code_puppy/agents/agent_cpp_reviewer.py +132 -0
  7. code_puppy/agents/agent_creator_agent.py +48 -9
  8. code_puppy/agents/agent_golang_reviewer.py +151 -0
  9. code_puppy/agents/agent_javascript_reviewer.py +160 -0
  10. code_puppy/agents/agent_manager.py +146 -199
  11. code_puppy/agents/agent_pack_leader.py +383 -0
  12. code_puppy/agents/agent_planning.py +163 -0
  13. code_puppy/agents/agent_python_programmer.py +165 -0
  14. code_puppy/agents/agent_python_reviewer.py +90 -0
  15. code_puppy/agents/agent_qa_expert.py +163 -0
  16. code_puppy/agents/agent_qa_kitten.py +208 -0
  17. code_puppy/agents/agent_security_auditor.py +181 -0
  18. code_puppy/agents/agent_terminal_qa.py +323 -0
  19. code_puppy/agents/agent_typescript_reviewer.py +166 -0
  20. code_puppy/agents/base_agent.py +1713 -1
  21. code_puppy/agents/event_stream_handler.py +350 -0
  22. code_puppy/agents/json_agent.py +12 -1
  23. code_puppy/agents/pack/__init__.py +34 -0
  24. code_puppy/agents/pack/bloodhound.py +304 -0
  25. code_puppy/agents/pack/husky.py +321 -0
  26. code_puppy/agents/pack/retriever.py +393 -0
  27. code_puppy/agents/pack/shepherd.py +348 -0
  28. code_puppy/agents/pack/terrier.py +287 -0
  29. code_puppy/agents/pack/watchdog.py +367 -0
  30. code_puppy/agents/prompt_reviewer.py +145 -0
  31. code_puppy/agents/subagent_stream_handler.py +276 -0
  32. code_puppy/api/__init__.py +13 -0
  33. code_puppy/api/app.py +169 -0
  34. code_puppy/api/main.py +21 -0
  35. code_puppy/api/pty_manager.py +446 -0
  36. code_puppy/api/routers/__init__.py +12 -0
  37. code_puppy/api/routers/agents.py +36 -0
  38. code_puppy/api/routers/commands.py +217 -0
  39. code_puppy/api/routers/config.py +74 -0
  40. code_puppy/api/routers/sessions.py +232 -0
  41. code_puppy/api/templates/terminal.html +361 -0
  42. code_puppy/api/websocket.py +154 -0
  43. code_puppy/callbacks.py +174 -4
  44. code_puppy/chatgpt_codex_client.py +283 -0
  45. code_puppy/claude_cache_client.py +586 -0
  46. code_puppy/cli_runner.py +916 -0
  47. code_puppy/command_line/add_model_menu.py +1079 -0
  48. code_puppy/command_line/agent_menu.py +395 -0
  49. code_puppy/command_line/attachments.py +395 -0
  50. code_puppy/command_line/autosave_menu.py +605 -0
  51. code_puppy/command_line/clipboard.py +527 -0
  52. code_puppy/command_line/colors_menu.py +520 -0
  53. code_puppy/command_line/command_handler.py +233 -627
  54. code_puppy/command_line/command_registry.py +150 -0
  55. code_puppy/command_line/config_commands.py +715 -0
  56. code_puppy/command_line/core_commands.py +792 -0
  57. code_puppy/command_line/diff_menu.py +863 -0
  58. code_puppy/command_line/load_context_completion.py +15 -22
  59. code_puppy/command_line/mcp/base.py +1 -4
  60. code_puppy/command_line/mcp/catalog_server_installer.py +175 -0
  61. code_puppy/command_line/mcp/custom_server_form.py +688 -0
  62. code_puppy/command_line/mcp/custom_server_installer.py +195 -0
  63. code_puppy/command_line/mcp/edit_command.py +148 -0
  64. code_puppy/command_line/mcp/handler.py +9 -4
  65. code_puppy/command_line/mcp/help_command.py +6 -5
  66. code_puppy/command_line/mcp/install_command.py +16 -27
  67. code_puppy/command_line/mcp/install_menu.py +685 -0
  68. code_puppy/command_line/mcp/list_command.py +3 -3
  69. code_puppy/command_line/mcp/logs_command.py +174 -65
  70. code_puppy/command_line/mcp/remove_command.py +2 -2
  71. code_puppy/command_line/mcp/restart_command.py +12 -4
  72. code_puppy/command_line/mcp/search_command.py +17 -11
  73. code_puppy/command_line/mcp/start_all_command.py +22 -13
  74. code_puppy/command_line/mcp/start_command.py +50 -31
  75. code_puppy/command_line/mcp/status_command.py +6 -7
  76. code_puppy/command_line/mcp/stop_all_command.py +11 -8
  77. code_puppy/command_line/mcp/stop_command.py +11 -10
  78. code_puppy/command_line/mcp/test_command.py +2 -2
  79. code_puppy/command_line/mcp/utils.py +1 -1
  80. code_puppy/command_line/mcp/wizard_utils.py +22 -18
  81. code_puppy/command_line/mcp_completion.py +174 -0
  82. code_puppy/command_line/model_picker_completion.py +89 -30
  83. code_puppy/command_line/model_settings_menu.py +884 -0
  84. code_puppy/command_line/motd.py +14 -8
  85. code_puppy/command_line/onboarding_slides.py +179 -0
  86. code_puppy/command_line/onboarding_wizard.py +340 -0
  87. code_puppy/command_line/pin_command_completion.py +329 -0
  88. code_puppy/command_line/prompt_toolkit_completion.py +626 -75
  89. code_puppy/command_line/session_commands.py +296 -0
  90. code_puppy/command_line/utils.py +54 -0
  91. code_puppy/config.py +1181 -51
  92. code_puppy/error_logging.py +118 -0
  93. code_puppy/gemini_code_assist.py +385 -0
  94. code_puppy/gemini_model.py +602 -0
  95. code_puppy/http_utils.py +220 -104
  96. code_puppy/keymap.py +128 -0
  97. code_puppy/main.py +5 -594
  98. code_puppy/{mcp → mcp_}/__init__.py +17 -0
  99. code_puppy/{mcp → mcp_}/async_lifecycle.py +35 -4
  100. code_puppy/{mcp → mcp_}/blocking_startup.py +70 -43
  101. code_puppy/{mcp → mcp_}/captured_stdio_server.py +2 -2
  102. code_puppy/{mcp → mcp_}/config_wizard.py +5 -5
  103. code_puppy/{mcp → mcp_}/dashboard.py +15 -6
  104. code_puppy/{mcp → mcp_}/examples/retry_example.py +4 -1
  105. code_puppy/{mcp → mcp_}/managed_server.py +66 -39
  106. code_puppy/{mcp → mcp_}/manager.py +146 -52
  107. code_puppy/mcp_/mcp_logs.py +224 -0
  108. code_puppy/{mcp → mcp_}/registry.py +6 -6
  109. code_puppy/{mcp → mcp_}/server_registry_catalog.py +25 -8
  110. code_puppy/messaging/__init__.py +199 -2
  111. code_puppy/messaging/bus.py +610 -0
  112. code_puppy/messaging/commands.py +167 -0
  113. code_puppy/messaging/markdown_patches.py +57 -0
  114. code_puppy/messaging/message_queue.py +17 -48
  115. code_puppy/messaging/messages.py +500 -0
  116. code_puppy/messaging/queue_console.py +1 -24
  117. code_puppy/messaging/renderers.py +43 -146
  118. code_puppy/messaging/rich_renderer.py +1027 -0
  119. code_puppy/messaging/spinner/__init__.py +33 -5
  120. code_puppy/messaging/spinner/console_spinner.py +92 -52
  121. code_puppy/messaging/spinner/spinner_base.py +29 -0
  122. code_puppy/messaging/subagent_console.py +461 -0
  123. code_puppy/model_factory.py +686 -80
  124. code_puppy/model_utils.py +167 -0
  125. code_puppy/models.json +86 -104
  126. code_puppy/models_dev_api.json +1 -0
  127. code_puppy/models_dev_parser.py +592 -0
  128. code_puppy/plugins/__init__.py +164 -10
  129. code_puppy/plugins/antigravity_oauth/__init__.py +10 -0
  130. code_puppy/plugins/antigravity_oauth/accounts.py +406 -0
  131. code_puppy/plugins/antigravity_oauth/antigravity_model.py +704 -0
  132. code_puppy/plugins/antigravity_oauth/config.py +42 -0
  133. code_puppy/plugins/antigravity_oauth/constants.py +136 -0
  134. code_puppy/plugins/antigravity_oauth/oauth.py +478 -0
  135. code_puppy/plugins/antigravity_oauth/register_callbacks.py +406 -0
  136. code_puppy/plugins/antigravity_oauth/storage.py +271 -0
  137. code_puppy/plugins/antigravity_oauth/test_plugin.py +319 -0
  138. code_puppy/plugins/antigravity_oauth/token.py +167 -0
  139. code_puppy/plugins/antigravity_oauth/transport.py +767 -0
  140. code_puppy/plugins/antigravity_oauth/utils.py +169 -0
  141. code_puppy/plugins/chatgpt_oauth/__init__.py +8 -0
  142. code_puppy/plugins/chatgpt_oauth/config.py +52 -0
  143. code_puppy/plugins/chatgpt_oauth/oauth_flow.py +328 -0
  144. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +94 -0
  145. code_puppy/plugins/chatgpt_oauth/test_plugin.py +293 -0
  146. code_puppy/plugins/chatgpt_oauth/utils.py +489 -0
  147. code_puppy/plugins/claude_code_oauth/README.md +167 -0
  148. code_puppy/plugins/claude_code_oauth/SETUP.md +93 -0
  149. code_puppy/plugins/claude_code_oauth/__init__.py +6 -0
  150. code_puppy/plugins/claude_code_oauth/config.py +50 -0
  151. code_puppy/plugins/claude_code_oauth/register_callbacks.py +308 -0
  152. code_puppy/plugins/claude_code_oauth/test_plugin.py +283 -0
  153. code_puppy/plugins/claude_code_oauth/utils.py +518 -0
  154. code_puppy/plugins/customizable_commands/__init__.py +0 -0
  155. code_puppy/plugins/customizable_commands/register_callbacks.py +169 -0
  156. code_puppy/plugins/example_custom_command/README.md +280 -0
  157. code_puppy/plugins/example_custom_command/register_callbacks.py +51 -0
  158. code_puppy/plugins/file_permission_handler/__init__.py +4 -0
  159. code_puppy/plugins/file_permission_handler/register_callbacks.py +523 -0
  160. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  161. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  162. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  163. code_puppy/plugins/oauth_puppy_html.py +228 -0
  164. code_puppy/plugins/shell_safety/__init__.py +6 -0
  165. code_puppy/plugins/shell_safety/agent_shell_safety.py +69 -0
  166. code_puppy/plugins/shell_safety/command_cache.py +156 -0
  167. code_puppy/plugins/shell_safety/register_callbacks.py +202 -0
  168. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  169. code_puppy/prompts/codex_system_prompt.md +310 -0
  170. code_puppy/pydantic_patches.py +131 -0
  171. code_puppy/reopenable_async_client.py +8 -8
  172. code_puppy/round_robin_model.py +10 -15
  173. code_puppy/session_storage.py +294 -0
  174. code_puppy/status_display.py +21 -4
  175. code_puppy/summarization_agent.py +52 -14
  176. code_puppy/terminal_utils.py +418 -0
  177. code_puppy/tools/__init__.py +139 -6
  178. code_puppy/tools/agent_tools.py +548 -49
  179. code_puppy/tools/browser/__init__.py +37 -0
  180. code_puppy/tools/browser/browser_control.py +289 -0
  181. code_puppy/tools/browser/browser_interactions.py +545 -0
  182. code_puppy/tools/browser/browser_locators.py +640 -0
  183. code_puppy/tools/browser/browser_manager.py +316 -0
  184. code_puppy/tools/browser/browser_navigation.py +251 -0
  185. code_puppy/tools/browser/browser_screenshot.py +179 -0
  186. code_puppy/tools/browser/browser_scripts.py +462 -0
  187. code_puppy/tools/browser/browser_workflows.py +221 -0
  188. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  189. code_puppy/tools/browser/terminal_command_tools.py +521 -0
  190. code_puppy/tools/browser/terminal_screenshot_tools.py +556 -0
  191. code_puppy/tools/browser/terminal_tools.py +525 -0
  192. code_puppy/tools/command_runner.py +941 -153
  193. code_puppy/tools/common.py +1146 -6
  194. code_puppy/tools/display.py +84 -0
  195. code_puppy/tools/file_modifications.py +288 -89
  196. code_puppy/tools/file_operations.py +352 -266
  197. code_puppy/tools/subagent_context.py +158 -0
  198. code_puppy/uvx_detection.py +242 -0
  199. code_puppy/version_checker.py +30 -11
  200. code_puppy-0.0.366.data/data/code_puppy/models.json +110 -0
  201. code_puppy-0.0.366.data/data/code_puppy/models_dev_api.json +1 -0
  202. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/METADATA +184 -67
  203. code_puppy-0.0.366.dist-info/RECORD +217 -0
  204. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/WHEEL +1 -1
  205. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/entry_points.txt +1 -0
  206. code_puppy/agent.py +0 -231
  207. code_puppy/agents/agent_orchestrator.json +0 -26
  208. code_puppy/agents/runtime_manager.py +0 -272
  209. code_puppy/command_line/mcp/add_command.py +0 -183
  210. code_puppy/command_line/meta_command_handler.py +0 -153
  211. code_puppy/message_history_processor.py +0 -490
  212. code_puppy/messaging/spinner/textual_spinner.py +0 -101
  213. code_puppy/state_management.py +0 -200
  214. code_puppy/tui/__init__.py +0 -10
  215. code_puppy/tui/app.py +0 -986
  216. code_puppy/tui/components/__init__.py +0 -21
  217. code_puppy/tui/components/chat_view.py +0 -550
  218. code_puppy/tui/components/command_history_modal.py +0 -218
  219. code_puppy/tui/components/copy_button.py +0 -139
  220. code_puppy/tui/components/custom_widgets.py +0 -63
  221. code_puppy/tui/components/human_input_modal.py +0 -175
  222. code_puppy/tui/components/input_area.py +0 -167
  223. code_puppy/tui/components/sidebar.py +0 -309
  224. code_puppy/tui/components/status_bar.py +0 -182
  225. code_puppy/tui/messages.py +0 -27
  226. code_puppy/tui/models/__init__.py +0 -8
  227. code_puppy/tui/models/chat_message.py +0 -25
  228. code_puppy/tui/models/command_history.py +0 -89
  229. code_puppy/tui/models/enums.py +0 -24
  230. code_puppy/tui/screens/__init__.py +0 -15
  231. code_puppy/tui/screens/help.py +0 -130
  232. code_puppy/tui/screens/mcp_install_wizard.py +0 -803
  233. code_puppy/tui/screens/settings.py +0 -290
  234. code_puppy/tui/screens/tools.py +0 -74
  235. code_puppy-0.0.169.data/data/code_puppy/models.json +0 -128
  236. code_puppy-0.0.169.dist-info/RECORD +0 -112
  237. /code_puppy/{mcp → mcp_}/circuit_breaker.py +0 -0
  238. /code_puppy/{mcp → mcp_}/error_isolation.py +0 -0
  239. /code_puppy/{mcp → mcp_}/health_monitor.py +0 -0
  240. /code_puppy/{mcp → mcp_}/retry_manager.py +0 -0
  241. /code_puppy/{mcp → mcp_}/status_tracker.py +0 -0
  242. /code_puppy/{mcp → mcp_}/system_tools.py +0 -0
  243. {code_puppy-0.0.169.dist-info → code_puppy-0.0.366.dist-info}/licenses/LICENSE +0 -0
code_puppy/main.py CHANGED
@@ -1,599 +1,10 @@
1
- import argparse
2
- import asyncio
3
- import os
4
- import subprocess
5
- import sys
6
- import time
7
- import webbrowser
1
+ """Main entry point for Code Puppy CLI.
8
2
 
9
- from rich.console import Console, ConsoleOptions, RenderResult
10
- from rich.markdown import CodeBlock, Markdown
11
- from rich.syntax import Syntax
12
- from rich.text import Text
13
-
14
- from code_puppy import __version__, callbacks, plugins
15
- from code_puppy.agent import get_custom_usage_limits
16
- from code_puppy.agents.runtime_manager import get_runtime_agent_manager
17
- from code_puppy.command_line.prompt_toolkit_completion import (
18
- get_input_with_combined_completion,
19
- get_prompt_with_active_model,
20
- )
21
- from code_puppy.config import (
22
- COMMAND_HISTORY_FILE,
23
- ensure_config_exists,
24
- initialize_command_history_file,
25
- save_command_to_history,
26
- )
27
- from code_puppy.http_utils import find_available_port
28
- from code_puppy.message_history_processor import (
29
- message_history_accumulator,
30
- prune_interrupted_tool_calls,
31
- )
32
- from code_puppy.state_management import is_tui_mode, set_message_history, set_tui_mode
33
- from code_puppy.tools.common import console
34
- from code_puppy.version_checker import default_version_mismatch_behavior
35
-
36
- plugins.load_plugin_callbacks()
37
-
38
-
39
- async def main():
40
- parser = argparse.ArgumentParser(description="Code Puppy - A code generation agent")
41
- parser.add_argument(
42
- "--version",
43
- "-v",
44
- action="version",
45
- version=f"{__version__}",
46
- help="Show version and exit",
47
- )
48
- parser.add_argument(
49
- "--interactive",
50
- "-i",
51
- action="store_true",
52
- help="Run in interactive mode",
53
- )
54
- parser.add_argument("--tui", "-t", action="store_true", help="Run in TUI mode")
55
- parser.add_argument(
56
- "--web",
57
- "-w",
58
- action="store_true",
59
- help="Run in web mode (serves TUI in browser)",
60
- )
61
- parser.add_argument(
62
- "--prompt",
63
- "-p",
64
- type=str,
65
- help="Execute a single prompt and exit (no interactive mode)",
66
- )
67
- parser.add_argument(
68
- "command", nargs="*", help="Run a single command (deprecated, use -p instead)"
69
- )
70
- args = parser.parse_args()
71
-
72
- if args.tui or args.web:
73
- set_tui_mode(True)
74
- elif args.interactive or args.command or args.prompt:
75
- set_tui_mode(False)
76
-
77
- message_renderer = None
78
- if not is_tui_mode():
79
- from rich.console import Console
80
-
81
- from code_puppy.messaging import (
82
- SynchronousInteractiveRenderer,
83
- get_global_queue,
84
- )
85
-
86
- message_queue = get_global_queue()
87
- display_console = Console() # Separate console for rendering messages
88
- message_renderer = SynchronousInteractiveRenderer(
89
- message_queue, display_console
90
- )
91
- message_renderer.start()
92
-
93
- if (
94
- not args.tui
95
- and not args.interactive
96
- and not args.web
97
- and not args.command
98
- and not args.prompt
99
- ):
100
- pass
101
-
102
- initialize_command_history_file()
103
- if args.web:
104
- from rich.console import Console
105
-
106
- direct_console = Console()
107
- try:
108
- # Find an available port for the web server
109
- available_port = find_available_port()
110
- if available_port is None:
111
- direct_console.print(
112
- "[bold red]Error:[/bold red] No available ports in range 8090-9010!"
113
- )
114
- sys.exit(1)
115
- python_executable = sys.executable
116
- serve_command = f"{python_executable} -m code_puppy --tui"
117
- textual_serve_cmd = [
118
- "textual",
119
- "serve",
120
- "-c",
121
- serve_command,
122
- "--port",
123
- str(available_port),
124
- ]
125
- direct_console.print(
126
- "[bold blue]🌐 Starting Code Puppy web interface...[/bold blue]"
127
- )
128
- direct_console.print(f"[dim]Running: {' '.join(textual_serve_cmd)}[/dim]")
129
- web_url = f"http://localhost:{available_port}"
130
- direct_console.print(
131
- f"[green]Web interface will be available at: {web_url}[/green]"
132
- )
133
- direct_console.print("[yellow]Press Ctrl+C to stop the server.[/yellow]\n")
134
- process = subprocess.Popen(textual_serve_cmd)
135
- time.sleep(0.3)
136
- try:
137
- direct_console.print(
138
- "[cyan]🚀 Opening web interface in your default browser...[/cyan]"
139
- )
140
- webbrowser.open(web_url)
141
- direct_console.print("[green]✅ Browser opened successfully![/green]\n")
142
- except Exception as e:
143
- direct_console.print(
144
- f"[yellow]⚠️ Could not automatically open browser: {e}[/yellow]"
145
- )
146
- direct_console.print(
147
- f"[yellow]Please manually open: {web_url}[/yellow]\n"
148
- )
149
- result = process.wait()
150
- sys.exit(result)
151
- except Exception as e:
152
- direct_console.print(
153
- f"[bold red]Error starting web interface:[/bold red] {str(e)}"
154
- )
155
- sys.exit(1)
156
- from code_puppy.messaging import emit_system_message
157
-
158
- emit_system_message("🐶 Code Puppy is Loading...")
159
-
160
- available_port = find_available_port()
161
- if available_port is None:
162
- error_msg = "Error: No available ports in range 8090-9010!"
163
- emit_system_message(f"[bold red]{error_msg}[/bold red]")
164
- return
165
-
166
- ensure_config_exists()
167
- current_version = __version__
168
-
169
- no_version_update = os.getenv("NO_VERSION_UPDATE", "").lower() in (
170
- "1",
171
- "true",
172
- "yes",
173
- "on",
174
- )
175
- if no_version_update:
176
- version_msg = f"Current version: {current_version}"
177
- update_disabled_msg = (
178
- "Update phase disabled because NO_VERSION_UPDATE is set to 1 or true"
179
- )
180
- emit_system_message(version_msg)
181
- emit_system_message(f"[dim]{update_disabled_msg}[/dim]")
182
- else:
183
- if len(callbacks.get_callbacks("version_check")):
184
- await callbacks.on_version_check(current_version)
185
- else:
186
- default_version_mismatch_behavior(current_version)
187
-
188
- await callbacks.on_startup()
189
-
190
- global shutdown_flag
191
- shutdown_flag = False
192
- try:
193
- initial_command = None
194
- prompt_only_mode = False
195
-
196
- if args.prompt:
197
- initial_command = args.prompt
198
- prompt_only_mode = True
199
- elif args.command:
200
- initial_command = " ".join(args.command)
201
- prompt_only_mode = False
202
-
203
- if prompt_only_mode:
204
- await execute_single_prompt(initial_command, message_renderer)
205
- elif is_tui_mode():
206
- try:
207
- from code_puppy.tui import run_textual_ui
208
-
209
- await run_textual_ui(initial_command=initial_command)
210
- except ImportError:
211
- from code_puppy.messaging import emit_error, emit_warning
212
-
213
- emit_error(
214
- "Error: Textual UI not available. Install with: pip install textual"
215
- )
216
- emit_warning("Falling back to interactive mode...")
217
- await interactive_mode(message_renderer)
218
- except Exception as e:
219
- from code_puppy.messaging import emit_error, emit_warning
220
-
221
- emit_error(f"TUI Error: {str(e)}")
222
- emit_warning("Falling back to interactive mode...")
223
- await interactive_mode(message_renderer)
224
- elif args.interactive or initial_command:
225
- await interactive_mode(message_renderer, initial_command=initial_command)
226
- else:
227
- await prompt_then_interactive_mode(message_renderer)
228
- finally:
229
- if message_renderer:
230
- message_renderer.stop()
231
- await callbacks.on_shutdown()
232
-
233
-
234
- # Add the file handling functionality for interactive mode
235
- async def interactive_mode(message_renderer, initial_command: str = None) -> None:
236
- from code_puppy.command_line.command_handler import handle_command
237
-
238
- """Run the agent in interactive mode."""
239
- from code_puppy.state_management import clear_message_history, get_message_history
240
-
241
- clear_message_history()
242
- display_console = message_renderer.console
243
- from code_puppy.messaging import emit_info, emit_system_message
244
-
245
- emit_info("[bold green]Code Puppy[/bold green] - Interactive Mode")
246
- emit_system_message("Type '/exit' or '/quit' to exit the interactive mode.")
247
- emit_system_message("Type 'clear' to reset the conversation history.")
248
- emit_system_message(
249
- "Type [bold blue]@[/bold blue] for path completion, or [bold blue]/m[/bold blue] to pick a model. Use [bold blue]Esc+Enter[/bold blue] for multi-line input."
250
- )
251
- emit_system_message(
252
- "Press [bold red]Ctrl+C[/bold red] during processing to cancel the current task or inference."
253
- )
254
- from code_puppy.command_line.command_handler import get_commands_help
255
-
256
- help_text = get_commands_help()
257
- emit_system_message(help_text)
258
- try:
259
- from code_puppy.command_line.motd import print_motd
260
-
261
- print_motd(console, force=False)
262
- except Exception as e:
263
- from code_puppy.messaging import emit_warning
264
-
265
- emit_warning(f"MOTD error: {e}")
266
- from code_puppy.agents.runtime_manager import get_runtime_agent_manager
267
- from code_puppy.messaging import emit_info
268
-
269
- emit_info("[bold cyan]Initializing agent...[/bold cyan]")
270
- # Initialize the runtime agent manager
271
- agent_manager = get_runtime_agent_manager()
272
- agent_manager.get_agent()
273
- if initial_command:
274
- from code_puppy.messaging import emit_info, emit_system_message
275
-
276
- emit_info(
277
- f"[bold blue]Processing initial command:[/bold blue] {initial_command}"
278
- )
279
-
280
- try:
281
- # Check if any tool is waiting for user input before showing spinner
282
- try:
283
- from code_puppy.tools.command_runner import is_awaiting_user_input
284
-
285
- awaiting_input = is_awaiting_user_input()
286
- except ImportError:
287
- awaiting_input = False
288
-
289
- # Run with or without spinner based on whether we're awaiting input
290
- if awaiting_input:
291
- # No spinner - use agent_manager's run_with_mcp method
292
- response = await agent_manager.run_with_mcp(
293
- initial_command,
294
- message_history=get_message_history(),
295
- usage_limits=get_custom_usage_limits(),
296
- )
297
- else:
298
- # Use our custom spinner for better compatibility with user input
299
- from code_puppy.messaging.spinner import ConsoleSpinner
300
-
301
- with ConsoleSpinner(console=display_console):
302
- # Use agent_manager's run_with_mcp method
303
- response = await agent_manager.run_with_mcp(
304
- initial_command,
305
- message_history=prune_interrupted_tool_calls(
306
- get_message_history()
307
- ),
308
- usage_limits=get_custom_usage_limits(),
309
- )
310
- set_message_history(
311
- prune_interrupted_tool_calls(get_message_history())
312
- )
313
-
314
- agent_response = response.output
315
-
316
- emit_system_message(
317
- f"\n[bold purple]AGENT RESPONSE: [/bold purple]\n{agent_response}"
318
- )
319
- new_msgs = response.all_messages()
320
- message_history_accumulator(new_msgs)
321
- set_message_history(prune_interrupted_tool_calls(get_message_history()))
322
- emit_system_message("\n" + "=" * 50)
323
- emit_info("[bold green]🐶 Continuing in Interactive Mode[/bold green]")
324
- emit_system_message(
325
- "Your command and response are preserved in the conversation history."
326
- )
327
- emit_system_message("=" * 50 + "\n")
328
-
329
- except Exception as e:
330
- from code_puppy.messaging import emit_error
331
-
332
- emit_error(f"Error processing initial command: {str(e)}")
333
-
334
- # Check if prompt_toolkit is installed
335
- try:
336
- from code_puppy.messaging import emit_system_message
337
-
338
- emit_system_message(
339
- "[dim]Using prompt_toolkit for enhanced tab completion[/dim]"
340
- )
341
- except ImportError:
342
- from code_puppy.messaging import emit_warning
343
-
344
- emit_warning("Warning: prompt_toolkit not installed. Installing now...")
345
- try:
346
- import subprocess
347
-
348
- subprocess.check_call(
349
- [sys.executable, "-m", "pip", "install", "prompt_toolkit"]
350
- )
351
- from code_puppy.messaging import emit_success
352
-
353
- emit_success("Successfully installed prompt_toolkit")
354
- except Exception as e:
355
- from code_puppy.messaging import emit_error, emit_warning
356
-
357
- emit_error(f"Error installing prompt_toolkit: {e}")
358
- emit_warning("Falling back to basic input without tab completion")
359
-
360
- while True:
361
- from code_puppy.agents.agent_manager import get_current_agent_config
362
- from code_puppy.messaging import emit_info
363
-
364
- # Get the custom prompt from the current agent, or use default
365
- current_agent = get_current_agent_config()
366
- user_prompt = current_agent.get_user_prompt() or "Enter your coding task:"
367
-
368
- emit_info(f"[bold blue]{user_prompt}[/bold blue]")
369
-
370
- try:
371
- # Use prompt_toolkit for enhanced input with path completion
372
- try:
373
- # Use the async version of get_input_with_combined_completion
374
- task = await get_input_with_combined_completion(
375
- get_prompt_with_active_model(), history_file=COMMAND_HISTORY_FILE
376
- )
377
- except ImportError:
378
- # Fall back to basic input if prompt_toolkit is not available
379
- task = input(">>> ")
380
-
381
- except (KeyboardInterrupt, EOFError):
382
- # Handle Ctrl+C or Ctrl+D
383
- from code_puppy.messaging import emit_warning
384
-
385
- emit_warning("\nInput cancelled")
386
- continue
387
-
388
- # Check for exit commands (plain text or command form)
389
- if task.strip().lower() in ["exit", "quit"] or task.strip().lower() in [
390
- "/exit",
391
- "/quit",
392
- ]:
393
- from code_puppy.messaging import emit_success
394
-
395
- emit_success("Goodbye!")
396
- # The renderer is stopped in the finally block of main().
397
- break
398
-
399
- # Check for clear command (supports both `clear` and `/clear`)
400
- if task.strip().lower() in ("clear", "/clear"):
401
- clear_message_history()
402
- from code_puppy.messaging import emit_system_message, emit_warning
403
-
404
- emit_warning("Conversation history cleared!")
405
- emit_system_message("The agent will not remember previous interactions.\n")
406
- continue
407
-
408
- # Handle / commands before anything else
409
- if task.strip().startswith("/"):
410
- command_result = handle_command(task.strip())
411
- if command_result is True:
412
- continue
413
- elif isinstance(command_result, str):
414
- # Command returned a prompt to execute
415
- task = command_result
416
- elif command_result is False:
417
- # Command not recognized, continue with normal processing
418
- pass
419
-
420
- if task.strip():
421
- # Write to the secret file for permanent history with timestamp
422
- save_command_to_history(task)
423
-
424
- try:
425
- prettier_code_blocks()
426
-
427
- # No need to get agent directly - use manager's run methods
428
-
429
- # Use our custom spinner for better compatibility with user input
430
- from code_puppy.messaging import emit_warning
431
- from code_puppy.messaging.spinner import ConsoleSpinner
432
-
433
- runtime_manager = get_runtime_agent_manager()
434
- with ConsoleSpinner(console=message_renderer.console):
435
- result = await runtime_manager.run_with_mcp(
436
- task,
437
- get_custom_usage_limits(),
438
- message_history=prune_interrupted_tool_calls(
439
- get_message_history()
440
- ),
441
- )
442
- # Check if the task was cancelled (but don't show message if we just killed processes)
443
- if result is None:
444
- continue
445
- # Get the structured response
446
- agent_response = result.output
447
- from code_puppy.messaging import emit_info
448
-
449
- emit_system_message(
450
- f"\n[bold purple]AGENT RESPONSE: [/bold purple]\n{agent_response}"
451
- )
452
-
453
- # Update message history - the agent's history processor will handle truncation
454
- new_msgs = result.all_messages()
455
- message_history_accumulator(new_msgs)
456
-
457
- emit_system_message(
458
- f"Context: {len(get_message_history())} messages in history\n"
459
- )
460
-
461
- # Ensure console output is flushed before next prompt
462
- # This fixes the issue where prompt doesn't appear after agent response
463
- display_console.file.flush() if hasattr(
464
- display_console.file, "flush"
465
- ) else None
466
- import time
467
-
468
- time.sleep(0.1) # Brief pause to ensure all messages are rendered
469
-
470
- except Exception:
471
- from code_puppy.messaging.queue_console import get_queue_console
472
-
473
- get_queue_console().print_exception()
474
-
475
-
476
- def prettier_code_blocks():
477
- class SimpleCodeBlock(CodeBlock):
478
- def __rich_console__(
479
- self, console: Console, options: ConsoleOptions
480
- ) -> RenderResult:
481
- code = str(self.text).rstrip()
482
- yield Text(self.lexer_name, style="dim")
483
- syntax = Syntax(
484
- code,
485
- self.lexer_name,
486
- theme=self.theme,
487
- background_color="default",
488
- line_numbers=True,
489
- )
490
- yield syntax
491
- yield Text(f"/{self.lexer_name}", style="dim")
492
-
493
- Markdown.elements["fence"] = SimpleCodeBlock
494
-
495
-
496
- async def execute_single_prompt(prompt: str, message_renderer) -> None:
497
- """Execute a single prompt and exit (for -p flag)."""
498
- from code_puppy.messaging import emit_info, emit_system_message
499
-
500
- emit_info(f"[bold blue]Executing prompt:[/bold blue] {prompt}")
501
-
502
- try:
503
- # Get agent through runtime manager and use its run_with_mcp method
504
- agent_manager = get_runtime_agent_manager()
505
-
506
- from code_puppy.messaging.spinner import ConsoleSpinner
507
-
508
- with ConsoleSpinner(console=message_renderer.console):
509
- response = await agent_manager.run_with_mcp(
510
- prompt,
511
- usage_limits=get_custom_usage_limits(),
512
- )
513
-
514
- agent_response = response.output
515
- emit_system_message(
516
- f"\n[bold purple]AGENT RESPONSE: [/bold purple]\n{agent_response}"
517
- )
518
-
519
- except asyncio.CancelledError:
520
- from code_puppy.messaging import emit_warning
521
-
522
- emit_warning("Execution cancelled by user")
523
- except Exception as e:
524
- from code_puppy.messaging import emit_error
525
-
526
- emit_error(f"Error executing prompt: {str(e)}")
527
-
528
-
529
- async def prompt_then_interactive_mode(message_renderer) -> None:
530
- """Prompt user for input, execute it, then continue in interactive mode."""
531
- from code_puppy.messaging import emit_info, emit_system_message
532
-
533
- emit_info("[bold green]🐶 Code Puppy[/bold green] - Enter your request")
534
- emit_system_message(
535
- "After processing your request, you'll continue in interactive mode."
536
- )
537
-
538
- try:
539
- # Get user input
540
- from code_puppy.command_line.prompt_toolkit_completion import (
541
- get_input_with_combined_completion,
542
- get_prompt_with_active_model,
543
- )
544
- from code_puppy.config import COMMAND_HISTORY_FILE
545
-
546
- emit_info("[bold blue]What would you like me to help you with?[/bold blue]")
547
-
548
- try:
549
- # Use prompt_toolkit for enhanced input with path completion
550
- user_prompt = await get_input_with_combined_completion(
551
- get_prompt_with_active_model(), history_file=COMMAND_HISTORY_FILE
552
- )
553
- except ImportError:
554
- # Fall back to basic input if prompt_toolkit is not available
555
- user_prompt = input(">>> ")
556
-
557
- if user_prompt.strip():
558
- # Execute the prompt
559
- await execute_single_prompt(user_prompt, message_renderer)
560
-
561
- # Transition to interactive mode
562
- emit_system_message("\n" + "=" * 50)
563
- emit_info("[bold green]🐶 Continuing in Interactive Mode[/bold green]")
564
- emit_system_message(
565
- "Your request and response are preserved in the conversation history."
566
- )
567
- emit_system_message("=" * 50 + "\n")
568
-
569
- # Continue in interactive mode with the initial command as history
570
- await interactive_mode(message_renderer, initial_command=user_prompt)
571
- else:
572
- # No input provided, just go to interactive mode
573
- await interactive_mode(message_renderer)
574
-
575
- except (KeyboardInterrupt, EOFError):
576
- from code_puppy.messaging import emit_warning
577
-
578
- emit_warning("\nInput cancelled. Starting interactive mode...")
579
- await interactive_mode(message_renderer)
580
- except Exception as e:
581
- from code_puppy.messaging import emit_error
582
-
583
- emit_error(f"Error in prompt mode: {str(e)}")
584
- emit_info("Falling back to interactive mode...")
585
- await interactive_mode(message_renderer)
586
-
587
-
588
- def main_entry():
589
- """Entry point for the installed CLI tool."""
590
- try:
591
- asyncio.run(main())
592
- except KeyboardInterrupt:
593
- # Just exit gracefully with no error message
594
- callbacks.on_shutdown()
595
- return 0
3
+ This module re-exports the main_entry function from cli_runner for backwards compatibility.
4
+ All the actual logic lives in cli_runner.py.
5
+ """
596
6
 
7
+ from code_puppy.cli_runner import main_entry
597
8
 
598
9
  if __name__ == "__main__":
599
10
  main_entry()
@@ -17,6 +17,15 @@ from .error_isolation import (
17
17
  )
18
18
  from .managed_server import ManagedMCPServer, ServerConfig, ServerState
19
19
  from .manager import MCPManager, ServerInfo, get_mcp_manager
20
+ from .mcp_logs import (
21
+ clear_logs,
22
+ get_log_file_path,
23
+ get_log_stats,
24
+ get_mcp_logs_dir,
25
+ list_servers_with_logs,
26
+ read_logs,
27
+ write_log,
28
+ )
20
29
  from .registry import ServerRegistry
21
30
  from .retry_manager import RetryManager, RetryStats, get_retry_manager, retry_mcp_call
22
31
  from .status_tracker import Event, ServerStatusTracker
@@ -46,4 +55,12 @@ __all__ = [
46
55
  "MCPDashboard",
47
56
  "MCPConfigWizard",
48
57
  "run_add_wizard",
58
+ # Log management
59
+ "get_mcp_logs_dir",
60
+ "get_log_file_path",
61
+ "read_logs",
62
+ "write_log",
63
+ "clear_logs",
64
+ "list_servers_with_logs",
65
+ "get_log_stats",
49
66
  ]