Compare commits
38
Commits
v1.0.10
...
v1.1.3-beta.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b03909c55 | ||
|
|
c3ea2be809 | ||
|
|
6f6a7361fe | ||
|
|
d9d65da6b7 | ||
|
|
c18054a810 | ||
|
|
032951882f | ||
|
|
ed186af2c6 | ||
|
|
d3dabc7843 | ||
|
|
987bd36137 | ||
|
|
cfcb74f32b | ||
|
|
273e10566e | ||
|
|
76a8f433a7 | ||
|
|
65a171f296 | ||
|
|
26312290ac | ||
|
|
63cbd70f38 | ||
|
|
235ab81efb | ||
|
|
12d7855ceb | ||
|
|
d1ab5206bd | ||
|
|
997e820be8 | ||
|
|
7fc78d5a83 | ||
|
|
818d4aa6c2 | ||
|
|
6aa74fcabc | ||
|
|
2a01d6f5b8 | ||
|
|
af920eda83 | ||
|
|
6b6802eaea | ||
|
|
e9d29db2ee | ||
|
|
9be5069aac | ||
|
|
cc9e2aaba1 | ||
|
|
19bb6459ed | ||
|
|
abf05b04fc | ||
|
|
849e94c942 | ||
|
|
d76c7496bb | ||
|
|
45a3925f65 | ||
|
|
113e91583d | ||
|
|
c60fb93e1a | ||
|
|
b16c24cb44 | ||
|
|
89a79c6f13 | ||
|
|
aa529835f7 |
@@ -0,0 +1,79 @@
|
|||||||
|
name: Release Beta
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*-beta*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release-beta:
|
||||||
|
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: Create GitHub pre-release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh release create "$GITHUB_REF_NAME" ClaudeChecker.zip \
|
||||||
|
--title "$GITHUB_REF_NAME" \
|
||||||
|
--prerelease \
|
||||||
|
--notes "$(cat RELEASE_NOTES.md 2>/dev/null || echo 'Beta release ${{ steps.version.outputs.version }}')"
|
||||||
|
|
||||||
|
- name: Update version-beta.json
|
||||||
|
run: |
|
||||||
|
notes=$(cat RELEASE_NOTES.md 2>/dev/null || echo "Beta 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-beta.json
|
||||||
|
|
||||||
|
- name: Update beta badge in README
|
||||||
|
run: |
|
||||||
|
shields_version=$(echo "${{ steps.version.outputs.version }}" | sed 's/-/--/g')
|
||||||
|
tag="${{ github.ref_name }}"
|
||||||
|
export BADGE="[](https://github.com/${{ github.repository }}/releases/tag/${tag}) <!-- BETA_BADGE -->"
|
||||||
|
python3 -c "
|
||||||
|
import os
|
||||||
|
badge = os.environ['BADGE']
|
||||||
|
lines = open('README.md').readlines()
|
||||||
|
out = []
|
||||||
|
for line in lines:
|
||||||
|
out.append(badge + chr(10) if '<!-- BETA_BADGE -->' in line else line)
|
||||||
|
open('README.md', 'w').writelines(out)
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Commit version-beta.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-beta.json README.md
|
||||||
|
git commit -m "Beta release ${{ github.ref_name }}"
|
||||||
|
git pull --rebase origin main
|
||||||
|
git push origin HEAD:main
|
||||||
@@ -7,6 +7,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
if: ${{ !contains(github.ref_name, '-') }}
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -65,10 +66,24 @@ jobs:
|
|||||||
../homebrew-tap/Casks/claudechecker.rb 2>/dev/null || true
|
../homebrew-tap/Casks/claudechecker.rb 2>/dev/null || true
|
||||||
|
|
||||||
- name: Update README badge
|
- name: Update README badge
|
||||||
|
env:
|
||||||
|
NEW_VERSION: ${{ steps.version.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
sed -i '' \
|
python3 -c "
|
||||||
's/version-[0-9][^-]*-orange/version-${{ steps.version.outputs.version }}-orange/' \
|
import os, re
|
||||||
README.md
|
v = os.environ['NEW_VERSION']
|
||||||
|
content = open('README.md').read()
|
||||||
|
content = re.sub(r'version-[0-9][^-]*-orange', 'version-' + v + '-orange', content)
|
||||||
|
lines = content.splitlines(keepends=True)
|
||||||
|
out = []
|
||||||
|
for line in lines:
|
||||||
|
if '<!-- BETA_BADGE -->' in line:
|
||||||
|
continue
|
||||||
|
out.append(line)
|
||||||
|
if 'license-MIT-blue' in line:
|
||||||
|
out.append('<!-- BETA_BADGE -->' + chr(10))
|
||||||
|
open('README.md', 'w').writelines(out)
|
||||||
|
"
|
||||||
|
|
||||||
- name: Commit version.json and README
|
- name: Commit version.json and README
|
||||||
run: |
|
run: |
|
||||||
@@ -76,6 +91,7 @@ jobs:
|
|||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
git add version.json README.md
|
git add version.json README.md
|
||||||
git commit -m "Release ${{ github.ref_name }}"
|
git commit -m "Release ${{ github.ref_name }}"
|
||||||
|
git pull --rebase origin main
|
||||||
git push origin HEAD:main
|
git push origin HEAD:main
|
||||||
|
|
||||||
- name: Update Homebrew tap
|
- name: Update Homebrew tap
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ 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)
|
||||||
|
|
||||||
@@ -166,7 +171,13 @@ 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: "")
|
||||||
button.title = "◔ \(fhStr) \(sdStr)"
|
let updatePrefix = updateManager.updateAvailable ? "↑ Update " : "◔ "
|
||||||
|
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 = ""
|
||||||
|
|||||||
@@ -47,13 +47,29 @@ struct ContentView: View {
|
|||||||
EmptyStateView()
|
EmptyStateView()
|
||||||
.padding(.vertical, 40)
|
.padding(.vertical, 40)
|
||||||
} else {
|
} else {
|
||||||
VStack(spacing: 1) {
|
VStack(spacing: 8) {
|
||||||
ForEach(vm.limits) { limit in
|
ForEach(vm.limits) { limit in
|
||||||
LimitCard(limit: limit)
|
VStack(spacing: 0) {
|
||||||
|
HStack {
|
||||||
|
Text(limit.window == .fiveHour ? "5hr Limit" : "7 Day Limit")
|
||||||
|
.font(.system(size: 11, weight: .semibold))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.textCase(.uppercase)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 16)
|
||||||
|
.padding(.top, 10)
|
||||||
|
.padding(.bottom, 4)
|
||||||
|
|
||||||
|
LimitCard(limit: limit)
|
||||||
|
.background(Color(nsColor: .controlBackgroundColor))
|
||||||
|
.cornerRadius(8)
|
||||||
|
.overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.primary.opacity(0.08), lineWidth: 0.5))
|
||||||
|
.padding(.horizontal, 8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background(Color.primary.opacity(0.05))
|
.padding(.bottom, 4)
|
||||||
.padding(.vertical, 1)
|
|
||||||
|
|
||||||
// Extra credits row
|
// Extra credits row
|
||||||
if let extra = vm.extraUsage, extra.isEnabled {
|
if let extra = vm.extraUsage, extra.isEnabled {
|
||||||
@@ -196,7 +212,7 @@ struct LimitCard: View {
|
|||||||
AgentIconView(agent: .claude, size: 14)
|
AgentIconView(agent: .claude, size: 14)
|
||||||
Text("Claude")
|
Text("Claude")
|
||||||
.font(.system(size: 13, weight: .semibold))
|
.font(.system(size: 13, weight: .semibold))
|
||||||
Text("· \(vm.planLabel) · \(limit.window.label)")
|
Text("· \(vm.planLabel)")
|
||||||
.font(.system(size: 11))
|
.font(.system(size: 11))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -773,25 +789,23 @@ struct SettingsView: View {
|
|||||||
.padding(.vertical, 1)
|
.padding(.vertical, 1)
|
||||||
.background(Color.primary.opacity(0.06))
|
.background(Color.primary.opacity(0.06))
|
||||||
.cornerRadius(4)
|
.cornerRadius(4)
|
||||||
if updater.updateAvailable {
|
}
|
||||||
Text("v\(updater.latestVersion) available")
|
if updater.updateAvailable {
|
||||||
.font(.system(size: 10, weight: .medium))
|
Text("v\(updater.latestVersion) available")
|
||||||
.foregroundColor(.white)
|
.font(.system(size: 10, weight: .medium))
|
||||||
.padding(.horizontal, 6)
|
.foregroundColor(.white)
|
||||||
.padding(.vertical, 2)
|
.padding(.horizontal, 6)
|
||||||
.background(Color.blue)
|
.padding(.vertical, 2)
|
||||||
.cornerRadius(4)
|
.background(Color.blue)
|
||||||
.fixedSize()
|
.cornerRadius(4)
|
||||||
} else if updater.betaAvailable {
|
} else if updater.betaAvailable {
|
||||||
Text("v\(updater.latestBetaVersion) available")
|
Text("v\(updater.latestBetaVersion) available")
|
||||||
.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")
|
||||||
.font(.system(size: 11))
|
.font(.system(size: 11))
|
||||||
@@ -1024,20 +1038,14 @@ struct UpdateBanner: View {
|
|||||||
VStack(alignment: .leading, spacing: 1) {
|
VStack(alignment: .leading, spacing: 1) {
|
||||||
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 {
|
Text("Tap Update to view what's new & install.")
|
||||||
ReleaseNotesText(text: updater.releaseNotes, font: .system(size: 11))
|
.font(.system(size: 11))
|
||||||
}
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("Update") { showSheet = true }
|
Button("Update") { showSheet = true }
|
||||||
.buttonStyle(.borderedProminent)
|
.buttonStyle(.borderedProminent)
|
||||||
.controlSize(.small)
|
.controlSize(.small)
|
||||||
Button { updater.updateAvailable = false } label: {
|
|
||||||
Image(systemName: "xmark")
|
|
||||||
.font(.system(size: 10, weight: .medium))
|
|
||||||
.foregroundColor(.secondary)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
|
|||||||
@@ -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.10</string>
|
<string>1.1.3-beta.1</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>30</string>
|
<string>35</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>13.0</string>
|
<string>13.0</string>
|
||||||
<key>LSUIElement</key>
|
<key>LSUIElement</key>
|
||||||
|
|||||||
@@ -24,21 +24,27 @@ struct LoginWebView: NSViewRepresentable {
|
|||||||
|
|
||||||
class Coordinator: NSObject, WKNavigationDelegate {
|
class Coordinator: NSObject, WKNavigationDelegate {
|
||||||
let onAuthenticated: () -> Void
|
let onAuthenticated: () -> Void
|
||||||
|
var didAuthenticate = false
|
||||||
|
|
||||||
init(onAuthenticated: @escaping () -> Void) {
|
init(onAuthenticated: @escaping () -> Void) {
|
||||||
self.onAuthenticated = onAuthenticated
|
self.onAuthenticated = onAuthenticated
|
||||||
}
|
}
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||||
|
guard !didAuthenticate else { return }
|
||||||
|
// Don't fire on the login/auth pages themselves
|
||||||
|
if let url = webView.url?.absoluteString,
|
||||||
|
url.contains("/login") || url.contains("/auth") { return }
|
||||||
|
|
||||||
WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
|
WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
|
||||||
let hasSession = cookies.contains {
|
let hasSession = cookies.contains {
|
||||||
$0.domain.contains("claude.ai") &&
|
$0.domain.contains("claude.ai") &&
|
||||||
($0.name == "sessionKey" || $0.name == "__Secure-next-auth.session-token")
|
($0.name == "sessionKey" || $0.name == "__Secure-next-auth.session-token")
|
||||||
}
|
}
|
||||||
if hasSession {
|
guard hasSession, !self.didAuthenticate else { return }
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
self.didAuthenticate = true
|
||||||
self.onAuthenticated()
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
}
|
self.onAuthenticated()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,9 +64,18 @@ struct LoginSheetView: View {
|
|||||||
Text(authenticated ? "✓ Signed in — loading data…" : "Sign in to Claude")
|
Text(authenticated ? "✓ Signed in — loading data…" : "Sign in to Claude")
|
||||||
.font(.system(size: 13, weight: .semibold))
|
.font(.system(size: 13, weight: .semibold))
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("Cancel") { isPresented = false }
|
if authenticated {
|
||||||
.buttonStyle(.bordered)
|
Button("Done") {
|
||||||
|
isPresented = false
|
||||||
|
onDone()
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
.controlSize(.small)
|
.controlSize(.small)
|
||||||
|
} else {
|
||||||
|
Button("Cancel") { isPresented = false }
|
||||||
|
.buttonStyle(.bordered)
|
||||||
|
.controlSize(.small)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 14)
|
.padding(.horizontal, 14)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
|
|||||||
@@ -318,13 +318,31 @@ class UpdateManager: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func isNewer(_ version: String, than current: String) -> Bool {
|
private func isNewer(_ version: String, than current: String) -> Bool {
|
||||||
let toInts = { (v: String) in v.split(separator: ".").compactMap { Int($0) } }
|
func parse(_ v: String) -> (base: [Int], pre: [Int]?) {
|
||||||
let a = toInts(version), b = toInts(current)
|
guard !v.isEmpty else { return ([], nil) }
|
||||||
for i in 0..<max(a.count, b.count) {
|
let halves = v.split(separator: "-", maxSplits: 1)
|
||||||
let av = i < a.count ? a[i] : 0
|
let base = halves[0].split(separator: ".").compactMap { Int($0) }
|
||||||
let bv = i < b.count ? b[i] : 0
|
let pre = halves.count > 1 ? String(halves[1]).split(separator: ".").compactMap { Int($0) } : nil
|
||||||
|
return (base, pre)
|
||||||
|
}
|
||||||
|
let a = parse(version), b = parse(current)
|
||||||
|
// Compare base version numbers
|
||||||
|
for i in 0..<max(a.base.count, b.base.count) {
|
||||||
|
let av = i < a.base.count ? a.base[i] : 0
|
||||||
|
let bv = i < b.base.count ? b.base[i] : 0
|
||||||
if av != bv { return av > bv }
|
if av != bv { return av > bv }
|
||||||
}
|
}
|
||||||
|
// Base equal: stable beats pre-release
|
||||||
|
if a.pre == nil && b.pre != nil { return true }
|
||||||
|
if a.pre != nil && b.pre == nil { return false }
|
||||||
|
// Both pre-release: compare pre-release numbers
|
||||||
|
if let ap = a.pre, let bp = b.pre {
|
||||||
|
for i in 0..<max(ap.count, bp.count) {
|
||||||
|
let av = i < ap.count ? ap[i] : 0
|
||||||
|
let bv = i < bp.count ? bp[i] : 0
|
||||||
|
if av != bv { return av > bv }
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +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)
|
||||||
|
<!-- BETA_BADGE -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
## What's new in v1.0.10
|
## What's new in v1.1.3
|
||||||
|
|
||||||
### Main window always opens on click
|
### Compact update banner
|
||||||
Closing 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.
|
The in-app update banner no longer shows full release notes — it now shows a short message and lets you tap Update to read what's new in the install sheet. This prevents the banner from pushing content around when release notes are long.
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"version": "1.1.2-beta.7",
|
||||||
|
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.1.2-beta.7/ClaudeChecker.zip",
|
||||||
|
"notes": "## What's new in v1.1.2\n\n### Cleaner card headers\nRemoved the redundant \"5h\" / \"7d\" window labels from each card row — the section headers already make it clear which limit is which."
|
||||||
|
}
|
||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.1.0",
|
"version": "1.1.2",
|
||||||
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.1.0/ClaudeChecker.zip",
|
"url": "https://github.com/superdooper86/claudechecker/releases/download/v1.1.2/ClaudeChecker.zip",
|
||||||
"notes": "## What's new in v1.1.0\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": "## What's new in v1.1.2\n\n### Cleaner usage cards\nRemoved the redundant \"5h\" / \"7d\" labels from each card row — the section headers already make it clear which limit is which.\n\n### Beta update support\nThe app now correctly detects and compares beta versions (e.g. v1.1.2-beta.2 > v1.1.2-beta.1) when the beta channel is enabled in Settings. Stable releases also correctly supersede beta builds of the same version — so users on a beta are prompted to install the final release.\n\n### Fixed crash when enabling beta channel\nEnabling the beta toggle could crash the app if no stable update was available. This is now fixed.\n\n### Fixed settings panel truncation\nThe app name and version number no longer get cut off when an update badge is displayed in Settings."
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user