code-puppy 0.0.92__tar.gz → 0.0.94__tar.gz

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 (32) hide show
  1. {code_puppy-0.0.92 → code_puppy-0.0.94}/PKG-INFO +1 -1
  2. code_puppy-0.0.94/code_puppy/tools/common.py +385 -0
  3. {code_puppy-0.0.92 → code_puppy-0.0.94}/pyproject.toml +1 -1
  4. code_puppy-0.0.92/code_puppy/tools/common.py +0 -118
  5. {code_puppy-0.0.92 → code_puppy-0.0.94}/.gitignore +0 -0
  6. {code_puppy-0.0.92 → code_puppy-0.0.94}/LICENSE +0 -0
  7. {code_puppy-0.0.92 → code_puppy-0.0.94}/README.md +0 -0
  8. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/__init__.py +0 -0
  9. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/agent.py +0 -0
  10. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/agent_prompts.py +0 -0
  11. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/command_line/__init__.py +0 -0
  12. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/command_line/file_path_completion.py +0 -0
  13. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/command_line/meta_command_handler.py +0 -0
  14. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/command_line/model_picker_completion.py +0 -0
  15. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/command_line/motd.py +0 -0
  16. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  17. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/command_line/utils.py +0 -0
  18. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/config.py +0 -0
  19. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/main.py +0 -0
  20. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/message_history_processor.py +0 -0
  21. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/model_factory.py +0 -0
  22. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/models.json +0 -0
  23. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/state_management.py +0 -0
  24. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/status_display.py +0 -0
  25. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/summarization_agent.py +0 -0
  26. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/token_utils.py +0 -0
  27. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/tools/__init__.py +0 -0
  28. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/tools/command_runner.py +0 -0
  29. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/tools/file_modifications.py +0 -0
  30. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/tools/file_operations.py +0 -0
  31. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/tools/token_check.py +0 -0
  32. {code_puppy-0.0.92 → code_puppy-0.0.94}/code_puppy/version_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.92
3
+ Version: 0.0.94
4
4
  Summary: Code generation agent
5
5
  Author: Michael Pfaffenberger
6
6
  License: MIT
@@ -0,0 +1,385 @@
1
+ import os
2
+ import fnmatch
3
+
4
+ from typing import Optional, Tuple
5
+ from rapidfuzz.distance import JaroWinkler
6
+ from rich.console import Console
7
+
8
+ from pathlib import Path
9
+ # get_model_context_length will be imported locally where needed to avoid circular imports
10
+
11
+ NO_COLOR = bool(int(os.environ.get("CODE_PUPPY_NO_COLOR", "0")))
12
+ console = Console(no_color=NO_COLOR)
13
+
14
+
15
+ def get_model_context_length() -> int:
16
+ """
17
+ Get the context length for the currently configured model from models.json
18
+ """
19
+ # Import locally to avoid circular imports
20
+ from code_puppy.model_factory import ModelFactory
21
+ from code_puppy.config import get_model_name
22
+ import os
23
+ from pathlib import Path
24
+
25
+ # Load model configuration
26
+ models_path = os.environ.get("MODELS_JSON_PATH")
27
+ if not models_path:
28
+ models_path = Path(__file__).parent.parent / "models.json"
29
+ else:
30
+ models_path = Path(models_path)
31
+
32
+ model_configs = ModelFactory.load_config(str(models_path))
33
+ model_name = get_model_name()
34
+
35
+ # Get context length from model config
36
+ model_config = model_configs.get(model_name, {})
37
+ context_length = model_config.get("context_length", 128000) # Default value
38
+
39
+ # Reserve 10% of context for response
40
+ return int(context_length)
41
+
42
+
43
+ # -------------------
44
+ # Shared ignore patterns/helpers
45
+ # -------------------
46
+ IGNORE_PATTERNS = [
47
+ # Version control
48
+ "**/.git/**",
49
+ "**/.git",
50
+ ".git/**",
51
+ ".git",
52
+ "**/.svn/**",
53
+ "**/.hg/**",
54
+ "**/.bzr/**",
55
+ # Node.js / JavaScript / TypeScript
56
+ "**/node_modules/**",
57
+ "**/node_modules/**/*.js",
58
+ "node_modules/**",
59
+ "node_modules",
60
+ "**/npm-debug.log*",
61
+ "**/yarn-debug.log*",
62
+ "**/yarn-error.log*",
63
+ "**/pnpm-debug.log*",
64
+ "**/.npm/**",
65
+ "**/.yarn/**",
66
+ "**/.pnpm-store/**",
67
+ "**/coverage/**",
68
+ "**/.nyc_output/**",
69
+ "**/dist/**",
70
+ "**/dist",
71
+ "**/build/**",
72
+ "**/build",
73
+ "**/.next/**",
74
+ "**/.nuxt/**",
75
+ "**/out/**",
76
+ "**/.cache/**",
77
+ "**/.parcel-cache/**",
78
+ "**/.vite/**",
79
+ "**/storybook-static/**",
80
+ # Python
81
+ "**/__pycache__/**",
82
+ "**/__pycache__",
83
+ "__pycache__/**",
84
+ "__pycache__",
85
+ "**/*.pyc",
86
+ "**/*.pyo",
87
+ "**/*.pyd",
88
+ "**/.pytest_cache/**",
89
+ "**/.mypy_cache/**",
90
+ "**/.coverage",
91
+ "**/htmlcov/**",
92
+ "**/.tox/**",
93
+ "**/.nox/**",
94
+ "**/site-packages/**",
95
+ "**/.venv/**",
96
+ "**/.venv",
97
+ "**/venv/**",
98
+ "**/venv",
99
+ "**/env/**",
100
+ "**/ENV/**",
101
+ "**/.env",
102
+ "**/pip-wheel-metadata/**",
103
+ "**/*.egg-info/**",
104
+ "**/dist/**",
105
+ "**/wheels/**",
106
+ # Java (Maven, Gradle, SBT)
107
+ "**/target/**",
108
+ "**/target",
109
+ "**/build/**",
110
+ "**/build",
111
+ "**/.gradle/**",
112
+ "**/gradle-app.setting",
113
+ "**/*.class",
114
+ "**/*.jar",
115
+ "**/*.war",
116
+ "**/*.ear",
117
+ "**/*.nar",
118
+ "**/hs_err_pid*",
119
+ "**/.classpath",
120
+ "**/.project",
121
+ "**/.settings/**",
122
+ "**/bin/**",
123
+ "**/project/target/**",
124
+ "**/project/project/**",
125
+ # Go
126
+ "**/vendor/**",
127
+ "**/*.exe",
128
+ "**/*.exe~",
129
+ "**/*.dll",
130
+ "**/*.so",
131
+ "**/*.dylib",
132
+ "**/*.test",
133
+ "**/*.out",
134
+ "**/go.work",
135
+ "**/go.work.sum",
136
+ # Rust
137
+ "**/target/**",
138
+ "**/Cargo.lock",
139
+ "**/*.pdb",
140
+ # Ruby
141
+ "**/vendor/**",
142
+ "**/.bundle/**",
143
+ "**/Gemfile.lock",
144
+ "**/*.gem",
145
+ "**/.rvm/**",
146
+ "**/.rbenv/**",
147
+ "**/coverage/**",
148
+ "**/.yardoc/**",
149
+ "**/doc/**",
150
+ "**/rdoc/**",
151
+ "**/.sass-cache/**",
152
+ "**/.jekyll-cache/**",
153
+ "**/_site/**",
154
+ # PHP
155
+ "**/vendor/**",
156
+ "**/composer.lock",
157
+ "**/.phpunit.result.cache",
158
+ "**/storage/logs/**",
159
+ "**/storage/framework/cache/**",
160
+ "**/storage/framework/sessions/**",
161
+ "**/storage/framework/testing/**",
162
+ "**/storage/framework/views/**",
163
+ "**/bootstrap/cache/**",
164
+ # .NET / C#
165
+ "**/bin/**",
166
+ "**/obj/**",
167
+ "**/packages/**",
168
+ "**/*.cache",
169
+ "**/*.dll",
170
+ "**/*.exe",
171
+ "**/*.pdb",
172
+ "**/*.user",
173
+ "**/*.suo",
174
+ "**/.vs/**",
175
+ "**/TestResults/**",
176
+ "**/BenchmarkDotNet.Artifacts/**",
177
+ # C/C++
178
+ "**/*.o",
179
+ "**/*.obj",
180
+ "**/*.so",
181
+ "**/*.dll",
182
+ "**/*.a",
183
+ "**/*.lib",
184
+ "**/*.dylib",
185
+ "**/*.exe",
186
+ "**/CMakeFiles/**",
187
+ "**/CMakeCache.txt",
188
+ "**/cmake_install.cmake",
189
+ "**/Makefile",
190
+ "**/compile_commands.json",
191
+ "**/.deps/**",
192
+ "**/.libs/**",
193
+ "**/autom4te.cache/**",
194
+ # Perl
195
+ "**/blib/**",
196
+ "**/_build/**",
197
+ "**/Build",
198
+ "**/Build.bat",
199
+ "**/*.tmp",
200
+ "**/*.bak",
201
+ "**/*.old",
202
+ "**/Makefile.old",
203
+ "**/MANIFEST.bak",
204
+ "**/META.yml",
205
+ "**/META.json",
206
+ "**/MYMETA.*",
207
+ "**/.prove",
208
+ # Scala
209
+ "**/target/**",
210
+ "**/project/target/**",
211
+ "**/project/project/**",
212
+ "**/.bloop/**",
213
+ "**/.metals/**",
214
+ "**/.ammonite/**",
215
+ "**/*.class",
216
+ # Elixir
217
+ "**/_build/**",
218
+ "**/deps/**",
219
+ "**/*.beam",
220
+ "**/.fetch",
221
+ "**/erl_crash.dump",
222
+ "**/*.ez",
223
+ "**/doc/**",
224
+ "**/.elixir_ls/**",
225
+ # Swift
226
+ "**/.build/**",
227
+ "**/Packages/**",
228
+ "**/*.xcodeproj/**",
229
+ "**/*.xcworkspace/**",
230
+ "**/DerivedData/**",
231
+ "**/xcuserdata/**",
232
+ "**/*.dSYM/**",
233
+ # Kotlin
234
+ "**/build/**",
235
+ "**/.gradle/**",
236
+ "**/*.class",
237
+ "**/*.jar",
238
+ "**/*.kotlin_module",
239
+ # Clojure
240
+ "**/target/**",
241
+ "**/.lein-**",
242
+ "**/.nrepl-port",
243
+ "**/pom.xml.asc",
244
+ "**/*.jar",
245
+ "**/*.class",
246
+ # Dart/Flutter
247
+ "**/.dart_tool/**",
248
+ "**/build/**",
249
+ "**/.packages",
250
+ "**/pubspec.lock",
251
+ "**/*.g.dart",
252
+ "**/*.freezed.dart",
253
+ "**/*.gr.dart",
254
+ # Haskell
255
+ "**/dist/**",
256
+ "**/dist-newstyle/**",
257
+ "**/.stack-work/**",
258
+ "**/*.hi",
259
+ "**/*.o",
260
+ "**/*.prof",
261
+ "**/*.aux",
262
+ "**/*.hp",
263
+ "**/*.eventlog",
264
+ "**/*.tix",
265
+ # Erlang
266
+ "**/ebin/**",
267
+ "**/rel/**",
268
+ "**/deps/**",
269
+ "**/*.beam",
270
+ "**/*.boot",
271
+ "**/*.plt",
272
+ "**/erl_crash.dump",
273
+ # Common cache and temp directories
274
+ "**/.cache/**",
275
+ "**/cache/**",
276
+ "**/tmp/**",
277
+ "**/temp/**",
278
+ "**/.tmp/**",
279
+ "**/.temp/**",
280
+ "**/logs/**",
281
+ "**/*.log",
282
+ "**/*.log.*",
283
+ # IDE and editor files
284
+ "**/.idea/**",
285
+ "**/.idea",
286
+ "**/.vscode/**",
287
+ "**/.vscode",
288
+ "**/*.swp",
289
+ "**/*.swo",
290
+ "**/*~",
291
+ "**/.#*",
292
+ "**/#*#",
293
+ "**/.emacs.d/auto-save-list/**",
294
+ "**/.vim/**",
295
+ "**/.netrwhist",
296
+ "**/Session.vim",
297
+ "**/.sublime-project",
298
+ "**/.sublime-workspace",
299
+ # OS-specific files
300
+ "**/.DS_Store",
301
+ ".DS_Store",
302
+ "**/Thumbs.db",
303
+ "**/Desktop.ini",
304
+ "**/.directory",
305
+ "**/*.lnk",
306
+ # Common artifacts
307
+ "**/*.orig",
308
+ "**/*.rej",
309
+ "**/*.patch",
310
+ "**/*.diff",
311
+ "**/.*.orig",
312
+ "**/.*.rej",
313
+ # Backup files
314
+ "**/*~",
315
+ "**/*.bak",
316
+ "**/*.backup",
317
+ "**/*.old",
318
+ "**/*.save",
319
+ # Hidden files (but be careful with this one)
320
+ # "**/.*", # Commented out as it might be too aggressive
321
+ ]
322
+
323
+
324
+ def should_ignore_path(path: str) -> bool:
325
+ """Return True if *path* matches any pattern in IGNORE_PATTERNS."""
326
+ # Convert path to Path object for better pattern matching
327
+ path_obj = Path(path)
328
+
329
+ for pattern in IGNORE_PATTERNS:
330
+ # Try pathlib's match method which handles ** patterns properly
331
+ try:
332
+ if path_obj.match(pattern):
333
+ return True
334
+ except ValueError:
335
+ # If pathlib can't handle the pattern, fall back to fnmatch
336
+ if fnmatch.fnmatch(path, pattern):
337
+ return True
338
+
339
+ # Additional check: if pattern contains **, try matching against
340
+ # different parts of the path to handle edge cases
341
+ if "**" in pattern:
342
+ # Convert pattern to handle different path representations
343
+ simplified_pattern = pattern.replace("**/", "").replace("/**", "")
344
+
345
+ # Check if any part of the path matches the simplified pattern
346
+ path_parts = path_obj.parts
347
+ for i in range(len(path_parts)):
348
+ subpath = Path(*path_parts[i:])
349
+ if fnmatch.fnmatch(str(subpath), simplified_pattern):
350
+ return True
351
+ # Also check individual parts
352
+ if fnmatch.fnmatch(path_parts[i], simplified_pattern):
353
+ return True
354
+
355
+ return False
356
+
357
+
358
+ def _find_best_window(
359
+ haystack_lines: list[str],
360
+ needle: str,
361
+ ) -> Tuple[Optional[Tuple[int, int]], float]:
362
+ """
363
+ Return (start, end) indices of the window with the highest
364
+ Jaro-Winkler similarity to `needle`, along with that score.
365
+ If nothing clears JW_THRESHOLD, return (None, score).
366
+ """
367
+ needle = needle.rstrip("\n")
368
+ needle_lines = needle.splitlines()
369
+ win_size = len(needle_lines)
370
+ best_score = 0.0
371
+ best_span: Optional[Tuple[int, int]] = None
372
+ best_window = ""
373
+ # Pre-join the needle once; join windows on the fly
374
+ for i in range(len(haystack_lines) - win_size + 1):
375
+ window = "\n".join(haystack_lines[i : i + win_size])
376
+ score = JaroWinkler.normalized_similarity(window, needle)
377
+ if score > best_score:
378
+ best_score = score
379
+ best_span = (i, i + win_size)
380
+ best_window = window
381
+
382
+ console.log(f"Best span: {best_span}")
383
+ console.log(f"Best window: {best_window}")
384
+ console.log(f"Best score: {best_score}")
385
+ return best_span, best_score
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.92"
7
+ version = "0.0.94"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,118 +0,0 @@
1
- import os
2
- import fnmatch
3
-
4
- from typing import Optional, Tuple
5
- from rapidfuzz.distance import JaroWinkler
6
- from rich.console import Console
7
-
8
- # get_model_context_length will be imported locally where needed to avoid circular imports
9
-
10
- NO_COLOR = bool(int(os.environ.get("CODE_PUPPY_NO_COLOR", "0")))
11
- console = Console(no_color=NO_COLOR)
12
-
13
-
14
- def get_model_context_length() -> int:
15
- """
16
- Get the context length for the currently configured model from models.json
17
- """
18
- # Import locally to avoid circular imports
19
- from code_puppy.model_factory import ModelFactory
20
- from code_puppy.config import get_model_name
21
- import os
22
- from pathlib import Path
23
-
24
- # Load model configuration
25
- models_path = os.environ.get("MODELS_JSON_PATH")
26
- if not models_path:
27
- models_path = Path(__file__).parent.parent / "models.json"
28
- else:
29
- models_path = Path(models_path)
30
-
31
- model_configs = ModelFactory.load_config(str(models_path))
32
- model_name = get_model_name()
33
-
34
- # Get context length from model config
35
- model_config = model_configs.get(model_name, {})
36
- context_length = model_config.get("context_length", 128000) # Default value
37
-
38
- # Reserve 10% of context for response
39
- return int(context_length)
40
-
41
-
42
- # -------------------
43
- # Shared ignore patterns/helpers
44
- # -------------------
45
- IGNORE_PATTERNS = [
46
- "**/node_modules/**",
47
- "**/node_modules/**/*.js",
48
- "node_modules/**",
49
- "node_modules",
50
- "**/.git/**",
51
- "**/.git",
52
- ".git/**",
53
- ".git",
54
- "**/__pycache__/**",
55
- "**/__pycache__",
56
- "__pycache__/**",
57
- "__pycache__",
58
- "**/.DS_Store",
59
- ".DS_Store",
60
- "**/.env",
61
- ".env",
62
- "**/.venv/**",
63
- "**/.venv",
64
- "**/venv/**",
65
- "**/venv",
66
- "**/.idea/**",
67
- "**/.idea",
68
- "**/.vscode/**",
69
- "**/.vscode",
70
- "**/dist/**",
71
- "**/dist",
72
- "**/build/**",
73
- "**/build",
74
- "**/*.pyc",
75
- "**/*.pyo",
76
- "**/*.pyd",
77
- "**/*.so",
78
- "**/*.dll",
79
- "**/.*",
80
- ]
81
-
82
-
83
- def should_ignore_path(path: str) -> bool:
84
- """Return True if *path* matches any pattern in IGNORE_PATTERNS."""
85
- for pattern in IGNORE_PATTERNS:
86
- if fnmatch.fnmatch(path, pattern):
87
- return True
88
- return False
89
-
90
-
91
- def _find_best_window(
92
- haystack_lines: list[str],
93
- needle: str,
94
- ) -> Tuple[Optional[Tuple[int, int]], float]:
95
- """
96
- Return (start, end) indices of the window with the highest
97
- Jaro-Winkler similarity to `needle`, along with that score.
98
- If nothing clears JW_THRESHOLD, return (None, score).
99
- """
100
- needle = needle.rstrip("\n")
101
- needle_lines = needle.splitlines()
102
- win_size = len(needle_lines)
103
- best_score = 0.0
104
- best_span: Optional[Tuple[int, int]] = None
105
- best_window = ""
106
- # Pre-join the needle once; join windows on the fly
107
- for i in range(len(haystack_lines) - win_size + 1):
108
- window = "\n".join(haystack_lines[i : i + win_size])
109
- score = JaroWinkler.normalized_similarity(window, needle)
110
- if score > best_score:
111
- best_score = score
112
- best_span = (i, i + win_size)
113
- best_window = window
114
-
115
- console.log(f"Best span: {best_span}")
116
- console.log(f"Best window: {best_window}")
117
- console.log(f"Best score: {best_score}")
118
- return best_span, best_score
File without changes
File without changes
File without changes