Skip to content

feat(index): styled progress bar for index and sync - #30

Merged
sunerpy merged 2 commits into
mainfrom
feat/index-progress
Jun 23, 2026
Merged

sunerpy merged 2 commits into
mainfrom
feat/index-progress

Conversation

@sunerpy

@sunerpy sunerpy commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Summary

codegraph index / init / sync showed no feedback during extraction, so users thought it was stuck. Add a styled indicatif progress bar with a live count.

  • index (and init's index phase): Scanning files… then a bar Indexing [====>---] 1234/5678 files (elapsed) <current file>. --verbose shows the current file in the bar message.
  • sync: a spinner with Syncing {pos}/{len} files (new sync_project_once_with_progress callback in codegraph-watch).
  • Progress is a pure side effect on stderr — never stdout. Hidden when stderr is not a TTY or --quiet, so pipes and CI logs stay clean.

indicatif was already in the dep tree (via self_update); no new top-level crate, single 0.17 major (no duplicate).

Verification (all green)

  • Golden byte-equivalence (cargo test -p codegraph-bench): 4/4 + 11/11 byte-identical — the bar does not reorder/alter extraction.
  • Hands-on: TTY → styled bar renders+clears; piped → clean stdout summary, stderr only Scanning files…, 0 carriage returns; --quiet → stdout & stderr both 0 bytes; DB counts identical with/without the bar (index + sync).
  • cargo test --workspace, cargo clippy --workspace --all-targets -- -D warnings, cargo fmt --all --check, bash scripts/guardrail.sh all clean; Windows x86_64 cross-compile exit 0.

feat: → release-please cuts v0.6.0.

sunerpy added 2 commits June 23, 2026 10:55
Users had no feedback during extraction and thought it was stuck.
Add an indicatif progress bar to `index` (incl. the `init` index phase)
and `sync`.

The bar draws to STDERR (stdout carries JSON / golden output) and counts
files as they are processed: `{spinner} Indexing [{bar}] {pos}/{len}
files ({elapsed}) {wide_msg}`. `--verbose` puts the current file in
`{wide_msg}` instead of printing to stdout. A "Scanning files…" stage
line precedes the bar; the existing summary stays.

It is hidden (`ProgressBar::hidden()`) when stderr is not a TTY or
`--quiet` is set, so CI logs and pipes stay clean — no `\r` spam.

Progress is a pure side effect: it only counts/displays and never gates,
reorders, or alters extraction, so the deterministic golden
byte-equivalence is preserved (par_iter / streaming insert order
unchanged). sync gains `sync_project_once_with_progress`, a per-file
callback variant; the bar lives in the CLI so the watch/extract crates
take no TTY dependency.

indicatif is pinned to 0.17 — the major already resolved transitively
via self_update — so Cargo.lock keeps a single copy.
… flake

The allowlist test set_var("CODEGRAPH_MCP_TOOLS") under a LOCAL fn-scoped
static Mutex, but CODEGRAPH_MCP_TOOLS is read from the process-global env in
schemas.rs and cargo runs tests multi-threaded in one process. The
default-surface readers (tools_list_matches_upstream_names_and_schemas and
default_project_indexed_serves_full_tools_list_after_initialize, both asserting
the 4-tool surface) did not share that lock, so a parallel reader could observe
the temporarily-set 2-tool allowlist and fail with 'left: 2 right: 4'.

Promote ENV_LOCK to a shared module-level static Mutex and have the setter plus
both default-surface readers acquire it; recover from poisoning so one failing
test cannot cascade-poison the rest. The setter still removes the var before any
assertion, so a failed assert never leaks it.

Test-only isolation fix: no product code, schemas.rs, or golden tools_list.json
change; golden byte-equivalence unaffected.
@sunerpy
sunerpy merged commit 6abc762 into main Jun 23, 2026
4 checks passed
@sunerpy
sunerpy deleted the feat/index-progress branch June 23, 2026 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant