Skip to content

Fix: config persistence, stale footer, and REPL rendering/timing#2806

Open
aniruddhaadak80 wants to merge 2 commits into
Tracer-Cloud:mainfrom
aniruddhaadak80:fix/first-batch-fixes-reapplied
Open

Fix: config persistence, stale footer, and REPL rendering/timing#2806
aniruddhaadak80 wants to merge 2 commits into
Tracer-Cloud:mainfrom
aniruddhaadak80:fix/first-batch-fixes-reapplied

Conversation

@aniruddhaadak80

Copy link
Copy Markdown
Contributor

Fixes #2058, #2117, #2230, #2116, #2115

This PR addresses the first batch of issues:

  1. Config Persistence ([BUG] PyInstaller builds: onboard wizard writes .env to ephemeral temp directory — config lost on exit #2058): Checks if sys.frozen is true, falling back to CWD to avoid config loss on PyInstaller temp directories.
  2. Stale Progress Footer ([BUG] Investigation live footer remains above final RCA report #2117): Configures the Rich live display as ransient=True so it gets cleared immediately upon completion.
  3. REPL Rendering & Timing ([BUG] /update output disappears in interactive shell #2230, [BUG] REPL spinner flashes and overlaps investigation footer during live RCA #2116, [BUG] Confirmation prompt shows normal input box and starts spinner timer #2115): Adds confirmation duration tracking, hides the spinner row during confirmations, makes the prompt placeholder dynamic, and blocks prompt-toolkit's redraw loop for investigations/synchronous commands.

Copilot AI review requested due to automatic review settings June 13, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

Greptile code review

This repo uses Greptile for automated review. Before merge, aim for Confidence Score: 5/5 with zero unresolved review threads — see CONTRIBUTING.md.

Run a review — add a PR comment with:

@greptile review

Give it ~5-10 minutes (sometimes longer) for results, then fix feedback and re-trigger until you reach Confidence Score: 5/5.

Optional: automate with the greploop skill.

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes four independent issues: config path resolution under PyInstaller, a stale Rich progress footer, and several REPL rendering/timing problems around confirmation dialogs and spinner elapsed time.

  • Config persistence: PROJECT_ROOT now falls back to Path.cwd() when sys.frozen is set or pyproject.toml is absent, preventing .env writes into PyInstaller temp directories.
  • Stale footer: Rich Live display is configured as transient=True so it clears on completion.
  • REPL timing: ReplState tracks per-dispatch confirmation wait time; SpinnerState.inline_spinner_ansi deducts that time from displayed elapsed, placeholder is hidden during confirmation, and dispatch_needs_exclusive_stdin is refactored to a simpler catch-all that now also gates new_alert routes.

Confidence Score: 3/5

The config and spinner-timing changes are safe, but the dispatch routing refactor has a likely regression that could corrupt user input.

The simplification of dispatch_needs_exclusive_stdin groups /watches with genuinely async background commands and returns False, removing the guard specifically called out in comments as preventing CPR byte leakage into the next prompt buffer. Every other change in the PR is well-scoped and low-risk.

app/cli/interactive_shell/runtime/dispatch.py — the /watches classification and the catch-all True logic need a second look before merging.

Important Files Changed

Filename Overview
app/cli/interactive_shell/runtime/dispatch.py Rewrites dispatch_needs_exclusive_stdin with a catch-all True for most slash commands; incorrectly groups /watches (a table-outputting list command) with async /watch and /unwatch, removing CPR-leakage protection. Also adds confirm timing and _is_awaiting_confirm on the prompt_toolkit app.
app/cli/interactive_shell/runtime/state.py Adds confirm_start_time and total_confirm_duration to ReplState, and updates inline_spinner_ansi to subtract accumulated confirmation wait time from the displayed elapsed duration. Logic is sound.
app/cli/interactive_shell/runtime/loop.py Resets confirm timing fields at the start of each dispatch and passes state to inline_spinner_ansi. Change is minimal and correct.
app/cli/wizard/config.py Falls back PROJECT_ROOT to Path.cwd() when running under PyInstaller (sys.frozen) or when pyproject.toml is absent, preventing config loss in packaged builds.
app/cli/interactive_shell/prompting/prompt_surface.py Hides placeholder text during confirmation by checking _is_awaiting_confirm on the prompt_toolkit app via getattr with a safe default. Straightforward change.
tests/cli/interactive_shell/test_terminal_runtime_routing.py Updates expectations for /integrations list to require exclusive stdin. No test coverage added for the /watches change or the new new_alert routing path.
tests/cli/test_output.py Adds raising=False to monkeypatch for os.fpathconf to handle platforms where the attribute doesn't exist. Correct fix.

Sequence Diagram

sequenceDiagram
    participant User
    participant RunLoop as run_interactive
    participant Dispatch as dispatch.py
    participant State as ReplState
    participant Spinner as SpinnerState
    participant Prompt as prompt_surface.py

    User->>RunLoop: submit text
    RunLoop->>State: reset total_confirm_duration and confirm_start_time
    RunLoop->>Dispatch: dispatch_needs_exclusive_stdin
    Note over Dispatch: new_alert route True, watch/unwatch False, all else True
    RunLoop->>Dispatch: dispatch_one_turn with confirm_fn

    alt confirmation needed
        Dispatch->>State: begin_confirmation and record confirm_start_time
        Dispatch->>Prompt: set _is_awaiting_confirm True on app
        Prompt-->>User: placeholder hidden
        Spinner-->>User: spinner row hidden during confirm
        User->>Dispatch: deliver answer
        Dispatch->>State: accumulate total_confirm_duration and clear start_time
        Dispatch->>Prompt: clear _is_awaiting_confirm on app
    end

    Spinner->>State: inline_spinner_ansi reads accumulated confirm duration
    Note over Spinner: elapsed excludes user wait time
    Spinner-->>User: shows LLM processing time only
Loading

Reviews (1): Last reviewed commit: "Fix: config persistence, stale footer, a..." | Re-trigger Greptile

Comment on lines +133 to +135
# /watch commands run asynchronously in the background, so they don't need exclusive stdin
if name in {"/watch", "/watches", "/unwatch"}:
return False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 /watches incorrectly removed from exclusive-stdin guard

/watches (list active watches) was previously in _EXCLUSIVE_STDIN_MENU_COMMANDS under the explicit comment "Table-outputting commands: must complete before the next prompt_async() starts, otherwise patch_stdout redraws trigger ESC[6n DSR queries whose CPR responses land as literal keystrokes in the incoming prompt buffer." The new code lumps it with /watch and /unwatch — which genuinely start background tasks — and returns False, removing that protection. Running /watches after a streaming investigation will now allow prompt_async() to start before the table finishes rendering, which can corrupt the next input buffer with stale CPR bytes — exactly the race the original comment described.

Comment on lines +137 to +140
# /tests run/synthetic/cloudopsbench are run as background tasks, others are synchronous
if name == "/tests":
_BACKGROUND_TEST_SUBCOMMANDS = {"run", "synthetic", "cloudopsbench"}
return not (args and args[0] in _BACKGROUND_TEST_SUBCOMMANDS)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 _BACKGROUND_TEST_SUBCOMMANDS is a set literal allocated on every call to dispatch_needs_exclusive_stdin. It should be a module-level constant like the existing frozen-set siblings above it.

Suggested change
# /tests run/synthetic/cloudopsbench are run as background tasks, others are synchronous
if name == "/tests":
_BACKGROUND_TEST_SUBCOMMANDS = {"run", "synthetic", "cloudopsbench"}
return not (args and args[0] in _BACKGROUND_TEST_SUBCOMMANDS)
# /tests run/synthetic/cloudopsbench are run as background tasks, others are synchronous
if name == "/tests":
return not (args and args[0] in _BACKGROUND_TEST_SUBCOMMANDS)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +204 to +206
app = get_app_or_none()
if app is not None:
setattr(app, "_is_awaiting_confirm", True) # noqa: B010

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Dynamic attribute on third-party Application object

setattr(app, "_is_awaiting_confirm", True) attaches a custom attribute directly to a prompt_toolkit Application instance. While getattr(..., False) in prompt_surface.py provides a safe read-side default, naming it with a leading underscore implies it is an internal prompt_toolkit attribute and risks a future collision if prompt_toolkit adds its own _is_awaiting_confirm. Exposing the flag through the ReplState object (already threaded through the same call site) would avoid touching the third-party instance entirely.

…greSQL blocking queries, unified /agents commands & autocomplete, and EmbeddingsClient
Comment thread app/agents/registry.py
val = int(arg)
if val > 0:
is_positive_int = True
except ValueError:
@property
def model_name(self) -> str:
"""The model name used for embeddings."""
...
@property
def dim(self) -> int:
"""The dimensionality of the embedding vectors."""
...

def embed(self, texts: list[str]) -> list[list[float]]:
"""Generate embeddings for the given list of texts."""
...
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.

[BUG] PyInstaller builds: onboard wizard writes .env to ephemeral temp directory — config lost on exit

3 participants