94 lines
3.8 KiB
Swift
94 lines
3.8 KiB
Swift
import CodexBarCore
|
|
import Foundation
|
|
|
|
extension SettingsStore {
|
|
func costSummaryShowsInlineDashboard(for provider: UsageProvider) -> Bool {
|
|
self.isCostUsageEffectivelyEnabled(for: provider) &&
|
|
self.costSummaryDisplayStyle.showsInlineSummary
|
|
}
|
|
|
|
func costSummaryShowsSubmenu(for provider: UsageProvider) -> Bool {
|
|
self.isCostUsageEffectivelyEnabled(for: provider) &&
|
|
self.costSummaryDisplayStyle.showsCostSubmenu
|
|
}
|
|
|
|
func applyTokenCostDefaultIfNeeded() {
|
|
// Settings are persisted in UserDefaults.standard.
|
|
guard UserDefaults.standard.object(forKey: "tokenCostUsageEnabled") == nil else { return }
|
|
|
|
Task { @MainActor [weak self] in
|
|
guard let self else { return }
|
|
let hasSources = await Task.detached(priority: .utility) {
|
|
Self.hasAnyTokenCostUsageSources()
|
|
}.value
|
|
guard hasSources else { return }
|
|
guard UserDefaults.standard.object(forKey: "tokenCostUsageEnabled") == nil else { return }
|
|
self.costUsageEnabled = true
|
|
}
|
|
}
|
|
|
|
nonisolated static func hasAnyTokenCostUsageSources(
|
|
env: [String: String] = ProcessInfo.processInfo.environment,
|
|
fileManager: FileManager = .default,
|
|
homeDirectory: URL? = nil) -> Bool
|
|
{
|
|
let home = homeDirectory ?? fileManager.homeDirectoryForCurrentUser
|
|
|
|
func hasAnyJsonl(in root: URL) -> Bool {
|
|
guard fileManager.fileExists(atPath: root.path) else { return false }
|
|
guard let enumerator = fileManager.enumerator(
|
|
at: root,
|
|
includingPropertiesForKeys: [.isRegularFileKey],
|
|
options: [.skipsHiddenFiles, .skipsPackageDescendants])
|
|
else { return false }
|
|
|
|
for case let url as URL in enumerator where url.pathExtension.lowercased() == "jsonl" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
let codexRoot: URL = {
|
|
let raw = env["CODEX_HOME"]?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if let raw, !raw.isEmpty {
|
|
return URL(fileURLWithPath: raw).appendingPathComponent("sessions", isDirectory: true)
|
|
}
|
|
return home
|
|
.appendingPathComponent(".codex", isDirectory: true)
|
|
.appendingPathComponent("sessions", isDirectory: true)
|
|
}()
|
|
|
|
let archivedCodexRoot: URL? = {
|
|
guard codexRoot.lastPathComponent == "sessions" else { return nil }
|
|
return codexRoot
|
|
.deletingLastPathComponent()
|
|
.appendingPathComponent("archived_sessions", isDirectory: true)
|
|
}()
|
|
|
|
if hasAnyJsonl(in: codexRoot) { return true }
|
|
if let archivedCodexRoot, hasAnyJsonl(in: archivedCodexRoot) { return true }
|
|
|
|
let claudeRoots: [URL] = {
|
|
if let env = env["CLAUDE_CONFIG_DIR"]?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
!env.isEmpty
|
|
{
|
|
return env.split(separator: ",").map { part in
|
|
let raw = String(part).trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let url = URL(fileURLWithPath: raw)
|
|
if url.lastPathComponent == "projects" {
|
|
return url
|
|
}
|
|
return url.appendingPathComponent("projects", isDirectory: true)
|
|
}
|
|
}
|
|
|
|
return [
|
|
home.appendingPathComponent(".config/claude/projects", isDirectory: true),
|
|
home.appendingPathComponent(".claude/projects", isDirectory: true),
|
|
] + ClaudeDesktopProjectsLocator.roots(homeDirectory: home, fileManager: fileManager)
|
|
}()
|
|
|
|
return claudeRoots.contains(where: hasAnyJsonl(in:))
|
|
}
|
|
}
|