Commit Graph

5797 Commits

Author SHA1 Message Date
Peter Steinberger c35b183093 fix(ui): highlight source code in chat and session diffs (#130578)
* fix(ui): highlight source code in chat and session diffs

* test(ui): isolate roster bootstrap from slug lookup

* fix(ui): preserve both languages in renamed diffs
2026-08-26 19:28:03 -07:00
Peter Steinberger 9ccbbf83f2 perf(control-ui): load built-in theme palettes on demand (#130473)
* perf(control-ui): load built-in theme palettes on demand

Every built-in theme's tokens shipped in the startup stylesheet, so the default
path downloaded six palettes it never painted and each new theme taxed everyone.
That is what pushed the startup CSS ceiling from 45 to 47 KiB when Tide, Beacon,
and Phosphor landed.

Moves the twelve non-default palettes into public/themes/<family>.css, one file
per family covering both modes. Claw stays inline because its tokens are the
:root defaults, so the default path loses nothing and gains the bytes back.

The first-paint story this needed: index.html's boot script now links the active
family's palette during head parsing, which makes it render-blocking exactly
like the app stylesheet, so a persisted theme paints its own colours on the
first frame instead of flashing the default. The href is built from the mount
prefix the gateway already stamps on <html>, so it follows a configured Control
UI base path without the script having to know one. theme.ts keeps the link
correct when the theme changes at runtime, reusing the helper the webfont
stylesheets already use.

The nested resolve-theme ternary became a family table in the same script, since
it now picks an asset as well as a data-theme value.

  startup CSS  45.8 -> 42.2 KiB gzip, below the 44.3 KiB it measured before the
               three themes landed; ceiling restored 47 -> 45 KiB
  base.css     64.0 -> 35.8 KiB raw

Adds a regression test that blocks every bundle script and asserts the palette
still applies, so moving this back into the app bundle fails instead of silently
reintroducing the flash. Verified it catches that: with the boot-script link
removed the assertion reports `expected null to be '/themes/tide.css'`.

* fix(control-ui): publish themes after their palettes load

* fix(control-ui): clean up palette completion listeners

* refactor(control-ui): consolidate theme name resolution
2026-08-26 18:56:14 -07:00
Peter Steinberger d8ff371780 fix(ui): usage copy actions silently hide clipboard failures (#129562)
* fix(ui): show usage copy success and failure

* test(ui): decouple usage copy proof from CSS classes
2026-08-26 18:14:54 -07:00
Peter Steinberger 6b17243232 fix(ui): prevent raw config reverts from retaining discarded edits (#130521)
Restore the saved form and draft tracking when Raw returns to the original bytes, so switching back to Form and editing another field cannot resubmit discarded values. Reuse the existing draft reset while preserving Raw authority and conflict status.
2026-08-26 17:53:26 -07:00
RoboClaw 4a40d553cb fix(ui): allow selecting side chat text (#130496)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-26 17:39:53 -07:00
Peter Steinberger 07eb320302 fix(ui): show frozen elapsed time for stopped goals (#130501) 2026-08-26 17:24:08 -07:00
Peter Steinberger fc6cf5e690 fix(ui): keep agent file saves intact during refresh (#130468)
* fix(ui): keep agent file saves intact during refresh

* test(ui): hold catalog requests through recovery startup
2026-08-26 17:20:39 -07:00
Peter Steinberger 565fd93544 fix(ui): show session diff path copy feedback (#129999) 2026-08-26 17:17:15 -07:00
Peter Steinberger a4c01c1a77 feat(ui): save appearance preferences per user profile (#130340)
* feat(ui): save appearance preferences per user profile

When a Control UI connection is bound to an authenticated user profile
(trusted-proxy, Tailscale, GitHub identity), theme, theme mode, and accent
become per-profile: stored in the existing user_preferences KV store via
users.prefs.set, overriding gateway-wide ui.prefs, with live cross-device
updates over a new additive users.prefs.changed event scoped to the same
merged profile. Restore default deletes only the profile key and falls back
to the gateway-wide value. talk.config projects the caller's profile accent
for native clients. Profile-less connections (token/password/none auth)
keep the existing gateway-config behavior byte-identically.

Release-note context: on multi-person gateways appearance choices are now
personal and follow you across devices; an admin restyling their own UI no
longer reskins the whole team.

* chore(protocol): allowlist users.prefs.changed for mobile clients

iOS and Android resolve the profile accent through talk.config on connect
and config refresh; live per-profile appearance push on natives is a named
follow-up.

* chore(protocol): regenerate Swift/Kotlin models for users.prefs.changed

* fix(ui): honor explicit defaults and identity switches for profile appearance

Addresses the three ClawSweeper review findings:
- resetValue for profile-bound appearance keys is the deletion fallback
  (gateway value), so an explicit product-default selection persists as a
  profile write instead of being misclassified as a reset.
- An identity switch between two known scopes forces a full appearance
  reconcile and clears appearance keys the returning identity never set,
  so a shared browser cannot keep the previous profile's look (boot keeps
  the last-seen shortcut).
- talk.config joins the profile-dependent dispatch gate so a pending
  GitHub identity sync completes before the profile accent is projected;
  token clients pass through untouched.

* chore(ui): satisfy assertion-safety ratchet and docs formatting

* refactor(ui): extract server-prefs storage primitives

server-prefs.ts crossed the 700-line cap after the review fixes; the
stateless localStorage persistence primitives move to
server-prefs-storage.ts (no behavior change). Shrink-prunes the
assertion-safety baseline for the moved casts.

* fix(ui): keep imported custom themes out of profile storage

Custom palettes are browser-local by contract, so a profile must never
carry theme=custom to a browser that cannot render it. The wire contract
drops custom from the storable theme values (readers self-heal any stored
value), a profile-bound custom selection stays retained browser-local
(including the offline-queued path), and the exhaustive theme test now
encodes the exception.
2026-08-26 16:48:26 -07:00
Josh Lehman 88aff1f21e fix(webchat): CLI skill and harness-injected turns render as operator-sent messages (#130427)
* fix(webchat): render CLI harness-injected turns as collapsed context, not operator bubbles

Claude Code writes harness-generated user-role turns (Skill instruction
bodies, continuation summaries) into its native transcript with
isMeta/isCompactSummary flags. The claude-cli history importer dropped
that provenance, so webchat rendered those turns as right-aligned
operator bubbles the operator never sent.

Record the provenance at the import boundary as structured
InputProvenance (internal_system / cli_harness_context) — the same
contract the embedded runner uses to keep internal system prompts out of
operator bubbles — and teach the system-notice path to render such turns
as a collapsed "Injected context" notice that does not start an operator
turn.

Regression coverage: importer unit test (provenance recorded only for
flagged rows), live chat.history gateway RPC test (provenance survives
merge + display projection), and a chat-thread UI test (injected turn
becomes a collapsed notice while a real operator message keeps its
bubble). Before/after webchat captures via
scripts/capture-injected-turn-notice-proof.mts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Publish openclaw/fix-cli-injected-turns-rendering-as-operator-messages

OpenClaw-Publication: 62f03fec-179b-4c5e-9423-4df80809de41

* chore: drop changelog entry; CHANGELOG.md is release-generated

Release-note context lives in the PR body per repo policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: register injected-turn proof capture as ui:proof script

Knip's full-tree unused-file scan requires capture scripts to be
package.json entry points, matching the sibling ui:proof:* captures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(gateway): cover isVisibleInTranscriptOnly harness rows; absorb provenance helper

Claude Code groups isMeta, isCompactSummary, and isVisibleInTranscriptOnly
as its own "not a real operator turn" predicate (verified in the v2.1.246
bundle); import all three through one canonical predicate. Inline the
one-use provenance literal at the importer, returning input-provenance.ts
to its main state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 16:46:07 -07:00
Peter Steinberger 395e5db41b chore(deps): refresh dependencies after seven-day cooldown (#130296)
* chore(deps): refresh cooled npm and plugin dependencies

* chore(deps): refresh cooled build and workflow tooling

* chore(deps): retain formatter compatibility

* chore(deps): retain lint compatibility
2026-08-26 16:13:18 -07:00
Vyctor H. Brzezowski 34ccf63e13 Control UI: unify composer attachment chip layout (#130312)
* fix(ui): unify composer attachment chips

* fix(ui): resolve composer attachment glyphs
2026-08-26 19:49:20 -03:00
Jason (Json) 7a550091d1 fix(ui): show dashboard replies when final events omit messages (#130417)
* fix(ui): recover dashboard finals after message-less terminal

* fix(ui): harden dashboard final recovery

* test(ui): coalesce terminal history recovery

* fix(ui): refresh finals after stale history loads

* test(ui): narrow final recovery fixture status

* fix(ui): preserve final refresh after pending reload
2026-08-26 16:43:54 -06:00
Peter Steinberger d4c8aaa536 test(control-ui): guard the hand-mirrored theme --bg copies (#130444)
Each theme's --bg is copied by hand into two places outside base.css, because
both have to paint before the app stylesheet is parsed: index.html's pre-paint
block, which fills the page during first paint, and the Appearance preview
chips, which are deliberately theme-invariant and so cannot read the live token.

Nothing tied those copies to the palette. Darkening Absolutely moved --bg and
left both behind; only a pre-paint assertion that happened to hardcode the old
value caught one of them. It is the same shape as the two defects review found
in the theme work — a hand-maintained list extended for new themes but not
exhaustively — and the third time is enough.

Derives the expected values from base.css and asserts both mirrors for every
palette (12 themed pre-paint rules plus the default), so a palette edit cannot
leave either copy stale. Verified by mutating each mirror:

  tide: pre-paint #123456 != --bg #10151b
  beacon: chip #abcdef != --bg #000000

Test-only; no production change.
2026-08-26 15:23:51 -07:00
Vyctor H. Brzezowski 50c7400a9a feat(ui): refine the mobile composer (#130308)
* feat(ui): refine the mobile composer

* fix(ui): preserve mobile composer controls

* fix(ui): keep mobile composer gates stable

* perf(ui): lazy-load chat goal styles
2026-08-26 19:08:46 -03:00
Dallin Romney 3fe6e5821b fix(ui): clarify gateway disconnect status in tab title (#130364)
* fix(ui): clarify disconnected gateway title

* fix(ui): keep disconnect title concise

* test(ui): align shell disconnect title
2026-08-26 15:08:31 -07:00
Vyctor H. Brzezowski f010c00ace fix(ui): distinguish inherited model defaults from session pins (#120805)
* fix(ui): distinguish inherited model defaults from session pins

The Gateway session projection collapsed inherited agent defaults and
persisted conversation pins into the same effective model fields, so the
Control UI picker marked a row Default while its footer simultaneously
called it a session override and offered a meaningless reset.

Project the authoritative persisted provenance instead: the session owner
resolves `modelOverrideSource` (normalizing entries written before source
tracking), `buildGatewaySessionRow` and the session change event carry the
additive `"user" | "auto" | null` protocol field, and the Control UI treats
only `"user"` as a conversation pin.

Closes #120752

* test(ui): scope model provenance to active pane

* fix(ui): derive the model picker's inherited sentinel from recorded provenance

Deriving "inherits the agent default" from the effective model matching the
default meant a session pinned to model X stopped reading as pinned once the
agent default moved to X. The picker then rendered the default row as already
selected, so clicking it matched its own commit value and was swallowed, leaving
the stored pin unreachable from the UI.

Project the session store's existing modelOverrideSource onto the gateway row and
let the UI resolve a closed selection source (inherited/pinned/fallback) from it,
falling back to the old equality guess only for gateways too old to send the
marker. Preserve the null tombstone in reconcile so a cleared pin stays
distinguishable from that silence.

* test(ui): pin the model picker's digit-key ownership

The numbered keycaps and the digit handler are paired by search focus, but the
guard that keeps digits in the search input had no coverage outside the browser
e2e lane. Add a unit regression for both halves and record the contract at the
numbering site, where reviewers keep reading the two gates as unrelated.

* fix(ui): keep session model selection provenance authoritative

Project saved model provenance through Gateway rows and events, retire temporary UI claims at their owner, and use canonical refresh after slash and status model changes. Preserve model intent through rollback and deletion without retaining a public cache setter.

Co-authored-by: Vyctor H. Brzezowski <krzyszchweski@gmail.com>

* refactor(ui): keep recovery with scoped session operations

Preserve recovery notifications, visible errors, and connection checks while keeping the optimistic mutation owner within its module limit.

Co-authored-by: Vyctor H. Brzezowski <krzyszchweski@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 15:02:54 -07:00
Jason (Json) 3fa31a7b2d fix(ui): make dashboard side panels enter split view (#130426)
* fix(ui): hide unavailable discussion panel

* fix(ui): couple dashboard side panel to split mode
2026-08-26 15:58:25 -06:00
Peter Steinberger a482a50cda perf(ui): bootstrap session rosters in one request (#130294)
* perf(ui): collapse session roster bootstrap RPCs

Amp-Thread-ID: https://ampcode.com/threads/T-01a037b3-be95-76ea-8fb3-75979929acf1

* fix(gateway): isolate and bound session roster bootstrap

Scope cached projections to the authenticated viewer, apply startup admission
consistently, and preserve the independent owner and shared preview budgets.
Regenerate the Swift client and document the bootstrap and cursor contract.
Publish Gateway test configuration atomically to remove the deferred-reader race.

Co-authored-by: Amp <amp@ampcode.com>

* test(gateway): extract session roster cache fixtures

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-26 14:34:48 -07:00
Peter Steinberger fa87acd0b8 fix(workers): recheck idle and node readiness after waits (#130390)
* fix(workers): revalidate idle and node readiness after waits

* test(cli): keep gateway fixture PID distinct from updater
2026-08-26 14:32:49 -07:00
Vyctor H. Brzezowski f290d6bc81 fix(ui): resize empty chat side panel (#130366)
* fix(ui): resize empty side panel

* test(ui): preserve empty sidebar geometry expectations
2026-08-26 18:06:47 -03:00
Peter Steinberger 2df6461280 fix(ui): preserve dictation draft ownership through preview and cancel (#130395) 2026-08-26 14:02:24 -07:00
Peter Steinberger 270c73cad7 fix(ui): Usage Shift-click selects the wrong session range (#130375)
* fix(ui): usage range selection follows visible session order

* test(ui): settle card animation before notice layout measurements
2026-08-26 14:02:19 -07:00
Peter Steinberger f0291d7e5d fix(ui): show dashboard refresh failures with a retry action (#130376)
Keep cached dashboards visible when their session-list refresh fails, show the existing stale-data notice, and retry the current agent query. Cover connected refresh failures, first-load recovery, and retired scope callbacks.
2026-08-26 14:01:58 -07:00
Peter Steinberger cba3b5d19b fix(ui): retire transcript search results when session filters change (#130378) 2026-08-26 13:52:16 -07:00
Shakker 887c668446 fix: stabilize chat layout test settling (#130397)
Prevents chat responsive CI from treating two transient matching frames as a settled layout. The browser fixture now waits for a short stable geometry window and includes a real delayed-layout regression.

Refs #130112.
2026-08-26 21:50:55 +01:00
Peter Steinberger 70c87cc98d fix(ui): open selected palette agents and follow visible result order (#130344) 2026-08-26 13:41:31 -07:00
Peter Steinberger 1932fd66cb test(ui): drop the resurrected duplicate attachment-URL e2e proof (#130343)
#127114 replaced the exact-revoke-count attachment preview test with the
invariant-based proof in new-session-page.attachment-url-lifecycle.e2e.test.ts,
deleting the old block from new-session-page.prompt-attachments.e2e.test.ts.
#124301 branched before that deletion, so its merge resurrected the stale copy
and main shipped two tests with the same name.

The resurrected copy asserts literal cumulative revokeObjectURL counts. Those
counts are not an invariant: on remount the durable IndexedDB draft restore
(draft-persistence.ts restoreScope) can re-hydrate the attachment into a fresh
id and object URL, then release the copy the in-memory route handoff carried,
producing one extra matched createObjectURL/revokeObjectURL pair. Reproduced
with stack capture under 6x CDP CPU throttling: revoked reached 3 before the
Remove click and 4 after, which is the "expected 4 to be 3" seen in CI.

No leak and no double-release: releaseChatAttachmentPayload deletes the payload
map entry before revoking, so every URL is created once and revoked once. The
surviving lifecycle test asserts exactly that (active URLs, duplicateRevocations
and unknownRevocations both zero) and pins the hydration step deterministically,
so deleting the duplicate loses no coverage.
2026-08-26 13:39:23 -07:00
Peter Steinberger d9b41332e4 fix(ui): restore person grouping for multiple session owners (#130326)
* fix(ui): restore person grouping for multiple session owners

Use the live session-owner roster for Person grouping and People sorting instead of the connection-time identity policy. Preserve preferences while the roster is unknown and retain single-owner dormancy across sidebar and Sessions page.

* docs(ui): match the owner sorting label

* refactor(ui): reuse session owner and menu selection paths
2026-08-26 13:28:36 -07:00
RoboClaw 64113d0fdc fix(ui): join collapsed mobile question to composer (#130179)
* fix(ui): join mobile question dock to composer

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>

* fix(ui): join collapsed mobile question to composer

OpenClaw-Publication: 6e1bdbe1-5f4f-4d4f-bb0a-96e3332b107a

* fix(ui): keep compound composer focus shell-owned

* fix(ui): cover compact landscape question composer

* fix(ui): keep dictation inside compound frame

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-26 13:23:42 -07:00
openclaw-mantis[bot] 899b4619da chore(ui): refresh control ui locales (#130330)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-26 13:15:47 -07:00
Peter Steinberger 281464f824 fix(usage): prevent model identity collisions (#130307) 2026-08-26 13:13:07 -07:00
Dallin Romney 0abe8dc4e6 fix(ui): pause progress cards without active runs (#130271) 2026-08-26 13:02:36 -07:00
Peter Steinberger a868258156 fix(control-ui): darken the Absolutely surface ramp (#130239)
Absolutely shipped as the lightest dark theme in the set by a wide margin: its
--bg #262624 sat well above Dash #1a1210, Claw #0e1015, and Knot #080808, which
left the clay accent and the Lora prose with less separation than the palette
was designed for.

Steps the whole ramp down one notch (--bg #262624 -> #1c1c1a, with the card,
elevated, hover, chrome, and border tiers following) and keeps the warm graphite
cast. Text and accent tokens are untouched, so this is purely a surface change.

Every measured pairing improved rather than regressed:
  worst text pair   4.68 -> 5.42:1 (in-browser, --muted on --bg-muted)
  accent on --card  4.47 -> 5.05:1 (AA where it previously was not)
  accent on --bg    4.86 -> 5.47:1
  danger on its own subtle tint over --bg-muted  3.76 -> 4.32:1

The first-paint background in index.html and the Appearance preview chip mirror
--bg by hand, so both move with it; the pre-paint assertion in mount-fallback
covers that they stay in lockstep.
2026-08-26 12:28:46 -07:00
openclaw-mantis[bot] 3e8749146f chore(ui): refresh control ui locales (#130265)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-26 12:26:29 -07:00
Vyctor H. Brzezowski 80b8e79778 improve(ui): calm the task progress card with relative time and clear terminal states (#130183)
* fix(ui): refine task progress status presentation

* fix(ui): keep progress activity current

* style(ui): format progress outcome selector
2026-08-26 16:20:03 -03:00
Peter Steinberger a665de9c1d refactor(ui): remove retired chat control styles (#130201)
* refactor(ui): remove retired chat control styles

* fix(ui): keep background config refreshes from blocking saves
2026-08-26 11:53:35 -07:00
Peter Steinberger 08a42a561c feat(control-ui): add the Tide, Beacon, and Phosphor themes (#130232)
* chore(control-ui): vendor JetBrains Mono and Atkinson Hyperlegible Next

Adds the woff2 faces for the Beacon and Phosphor themes plus the stylesheets
that declare them. Both families are SIL Open Font License 1.1 and ship
unmodified with their upstream license text, as the license requires.

Atkinson Hyperlegible Next was drawn by the Braille Institute for low vision:
its letterforms disambiguate the pairs that blur first at low acuity (I/l/1,
O/0, rn/m), which is why it belongs to the accessibility theme specifically.

base.css has always named JetBrains Mono first in --mono, but nothing shipped
it, so code blocks rendered in it only for people who happened to have it
installed locally. Phosphor makes that deterministic.

Latin and latin-ext subsets only, 195 KB. Served from the gateway rather than a
font CDN so font-src 'self' holds, no third-party request happens on load, and
an offline or LAN-only gateway still renders correctly. The url() references are
relative to their stylesheet so they follow a configured Control UI mount.

* feat(control-ui): add the Tide, Beacon, and Phosphor themes

Three built-in themes, each filling a gap the existing four share rather than
adding a fifth variation on them. Every shipped accent today is warm — coral,
crimson, chocolate, clay — and the only cool token anywhere is Claw's teal
secondary.

Tide is the cool one: steel cyan on deep slate, deep teal-blue on cool paper.
It deliberately ships no webfonts, so it costs nothing beyond its tokens.

Beacon is the accessibility one. It targets WCAG AAA (7:1) rather than the AA
4.5:1 floor the other themes hold, for low vision, direct sunlight, projectors,
and poor panels, and sets everything in Atkinson Hyperlegible Next. Reaching AAA
forced one deliberate break from the status-token convention: elsewhere each
--x-subtle is --x at 8%, but a label on a tint of its own hue caps achievable
contrast because the tint pulls the background toward the text. Beacon tints
neutrally and lets the label carry the contrast. Its focus ring is opaque and
3px for the same reason — a translucent ring is the first thing to vanish on a
bad panel. The contrast guardrail now enforces 7:1 for Beacon specifically, so a
later palette edit cannot quietly demote it to an ordinary dark theme.

Phosphor is the terminal one: phosphor green on green-cast black with the whole
surface, chat prose included, in JetBrains Mono. Monospace prose is a character
choice for an operator console, not a readability claim, which is why it is
opt-in.

Every palette was solved against the real guardrail before any CSS was written.
Worst text pairing per theme: Tide 6.12:1 dark / 4.63:1 light, Beacon 10.29:1 /
9.72:1, Phosphor 6.69:1 / 4.76:1. Worst status label on its own tint: Beacon
7.05:1 / 7.02:1, the others above 4.6:1.

Budgets: the startup CSS ceiling moves 45 -> 47 KiB and the JS ratchet baseline
moves 523 B. Every built-in theme's tokens ship in the startup sheet, so each
new theme costs ~0.5 KiB gzip whether or not anyone selects it. Moving per-theme
palettes to lazily linked stylesheets (as theme webfonts already are) would take
this back under the old ceiling, but it needs a first-paint story first: a late
palette flashes default colors where a late font only swaps.

* fix(control-ui): use Beacon's destructive foreground in chat confirmations

The chat confirmation button paints from --danger under --media-foreground, a
theme-invariant white, and each dark palette opts out of that pairing through a
selector list in chat/grouped.css. Beacon defines a deliberately light --danger
(#ffabab, chosen so status labels clear AAA) but was missing from that list, so
its confirm button rendered white on pale pink at 1.80:1 — on the theme whose
entire promise is contrast.

Adds Beacon to the list, which routes it to --destructive over
--destructive-foreground at 11.67:1.

Also adds a guardrail for the bug class, since the selector list has to be
extended by hand for every new dark theme and I have now missed it once. The
test reads membership back out of grouped.css rather than restating it, resolves
each theme's effective (background, color) pair, and holds it to that theme's
floor. It reproduces this defect at 1.80:1 against the pre-fix stylesheet.

Reported by ClawSweeper review on #130232.
2026-08-26 11:47:01 -07:00
RoboClaw bfb052942d fix: session owner filters reset after reload (#130143)
* fix(ui): persist session owner filters

Keep owner and involving-me filters across reloads and transient ownership metadata gaps, scoped to the authenticated user and gateway.

Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>
Worked on by:
- @Solvely-Colin

* refactor(ui): keep owner filter helpers within lint limits

Move persisted owner-filter state into a reactive controller and proof-only browser helpers into the existing visual support module without changing behavior.

Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>
Worked on by:
- @Solvely-Colin

* test(ui): restore ownership proof dependencies

Keep the shared proof artifact directory and filesystem helper available to the existing ownership screenshot and video scenarios after the lint-limit extraction.

Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>

Worked on by:
- @Solvely-Colin

* refactor(ui): harden owner filter persistence

Make the reload assertion consume only the reloaded document request log, retire stored owners only from an authoritative facet, preserve a clear-filter escape hatch while metadata is unresolved, and tolerate unavailable browser storage.

Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>

Worked on by:
- @Solvely-Colin

* fix(ui): scope owner facets to authenticated identity

Hold owner-facet validation until the new identity filter request settles and advances the canonical roster revision, preventing stale options from deleting another user’s saved preference.

Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>

Worked on by:
- @Solvely-Colin

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>
Co-authored-by: Colin Johnson <colin@solvely.net>
2026-08-26 14:28:04 -04:00
Peter Steinberger 04949c1393 fix(cli): return JSON errors for rejected onboarding recommendation options (#130245)
* fix(cli): preserve JSON errors for onboarding recommendations

* test(ui): tolerate subpixel chat layout jitter
2026-08-26 11:26:16 -07:00
RoboClaw f1491a203c fix(ui): keep PR chip above transcript rows (#130224)
* fix(ui): keep PR chip above transcript rows

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>

* fix(ui): keep PR chip above transcript rows

OpenClaw-Publication: d6486664-bbca-4012-ae1d-0b5149319c9e

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-26 10:53:33 -07:00
Peter Steinberger b6662bf157 fix(ui): show sessions while remote projects clone (#130192)
* fix(ui): show sessions while projects prepare

Create remote-project sessions before cloning, expose workspace preparation progress, and retain private restart-safe project intent until the workspace binds.

* fix(ui): materialize remote projects before worktree sessions

* fix(protocol): refresh session create clients
2026-08-26 10:38:29 -07:00
Peter Steinberger 911b1c467c fix(ui): show workspace copy-path outcomes (#129727)
* fix(ui): show workspace copy-path outcomes

* test(ui): provide required workspace file state
2026-08-26 10:34:01 -07:00
Peter Steinberger a9e1b318d3 fix(workers): preserve remote turns through drain and cancellation (#130235) 2026-08-26 10:33:20 -07:00
Vyctor H. Brzezowski 7afda00643 fix(ui): collapse chat side panel after final tab closes (#130102)
* fix(ui): collapse side panel after final tab closes

* fix(ui): preserve side panel owner state

* fix(ui): preserve projected panel closure

* fix(ui): align projected panel close contract
2026-08-26 14:13:42 -03:00
Peter Steinberger b3376cedca fix(ui): restore startup CSS budget (#130033)
Amp-Thread-ID: https://ampcode.com/threads/T-01a021f6-157a-707a-aab4-df4ff9e0ae98

Co-authored-by: Amp <amp@ampcode.com>
2026-08-26 09:28:15 -07:00
Vyctor H. Brzezowski 2155e515cd fix(ui): align side chat composer controls (#130119) 2026-08-26 13:26:07 -03:00
Vyctor H. Brzezowski 60ef0d169f fix(ui): keep progress in main chat when side chat opens (#130109)
* fix(ui): keep progress in main chat when side chat opens

* fix(ui): align progress placement with current chat
2026-08-26 12:55:14 -03:00
Miorbnli 20eef858aa fix(infra): prevent $-pattern injection in home directory tilde expansion (#122991)
* fix(infra): prevent dollar-pattern injection in home dir tilde expansion

String.replace interprets dollar-amp/dollar-1/dollar-backtick in the
replacement string. When the home directory contains these sequences
(e.g. a username with a dollar sign), tilde expansion via
.replace(/^~/, fallbackHome) corrupts the path silently.

Use a function replacement so the home path is treated literally,
matching the pattern already fixed in terminal-core/display-string (#111398).
Two call sites: resolveRawHomeDir and expandHomePrefix.

* fix(daemon): prevent dollar-pattern injection in state dir tilde expansion

Address review rank-up: the daemon state-path expansion deliberately does
not use the core helper and still passed home as a string replacement.
Apply the callback form here too and add a literal-dollar regression to
the existing service-env suite (fails on the string form, passes with
the callback).

* fix(launcher): keep literal $ patterns when expanding tilde OPENCLAW_HOME

* fix(ui): keep literal $ patterns in local media tilde expansion

* test(ui): prove literal-$ tilde local media preview through Control UI e2e

* test(ui): align literal-dollar media proof with compact attachment contract

Preserve the current authenticated metadata and ticket-scoped download behavior while exercising the real Chromium Control UI under a literal-dollar home.

Co-authored-by: liyuanbin <li.yuanbin1@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 08:24:10 -07:00
Josh Avant e6ed7e30cc feat(audit): record session action decisions (#129093)
* feat(audit): record session action decisions

* fix(protocol): preserve session sharing client compatibility
2026-08-26 08:21:37 -07:00