code-puppy 0.0.325__py3-none-any.whl → 0.0.327__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.
@@ -4,7 +4,6 @@ import asyncio
4
4
  import json
5
5
  import math
6
6
  import signal
7
- import sys
8
7
  import threading
9
8
  import uuid
10
9
  from abc import ABC, abstractmethod
@@ -1957,69 +1956,27 @@ class BaseAgent(ABC):
1957
1956
  from code_puppy.keymap import get_cancel_agent_display_name
1958
1957
 
1959
1958
  cancel_key = get_cancel_agent_display_name()
1960
- if sys.platform == "win32":
1961
- # On Windows, we use keyboard listener, so SIGINT might still fire
1962
- # but we handle cancellation via the key listener
1963
- pass # Silent on Windows - the key listener handles it
1964
- else:
1965
- emit_info(f"Use {cancel_key} to cancel the agent task.")
1959
+ emit_info(f"Use {cancel_key} to cancel the agent task.")
1966
1960
 
1967
1961
  original_handler = None
1968
1962
  key_listener_stop_event = None
1969
1963
  _key_listener_thread = None
1970
- _windows_ctrl_handler = None # Store reference to prevent garbage collection
1971
1964
 
1972
1965
  try:
1973
- if sys.platform == "win32":
1974
- # Windows: Use SetConsoleCtrlHandler for reliable Ctrl+C handling
1975
- import ctypes
1976
-
1977
- # Define the handler function type
1978
- HANDLER_ROUTINE = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_ulong)
1979
-
1980
- def windows_ctrl_handler(ctrl_type):
1981
- """Handle Windows console control events."""
1982
- CTRL_C_EVENT = 0
1983
- CTRL_BREAK_EVENT = 1
1984
-
1985
- if ctrl_type in (CTRL_C_EVENT, CTRL_BREAK_EVENT):
1986
- # Check if we're awaiting user input
1987
- if is_awaiting_user_input():
1988
- return False # Let default handler run
1989
-
1990
- # Schedule agent cancellation
1991
- schedule_agent_cancel()
1992
- return True # We handled it, don't terminate
1993
-
1994
- return False # Let other handlers process it
1995
-
1996
- # Create the callback - must keep reference alive!
1997
- _windows_ctrl_handler = HANDLER_ROUTINE(windows_ctrl_handler)
1998
-
1999
- # Register the handler
2000
- kernel32 = ctypes.windll.kernel32
2001
- if not kernel32.SetConsoleCtrlHandler(_windows_ctrl_handler, True):
2002
- emit_warning("Failed to set Windows Ctrl+C handler")
2003
-
2004
- # Also spawn keyboard listener for Ctrl+X (shell cancel) and other keys
2005
- key_listener_stop_event = threading.Event()
2006
- _key_listener_thread = self._spawn_ctrl_x_key_listener(
2007
- key_listener_stop_event,
2008
- on_escape=lambda: None, # Ctrl+X handled by command_runner
2009
- on_cancel_agent=None, # Ctrl+C handled by SetConsoleCtrlHandler above
2010
- )
2011
- elif cancel_agent_uses_signal():
2012
- # Unix with Ctrl+C: Use SIGINT-based cancellation
1966
+ if cancel_agent_uses_signal():
1967
+ # Use SIGINT-based cancellation (default Ctrl+C behavior)
2013
1968
  original_handler = signal.signal(
2014
1969
  signal.SIGINT, keyboard_interrupt_handler
2015
1970
  )
2016
1971
  else:
2017
- # Unix with different cancel key: Use keyboard listener
1972
+ # Use keyboard listener for agent cancellation
1973
+ # Set a graceful SIGINT handler that shows a hint
2018
1974
  original_handler = signal.signal(signal.SIGINT, graceful_sigint_handler)
1975
+ # Spawn keyboard listener with the cancel agent callback
2019
1976
  key_listener_stop_event = threading.Event()
2020
1977
  _key_listener_thread = self._spawn_ctrl_x_key_listener(
2021
1978
  key_listener_stop_event,
2022
- on_escape=lambda: None,
1979
+ on_escape=lambda: None, # Ctrl+X handled by command_runner
2023
1980
  on_cancel_agent=schedule_agent_cancel,
2024
1981
  )
