Skip to content

enhancement(jaw-manager): show in-progress / unread badge on sidebar row when target receives a response #137

@lidge-jun

Description

@lidge-jun

Context

The jaw-manager dashboard sidebar lists every running instance, but currently gives no signal when one of those instances has activity (a response just arrived, an in-progress reply, etc.). The user has to switch into each preview to see whether anything happened.

Today's behaviour:

default :3457   ← no signal even if a reply just streamed
cli-jaw-3458    ← no signal even if a long-running command finished
cli-jaw-3459    ← no signal even if an unread response is waiting

Desired behaviour (Slack/Discord-style):

default :3457   (1)   ← something arrived since you last viewed it
cli-jaw-3458   ●in-progress
cli-jaw-3459   (3)

Proposed scope

Data path

Add a new field to DashboardInstance (or a sibling DashboardInstanceActivity) that reports:

type DashboardInstanceActivity = {
    inProgress: boolean;          // a turn is currently running on the target
    unreadCount: number;          // turns completed since the dashboard last
                                  // marked this instance as 'viewed'
    lastActivityAt: string | null;
};

Source of truth: the target's existing /api/events or /api/runtime stream. The dashboard already polls each instance for health; it can poll a small /api/activity-summary (or piggy-back on the existing endpoint) for these counters.

UI path

InstanceRow (public/manager/src/components/InstanceRow.tsx) renders one of:

  • in-progress: small spinner / pulsing dot + label running
  • unread > 0: numeric pill (N) next to the title, accent color
  • otherwise: nothing (current behaviour)

Mark-as-read trigger: when the user opens the instance in the workbench preview tab, or clicks the row, the dashboard sends POST /api/dashboard/activity/seen { port } to reset the counter.

Persistence

  • lastSeenAt per port stored in dashboard registry (registry.ts already persists per-instance state).
  • Counter is recomputed from lastActivityAt vs lastSeenAt on every scan, not stored as an absolute number — avoids drift when the dashboard restarts.

Acceptance

  • Sidebar instance row shows a numeric (N) badge when the target has completed N turns since the dashboard last marked the row as seen.
  • In-progress state is visibly distinct from unread count.
  • Selecting/opening the instance clears the badge.
  • Counter survives dashboard restart (recomputed from persisted lastSeenAt).
  • Counter does not double-count: the same completion event must not increment twice across polls.

Non-goals

  • No deep activity stream UI in the sidebar (that already exists in ActivityDock).
  • No push/notification API.
  • No cross-device sync.

Links

  • Plan tracker: devlog/_plan/260426_jaw_manager_dashboard/10.10_dashboard_lifecycle_persistence.md (sibling slice — different concern, both under jaw-manager 10.x)
  • Component: public/manager/src/components/InstanceRow.tsx
  • Registry: src/manager/registry.ts (will hold lastSeenAt)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:web-uiWeb UI and frontend behaviorenhancementNew feature or requestpriority:P2Important, but not next

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions