Adds an 'Applying AI-returned changes' section covering the manifest
mechanism, the new/modified/unchanged/drifted/untracked classification
table, safety guarantees, and inbox/manifest resolution. Also updates
the command table, Python API table, and workspace layout diagram to
include inbox/, backups/, and the manifest sidecar.
Adds apply_zip() alongside get_files/get_git_changes/create_zip,
following the same plain-function, exception-raising style (no Click,
no Rich, no SystemExit). Exposes ApplyResult and ZipNotFoundError
from the package root.
Wires applier.py into the CLI: auto-detects a zip from
.contextzip/inbox/ (or takes an explicit path), prints a plan summary
(new/modified/unchanged/drifted/untracked counts), and only prompts
for confirmation when something looks risky — drift, untracked paths,
or no manifest at all. Clean modifications and new files apply with
no prompt.
Flags: --dry-run/-n, --verbose/-v, --yes/-y, --manifest.
Introduces applier.py: resolves the AI-returned zip (inbox or explicit
path), diffs it against a per-zip manifest, and classifies every file
as new/modified/unchanged/drifted/untracked before writing anything.
Only ever adds or modifies files — no deletions are inferred.
packager.py now writes a <name>.manifest.json sidecar next to every
zip it creates, containing a hash of each included file. It's written
to disk only, never added as a zip entry, so it's never uploaded or
visible to whatever AI tool the zip is pasted into.
Safety: zip entries are validated against path traversal before
extraction; every file about to be overwritten is backed up under
.contextzip/backups/<timestamp>/ first; consumed zips are archived to
.contextzip/inbox/applied/ rather than deleted.
- 'contextzip config --ui' launches the local config UI directly
- First run in a project with no config at all offers to launch it
interactively, gated on TTY + no CI env var + no --prompt/--output
- Declining is remembered per-machine (config.py) so it only asks once
- Accepting and saving mid-run reloads config and continues packaging
immediately in the same invocation
Single-file HTML/CSS/JS, no build step, no CDN calls — colors and
typography matched to the showcase site's design tokens. Live file tree
with checkboxes, one-click exclude suggestions, working-config panel
with raw JSON preview, and a save flow with a success overlay.
Stdlib-only HTTP server bound to 127.0.0.1, with a random per-session
token (same approach as Jupyter Notebook) and no outbound network calls
of its own. Auto-shuts down on save, tab idle, or a hard time ceiling.
Includes:
- suggestions.py: detects PDFs, office docs, fonts, media, and anything
over 1MB that isn't already covered by the default exclusion rules
- persist.py: writes always_include/always_exclude to
.contextzip/config.json, reusing the existing workspace/.gitignore setup
Splits file-tree scanning into a one-time disk walk (scan_all_files) plus
a pure in-memory classifier (classify_scanned_files) that can be run
against different include/exclude patterns without re-touching the
filesystem. resolve_files() is untouched — this is purely additive.
Prunes known-huge, always-irrelevant directories (.venv, node_modules,
.git, __pycache__, build output, etc.) during the walk itself, and
rejects symlinks that resolve outside the project tree (e.g. a venv's
bin/python pointing at the system interpreter).
- 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)
Adds a precedence chain for where .contextzip/ is created:
env var (CONTEXTZIP_WORKSPACE_LOCATION) > project config
(.contextzip.json, git-committed, team-shared) > personal config
(per-machine, contextzip config --set-workspace) > default
(git-root, unchanged behavior).
Also fixes a latent bug this surfaced: .gitignore registration
derived git_root as workspace.parent, which only held true when
the workspace was always directly under git root. Now derives it
independently via _find_git_root and only registers .gitignore
when the workspace is actually inside the repo.
New: project_config.py (loads .contextzip.json), config.py
get/save/delete_workspace_location, cli.py --set-workspace/
--reset-workspace on `contextzip config`.
Detection previously only checked project_dir itself, so a monorepo
like root/frontend/package.json + root/backend/requirements.txt
detected nothing and fell through to only the universal base
exclusion rules — leaving node_modules/, .venv/, etc. unexcluded
except by whatever .gitignore happened to catch.
Now scans project_dir plus a shallow, bounded subdirectory tree
(depth 2), skipping dependency/build dirs (node_modules, .venv,
.git, etc.) so it never walks into a large dependency tree. Runs
unconditionally, not just when root comes up empty, since a
root-level marker doesn't imply there's nothing else to find in
sibling directories.
DetectionResult now tracks which subdirectory each ecosystem was
found in (`sources`), surfaced in the CLI panel, e.g.
"Next.js (frontend/) + FastAPI (backend/)".
fix: revert version to 0.3.0 and update __all__ exports in __init__.py
feat: implement create_zip_silent for silent ZIP creation without console output
Adds Terminal error watcher section covering the full flow, ZIP contents
table, Ctrl+C fallback, supported frameworks, and PTY/Windows note.
Updates features list and subcommands reference.
Adds `contextzip watch -- COMMAND [ARGS]` to the CLI group.
Runs ecosystem detection, prints the Windows PTY warning where relevant,
and delegates to watcher.run_watch().
cli.py was 1,100+ lines. Extracted with no behaviour changes:
- cli_display.py — all Rich rendering helpers
- cli_ai.py — AI selection orchestration + normalize_pattern
- cli_onboard.py — Gemini API key onboarding flow
cli.py retains only Click routing and _run().
Spawns child process via subprocess.Popen, buffers output across two
daemon reader threads, detects errors via polling, and renders the D/S
prompt using termios raw mode (Unix) / msvcrt (Windows).
Writes debug-context.zip flat: prompt.txt, terminal-error.txt, source-files.zip.