gwc-pybundle 1.4.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of gwc-pybundle might be problematic. Click here for more details.

Files changed (55) hide show
  1. gwc_pybundle-1.4.5.dist-info/METADATA +876 -0
  2. gwc_pybundle-1.4.5.dist-info/RECORD +55 -0
  3. gwc_pybundle-1.4.5.dist-info/WHEEL +5 -0
  4. gwc_pybundle-1.4.5.dist-info/entry_points.txt +2 -0
  5. gwc_pybundle-1.4.5.dist-info/licenses/LICENSE.md +25 -0
  6. gwc_pybundle-1.4.5.dist-info/top_level.txt +1 -0
  7. pybundle/__init__.py +0 -0
  8. pybundle/__main__.py +4 -0
  9. pybundle/cli.py +365 -0
  10. pybundle/context.py +362 -0
  11. pybundle/doctor.py +148 -0
  12. pybundle/filters.py +178 -0
  13. pybundle/manifest.py +77 -0
  14. pybundle/packaging.py +45 -0
  15. pybundle/policy.py +132 -0
  16. pybundle/profiles.py +340 -0
  17. pybundle/roadmap_model.py +42 -0
  18. pybundle/roadmap_scan.py +295 -0
  19. pybundle/root_detect.py +14 -0
  20. pybundle/runner.py +163 -0
  21. pybundle/steps/__init__.py +26 -0
  22. pybundle/steps/bandit.py +72 -0
  23. pybundle/steps/base.py +20 -0
  24. pybundle/steps/compileall.py +76 -0
  25. pybundle/steps/context_expand.py +272 -0
  26. pybundle/steps/copy_pack.py +293 -0
  27. pybundle/steps/coverage.py +101 -0
  28. pybundle/steps/cprofile_step.py +155 -0
  29. pybundle/steps/dependency_sizes.py +120 -0
  30. pybundle/steps/duplication.py +94 -0
  31. pybundle/steps/error_refs.py +204 -0
  32. pybundle/steps/handoff_md.py +167 -0
  33. pybundle/steps/import_time.py +165 -0
  34. pybundle/steps/interrogate.py +84 -0
  35. pybundle/steps/license_scan.py +96 -0
  36. pybundle/steps/line_profiler.py +108 -0
  37. pybundle/steps/memory_profile.py +173 -0
  38. pybundle/steps/mutation_testing.py +136 -0
  39. pybundle/steps/mypy.py +60 -0
  40. pybundle/steps/pip_audit.py +45 -0
  41. pybundle/steps/pipdeptree.py +61 -0
  42. pybundle/steps/pylance.py +562 -0
  43. pybundle/steps/pytest.py +66 -0
  44. pybundle/steps/radon.py +121 -0
  45. pybundle/steps/repro_md.py +161 -0
  46. pybundle/steps/rg_scans.py +78 -0
  47. pybundle/steps/roadmap.py +153 -0
  48. pybundle/steps/ruff.py +111 -0
  49. pybundle/steps/shell.py +74 -0
  50. pybundle/steps/slow_tests.py +170 -0
  51. pybundle/steps/test_flakiness.py +172 -0
  52. pybundle/steps/tree.py +116 -0
  53. pybundle/steps/unused_deps.py +112 -0
  54. pybundle/steps/vulture.py +83 -0
  55. pybundle/tools.py +63 -0
