RepoPackPy 0.1.8__tar.gz → 0.2.0__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.
@@ -0,0 +1,262 @@
1
+ Metadata-Version: 2.4
2
+ Name: RepoPackPy
3
+ Version: 0.2.0
4
+ Summary: Pack/unpack any source workspace into portable JSON, with MCP server support.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: mcp[cli]>=1.0
9
+ Requires-Dist: pathspec>=0.12
10
+ Requires-Dist: typer>=0.12
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest>=8; extra == 'dev'
13
+ Description-Content-Type: text/markdown
14
+
15
+ # RepoPack
16
+
17
+ Pack/unpack **any source workspace regardless of technology stack** (Python, Node.js, React, Angular, Vue, Rust, Go, Java, C#, and more) into a portable, structured JSON payload — and restore it faithfully from that payload.
18
+
19
+ ## Features
20
+
21
+ - **Universal ignore engine** — respects root and nested `.gitignore` files plus stack-agnostic defaults (node_modules, __pycache__, .venv, target/, dist/, secrets, lock files, …)
22
+ - **Polyglot stack detection** — auto-detects Node.js, React, TypeScript, Angular, Next.js, Vue, Python, Rust, Go, Java, C# from project sentinel files
23
+ - **Binary safety** — text files encoded as UTF-8; binaries skipped by default or included as Base64 with `--include-binary`
24
+ - **5 MB guard** — files larger than 5 MB are skipped with a warning
25
+ - **Dry-run mode** — preview exactly which files would be packed or unpacked before committing with `--dry-run`
26
+ - **Path traversal shield** — `unpack` validates every path against the destination root before writing anything; blocks `../`, absolute paths, and injection attempts (CWE-22)
27
+ - **Secure PyPI version check** — uses `http.client.HTTPSConnection` (not `urlopen`) to enforce HTTPS at the type level
28
+ - **MCP server** — expose pack/unpack as tools to any MCP-compatible AI client (Claude Desktop, etc.)
29
+ - **Automated security auditing** — weekly `pip-audit` + `bandit` CI scans on all dependencies
30
+
31
+ ## Installation
32
+
33
+ ### From PyPI (recommended)
34
+
35
+ ```bash
36
+ pip install RepoPackPy
37
+ ```
38
+
39
+ Requires Python 3.10+.
40
+
41
+ ### Quick start after install
42
+
43
+ ```bash
44
+ # Verify the install
45
+ repopack --version
46
+ repopack --help
47
+
48
+ # Pack your project
49
+ repopack pack . -o my-workspace.json
50
+
51
+ # Preview what would be packed (no output written)
52
+ repopack pack . --dry-run
53
+
54
+ # Restore it somewhere else
55
+ repopack unpack my-workspace.json -t ./restored
56
+
57
+ # Preview what would be unpacked (nothing written)
58
+ repopack unpack my-workspace.json -t ./restored --dry-run
59
+ ```
60
+
61
+ ### For development
62
+
63
+ ```bash
64
+ git clone https://github.com/ShanKonduru/RepoPack.git
65
+ cd RepoPack
66
+ pip install ".[dev]"
67
+ ```
68
+
69
+ > **Note:** Install without `-e` (editable) so `pip-audit` can audit the package metadata correctly.
70
+
71
+ ## CLI Usage
72
+
73
+ ```
74
+ repopack pack [DIRECTORY] [-o output.json] [--include-binary] [--custom-ignore ".next,dist"] [--dry-run]
75
+ repopack unpack <input.json> [-t TARGET_DIR] [--force] [--dry-run]
76
+ repopack validate <input.json> [DIRECTORY]
77
+ repopack fix <input.json> [DIRECTORY] [--include-binary]
78
+ repopack serve
79
+ ```
80
+
81
+ ### Options
82
+
83
+ | Command | Flag | Description |
84
+ |---|---|---|
85
+ | `pack` | `-o / --output` | Write packed JSON to this file (prints to stdout if omitted) |
86
+ | `pack` | `--include-binary` | Include binary files encoded as Base64 |
87
+ | `pack` | `--custom-ignore` | Comma-separated extra ignore patterns |
88
+ | `pack` | `--dry-run` | List files that would be packed — encoding, size, path — without writing anything |
89
+ | `unpack` | `-t / --target` | Destination directory (default: current directory) |
90
+ | `unpack` | `--force` | Overwrite existing files |
91
+ | `unpack` | `--dry-run` | List files that would be extracted or skipped without writing anything |
92
+ | `validate` | _(none)_ | Compare JSON against the live workspace; exit 1 if outdated |
93
+ | `fix` | `--include-binary` | Re-pack workspace into the JSON file, adding/removing/refreshing as needed |
94
+
95
+ ### Examples
96
+
97
+ ```bash
98
+ # Pack current directory
99
+ repopack pack . -o workspace.json
100
+
101
+ # Dry-run: see what would be packed
102
+ repopack pack . --dry-run
103
+
104
+ # Pack a specific project, include binaries
105
+ repopack pack ~/projects/my-app -o my-app.json --include-binary
106
+
107
+ # Unpack into a new directory
108
+ repopack unpack workspace.json -t ./restored
109
+
110
+ # Dry-run: see what would be unpacked (and what would be skipped)
111
+ repopack unpack workspace.json -t ./restored --dry-run
112
+
113
+ # Unpack and overwrite existing files
114
+ repopack unpack workspace.json -t ./restored --force
115
+
116
+ # Validate: check if workspace.json is complete and up to date
117
+ repopack validate workspace.json .
118
+
119
+ # Fix: update workspace.json with all latest files and folders
120
+ repopack fix workspace.json .
121
+ ```
122
+
123
+ #### Sample `--dry-run` output
124
+
125
+ ```
126
+ # pack --dry-run
127
+ Dry run — would pack 42 files (186320 bytes)
128
+ Root : /home/user/my-app
129
+ Stack : Node.js, React, TypeScript
130
+ utf-8 1024 src/App.tsx
131
+ utf-8 512 src/index.tsx
132
+ base64 8192 public/favicon.ico
133
+ ...
134
+
135
+ # unpack --dry-run
136
+ Dry run — destination: /home/user/restored
137
+ Would extract : 40
138
+ Would skip : 2
139
+ create src/App.tsx
140
+ create src/index.tsx
141
+ skip (exists) README.md
142
+ ...
143
+ ```
144
+
145
+ #### Sample `validate` output
146
+
147
+ ```
148
+ Status : OUTDATED
149
+ JSON : workspace.json
150
+ Workspace: /home/user/my-app
151
+ Missing from JSON : 2
152
+ Extra in JSON : 1
153
+ Stale in JSON : 3
154
+ Up to date : 36
155
+
156
+ Missing (in workspace, not in JSON):
157
+ + src/NewComponent.tsx
158
+ + src/utils/helper.ts
159
+
160
+ Extra (in JSON, not in workspace):
161
+ - src/OldComponent.tsx
162
+
163
+ Stale (content changed since packing):
164
+ ~ README.md
165
+ ~ src/App.tsx
166
+ ~ package.json
167
+ ```
168
+
169
+ #### Sample `fix` output
170
+
171
+ ```
172
+ Updated : workspace.json
173
+ Workspace: /home/user/my-app
174
+ Added : 2 files
175
+ Removed : 1 files
176
+ Refreshed: 3 files
177
+ Total : 42 files (189440 bytes)
178
+ ```
179
+
180
+ ## JSON Payload Schema
181
+
182
+ ```json
183
+ {
184
+ "version": "1.0",
185
+ "metadata": {
186
+ "created_at": "2026-07-26T12:00:00Z",
187
+ "root_directory_name": "my-app",
188
+ "detected_stack": ["Node.js", "React", "TypeScript"],
189
+ "total_files": 38,
190
+ "total_bytes": 128450
191
+ },
192
+ "files": [
193
+ { "path": "src/App.tsx", "encoding": "utf-8", "content": "..." },
194
+ { "path": "public/favicon.ico", "encoding": "base64", "content": "..." }
195
+ ]
196
+ }
197
+ ```
198
+
199
+ ## MCP Server Tools
200
+
201
+ When running `repopack serve`, two tools are registered via FastMCP:
202
+
203
+ | Tool | Parameters | Description |
204
+ |---|---|---|
205
+ | `export_workspace` | `workspace_path, output_json_path, include_binary, dry_run` | Pack a directory into JSON |
206
+ | `import_workspace` | `json_input, destination_path, overwrite, dry_run` | Unpack JSON into a directory |
207
+ | `validate_workspace_tool` | `json_path, workspace_path` | Report missing, extra, and stale files vs the live workspace |
208
+ | `fix_workspace_tool` | `json_path, workspace_path, include_binary` | Re-pack and overwrite the JSON with all latest files and folders |
209
+
210
+ Set `dry_run=true` on `export_workspace` or `import_workspace` to get a plain-text report without reading file content or writing to disk.
211
+
212
+ ## Security
213
+
214
+ ### Path traversal protection
215
+
216
+ Every path in an incoming JSON payload is validated before the filesystem is touched:
217
+
218
+ - Absolute paths are rejected.
219
+ - Any path component equal to `..` is rejected.
220
+ - The resolved output path is checked with `os.path.commonpath` to confirm it stays inside the destination root.
221
+
222
+ This blocks directory traversal attacks (CWE-22) regardless of how the JSON was produced.
223
+
224
+ ### PyPI version check
225
+
226
+ The `--version` flag checks for newer releases on PyPI using `http.client.HTTPSConnection` directly, which enforces HTTPS at the type level and is not susceptible to `file://` or custom-scheme abuse (bandit B310 / CWE-22).
227
+
228
+ ### CI security scanning
229
+
230
+ Every push and weekly schedule runs:
231
+
232
+ - **`pip-audit --strict`** — checks all third-party dependencies against known CVE databases.
233
+ - **`bandit -r repopack/ -ll -ii`** — static analysis for common Python security issues.
234
+
235
+ ## Project Structure
236
+
237
+ ```
238
+ repopack/
239
+ ├── pyproject.toml
240
+ ├── README.md
241
+ └── repopack/
242
+ ├── __init__.py
243
+ ├── cli.py # Typer CLI (pack / unpack / serve)
244
+ ├── mcp_server.py # FastMCP server
245
+ ├── packer.py # Directory walker & JSON builder
246
+ ├── unpacker.py # JSON extractor & path-safe reconstructor
247
+ └── utils.py # Ignore engine, binary detector, stack detection
248
+ tests/
249
+ └── test_repopack.py
250
+ ```
251
+
252
+ ## Running Tests
253
+
254
+ ```bash
255
+ pytest tests/ -v
256
+ ```
257
+
258
+ ## Dependencies
259
+
260
+ - [typer](https://typer.tiangolo.com/) — CLI framework
261
+ - [mcp](https://github.com/modelcontextprotocol/python-sdk) — MCP SDK (FastMCP)
262
+ - [pathspec](https://github.com/cpburnz/python-pathspec) — gitignore wildmatch pattern matching
@@ -0,0 +1,248 @@
1
+ # RepoPack
2
+
3
+ Pack/unpack **any source workspace regardless of technology stack** (Python, Node.js, React, Angular, Vue, Rust, Go, Java, C#, and more) into a portable, structured JSON payload — and restore it faithfully from that payload.
4
+
5
+ ## Features
6
+
7
+ - **Universal ignore engine** — respects root and nested `.gitignore` files plus stack-agnostic defaults (node_modules, __pycache__, .venv, target/, dist/, secrets, lock files, …)
8
+ - **Polyglot stack detection** — auto-detects Node.js, React, TypeScript, Angular, Next.js, Vue, Python, Rust, Go, Java, C# from project sentinel files
9
+ - **Binary safety** — text files encoded as UTF-8; binaries skipped by default or included as Base64 with `--include-binary`
10
+ - **5 MB guard** — files larger than 5 MB are skipped with a warning
11
+ - **Dry-run mode** — preview exactly which files would be packed or unpacked before committing with `--dry-run`
12
+ - **Path traversal shield** — `unpack` validates every path against the destination root before writing anything; blocks `../`, absolute paths, and injection attempts (CWE-22)
13
+ - **Secure PyPI version check** — uses `http.client.HTTPSConnection` (not `urlopen`) to enforce HTTPS at the type level
14
+ - **MCP server** — expose pack/unpack as tools to any MCP-compatible AI client (Claude Desktop, etc.)
15
+ - **Automated security auditing** — weekly `pip-audit` + `bandit` CI scans on all dependencies
16
+
17
+ ## Installation
18
+
19
+ ### From PyPI (recommended)
20
+
21
+ ```bash
22
+ pip install RepoPackPy
23
+ ```
24
+
25
+ Requires Python 3.10+.
26
+
27
+ ### Quick start after install
28
+
29
+ ```bash
30
+ # Verify the install
31
+ repopack --version
32
+ repopack --help
33
+
34
+ # Pack your project
35
+ repopack pack . -o my-workspace.json
36
+
37
+ # Preview what would be packed (no output written)
38
+ repopack pack . --dry-run
39
+
40
+ # Restore it somewhere else
41
+ repopack unpack my-workspace.json -t ./restored
42
+
43
+ # Preview what would be unpacked (nothing written)
44
+ repopack unpack my-workspace.json -t ./restored --dry-run
45
+ ```
46
+
47
+ ### For development
48
+
49
+ ```bash
50
+ git clone https://github.com/ShanKonduru/RepoPack.git
51
+ cd RepoPack
52
+ pip install ".[dev]"
53
+ ```
54
+
55
+ > **Note:** Install without `-e` (editable) so `pip-audit` can audit the package metadata correctly.
56
+
57
+ ## CLI Usage
58
+
59
+ ```
60
+ repopack pack [DIRECTORY] [-o output.json] [--include-binary] [--custom-ignore ".next,dist"] [--dry-run]
61
+ repopack unpack <input.json> [-t TARGET_DIR] [--force] [--dry-run]
62
+ repopack validate <input.json> [DIRECTORY]
63
+ repopack fix <input.json> [DIRECTORY] [--include-binary]
64
+ repopack serve
65
+ ```
66
+
67
+ ### Options
68
+
69
+ | Command | Flag | Description |
70
+ |---|---|---|
71
+ | `pack` | `-o / --output` | Write packed JSON to this file (prints to stdout if omitted) |
72
+ | `pack` | `--include-binary` | Include binary files encoded as Base64 |
73
+ | `pack` | `--custom-ignore` | Comma-separated extra ignore patterns |
74
+ | `pack` | `--dry-run` | List files that would be packed — encoding, size, path — without writing anything |
75
+ | `unpack` | `-t / --target` | Destination directory (default: current directory) |
76
+ | `unpack` | `--force` | Overwrite existing files |
77
+ | `unpack` | `--dry-run` | List files that would be extracted or skipped without writing anything |
78
+ | `validate` | _(none)_ | Compare JSON against the live workspace; exit 1 if outdated |
79
+ | `fix` | `--include-binary` | Re-pack workspace into the JSON file, adding/removing/refreshing as needed |
80
+
81
+ ### Examples
82
+
83
+ ```bash
84
+ # Pack current directory
85
+ repopack pack . -o workspace.json
86
+
87
+ # Dry-run: see what would be packed
88
+ repopack pack . --dry-run
89
+
90
+ # Pack a specific project, include binaries
91
+ repopack pack ~/projects/my-app -o my-app.json --include-binary
92
+
93
+ # Unpack into a new directory
94
+ repopack unpack workspace.json -t ./restored
95
+
96
+ # Dry-run: see what would be unpacked (and what would be skipped)
97
+ repopack unpack workspace.json -t ./restored --dry-run
98
+
99
+ # Unpack and overwrite existing files
100
+ repopack unpack workspace.json -t ./restored --force
101
+
102
+ # Validate: check if workspace.json is complete and up to date
103
+ repopack validate workspace.json .
104
+
105
+ # Fix: update workspace.json with all latest files and folders
106
+ repopack fix workspace.json .
107
+ ```
108
+
109
+ #### Sample `--dry-run` output
110
+
111
+ ```
112
+ # pack --dry-run
113
+ Dry run — would pack 42 files (186320 bytes)
114
+ Root : /home/user/my-app
115
+ Stack : Node.js, React, TypeScript
116
+ utf-8 1024 src/App.tsx
117
+ utf-8 512 src/index.tsx
118
+ base64 8192 public/favicon.ico
119
+ ...
120
+
121
+ # unpack --dry-run
122
+ Dry run — destination: /home/user/restored
123
+ Would extract : 40
124
+ Would skip : 2
125
+ create src/App.tsx
126
+ create src/index.tsx
127
+ skip (exists) README.md
128
+ ...
129
+ ```
130
+
131
+ #### Sample `validate` output
132
+
133
+ ```
134
+ Status : OUTDATED
135
+ JSON : workspace.json
136
+ Workspace: /home/user/my-app
137
+ Missing from JSON : 2
138
+ Extra in JSON : 1
139
+ Stale in JSON : 3
140
+ Up to date : 36
141
+
142
+ Missing (in workspace, not in JSON):
143
+ + src/NewComponent.tsx
144
+ + src/utils/helper.ts
145
+
146
+ Extra (in JSON, not in workspace):
147
+ - src/OldComponent.tsx
148
+
149
+ Stale (content changed since packing):
150
+ ~ README.md
151
+ ~ src/App.tsx
152
+ ~ package.json
153
+ ```
154
+
155
+ #### Sample `fix` output
156
+
157
+ ```
158
+ Updated : workspace.json
159
+ Workspace: /home/user/my-app
160
+ Added : 2 files
161
+ Removed : 1 files
162
+ Refreshed: 3 files
163
+ Total : 42 files (189440 bytes)
164
+ ```
165
+
166
+ ## JSON Payload Schema
167
+
168
+ ```json
169
+ {
170
+ "version": "1.0",
171
+ "metadata": {
172
+ "created_at": "2026-07-26T12:00:00Z",
173
+ "root_directory_name": "my-app",
174
+ "detected_stack": ["Node.js", "React", "TypeScript"],
175
+ "total_files": 38,
176
+ "total_bytes": 128450
177
+ },
178
+ "files": [
179
+ { "path": "src/App.tsx", "encoding": "utf-8", "content": "..." },
180
+ { "path": "public/favicon.ico", "encoding": "base64", "content": "..." }
181
+ ]
182
+ }
183
+ ```
184
+
185
+ ## MCP Server Tools
186
+
187
+ When running `repopack serve`, two tools are registered via FastMCP:
188
+
189
+ | Tool | Parameters | Description |
190
+ |---|---|---|
191
+ | `export_workspace` | `workspace_path, output_json_path, include_binary, dry_run` | Pack a directory into JSON |
192
+ | `import_workspace` | `json_input, destination_path, overwrite, dry_run` | Unpack JSON into a directory |
193
+ | `validate_workspace_tool` | `json_path, workspace_path` | Report missing, extra, and stale files vs the live workspace |
194
+ | `fix_workspace_tool` | `json_path, workspace_path, include_binary` | Re-pack and overwrite the JSON with all latest files and folders |
195
+
196
+ Set `dry_run=true` on `export_workspace` or `import_workspace` to get a plain-text report without reading file content or writing to disk.
197
+
198
+ ## Security
199
+
200
+ ### Path traversal protection
201
+
202
+ Every path in an incoming JSON payload is validated before the filesystem is touched:
203
+
204
+ - Absolute paths are rejected.
205
+ - Any path component equal to `..` is rejected.
206
+ - The resolved output path is checked with `os.path.commonpath` to confirm it stays inside the destination root.
207
+
208
+ This blocks directory traversal attacks (CWE-22) regardless of how the JSON was produced.
209
+
210
+ ### PyPI version check
211
+
212
+ The `--version` flag checks for newer releases on PyPI using `http.client.HTTPSConnection` directly, which enforces HTTPS at the type level and is not susceptible to `file://` or custom-scheme abuse (bandit B310 / CWE-22).
213
+
214
+ ### CI security scanning
215
+
216
+ Every push and weekly schedule runs:
217
+
218
+ - **`pip-audit --strict`** — checks all third-party dependencies against known CVE databases.
219
+ - **`bandit -r repopack/ -ll -ii`** — static analysis for common Python security issues.
220
+
221
+ ## Project Structure
222
+
223
+ ```
224
+ repopack/
225
+ ├── pyproject.toml
226
+ ├── README.md
227
+ └── repopack/
228
+ ├── __init__.py
229
+ ├── cli.py # Typer CLI (pack / unpack / serve)
230
+ ├── mcp_server.py # FastMCP server
231
+ ├── packer.py # Directory walker & JSON builder
232
+ ├── unpacker.py # JSON extractor & path-safe reconstructor
233
+ └── utils.py # Ignore engine, binary detector, stack detection
234
+ tests/
235
+ └── test_repopack.py
236
+ ```
237
+
238
+ ## Running Tests
239
+
240
+ ```bash
241
+ pytest tests/ -v
242
+ ```
243
+
244
+ ## Dependencies
245
+
246
+ - [typer](https://typer.tiangolo.com/) — CLI framework
247
+ - [mcp](https://github.com/modelcontextprotocol/python-sdk) — MCP SDK (FastMCP)
248
+ - [pathspec](https://github.com/cpburnz/python-pathspec) — gitignore wildmatch pattern matching
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "RepoPackPy"
7
- version = "0.1.8"
7
+ version = "0.2.0"
8
8
  description = "Pack/unpack any source workspace into portable JSON, with MCP server support."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"
@@ -5,7 +5,7 @@ import typer
5
5
  from pathlib import Path
6
6
 
7
7
  from repopack import __version__
8
- from repopack.packer import pack_workspace
8
+ from repopack.packer import fix_workspace, pack_workspace, validate_workspace
9
9
  from repopack.unpacker import unpack_workspace
10
10
  from repopack.mcp_server import run_server
11
11
 
@@ -109,6 +109,62 @@ def unpack(
109
109
  raise typer.Exit(1)
110
110
 
111
111
 
112
+ @app.command()
113
+ def validate(
114
+ json_file: str = typer.Argument(..., help="Packed JSON file to validate."),
115
+ directory: str = typer.Argument(".", help="Workspace directory to compare against."),
116
+ ):
117
+ """Check whether a packed JSON is complete and up to date with the workspace."""
118
+ try:
119
+ report = validate_workspace(json_file, Path(directory))
120
+ s = report["summary"]
121
+ status = "OK" if report["valid"] else "OUTDATED"
122
+ typer.echo(f"Status : {status}")
123
+ typer.echo(f"JSON : {report['json_path']}")
124
+ typer.echo(f"Workspace: {report['workspace']}")
125
+ typer.echo(f" Missing from JSON : {s['missing_from_json']}")
126
+ typer.echo(f" Extra in JSON : {s['extra_in_json']}")
127
+ typer.echo(f" Stale in JSON : {s['stale_in_json']}")
128
+ typer.echo(f" Up to date : {s['up_to_date']}")
129
+ if report["missing_from_json"]:
130
+ typer.echo("\nMissing (in workspace, not in JSON):")
131
+ for p in report["missing_from_json"]:
132
+ typer.echo(f" + {p}")
133
+ if report["extra_in_json"]:
134
+ typer.echo("\nExtra (in JSON, not in workspace):")
135
+ for p in report["extra_in_json"]:
136
+ typer.echo(f" - {p}")
137
+ if report["stale_in_json"]:
138
+ typer.echo("\nStale (content changed since packing):")
139
+ for p in report["stale_in_json"]:
140
+ typer.echo(f" ~ {p}")
141
+ if not report["valid"]:
142
+ raise typer.Exit(1)
143
+ except (ValueError, OSError) as e:
144
+ typer.echo(str(e), err=True)
145
+ raise typer.Exit(1)
146
+
147
+
148
+ @app.command()
149
+ def fix(
150
+ json_file: str = typer.Argument(..., help="Packed JSON file to update."),
151
+ directory: str = typer.Argument(".", help="Workspace directory to pack from."),
152
+ include_binary: bool = typer.Option(False, "--include-binary", help="Include binary files."),
153
+ ):
154
+ """Re-pack the workspace and update the JSON file with all latest files and folders."""
155
+ try:
156
+ result = fix_workspace(json_file, Path(directory), include_binary=include_binary)
157
+ typer.echo(f"Updated : {result['json_path']}")
158
+ typer.echo(f"Workspace: {result['workspace']}")
159
+ typer.echo(f" Added : {len(result['added'])} files")
160
+ typer.echo(f" Removed : {len(result['removed'])} files")
161
+ typer.echo(f" Refreshed: {len(result['refreshed'])} files")
162
+ typer.echo(f" Total : {result['total_files']} files ({result['total_bytes']} bytes)")
163
+ except (ValueError, OSError) as e:
164
+ typer.echo(str(e), err=True)
165
+ raise typer.Exit(1)
166
+
167
+
112
168
  @app.command()
113
169
  def serve():
114
170
  typer.echo("Starting RepoPack MCP server (stdio)...", err=True)
@@ -3,7 +3,7 @@ from pathlib import Path
3
3
 
4
4
  from mcp.server.fastmcp import FastMCP
5
5
 
6
- from repopack.packer import pack_workspace
6
+ from repopack.packer import fix_workspace, pack_workspace, validate_workspace
7
7
  from repopack.unpacker import unpack_workspace
8
8
 
9
9
  mcp = FastMCP("RepoPack")
@@ -49,6 +49,45 @@ def import_workspace(
49
49
  return f"Extracted {summary['extracted']} files to {summary['destination']} ({summary['skipped']} skipped)"
50
50
 
51
51
 
52
+ @mcp.tool()
53
+ def validate_workspace_tool(
54
+ json_path: str,
55
+ workspace_path: str = ".",
56
+ ) -> str:
57
+ report = validate_workspace(json_path, Path(workspace_path))
58
+ s = report["summary"]
59
+ lines = [
60
+ f"Status : {'OK' if report['valid'] else 'OUTDATED'}",
61
+ f"Missing from JSON : {s['missing_from_json']}",
62
+ f"Extra in JSON : {s['extra_in_json']}",
63
+ f"Stale in JSON : {s['stale_in_json']}",
64
+ f"Up to date : {s['up_to_date']}",
65
+ ]
66
+ for p in report["missing_from_json"]:
67
+ lines.append(f" + {p}")
68
+ for p in report["extra_in_json"]:
69
+ lines.append(f" - {p}")
70
+ for p in report["stale_in_json"]:
71
+ lines.append(f" ~ {p}")
72
+ return "\n".join(lines)
73
+
74
+
75
+ @mcp.tool()
76
+ def fix_workspace_tool(
77
+ json_path: str,
78
+ workspace_path: str = ".",
79
+ include_binary: bool = False,
80
+ ) -> str:
81
+ result = fix_workspace(json_path, Path(workspace_path), include_binary=include_binary)
82
+ return (
83
+ f"Updated {result['json_path']}: "
84
+ f"+{len(result['added'])} added, "
85
+ f"-{len(result['removed'])} removed, "
86
+ f"~{len(result['refreshed'])} refreshed. "
87
+ f"Total: {result['total_files']} files ({result['total_bytes']} bytes)."
88
+ )
89
+
90
+
52
91
  def run_server():
53
92
  mcp.run(transport="stdio")
54
93
 
@@ -1,5 +1,6 @@
1
1
  import base64
2
2
  import datetime
3
+ import json
3
4
  import os
4
5
  import sys
5
6
  from pathlib import Path
@@ -109,3 +110,72 @@ def pack_workspace(
109
110
  },
110
111
  "files": files,
111
112
  }
113
+
114
+
115
+ def validate_workspace(json_path: str, directory: Path) -> dict:
116
+ """Compare a packed JSON against the live workspace and report differences."""
117
+ with open(json_path, "r", encoding="utf-8") as f:
118
+ data = json.load(f)
119
+
120
+ if "files" not in data:
121
+ raise ValueError("Malformed JSON: missing 'files' key.")
122
+
123
+ packed_paths = {entry["path"] for entry in data["files"]}
124
+
125
+ live = pack_workspace(directory, dry_run=True)
126
+ live_files = {f["path"]: f for f in live["files"]}
127
+ live_paths = set(live_files)
128
+
129
+ missing = sorted(live_paths - packed_paths) # in workspace, not in JSON
130
+ extra = sorted(packed_paths - live_paths) # in JSON, not in workspace
131
+ common = packed_paths & live_paths
132
+
133
+ stale: list[str] = []
134
+ for path in sorted(common):
135
+ live_size = live_files[path]["size"]
136
+ disk_path = directory.resolve() / path
137
+ try:
138
+ packed_entry = next(e for e in data["files"] if e["path"] == path)
139
+ packed_len = len(packed_entry.get("content", ""))
140
+ # Compare mtime-derived size vs packed content length as a quick staleness check.
141
+ # For utf-8 files packed content length approximates byte size; good enough to flag.
142
+ if abs(live_size - packed_len) > 0:
143
+ stale.append(path)
144
+ except (StopIteration, OSError):
145
+ pass
146
+
147
+ up_to_date = len(common) - len(stale)
148
+
149
+ return {
150
+ "json_path": json_path,
151
+ "workspace": str(directory.resolve()),
152
+ "summary": {
153
+ "missing_from_json": len(missing),
154
+ "extra_in_json": len(extra),
155
+ "stale_in_json": len(stale),
156
+ "up_to_date": up_to_date,
157
+ },
158
+ "missing_from_json": missing,
159
+ "extra_in_json": extra,
160
+ "stale_in_json": stale,
161
+ "valid": len(missing) == 0 and len(extra) == 0 and len(stale) == 0,
162
+ }
163
+
164
+
165
+ def fix_workspace(json_path: str, directory: Path, include_binary: bool = False) -> dict:
166
+ """Re-pack the live workspace and overwrite the JSON file with the latest content."""
167
+ report = validate_workspace(json_path, directory)
168
+
169
+ result = pack_workspace(directory, include_binary=include_binary)
170
+ with open(json_path, "w", encoding="utf-8") as f:
171
+ json.dump(result, f, indent=2)
172
+
173
+ return {
174
+ "json_path": json_path,
175
+ "workspace": str(directory.resolve()),
176
+ "added": report["missing_from_json"],
177
+ "removed": report["extra_in_json"],
178
+ "refreshed": report["stale_in_json"],
179
+ "total_files": result["metadata"]["total_files"],
180
+ "total_bytes": result["metadata"]["total_bytes"],
181
+ }
repopackpy-0.1.8/PKG-INFO DELETED
@@ -1,153 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: RepoPackPy
3
- Version: 0.1.8
4
- Summary: Pack/unpack any source workspace into portable JSON, with MCP server support.
5
- License: MIT
6
- License-File: LICENSE
7
- Requires-Python: >=3.10
8
- Requires-Dist: mcp[cli]>=1.0
9
- Requires-Dist: pathspec>=0.12
10
- Requires-Dist: typer>=0.12
11
- Provides-Extra: dev
12
- Requires-Dist: pytest>=8; extra == 'dev'
13
- Description-Content-Type: text/markdown
14
-
15
- # RepoPack
16
-
17
- Pack/unpack **any source workspace regardless of technology stack** (Python, Node.js, React, Angular, Vue, Rust, Go, Java, C#, and more) into a portable, structured JSON payload — and restore it faithfully from that payload.
18
-
19
- ## Features
20
-
21
- - **Universal ignore engine** — respects root and nested `.gitignore` files plus stack-agnostic defaults (node_modules, __pycache__, .venv, target/, dist/, secrets, lock files, …)
22
- - **Polyglot stack detection** — auto-detects Node.js, React, TypeScript, Angular, Next.js, Vue, Python, Rust, Go, Java, C# from project sentinel files
23
- - **Binary safety** — text files encoded as UTF-8; binaries skipped by default or included as Base64 with `--include-binary`
24
- - **5 MB guard** — files larger than 5 MB are skipped with a warning
25
- - **Path traversal shield** — `unpack` validates every path against the destination root before writing anything
26
- - **MCP server** — expose pack/unpack as tools to any MCP-compatible AI client (Claude Desktop, etc.)
27
-
28
- ## Installation
29
-
30
- ### From PyPI (recommended)
31
-
32
- Install the latest stable release:
33
-
34
- ```bash
35
- pip install RepoPackPy
36
- ```
37
-
38
- Pin to a specific version:
39
-
40
- ```bash
41
- pip install RepoPackPy==0.1.1
42
- ```
43
-
44
- Requires Python 3.10+.
45
-
46
- ### Quick start after install
47
-
48
- ```bash
49
- # Verify the install
50
- repopack --help
51
-
52
- # Pack your project
53
- repopack pack . -o my-workspace.json
54
-
55
- # Restore it somewhere else
56
- repopack unpack my-workspace.json -t ./restored
57
- ```
58
-
59
- ### For development
60
-
61
- Clone the repo and install in editable mode with test dependencies:
62
-
63
- ```bash
64
- git clone https://github.com/ShanKonduru/RepoPack.git
65
- cd RepoPack
66
- pip install -e ".[dev]"
67
- ```
68
-
69
- ## CLI Usage
70
-
71
- ```bash
72
- # Pack a directory into JSON
73
- repopack pack [DIRECTORY] [-o output.json] [--include-binary] [--custom-ignore ".next,dist"]
74
-
75
- # Unpack JSON back into a directory
76
- repopack unpack <input.json> [-t TARGET_DIR] [--force]
77
-
78
- # Start the MCP server (stdio transport)
79
- repopack serve
80
- ```
81
-
82
- ### Examples
83
-
84
- ```bash
85
- # Pack current directory, write to file
86
- repopack pack . -o workspace.json
87
-
88
- # Pack a specific project, include binaries
89
- repopack pack ~/projects/my-app -o my-app.json --include-binary
90
-
91
- # Unpack into a new directory
92
- repopack unpack workspace.json -t ./restored
93
-
94
- # Unpack and overwrite existing files
95
- repopack unpack workspace.json -t ./restored --force
96
- ```
97
-
98
- ## JSON Payload Schema
99
-
100
- ```json
101
- {
102
- "version": "1.0",
103
- "metadata": {
104
- "created_at": "2026-07-26T12:00:00Z",
105
- "root_directory_name": "my-app",
106
- "detected_stack": ["Node.js", "React", "TypeScript"],
107
- "total_files": 38,
108
- "total_bytes": 128450
109
- },
110
- "files": [
111
- { "path": "src/App.tsx", "encoding": "utf-8", "content": "..." },
112
- { "path": "public/favicon.ico", "encoding": "base64", "content": "..." }
113
- ]
114
- }
115
- ```
116
-
117
- ## MCP Server Tools
118
-
119
- When running `repopack serve`, two tools are registered via FastMCP:
120
-
121
- | Tool | Description |
122
- |---|---|
123
- | `export_workspace(workspace_path, output_json_path, include_binary)` | Pack a directory into JSON |
124
- | `import_workspace(json_input, destination_path, overwrite)` | Unpack JSON into a directory |
125
-
126
- ## Project Structure
127
-
128
- ```
129
- repopack/
130
- ├── pyproject.toml
131
- ├── README.md
132
- └── repopack/
133
- ├── __init__.py
134
- ├── cli.py # Typer CLI (pack / unpack / serve)
135
- ├── mcp_server.py # FastMCP server
136
- ├── packer.py # Directory walker & JSON builder
137
- ├── unpacker.py # JSON extractor & path-safe reconstructor
138
- └── utils.py # Ignore engine, binary detector, stack detection
139
- tests/
140
- └── test_repopack.py # 26-test pytest suite
141
- ```
142
-
143
- ## Running Tests
144
-
145
- ```bash
146
- pytest tests/ -v
147
- ```
148
-
149
- ## Dependencies
150
-
151
- - [typer](https://typer.tiangolo.com/) — CLI framework
152
- - [mcp](https://github.com/modelcontextprotocol/python-sdk) — MCP SDK (FastMCP)
153
- - [pathspec](https://github.com/cpburnz/python-pathspec) — gitignore wildmatch pattern matching
@@ -1,139 +0,0 @@
1
- # RepoPack
2
-
3
- Pack/unpack **any source workspace regardless of technology stack** (Python, Node.js, React, Angular, Vue, Rust, Go, Java, C#, and more) into a portable, structured JSON payload — and restore it faithfully from that payload.
4
-
5
- ## Features
6
-
7
- - **Universal ignore engine** — respects root and nested `.gitignore` files plus stack-agnostic defaults (node_modules, __pycache__, .venv, target/, dist/, secrets, lock files, …)
8
- - **Polyglot stack detection** — auto-detects Node.js, React, TypeScript, Angular, Next.js, Vue, Python, Rust, Go, Java, C# from project sentinel files
9
- - **Binary safety** — text files encoded as UTF-8; binaries skipped by default or included as Base64 with `--include-binary`
10
- - **5 MB guard** — files larger than 5 MB are skipped with a warning
11
- - **Path traversal shield** — `unpack` validates every path against the destination root before writing anything
12
- - **MCP server** — expose pack/unpack as tools to any MCP-compatible AI client (Claude Desktop, etc.)
13
-
14
- ## Installation
15
-
16
- ### From PyPI (recommended)
17
-
18
- Install the latest stable release:
19
-
20
- ```bash
21
- pip install RepoPackPy
22
- ```
23
-
24
- Pin to a specific version:
25
-
26
- ```bash
27
- pip install RepoPackPy==0.1.1
28
- ```
29
-
30
- Requires Python 3.10+.
31
-
32
- ### Quick start after install
33
-
34
- ```bash
35
- # Verify the install
36
- repopack --help
37
-
38
- # Pack your project
39
- repopack pack . -o my-workspace.json
40
-
41
- # Restore it somewhere else
42
- repopack unpack my-workspace.json -t ./restored
43
- ```
44
-
45
- ### For development
46
-
47
- Clone the repo and install in editable mode with test dependencies:
48
-
49
- ```bash
50
- git clone https://github.com/ShanKonduru/RepoPack.git
51
- cd RepoPack
52
- pip install -e ".[dev]"
53
- ```
54
-
55
- ## CLI Usage
56
-
57
- ```bash
58
- # Pack a directory into JSON
59
- repopack pack [DIRECTORY] [-o output.json] [--include-binary] [--custom-ignore ".next,dist"]
60
-
61
- # Unpack JSON back into a directory
62
- repopack unpack <input.json> [-t TARGET_DIR] [--force]
63
-
64
- # Start the MCP server (stdio transport)
65
- repopack serve
66
- ```
67
-
68
- ### Examples
69
-
70
- ```bash
71
- # Pack current directory, write to file
72
- repopack pack . -o workspace.json
73
-
74
- # Pack a specific project, include binaries
75
- repopack pack ~/projects/my-app -o my-app.json --include-binary
76
-
77
- # Unpack into a new directory
78
- repopack unpack workspace.json -t ./restored
79
-
80
- # Unpack and overwrite existing files
81
- repopack unpack workspace.json -t ./restored --force
82
- ```
83
-
84
- ## JSON Payload Schema
85
-
86
- ```json
87
- {
88
- "version": "1.0",
89
- "metadata": {
90
- "created_at": "2026-07-26T12:00:00Z",
91
- "root_directory_name": "my-app",
92
- "detected_stack": ["Node.js", "React", "TypeScript"],
93
- "total_files": 38,
94
- "total_bytes": 128450
95
- },
96
- "files": [
97
- { "path": "src/App.tsx", "encoding": "utf-8", "content": "..." },
98
- { "path": "public/favicon.ico", "encoding": "base64", "content": "..." }
99
- ]
100
- }
101
- ```
102
-
103
- ## MCP Server Tools
104
-
105
- When running `repopack serve`, two tools are registered via FastMCP:
106
-
107
- | Tool | Description |
108
- |---|---|
109
- | `export_workspace(workspace_path, output_json_path, include_binary)` | Pack a directory into JSON |
110
- | `import_workspace(json_input, destination_path, overwrite)` | Unpack JSON into a directory |
111
-
112
- ## Project Structure
113
-
114
- ```
115
- repopack/
116
- ├── pyproject.toml
117
- ├── README.md
118
- └── repopack/
119
- ├── __init__.py
120
- ├── cli.py # Typer CLI (pack / unpack / serve)
121
- ├── mcp_server.py # FastMCP server
122
- ├── packer.py # Directory walker & JSON builder
123
- ├── unpacker.py # JSON extractor & path-safe reconstructor
124
- └── utils.py # Ignore engine, binary detector, stack detection
125
- tests/
126
- └── test_repopack.py # 26-test pytest suite
127
- ```
128
-
129
- ## Running Tests
130
-
131
- ```bash
132
- pytest tests/ -v
133
- ```
134
-
135
- ## Dependencies
136
-
137
- - [typer](https://typer.tiangolo.com/) — CLI framework
138
- - [mcp](https://github.com/modelcontextprotocol/python-sdk) — MCP SDK (FastMCP)
139
- - [pathspec](https://github.com/cpburnz/python-pathspec) — gitignore wildmatch pattern matching
@@ -1 +0,0 @@
1
- __version__ = "0.1.8"
File without changes
File without changes
File without changes
File without changes
File without changes