Skip to content

Fleet: sessions dropdown enrichment (bridge + icon + context menu) #358

Closed

Description

@jeonghun-jj-lee

Important

Approach

Enrich the sessions dropdown in the opencode app with fleet awareness. The extension
pushes fleet state via the chat bridge (postMessage relay); the app renders a fleet
icon on fleet-managed sessions and exposes per-session fleet actions (steer, stop,
re-tier, view details) in a context menu. Actions flow back through the bridge and
the extension enqueues signal files (same path as CLI verbs).


Acceptance Criteria

Bridge Protocol

  • chat_bridge.ts allowlist includes fleet-state (inbound: extension → app)
  • chat_bridge.ts allowlist includes fleet-action (outbound: app → extension)
  • Extension pushes FleetStateSnapshot on fleet record change (debounced 500ms):
    { "type": "fleet-state", "payload": { "sessions": [
      { "session_id": "...", "state": "running", "profile_name": "...",
        "tokens": 42000, "host": "...", "current_step": "..." }
    ] } }
  • App receives and stores fleet state in a SolidJS store/signal

Sessions Dropdown

  • Fleet-managed sessions show a fleet icon (small badge) next to their title
  • Fleet icon only appears for sessions whose session_id matches a FleetRecord
  • Session subtitle shows fleet state when relevant ("Running" / "Blocked" / "Crashed")
    in appropriate color

Context Menu

  • Right-click a fleet-managed session → context menu with fleet actions
  • Steer: text input dialog → sends instruction (available when state = running)
  • Stop: enqueues cancel/stop (available when running or blocked)
  • Re-tier: submenu with tier up / tier down / respool (available when running or blocked)
  • View details: popover showing profile, state, tokens, runtime, current step (always available)
  • Actions post fleet-action message back through the bridge:
    { "type": "fleet-action", "verb": "stop", "session_id": "...", "params": {} }
  • Extension receives fleet-action, enqueues signal file (same as amico fleet stop/steer/re-tier)
  • Plain (non-fleet) sessions have NO fleet icon and NO fleet context menu items

Testing Decisions

  • Unit test (extension): fleet_bridge.test.ts — FleetStateSnapshot construction from
    records, debounce behavior (multiple rapid changes → single push)
  • Unit test (extension): fleet-action handler — given action message, verify correct
    signal file written
  • Unit test (app): fleet store hydration — given a fleet-state message, verify store
    updates and re-renders session list with icons
  • Integration (app): context menu renders correct actions per state (running → all four;
    settled → view details only)
  • Manual verification (HITL): end-to-end bridge flow across the iframe boundary

Key Decisions

Decision Rationale
Bridge push (not server-reads-TOML) Keeps fleet as amicode concern; no upstream opencode server pollution
500ms debounce Prevents flooding during sweep (10 records changed at once)
Signal-file enqueue for actions Same single-writer discipline as CLI verbs; never writes records directly
SolidJS store for fleet state Reactive; sessions list re-renders automatically on state change

Constraints & Invariants

  • Bridge messages MUST be origin-checked (same as existing chat_bridge security model)
  • Fleet state is ephemeral in the app (not persisted — re-pushed on reconnect/reload)
  • Context menu items are state-gated: disabled/hidden actions never shown
  • The fleet icon is a visual indicator only — clicking it does nothing (actions are in the menu)

Source

Part of #350
Blocked by #357
ADR 0007: docs/adr/0007-fleet-panel-and-profile-ui.md

Metadata

Metadata

Labels

enhancementNew feature or requesthitlNeeds human review before merge

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions