3624 Commits
Author SHA1 Message Date
7ad20c6ba1 fix(ui): show profile display name in chat (#111987)
* fix(ui): show profile display name in chat

* fix(ui): preserve chat sender identity labels

* perf(ui): keep chat startup budget green

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-07-20 20:05:17 -06:00
Peter SteinbergerandGitHub d4766068b8 feat(ui): preview lobster sound when enabled (#111996)
* feat(ui): preview lobster sounds on enable

* perf(ui): keep sound preview within startup budget

* perf(ui): add sound preview bundle margin
2026-07-20 18:46:59 -07:00
Peter SteinbergerandGitHub 926c603006 fix(ui): dismiss new-session model picker on outside click (#111988)
* fix(ui): dismiss new-session picker on outside click

* perf(ui): keep picker dismissal within startup budget

* perf(ui): lazy-load new-session catalog helpers
2026-07-20 18:44:44 -07:00
Peter SteinbergerandGitHub 7c896d7859 test(ui): serialize full-app responsive browser cases (#111997) 2026-07-20 18:26:59 -07:00
Peter SteinbergerandGitHub 49ff6a4497 fix(protocol): classify system agents in rosters (#111920)
* fix(protocol): classify system agents in rosters

* fix(ci): align agent kind client gates

* fix(ci): keep roster filtering in startup bundle

* chore(ui): remove superseded roster module

* style(android): satisfy agent kind test formatting

* style(linux): format merged agent capability assertion

* fix(config): reject reserved system agent ids

* chore(i18n): refresh native source inventory

* style(android): format agent kind surfaces

* fix(gateway): preserve configured agent ownership
2026-07-20 16:57:04 -07:00
Peter SteinbergerandGitHub 2220e9f841 fix(ui): give settings sidebar rows unique icons (#111974) 2026-07-20 16:34:05 -07:00
Peter SteinbergerandGitHub b41263339b fix(ui): use layout-dashboard glyph for session dashboard indicator (#111975) 2026-07-20 16:32:25 -07:00
Peter SteinbergerandGitHub d5a8233e76 feat(gateway,ui): agent-scoped model provider credentials (#111796)
* feat: scope model provider credentials by agent

* fix: reject unknown model auth agent ids

* fix: discard stale model provider preload

* fix(gateway): reject whitespace-only explicit agent ids

* fix: scope model provider probes by agent

* fix: complete model provider agent scoping

* fix(ui): always clear the providers refresh flag on completion

* fix(ui): keep probe epochs monotonic across agent switches

* fix: derive agent scope for provider aborts

* fix: satisfy model provider CI checks
2026-07-20 16:22:09 -07:00
Patrick ErichsenandGitHub b628882d0b fix(ui): select AGENTS.md when files open (#111967) 2026-07-20 15:57:35 -07:00
Patrick ErichsenandGitHub 3a9f89e42e fix(ui): keep agent files readable when unfocused (#111963) 2026-07-20 14:46:15 -07:00
Jason (Json)andGitHub 21bfc75648 fix(ui): show new task prompts immediately without duplicates (#111953)
* fix(ui): stabilize new task prompt rendering

* test(ui): cover prompt handoff integration

* test(ui): initialize prompt handoff fixtures
2026-07-20 14:47:32 -06:00
Peter SteinbergerandGitHub 4aaea7b072 fix(ui): persist synchronized sidebar preferences (#111929) 2026-07-20 11:11:45 -07:00
Peter SteinbergerandGitHub 8195cf8707 feat(dashboard): reveal widget card chrome on hover for fine-pointer devices (#111914)
* feat(dashboard): reveal widget card chrome on hover for fine-pointer devices

* test(dashboard): deterministic focus sink for widget chrome hide assertions

* test(dashboard): finish animations before asserting widget chrome hides
2026-07-20 11:05:13 -07:00
Peter SteinbergerandGitHub bf6961d33e fix(ui): actionable diagnostics for missing widget sandbox origin behind proxies (#111909)
* fix(ui): actionable error and doctor warning for missing widget sandbox origin

* fix(ui): phrase sandbox-origin diagnostics as conditional guidance

* test(ui): satisfy deadcode and mock-factory gates for sandbox diagnostics
2026-07-20 10:35:47 -07:00
Peter SteinbergerandGitHub 271e6b7391 fix(ui): tolerate absent chat-event messages in text extractors (#111918) 2026-07-20 10:33:20 -07:00
Peter SteinbergerandGitHub febeb6ac12 fix(dashboard): review follow-ups — provider lifecycle, scope-gated controls, pin robustness (#111907)
* fix(canvas): validate dashboard pins before materializing

* fix(ui): bound dashboard provider lifecycles

* fix(gateway): harden board widget descendant frames

* test(ui): clean up dashboard provider tests

* fix(ui): harden dashboard availability lifecycle

* fix(ui): invalidate stale board availability

* perf(ui): keep dashboard bundle within budget
2026-07-20 10:27:52 -07:00
Peter SteinbergerandGitHub c715d89de8 fix(ui): show newly created PRs in session sidebar (#111783)
* fix(ui): surface newly created session PRs

* test(ui): split sidebar PR state coverage
2026-07-20 10:04:41 -07:00
Peter SteinbergerandGitHub e0206b4967 fix(dashboard): make the board face scrollable (#111911) 2026-07-20 09:53:27 -07:00
Peter SteinbergerandGitHub 5ca5c5c1e0 fix(ui): render sidebar view-archived icon as outline (#111867)
The .sidebar-view-archived svg rule set stroke: currentColor but never
fill: none, so the archive icon's lid <rect> rendered with SVG's default
black fill — a solid black bar instead of the outlined Lucide archive
box. Align the rule with sibling sidebar icon styles (fill: none,
1.7px stroke, round caps/joins).
2026-07-20 08:47:35 -07:00
Peter SteinbergerandGitHub 336b01a2e3 fix(dashboard): inset board widgets from pane edges (#111876) 2026-07-20 08:24:15 -07:00
Peter SteinbergerandGitHub f6f484fb1c fix(ui): auto-show the discussion sidebar when a session has an open discussion (#111871)
* fix(ui): auto-show the discussion sidebar when a session has an open discussion

* docs(ui): document why probe resolution is the only auto-show hook
2026-07-20 08:22:04 -07:00
Peter SteinbergerandGitHub 154a49a78b feat(dashboard): widget capabilities — net CSP, host tools, hardened shared sandbox (#111687)
* feat(boards): enforce widget capability grants

* feat(ui): expose dashboard widget capabilities

* test(dashboard): align rebased gateway contracts

* refactor(dashboard): finish capability alignment

* chore: internalize unused board sandbox exports

* test(dashboard): bind grants to widget instances

* fix(dashboard): close widget authority lifetime gaps

* refactor(ui): preserve modular widget frame ownership

* test(ui): preserve explicit MCP App lease refresh

* test(ui): use shared dashboard sandbox server

* fix(ui): settle widget requests on reconnect

* fix(ui): retry transient widget document loads

* refactor(dashboard): document WebRTC egress residual

* fix(dashboard): clear landing checks
2026-07-20 06:54:44 -07:00
Peter SteinbergerandGitHub 7fe1d70a50 fix(mcp): prevent custom server config races and parsing errors (#111761)
* fix(mcp): harden custom server management

* fix(ui): keep config patch types private
2026-07-20 02:34:13 -07:00
Peter SteinbergerandGitHub a1f43b218a feat(ui): offer page refresh on protocol-mismatch failure (#111772) 2026-07-20 02:31:40 -07:00
Peter SteinbergerandGitHub fd081d6521 fix(ui): keep Codex commentary visible after runs (#111648)
* fix(ui): keep Codex commentary visible

* fix(codex): preserve commentary transcript ordering

* fix(ui): preserve commentary retention opt-out
2026-07-20 02:10:56 -07:00
Peter SteinbergerandGitHub 5d80b62d21 fix(ui): nudge stale tabs after gateway updates (#111619)
* fix(ui): nudge stale tabs after gateway updates

* fix(ui): resolve external packages in worktrees
2026-07-20 01:51:22 -07:00
Jason (Json)andGitHub 779cf40d46 feat(dashboard): harden transcript MCP App pinning (#111748) 2026-07-20 02:42:00 -06:00
Pavan Kumar GondhiandGitHub 391c3bcb17 fix(ui): neutralize Usage CSV text cells [AI] (#111653)
* fix(ui): neutralize usage csv text cells

* test(ui): align usage csv fixture types

* fix(ui): preserve benign usage csv whitespace
2026-07-20 14:08:33 +05:30
Peter SteinbergerandGitHub 0e62293104 fix(ui): keep sidebar session titles aligned (#111698)
* fix(ui): stabilize sidebar session indicators

* test(ui): update sidebar leading-slot assertion
2026-07-20 01:27:25 -07:00
Peter SteinbergerandGitHub 629de998f9 feat(system-agent): agentic cached caretaker greeting with quick actions (#111615)
* feat(system-agent): agentic cached caretaker greeting with quick actions

* test(gateway): pin caretaker greeting in session-ownership tests

* fix(system-agent): offer agent handoff chip only when a model is available

* fix(ci): typecheck narrowing, lint, and knip gates for greeting module

* fix(system-agent): reject structured greeting output on every retained line

* test(gateway): split caretaker welcome tests under the max-lines gate
2026-07-20 01:21:09 -07:00
Peter SteinbergerandGitHub 83e78d8681 fix(ui): quiet the reconnect-wait queue row and hide its raw transport error (#111703) 2026-07-20 01:11:27 -07:00
Peter SteinbergerandGitHub 248726fafd feat(anthropic): import Claude Desktop custom groups (#111644)
* feat(anthropic): import Claude Desktop custom groups

* fix(anthropic): resolve Claude Desktop groups from LevelDB entries

Group discovery regexed whole decompressed blocks, so matches were not
attributable to a Local Storage value and byte order decided the winner.
On a real 5.4MB store that mislabelled 59 of 159 sessions, surfacing a
mojibake label spliced out of Snappy copy-record bytes.

Parse SSTable entries properly instead: prefix-delta keys bounded by the
restart array, newest internal sequence per user key (honoring deletions),
and record scanning confined to a single value. Values are normalized so
Chromium's UTF-16 form scans like Latin-1, and unflushed WAL writes keep
precedence over SSTables.

Prod LOC grows ~77; it buys structural correctness in place of ordering
luck, and folds the old index-only walk into one shared entry decoder.

Verified against the live store: 159 assignments, 0 mislabelled versus an
independent entry-level ground truth, 0 control-character labels.

* fix(ui): sort custom session groups ahead of project groups

Custom groups were pushed into the section list as encountered, so their
position depended on roster order rather than the documented behavior;
the existing test only passed because its fixture happened to be ordered
that way. Collect custom and project groups separately and concatenate,
and assert the guarantee with a reversed-input case.

* fix(anthropic): widen LevelDB fixture key type for test typecheck

The prefix-delta helper assigned a Buffer into a Buffer-typed accumulator
whose generic argument differed, which tsgo rejects in the test lane.

* chore(anthropic): drop release-owned changelog edit from the PR

CHANGELOG.md is generated at release time, so a normal PR must not carry
an entry. The release-note context lives in the feature commit message and
the PR body instead.
2026-07-20 00:30:37 -07:00
Peter SteinbergerandGitHub 3e14caa2bd fix(ui): give markdown list items more breathing room (#111693) 2026-07-20 00:15:04 -07:00
Peter SteinbergerandGitHub f5940ee92d fix(ui): make stale-chunk Reload survive the gateway restart (#111670)
* fix(ui): make stale-chunk Reload survive the gateway restart

The 'A new version is available' banner appears precisely because the
gateway was just updated — so when the user clicks Reload, that gateway
is usually still restarting. The handler probed once and, on failure,
silently fell back to revalidating the same replaced chunk, so the
button looked dead and a manual hard reload was the only way out.

Poll the document probe until the gateway answers (bounded, so an
unreachable gateway still degrades to the recoverable panel error
rather than a fatal navigation), and show a disabled 'Reloading…' state
while waiting.

* fix(ui): enforce the reload wait deadline locally

The bound was only checked after each probe settled, so it relied on the
probe timing itself out. The default probe does self-abort, but a
caller-supplied one need not, and a probe that never settles would leave
the Reload button disabled forever. Race each probe against the
remaining deadline instead.

* fix(ui): satisfy lint and deadcode gates for the reload retry

CI caught two things local oxlint does not: the wait default returned
the timer id from a Promise executor (eslint no-promise-executor-return),
and retryStaleChunkReload became an unused export once the lazy-route
button moved to the polling variant.

Wrap the executor body, and collapse the two near-identical retry paths
into one: the polling helper with timeoutMs: 0 is exactly the old
single-shot behavior, which the stylesheet-recovery banner keeps.

* fix(ui): keep the reload wait bounded across interval waits

The deadline was checked before the interval wait, so a wait that
carried past it left the next iteration taking the unbounded
single-shot branch — a probe that never settles would then strand the
disabled Reload button past its own bound. Only the first attempt may
probe from outside the window.
2026-07-20 00:11:01 -07:00
Peter SteinbergerandGitHub 873c2a0c32 fix(ui): keep completed work expanded outside dashboard sessions (#111640) 2026-07-20 00:08:53 -07:00
Peter SteinbergerandGitHub 46ceb21b89 fix(control-ui): keep OpenClaw in settings (#111686) 2026-07-20 00:00:23 -07:00
Peter SteinbergerandGitHub e2e394e1ab fix(ui): give roster rows their avatar-text gap and add presence mock fixtures (#111689)
* fix(ui): add avatar-text gap in roster menu and presence mock fixtures

* refactor(ui): keep presence snapshot helper out of the connect auth hunk
2026-07-19 23:38:40 -07:00
Jason (Json)andGitHub 8c1ea03da0 fix(ui): bound dashboard MCP App lifecycle (#111691) 2026-07-20 00:38:04 -06:00
Jason (Json)andGitHub 6304a47762 feat(dashboard): harden MCP widget authority (#111679) 2026-07-20 00:32:02 -06:00
8e40acbbb7 fix(control-ui): tighten About build grid spacing (#111532)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-19 23:18:12 -07:00
Peter SteinbergerandGitHub 401ef9770e fix(ui): restyle chat pane error banner as a compact centered alert (#111681) 2026-07-19 23:12:03 -07:00
Peter SteinbergerandGitHub e67fda8ec8 fix(clickclack): accept omitted nullable managed-channel fields and auto-open the discussion panel (#111685)
* fix(clickclack): accept omitted nullable managed-channel fields and auto-open the discussion panel

* fix(ui): open the discussion when write access arrives after it resolved
2026-07-19 23:10:29 -07:00
Peter SteinbergerandGitHub a22ede72e4 fix(ui): redesign the who's-online roster menu (#111668) 2026-07-19 22:24:53 -07:00
Peter SteinbergerandGitHub 69ee7127c0 fix(ui): prevent chat jump when the working claw appears (#111642)
* fix(ui): smooth working claw transition

* test(ui): satisfy chat transition checks
2026-07-19 22:13:42 -07:00
Peter SteinbergerandGitHub d18a7cff8e refactor(ui): extract the steered-message lifecycle into a typed state machine (#111610)
* refactor(ui): extract the steered-message lifecycle into a typed state machine

The steer flow was an implicit state machine spread across five chat modules,
with chip states encoded in loosely coupled optional fields and duplicated
guard predicates. This extracts it behind structural types:

- steered-chip.ts: leaf chip model — SteeredChip union (in-flight requires
  sendState "steering"; acknowledged requires pendingRunId and forbids
  sendState), constructors, and narrowing guards; impossible states are
  unrepresentable and every call site uses the guards
- steer-lifecycle.ts: owns the steer send flow, single terminal retirement
  pipeline (remember -> materialize acked chips -> clear), and history-proven
  retirement; absorbs queued-user-turn.ts
- terminal handling in chat-gateway/chat-state and the stored-outbox history
  verification in chat-send consolidate onto the shared helpers; chat-send.ts
  shrinks by ~300 lines; net prod LOC is flat
- behavior fixes riding the pipeline: acknowledged chips retire once
  authoritative history contains their user turn (no more brief chip/history
  double display) and lingering chips keyed to a filtered run id now retire on
  the next history load
- isTerminalFailureChatSendAck moves to chat-send-contract.ts so ack
  narrowing stays type-safe at every formatter call site

* fix(ui): satisfy type, lint, and dead-export gates for the steer-lifecycle split

- restore the snapshotChatAttachments helper (oxc no-map-spread fires on the
  inlined form)
- select the stored-outbox drain head with an explicit loop; the find-predicate
  form made TS narrow away the failed state and flagged the guard (TS2367)
- drop the unused chip re-exports from steer-lifecycle and the consumer-less
  isSteeredChip guard; chip types stay module-local, guard consumers import
  the steered-chip leaf directly

* style(ui): oxfmt line joins in chat-send and chat-state
2026-07-19 21:14:56 -07:00
Peter SteinbergerandGitHub bc76bb8933 feat(agents): agent-controlled session status, attention, and TTL in the sessions tool (#111583)
* feat(agents): agent-controlled session status, attention, and TTL in the sessions tool

* feat(protocol): sessions.patch agent status fields and curated attention icon ids

* chore(protocol): regenerate bindings for agent-status patch fields, unexport internal cap

* chore(sessions): unexport internal agent-status TTL default
2026-07-19 21:01:09 -07:00
Peter SteinbergerandGitHub 7d4dccf959 improve(swarm): close out wait, phase, and worker follow-ups (#111605)
* fix(codex): support full swarm wait budgets

* feat(ui): bucket swarm dots by phase

* docs(swarm): document flat worker patterns

* fix(codex): configured per-tool timeout still wins over swarm wait default

* fix(codex): outer swarm-wait watchdog outlives the 600s budget (cap + grace)

* fix(ui): order swarm phase buckets by observation rank

* fix(ui): repair rank-order widget test — proper lit render container, untangle sibling assertions

* fix(ui): implicit swarm phase assignment only on child creation events

* test(ui): split swarm activity integration coverage
2026-07-19 20:11:54 -07:00
Peter SteinbergerandGitHub eb3a600571 fix(ui): preserve native context menu for chat links (#111618) 2026-07-19 19:58:37 -07:00
Peter SteinbergerandGitHub da10827439 feat(ui): accept drag-and-drop attachments in the new-session composer (#111530)
* feat(ui): accept drag-and-drop attachments in new-session composer

The new-thread composer only accepted attachments via paste and the +
menu; dragging a file onto it was silently ignored. Wire the shared
chat attachment drop handling onto the composer shell with the same
balanced drag affordance as the chat pane, and gate both composers'
drop/dragover cancellation on file drags so text/URL drops keep the
textarea's native behavior.

* fix(ui): cancel non-file drops outside editable composer targets

A URL dropped on the transcript, header, or composer chrome would hit
the browser default and navigate the app away, discarding drafts. Keep
native text/URL drops only when the drop target is an editable control;
cancel them everywhere else in both composers.

* fix(ui): treat disabled and readonly inputs as non-editable drop targets

A URL dropped precisely on a disabled composer textarea would still hit
the browser default and could navigate away. Check actual editability
(disabled/readOnly/isContentEditable) instead of selector shape.

* fix(ui): limit native drops to text-entry inputs

Enabled non-text inputs (checkbox, range) counted as editable drop
targets, so a URL dropped on one skipped cancellation and could
navigate the browser away. Restrict the native-drop exception to
text-capable input types, textareas, and contenteditable content.
2026-07-19 19:55:29 -07:00
Peter SteinbergerandGitHub 64c82812a5 feat(dashboard): pinned MCP apps — board rendering, lease re-mint, durable tool grants (#111524)
* feat(boards): mint pinned MCP app views

* feat(ui): render pinned MCP apps on dashboards

* fix(dashboard): reconcile MCP app rebase

* fix(dashboard): align generated CI contracts

* test(gateway): record board.widget.appView release train

* fix(dashboard): revalidate pinned MCP app views
2026-07-19 19:51:26 -07:00