Commit Graph
158 Commits
Author SHA1 Message Date
akadeepesh 88bde9fff7 fix(clipboard): put the ZIP on the clipboard as a real file on Windows and Linux
Windows had no clipboard step (it went straight to Explorer). Linux wrote the ZIP's raw bytes as application/zip, which browsers ignore, and only if xclip was installed.

Windows: set CF_HDROP via ctypes plus Preferred DropEffect, read it back with DragQueryFileW to verify; fall back to PowerShell Set-Clipboard -LiteralPath (path passed via env var); then Explorer. Linux: wl-copy (if present on Wayland) -> built-in X11 owner -> xclip (if present), all setting text/uri-list and read back before reporting success. xclip/wl-copy output is no longer captured, so they can't block the CLI.

Also: Explorer /select is now a single quoted command line (paths with spaces/commas), headless/SSH Linux sessions print the path instead of launching xdg-open, and macOS escapes quotes in the path. ClipboardResult gains an optional hint field.
2026-10-07 21:22:25 +05:30
akadeepesh ae0f6772c3 feat(clipboard): add pure-Python X11 clipboard owner for Linux
Owns the CLIPBOARD selection through the raw X protocol (stdlib only), so pasting a file works without xclip or any other system package.

Serves text/uri-list (read by browsers on paste), x-special/gnome-copied-files and application/x-kde-cutselection, answers TARGETS, and exits when another app takes the clipboard. Reads MIT-MAGIC-COOKIE from XAUTHORITY / ~/.Xauthority. Signals 'ready' once it owns the selection so the launcher can verify the copy.
2026-10-07 21:22:24 +05:30
akadeepesh c927bca5fb chore(version): bump version to 0.4.5 v0.4.5 2026-10-07 11:17:54 +05:30
akadeepesh f922945729 chore(gitignore): clean up contextzip output file comments and add local_docs 2026-10-07 11:17:49 +05:30
akadeepesh f213a3c282 feat(api): enhance git change retrieval with project config support 2026-10-07 11:17:15 +05:30
akadeepesh e7b62f359e feat(cli): enhance exclusion pattern handling and improve user feedback 2026-10-07 11:17:08 +05:30
akadeepesh 1f920f81e5 feat(process_buffer): add support for always_include and always_exclude patterns in file path filtering 2026-10-07 11:16:01 +05:30
akadeepesh 39a3b3c616 feat(filters): enhance file resolution with manual include/exclude support 2026-10-07 11:15:56 +05:30
akadeepesh a466e0cdb4 fix(watcher): respect manual include/exclude settings in debug context packaging 2026-10-07 11:15:50 +05:30
Deepesh KumarandGitHub f3831728b5 Update README with asset link and comment out image
Added a link to an asset and commented out an image tag in the README.
2026-10-05 04:17:56 +05:30
akadeepesh 7f01c450bb chore(release): bump version to 0.4.4 v0.4.4 2026-09-22 02:44:07 +05:30
akadeepesh 575f915ed0 fix(inbox): add README and ensure inbox directory is created for apply-zip 2026-09-22 02:39:50 +05:30
akadeepesh 7c33f19b8e fix(docs): update apply-zip section to mention manifest diffing for improved clarity 2026-09-22 02:32:49 +05:30
akadeepesh ad47ab87f1 fix(cleanup): remove backup handling and references from apply-zip and related components 2026-09-22 02:32:37 +05:30
akadeepesh c21079d295 fix(cleanup): add handling for loose apply-report files in inbox to prevent accumulation 2026-09-22 02:27:31 +05:30
akadeepesh 63c19a959d fix(report): write apply-zip report to .contextzip/inbox/ to avoid cluttering project directory 2026-09-22 02:26:09 +05:30
akadeepesh e244810ec1 fix(applier): fall back to on-disk layout when manifest can't settle wrapper-strip
Manifest-based match-rate comparison ties at 0% (both stripped and
unstripped) whenever the freshest manifest is scoped to a subset of the
project — most commonly a git-diff manifest from output/git-changes/,
which only ever tracked files touched in one prior change. A zip of
otherwise-legitimate new files then looks equally unmatched either way,
so the previous logic played it safe and left the wrapper folder in
place, dumping it verbatim into the project.

Now, when the manifest signal ties, fall back to comparing top-level
path segments against the project's real, current directory layout
(app/, components/, lib/, etc.) instead. Confirmed against a
reproduction of the exact reported case.
2026-09-20 15:48:19 +05:30
akadeepesh 4f185984e1 chore(changelog): update changelog for version 0.4.3 with new features and fixes v0.4.3 2026-09-20 11:56:47 +05:30
akadeepesh 4e52122e42 chore(release): bump version to 0.4.3 2026-09-20 11:56:37 +05:30
akadeepesh 777e798041 fix(webui): auto-close the config UI tab after saving
The success overlay already told the user they could close the tab,
but nothing ever tried to. Calls window.close() shortly after the save
+ shutdown round-trip completes. Browsers permit scripted close on
tabs whose entire session history is a single page, which the config
UI always is, so this closes cleanly and drops the user back to their
terminal; if a browser still blocks it, the existing on-screen message
remains as the manual fallback.
2026-09-20 11:56:37 +05:30
akadeepesh 20490a75e8 feat(cli): add contextzip update / cz update self-update command
Queries PyPI for the latest published version and compares it against
the running __version__. When a newer release exists, re-invokes
whichever installer matches how contextzip was installed (pip, pipx,
or uv tool), always against the currently running interpreter rather
than a bare 'pip' off PATH.

  cz update            # check, then confirm before updating
  cz update --yes      # update immediately if available
  cz update --check    # report versions only, install nothing

Never raises on network failure — a bad connection or PyPI hiccup
degrades to a clear 'couldn't check' message instead of a traceback.
2026-09-20 11:56:37 +05:30
akadeepesh 6ac6b85070 fix(applier): stop skipping wrapper-strip when project has a same-named folder
apply-zip's wrapper-folder detection refused to strip a zip's outer
folder whenever the project already had a real directory of that same
name — which backfires on the single most common shape of AI-returned
zip: the whole project wrapped in a folder named after the project (or
its own package dir), e.g. 'project/' or 'contextzip/contextzip/...'.
Since the project's real package dir almost always shares that name,
the guard treated the wrapper as legitimate structure and dumped a
nested copy at the project root instead of updating the real files.

Now, whenever a manifest is available, the decision is made by
comparing manifest match-rate with vs. without stripping (ground
truth about what paths this project actually has) instead of
inferring intent from what merely exists on disk. Falls back to the
old on-disk heuristic only when no manifest exists to check against.

