Skip to content

[FIX] Hide ProgressBar when ingest finishes - #132

Merged
four-bytes-robby merged 13 commits into
mainfrom
fix/131-hide-progressbar-when-done
Jun 14, 2026
Merged

four-bytes-robby merged 13 commits into
mainfrom
fix/131-hide-progressbar-when-done

Conversation

@four-bytes-robby

@four-bytes-robby four-bytes-robby commented Jun 13, 2026

Copy link
Copy Markdown
Member

Summary

Resets the current and total signals in handleStatus when an ingest finishes (ready/success) and when a new ingest starts (init), so the ProgressBar reliably disappears and starts from a clean baseline.

Root cause

The render condition in src/tui.tsx was:

{busy() && current() > 0 && total() > 0 && (<ProgressBar ... />)}

After a busy → ready transition, busy flipped to false but current/total retained the last values. On the very next event, the current > 0 && total > 0 guard could still evaluate true before any new busy event arrived (e.g. during a transient bus reconnect), causing a stale bar to flash. The init branch also didn't reset, so a second ingest could briefly show numbers from a prior run.

Changes

  • src/tui.tsxhandleStatus():
    • init branch: add setCurrent(0); setTotal(0);
    • ready/success (else) branch: add setCurrent(0); setTotal(0);
    • busy branch: unchanged — keeps the live values

Acceptance

  • ProgressBar disappears immediately on ready (signals zeroed)
  • New ingest (initbusy) starts from 0/0 (no leaked values)
  • bun run build succeeds (server + TUI)
  • No changes to render condition — the existing current > 0 && total > 0 guard is now sufficient

Closes #131


Summary by cubic

Hide the ingest ProgressBar as soon as a run finishes and show it inline only while work is active, now with a light grey bar and black text for better contrast. Status updates stream in real time on session-scoped bus channels with an HTTP fallback, and ingest has a 10s per-file timeout to avoid hangs.

  • Bug Fixes

    • Reset current/total on init and on ready/success so the bar disappears and new ingests start at 0.
    • Inline the ProgressBar with its label to remove the extra line and stop transient flashes; remove the duplicate file counter from busy text.
    • Improve readability by using black foreground on filled progress cells.
  • New Features

    • Publish status via BusClient on brain/{sessionId}; TUI subscribes with BusTui and falls back to HTTP polling.
    • Upgrade @four-bytes/opencode-plugin-lib to v0.5.0 and use its shared ProgressBar with a light grey fill.
    • Add a 10s per-file ingest timeout to prevent hangs on large repos.

Written for commit a6bae9b. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

5 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/four-opencode-brain.ts">

<violation number="1" location="src/four-opencode-brain.ts:694">
P2: Global status channel is overwritten per latest chat message, so concurrent sessions can receive each other’s status updates. This causes incorrect progress/status display across sessions.</violation>
</file>

<file name="src/status.ts">

<violation number="1" location="src/status.ts:54">
P2: getBus permanently caches a rejected BusClient connection. One transient connect failure disables all future bus publishes until process restart.</violation>
</file>

<file name="src/tui.tsx">

<violation number="1" location="src/tui.tsx:80">
P2: Async bus subscription can leak when component unmounts before `BusTui.connect()` resolves. Guard with a disposed flag and close/unsubscribe immediately in the resolve path when already unmounted.</violation>

