Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8e52a09
feat: Add Windows support
samlehoy May 30, 2026
d4f0783
chore: bump version to 0.6.25
samlehoy May 30, 2026
2706370
fix: correct github action shell for windows
samlehoy May 31, 2026
d561e46
fix: move secrets check to bash script
samlehoy May 31, 2026
948c474
fix: resolve Windows rust compilation errors and disable macos matrix
samlehoy May 31, 2026
8e2dd69
fix: gracefully disable updater on forks missing private keys
samlehoy May 31, 2026
9d818ef
fix: gracefully handle updater initialization failure
samlehoy May 31, 2026
beb7637
docs: update README to reflect Windows fork
samlehoy May 31, 2026
d6e4c5d
fix: hide console windows spawned by plugin commands on Windows
samlehoy May 31, 2026
5b15859
fix: add missing utils.rs file for windows console hiding
samlehoy May 31, 2026
3dadfea
fix: add windows specific plugin paths, enable dragging, and remove w…
samlehoy May 31, 2026
2e08a96
fix: process discovery on windows, overlapping taskbar, drag on trans…
samlehoy May 31, 2026
572e99a
feat: implement window pinning and fix antigravity detection
samlehoy May 31, 2026
2392c4b
fix: port discovery with netstat on windows, add startDragging permis…
samlehoy May 31, 2026
3f5ee17
fix: cursor db path on windows and os-agnostic error messages
samlehoy May 31, 2026
a1e40ab
chore: bump version to 0.6.37
samlehoy May 31, 2026
d421866
fix: implement native rusqlite for windows cursor detection and fix w…
samlehoy May 31, 2026
8584e9a
fix: remove unused imports and functions to fix tsc errors
samlehoy May 31, 2026
a4dc731
docs: update screenshot for windows
samlehoy Jun 1, 2026
d719a6c
docs: add windows specific features to readme
samlehoy Jun 1, 2026
f5b9a2f
docs: add known issues section to readme
samlehoy Jun 1, 2026
4ff643d
chore: restore original readme and screenshot for PR
samlehoy Jun 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ jobs:
fail-fast: false
matrix:
include:
- platform: macos-latest
args: "--target aarch64-apple-darwin"
- platform: macos-latest
args: "--target x86_64-apple-darwin"
- platform: windows-latest
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Release workflow matrix removed all macOS build targets, breaking macOS releases while the Apple certificate step still expects a macos-latest platform that no longer exists.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/publish.yml, line 18:

<comment>Release workflow matrix removed all macOS build targets, breaking macOS releases while the Apple certificate step still expects a `macos-latest` platform that no longer exists.</comment>

<file context>
@@ -15,10 +15,8 @@ jobs:
-            args: "--target aarch64-apple-darwin"
-          - platform: macos-latest
-            args: "--target x86_64-apple-darwin"
+          - platform: windows-latest
+            args: "--target x86_64-pc-windows-msvc"
     runs-on: ${{ matrix.platform }}
</file context>
Fix with Cubic

args: "--target x86_64-pc-windows-msvc"
Comment on lines 17 to +19
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Matrix now only includes Windows, removing macOS builds.

The matrix has been replaced to only target Windows, effectively removing macOS builds from this workflow. This contradicts the PR's goal of "preserving macOS compatibility" and would prevent macOS releases from being published.

The matrix should include both platforms:

🐛 Proposed fix to restore macOS targets
     matrix:
       include:
         - platform: windows-latest
           args: "--target x86_64-pc-windows-msvc"
+        - platform: macos-latest
+          args: "--target aarch64-apple-darwin"
+        - platform: macos-latest
+          args: "--target x86_64-apple-darwin"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
include:
- platform: macos-latest
args: "--target aarch64-apple-darwin"
- platform: macos-latest
args: "--target x86_64-apple-darwin"
- platform: windows-latest
args: "--target x86_64-pc-windows-msvc"
include:
- platform: windows-latest
args: "--target x86_64-pc-windows-msvc"
- platform: macos-latest
args: "--target aarch64-apple-darwin"
- platform: macos-latest
args: "--target x86_64-apple-darwin"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 17 - 19, The workflow matrix
currently only includes the "platform: windows-latest" entry with "args:
--target x86_64-pc-windows-msvc", removing macOS builds; restore macOS by adding
a matrix entry for "platform: macos-latest" with the appropriate build args
(e.g., "--target x86_64-apple-darwin" or your macOS target triple) alongside the
existing Windows entry so both platforms are included in the matrix.

runs-on: ${{ matrix.platform }}
env:
RELEASE_TAG: ${{ github.ref_name }}
Expand All @@ -29,7 +27,7 @@ jobs:

- uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin,x86_64-apple-darwin
targets: aarch64-apple-darwin,x86_64-apple-darwin,x86_64-pc-windows-msvc
Comment on lines 28 to +30
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Apple Darwin targets installed but matrix has no macOS runner.

The Rust toolchain installs aarch64-apple-darwin and x86_64-apple-darwin targets, but the matrix only runs on windows-latest. These targets cannot be used for cross-compilation from Windows (requires macOS SDK). If macOS builds are restored to the matrix, each runner should only install the targets it needs.

🛠️ Proposed fix: make targets platform-specific
       - uses: dtolnay/rust-toolchain@stable
         with:
-          targets: aarch64-apple-darwin,x86_64-apple-darwin,x86_64-pc-windows-msvc
+          targets: ${{ contains(matrix.platform, 'macos') && 'aarch64-apple-darwin,x86_64-apple-darwin' || 'x86_64-pc-windows-msvc' }}

Alternatively, define targets in each matrix entry for clarity.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 28-28: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 28 - 30, The workflow installs
macOS Rust targets via the dtolnay/rust-toolchain action but the job matrix only
uses windows-latest, causing invalid cross-target installs; either add macOS
runners to the matrix (e.g., macos-latest) and limit each runner's
dtolnay/rust-toolchain "targets" to only that runner's needed targets, or keep
windows-latest only and remove the aarch64-apple-darwin and x86_64-apple-darwin
entries from the "targets" list; update the action invocation (the
dtolnay/rust-toolchain step) or define per-matrix "targets" so each matrix entry
installs only the platform-appropriate Rust targets.

- uses: swatinem/rust-cache@v2
with:
workspaces: "./src-tauri -> target"
Expand All @@ -41,6 +39,7 @@ jobs:
- name: Bundle plugins
run: bun run bundle:plugins
- name: Verify bundled plugins
shell: bash
run: |
COUNT=$(find src-tauri/resources/bundled_plugins -maxdepth 2 -name plugin.json | wc -l | tr -d ' ')
if [[ "$COUNT" -lt 1 ]]; then
Expand All @@ -49,6 +48,7 @@ jobs:
fi

- name: Validate release tag
shell: bash
run: |
if [[ -z "$RELEASE_TAG" ]]; then
echo "Missing RELEASE_TAG (push a v* tag)."
Expand All @@ -60,6 +60,7 @@ jobs:
fi

- name: Validate app version matches tag
shell: bash
run: |
TAG_VERSION="${RELEASE_TAG#v}"

Expand All @@ -81,11 +82,16 @@ jobs:
fi

- name: Import Apple Developer Certificate
if: matrix.platform == 'macos-latest'
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
if [[ -z "$APPLE_CERTIFICATE" ]]; then
echo "Skipping Apple Certificate import because secret is empty."
exit 0
fi
echo "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security default-keychain -s build.keychain
Expand All @@ -95,6 +101,24 @@ jobs:
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
rm certificate.p12

- name: Handle missing updater key (for forks)
shell: bash
env:
TAURI_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
run: |
if [[ -z "$TAURI_KEY" ]]; then
echo "HAS_TAURI_KEY=false" >> $GITHUB_ENV
node -e "
const fs = require('fs');
const conf = JSON.parse(fs.readFileSync('./src-tauri/tauri.conf.json'));
if(conf.bundle) conf.bundle.createUpdaterArtifacts = false;
if(conf.plugins && conf.plugins.updater) delete conf.plugins.updater;
fs.writeFileSync('./src-tauri/tauri.conf.json', JSON.stringify(conf, null, 2));
"
else
echo "HAS_TAURI_KEY=true" >> $GITHUB_ENV
fi

- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -114,10 +138,12 @@ jobs:
releaseName: ${{ env.RELEASE_TAG }}
releaseDraft: false
prerelease: false
includeUpdaterJson: true
includeUpdaterJson: ${{ env.HAS_TAURI_KEY == 'true' }}
args: ${{ matrix.args }}

- name: Verify updater assets uploaded
if: env.HAS_TAURI_KEY == 'true'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## v0.6.37
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align release notes metadata with the shipped version and canonical repo links.

Line 3 documents v0.6.37, but this PR bumps app versions to 0.6.39 (in package.json and src-tauri/tauri.conf.json). Also, Lines 12–14 switch links to samlehoy/openusage while the rest of this changelog uses robinebers/openusage; that inconsistency can break release/compare navigation after merge.

