oxlint's consistent-type-imports rule bans `import()` type annotations;
the two `importOriginal<typeof import(...)>()` mock helpers needed the
oxlint-disable comment already used elsewhere in the codebase for this
pattern.
The shell-quoting test pinned `isMac`/`isWin` but not `process.platform`,
which CodeCliService's terminal-launch switch branches on directly. On
Linux CI runners this fell through to the Linux/xterm branch instead of
the macOS branch the test asserts on, producing unescaped output.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
Resolve AtomsH4's review on #16491:
- A4 (blocker): shell-quote provider-derived fragments in the terminal-launch
command. New shellQuote.ts (posixQuote / escapeForDoubleQuotes /
isShellSafeModelId); OpenCode `model` is validated + rejected on unsafe ids;
`directory` is single-quoted in the macOS fullCommand and Linux xterm arg;
terminals.ts escapes `'` for the `osascript -e` layer and single-quotes the
raw directory + $/backtick-escapes fullCommand in the kitty/alacritty/wezterm/
ghostty adapters.
- A3: only update currentProvider/connection after clearCliConfig (and the
own-login write) succeed, so a failed scrub can't leave a half-updated
active-provider state.
- A1: parse .env via the real dotenv loader (handles `export ` prefix, inline
comments, and multi-line quoted values), and quote newline values on render
so scrubbing a managed key can't corrupt an adjacent user value.
- B7: redirect a persisted /app/openclaw pinned tab to /app/code on restore.
Regression tests cover model/directory with spaces/quotes/$()/backticks, the
clear-failure state ordering, dotenv export/comment/multiline round-trips, and
the OpenClaw pinned-tab recovery.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
Collapse the nine scattered `switch (cliTool)` sites across the cliConfig
layer (draft/draftUpdater/clear/parser/sanitize/providerMatching) into a
single `CLI_CONFIG_ADAPTERS` registry — one `CliConfigAdapter` per file-based
CLI. Each dispatch function is now a thin `getAdapter(cliTool).method()`
lookup, so adding a CLI touches one adapter instead of every switch.
- New `adapters.ts`: `CliConfigAdapter` interface + 6 adapters + `getAdapter`
+ the `sanitizeCliConfigBlob` dispatcher (moved from sanitize.ts, which now
holds only the pure per-CLI sanitizers).
- Registry typed as a total `Record<FileConfiguredCli, CliConfigAdapter>`
(keyed off `CLI_CONFIG_TARGETS`), so a missing/extra adapter is a compile
error; a runtime completeness test also guards targets + own-login shape.
- Shared arg/context types moved to the neutral `types.ts` to break the
adapters<->draft import cycle.
- Behavior-preserving: the existing per-CLI parity tests stay green; adds
registry-completeness, 6-CLI updateDraftConfig/extractConfig, and own-login
disk-read glue coverage (182 cliConfig tests).
Resolves the reviewer suggestion to centralize per-CLI config dispatch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
Resolve conflicts from #16782 (TopView god-component → imperative popup/toast
tracks), which removed the window.toast/window.modal/window.popup globals:
- pages/openclaw/{OpenClawPage,UpdateButton}.tsx (modify/delete): keep the
branch's deletion. v2 rebuilt OpenClaw into the Code CLI page (c65367a173);
main only did a mechanical window.toast→toast rename on the removed files.
- pages/code/{CodeCliPage.tsx, __tests__/CodeCliPage.test.tsx} (content): keep
the branch's rebuilt page/test — main's only edit was the same toast rename,
which N/A's on the rewritten page (it never used window.toast).
- Migrate the branch's remaining code-page window.toast usage (6 hooks/
components) to the new @renderer/services/toast service, and switch the 4
affected tests to the globally-mocked toast from tests/renderer.setup.ts.
The final v1 release is expected around 1.9.12 (with at most 1-2 more
patches to follow), so raise the migration gate's minimum required v1
version from 1.9.0 to 1.9.12. Update the versionPolicy tests and the
migration README to match the new floor.
Demand-first review (PR #16491) traced every consumer of the new code_cli.*
and openclaw.* routes and found 4 contract fields/params with zero
consumption. Remove them, plus the dead code they were the last consumers of.
- code_cli.run input: drop options.autoUpdateToLatest (no producer ever sets
it). This orphaned the auto-update-on-launch branch and the whole
version-check/update subsystem it was the sole caller of — getVersionInfo,
fetchLatestVersion, getNpmRegistryUrl, updatePackage, getPackageName, the
versionCache field, the VersionInfo type, and the regionService import — all
removed. Version/install is owned by BinaryManager (binary.*) now.
- openclaw.get_status output: reduce to { status }; the handler projects it
(the renderer already owns the gateway port via preference).
- code_cli.run output: drop command (no consumer reads it).
- code_cli.get_available_terminals output: drop bundleId; the handler projects
to { id, name } (bundleId stays internal, used for macOS mdfind resolution).
IpcRouter does not re-parse handler output, so the two reduced routes strip
the dropped fields at the handler to keep them off the wire; tests pin both
runtime strips. Also drop the now-moot getPackageName regression test and fix
three doc comments the deletions falsified.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
BinaryManager: prefer a requested semver when `mise ls` returns multiple installed versions so installs/upgrades can pin a specific version and persist it.
Renderer/hooks: allow passing a version to runInstallTool; upgrade now pins the detected latest version. useCliVersionStatuses now uses semver to compute upgradeability, fetches latest versions via `binary.get_latest_versions` only when a supported CLI is installed, and preserves per-tool latest hints on state changes. useCodeCliPageViewProps forwards the latest-version to the upgrade action.
UI/tests: VersionStatusCard shows an up-to-date Badge, moves the upgrade action into the action group and exposes an installing state. Added/updated unit tests for BinaryManager, hooks, and components to cover these behaviors.
- The active toggle now uses the destructive variant for its Disable state
(kept the Power icon), leaving Enable as the solid default + Play.
- Drop the explicit text-muted-foreground/hover override on Configure so it
inherits the outline variant's foreground color.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
- Reveal the Enable/Configure actions on hover or keyboard focus only
(group-has-[:focus-visible] instead of group-focus-within) and drop the
full-card click target from the tab order (tabIndex -1), so a mouse click on
the card body no longer keeps them pinned open via lingering focus.
- Give the active toggle a distinct look: outline variant + Power icon for
Disable, keeping the solid Play button for Enable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
- Clicking anywhere on a provider / own-login card now toggles it, via a
full-bleed ghost Button behind the content (content is pointer-events-none
so clicks pass through; the hover action buttons stay interactive). Uses the
design-system Button instead of a raw <button>.
- Relabel the active toggle from "Enabled" to "Disable" to match what a click
actually does.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
- Provider and own-login cards now reveal Enable + Configure only on hover
(keeps the list clean); Enable gets a filled variant and a Play icon.
- The "add provider" hint opens Settings in a tab (openSettingsTab) instead
of navigating in place, so the code page is preserved.
- Filter out login-based providers (Claude Code / Codex OAuth, etc.) from the
supported-provider list — they carry no API key/baseUrl to inject and their
own login is already surfaced by the own-login card.
- Rename the own-login card title to "{{toolName}} Official".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
Enabling a provider injects config into the CLI's own files, which is
meaningless until the tool is installed — the write silently no-ops on the
missing config directory while the UI still flips to "enabled". Gate the
enable path on the tool's installed status and toast a nudge to install
first instead. Disabling (scrubbing config) stays allowed regardless.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
Racing handle.finished against a self-managed setTimeout deadline is flaky
under CI event-loop starvation: when the worker thread resumes, the job's
promotion timer and the deadline expire in the same libuv batch and the
deadline's synchronous resolve('timeout') beats the job's multi-hop async
completion chain, so the race settles 'timeout' even though the job finished
moments later. Await handle.finished directly and assert the terminal
snapshot status; vitest's per-test timeout bounds a genuine hang with a
clearer error. Applied to all five occurrences that shared the pattern.
`htmlPath: ''` already makes WindowManager skip content loading so a domain
service can load the window itself, but the behavior was implicit — undocumented
at the type level and untested as a contract.
- types.ts: document that `htmlPath: ''` is a consumer-loaded window and how the
consumer loads content afterward (getWindow(id) -> webContents.loadURL/loadFile,
plus show/close ownership); fix the preload cross-reference that wrongly claimed
htmlPath is three-state.
- WindowManager.test.ts: lock the contract — empty htmlPath skips loadFile/loadURL,
non-empty htmlPath loads on create.
- usage guide: add a "Consumer-loaded windows" section (recipe + getWindow caveat).
Add a virtual "own login" entry to the provider list for login-capable CLI
tools (Claude Code, Codex, Gemini CLI, Qwen, Kimi) so users can launch with
the tool's own OAuth login instead of a Cherry provider. Selecting it marks a
reserved id so the launch gate passes and runs the CLI without injecting a
provider/model.
- The entry is draggable in the list like a normal provider and, for
configurable tools, opens a config panel for tool params (permission mode /
effort / toggles) with no model selection, plus the advanced raw-config editor.
- The apply flow scrubs Cherry-managed credentials/model first (clearCliConfig,
which also clears credential-only side files like Codex auth.json / Gemini
.env) then layers the saved tool params back on, preserving the tool's own
login. Per-tool own-login builders strip managed keys and re-apply only the
writable params.
- Also reorder the CLI tool list (OpenClaw last) and give Gemini CLI a specific
add-provider hint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: eeee0717 <chentao020717Work@outlook.com>