Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecbae7d7ca | ||
|
|
37a039e1d3 | ||
|
|
8f3ead2f65 | ||
|
|
734670bb3f | ||
|
|
94430e00ba | ||
|
|
7b0368b001 | ||
|
|
4629aeffbc | ||
|
|
2cb4ddfe97 | ||
|
|
73b251a1e9 | ||
|
|
7bab6a0df0 | ||
|
|
db6380fa66 | ||
|
|
47a148fa67 | ||
|
|
85ac329d36 | ||
|
|
a0fb6eabcf | ||
|
|
b778d03323 |
@@ -911,12 +911,12 @@ struct ErrorBanner: View {
|
|||||||
struct EmptyStateView: View {
|
struct EmptyStateView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 10) {
|
VStack(spacing: 10) {
|
||||||
Image(systemName: "key.slash")
|
Image(systemName: "person.crop.circle.badge.questionmark")
|
||||||
.font(.system(size: 28))
|
.font(.system(size: 28))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
Text("No API key configured")
|
Text("Not signed in")
|
||||||
.font(.system(size: 13, weight: .medium))
|
.font(.system(size: 13, weight: .medium))
|
||||||
Text("Open Settings to add your Anthropic API key.")
|
Text("Sign in to claude.ai to see your usage.")
|
||||||
.font(.system(size: 11.5))
|
.font(.system(size: 11.5))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.1.4-beta.7</string>
|
<string>1.2.1-beta.3</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>47</string>
|
<string>51</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>13.0</string>
|
<string>13.0</string>
|
||||||
<key>LSUIElement</key>
|
<key>LSUIElement</key>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ struct LoginWebView: NSViewRepresentable {
|
|||||||
|
|
||||||
let webView = WKWebView(frame: .zero, configuration: config)
|
let webView = WKWebView(frame: .zero, configuration: config)
|
||||||
webView.navigationDelegate = context.coordinator
|
webView.navigationDelegate = context.coordinator
|
||||||
webView.load(URLRequest(url: URL(string: "https://claude.ai/login")!))
|
webView.load(URLRequest(url: URL(string: "https://claude.ai")!))
|
||||||
return webView
|
return webView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,16 @@ class UsageViewModel: ObservableObject {
|
|||||||
burnHistoryStore = saved
|
burnHistoryStore = saved
|
||||||
}
|
}
|
||||||
loadPlaceholderData()
|
loadPlaceholderData()
|
||||||
|
Task { await checkInitialSignInState() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkInitialSignInState() async {
|
||||||
|
let cookies = await WKWebsiteDataStore.default().httpCookieStore.allCookies()
|
||||||
|
let hasSession = cookies.contains {
|
||||||
|
$0.domain.contains("claude.ai") &&
|
||||||
|
($0.name == "sessionKey" || $0.name == "__Secure-next-auth.session-token")
|
||||||
|
}
|
||||||
|
if hasSession { isSignedIn = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
func signOut() async {
|
func signOut() async {
|
||||||
@@ -140,11 +150,22 @@ class UsageViewModel: ObservableObject {
|
|||||||
let memberships = (account?["memberships"] ?? json["memberships"]) as? [[String: Any]]
|
let memberships = (account?["memberships"] ?? json["memberships"]) as? [[String: Any]]
|
||||||
let firstOrg = memberships?.first?["organization"] as? [String: Any]
|
let firstOrg = memberships?.first?["organization"] as? [String: Any]
|
||||||
|
|
||||||
// org ID — primary path then flat-list fallback
|
// org ID — primary path then flat-list fallback then dedicated endpoint
|
||||||
var orgId: String? = firstOrg?["uuid"] as? String
|
var orgId: String? = firstOrg?["uuid"] as? String
|
||||||
if orgId == nil {
|
if orgId == nil {
|
||||||
orgId = (json["organizations"] as? [[String: Any]])?.first?["uuid"] as? String
|
orgId = (json["organizations"] as? [[String: Any]])?.first?["uuid"] as? String
|
||||||
}
|
}
|
||||||
|
if orgId == nil, let cookie = await claudeCookieHeader() {
|
||||||
|
// Final fallback: fetch /api/organizations directly
|
||||||
|
var orgsReq = URLRequest(url: URL(string: "https://claude.ai/api/organizations")!)
|
||||||
|
orgsReq.setValue("application/json", forHTTPHeaderField: "accept")
|
||||||
|
orgsReq.setValue(cookie, forHTTPHeaderField: "Cookie")
|
||||||
|
if let (orgsData, orgsResp) = try? await URLSession.shared.data(for: orgsReq),
|
||||||
|
let orgsHttp = orgsResp as? HTTPURLResponse, orgsHttp.statusCode == 200,
|
||||||
|
let orgs = try? JSONSerialization.jsonObject(with: orgsData) as? [[String: Any]] {
|
||||||
|
orgId = orgs.first?["uuid"] as? String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let email = account?["email_address"] as? String
|
let email = account?["email_address"] as? String
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
[](https://www.apple.com/macos/)
|
[](https://www.apple.com/macos/)
|
||||||
[](https://swift.org)
|
[](https://swift.org)
|
||||||
[](https://github.com/superdooper86/claudechecker/releases)
|
[](https://github.com/superdooper86/claudechecker/releases)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://github.com/superdooper86/claudechecker/releases/tag/v1.1.4-beta.6) <!-- BETA_BADGE -->
|
[](https://github.com/superdooper86/claudechecker/releases/tag/v1.2.1-beta.2) <!-- BETA_BADGE -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -1,4 +1,9 @@
|
|||||||
## What's new in v1.1.4-beta.7
|
## What's new in v1.2.1
|
||||||
|
|
||||||
### Bug fix
|
### Bug fixes
|
||||||
- Main panel no longer scrolls — popover now auto-sizes to fit content
|
- Fixed "Not signed in" showing incorrectly on launch when the session was already active
|
||||||
|
- Sign-in state is now detected immediately from stored cookies on startup, before the first data refresh completes
|
||||||
|
- Fixed Re-authenticate (and Sign In) not detecting an existing session — the login window now loads `claude.ai` directly so already-signed-in users are detected correctly and the window auto-dismisses
|
||||||
|
- Fixed "No API key configured" showing after signing out — now correctly shows "Not signed in" with a prompt to sign in
|
||||||
|
- Added `/api/organizations` as a final fallback for org ID resolution when the bootstrap API response doesn't include it
|
||||||
|
- Session cookie detection now checks both `sessionKey` and `__Secure-next-auth.session-token` cookie names
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.1.4-beta.6",
|
"version": "1.2.1-beta.2",
|
||||||
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.1.4-beta.6/ClaudeChecker.zip",
|
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.2.1-beta.2/ClaudeChecker.zip",
|
||||||
"notes": "## What's new in v1.1.4-beta.6\n\n### UI improvement\n- Session Diary card: removed the Claude icon and header row; now shows sample count and avg burn rate left/right with the sparkline below — matching the cleaner Windows layout"
|
"notes": "## What's new in v1.2.1\n\n### Bug fixes\n- Fixed \"Not signed in\" showing incorrectly on launch when the session was already active\n- Sign-in state is now detected immediately from stored cookies on startup, before the first data refresh completes\n- Fixed Re-authenticate (and Sign In) not detecting an existing session — the login window now loads `claude.ai` directly so already-signed-in users are detected correctly and the window auto-dismisses\n- Added `/api/organizations` as a final fallback for org ID resolution when the bootstrap API response doesn't include it\n- Session cookie detection now checks both `sessionKey` and `__Secure-next-auth.session-token` cookie names"
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.1.3",
|
"version": "1.2.0",
|
||||||
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.1.3/ClaudeChecker.zip",
|
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.2.0/ClaudeChecker.zip",
|
||||||
"notes": "## What's new in v1.1.3\n\n### UI polish\n- Limit headers now read \"5 Hour Limit\" and \"7 Day Limit\"\n- Tapping anywhere on the blue update banner opens the update window\n\n### Session Diary fix\n- Burn history is persisted across app launches — the sparkline populates immediately on first open instead of requiring a manual refresh\n\n### Window sizing fixes\n- The popover now resizes correctly when switching between the main view and settings\n- Background colour no longer shows through during the resize animation"
|
"notes": "## What's new in v1.2.0\n\n### Bug fixes\n- App now works for all users — org ID is fetched dynamically from the API instead of being hardcoded\n- Plan name (e.g. Pro, Max) now updates correctly on every refresh\n\n### Improvements\n- Plan name is read from the API rather than hardcoded\n- Bootstrap API call consolidated — org ID, email, and plan name fetched in a single request per refresh\n- Main panel no longer scrolls — popover auto-sizes to fit content\n- Session Diary card redesigned — sample count and avg burn rate shown left/right above the sparkline, Claude header removed"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user