2025
1982
 
@@ -2044,17 +2001,8 @@ class BaseAgent(ABC):
2044
2001
  # Stop keyboard listener if it was started
2045
2002
  if key_listener_stop_event is not None:
2046
2003
  key_listener_stop_event.set()
2047
-
2048
- # Unregister Windows Ctrl handler
2049
- if sys.platform == "win32" and _windows_ctrl_handler is not None:
2050
- try:
2051
- import ctypes
2052
-
2053
- kernel32 = ctypes.windll.kernel32
2054
- kernel32.SetConsoleCtrlHandler(_windows_ctrl_handler, False)
2055
- except Exception:
2056
- pass # Best effort cleanup
2057
-
2058
- # Restore original signal handler (Unix)
2059
- if original_handler is not None:
2004
+ # Restore original signal handler
2005
+ if (
2006
+ original_handler is not None
2007
+ ): # Explicit None check - SIG_DFL can be 0/falsy!
2060
2008
  signal.signal(signal.SIGINT, original_handler)
code_puppy/cli_runner.py CHANGED
@@ -790,6 +790,5 @@ def main_entry():
790
790
  DBOS.destroy()
791
791
  return 0
792
792
  finally:
793
- # Reset terminal on all platforms for clean state
794
- reset_windows_terminal_full() # Safe no-op on non-Windows
793
+ # Reset terminal on Unix-like systems (not Windows)
795
794
  reset_unix_terminal()
@@ -46,6 +46,7 @@ def handle_show_command(command: str) -> bool:
46
46
  get_use_dbos,
47
47
  get_yolo_mode,
48
48
  )
49
+ from code_puppy.keymap import get_cancel_agent_key, get_cancel_agent_display_name
49
50
  from code_puppy.messaging import emit_info
50
51
 
51
52
  puppy_name = get_puppy_name()
@@ -79,6 +80,7 @@ def handle_show_command(command: str) -> bool:
79
80
  [bold]reasoning_effort:[/bold] [cyan]{get_openai_reasoning_effort()}[/cyan]
80
81
  [bold]verbosity:[/bold] [cyan]{get_openai_verbosity()}[/cyan]
81
82
  [bold]temperature:[/bold] [cyan]{effective_temperature if effective_temperature is not None else "(model default)"}[/cyan]{" (per-model)" if effective_temperature != global_temperature and effective_temperature is not None else ""}
83
+ [bold]cancel_agent_key:[/bold] [cyan]{get_cancel_agent_display_name()}[/cyan] (options: ctrl+c, ctrl+k, ctrl+q)
82
84
 
83
85
  """
84
86
  emit_info(Text.from_markup(status_msg))
@@ -200,9 +202,13 @@ def handle_set_command(command: str) -> bool:
200
202
  "\n[yellow]Session Management[/yellow]"
201
203
  "\n [cyan]auto_save_session[/cyan] Auto-save chat after every response (true/false)"
202
204
  )
205
+ keymap_help = (
206
+ "\n[yellow]Keyboard Shortcuts[/yellow]"
207
+ "\n [cyan]cancel_agent_key[/cyan] Key to cancel agent tasks (ctrl+c, ctrl+k, or ctrl+q)"
208
+ )
203
209
  emit_warning(
204
210
  Text.from_markup(
205
- f"Usage: /set KEY=VALUE or /set KEY VALUE\nConfig keys: {', '.join(config_keys)}\n[dim]Note: compaction_strategy can be 'summarization' or 'truncation'[/dim]{session_help}"
211
+ f"Usage: /set KEY=VALUE or /set KEY VALUE\nConfig keys: {', '.join(config_keys)}\n[dim]Note: compaction_strategy can be 'summarization' or 'truncation'[/dim]{session_help}{keymap_help}"
206
212
  )
207
213
  )
208
214
  return True
@@ -215,6 +221,23 @@ def handle_set_command(command: str) -> bool:
215
221
  )
216
222
  )
217
223
 
224
+ # Validate cancel_agent_key before setting
225
+ if key == "cancel_agent_key":
226
+ from code_puppy.keymap import VALID_CANCEL_KEYS
227
+
228
+ normalized_value = value.strip().lower()
229
+ if normalized_value not in VALID_CANCEL_KEYS:
230
+ emit_error(
231
+ f"Invalid cancel_agent_key '{value}'. Valid options: {', '.join(sorted(VALID_CANCEL_KEYS))}"
232
+ )
233
+ return True
234
+ value = normalized_value # Use normalized value
235
+ emit_info(
236
+ Text.from_markup(
237
+ "[yellow]⚠️ cancel_agent_key changed. Please restart Code Puppy for this change to take effect.[/yellow]"
238
+ )
239
+ )
240
+
218
241
  set_config_value(key, value)
219
242
  emit_success(f'Set {key} = "{value}" in puppy.cfg!')
220
243
 
code_puppy/keymap.py CHANGED
@@ -86,15 +86,9 @@ def cancel_agent_uses_signal() -> bool:
86
86
  """Check if the cancel agent key uses SIGINT (Ctrl+C).
87
87
 
88
88
  Returns:
89
- True if the cancel key is ctrl+c AND we're not on Windows
90
- (uses SIGINT handler), False if it uses keyboard listener approach.
89
+ True if the cancel key is ctrl+c (uses SIGINT handler),
90
+ False if it uses keyboard listener approach.
91
91
  """
92
- import sys
93
-
94
- # On Windows, always use keyboard listener - SIGINT is unreliable
95
- if sys.platform == "win32":
96
- return False
97
-
98
92
  return get_cancel_agent_key() == "ctrl+c"
99
93
 
100
94
 
@@ -192,11 +192,6 @@ def kill_all_running_shell_processes() -> int:
192
192
  """Kill all currently tracked running shell processes and stop reader threads.
193
193
 
194
194
  Returns the number of processes signaled.
195
-
196
- Implementation notes:
197
- - Atomically snapshot and clear the registry to prevent race conditions
198
- - Deduplicate by PID to ensure each process is killed at most once
199
- - Let exceptions from _kill_process_group propagate (tests expect this)
200
195
  """
201
196
  global _READER_STOP_EVENT
202
197
 
@@ -204,52 +199,30 @@ def kill_all_running_shell_processes() -> int:
204
199
  if _READER_STOP_EVENT:
205
200
  _READER_STOP_EVENT.set()
206
201
 
207
- # Atomically take snapshot and clear registry
208
- # This prevents other threads from seeing/processing the same processes
202
+ procs: list[subprocess.Popen]
209
203
  with _RUNNING_PROCESSES_LOCK:
210
- procs_snapshot = list(_RUNNING_PROCESSES)
211
- _RUNNING_PROCESSES.clear()
212
-
213
- # Deduplicate by pid to ensure at-most-one kill per process
214
- seen_pids: set = set()
215
- killed_count = 0
216
-
217
- for proc in procs_snapshot:
218
- if proc is None:
219
- continue
220
-
221
- pid = getattr(proc, "pid", None)
222
- key = pid if pid is not None else id(proc)
223
-
224
- if key in seen_pids:
225
- continue
226
- seen_pids.add(key)
227
-
228
- # Close pipes first to unblock readline()
204
+ procs = list(_RUNNING_PROCESSES)
205
+ count = 0
206
+ for p in procs:
229
207
  try:
230
- if proc.stdout and not proc.stdout.closed:
231
- proc.stdout.close()
232
- if proc.stderr and not proc.stderr.closed:
233
- proc.stderr.close()
234
- if proc.stdin and not proc.stdin.closed:
235
- proc.stdin.close()
236
- except (OSError, ValueError):
237
- pass
238
-
239
- # Only attempt to kill processes that are still running
240
- if proc.poll() is None:
241
- # Let exceptions bubble up (tests expect this behavior)
242
- _kill_process_group(proc)
243
- killed_count += 1
244
-
245
- # Track user-killed PIDs
246
- if pid is not None:
247
- try:
248
- _USER_KILLED_PROCESSES.add(pid)
249
- except Exception:
250
- pass # Non-fatal bookkeeping
208
+ # Close pipes first to unblock readline()
209
+ try:
210
+ if p.stdout and not p.stdout.closed:
211
+ p.stdout.close()
212
+ if p.stderr and not p.stderr.closed:
213
+ p.stderr.close()
214
+ if p.stdin and not p.stdin.closed:
215
+ p.stdin.close()
216
+ except (OSError, ValueError):
217
+ pass
251
218
 
252
- return killed_count
219
+ if p.poll() is None:
220
+ _kill_process_group(p)
221
+ count += 1
222
+ _USER_KILLED_PROCESSES.add(p.pid)
223
+ finally:
224
+ _unregister_process(p)
225
+ return count
253
226
 
254
227
 
255
228
  def get_running_shell_process_count() -> int:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.325
3
+ Version: 0.0.327
4
4
  Summary: Code generation agent
5
5
  Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
6
6
  Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
@@ -100,6 +100,8 @@ uvx code-puppy -i
100
100
 
101
101
  ### UV (Recommended)
102
102
 
103
+ #### macOS / Linux
104
+
103
105
  ```bash
104
106
  # Install UV if you don't have it
105
107
  curl -LsSf https://astral.sh/uv/install.sh | sh
@@ -112,6 +114,33 @@ source ~/.zshrc # or ~/.bashrc
112
114
  uvx code-puppy -i
113
115
  ```
114
116
 
117
+ #### Windows
118
+
119
+ On Windows, we recommend installing code-puppy as a global tool for the best experience with keyboard shortcuts (Ctrl+C/Ctrl+X cancellation):
120
+
121
+ ```powershell
122
+ # Install UV if you don't have it (run in PowerShell as Admin)
123
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
124
+
125
+ # Install code-puppy as a global tool
126
+ uv tool install code-puppy
127
+
128
+ # Run code-puppy
129
+ code-puppy -i
130
+ ```
131
+
132
+ **Why `uv tool install` on Windows?** Running with `uvx` creates an extra process layer that can interfere with keyboard signal handling (Ctrl+C, Ctrl+X). Installing as a tool runs code-puppy directly for reliable cancellation.
133
+
134
+ #### Upgrading
135
+
136
+ ```bash
137
+ # Upgrade code-puppy to the latest version
138
+ uv tool upgrade code-puppy
139
+
140
+ # Or upgrade all installed tools
141
+ uv tool upgrade --all
142
+ ```
143
+
115
144
  UV will automatically download the latest compatible Python version (3.11+) if your system doesn't have one.
116
145
 
117
146
  ### pip (Alternative)
@@ -3,12 +3,12 @@ code_puppy/__main__.py,sha256=pDVssJOWP8A83iFkxMLY9YteHYat0EyWDQqMkKHpWp4,203
3
3
  code_puppy/callbacks.py,sha256=hqTV--dNxG5vwWWm3MrEjmb8MZuHFFdmHePl23NXPHk,8621
4
4
  code_puppy/chatgpt_codex_client.py,sha256=Om0ANB_kpHubhCwNzF9ENf8RvKBqs0IYzBLl_SNw0Vk,9833
5
5
  code_puppy/claude_cache_client.py,sha256=hZr_YtXZSQvBoJFtRbbecKucYqJgoMopqUmm0IxFYGY,6071
6
- code_puppy/cli_runner.py,sha256=UIM04pqMb3qkVKG0lKtHQuVSrevsQhEqDC__wAdjqy8,29646
6
+ code_puppy/cli_runner.py,sha256=qAP5cocyUoRVJwvOmlhNsDcoh6h-AXEakDomWxNYlfs,29581
7
7
  code_puppy/config.py,sha256=qqeJrQP7gqADqeYqVzfksP7NYGROLrBQCuYic5PuQfY,52295
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/http_utils.py,sha256=w5mWYIGIWJZJvgvMahXs9BmdidoJvGn4CASDRY88a8o,13414
11
- code_puppy/keymap.py,sha256=kbC6S_s57rXcONdE2e1xdj2XNRJ4nHJI32RxbI83DC4,3400
11
+ code_puppy/keymap.py,sha256=Uzvq7HB-6inTjKox-90JWzuijztRdWqhJpfTDZVy5no,3235
12
12
  code_puppy/main.py,sha256=82r3vZy_XcyEsenLn82BnUusaoyL3Bpm_Th_jKgqecE,273
13
13
  code_puppy/model_factory.py,sha256=H_a5nX462Q-dhX3g3ZY7dmBCIAUOd1aOSZa4HMxF1o4,34191
14
14
  code_puppy/model_utils.py,sha256=NU8W8NW5F7QS_PXHaLeh55Air1koUV7IVYFP7Rz3XpY,3615
@@ -39,7 +39,7 @@ code_puppy/agents/agent_qa_expert.py,sha256=5Ikb4U3SZQknUEfwlHZiyZXKqnffnOTQagr_
39
39
  code_puppy/agents/agent_qa_kitten.py,sha256=5PeFFSwCFlTUvP6h5bGntx0xv5NmRwBiw0HnMqY8nLI,9107
40
40
  code_puppy/agents/agent_security_auditor.py,sha256=SpiYNA0XAsIwBj7S2_EQPRslRUmF_-b89pIJyW7DYtY,12022
41
41
  code_puppy/agents/agent_typescript_reviewer.py,sha256=vsnpp98xg6cIoFAEJrRTUM_i4wLEWGm5nJxs6fhHobM,10275
42
- code_puppy/agents/base_agent.py,sha256=ptca2ZgoNbWv9oTnCw1G3vE87U3mmqm6TOVUXuXofds,85399
42
+ code_puppy/agents/base_agent.py,sha256=cnfzDbmFlXUpg6bxFXbIs4NdOWM7hiMmied9_W6Sp5k,83040
43
43
  code_puppy/agents/json_agent.py,sha256=lhopDJDoiSGHvD8A6t50hi9ZBoNRKgUywfxd0Po_Dzc,4886
44
44
  code_puppy/agents/prompt_reviewer.py,sha256=JJrJ0m5q0Puxl8vFsyhAbY9ftU9n6c6UxEVdNct1E-Q,5558
45
45
  code_puppy/command_line/__init__.py,sha256=y7WeRemfYppk8KVbCGeAIiTuiOszIURCDjOMZv_YRmU,45
@@ -49,7 +49,7 @@ code_puppy/command_line/autosave_menu.py,sha256=7w2SXfEfR-SGFZcHxM-QZfT0p42KxJjX
49
49
  code_puppy/command_line/colors_menu.py,sha256=F_OYuApwXWGP2w9o0CMEbIHtqwdKUh5eDhi7qtDP9h0,17144
50
50
  code_puppy/command_line/command_handler.py,sha256=CY9F27eovZJK_kpU1YmbroYLWGTCuouCOQ-TXfDp-nw,10916
51
51
  code_puppy/command_line/command_registry.py,sha256=qFySsw1g8dol3kgi0p6cXrIDlP11_OhOoaQ5nAadWXg,4416
52
- code_puppy/command_line/config_commands.py,sha256=YQzc6y5NMOW9EsrfpoldNYew4BR3bEKqph_00FLPdKw,24627
52
+ code_puppy/command_line/config_commands.py,sha256=5RG8oBaG52vBbZ2Nd5BnHszh_uwPit23AYmEckJRyTc,25764
53
53
  code_puppy/command_line/core_commands.py,sha256=qxIZ5tCAPkNDfDYjcG86h0tsi7RUQ4ueQ5C2BZ2H214,24809
54
54
  code_puppy/command_line/diff_menu.py,sha256=6qolM8ECpXTAo2q0Yvqw8Oohsj3MLPxQI8PJvYuKGS4,24014
55
55
  code_puppy/command_line/file_path_completion.py,sha256=gw8NpIxa6GOpczUJRyh7VNZwoXKKn-yvCqit7h2y6Gg,2931
@@ -144,7 +144,7 @@ code_puppy/plugins/shell_safety/register_callbacks.py,sha256=W3v664RR48Fdbbbltf_
144
144
  code_puppy/prompts/codex_system_prompt.md,sha256=hEFTCziroLqZmqNle5kG34A8kvTteOWezCiVrAEKhE0,24400
145
145
  code_puppy/tools/__init__.py,sha256=BVTZ85jLHgDANwOnUSOz3UDlp8VQDq4DoGF23BRlyWw,6032
146
146
  code_puppy/tools/agent_tools.py,sha256=snBI6FlFtR03CbYKXwu53R48c_fRSuDIwcNdVUruLcA,21020
147
- code_puppy/tools/command_runner.py,sha256=Sz2AI9CCE3fUcFv-86p1BB5tBkt_UbrPNi57Tfk031E,45281
147
+ code_puppy/tools/command_runner.py,sha256=WLesijwbXEsnyuIJvWZHbVVyoUAPQcTWJbz31pXPSi0,44325
148
148
  code_puppy/tools/common.py,sha256=IboS6sbwN4a3FzHdfsZJtEFiyDUCszevI6LpH14ydEk,40561
149
149
  code_puppy/tools/file_modifications.py,sha256=vz9n7R0AGDSdLUArZr_55yJLkyI30M8zreAppxIx02M,29380
150
150
  code_puppy/tools/file_operations.py,sha256=CqhpuBnOFOcQCIYXOujskxq2VMLWYJhibYrH0YcPSfA,35692
@@ -159,10 +159,10 @@ code_puppy/tools/browser/browser_scripts.py,sha256=sNb8eLEyzhasy5hV4B9OjM8yIVMLV
159
159
  code_puppy/tools/browser/browser_workflows.py,sha256=nitW42vCf0ieTX1gLabozTugNQ8phtoFzZbiAhw1V90,6491
160
160
  code_puppy/tools/browser/camoufox_manager.py,sha256=RZjGOEftE5sI_tsercUyXFSZI2wpStXf-q0PdYh2G3I,8680
161
161
  code_puppy/tools/browser/vqa_agent.py,sha256=DBn9HKloILqJSTSdNZzH_PYWT0B2h9VwmY6akFQI_uU,2913
162
- code_puppy-0.0.325.data/data/code_puppy/models.json,sha256=IPABdOrDw2OZJxa0XGBWSWmBRerV6_pIEmKVLRtUbAk,3105
163
- code_puppy-0.0.325.data/data/code_puppy/models_dev_api.json,sha256=wHjkj-IM_fx1oHki6-GqtOoCrRMR0ScK0f-Iz0UEcy8,548187
164
- code_puppy-0.0.325.dist-info/METADATA,sha256=wo7WPKOxHwhkioUQNvZCOVzyOPClCRR3oBwQxesHVQA,28030
165
- code_puppy-0.0.325.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
166
- code_puppy-0.0.325.dist-info/entry_points.txt,sha256=Tp4eQC99WY3HOKd3sdvb22vZODRq0XkZVNpXOag_KdI,91
167
- code_puppy-0.0.325.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
168
- code_puppy-0.0.325.dist-info/RECORD,,
162
+ code_puppy-0.0.327.data/data/code_puppy/models.json,sha256=IPABdOrDw2OZJxa0XGBWSWmBRerV6_pIEmKVLRtUbAk,3105
163
+ code_puppy-0.0.327.data/data/code_puppy/models_dev_api.json,sha256=wHjkj-IM_fx1oHki6-GqtOoCrRMR0ScK0f-Iz0UEcy8,548187
164
+ code_puppy-0.0.327.dist-info/METADATA,sha256=8waMztx7WRaBW1dx_pizAmLEvWqXKzD5p7M4F9X-zGc,28854
165
+ code_puppy-0.0.327.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
166
+ code_puppy-0.0.327.dist-info/entry_points.txt,sha256=Tp4eQC99WY3HOKd3sdvb22vZODRq0XkZVNpXOag_KdI,91
167
+ code_puppy-0.0.327.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
168
+ code_puppy-0.0.327.dist-info/RECORD,,