Add dry-run index preview - #274
Conversation
|
Hi @faysou , Thanks for the PR! Just wonder what's the main motivation for this new feature? When will you use it? I ask because this will determine how precise we need it to be. Under the current implementation, we'll show new files and deleted files, but not showing updated files. It may be unexpected and misleading for many cases. cocoindex has a "shadow run / preview API". With this, we may be able to report more precise diffs. |
|
Hi @georgeh0 my use case was initially for new files. I saw many more files were about to get indexed but I didn't know where they were from. They turned up to be from another wortree created by an agent. I asked the agent where are the files and it wrote some custom script and I thought it could be useful for the future as a proper feature. But I agree that it could be more precise as well for updated files. I can leave the implementation to you if you prefer or I can update the PR. But I'm not a regular on this project so you may know better. |
492e563 to
cf4c51e
Compare
- Track file fingerprints after successful index updates - Report added, updated, and deleted files without writes - Preserve path-only previews until the manifest exists
cf4c51e to
6ed59d7
Compare
|
I've updated the PR. |
Summary
ccc index --drylists files that the next index would add, update, or delete. It uses the same include patterns, exclude patterns, nested.gitignorerules, andmax_file_sizelimit as normal indexing, then prints each group in sorted order with an exact count. Modified files appear underFiles to update.Successful indexes persist a content fingerprint for every matched source file. The dry-run command hashes the current matched files and reads those fingerprints through a read-only SQLite connection. It does not start indexing or change the target database.
Design
CocoIndex 1.0.18 exposes
App.update(preview=True), but its preview planner supports only flat target actions. The code index uses a SQLite table target with child row providers, so applying that API to the indexing app fails before it can report file changes.This change adds a small flat CocoIndex app for the file manifest. Each
track_filecomponent owns one path and stores the file content fingerprint incode_file_manifest. CocoIndex memoization lets normal incremental indexes skip unchanged manifest components. The manifest update runs only after the main indexing app succeeds.flowchart TB Index["ccc index"] --> Main["Update search index"] Main --> Manifest["Update file manifest"] Manifest --> Stored["code_file_manifest"] Dry["ccc index --dry"] --> Match["Match and hash source files"] Dry --> Read["Read stored fingerprints"] Stored --> Read Match --> Compare["Compare paths and fingerprints"] Read --> Compare Compare --> Added["Added"] Compare --> Updated["Updated"] Compare --> Deleted["Deleted"]The normal index writes the baseline. Dry runs compare against that baseline without updating it.
Behavior and compatibility
target_sqlite.db.Relevant files
src/cocoindex_code/cli.py: prints added, updated, and deleted files and explains the legacy fallback.src/cocoindex_code/index_changes.py: tracks source fingerprints and performs the read-only comparison.src/cocoindex_code/project.py: creates the manifest table and updates it after successful indexing.tests/test_index_changes.py: covers missing and legacy indexes, content updates, additions, deletions, stable repeated output, and byte-exact database preservation.tests/test_e2e.py: verifies the CLI and daemon path while confirming that indexed search rows remain unchanged.tests/test_project_indexing.py: keeps the controlled project fixture aligned with the manifest app lifecycle and asserts one manifest update per completed index.Verification
uv run --no-sync pytest tests/test_index_changes.py tests/test_cli_helpers.py -q: 31 passed.uv run --no-sync pytest tests/test_e2e.py::test_session_index_dry_lists_changes_without_indexing -q: 1 passed.uv run --no-sync pytest tests/test_embed_params_forwarding.py tests/test_chunker_registry.py -q: 7 passed.uv run --no-sync pytest tests/test_project_indexing.py -q: 5 passed.git diff --check: passed.