feat(coordination): move the worklist API-side (server authority + TUI/app clients + push) - #178
Conversation
Add a pure buildCoordinationView (model + worklist in one pass, shared by server and TUI fallback so they never diverge) and a GET /coordination-worklist endpoint that assembles it server-side from desktop.getState() + notifications + thread entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the Coordination screen service-first: a new getFromProjectService (sharing postToProjectService's retry/recovery loop) fetches /coordination-worklist, applied via a shared applyCoordinationModel so the service and the local fallback produce identical host state. Refresh is decoupled from render — nav/render use the cached worklist, while screen entry, the heartbeat, and mutations refresh from the service (local build remains the offline fallback). Tab re-filters the cached list with no rebuild. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add getCoordinationWorklist + typed response interfaces to app/lib/api.ts so the Expo client can consume the same reconciled worklist authority the TUI uses, mirroring the WorklistItem / CoordinationModel shapes from the server. Client contract only — no UI wired yet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hook the dashboard's in-process event-bus subscriber so a coordination- relevant alert (agent needs you, task done, …) refreshes the worklist and re-renders immediately when the screen is showing, instead of waiting for the heartbeat poll. Coalesced so an event burst does a single refresh; the 1s heartbeat remains the fallback cadence. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughAdds a ChangesService-driven coordination worklist
Sequence Diagram(s)sequenceDiagram
rect rgba(70, 130, 180, 0.5)
Note over Multiplexer,MetadataServer: Push-triggered coordination refresh
end
participant Multiplexer
participant scheduleCoordinationPush
participant reloadCoordination
participant refreshCoordinationFromService
participant MetadataServer
participant applyCoordinationModel
participant renderCoordination
Multiplexer->>scheduleCoordinationPush: alert event (coalesced)
scheduleCoordinationPush->>reloadCoordination: host
reloadCoordination->>refreshCoordinationFromService: host (service preferred)
refreshCoordinationFromService->>MetadataServer: GET /coordination-worklist?participant=user
MetadataServer-->>refreshCoordinationFromService: { model, worklist, threads }
refreshCoordinationFromService->>applyCoordinationModel: payload
applyCoordinationModel-->>refreshCoordinationFromService: host state updated
refreshCoordinationFromService-->>reloadCoordination: true
reloadCoordination-->>scheduleCoordinationPush: done
scheduleCoordinationPush->>renderCoordination: re-render
scheduleCoordinationPush->>scheduleCoordinationPush: clear coordinationPushScheduled
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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/multiplexer/runtime-state.ts`:
- Around line 166-167: The promise chain at line 166 with the void operator in
the heartbeat path is missing a rejection handler. The call to
host.refreshCoordinationFromService().then(() =>
host.renderCurrentDashboardView()) needs to have a .catch() handler appended to
it to gracefully handle any rejections from refreshCoordinationFromService,
preventing unhandled rejection errors from surfacing on the status-refresh
interval. Add the rejection handler right after the .then() call to ensure any
errors are properly caught and logged.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 93ed2378-f198-48d1-b629-07fb45724a56
📒 Files selected for processing (15)
app/lib/api.tssrc/coordination-model.test.tssrc/coordination-model.tssrc/metadata-server.test.tssrc/metadata-server.tssrc/multiplexer/coordination.test.tssrc/multiplexer/coordination.tssrc/multiplexer/dashboard-actions-methods.tssrc/multiplexer/dashboard-control.tssrc/multiplexer/index.tssrc/multiplexer/notifications.test.tssrc/multiplexer/notifications.tssrc/multiplexer/runtime-state.tssrc/multiplexer/session-launch.tssrc/multiplexer/subscreens.ts
Review fixes: validate the service payload shape (model.items/worklist.items are arrays) before applying so a malformed/version-skewed response fails fast into the local fallback; guard notificationEntries access in applyCoordinationFilter; add .catch to the heartbeat, showCoordination, and thread-refresh fire-and-forget chains; kick a service refresh on the session-launch coordination entry path so it reaches the same authority as showCoordination. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Moves the Coordination model fully to the per-project control service so the worklist is built once, server-side, and consumed by both front-ends — the terminal TUI now, the Expo app next. Completes the A+C direction (service = single authority; front-ends are thin clients) for the Coordination screen.
Previously the TUI recomputed the reconciled "needs-you" worklist locally on every render. Now the service owns it; the TUI is a service-first client with a local fallback, and updates arrive via push.
Phases
buildCoordinationView(input) → { model, worklist }(shared by server + TUI fallback so they never diverge) +GET /coordination-worklistassembling it fromdesktop.getState()+ notifications + thread entries.getFromProjectService(sharespostToProjectService's retry/recovery loop);applyCoordinationModel/applyCoordinationFiltershared by service + local paths; refresh decoupled from render (nav renders cache; screen entry, heartbeat, and mutations refresh from the service; local build is the offline fallback).getCoordinationWorklist+ typed response inapp/lib/api.tsso the non-TUI app can consume the same authority (client only, no UI yet).Testing
yarn typecheck,yarn lint, fullyarn vitest(1489 passing),yarn build— all green.cd app && yarn typecheck+eslint lib/api.ts— clean.buildCoordinationViewparity, the/coordination-worklistroute, TUI service-first + fallback, andscheduleCoordinationPush(off-screen no-op / refresh / coalesce).🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Improvements
Bug Fixes