Fixes the case where apply-zip silently mis-applies a returned zip.
2026-09-20 11:56:37 +05:30
akadeepesh c84ba3367b chore: update version to 0.4.2 and enhance changelog with limits.redact_secrets enforcement v0.4.2 2026-09-03 08:46:50 +05:30
akadeepesh a858f39359 fix: stop gitignoring an exception for config.json
.contextzip/.gitignore now ignores the entire workspace with no
exceptions (previously carved out !config.json so it stayed
trackable by default). config.json is local by default like
everything else in the workspace; a team that wants to share it now
has to explicitly \`git add -f .contextzip/config.json\`, rather than
that happening automatically on a plain \`git add\`.

The core of this change (the .gitignore contents themselves, and the
docstrings in packager.py / project_config.py) landed in the previous
commit since those files were already being touched for redact_secrets.
This commit is the remaining two files whose only change is this.
2026-09-03 01:34:01 +05:30
akadeepesh fa247e34e1 feat: implement limits.redact_secrets enforcement
Previously persisted by config.py / the config UI but never actually
enforced (flagged as a known limitation as of 0.4.0). Text files
already going into the archive are now scanned for secret-shaped
values and matched values are replaced with [REDACTED] before
writing.

- New redact.py: curated high-precision patterns (AWS/Google/GitHub/
  Slack/Stripe/Anthropic/OpenAI keys, JWTs, private-key blocks, and a
  conservative generic key/secret/token/password assignment pattern)
  with placeholder-value filtering (changeme, xxxxxxxx, <placeholder>,
  ${ENV_VAR} interpolation are left alone).
- packager.py: new _write_member() helper shared by create_zip() and
  create_zip_silent(); only scans files already known (via
  ResolveResult) to be text and within limits.max_file_size_mb —
  binary and oversized files are never touched. PackageResult gains a
  redacted field.
- cli.py: passes limits.redact_secrets into create_zip(), prints a
  one-line redaction summary, forwards redacted entries to the report.
- cli_display.py: print_redaction_summary() — same 'surface it, don't
  hide it' treatment as large-file warnings, silent when nothing was
  redacted.
- report.py: itemizes every redacted file + which pattern matched.
- project_config.py: also touches the workspace-gitignore docstrings
  as part of the same pass — see the next commit for the rest of that
  change (config.py, webui/persist.py), which landed separately
  because those files have no redaction-related content.
2026-09-03 01:33:22 +05:30
Deepesh KumarandGitHub cc907cf4d4 Update README.md 2026-08-31 02:01:31 +05:30
akadeepesh 74529836d9 docs: add changelog for 0.4.1 v0.4.1 2026-08-30 23:28:59 +05:30
akadeepesh 3e4773c2d5 feat: automatic workspace cleanup and secret-redaction config
- New cleanup.py: after every successful command, prunes
  .contextzip/output/<mode>/ zip sets, backups/, and inbox/applied/
  down to the most recent cleanup.keep_recent (default 1) — no
  confirmation, no separate command. Deliberately brutal rather than
  cautious, since every zip is trivially reproducible.
- New redact.py: curated high-precision patterns (AWS/Google/GitHub/
  Slack/Stripe/Anthropic/OpenAI keys, JWTs, private-key blocks, and a
  conservative generic key/secret/token/password assignment pattern)
  with placeholder-value filtering.
- project_config.py: new CleanupConfig (enabled, keep_recent); updated
  the redact_secrets docstring to describe actual enforced behavior
  instead of 'reserved for a future...not yet enforced.
2026-08-30 23:25:25 +05:30
akadeepesh 7f7954ad1f chore(release): bump version to 0.4.1 and update changelog 2026-08-30 23:24:06 +05:30
akadeepesh 0ba6b1f121 feat(cli): wire per-mode output, auto-cleanup, and redaction into the run
- Main run, apply-zip, watch, and config converted from Panel-based
  messaging to ok/warn/err/info.
- Wire write_scan_report()/write_apply_report() into the main
  packaging flow and apply-zip; print a dim 'Full report: ...' line.
- Compute run mode (standard/git-changes/prompt) once and pass it
  through to create_zip() and the report, replacing the old
  git_changes boolean.
- Pass limits.redact_secrets into create_zip() and print a one-line
  redaction summary when anything was caught.
- Auto-run .contextzip/ cleanup after every successful command
  (main run and apply-zip) per the new cleanup.* project settings.
- Drop the '.gitignore patterns applied' line entirely (dead weight,
  no signal) and remove the now-unused used_gitignore variable.
- Clipboard step no longer wraps in a status spinner; folder-opened
  no longer prints anything.
2026-08-30 23:24:06 +05:30
akadeepesh 4f1fffd04d feat(packager): per-mode output folders + in-content secret redaction
- .contextzip/output/ now branches by run mode: output/codebase/,
  output/git-changes/, output/prompt/ (vibe.zip), output/watch/ —
  named after the flag that produced it, so it's unambiguous which
  zip is which without guessing.
- output_subdir_for_mode()/zip_filename_for_mode() are the single
  source of truth other modules (watcher.py, cleanup.py) build on.
- apply-zip's manifest auto-detection (find_latest_manifest) now
  searches recursively across the new per-mode subfolders instead of
  a flat glob.
- Implements limits.redact_secrets (previously persisted but never
  enforced, per the 0.4.0 changelog): text files already going into
  the archive get scanned for secret-shaped values and matched values
  are replaced with [REDACTED] before writing. Only ever scans files
  already known to be text and within max_file_size_mb, reusing the
  existing binary/large-file classification — never re-scans, never
  touches binaries or oversized files.
- Workspace-creation fallback warning converted from panel to a
  single warn()-style line.
2026-08-30 23:24:06 +05:30
akadeepesh b8c86674cc refactor(watch): minimal log output + bucket debug zip under output/watch/
- Convert 'Watching <command>' line, error prompts, exit summary, and
  the debug-context success/failure banner from panels to plain lines.
- debug-context.zip now writes to .contextzip/output/watch/ instead of
  the flat output/ folder, matching the same per-mode split applied to
  the main packaging command (see the packager.py commit).
2026-08-30 23:24:06 +05:30
akadeepesh afd0331a4e refactor(cli_display): replace boxed panels with a minimal log
- Introduce ok()/warn()/err()/info() as the four output primitives,
  replacing all rich.Panel/rich.Table usage.
- Merge the old 'Scanned N files' + 'Packed N files' steps into one
  print_scan_and_pack() line.
- Drop the contextzip vX.X.X / project-path banner from every command.
- Full file listings and exclusion breakdowns move to the report file
  (report.py) and behind -v/--verbose; the terminal shows one line
  per step.
- Add print_auto_cleanup() and print_redaction_summary() for the two
  newer background steps (workspace cleanup, secret redaction).
2026-08-30 23:24:06 +05:30
akadeepesh db597e04c2 refactor: improve workspace creation error message 2026-08-30 01:43:02 +05:30
akadeepesh ab3aa5105c refactor: simplify config UI server output 2026-08-30 01:42:03 +05:30
akadeepesh fb89c435f0 refactor: simplify watch mode output 2026-08-30 01:41:57 +05:30
akadeepesh 10f2f7b512 refactor: simplify AI and onboarding output 2026-08-30 01:41:49 +05:30
akadeepesh a311e68386 refactor: streamline CLI command output 2026-08-30 01:41:24 +05:30
akadeepesh 46e7aeabc2 refactor: simplify CLI terminal output 2026-08-30 01:41:07 +05:30
akadeepesh 1c8e815658 feat: add packaging reports for detailed output 2026-08-30 01:40:58 +05:30
akadeepesh ae94603520 ci: improve PyPI release validation 2026-08-30 01:40:45 +05:30
akadeepesh 35f7fb6ad8 fix: bump pyproject.toml to 0.4.0 v0.4.0 2026-08-26 21:35:24 +05:30
akadeepesh aaf0ed87dd chore(release): 0.4.0
Document the new config schema, the redesigned config UI, and the
known limitation that limits.redact_secrets is persisted but not yet
enforced.
2026-08-26 16:16:56 +05:30
akadeepesh 9869f4c96f refactor(README): streamline contextzip explanation and enhance feature descriptions 2026-08-26 16:16:53 +05:30
akadeepesh d2a4728ae1 feat(webui): redesign the config UI with tabs and a diff-based tree
Replace the single always_include/always_exclude pane with five tabs:
Files, AI selection, Workspace, Advanced, and a live Raw JSON preview.
The file tree and pattern list now render as a diff — a solid gutter
and +/- marks on every row — instead of checkboxes, matching the
git-diff mental model the rest of the tool already uses.

Still a single dependency-free HTML string: no build step, no Node.js,
no network calls from the page itself. Typography uses each OS's own
system font stack rather than a bundled or CDN-fetched face, to keep
that property.

Pattern-list and tree updates are now applied optimistically on every
edit instead of waiting on the debounced /api/preview round-trip.
2026-08-26 14:44:30 +05:30
akadeepesh 410d51e6bd feat(webui): expose and persist the full project config
/api/state now returns workspace_location, scan_depth, ai, limits,
applied_zip_retention, and webui alongside the file tree — previously
only always_include/always_exclude. /api/save accepts and validates
the same full shape. save_config_from_ui() merges nested objects
(ai/limits/webui) key-by-key rather than replacing them wholesale, so
a partial save can't wipe fields it doesn't know about.

launch_config_ui() now honors webui.port (falling back to a random
port if the configured one is taken) and webui.auto_open (skips
launching a browser tab when off).
2026-08-26 14:44:25 +05:30
akadeepesh b4b787fe50 feat(apply-zip): make applied-zip retention configurable
_move_zip_to_applied() and execute_plan() take a retain count instead
of always keeping only 1. cmd_apply_zip now loads the project config
and passes applied_zip_retention through, defaulting to 1 to match
prior behavior.
2026-08-26 14:44:19 +05:30
akadeepesh 2dedeb48dc feat(ai): support a project-level prompt template
ai.prompt_template is now prepended to every generated prompt.txt,
ahead of the task description, as a 'Project conventions:' block.
Threaded through ai_select()/build_prompt_only_txt() in selector.py,
run_ai_selection() in cli_ai.py, and the --prompt call site in cli.py.
2026-08-26 14:44:13 +05:30
akadeepesh e65e7b19c7 feat(filters): make the large-file threshold configurable
resolve_files() and resolve_files_from_git() now accept
large_file_warn_bytes instead of a fixed 1 MB constant. cli.py threads
a project's limits.max_file_size_mb through to both the filtering and
the warning text in output.
2026-08-26 14:44:08 +05:30
akadeepesh cb2110fde6 feat(config): extend project config schema
Add ai.prompt_template, a new LimitsConfig (max_file_size_mb,
redact_secrets), a new WebUIConfig (auto_open, port), and
applied_zip_retention. All new fields are optional with sensible
defaults and defensive parsing — a malformed value falls back to the
default rather than erroring. Foundation for the config UI redesign
and the features that follow in this release.
2026-08-26 14:44:03 +05:30