<violation number="2" location="src/tui.tsx:154">
P2: ProgressBar can remain visible on error/idle because render guard ignores `busy()`. Gate the bar by `busy()` (or clear progress on error) to avoid stale progress display.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread package.json Outdated
output.system.push(brainSystemPrompt());
},
"chat.message": async (_hookInput, output) => {
if (_hookInput?.sessionID) setSessionId(_hookInput.sessionID);

@cubic-dev-ai cubic-dev-ai Bot Jun 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Global status channel is overwritten per latest chat message, so concurrent sessions can receive each other’s status updates. This causes incorrect progress/status display across sessions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/four-opencode-brain.ts, line 694:

<comment>Global status channel is overwritten per latest chat message, so concurrent sessions can receive each other’s status updates. This causes incorrect progress/status display across sessions.</comment>

<file context>
@@ -691,6 +691,7 @@ const _serverPlugin = async (input: PluginInput) => {
       output.system.push(brainSystemPrompt());
     },
     "chat.message": async (_hookInput, output) => {
+      if (_hookInput?.sessionID) setSessionId(_hookInput.sessionID);
       if (output.message?.role === "user" && output.message?.content) {
         const stored = await onChatMessage(input, output.message as { role: string; content: string });
</file context>
Fix with cubic

Comment thread src/status.ts
Comment on lines +54 to +57
_busPromise = BusClient.connect().catch((err) => {
console.warn("[brain] BusClient connect failed:", (err as Error).message);
throw err;
});

@cubic-dev-ai cubic-dev-ai Bot Jun 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: getBus permanently caches a rejected BusClient connection. One transient connect failure disables all future bus publishes until process restart.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/status.ts, line 54:

<comment>getBus permanently caches a rejected BusClient connection. One transient connect failure disables all future bus publishes until process restart.</comment>

<file context>
@@ -23,22 +24,41 @@ export interface StatusOpts {
 
+function getBus(): Promise<BusClient> {
+  if (!_busPromise) {
+    _busPromise = BusClient.connect().catch((err) => {
+      console.warn("[brain] BusClient connect failed:", (err as Error).message);
+      throw err;
</file context>
Suggested change
_busPromise = BusClient.connect().catch((err) => {
console.warn("[brain] BusClient connect failed:", (err as Error).message);
throw err;
});
_busPromise = BusClient.connect().catch((err) => {
_busPromise = null;
console.warn("[brain] BusClient connect failed:", (err as Error).message);
throw err;
});
Fix with cubic

Comment thread src/tui.tsx
});

// Real-time WebSocket subscription via plugin bus
BusTui.connect()

@cubic-dev-ai cubic-dev-ai Bot Jun 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Async bus subscription can leak when component unmounts before BusTui.connect() resolves. Guard with a disposed flag and close/unsubscribe immediately in the resolve path when already unmounted.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tui.tsx, line 80:

<comment>Async bus subscription can leak when component unmounts before `BusTui.connect()` resolves. Guard with a disposed flag and close/unsubscribe immediately in the resolve path when already unmounted.</comment>

<file context>
@@ -60,9 +66,30 @@ function BrainStatusBar(props: { centered?: boolean; api: TuiPluginApi }) {
+    });
+
+    // Real-time WebSocket subscription via plugin bus
+    BusTui.connect()
+      .then((b) => {
+        bus = b;
</file context>
Fix with cubic

Comment thread src/tui.tsx Outdated
{busy() ? <Spinner fg={fg()} /> : <text fg={connecting() ? theme().error : fg()}>{indicator()}</text>}
<text fg={connecting() ? theme().error : theme().textMuted}> {connecting() ? "connecting..." : status()}</text>
</box>
{current() > 0 && total() > 0 && (

@cubic-dev-ai cubic-dev-ai Bot Jun 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: ProgressBar can remain visible on error/idle because render guard ignores busy(). Gate the bar by busy() (or clear progress on error) to avoid stale progress display.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/tui.tsx, line 154:

<comment>ProgressBar can remain visible on error/idle because render guard ignores `busy()`. Gate the bar by `busy()` (or clear progress on error) to avoid stale progress display.</comment>

<file context>
@@ -125,6 +151,9 @@ function BrainStatusBar(props: { centered?: boolean; api: TuiPluginApi }) {
             {busy() ? <Spinner fg={fg()} /> : <text fg={connecting() ? theme().error : fg()}>{indicator()}</text>}
             <text fg={connecting() ? theme().error : theme().textMuted}> {connecting() ? "connecting..." : status()}</text>
           </box>
+          {current() > 0 && total() > 0 && (
+            <ProgressBar current={current()} total={total()} />
+          )}
</file context>
Suggested change
{current() > 0 && total() > 0 && (
{busy() && current() > 0 && total() > 0 && (
Fix with cubic

@four-bytes-robby
four-bytes-robby merged commit 49ec7c4 into main Jun 14, 2026
4 checks passed
@four-bytes-robby
four-bytes-robby deleted the fix/131-hide-progressbar-when-done branch June 14, 2026 07:07
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.

[FIX] Hide ProgressBar when ingest finishes

1 participant