@@ -0,0 +1,876 @@
1
+ Metadata-Version: 2.4
2
+ Name: gwc-pybundle
3
+ Version: 1.4.5
4
+ Summary: Deterministic Python project context bundling for humans, automation, and AI
5
+ Author-email: Jessica Brown <jessica@codenamejessica.com>
6
+ License: The MIT License (MIT)
7
+ =====================
8
+
9
+ Copyright © 2025 Jessica Brown
10
+
11
+ Permission is hereby granted, free of charge, to any person
12
+ obtaining a copy of this software and associated documentation
13
+ files (the “Software”), to deal in the Software without
14
+ restriction, including without limitation the rights to use,
15
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the
17
+ Software is furnished to do so, subject to the following
18
+ conditions:
19
+
20
+ The above copyright notice and this permission notice shall be
21
+ included in all copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
24
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30
+ OTHER DEALINGS IN THE SOFTWARE.
31
+ Project-URL: Homepage, https://github.com/girls-whocode/pybundle
32
+ Project-URL: Repository, https://github.com/girls-whocode/pybundle
33
+ Project-URL: Issues, https://github.com/girls-whocode/pybundle/issues
34
+ Classifier: Development Status :: 5 - Production/Stable
35
+ Classifier: Intended Audience :: Developers
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.9
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Topic :: Software Development :: Build Tools
43
+ Classifier: Topic :: Software Development :: Debuggers
44
+ Classifier: Topic :: Software Development :: Quality Assurance
45
+ Requires-Python: >=3.9
46
+ Description-Content-Type: text/markdown
47
+ License-File: LICENSE.md
48
+ Requires-Dist: colorama>=0.4.6
49
+ Dynamic: license-file
50
+
51
+ # 🧳 pybundle ![PyPI - Version](https://img.shields.io/pypi/v/gwc-pybundle)
52
+
53
+ ![GitHub Release Date](https://img.shields.io/github/release-date/girls-whocode/pybundle?color=orange)
54
+
55
+ [![Python versions](https://img.shields.io/pypi/pyversions/gwc-pybundle.svg?color=3776AB)](https://pypi.org/project/gwc-pybundle/)
56
+ [![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE.md)
57
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/gwc-pybundle?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLUE&right_color=GREY&left_text=downloads)](https://pepy.tech/projects/gwc-pybundle)
58
+ ![GitHub Sponsors](https://img.shields.io/github/sponsors/girls-whocode?color=ec4899)
59
+
60
+ [![CI](https://github.com/girls-whocode/pybundle/actions/workflows/publish.yml/badge.svg?color=fb923c)](https://github.com/girls-whocode/pybundle/actions)
61
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-14b8a6.svg)](https://github.com/astral-sh/ruff)
62
+ [![Type checked](https://img.shields.io/badge/type%20checked-mypy-0ea5e9.svg)](https://mypy-lang.org/)
63
+ ![Commit Activity](https://img.shields.io/github/commit-activity/t/girls-whocode/pybundle?color=f59e0b)
64
+
65
+
66
+ **pybundle** is a deterministic, automation-friendly CLI that captures Python project context into a single, reproducible bundle — ideal for debugging, CI artifacts, audits, and AI-assisted workflows.
67
+
68
+ It produces **machine-readable outputs first**, with optional human-readable summaries layered on top.
69
+
70
+ > Think “`git archive` + diagnostics + metadata”, without guessing or heuristics.
71
+
72
+ > **Note:** The PyPI package name is `gwc-pybundle`, but the tool is installed and used as `pybundle`.
73
+ ---
74
+
75
+ ## 🧠 Why pybundle exists
76
+
77
+ Modern software development compresses what used to be entire teams into a single role.
78
+
79
+ Today, one developer is often responsible for:
80
+ - application code
81
+ - build systems
82
+ - test tooling
83
+ - deployment logic
84
+ - CI/CD behavior
85
+ - environment differences
86
+ - security implications
87
+ - and increasingly, AI-assisted workflows
88
+
89
+ The problem is no longer *how* to write code.
90
+
91
+ It’s answering:
92
+
93
+ > **“Why is this system behaving the way it is?”**
94
+
95
+ That question is hard to answer when:
96
+ - context is scattered
97
+ - tooling output is ephemeral
98
+ - environment details are lost
99
+ - source snapshots are incomplete or noisy
100
+
101
+ AI didn’t create this problem - it exposed it.
102
+
103
+ Large language models don’t fail because they lack intelligence.
104
+ They fail because we give them **uncurated context**.
105
+
106
+ Humans don’t fail because they can’t debug.
107
+ They fail because the **cost of reconstructing context** exceeds the time they have.
108
+
109
+ **pybundle exists to reduce context debt.**
110
+
111
+ It captures *what matters*, ignores what doesn’t, and produces a deterministic artifact that explains:
112
+ - what code exists
113
+ - what tools ran
114
+ - what environment was used
115
+ - and why the outputs exist
116
+
117
+ For humans, automation, and AI alike.
118
+
119
+ ---
120
+
121
+ ## ✨ Features
122
+
123
+ * 📦 **Single archive output** (`.zip` or `.tar.gz`)
124
+ * 🧠 **Machine-readable manifest** (`MANIFEST.json`) for automation
125
+ * 🧾 **Structured summaries** (`SUMMARY.json`)
126
+ * 🧭 **Respects `.gitignore`** exactly when available
127
+ * 🛑 **Safely ignores virtualenvs and caches** (even with non-standard names)
128
+ * 🔍 Optional tooling checks (ruff, mypy, pytest, pylance, bandit, pip-audit, coverage)
129
+ * 🛡️ Security scanning (bandit for code issues, pip-audit for dependency CVEs)
130
+ * 🧪 Deterministic output (stable paths, timestamps, schemas)
131
+ * 🔒 Secret-safe (optional redaction)
132
+
133
+ ---
134
+
135
+ ## 📂 What’s in a pybundle archive?
136
+
137
+ At minimum, a bundle contains:
138
+
139
+ ```text
140
+ MANIFEST.json # stable, machine-readable metadata
141
+ SUMMARY.json # structured summary of collected data
142
+ src/ # filtered project source snapshot
143
+ logs/ # tool outputs (ruff, mypy, pytest, pylance, bandit, pip-audit, coverage, rg scans)
144
+ meta/ # environment + tool detection
145
+ ```
146
+
147
+ ### `MANIFEST.json` (automation fuel)
148
+
149
+ Includes:
150
+
151
+ * tool paths detected
152
+ * options used
153
+ * archive name + format
154
+ * git commit hash (if available)
155
+ * UTC timestamp
156
+ * schema version (stable)
157
+
158
+ Another script can fully understand a bundle **without reading markdown**.
159
+
160
+ ---
161
+
162
+ ## 🚀 Installation
163
+
164
+ We recommend using a Python virtual environment for development tooling.
165
+
166
+ ### Quick installation (pybundle tooling) - RECOMMENDED
167
+
168
+ Create a dedicated requirements file in the root of your project:
169
+
170
+ ```txt
171
+ # requirements-pybundle.txt
172
+ ruff
173
+ mypy
174
+ pytest
175
+ pytest-cov
176
+ bandit
177
+ pip-audit
178
+ gwc-pybundle==1.3.1
179
+ ```
180
+
181
+ Then install:
182
+
183
+ ```bash
184
+ pip install -r requirements-pybundle.txt
185
+ ```
186
+
187
+ > **System dependency:**
188
+ > pybundle uses `ripgrep (rg)` for source scanning and expects the system binary.
189
+ >
190
+ > * macOS: `brew install ripgrep`
191
+ > * Ubuntu/Debian: `sudo apt install ripgrep`
192
+ > * Fedora: `sudo dnf install ripgrep`
193
+
194
+ After installation, run:
195
+
196
+ ```bash
197
+ pybundle run analysis
198
+ ```
199
+
200
+ A new `artifacts/` directory will be created containing:
201
+
202
+ * the compressed bundle
203
+ * an extracted working directory
204
+ * machine-readable metadata (`MANIFEST.json`, `SUMMARY.json`)
205
+
206
+ See **Usage** for more details.
207
+
208
+ ---
209
+
210
+ ### Advanced installation
211
+
212
+ #### From GitHub
213
+
214
+ ```bash
215
+ pip install "gwc-pybundle @ git+https://github.com/girls-whocode/pybundle.git@v1.3.1"
216
+ ```
217
+
218
+ Pinning to a tag ensures reproducible behavior.
219
+
220
+ #### Editable install (for development)
221
+
222
+ ```bash
223
+ pip install -e .
224
+ ```
225
+
226
+ ---
227
+
228
+ ## 🧪 Usage
229
+
230
+ From the root of a Python project, run a profile using the `run` command:
231
+
232
+ ```bash
233
+ pybundle run analysis
234
+ ```
235
+
236
+ This builds a timestamped diagnostic bundle under the default `artifacts/` directory.
237
+
238
+ ### Profiles
239
+
240
+ Profiles define *what* pybundle collects and *which tools* are run.
241
+
242
+ **Available profiles** (v1.4.3+):
243
+
244
+ * **`analysis`** - What the code IS (structure, metrics, dependencies, docs)
245
+ - Code structure, complexity metrics, documentation coverage
246
+ - Dependency analysis, licenses, performance profiling
247
+ - No error detection or linting
248
+
249
+ * **`debug`** - What's WRONG with the code (errors, issues, problems)
250
+ - Linting, type checking, testing, security scans
251
+ - Error context extraction, anti-pattern detection
252
+ - Includes everything needed for troubleshooting
253
+
254
+ * **`ai`** - Debug optimized for AI (reduced noise, problem-focused)
255
+ - Same as debug but with defaults tuned for AI consumption
256
+
257
+ * **`backup`** - Minimal snapshot (source + git + env, no analysis)
258
+
259
+ To list all available profiles:
260
+
261
+ ```bash
262
+ pybundle list-profiles
263
+ ```
264
+
265
+ Profiles are always invoked via:
266
+
267
+ ```bash
268
+ pybundle run <profile>
269
+ ```
270
+
271
+ ---
272
+
273
+ ### 💾 Backup profile
274
+
275
+ The `backup` profile creates a minimal, lightweight snapshot ideal for version archival or disaster recovery.
276
+
277
+ Run it with:
278
+
279
+ ```bash
280
+ pybundle run backup
281
+ ```
282
+
283
+ #### What `backup` includes
284
+
285
+ * ✅ Full source code snapshot (respects `.gitignore`)
286
+ * ✅ Git status and diff (`meta/00_git_status.txt`, `meta/01_git_diff.txt`)
287
+ * ✅ Python version (`meta/20_python_version.txt`)
288
+ * ✅ Installed packages (`meta/22_pip_freeze.txt`)
289
+ * ✅ Copy manifest (`meta/50_copy_manifest.txt`)
290
+ * ❌ No linting, type-checking, or tests
291
+ * ❌ No security scanning
292
+ * ❌ No ripgrep scans
293
+
294
+ The result is a **fast, small, restorable archive** with just source code and environment context.
295
+
296
+ #### Restoring a backup
297
+
298
+ Backups are created as either `.zip` or `.tar.gz` archives (see Archive Format below).
299
+
300
+ To extract and inspect:
301
+
302
+ **For .zip archives:**
303
+ ```bash
304
+ # Look for filename with *_backup_<TIMESTAMP>.zip
305
+ unzip <FILENAME>.zip -d restored/
306
+ cd restored/<FILENAME>/
307
+ ```
308
+
309
+ **For .tar.gz archives:**
310
+ ```bash
311
+ # Look for filename with *_backup_<TIMESTAMP>.tar.gz
312
+ tar -xzf <FILENAME>.tar.gz -C restored/
313
+ cd restored/<FILENAME>/
314
+ ```
315
+
316
+ Inside the extracted directory:
317
+
318
+ ```text
319
+ src/ # Your project source code
320
+ meta/
321
+ 00_git_status.txt # Git working tree status at backup time
322
+ 01_git_diff.txt # Uncommitted changes (if any)
323
+ 20_python_version.txt # Python version used
324
+ 22_pip_freeze.txt # Exact package versions
325
+ 50_copy_manifest.txt # List of files included
326
+ MANIFEST.json # Machine-readable metadata
327
+ SUMMARY.json # Structured summary
328
+ RUN_LOG.txt # Execution log
329
+ ```
330
+
331
+ The `src/` directory contains your complete project structure.
332
+ The `meta/22_pip_freeze.txt` file can be used to recreate the exact environment:
333
+
334
+ ```bash
335
+ python -m venv venv
336
+ source venv/bin/activate # or venv\Scripts\activate on Windows
337
+ pip install -r meta/22_pip_freeze.txt
338
+ ```
339
+
340
+ Then copy your source code back:
341
+
342
+ ```bash
343
+ cp -r src/* /path/to/your/project/
344
+ ```
345
+
346
+ #### Archive format fallback
347
+
348
+ pybundle uses **zip** by default for maximum portability.
349
+
350
+ If the `zip` command is not available on your system, pybundle **automatically falls back to tar.gz** format without requiring configuration.
351
+
352
+ This ensures backups can be created on any system, regardless of installed compression tools.
353
+
354
+ To explicitly control the format:
355
+
356
+ ```bash
357
+ pybundle run backup --format zip # Force zip (requires zip command)
358
+ pybundle run backup --format tar.gz # Force tar.gz (requires tar command)
359
+ pybundle run backup --format auto # Auto-detect (default behavior)
360
+ ```
361
+
362
+ Both formats preserve the same internal structure and metadata.
363
+
364
+ ---
365
+
366
+ ### 🔍 Analysis Tools
367
+
368
+ The `analysis` and `debug` profiles run comprehensive quality and security checks:
369
+
370
+ #### Code Quality
371
+ * **ruff** - Fast Python linter and formatter checks
372
+ * **mypy** - Static type checking for type hints
373
+ * **pylance** - Syntax error detection and import analysis
374
+ * **vulture** - Dead code detection (v1.3.0+)
375
+ * **radon** - Cyclomatic complexity and maintainability metrics (v1.3.0+)
376
+ * **interrogate** - Docstring coverage analysis (v1.3.0+)
377
+ * **pylint duplication** - Code duplication detection (v1.3.0+)
378
+
379
+ #### Testing & Coverage
380
+ * **pytest** - Test execution and results
381
+ * **coverage** - Code coverage analysis (shows tested vs untested code)
382
+
383
+ #### Security
384
+ * **bandit** - Security vulnerability scanning for Python code
385
+ * **pip-audit** - Dependency vulnerability checking against known CVEs
386
+
387
+ #### Dependency Analysis (v1.3.1+)
388
+ * **pipdeptree** - Full dependency tree with conflict detection
389
+ * **unused dependencies** - Identify installed but unused packages
390
+ * **pip-licenses** - License scanning and compatibility warnings
391
+ * **dependency sizes** - Disk usage analysis per package
392
+
393
+ #### Performance Profiling (v1.4.0+)
394
+ * **cProfile** - CPU profiling to identify bottlenecks
395
+ * **import time analysis** - Detect slow module imports
396
+ * **tracemalloc** - Memory profiling (*enabled by default in v1.4.2+*)
397
+ * **line_profiler** - Line-by-line profiling (optional, requires `@profile` decorators and `--enable-line-profiler`)
398
+
399
+ #### Test Quality & Coverage Enhancement (v1.4.1+)
400
+ * **Colorful progress indicators** - Real-time colored output with step counts (🟢 green = success, 🟡 yellow = skipped, 🔴 red = failed)
401
+ - *v1.4.2: Fixed color support for xterm and other terminals*
402
+ * **Test flakiness detection** - Run tests multiple times to identify non-deterministic failures
403
+ * **Branch coverage** - Enhanced coverage.py integration showing missing branches, not just lines
404
+ * **Slow test identification** - Automatically identify and rank tests exceeding time threshold
405
+ * **Mutation testing** - Optional mutmut integration to measure test suite effectiveness (VERY SLOW - disabled by default)
406
+
407
+ #### Performance Profiling (v1.4.0+)
408
+ * **cProfile integration** - CPU profiling showing slowest functions
409
+ * **import time analysis** - Detect slow module imports
410
+ * **tracemalloc** - Memory profiling (*v1.4.2: enabled by default*)
411
+ * **line_profiler** - Line-by-line profiling (optional, requires `@profile` decorators and `--enable-line-profiler`)
412
+
413
+ #### Pattern Scanning
414
+ * **ripgrep scans** - TODO detection, print statements, bare excepts
415
+
416
+ All tools gracefully skip if not installed. Install recommended tools:
417
+
418
+ ```bash
419
+ pip install ruff mypy pytest pytest-cov bandit pip-audit vulture radon interrogate pylint pipdeptree pip-licenses
420
+ ```
421
+
422
+ For ripgrep (system dependency):
423
+ * macOS: `brew install ripgrep`
424
+ * Ubuntu/Debian: `sudo apt install ripgrep`
425
+
426
+ ---
427
+
428
+ ### 🤖 AI profile (NEW)
429
+
430
+ The `ai` profile is optimized for handing a project to AI tooling
431
+ (ChatGPT, local LLMs, code assistants, etc.).
432
+
433
+ It prioritizes **source code and reproducible context**, while skipping
434
+ expensive or noisy steps by default.
435
+
436
+ Run it with:
437
+
438
+ ```bash
439
+ pybundle run ai
440
+ ```
441
+
442
+ #### What `ai` does by default
443
+
444
+ * ✅ Includes full curated source snapshot (`src/`)
445
+ * ✅ Includes environment + git metadata
446
+ * ✅ Generates `REPRO.md` and `HANDOFF.md`
447
+ * ❌ Skips linting, type-checking, tests
448
+ * ❌ Skips ripgrep scans and error-context expansion
449
+ * ❌ Skips `compileall` unless explicitly enabled
450
+
451
+ The result is a **small, fast, AI-friendly bundle** that still preserves
452
+ determinism and traceability.
453
+
454
+ You may selectively re-enable tools:
455
+
456
+ ```bash
457
+ pybundle run ai --ruff --mypy
458
+ pybundle run ai --compileall
459
+ ```
460
+
461
+ This makes `ai` suitable for:
462
+
463
+ * AI-assisted refactoring
464
+ * Large-context summarization
465
+ * Code review handoff
466
+ * Offline or local LLM workflows
467
+
468
+ ---
469
+
470
+ ### Common options
471
+
472
+ Most usage customizations are done through flags on `pybundle run`.
473
+
474
+ Example:
475
+
476
+ ```bash
477
+ pybundle run analysis \
478
+ --format zip \
479
+ --outdir ./artifacts \
480
+ --name myproject-bundle \
481
+ --strict
482
+ ```
483
+
484
+ Commonly used options:
485
+
486
+ * `--format {auto,zip,tar.gz}` - archive format
487
+ * `--outdir PATH` - output directory (default: `<project>/artifacts`)
488
+ * `--name NAME` - override archive name prefix
489
+ * `--strict` - fail with non-zero exit code if any step fails
490
+ * `--redact / --no-redact` - control secret redaction
491
+
492
+ Tool execution can be selectively disabled:
493
+
494
+ ```bash
495
+ --no-ruff
496
+ --no-mypy
497
+ --no-pylance
498
+ --no-pytest
499
+ --no-bandit
500
+ --no-pip-audit
501
+ --no-coverage
502
+ --no-rg
503
+ --no-error-refs
504
+ --no-context
505
+ ```
506
+
507
+ For the full list of options:
508
+
509
+ ```bash
510
+ pybundle run --help
511
+ ```
512
+
513
+ ---
514
+
515
+ ### Doctor mode
516
+
517
+ To see which tools are available and what *would* run (without creating a bundle):
518
+
519
+ ```bash
520
+ pybundle doctor
521
+ ```
522
+
523
+ You may optionally specify a profile to preview:
524
+
525
+ ```bash
526
+ pybundle doctor analysis
527
+ ```
528
+
529
+ This is useful for validating environment readiness (CI, fresh machines, etc.).
530
+
531
+ ---
532
+
533
+ ### Version
534
+
535
+ To check the installed version:
536
+
537
+ ```bash
538
+ pybundle version
539
+ ```
540
+
541
+ ---
542
+
543
+ ## 🧠 Ignore behavior (important)
544
+
545
+ ### If inside a Git repository
546
+
547
+ pybundle uses **Git itself** to determine which files are included:
548
+
549
+ * `.gitignore`
550
+ * `.git/info/exclude`
551
+ * global gitignore rules
552
+
553
+ This guarantees pybundle sees the project **exactly as Git does**.
554
+
555
+ ### If Git is unavailable
556
+
557
+ pybundle falls back to safe structural rules:
558
+
559
+ * ignores `__pycache__`, `.ruff_cache`, `.mypy_cache`, `.pytest_cache`, etc.
560
+ * detects virtual environments by structure (`pyvenv.cfg`, `bin/activate`), not by name
561
+ → works with `.venv`, `.pybundle-venv`, `env-prod-2025`, etc.
562
+
563
+ ---
564
+
565
+ ## 🧾 Machine-Readable Output (`--json`)
566
+
567
+ All `pybundle` commands support a **machine-readable JSON output mode** via the `--json` flag.
568
+
569
+ When enabled, `pybundle` emits **exactly one JSON object to stdout**, with a **stable schema** intended for:
570
+
571
+ * CI pipelines
572
+ * automation scripts
573
+ * external tooling
574
+ * AI orchestration
575
+ * reproducible analysis
576
+
577
+ No human text or formatting are mixed into the output.
578
+
579
+ ### Example
580
+
581
+ ```bash
582
+ pybundle run analysis --json
583
+ ```
584
+
585
+ Output:
586
+
587
+ ```json
588
+ {
589
+ "status": "ok",
590
+ "command": "run",
591
+ "profile": "analysis",
592
+ "files_included": 39,
593
+ "files_excluded": 0,
594
+ "duration_ms": 394,
595
+ "bundle_path": "/home/jessica/repositories/python/pybundle/artifacts/pybundle_analysis_20260103T102440Z.zip"
596
+ }
597
+ ```
598
+
599
+ The same structure applies to **all profiles**:
600
+
601
+ ```bash
602
+ pybundle run ai --json
603
+ pybundle run debug --json
604
+ pybundle run backup --json
605
+ ```
606
+
607
+ ---
608
+
609
+ ### JSON Field Definitions
610
+
611
+ | Field | Description |
612
+ | ---------------- | -------------------------------------------------- |
613
+ | `status` | `"ok"` or `"fail"` based on execution result |
614
+ | `command` | The command executed (`run` or `doctor`) |
615
+ | `profile` | The profile used (`analysis`, `ai`, `debug`, etc.) |
616
+ | `files_included` | Number of files copied into the bundle |
617
+ | `files_excluded` | Number of *evaluated* files skipped by policy |
618
+ | `duration_ms` | Total execution time in milliseconds |
619
+ | `bundle_path` | Absolute path to the generated archive |
620
+
621
+ ---
622
+
623
+ ### Important Semantics: `files_excluded`
624
+
625
+ `files_excluded` **does not** mean “everything in the repository that was not bundled.”
626
+
627
+ Instead, it means:
628
+
629
+ > Files that were **eligible under the active profile’s policy** and were *explicitly skipped* after evaluation.
630
+
631
+ Files and directories that are **intentionally out of scope** — such as:
632
+
633
+ * `.git/`
634
+ * `node_modules/`
635
+ * virtual environments
636
+ * build artifacts
637
+ * caches
638
+
639
+ are **never considered**, and therefore are **not counted as excluded**.
640
+
641
+ This design keeps metrics honest and avoids inflating counts with known-irrelevant infrastructure.
642
+
643
+ A value of `files_excluded = 0` simply means:
644
+
645
+ > *Everything that was evaluated was worth keeping.*
646
+
647
+ This is expected and normal for clean, well-structured projects — especially in `ai` mode.
648
+
649
+ ---
650
+
651
+ ### JSON Stability Guarantee
652
+
653
+ The JSON schema emitted by `--json` is considered **part of the public API**.
654
+
655
+ Starting with **v1.0**, field names and meanings will remain stable.
656
+ New fields may be added, but existing fields will not be renamed or removed.
657
+
658
+ This allows `pybundle` to be safely embedded into:
659
+
660
+ * CI workflows
661
+ * automation scripts
662
+ * AI pipelines
663
+ * external tooling
664
+
665
+ without fear of breaking changes.
666
+
667
+ ---
668
+
669
+ ## 📜 Profiles
670
+
671
+ pybundle is profile-driven. Each profile defines:
672
+
673
+ * what files are collected
674
+ * which tools run
675
+ * what metadata is emitted
676
+
677
+ Example profiles:
678
+
679
+ * `analysis`
680
+ * `source`
681
+ * `minimal`
682
+
683
+ Profiles are extensible - add your own without modifying core logic.
684
+
685
+ ---
686
+
687
+ ## 🔐 Safety & Redaction
688
+
689
+ By default, pybundle:
690
+
691
+ * avoids scanning known secret locations
692
+ * supports optional redaction of sensitive strings in logs
693
+
694
+ Use `--redact / --no-redact` to control behavior.
695
+
696
+ ---
697
+ ## 🔒 Security Considerations
698
+
699
+ **pybundle** is a development tool designed for trusted environments.
700
+
701
+ ### Threat Model
702
+
703
+ * **Environment:** Development machines and CI/CD pipelines
704
+ * **Trust Boundary:** Assumes trusted development environment
705
+ * **Execution Context:** Runs external tools (git, ruff, mypy, pytest, etc.)
706
+ * **Input Sources:** Project files, git repository, installed packages
707
+
708
+ ### Security Posture
709
+
710
+ **Tool Path Resolution:**
711
+ - All external tools use full resolved paths (via `shutil.which()`)
712
+ - Tools are resolved at detection time and stored in `Tooling` dataclass
713
+ - No dynamic PATH manipulation or shell interpretation
714
+ - Eliminates partial path execution vulnerabilities (B607)
715
+ - **Optional strict-paths mode** for enhanced security (v1.2.0+)
716
+ - **Code quality tools** for dead code, complexity, docstrings, and duplication (v1.3.0+)
717
+ - **Dependency intelligence** for conflict detection, license scanning, and size analysis (v1.3.1+)
718
+
719
+ **Subprocess Execution:**
720
+ - All subprocess calls use `shell=False` (default, secure)
721
+ - Arguments passed as lists, never as strings
722
+ - No user-controlled command construction
723
+ - Commands are hardcoded in source code
724
+
725
+ **Data Handling:**
726
+ - Optional secret redaction for sensitive strings in logs
727
+ - Environment variables and paths logged for reproducibility
728
+ - All file operations respect `.gitignore` rules
729
+
730
+ ### Strict-Paths Mode (v1.2.0+)
731
+
732
+ For high-security environments, enable `--strict-paths` to enforce that all tools must be in trusted system directories:
733
+
734
+ ```bash
735
+ pybundle run analysis --strict-paths
736
+ ```
737
+
738
+ **Trusted directories** (configurable via `PYBUNDLE_TRUSTED_PATHS`):
739
+ - `/usr/bin/`, `/usr/local/bin/`, `/bin/`
740
+ - `/opt/homebrew/bin/` (macOS Homebrew)
741
+ - `/snap/bin/` (Ubuntu snaps)
742
+ - Virtual environment paths (`.venv`, `venv`, `.pybundle-venv`)
743
+
744
+ Tools outside trusted directories are excluded in strict mode. This prevents:
745
+ - Accidental execution of tools from user-writable directories
746
+ - PATH manipulation attacks
747
+ - Use of potentially compromised tool installations
748
+
749
+ **Example:** Verify tool paths before running:
750
+ ```bash
751
+ pybundle doctor --strict-paths
752
+ ```
753
+
754
+ Output shows trust status:
755
+ ```
756
+ 🔧 Tool Detection:
757
+ git ✅ /usr/bin/git
758
+ python ✅ /path/to/venv/bin/python
759
+ npm ⚠️ /home/user/.nvm/.../npm (untrusted in strict mode)
760
+ ```
761
+
762
+ **Configure custom trusted paths:**
763
+ ```bash
764
+ export PYBUNDLE_TRUSTED_PATHS="/opt/custom/bin:/company/tools/bin"
765
+ pybundle run debug --strict-paths
766
+ ```
767
+
768
+ ### Known Limitations
769
+
770
+ 1. **Requires Trusted Environment**
771
+ - Assumes developer controls their machine and installed tools
772
+ - Not designed for untrusted code execution or sandboxing
773
+ - Tool integrity depends on system package management
774
+
775
+ 2. **Tool Availability**
776
+ - External tools (git, ruff, mypy) are optional
777
+ - Missing tools result in SKIP status, not failure
778
+ - Use `pybundle doctor` to verify available tools
779
+
780
+ 3. **File System Access**
781
+ - Reads entire project tree (respecting ignore rules)
782
+ - Writes to `artifacts/` directory by default
783
+ - No privilege escalation or system modification
784
+
785
+ ### For Security Auditors
786
+
787
+ **Bandit Security Scan Results:**
788
+ - 33 low-severity findings (all expected for CLI tool)
789
+ - **B404** (subprocess import): Required for tool functionality
790
+ - **B603** (subprocess calls): Using secure pattern (shell=False, full paths)
791
+ - **B112** (try/except/continue): Acceptable error handling pattern
792
+
793
+ **Risk Classification:** LOW
794
+ - No user-controlled command injection
795
+ - No untrusted input in command execution
796
+ - Full path resolution prevents PATH manipulation attacks
797
+ - Standard development tool security posture
798
+
799
+ **Recommended Usage:**
800
+ ```bash
801
+ # Verify tool paths before execution
802
+ pybundle doctor
803
+
804
+ # Review what tools will be used
805
+ pybundle doctor analysis --json
806
+ ```
807
+
808
+ ---
809
+ ## 🧩 Why pybundle?
810
+
811
+ pybundle is designed for:
812
+
813
+ * handing a project to another engineer
814
+ * attaching context to a bug report
815
+ * feeding a codebase to AI tooling
816
+ * generating CI artifacts
817
+ * preserving “what exactly did we run?”
818
+ * producing **AI-consumable project context** without guesswork
819
+
820
+ It prioritizes **determinism, traceability, and automation** over clever heuristics.
821
+
822
+ ---
823
+
824
+ ## 🛠 Development Notes
825
+
826
+ * Python ≥ 3.9
827
+ * Uses modern tooling (ruff, mypy)
828
+ * Fully type-checked
829
+ * Formatter-clean
830
+ * No test suite *yet* (intentional; coming later)
831
+
832
+ During development, run:
833
+
834
+ ```bash
835
+ python -m pybundle ...
836
+ ```
837
+
838
+ to bypass shell caching.
839
+
840
+ ---
841
+
842
+ ## 📌 Versioning
843
+
844
+ pybundle follows **Semantic Versioning**.
845
+
846
+ Pinned Git tags are recommended when used as a dependency:
847
+
848
+ ```txt
849
+ gwc-pybundle @ git+https://github.com/girls-whocode/pybundle.git@v1.3.1
850
+ ```
851
+
852
+ ---
853
+
854
+ ## 🧠 Philosophy
855
+
856
+ > If a tool produces output, it should also produce metadata about **how** and **why** that output exists.
857
+
858
+ pybundle treats context as a first-class artifact.
859
+
860
+ ---
861
+
862
+ ## 📦 Package naming note
863
+
864
+ The distribution name on PyPI is **`gwc-pybundle`** to avoid conflicts with existing packages.
865
+
866
+ The project name, imports, and CLI remain **`pybundle`**.
867
+
868
+ ```bash
869
+ pip install gwc-pybundle
870
+ pybundle run analysis
871
+ ```
872
+ Look in the autocreated `artifacts/` folder.
873
+
874
+ ## 📄 License
875
+
876
+ MIT License