Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
6ff5751
fix(opentrack): restore the tray popup and round its corners
bircni Nov 8, 2026
07df36e
build: add the Rust workspace for the 5.0 rewrite
bircni Nov 8, 2026
1ccbeec
feat(core): write JSON numbers and sort keys as 4.x does
bircni Nov 8, 2026
578fe32
feat(core): add calendar days and JS-compatible timestamp parsing
bircni Nov 8, 2026
0e5d6c5
feat(core): port model ids, project remotes and machine names
bircni Nov 8, 2026
e755175
feat(core): add environment, config and the Core context
bircni Nov 8, 2026
b9be522
feat(core): add the machine file and token count types
bircni Nov 8, 2026
6b240cc
build: name the CLI binary aitrack again
bircni Nov 8, 2026
14852d4
feat(core): port the Claude and Codex log readers
bircni Nov 8, 2026
74fbfae
test(core): keep the reader corpus bytes exact in git
bircni Nov 8, 2026
adb27d8
feat(core): add the parse cache, scan pool and provider read pipeline
bircni Nov 8, 2026
ad8df14
test(core): add a day dump for comparing readers on real logs
bircni Nov 8, 2026
ad05dd5
feat(core): port pricing, the pricing pack store and an HTTP seam
bircni Nov 8, 2026
cdfbc34
feat(core): port machine-file validation, encryption, merges and comp…
bircni Nov 8, 2026
60494e8
feat(core): add the provider registry and the usage-data loader
bircni Nov 8, 2026
ab87ba6
feat(core): port git sync, recompute-costs and machine renames
bircni Nov 8, 2026
d5d735d
feat(core): port live quotas and the Cursor export reader
bircni Nov 8, 2026
28955c9
feat(core): port usage reports, periods, rankings and project breakdowns
bircni Nov 8, 2026
28b9e3c
test(core): pin quotas, pacing and Cursor's export to 4.x
bircni Nov 8, 2026
1db202a
build(npm): ship the CLI as a launcher with one package per platform
bircni Nov 8, 2026
02e7d75
feat(core): port the terminal, CSV, PDF and PNG renderers
bircni Nov 8, 2026
646123f
test(core): pin display output to 4.x
bircni Nov 8, 2026
c865294
Merge branch 'worktree-agent-ae36800b502477d21' into rust
bircni Nov 8, 2026
13b9eb3
feat(opentrack): fold the Node sidecar into the Rust app
bircni Nov 8, 2026
1cd77c2
feat(cli): port the aitrack CLI to Rust
bircni Nov 8, 2026
9c287c2
Merge branch 'worktree-agent-a88dc9000766f2e65' into rust
bircni Nov 8, 2026
59c0f60
fix(cli): accept --providers without a clap type panic
bircni Nov 8, 2026
0cc7f4b
perf(core): ask git for every scanned repository side by side
bircni Nov 8, 2026
4ce0caf
test: diff the Rust CLI against 4.x in four time zones
bircni Nov 8, 2026
c2504c4
test: pin goldens to jiff's tzdb and isolate the smoke home on Windows
bircni Nov 8, 2026
1a2e77d
test: run goldens on jiff's bundled tzdb and fix Windows path expecta…
bircni Nov 8, 2026
f2569e1
build: release the CLI binaries and version everything from Cargo.toml
bircni Nov 8, 2026
6f29a40
ci: check out the README the npm launcher package ships
bircni Nov 8, 2026
0f2271c
refactor(opentrack-ui): vendor the helpers it took from aitrack-lib
bircni Nov 8, 2026
bfb2f96
build!: remove the 4.x TypeScript tree and Nx
bircni Nov 8, 2026
f6e5223
build(xtask): build and check the pricing pack in Rust
bircni Nov 8, 2026
ae0843a
build(release): cut every release from main again
bircni Nov 8, 2026
fb1092a
docs: describe aitrack 5.0 and retire the library guide
bircni Nov 8, 2026
c5dcc13
Merge remote-tracking branch 'origin/main' into rust
bircni Nov 8, 2026
3d47342
Merge branch 'rust-cutover' into rust
bircni Nov 8, 2026
885e43a
build: keep the TypeScript 7 compiler the type checks call as tsc
bircni Nov 8, 2026
56492a7
build: drop the 4.x fixture generators and the unused coverage setup
bircni Nov 8, 2026
9edf66f
chore: untrack local coverage reports committed by mistake
bircni Nov 8, 2026
fc392c0
ci: run on pushes to main only, not also on the PR branch
bircni Nov 8, 2026
73b15ac
chore: format the oxlint config
bircni Nov 8, 2026
4ff3f00
refactor(core): move opentrack's release download and install into core
bircni Nov 8, 2026
30dc00a
build(xtask): port the release and packaging scripts to Rust
bircni Nov 8, 2026
0503e99
build!: drop the JavaScript toolchain
bircni Nov 8, 2026
ffdaddc
feat(opentrack): draw the popup natively with egui instead of a webview
bircni Nov 8, 2026
d9f1eed
build(opentrack): package with cargo-packager in Tauri's bundle layout
bircni Nov 8, 2026
9c3c461
build(opentrack)!: remove the Svelte renderer and Tauri config
bircni Nov 8, 2026
8b9cafb
Merge branch 'native-opentrack' into rust
bircni Nov 8, 2026
717791e
fix(opentrack): start hidden, open on the first tray click and keep t…
bircni Nov 8, 2026
2a38aa7
fix(opentrack): build the tray and the tests on Windows
bircni Nov 8, 2026
2c296bd
refactor(core): share semver, heatmap levels, digit grouping and byte…
bircni Nov 8, 2026
7e70c01
fix(opentrack): relaunch after updates, place the popup per monitor a…
bircni Nov 8, 2026
8852b70
refactor(xtask): one table of installer names, one command runner and…
bircni Nov 8, 2026
d67160f
ci: lint and build Windows from Ubuntu instead of a Windows runner
bircni Nov 8, 2026
ce997ed
ci: check Linux on pull requests and run macOS and Windows on demand
bircni Nov 8, 2026
6f679bf
fix(opentrack): hand updates the lock, keep .deb notices and order saves
bircni Nov 8, 2026
a18c55c
refactor(xtask): run commands through core and take updater keys from it
bircni Nov 8, 2026
e66d0fd
fix(opentrack): open the popup on every tray click
bircni Nov 8, 2026
fb0fd89
fix(opentrack): import the GDK monitor trait for the Linux work area
bircni Nov 8, 2026
efcf450
build(xtask): release only after CI and Platforms pass on the commit
bircni Nov 8, 2026
b0f8b8d
build: drop just for cargo aliases and xtask commands
bircni Nov 8, 2026
814e705
build: lint the whole workspace with the cargo-* rule set
bircni Nov 8, 2026
b2b26b5
refactor: apply clippy's suggested fixes and give every lint exceptio…
bircni Nov 8, 2026
aceab40
refactor: recover poisoned locks, justify every expect and document e…
bircni Nov 8, 2026
aecbae0
refactor: apply clippy's suggestions for match arms, Option chains an…
bircni Nov 8, 2026
d62d18d
build: make cargo lint report every crate's warnings before failing
bircni Nov 8, 2026
f740069
fix: More lints manually
bircni Nov 8, 2026
438d76f
refactor(opentrack): map the optional usage at the call site
bircni Nov 8, 2026
15549a5
chore: format
bircni Nov 8, 2026
9d54540
refactor: satisfy the lint set in the Linux- and Windows-only code
bircni Nov 8, 2026
c79cb5c
build: lint float comparisons and truncating casts again
bircni Nov 8, 2026
b18af08
refactor: convert JavaScript millisecond times in one place
bircni Nov 8, 2026
be5e0cf
refactor: state the real bound behind every cast exception
bircni Nov 8, 2026
8db9334
fix(core): report a missing random source instead of panicking while …
bircni Nov 8, 2026
6462c40
refactor: justify each remaining expect precisely or drop it
bircni Nov 8, 2026
47caa0f
refactor: split long UI functions and scope the remaining exceptions
bircni Nov 8, 2026
2d16543
refactor: serialize the workspace's own data through one infallible h…
bircni Nov 8, 2026
df4ba96
refactor: let types and iterators carry what the expects assumed
bircni Nov 8, 2026
41ec72c
refactor(core): saturate calendar arithmetic at the years a data file…
bircni Nov 8, 2026
833c3e4
refactor(core): format numbers without re-parsing their own output
bircni Nov 8, 2026
812ff9e
refactor: parse embedded data in one place each and pin it with tests
bircni Nov 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[alias]
xtask = "run --quiet --package xtask --"
# Warnings fail the run at the end instead of stopping at the first crate, so every crate is linted;
# extra arguments (`cargo lint -p aitrack-core`) reach cargo.
lint = ["clippy", "--all-targets", "--keep-going", "--config", "build.warnings='deny'"]
# opentrack in debug; a separate data dir keeps it apart from an installed copy
dev = "run --package opentrack -- --data-dir target/opentrack-dev"
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
* text=auto eol=lf
# Reader corpora test exact bytes: CRLF lines and invalid UTF-8.
crates/core/tests/fixtures/readers/corpus/** -text
15 changes: 15 additions & 0 deletions .githooks/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh
# Conventional Commits: the changelog and release notes are generated from them.
header=$(head -n 1 "$1")
case "$header" in
Merge\ * | Revert\ * | fixup!\ * | squash!\ *) exit 0 ;;
esac
if ! printf '%s\n' "$header" | grep -Eq '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|test)(\([^)]+\))?!?: [^ ]'; then
echo "commit-msg: \"$header\" is not <type>(<scope>)?!?: <subject>" >&2
echo "commit-msg: types are build, chore, ci, docs, feat, fix, perf, refactor, revert, test" >&2
exit 1
fi
if [ "${#header}" -gt 100 ]; then
echo "commit-msg: the header is ${#header} characters; keep it to 100" >&2
exit 1
fi
6 changes: 6 additions & 0 deletions .github/actions/setup-rust/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
name: Set up Rust
description: Install the toolchain pinned in rust-toolchain.toml
inputs:
targets:
description: Extra targets to install, comma-separated
required: false
default: ''
runs:
using: composite
steps:
Expand All @@ -19,3 +24,4 @@ runs:
with:
toolchain: ${{ steps.toolchain.outputs.version }}
components: ${{ steps.toolchain.outputs.components }}
targets: ${{ inputs.targets }}
26 changes: 1 addition & 25 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
version: 2
updates:
- package-ecosystem: bun
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
# Let a compromised release get caught and yanked before it is proposed; security updates skip this.
cooldown:
default-days: 7
# One PR per weekly run instead of a dozen: dev tooling and runtime deps
# each move together, and majors stay separate so they get a real look.
groups:
# Before the groups below: Tauri's api (runtime) and cli (dev) must move together.
tauri:
patterns: ['@tauri-apps/*']
runtime:
dependency-type: production
update-types: [minor, patch]
dev:
dependency-type: development
update-types: [minor, patch]
commit-message:
prefix: chore
prefix-development: chore
include: scope

- package-ecosystem: cargo
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
# Let a compromised release get caught and yanked before it is proposed; security updates skip this.
cooldown:
default-days: 7
groups:
Expand Down
215 changes: 33 additions & 182 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: CI

on:
push:
# main runs fill the Rust and Nx caches that pull requests restore.
branches: [main]
pull_request:
branches: [main]
Expand All @@ -15,223 +14,75 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
CARGO_INCREMENTAL: 0
CARGO_TERM_COLOR: always

jobs:
audit:
name: Audit
name: Audit (Rust)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Lint workflows
uses: docker://rhysd/actionlint@sha256:b1934ee5f1c509618f2508e6eb47ee0d3520686341fec936f3b79331f9315667 # 1.7.12
with:
args: -color

- name: Review dependency changes
if: github.event_name == 'pull_request'
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: high

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: package.json

# Audit reads only the lockfile, so it needs no install.
- run: bun audit --audit-level=high

- uses: taiki-e/install-action@3a3daafd3b7f23b8f65d9f5ba2db203fb59b79e2 # v2
with:
tool: cargo-audit
tool: cargo-deny

# Fails on vulnerabilities; unmaintained and yanked crates stay warnings.
- run: cargo audit
- run: cargo deny check advisories sources

test:
name: Check
lint:
name: Lint (Rust)
runs-on: ubuntu-latest
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
# `nx affected` diffs against the merge base, which a shallow clone
# does not have; a blobless clone keeps the history without old file contents.
fetch-depth: 0
filter: blob:none

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: package.json

- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version-file: .node-version

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Set up Rust
uses: ./.github/actions/setup-rust

- uses: nrwl/nx-set-shas@e602fada7ad5987b0f7b1905e7a99ea1c661514c # v5.1.0

# One run lets Nx schedule the checks in parallel. The desktop matrix, Linux
# included, checks the Rust shell with its system libraries.
- name: Format, lint, typecheck, unused, test and build
run: bun nx affected -t format:check,lint,typecheck,check:unused,test,build --configuration ci --exclude opentrack

# Separate from the unit tests, which would otherwise pick up SMOKE_CLI too.
- name: CLI smoke tests and publish tarballs
run: bun nx affected -t test:smoke,package:check
env:
SMOKE_CLI: dist/cli.js

# `engines` promises this to users, while everything else runs on .node-version.
node-floor:
name: Check (Node 24)
runs-on: ubuntu-latest
env:
NX_NO_CLOUD: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
filter: blob:none

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with:
bun-version-file: package.json
shared-key: lint
save-if: ${{ github.ref == 'refs/heads/main' }}

- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version: 24
- name: Install GTK
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libayatana-appindicator3-dev libxdo-dev

- name: Install dependencies
run: bun install --frozen-lockfile
- run: cargo fmt --all --check

- name: Set up Rust
uses: ./.github/actions/setup-rust
- run: cargo lint

- uses: nrwl/nx-set-shas@e602fada7ad5987b0f7b1905e7a99ea1c661514c # v5.1.0

# Skip the cache: Nx does not hash the Node version into these test results.
- name: Test the published packages
run: bun nx affected -t test --exclude repo-tools,opentrack,opentrack-ui --skip-nx-cache

- name: CLI smoke tests
run: bun nx affected -t test:smoke --skip-nx-cache
env:
SMOKE_CLI: dist/cli.js

cross-platform:
name: Check (${{ matrix.os }})
runs-on: ${{ matrix.os }}
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
# Avoid the native runner's allocation crash after successful Windows tasks.
NX_NATIVE_COMMAND_RUNNER: ${{ matrix.os == 'windows-latest' && 'false' || 'true' }}
# Debug info only slows the clippy and test builds; nothing here is debugged.
CARGO_PROFILE_DEV_DEBUG: 0
# These packages only prove the bundle works; Publish keeps the size-tuned profile.
CARGO_PROFILE_RELEASE_LTO: false
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 16
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
platform: macos-arm64
installer: target/release/bundle/dmg/*.dmg
cargo-jobs: 3
- os: windows-latest
platform: windows-x64
installer: target/release/bundle/nsis/*.exe
cargo-jobs: 2
- os: ubuntu-24.04 # The release image, so packaging breaks here before it does at a tag.
platform: linux-x64
installer: |
target/release/bundle/appimage/*.AppImage
target/release/bundle/deb/*.deb
cargo-jobs: 4
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
filter: blob:none

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version-file: package.json

- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version-file: .node-version

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Set up Rust
uses: ./.github/actions/setup-rust

- uses: nrwl/nx-set-shas@e602fada7ad5987b0f7b1905e7a99ea1c661514c # v5.1.0

# The Ubuntu Check job already runs these on Linux.
- name: CLI smoke tests and publish tarballs
if: runner.os != 'Linux'
run: bun nx affected -t test:smoke,package:check
env:
SMOKE_CLI: dist/cli.js
- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with:
shared-key: test
save-if: ${{ github.ref == 'refs/heads/main' }}

# A pull request that cannot change the desktop app skips its Rust build.
- name: Check whether Opentrack is affected
id: opentrack
shell: bash
run: |
affected=true
if [ "$GITHUB_EVENT_NAME" = pull_request ]; then
projects=$(bun nx show projects --affected -p opentrack --json)
[[ $projects == *'"opentrack"'* ]] || affected=
fi
echo "affected=$affected" >> "$GITHUB_OUTPUT"

- name: Install Linux desktop libraries
if: runner.os == 'Linux' && steps.opentrack.outputs.affected
# Not cached: the caching action saves an empty cache when a mirror 404s, failing every later run.
- name: Install GTK
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev libxdo-dev libssl-dev patchelf
sudo apt-get install -y libgtk-3-dev libayatana-appindicator3-dev libxdo-dev

- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
if: steps.opentrack.outputs.affected
with:
# Pull request caches are visible only to that pull request; main's serve them all.
save-if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' }}

- name: Check Rust formatting
if: steps.opentrack.outputs.affected
run: bun nx run opentrack:format:check

# The Rust shell embeds the renderer and bundles the native Node sidecar;
# Nx builds those dependencies without running their JS checks or tests.
- name: Lint Rust
if: steps.opentrack.outputs.affected
run: bun nx run opentrack:lint

- name: Test Rust
if: steps.opentrack.outputs.affected
run: bun nx run opentrack:test

- name: Package and check Opentrack
if: steps.opentrack.outputs.affected
run: bun nx run opentrack:bundle:check
env:
CARGO_BUILD_JOBS: ${{ matrix.cargo-jobs }}

- name: Upload installer artifact
if: steps.opentrack.outputs.affected
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
- uses: taiki-e/install-action@3a3daafd3b7f23b8f65d9f5ba2db203fb59b79e2 # v2
with:
name: opentrack-${{ matrix.platform }}
path: ${{ matrix.installer }}
if-no-files-found: error
tool: cargo-nextest

- run: cargo nextest run --workspace

39 changes: 39 additions & 0 deletions .github/workflows/platforms.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Platforms

# macOS and Windows runners cost far more than Linux, so pull requests check Linux only and these run
# on demand, e.g. before a release or after platform-specific changes.
on:
workflow_dispatch:

permissions:
contents: read

env:
CARGO_INCREMENTAL: 0
CARGO_TERM_COLOR: always

jobs:
check:
name: Lint and test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Set up Rust
uses: ./.github/actions/setup-rust

- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with:
shared-key: platforms

- uses: taiki-e/install-action@3a3daafd3b7f23b8f65d9f5ba2db203fb59b79e2 # v2
with:
tool: cargo-nextest

- run: cargo lint

- run: cargo nextest run --workspace
Loading
Loading