Compare commits

..
50 Commits
Author SHA1 Message Date
superdooper86 02440c5340 Add fake beta version 3.1.0-beta for testing 2026-05-07 16:06:23 +02:00
superdooper86 6fe3e9722b v3.0.0 — built-by credit fix, version bump 2026-05-07 16:03:23 +02:00
superdooper86 f5114a31f8 README: add notification details, split update section, remove internal beta notes 2026-05-07 15:59:28 +02:00
superdooper86 4f260a3d4b v2.0.10 — limit notifications, fix positioning, add notification screenshots 2026-05-07 15:57:06 +02:00
superdooper86 3d1bae3d0a v2.0.9 — limit notifications using custom floating window (same style as update notifications) 2026-05-07 15:44:38 +02:00
superdooper86 b95102cb1b v2.0.9 — limit notifications at 80%/95% and on reset 2026-05-07 15:40:13 +02:00
superdooper86 2b48114996 Rename screenshots to bust CDN cache 2026-05-07 15:29:47 +02:00
superdooper86 6a4bb73c4f v2.0.8 — Fix data source endpoints in settings, update screenshots 2026-05-07 15:28:08 +02:00
superdooper86 d2815d65ce v2.0.7 — Show account email in settings auth section 2026-05-07 15:21:35 +02:00
superdooper86 a1c3c0b314 v2.0.6 — Auth section shows sign-in status, re-authenticate and sign out buttons 2026-05-07 15:17:11 +02:00
superdooper86 d3ec3f5dd7 revert: restore v2.0.5 after testing 2026-05-07 14:47:04 +02:00
superdooper86 5fee0af18b temp: bump fake version to 9.9.10 2026-05-07 14:37:39 +02:00
superdooper86 4edca2962c temp: fake update for testing 2026-05-07 14:33:51 +02:00
superdooper86 ef2cdd8bf3 v2.0.5 — Fixed window size on open, update banner now clears when up to date 2026-05-07 14:28:33 +02:00
superdooper86 2da3eeaf72 Improve screenshots layout with grid table 2026-05-07 14:24:36 +02:00
superdooper86 d229581de1 Add screenshots to README 2026-05-07 14:21:26 +02:00
superdooper86 169cfd8950 revert: restore v2.0.4 after screenshot 2026-05-07 14:17:37 +02:00
superdooper86 a5218fa44f temp: bump version for screenshot 2026-05-07 14:16:08 +02:00
superdooper86 1f7afab61c Update Data Sources section with new billing endpoints 2026-05-07 14:06:46 +02:00
superdooper86 1507c6490f v2.0.4 — Show spent, limit and balance from dedicated billing endpoints 2026-05-07 14:04:19 +02:00
superdooper86 ccf3468621 v2.0.3 — Clean up extra usage display, remove non-existent balance field 2026-05-07 13:56:31 +02:00
superdooper86 3199b228a8 v2.0.2 — Show spent, limit, and balance in extra usage section 2026-05-07 13:46:36 +02:00
superdooper86 255f3f6cd5 v2.0.2 — Fix unlimited monthly limit display in extra usage section 2026-05-07 13:44:05 +02:00
superdooper86 773fcb1a46 Bump to v2.0.1 2026-05-07 13:39:18 +02:00
superdooper86 464884e88f Fix crash when extra_usage fields are null 2026-05-07 13:36:23 +02:00
superdooper86 edd8d42c8d Bump CFBundleShortVersionString to 2.0 2026-05-07 13:33:16 +02:00
superdooper86 e123b48812 Bump to v2.0 2026-05-07 13:22:06 +02:00
superdooper86 603d405c87 Fix icon URL in README to raw GitHub path 2026-05-07 13:19:25 +02:00
superdooper86 f976a90875 Add Xcode project source for v1.6 2026-05-07 13:18:00 +02:00
SuperDooper c79bd41504 Bump version to 1.6 and update download URL 2026-05-07 12:53:37 +02:00
SuperDooper dfbd276616 Remove instructions from README
Removed instructions
2026-05-07 12:38:27 +02:00
SuperDooper dbf14bdd70 Update contributors in README.md 2026-05-07 12:37:08 +02:00
SuperDooper 6c894c32a4 Create README.md for ClaudeChecker app
Add README for ClaudeChecker macOS app with features and installation instructions.
2026-05-07 12:36:35 +02:00
SuperDooper 345150e894 Update version to 1.5 with notification fixes 2026-05-07 12:32:57 +02:00
SuperDooper d724622533 Downgrade version from 1.5 to 1.4 2026-05-07 12:21:37 +02:00
SuperDooper 8ecb5f3670 Bump version to 1.5 and update release notes 2026-05-07 12:17:08 +02:00
SuperDooper cf6f9184e3 Remove beta version information from JSON 2026-05-07 12:16:49 +02:00
SuperDooper d734fec836 Update version to 1.4 and change download URL 2026-05-07 12:08:18 +02:00
SuperDooper b6542e099a Update version to 1.3 and change download URL 2026-05-07 11:56:24 +02:00
SuperDooper c4e798b484 Update download URL in version.json 2026-05-07 11:47:15 +02:00
SuperDooper 0dd1ac3a8f Update version.json for release 1.2
Updated the version URL and release notes for version 1.2.
2026-05-07 11:45:28 +02:00
SuperDooper 2d8a3629da Rename version-beta to version-beta.json 2026-05-07 11:35:10 +02:00
SuperDooper e07af519a6 Rename version to version.json 2026-05-07 11:35:00 +02:00
SuperDooper 6b1f85dbaf Update version to 1.2 2026-05-07 11:31:12 +02:00
SuperDooper 74fe785898 Add version information for beta release 2026-05-07 11:26:21 +02:00
SuperDooper 3de4e09876 Create version-beta 2026-05-07 11:24:20 +02:00
SuperDooper 43dbb155f5 Delete version-beta.json 2026-05-07 11:24:08 +02:00
SuperDooper 79209eee6f Create version-beta.json 2026-05-07 11:23:50 +02:00
SuperDooper d9598a70ea Add version file with release information 2026-05-07 10:59:12 +02:00
SuperDooper c8cae1827f Initial commit 2026-05-07 10:58:23 +02:00
11 changed files with 59 additions and 244 deletions
-95
View File
@@ -1,95 +0,0 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: macos-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get version from tag
id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
- name: Build
run: |
xcodebuild \
-project ClaudeChecker.xcodeproj \
-scheme ClaudeChecker \
-configuration Release \
-derivedDataPath build \
clean build
- name: Zip app
run: |
ditto -c -k --keepParent \
build/Build/Products/Release/ClaudeChecker.app \
ClaudeChecker.zip
- name: Compute SHA256
id: sha
run: echo "sha256=$(shasum -a 256 ClaudeChecker.zip | awk '{print $1}')" >> $GITHUB_OUTPUT
- name: Create GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "$GITHUB_REF_NAME" ClaudeChecker.zip \
--title "$GITHUB_REF_NAME" \
--notes "$(cat RELEASE_NOTES.md 2>/dev/null || echo 'Release ${{ steps.version.outputs.version }}')"
- name: Update version.json
run: |
notes=$(cat RELEASE_NOTES.md 2>/dev/null || echo "Release ${{ steps.version.outputs.version }}")
jq -n \
--arg version "${{ steps.version.outputs.version }}" \
--arg url "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/ClaudeChecker.zip" \
--arg notes "$notes" \
'{version: $version, url: $url, notes: $notes}' > version.json
- name: Update Homebrew cask
run: |
sed -i '' \
-e 's/version "[^"]*"/version "${{ steps.version.outputs.version }}"/' \
-e 's/sha256 "[^"]*"/sha256 "${{ steps.sha.outputs.sha256 }}"/' \
../homebrew-tap/Casks/claudechecker.rb 2>/dev/null || true
- name: Update README badge
run: |
sed -i '' \
's/version-[0-9][^-]*-orange/version-${{ steps.version.outputs.version }}-orange/' \
README.md
- name: Commit version.json and README
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add version.json README.md
git commit -m "Release ${{ github.ref_name }}"
git push origin HEAD:main
- name: Update Homebrew tap
env:
TAP_TOKEN: ${{ secrets.TAP_TOKEN }}
run: |
git clone https://x-access-token:${{ secrets.TAP_TOKEN }}@github.com/${{ github.repository_owner }}/homebrew-tap /tmp/homebrew-tap
sed -i '' \
-e 's/version "[^"]*"/version "${{ steps.version.outputs.version }}"/' \
-e 's/sha256 "[^"]*"/sha256 "${{ steps.sha.outputs.sha256 }}"/' \
/tmp/homebrew-tap/Casks/claudechecker.rb
cd /tmp/homebrew-tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Casks/claudechecker.rb
git commit -m "Update claudechecker to ${{ github.ref_name }}"
git push
+1 -14
View File
@@ -60,11 +60,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
.sink { [weak self] _ in self?.updateStatusItem() } .sink { [weak self] _ in self?.updateStatusItem() }
.store(in: &cancellables) .store(in: &cancellables)
updateManager.$updateAvailable
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in self?.updateStatusItem() }
.store(in: &cancellables)
// Refresh timer // Refresh timer
scheduleTimer(interval: usageViewModel.refreshInterval) scheduleTimer(interval: usageViewModel.refreshInterval)
@@ -171,13 +166,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let sdStr = sd.map { "\(Int($0.usedPercent.rounded()))%" } ?? "" let sdStr = sd.map { "\(Int($0.usedPercent.rounded()))%" } ?? ""
button.image = nil button.image = nil
button.attributedTitle = NSAttributedString(string: "") button.attributedTitle = NSAttributedString(string: "")
let updatePrefix = updateManager.updateAvailable ? "↑ Update " : "" button.title = "\(fhStr) \(sdStr)"
button.title = "\(updatePrefix)\(fhStr) \(sdStr)"
button.font = NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .medium)
} else if updateManager.updateAvailable {
button.image = nil
button.attributedTitle = NSAttributedString(string: "")
button.title = "↑ Update"
button.font = NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .medium) button.font = NSFont.monospacedDigitSystemFont(ofSize: 12, weight: .medium)
} else { } else {
button.title = "" button.title = ""
@@ -210,7 +199,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@objc func showPopover() { @objc func showPopover() {
guard let button = statusItem?.button, let popover else { return } guard let button = statusItem?.button, let popover else { return }
if !popover.isShown { if !popover.isShown {
NotificationCenter.default.post(name: .popoverWillOpen, object: nil)
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY) popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
} }
@@ -221,7 +209,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
if popover.isShown { if popover.isShown {
popover.performClose(nil) popover.performClose(nil)
} else { } else {
NotificationCenter.default.post(name: .popoverWillOpen, object: nil)
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY) popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
} }
+8 -42
View File
@@ -94,13 +94,6 @@ struct ContentView: View {
} }
.frame(width: 480) .frame(width: 480)
.animation(.easeInOut(duration: 0.2), value: showSettings) .animation(.easeInOut(duration: 0.2), value: showSettings)
.onReceive(NotificationCenter.default.publisher(for: .popoverWillOpen)) { _ in
showSettings = false
}
.onReceive(NotificationCenter.default.publisher(for: .openUpdateSheet)) { _ in
showSettings = false
showUpdateSheet = true
}
.sheet(isPresented: $showLogin) { .sheet(isPresented: $showLogin) {
LoginSheetView(isPresented: $showLogin) { LoginSheetView(isPresented: $showLogin) {
Task { await vm.refresh() } Task { await vm.refresh() }
@@ -781,16 +774,14 @@ struct SettingsView: View {
.padding(.vertical, 2) .padding(.vertical, 2)
.background(Color.blue) .background(Color.blue)
.cornerRadius(4) .cornerRadius(4)
.fixedSize()
} else if updater.betaAvailable { } else if updater.betaAvailable {
Text("v\(updater.latestBetaVersion) available") Text("v\(updater.latestBetaVersion) beta")
.font(.system(size: 10, weight: .medium)) .font(.system(size: 10, weight: .medium))
.foregroundColor(.white) .foregroundColor(.white)
.padding(.horizontal, 6) .padding(.horizontal, 6)
.padding(.vertical, 2) .padding(.vertical, 2)
.background(Color.orange) .background(Color.orange)
.cornerRadius(4) .cornerRadius(4)
.fixedSize()
} }
} }
Text("Built by superdooper86 & claude") Text("Built by superdooper86 & claude")
@@ -980,36 +971,6 @@ struct UpdateSuccessBanner: View {
} }
} }
// MARK: - Markdown notes renderer
struct ReleaseNotesText: View {
let text: String
var font: Font = .system(size: 12)
var body: some View {
let processed = text
.split(separator: "\n", omittingEmptySubsequences: false)
.map { line -> String in
let s = String(line)
if s.hasPrefix("### ") { return "**\(s.dropFirst(4))**" }
if s.hasPrefix("## ") { return "**\(s.dropFirst(3))**" }
if s.hasPrefix("# ") { return "**\(s.dropFirst(2))**" }
if s.hasPrefix("- ") { return "\(s.dropFirst(2))" }
return s
}
.joined(separator: "\n")
if let attr = try? AttributedString(markdown: processed,
options: .init(interpretedSyntax: .inlineOnlyPreservingWhitespace)) {
Text(attr).font(font).foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
} else {
Text(text).font(font).foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
}
}
}
// MARK: - Update Banner // MARK: - Update Banner
struct UpdateBanner: View { struct UpdateBanner: View {
@@ -1025,7 +986,10 @@ struct UpdateBanner: View {
Text("Update available — v\(updater.latestVersion)") Text("Update available — v\(updater.latestVersion)")
.font(.system(size: 12, weight: .semibold)) .font(.system(size: 12, weight: .semibold))
if !updater.releaseNotes.isEmpty { if !updater.releaseNotes.isEmpty {
ReleaseNotesText(text: updater.releaseNotes, font: .system(size: 11)) Text(updater.releaseNotes)
.font(.system(size: 11))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
} }
} }
Spacer() Spacer()
@@ -1085,7 +1049,9 @@ struct UpdateSheet: View {
.foregroundColor(.blue) .foregroundColor(.blue)
} }
if !updater.releaseNotes.isEmpty { if !updater.releaseNotes.isEmpty {
ReleaseNotesText(text: updater.releaseNotes) Text(updater.releaseNotes)
.font(.system(size: 12))
.foregroundColor(.secondary)
} }
} }
Spacer() Spacer()
+2 -2
View File
@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.11</string> <string>3.0.0</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>31</string> <string>18</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>13.0</string> <string>13.0</string>
<key>LSUIElement</key> <key>LSUIElement</key>
+3 -15
View File
@@ -46,8 +46,6 @@ class UpdateManager: ObservableObject {
@Published var updateComplete = false @Published var updateComplete = false
@Published var justUpdated = false @Published var justUpdated = false
private var notifiedVersion: String = ""
@Published var betaChannel: Bool = false { @Published var betaChannel: Bool = false {
didSet { didSet {
UserDefaults.standard.set(betaChannel, forKey: "beta_channel") UserDefaults.standard.set(betaChannel, forKey: "beta_channel")
@@ -72,13 +70,14 @@ class UpdateManager: ObservableObject {
if let stable = await stableResult { if let stable = await stableResult {
print("[UpdateManager] Stable remote=\(stable.version), isNewer=\(isNewer(stable.version, than: currentVersion))") print("[UpdateManager] Stable remote=\(stable.version), isNewer=\(isNewer(stable.version, than: currentVersion))")
if isNewer(stable.version, than: currentVersion) { if isNewer(stable.version, than: currentVersion) {
let wasAvailable = updateAvailable
latestVersion = stable.version latestVersion = stable.version
releaseNotes = stable.notes ?? "" releaseNotes = stable.notes ?? ""
downloadURL = stable.url downloadURL = stable.url
updateAvailable = true updateAvailable = true
print("[UpdateManager] updateAvailable set to true") print("[UpdateManager] updateAvailable set to true")
if notifiedVersion != stable.version { // Only notify once when first detected
notifiedVersion = stable.version if !wasAvailable {
NotificationCenter.default.post(name: .updateDetected, object: stable.version) NotificationCenter.default.post(name: .updateDetected, object: stable.version)
} }
} else { } else {
@@ -87,8 +86,6 @@ class UpdateManager: ObservableObject {
} }
} else { } else {
print("[UpdateManager] Stable fetch returned nil") print("[UpdateManager] Stable fetch returned nil")
updateAvailable = false
latestVersion = ""
} }
if let beta = await betaResult { if let beta = await betaResult {
@@ -101,19 +98,10 @@ class UpdateManager: ObservableObject {
releaseNotes = beta.notes ?? "" releaseNotes = beta.notes ?? ""
downloadURL = beta.url downloadURL = beta.url
updateAvailable = true updateAvailable = true
if notifiedVersion != beta.version {
notifiedVersion = beta.version
NotificationCenter.default.post(name: .updateDetected, object: beta.version)
}
} }
} else {
betaAvailable = false
latestBetaVersion = ""
} }
} else { } else {
print("[UpdateManager] Beta fetch returned nil") print("[UpdateManager] Beta fetch returned nil")
betaAvailable = false
latestBetaVersion = ""
} }
} }
+28 -51
View File
@@ -14,7 +14,7 @@ class UpdateNotificationWindowController: NSWindowController {
// Called when a new update is detected while running // Called when a new update is detected while running
static func showUpdate(version: String, notes: String, near statusItem: NSStatusItem?) { static func showUpdate(version: String, notes: String, near statusItem: NSStatusItem?) {
showWindow(version: version, subtitle: "Tap to view release notes & update now!", near: statusItem, isUpdate: true) showWindow(version: version, subtitle: notes.isEmpty ? "Tap to update now." : notes, near: statusItem, isUpdate: true)
} }
static func showLimitWarning(windowName: String, percent: Int, near statusItem: NSStatusItem?) { static func showLimitWarning(windowName: String, percent: Int, near statusItem: NSStatusItem?) {
@@ -39,12 +39,7 @@ class UpdateNotificationWindowController: NSWindowController {
sharedLimit?.close() sharedLimit?.close()
let content = UpdateNotificationView( let content = UpdateNotificationView(
version: "", subtitle: subtitle, isUpdate: false, version: "", subtitle: subtitle, isUpdate: false,
titleText: title, badgeIcon: badgeIcon, badgeColor: badgeColor, titleText: title, badgeIcon: badgeIcon, badgeColor: badgeColor
onTap: {
sharedLimit?.close()
sharedLimit = nil
NotificationCenter.default.post(name: .showPopover, object: nil)
}
) { ) {
sharedLimit?.close() sharedLimit?.close()
sharedLimit = nil sharedLimit = nil
@@ -58,16 +53,7 @@ class UpdateNotificationWindowController: NSWindowController {
private static func showWindow(version: String, subtitle: String, near statusItem: NSStatusItem?, isUpdate: Bool) { private static func showWindow(version: String, subtitle: String, near statusItem: NSStatusItem?, isUpdate: Bool) {
shared?.close() shared?.close()
let content = UpdateNotificationView(version: version, subtitle: subtitle, isUpdate: isUpdate, let content = UpdateNotificationView(version: version, subtitle: subtitle, isUpdate: isUpdate) {
onTap: {
shared?.close()
shared = nil
NotificationCenter.default.post(name: .showPopover, object: nil)
if isUpdate {
NotificationCenter.default.post(name: .openUpdateSheet, object: nil)
}
}
) {
shared?.close() shared?.close()
shared = nil shared = nil
} }
@@ -143,7 +129,6 @@ struct UpdateNotificationView: View {
var titleText: String? = nil var titleText: String? = nil
var badgeIcon: String? = nil var badgeIcon: String? = nil
var badgeColor: Color? = nil var badgeColor: Color? = nil
var onTap: (() -> Void)? = nil
let onDismiss: () -> Void let onDismiss: () -> Void
private var effectiveTitle: String { private var effectiveTitle: String {
@@ -157,40 +142,30 @@ struct UpdateNotificationView: View {
} }
var body: some View { var body: some View {
ZStack(alignment: .topTrailing) { HStack(spacing: 12) {
Button(action: { onTap?() }) { ZStack(alignment: .bottomTrailing) {
HStack(spacing: 12) { Image(nsImage: NSImage(named: "AppIcon") ?? NSImage())
ZStack(alignment: .bottomTrailing) { .resizable()
Image(nsImage: NSImage(named: "AppIcon") ?? NSImage()) .frame(width: 44, height: 44)
.resizable() .cornerRadius(10)
.frame(width: 44, height: 44)
.cornerRadius(10)
Image(systemName: effectiveBadgeIcon) Image(systemName: effectiveBadgeIcon)
.font(.system(size: 16, weight: .semibold)) .font(.system(size: 16, weight: .semibold))
.foregroundColor(effectiveBadgeColor) .foregroundColor(effectiveBadgeColor)
.background(Color(nsColor: .windowBackgroundColor).clipShape(Circle())) .background(Color(nsColor: .windowBackgroundColor).clipShape(Circle()))
.offset(x: 4, y: 4) .offset(x: 4, y: 4)
}
VStack(alignment: .leading, spacing: 3) {
Text(effectiveTitle)
.font(.system(size: 13, weight: .semibold))
.foregroundColor(.primary)
Text(subtitle)
.font(.system(size: 11))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
}
Spacer(minLength: 24)
}
.padding(.horizontal, 14)
.padding(.vertical, 14)
.frame(width: 340, alignment: .leading)
.contentShape(Rectangle())
} }
.buttonStyle(.plain)
VStack(alignment: .leading, spacing: 3) {
Text(effectiveTitle)
.font(.system(size: 13, weight: .semibold))
Text(subtitle)
.font(.system(size: 11))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
}
Spacer(minLength: 8)
Button(action: onDismiss) { Button(action: onDismiss) {
Image(systemName: "xmark") Image(systemName: "xmark")
@@ -198,8 +173,10 @@ struct UpdateNotificationView: View {
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
.buttonStyle(.plain) .buttonStyle(.plain)
.padding(14)
} }
.padding(.horizontal, 14)
.padding(.vertical, 14)
.frame(width: 340, alignment: .leading)
.background( .background(
RoundedRectangle(cornerRadius: 13) RoundedRectangle(cornerRadius: 13)
.fill(Color(nsColor: .windowBackgroundColor)) .fill(Color(nsColor: .windowBackgroundColor))
-2
View File
@@ -307,9 +307,7 @@ extension Notification.Name {
static let refreshIntervalChanged = Notification.Name("refreshIntervalChanged") static let refreshIntervalChanged = Notification.Name("refreshIntervalChanged")
static let closePopover = Notification.Name("closePopover") static let closePopover = Notification.Name("closePopover")
static let showPopover = Notification.Name("showPopover") static let showPopover = Notification.Name("showPopover")
static let popoverWillOpen = Notification.Name("popoverWillOpen")
static let updateDetected = Notification.Name("updateDetected") static let updateDetected = Notification.Name("updateDetected")
static let limitWarning = Notification.Name("limitWarning") static let limitWarning = Notification.Name("limitWarning")
static let limitReset = Notification.Name("limitReset") static let limitReset = Notification.Name("limitReset")
static let openUpdateSheet = Notification.Name("openUpdateSheet")
} }
+9 -13
View File
@@ -8,7 +8,7 @@
[![macOS](https://img.shields.io/badge/macOS-13.0+-000000?style=flat&logo=apple&logoColor=white)](https://www.apple.com/macos/) [![macOS](https://img.shields.io/badge/macOS-13.0+-000000?style=flat&logo=apple&logoColor=white)](https://www.apple.com/macos/)
[![Swift](https://img.shields.io/badge/Swift-5.9-F05138?style=flat&logo=swift&logoColor=white)](https://swift.org) [![Swift](https://img.shields.io/badge/Swift-5.9-F05138?style=flat&logo=swift&logoColor=white)](https://swift.org)
[![Version](https://img.shields.io/badge/version-1.0.10-orange?style=flat)](https://github.com/superdooper86/claudechecker/releases) [![Version](https://img.shields.io/badge/version-3.0.0-orange?style=flat)](https://github.com/superdooper86/claudechecker/releases)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat)](LICENSE) [![License](https://img.shields.io/badge/license-MIT-blue?style=flat)](LICENSE)
</div> </div>
@@ -113,29 +113,25 @@ No API key required. It reads directly from your `claude.ai` session using a bui
## Requirements ## Requirements
- macOS 13 Ventura or later - macOS 13 Ventura or later
- Xcode 15+ (to build from source)
- A claude.ai account - A claude.ai account
--- ---
## Installation ## Installation
### Homebrew (easiest) ### Download (recommended)
```bash
brew tap superdooper86/tap
brew install --cask claudechecker
```
### Download
1. Go to [Releases](https://github.com/superdooper86/claudechecker/releases) 1. Go to [Releases](https://github.com/superdooper86/claudechecker/releases)
2. Download `ClaudeChecker.zip` from the latest release 2. Download `ClaudeChecker.zip` from the latest release
3. Unzip and drag `ClaudeChecker.app` to `/Applications` 3. Unzip and drag `ClaudeChecker.app` to `/Applications`
4. Open from Applications — it will appear in your menubar 4. Open from Applications — it will appear in your menubar
> **macOS security prompt?** If macOS blocks the app on first launch, run this in Terminal: ### Build from source
> ```bash ```bash
> xattr -cr /Applications/ClaudeChecker.app git clone https://github.com/superdooper86/claudechecker.git
> ``` open ClaudeChecker/ClaudeChecker.xcodeproj
> This is not needed when installing via Homebrew. ```
Then in Xcode: set your Team under Signing & Capabilities, then **⌘R** to run.
--- ---
-7
View File
@@ -1,7 +0,0 @@
## What's new in v1.0.11
### Update indicator in menubar
When an update is available, the menubar now shows **↑ Update** alongside your usage percentages — so you can see there's an update without opening the app.
### Update banner can't be dismissed
The × close button has been removed from the update banner. The banner stays visible until you install the update.
+5
View File
@@ -0,0 +1,5 @@
{
"version": "3.1.0-beta",
"url": "https://github.com/superdooper86/claudechecker/releases/download/v3.0.0/ClaudeChecker.zip",
"notes": "Beta test build."
}
+3 -3
View File
@@ -1,5 +1,5 @@
{ {
"version": "1.1.1", "version": "3.0.0",
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.0.10/ClaudeChecker.zip", "url": "https://github.com/superdooper86/claudechecker/releases/download/v3.0.0/ClaudeChecker.zip",
"notes": "## What's new in v1.0.10\\n\\n### Main window always opens on click\\nClosing the app while Settings was open would cause the next click to reopen straight to Settings. The app now always returns to the main window when reopened." "notes": "Limit notifications for 80% and 95% usage, and on quota reset."
} }