Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
613caed
Update Everything: one action updates the app, every machine's daemon…
teamleaderleo Oct 18, 2026
4ace32e
chore(next): PR autofix at 613caed1dc12
Oct 18, 2026
ad4e307
Update Everything: its three entry types are structs (namespace lint)
teamleaderleo Oct 18, 2026
b5d67a3
Merge remote-tracking branch 'origin/feat-cmux-next' into recut/updat…
teamleaderleo Oct 18, 2026
2fc1a2e
Update Everything: translate the catalog into all 21 languages
teamleaderleo Oct 18, 2026
64d4162
Merge remote-tracking branch 'origin/feat-cmux-next' into recut/updat…
teamleaderleo Oct 19, 2026
1683682
Merge remote-tracking branch 'origin/feat-cmux-next' into codex/cx-1m…
teamleaderleo Oct 19, 2026
90889de
chore(next): PR autofix at 168368272e98
Oct 19, 2026
b77f2d8
Merge remote-tracking branch 'origin/feat-cmux-next' into codex/cx-1m…
teamleaderleo Oct 19, 2026
77dd4d1
chore(next): regenerate ci-target-graph.json
teamleaderleo Oct 19, 2026
5976f56
chore(next): PR autofix at 77dd4d17f2bd
Oct 19, 2026
282c136
Merge origin/feat-cmux-next into codex/cx-1mbnu-update-everything
teamleaderleo Oct 19, 2026
3ece2c8
test(next): Update Everything relaunch, deferred daemons and launch-c…
teamleaderleo Oct 19, 2026
e355e58
fix(next): Update Everything finishes only after a real relaunch, onc…
teamleaderleo Oct 19, 2026
1e5d6c1
test(next): Update Everything run expects devbox after the relaunch; …
teamleaderleo Oct 19, 2026
59acaf8
Merge origin/feat-cmux-next into codex/cx-1mbnu-update-everything
teamleaderleo Oct 19, 2026
ca42462
Merge origin/feat-cmux-next into codex/cx-1mbnu-update-everything
teamleaderleo Oct 20, 2026
a1d58df
Merge origin/feat-cmux-next into codex/cx-1mbnu-update-everything
teamleaderleo Oct 20, 2026
9471ca7
Merge origin/feat-cmux-next into codex/cx-1mbnu-update-everything
teamleaderleo Oct 20, 2026
98e400f
Merge origin/feat-cmux-next into codex/cx-1mbnu-update-everything
teamleaderleo Oct 20, 2026
d542db0
chore(next): PR autofix at 98e400f4b1b7
Oct 20, 2026
6c76066
Merge feat-cmux-next into codex/cx-1mbnu-update-everything
teamleaderleo Oct 21, 2026
1f102c9
fix(cmux-next): keep SettingsActionCatalog under its god-file size; i…
teamleaderleo Oct 21, 2026
7bf44b0
Merge remote-tracking branch 'origin/feat-cmux-next' into orphan-20940
teamleaderleo Oct 21, 2026
8e71df2
chore(cmux-next): regenerate ci-target-graph.json on the merged head
teamleaderleo Oct 21, 2026
5d16013
chore(cmux-next): take base's action exports; the PR autofix regenera…
teamleaderleo Oct 21, 2026
2484b62
Merge remote-tracking branch 'origin/feat-cmux-next' into adopt-20940
teamleaderleo Oct 21, 2026
38c7577
Update Everything: paired servers stay out by default; updates.update…
teamleaderleo Oct 21, 2026
6bc856b
Update Everything: debug.update_everything and a tour capture its con…
teamleaderleo Oct 21, 2026
63f61d2
ci-target-graph.json: take base's copy; only the base autofix writes it
teamleaderleo Oct 21, 2026
eca67ca
Merge remote-tracking branch 'origin/feat-cmux-next' into adopt-20940
teamleaderleo Oct 21, 2026
103bbec
Merge remote-tracking branch 'origin/feat-cmux-next' into adopt-20940
teamleaderleo Oct 21, 2026
7a2dbd6
chore(next): settings and action exports from PR autofix run 39602257463
teamleaderleo Oct 21, 2026
c242dc8
Merge remote-tracking branch 'origin/feat-cmux-next' into adopt-20940
teamleaderleo Oct 21, 2026
59ae151
fix(next updates): the relaunched app finishes only the machines the …
teamleaderleo Oct 21, 2026
9dd5810
Merge remote-tracking branch 'origin/feat-cmux-next' into adopt-20940
teamleaderleo Oct 21, 2026
4ce25c6
Regenerate generated files from the PR autofix (run 39651226919)
teamleaderleo Oct 21, 2026
897eac6
Merge remote-tracking branch 'origin/feat-cmux-next' into adopt-20940
teamleaderleo Oct 21, 2026
395a5e1
Regenerate generated files from the PR autofix (run 39661203445)
teamleaderleo Oct 21, 2026
78eaf08
Give updates.updateEverythingServers an agent policy (user only)
teamleaderleo Oct 22, 2026
d63c78b
Merge feat-cmux-next (eb423e12) into Update Everything
teamleaderleo Oct 22, 2026
15a20a7
Merge feat-cmux-next (47ae435f) into Update Everything
teamleaderleo Oct 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Packages/macOS/CmuxNext/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ let package = Package(
"CmuxNextMobile",
"CmuxNextMobileHost",
"CmuxNextUpdater",
"CmuxNextUpdateEverything",
"CmuxNextWebUpdates",
"CmuxNextResources",
"CmuxNextBrowserImport",
Expand Down Expand Up @@ -1061,6 +1062,15 @@ let package = Package(
],
swiftSettings: uiSwiftSettings
),
// Update Everything (cx-1mbnu) and the app's update actions: the plan, confirmation,
// runner, relaunch note, daemon reads and agent CLI steps over an injected
// UpdateEverythingHost (kept out of CmuxNextApp's size cap).
.target(
name: "CmuxNextUpdateEverything",
dependencies: ["CmuxNextActions", "CmuxNextCompat", "CmuxNextDaemon", "CmuxNextDaemonService", "CmuxNextDesign", "CmuxNextRemote", "CmuxNextUpdater"],
resources: [.process("Resources/Localizable.xcstrings")],
swiftSettings: uiSwiftSettings
),
// Web updates in the app (plans/cmux-next/web-ota.md): serves a signed web update from
// a safe point and answers `updates.web.*`.
.target(
Expand Down Expand Up @@ -1447,6 +1457,7 @@ let package = Package(
"CmuxNextTabs",
"CmuxNextTasks",
"CmuxNextTerminalGeometry",
"CmuxNextUpdateEverything",
"CmuxNextVSCodeServer",
"CmuxNextWakeups",
"CmuxNextWorkspaceNaming",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,137 @@
{
"sourceLanguage": "en",
"strings": {
"action.updates.updateEverything": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Update Everything…"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Alles aktualisieren …"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Tout mettre à jour…"
}
},
"ar": {
"stringUnit": {
"state": "translated",
"value": "تحديث كل شيء…"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Actualizar todo…"
}
},
"zh-Hant": {
"stringUnit": {
"state": "translated",
"value": "全部更新…"
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "全部更新…"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "모두 업데이트…"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "すべてをアップデート…"
}
},
"bs": {
"stringUnit": {
"state": "translated",
"value": "Ažuriraj sve…"
}
},
"da": {
"stringUnit": {
"state": "translated",
"value": "Opdater alt…"
}
},
"it": {
"stringUnit": {
"state": "translated",
"value": "Aggiorna tutto…"
}
},
"km": {
"stringUnit": {
"state": "translated",
"value": "ធ្វើបច្ចុប្បន្នភាពទាំងអស់…"
}
},
"nb": {
"stringUnit": {
"state": "translated",
"value": "Oppdater alt …"
}
},
"pl": {
"stringUnit": {
"state": "translated",
"value": "Zaktualizuj wszystko…"
}
},
"pt-BR": {
"stringUnit": {
"state": "translated",
"value": "Atualizar Tudo…"
}
},
"ru": {
"stringUnit": {
"state": "translated",
"value": "Обновить всё…"
}
},
"th": {
"stringUnit": {
"state": "translated",
"value": "อัปเดตทั้งหมด…"
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Her Şeyi Güncelle…"
}
},
"uk": {
"stringUnit": {
"state": "translated",
"value": "Оновити все…"
}
},
"vi": {
"stringUnit": {
"state": "translated",
"value": "Cập nhật tất cả…"
}
}
}
},
"palette.family.workspace.move": {
"extractionState": "manual",
"localizations": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ nonisolated extension ActionSurfaceCatalog {
"palette.toggleFullWidthTab", "tab.showResources", "workspace.showResources",
"toggleBrowserDeveloperTools", "showBrowserJavaScriptConsole", "inspectBrowserElement", "browserPrint",
"toggleBrowserFocusMode", "toggleBrowserDesignMode", "toggleReactGrab", "palette.browserToggleOmnibar",
"importFromBrowser", "password.importCSV", "browser.importFromFiles", "browser.allowAgentWithExtensions", "browserProfile.delete", "openLinkInDefaultBrowser", "filePreviewOpenWith", "filePreviewOpenExternally",
"importFromBrowser", "password.importCSV", "browser.importFromFiles", "browser.allowAgentWithExtensions", "browserProfile.delete", "updates.updateEverything", "openLinkInDefaultBrowser", "filePreviewOpenWith", "filePreviewOpenExternally",
"filePreviewRevealInFinder", "filePreviewRevealInFiles", "palette.vscodeServeWebStop", "palette.vscodeServeWebRestart",
"browser.pageInfo", "browser.pageInfo.connection", "browser.pageInfo.certificate",
"browser.pageInfo.cookies", "browser.pageInfo.manageSiteData", "browser.pageInfo.siteSettings",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ nonisolated extension ActionSurfaceCatalog {
"palette.openGhosttySettings", "ghostty.showDiagnostics", "palette.makeDefaultBrowser", "palette.makeDefaultTerminal",
"palette.toggleSetting", "palette.shortcutKeymap", "palette.searchShortcuts", "palette.installCLI",
"palette.uninstallCLI", "palette.restartSocketListener", "palette.restartServer", "palette.checkForUpdates", "updates.whatsNew", "announcements.show", "announcements.hide",
"palette.applyUpdateIfAvailable", "palette.switchAppChannel", "updates.rollback", "palette.pro.upgrade",
"palette.applyUpdateIfAvailable", "palette.switchAppChannel", "updates.rollback", "palette.pro.upgrade", "updates.updateEverything",
"sendFeedback", "help.featureFlags", "help.documentation", "help.showCrashLogs",
"appearance.density.compact", "appearance.density.comfortable", "appearance.density.ultraCompact", "appearance.density.cozy", "appearance.density.spacious", "appearance.density.set", "appearance.density.create", "appearance.animationSpeed.fast",
"appearance.animationSpeed.normal", "appearance.animationSpeed.off", "appearance.animations.newTab.toggle", "appearance.animations.newWorkspace.toggle", "appearance.animations.bounce.subtle", "appearance.animations.bounce.none", "appearance.animations.toggle", "appearance.animations.sidebar.toggle", "appearance.animations.tabs.toggle", "appearance.animations.panes.toggle", "appearance.animations.overlays.toggle", "appearance.animations.hoverCards.toggle", "appearance.animations.home.toggle", "appearance.animations.cursor.toggle", "appearance.animations.indicators.toggle", "appearance.animations.feedback.toggle", "appearance.animations.web.toggle",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
nonisolated extension SettingsActionCatalog {
/// Update Everything (cx-1mbnu): the app, every connected machine's cmux and agent CLIs, then
/// the threads. Only a person starts it: it restarts daemons, agents and the app.
static var updateEverything: ActionDescriptor {
var descriptor = ActionDescriptor(
id: "updates.updateEverything",
title: String(localized: "action.updates.updateEverything", defaultValue: "Update Everything…", bundle: .module),
keywords: ["update", "upgrade", "machines", "agents", "claude", "codex", "daemon", "sparkle"], category: .settings,
symbol: "arrow.triangle.2.circlepath.circle", surfaces: [.palette, .menu], mainMenu: .app
)
descriptor.isPersonOnly = true
return descriptor
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ nonisolated enum SettingsActionCatalog: ActionCatalogGroup {
title: String(localized: "action.palette.applyUpdateIfAvailable", defaultValue: "Install Available Update", bundle: .module),
keywords: ["update", "install"], category: .settings, symbol: "arrow.down.circle.fill",
surfaces: [.palette, .menu], cliName: "settings install-available-update", mainMenu: .app
),
), updateEverything, // SettingsActionCatalog+UpdateEverything.swift
ActionDescriptor(
id: "palette.attemptUpdate",
title: String(localized: "action.palette.attemptUpdate", defaultValue: "Attempt Update", bundle: .module),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ nonisolated struct CloudMoveCLI: Sendable {
}

/// `cmux link machine update`: updates the cmux-tui of the machine whose daemon `socket`
/// reaches to this app's own pinned build, when that machine is outdated (cx-rppd.13).
func machineUpdate(socket: String) async throws -> Answer {
try await run(["link", "machine", "update", "--socket", socket], timeout: max(timeout, Self.machineUpdateTimeout))
/// reaches to this app's own pinned build, when that machine is outdated (cx-rppd.13), or with `toBundled` whenever its build differs (cx-1mbnu).
func machineUpdate(socket: String, toBundled: Bool = false) async throws -> Answer {
try await run(["link", "machine", "update", "--socket", socket] + (toBundled ? ["--to-bundled"] : []), timeout: max(timeout, Self.machineUpdateTimeout))
}

/// Longer than `link machine update`'s own wait for the machine (25 minutes) plus a first download.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Foundation
import AppKit
import CmuxNextBridge
import CmuxNextSidebar
import CmuxNextUpdateEverything
import WebKit
#endif

Expand Down Expand Up @@ -136,6 +137,20 @@ extension AppControl {
throw ControlError.invalidParams("debug.update_surfaces: unknown action \(action)")
}
},
// `debug.update_everything {action}`: Update Everything's surfaces with a fixed plan, for
// captures. "confirm" (default) opens its confirmation, "progress" its progress toast.
// Nothing updates.
.mainActor("debug.update_everything") { [weak services = appServices] call in
guard let window = services?.windows.active?.window else {
throw ControlError.invalidParams("debug.update_everything: no active window")
}
switch call.params["action"]?.stringValue ?? "confirm" {
case "confirm": UpdateEverythingPreview.confirm(in: window)
case "progress": UpdateEverythingPreview.progress(in: window)
case let action: throw ControlError.invalidParams("debug.update_everything: unknown action \(action)")
}
return .value(.null)
},
.mainActor("debug.update_indicator") { call in
updater.debugIndicatorPhase = UpdateIndicatorPhase(debugParams: call.params)
return .value(.object(["phase": .string(String(describing: updater.indicatorPhase))]))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AppKit
import CmuxNextActions
import CmuxNextSettings
import CmuxNextTerminal
import CmuxNextUpdateEverything
import os

/// Settings and help actions (category `settings`, except appearance, see
Expand Down Expand Up @@ -39,6 +40,7 @@ enum SettingsHandlers {
UpdateHandlers.bind(into: registry, updater: context.services.updater,
openWhatsNew: { [weak services = context.services] in services.map { WhatsNewPage.open($0) } ?? false },
stateDirectories: { [weak services = context.services] in services?.environment.daemonStateDirectories ?? [nil] })
UpdateEverything.bind(into: registry, host: .app(context.services))
OnboardingHandlers.bind(into: registry, context: context)
CLIInstallHandlers.bind(into: registry, context: context)
KeymapHandlers.bind(into: registry, context: context)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import AppKit
import CmuxNextDaemonService
import CmuxNextUpdateEverything

extension UpdateEverythingHost {
/// Update Everything over the App's services (cx-1mbnu); the rest lives in its module.
static func app(_ services: AppServices) -> Self {
let machines = services.machines
return Self(local: { machines.local }, remotes: {
var targets: [UpdateEverythingDaemon.Target] = machines.ssh.filter { $0.daemon.connection != nil }.map { ($0.machineID, $0.host.label, .ssh, $0.daemon) }
targets += machines.cloud.filter { $0.daemon.connection != nil }.map { ($0.machineID, $0.machine.title, .cloud, $0.daemon) }
// A paired server's cmux belongs to its installer and the server may be shared: off by default.
if services.settings?.snapshot.updates.updateEverythingServers == true {
targets += machines.servers.filter { $0.daemon.connection != nil }.map { ($0.machineID, $0.name, .server, $0.daemon) }
}
return targets
}, daemon: { machines.anyDaemon(machine: $0) }, installSSH: { id in
guard let session = machines.sshSession(id) else { throw ActionFailure(message: UpdateEverythingMachine.disconnected) }
try await services.ssh.install(session)
}, updateCloud: { socket in
// Gated like SSH's install: turned off by the organization (or no managed team) refuses.
if let refusal = services.cloud.unavailableReason { throw ActionFailure(message: refusal) }
guard let binary = services.cloud.move.cli else { throw ActionFailure(message: UpdateEverythingMachine.disconnected) }
let answer = try await CloudMoveCLI(binary: binary).machineUpdate(socket: socket, toBundled: true)
if !answer.ok { throw ActionFailure(message: UpdateEverythingMachine.failureText(answer.error)) }
return answer.updated
}, updater: services.updater, appVersion: Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String,
window: { services.windows.active?.window ?? NSApp.mainWindow },
journal: UpdateEverythingDaemon.journalURL(bundleID: services.environment.launch.bundleID))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ public struct DaemonCapabilities: Sendable {
/// Read-only observation of a remote agent session. An observer never falls back to the
/// writable attach capability (`cmux-tui/spec/commands.md`, `agent-session-observe`).
public let agentSessionObserve = "agent-session-observe-v1"
/// `agent-update-plan` / `agent-update-apply`: a machine's outdated agent CLIs, their update and
/// its chats' restart on them (Update Everything, cmux-tui/spec/commands.md "Agent CLI updates").
public let agentUpdate = "agent-update-v1"
/// `agent-session-start`: the session daemon starts a new chat for one of its agent tabs in
/// its own machine's acpmux (policy `ask`) and binds it (cmux-tui/spec/commands.md
/// "agent-session-start"). A chat in a remote workspace starts only through it; without it
Expand Down Expand Up @@ -472,7 +475,7 @@ public struct DaemonCapabilities: Sendable {
terminalCommandHistory, dockColumns, edgeDocks, dockColumnRole, pinnedDock, pinnedDockAlone, rows, columnMove, tabColumnRespawn, endTerminalsKeepLayout, stateResources,
sessionIdentity, localConversations, conversationDraftEvents, chiefLive, cloudChiefLive, conversationRuns, cloudConversationRuns, cloudConversationTyping, tabSplitRespawn, tabSplitKeepFocus, workspaceCreateFocus, frontendBrowserHistory, frontendBrowserTabProfile,
attachIdentity, creationReceipts, creationAttemptKeys, terminalColorOverrides,
workspaceKind, workspaceAgentFolder, workspaceAgentStart, conversationTabs, agentSessionTabs, agentSessionAttach, agentSessionObserve, agentSessionStart, agentSessionStartKeyedReason, agentSessionTrust, agentSessionChildren, pageTabs, pageTabRoute, windowRecords, appScreens, conversationSearch, conversationThreads, conversationThread, conversationInboxState, homeInbox, chiefEvents, cloudConversations, cloudHostReplica, cloudAttachments, cloudSelfHost, pageCredential, scopedPageCredential, wsListen, wsListenOrigins, localAttachments,
workspaceKind, workspaceAgentFolder, workspaceAgentStart, conversationTabs, agentSessionTabs, agentSessionAttach, agentSessionObserve, agentSessionStart, agentSessionStartKeyedReason, agentSessionTrust, agentSessionChildren, agentUpdate, pageTabs, pageTabRoute, windowRecords, appScreens, conversationSearch, conversationThreads, conversationThread, conversationInboxState, homeInbox, chiefEvents, cloudConversations, cloudHostReplica, cloudAttachments, cloudSelfHost, pageCredential, scopedPageCredential, wsListen, wsListenOrigins, localAttachments,
tabWorkspaceName, terminalSnapshotHistory, terminalSnapshotLocalHistory, terminalSnapshotImages,
terminalClipboardRead, personalMixedOrder, sidebarLayout, sidebarDoc, placementShift, paletteUsage, browserDevices, browserFit, browserFitWidth, projectList, splitClientKeys, splitClientSplitID, conversationTabSplit, terminalInputWhileCreating,
workspaceGroupIcon, workspaceGroupPin, screenGroupIcon, tabGroupIcon, sessionIcon, chiefInspect, feedLocalOwner, remoteTerminalTabs, detachedTerminals, tabRestart, tabRestartKeptLayout, tabPark,
Expand Down
Loading