-
Notifications
You must be signed in to change notification settings - Fork 690
feat(cache): add cookie cache clearing to Debug tab and CLI #592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| import CodexBarCore | ||
| import Commander | ||
| import Foundation | ||
|
|
||
| extension CodexBarCLI { | ||
| static func runCacheClear(_ values: ParsedValues) { | ||
| let output = CLIOutputPreferences.from(values: values) | ||
| let cookies = values.flags.contains("cookies") | ||
| let cost = values.flags.contains("cost") | ||
| let all = values.flags.contains("all") | ||
| let rawProvider = values.options["provider"]?.last | ||
|
|
||
| let clearCookies = cookies || all | ||
| let clearCost = cost || all | ||
|
|
||
| if !clearCookies && !clearCost { | ||
| Self.exit( | ||
| code: .failure, | ||
| message: "Specify --cookies, --cost, or --all.", | ||
| output: output, | ||
| kind: .args) | ||
| } | ||
|
|
||
| var results: [CacheClearResult] = [] | ||
|
|
||
| if clearCookies { | ||
| if let rawProvider { | ||
| if let provider = ProviderDescriptorRegistry.cliNameMap[rawProvider.lowercased()] { | ||
| let had = CookieHeaderCache.load(provider: provider) != nil | ||
| CookieHeaderCache.clear(provider: provider) | ||
|
Comment on lines
+29
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The provider-specific path derives Useful? React with 👍 / 👎. |
||
| results.append(CacheClearResult( | ||
| cache: "cookies", | ||
| provider: provider.rawValue, | ||
| cleared: had ? 1 : 0)) | ||
| } else { | ||
| Self.exit( | ||
| code: .failure, | ||
| message: "Unknown provider: \(rawProvider)", | ||
| output: output, | ||
| kind: .args) | ||
| } | ||
| } else { | ||
| let cleared = CookieHeaderCache.clearAll() | ||
| results.append(CacheClearResult(cache: "cookies", provider: nil, cleared: cleared)) | ||
| } | ||
| } | ||
|
|
||
| if clearCost { | ||
| let fm = FileManager.default | ||
| let cacheDir = Self.costUsageCacheDirectory(fileManager: fm) | ||
| var cleared = 0 | ||
| var costError: String? | ||
| if fm.fileExists(atPath: cacheDir.path) { | ||
| do { | ||
| try fm.removeItem(at: cacheDir) | ||
| cleared = 1 | ||
| } catch { | ||
| costError = error.localizedDescription | ||
| } | ||
| } | ||
| results.append(CacheClearResult(cache: "cost", provider: nil, cleared: cleared, error: costError)) | ||
| } | ||
|
|
||
| switch output.format { | ||
| case .text: | ||
| for result in results { | ||
| let scope = result.provider ?? "all providers" | ||
| if let error = result.error { | ||
| print("\(result.cache): failed to clear (\(scope)) - \(error)") | ||
| } else if result.cleared > 0 { | ||
| print("\(result.cache): cleared (\(scope))") | ||
| } else { | ||
| print("\(result.cache): nothing to clear (\(scope))") | ||
| } | ||
| } | ||
| case .json: | ||
| Self.printJSON(results, pretty: output.pretty) | ||
| } | ||
|
|
||
| let hasErrors = results.contains(where: { $0.error != nil }) | ||
| Self.exit(code: hasErrors ? .failure : .success, output: output, kind: .runtime) | ||
| } | ||
| } | ||
|
|
||
| struct CacheOptions: CommanderParsable { | ||
| @Flag(names: [.short("v"), .long("verbose")], help: "Enable verbose logging") | ||
| var verbose: Bool = false | ||
|
|
||
| @Flag(name: .long("json-output"), help: "Emit machine-readable logs") | ||
| var jsonOutput: Bool = false | ||
|
|
||
| @Option(name: .long("log-level"), help: "Set log level (trace|verbose|debug|info|warning|error|critical)") | ||
| var logLevel: String? | ||
|
|
||
| @Option(name: .long("format"), help: "Output format: text | json") | ||
| var format: OutputFormat? | ||
|
|
||
| @Flag(name: .long("json"), help: "") | ||
| var jsonShortcut: Bool = false | ||
|
|
||
| @Flag(name: .long("json-only"), help: "Emit JSON only (suppress non-JSON output)") | ||
| var jsonOnly: Bool = false | ||
|
|
||
| @Flag(name: .long("pretty"), help: "Pretty-print JSON output") | ||
| var pretty: Bool = false | ||
|
|
||
| @Flag(name: .long("cookies"), help: "Clear browser cookie caches") | ||
| var cookies: Bool = false | ||
|
|
||
| @Flag(name: .long("cost"), help: "Clear cost usage caches") | ||
| var cost: Bool = false | ||
|
|
||
| @Flag(name: .long("all"), help: "Clear all caches") | ||
| var all: Bool = false | ||
|
|
||
| @Option(name: .long("provider"), help: "Clear cache for a specific provider only") | ||
| var provider: String? | ||
| } | ||
|
|
||
| private struct CacheClearResult: Encodable { | ||
| let cache: String | ||
| let provider: String? | ||
| let cleared: Int | ||
| var error: String? | ||
| } | ||
|
|
||
| extension CodexBarCLI { | ||
| /// Mirrors the cost usage cache directory used by the app (UsageStore.costUsageCacheDirectory). | ||
| static func costUsageCacheDirectory(fileManager: FileManager = .default) -> URL { | ||
| let root = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first! | ||
| return root | ||
| .appendingPathComponent("CodexBar", isDirectory: true) | ||
| .appendingPathComponent("cost-usage", isDirectory: true) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--provideris currently accepted whenever any clear action is chosen, but it is only used inside the cookie-clearing branch. In practice,codexbar cache clear --cost --provider claudesilently ignores the provider and still exits success after clearing cost cache, which is misleading for users and scripts that expect provider-scoped behavior. Add validation so--providerrequires--cookies(or explicitly documented semantics with--all) instead of being ignored.Useful? React with 👍 / 👎.