Skip to content

fix(cli): print find results on stdout, keep diagnostics on stderr - #1734

Merged
Shashankss1205 merged 2 commits into
CodeGraphContext:mainfrom
MorningStar0709:fix/find-result-stdout
Sep 27, 2026
Merged

Shashankss1205 merged 2 commits into
CodeGraphContext:mainfrom
MorningStar0709:fix/find-result-stdout

Conversation

@MorningStar0709

@MorningStar0709 MorningStar0709 commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

What

Follow-up to #1725, as discussed there: the find subcommands still print their
result tables on the module-level Console(stderr=True), so

cgc find name busy > matches.txt

captures the init chatter and loses the matches. This adds a stdout console for
the find family and routes the product to it, keeping console for prompts
and diagnostics — the same split #1725 landed for analyze.

find already sits alongside stats and diagram, which print their product on
stdout, so this closes the last command family that had its streams inverted.

Scope measured, not guessed

The follow-up was approved "in the same shape" for "the five find commands".
On current main the group actually has seven subcommands — name,
pattern, type, variable, content, decorator, argument — and 28
console.print sites in that block (tests/integration/cli/test_cli_commands.py:427
asserts the same seven). All seven are handled here.

Command Lines (pre-change) Content Stream
find name 2159 Invalid --type '…' argument error, then typer.Exit(1) stays stderr
2225 No code elements found with name '…' stdout
2249 / 2250 Found N matches for '…': + table stdout
find pattern 2313 / 2342 / 2343 empty notice, header, table stdout
2322 wildcard/regex-not-supported note stdout
find type 2373 / 2401 / 2402 empty notice, header, table stdout
find variable 2428 / 2447 / 2448 empty notice, header, table stdout
find content 2479 / 2480 / 2481 "Neo4j full-text index is unavailable" + how to create it + cgc find pattern pointer stays stderr
2486 / 2505 / 2506 empty notice, header, table stdout
find decorator 2537 / 2557 / 2558 / 2560 empty notice, header, table, truncation footer stdout
find argument 2592 / 2609 / 2610 / 2612 empty notice, header, table, truncation footer stdout

24 sites move, 4 stay.

Why the four stay:

  • The --type validation message is not a result and must not land in a
    redirected document — same reasoning as fix(cli): print analyze results on stdout, keep prompts on stderr #1725's third rule.
  • The three Neo4j lines are environment diagnostics on a failure path, not the
    answer to the query that was asked, and they are followed by an empty-result
    notice that is the result and does move.

The wildcard/regex note (2322) and the truncation footers move because they
qualify the rows the caller is about to read — consistent with treating the
analyze footer as part of the product.

A separate find_result_console is added rather than reusing
analyze_result_console, so the already-reviewed analyze symbol keeps its
meaning and this change cannot regress it.

Tests

tests/integration/test_find_text_output_stream.py mirrors
tests/integration/test_analyze_text_output_stream.py (isolated HOME,
DEFAULT_DATABASE=kuzudb, global context) over the seven subcommands. Each
positive case asserts both directions — header and table on stdout and the
header absent from stderr — so printing to both streams cannot satisfy it.
Empty-result notices are asserted as stdout content, and the --type error is
asserted to stay off stdout.

Committed test-first: the test commit fails 8/9 against the pre-change tree
(the ninth is the stderr guard that already holds) and passes after the fix
commit.

Smoke check on a real install, with stderr discarded:

$ cgc find name busy 2>/dev/null
Resolving context...
Initializing services and database connection...
Services initialized.
Found 1 matches for 'busy':
╭──────┬──────────┬──────────────────────────╮
│ Name │ Type     │ Location                 │
├──────┼──────────┼──────────────────────────┤
│ busy │ Function │ /tmp/…/repo/app.py       │
╰──────┴──────────┴──────────────────────────╯

Local verification

  • CI-equivalent pytest tests/unit/ tests/integration/ (i.e. ./tests/run_tests.sh fast) on this branch at b05d549, two back-to-back runs: 1605 passed, 0 failed, 8 skipped in 16:40 and 1605 passed, 0 failed, 8 skipped in 16:32.
  • Both stream files together (test_find_text_output_stream.py + test_analyze_text_output_stream.py) → 13 passed in 131 s.
  • ruff check on the changed file → 19 findings, byte-identical to the pre-change file at a864a9f; the new test file is clean. (cli/main.py is not in the lint workflow's file list, so these are not gate findings.)

One stability note so the numbers above are read correctly: fast is load-sensitive on this machine. In an earlier session the identical command on the identical tree returned 16 failures, then 1 on a repeat, with no overlap between the two sets — and most of those files are untouched by this branch. The two runs above are clean; CI is the better arbiter for this suite.

What the change actually does, measured

Same fixture (1 file, 3 function nodes, isolated HOME, DEFAULT_DATABASE=kuzudb), same command set, same interpreter — the only variable is the code version: a864a9f versus this branch. Every command is read-only, so the database is identical for both runs.

Command Before: stdout Before: stderr After: stdout After: stderr
find name busy 3 L / 92 B 8 L / 462 B 9 L / 445 B 2 L / 109 B
find name nothing_here 3 / 92 3 / 157 4 / 140 2 / 109
find pattern busy 3 / 92 8 / 534 9 / 517 2 / 109
find type function 3 / 92 11 / 700 12 / 683 2 / 109
find variable MAX_LIMIT 3 / 92 8 / 493 9 / 476 2 / 109
find content busy 3 / 92 9 / 561 10 / 544 2 / 109
find decorator route (empty result) 3 / 92 3 / 152 4 / 135 2 / 109
find argument x 3 / 92 8 / 438 9 / 421 2 / 109
analyze callers busy 4 / 120 2 / 109 4 / 120 2 / 109
analyze complexity --threshold 2 15 / 740 2 / 109 15 / 740 2 / 109

Two cross-checks that come out of this table:

  1. The payload is unchanged, only its stream moved. For find name busy: before 462 B - 109 B = 353 B, after 445 B - 92 B = 353 B. The residual bytes are what stays behind on each stream (two config lines on stderr; three pre-existing progress lines on stdout), so the table itself is byte-identical on both sides — this change does not touch rendering.
  2. Blast radius. The two analyze rows are identical before and after, which is the same guarantee the existing test_analyze_text_output_stream.py locks in: the new console does not reach into fix(cli): print analyze results on stdout, keep prompts on stderr #1725's symbols.

One adjacent thing, deliberately untouched

Those three progress lines ("Resolving context…", "Initializing services…",
"Services initialized.") are already on stdout today for every command, so
post-change stdout is chatter + table. A script consuming find output still
has to skip that prefix; analyze, stats and diagram have the same property
today. Fixing it means deciding where those stage messages belong, which is a
different contract question than this one, so it stays out of this PR.

Mirrors tests/integration/test_analyze_text_output_stream.py for the seven
`find` subcommands. Fails today: the result headers and empty-result notices
are still on the stderr console.

Refs CodeGraphContext#1725
`analyze` got a stdout console in CodeGraphContext#1725; the seven `find` subcommands still
carried their tables there. A separate console per command family keeps the
blast radius inside `find`: result tables, empty-result notices and the
truncation/wildcard footers move to stdout, while the `Invalid --type`
argument error and the Neo4j full-text-index diagnostics stay on stderr.
@vercel

vercel Bot commented Sep 24, 2026

Copy link
Copy Markdown

@MorningStar0709 is attempting to deploy a commit to the shashankss1205's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Shashankss1205 Shashankss1205 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified locally on a trial merge (new stream test + CLI command tests pass). Thanks for measuring the actual seven subcommands rather than the five in the thread.

@Shashankss1205
Shashankss1205 merged commit 1d4957f into CodeGraphContext:main Sep 27, 2026
19 of 21 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog tasks to Done in CGC Progress Board Sep 27, 2026
@Shashankss1205 Shashankss1205 added gssoc:approved GSSoC validation: counts toward scoring level:intermediate GSSoC difficulty: 35 pts contributor / 20 mentor mentor:Shashankss1205 GSSoC mentor attribution: credits reviewing mentor quality:clean GSSoC quality: x1.2 contributor / +5 mentor type:bug GSSoC type bonus: bug labels Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved GSSoC validation: counts toward scoring level:intermediate GSSoC difficulty: 35 pts contributor / 20 mentor mentor:Shashankss1205 GSSoC mentor attribution: credits reviewing mentor quality:clean GSSoC quality: x1.2 contributor / +5 mentor type:bug GSSoC type bonus: bug

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants