Skip to content

Commit 596394e

Browse files
committed
feat: migrate cmux UserDefaults keys → programa with one-time shim (Phase 6, UserDefaults)
Add a version-gated startup migration that copies every cmux-prefixed default to its programa-prefixed key (never deletes the legacy key), so no user preference is lost by the rebrand. Rename the standalone persisted keys (welcomeShown, surfacePoolEnabled, devMutate…, debugBG, focusDebug, keyLatencyProbe, shortcutMonitorTrace, typingTimingLogs, settingsFile.backups). Port keys (cmuxPortBase/Range) and socket-mode value (cmuxonly) deferred to their own contracts (shell-integration / socket-mode). Builds green.
1 parent 6d2b03b commit 596394e

6 files changed

Lines changed: 30 additions & 11 deletions

Sources/AppDelegate.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ enum ProgramaTypingTiming {
7979
return true
8080
}
8181
let defaults = UserDefaults.standard
82-
return defaults.bool(forKey: "cmuxTypingTimingLogs") || defaults.bool(forKey: "cmuxKeyLatencyProbe")
82+
return defaults.bool(forKey: "programaTypingTimingLogs") || defaults.bool(forKey: "programaKeyLatencyProbe")
8383
}()
8484
static let isVerboseProbeEnabled: Bool = {
8585
let environment = ProcessInfo.processInfo.environment
8686
if environment["PROGRAMA_KEY_LATENCY_PROBE"] == "1" {
8787
return true
8888
}
89-
return UserDefaults.standard.bool(forKey: "cmuxKeyLatencyProbe")
89+
return UserDefaults.standard.bool(forKey: "programaKeyLatencyProbe")
9090
}()
9191
private static let delayLogThresholdMs: Double = 6.0
9292
private static let durationLogThresholdMs: Double = 1.0
@@ -10359,7 +10359,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
1035910359
ProgramaTypingTiming.logEventDelay(path: "appMonitor", event: event)
1036010360
let shortcutMonitorTraceEnabled =
1036110361
ProcessInfo.processInfo.environment["PROGRAMA_SHORTCUT_MONITOR_TRACE"] == "1"
10362-
|| UserDefaults.standard.bool(forKey: "cmuxShortcutMonitorTrace")
10362+
|| UserDefaults.standard.bool(forKey: "programaShortcutMonitorTrace")
1036310363
if shortcutMonitorTraceEnabled {
1036410364
let frType = NSApp.keyWindow?.firstResponder.map { String(describing: type(of: $0)) } ?? "nil"
1036510365
dlog(

Sources/GhosttyTerminalView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,7 @@ class GhosttyApp {
13431343
if ProcessInfo.processInfo.environment["GHOSTTYTABS_DEBUG_BG"] == "1" {
13441344
return true
13451345
}
1346-
if UserDefaults.standard.bool(forKey: "cmuxDebugBG") {
1346+
if UserDefaults.standard.bool(forKey: "programaDebugBG") {
13471347
return true
13481348
}
13491349
return UserDefaults.standard.bool(forKey: "GhosttyTabsDebugBG")
@@ -4967,7 +4967,7 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
49674967
if ProcessInfo.processInfo.environment["PROGRAMA_FOCUS_DEBUG"] == "1" {
49684968
return true
49694969
}
4970-
return UserDefaults.standard.bool(forKey: "cmuxFocusDebug")
4970+
return UserDefaults.standard.bool(forKey: "programaFocusDebug")
49714971
}()
49724972
internal enum DropPlan: Equatable {
49734973
case insertText(String)
@@ -5104,7 +5104,7 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
51045104
if ProcessInfo.processInfo.environment["PROGRAMA_KEY_LATENCY_PROBE"] == "1" {
51055105
return true
51065106
}
5107-
return UserDefaults.standard.bool(forKey: "cmuxKeyLatencyProbe")
5107+
return UserDefaults.standard.bool(forKey: "programaKeyLatencyProbe")
51085108
}()
51095109
static var debugGhosttySurfaceKeyEventObserver: ((ghostty_input_key_s) -> Void)?
51105110
#endif

Sources/KeyboardShortcutSettingsFileStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ final class ProgramaSettingsFileStore {
2424
static let schemaURLString = "https://raw.githubusercontent.com/darkroomengineering/programa/main/Resources/settings.schema.json"
2525

2626
private static let releaseBundleIdentifier = "com.darkroom.programa"
27-
private static let backupsDefaultsKey = "cmux.settingsFile.backups.v1"
27+
private static let backupsDefaultsKey = "programa.settingsFile.backups.v1"
2828
fileprivate static let trustedDirectoriesBackupIdentifier = "customCommands.trustedDirectories"
2929
fileprivate static let socketPasswordBackupIdentifier = "automation.socketPassword"
3030

Sources/ProgramaApp.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,11 @@ struct cmuxApp: App {
171171
let startupAppearance = AppearanceSettings.resolvedMode()
172172
Self.applyAppearance(startupAppearance)
173173
_tabManager = StateObject(wrappedValue: TabManager())
174-
// Migrate legacy and old-format socket mode values to the new enum.
175174
let defaults = UserDefaults.standard
175+
// Rebrand: forward every legacy cmux-prefixed default to its programa key
176+
// before anything reads the new keys, so existing users keep their prefs.
177+
Self.migrateCmuxDefaultsToProgramaIfNeeded(defaults: defaults)
178+
// Migrate legacy and old-format socket mode values to the new enum.
176179
if let stored = defaults.string(forKey: SocketControlSettings.appStorageKey) {
177180
let migrated = SocketControlSettings.migrateMode(stored)
178181
if migrated.rawValue != stored {
@@ -268,6 +271,22 @@ struct cmuxApp: App {
268271
setenv(key, updated, 1)
269272
}
270273

274+
/// One-time rebrand migration: copy every `cmux`-prefixed UserDefaults value to
275+
/// the corresponding `programa`-prefixed key. Version-gated so it runs once, and
276+
/// never deletes the legacy keys (a downgrade still finds its old values).
277+
private static func migrateCmuxDefaultsToProgramaIfNeeded(defaults: UserDefaults) {
278+
let migrationKey = "programaDefaultsRebrandMigrationVersion"
279+
let targetVersion = 1
280+
guard defaults.integer(forKey: migrationKey) < targetVersion else { return }
281+
for (key, value) in defaults.dictionaryRepresentation() where key.hasPrefix("cmux") {
282+
let newKey = "programa" + key.dropFirst("cmux".count)
283+
if defaults.object(forKey: newKey) == nil {
284+
defaults.set(value, forKey: newKey)
285+
}
286+
}
287+
defaults.set(targetVersion, forKey: migrationKey)
288+
}
289+
271290
private func migrateSidebarAppearanceDefaultsIfNeeded(defaults: UserDefaults) {
272291
let migrationKey = "sidebarAppearanceDefaultsVersion"
273292
let targetVersion = 1
@@ -3828,7 +3847,7 @@ enum ClaudeCodeIntegrationSettings {
38283847
}
38293848

38303849
enum WelcomeSettings {
3831-
static let shownKey = "cmuxWelcomeShown"
3850+
static let shownKey = "programaWelcomeShown"
38323851
}
38333852

38343853
enum TelemetrySettings {

Sources/SurfacePool.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ final class SurfacePool {
3434

3535
/// Whether the pool is enabled. Reads user default, defaulting to true.
3636
var isEnabled: Bool {
37-
UserDefaults.standard.object(forKey: "cmuxSurfacePoolEnabled") as? Bool ?? true
37+
UserDefaults.standard.object(forKey: "programaSurfacePoolEnabled") as? Bool ?? true
3838
}
3939

4040
#if DEBUG

Sources/TabManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,7 @@ class TabManager: ObservableObject {
13261326
if let raw = env["PROGRAMA_DEV_MUTATE_WORKSPACE_SELECTION_DURING_CREATION"] {
13271327
return raw == "1" || raw.caseInsensitiveCompare("true") == .orderedSame
13281328
}
1329-
return UserDefaults.standard.bool(forKey: "cmuxDevMutateWorkspaceSelectionDuringCreation")
1329+
return UserDefaults.standard.bool(forKey: "programaDevMutateWorkspaceSelectionDuringCreation")
13301330
}()
13311331
guard isEnabled,
13321332
let selectedTabId = snapshot.selectedTabId,

0 commit comments

Comments
 (0)