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.
- repopackpy-0.2.0/PKG-INFO +262 -0
- repopackpy-0.2.0/README.md +248 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/pyproject.toml +1 -1
- repopackpy-0.2.0/repopack/__init__.py +1 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/repopack/cli.py +57 -1
- {repopackpy-0.1.8 → repopackpy-0.2.0}/repopack/mcp_server.py +40 -1
- {repopackpy-0.1.8 → repopackpy-0.2.0}/repopack/packer.py +70 -0
- repopackpy-0.1.8/PKG-INFO +0 -153
- repopackpy-0.1.8/README.md +0 -139
- repopackpy-0.1.8/repopack/__init__.py +0 -1
- {repopackpy-0.1.8 → repopackpy-0.2.0}/.github/workflows/ci.yml +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/.github/workflows/publish.yml +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/.github/workflows/security.yml +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/.gitignore +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/CLAUDE.md +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/LICENSE +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/repopack/unpacker.py +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/repopack/utils.py +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/system_prompt.txt +0 -0
- {repopackpy-0.1.8 → repopackpy-0.2.0}/tests/test_repopack.py +0 -0
|
@@ -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
|
|
@@ -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
|
repopackpy-0.1.8/README.md
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|