Context
Sub-issue of #1. Depends on W1.1a (#26) for the boolean-presence pattern.
apiConfiguration is passed wholesale through getStateToPostToWebview(). It contains raw API keys for every configured provider (openAiNativeApiKey, openAiApiKey, requestyApiKey, sambaNovaApiKey, litellmApiKey, openRouterApiKey, and more). These keys are currently rendered as editable <input> values in ~15+ provider settings components.
The fix requires a settings-input UX pattern change across all provider components: show ••••••••<last4> when a key is already saved; let the user type a new key to replace it. The raw key is never sent to the renderer — only its masked form and a presence boolean.
This is the harder half of W1.1; it's scoped to its own PR so reviewers can evaluate the UI pattern change separately from the simple boolean swap in W1.1a.
Developer Notes
- Define a
MaskedApiKey shape: { configured: boolean; hint?: string } where hint is the last 4 characters (or omitted if not set). Add to packages/types/src/.
- In
getStateToPostToWebview(): strip all raw key fields from apiConfiguration before broadcasting; replace each with its MaskedApiKey equivalent (or extend ApiConfiguration to a ApiConfigurationState type where key fields are MaskedApiKey instead of string).
- Update
ExtensionState and ApiConfiguration types accordingly.
- Update
webview-ui/src/context/ExtensionStateContext.tsx: new state shape.
- For each provider settings component (
ApiOptions.tsx, OpenAI.tsx, SambaNova.tsx, and all others under webview-ui/src/components/settings/providers/): replace value={apiConfiguration?.xyzApiKey || ""} with a masked-key input pattern:
- If
configured && user hasn't started typing: show placeholder ••••••••<hint> and an "Update" affordance.
- If user starts typing (or clicks "Update"): show a normal text input; on save, post the new value.
- If not configured: show normal empty input as today.
- The settings-save message path is unchanged — when a new key is typed, it's posted back to the extension as today.
checkExistKey in ExtensionStateContext.tsx should use apiConfiguration.anthropicApiKey.configured (or equivalent) instead of checking the raw string.
- Files:
packages/types/src/, src/core/webview/ClineProvider.ts, webview-ui/src/context/ExtensionStateContext.tsx, all provider settings components under webview-ui/src/components/settings/.
- Validation: webview settings function identically end-to-end; unit test asserts broadcast payload contains no raw key strings; masked input shows correct hint; typing a new key and saving persists correctly.
Context
Sub-issue of #1. Depends on W1.1a (#26) for the boolean-presence pattern.
apiConfigurationis passed wholesale throughgetStateToPostToWebview(). It contains raw API keys for every configured provider (openAiNativeApiKey,openAiApiKey,requestyApiKey,sambaNovaApiKey,litellmApiKey,openRouterApiKey, and more). These keys are currently rendered as editable<input>values in ~15+ provider settings components.The fix requires a settings-input UX pattern change across all provider components: show
••••••••<last4>when a key is already saved; let the user type a new key to replace it. The raw key is never sent to the renderer — only its masked form and a presence boolean.This is the harder half of W1.1; it's scoped to its own PR so reviewers can evaluate the UI pattern change separately from the simple boolean swap in W1.1a.
Developer Notes
MaskedApiKeyshape:{ configured: boolean; hint?: string }wherehintis the last 4 characters (or omitted if not set). Add topackages/types/src/.getStateToPostToWebview(): strip all raw key fields fromapiConfigurationbefore broadcasting; replace each with itsMaskedApiKeyequivalent (or extendApiConfigurationto aApiConfigurationStatetype where key fields areMaskedApiKeyinstead ofstring).ExtensionStateandApiConfigurationtypes accordingly.webview-ui/src/context/ExtensionStateContext.tsx: new state shape.ApiOptions.tsx,OpenAI.tsx,SambaNova.tsx, and all others underwebview-ui/src/components/settings/providers/): replacevalue={apiConfiguration?.xyzApiKey || ""}with a masked-key input pattern:configured && user hasn't started typing: show placeholder••••••••<hint>and an "Update" affordance.checkExistKeyinExtensionStateContext.tsxshould useapiConfiguration.anthropicApiKey.configured(or equivalent) instead of checking the raw string.packages/types/src/,src/core/webview/ClineProvider.ts,webview-ui/src/context/ExtensionStateContext.tsx, all provider settings components underwebview-ui/src/components/settings/.