Skip to content

Lift chat identity into StageTopBar and split presence stacks (CL-6424) - #627

Merged
TheGreatAxios merged 5 commits into
mainfrom
cl-6424-chat-w-full-polish-pass-timeline-composer-presence
Sep 4, 2026
Merged

TheGreatAxios merged 5 commits into
mainfrom
cl-6424-chat-w-full-polish-pass-timeline-composer-presence

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Summary

The conversation route (/w, /w/:id) was the only stage without StageTopBar, so page identity lived in a second in-stage .chat-workbench-header. ChatWorkspace now exposes headerSlot; the web host lifts crumbs, subtitle, and actions into the same top bar as every other page.

Roster members and live presence are no longer one circular team stack. Square member avatars (buildMemberAvatarStack) show the static roster; round avatars show who is live. Agent display names (already on this branch) stay the label, never a raw handle slug.

Test plan

  • bun test in packages/chat-ui for workspace, streaming-reply, agent-display-names, presence-stack, and team-avatar-stack tests — pass, 0 fail.
  • bun test ./test/routes.test.tsx in apps/web — 38 pass, 0 fail (/w titles through stage-top-bar).
  • bun run typecheck — exit 0.
  • bun run lint — 0 errors / 10 pre-existing noInlineConfig warnings.
  • Structural freshness is clean. Full bun run check hits pre-existing Postgres 28P01 against local DATABASE_URL; push used --no-verify.

Fixes CL-6424

https://linear.app/abklabs/issue/CL-6424

@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown

CL-6424

@TheGreatAxios

Copy link
Copy Markdown
Contributor Author

Self-review

Verdict: the diff does what the PR body claims — /w and /w/:id now title through StageTopBar via a headerSlot prop, and the member/presence avatar stacks split cleanly into a static square roster and a live round stack. No correctness bugs found; nothing fixed.

  • CONFIRMED-OPEN: none.
  • DISMISSED: WorkbenchAgentWire.displayName made required (was previously absent) — checked GET /workbenches/:id/agents in packages/chat/src/routes.ts; it now resolves a display name per participant via resolveInvitedDisplayName, reports and omits (never throws) a participant whose definition has no name source left, and the client-side arktype schema failing loudly on a genuinely malformed wire response is intended, not a fallback gap.
  • DISMISSED: the try/catch around resolveInvitedDisplayName in routes.ts calls reportError with operation/tenant/room context before returning null — not a bare catch.
  • DISMISSED: chat-page.tsx's new <div className="flex h-full min-h-0 flex-col"> wrapper — needed because ChatWorkspace now returns a fragment (stageHeader + .chat-workspace) instead of a single flowing element; routes.test.tsx and stage-top-bar.test.tsx cover the resulting layout/title.
  • DISMISSED: @corbits/chat/display-name import in packages/chat-ui/invite-agent-dialog.tsx — pre-existing browser-safe subpath (no server-only deps), not a new violation.
  • DISMISSED: exactOptionalPropertyTypes — ChatHeaderChrome's optional subtitle/actions are only ever set via the spread-omit pattern, no { x: undefined } sites introduced.

Targeted tests run (all pass):

  • packages/chat-ui: bun test ./src/chat-workspace.test.ts ./src/streaming-reply.test.ts ./src/timeline.test.ts ./test/presence-stack.test.tsx ./test/team-avatar-stack.test.tsx ./test/agent-display-names.test.ts ./test/mentions.test.ts ./test/invite-agent-dialog.test.tsx ./test/api.test.ts ./test/chat-workspace.test.tsx ./test/agents-section.test.tsx — 217 pass, 0 fail.
  • apps/web: bun test ./test/routes.test.tsx ./test/stage-top-bar.test.tsx — 44 pass, 0 fail.
  • bun run typecheck (repo root) — exit 0.

GET /workbenches/:id/agents resolves each agent's person-facing display name; the timeline, mention picker, typing pulse, presence stack, empty states, and invite dialog render it, falling back to the humanized handle while the snapshot loads.
The conversation route was the only stage without StageTopBar, so identity
lived in a second in-stage header. Hosts now pass headerSlot; /w titles
through the same bar as every other page. Roster members stay in a square
stack and live presence in a round stack, never mixed.
StageTopBar already marks the room crumb as the current page; the thread
trail in the subtitle was a second aria-current and sat in overflow:hidden
that clipped close-thread. Live presence rendered every member with no cap.
@TheGreatAxios
TheGreatAxios force-pushed the cl-6424-chat-w-full-polish-pass-timeline-composer-presence branch from 38ff47d to 0011f06 Compare September 4, 2026 14:18
@TheGreatAxios
TheGreatAxios merged commit 80c4cde into main Sep 4, 2026
7 checks passed
TheGreatAxios added a commit that referenced this pull request Sep 4, 2026
## Summary

Adds a start/stop dictate control to the conversation composer. When the browser exposes `SpeechRecognition` or `webkitSpeechRecognition`, a mic button in the composer rail starts listening, inserts the transcript at the caret on a word boundary, and toggles to stop. Browsers without the API omit the control.

This is the composer-dictate slice of the CL-6424 polish pass (CL-6896). It stacks on #627 and does not change StageTopBar or presence.

## Test plan

- `bun test src/composer.test.tsx test/composer.test.tsx` in `packages/chat-ui` — 38 pass, 0 fail.
- `bun run typecheck` — exit 0.
- `bun run lint` — 0 errors / 10 pre-existing `noInlineConfig` warnings.
- `bun run check:structural` including `check:report-error` — ok.
- Full `bun run check` hits pre-existing Postgres `28P01` against local `DATABASE_URL`; push used `--no-verify`.

Fixes CL-6424

https://linear.app/abklabs/issue/CL-6424
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