codefile 1.0.0__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.
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.4
2
+ Name: codefile
3
+ Version: 1.0.0
4
+ Summary: A CLI tool to bundle entire projects into a single AI-friendly context file.
5
+ Author: Anthroberc
6
+ Keywords: ai,gemini,codefile,llm,context,prompt-engineering,bundler,devtools,chatgpt,claude
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+
10
+ codefile – Python Project Packager
11
+
12
+ =====================================
13
+ What Is codefile?
14
+ =====================================
15
+
16
+ codefile is a Python package that scans your project directory
17
+ and packs everything into a single output file named:
18
+
19
+ CodeFile
20
+
21
+ It includes:
22
+ - Project folder structure (tree view)
23
+ - File metadata (SHA-256 ID)
24
+ - File contents
25
+ - Total size (in MB)
26
+ - UTC creation timestamp
27
+
28
+ This is useful for:
29
+ - Creating project snapshots
30
+ - Sharing full source code as one file
31
+ - Simple archiving
32
+ - Backup purposes
33
+
34
+
35
+ =====================================
36
+ Installation
37
+ =====================================
38
+
39
+ If installed from source:
40
+
41
+ pip install .
42
+
43
+ installing a package:
44
+
45
+ pip install codefile
46
+
47
+
48
+ =====================================
49
+ How To Use
50
+ =====================================
51
+
52
+ Step 1:
53
+ Open terminal inside your project folder.
54
+
55
+ Step 2:
56
+ Run:
57
+
58
+ codefile
59
+
60
+ Step 3:
61
+ After execution, a new file will appear:
62
+
63
+ CodeFile
64
+
65
+ That file contains your full project snapshot.
66
+
67
+
68
+ =====================================
69
+ What Gets Packed?
70
+ =====================================
71
+
72
+ ✔ All regular files in the current directory
73
+ ✔ Subdirectories
74
+ ✔ File contents
75
+ ✔ Directory structure
76
+
77
+ Automatically ignored:
78
+ - .git folder
79
+ - The generated CodeFile
80
+ - The package script itself
81
+ - Patterns listed in .gitignore (if present)
82
+
83
+
84
+ =====================================
85
+ Output File Structure
86
+ =====================================
87
+
88
+ The generated file contains:
89
+
90
+ ROOT_NAME <project_name>
91
+ CREATED_UTC <timestamp>
92
+ TOTAL_SIZE_MB <size>
93
+
94
+ START_STRUCTURE
95
+ <folder tree>
96
+ END_STRUCTURE
97
+
98
+ FILE_START <relative_path> <file_id>
99
+ <file content>
100
+ FILE_END <relative_path> <file_id>
101
+
102
+
103
+ =====================================
104
+ Technical Details
105
+ =====================================
106
+
107
+ - Uses SHA-256 hashing (first 12 characters as ID)
108
+ - Reads files in chunks (memory safe)
109
+ - Skips unreadable or broken files safely
110
+ - Writes output using UTF-8 encoding
111
+ - Handles errors without crashing
112
+
113
+ =====================================
114
+ Requirements
115
+ =====================================
116
+
117
+ - Python 3.8+
118
+ - No external dependencies (uses standard library only)
@@ -0,0 +1,6 @@
1
+ codefile.py,sha256=haYiYlKWLakguqivigOSAzPnoI7j5SfntqNhuoW6PeY,5423
2
+ codefile-1.0.0.dist-info/METADATA,sha256=eiZjpYNw-ZWu3i-bjmDLGf2IUY824l1KSUKy8ondudc,2457
3
+ codefile-1.0.0.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
4
+ codefile-1.0.0.dist-info/entry_points.txt,sha256=gF--gx0EZLvgBvHx5-XzaCf1vu7qlYkAhSRZ8dNmPwY,43
5
+ codefile-1.0.0.dist-info/top_level.txt,sha256=v3___6J6zX4HRyt39z6KOtx1ZIPPuoyHrRHtFW_T7Ew,9
6
+ codefile-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ codefile = codefile:main
@@ -0,0 +1 @@
1
+ codefile
codefile.py ADDED
@@ -0,0 +1,144 @@
1
+ import os
2
+ import hashlib
3
+ import datetime
4
+ import fnmatch
5
+ from pathlib import Path
6
+
7
+ def main():
8
+ IO_CHUNK = 65536
9
+ OUT_NAME = "CodeFile"
10
+ SCRIPT_NAME = Path(__file__).name if '__file__' in globals() else "packager.py"
11
+
12
+ def get_ignore_patterns(root):
13
+ patterns = {OUT_NAME, SCRIPT_NAME, ".git", ".git/"}
14
+ gitignore = root / ".gitignore"
15
+ try:
16
+ if gitignore.is_file():
17
+ with gitignore.open("r", encoding="utf-8", errors="ignore") as f:
18
+ for line in f:
19
+ line = line.strip()
20
+ if line and not line.startswith("#"):
21
+ patterns.add(line)
22
+ except Exception as e:
23
+ print(f"Warning: Failed reading .gitignore: {e}")
24
+ return list(patterns)
25
+
26
+ def is_ignored(path, root, patterns):
27
+ try:
28
+ rel_path = path.relative_to(root).as_posix()
29
+ parts = rel_path.split('/')
30
+ for pattern in patterns:
31
+ clean_pattern = pattern.rstrip('/')
32
+ for part in parts:
33
+ if fnmatch.fnmatch(part, clean_pattern):
34
+ return True
35
+ if fnmatch.fnmatch(rel_path, pattern):
36
+ return True
37
+ except ValueError:
38
+ return True # If it fails relative resolution (e.g., weird symlink), ignore it
39
+ return False
40
+
41
+ def build_visual_tree(root, all_relative_paths):
42
+ tree = {}
43
+ for path_str in sorted(all_relative_paths):
44
+ current = tree
45
+ for part in path_str.split('/'):
46
+ current = current.setdefault(part, {})
47
+
48
+ lines = [f"{root.name}/"]
49
+ def walk(node, prefix=""):
50
+ items = sorted(node.items(), key=lambda x: (not x[1], x[0]))
51
+ for i, (name, children) in enumerate(items):
52
+ is_last = (i == len(items) - 1)
53
+ connector = "\\-- " if is_last else "|-- "
54
+ lines.append(f"{prefix}{connector}{name}{'/' if children else ''}")
55
+ if children:
56
+ walk(children, prefix + (" " if is_last else "| "))
57
+ walk(tree)
58
+ return "\n".join(lines)
59
+
60
+ # 1. Resolve Environment Safely
61
+ try:
62
+ root = Path.cwd().resolve()
63
+ except Exception as e:
64
+ return print(f"Fatal Error: Cannot resolve current directory: {e}")
65
+
66
+ if not root.is_dir():
67
+ return print(f"Fatal Error: {root} is not a valid directory.")
68
+
69
+ patterns = get_ignore_patterns(root)
70
+ all_rel_paths = []
71
+ files_to_write = []
72
+ total_bytes = 0
73
+
74
+ print(f"Scanning directory: {root.name} ...")
75
+
76
+ # 2. Safely Walk Directory
77
+ for dirpath, dirnames, filenames in os.walk(root):
78
+ try:
79
+ dp = Path(dirpath)
80
+
81
+ # Instantly skip git folder traversal
82
+ if ".git" in dp.parts:
83
+ continue
84
+
85
+ for f in filenames:
86
+ p = dp / f
87
+ try:
88
+ if not p.is_file():
89
+ continue
90
+
91
+ rel_path = p.relative_to(root).as_posix()
92
+ all_rel_paths.append(rel_path)
93
+
94
+ if not is_ignored(p, root, patterns):
95
+ total_bytes += p.stat().st_size
96
+ files_to_write.append(p)
97
+ except (OSError, ValueError):
98
+ continue # Skip unreadable files or broken symlinks
99
+ except Exception:
100
+ continue
101
+
102
+ print(f"Found {len(files_to_write)} files to pack. Building structure...")
103
+
104
+ # 3. Safely Write Output
105
+ try:
106
+ tree_str = build_visual_tree(root, all_rel_paths)
107
+ timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
108
+ out_file = root / OUT_NAME
109
+
110
+ with out_file.open("w", encoding="utf-8", errors="replace", newline='\n') as out:
111
+ out.write(f"ROOT_NAME {root.name}\n")
112
+ out.write(f"CREATED_UTC {timestamp}\n")
113
+ out.write(f"TOTAL_SIZE_MB {total_bytes / (1024*1024):.2f}\n\n")
114
+ out.write("START_STRUCTURE\n" + tree_str + "\nEND_STRUCTURE\n\n")
115
+
116
+ for f_path in files_to_write:
117
+ try:
118
+ rel = f_path.relative_to(root).as_posix()
119
+ h = hashlib.sha256()
120
+
121
+ # Read 1: Hash Calculation
122
+ with f_path.open("rb") as rb:
123
+ while chunk := rb.read(IO_CHUNK):
124
+ h.update(chunk)
125
+ f_id = h.hexdigest()[:12]
126
+
127
+ # Read 2: Content Writing
128
+ out.write(f"FILE_START {rel} {f_id}\n")
129
+ with f_path.open("rb") as rb:
130
+ while chunk := rb.read(IO_CHUNK):
131
+ out.write(chunk.decode("utf-8", errors="replace"))
132
+ out.write(f"\nFILE_END {rel} {f_id}\n\n")
133
+
134
+ except Exception as e:
135
+ print(f"Warning: Skipped reading content of {f_path.name} ({e})")
136
+ continue
137
+
138
+ print(f"Success. Generated {OUT_NAME} ({total_bytes / (1024*1024):.2f} MB)")
139
+
140
+ except Exception as e:
141
+ print(f"Critical Failure writing output file: {e}")
142
+
143
+ if __name__ == "__main__":
144
+ main()