Skip to content

[FEATURE]: Publish tui.session.select bus event on internal session navigation #20996

@c0dn

Description

@c0dn

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

Background

I'm building a plugin called opencode-cache-guard that warns users when they switch to a session whose Anthropic prompt cache has likely expired (idle > 55 min, > 10K cached tokens). Stale caches silently re-warm at 10-20x the cost of a cache hit, so the plugin exists to surface this before the user is surprised.

The ideal UX is: warn the moment you switch to a stale session, not when you hit send. To do that, a plugin needs to know when session focus changes.

What's missing

The `tui.session.select` BusEvent already exists in `src/cli/cmd/tui/event.ts`, the server route `/tui/select-session` publishes it, and the TUI already listens for it in `app.tsx`:

```ts
sdk.event.on(TuiEvent.SessionSelect.type, (evt) => {
route.navigate({ type: "session", sessionID: evt.properties.sessionID })
})
```

But internal TUI navigation calls `route.navigate()` directly, so the bus event never fires and plugins never see it. The three affected paths are:

  1. `dialog-session-list.tsx` `onSelect` — user picks a session from the list
  2. `app.tsx` `onMount` with `args.sessionID` — `opencode -s ` startup
  3. `app.tsx` `createEffect` with `args.continue` — `opencode -c` resume last session

Because `bus.subscribeAll()` forwards all bus events to plugin `event` hooks, wiring up these paths would give plugins a clean way to react to session focus changes without any new plugin API surface.

Proposed fix

For the session list dialog: replace `route.navigate()` with `sdk.client.tui.selectSession()`. The existing event handler in `app.tsx` will call `route.navigate()`, so navigation is unchanged. The bus event now fires, plugins can see it.

PR submitted for the dialog case: #20997

The startup args cases (`-s` and `-c`) in `app.tsx` would need the same treatment but left for follow-up since they have slightly different async timing considerations.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions