@@ -119,7 +119,7 @@ final class ConnectionStorage {
119119 color: connection. color,
120120 tagId: connection. tagId,
121121 groupId: connection. groupId,
122- isReadOnly : connection. isReadOnly ,
122+ safeModeLevel : connection. safeModeLevel ,
123123 aiPolicy: connection. aiPolicy,
124124 mongoReadPreference: connection. mongoReadPreference,
125125 mongoWriteConcern: connection. mongoWriteConcern,
@@ -362,8 +362,8 @@ private struct StoredConnection: Codable {
362362 let tagId : String ?
363363 let groupId : String ?
364364
365- // Read-only mode
366- let isReadOnly : Bool
365+ // Safe mode level
366+ let safeModeLevel : String
367367
368368 // AI policy
369369 let aiPolicy : String ?
@@ -407,8 +407,8 @@ private struct StoredConnection: Codable {
407407 self . tagId = connection. tagId? . uuidString
408408 self . groupId = connection. groupId? . uuidString
409409
410- // Read-only mode
411- self . isReadOnly = connection. isReadOnly
410+ // Safe mode level
411+ self . safeModeLevel = connection. safeModeLevel . rawValue
412412
413413 // AI policy
414414 self . aiPolicy = connection. aiPolicy? . rawValue
@@ -423,6 +423,48 @@ private struct StoredConnection: Codable {
423423 self . startupCommands = connection. startupCommands
424424 }
425425
426+ private enum CodingKeys : String , CodingKey {
427+ case id, name, host, port, database, username, type
428+ case sshEnabled, sshHost, sshPort, sshUsername, sshAuthMethod, sshPrivateKeyPath
429+ case sshUseSSHConfig, sshAgentSocketPath
430+ case sslMode, sslCaCertificatePath, sslClientCertificatePath, sslClientKeyPath
431+ case color, tagId, groupId
432+ case safeModeLevel
433+ case isReadOnly // Legacy key for migration reading only
434+ case aiPolicy, mssqlSchema, oracleServiceName, startupCommands
435+ }
436+
437+ func encode( to encoder: Encoder ) throws {
438+ var container = encoder. container ( keyedBy: CodingKeys . self)
439+ try container. encode ( id, forKey: . id)
440+ try container. encode ( name, forKey: . name)
441+ try container. encode ( host, forKey: . host)
442+ try container. encode ( port, forKey: . port)
443+ try container. encode ( database, forKey: . database)
444+ try container. encode ( username, forKey: . username)
445+ try container. encode ( type, forKey: . type)
446+ try container. encode ( sshEnabled, forKey: . sshEnabled)
447+ try container. encode ( sshHost, forKey: . sshHost)
448+ try container. encode ( sshPort, forKey: . sshPort)
449+ try container. encode ( sshUsername, forKey: . sshUsername)
450+ try container. encode ( sshAuthMethod, forKey: . sshAuthMethod)
451+ try container. encode ( sshPrivateKeyPath, forKey: . sshPrivateKeyPath)
452+ try container. encode ( sshUseSSHConfig, forKey: . sshUseSSHConfig)
453+ try container. encode ( sshAgentSocketPath, forKey: . sshAgentSocketPath)
454+ try container. encode ( sslMode, forKey: . sslMode)
455+ try container. encode ( sslCaCertificatePath, forKey: . sslCaCertificatePath)
456+ try container. encode ( sslClientCertificatePath, forKey: . sslClientCertificatePath)
457+ try container. encode ( sslClientKeyPath, forKey: . sslClientKeyPath)
458+ try container. encode ( color, forKey: . color)
459+ try container. encodeIfPresent ( tagId, forKey: . tagId)
460+ try container. encodeIfPresent ( groupId, forKey: . groupId)
461+ try container. encode ( safeModeLevel, forKey: . safeModeLevel)
462+ try container. encodeIfPresent ( aiPolicy, forKey: . aiPolicy)
463+ try container. encodeIfPresent ( mssqlSchema, forKey: . mssqlSchema)
464+ try container. encodeIfPresent ( oracleServiceName, forKey: . oracleServiceName)
465+ try container. encodeIfPresent ( startupCommands, forKey: . startupCommands)
466+ }
467+
426468 // Custom decoder to handle migration from old format
427469 init ( from decoder: Decoder ) throws {
428470 let container = try decoder. container ( keyedBy: CodingKeys . self)
@@ -456,7 +498,13 @@ private struct StoredConnection: Codable {
456498 color = try container. decodeIfPresent ( String . self, forKey: . color) ?? ConnectionColor . none. rawValue
457499 tagId = try container. decodeIfPresent ( String . self, forKey: . tagId)
458500 groupId = try container. decodeIfPresent ( String . self, forKey: . groupId)
459- isReadOnly = try container. decodeIfPresent ( Bool . self, forKey: . isReadOnly) ?? false
501+ // Migration: read new safeModeLevel first, fall back to old isReadOnly boolean
502+ if let levelString = try container. decodeIfPresent ( String . self, forKey: . safeModeLevel) {
503+ safeModeLevel = levelString
504+ } else {
505+ let wasReadOnly = try container. decodeIfPresent ( Bool . self, forKey: . isReadOnly) ?? false
506+ safeModeLevel = wasReadOnly ? SafeModeLevel . readOnly. rawValue : SafeModeLevel . silent. rawValue
507+ }
460508 aiPolicy = try container. decodeIfPresent ( String . self, forKey: . aiPolicy)
461509 mssqlSchema = try container. decodeIfPresent ( String . self, forKey: . mssqlSchema)
462510 oracleServiceName = try container. decodeIfPresent ( String . self, forKey: . oracleServiceName)
@@ -500,7 +548,7 @@ private struct StoredConnection: Codable {
500548 color: parsedColor,
501549 tagId: parsedTagId,
502550 groupId: parsedGroupId,
503- isReadOnly : isReadOnly ,
551+ safeModeLevel : SafeModeLevel ( rawValue : safeModeLevel ) ?? . silent ,
504552 aiPolicy: parsedAIPolicy,
505553 mssqlSchema: mssqlSchema,
506554 oracleServiceName: oracleServiceName,
0 commit comments