Skip to content

fix: sidebar always subscribes to brain/status for ingest progress#148

Merged
four-bytes-robby merged 8 commits into
mainfrom
fix/sidebar-ingest-progress
Jun 14, 2026
Merged

fix: sidebar always subscribes to brain/status for ingest progress#148
four-bytes-robby merged 8 commits into
mainfrom
fix/sidebar-ingest-progress

Conversation

@four-bytes-robby

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

Copy link
Copy Markdown
Member

Sidebar now subscribes to both unscoped (brain/status) and scoped (brain/{sessionID}) channels so ingest progress is visible before session ID is set.


Summary by cubic

Scope brain status updates to the active session on both publish and subscribe, defer auto‑ingest until a session exists, and re‑publish status when a session attaches so progress appears in the right session (including continue mode). Also expose a brain-cli binary for global use.

  • Bug Fixes

    • TUI now uses useServiceBus from @four-bytes/opencode-plugin-lib@v0.6.1 to subscribe to forService("brain").forSession(sessionId) and re‑subscribe when sessionId changes; passes sessionId into sidebar and home_bottom; cleans up automatically.
    • Server scopes all updates with withSessionId; defers auto‑ingest to session.created and runs once inside the session; skips bus publish when no sessionId; re‑publishes current state on setSessionId so continue mode receives status.
  • New Features

    • Adds brain-cli in the bin field so it can be installed globally (e.g., bun link) and used from the shell.

Written for commit 77dbb88. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added a brain-cli executable entry point.
    • Session-aware UI now derives and supplies the active session id to the brain status bar.
  • Refactor
    • Status publishing and tool activity are now scoped to the active session, with auto-ingest deferred until the session is created.
  • Bug Fixes
    • Real-time status publishing is suppressed when no session id is available.
    • Session changes immediately re-sync status to the correct session context.
  • Documentation
    • Added a “Known Issues” section to capture current bus reconnect and future session-scoping work.

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

Recent review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f43844e4-9698-48ad-a0ce-a23c81e74149

Commits

Reviewing files that changed from the base of the PR and between bb38b8f and 77dbb88.

Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
Files selected for processing (5)
  • ISSUES.md
  • package.json
  • src/four-opencode-brain.ts
  • src/status.ts
  • src/tui.tsx
✅ Files skipped from review due to trivial changes (1)
  • ISSUES.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • package.json
  • src/four-opencode-brain.ts
  • src/tui.tsx

Walkthrough

Walkthrough

Status publishing is refactored to scope updates to sessions via withSessionId, the plugin captures sessionID on session.created and experimental.chat.system.transform, and triggers deferred auto-ingest within session context. All tool handlers wrap execution with session-scoped status operations. BrainStatusBar subscribes to session-scoped status streams routed from the TUI's current route context. Package.json declares a CLI entry point and updates a dependency version. ISSUES.md documents known issues and roadmap items.

Changes

End-to-end session-scoped status lifecycle

Layer / File(s) Summary
Status publication session-scoping
src/status.ts
write() now skips real-time bus publishing entirely when no AsyncLocalStorage session id exists, and publishes only to session-scoped bus targets via forSession(sid) when a session id is present. setSessionId() re-publishes the current in-memory status state into the new session context immediately after updating the session id.
Session initialization and deferred auto-ingest
src/four-opencode-brain.ts
Plugin imports withSessionId, captures sessionID on session.created and experimental.chat.system.transform hook, calls setSessionId, and triggers a single deferred auto-ingest run (guarded by _autoIngestDone flag) inside withSessionId context. Auto-ingest scaffolding moves initial scanning and status setup from eager startup into the deferred path with non-null asserted directory arguments for ingestPath invocation and diagnostic directory name computation.
Tool handlers session-scoping
src/four-opencode-brain.ts
All tool handlers (brain_ingest, brain_search, brain_reindex, brain_memory, brain_kb_add, brain_kb_record, brain_kb_review, brain_kb_search) update their execute signatures to accept toolCtx and wrap execution bodies with withSessionId(toolCtx.sessionID), ensuring all status and toast updates are session-scoped.
TUI session-scoped subscription and routing
src/tui.tsx
Imports updated to use useServiceBus instead of lifecycle hooks and BusTui. BrainStatusBar now subscribes to session-scoped brain status via useServiceBus("brain", () => props.sessionId, "status", ...) when sessionId prop is present; otherwise no subscription is established. The home_bottom slot extracts sessionID from the current route when it is a session route and passes it to BrainStatusBar.

CLI infrastructure and documentation updates

