Skip to content

fix(desktop): honor minimizeOnLaunch on auto-start (#115)#121

Merged
legeling merged 3 commits into
legeling:mainfrom
TuTouPower:fix/issue-115-start-minimized
May 10, 2026
Merged

fix(desktop): honor minimizeOnLaunch on auto-start (#115)#121
legeling merged 3 commits into
legeling:mainfrom
TuTouPower:fix/issue-115-start-minimized

Conversation

@TuTouPower
Copy link
Copy Markdown
Contributor

@TuTouPower TuTouPower commented May 9, 2026

Summary

Fixes #115 — when a user enables both "launch at startup" and "minimize on launch" on Windows (and by extension, all platforms), the window still pops up on auto-start instead of staying hidden.

Root cause

The renderer stored `minimizeOnLaunch` only in zustand `persist` (localStorage), but the main process reads it from the SQLite `settings` table on startup. The value was never synced to SQLite, so main always saw the default (`false`) and showed the window — even when the UI displayed the toggle as enabled.

On Windows, there is a second issue: electron's `openAsHidden` flag on `app.setLoginItemSettings` is a macOS-only hint. On Windows the OS has no way to tell the app it was auto-started hidden.

Fix

  1. Persist to main DB

    • `setMinimizeOnLaunch` and `setLaunchAtStartup` in the renderer store now also call `window.api.settings.set({...})` so the value lands in the main SQLite settings table.
    • `onRehydrateStorage` re-syncs both keys on every app load, which migrates existing users whose value currently lives only in localStorage.
  2. OS-level signal on Windows

    • `app.setLoginItemSettings` now also registers `--hidden` as a launch argument when the user opts in.
    • On `ready-to-show`, the main process honors `--hidden` (Windows) or `wasOpenedAsHidden` (macOS) in addition to the persisted DB value. If the OS already told us to start hidden, we don't even need the DB.
  3. Shared types

    • Added optional `launchAtStartup` / `minimizeOnLaunch` fields to `Settings` so the new DB writes are type-safe.

Tests

  • `apps/desktop/tests/unit/main/settings-startup.test.ts`: verifies `getMinimizeOnLaunchSetting` reads the persisted SQLite value correctly and tolerates missing / malformed rows (including a `{not-json` value that previously would have been silently swallowed).
  • `apps/desktop/tests/unit/stores/settings-startup.test.ts`: verifies the renderer pushes `minimizeOnLaunch` and `launchAtStartup` to `window.api.settings.set` when the user toggles them.

Verification

  • `pnpm test -- --run tests/unit/main/settings-startup.test.ts tests/unit/stores/settings-startup.test.ts` — 9/9 passing.
  • `pnpm lint` — clean.
  • Full suite has 5 pre-existing failures unrelated to this change (updater homebrew detection + i18n skill smoke + top-bar rules search); confirmed they fail on `main` too.

Notes

  • The `setMinimizeToTray` side-effect inside `setMinimizeOnLaunch` is left as-is to avoid scope creep; that coupling is worth a follow-up but is not the root cause of [Bug]: 启动时最小化未生效 #115.

Summary by CodeRabbit

  • 新功能

    • 增强了启动行为设置:支持“启动时运行”和“启动时最小化”,并在启动时更可靠地响应系统隐藏请求(含启动参数回退)。
  • Bug 修复

    • 启动流程现在更准确地结合系统登录项与用户偏好决定窗口初始可见性。
  • 测试

    • 新增主进程与渲染进程单元测试,覆盖偏好读取、持久化与同步场景。
  • 其他

    • 设置类型新增启动选项字段以支持同步。

Review Change Stack

The renderer stored minimizeOnLaunch only in zustand persist (localStorage),
but the main process reads it from the SQLite settings table at startup —
so the value was never actually visible to main. The main process always
saw the default (false) and opened the window even when the user had
enabled 'Minimize on Launch' in the UI.

Fix:
- Sync minimizeOnLaunch (and launchAtStartup, for symmetry) to the main
  process DB on toggle and on every store rehydrate. This also migrates
  existing users whose value currently lives only in localStorage.
- On Windows, also pass '--hidden' as the auto-launch argument so the
  main process can detect hidden startup independently of the DB (the
  macOS 'openAsHidden' flag is a no-op on Windows).
- On startup, respect an OS-level hidden signal (wasOpenedAsHidden or
  '--hidden' arg) in addition to the persisted setting, so the window
  stays hidden reliably even if the DB sync has not yet happened.

Tests:
- tests/unit/main/settings-startup.test.ts: verifies
  getMinimizeOnLaunchSetting reads the persisted SQLite value correctly
  and tolerates missing / malformed rows.
- tests/unit/stores/settings-startup.test.ts: verifies the renderer
  store pushes minimizeOnLaunch and launchAtStartup to
  window.api.settings.set() so the main process can read them.

Fixes legeling#115
@vercel
Copy link
Copy Markdown

vercel Bot commented May 9, 2026

@TuTouPower is attempting to deploy a commit to the legeling's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0a4fa7c2-b52a-4c4b-8865-991bfcefdc04

📥 Commits

Reviewing files that changed from the base of the PR and between f9da9fd and b98710c.

📒 Files selected for processing (2)
  • apps/desktop/src/renderer/stores/settings.store.ts
  • packages/shared/types/settings.ts

📝 Walkthrough

Walkthrough

本 PR 添加启动时最小化设置:扩展 Settings 类型、主进程在 ready-to-show 根据 OS 隐藏信号与持久化设置决定窗口可见性,渲染器同步设置到主进程,并补充单元测试覆盖主进程与渲染器行为。

启动时最小化功能

Layer / File(s) Summary
数据契约
packages/shared/types/settings.ts
Settings 接口新增可选字段 launchAtStartupminimizeOnLaunch
主进程启动逻辑
apps/desktop/src/main/index.ts
ready-to-show 现在检测 --hiddenapp.getLoginItemSettings().wasOpenedAsHidden(安全回退),并结合 getMinimizeOnLaunchSetting 计算 shouldMinimizeapp:setAutoLaunch 处理器设置 openAtLoginopenAsHidden 与条件 args: ["--hidden"]
渲染器设置同步
apps/desktop/src/renderer/stores/settings.store.ts
setLaunchAtStartupsetMinimizeOnLaunch 在更新 zustand 状态后调用 syncSettingsToMain 将值写入主进程;rehydration 时也同步这两个设置(缺省 false)。
单元测试
apps/desktop/tests/unit/main/settings-startup.test.ts, apps/desktop/tests/unit/stores/settings-startup.test.ts
主进程测试使用内存 SQLite 覆盖默认、布尔、非布尔与畸形 JSON 情况;渲染器测试验证状态更新后通过 IPC 同步到主进程。
sequenceDiagram
  participant User
  participant AppMain as MainProcess
  participant Store as RendererStore
  participant DB as SettingsDB
  participant Window as mainWindow

  User->>Store: 切换启动设置
  Store->>Store: 更新本地状态
  Store->>AppMain: syncSettingsToMain via IPC
  AppMain->>DB: 持久化设置
  AppMain->>Window: 启动时检测 OS hidden / args / DB
  alt shouldMinimize
    Window->>Window: 隐藏/最小化
  else
    Window->>Window: 显示
  end
Loading

🎯 3 (中等) | ⏱️ ~25 分钟

可能相关的 PRs:

  • legeling/PromptHub#121: 与本次变更在代码层面高度相关,均修改桌面启动行为、渲染器同步、测试与共享类型。

🐰 启动最小化终成真,
OS 信号与设置齐,
数据库持久保平安,
同步往返双向行,
测试护航百般稳!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题清晰准确地描述了主要变更:修复在自动启动时未能遵守最小化设置的问题。
Linked Issues check ✅ Passed 代码变更充分解决了 #115 中的问题:渲染器进程现在向主进程数据库持久化最小化和启动设置,主进程在启动时读取并应用这些设置,支持 Windows 和 macOS 的 OS 级隐藏信号。
Out of Scope Changes check ✅ Passed 所有变更都直接相关:Settings 类型扩展、主进程启动逻辑改进、渲染器存储持久化、以及相应的单元测试,均在修复 #115 的范围内。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix minimize-on-launch not honored on auto-start by syncing to main DB

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Sync minimizeOnLaunch and launchAtStartup to main process DB on toggle
• Honor OS-level hidden signals (--hidden arg, wasOpenedAsHidden) at startup
• Add comprehensive tests for settings persistence and startup behavior
• Migrate existing users whose settings live only in localStorage
Diagram
flowchart LR
  A["Renderer toggles<br/>minimizeOnLaunch"] -->|syncSettingsToMain| B["Main process<br/>SQLite DB"]
  C["App auto-starts"] -->|check OS signal| D["--hidden arg or<br/>wasOpenedAsHidden"]
  D -->|if present| E["Start minimized"]
  D -->|if absent| F["Check DB setting"]
  F -->|minimizeOnLaunch=true| E
  F -->|minimizeOnLaunch=false| G["Show window"]
  B -->|persisted| F
Loading

Grey Divider

File Changes

1. apps/desktop/src/main/index.ts 🐞 Bug fix +40/-9

Honor OS signals and DB setting for minimize-on-launch

• Check OS-level hidden signals (--hidden arg and wasOpenedAsHidden) before showing window
• Fall back to persisted DB setting only if OS didn't request hidden startup
• Ensure tray is created when minimizing on launch so user can restore window
• Pass --hidden as launch argument when registering auto-launch with minimize enabled

apps/desktop/src/main/index.ts


2. apps/desktop/src/renderer/stores/settings.store.ts 🐞 Bug fix +20/-1

Persist startup settings to main process database

• Sync minimizeOnLaunch to main process DB when toggled via syncSettingsToMain
• Sync launchAtStartup to main process DB when toggled
• Re-sync both startup settings on store rehydrate to migrate existing users
• Ensures main process can read settings on next launch

apps/desktop/src/renderer/stores/settings.store.ts


3. apps/desktop/tests/unit/main/settings-startup.test.ts 🧪 Tests +72/-0

Test main process startup settings retrieval

• Test getMinimizeOnLaunchSetting reads persisted SQLite value correctly
• Verify function returns false when setting never written
• Test defensive handling of non-boolean and malformed JSON values
• Ensure setting is independent from other keys in settings table

apps/desktop/tests/unit/main/settings-startup.test.ts


View more (2)
4. apps/desktop/tests/unit/stores/settings-startup.test.ts 🧪 Tests +92/-0

Test renderer store syncs startup settings to main

• Test that toggling minimizeOnLaunch calls window.api.settings.set
• Test that toggling launchAtStartup calls window.api.settings.set
• Verify both true and false values are synced to main process
• Guard against regression where settings only persisted to localStorage

apps/desktop/tests/unit/stores/settings-startup.test.ts


5. packages/shared/types/settings.ts ✨ Enhancement +4/-0

Add startup behavior fields to Settings type

• Add optional launchAtStartup field to Settings interface
• Add optional minimizeOnLaunch field to Settings interface
• Include comments explaining these fields are read by main process at startup

packages/shared/types/settings.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 9, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. getLoginItemSettings error swallowed ✓ Resolved 📘 Rule violation ☼ Reliability
Description
The new try { ... } catch { ... } suppresses any exception from app.getLoginItemSettings() and
silently falls back to false, which hides failures and can lead to incorrect startup visibility
behavior.
Code

apps/desktop/src/main/index.ts[R236-241]

+    try {
+      openedAsHiddenByOs =
+        app.getLoginItemSettings().wasOpenedAsHidden === true;
+    } catch {
+      openedAsHiddenByOs = false;
+    }
Evidence
PR Compliance IDs 7 and 8 require meaningful error handling and prohibit swallowing errors while
returning defaults. The added catch { openedAsHiddenByOs = false; } handles the error silently and
forces a default value.

AGENTS.md
AGENTS.md
apps/desktop/src/main/index.ts[236-241]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`app.getLoginItemSettings()` exceptions are swallowed and replaced with a default `false`, creating a silent failure path.
## Issue Context
This code runs during startup window visibility decisions, so suppressed failures can cause user-visible behavior regressions that are hard to diagnose.
## Fix Focus Areas
- apps/desktop/src/main/index.ts[236-241]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. as assertions lack comments ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
New type assertions (as Partial and as Record | undefined) are introduced without an explanatory
comment justifying why the cast is safe/required, increasing the chance of masked type mismatches.
Code

apps/desktop/src/renderer/stores/settings.store.ts[R812-815]

+          // Persist to main process DB so the main-process startup path
+          // can read the setting on next launch (#115)
+          // 同步到主进程数据库,下次启动时主进程能够正确读取该设置 (#115)
+          syncSettingsToMain({ launchAtStartup: enabled } as Partial<Settings>);
Evidence
PR Compliance ID 4 requires any introduced type assertions to have a nearby justification comment
explaining why the assertion is safe/necessary. The added as ... casts are used without explaining
the safety/need for the assertion itself.

AGENTS.md
apps/desktop/src/renderer/stores/settings.store.ts[812-815]
apps/desktop/src/renderer/stores/settings.store.ts[828-834]
apps/desktop/src/renderer/stores/settings.store.ts[1452-1460]
apps/desktop/tests/unit/stores/settings-startup.test.ts[34-43]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Type assertions were added without documenting why they are safe/required.
## Issue Context
Unjustified assertions can hide real type mismatches and make refactors riskier.
## Fix Focus Areas
- apps/desktop/src/renderer/stores/settings.store.ts[812-815]
- apps/desktop/src/renderer/stores/settings.store.ts[828-834]
- apps/desktop/src/renderer/stores/settings.store.ts[1452-1460]
- apps/desktop/tests/unit/stores/settings-startup.test.ts[34-43]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Chinese text outside locales ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
Chinese characters are introduced in non-locale TypeScript source files (as comments), violating the
rule that Chinese text must be confined to locale JSON resources.
Code

packages/shared/types/settings.ts[R25-28]

+  // Startup behavior — main process reads these to honor "minimize on launch"
+  // 启动行为 —— 主进程读取这些字段以实现"启动时最小化"
+  launchAtStartup?: boolean;
+  minimizeOnLaunch?: boolean;
Evidence
PR Compliance ID 12 forbids adding Chinese characters outside locale JSON files. The PR adds Chinese
text in comments across multiple TypeScript files.

AGENTS.md
packages/shared/types/settings.ts[25-28]
apps/desktop/src/main/index.ts[230-232]
apps/desktop/src/renderer/stores/settings.store.ts[812-815]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Chinese characters were added in TypeScript source files (comments), but Chinese text must live only in locale JSON resources.
## Issue Context
Keeping Chinese text centralized in locale files avoids mixed-language source and keeps localization consistent.
## Fix Focus Areas
- packages/shared/types/settings.ts[25-28]
- apps/desktop/src/main/index.ts[230-232]
- apps/desktop/src/renderer/stores/settings.store.ts[812-815]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. setAutoLaunch lacks safe errors ✓ Resolved 📘 Rule violation ☼ Reliability
Description
The IPC listener calls app.setLoginItemSettings(...) without any error handling or structured
error response, so failures can propagate unpredictably and are not safely reported back to the
renderer.
Code

apps/desktop/src/main/index.ts[R454-464]

+    const startHidden = enabled && minimizeOnLaunch === true;
+    // Pass `--hidden` as a launch arg so Windows (and any other platform where
+    // `openAsHidden` is not honored by the OS) can still detect that the app
+    // should start minimized (#115).
+    // 通过 `--hidden` 启动参数让 Windows(以及 macOS 以外、`openAsHidden` 不生效的
+    // 平台)在开机自启时能识别出应该最小化启动 (#115)。
 app.setLoginItemSettings({
   openAtLogin: enabled,
-      // If minimizeOnLaunch is true, start hidden (minimize to tray on launch)
-      // 如果 minimizeOnLaunch 为 true,则隐藏启动(启动时最小化到托盘)
-      openAsHidden: enabled && minimizeOnLaunch === true,
+      openAsHidden: startHidden,
+      args: startHidden ? ["--hidden"] : [],
 });
Evidence
PR Compliance ID 10 requires IPC handlers to catch errors and return structured error responses
instead of allowing uncaught errors or silent failures. The modified IPC handler still performs
OS-level work without a protective try/catch and without returning a structured result.

AGENTS.md
apps/desktop/src/main/index.ts[454-464]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `ipcMain.on(...setAutoLaunch...)` handler performs `app.setLoginItemSettings(...)` without catching errors or communicating failures in a structured way.
## Issue Context
OS integration calls may fail depending on platform/policies; IPC handlers should not crash or fail silently.
## Fix Focus Areas
- apps/desktop/src/main/index.ts[454-464]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (7)
apps/desktop/tests/unit/stores/settings-startup.test.ts (4)

82-91: ⚡ Quick win

移除冗余的 .toBeDefined() 断言

同上,expect(payload).toBeDefined() 是多余的。

♻️ 建议的修复
    const payload = lastPayloadWithKey(setSpy, "launchAtStartup");
-   expect(payload).toBeDefined();
-   expect(payload?.launchAtStartup).toBe(true);
+   expect(payload?.launchAtStartup).toBe(true);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/tests/unit/stores/settings-startup.test.ts` around lines 82 -
91, The test "syncs launchAtStartup to the main process when toggled" contains a
redundant assertion; remove the unnecessary expect(payload).toBeDefined() in the
test that imports setSpy and uses lastPayloadWithKey, leaving the existing
checks that assert useSettingsStore.getState().launchAtStartup is true and that
payload?.launchAtStartup is true after calling
useSettingsStore.getState().setLaunchAtStartup(true).

71-80: ⚡ Quick win

移除冗余的 .toBeDefined() 断言

同上,expect(payload).toBeDefined() 是多余的。

♻️ 建议的修复
    const payload = lastPayloadWithKey(setSpy, "minimizeOnLaunch");
-   expect(payload).toBeDefined();
-   expect(payload?.minimizeOnLaunch).toBe(false);
+   expect(payload?.minimizeOnLaunch).toBe(false);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/tests/unit/stores/settings-startup.test.ts` around lines 71 -
80, Remove the redundant assertion expect(payload).toBeDefined() in the test
"syncs minimizeOnLaunch=false to the main process when toggled off"; keep the
existing checks using lastPayloadWithKey(setSpy, "minimizeOnLaunch") and the
subsequent expect(payload?.minimizeOnLaunch).toBe(false) so the test still
verifies the payload value, referencing
useSettingsStore.getState().setMinimizeOnLaunch, lastPayloadWithKey, and setSpy.

60-80: 💤 Low value

考虑使用参数化测试减少重复

两个 minimizeOnLaunch 测试仅在布尔值上有差异,可以使用 it.each() 合并以符合编码规范:"禁止复制粘贴仅有细微差异的测试块;使用 it.each() 或参数化测试"。

♻️ 可选的重构建议
it.each([
  { value: true, label: "true" },
  { value: false, label: "false" },
])(
  "syncs minimizeOnLaunch=$label to the main process when toggled",
  async ({ value }) => {
    const { useSettingsStore, setSpy } = await importStoreWithSpy();

    useSettingsStore.getState().setMinimizeOnLaunch(value);

    expect(useSettingsStore.getState().minimizeOnLaunch).toBe(value);
    const payload = lastPayloadWithKey(setSpy, "minimizeOnLaunch");
    expect(payload?.minimizeOnLaunch).toBe(value);
  }
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/tests/unit/stores/settings-startup.test.ts` around lines 60 -
80, Replace the two nearly-identical tests for setMinimizeOnLaunch with a
parameterized test using Jest's it.each to remove duplication: write an it.each
over [{value:true,label:"true"},{value:false,label:"false"}] that imports
importStoreWithSpy, calls
useSettingsStore.getState().setMinimizeOnLaunch(value), asserts
useSettingsStore.getState().minimizeOnLaunch === value, and checks
lastPayloadWithKey(setSpy, "minimizeOnLaunch")?.minimizeOnLaunch === value; keep
the existing helpers (importStoreWithSpy, useSettingsStore, setMinimizeOnLaunch,
lastPayloadWithKey) but consolidate into one parameterized test named like
"syncs minimizeOnLaunch=$label to the main process when toggled".

60-69: ⚡ Quick win

移除冗余的 .toBeDefined() 断言

下一行已经使用可选链 payload?.minimizeOnLaunch 检查实际值,因此 expect(payload).toBeDefined() 是多余的懒惰断言。如果 payloadundefined,实际值检查会提供更明确的错误信息。

根据编码规范:"禁止使用懒惰断言如 expect(result).toBeDefined(),应直接检查实际值"。

♻️ 建议的修复
    const payload = lastPayloadWithKey(setSpy, "minimizeOnLaunch");
-   expect(payload).toBeDefined();
-   expect(payload?.minimizeOnLaunch).toBe(true);
+   expect(payload?.minimizeOnLaunch).toBe(true);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/tests/unit/stores/settings-startup.test.ts` around lines 60 -
69, Remove the redundant lazy assertion expect(payload).toBeDefined() in the
test "syncs minimizeOnLaunch=true to the main process when toggled" and rely on
the direct check expect(payload?.minimizeOnLaunch).toBe(true); specifically,
delete the line that calls expect(payload).toBeDefined() in
apps/desktop/tests/unit/stores/settings-startup.test.ts where payload is
obtained from lastPayloadWithKey(setSpy, "minimizeOnLaunch") and keep the
remaining assertions using useSettingsStore.getState(), setMinimizeOnLaunch, and
lastPayloadWithKey.
apps/desktop/src/renderer/stores/settings.store.ts (3)

812-815: ⚡ Quick win

移除不必要的类型断言

syncSettingsToMain 的参数类型是 Partial<Settings>,对象字面量 { launchAtStartup: enabled } 应该可以直接赋值,无需 as Partial<Settings> 断言。根据编码规范,类型断言必须有注释说明必要性,或者应该修复底层类型错误而非使用断言。

♻️ 建议的修复
-      syncSettingsToMain({ launchAtStartup: enabled } as Partial<Settings>);
+      syncSettingsToMain({ launchAtStartup: enabled });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/stores/settings.store.ts` around lines 812 - 815,
Remove the unnecessary type assertion on the object passed to
syncSettingsToMain: change the call that currently uses "{ launchAtStartup:
enabled } as Partial<Settings>" to pass the object literal directly, e.g.
syncSettingsToMain({ launchAtStartup: enabled }); ensure the property name
matches the Settings interface (launchAtStartup) and that enabled is the correct
boolean, and only add a typed cast if a real type mismatch in the Settings
definition is discovered and cannot be fixed.

1452-1460: ⚡ Quick win

移除不必要的类型断言

rehydration 回调中的对象字面量也可以直接满足 Partial<Settings> 类型,无需断言。

♻️ 建议的修复
          launchAtStartup: state?.launchAtStartup ?? false,
          minimizeOnLaunch: state?.minimizeOnLaunch ?? false,
-        } as Partial<Settings>);
+        });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/stores/settings.store.ts` around lines 1452 - 1460,
Remove the unnecessary type assertion "as Partial<Settings>" from the object
literal returned in the rehydration callback around the properties
launchAtStartup and minimizeOnLaunch; the literal already conforms to
Partial<Settings>, so update the rehydrate/restore block (the object that sets
launchAtStartup and minimizeOnLaunch) to return the object without the type
cast, leaving TypeScript to infer the Partial<Settings> type.

828-834: ⚡ Quick win

移除不必要的类型断言

同上,{ minimizeOnLaunch: enabled } 可以直接传递给 syncSettingsToMain,无需类型断言。

♻️ 建议的修复
-      syncSettingsToMain({ minimizeOnLaunch: enabled } as Partial<Settings>);
+      syncSettingsToMain({ minimizeOnLaunch: enabled });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/stores/settings.store.ts` around lines 828 - 834,
The code is using an unnecessary type assertion when calling syncSettingsToMain;
remove the "as Partial<Settings>" so you pass the object literal {
minimizeOnLaunch: enabled } directly to syncSettingsToMain (update the call site
where syncSettingsToMain({ minimizeOnLaunch: enabled } as Partial<Settings}) is
used to simply syncSettingsToMain({ minimizeOnLaunch: enabled })). Ensure the
call still type-checks against syncSettingsToMain's parameter type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/desktop/src/renderer/stores/settings.store.ts`:
- Around line 812-815: Remove the unnecessary type assertion on the object
passed to syncSettingsToMain: change the call that currently uses "{
launchAtStartup: enabled } as Partial<Settings>" to pass the object literal
directly, e.g. syncSettingsToMain({ launchAtStartup: enabled }); ensure the
property name matches the Settings interface (launchAtStartup) and that enabled
is the correct boolean, and only add a typed cast if a real type mismatch in the
Settings definition is discovered and cannot be fixed.
- Around line 1452-1460: Remove the unnecessary type assertion "as
Partial<Settings>" from the object literal returned in the rehydration callback
around the properties launchAtStartup and minimizeOnLaunch; the literal already
conforms to Partial<Settings>, so update the rehydrate/restore block (the object
that sets launchAtStartup and minimizeOnLaunch) to return the object without the
type cast, leaving TypeScript to infer the Partial<Settings> type.
- Around line 828-834: The code is using an unnecessary type assertion when
calling syncSettingsToMain; remove the "as Partial<Settings>" so you pass the
object literal { minimizeOnLaunch: enabled } directly to syncSettingsToMain
(update the call site where syncSettingsToMain({ minimizeOnLaunch: enabled } as
Partial<Settings}) is used to simply syncSettingsToMain({ minimizeOnLaunch:
enabled })). Ensure the call still type-checks against syncSettingsToMain's
parameter type.

In `@apps/desktop/tests/unit/stores/settings-startup.test.ts`:
- Around line 82-91: The test "syncs launchAtStartup to the main process when
toggled" contains a redundant assertion; remove the unnecessary
expect(payload).toBeDefined() in the test that imports setSpy and uses
lastPayloadWithKey, leaving the existing checks that assert
useSettingsStore.getState().launchAtStartup is true and that
payload?.launchAtStartup is true after calling
useSettingsStore.getState().setLaunchAtStartup(true).
- Around line 71-80: Remove the redundant assertion
expect(payload).toBeDefined() in the test "syncs minimizeOnLaunch=false to the
main process when toggled off"; keep the existing checks using
lastPayloadWithKey(setSpy, "minimizeOnLaunch") and the subsequent
expect(payload?.minimizeOnLaunch).toBe(false) so the test still verifies the
payload value, referencing useSettingsStore.getState().setMinimizeOnLaunch,
lastPayloadWithKey, and setSpy.
- Around line 60-80: Replace the two nearly-identical tests for
setMinimizeOnLaunch with a parameterized test using Jest's it.each to remove
duplication: write an it.each over
[{value:true,label:"true"},{value:false,label:"false"}] that imports
importStoreWithSpy, calls
useSettingsStore.getState().setMinimizeOnLaunch(value), asserts
useSettingsStore.getState().minimizeOnLaunch === value, and checks
lastPayloadWithKey(setSpy, "minimizeOnLaunch")?.minimizeOnLaunch === value; keep
the existing helpers (importStoreWithSpy, useSettingsStore, setMinimizeOnLaunch,
lastPayloadWithKey) but consolidate into one parameterized test named like
"syncs minimizeOnLaunch=$label to the main process when toggled".
- Around line 60-69: Remove the redundant lazy assertion
expect(payload).toBeDefined() in the test "syncs minimizeOnLaunch=true to the
main process when toggled" and rely on the direct check
expect(payload?.minimizeOnLaunch).toBe(true); specifically, delete the line that
calls expect(payload).toBeDefined() in
apps/desktop/tests/unit/stores/settings-startup.test.ts where payload is
obtained from lastPayloadWithKey(setSpy, "minimizeOnLaunch") and keep the
remaining assertions using useSettingsStore.getState(), setMinimizeOnLaunch, and
lastPayloadWithKey.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8dbfe0fc-8cac-4bef-a6f6-326260957032

📥 Commits

Reviewing files that changed from the base of the PR and between ebc43d9 and 01ed797.

📒 Files selected for processing (5)
  • apps/desktop/src/main/index.ts
  • apps/desktop/src/renderer/stores/settings.store.ts
  • apps/desktop/tests/unit/main/settings-startup.test.ts
  • apps/desktop/tests/unit/stores/settings-startup.test.ts
  • packages/shared/types/settings.ts

Comment thread apps/desktop/src/main/index.ts
Comment thread apps/desktop/src/renderer/stores/settings.store.ts Outdated
Comment thread packages/shared/types/settings.ts
TuTouPower and others added 2 commits May 10, 2026 05:15
- Drop Chinese-only comments introduced by this PR (AGENTS.md rule)
- Drop unnecessary `as Partial<Settings>` assertions — the object
  literals already satisfy the parameter type
- Log `app.getLoginItemSettings()` failures instead of silently falling
  back; electron can throw on systems without a login-items service,
  and a silent false caused issue legeling#115 all over again in those paths
- Wrap `app:setAutoLaunch` handler's `setLoginItemSettings` call in a
  try/catch so OS-level policy denials don't crash the main process
- Parameterize the two renderer store tests with `it.each` instead of
  copy-paste, and drop redundant `.toBeDefined()` assertions in
  favor of the more specific `toBe(value)` check
@legeling legeling merged commit d9dcbe1 into legeling:main May 10, 2026
0 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 启动时最小化未生效

2 participants