Skip to content

feat(updater): add update install mode preference (#4467) - #4543

Closed
cbeaulieu-gt wants to merge 9 commits into
nexu-io:mainfrom
cbeaulieu-gt:feat/4467-update-install-mode
Closed

feat(updater): add update install mode preference (#4467)#4543
cbeaulieu-gt wants to merge 9 commits into
nexu-io:mainfrom
cbeaulieu-gt:feat/4467-update-install-mode

Conversation

@cbeaulieu-gt

@cbeaulieu-gt cbeaulieu-gt commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #4467

Why

Following up on #4467 after #4471 landed the payload-capability foundation. #4471 made capabilitiesFor artifact-aware (payload ⇒ in-app install) but intentionally deferred the user-facing preference. This PR adds that preference and the clearer manual-install copy, as scoped with @lefarcen in the issue thread.

The pain: on a packaged install there was no way to opt out of in-app payload updates back to the installer/DMG flow, and the "update ready" copy for the installer case read like a generic prompt rather than telling the user they need to run the installer themselves.

Who Manual mode is for

Manual is an escape hatch, not the happy path — most users should stay on Automatic. But since the app already has to understand the installer-vs-payload paths, leaving Manual wired gives power users and maintainers a controlled way to opt out of automatic apply when that is safer or easier to debug. Concrete cases (raised by @TheAngryPit in the thread):

  • Open-source debugging — when someone is testing update behavior on a fork, local build, or odd install state, Manual lets them use the installer path instead of having the app immediately apply a payload.
  • Support / debugging — if an update keeps failing in-app, a user can switch to installer mode and send clearer evidence, such as which artifact downloaded and whether the installer opens.
  • Security / incident response — if someone distrusts the automatic path during a bad release (suspicious network behavior, mirror concern, corrupted-payload suspicion), Manual lets them stop automatic apply and choose the installer flow while investigating.
  • Managed machines — some users may be on machines where automatic app replacement is restricted, but downloading/opening the installer is acceptable for an admin-controlled install.

Importantly, unset/absent still maps back to Automatic, so this does not change the default experience.

This is the cross-platform first slice (PR1). Per the agreement in #4467, macOS-native end-to-end acceptance (real payload extraction, DMG mount/Finder drag-install, signed-bundle identity) is deferred to a follow-up (PR2) that needs a Mac.

What users will see

  • Settings → About gains an "Update install mode" dropdown — Automatic (in-app) vs Manual (installer) — shown only on payload-capable packaged installs. Default is Automatic, so existing behavior is unchanged unless the user opts out.
  • The "update ready" popup now shows clearer copy when the update must be applied by running the installer: "Open Design {version} is ready. Open the downloaded installer to apply it." with an Open installer button, instead of the previous generic wording.
  • CLI parity: od config set updateInstallMode manual (and get/unset) via the existing generic od config command — no new subcommand.

Surface area

  • UI — Settings → About "Update install mode" dropdown; clearer manual-install copy in the updater popup
  • Keyboard shortcut
  • CLI / env varod config set updateInstallMode manual (rides the existing generic od config command; key added to the app-config allowlist — no new subcommand)
  • API / contract/api/app-config gains an optional updateInstallMode: 'automatic' | 'manual' field (additive, backward-safe)
  • Extension point
  • i18n keys — 3 updater + 3 settings keys, added across all locales
  • New top-level dependency
  • Default behavior change — none; absent/unset ⇒ Automatic, preserving fix(desktop): treat payload updates as in-app installs #4471's default
  • None

Screenshots

4467-shot-toggle 4467-shot-manual-install-copy

Bug fix verification

This PR also fixes a dead-code branch found while wiring the manual-install copy: capabilitiesFor couples canOpenInstaller and requiresManualInstall (both equal manualInstaller), so the popup's isManualInstallCase guard requiresManualInstall && !canOpenInstaller was always false — the manual-install copy never rendered. The guard now keys on requiresManualInstall alone.

  • Test path that reproduces the bug: apps/web/tests/components/UpdaterPopup-update-install-mode.test.tsx
  • Did the test go red before the fix and green after? Yes — verified by reverting the one-line guard change: the test fails for the right reason (standard copy renders; zh button 安装更新 instead of 打开安装程序), and passes with the fix. The earlier version of this test used an impossible capability combo (canOpenInstaller: false + requiresManualInstall: true) that capabilitiesFor never emits, which masked the bug; it now uses the real combo (canOpenInstaller: true).

Validation

  • pnpm typecheck — clean
  • pnpm --filter @open-design/web test — green (UpdaterPopup 12/12; pre-existing unrelated failures only: design-system style fixtures, sidecar-proxy socket)
  • pnpm --filter @open-design/desktop test (run locally; not in PR CI gate) — update-install-mode suites 9/9
  • pnpm --filter @open-design/daemon test — app-config round-trip green
  • pnpm guard — failures are pre-existing design-system component-fixture coverage only; zero overlap with the files in this PR
  • End-to-end: rebuilt the packaged Windows app and confirmed the manual-install copy renders live (screenshot above)

🤖 Generated by Claude Code on behalf of @cbeaulieu-gt

Add a user-facing Automatic vs Manual update-install preference, persist it
through /api/app-config, wire it into updater candidate selection, and add
clearer manual-install copy for the DMG/installer case.

- daemon: `updateInstallMode` config field (enum-validated, defaults to
  automatic; reachable via `od config set updateInstallMode manual`).
- desktop: lazy-read the pref at check time and force installer/DMG selection
  when manual; `readUpdateInstallMode` helper wired into createDesktopUpdater.
- web: Settings toggle (gated on canApplyInPlace), `requiresManualInstall`
  surfaced on UpdaterModel, and a manual-install copy branch in UpdaterPopup.
- i18n: new updater/settings keys across all locales.

Fix the dead manual-install copy branch: capabilitiesFor couples
canOpenInstaller and requiresManualInstall, so `requiresManualInstall &&
!canOpenInstaller` was always false and the manual-install copy never
rendered. Gate on requiresManualInstall alone. The frozen test now uses the
real capability combo capabilitiesFor emits (canOpenInstaller: true) instead
of an impossible one that masked the bug.

Note: this is cross-platform PR1. macOS-native end-to-end acceptance
(payload extraction, DMG drag-install, signed-bundle identity) defers to PR2.

Fixes nexu-io#4467
@cbeaulieu-gt
cbeaulieu-gt requested a review from a team as a code owner June 19, 2026 00:33
@lefarcen

Copy link
Copy Markdown
Contributor

Hi @cbeaulieu-gt! The PR body here is very easy to follow — the PR1/PR2 split and the updater UX tradeoff are laid out clearly.

I've queued the reviewer routing and the follow-up checks this change needs on our side.

💡 To drive this PR to merge hands-free, paste this to your AI coding agent (Claude Code / Codex / opencode / Cursor …):
Take over nexu-io/open-design#4543 until it merges — read https://raw.githubusercontent.com/nexu-io/looper/main/skills/pr-takeover/SKILL.md and follow it.

@lefarcen lefarcen added size/XL PR changes 700-1500 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/feature New feature needs-validation Runtime change detected; needs human or /explore agent validation. labels Jun 19, 2026
@lefarcen

Copy link
Copy Markdown
Contributor

🧪 This PR has changes that need a manual QA pass before merge — please hold off self-merging for now; we'll loop QA in once it's merge-ready (and design/product have signed off, where applicable).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92509be316

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/daemon/src/app-config.ts

@PerishCode PerishCode left a comment

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.

I found two blockers in the install-mode wiring that need to be fixed before this can satisfy #4467: the new app-config field is not part of the shared contract/config sync path, and the Settings control is hidden unless the current selected update artifact is already a payload.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/daemon/src/app-config.ts
Comment thread apps/web/src/components/SettingsDialog.tsx Outdated
@lefarcen

Copy link
Copy Markdown
Contributor

Hey @cbeaulieu-gt — following up on the review loop here: @PerishCode's blocking review covers the two changes that need to land on this head before this can move forward.

The current blockers are:

  • wiring updateInstallMode through the shared app-config contract + normal web config sync path, and
  • making the Settings preference visible from a stable payload-capable runtime signal instead of the currently selected artifact state.

Once those are addressed, the product/design/QA routing that's already queued on this PR can continue from there.

… gate (nexu-io#4543)

Resolves the two blockers from PerishCode's review on nexu-io#4543:

- Contract/sync: add `updateInstallMode` to the shared `AppConfigPrefs`
  (packages/contracts), merge it from daemon config in `mergeDaemonConfig`,
  and include it in `syncConfigToDaemon`. Previously the field lived only on
  the daemon-local shape and the Settings dialog's direct PUT, so the normal
  web merge/sync path dropped it — leaving the toggle and the daemon updater
  able to disagree after a daemon-hydrated load.

- Toggle visibility: gate the Settings "Update install mode" control on a new
  artifact-independent `payloadCapable` signal (derived in `deriveUpdaterModel`
  as host + supported + package-launcher) instead of `canApplyInPlace`.
  `canApplyInPlace` is artifact-aware and false until a payload candidate is
  selected, which hid the preference exactly when the user wants to opt out of
  payload updates before one is picked.

Tests: contract/sync round-trip in web config-state tests; SettingsDialog
visibility on idle and installer-pending payload-capable runtimes (toggle
shown) vs non-package-launcher runtimes (hidden).

@PerishCode PerishCode left a comment

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.

I found one remaining blocker in the install-mode config surface: the new preference can be set, but the advertised CLI unset path does not actually clear the stored value.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/daemon/src/app-config.ts
@lefarcen

Copy link
Copy Markdown
Contributor

Hey @cbeaulieu-gt — quick follow-up on the new head: @PerishCode has narrowed this down to one remaining blocker on the current commit.

The remaining item is the advertised od config unset updateInstallMode path: the field can now be set and round-tripped, but the generic merge-style config update still needs to actually clear the stored value when the CLI unset flow runs.

Once that unset path is fixed on this head, the review can move forward from there.

…nexu-io#4543)

Addresses PerishCode's third review blocker on nexu-io#4543. `od config unset
<key>` deleted the key client-side then PUT the remaining object, but the
daemon's writeAppConfig is merge-style (only applies keys present in the
body), so the stored value survived — `od config unset updateInstallMode`
could not return to the documented unset⇒automatic state.

Send `{ ...cfg, [key]: null }` instead of omitting the key, matching the
daemon's merge-patch + null-clears convention (applyConfigValue already
deletes updateInstallMode on null; existing writeAppConfig({ agentId: null })
behaviour relies on the same idiom).

Regression test exercises the real CLI unset path against a stub daemon and
asserts the PUT body carries `{ updateInstallMode: null }`.

@PerishCode PerishCode left a comment

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.

I found one remaining blocker in the install-mode config merge path: clearing the preference through the CLI can still be undone by the web app's persisted local state.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/web/src/state/config.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 234b70ae66

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4760 to +4765
setCfg((prev) => ({ ...prev, updateInstallMode: mode }));
await fetch('/api/app-config', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ updateInstallMode: mode }),
}).catch(() => {/* best-effort */});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reconcile pending payload when switching to manual

When a payload update has already been selected or downloaded, changing this setting to manual only updates React state and writes the daemon config. The desktop updater reads updateInstallMode only during checkForCandidate, while installUpdate still applies the current activeRelease, so a user who switches to Manual after an automatic payload download can still click the existing update prompt and get the in-place payload relaunch instead of the installer path. Please trigger/reconcile a new updater selection here, clear the active payload, or make install re-check the preference before applying a payload.

Useful? React with 👍 / 👎.

@lefarcen

Copy link
Copy Markdown
Contributor

Hey @cbeaulieu-gt — one more follow-up on the latest head: @PerishCode has reduced the current review to a single remaining blocker in the config merge path.

The remaining issue is that clearing updateInstallMode via the CLI can still be reintroduced by stale web local state during bootstrap, so the absent/unset ⇒ automatic behavior needs to win when the daemon omits this field.

Once that local-state merge case is fixed on this head, the review can move forward from there.

mergeDaemonConfig preserved the local updateInstallMode when the daemon
config omitted the field, so a browser holding 'manual' in localStorage
kept it. App.tsx bootstrap then re-synced that stale value back to the
daemon, undoing `od config unset updateInstallMode` and breaking the
absent/unset => automatic contract.

Treat omission from a present daemon config as a clear: the daemon is
authoritative for this key. Flip the merge round-trip test to assert the
local manual value is removed when the daemon omits the field.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@PerishCode PerishCode left a comment

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.

I found one blocker in the install-mode lifecycle: switching to Manual after a payload is already downloaded can still apply the payload instead of moving the user back to the installer path.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/desktop/src/main/updater.ts Outdated
@lefarcen

Copy link
Copy Markdown
Contributor

Hey @cbeaulieu-gt — another quick follow-up on the latest head: @PerishCode has the review narrowed to one remaining lifecycle blocker on this commit.

The remaining issue is the Manual-mode switch after a payload is already downloaded: changing the preference in Settings still needs to force the updater back onto the installer/manual path instead of letting an already-prepared payload continue through the in-place apply flow.

Once that downloaded-payload handoff is reconciled on this head, the review can continue from there.

@TheAngryPit

Copy link
Copy Markdown
Contributor

Hey @cbeaulieu-gt, @lefarcen, I picked up the remaining manual-mode lifecycle blocker from the latest review. I could not push directly to cbeaulieu-gt/open-design:feat/4467-update-install-mode from @TheAngryPit's auth because GitHub returned a 403, so I pushed the validated patch here instead:

What this patch changes:

  • re-checks updateInstallMode before applying an already downloaded payload
  • when the user has switched to Manual, reselects/downloads the installer path before continuing
  • preserves the existing downloaded payload if metadata/download fails during that reselection
  • avoids double-opening the installer when autoOpen already performed the manual install during reselection

Proof run locally:

  • pnpm --filter @open-design/desktop exec vitest run -c vitest.config.ts tests/main/updater-update-install-mode.test.ts --reporter=dot --maxWorkers=1 --pool=forks (6 passed)
  • pnpm --filter @open-design/desktop exec tsc -p tsconfig.json --noEmit
  • git diff --check
  • openclaw-autoreview --mode commit --commit HEAD with the focused Vitest command in parallel: clean, no accepted/actionable findings

Aegis, on behalf of @TheAngryPit

@lefarcen

Copy link
Copy Markdown
Contributor

Hey @TheAngryPit — thanks for doing the legwork on this and for dropping a validated branch/commit with the exact proof run. That’s very helpful.

@cbeaulieu-gt, the current blocker looks well-scoped to the patch linked above. If you cherry-pick or port 220ad4bd onto this PR branch, we can have the remaining manual-mode lifecycle issue re-checked on the current head from there.

@cbeaulieu-gt

Copy link
Copy Markdown
Contributor Author

Both review blockers on the latest head are addressed.

F1 — stale local state could undo the CLI unset (apps/web/src/state/config.ts)
mergeDaemonConfig now treats omission of updateInstallMode from a present daemon config as a clear, so od config unset updateInstallMode is no longer re-written by the bootstrap syncConfigToDaemon. The merge round-trip test was flipped to assert the local manual value is removed when the daemon omits the field. — commit 74daba287

F2 — switching to Manual after a payload was already downloaded (apps/desktop/src/main/updater.ts)
Ported from @TheAngryPit's branch (codex/4543-update-install-mode-fix, commit 220ad4bd) — thanks for the legwork and the proof run. installUpdate() now reconciles before applying: when the active release is a payload and the preference is manual, it reselects/downloads the installer path, preserves the downloaded payload if reselection fails, and avoids a double-open when autoOpen already performed the install during reselection. Cherry-picked with original authorship retained.

Verified locally on Windows:

  • pnpm --filter @open-design/desktop exec vitest run -c vitest.config.ts tests/main/updater-update-install-mode.test.ts — 6 passed
  • full @open-design/desktop suite — 141 passed, 2 skipped
  • tsc -p tsconfig.json --noEmit — clean

Current head: 5d0530b53. macOS-native end-to-end acceptance (real DMG drag-install) remains out of scope for this PR and is tracked by #4467.

🤖 Generated by Claude Code on behalf of @cbeaulieu-gt

@lefarcen

Copy link
Copy Markdown
Contributor

Hey @TheAngryPit — the part that still needed movement here wasn't another code change so much as the product call on whether the Manual path should ship at all.

This PR already had the Settings → About install-mode toggle, the clearer Open installer updater copy, and the daemon/CLI/API wiring in place; design sign-off landed on the same head, but the PR was then auto-closed while waiting on that last product-direction decision.

The most helpful next step is to carry the concrete user cases you outlined back into #4467 and ask whether the team wants to reopen this exact PR or take a smaller follow-up from there. If you and @cbeaulieu-gt still want to push it forward, that issue is the clean place to anchor the reopen / next-PR decision.

@lefarcen lefarcen reopened this Jun 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Closing this PR for now because it has been waiting on an author response for more than 5 days after reviewer or maintainer feedback.

This is only a queue-management step, not a rejection of the work. If you would like to continue, please leave a comment or push an update and reopen the PR when ready.

@github-actions github-actions Bot closed this Jun 27, 2026
@cbeaulieu-gt

Copy link
Copy Markdown
Contributor Author

Seriously actions-bot. It was just reopened.

@lefarcen

Copy link
Copy Markdown
Contributor

@cbeaulieu-gt You're right — that auto-close comment landed at the wrong moment.

The code-side review on 5d0530b5 had already cleared. The thing still blocking this work is the product call in #4467 on whether the manual install mode should ship at all, not a new review round from this thread.

If that decision lands positive, reopening this PR (or spinning the narrower follow-up from #4467) is still the right next step.

@lefarcen lefarcen reopened this Jun 29, 2026
@lefarcen lefarcen added the exempt-from-stale Issue is exempt from automatic stale handling (set by stale-issues workflow). label Jun 29, 2026
@lefarcen
lefarcen requested a review from 811634243-sketch July 2, 2026 08:53
@lefarcen lefarcen added the needs-product-review Feature PR awaiting product sign-off before merge (see roadmap) label Jul 2, 2026
@lefarcen
lefarcen requested a review from xiaoche-hub July 5, 2026 09:30
@lefarcen lefarcen removed the needs-product-review Feature PR awaiting product sign-off before merge (see roadmap) label Jul 5, 2026
@lefarcen
lefarcen requested a review from PerishCode July 5, 2026 09:34
@lefarcen lefarcen added size/XXL PR changes 1500+ lines and removed size/XL PR changes 700-1500 lines labels Jul 5, 2026
…all-mode

# Conflicts:
#	apps/web/src/i18n/locales/zh-CN.ts
#	apps/web/src/i18n/locales/zh-TW.ts
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Visual regression review

Head: c2c9f65 · Base: 50b38c4

⚠️ 1 case(s) failed during diff generation; partial captures are shown below.

0 changed · 0 unchanged · 0 new without baseline · 1 failed

Capture or diff failures

  • visual-capture: No PNG screenshots found in /home/runner/work/_temp/visual-combined/visual-screenshots. Check the Playwright capture logs for details.

Visual diff is advisory only and does not block merging.

@lefarcen

lefarcen commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@PerishCode This PR's current head c2c9f65 is waiting on your review.

@lefarcen
lefarcen removed the request for review from xiaoche-hub July 9, 2026 03:45
@lefarcen lefarcen added the needs-design-review Awaiting design review (external UI change); cleared by the Odcrew App applying design-approved label Jul 9, 2026
@open-design-crew open-design-crew Bot added the design-approved Design signed off (must be applied by the Odcrew App open-design-crew[bot]) label Jul 21, 2026
@lefarcen lefarcen removed the needs-design-review Awaiting design review (external UI change); cleared by the Odcrew App applying design-approved label Jul 21, 2026
reconcileManualModeBeforePayloadInstall only reselected the payload
path on Automatic->Manual. Switching Manual->Automatic after an
installer/DMG was already downloaded left installUpdate() opening the
stale installer until the next update check, per chatgpt-codex-connector
review on PR nexu-io#4543.

Renamed to reconcileInstallModeBeforeInstall and generalized the gate
to a symmetric mismatch check (wantsManual !== activeIsPayload) so
both directions reconcile. Added hasValidLauncherPayloadContext guard
on the new Automatic direction so an offline/no-launcher-context
install still falls back to the installer instead of forcing a network
reselect that could error.

Added regression test covering the Manual->Automatic reselect case.
@lefarcen

Copy link
Copy Markdown
Contributor

@PerishCode This PR's current head 217086d is waiting on your review.

cbeaulieu-gt and others added 2 commits July 28, 2026 20:37
# Conflicts:
#	apps/desktop/src/main/updater.ts
#	apps/web/src/components/SettingsDialog.tsx
#	apps/web/src/components/UpdaterPopup.tsx
#	apps/web/src/i18n/locales/ar.ts
#	apps/web/src/i18n/locales/de.ts
#	apps/web/src/i18n/locales/en.ts
#	apps/web/src/i18n/locales/es-ES.ts
#	apps/web/src/i18n/locales/fa.ts
#	apps/web/src/i18n/locales/fr.ts
#	apps/web/src/i18n/locales/hu.ts
#	apps/web/src/i18n/locales/id.ts
#	apps/web/src/i18n/locales/it.ts
#	apps/web/src/i18n/locales/ja.ts
#	apps/web/src/i18n/locales/ko.ts
#	apps/web/src/i18n/locales/pl.ts
#	apps/web/src/i18n/locales/pt-BR.ts
#	apps/web/src/i18n/locales/ru.ts
#	apps/web/src/i18n/locales/th.ts
#	apps/web/src/i18n/locales/tr.ts
#	apps/web/src/i18n/locales/uk.ts
#	apps/web/src/i18n/locales/zh-CN.ts
#	apps/web/src/i18n/locales/zh-TW.ts
#	apps/web/src/i18n/types.ts
#	apps/web/tests/components/UpdaterPopup.test.tsx
#	apps/web/tests/state/config.test.ts
Follow-up to the origin/main merge commit (9c52816): the hand-resolved
SettingsDialog.tsx carried forward a pre-existing duplicate import block
from '../lib/updater' (TS2300 duplicate identifiers under tsc -b), and
updater.ts's reconcileInstallModeBeforeInstall did not surface a failed
metadata reselect as an error, silently returning the stale downloaded
snapshot instead of the ERROR state the existing
updater-update-install-mode.test.ts test expects.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

design-approved Design signed off (must be applied by the Odcrew App open-design-crew[bot]) exempt-from-stale Issue is exempt from automatic stale handling (set by stale-issues workflow). needs-validation Runtime change detected; needs human or /explore agent validation. risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/XXL PR changes 1500+ lines type/feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve macOS update flow so payload updates are the default

4 participants