Layer / File(s) Summary
CLI executable declaration and dependency update
package.json
Package.json adds a top-level bin field mapping brain-cli to src/cli.ts and bumps the @four-bytes/opencode-plugin-lib dependency from v0.6.0 to v0.6.1.
Known issues documentation
ISSUES.md
ISSUES.md updated with a Known Issues section documenting Issue #1 (bus reconnect failure, marked FIXED in commit cb15dc8) and Issue #2 (AsyncLocalStorage session scoping as a future footgun, planned for Wave 2 replacement with explicit SessionPublisher).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • four-bytes/four-opencode-brain#145: Both PRs align on switching status publishing and subscription to the session-scoped bus model via forService("brain")/forSession(...) and withSessionId.
  • four-bytes/four-opencode-brain#144: Both PRs change how brain status messages are emitted and consumed by adding session scoping to prevent cross-session status bleed in src/status.ts and src/tui.tsx.
  • four-bytes/four-opencode-brain#141: Both PRs modify how BrainStatusBar subscribes to brain status channels based on session availability, shifting from global to session-scoped subscription behavior.
Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: the sidebar now subscribes to brain/status for ingest progress, which addresses the core issue in the changeset.
Description check ✅ Passed The description is mostly complete with clear explanations of what was fixed, but the checklist items are not marked as completed, which is a non-critical formatting issue.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Tip: You can configure your own custom pre-merge checks in the settings.

Finishing Touches
Generate docstrings
  • Create stacked PR
  • Commit on current branch
Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sidebar-ingest-progress
Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/sidebar-ingest-progress

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tui.tsx`:
- Around line 87-91: The session subscription logic is currently in an onMount
hook which only runs once during component initialization, causing it to skip
the session subscription if props.sessionId is undefined at that time and never
recheck when it becomes available later. Move the bus and unsubSession variables
to component scope, import createEffect from "solid-js", and replace the
session-scoped subscription conditional block (the if statement checking
props.sessionId that calls scoped.forSession and handleStatus) with a
createEffect that reactively watches both bus and props.sessionId as
dependencies, re-establishing the subscription whenever either changes, while
ensuring proper cleanup of the previous unsubSession when the effect re-runs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 226c129f-8744-4e66-9a04-e34984c99b43

Commits

Reviewing files that changed from the base of the PR and between cb15dc8 and 8fa32c1.

Files selected for processing (1)
  • src/tui.tsx

Comment thread src/tui.tsx Outdated

@coderabbitai coderabbitai 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.

Nitpick comments (1)
src/four-opencode-brain.ts (1)

653-676: 💤 Low value

Consider adding initial busy status for consistency.

Unlike brain_search (line 314) which calls updateStatus("busy", { text: "searching..." }) at the start, brain_kb_search does not set a busy indicator before executing the search. This results in inconsistent UX where one search operation shows a status indicator and the other does not.

Suggested fix
     execute: async (args, toolCtx) => {
       return withSessionId(toolCtx.sessionID, async () => {
+      updateStatus("busy", { text: "searching knowledge..." });
       const db = initBrainDatabase();
       try {
Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/four-opencode-brain.ts` around lines 653 - 676, Add an initial busy
status indicator to the brain_kb_search tool's execute function to match the UX
pattern used in brain_search. Call updateStatus("busy", { text: "searching..."
}) at the start of the execute function (after initBrainDatabase but before the
try block), and ensure the status is reset to "ready" not just in the catch
block for errors but also after successful completion, possibly by moving the
updateStatus("ready") call to the finally block to guarantee it runs in both
success and failure paths.
Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/four-opencode-brain.ts`:
- Around line 653-676: Add an initial busy status indicator to the
brain_kb_search tool's execute function to match the UX pattern used in
brain_search. Call updateStatus("busy", { text: "searching..." }) at the start
of the execute function (after initBrainDatabase but before the try block), and
ensure the status is reset to "ready" not just in the catch block for errors but
also after successful completion, possibly by moving the updateStatus("ready")
call to the finally block to guarantee it runs in both success and failure
paths.

Review info
Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f3e23c8-2b1a-4b02-bc29-1bdd2d3af697

Commits

Reviewing files that changed from the base of the PR and between fef1dc8 and a242763.

Files selected for processing (2)
  • src/four-opencode-brain.ts
  • src/status.ts

Enables `bun link` to install brain-cli globally (~/.bun/bin/brain-cli).
Makes the brain accessible from Claude Code, Cursor, and any AI tool via Bash —
not just opencode's native plugin tool calls.
…ion subscription

onMount fires once — if sessionId is undefined at mount time (sidebar exists before
any session), the early return prevents the subscription from ever being set up.
When the session is later created, props.sessionId changes reactively but onMount
does not re-run, so the TUI never receives bus events.

Fix: split into two parts:
- onMount: establishes the BusTui connection exactly once per component instance
- createEffect: reactively subscribes/resubscribes whenever busTui() or props.sessionId
  changes; onCleanup inside the effect tears down stale subscriptions before each re-run

This ensures the sidebar status bar connects correctly even when it mounts before
a session exists (the typical case).
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