contextzip 0.2.0__tar.gz → 0.2.2__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.
- {contextzip-0.2.0 → contextzip-0.2.2}/PKG-INFO +19 -2
- {contextzip-0.2.0 → contextzip-0.2.2}/README.md +18 -1
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/__init__.py +1 -1
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/cli.py +254 -42
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip.egg-info/PKG-INFO +19 -2
- {contextzip-0.2.0 → contextzip-0.2.2}/pyproject.toml +1 -1
- {contextzip-0.2.0 → contextzip-0.2.2}/LICENSE +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/clipboard.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/detector.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/filters.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/git.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/packager.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/rules/__init__.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/rules/base.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/rules/go.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/rules/node.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/rules/python.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip/rules/rust.py +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip.egg-info/SOURCES.txt +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip.egg-info/dependency_links.txt +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip.egg-info/entry_points.txt +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip.egg-info/requires.txt +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/contextzip.egg-info/top_level.txt +0 -0
- {contextzip-0.2.0 → contextzip-0.2.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: contextzip
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Intelligently package your codebase for AI tools
|
|
5
5
|
Author-email: Deepesh <akadeepesh@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -112,6 +112,8 @@ contextzip [OPTIONS]
|
|
|
112
112
|
|---|---|
|
|
113
113
|
| `-i`, `--include PATH` | Only include files under this path. Repeatable. |
|
|
114
114
|
| `-e`, `--exclude PATTERN` | Extra exclusion patterns (gitignore syntax). Repeatable. |
|
|
115
|
+
| `exclude` | Subcommand: exclude specific files/patterns. `contextzip exclude CHANGELOG.md LICENSE .github/` |
|
|
116
|
+
| `include` | Subcommand: include only specific paths. `contextzip include src/ app/` |
|
|
115
117
|
| `--git-changes` | Only include files reported by git as modified, staged, or untracked. |
|
|
116
118
|
| `-n`, `--dry-run` | Preview what would be included, no ZIP created. |
|
|
117
119
|
| `-o`, `--output FILE` | Custom output path for the ZIP file. |
|
|
@@ -140,6 +142,21 @@ contextzip --include src --include app
|
|
|
140
142
|
contextzip --exclude "*.log" --exclude "*.sqlite" --exclude "tests/"
|
|
141
143
|
```
|
|
142
144
|
|
|
145
|
+
**Exclude files using the subcommand (space-separated, no repetition):**
|
|
146
|
+
```bash
|
|
147
|
+
contextzip exclude CHANGELOG.md CONTRIBUTING.md LICENSE .github/
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Exclude with flags:**
|
|
151
|
+
```bash
|
|
152
|
+
contextzip exclude CHANGELOG.md --dry-run --verbose
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Include only specific directories using the subcommand:**
|
|
156
|
+
```bash
|
|
157
|
+
contextzip include src/ app/
|
|
158
|
+
```
|
|
159
|
+
|
|
143
160
|
**Only package files changed in git:**
|
|
144
161
|
```bash
|
|
145
162
|
contextzip --git-changes
|
|
@@ -234,7 +251,7 @@ contextzip surfaces issues before they waste your time:
|
|
|
234
251
|
contextzip/
|
|
235
252
|
├── contextzip/
|
|
236
253
|
│ ├── __init__.py # version string
|
|
237
|
-
│ ├── cli.py # Click entry point, all flags, rich output
|
|
254
|
+
│ ├── cli.py # Click entry point, all flags, subcommands (exclude, include), rich output
|
|
238
255
|
│ ├── detector.py # framework/language detection engine
|
|
239
256
|
│ ├── filters.py # pathspec-based file filtering + ResolveResult
|
|
240
257
|
│ ├── git.py # git status parsing + changed-file detection
|
|
@@ -84,6 +84,8 @@ contextzip [OPTIONS]
|
|
|
84
84
|
|---|---|
|
|
85
85
|
| `-i`, `--include PATH` | Only include files under this path. Repeatable. |
|
|
86
86
|
| `-e`, `--exclude PATTERN` | Extra exclusion patterns (gitignore syntax). Repeatable. |
|
|
87
|
+
| `exclude` | Subcommand: exclude specific files/patterns. `contextzip exclude CHANGELOG.md LICENSE .github/` |
|
|
88
|
+
| `include` | Subcommand: include only specific paths. `contextzip include src/ app/` |
|
|
87
89
|
| `--git-changes` | Only include files reported by git as modified, staged, or untracked. |
|
|
88
90
|
| `-n`, `--dry-run` | Preview what would be included, no ZIP created. |
|
|
89
91
|
| `-o`, `--output FILE` | Custom output path for the ZIP file. |
|
|
@@ -112,6 +114,21 @@ contextzip --include src --include app
|
|
|
112
114
|
contextzip --exclude "*.log" --exclude "*.sqlite" --exclude "tests/"
|
|
113
115
|
```
|
|
114
116
|
|
|
117
|
+
**Exclude files using the subcommand (space-separated, no repetition):**
|
|
118
|
+
```bash
|
|
119
|
+
contextzip exclude CHANGELOG.md CONTRIBUTING.md LICENSE .github/
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Exclude with flags:**
|
|
123
|
+
```bash
|
|
124
|
+
contextzip exclude CHANGELOG.md --dry-run --verbose
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Include only specific directories using the subcommand:**
|
|
128
|
+
```bash
|
|
129
|
+
contextzip include src/ app/
|
|
130
|
+
```
|
|
131
|
+
|
|
115
132
|
**Only package files changed in git:**
|
|
116
133
|
```bash
|
|
117
134
|
contextzip --git-changes
|
|
@@ -206,7 +223,7 @@ contextzip surfaces issues before they waste your time:
|
|
|
206
223
|
contextzip/
|
|
207
224
|
├── contextzip/
|
|
208
225
|
│ ├── __init__.py # version string
|
|
209
|
-
│ ├── cli.py # Click entry point, all flags, rich output
|
|
226
|
+
│ ├── cli.py # Click entry point, all flags, subcommands (exclude, include), rich output
|
|
210
227
|
│ ├── detector.py # framework/language detection engine
|
|
211
228
|
│ ├── filters.py # pathspec-based file filtering + ResolveResult
|
|
212
229
|
│ ├── git.py # git status parsing + changed-file detection
|
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
"""
|
|
2
2
|
cli.py — contextzip entry point. Phases 1–5 complete.
|
|
3
|
+
|
|
4
|
+
Command surface
|
|
5
|
+
───────────────
|
|
6
|
+
Main command (unchanged, fully backwards-compatible):
|
|
7
|
+
contextzip [OPTIONS]
|
|
8
|
+
-i / --include PATH only include files under these paths (repeatable)
|
|
9
|
+
-e / --exclude PATTERN extra exclusion patterns (repeatable)
|
|
10
|
+
-n / --dry-run preview without creating ZIP
|
|
11
|
+
-o / --output FILE custom output path
|
|
12
|
+
--no-clipboard skip clipboard / folder-open step
|
|
13
|
+
--no-gitignore ignore project .gitignore
|
|
14
|
+
--git-changes only package files changed in git
|
|
15
|
+
-v / --verbose show every file decision
|
|
16
|
+
|
|
17
|
+
Subcommands (new — all modifier flags available on each):
|
|
18
|
+
contextzip exclude PATTERN… [OPTIONS]
|
|
19
|
+
contextzip include PATH… [OPTIONS]
|
|
20
|
+
|
|
21
|
+
Both subcommands accept the same modifier flags as the main command so that
|
|
22
|
+
the flags naturally follow the verb, matching the git / docker / cargo UX:
|
|
23
|
+
contextzip exclude CHANGELOG.md --dry-run --verbose
|
|
24
|
+
contextzip include src/ app/ --output ~/Desktop/out.zip
|
|
3
25
|
"""
|
|
4
26
|
|
|
5
27
|
from __future__ import annotations
|
|
@@ -30,55 +52,88 @@ console = Console()
|
|
|
30
52
|
|
|
31
53
|
|
|
32
54
|
# ---------------------------------------------------------------------------
|
|
33
|
-
#
|
|
55
|
+
# Shared modifier-flag decorator
|
|
34
56
|
# ---------------------------------------------------------------------------
|
|
57
|
+
# Defined once so the main command and every subcommand declare exactly the
|
|
58
|
+
# same flags without duplicating help strings.
|
|
59
|
+
|
|
60
|
+
def _modifier_options(f):
|
|
61
|
+
"""
|
|
62
|
+
Attach all run-modifier flags to a command.
|
|
63
|
+
|
|
64
|
+
Applied to both the main command and every subcommand so that flags
|
|
65
|
+
always follow the verb — matching the git / docker / cargo convention:
|
|
66
|
+
contextzip exclude CHANGELOG.md --dry-run --verbose
|
|
67
|
+
"""
|
|
68
|
+
decorators = [
|
|
69
|
+
click.option(
|
|
70
|
+
"--dry-run", "-n",
|
|
71
|
+
is_flag=True, default=False,
|
|
72
|
+
help="Show what would be included without creating the ZIP.",
|
|
73
|
+
),
|
|
74
|
+
click.option(
|
|
75
|
+
"--output", "-o",
|
|
76
|
+
default=None, metavar="FILE",
|
|
77
|
+
help="Output ZIP path. Defaults to <project>_context_<timestamp>.zip in temp dir.",
|
|
78
|
+
),
|
|
79
|
+
click.option(
|
|
80
|
+
"--no-clipboard",
|
|
81
|
+
is_flag=True, default=False,
|
|
82
|
+
help="Skip clipboard / folder-open step after creating the ZIP.",
|
|
83
|
+
),
|
|
84
|
+
click.option(
|
|
85
|
+
"--no-gitignore",
|
|
86
|
+
is_flag=True, default=False,
|
|
87
|
+
help="Ignore the project's .gitignore file (use only built-in rules).",
|
|
88
|
+
),
|
|
89
|
+
click.option(
|
|
90
|
+
"--git-changes",
|
|
91
|
+
is_flag=True, default=False,
|
|
92
|
+
help=(
|
|
93
|
+
"Only include files that git reports as modified, added, or untracked. "
|
|
94
|
+
"Requires the project to be inside a git repository."
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
click.option(
|
|
98
|
+
"--verbose", "-v",
|
|
99
|
+
is_flag=True, default=False,
|
|
100
|
+
help="Show every included and excluded file.",
|
|
101
|
+
),
|
|
102
|
+
]
|
|
103
|
+
for dec in reversed(decorators):
|
|
104
|
+
f = dec(f)
|
|
105
|
+
return f
|
|
106
|
+
|
|
35
107
|
|
|
36
|
-
|
|
108
|
+
# ---------------------------------------------------------------------------
|
|
109
|
+
# CLI group
|
|
110
|
+
# ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
@click.group(
|
|
113
|
+
invoke_without_command=True,
|
|
114
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
115
|
+
)
|
|
37
116
|
@click.option(
|
|
38
117
|
"--include", "-i",
|
|
39
118
|
multiple=True, metavar="PATH",
|
|
40
|
-
help=
|
|
41
|
-
|
|
119
|
+
help=(
|
|
120
|
+
"Only include files under these paths (relative to project root). "
|
|
121
|
+
"Repeatable: --include src --include app | or use: contextzip include src app"
|
|
122
|
+
),
|
|
42
123
|
)
|
|
43
124
|
@click.option(
|
|
44
125
|
"--exclude", "-e",
|
|
45
126
|
multiple=True, metavar="PATTERN",
|
|
46
|
-
help=
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"--dry-run", "-n",
|
|
51
|
-
is_flag=True, default=False,
|
|
52
|
-
help="Show what would be included without creating the ZIP.",
|
|
53
|
-
)
|
|
54
|
-
@click.option(
|
|
55
|
-
"--output", "-o",
|
|
56
|
-
default=None, metavar="FILE",
|
|
57
|
-
help="Output ZIP path. Defaults to <project>_context_<timestamp>.zip in temp dir.",
|
|
58
|
-
)
|
|
59
|
-
@click.option(
|
|
60
|
-
"--no-clipboard",
|
|
61
|
-
is_flag=True, default=False,
|
|
62
|
-
help="Skip clipboard / folder-open step after creating the ZIP.",
|
|
63
|
-
)
|
|
64
|
-
@click.option(
|
|
65
|
-
"--no-gitignore",
|
|
66
|
-
is_flag=True, default=False,
|
|
67
|
-
help="Ignore the project's .gitignore file (use only built-in rules).",
|
|
68
|
-
)
|
|
69
|
-
@click.option(
|
|
70
|
-
"--git-changes",
|
|
71
|
-
is_flag=True, default=False,
|
|
72
|
-
help="Only include files that git reports as modified, added, or untracked. "
|
|
73
|
-
"Requires the project to be inside a git repository.",
|
|
74
|
-
)
|
|
75
|
-
@click.option(
|
|
76
|
-
"--verbose", "-v",
|
|
77
|
-
is_flag=True, default=False,
|
|
78
|
-
help="Show every included and excluded file.",
|
|
127
|
+
help=(
|
|
128
|
+
"Extra exclusion patterns on top of auto-rules (gitignore syntax). "
|
|
129
|
+
"Repeatable: -e '*.log' -e CHANGELOG.md | or use: contextzip exclude CHANGELOG.md *.log"
|
|
130
|
+
),
|
|
79
131
|
)
|
|
132
|
+
@_modifier_options
|
|
80
133
|
@click.version_option(version=__version__, prog_name="contextzip")
|
|
134
|
+
@click.pass_context
|
|
81
135
|
def main(
|
|
136
|
+
ctx: click.Context,
|
|
82
137
|
include: tuple[str, ...],
|
|
83
138
|
exclude: tuple[str, ...],
|
|
84
139
|
dry_run: bool,
|
|
@@ -94,8 +149,132 @@ def main(
|
|
|
94
149
|
|
|
95
150
|
Run from your project root to produce a smart, lightweight ZIP
|
|
96
151
|
ready to paste directly into Claude, ChatGPT, or any AI interface.
|
|
152
|
+
|
|
153
|
+
\b
|
|
154
|
+
SUBCOMMANDS
|
|
155
|
+
contextzip exclude CHANGELOG.md LICENSE .github/
|
|
156
|
+
contextzip include src/ app/
|
|
157
|
+
|
|
158
|
+
Both subcommands accept the same flags as the main command:
|
|
159
|
+
contextzip exclude CHANGELOG.md --dry-run --verbose
|
|
160
|
+
"""
|
|
161
|
+
# A subcommand was invoked — let it handle everything.
|
|
162
|
+
if ctx.invoked_subcommand is not None:
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
_run(
|
|
166
|
+
extra_exclude=list(exclude),
|
|
167
|
+
include_only=list(include),
|
|
168
|
+
dry_run=dry_run,
|
|
169
|
+
output=output,
|
|
170
|
+
no_clipboard=no_clipboard,
|
|
171
|
+
no_gitignore=no_gitignore,
|
|
172
|
+
git_changes=git_changes,
|
|
173
|
+
verbose=verbose,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# ---------------------------------------------------------------------------
|
|
178
|
+
# Subcommand: exclude
|
|
179
|
+
# ---------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
@main.command("exclude")
|
|
182
|
+
@click.argument("patterns", nargs=-1, required=True, metavar="PATTERN…")
|
|
183
|
+
@_modifier_options
|
|
184
|
+
def cmd_exclude(
|
|
185
|
+
patterns: tuple[str, ...],
|
|
186
|
+
dry_run: bool,
|
|
187
|
+
output: str | None,
|
|
188
|
+
no_clipboard: bool,
|
|
189
|
+
no_gitignore: bool,
|
|
190
|
+
git_changes: bool,
|
|
191
|
+
verbose: bool,
|
|
192
|
+
) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Exclude specific files or patterns and package everything else.
|
|
195
|
+
|
|
196
|
+
\b
|
|
197
|
+
EXAMPLES
|
|
198
|
+
contextzip exclude CHANGELOG.md CONTRIBUTING.md LICENSE
|
|
199
|
+
contextzip exclude .github/ tests/ '*.log'
|
|
200
|
+
contextzip exclude CHANGELOG.md --dry-run --verbose
|
|
201
|
+
contextzip exclude .github/ CHANGELOG.md --output ~/Desktop/out.zip
|
|
202
|
+
|
|
203
|
+
Patterns follow gitignore syntax. Folders are matched with or without
|
|
204
|
+
a trailing slash: both '.github' and '.github/' work.
|
|
205
|
+
"""
|
|
206
|
+
_run(
|
|
207
|
+
extra_exclude=list(patterns),
|
|
208
|
+
include_only=None,
|
|
209
|
+
dry_run=dry_run,
|
|
210
|
+
output=output,
|
|
211
|
+
no_clipboard=no_clipboard,
|
|
212
|
+
no_gitignore=no_gitignore,
|
|
213
|
+
git_changes=git_changes,
|
|
214
|
+
verbose=verbose,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# ---------------------------------------------------------------------------
|
|
219
|
+
# Subcommand: include
|
|
220
|
+
# ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
@main.command("include")
|
|
223
|
+
@click.argument("paths", nargs=-1, required=True, metavar="PATH…")
|
|
224
|
+
@_modifier_options
|
|
225
|
+
def cmd_include(
|
|
226
|
+
paths: tuple[str, ...],
|
|
227
|
+
dry_run: bool,
|
|
228
|
+
output: str | None,
|
|
229
|
+
no_clipboard: bool,
|
|
230
|
+
no_gitignore: bool,
|
|
231
|
+
git_changes: bool,
|
|
232
|
+
verbose: bool,
|
|
233
|
+
) -> None:
|
|
97
234
|
"""
|
|
235
|
+
Package only the specified paths and skip everything else.
|
|
236
|
+
|
|
237
|
+
\b
|
|
238
|
+
EXAMPLES
|
|
239
|
+
contextzip include src/ app/
|
|
240
|
+
contextzip include src/ app/ --dry-run
|
|
241
|
+
contextzip include src/ --output ~/Desktop/out.zip --verbose
|
|
98
242
|
|
|
243
|
+
Paths are matched as exact prefixes at directory boundaries:
|
|
244
|
+
'src' matches 'src/index.ts' but not 'src2/index.ts'.
|
|
245
|
+
"""
|
|
246
|
+
_run(
|
|
247
|
+
extra_exclude=None,
|
|
248
|
+
include_only=list(paths),
|
|
249
|
+
dry_run=dry_run,
|
|
250
|
+
output=output,
|
|
251
|
+
no_clipboard=no_clipboard,
|
|
252
|
+
no_gitignore=no_gitignore,
|
|
253
|
+
git_changes=git_changes,
|
|
254
|
+
verbose=verbose,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# ---------------------------------------------------------------------------
|
|
259
|
+
# Core execution logic (shared by main command + all subcommands)
|
|
260
|
+
# ---------------------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
def _run(
|
|
263
|
+
*,
|
|
264
|
+
extra_exclude: list[str] | None,
|
|
265
|
+
include_only: list[str] | None,
|
|
266
|
+
dry_run: bool,
|
|
267
|
+
output: str | None,
|
|
268
|
+
no_clipboard: bool,
|
|
269
|
+
no_gitignore: bool,
|
|
270
|
+
git_changes: bool,
|
|
271
|
+
verbose: bool,
|
|
272
|
+
) -> None:
|
|
273
|
+
"""
|
|
274
|
+
All actual work lives here. The main command and every subcommand
|
|
275
|
+
delegate to this function after collecting their arguments/flags,
|
|
276
|
+
keeping the CLI surface thin and the logic testable in isolation.
|
|
277
|
+
"""
|
|
99
278
|
project_dir = Path(os.getcwd()).resolve()
|
|
100
279
|
|
|
101
280
|
# ── Header ───────────────────────────────────────────────────────────────
|
|
@@ -153,10 +332,15 @@ def main(
|
|
|
153
332
|
and gitignore_path.is_file()
|
|
154
333
|
)
|
|
155
334
|
|
|
335
|
+
normalized_exclude = (
|
|
336
|
+
[_normalize_pattern(p) for p in extra_exclude]
|
|
337
|
+
if extra_exclude else []
|
|
338
|
+
)
|
|
339
|
+
|
|
156
340
|
with console.status("[cyan]Building exclusion rules…[/]", spinner="dots"):
|
|
157
341
|
spec = build_spec(
|
|
158
342
|
rule_modules=detection.rule_modules,
|
|
159
|
-
extra_exclude=
|
|
343
|
+
extra_exclude=normalized_exclude if normalized_exclude else None,
|
|
160
344
|
gitignore_path=gitignore_path,
|
|
161
345
|
)
|
|
162
346
|
|
|
@@ -169,7 +353,7 @@ def main(
|
|
|
169
353
|
resolved = resolve_files(
|
|
170
354
|
project_dir=project_dir,
|
|
171
355
|
spec=spec,
|
|
172
|
-
include_only=
|
|
356
|
+
include_only=include_only if include_only else None,
|
|
173
357
|
)
|
|
174
358
|
|
|
175
359
|
# ── File scan summary ────────────────────────────────────────────────────
|
|
@@ -189,7 +373,8 @@ def main(
|
|
|
189
373
|
if len(resolved.large_files) > 5:
|
|
190
374
|
console.print(f" [dim]… and {len(resolved.large_files) - 5} more[/]")
|
|
191
375
|
console.print(
|
|
192
|
-
|
|
376
|
+
" [dim] Use [cyan]-e PATTERN[/] or [cyan]contextzip exclude PATTERN[/] "
|
|
377
|
+
"to drop them if unneeded.[/]"
|
|
193
378
|
)
|
|
194
379
|
|
|
195
380
|
# ── Warnings: binary files ───────────────────────────────────────────────
|
|
@@ -232,7 +417,7 @@ def main(
|
|
|
232
417
|
if not resolved.included:
|
|
233
418
|
console.print(
|
|
234
419
|
"\n[red]Nothing to package.[/] All files were excluded — "
|
|
235
|
-
"try [cyan]
|
|
420
|
+
"try [cyan]contextzip include PATH[/] or [cyan]-i PATH[/] to override."
|
|
236
421
|
)
|
|
237
422
|
return
|
|
238
423
|
|
|
@@ -272,6 +457,33 @@ def main(
|
|
|
272
457
|
_print_clipboard_result(cb)
|
|
273
458
|
|
|
274
459
|
|
|
460
|
+
# ---------------------------------------------------------------------------
|
|
461
|
+
# Normalisation
|
|
462
|
+
# ---------------------------------------------------------------------------
|
|
463
|
+
|
|
464
|
+
def _normalize_pattern(p: str) -> str:
|
|
465
|
+
"""
|
|
466
|
+
Canonicalise a user-supplied exclusion pattern.
|
|
467
|
+
|
|
468
|
+
Rules applied in order:
|
|
469
|
+
1. Strip a leading ``./`` or ``.\\`` so that ``./CHANGELOG.md``
|
|
470
|
+
and ``CHANGELOG.md`` are treated identically.
|
|
471
|
+
2. Replace every backslash with a forward slash for cross-platform
|
|
472
|
+
consistency (Windows paths entered on the CLI).
|
|
473
|
+
3. Collapse ``folder/*`` → ``folder/`` so that gitignore-style
|
|
474
|
+
directory globs work as expected.
|
|
475
|
+
"""
|
|
476
|
+
# 1. Strip leading ./ or .\
|
|
477
|
+
if p.startswith("./") or p.startswith(".\\"):
|
|
478
|
+
p = p[2:]
|
|
479
|
+
# 2. Normalise path separators
|
|
480
|
+
p = p.replace("\\", "/")
|
|
481
|
+
# 3. folder/* → folder/
|
|
482
|
+
if p.endswith("/*"):
|
|
483
|
+
p = p[:-1]
|
|
484
|
+
return p
|
|
485
|
+
|
|
486
|
+
|
|
275
487
|
# ---------------------------------------------------------------------------
|
|
276
488
|
# Display helpers
|
|
277
489
|
# ---------------------------------------------------------------------------
|
|
@@ -436,4 +648,4 @@ def _human_size(n: int) -> str:
|
|
|
436
648
|
if n < 1024:
|
|
437
649
|
return f"{n:.0f} {unit}"
|
|
438
650
|
n /= 1024
|
|
439
|
-
return f"{n:.1f} TB"
|
|
651
|
+
return f"{n:.1f} TB"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: contextzip
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Intelligently package your codebase for AI tools
|
|
5
5
|
Author-email: Deepesh <akadeepesh@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -112,6 +112,8 @@ contextzip [OPTIONS]
|
|
|
112
112
|
|---|---|
|
|
113
113
|
| `-i`, `--include PATH` | Only include files under this path. Repeatable. |
|
|
114
114
|
| `-e`, `--exclude PATTERN` | Extra exclusion patterns (gitignore syntax). Repeatable. |
|
|
115
|
+
| `exclude` | Subcommand: exclude specific files/patterns. `contextzip exclude CHANGELOG.md LICENSE .github/` |
|
|
116
|
+
| `include` | Subcommand: include only specific paths. `contextzip include src/ app/` |
|
|
115
117
|
| `--git-changes` | Only include files reported by git as modified, staged, or untracked. |
|
|
116
118
|
| `-n`, `--dry-run` | Preview what would be included, no ZIP created. |
|
|
117
119
|
| `-o`, `--output FILE` | Custom output path for the ZIP file. |
|
|
@@ -140,6 +142,21 @@ contextzip --include src --include app
|
|
|
140
142
|
contextzip --exclude "*.log" --exclude "*.sqlite" --exclude "tests/"
|
|
141
143
|
```
|
|
142
144
|
|
|
145
|
+
**Exclude files using the subcommand (space-separated, no repetition):**
|
|
146
|
+
```bash
|
|
147
|
+
contextzip exclude CHANGELOG.md CONTRIBUTING.md LICENSE .github/
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Exclude with flags:**
|
|
151
|
+
```bash
|
|
152
|
+
contextzip exclude CHANGELOG.md --dry-run --verbose
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Include only specific directories using the subcommand:**
|
|
156
|
+
```bash
|
|
157
|
+
contextzip include src/ app/
|
|
158
|
+
```
|
|
159
|
+
|
|
143
160
|
**Only package files changed in git:**
|
|
144
161
|
```bash
|
|
145
162
|
contextzip --git-changes
|
|
@@ -234,7 +251,7 @@ contextzip surfaces issues before they waste your time:
|
|
|
234
251
|
contextzip/
|
|
235
252
|
├── contextzip/
|
|
236
253
|
│ ├── __init__.py # version string
|
|
237
|
-
│ ├── cli.py # Click entry point, all flags, rich output
|
|
254
|
+
│ ├── cli.py # Click entry point, all flags, subcommands (exclude, include), rich output
|
|
238
255
|
│ ├── detector.py # framework/language detection engine
|
|
239
256
|
│ ├── filters.py # pathspec-based file filtering + ResolveResult
|
|
240
257
|
│ ├── git.py # git status parsing + changed-file detection
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|