diff --git a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift index 272fd81c11d..5328a5b692f 100644 --- a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift @@ -103,18 +103,22 @@ public final class OpenClawChatViewModel { let now = Date().timeIntervalSince1970 * 1000 let cutoff = now - (24 * 60 * 60 * 1000) let sorted = self.sessions.sorted { ($0.updatedAt ?? 0) > ($1.updatedAt ?? 0) } - var seen = Set() - var recent: [OpenClawChatSessionEntry] = [] - for entry in sorted { - guard !seen.contains(entry.key) else { continue } - seen.insert(entry.key) - guard (entry.updatedAt ?? 0) >= cutoff else { continue } - recent.append(entry) - } var result: [OpenClawChatSessionEntry] = [] var included = Set() - for entry in recent where !included.contains(entry.key) { + + // Always show the main session first, even if it hasn't been updated recently. + if let main = sorted.first(where: { $0.key == "main" }) { + result.append(main) + included.insert(main.key) + } else { + result.append(self.placeholderSession(key: "main")) + included.insert("main") + } + + for entry in sorted { + guard !included.contains(entry.key) else { continue } + guard (entry.updatedAt ?? 0) >= cutoff else { continue } result.append(entry) included.insert(entry.key) } diff --git a/apps/shared/OpenClawKit/Sources/OpenClawKit/OpenClawKitResources.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/OpenClawKitResources.swift index b19792ad7b8..5af33d1d35c 100644 --- a/apps/shared/OpenClawKit/Sources/OpenClawKit/OpenClawKitResources.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawKit/OpenClawKitResources.swift @@ -52,18 +52,26 @@ public enum OpenClawKitResources { for candidate in candidates { guard let baseURL = candidate else { continue } - // Direct path - let directURL = baseURL.appendingPathComponent("\(bundleName).bundle") - if let bundle = Bundle(url: directURL) { - return bundle + // SwiftPM often places the resource bundle next to (or near) the test runner bundle, + // not inside it. Walk up a few levels and check common container paths. + var roots: [URL] = [] + roots.append(baseURL) + roots.append(baseURL.appendingPathComponent("Resources")) + roots.append(baseURL.appendingPathComponent("Contents/Resources")) + + var current = baseURL + for _ in 0 ..< 5 { + current = current.deletingLastPathComponent() + roots.append(current) + roots.append(current.appendingPathComponent("Resources")) + roots.append(current.appendingPathComponent("Contents/Resources")) } - // Inside Resources/ - let resourcesURL = baseURL - .appendingPathComponent("Resources") - .appendingPathComponent("\(bundleName).bundle") - if let bundle = Bundle(url: resourcesURL) { - return bundle + for root in roots { + let bundleURL = root.appendingPathComponent("\(bundleName).bundle") + if let bundle = Bundle(url: bundleURL) { + return bundle + } } }