@@ -22,6 +22,7 @@ enum UISmokeRunner {
2222
2323 @MainActor
2424 private static func run( ) async throws {
25+ cleanSmokeInstallPaths ( )
2526 try await testEmptyState ( )
2627 try await testSettingsLayout ( )
2728 try await testRegisterWizardValidation ( )
@@ -38,6 +39,7 @@ enum UISmokeRunner {
3839 try testManagedShellConfigurationCleanup ( )
3940 try await testContextActions ( )
4041 try await testManagementActions ( )
42+ try await testHealthyDaemonRetriesTransientSnapshotLoad ( )
4143 try await testUpdateChecking ( )
4244 try testAuditRelatedItemRouting ( )
4345 try await testActivationRefreshLoadsMissingSnapshot ( )
@@ -352,6 +354,7 @@ enum UISmokeRunner {
352354
353355 @MainActor
354356 private static func testDaemonUnavailableState( ) async throws {
357+ cleanSmokeInstallPaths ( )
355358 let store = ControlPlaneStore (
356359 client: ThrowingControlPlaneClient ( ) ,
357360 brokerController: StubBrokerStatusController ( statusValue: unavailableBrokerStatus ( ) )
@@ -640,7 +643,11 @@ enum UISmokeRunner {
640643 @MainActor
641644 private static func testBrokerInstallPlanState( ) async throws {
642645 let plan = smokeInstallPlan ( supported: true , missingExecutables: [ ] )
643- try ? FileManager . default. removeItem ( atPath: plan. prefixPath)
646+ let launchAgentPlist = LocalBrokerStatusController . launchAgentPlist ( plan: plan)
647+ try expect ( launchAgentPlist. contains ( " <string>--state-dir</string> " ) , " LaunchAgent passes explicit state directory to broker daemon " )
648+ try expect ( launchAgentPlist. contains ( " <string> \( plan. stateDirectoryPath) </string> " ) , " LaunchAgent state directory matches install plan " )
649+ cleanSmokeInstallPaths ( )
650+ defer { cleanSmokeInstallPaths ( ) }
644651 let installed = BrokerStatus (
645652 state: . unavailable,
646653 socketPath: plan. socketPath,
@@ -663,7 +670,6 @@ enum UISmokeRunner {
663670 try expect ( !store. canOpenInstalledApp, " installed app command is unavailable before the app copy exists " )
664671 await store. installOrRepairDaemon ( )
665672 try FileManager . default. createDirectory ( atPath: plan. appDestinationPath, withIntermediateDirectories: true )
666- defer { try ? FileManager . default. removeItem ( atPath: plan. prefixPath) }
667673 try expect ( store. brokerStatus. message. contains ( " Open the installed copy " ) , " install result explains installed-copy handoff " )
668674 try expect ( store. bestDaemonAction == . openInstalledApp, " installed-copy handoff highlights open installed copy as the next action " )
669675 try expect ( store. canOpenInstalledApp, " installed app command becomes available when the app copy exists " )
@@ -912,15 +918,16 @@ enum UISmokeRunner {
912918 updateChecker: StubAppUpdateChecker ( update: latest) ,
913919 updateIgnoreDefaults: ignoredDefaults
914920 )
921+ await store. refresh ( )
915922 await store. checkForUpdates ( manual: true )
916923 try expect ( store. availableUpdate == latest, " update checker stores available release " )
917924 try expect ( store. updateMenuTitle == " Update 9.0.0 " , " update menu title includes latest version " )
918925 try expect ( store. successMessage == " Agentic Secrets 9.0.0 is available " , " manual update check reports available release " )
919926 try verifyHostingLayout (
920- ContentView ( store: store) ,
927+ DetailView ( store: store) ,
921928 width: 1180 ,
922929 height: 760 ,
923- label: " content view with update button "
930+ label: " detail view with update feedback "
924931 )
925932 store. ignoreAvailableUpdate ( )
926933 try expect ( store. availableUpdate == nil , " noncritical update can be ignored " )
@@ -1023,6 +1030,21 @@ enum UISmokeRunner {
10231030 try expect ( store. brokerStatus. state == . healthy, " activation refresh keeps daemon status current after snapshot load " )
10241031 }
10251032
1033+ @MainActor
1034+ private static func testHealthyDaemonRetriesTransientSnapshotLoad( ) async throws {
1035+ let store = ControlPlaneStore (
1036+ client: FlakySnapshotControlPlaneClient (
1037+ transientFailuresBeforeSuccess: 2 ,
1038+ snapshot: snapshot ( cliNames: [ " hcloud " ] )
1039+ ) ,
1040+ brokerController: StubBrokerStatusController ( statusValue: healthyBrokerStatus ( ) )
1041+ )
1042+ await store. refresh ( )
1043+ try expect ( store. brokerStatus. state == . healthy, " transient snapshot retry starts from a healthy daemon " )
1044+ try expect ( store. snapshot? . cliRegistrations. first? . name == " hcloud " , " healthy daemon refresh retries transient snapshot IPC failures " )
1045+ try expect ( store. errorMessage == nil , " transient snapshot IPC recovery does not leave a stale error " )
1046+ }
1047+
10261048 @MainActor
10271049 private static func testSelectionSurvivesRefresh( ) async throws {
10281050 let first = snapshot ( cliNames: [ " hcloud " , " gh " ] )
@@ -1196,6 +1218,11 @@ enum UISmokeRunner {
11961218 currentAppIsInstalledCopy: false
11971219 )
11981220 }
1221+
1222+ private static func cleanSmokeInstallPaths( ) {
1223+ try ? FileManager . default. removeItem ( atPath: " /tmp/agentic-secrets-ui-smoke " )
1224+ try ? FileManager . default. removeItem ( atPath: " /tmp/agentic-secrets-ui-smoke-home " )
1225+ }
11991226}
12001227
12011228private enum SmokeError : Error , CustomStringConvertible {
@@ -1335,6 +1362,44 @@ private struct ThrowingControlPlaneClient: ControlPlaneClient {
13351362 func exportRedactedAuditJSON( ) async throws -> String { throw SmokeError . failed ( " unexpected audit " ) }
13361363}
13371364
1365+ private actor FlakySnapshotControlPlaneClient : ControlPlaneClient {
1366+ private var remainingFailures : Int
1367+ private let snapshot : ControlPlaneSnapshot
1368+
1369+ init ( transientFailuresBeforeSuccess: Int , snapshot: ControlPlaneSnapshot ) {
1370+ self . remainingFailures = transientFailuresBeforeSuccess
1371+ self . snapshot = snapshot
1372+ }
1373+
1374+ func health( ) async throws { }
1375+
1376+ func loadSnapshot( ) async throws -> ControlPlaneSnapshot {
1377+ if remainingFailures > 0 {
1378+ remainingFailures -= 1
1379+ throw SmokeError . failed ( " socket( \" connect: No such file or directory \" ) " )
1380+ }
1381+ return snapshot
1382+ }
1383+
1384+ func registerCLI( _ request: ControlPlaneCommandLineToolRegistrationRequest ) async throws -> CLIRegistrationSummary { throw SmokeError . failed ( " unexpected register " ) }
1385+ func unregisterCLI( _ request: ControlPlaneNameRequest ) async throws -> CLIRegistrationSummary { throw SmokeError . failed ( " unexpected unregister " ) }
1386+ func refreshCLITrust( _ request: ControlPlaneNameRequest ) async throws -> CLIRegistrationSummary { throw SmokeError . failed ( " unexpected refresh trust " ) }
1387+ func replaceSecret( _ request: ControlPlaneSecretReplacementRequest ) async throws -> ManagedSecretSummary { throw SmokeError . failed ( " unexpected replace " ) }
1388+ func deleteSecret( _ request: ControlPlaneSecretDeletionRequest ) async throws { throw SmokeError . failed ( " unexpected delete " ) }
1389+ func upsertAPISessionProfile( _ profile: APISessionProfile ) async throws -> APISessionProfileSummary { throw SmokeError . failed ( " unexpected proxy " ) }
1390+ func deleteAPISessionProfile( _ request: ControlPlaneNameRequest ) async throws { throw SmokeError . failed ( " unexpected proxy delete " ) }
1391+ func upsertMCPProfile( _ profile: MCPUpstreamProfile ) async throws -> MCPProfileSummary { throw SmokeError . failed ( " unexpected mcp " ) }
1392+ func deleteMCPProfile( _ request: ControlPlaneNameRequest ) async throws { throw SmokeError . failed ( " unexpected mcp delete " ) }
1393+ func upsertBitwardenBinding( _ binding: BitwardenSecretBinding ) async throws -> BitwardenBindingSummary { throw SmokeError . failed ( " unexpected bws " ) }
1394+ func deleteBitwardenBinding( _ request: ControlPlaneNameRequest ) async throws { throw SmokeError . failed ( " unexpected bws delete " ) }
1395+ func installAdapter( _ payload: CommandPolicyPackPayload ) async throws -> PolicyPackSummary { throw SmokeError . failed ( " unexpected adapter install " ) }
1396+ func revokeAdapter( _ request: ControlPlaneNameRequest ) async throws { throw SmokeError . failed ( " unexpected command policy pack revoke " ) }
1397+ func updateCommandPolicy( _ request: ControlPlaneCommandPolicyUpdateRequest ) async throws -> CommandPolicySummary { throw SmokeError . failed ( " unexpected command policy " ) }
1398+ func createAPISession( _ request: ControlPlaneAPISessionRequest ) async throws -> ControlPlaneAPISessionResponse { throw SmokeError . failed ( " unexpected API session " ) }
1399+ func clearDeliveryGrants( ) async throws { throw SmokeError . failed ( " unexpected grants " ) }
1400+ func exportRedactedAuditJSON( ) async throws -> String { throw SmokeError . failed ( " unexpected audit " ) }
1401+ }
1402+
13381403private struct StubAppUpdateChecker : AppUpdateChecking {
13391404 var update : AppUpdateRelease ?
13401405
0 commit comments