code-puppy 0.0.379__py3-none-any.whl → 0.0.381__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/agents/base_agent.py +76 -2
- code_puppy/callbacks.py +84 -0
- code_puppy/cli_runner.py +93 -1
- code_puppy/command_line/core_commands.py +61 -0
- code_puppy/command_line/motd.py +26 -3
- code_puppy/command_line/wiggum_state.py +78 -0
- code_puppy/config.py +15 -0
- code_puppy/mcp_/server_registry_catalog.py +14 -1
- code_puppy/model_factory.py +43 -0
- code_puppy/tools/browser/browser_manager.py +66 -5
- {code_puppy-0.0.379.dist-info → code_puppy-0.0.381.dist-info}/METADATA +1 -1
- {code_puppy-0.0.379.dist-info → code_puppy-0.0.381.dist-info}/RECORD +17 -24
- code_puppy/plugins/ralph/__init__.py +0 -13
- code_puppy/plugins/ralph/agents.py +0 -433
- code_puppy/plugins/ralph/commands.py +0 -208
- code_puppy/plugins/ralph/loop_controller.py +0 -289
- code_puppy/plugins/ralph/models.py +0 -125
- code_puppy/plugins/ralph/register_callbacks.py +0 -140
- code_puppy/plugins/ralph/state_manager.py +0 -322
- code_puppy/plugins/ralph/tools.py +0 -451
- {code_puppy-0.0.379.data → code_puppy-0.0.381.data}/data/code_puppy/models.json +0 -0
- {code_puppy-0.0.379.data → code_puppy-0.0.381.data}/data/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.379.dist-info → code_puppy-0.0.381.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.379.dist-info → code_puppy-0.0.381.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.379.dist-info → code_puppy-0.0.381.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,13 +8,41 @@ import atexit
|
|
|
8
8
|
import contextvars
|
|
9
9
|
import os
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Optional
|
|
11
|
+
from typing import Callable, Dict, Optional
|
|
12
12
|
|
|
13
13
|
from playwright.async_api import Browser, BrowserContext, Page
|
|
14
14
|
|
|
15
15
|
from code_puppy import config
|
|
16
16
|
from code_puppy.messaging import emit_info, emit_success, emit_warning
|
|
17
17
|
|
|
18
|
+
# Registry for custom browser types from plugins (e.g., Camoufox for stealth browsing)
|
|
19
|
+
_CUSTOM_BROWSER_TYPES: Dict[str, Callable] = {}
|
|
20
|
+
_BROWSER_TYPES_LOADED: bool = False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _load_plugin_browser_types() -> None:
|
|
24
|
+
"""Load custom browser types from plugins.
|
|
25
|
+
|
|
26
|
+
This is called lazily on first browser initialization to allow plugins
|
|
27
|
+
to register custom browser providers (like Camoufox for stealth browsing).
|
|
28
|
+
"""
|
|
29
|
+
global _CUSTOM_BROWSER_TYPES, _BROWSER_TYPES_LOADED
|
|
30
|
+
|
|
31
|
+
if _BROWSER_TYPES_LOADED:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
_BROWSER_TYPES_LOADED = True
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from code_puppy.callbacks import on_register_browser_types
|
|
38
|
+
|
|
39
|
+
results = on_register_browser_types()
|
|
40
|
+
for result in results:
|
|
41
|
+
if isinstance(result, dict):
|
|
42
|
+
_CUSTOM_BROWSER_TYPES.update(result)
|
|
43
|
+
except Exception:
|
|
44
|
+
pass # Don't break if plugins fail to load
|
|
45
|
+
|
|
18
46
|
# Store active manager instances by session ID
|
|
19
47
|
_active_managers: dict[str, "BrowserManager"] = {}
|
|
20
48
|
|
|
@@ -78,14 +106,19 @@ class BrowserManager:
|
|
|
78
106
|
_context: Optional[BrowserContext] = None
|
|
79
107
|
_initialized: bool = False
|
|
80
108
|
|
|
81
|
-
def __init__(
|
|
109
|
+
def __init__(
|
|
110
|
+
self, session_id: Optional[str] = None, browser_type: Optional[str] = None
|
|
111
|
+
):
|
|
82
112
|
"""Initialize manager settings.
|
|
83
113
|
|
|
84
114
|
Args:
|
|
85
115
|
session_id: Optional session ID for this instance.
|
|
86
116
|
If None, uses 'default' as the session ID.
|
|
117
|
+
browser_type: Optional browser type to use. If None, uses Chromium.
|
|
118
|
+
Custom types can be registered via the register_browser_types hook.
|
|
87
119
|
"""
|
|
88
120
|
self.session_id = session_id or "default"
|
|
121
|
+
self.browser_type = browser_type # None means default Chromium
|
|
89
122
|
|
|
90
123
|
# Default to headless=True (no browser spam during tests)
|
|
91
124
|
# Override with BROWSER_HEADLESS=false to see the browser
|
|
@@ -124,7 +157,27 @@ class BrowserManager:
|
|
|
124
157
|
raise
|
|
125
158
|
|
|
126
159
|
async def _initialize_browser(self) -> None:
|
|
127
|
-
"""Initialize
|
|
160
|
+
"""Initialize browser with persistent context.
|
|
161
|
+
|
|
162
|
+
Checks for custom browser types registered via plugins first,
|
|
163
|
+
then falls back to default Playwright Chromium.
|
|
164
|
+
"""
|
|
165
|
+
# Load plugin browser types on first initialization
|
|
166
|
+
_load_plugin_browser_types()
|
|
167
|
+
|
|
168
|
+
# Check if a custom browser type was requested and is available
|
|
169
|
+
if self.browser_type and self.browser_type in _CUSTOM_BROWSER_TYPES:
|
|
170
|
+
emit_info(
|
|
171
|
+
f"Using custom browser type '{self.browser_type}' "
|
|
172
|
+
f"(session: {self.session_id})"
|
|
173
|
+
)
|
|
174
|
+
init_func = _CUSTOM_BROWSER_TYPES[self.browser_type]
|
|
175
|
+
# Custom init functions should set self._context and self._browser
|
|
176
|
+
await init_func(self)
|
|
177
|
+
self._initialized = True
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
# Default: use Playwright Chromium
|
|
128
181
|
from playwright.async_api import async_playwright
|
|
129
182
|
|
|
130
183
|
emit_info(f"Using persistent profile: {self.profile_dir}")
|
|
@@ -220,13 +273,18 @@ class BrowserManager:
|
|
|
220
273
|
emit_info(f"Browser closed (session: {self.session_id})")
|
|
221
274
|
|
|
222
275
|
|
|
223
|
-
def get_browser_manager(
|
|
276
|
+
def get_browser_manager(
|
|
277
|
+
session_id: Optional[str] = None, browser_type: Optional[str] = None
|
|
278
|
+
) -> BrowserManager:
|
|
224
279
|
"""Get or create a BrowserManager instance.
|
|
225
280
|
|
|
226
281
|
Args:
|
|
227
282
|
session_id: Optional session ID. If provided and a manager with this
|
|
228
283
|
session exists, returns that manager. Otherwise creates a new one.
|
|
229
284
|
If None, uses 'default' as the session ID.
|
|
285
|
+
browser_type: Optional browser type to use for new managers.
|
|
286
|
+
Ignored if a manager for this session already exists.
|
|
287
|
+
Custom types can be registered via the register_browser_types hook.
|
|
230
288
|
|
|
231
289
|
Returns:
|
|
232
290
|
A BrowserManager instance.
|
|
@@ -237,11 +295,14 @@ def get_browser_manager(session_id: Optional[str] = None) -> BrowserManager:
|
|
|
237
295
|
|
|
238
296
|
# Named session (for multi-agent use)
|
|
239
297
|
manager = get_browser_manager("qa-agent-1")
|
|
298
|
+
|
|
299
|
+
# Custom browser type (e.g., stealth browser from plugin)
|
|
300
|
+
manager = get_browser_manager("stealth-session", browser_type="camoufox")
|
|
240
301
|
"""
|
|
241
302
|
session_id = session_id or "default"
|
|
242
303
|
|
|
243
304
|
if session_id not in _active_managers:
|
|
244
|
-
_active_managers[session_id] = BrowserManager(session_id)
|
|
305
|
+
_active_managers[session_id] = BrowserManager(session_id, browser_type)
|
|
245
306
|
|
|
246
307
|
return _active_managers[session_id]
|
|
247
308
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
code_puppy/__init__.py,sha256=xMPewo9RNHb3yfFNIk5WCbv2cvSPtJOCgK2-GqLbNnU,373
|
|
2
2
|
code_puppy/__main__.py,sha256=pDVssJOWP8A83iFkxMLY9YteHYat0EyWDQqMkKHpWp4,203
|
|
3
|
-
code_puppy/callbacks.py,sha256=
|
|
3
|
+
code_puppy/callbacks.py,sha256=KrIvt3dZemb2wbcLc-Tn1n9g9w2M2m2Blf5fFW4tRu0,19648
|
|
4
4
|
code_puppy/chatgpt_codex_client.py,sha256=upMuAfOhMB7SEpVw4CU4GjgaeZ8X65ri3yNM-dnlmYA,12308
|
|
5
5
|
code_puppy/claude_cache_client.py,sha256=GtwYrxcTe0pE-JGtl1ysR2qskfeE73_x4w7q_u-kR1k,24026
|
|
6
|
-
code_puppy/cli_runner.py,sha256=
|
|
7
|
-
code_puppy/config.py,sha256=
|
|
6
|
+
code_puppy/cli_runner.py,sha256=xgEEbLHhhhFpZHUdnGGTYqmJQYVz1JOUZIYVs6PyiV4,38866
|
|
7
|
+
code_puppy/config.py,sha256=mdup26I0W599y297WuYm2vPRPCtm7Qbwf_DfN90k2A4,56325
|
|
8
8
|
code_puppy/error_logging.py,sha256=a80OILCUtJhexI6a9GM-r5LqIdjvSRzggfgPp2jv1X0,3297
|
|
9
9
|
code_puppy/gemini_code_assist.py,sha256=KGS7sO5OLc83nDF3xxS-QiU6vxW9vcm6hmzilu79Ef8,13867
|
|
10
10
|
code_puppy/gemini_model.py,sha256=UHb5vFC9zrEdFJ-yCN3vNCdp0UxP156BL_fwbnEhaw8,27988
|
|
11
11
|
code_puppy/http_utils.py,sha256=Xel6UyQGO6X_5BlrtPYO1hVXN24aqP72tn5g1uUkluU,11491
|
|
12
12
|
code_puppy/keymap.py,sha256=IvMkTlB_bIqOWpbTpmftkdyjhtD5todXuEIw1zCZ4u0,3584
|
|
13
13
|
code_puppy/main.py,sha256=82r3vZy_XcyEsenLn82BnUusaoyL3Bpm_Th_jKgqecE,273
|
|
14
|
-
code_puppy/model_factory.py,sha256=
|
|
14
|
+
code_puppy/model_factory.py,sha256=CbYlI1dkkUayEZ7D7XG_Ybjd4uvYe39xdjOYcVmqLcI,33935
|
|
15
15
|
code_puppy/model_switching.py,sha256=3IsnSWKHLWzI5d2WDYNg0Xr78BeYNN1WrZuzas-lYJ4,2064
|
|
16
16
|
code_puppy/model_utils.py,sha256=cG1V4fsIOEQIb0W88FyGcsMWNv8SpmRAXN3A7LBEoyE,5116
|
|
17
17
|
code_puppy/models.json,sha256=SC7N2lV1Q8ikXlalRNqABkNvuuL_8fIIk638739-gGY,3319
|
|
@@ -45,7 +45,7 @@ code_puppy/agents/agent_qa_kitten.py,sha256=qvry-1u_CiXi8eRueHTax4OtqsS_mQrtXHsb
|
|
|
45
45
|
code_puppy/agents/agent_security_auditor.py,sha256=SpiYNA0XAsIwBj7S2_EQPRslRUmF_-b89pIJyW7DYtY,12022
|
|
46
46
|
code_puppy/agents/agent_terminal_qa.py,sha256=U-iyP7OBWdAmchW_oUU8k6asH2aignTMmgqqYDyf-ms,10343
|
|
47
47
|
code_puppy/agents/agent_typescript_reviewer.py,sha256=vsnpp98xg6cIoFAEJrRTUM_i4wLEWGm5nJxs6fhHobM,10275
|
|
48
|
-
code_puppy/agents/base_agent.py,sha256=
|
|
48
|
+
code_puppy/agents/base_agent.py,sha256=oc59XiPb7xfuLo70vduxGtjAWGWZd6ZzsV_rsNcsmB4,78924
|
|
49
49
|
code_puppy/agents/event_stream_handler.py,sha256=JttLZJpNADE5HXiXY-GZ6tpwaBeFRODcy34KiquPOvU,14952
|
|
50
50
|
code_puppy/agents/json_agent.py,sha256=FtbZxO8mo563kvXgpgRM4b-c9VA3G3cty7r-O0nBZQk,5690
|
|
51
51
|
code_puppy/agents/prompt_reviewer.py,sha256=JJrJ0m5q0Puxl8vFsyhAbY9ftU9n6c6UxEVdNct1E-Q,5558
|
|
@@ -78,14 +78,14 @@ code_puppy/command_line/colors_menu.py,sha256=AI36z4vicbhwDQkziQZXCfy_F59bJLYs-1
|
|
|
78
78
|
code_puppy/command_line/command_handler.py,sha256=yDR_NAvgwjFKxUuQMY5yzkkihFovDiT24wyKALmJSRU,10969
|
|
79
79
|
code_puppy/command_line/command_registry.py,sha256=qFySsw1g8dol3kgi0p6cXrIDlP11_OhOoaQ5nAadWXg,4416
|
|
80
80
|
code_puppy/command_line/config_commands.py,sha256=uwS7ln0I0w0A3tSSWZEtq7Xgj-VOaGEYLE1CihdQ8ic,25759
|
|
81
|
-
code_puppy/command_line/core_commands.py,sha256=
|
|
81
|
+
code_puppy/command_line/core_commands.py,sha256=l6HWaxPIvVZxZillknNzoWPc4ni6-L79KtLxrgxHbfY,29090
|
|
82
82
|
code_puppy/command_line/diff_menu.py,sha256=tokSiQXv9cWDd7HTBEkKKnxZjwSNyVjpIReXe-K2vL4,24245
|
|
83
83
|
code_puppy/command_line/file_path_completion.py,sha256=gw8NpIxa6GOpczUJRyh7VNZwoXKKn-yvCqit7h2y6Gg,2931
|
|
84
84
|
code_puppy/command_line/load_context_completion.py,sha256=a3JvLDeLLSYxVgTjAdqWzS4spjv6ccCrK2LKZgVJ1IM,2202
|
|
85
85
|
code_puppy/command_line/mcp_completion.py,sha256=eKzW2O7gun7HoHekOW0XVXhNS5J2xCtK7aaWyA8bkZk,6952
|
|
86
86
|
code_puppy/command_line/model_picker_completion.py,sha256=YRudzwGVtIjr02MyeIdmbkDhS00ENjCt9k3nATT3KdM,6143
|
|
87
87
|
code_puppy/command_line/model_settings_menu.py,sha256=1SrhwmiL8fTqaM-frV0mSnssiVvjKfjMNoZAm1ofiYo,33708
|
|
88
|
-
code_puppy/command_line/motd.py,sha256=
|
|
88
|
+
code_puppy/command_line/motd.py,sha256=MMaRdJ9fsGnQ6Q01PPQO9kJaNUPwHbSIZrsIl-AF5pg,3066
|
|
89
89
|
code_puppy/command_line/onboarding_slides.py,sha256=itqAsuHzjHpD_XNz6FniBIYr6dNyP1AW_XQZQ6SbVek,7125
|
|
90
90
|
code_puppy/command_line/onboarding_wizard.py,sha256=mAFmQsPU8N48MGxHXOPBFRz7zeC4otdlqM6MpYVmrrc,10353
|
|
91
91
|
code_puppy/command_line/pin_command_completion.py,sha256=juSvdqRpk7AdfkPy1DJx5NzfEUU5KYGlChvP0hisM18,11667
|
|
@@ -93,6 +93,7 @@ code_puppy/command_line/prompt_toolkit_completion.py,sha256=49GM3jVE89G1M3XroMZk
|
|
|
93
93
|
code_puppy/command_line/session_commands.py,sha256=Jh8GGfhlfBAEVfucKLbcZjNaXYd0twImiOwq2ZnGdQQ,9902
|
|
94
94
|
code_puppy/command_line/uc_menu.py,sha256=DWxcqhHDQtaAmf00VLoG3j7W47lI_sPl1vMnTaNMofI,26141
|
|
95
95
|
code_puppy/command_line/utils.py,sha256=_upMrrmDp5hteUjrRiEgVR6SoeNEPNZGXb5lOWYqcUQ,2952
|
|
96
|
+
code_puppy/command_line/wiggum_state.py,sha256=L64-JF0CFYKyxAUcETeeYQr8_1PO35tkjdrs1YUvi1k,1952
|
|
96
97
|
code_puppy/command_line/mcp/__init__.py,sha256=0-OQuwjq_pLiTVJ1_NrirVwdRerghyKs_MTZkwPC7YY,315
|
|
97
98
|
code_puppy/command_line/mcp/base.py,sha256=pPeNnSyM0GGqD6mhYN-qA22rAT9bEapxliwH_YiIu3Q,823
|
|
98
99
|
code_puppy/command_line/mcp/catalog_server_installer.py,sha256=G9FvQPTBB4LeJ4cOR9DvIkp82mClKRKI35KELbFLCKU,6181
|
|
@@ -130,7 +131,7 @@ code_puppy/mcp_/manager.py,sha256=_2ZRTLS8Sf3SMgEpAHl-wXBDYVqg2l-j9uI9EkfCNaE,31
|
|
|
130
131
|
code_puppy/mcp_/mcp_logs.py,sha256=o4pSHwELWIjEjqhfaMMEGrBvb159-VIgUp21E707BPo,6264
|
|
131
132
|
code_puppy/mcp_/registry.py,sha256=U_t12WQ-En-KGyZoiTYdqlhp9NkDTWafu8g5InvF2NM,15774
|
|
132
133
|
code_puppy/mcp_/retry_manager.py,sha256=evVxbtrsHNyo8UoI7zpO-NVDegibn82RLlgN8VKewA8,10665
|
|
133
|
-
code_puppy/mcp_/server_registry_catalog.py,sha256=
|
|
134
|
+
code_puppy/mcp_/server_registry_catalog.py,sha256=HhWXMsU4xq3zxpzKhV5DvFh7i7Ho30kPkm4XIY6V0tE,39898
|
|
134
135
|
code_puppy/mcp_/status_tracker.py,sha256=uekxrzkzIWrv3OfSVgblaPuoGFcAh_dBYwCcaHZ_CrM,12183
|
|
135
136
|
code_puppy/mcp_/system_tools.py,sha256=7_oR8k0c8YjtCcYF9g7A946oAGuKOf_i-92aJH7VmlQ,7331
|
|
136
137
|
code_puppy/mcp_/examples/retry_example.py,sha256=Qi5K6cNmhc5-zncZa0F_dkJUEdZ6OIgt1xfG5PUxt3Q,7234
|
|
@@ -184,14 +185,6 @@ code_puppy/plugins/file_permission_handler/register_callbacks.py,sha256=QlUqENkb
|
|
|
184
185
|
code_puppy/plugins/frontend_emitter/__init__.py,sha256=4_o6anYxDpJGvKyMomRy4FfLXZx6VOLnX0PcZIL-fws,661
|
|
185
186
|
code_puppy/plugins/frontend_emitter/emitter.py,sha256=GNcnoKLPAjrD_see82nuRutZEHxXwb2aUEKR4K8TJvQ,3787
|
|
186
187
|
code_puppy/plugins/frontend_emitter/register_callbacks.py,sha256=3j7Emn3VeWSJSN9ozZ_Z78ZU8JvN7yfJNQ4bSH2KGdE,7704
|
|
187
|
-
code_puppy/plugins/ralph/__init__.py,sha256=drPRgJ2LGLh8v_8dk7TJIklv-51XHjqW7SMfNTzwiGI,448
|
|
188
|
-
code_puppy/plugins/ralph/agents.py,sha256=EQ2pvb8tb8aFfYZYtBuo9rBIvVp18XCieeK5PRvH3K4,11914
|
|
189
|
-
code_puppy/plugins/ralph/commands.py,sha256=J1sVNrm4SBj_ujkO51ILWzdH5L3px6NPR_mn0mXD_FQ,6736
|
|
190
|
-
code_puppy/plugins/ralph/loop_controller.py,sha256=uhEOKpmkxlfj5MK6_zVvSHH9D79JRx4RRkNtBkrBkNk,10107
|
|
191
|
-
code_puppy/plugins/ralph/models.py,sha256=IrAJW85CgKA6yYSrWRn3VHx_65ukFkrasUhbVM1emF0,3983
|
|
192
|
-
code_puppy/plugins/ralph/register_callbacks.py,sha256=_q1SILAYc8BHyWpXZoA8MOVsLCFnOvQ3vU8PzjfzZxc,4429
|
|
193
|
-
code_puppy/plugins/ralph/state_manager.py,sha256=jv7bnQBiy_XQTj7Kfl3zBIMLV3XN5U-IS_U-fIdpHe0,10215
|
|
194
|
-
code_puppy/plugins/ralph/tools.py,sha256=p767ZdjkeRmfWTqUYdFmXnKEHC15ek1Ho3tkLcjWb20,14391
|
|
195
188
|
code_puppy/plugins/shell_safety/__init__.py,sha256=B-RYLWKlvrws9XCHG1Z99mBMC3VC394HAlMOhhCoGGI,243
|
|
196
189
|
code_puppy/plugins/shell_safety/agent_shell_safety.py,sha256=5JutYlzzTzyFcbFujlNkV4NunVvD5QIpOSumjS3Fjc8,2408
|
|
197
190
|
code_puppy/plugins/shell_safety/command_cache.py,sha256=adYtSPNVOZfW_6dQdtEihO6E-JYXYrdvlS1Cl7xBkDU,4546
|
|
@@ -216,7 +209,7 @@ code_puppy/tools/browser/__init__.py,sha256=Mu6zvTQHdKcEh3ttwNgjiKtaKjVkNQ4ncpQ0
|
|
|
216
209
|
code_puppy/tools/browser/browser_control.py,sha256=qul611bbXteH3pBoN39AystbYr3ZXkCs9mbjobir5Io,8429
|
|
217
210
|
code_puppy/tools/browser/browser_interactions.py,sha256=toroY2hDVDaNN9g6UV-vJ5IA1htaf_Pk85Z7PXwpMm4,16774
|
|
218
211
|
code_puppy/tools/browser/browser_locators.py,sha256=--cYu5pi1nvVh673fFCV2GSOJ5XuAUHvyPpPJREOx7s,19176
|
|
219
|
-
code_puppy/tools/browser/browser_manager.py,sha256=
|
|
212
|
+
code_puppy/tools/browser/browser_manager.py,sha256=9R6Qd9rjoIWPAnfLu_0ljplO--2YYGRTj_C6vW_UwJ8,12845
|
|
220
213
|
code_puppy/tools/browser/browser_navigation.py,sha256=MbfIL6UNs79ImbCli1854_ftwqLke37jhwQzfcA0Zag,7415
|
|
221
214
|
code_puppy/tools/browser/browser_screenshot.py,sha256=YT35iJc9SfFI8PiIfskyehDFpk1YfJ1K6lFwrzRwkH8,6281
|
|
222
215
|
code_puppy/tools/browser/browser_scripts.py,sha256=swQLuD61mwE3uFghOZmSSJXggg5ZIPKHqKu-KvdY49Y,14778
|
|
@@ -225,10 +218,10 @@ code_puppy/tools/browser/chromium_terminal_manager.py,sha256=w1thQ_ACb6oV45L93TS
|
|
|
225
218
|
code_puppy/tools/browser/terminal_command_tools.py,sha256=9byOZku-dwvTtCl532xt7Lumed_jTn0sLvUe_X75XCQ,19068
|
|
226
219
|
code_puppy/tools/browser/terminal_screenshot_tools.py,sha256=J_21YO_495NvYgNFu9KQP6VYg2K_f8CtSdZuF94Yhnw,18448
|
|
227
220
|
code_puppy/tools/browser/terminal_tools.py,sha256=F5LjVH3udSCFHmqC3O1UJLoLozZFZsEdX42jOmkqkW0,17853
|
|
228
|
-
code_puppy-0.0.
|
|
229
|
-
code_puppy-0.0.
|
|
230
|
-
code_puppy-0.0.
|
|
231
|
-
code_puppy-0.0.
|
|
232
|
-
code_puppy-0.0.
|
|
233
|
-
code_puppy-0.0.
|
|
234
|
-
code_puppy-0.0.
|
|
221
|
+
code_puppy-0.0.381.data/data/code_puppy/models.json,sha256=SC7N2lV1Q8ikXlalRNqABkNvuuL_8fIIk638739-gGY,3319
|
|
222
|
+
code_puppy-0.0.381.data/data/code_puppy/models_dev_api.json,sha256=wHjkj-IM_fx1oHki6-GqtOoCrRMR0ScK0f-Iz0UEcy8,548187
|
|
223
|
+
code_puppy-0.0.381.dist-info/METADATA,sha256=sLQPLb3yvsL_sAhHULeuWoH9A5Ydkk6zKa0Us_vKWuU,27604
|
|
224
|
+
code_puppy-0.0.381.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
225
|
+
code_puppy-0.0.381.dist-info/entry_points.txt,sha256=Tp4eQC99WY3HOKd3sdvb22vZODRq0XkZVNpXOag_KdI,91
|
|
226
|
+
code_puppy-0.0.381.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
|
|
227
|
+
code_puppy-0.0.381.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"""Ralph Plugin - Autonomous AI agent loop for completing PRDs.
|
|
2
|
-
|
|
3
|
-
Based on Geoffrey Huntley's Ralph pattern: https://ghuntley.com/ralph/
|
|
4
|
-
|
|
5
|
-
This plugin provides:
|
|
6
|
-
- PRD Generator agent for creating detailed requirements
|
|
7
|
-
- Ralph Converter agent for converting PRDs to JSON format
|
|
8
|
-
- Ralph Orchestrator agent for autonomous execution
|
|
9
|
-
- Tools for managing prd.json and progress.txt
|
|
10
|
-
- /ralph commands for controlling the workflow
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
__version__ = "0.1.0"
|
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
"""Ralph plugin agents - registered via the register_agents callback."""
|
|
2
|
-
|
|
3
|
-
from typing import Any, Dict, List
|
|
4
|
-
|
|
5
|
-
from code_puppy.agents.base_agent import BaseAgent
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class RalphPRDGeneratorAgent(BaseAgent):
|
|
9
|
-
"""Agent for creating Product Requirements Documents."""
|
|
10
|
-
|
|
11
|
-
@property
|
|
12
|
-
def name(self) -> str:
|
|
13
|
-
return "ralph-prd-generator"
|
|
14
|
-
|
|
15
|
-
@property
|
|
16
|
-
def display_name(self) -> str:
|
|
17
|
-
return "Ralph PRD Generator 📋"
|
|
18
|
-
|
|
19
|
-
@property
|
|
20
|
-
def description(self) -> str:
|
|
21
|
-
return "Creates detailed Product Requirements Documents with user stories"
|
|
22
|
-
|
|
23
|
-
def get_available_tools(self) -> List[str]:
|
|
24
|
-
return [
|
|
25
|
-
"list_files",
|
|
26
|
-
"read_file",
|
|
27
|
-
"edit_file",
|
|
28
|
-
"agent_share_your_reasoning",
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
def get_system_prompt(self) -> str:
|
|
32
|
-
return """You are a PRD (Product Requirements Document) Generator, part of the Ralph autonomous agent system.
|
|
33
|
-
|
|
34
|
-
## Your Job
|
|
35
|
-
|
|
36
|
-
Help users create detailed, well-structured PRDs that can be converted to Ralph's prd.json format for autonomous execution.
|
|
37
|
-
|
|
38
|
-
## Process
|
|
39
|
-
|
|
40
|
-
### Step 1: Clarifying Questions
|
|
41
|
-
Ask 3-5 essential questions with LETTERED OPTIONS so users can respond quickly (e.g., "1A, 2C, 3B"):
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
1. What is the primary goal?
|
|
45
|
-
A. Option 1
|
|
46
|
-
B. Option 2
|
|
47
|
-
C. Other: [specify]
|
|
48
|
-
|
|
49
|
-
2. Who is the target user?
|
|
50
|
-
A. All users
|
|
51
|
-
B. Admin only
|
|
52
|
-
C. New users only
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Step 2: Generate PRD
|
|
56
|
-
|
|
57
|
-
After getting answers, create a PRD with these sections:
|
|
58
|
-
|
|
59
|
-
```markdown
|
|
60
|
-
# PRD: [Feature Name]
|
|
61
|
-
|
|
62
|
-
## Introduction
|
|
63
|
-
Brief description of the feature and problem it solves.
|
|
64
|
-
|
|
65
|
-
## Goals
|
|
66
|
-
- Specific, measurable objective 1
|
|
67
|
-
- Specific, measurable objective 2
|
|
68
|
-
|
|
69
|
-
## User Stories
|
|
70
|
-
|
|
71
|
-
### US-001: [Title]
|
|
72
|
-
**Description:** As a [user], I want [feature] so that [benefit].
|
|
73
|
-
|
|
74
|
-
**Acceptance Criteria:**
|
|
75
|
-
- [ ] Specific verifiable criterion
|
|
76
|
-
- [ ] Another criterion
|
|
77
|
-
- [ ] Typecheck passes
|
|
78
|
-
- [ ] [For UI stories] Verify in browser using qa-kitten
|
|
79
|
-
|
|
80
|
-
### US-002: [Title]
|
|
81
|
-
...
|
|
82
|
-
|
|
83
|
-
## Functional Requirements
|
|
84
|
-
- FR-1: The system must...
|
|
85
|
-
- FR-2: When user clicks X, the system must...
|
|
86
|
-
|
|
87
|
-
## Non-Goals (Out of Scope)
|
|
88
|
-
- What this feature will NOT include
|
|
89
|
-
|
|
90
|
-
## Technical Considerations
|
|
91
|
-
- Known constraints or dependencies
|
|
92
|
-
- Integration points
|
|
93
|
-
|
|
94
|
-
## How to Test
|
|
95
|
-
Describe how to verify this feature works:
|
|
96
|
-
- Command to run (e.g., `python main.py --feature`)
|
|
97
|
-
- API endpoints to test (e.g., `curl http://localhost:8000/api/...`)
|
|
98
|
-
- URL to visit for UI features (e.g., `http://localhost:3000/dashboard`)
|
|
99
|
-
- Expected behavior or output
|
|
100
|
-
|
|
101
|
-
## Success Metrics
|
|
102
|
-
- How success will be measured
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## CRITICAL: Story Sizing
|
|
106
|
-
|
|
107
|
-
Each story must be completable in ONE iteration (one context window). Right-sized:
|
|
108
|
-
- Add a database column and migration
|
|
109
|
-
- Add a UI component to an existing page
|
|
110
|
-
- Update a server action with new logic
|
|
111
|
-
|
|
112
|
-
TOO BIG (split these):
|
|
113
|
-
- "Build the entire dashboard" → Split into schema, queries, components
|
|
114
|
-
- "Add authentication" → Split into schema, middleware, login UI, session
|
|
115
|
-
|
|
116
|
-
**Rule of thumb:** If you can't describe the change in 2-3 sentences, it's too big.
|
|
117
|
-
|
|
118
|
-
## Acceptance Criteria Rules
|
|
119
|
-
|
|
120
|
-
Criteria must be VERIFIABLE, not vague:
|
|
121
|
-
- ✅ "Button shows confirmation dialog before deleting"
|
|
122
|
-
- ✅ "Filter dropdown has options: All, Active, Completed"
|
|
123
|
-
- ❌ "Works correctly"
|
|
124
|
-
- ❌ "Good UX"
|
|
125
|
-
|
|
126
|
-
Always include:
|
|
127
|
-
- "Typecheck passes" for all stories
|
|
128
|
-
- "Verify in browser using qa-kitten" for UI stories
|
|
129
|
-
|
|
130
|
-
## How to Test Section
|
|
131
|
-
|
|
132
|
-
ALWAYS include a "How to Test" section that tells Ralph exactly how to verify the feature:
|
|
133
|
-
|
|
134
|
-
**Good examples:**
|
|
135
|
-
```markdown
|
|
136
|
-
## How to Test
|
|
137
|
-
1. Run `python -m pytest tests/test_auth.py` - all tests should pass
|
|
138
|
-
2. Start the server with `python manage.py runserver`
|
|
139
|
-
3. Visit http://localhost:8000/login and verify the login form appears
|
|
140
|
-
4. Try logging in with test@example.com / password123
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**Bad examples:**
|
|
144
|
-
- "Test that it works" (too vague)
|
|
145
|
-
- "Verify the feature" (no specific steps)
|
|
146
|
-
|
|
147
|
-
## Output
|
|
148
|
-
|
|
149
|
-
Save the PRD to `tasks/prd-[feature-name].md` using the edit_file tool.
|
|
150
|
-
|
|
151
|
-
After creating the PRD, tell the user to run `/ralph convert` to convert it to prd.json format.
|
|
152
|
-
"""
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
class RalphConverterAgent(BaseAgent):
|
|
156
|
-
"""Agent for converting PRDs to prd.json format."""
|
|
157
|
-
|
|
158
|
-
@property
|
|
159
|
-
def name(self) -> str:
|
|
160
|
-
return "ralph-converter"
|
|
161
|
-
|
|
162
|
-
@property
|
|
163
|
-
def display_name(self) -> str:
|
|
164
|
-
return "Ralph Converter 🔄"
|
|
165
|
-
|
|
166
|
-
@property
|
|
167
|
-
def description(self) -> str:
|
|
168
|
-
return "Converts markdown PRDs to prd.json format for Ralph execution"
|
|
169
|
-
|
|
170
|
-
def get_available_tools(self) -> List[str]:
|
|
171
|
-
return [
|
|
172
|
-
"list_files",
|
|
173
|
-
"read_file",
|
|
174
|
-
"edit_file",
|
|
175
|
-
"agent_share_your_reasoning",
|
|
176
|
-
]
|
|
177
|
-
|
|
178
|
-
def get_system_prompt(self) -> str:
|
|
179
|
-
return """You are the Ralph Converter, responsible for converting markdown PRDs to prd.json format.
|
|
180
|
-
|
|
181
|
-
## Your Job
|
|
182
|
-
|
|
183
|
-
Take a PRD (markdown file or text) and convert it to the prd.json format that Ralph uses for autonomous execution.
|
|
184
|
-
|
|
185
|
-
## Output Format
|
|
186
|
-
|
|
187
|
-
```json
|
|
188
|
-
{
|
|
189
|
-
"project": "[Project Name]",
|
|
190
|
-
"branchName": "ralph/[feature-name-kebab-case]",
|
|
191
|
-
"description": "[Feature description]",
|
|
192
|
-
"userStories": [
|
|
193
|
-
{
|
|
194
|
-
"id": "US-001",
|
|
195
|
-
"title": "[Story title]",
|
|
196
|
-
"description": "As a [user], I want [feature] so that [benefit]",
|
|
197
|
-
"acceptanceCriteria": [
|
|
198
|
-
"Criterion 1",
|
|
199
|
-
"Criterion 2",
|
|
200
|
-
"Typecheck passes"
|
|
201
|
-
],
|
|
202
|
-
"priority": 1,
|
|
203
|
-
"passes": false,
|
|
204
|
-
"notes": ""
|
|
205
|
-
}
|
|
206
|
-
]
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## Conversion Rules
|
|
211
|
-
|
|
212
|
-
1. **Story IDs**: Sequential (US-001, US-002, etc.)
|
|
213
|
-
2. **Priority**: Based on dependency order, then document order (1 = highest)
|
|
214
|
-
3. **All stories**: `passes: false` and empty `notes`
|
|
215
|
-
4. **branchName**: Derive from feature name, kebab-case, prefixed with `ralph/`
|
|
216
|
-
|
|
217
|
-
## Story Ordering (CRITICAL)
|
|
218
|
-
|
|
219
|
-
Order by dependency - earlier stories must NOT depend on later ones:
|
|
220
|
-
1. Schema/database changes (migrations)
|
|
221
|
-
2. Server actions / backend logic
|
|
222
|
-
3. UI components that use the backend
|
|
223
|
-
4. Dashboard/summary views that aggregate
|
|
224
|
-
|
|
225
|
-
## Story Size Validation
|
|
226
|
-
|
|
227
|
-
Each story must be completable in ONE iteration. If a story is too big, SPLIT IT:
|
|
228
|
-
|
|
229
|
-
TOO BIG: "Add user notification system"
|
|
230
|
-
|
|
231
|
-
SPLIT INTO:
|
|
232
|
-
- US-001: Add notifications table to database
|
|
233
|
-
- US-002: Create notification service
|
|
234
|
-
- US-003: Add notification bell icon to header
|
|
235
|
-
- US-004: Create notification dropdown panel
|
|
236
|
-
- US-005: Add mark-as-read functionality
|
|
237
|
-
|
|
238
|
-
## Acceptance Criteria Requirements
|
|
239
|
-
|
|
240
|
-
ALWAYS add these criteria:
|
|
241
|
-
- "Typecheck passes" → ALL stories
|
|
242
|
-
- "Verify in browser using qa-kitten" → UI stories only
|
|
243
|
-
|
|
244
|
-
## Process
|
|
245
|
-
|
|
246
|
-
1. Read the PRD file (ask for path if not provided)
|
|
247
|
-
2. Extract user stories and requirements
|
|
248
|
-
3. Validate story sizes (split if needed)
|
|
249
|
-
4. Order by dependencies
|
|
250
|
-
5. Generate prd.json
|
|
251
|
-
6. Save to `prd.json` in the current directory
|
|
252
|
-
|
|
253
|
-
After saving, tell the user to run `/ralph start` to begin autonomous execution.
|
|
254
|
-
"""
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
class RalphOrchestratorAgent(BaseAgent):
|
|
258
|
-
"""Agent for orchestrating the autonomous Ralph loop."""
|
|
259
|
-
|
|
260
|
-
@property
|
|
261
|
-
def name(self) -> str:
|
|
262
|
-
return "ralph-orchestrator"
|
|
263
|
-
|
|
264
|
-
@property
|
|
265
|
-
def display_name(self) -> str:
|
|
266
|
-
return "Ralph Orchestrator 🐺"
|
|
267
|
-
|
|
268
|
-
@property
|
|
269
|
-
def description(self) -> str:
|
|
270
|
-
return "Orchestrates the autonomous Ralph loop, implementing stories one by one"
|
|
271
|
-
|
|
272
|
-
def get_available_tools(self) -> List[str]:
|
|
273
|
-
return [
|
|
274
|
-
# Ralph-specific tools
|
|
275
|
-
"ralph_get_current_story",
|
|
276
|
-
"ralph_mark_story_complete",
|
|
277
|
-
"ralph_log_progress",
|
|
278
|
-
"ralph_check_all_complete",
|
|
279
|
-
"ralph_read_prd",
|
|
280
|
-
"ralph_read_patterns",
|
|
281
|
-
"ralph_add_pattern",
|
|
282
|
-
# Standard coding tools
|
|
283
|
-
"list_files",
|
|
284
|
-
"read_file",
|
|
285
|
-
"edit_file",
|
|
286
|
-
"delete_file",
|
|
287
|
-
"grep",
|
|
288
|
-
"agent_run_shell_command",
|
|
289
|
-
"agent_share_your_reasoning",
|
|
290
|
-
# Sub-agent tools for delegation
|
|
291
|
-
"list_agents",
|
|
292
|
-
"invoke_agent",
|
|
293
|
-
]
|
|
294
|
-
|
|
295
|
-
def get_system_prompt(self) -> str:
|
|
296
|
-
return """You are the Ralph Orchestrator 🐺, an autonomous coding agent that implements PRD user stories one at a time.
|
|
297
|
-
|
|
298
|
-
## Your Mission
|
|
299
|
-
|
|
300
|
-
Execute user stories from prd.json until ALL stories have `passes: true`.
|
|
301
|
-
|
|
302
|
-
## CRITICAL WORKFLOW
|
|
303
|
-
|
|
304
|
-
For EACH iteration:
|
|
305
|
-
|
|
306
|
-
### 1. READ CONTEXT FIRST
|
|
307
|
-
```
|
|
308
|
-
- Call ralph_read_patterns() to get codebase patterns
|
|
309
|
-
- Call ralph_get_current_story() to get the next story
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
### 2. CHECK FOR COMPLETION
|
|
313
|
-
If `all_complete: true`, output this EXACT text:
|
|
314
|
-
```
|
|
315
|
-
<promise>COMPLETE</promise>
|
|
316
|
-
```
|
|
317
|
-
Then STOP. Do not continue.
|
|
318
|
-
|
|
319
|
-
### 3. IMPLEMENT THE STORY
|
|
320
|
-
- Understand the acceptance criteria
|
|
321
|
-
- Explore relevant code with list_files and read_file
|
|
322
|
-
- Make changes with edit_file
|
|
323
|
-
- Keep changes focused and minimal
|
|
324
|
-
|
|
325
|
-
### 4. VERIFY THE IMPLEMENTATION WORKS
|
|
326
|
-
|
|
327
|
-
**You MUST test your implementation before committing.** The PRD acceptance criteria should guide you, but use your judgment.
|
|
328
|
-
|
|
329
|
-
#### For CLI/Backend Programs:
|
|
330
|
-
```bash
|
|
331
|
-
# Run the program directly
|
|
332
|
-
python main.py --help
|
|
333
|
-
./my_program test_input.txt
|
|
334
|
-
|
|
335
|
-
# Check exit codes
|
|
336
|
-
echo $?
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
#### For Backend Web Services (APIs):
|
|
340
|
-
```bash
|
|
341
|
-
# Test endpoints with curl
|
|
342
|
-
curl -X GET http://localhost:8000/api/endpoint
|
|
343
|
-
curl -X POST http://localhost:8000/api/resource -d '{"key": "value"}'
|
|
344
|
-
|
|
345
|
-
# Verify responses are correct
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
#### For Frontend Websites (UI stories):
|
|
349
|
-
Invoke the **qa-kitten** agent for browser-based verification:
|
|
350
|
-
```
|
|
351
|
-
invoke_agent("qa-kitten", "Navigate to http://localhost:3000 and verify: [acceptance criteria]. Take a screenshot and confirm the feature works.")
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
#### For TUI (Terminal UI) Applications:
|
|
355
|
-
Invoke the **terminal-qa** agent for terminal-based verification:
|
|
356
|
-
```
|
|
357
|
-
invoke_agent("terminal-qa", "Run the TUI application with 'python app.py' and verify: [acceptance criteria]. Take a screenshot and confirm the interface works.")
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
#### General Testing Guidelines:
|
|
361
|
-
- If the PRD specifies how to test → follow it exactly
|
|
362
|
-
- If not specified → improvise appropriate tests based on the feature type
|
|
363
|
-
- For code changes → at minimum run typecheck/linter
|
|
364
|
-
- For new features → actually exercise the feature, don't just assume it works
|
|
365
|
-
- **Don't skip testing** - untested code often has bugs!
|
|
366
|
-
|
|
367
|
-
### 5. COMMIT CHANGES
|
|
368
|
-
```bash
|
|
369
|
-
git add -A
|
|
370
|
-
git commit -m "feat: [Story ID] - [Story Title]"
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### 6. MARK COMPLETE & LOG
|
|
374
|
-
```
|
|
375
|
-
ralph_mark_story_complete(story_id, notes)
|
|
376
|
-
ralph_log_progress(story_id, summary, files_changed, learnings)
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
If you discovered reusable patterns, add them:
|
|
380
|
-
```
|
|
381
|
-
ralph_add_pattern("Use X pattern for Y")
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
### 7. CHECK IF ALL DONE
|
|
385
|
-
```
|
|
386
|
-
ralph_check_all_complete()
|
|
387
|
-
```
|
|
388
|
-
If all complete, output `<promise>COMPLETE</promise>` and STOP.
|
|
389
|
-
|
|
390
|
-
## RULES
|
|
391
|
-
|
|
392
|
-
1. **ONE story per iteration** - Don't try to do multiple
|
|
393
|
-
2. **Read patterns FIRST** - Learn from previous iterations
|
|
394
|
-
3. **VERIFY BEFORE COMMIT** - Never commit untested code
|
|
395
|
-
4. **Actually run the code** - Don't just assume it works
|
|
396
|
-
5. **Keep changes minimal** - Don't refactor unrelated code
|
|
397
|
-
6. **Log learnings** - Help future iterations succeed
|
|
398
|
-
|
|
399
|
-
## COMPLETION SIGNAL
|
|
400
|
-
|
|
401
|
-
When ALL stories are done, you MUST output:
|
|
402
|
-
```
|
|
403
|
-
<promise>COMPLETE</promise>
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
## ERROR HANDLING
|
|
407
|
-
|
|
408
|
-
If verification fails:
|
|
409
|
-
1. Read the error message carefully
|
|
410
|
-
2. Fix the code
|
|
411
|
-
3. Re-run verification
|
|
412
|
-
4. Only proceed when verification passes
|
|
413
|
-
|
|
414
|
-
If truly stuck after 3 attempts:
|
|
415
|
-
1. Log detailed notes about the issue
|
|
416
|
-
2. Mark story with notes explaining the blocker
|
|
417
|
-
3. Move on (but this should be rare!)
|
|
418
|
-
|
|
419
|
-
Now, let's get to work! Start by reading patterns and getting the current story.
|
|
420
|
-
"""
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
def get_ralph_agents() -> List[Dict[str, Any]]:
|
|
424
|
-
"""Get all Ralph agents for registration via the register_agents callback.
|
|
425
|
-
|
|
426
|
-
Returns:
|
|
427
|
-
List of agent definitions with name and class.
|
|
428
|
-
"""
|
|
429
|
-
return [
|
|
430
|
-
{"name": "ralph-prd-generator", "class": RalphPRDGeneratorAgent},
|
|
431
|
-
{"name": "ralph-converter", "class": RalphConverterAgent},
|
|
432
|
-
{"name": "ralph-orchestrator", "class": RalphOrchestratorAgent},
|
|
433
|
-
]
|