mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-30 10:25:05 +08:00
feat(settings): add option to skip Claude Code first-run confirmation
Add a new setting to automatically skip Claude Code's onboarding screen
by writing hasCompletedOnboarding=true to ~/.claude.json. The setting
defaults to enabled for better user experience.
Cherry-picked from main (ddbff07) with conflict resolution.
This commit is contained in:
@@ -63,7 +63,7 @@ describe("ImportExportSection Component", () => {
|
||||
fireEvent.click(importButton);
|
||||
expect(baseProps.onImport).toHaveBeenCalledTimes(1);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Clear selection" }));
|
||||
fireEvent.click(screen.getByRole("button", { name: "common.clear" }));
|
||||
expect(baseProps.onClear).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ const mutateAsyncMock = vi.fn();
|
||||
const useSettingsQueryMock = vi.fn();
|
||||
const setAppConfigDirOverrideMock = vi.fn();
|
||||
const applyClaudePluginConfigMock = vi.fn();
|
||||
const applyClaudeOnboardingSkipMock = vi.fn();
|
||||
const clearClaudeOnboardingSkipMock = vi.fn();
|
||||
const syncCurrentProvidersLiveMock = vi.fn();
|
||||
const updateTrayMenuMock = vi.fn();
|
||||
const toastErrorMock = vi.fn();
|
||||
@@ -50,6 +52,10 @@ vi.mock("@/lib/api", () => ({
|
||||
setAppConfigDirOverrideMock(...args),
|
||||
applyClaudePluginConfig: (...args: unknown[]) =>
|
||||
applyClaudePluginConfigMock(...args),
|
||||
applyClaudeOnboardingSkip: (...args: unknown[]) =>
|
||||
applyClaudeOnboardingSkipMock(...args),
|
||||
clearClaudeOnboardingSkip: (...args: unknown[]) =>
|
||||
clearClaudeOnboardingSkipMock(...args),
|
||||
syncCurrentProvidersLive: (...args: unknown[]) =>
|
||||
syncCurrentProvidersLiveMock(...args),
|
||||
},
|
||||
@@ -63,6 +69,7 @@ const createSettingsFormMock = (overrides: Record<string, unknown> = {}) => ({
|
||||
showInTray: true,
|
||||
minimizeToTrayOnClose: true,
|
||||
enableClaudePluginIntegration: false,
|
||||
skipClaudeOnboarding: true,
|
||||
claudeConfigDir: "/claude",
|
||||
codexConfigDir: "/codex",
|
||||
language: "zh",
|
||||
@@ -111,6 +118,8 @@ describe("useSettings hook", () => {
|
||||
useSettingsQueryMock.mockReset();
|
||||
setAppConfigDirOverrideMock.mockReset();
|
||||
applyClaudePluginConfigMock.mockReset();
|
||||
applyClaudeOnboardingSkipMock.mockReset();
|
||||
clearClaudeOnboardingSkipMock.mockReset();
|
||||
syncCurrentProvidersLiveMock.mockReset();
|
||||
toastErrorMock.mockReset();
|
||||
toastSuccessMock.mockReset();
|
||||
@@ -120,6 +129,7 @@ describe("useSettings hook", () => {
|
||||
showInTray: true,
|
||||
minimizeToTrayOnClose: true,
|
||||
enableClaudePluginIntegration: false,
|
||||
skipClaudeOnboarding: true,
|
||||
claudeConfigDir: "/server/claude",
|
||||
codexConfigDir: "/server/codex",
|
||||
language: "zh",
|
||||
@@ -142,6 +152,64 @@ describe("useSettings hook", () => {
|
||||
mutateAsyncMock.mockResolvedValue(true);
|
||||
setAppConfigDirOverrideMock.mockResolvedValue(true);
|
||||
applyClaudePluginConfigMock.mockResolvedValue(true);
|
||||
applyClaudeOnboardingSkipMock.mockResolvedValue(true);
|
||||
clearClaudeOnboardingSkipMock.mockResolvedValue(true);
|
||||
});
|
||||
|
||||
it("auto-saves and applies Claude onboarding skip when toggled on", async () => {
|
||||
serverSettings = {
|
||||
...serverSettings,
|
||||
skipClaudeOnboarding: false,
|
||||
};
|
||||
useSettingsQueryMock.mockReturnValue({
|
||||
data: serverSettings,
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
settingsFormMock = createSettingsFormMock({
|
||||
settings: {
|
||||
...serverSettings,
|
||||
language: "zh",
|
||||
skipClaudeOnboarding: false,
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSettings());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.autoSaveSettings({ skipClaudeOnboarding: true });
|
||||
});
|
||||
|
||||
expect(applyClaudeOnboardingSkipMock).toHaveBeenCalledTimes(1);
|
||||
expect(toastErrorMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("auto-saves and clears Claude onboarding skip when toggled off", async () => {
|
||||
serverSettings = {
|
||||
...serverSettings,
|
||||
skipClaudeOnboarding: true,
|
||||
};
|
||||
useSettingsQueryMock.mockReturnValue({
|
||||
data: serverSettings,
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
settingsFormMock = createSettingsFormMock({
|
||||
settings: {
|
||||
...serverSettings,
|
||||
language: "zh",
|
||||
skipClaudeOnboarding: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useSettings());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.autoSaveSettings({ skipClaudeOnboarding: false });
|
||||
});
|
||||
|
||||
expect(clearClaudeOnboardingSkipMock).toHaveBeenCalledTimes(1);
|
||||
expect(toastErrorMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("saves settings and flags restart when app config directory changes", async () => {
|
||||
|
||||
@@ -176,6 +176,10 @@ export const handlers = [
|
||||
},
|
||||
),
|
||||
|
||||
http.post(`${TAURI_ENDPOINT}/apply_claude_onboarding_skip`, () => success(true)),
|
||||
|
||||
http.post(`${TAURI_ENDPOINT}/clear_claude_onboarding_skip`, () => success(true)),
|
||||
|
||||
http.post(`${TAURI_ENDPOINT}/get_config_dir`, async ({ request }) => {
|
||||
const { app } = await withJson<{ app: AppId }>(request);
|
||||
return success(app === "claude" ? "/default/claude" : "/default/codex");
|
||||
|
||||
Reference in New Issue
Block a user