fix(auto-update): autoDownload=true + manual-check toast gate (Greg's #314 follow-up)#327
Conversation
8829e04 to
c8a27dc
Compare
79123c1 to
fd53769
Compare
|
Rebased onto current main (was 37 behind) and marking ready for review. CI green across all three checks. This is the auto-download follow-up you flagged when merging #314: "I'll accept this to avoid the error conditions, but plan to move toward auto-download in the future." With #314's Squirrel.Mac proxy race fixed, One thing worth your call: auto-download now happens on metered connections too, since that is the electron-updater default we are returning to. If you would rather gate auto-download on a connection-type or settings check, I can add that, but I kept this PR to the minimal flag-flip + toast-gate you described. |
|
Putting this back to DRAFT after a closer look. With It is likely mitigated (electron-updater returns the in-flight download promise on a re-entrant |
fd53769 to
6f81c81
Compare
|
It feels like Check for Update should just do the download and show the restart now toast. I think we can just get rid of the Update Available toast. I'd like to keep the manual trigger to check for download as I use that in testing frequently. |
…nimbalyst#327) Per maintainer direction on nimbalyst#327: with autoDownload=true both background polls and the manual "Check for Updates" trigger download immediately and surface only the "Ready to install" toast. The "Update Available" toast is removed at the source (main no longer emits update-toast:show-available); the renderer listener for it is now dormant. The manual menu trigger is unchanged.
6f81c81 to
f57c0de
Compare
|
@ghinkle, I have implemented finally your direction. Rebased onto current main as a single commit, CI green. One scoping note: I removed the toast at the source (main no longer emits My appologies on the delayed response, due to speaking commitments this week. |
- Non-markdown shared documents (Excalidraw, Mindmap, Mockup, etc.) now show the unified editor header bar with breadcrumb, View History, and local-source actions (Open Local, Relink, Clear). - Editor header bar's "Shared to Team" dropdown now includes a link that jumps to the shared document, showing its name with the team-side folder path in subscript. - Shared documents have revision history: Cmd/Ctrl+S saves a named version, auto snapshots run after idle, and any past revision can be restored from the History dialog. - Custom shared-document editors can publish history controllers so the global History dialog can route to collaborative revisions. - Extensions SDK permissions and backend modules - Extension panels can run read-only SQL via `host.data.query()` against the local PGLite store when the manifest declares `nimbalyst-database-read` in `permissions.catalog`. - Backend-module allowlist: only built-in extensions, curated marketplace ids, and dev-installed extensions with `NIMBALYST_ALLOW_DEV_BACKEND_MODULES=1` can ship native-code backends. - Auto-update now downloads in the background and shows only the "Ready to install" toast; the redundant "Update Available" toast has been removed. (#327) - Extension docs now cover all four markdown/transcript contribution surfaces in both the internal architecture doc and the public SDK docs, including declarative module exports, diff handlers, transcript renderer hooks, and the current `@nimbalyst/runtime` import surface. - Backend-module consent prompt now leads with an explicit "this extension will run native code on your computer" banner; granular catalog ids only cover host-brokered services. - Catalog permission ids `spawn-process`, `network-loopback`, `network-internet`, and `filesystem` were unenforceable inside a Node backend (the module can `require('child_process')` directly) and are no longer accepted. Manifests that still list them load with a non-fatal warning; the ids are silently dropped when computing effective permissions. - CI `npm ci` no longer fails resolving `@nimbalyst/collab-adapters`; the workspace was missing from `package-lock.json` after the CollabContentAdapter commit. - Claude Code sessions now flip to "ready" the moment the model's turn finishes instead of sitting on the last output for up to 30 s while the SDK stdin grace period expired. - Claude Code sessions no longer reset mid-conversation when the agent spawns sub-agents. Sub-agent assistant chunks carry their own `session_id`; the transcript adapter was capturing that as the lead's, corrupting resume on the next turn. (#451, #456, #457) - Project quick open now loads recent projects from stored recents instead of crawling every workspace on open. - Rebuild Extensions submenu now lists buildable extensions alphabetically. - Shared Excalidraw and mockup tabs no longer come back blank after restart or close+reopen — the document type is now persisted with each open tab and recovered server-side as a backstop. - Tracker list, table, and kanban views now share the session-style `#tag` typeahead filter. - Session history search bar no longer overlaps floating popovers (e.g. Claude Usage). - Re-uploading a local source into a shared markdown document now waits for the collab write to be acknowledged before tearing down the headless sync client. - Codex session-naming reminder no longer leaks into the chat transcript; its turn output is tagged so the transcript hides it. (#420) - Mobile sync now picks up Codex sessions running in git worktrees by resolving worktree workspaceIds to the parent project path when matching against enabled sync projects. (#430) Thanks @stamkivi. - Claude Code plugins installed at the project scope (via `<workspace>/.claude/settings.json` `enabledPlugins`) now appear in the Installed plugins list when the panel is opened from a project's settings, with badges showing the marketplace source and whether the plugin is user- or project-scoped. - Slash-command typeahead now lists commands and skills from Claude CLI plugins (`~/.claude/plugins/`) without requiring the experimental "Agent Workflows" toggle, matching what the Claude Agent SDK auto-loads from `enabledPlugins`. - Excalidraw "import mermaid" now registers the rendered diagram image, so it no longer shows as a broken thumbnail. (#428) - Codex sessions now append actionable guidance when `~/.codex/config.toml` has a url-based MCP server the bundled Codex rejects, instead of an opaque config-load failure. (#424) - Dollar signs in markdown no longer collapse currency text like `$7M ... $40M` as inline LaTeX math; the typing-time `$...$` shortcut is removed in favor of slash-menu "Math (inline)" / "Math (block)" entries. Pasting or loading markdown that already contains `$x$` still renders as math. (#447) - Trackers panel now refetches when switching projects in the sidebar rail instead of staying pinned to the workspace that was active at app startup. (#441)
- Non-markdown shared documents (Excalidraw, Mindmap, Mockup, etc.) now show the unified editor header bar with breadcrumb, View History, and local-source actions. - Editor header bar's "Shared to Team" dropdown links to the shared document, showing its name with the team-side folder path in subscript. - Shared documents have revision history: Cmd/Ctrl+S saves a named version, auto snapshots run after idle, and any past revision can be restored. - Custom shared-document editors can publish history controllers so the global History dialog can route to collaborative revisions. - Extensions SDK permissions and backend modules. - Extension panels can run read-only SQL via `host.data.query()` against the local PGLite store when the manifest declares `nimbalyst-database-read`. - Backend-module allowlist: only built-in extensions, curated marketplace ids, and dev-installed extensions with `NIMBALYST_ALLOW_DEV_BACKEND_MODULES=1` can ship native-code backends. - Auto-update downloads in the background and shows only the "Ready to install" toast; the redundant "Update Available" toast is removed. (#327) - Extension docs now cover all four markdown/transcript contribution surfaces in both the internal architecture doc and the public SDK docs. - Backend-module consent prompt leads with an explicit "this extension will run native code on your computer" banner; granular catalog ids only cover host-brokered services. - Claude Code sessions break out of the SDK iterator after the `result` chunk so the binary's task-list reminder hook can't emit a 14+ minute `tool_result(Stream closed)` flood that pins sendMessage open. - Claude Code sessions flip to "ready" the moment the model's turn finishes instead of sitting on the last output for up to 30 s while the SDK stdin grace period expired. - Claude Code sessions no longer reset mid-conversation when the agent spawns sub-agents. (#451, #456, #457) - CI `npm ci` no longer fails resolving `@nimbalyst/collab-adapters`; the workspace was missing from `package-lock.json`. - Project quick open loads recent projects from stored recents instead of crawling every workspace on open. - Rebuild Extensions submenu lists buildable extensions alphabetically. - Shared Excalidraw and mockup tabs no longer come back blank after restart or close+reopen. - Tracker list, table, and kanban views share the session-style `#tag` typeahead filter. - Session history search bar no longer overlaps floating popovers (e.g. Claude Usage). - Re-uploading a local source into a shared markdown document waits for the collab write to be acknowledged before tearing down the headless sync client. - Codex session-naming reminder no longer leaks into the chat transcript. (#420) - Mobile sync picks up Codex sessions running in git worktrees by resolving worktree workspaceIds to the parent project path. (#430) Thanks @stamkivi. - Claude Code plugins installed at the project scope appear in the Installed plugins list with marketplace and scope badges. - Slash-command typeahead lists commands and skills from Claude CLI plugins without requiring the experimental "Agent Workflows" toggle. - Excalidraw "import mermaid" registers the rendered diagram image, so it no longer shows as a broken thumbnail. (#428) - Codex sessions append actionable guidance when `~/.codex/config.toml` has a url-based MCP server the bundled Codex rejects, instead of an opaque failure. (#424) - Dollar signs in markdown no longer collapse currency text like `$7M ... $40M` as inline LaTeX; the typing-time `$...$` shortcut is replaced by slash-menu "Math (inline)" / "Math (block)". (#447) - Trackers panel refetches when switching projects in the sidebar rail instead of staying pinned to the workspace that was active at app startup. (#441) - Catalog permission ids `spawn-process`, `network-loopback`, `network-internet`, and `filesystem` are no longer accepted; they were unenforceable inside a Node backend. Manifests listing them load with a non-fatal warning.
Summary
Follow-up to PR #314 (closed-merged 2026-05-15). Greg signed off there with:
This is that auto-download follow-up, marked DRAFT so it sits as an option you can pull in when ready rather than asking for review now.
What changes
Two-line behavioral change plus a small testable gate function:
autoUpdater.autoDownload = false->trueinAutoUpdaterServiceconstructor. With fix(updater): drop redundant checkForUpdates that tore down Squirrel.Mac proxy (#245) #314's Squirrel.Mac proxy race fixed, the safe-choice flag flips back to its electron-updater default.update-toast:show-availablesend inside theupdate-availableevent handler is now gated onwasManualCheck. Background-poll updates surface only the post-download "Ready to install" toast; the manual "Check for Updates" menu item still confirms the find before bytes start arriving.shouldShowAvailableToast(wasManualCheck)inautoUpdaterUtils.ts, same pattern as theclassifyUpdateErrorextraction from fix(updater): drop redundant checkForUpdates that tore down Squirrel.Mac proxy (#245) #314. Unit-tested without booting an Electron app global.Flow under the new policy
The renderer's
updateListeners.tsalready transitions'available' -> 'downloading'on the firstdownload-progressevent (line 113-118), so the manual-check toast does not get stuck on "click Download" while the bytes are already coming in.Tests
packages/electron/src/main/services/__tests__/autoUpdater.shouldShowAvailableToast.test.ts, 3 cases:Run locally, 3/3 pass. The existing
autoUpdater.classifyUpdateError.test.ts(8 cases) still passes unchanged.Why DRAFT
Two design questions I want to surface before this leaves DRAFT, both raised in my earlier reply on #314 that I never got to answer concretely:
1. Cancellation / retry hook if a newer release lands mid-download. electron-updater's internal state handles version-ahead detection on the next poll cycle automatically (4h interval), so a newer version landing during a silent download will be picked up. I did not add a separate hook because the existing poll loop covers it. Happy to add an explicit cancel-and-restart path inside
AutoUpdaterServiceif you'd rather not rely on the poll loop alone.2. The "Update Now" button on
UpdateAvailableToaston the manual-check path. WithautoDownload = true, when the user clicks "Check for Updates" and then clicks "Update Now" on the available toast, the toast button sendsupdate-toast:download->downloadUpdate()while electron-updater has already started the same download internally. electron-updater treats a repeatdownloadUpdate()call as a no-op (returns the in-flight promise), so the user sees the toast immediately transition to 'downloading' as the existing progress events arrive. No double-download, no error. If you'd prefer the manual-check available toast to skip the "Update Now" button entirely (since the download is already happening), I can wirestate === 'available' && autoDownloadInFlightto suppress the button inUpdateAvailableToast.tsx. That's a renderer-side polish so I left it out of this DRAFT.Test plan
npx vitest run packages/electron/src/main/services/__tests__/autoUpdater.shouldShowAvailableToast.test.ts(3/3)npx vitest run packages/electron/src/main/services/__tests__/autoUpdater.classifyUpdateError.test.ts(8/8 unchanged)npx tsc --noEmit -p packages/electron/tsconfig.jsonclean for the auto-update files (pre-existing lexical type errors inpackages/runtimeare upstream and unrelated)Refs #245 #314