mirror of
https://github.com/akadeepesh/contextzip.git
synced 2026-10-20 08:36:20 +02:00
docs: document monorepo detection and workspace config; bump to 0.3.5
- README: expand framework detection section, new "Workspace location" section, drop stale exports/ mention left over from the eod/handoff removal - Add CHANGELOG.md - Bump version 0.3.4 -> 0.3.5 (pyproject.toml, __init__.py)
This commit is contained in:
+505
@@ -0,0 +1,505 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to contextzip are documented here.
|
||||
|
||||
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
This project uses [Semantic Versioning](https://semver.org/).
|
||||
|
||||
---
|
||||
|
||||
## [0.1.1] — 2026-05-15
|
||||
|
||||
### Fixed
|
||||
- LICENSE link in README now points to GitHub instead of a relative path that broke on PyPI
|
||||
- License metadata updated to SPDX string format (`"MIT"`) to comply with setuptools ≥ 77
|
||||
|
||||
---
|
||||
|
||||
## [0.1.2] — 2026-05-15
|
||||
|
||||
### Added
|
||||
- Smart framework and language detection (Next.js, Node.js, Python, Django, FastAPI, Rust, Go, Ruby)
|
||||
- Automatic exclusion rules per detected ecosystem
|
||||
- `.gitignore` patterns respected automatically (`--no-gitignore` to bypass)
|
||||
- `--include` flag for scoping to specific directories (exact path-boundary matching)
|
||||
- `--exclude` flag for additional gitignore-style exclusion patterns
|
||||
- `--dry-run` flag to preview without creating any files
|
||||
- `--verbose` flag showing every file with its size
|
||||
- `--output` flag for custom ZIP destination
|
||||
- `--no-clipboard` flag to skip clipboard/folder-open step
|
||||
- Tiered clipboard strategy: file-on-clipboard (macOS/Linux), Explorer with file selected (Windows), path fallback
|
||||
- Warnings for large files (≥ 1 MB), binary files, and skipped files (dangling symlinks, permission errors)
|
||||
- Rich terminal output with panels, progress bars, and colour-coded detection results
|
||||
- Compression stats (ratio, size before/after) shown after ZIP creation
|
||||
|
||||
---
|
||||
|
||||
## [0.2.0] — 2026-05-15
|
||||
|
||||
### Added
|
||||
- `--git-changes` mode for packaging only files reported as changed by git
|
||||
- Automatic detection of:
|
||||
- staged files
|
||||
- unstaged modifications
|
||||
- untracked files
|
||||
- Dedicated git-aware packaging pipeline optimised for AI/code review workflows
|
||||
- Rich git change summary panel with staged/unstaged/untracked breakdown
|
||||
- Verbose git mode output showing categorized changed files
|
||||
- Graceful handling for:
|
||||
- repositories with no changes
|
||||
- deleted files
|
||||
- submodules
|
||||
- repositories outside the selected project tree
|
||||
- missing git installations
|
||||
- non-git directories
|
||||
- Support for monorepo-aware repository root resolution
|
||||
- Binary and large-file checks now also apply in git-changes mode
|
||||
|
||||
### Improved
|
||||
- File resolution architecture refactored to support multiple packaging strategies cleanly
|
||||
- Internal file scanning pipeline separated from git-based file selection logic
|
||||
- CLI output consistency improved between standard scan mode and git-changes mode
|
||||
|
||||
### Developer Notes
|
||||
- Introduced new `contextzip.git` module for git integration and porcelain parsing
|
||||
- Added `resolve_files_from_git()` pipeline for pre-selected file resolution
|
||||
- Added structured `GitChanges` and `GitError` models for cleaner error handling and extensibility
|
||||
|
||||
---
|
||||
|
||||
## [0.2.1] — 2026-05-16
|
||||
|
||||
### Fixed
|
||||
- `--exclude` / `-e` patterns containing Windows-style paths (e.g. `.\CHANGELOG.md`) were silently ignored due to backslash and leading `.\` — patterns are now normalized to forward-slash posix paths before matching
|
||||
- Files passed to `-e` were not being excluded from the ZIP despite appearing in the exclusion list
|
||||
|
||||
### Improved
|
||||
- `-e` now accepts multiple space-separated patterns in a single flag invocation: `-e file1 file2 folder/` in addition to the existing repeatable form `-e file1 -e file2`
|
||||
- Folder exclusion via `-e folder/*` is now supported and normalized to `folder/` automatically
|
||||
|
||||
## [0.2.2] - 2026-05-16
|
||||
|
||||
### Added
|
||||
- `contextzip exclude PATTERN…` subcommand — exclude multiple files and folders
|
||||
in a single invocation without repeating `-e` (e.g. `contextzip exclude CHANGELOG.md LICENSE .github/`)
|
||||
- `contextzip include PATH…` subcommand — symmetric counterpart to `exclude`;
|
||||
packages only the specified paths (e.g. `contextzip include src/ app/`)
|
||||
- All modifier flags (`--dry-run`, `--verbose`, `--output`, `--no-clipboard`,
|
||||
`--git-changes`, `--no-gitignore`) work on both subcommands
|
||||
|
||||
### Changed
|
||||
- `-e` / `--exclude` flag on the main command restored and kept for full
|
||||
backwards compatibility alongside the new subcommand
|
||||
- Warning messages for large files now mention both `-e PATTERN` and
|
||||
`contextzip exclude PATTERN` as remediation options
|
||||
- `_normalize_pattern` promoted to a named module-level function (testable,
|
||||
documented); behaviour is unchanged
|
||||
|
||||
### Fixed
|
||||
- Removed the previous positional-argument approach to exclusions on the main
|
||||
command, which was ambiguous and undiscoverable
|
||||
|
||||
---
|
||||
|
||||
## [0.2.3] — 2026-05-19
|
||||
|
||||
### Added
|
||||
- Dedicated Ruby ecosystem exclusion rules via new `contextzip.rules.ruby` module
|
||||
- Automatic exclusion of common Ruby / Rails artifacts:
|
||||
- Bundler directories and lockfiles
|
||||
- Rails logs, temp files, assets, storage, and Spring cache
|
||||
- Built gems and compiled Ruby extensions
|
||||
- Coverage and generated documentation directories
|
||||
- Additional package discovery keywords for AI tooling and code packaging:
|
||||
- `claude`
|
||||
- `chatgpt`
|
||||
- `code-packaging`
|
||||
|
||||
### Changed
|
||||
- Ruby project detection now uses the dedicated Ruby rule module instead of the generic base rules
|
||||
- Git-based packaging now enforces base exclusion safety rules even for tracked files
|
||||
- Repository governance and metadata files are now excluded by default:
|
||||
- `CHANGELOG*`
|
||||
- `LICENSE*`
|
||||
- `CONTRIBUTING*`
|
||||
- `SECURITY.md`
|
||||
- `.github` issue / PR templates
|
||||
- `.gitignore` is no longer excluded automatically from packaged context archives
|
||||
|
||||
### Fixed
|
||||
- Prevented git-tracked sensitive files (e.g. `.env`, secrets, binaries) from being included in `--git-changes` mode
|
||||
- Improved ZIP packaging resilience when file stat operations fail during archive creation
|
||||
- Fixed progress tracking during ZIP generation to avoid repeated filesystem stat calls
|
||||
- Fixed Ruby framework detection routing so Ruby projects receive ecosystem-specific exclusion behaviour
|
||||
|
||||
---
|
||||
|
||||
## [0.2.4] — 2026-05-20
|
||||
|
||||
### Added
|
||||
|
||||
* Persistent `.contextzip/` workspace directory for generated context packages
|
||||
* Automatic output naming based on packaging mode:
|
||||
|
||||
* `codebase.zip` for standard packaging
|
||||
* `changes.zip` for `--git-changes`
|
||||
* Automatic `.contextzip/` exclusion from packaged archives and file scanning
|
||||
* Automatic `.gitignore` integration:
|
||||
|
||||
* `.contextzip/` is appended when a git repository is detected
|
||||
* missing entries are added only once
|
||||
* Repository-root-aware workspace placement:
|
||||
|
||||
* `.contextzip/` is created at the git repository root when `.git/` is detected
|
||||
* falls back to the current working directory outside git repositories
|
||||
|
||||
### Changed
|
||||
|
||||
* ZIP outputs are now written to the persistent `.contextzip/` workspace by default instead of temporary system directories
|
||||
* Generated archives now overwrite previous outputs with the same logical name instead of creating temporary randomized filenames
|
||||
* `--output` now bypasses all `.contextzip/` workspace logic and writes directly to the user-specified destination
|
||||
|
||||
### Improved
|
||||
|
||||
* Generated context packages are now easier to rediscover, reuse, and inspect across AI-assisted development workflows
|
||||
* Workspace output structure now provides a foundation for future features such as:
|
||||
|
||||
* timestamped package history
|
||||
* metadata indexing
|
||||
* incremental packaging
|
||||
* AI debug sessions
|
||||
* package caching
|
||||
|
||||
### Fixed
|
||||
|
||||
* Prevented `.contextzip/` contents from recursively packaging previous generated archives
|
||||
* Improved fallback behaviour when workspace creation fails due to filesystem permissions or read-only directories
|
||||
|
||||
## [0.3.0] — 2026-05-24
|
||||
|
||||
### Added
|
||||
|
||||
* `--prompt` / `-p` flag for AI-powered file selection — describe your task in
|
||||
plain English and contextzip automatically selects the minimum relevant files
|
||||
(e.g. `contextzip --prompt "Change toast color on failed login"`)
|
||||
* Gemini 2.5 Flash Lite integration via a thin `httpx` client — no Google SDK
|
||||
required; a single lightweight POST call to the Gemini API
|
||||
* First-run onboarding flow for users without an API key:
|
||||
* Displays a guided panel with a link to [Google AI Studio](https://aistudio.google.com/apikey) (free, no credit card)
|
||||
* Optionally opens the browser automatically
|
||||
* Saves the key persistently on confirmation
|
||||
* Persistent API key storage in the platform-appropriate config directory:
|
||||
* `~/.config/contextzip/config.json` on Linux / macOS
|
||||
* `%APPDATA%\contextzip\config.json` on Windows
|
||||
* `GEMINI_API_KEY` environment variable always takes precedence
|
||||
* `contextzip config` subcommand for key management:
|
||||
* `contextzip config` — show current key status and source
|
||||
* `contextzip config --reset-key` — clear stored key and re-run onboarding
|
||||
* `contextzip config --show-key-path` — print config file location
|
||||
* `prompt.txt` is written as the first entry in every AI-generated ZIP,
|
||||
containing the task description, detected framework, and selected file list —
|
||||
so any AI tool receiving the archive immediately knows the context
|
||||
* Keyword-based heuristic file scorer as a rate-limit fallback:
|
||||
* Activates only on confirmed HTTP 429 from Gemini
|
||||
* Scores files by token overlap with the prompt, directory semantics, and
|
||||
extension type
|
||||
* User is warned clearly that heuristic was used and Gemini results are
|
||||
preferred
|
||||
* `--prompt --dry-run` combination — preview AI-selected files without
|
||||
creating a ZIP
|
||||
* API key validation on load — keys not starting with `AIza` are treated as
|
||||
unconfigured and trigger onboarding rather than a cryptic API error
|
||||
* `diagnose_api_key()` surfaces a human-readable explanation when a key exists
|
||||
but fails validation, before any API call is attempted
|
||||
|
||||
### Changed
|
||||
|
||||
* `create_zip()` in `packager.py` now accepts an optional `prompt_txt`
|
||||
parameter; when provided, `prompt.txt` is written as the first ZIP entry
|
||||
* xdg-open on Linux now runs with stdout and stderr suppressed to prevent
|
||||
KDE / DBus / MIME warnings from appearing over the API key prompt
|
||||
|
||||
### Developer Notes
|
||||
|
||||
* Introduced `contextzip.config` module for cross-platform config path
|
||||
resolution and key read / write / delete operations
|
||||
* Introduced `contextzip.ai` package with three modules:
|
||||
* `gemini.py` — Gemini API client with typed exception hierarchy
|
||||
(`GeminiError`, `GeminiRateLimitError`, `GeminiUnavailable`)
|
||||
* `heuristic.py` — keyword + directory scoring fallback scorer
|
||||
* `selector.py` — project map builder, AI orchestration, `prompt.txt`
|
||||
generation; returns `(paths, prompt_txt, method)` so callers know
|
||||
which selection path was taken
|
||||
* Added `httpx` as a required runtime dependency
|
||||
|
||||
## [0.3.1] — 2026-05-25
|
||||
|
||||
### Added
|
||||
|
||||
* `contextzip watch -- <command>` subcommand — wraps any dev server or build
|
||||
process, buffers its output, detects errors automatically, and packages a
|
||||
debug-ready ZIP in a single keypress
|
||||
* Supports `npm run dev`, `python manage.py runserver`, and any process
|
||||
that writes errors to stdout/stderr
|
||||
* On error detection, renders an inline prompt beneath the error output:
|
||||
`[D] package debug context [S] skip`
|
||||
* Pressing `D` writes `.contextzip/debug-context.zip` immediately; the
|
||||
wrapped process continues running uninterrupted
|
||||
* On `Ctrl+C`, if no errors were packaged during the session, a final
|
||||
prompt offers to capture the full session output as a fallback
|
||||
* `debug-context.zip` — flat ZIP structure produced by `watch`:
|
||||
* `prompt.txt` — auto-generated from detected framework, error type, and
|
||||
referenced files; no `--prompt` flag required from the user
|
||||
* `terminal-error.txt` — cleaned, noise-stripped error block and stack trace
|
||||
* `source-files.zip` — inner ZIP containing source files extracted from
|
||||
stack frames, with relative paths preserved
|
||||
* `contextzip/error_parser.py` — full terminal output processing pipeline:
|
||||
* `strip_ansi()` — removes all CSI, OSC, and Fe escape sequences and bare
|
||||
carriage returns from raw process output
|
||||
* `detect_error_block()` — backward scan through the rolling buffer to find
|
||||
the most recent error; walks back from terminal exception lines to capture
|
||||
the full block including the `Traceback` header
|
||||
* `extract_paths()` — runs per-framework path regexes on the error block,
|
||||
resolves relative and bare filenames, and filters out stdlib, venv, and
|
||||
`node_modules` paths
|
||||
* `strip_noise()` — removes known noise lines (request logs, startup
|
||||
banners, HMR chatter) and collapses blank line runs
|
||||
* `build_prompt_txt()` — generates structured, AI-ready `prompt.txt` content
|
||||
* `process_buffer()` — convenience function running the full pipeline in a
|
||||
single call
|
||||
* `contextzip/watcher.py` — process management and packaging:
|
||||
* Spawns child via `subprocess.Popen` with piped stdout/stderr; two daemon
|
||||
threads drain pipes concurrently into a `deque(maxlen=2000)` rolling buffer
|
||||
* Detection thread polls the buffer every 300ms using `detect_error_block()`
|
||||
* Error deduplication: MD5 of the first three non-blank lines of an error
|
||||
block; same signature within a session suppresses repeat prompts
|
||||
* Single-keypress D/S prompt via `termios`/`tty` raw mode on Unix and
|
||||
`msvcrt` on Windows, with an `input()` fallback for unusual environments
|
||||
* Child terminated cleanly on `Ctrl+C`: SIGTERM → 3-second grace period →
|
||||
SIGKILL
|
||||
* `contextzip/rules/errors/python.py` — error detection pattern sets for
|
||||
Python, Django, and FastAPI:
|
||||
* 18 error start patterns covering tracebacks, syntax errors, Django/DRF
|
||||
exceptions, uvicorn/gunicorn ERROR logs, and pytest failures
|
||||
* 4 stack frame path patterns
|
||||
* 21 noise patterns for Django startup, request logs, pytest collection
|
||||
output, and pip install chatter
|
||||
* `contextzip/rules/errors/node.py` — error detection pattern sets for
|
||||
Node.js, Next.js, and React:
|
||||
* 33 error start patterns covering JS runtime errors, Next.js error symbols
|
||||
(`✗`, `×`, `⨯`), webpack/bundler errors, npm errors, and unhandled
|
||||
promise rejections
|
||||
* 7 stack frame and import path patterns
|
||||
* 32 noise patterns for Next.js/Vite/CRA startup, HMR chatter, and request
|
||||
logs
|
||||
|
||||
### Changed
|
||||
|
||||
* `cli.py` refactored from a single 1,100-line file into four focused modules
|
||||
with no behaviour changes:
|
||||
* `cli.py` — Click group, four subcommands, and `_run()`; routing only
|
||||
* `cli_display.py` — all Rich rendering helpers (`print_detection`,
|
||||
`print_scan_summary`, `print_file_warnings`, `print_package_result`, etc.)
|
||||
* `cli_ai.py` — AI selection orchestration and `normalize_pattern`
|
||||
* `cli_onboard.py` — Gemini API key onboarding flow and browser launch
|
||||
* `pyproject.toml` updated to include `contextzip.rules.errors` in package
|
||||
discovery
|
||||
|
||||
### Developer Notes
|
||||
|
||||
* `contextzip/rules/errors/` follows the same pattern as `contextzip/rules/`:
|
||||
one file per ecosystem, each exporting `ERROR_START_PATTERNS`,
|
||||
`PATH_PATTERNS`, and `NOISE_PATTERNS` as lists of compiled `re.Pattern`
|
||||
objects — adding support for a new framework means adding one file
|
||||
* `_load_patterns()` in `error_parser.py` maps ecosystem names from
|
||||
`DetectionResult.ecosystems` to rule modules; unrecognised ecosystems fall
|
||||
back to loading both Python and Node patterns as a best-effort default
|
||||
* `cli_display.py` functions accept an optional `con: Console` parameter
|
||||
(defaulting to the module-level console) making every display function
|
||||
independently testable without monkey-patching
|
||||
* No new runtime dependencies introduced — `watch` uses only stdlib
|
||||
(`subprocess`, `threading`, `queue`, `termios`/`msvcrt`, `zipfile`)
|
||||
|
||||
## [0.3.2] — 2026-05-25
|
||||
|
||||
### Added
|
||||
|
||||
* **Python API** — contextzip is now usable as a library, not just a CLI tool:
|
||||
* `get_git_changes(path?)` — returns a `FileCollection` of git-modified,
|
||||
added, and untracked files; applies base safety rules (no secrets, no
|
||||
binaries) automatically
|
||||
* `get_files(path?, include?, exclude?, use_gitignore?)` — returns a
|
||||
`FileCollection` of all project files after applying ecosystem rules,
|
||||
`.gitignore`, and any extra exclusion patterns
|
||||
* `create_zip(collection, output?)` — writes a `FileCollection` to a ZIP
|
||||
archive and returns a `PackageResult`; output path is caller-controlled
|
||||
* `detect_ecosystem(path?)` — returns a `DetectionResult` with ecosystem
|
||||
names, display string, and confidence level
|
||||
* `FileCollection` — unified return type for `get_git_changes` and
|
||||
`get_files`; supports iteration, `len()`, and `bool()` directly; `.files`
|
||||
is always a plain `list[pathlib.Path]` usable without zipping
|
||||
* `PackageResult` re-exported from the top-level package
|
||||
* Exception hierarchy: `ContextzipError` (base), `NotARepositoryError`,
|
||||
`GitNotFoundError`, `GitCommandError`, `NoFilesError`
|
||||
* All API functions default `path` to `Path.cwd()`, matching CLI behaviour
|
||||
|
||||
* `contextzip/api.py` — new module implementing the public API; no Click, no
|
||||
Rich output, no `SystemExit`; raises typed exceptions on failure
|
||||
* `contextzip/packager.py` — added `create_zip_silent()` and
|
||||
`_workspace_output_path_silent()`: same ZIP logic as the CLI path but
|
||||
without a `Console` dependency, used internally by the API
|
||||
|
||||
### Changed
|
||||
|
||||
* `contextzip/__init__.py` — now exports the full public API
|
||||
(`get_git_changes`, `get_files`, `create_zip`, `detect_ecosystem`,
|
||||
`FileCollection`, `PackageResult`, and all exception types) so
|
||||
`from contextzip import ...` works without knowing internal module paths
|
||||
|
||||
### Fixed
|
||||
|
||||
* `filters.py` — symlink guard inner `try` block repeated the identical
|
||||
`relative_to` call that already failed in the outer block; the fallback now
|
||||
correctly uses the pre-resolve (`original_path`) to compute the relative
|
||||
path for symlinks that point outside the project tree
|
||||
* `watcher.py` — `_drain_output_queue` silently consumed sentinel values
|
||||
(`raw=None`) with `continue`, making them invisible to `_check_reader_done`;
|
||||
sentinels are now put back into the queue so done flags are set correctly
|
||||
* `watcher.py` — `_read_key_windows` had no timeout and would spin forever in
|
||||
non-interactive terminals; now uses a 60-second `monotonic` deadline
|
||||
matching the existing Unix `select` timeout
|
||||
* `packager.py` — removed unused `_safe_name` helper
|
||||
* `ai/gemini.py` — corrected stale docstring (`gemini-2.0-flash-lite` →
|
||||
`gemini-2.5-flash-lite`) to match the actual `DEFAULT_MODEL` constant
|
||||
|
||||
## [0.3.3] — 2026-05-29
|
||||
|
||||
### Fixed
|
||||
|
||||
* `contextzip.ai` and all subpackages were missing from the published wheel
|
||||
due to an incomplete `include` allowlist in `pyproject.toml` — replaced
|
||||
with auto-discovery so all current and future subpackages are captured
|
||||
automatically
|
||||
|
||||
## [0.3.4] — 2026-06-21
|
||||
|
||||
### Added
|
||||
|
||||
* `contextzip eod` — builds a paste-ready end-of-day prompt from today's
|
||||
Claude/ChatGPT conversation plus whatever code changed, copied straight
|
||||
to the clipboard. Does no summarizing itself — that's left to whichever
|
||||
AI tool the prompt gets pasted into
|
||||
* `contextzip handoff` — same pipeline, aimed at continuing a project in a
|
||||
fresh chat after hitting a usage limit, rather than at an end-of-day report
|
||||
* Per-branch commit checkpoints (`.contextzip/markers/eod.json`,
|
||||
`.contextzip/markers/handoff.json`) so every run only reports what's new
|
||||
since *that command* last ran on *that branch* — no manual bookkeeping,
|
||||
no date-based guessing
|
||||
* Three-case code-change resolution per file, checked in priority order:
|
||||
1. **Not pushed** — diff against the upstream branch (covers committed-
|
||||
but-unpushed commits and uncommitted edits in one comparison) + the
|
||||
complete current file
|
||||
2. **Diverged from Claude** — diff against the version Claude last
|
||||
produced, matched by filename against a local artifacts folder + the
|
||||
complete current codebase file
|
||||
3. **Since last run** — diff against the stored marker commit, or the
|
||||
branch's merge-base with the default branch on a branch never tracked
|
||||
before + the complete current file
|
||||
|
||||
Brand-new untracked files skip the diff (no baseline exists) and are
|
||||
included as full content only
|
||||
* Best-effort fetching of Claude's artifact files for case 2, using the
|
||||
user's own Claude.ai session key (`contextzip config --set-session-key`).
|
||||
Explicitly degrades gracefully — a missing key, an expired cookie, or the
|
||||
endpoint changing shape just skips case 2 with a warning, never fails the
|
||||
whole `eod`/`handoff` run
|
||||
* `contextzip config --set-session-key` / `--reset-session-key` — manage
|
||||
the Claude session key alongside the existing Gemini key; default
|
||||
`contextzip config` now shows both keys' status
|
||||
* Text-clipboard support (`clipboard.handle_text()`) — `eod`/`handoff`
|
||||
produce a prompt to paste, not a file to upload, so the existing
|
||||
file-clipboard tiers gained a text-mode sibling (`pbcopy` / `xclip`+`xsel`
|
||||
/ `clip.exe`)
|
||||
* `exports/` added to the base exclusion ruleset (next to `.contextzip/`) —
|
||||
conversation exports and fetched Claude artifacts are contextzip's own
|
||||
working files, never code to package or report on
|
||||
|
||||
### Changed
|
||||
|
||||
* `packager._ensure_gitignore()` generalised to accept an arbitrary entry
|
||||
instead of being hardcoded to `.contextzip/`, so `exports/` can register
|
||||
itself in `.gitignore` the same way on first use
|
||||
|
||||
### Developer Notes
|
||||
|
||||
* New modules: `markers.py` (per-branch checkpoint storage), `code_changes.py`
|
||||
(the three-case decision tree), `claude_export.py` (locating the latest
|
||||
export, inline-vs-attach sizing), `claude_artifacts.py` (best-effort
|
||||
artifact fetching, rewritten on `httpx` for consistency with `ai/gemini.py`
|
||||
rather than introducing a second HTTP stack), `brief.py` (orchestrates
|
||||
`eod`/`handoff` end to end)
|
||||
* `git.py` gained branch-aware primitives: `get_current_branch()`,
|
||||
`get_default_branch()` (origin/HEAD detection with fallback chain),
|
||||
`get_merge_base()`, `is_ancestor()`, `get_upstream_branch()`,
|
||||
`diff_against()` (working-tree-aware — captures committed-since-baseline
|
||||
and uncommitted changes in one diff), `changed_files_against()`
|
||||
* A stored marker that's no longer an ancestor of `HEAD` (e.g. after a
|
||||
rebase) is detected via `is_ancestor()` and silently recomputed from the
|
||||
branch's merge-base, with a warning surfaced to the user rather than
|
||||
producing a nonsense diff
|
||||
* `claude_artifacts.py` matches Claude's flat artifact filenames against the
|
||||
codebase by basename only, since artifacts carry no knowledge of the
|
||||
repo's directory structure; ambiguous matches (same filename in multiple
|
||||
directories) pick the most recently modified candidate and surface a
|
||||
warning rather than guessing silently
|
||||
|
||||
## [0.3.5] — 2026-08-09
|
||||
|
||||
### Added
|
||||
- **Monorepo-aware framework detection.** Detection now scans project_dir plus a
|
||||
shallow, bounded subdirectory tree (2 levels deep), instead of only checking
|
||||
the project root. A layout like `root/frontend/package.json` +
|
||||
`root/backend/requirements.txt` now correctly detects both Node.js and
|
||||
Python and stacks both exclusion rule sets — previously this fell through
|
||||
to only the universal base rules, leaving `node_modules/`, `.venv/`, and
|
||||
similar unexcluded except by whatever `.gitignore` happened to catch. The
|
||||
scan skips dependency/build directories (`node_modules/`, `.venv/`, `.git/`,
|
||||
etc.) so it never walks into a large dependency tree. Detection output now
|
||||
shows which subdirectory each ecosystem was found in, e.g.
|
||||
`Next.js (frontend/) + FastAPI (backend/)`.
|
||||
- **Configurable `.contextzip/` workspace location**, resolved in priority
|
||||
order: `CONTEXTZIP_WORKSPACE_LOCATION` env var → project config
|
||||
(`.contextzip.json`, committed, team-shared) → personal config (per-machine,
|
||||
via `contextzip config --set-workspace`) → default (`git-root`, unchanged
|
||||
behavior). Accepts `"git-root"`, `"cwd"`, or an explicit path.
|
||||
- `contextzip config --set-workspace <location>` / `--reset-workspace` — set
|
||||
or clear your personal workspace location default.
|
||||
- `contextzip config` (no flags) now shows the resolved workspace location
|
||||
and which config tier it came from.
|
||||
- New `.contextzip.json` project config file (optional, git-committed) for
|
||||
pinning `workspace_location` for every contributor.
|
||||
|
||||
### Fixed
|
||||
- `.gitignore` registration for the `.contextzip/` entry now correctly
|
||||
derives the git root independently, rather than assuming it's always the
|
||||
workspace directory's parent — a latent bug this release's configurable
|
||||
workspace location would otherwise have triggered (it only skips writing
|
||||
when the workspace is genuinely outside the repo, e.g. an absolute custom
|
||||
path).
|
||||
|
||||
### Removed
|
||||
- **`eod` and `handoff` commands**, along with the Claude.ai session-key
|
||||
config option they depended on. Both relied on an undocumented Claude.ai
|
||||
endpoint to fetch previously-produced artifacts, which was never a stable
|
||||
foundation for a shipped feature.
|
||||
- Removed modules: `brief.py`, `claude_export.py`, `claude_artifacts.py`,
|
||||
`code_changes.py`, `markers.py`
|
||||
- Removed CLI options: `contextzip config --set-session-key` /
|
||||
`--reset-session-key`
|
||||
- Removed config keys: `claude_session_key`
|
||||
- Also removed now-unused branch-diffing internals from `git.py`
|
||||
(`get_current_branch`, `get_upstream_branch`, `diff_against`, and related
|
||||
helpers) that existed solely to support `eod`/`handoff`
|
||||
- If you relied on `eod`/`handoff`, there's no replacement in this
|
||||
release — conversation exports and per-file diff prompts will need to be
|
||||
built by hand, or via your own script against `contextzip --git-changes`.
|
||||
@@ -18,12 +18,13 @@ contextzip eliminates that entirely. Run it from your project root — it detect
|
||||
|
||||
## Features
|
||||
|
||||
- **Smart framework detection** — automatically identifies Node.js, Next.js, Python, Django, FastAPI, Rust, Go, and Ruby, applying the right exclusion rules for each
|
||||
- **Smart framework detection** — automatically identifies Node.js, Next.js, Python, Django, FastAPI, Rust, Go, and Ruby, applying the right exclusion rules for each. Detection isn't limited to the project root: a shallow, bounded scan of subdirectories means a monorepo (`frontend/` + `backend/`, etc.) gets every ecosystem it contains detected and excluded correctly, not just whatever sits at the top level
|
||||
- **Respects `.gitignore`** — your existing ignore patterns are honoured automatically
|
||||
- **Git-aware packaging** — use `--git-changes` to package only modified, staged, and untracked files; perfect for incremental debugging and PR review sessions
|
||||
- **AI-powered file selection** — describe your task in plain English with `--prompt` and Gemini selects the minimum relevant files automatically, no manual hunting required
|
||||
- **Terminal error watcher** — wrap any dev server with `contextzip watch` to auto-detect errors and package a ready-to-upload debug context in one keypress
|
||||
- **Persistent workspace** — all generated ZIPs land in `.contextzip/` at your project root, discoverable, reusable, and git-ignored automatically
|
||||
- **Configurable workspace location** — `.contextzip/` lives at the git root by default, but you can pin it elsewhere per-machine (`contextzip config --set-workspace`) or for the whole team via a committed `.contextzip.json`
|
||||
- **Persistent workspace** — all generated ZIPs land in `.contextzip/`, discoverable, reusable, and git-ignored automatically
|
||||
- **Warns before it's a problem** — flags large (≥ 1 MB) and binary files that AI tools can't read, before you waste an upload
|
||||
- **Handles edge cases** — dangling symlinks, unreadable files, and paths outside the project tree are caught and reported, never silently dropped
|
||||
- **Full CLI control** — `--include`, `--exclude`, `--dry-run`, `--output`, all composable
|
||||
@@ -218,7 +219,7 @@ Press **D** and contextzip immediately writes `.contextzip/debug-context.zip`. Y
|
||||
|
||||
contextzip stacks exclusion rules based on your detected stack, on top of your `.gitignore`.
|
||||
|
||||
**Always excluded:** `.git/`, `.env` files, logs, caches, editor config (`.vscode/`, `.idea/`), OS files (`.DS_Store`, `Thumbs.db`), common binary formats, and contextzip's own `.contextzip/` and `exports/` working folders.
|
||||
**Always excluded:** `.git/`, `.env` files, logs, caches, editor config (`.vscode/`, `.idea/`), OS files (`.DS_Store`, `Thumbs.db`), common binary formats, and contextzip's own `.contextzip/` working folder.
|
||||
|
||||
**By framework:**
|
||||
|
||||
@@ -229,7 +230,38 @@ contextzip stacks exclusion rules based on your detected stack, on top of your `
|
||||
| Rust | `target/`, `Cargo.lock`, `*.rlib` |
|
||||
| Go | `vendor/`, `go.sum`, `bin/` |
|
||||
|
||||
Detection is additive — a monorepo with both `package.json` and `pyproject.toml` gets both rule sets applied.
|
||||
Detection is additive — a monorepo with both `package.json` and `pyproject.toml` gets both rule sets applied. Marker files don't have to sit at the project root: contextzip also does a shallow, bounded scan of subdirectories (2 levels deep, skipping `node_modules/`, `.venv/`, `.git/`, and other dependency/build dirs it would never want to look inside anyway), so a layout like
|
||||
|
||||
```
|
||||
root/
|
||||
frontend/package.json
|
||||
backend/requirements.txt
|
||||
```
|
||||
|
||||
detects both Node.js and Python from `root/`, without either marker existing at the top level. Run with default output (not `--dry-run --verbose`) and you'll see which subdirectory each ecosystem came from, e.g. `Next.js (frontend/) + FastAPI (backend/)`.
|
||||
|
||||
---
|
||||
|
||||
## Workspace location
|
||||
|
||||
By default, `.contextzip/` is created at your git root — that's `_find_git_root()` walking up from the current directory until it finds a `.git` folder; outside a repo, it falls back to the current directory. This can be overridden two ways, in order of priority:
|
||||
|
||||
1. **`CONTEXTZIP_WORKSPACE_LOCATION` environment variable** — for a one-off override on a single run
|
||||
2. **A committed `.contextzip.json` at the project root** — team-shared, applies to everyone who clones the repo:
|
||||
```json
|
||||
{ "workspace_location": "git-root" }
|
||||
```
|
||||
3. **Your personal config** — a per-machine default that doesn't get committed:
|
||||
```bash
|
||||
contextzip config --set-workspace cwd # always use ./.contextzip wherever you run it
|
||||
contextzip config --set-workspace git-root # back to the default
|
||||
contextzip config --set-workspace ~/zips # a fixed custom location, anywhere
|
||||
contextzip config --reset-workspace # clear your personal override
|
||||
```
|
||||
|
||||
Accepted values are `"git-root"`, `"cwd"`, or any path (absolute, or relative to the git root). Run `contextzip config` with no flags to see which value is currently active and where it came from.
|
||||
|
||||
This matters most for monorepos where you sometimes run contextzip from a subdirectory (`cd frontend && contextzip`) — with the default `git-root` setting, the workspace still lands at the repo root no matter where you ran it from, so you don't end up with scattered `.contextzip/` folders across `frontend/`, `backend/`, etc. Set `workspace_location: "cwd"` in a project's `.contextzip.json` instead if you'd rather each subproject keep its own.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""contextzip — intelligent codebase packager for AI tools."""
|
||||
|
||||
__version__ = "0.3.4"
|
||||
__version__ = "0.3.5"
|
||||
|
||||
from contextzip.api import (
|
||||
FileCollection,
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "contextzip"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
description = "Intelligently package your codebase for AI tools"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
|
||||
Reference in New Issue
Block a user