Also applies to: 12-14

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 3, Update the release metadata in CHANGELOG.md so the
header "v0.6.37" matches the bumped app version (change it to "v0.6.39") and fix
the repository links on lines that reference "samlehoy/openusage" to use the
canonical "robinebers/openusage" so links are consistent with the rest of the
changelog and the package.json/tauri.conf.json version bump.


### Bug Fixes
- fix: cursor db path on windows and os-agnostic error messages by @Native Muttaqien

---

### Changelog

**Full Changelog**: [v0.6.36...v0.6.37](https://github.com/samlehoy/openusage/compare/v0.6.36...v0.6.37)

- [3f5ee17](https://github.com/samlehoy/openusage/commit/3f5ee17) fix: cursor db path on windows and os-agnostic error messages by @Native Muttaqien
Comment on lines +12 to +14
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Incorrect repository owner in v0.6.37 changelog links breaks URLs

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CHANGELOG.md, line 12:

<comment>Incorrect repository owner in v0.6.37 changelog links breaks URLs</comment>

<file context>
@@ -1,5 +1,18 @@
+
+### Changelog
+
+**Full Changelog**: [v0.6.36...v0.6.37](https://github.com/samlehoy/openusage/compare/v0.6.36...v0.6.37)
+
+- [3f5ee17](https://github.com/samlehoy/openusage/commit/3f5ee17) fix: cursor db path on windows and os-agnostic error messages by @Native Muttaqien
</file context>
Suggested change
**Full Changelog**: [v0.6.36...v0.6.37](https://github.com/samlehoy/openusage/compare/v0.6.36...v0.6.37)
- [3f5ee17](https://github.com/samlehoy/openusage/commit/3f5ee17) fix: cursor db path on windows and os-agnostic error messages by @Native Muttaqien
+**Full Changelog**: [v0.6.36...v0.6.37](https://github.com/robinebers/openusage/compare/v0.6.36...v0.6.37)
+
+- [3f5ee17](https://github.com/robinebers/openusage/commit/3f5ee17) fix: cursor db path on windows and os-agnostic error messages by @Native Muttaqien
Fix with Cubic


## v0.6.24

### New Features
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "openusage",
"private": true,
"version": "0.6.24",
"version": "0.6.39",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
9 changes: 6 additions & 3 deletions plugins/antigravity/plugin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(function () {
var LS_SERVICE = "exa.language_server_pb.LanguageServerService"
var STATE_DB = "~/Library/Application Support/Antigravity/User/globalStorage/state.vscdb"
var STATE_DB_MAC = "~/Library/Application Support/Antigravity/User/globalStorage/state.vscdb"
var STATE_DB_WIN = "~/AppData/Roaming/Antigravity/User/globalStorage/state.vscdb"
var CLOUD_CODE_URLS = [
"https://daily-cloudcode-pa.googleapis.com",
"https://cloudcode-pa.googleapis.com",
Expand Down Expand Up @@ -94,8 +95,9 @@

function loadOAuthTokens(ctx) {
try {
var dbPath = ctx.app.platform === "windows" ? STATE_DB_WIN : STATE_DB_MAC
var rows = ctx.host.sqlite.query(
STATE_DB,
dbPath,
"SELECT value FROM ItemTable WHERE key = '" + OAUTH_TOKEN_KEY + "' LIMIT 1"
)
var parsed = ctx.util.tryParseJson(rows)
Expand Down Expand Up @@ -187,8 +189,9 @@
// --- LS discovery ---

function discoverLs(ctx) {
var procName = ctx.app.platform === "windows" ? "language_server.exe" : "language_server_macos"
return ctx.host.ls.discover({
processName: "language_server_macos",
processName: procName,
markers: ["antigravity"],
csrfFlag: "--csrf_token",
portFlag: "--extension_server_port",
Expand Down
8 changes: 4 additions & 4 deletions plugins/claude/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,9 @@
if (body) errorCode = body.error || body.error_description
ctx.host.log.error("refresh failed: status=" + resp.status + " error=" + String(errorCode))
if (errorCode === "invalid_grant") {
throw "Session expired. Run `claude` to log in again."
throw "Session expired. Please log in again."
}
throw "Token expired. Run `claude` to log in again."
throw "Token expired. Please log in again."
}
if (resp.status < 200 || resp.status >= 300) {
ctx.host.log.warn("refresh returned unexpected status: " + resp.status)
Expand Down Expand Up @@ -632,7 +632,7 @@
const creds = loadCredentials(ctx)
if (!creds || !creds.oauth || !creds.oauth.accessToken || !creds.oauth.accessToken.trim()) {
ctx.host.log.error("probe failed: not logged in")
throw "Not logged in. Run `claude` to authenticate."
throw "Not logged in. Please authenticate with Claude Code."
}

const nowMs = Date.now()
Expand Down Expand Up @@ -709,7 +709,7 @@

if (ctx.util.isAuthStatus(resp.status)) {
ctx.host.log.error("usage returned auth error after all retries: status=" + resp.status)
throw "Token expired. Run `claude` to log in again."
throw "Token expired. Please log in again."
}

if (resp.status === 429) {
Expand Down
7 changes: 4 additions & 3 deletions plugins/cursor/plugin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(function () {
const STATE_DB =
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
const STATE_DB = ctx.app.platform === "windows"
? "~/AppData/Roaming/Cursor/User/globalStorage/state.vscdb"
: "~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
const KEYCHAIN_ACCESS_TOKEN_SERVICE = "cursor-access-token"
const KEYCHAIN_REFRESH_TOKEN_SERVICE = "cursor-refresh-token"
const BASE_URL = "https://api2.cursor.sh"
Expand All @@ -12,7 +13,7 @@
const STRIPE_URL = "https://cursor.com/api/auth/stripe"
const CLIENT_ID = "KbZUR41cY7W6zRSdpSUJ7I7mLYBKOCmB"
const REFRESH_BUFFER_MS = 5 * 60 * 1000 // refresh 5 minutes before expiration
const LOGIN_HINT = "Sign in via Cursor app or run `agent login`."
const LOGIN_HINT = "Sign in via Cursor app."

function readStateValue(ctx, key) {
try {
Expand Down
9 changes: 6 additions & 3 deletions plugins/windsurf/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
{
marker: "windsurf",
ideName: "windsurf",
stateDb: "~/Library/Application Support/Windsurf/User/globalStorage/state.vscdb",
stateDbWin: "~/AppData/Roaming/Windsurf/User/globalStorage/state.vscdb",
stateDbMac: "~/Library/Application Support/Windsurf/User/globalStorage/state.vscdb",
},
{
marker: "windsurf-next",
ideName: "windsurf-next",
stateDb: "~/Library/Application Support/Windsurf - Next/User/globalStorage/state.vscdb",
stateDbWin: "~/AppData/Roaming/Windsurf - Next/User/globalStorage/state.vscdb",
stateDbMac: "~/Library/Application Support/Windsurf - Next/User/globalStorage/state.vscdb",
},
]

Expand All @@ -38,8 +40,9 @@

function loadApiKey(ctx, variant) {
try {
var dbPath = ctx.app.platform === "windows" ? variant.stateDbWin : variant.stateDbMac
var rows = ctx.host.sqlite.query(
variant.stateDb,
dbPath,
"SELECT value FROM ItemTable WHERE key = 'windsurfAuthStatus' LIMIT 1"
)
var parsed = ctx.util.tryParseJson(rows)
Expand Down
8 changes: 5 additions & 3 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "openusage"
version = "0.6.24"
version = "0.6.39"
description = "OpenUsage is an open source AI subscription limit tracker"
authors = ["Robin Ebers"]
edition = "2024"
Expand All @@ -21,8 +21,9 @@ tauri-build = { version = "2", features = [] }
tauri = { version = "2", features = ["macos-private-api", "tray-icon", "image-png"] }
tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tauri-nspanel = { git = "https://github.com/ahkohd/tauri-nspanel", branch = "v2.1" }
serde_json = "1.0.133"
rusqlite = { version = "0.31.0", features = ["bundled"] }

time = { version = "0.3.47", features = ["formatting"] }
dirs = "6"
log = "0.4"
Expand All @@ -44,6 +45,7 @@ aes-gcm = "0.10.3"
sha2 = "0.11"

[target.'cfg(target_os = "macos")'.dependencies]
tauri-nspanel = { git = "https://github.com/ahkohd/tauri-nspanel", branch = "v2.1" }
objc2 = "0.6"
objc2-foundation = { version = "0.3", features = ["NSProcessInfo", "NSString"] }
objc2-app-kit = { version = "0.3", features = ["NSEvent", "NSScreen", "NSGraphics"] }
Expand Down
8 changes: 8 additions & 0 deletions src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@
"core:window:allow-outer-size",
"core:window:allow-inner-size",
"core:window:allow-scale-factor",
"core:window:allow-start-dragging",
"core:window:allow-set-position",
"core:window:allow-show",
"core:window:allow-hide",
"core:window:allow-set-focus",
"core:window:allow-is-visible",
"core:window:allow-set-resizable",
"opener:default",
"store:default",
"aptabase:allow-track-event",
"updater:default",
"process:allow-restart",
"process:allow-exit",
"global-shortcut:default",
"autostart:default",
"core:menu:default"
Expand Down
Loading
Loading