RepoPackPy 0.1.7__tar.gz → 0.1.8__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.
- {repopackpy-0.1.7 → repopackpy-0.1.8}/PKG-INFO +1 -1
- {repopackpy-0.1.7 → repopackpy-0.1.8}/pyproject.toml +1 -1
- repopackpy-0.1.8/repopack/__init__.py +1 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/repopack/cli.py +20 -4
- {repopackpy-0.1.7 → repopackpy-0.1.8}/repopack/mcp_server.py +18 -2
- {repopackpy-0.1.7 → repopackpy-0.1.8}/repopack/packer.py +18 -3
- {repopackpy-0.1.7 → repopackpy-0.1.8}/repopack/unpacker.py +24 -1
- repopackpy-0.1.7/repopack/__init__.py +0 -1
- {repopackpy-0.1.7 → repopackpy-0.1.8}/.github/workflows/ci.yml +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/.github/workflows/publish.yml +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/.github/workflows/security.yml +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/.gitignore +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/CLAUDE.md +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/LICENSE +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/README.md +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/repopack/utils.py +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/system_prompt.txt +0 -0
- {repopackpy-0.1.7 → repopackpy-0.1.8}/tests/test_repopack.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.8"
|
|
@@ -60,14 +60,22 @@ def pack(
|
|
|
60
60
|
output: str = typer.Option(None, "-o", "--output", help="Output JSON file path."),
|
|
61
61
|
include_binary: bool = typer.Option(False, "--include-binary", help="Include binary files."),
|
|
62
62
|
custom_ignore: str = typer.Option(None, "--custom-ignore", help="Comma-separated extra ignore patterns."),
|
|
63
|
+
dry_run: bool = typer.Option(False, "--dry-run", help="Report files that would be packed without writing output."),
|
|
63
64
|
):
|
|
64
65
|
try:
|
|
65
|
-
result = pack_workspace(Path(directory), include_binary, custom_ignore)
|
|
66
|
+
result = pack_workspace(Path(directory), include_binary, custom_ignore, dry_run=dry_run)
|
|
67
|
+
if dry_run:
|
|
68
|
+
typer.echo(f"Dry run — would pack {result['total_files']} files ({result['total_bytes']} bytes)")
|
|
69
|
+
typer.echo(f"Root : {result['root_directory']}")
|
|
70
|
+
typer.echo(f"Stack : {', '.join(result['detected_stack']) or 'unknown'}")
|
|
71
|
+
for f in result["files"]:
|
|
72
|
+
typer.echo(f" {f['encoding']:6} {f['size']:>10} {f['path']}")
|
|
73
|
+
return
|
|
66
74
|
if output:
|
|
67
75
|
with open(output, "w", encoding="utf-8") as f:
|
|
68
76
|
json.dump(result, f, indent=2)
|
|
69
|
-
total_files = result.get("total_files", 0)
|
|
70
|
-
total_bytes = result.get("total_bytes", 0)
|
|
77
|
+
total_files = result.get("metadata", {}).get("total_files", 0)
|
|
78
|
+
total_bytes = result.get("metadata", {}).get("total_bytes", 0)
|
|
71
79
|
typer.echo(f"Packed {total_files} files ({total_bytes} bytes) -> {output}", err=True)
|
|
72
80
|
else:
|
|
73
81
|
print(json.dumps(result, indent=2))
|
|
@@ -81,9 +89,17 @@ def unpack(
|
|
|
81
89
|
input: str = typer.Argument(..., help="File path or raw JSON string to unpack."),
|
|
82
90
|
target: str = typer.Option(".", "-t", "--target", help="Output directory."),
|
|
83
91
|
force: bool = typer.Option(False, "--force/--no-force", help="Overwrite existing files."),
|
|
92
|
+
dry_run: bool = typer.Option(False, "--dry-run", help="Report files that would be unpacked without writing anything."),
|
|
84
93
|
):
|
|
85
94
|
try:
|
|
86
|
-
result = unpack_workspace(input, Path(target), overwrite=force)
|
|
95
|
+
result = unpack_workspace(input, Path(target), overwrite=force, dry_run=dry_run)
|
|
96
|
+
if dry_run:
|
|
97
|
+
typer.echo(f"Dry run — destination: {result['destination']}")
|
|
98
|
+
typer.echo(f" Would extract : {result['would_extract']}")
|
|
99
|
+
typer.echo(f" Would skip : {result['would_skip']}")
|
|
100
|
+
for f in result["files"]:
|
|
101
|
+
typer.echo(f" {f['action']:20} {f['path']}")
|
|
102
|
+
return
|
|
87
103
|
extracted = result.get("extracted", 0)
|
|
88
104
|
destination = result.get("destination", target)
|
|
89
105
|
skipped = result.get("skipped", 0)
|
|
@@ -14,8 +14,16 @@ def export_workspace(
|
|
|
14
14
|
workspace_path: str = ".",
|
|
15
15
|
output_json_path: str | None = None,
|
|
16
16
|
include_binary: bool = False,
|
|
17
|
+
dry_run: bool = False,
|
|
17
18
|
) -> str:
|
|
18
|
-
result = pack_workspace(Path(workspace_path), include_binary=include_binary)
|
|
19
|
+
result = pack_workspace(Path(workspace_path), include_binary=include_binary, dry_run=dry_run)
|
|
20
|
+
if dry_run:
|
|
21
|
+
lines = [
|
|
22
|
+
f"Dry run — would pack {result['total_files']} files ({result['total_bytes']} bytes)",
|
|
23
|
+
f"Root : {result['root_directory']}",
|
|
24
|
+
f"Stack : {', '.join(result['detected_stack']) or 'unknown'}",
|
|
25
|
+
] + [f" {f['encoding']:6} {f['size']:>10} {f['path']}" for f in result["files"]]
|
|
26
|
+
return "\n".join(lines)
|
|
19
27
|
if output_json_path is not None:
|
|
20
28
|
with open(output_json_path, "w", encoding="utf-8") as f:
|
|
21
29
|
json.dump(result, f, indent=2)
|
|
@@ -28,8 +36,16 @@ def import_workspace(
|
|
|
28
36
|
json_input: str,
|
|
29
37
|
destination_path: str,
|
|
30
38
|
overwrite: bool = False,
|
|
39
|
+
dry_run: bool = False,
|
|
31
40
|
) -> str:
|
|
32
|
-
summary = unpack_workspace(json_input, Path(destination_path), overwrite=overwrite)
|
|
41
|
+
summary = unpack_workspace(json_input, Path(destination_path), overwrite=overwrite, dry_run=dry_run)
|
|
42
|
+
if dry_run:
|
|
43
|
+
lines = [
|
|
44
|
+
f"Dry run — destination: {summary['destination']}",
|
|
45
|
+
f" Would extract : {summary['would_extract']}",
|
|
46
|
+
f" Would skip : {summary['would_skip']}",
|
|
47
|
+
] + [f" {f['action']:20} {f['path']}" for f in summary["files"]]
|
|
48
|
+
return "\n".join(lines)
|
|
33
49
|
return f"Extracted {summary['extracted']} files to {summary['destination']} ({summary['skipped']} skipped)"
|
|
34
50
|
|
|
35
51
|
|
|
@@ -13,6 +13,7 @@ def pack_workspace(
|
|
|
13
13
|
directory: Path,
|
|
14
14
|
include_binary: bool = False,
|
|
15
15
|
custom_ignore: str | None = None,
|
|
16
|
+
dry_run: bool = False,
|
|
16
17
|
) -> dict:
|
|
17
18
|
directory = directory.resolve()
|
|
18
19
|
|
|
@@ -58,21 +59,25 @@ def pack_workspace(
|
|
|
58
59
|
if binary and not include_binary:
|
|
59
60
|
continue
|
|
60
61
|
|
|
62
|
+
encoding = "base64" if binary else "utf-8"
|
|
63
|
+
total_bytes += file_size
|
|
64
|
+
|
|
65
|
+
if dry_run:
|
|
66
|
+
files.append({"path": rel_path.as_posix(), "encoding": encoding, "size": file_size})
|
|
67
|
+
continue
|
|
68
|
+
|
|
61
69
|
if binary:
|
|
62
70
|
try:
|
|
63
71
|
raw = file_path.read_bytes()
|
|
64
72
|
except OSError:
|
|
65
73
|
continue
|
|
66
74
|
content = base64.b64encode(raw).decode("ascii")
|
|
67
|
-
encoding = "base64"
|
|
68
75
|
else:
|
|
69
76
|
try:
|
|
70
77
|
content = file_path.read_text(encoding="utf-8", errors="replace")
|
|
71
78
|
except OSError:
|
|
72
79
|
continue
|
|
73
|
-
encoding = "utf-8"
|
|
74
80
|
|
|
75
|
-
total_bytes += file_size
|
|
76
81
|
files.append(
|
|
77
82
|
{
|
|
78
83
|
"path": rel_path.as_posix(),
|
|
@@ -83,6 +88,16 @@ def pack_workspace(
|
|
|
83
88
|
|
|
84
89
|
detected_stack = detect_stack(directory)
|
|
85
90
|
|
|
91
|
+
if dry_run:
|
|
92
|
+
return {
|
|
93
|
+
"dry_run": True,
|
|
94
|
+
"root_directory": str(directory),
|
|
95
|
+
"detected_stack": detected_stack,
|
|
96
|
+
"total_files": len(files),
|
|
97
|
+
"total_bytes": total_bytes,
|
|
98
|
+
"files": files,
|
|
99
|
+
}
|
|
100
|
+
|
|
86
101
|
return {
|
|
87
102
|
"version": "1.0",
|
|
88
103
|
"metadata": {
|
|
@@ -11,6 +11,7 @@ def unpack_workspace(
|
|
|
11
11
|
destination_path: Path,
|
|
12
12
|
overwrite: bool = False,
|
|
13
13
|
force: bool = False,
|
|
14
|
+
dry_run: bool = False,
|
|
14
15
|
) -> dict:
|
|
15
16
|
if Path(json_input).is_file():
|
|
16
17
|
with open(json_input, "r", encoding="utf-8") as f:
|
|
@@ -25,6 +26,7 @@ def unpack_workspace(
|
|
|
25
26
|
|
|
26
27
|
extracted = 0
|
|
27
28
|
skipped = 0
|
|
29
|
+
dry_run_files: list[dict] = []
|
|
28
30
|
|
|
29
31
|
for entry in data["files"]:
|
|
30
32
|
rel = entry.get("path", "")
|
|
@@ -40,8 +42,20 @@ def unpack_workspace(
|
|
|
40
42
|
raise ValueError(f"Path traversal detected: {rel}")
|
|
41
43
|
|
|
42
44
|
output_path = destination_path / rel_path
|
|
45
|
+
would_skip = output_path.exists() and not overwrite
|
|
46
|
+
|
|
47
|
+
if dry_run:
|
|
48
|
+
dry_run_files.append({
|
|
49
|
+
"path": rel,
|
|
50
|
+
"action": "skip (exists)" if would_skip else "create",
|
|
51
|
+
})
|
|
52
|
+
if would_skip:
|
|
53
|
+
skipped += 1
|
|
54
|
+
else:
|
|
55
|
+
extracted += 1
|
|
56
|
+
continue
|
|
43
57
|
|
|
44
|
-
if
|
|
58
|
+
if would_skip:
|
|
45
59
|
skipped += 1
|
|
46
60
|
continue
|
|
47
61
|
|
|
@@ -57,4 +71,13 @@ def unpack_workspace(
|
|
|
57
71
|
|
|
58
72
|
extracted += 1
|
|
59
73
|
|
|
74
|
+
if dry_run:
|
|
75
|
+
return {
|
|
76
|
+
"dry_run": True,
|
|
77
|
+
"destination": str(destination_path),
|
|
78
|
+
"would_extract": extracted,
|
|
79
|
+
"would_skip": skipped,
|
|
80
|
+
"files": dry_run_files,
|
|
81
|
+
}
|
|
82
|
+
|
|
60
83
|
return {"extracted": extracted, "skipped": skipped, "destination": str(destination_path)}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.7"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|