Skip to content

feat(app-control): wire "redo" op into the BACKGROUND action (#10694) - #10960

Merged
lalalune merged 2 commits into
developfrom
fix/10694-background-redo
Jul 1, 2026
Merged

lalalune merged 2 commits into
developfrom
fix/10694-background-redo

Conversation

@lalalune

@lalalune lalalune commented Jul 1, 2026

Copy link
Copy Markdown
Member

What & why

Closes a dead chat contract in #10694. The versioned undo/redo UI shipped in PR #10771useBackgroundApplyChannel already handles op === "redo"redoBackgroundConfig(), and BackgroundApplyOp on the UI side is "set"|"undo"|"redo"|"reset". But the agent-side BACKGROUND action (plugins/plugin-app-control/src/actions/background.ts) had no redo path — its op union, plan, regex, handler, and examples all stopped at undo/reset. So "redo the background" from chat inferred no plan and silently broadcast nothing; the background stayed stuck on the undone state.

Fix (mirror of the existing undo op)

  • "redo" added to BackgroundApplyOp + BackgroundApplyPayload (matching the UI union) and a { op: "redo" } BackgroundPlan variant.
  • REDO_RE = /\b(redo|re-?do|go forward|step forward|re-?apply)\b/i, detected in inferBackgroundPlan before color resolution and guarded with !RESET_RE (exactly like UNDO_RE) — so "red" inside "redo" can never false-match a color.
  • Handler branch emits { op: "redo" } → the already-merged channel calls redoBackgroundConfig(); reply "Re-applied the background you undid."
  • REDO_BACKGROUND simile, a redo example, and updated description/enum.

Tests

background.test.ts +6: "redo the background" / "go forward" infer op:"redo" and broadcast {op:"redo"}; a color word ("red") still resolves to a color set, not redo.

background.test.ts   21 passed  (+6)
packages/plugin-app-control typecheck → exit 0

Fail-without-fix proven (independently re-verified): reverting only background.ts reds the 3 new redo tests (the "red"→color test still passes, confirming no false-match); restoring greens all 21.

Evidence

On-device (Android 14 emulator) — the chat flow blue → green → undo (→blue) → "redo the background" stepping forward to green, over the redone background, with the before-note ("stuck on blue") — .github/issue-evidence/10694-background-redo-android.png. Real render surface: the redo path drives the always-mounted AppBackground via the shipped channel.

Scope

This is the redo-op emitter slice — the clean, self-contained half #10771 left open. The headline programmable GLSL shader mode (real WebGL + uniform schema + preset library + GPU safety) is a separate multi-file epic, explicitly out of scope here.

🤖 Generated with Claude Code

lalalune and others added 2 commits July 1, 2026 13:00
The UI redo half shipped in PR #10771 (useBackgroundApplyChannel already
handles op:"redo" via redoBackgroundConfig), but the agent-side emitter
silently dropped "redo the background" — there was no redo path in
inferBackgroundPlan, so chat could undo but never redo.

Mirror the existing undo op end to end:
- add "redo" to BackgroundApplyOp / the BackgroundPlan union and the op
  parameter enum so it matches the UI contract;
- add REDO_RE and detect it BEFORE color resolution (so "red" inside
  "redo" can't false-match a color), alongside undo/reset;
- map the redo plan to emit { op: "redo" };
- add REDO_BACKGROUND simile + a redo example.

Real tests: "redo the background" / "go forward on the background" infer
op:"redo" and emit { op:"redo" }; "red" still resolves to a color set,
not redo. Fail-without-fix verified (removing the detection reds the 3
new tests, greens the rest).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 66147cba-1310-42fb-b3b7-90ca95d94966

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/10694-background-redo

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@lalalune
lalalune merged commit 6220f72 into develop Jul 1, 2026
23 of 36 checks passed
@lalalune
lalalune deleted the fix/10694-background-redo branch July 1, 2026 20:04
lalalune pushed a commit that referenced this pull request Jul 1, 2026
Resolve 3 conflicts:
- plugins/plugin-app-control/src/actions/background.ts + .test.ts: take
  develop's #10960 BACKGROUND redo action (more thorough: re-apply|go forward
  + RESET_RE exclusion). PR's unique settings-UI redo button in
  BackgroundSettingsControls.tsx (non-conflicting) preserved.
- packages/ui/src/components/shell/__e2e__/run-chat-sheet-e2e.mjs: take
  develop's #10972 real-touch comment; gesture code identical on both sides
  and already drives touchDragHold real-touch path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lalalune pushed a commit that referenced this pull request Jul 2, 2026
…10694)

develop already shipped the versioned undo/redo half of #10694 (#10771 +
#10960). This adds the headline feature it was missing: a real, arbitrary
GLSL fragment-shader background mode.

Renderer (@elizaos/ui/backgrounds):
- shader-schema.ts — typed, clamped uniform contract (u_speed/scale/intensity/
  seed), hexToRgb, and a static fragment-source safety gate (size bound + reject
  unbounded while/do loops). three.js-free so it unit-tests without WebGL.
- shader-presets.ts — 5 self-contained GLSL ES 1.00 presets (aurora, lava,
  plasma, waves, nebula), bounded loops only.
- ProgrammableShaderBackground.tsx — renders the fragment via raw three.js
  (already a dep; no new deps) with the full safety sandbox required for
  untrusted GPU code: compile-validate BEFORE showing, uniform clamping, a
  frame-time watchdog that falls back on a GPU stall, WebGL context-loss
  recovery, and a single static frame under prefers-reduced-motion. Any failure
  → onFallback and the color field paints instead — a bad shader can never
  white-screen or hang the app.
- BackgroundConfig gains a `glsl` mode (source + presetId + uniforms);
  normalizeBackgroundConfig validates/clamps it and collapses a
  missing/hostile/oversized source to the color field on load.
- AppBackground switches to the shader (keyed by source for a fresh attempt on
  replacement) with the color-field fallback; useBackgroundApplyChannel handles
  glsl payloads: preset set, explicit source, and live-shader uniform tweaks.

Agent (plugin-app-control BACKGROUND action):
- NL → shader plan: named presets (+ synonyms: molten→lava, ocean→waves,
  cosmic→nebula), a generic "animated shader" → default preset, and relative
  tweaks (slower/faster/brighter/dimmer/bigger/more-detailed) → uniform patch.
  Precedence: named preset > concrete color > tweak > generic shader, so
  "red brighter" stays red and "molten" beats a bare color. The action names a
  preset id + uniforms only; GLSL source stays in the renderer.

Tests (all green): shader-schema (clamp/NaN/hostile/while-loop/hex), preset
library integrity, ProgrammableShaderBackground fallback + no-crash-on-garbage,
persistence glsl round-trip + hostile-source collapse, AppBackground glsl render
+ fallback, a 400-step set/undo/redo storm fuzz across shader/image/glsl
asserting clamped-finite uniforms + history-cap + flag invariants, and BACKGROUND
action preset/tweak inference + emit. Stories added for story-gate. ui +
plugin-app-control typecheck + biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lalalune pushed a commit that referenced this pull request Jul 2, 2026
…#10694)

The rebase onto develop merged both develop's original standalone redo button
(#10960) and this branch's paired undo+redo layout into
BackgroundSettingsControls — two "Redo background change" buttons sharing the
same background-redo agent-element ref. Kept the paired-disabled layout (undo +
redo shown together, redo disabled without redo history) and removed the
superseded standalone. BackgroundSettingsControls.test.tsx 4/4 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lalalune added a commit that referenced this pull request Jul 2, 2026
…ckground + interaction/QA de-larp (#9952, #10694, #10722, #10434) (#11083)

* feat(app-control/ui): give background redo its real triggers — agent op + settings button (#10694)

The #10771 slice landed redo in the store and the background:apply
receiver, but nothing could emit it: the BACKGROUND action op union
stopped at set|undo|reset and the settings controls only rendered Undo.

- BACKGROUND action: add "redo" to the op union/param enum, REDO plan
  inference (checked before UNDO so "restore the change I undid" reads
  as redo), handler branch broadcasting {op:"redo"}, REDO_BACKGROUND
  simile, examples + docs.
- Settings: Redo2 button paired with Undo, disabled without redo
  history, registered as agent-surface element background-redo.
- Tests: 5 new action tests (21/21 green; plugin suite 1262 green),
  new BackgroundSettingsControls.test.tsx, BackgroundView redo case,
  fuzz/store seeds carry the redo fields.
- background e2e: fixture mirrors useDisplayPreferences redo semantics;
  runner gains set→set→undo→redo round-trip (agent redo + UI redo) with
  refreshed screenshots/video evidence (11/11 assertions green).

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

* fix(ui): de-larp gesture e2e to real CDP touch — and fix the two real bugs it exposed (#10722)

CI gated the synthetic-event gesture runner while the real-touch runner
was excluded — the gated test was the larp. Converting to real input
immediately surfaced two real production bugs the synthetic events
masked:

- TopicGroup: pointerup→onTap toggles, React swaps header↔pill, and the
  browser's synthesized click re-hit-tests onto the replacement element
  and toggles BACK — a tap/click on the header/pill was a visible no-op
  on phones and desktop. Fixed with the suppressClickRef +
  onClickCapture idiom (onClick kept for keyboard activation).
- HomeScreen: the home scroller (overflow-y-auto ⇒ touch-action:auto)
  consumed horizontal touch pans itself, so home→launcher swipe could
  never fire from the widget area on real touch. Added touch-pan-y.

Test/CI changes:
- run-chatux-gesture-e2e: synthetic PointerEvent dispatch → shared
  touchTap/touchSwipe (real CDP touch) + real mouse flicks for the
  fine-pointer profile; assertions now match real behavior (vertical
  touch flick on a pan-y header scrolls, it does not collapse).
- run-home-screen-e2e: the 3 mobile outer-rail swipes converted to real
  touch (+touchSwipeRight); desktop rail paging deliberately stays
  mouse (fine-pointer affordance, documented).
- real-touch-gestures: settleMainThread (rAF round-trip) before every
  gesture — root-causes and fixes a pre-existing develop red where CDP
  touch raced a busy renderer main thread in conversation-swipe;
  deleted the zero-consumer touchPinch export (touchTap now consumed).
- ui-e2e-gate.yml: gate test:home-screen-e2e (the honest runner is now
  in CI), fix the mislabeled chatux step, add output-home artifacts +
  src/testing path filters.

Verified locally: chatux 7/7, home-screen full pass (~70 asserts),
conversation-swipe ALL PASSED (5 failed on develop baseline before the
helper fix), chat-sheet pass, 40/40 unit tests, Biome clean, workflow
YAML parsed. Evidence re-captured in output-home/ and output/.

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

* test(agent/app-core): de-larp #10712 — honest SSE contract + live streaming/thinking assertions with real Cerebras evidence

The "local-inference vs cloud-resolved provider path" parity matrix was
a labeled mock: the providerPath string only round-tripped through the
test's own fixtures, and no code under test reads a provider branch
(route → generateChatResponse → messageService → useModel is
provider-agnostic; selection lives in core's model registry, which the
contract test mocks by design). Collapsed to one honestly-named
conversation-stream-sse-contract.test.ts pinning the full frame
contract: thinking→streaming status ordering, ordered cumulative
tokens, terminal done with fullText+thought, done-is-terminal,
thought-never-in-visible-text.

The real provider path is now covered where it belongs — the live e2e:
- streaming-visible-text.live.e2e.test.ts records every SSE payload and
  adds a live frame-contract test (status ordering, monotonic fullText,
  done schema, conditional-but-contractual thought that must never leak
  into visible frames).
- Fixed a real warm-boot race it exposed: /api/health flips ready
  before the deferred provider plugin registers — gate on
  /api/status.canRespond instead.
- Hardened the lane: persistent models cache, 300s ready timeout,
  hang-proof teardown, ELIZA_STREAM_FRAME_DUMP evidence hook.

Live evidence (hand-read, key-free logs) in
.github/issue-evidence/10712-live-streaming-thinking/: 3 consecutive
green runs against Cerebras gpt-oss-120b, 19 token frames growing
43→909 chars, real usage (2737 prompt / 229-234 completion tokens).
Honest findings recorded: live reply arrives via running_action (REPLY
callback), and thought was absent on this path in both dumped runs —
the thought-carrying branch stays pinned deterministically.

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

* test(app): give the Her-minimal aesthetic gate teeth — ratchet with committed baseline (#9950)

The minimalism metrics were computed but could never block: computeVerdict
mapped every breach to needs-eyeball, and the signal was actually DEAD in
real runs — the audit spec never passed viewportArea, so
exceedsMinimalismBudget always returned false. A cramped view shipped
green.

Ratchet design (same idiom as ui-determinism-baseline):
- aesthetic-minimalism-baseline.json records breaching views' metrics
  (83 entries / 33 slugs from a real full audit:app run on this tree).
- Breaching view NOT in baseline → needs-work (BLOCKING).
- Baselined view → blocks only when a metric regresses past baseline
  ±5% relative tolerance (live-DOM jitter absorber; real regressions
  move density far past 5% — recorded values cluster at 89-304 vs the
  45 ceiling). Within tolerance stays soft.
- Spec afterAll now throws unconditionally on ratchet failures (verified
  live: the empty-baseline run correctly failed on all 83). Corrupt
  baseline fails loudly via parseMinimalismBaseline.
- Refresh: bun run --cwd packages/app audit:app:minimalism:update
  (regenerates from the latest report.json; prunes healed views so a
  re-breach counts as new).

Also: collectHoverViolations no longer swallows hover failures with
.catch(()=>{}) — failed probes are recorded as hoverFailures findings.
First real run surfaced 8 previously-invisible probe failures.

Verified: full audit:app run (348 passed, gate replay against committed
baseline → ratchet-blocking=0, good=136/needs-eyeball=212); 55/55 audit
unit tests incl. 12 new ratchet cases; Biome clean.

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

* feat(ui): lock the floating chat to onboarding until an option is chosen, auto-collapse on completion (#9952 follow-up)

During in-chat first-run the overlay was fully interactive: free text
went to the real server before a runtime existed, and Escape/outside
tap/pull-down could dismiss the onboarding sheet entirely (the e2e
helpers relied on it). Now, while first-run is pending:

- Composer locked: textarea disabled with "Choose an option to
  continue"; attach/mic/send (and push-to-talk) disabled; submitText
  hard-guarded against the prefill/dictation/slash side doors. The
  transcript choice widgets and OAuth/secret blocks stay interactive.
- Send seam hard-blocked: sendActionMessage drops any
  non-__first_run__: value while firstRunComplete is false — nothing
  reaches rawSendActionMessage.
- Collapse locked at one choke point plus drag gates: document/thread/
  composer Escape, grabber tap + keyboard close, outside-tap detector,
  pull-down/drag/settle-free, header clear + launcher buttons, and
  conversation swipe are all no-ops; the sheet stays pinned at full.
- Auto-collapse exactly once on the completion falling edge
  (wasFirstRunOpenRef), revealing home; ordinary sessions never
  collapse. Desktop ?shellMode=chat-overlay verified unaffected — that
  shell never mounts the overlay/conductor.
- Dead code: finishRemote + normalizeRemoteTarget deleted;
  runFirstRunFinish narrowed to FirstRunFinishDraft (cloud|local); dead
  switchAgentProfile port unwired (live remote path is
  adopt-remote-first-run, untouched).

Tests: new ContinuousChatOverlay.firstrun.test.tsx (8 — lock, no-collapse
paths, choice interactivity, one-shot auto-collapse + unlock);
conductor state-machine tests now drive the real handleFirstRunAction
seam (local end-to-end + POST-once + re-tap idempotency, BYO-keys
banner, cloud OAuth→agent-pick→bind→tutorial, cloud error→local retry,
unmount unregistration); e2e asserts the lock + negative Escape mid-
onboarding and auto-collapse + unlock in all five completion flows
(14 passed incl. Pixel-7 touch lane); cloud-live spec picks
tutorial:skip before its real turn since completion now gates the
composer.

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

* refactor(agent,ui): remove the dead custom-VRM / custom-background upload routes (#10434 follow-up)

The 3D companion (VRM avatar + its scene background) was removed in #10434,
but the plumbing that fed it was left behind: the POST/GET
`/api/avatar/vrm` + `/api/avatar/background` routes, the client's
uploadCustomVrm/hasCustomVrm/uploadCustomBackground/hasCustomBackground
methods (upload* had no callers at all), and the startup existence probes.
Nothing renders an uploaded model or scene background anymore, so those
HEAD probes only produced 404 noise on every first-run/startup.

- avatar-routes.ts: drop the four vrm/background handlers (keep the live
  Discord avatar cache route); drop the now-unused readRequestBodyBuffer +
  resolveStateDir imports and the unused req/json ctx destructure.
- client-agent.ts: delete the four dead ElizaClient methods + their type
  declarations.
- startup-phase-hydrate.ts: drop the hasCustomVrm/hasCustomBackground
  probes (and the resolveApiUrl import + two Date.now() render-time
  nondeterminism sources they carried), keeping the live
  `resolvedIdx === 0 -> setSelectedVrmIndex(1)` default-avatar fallback.

Live built-in avatar selection (selectedVrmIndex / avatarIndex /
getVrmPreviewUrl) and the content-pack asset path are untouched. Agent +
UI typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(ui,app-control): arbitrary programmable GLSL shader background (#10694)

develop already shipped the versioned undo/redo half of #10694 (#10771 +
#10960). This adds the headline feature it was missing: a real, arbitrary
GLSL fragment-shader background mode.

Renderer (@elizaos/ui/backgrounds):
- shader-schema.ts — typed, clamped uniform contract (u_speed/scale/intensity/
  seed), hexToRgb, and a static fragment-source safety gate (size bound + reject
  unbounded while/do loops). three.js-free so it unit-tests without WebGL.
- shader-presets.ts — 5 self-contained GLSL ES 1.00 presets (aurora, lava,
  plasma, waves, nebula), bounded loops only.
- ProgrammableShaderBackground.tsx — renders the fragment via raw three.js
  (already a dep; no new deps) with the full safety sandbox required for
  untrusted GPU code: compile-validate BEFORE showing, uniform clamping, a
  frame-time watchdog that falls back on a GPU stall, WebGL context-loss
  recovery, and a single static frame under prefers-reduced-motion. Any failure
  → onFallback and the color field paints instead — a bad shader can never
  white-screen or hang the app.
- BackgroundConfig gains a `glsl` mode (source + presetId + uniforms);
  normalizeBackgroundConfig validates/clamps it and collapses a
  missing/hostile/oversized source to the color field on load.
- AppBackground switches to the shader (keyed by source for a fresh attempt on
  replacement) with the color-field fallback; useBackgroundApplyChannel handles
  glsl payloads: preset set, explicit source, and live-shader uniform tweaks.

Agent (plugin-app-control BACKGROUND action):
- NL → shader plan: named presets (+ synonyms: molten→lava, ocean→waves,
  cosmic→nebula), a generic "animated shader" → default preset, and relative
  tweaks (slower/faster/brighter/dimmer/bigger/more-detailed) → uniform patch.
  Precedence: named preset > concrete color > tweak > generic shader, so
  "red brighter" stays red and "molten" beats a bare color. The action names a
  preset id + uniforms only; GLSL source stays in the renderer.

Tests (all green): shader-schema (clamp/NaN/hostile/while-loop/hex), preset
library integrity, ProgrammableShaderBackground fallback + no-crash-on-garbage,
persistence glsl round-trip + hostile-source collapse, AppBackground glsl render
+ fallback, a 400-step set/undo/redo storm fuzz across shader/image/glsl
asserting clamped-finite uniforms + history-cap + flag invariants, and BACKGROUND
action preset/tweak inference + emit. Stories added for story-gate. ui +
plugin-app-control typecheck + biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ui): gate the last onboarding-lock collapse seam + document the contract (#9952)

Cluster-A audit follow-up. Two gaps on the onboarding lock:

- The TUTORIAL_CHAT_CONTROL_EVENT handler (rest/reset → collapse, prefill →
  un-pill) was the one collapse seam outside the gated funnel. It is unreachable
  in the real flow (the tour starts only after completeFirstRun), but a stray or
  adversarial window event during onboarding could have collapsed the pinned
  sheet. Now the handler no-ops while firstRunOpen. New firstrun test drives
  rest/reset/pill/prefill during onboarding and asserts the sheet stays pinned
  FULL and the composer stays locked.
- The lock contract had zero documentation. Documented the full contract (pinned
  FULL, composer + side-door lock, every gated collapse path, one-shot
  auto-collapse) in first-run/IN_CHAT_ONBOARDING_DESIGN.md + a README pointer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ui,app): strict-typecheck cleanups + de-larp the aesthetic density probe (#9950, #10712)

- #9950: the all-views aesthetic audit caught a crashed density probe with a
  zero-density placeholder ({borderDividerCount:0, whitespaceRatio:1}), which
  SILENTLY satisfied both the minimalism budget and the ratchet — a probe crash
  read as "perfectly minimal → pass". Now the failure is recorded as a
  densityProbeFailures finding (surfaced in the summary log + per-view markdown,
  same posture as hoverFailures) and the budget/ratchet are skipped when the
  probe failed, so a crash can never manufacture a pass.
- #10712: force-add the four gitignored live-run streaming logs the evidence
  README cites (git add -f) so a fresh clone keeps the real-Cerebras run proof.
- Strict-config typecheck fixes for the #10694/#10434 work: widen
  makeGlslConfig's uniforms param to the unknown-valued partial it already
  normalizes, and drop the two now-removed avatar setters (setCustomVrmUrl/
  setCustomBackgroundUrl) from the useStartupCoordinator deps literal in
  AppContext (they left HydratingDeps with the dead-route removal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(spatial): de-larp the WEBXR "validated end-to-end" overclaim (#10722)

Cluster-E audit: WEBXR_PLATFORMS.md claimed the production enterImmersiveScene()
was "validated end-to-end against the IWER emulator … read back two textured
quads from the session framebuffer", but no committed test opens an immersive
session or reads pixels — the only test exercises the mocked navigator.xr
availability contract — and enterImmersiveScene/enterImmersiveFromSpecs have no
production caller. Removed the unbacked claim and added an explicit "NOT yet
validated" section stating the immersive render path + hand-pose interaction are
uncovered and the entry points are unused, so the doc no longer advertises a
validation that doesn't exist.

(The sibling tui-pty "vacuous skip" audit finding was a false negative: the
real-PTY suite IS wired into CI via test.yml's "Real-PTY TUI smoke" step —
`test:tui-pty` sets RUN_TUI_PTY=1 internally — and passes locally; left as-is.)

Also bundles the four force-added #10712 live-run streaming logs the evidence
README cites (were gitignored).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ui): drop the duplicate background redo button left by the rebase (#10694)

The rebase onto develop merged both develop's original standalone redo button
(#10960) and this branch's paired undo+redo layout into
BackgroundSettingsControls — two "Redo background change" buttons sharing the
same background-redo agent-element ref. Kept the paired-disabled layout (undo +
redo shown together, redo disabled without redo history) and removed the
superseded standalone. BackgroundSettingsControls.test.tsx 4/4 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Shaw <shawgotbags@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant