Skip to content

feat: 自动模式下跳过更新弹窗的展示,保留到下次手动#141

Merged
MistEO merged 8 commits intoMistEO:mainfrom
ShadowLemoon:fix/auto-stuck-at-update
Apr 4, 2026
Merged

feat: 自动模式下跳过更新弹窗的展示,保留到下次手动#141
MistEO merged 8 commits intoMistEO:mainfrom
ShadowLemoon:fix/auto-stuck-at-update

Conversation

@ShadowLemoon
Copy link
Copy Markdown
Contributor

@ShadowLemoon ShadowLemoon commented Mar 31, 2026

Summary by Sourcery

调整自动启动行为,将任务执行延迟到更新检查之后,同时在自动运行场景中跳过阻塞性的更新对话框。

新功能:

  • 允许自动运行模式(包括开机自启和启动即自动运行)跳过显示更新完成后的对话框,并将其推迟到下一次手动启动时再显示。

增强:

  • 将自启动任务的分发延迟到更新检查之后,这样在有可用更新时,任务可以在更新后的版本上运行。
  • 跟踪挂起的自动任务,并在更新下载失败或被取消时恢复这些任务。
  • 引入一个对已存储的更新完成信息的无破坏性读取助手,以支持自动运行和手动运行之间的不同行为。
  • 明确并扩展自动启动模式标志的语义,使其表示通用的自动运行模式。
Original summary in English

Summary by Sourcery

Adjust automatic startup behavior to delay task execution until after update checks while skipping blocking update dialogs in automatic run scenarios.

New Features:

  • Allow automatic run mode (including autostart and auto-run-on-launch) to skip showing the post-update dialog and defer it to the next manual launch.

Enhancements:

  • Defer autostart task dispatch until after update checking so tasks can run on the updated version when an update is available.
  • Track pending automatic tasks and resume them when update download fails or is canceled.
  • Introduce a non-destructive read helper for stored update completion info to support different behaviors between automatic and manual runs.
  • Clarify and broaden the semantics of the auto start mode flag to represent general automatic run mode.
Original summary in English

Summary by Sourcery

调整自动启动行为,将任务执行延迟到更新检查之后,同时在自动运行场景中跳过阻塞性的更新对话框。

新功能:

  • 允许自动运行模式(包括开机自启和启动即自动运行)跳过显示更新完成后的对话框,并将其推迟到下一次手动启动时再显示。

增强:

  • 将自启动任务的分发延迟到更新检查之后,这样在有可用更新时,任务可以在更新后的版本上运行。
  • 跟踪挂起的自动任务,并在更新下载失败或被取消时恢复这些任务。
  • 引入一个对已存储的更新完成信息的无破坏性读取助手,以支持自动运行和手动运行之间的不同行为。
  • 明确并扩展自动启动模式标志的语义,使其表示通用的自动运行模式。
Original summary in English

Summary by Sourcery

Adjust automatic startup behavior to delay task execution until after update checks while skipping blocking update dialogs in automatic run scenarios.

New Features:

  • Allow automatic run mode (including autostart and auto-run-on-launch) to skip showing the post-update dialog and defer it to the next manual launch.

Enhancements:

  • Defer autostart task dispatch until after update checking so tasks can run on the updated version when an update is available.
  • Track pending automatic tasks and resume them when update download fails or is canceled.
  • Introduce a non-destructive read helper for stored update completion info to support different behaviors between automatic and manual runs.
  • Clarify and broaden the semantics of the auto start mode flag to represent general automatic run mode.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - 我在这里提供了一些总体反馈:

  • 在 zip/自动安装 分支中,clearPendingUpdateInfo() 现在只在 !isAutoStartModeNow 时被调用;如果自动启动的会话检测到更新已完成,你可能仍然希望清除挂起更新状态,只是延后展示 UI/确认弹窗,以避免留下过期的挂起更新信息。
  • 设置 justUpdatedInfo 并展示安装确认弹窗的逻辑,现在在版本已验证分支和直接完成分支中都有重复;可以考虑把这部分提取成一个小的辅助函数,以便让更新完成流程更易维护。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- In the zip/auto-install branch, `clearPendingUpdateInfo()` is now only called when `!isAutoStartModeNow`; if an auto-started session detects a completed update, you may want to clear the pending-update state regardless and only defer the UI/confirm modal, to avoid leaving stale pending-update info around.
- The logic that sets `justUpdatedInfo` and shows the install confirm modal is now duplicated in both the version-verified branch and the direct-complete branch; consider extracting this into a small helper to keep the update-complete flow easier to maintain.

Sourcery 对开源项目是免费的——如果你觉得我们的代码审查有帮助,欢迎分享给更多人 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've left some high level feedback:

  • In the zip/auto-install branch, clearPendingUpdateInfo() is now only called when !isAutoStartModeNow; if an auto-started session detects a completed update, you may want to clear the pending-update state regardless and only defer the UI/confirm modal, to avoid leaving stale pending-update info around.
  • The logic that sets justUpdatedInfo and shows the install confirm modal is now duplicated in both the version-verified branch and the direct-complete branch; consider extracting this into a small helper to keep the update-complete flow easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the zip/auto-install branch, `clearPendingUpdateInfo()` is now only called when `!isAutoStartModeNow`; if an auto-started session detects a completed update, you may want to clear the pending-update state regardless and only defer the UI/confirm modal, to avoid leaving stale pending-update info around.
- The logic that sets `justUpdatedInfo` and shows the install confirm modal is now duplicated in both the version-verified branch and the direct-complete branch; consider extracting this into a small helper to keep the update-complete flow easier to maintain.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@MistEO
Copy link
Copy Markdown
Owner

MistEO commented Apr 2, 2026

我觉得不对,应该是暂存本次启动参数,自动更新完成后自动使用本次启动参数重启

@ShadowLemoon
Copy link
Copy Markdown
Contributor Author

我觉得不对,应该是暂存本次启动参数,自动更新完成后自动使用本次启动参数重启

这个逻辑本身已经存在了,这里处理的是重启后的状态

@ShadowLemoon
Copy link
Copy Markdown
Contributor Author

等下,看了下可能需要在开启模态框的情况下才能自动安装

@MistEO
Copy link
Copy Markdown
Owner

MistEO commented Apr 2, 2026

哦理解错了,那没问题,你改好了说一哈我再瞅瞅

@ShadowLemoon
Copy link
Copy Markdown
Contributor Author

手动启动且勾选了"手动启动时也自动执行"
这种情况下目前没有延迟分发任务运行,需要么

@MistEO
Copy link
Copy Markdown
Owner

MistEO commented Apr 3, 2026

手动启动且勾选了"手动启动时也自动执行" 这种情况下目前没有延迟分发任务运行,需要么

感觉可以也改成先检查更新。另外有冲突了康康

@ShadowLemoon
Copy link
Copy Markdown
Contributor Author

记录:如果用户取消下载也马上开始任务

@ShadowLemoon
Copy link
Copy Markdown
Contributor Author

手动启动下自动运行似乎不适合跳过弹窗,考虑把弹窗弹出并自动开始任务

@MistEO MistEO requested a review from Copilot April 4, 2026 09:08
@MistEO
Copy link
Copy Markdown
Owner

MistEO commented Apr 4, 2026

@sourcery-ai review

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - 我发现了两个问题,并给出了一些整体性的反馈:

  • peekUpdateCompleteInfo 中,建议在处理 JSON 解析异常时清除已存储的值(类似 consumeUpdateCompleteInfo),这样可以避免单个错误的 localStorage 条目导致持续的解析告警或不一致的行为。
  • 负责分发挂起自动任务的 effect 目前只在 downloadStatus === 'failed' 时触发,但注释中同时提到了失败和取消;如果“取消”对应的是另一个状态值,建议将其也显式包含进来,或者调整注释使其与实际行为保持一致。
提供给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
-`peekUpdateCompleteInfo` 中,建议在处理 JSON 解析异常时清除已存储的值(类似 `consumeUpdateCompleteInfo`),这样可以避免单个错误的 `localStorage` 条目导致持续的解析告警或不一致的行为。
- 负责分发挂起自动任务的 effect 目前只在 `downloadStatus === 'failed'` 时触发,但注释中同时提到了失败和取消;如果“取消”对应的是另一个状态值,建议将其也显式包含进来,或者调整注释使其与实际行为保持一致。

## Individual Comments

### Comment 1
<location path="src/services/updateService.ts" line_range="1159-1162" />
<code_context>
+/**
+ * 读取更新完成信息(不清除)
+ */
+export function peekUpdateCompleteInfo(): UpdateCompleteInfo | null {
+  try {
+    const data = localStorage.getItem(UPDATE_COMPLETE_STORAGE_KEY);
+    if (!data) return null;
+    return JSON.parse(data) as UpdateCompleteInfo;
+  } catch (error) {
+    log.warn('读取更新完成信息失败:', error);
</code_context>
<issue_to_address>
**suggestion:** 考虑在 JSON 解析失败时清除已存储的值,以避免每次启动时反复出现警告。

目前解析失败后会将错误数据保留在 `localStorage` 中,因此之后的每一次调用都会持续抛出异常并记录日志,直到用户手动清除数据。为避免这种持续失败的情况,可以在 `catch` 块中调用 `localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY)````suggestion
  } catch (error) {
    log.warn('读取更新完成信息失败:', error);
    // 当解析失败时清除存储的异常数据,避免下次继续报错
    localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY);
    return null;
  }
```
</issue_to_address>

### Comment 2
<location path="src/App.tsx" line_range="933" />
<code_context>

+  // 下载失败或取消时,如果有等待中的自动任务,立即分发
+  useEffect(() => {
+    if (pendingAutoTasksRef.current && downloadStatus === 'failed') {
+      pendingAutoTasksRef.current = false;
+      log.info('下载失败/取消,分发挂起的自动任务');
</code_context>
<issue_to_address>
**question:** 该 effect 只对 `failed` 状态做出响应,但注释中也提到了“下载取消”;请说明原因或使其与实际的下载状态值保持一致。

根据当前注释文本,“取消”也应该触发这个 effect,但条件判断只匹配 `downloadStatus === 'failed'`。如果“取消”映射为其他状态(例如 `idle``canceled`),那么在取消时挂起的自动任务将永远不会被分发。可以考虑在条件中同时包含取消状态,或者更新注释以匹配实际行为。
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得这些 review 有帮助,欢迎分享 ✨
帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的 review。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In peekUpdateCompleteInfo, consider handling malformed JSON by clearing the stored value (similar to consumeUpdateCompleteInfo) so that a single bad localStorage entry doesn't cause repeated parse warnings or inconsistent behavior.
  • The effect that dispatches pending auto tasks only triggers when downloadStatus === 'failed', but the comment mentions both failure and cancellation; if cancellations are represented by a different status, you may want to include that explicitly or adjust the comment to match the actual behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `peekUpdateCompleteInfo`, consider handling malformed JSON by clearing the stored value (similar to `consumeUpdateCompleteInfo`) so that a single bad `localStorage` entry doesn't cause repeated parse warnings or inconsistent behavior.
- The effect that dispatches pending auto tasks only triggers when `downloadStatus === 'failed'`, but the comment mentions both failure and cancellation; if cancellations are represented by a different status, you may want to include that explicitly or adjust the comment to match the actual behavior.

## Individual Comments

### Comment 1
<location path="src/services/updateService.ts" line_range="1159-1162" />
<code_context>
+/**
+ * 读取更新完成信息(不清除)
+ */
+export function peekUpdateCompleteInfo(): UpdateCompleteInfo | null {
+  try {
+    const data = localStorage.getItem(UPDATE_COMPLETE_STORAGE_KEY);
+    if (!data) return null;
+    return JSON.parse(data) as UpdateCompleteInfo;
+  } catch (error) {
+    log.warn('读取更新完成信息失败:', error);
</code_context>
<issue_to_address>
**suggestion:** Consider clearing the stored value when JSON parsing fails to avoid repeated warnings on every launch.

Right now a failed parse leaves the bad value in `localStorage`, so every subsequent call will keep throwing and logging until someone manually clears it. To avoid this persistent failure mode, you could call `localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY)` in the `catch` block.

```suggestion
  } catch (error) {
    log.warn('读取更新完成信息失败:', error);
    // 当解析失败时清除存储的异常数据,避免下次继续报错
    localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY);
    return null;
  }
```
</issue_to_address>

### Comment 2
<location path="src/App.tsx" line_range="933" />
<code_context>

+  // 下载失败或取消时,如果有等待中的自动任务,立即分发
+  useEffect(() => {
+    if (pendingAutoTasksRef.current && downloadStatus === 'failed') {
+      pendingAutoTasksRef.current = false;
+      log.info('下载失败/取消,分发挂起的自动任务');
</code_context>
<issue_to_address>
**question:** The effect only reacts on `failed`, but the comment mentions download cancellation as well; clarify or align with the actual download status values.

Given the comment text, cancellation should also trigger this effect, but the condition only matches `downloadStatus === 'failed'`. If cancel maps to a different status (e.g. `idle` or `canceled`), pending auto tasks will never be dispatched on cancel. Either include the cancellation status in the condition or update the comment to match the actual behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +1159 to +1162
} catch (error) {
log.warn('读取更新完成信息失败:', error);
return null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: 考虑在 JSON 解析失败时清除已存储的值,以避免每次启动时反复出现警告。

目前解析失败后会将错误数据保留在 localStorage 中,因此之后的每一次调用都会持续抛出异常并记录日志,直到用户手动清除数据。为避免这种持续失败的情况,可以在 catch 块中调用 localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY)

Suggested change
} catch (error) {
log.warn('读取更新完成信息失败:', error);
return null;
}
} catch (error) {
log.warn('读取更新完成信息失败:', error);
// 当解析失败时清除存储的异常数据,避免下次继续报错
localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY);
return null;
}
Original comment in English

suggestion: Consider clearing the stored value when JSON parsing fails to avoid repeated warnings on every launch.

Right now a failed parse leaves the bad value in localStorage, so every subsequent call will keep throwing and logging until someone manually clears it. To avoid this persistent failure mode, you could call localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY) in the catch block.

Suggested change
} catch (error) {
log.warn('读取更新完成信息失败:', error);
return null;
}
} catch (error) {
log.warn('读取更新完成信息失败:', error);
// 当解析失败时清除存储的异常数据,避免下次继续报错
localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY);
return null;
}

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

该 PR 调整应用在“自动运行模式”(开机自启动或手动启动但勾选自动执行)下的更新提示策略:在自动模式下延后展示更新完成/待安装更新相关 UI,到下次手动启动再提示,并新增对更新完成信息的非破坏性读取能力。

Changes:

  • 新增 peekUpdateCompleteInfo() 用于不消费地读取“更新完成”元数据。
  • App.tsx 启动流程中:自动模式下对“更新完成/待安装更新”提示改为延后处理,并调整 autostart 任务分发时机到更新检查之后。
  • 更新 isAutoStartMode 的注释表述为“自动运行模式”。

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/stores/types.ts 更新 isAutoStartMode 语义注释为“自动运行模式”。
src/stores/appStore.ts 同步 store 内 isAutoStartMode 注释。
src/services/updateService.ts 增加 peekUpdateCompleteInfo() 非破坏性读取更新完成信息。
src/App.tsx 自动模式下延后更新完成/待安装更新弹窗;调整自动任务分发与更新检查/下载的交互逻辑。
Comments suppressed due to low confidence (1)

src/App.tsx:320

  • tryAutoInstallUpdate 现在在 downloadStatus==='completed' 时总会 setShowInstallConfirmModal(true),不再跳过 isAutoStartMode。这样在“自动运行模式”下仍可能弹出安装确认模态框(与本 PR 目标:自动模式下跳过阻塞式更新弹窗不一致),并可能阻塞无人值守启动。建议在这里(以及触发安装模态框的相关路径)统一判断 isAutoStartMode,自动模式下仅记录待处理更新并延后到下次手动启动再弹窗。
  // 尝试自动安装更新(无任务运行中时触发)
  const tryAutoInstallUpdate = useCallback(() => {
    const state = useAppStore.getState();
    if (state.downloadStatus !== 'completed') return;
    if (state.installStatus !== 'idle') return;
    if (state.autoInstallPending) return;
    if (state.instances.some((i) => i.isRunning)) return;

    log.info('自动安装更新:条件满足,弹出安装');
    state.setAutoInstallPending(true);
    state.setShowInstallConfirmModal(true);
  }, []);

src/App.tsx Outdated
Comment on lines +618 to +650
@@ -645,6 +646,8 @@ function App() {
if (targetInstance) {
const source = isAutoStart ? '开机自启动' : '手动启动';
log.info(`${source}:激活配置并启动任务:`, targetInstance.name);
// 标记为自动运行模式,跳过阻塞式弹窗
useAppStore.getState().setIsAutoStartMode(true);
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

这里不再在 is_autostart=true 时直接 setIsAutoStartMode(true),而是只在找到 targetInstance 并准备自动执行任务时才设置。若用户配置了“开机自启动但不自动跑任务”(或实例不存在导致跳过自动执行),当前启动仍然是 autostart 场景,但 isAutoStartMode 会保持为 false,从而不会延后更新完成/待安装更新等提示,可能违背“自动启动模式下跳过更新弹窗”的需求。建议将“是否 autostart 启动”与“是否要自动跑任务”解耦:只要 is_autostart=true 就设置一个用于 UI 抑制的标志,任务相关逻辑再单独判断 shouldAutoRun/targetInstance。

Copilot uses AI. Check for mistakes.
Comment on lines +796 to 816
if (updateResult) {
setUpdateInfo(updateResult);
if (updateResult.hasUpdate) {
log.info(`发现新版本: ${updateResult.versionName}`);
// 强制弹出更新气泡
useAppStore.getState().setShowUpdateDialog(true);
// 有更新且有下载链接时自动开始下载
if (updateResult.downloadUrl) {
startAutoDownload(updateResult);
// 下载→安装→重启后任务在新版本上执行,取消本次任务分发
// 但如果下载失败/取消,需要通过 pendingAutoTasksRef 重新触发任务
if (autoStartTasksPending) {
autoStartTasksPending = false;
pendingAutoTasksRef.current = true;
}
} else if (updateResult.errorCode) {
// API 返回错误(如 CDK 问题),也弹出气泡提示用户
log.warn(`更新检查返回错误: code=${updateResult.errorCode}`);
useAppStore.getState().setShowUpdateDialog(true);
}
} else if (updateResult.errorCode) {
// API 返回错误(如 CDK 问题),也弹出气泡提示用户
log.warn(`更新检查返回错误: code=${updateResult.errorCode}`);
useAppStore.getState().setShowUpdateDialog(true);
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

自动检查更新后,如果发现更新/错误码仍会强制 setShowUpdateDialog(true)。在 isAutoStartModeNow=true 的自动运行模式下,这会导致更新气泡仍然出现(并且下方“回到主界面时弹窗”的 effect 也会进一步触发),与“自动模式下跳过更新弹窗展示,延后到下次手动”的目标不一致。建议在自动模式下不要触发 setShowUpdateDialog / focusWindow / 安装确认 UI,仅保存必要的更新元数据供下次手动启动展示。

Copilot uses AI. Check for mistakes.
if (!data) return null;
return JSON.parse(data) as UpdateCompleteInfo;
} catch (error) {
log.warn('读取更新完成信息失败:', error);
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

peekUpdateCompleteInfo 在 JSON.parse / localStorage 读取异常时只记录 warn 并返回 null,但不会清理 UPDATE_COMPLETE_STORAGE_KEY。若存储内容损坏,将导致每次启动都重复告警且永远无法恢复到可消费状态。建议在 catch 中也移除该 key(或至少在检测到 JSON 无法解析时移除),以避免持久化的坏数据。

Suggested change
log.warn('读取更新完成信息失败:', error);
log.warn('读取更新完成信息失败:', error);
localStorage.removeItem(UPDATE_COMPLETE_STORAGE_KEY);

Copilot uses AI. Check for mistakes.
ShadowLemoon and others added 2 commits April 4, 2026 17:27
- 移除 tryAutoInstallUpdate 的 isAutoStartMode 跳过,允许自启动模式自动安装
- 任务分发延迟到更新检查完成后(await 替代 .then)
- 更新完成信息统一 consume(不用 peek),autostart 跳过弹窗但不跳过安装
- 待安装更新所有模式都处理(不跳过 autostart),确保尽早安装
- 下载失败/取消(failed + idle)和弹窗关闭时恢复挂起的自动任务
- 提取 showUpdateCompletedUI 辅助函数减少重复代码

Made-with: Cursor
@MistEO MistEO merged commit 293fcd7 into MistEO:main Apr 4, 2026
9 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.

3 participants