fix(ux): consolidate Convert into a single coral chip + restore agent on reload + #16 follow-up - #22
Merged
Merged
Conversation
The Toolbar carried its own Convert/Stop button (and the ⌘/Ctrl+Enter shortcut) while a floating ConvertChip rendered the same action over the editor / preview divider. Two buttons, identical action — confusing. Drop the toolbar pair, leave the chip as the single source of Convert truth, and migrate the keyboard shortcut onto it. Recolor the chip from the previous near-black `var(--ink)` to `var(--coral)` (idle) / `var(--coral-hover)` (running) so the primary CTA is visually distinct from the muted toolbar surface and from text content. Disabled state still renders coral at 0.4 opacity. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…load The store persists `selectedAgent` across hard reloads but not the `agents[]` list. Today that list is only populated when Settings or Welcome modals open and call `/api/agents`. So a user who reloads without opening either modal sees the toolbar agent chip render the red "Select agent" fallback even though their selection is intact — because `agents.find(a => a.id === selectedAgent)` returns undefined against an empty list. Fire the same `/api/agents` fetch from the home page on mount (after hydration, so it doesn't fight SSR). Failures fall through silently — Settings / Welcome retain their own retry-on-open paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-up) PR #17 fixed the win32 spawn EINVAL in `invokeAgent` but missed the matching `spawn` inside `resolveOpenclawAgentId`. The same root cause applies — npm-installed openclaw on Windows is a `.cmd` shim that Node cannot launch directly without `shell: true`. Same Unix behavior, no shell-injection surface (argv is a fixed `["agents", "list"]`, not user input). Closes #16 (the second of two locations identified in the original report). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lefarcen
approved these changes
May 15, 2026
This was referenced May 15, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three small UX/agent-layer fixes that landed at the same time. All
discovered while validating
mainafter #17 merged.var(--ink)tovar(--coral)so it reads as a primary CTAfix(ux): consolidate Convert into a single coral chip/api/agentson mount in the home page (after hydration) so the chip can resolveselectedAgentto a label without waiting for the user to open Settings/Welcomefix(home): detect agents on mount so the agent chip restores after reloadinvokeAgent's win32 spawn but missed the matching one insideresolveOpenclawAgentId— same root cause, same fixshell: process.platform === "win32"on the secondspawn. Closes the rest of #16.fix(agents): use shell on win32 in resolveOpenclawAgentId (#16 follow-up)Detail
Convert chip consolidation
Before:
⚡ Convert to HTML+ Stop button +⌘/Ctrl+Enterglobal shortcut (in
Toolbar'suseEffect).ConvertChipdoing the same thing,near-black
var(--ink).Two CTAs for one action read as either "is this two different things?"
or "did I miss something?". The toolbar pair gets removed; the chip
inherits the keyboard shortcut so muscle memory survives.
Color:
var(--coral)(#c96442) idle,var(--coral-hover)(#b25737)running, with a coral-tinted shadow to match. Disabled state still
renders coral at 0.4 opacity. Stop variant in running state stays the
same shape — pulse-dot + label — only the coral-hover background
distinguishes it.
Agent restoration on reload
The store partializer persists
selectedAgentbut neveragents[](correct —
agentsis a transient capability list, not user state).The only paths that called
/api/agentswere the modal mount effectsin
welcome-modal.tsxandsettings-modal.tsx. So a user who hard-reloaded without opening either modal saw
agents = [], and thetoolbar's
agents.find(a => a.id === selectedAgent)returned undefined→ red "Select agent" fallback rendered, even though selection was
fine in localStorage.
Fix: fire the same fetch from the home page on mount, behind a
hydratedgate so SSR isn't impacted. On failure (offline, agentbackend hiccup) the fallback paths in the modals still cover retry.
Win32 spawn (
resolveOpenclawAgentId)@lux237859-boop's report on #16 identified two
spawncall sites thatneeded
shell: trueon win32. PR #17 fixedinvokeAgent's; theresolveOpenclawAgentIdone was missed. The argv is a fixed["agents", "list"](no user input), so flippingshell: trueonwin32 here doesn't widen the shell-injection surface — same safety
analysis as #17.
Verified
pnpm exec tsc --noEmitclean.resolveOpenclawAgentId) is by inspection — does not regress unix.Test plan for reviewers
selectedAgentset in localStorage. Agent chip renders the agent label without opening any modal.openclawselected as the agent, Convert no longer trips aspawn EINVALfrom insideresolveOpenclawAgentId(closes the second half of 在 Windows 上使用 html-anything 生成 HTML 时,agent 调用立即失败,报错 spawn EINVAL,耗时 0.0s,输出 0.0 KB。 #16).pnpm buildclean.Out of scope
convertChip.label/toolbar.stopkeys.🤖 Generated with Claude Code