code-puppy 0.0.54__tar.gz → 0.0.55__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 (27) hide show
  1. {code_puppy-0.0.54 → code_puppy-0.0.55}/PKG-INFO +1 -1
  2. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/tools/file_operations.py +134 -15
  3. {code_puppy-0.0.54 → code_puppy-0.0.55}/pyproject.toml +1 -1
  4. {code_puppy-0.0.54 → code_puppy-0.0.55}/.gitignore +0 -0
  5. {code_puppy-0.0.54 → code_puppy-0.0.55}/LICENSE +0 -0
  6. {code_puppy-0.0.54 → code_puppy-0.0.55}/README.md +0 -0
  7. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/__init__.py +0 -0
  8. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/agent.py +0 -0
  9. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/agent_prompts.py +0 -0
  10. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/command_line/__init__.py +0 -0
  11. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/command_line/file_path_completion.py +0 -0
  12. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/command_line/meta_command_handler.py +0 -0
  13. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/command_line/model_picker_completion.py +0 -0
  14. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  15. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/command_line/utils.py +0 -0
  16. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/config.py +0 -0
  17. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/main.py +0 -0
  18. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/model_factory.py +0 -0
  19. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/models.json +0 -0
  20. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/session_memory.py +0 -0
  21. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/tools/__init__.py +0 -0
  22. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/tools/code_map.py +0 -0
  23. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/tools/command_runner.py +0 -0
  24. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/tools/common.py +0 -0
  25. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/tools/file_modifications.py +0 -0
  26. {code_puppy-0.0.54 → code_puppy-0.0.55}/code_puppy/tools/web_search.py +0 -0
  27. {code_puppy-0.0.54 → code_puppy-0.0.55}/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.54
3
+ Version: 0.0.55
4
4
  Summary: Code generation agent
5
5
  Author: Michael Pfaffenberger
6
6
  License: MIT
@@ -40,29 +40,148 @@ def should_ignore_path(path: str) -> bool:
40
40
  def _list_files(
41
41
  context: RunContext, directory: str = ".", recursive: bool = True
42
42
  ) -> List[Dict[str, Any]]:
43
- """Light-weight `list_files` implementation sufficient for unit-tests and agent tooling."""
43
+ results = []
44
+ directory = os.path.abspath(directory)
45
+ console.print("\n[bold white on blue] DIRECTORY LISTING [/bold white on blue]")
44
46
  console.print(
45
- f"\n[bold white on blue] LIST FILES [/bold white on blue] \U0001f4c2 [bold cyan]{directory}[/bold cyan]"
47
+ f"\U0001f4c2 [bold cyan]{directory}[/bold cyan] [dim](recursive={recursive})[/dim]"
46
48
  )
47
49
  console.print("[dim]" + "-" * 60 + "[/dim]")
48
- directory = os.path.abspath(directory)
49
- results: List[Dict[str, Any]] = []
50
- if not os.path.exists(directory) or not os.path.isdir(directory):
50
+ if not os.path.exists(directory):
51
51
  console.print(
52
- f"[bold red]Directory '{directory}' does not exist or is not a directory[/bold red]"
52
+ f"[bold red]Error:[/bold red] Directory '{directory}' does not exist"
53
53
  )
54
- return [
55
- {"error": f"Directory '{directory}' does not exist or is not a directory"}
56
- ]
54
+ console.print("[dim]" + "-" * 60 + "[/dim]\n")
55
+ return [{"error": f"Directory '{directory}' does not exist"}]
56
+ if not os.path.isdir(directory):
57
+ console.print(f"[bold red]Error:[/bold red] '{directory}' is not a directory")
58
+ console.print("[dim]" + "-" * 60 + "[/dim]\n")
59
+ return [{"error": f"'{directory}' is not a directory"}]
60
+ folder_structure = {}
61
+ file_list = []
57
62
  for root, dirs, files in os.walk(directory):
58
- rel_root = os.path.relpath(root, directory)
59
- if rel_root == ".":
60
- rel_root = ""
61
- for f in files:
62
- fp = os.path.join(rel_root, f) if rel_root else f
63
- results.append({"path": fp, "type": "file"})
63
+ dirs[:] = [d for d in dirs if not should_ignore_path(os.path.join(root, d))]
64
+ rel_path = os.path.relpath(root, directory)
65
+ depth = 0 if rel_path == "." else rel_path.count(os.sep) + 1
66
+ if rel_path == ".":
67
+ rel_path = ""
68
+ if rel_path:
69
+ dir_path = os.path.join(directory, rel_path)
70
+ results.append(
71
+ {
72
+ "path": rel_path,
73
+ "type": "directory",
74
+ "size": 0,
75
+ "full_path": dir_path,
76
+ "depth": depth,
77
+ }
78
+ )
79
+ folder_structure[rel_path] = {
80
+ "path": rel_path,
81
+ "depth": depth,
82
+ "full_path": dir_path,
83
+ }
84
+ for file in files:
85
+ file_path = os.path.join(root, file)
86
+ if should_ignore_path(file_path):
87
+ continue
88
+ rel_file_path = os.path.join(rel_path, file) if rel_path else file
89
+ try:
90
+ size = os.path.getsize(file_path)
91
+ file_info = {
92
+ "path": rel_file_path,
93
+ "type": "file",
94
+ "size": size,
95
+ "full_path": file_path,
96
+ "depth": depth,
97
+ }
98
+ results.append(file_info)
99
+ file_list.append(file_info)
100
+ except (FileNotFoundError, PermissionError):
101
+ continue
64
102
  if not recursive:
65
103
  break
104
+
105
+ def format_size(size_bytes):
106
+ if size_bytes < 1024:
107
+ return f"{size_bytes} B"
108
+ elif size_bytes < 1024 * 1024:
109
+ return f"{size_bytes / 1024:.1f} KB"
110
+ elif size_bytes < 1024 * 1024 * 1024:
111
+ return f"{size_bytes / (1024 * 1024):.1f} MB"
112
+ else:
113
+ return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
114
+
115
+ def get_file_icon(file_path):
116
+ ext = os.path.splitext(file_path)[1].lower()
117
+ if ext in [".py", ".pyw"]:
118
+ return "\U0001f40d"
119
+ elif ext in [".js", ".jsx", ".ts", ".tsx"]:
120
+ return "\U0001f4dc"
121
+ elif ext in [".html", ".htm", ".xml"]:
122
+ return "\U0001f310"
123
+ elif ext in [".css", ".scss", ".sass"]:
124
+ return "\U0001f3a8"
125
+ elif ext in [".md", ".markdown", ".rst"]:
126
+ return "\U0001f4dd"
127
+ elif ext in [".json", ".yaml", ".yml", ".toml"]:
128
+ return "\u2699\ufe0f"
129
+ elif ext in [".jpg", ".jpeg", ".png", ".gif", ".svg", ".webp"]:
130
+ return "\U0001f5bc\ufe0f"
131
+ elif ext in [".mp3", ".wav", ".ogg", ".flac"]:
132
+ return "\U0001f3b5"
133
+ elif ext in [".mp4", ".avi", ".mov", ".webm"]:
134
+ return "\U0001f3ac"
135
+ elif ext in [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx"]:
136
+ return "\U0001f4c4"
137
+ elif ext in [".zip", ".tar", ".gz", ".rar", ".7z"]:
138
+ return "\U0001f4e6"
139
+ elif ext in [".exe", ".dll", ".so", ".dylib"]:
140
+ return "\u26a1"
141
+ else:
142
+ return "\U0001f4c4"
143
+
144
+ if results:
145
+ files = sorted(
146
+ [f for f in results if f["type"] == "file"], key=lambda x: x["path"]
147
+ )
148
+ console.print(
149
+ f"\U0001f4c1 [bold blue]{os.path.basename(directory) or directory}[/bold blue]"
150
+ )
151
+ all_items = sorted(results, key=lambda x: x["path"])
152
+ parent_dirs_with_content = set()
153
+ for i, item in enumerate(all_items):
154
+ if item["type"] == "directory" and not item["path"]:
155
+ continue
156
+ if os.sep in item["path"]:
157
+ parent_path = os.path.dirname(item["path"])
158
+ parent_dirs_with_content.add(parent_path)
159
+ depth = item["path"].count(os.sep) + 1 if item["path"] else 0
160
+ prefix = ""
161
+ for d in range(depth):
162
+ if d == depth - 1:
163
+ prefix += "\u2514\u2500\u2500 "
164
+ else:
165
+ prefix += " "
166
+ name = os.path.basename(item["path"]) or item["path"]
167
+ if item["type"] == "directory":
168
+ console.print(f"{prefix}\U0001f4c1 [bold blue]{name}/[/bold blue]")
169
+ else:
170
+ icon = get_file_icon(item["path"])
171
+ size_str = format_size(item["size"])
172
+ console.print(
173
+ f"{prefix}{icon} [green]{name}[/green] [dim]({size_str})[/dim]"
174
+ )
175
+ else:
176
+ console.print("[yellow]Directory is empty[/yellow]")
177
+ dir_count = sum(1 for item in results if item["type"] == "directory")
178
+ file_count = sum(1 for item in results if item["type"] == "file")
179
+ total_size = sum(item["size"] for item in results if item["type"] == "file")
180
+ console.print("\n[bold cyan]Summary:[/bold cyan]")
181
+ console.print(
182
+ f"\U0001f4c1 [blue]{dir_count} directories[/blue], \U0001f4c4 [green]{file_count} files[/green] [dim]({format_size(total_size)} total)[/dim]"
183
+ )
184
+ console.print("[dim]" + "-" * 60 + "[/dim]\n")
66
185
  return results
67
186
 
68
187
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.54"
7
+ version = "0.0.55"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes
File without changes