Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
202 commits
Select commit Hold shift + click to select a range
e37b818
fix(tui): align scrollbar position with viewport (#694)
astkaasa Jun 9, 2026
31d070f
feat(codex): add multi-account usage controls (#696)
astkaasa Jun 9, 2026
010acd8
feat(cli): add yesterday date filter (#693)
mijanx Jun 9, 2026
839ce37
feat(kimi): support kimi-code alongside legacy kimi-cli (#682)
chi2nagisa Jun 9, 2026
54a3717
ci: update coverage badge [skip ci]
github-actions[bot] Jun 9, 2026
d469e5e
fix(ci): retry badge push with rebase to survive merge races
junhoyeo Jun 9, 2026
28aec20
feat(grok): add Grok Build subscription usage (#669)
bengHak Jun 9, 2026
6e8d08e
fix(codex): clamp click areas, stop auth.json writes on remove, cance…
junhoyeo Jun 9, 2026
7c19e08
refactor(codex): deduplicate import paths, fetch wrappers, and test s…
junhoyeo Jun 9, 2026
a8f39ec
refactor(cli): replace parallel date-filter bools with DateRangeFlags…
junhoyeo Jun 9, 2026
052f43d
refactor(kimi): detect kimi-code format structurally and dedup usage …
junhoyeo Jun 9, 2026
1b399e2
refactor(tui): rename scrollbar helper and strengthen its tests
junhoyeo Jun 9, 2026
49e07e7
ci: update coverage badge [skip ci]
github-actions[bot] Jun 9, 2026
8718113
chore: bump version to 3.1.1
github-actions[bot] Jun 9, 2026
7c3d67d
feat: multi-device support with UUID device id and multi device TUI a…
blpeng2 Jun 10, 2026
19dc2ac
fix(cli): detect musl correctly under Bun and Alpine (#700)
junhoyeo Jun 10, 2026
d9a9333
fix(frontend): allow the deployment's own origin in the CSRF allowlis…
junhoyeo Jun 10, 2026
4125839
chore: bump version to 3.1.2
github-actions[bot] Jun 10, 2026
c9111b0
feat(frontend): per-device usage breakdown on profile and settings (#…
junhoyeo Jun 10, 2026
aebe4ea
fix(pricing): parse modern Claude version from id instead of hardcodi…
xczllgit Jun 10, 2026
5017eef
fix(pricing): block brand-token fuzzy matches and prefer canonical pr…
junhoyeo Jun 14, 2026
34bdd6f
chore: bump version to 3.1.3
github-actions[bot] Jun 14, 2026
0ce3d73
feat(jcode): add support for Jcode (#718)
yousiki Jun 17, 2026
f1b440f
fix: update copyright year to use current year dynamically (#704)
wilsonwu Jun 17, 2026
d50da47
feat(kiro): add globalStorage support (#715)
leecoder Jun 17, 2026
3a68cf5
fix(codex): count user fork turns after replay (#719)
wuruoye Jun 17, 2026
18c7e87
feat(sessions): add Command Code as a tracked source (#717)
baanish Jun 17, 2026
a75533e
feat: add MiMo Code client support (#710)
LynnGuo666 Jun 17, 2026
70fd524
feat(sessions): read Antigravity CLI usage from local SQLite database…
haunchen Jun 17, 2026
8e31b29
ci: update coverage badge [skip ci]
github-actions[bot] Jun 17, 2026
46f8fff
feat(report): add multi-backend summarizer and LLM task grouping (#633)
leecoder Jun 17, 2026
1759b47
test(cli): add micode + antigravity-cli to legacy-flag filter test ro…
junhoyeo Jun 18, 2026
6a6fd5f
test(cli): drop antigravity-cli from legacy-flag roster (it has no bo…
junhoyeo Jun 18, 2026
dddeb26
ci: update coverage badge [skip ci]
github-actions[bot] Jun 18, 2026
2e4bc54
feat(report): native Rust apple-fm summarizer via FoundationModels FF…
junhoyeo Jun 18, 2026
adaa824
docs(readme): sync EN/ja/ko/zh — Command Code, Antigravity CLI, repor…
junhoyeo Jun 18, 2026
cbbd0df
fix: handle underscore-format cache token attributes from Copilot CLI…
larsbj1988 Jun 18, 2026
81d721f
fix(copilot): populate Agents tab from gen_ai.agent.id in OTEL spans …
larsbj1988 Jun 20, 2026
6e40803
feat(usage): add MiniMax Token Plan subscription usage (CN + Global) …
xczllgit Jun 20, 2026
c0d7646
fix(apple-fm): real on-device generation (programmatic schema) + dlop…
junhoyeo Jun 21, 2026
633ea94
feat(clients): add JetBrains Junie client support (#727)
Haehnchen Jun 21, 2026
7355f57
feat(cli)!: remove deprecated per-client boolean flags (#465)
junhoyeo Jun 22, 2026
1c73c5b
feat(tui): add subscription usage dashboard (#731)
astkaasa Jun 22, 2026
b49cec1
fix(roocode): invalidate cache when sibling api_conversation_history.…
Nanako0129 Jun 22, 2026
7f48257
fix(micode): namespace dedup key by database; guard authoritative cos…
Nanako0129 Jun 22, 2026
0549e2e
fix(gjc): namespace header-less session fallback by file name (#743)
Nanako0129 Jun 22, 2026
686f3cf
fix(antigravity-cli): date each turn by its per-generation timestamp …
Nanako0129 Jun 22, 2026
783bbb8
fix(codex): compare the v7 millisecond timestamp, not the full UUID, …
Nanako0129 Jun 22, 2026
b7c81a3
fix(usage): set new UsageOutput credit fields in MiniMax Token Plan
junhoyeo Jun 22, 2026
8ffea18
ci: update coverage badge [skip ci]
github-actions[bot] Jun 22, 2026
959cce8
feat: support Sakana / Fugu (pricing + provider identity + docs) (#744)
junhoyeo Jun 22, 2026
c634d1a
feat(usage): Sakana (Fugu) subscription-usage provider via billing-co…
junhoyeo Jun 22, 2026
67f96c6
ci: update coverage badge [skip ci]
github-actions[bot] Jun 22, 2026
35c0d2a
feat(tui): brand the Sakana usage provider red in the dashboard (#748)
junhoyeo Jun 22, 2026
5ff7bf4
fix(usage,sessions): resolve token/subscription usage integration dis…
junhoyeo Jun 22, 2026
4fe49ad
fix(display): render provider names correctly in Models views (#763)
junhoyeo Jun 22, 2026
ce27522
fix(display): preserve all providers in merged Models rows (#764)
junhoyeo Jun 22, 2026
c2156fe
fix(micode): normalize epoch seconds vs milliseconds in time.created …
junhoyeo Jun 22, 2026
77948d9
fix(junie): unique dedup ordinal, scoped turn-start, kind-based skip …
junhoyeo Jun 22, 2026
db88138
fix(commandcode): char-safe model canonicalize, MiniMax pricing, per-…
junhoyeo Jun 22, 2026
cb6ebf6
fix(copilot): per-message agent attribution, whitespace ids, cache-ke…
junhoyeo Jun 22, 2026
24e3771
fix(kiro): de-duplicate snapshot traversal and align model-id key-set…
junhoyeo Jun 22, 2026
4bc2aa0
fix(jcode): prefer journal token_usage over stale snapshot + parse tz…
junhoyeo Jun 22, 2026
fe16ef3
fix(usage): correct Sakana decimal percent, config-dir, and logged-ou…
junhoyeo Jun 22, 2026
52cfb70
fix(usage/codex): preserve reset-credit count and gate detail fetch (…
junhoyeo Jun 22, 2026
dc9e95a
fix(usage): surface active-provider fetch errors instead of dropping …
junhoyeo Jun 22, 2026
471ad5a
chore(release): pre-v4.0.0 doc sync + fix report summarizer content (…
junhoyeo Jun 22, 2026
c94bda1
fix(report): bucket and filter report dates in local time (#753)
junhoyeo Jun 22, 2026
f96d27f
fix(report): stop LLM title clustering from over-merging unrelated se…
junhoyeo Jun 22, 2026
afa65ed
fix(tui): color Fable models in the Anthropic palette like Opus (#762)
junhoyeo Jun 22, 2026
af24c8f
docs(sakana): create session-cookie file mode 600 at creation (#765)
junhoyeo Jun 22, 2026
2ec803e
ci: update coverage badge [skip ci]
github-actions[bot] Jun 22, 2026
235230a
fix(antigravity-cli): clamp untrusted token varints + pre-release har…
junhoyeo Jun 22, 2026
9b85b67
chore(format): unblock v4 release CI with rustfmt output
junhoyeo Jun 22, 2026
64f92fe
fix(docs): use tokscale.ai everywhere; drop stale .com/.dev refs (#768)
junhoyeo Jun 22, 2026
cd603c2
docs: full ja/ko/zh-cn re-sync with EN README (#767)
junhoyeo Jun 23, 2026
4efba61
chore: bump version to 4.0.0
github-actions[bot] Jun 23, 2026
b6c2d74
fix(tui): cancel pending Codex login child (#769)
astkaasa Jun 24, 2026
640e97b
feat: add ZCode (z.ai GLM-5.2) session parser (#770)
pinion05 Jun 24, 2026
4236758
chore: bump version to 4.0.1
github-actions[bot] Jun 24, 2026
f7a124d
fix: zcode empty-string content + codex login cancel barrier (#773)
junhoyeo Jun 24, 2026
7c1c7ba
chore: bump version to 4.0.2
github-actions[bot] Jun 24, 2026
38202b7
fix(tui): refine usage dashboard interactions (#774)
astkaasa Jun 25, 2026
4062d4d
chore: bump version to 4.0.3
github-actions[bot] Jun 25, 2026
c093be0
fix(usage): show reset times in local compact format (#775)
astkaasa Jun 25, 2026
39cb8e2
chore: bump version to 4.0.4
github-actions[bot] Jun 25, 2026
aa6eecb
fix(usage): harden Codex account loading (#783)
astkaasa Jun 27, 2026
302d39c
feat: add OpenCodeReview as token tracking provider (#777)
lizhengfeng101 Jun 28, 2026
855ca82
ci: update coverage badge [skip ci]
github-actions[bot] Jun 28, 2026
bc06d4e
fix(mimocode): scan `~/.local/share/mimocode`, not `/micode` (#784)
Javis603 Jun 28, 2026
8256280
style(opencodereview): apply rustfmt to satisfy strict fmt check
junhoyeo Jun 28, 2026
b4e614d
chore: bump version to 4.0.5
github-actions[bot] Jun 28, 2026
e4196d2
fix(frontend): register zcode + opencodereview in client metadata
junhoyeo Jun 29, 2026
a3e26ab
fix(leaderboard): widen cost casts to match numeric(18,4) columns (#780)
YoannLetacq Jun 29, 2026
26b4c06
test(leaderboard): width-based cost-cast coverage across all query sh…
junhoyeo Jun 29, 2026
df6d9d2
test(leaderboard): extract shared cost-cast-width assertion helper (#…
junhoyeo Jun 29, 2026
7efcf1a
[codex] Add profile range filters (#785)
Zhan-boyi Jun 29, 2026
d8ef9ac
feat(tui): make hotkeys layout-independent (#786)
niazlv Jun 29, 2026
61b24d9
chore: bump version to 4.0.6
github-actions[bot] Jun 29, 2026
ed6f8b9
fix(zcode): parse v2 usage database (#790)
BenLampson Jun 29, 2026
1c91cb3
feat(codebuddy): add local usage parser (#795)
Tito-XD Jul 1, 2026
e5cfbae
fix(kiro): improve IDE globalStorage model detection (#796)
leecoder Jul 1, 2026
c477930
feat(report): add --full flag, local timezone, update CLI backends (#…
leecoder Jul 1, 2026
6a1535d
feat(workbuddy): add local usage parser (#794)
Tito-XD Jul 1, 2026
6d3c84f
chore: bump version to 4.0.7
github-actions[bot] Jul 1, 2026
979b701
fix(core): preserve provider-reported usage costs (#791)
IvGolovach Jul 1, 2026
2c738c3
feat(cli): add scheduled autosubmit command (#792)
IvGolovach Jul 1, 2026
971a9e2
ci(release): smoke-test packaged CLI artifacts before publish (#793)
IvGolovach Jul 1, 2026
02e34dd
chore: bump version to 4.0.8
github-actions[bot] Jul 1, 2026
90d28ec
fix: improve CodeBuddy and WorkBuddy token usage parsing (#801)
Tito-XD Jul 2, 2026
f6f7ece
feat(copilot): parse GitHub Copilot Desktop app SQLite database (#800)
leecoder Jul 2, 2026
b64e4f1
feat(kiro): parse IDE execution files for accurate token estimation (…
leecoder Jul 2, 2026
c8386ed
fix(usage): clarify Codex reset credit display (#804)
astkaasa Jul 2, 2026
7403daf
feat(grok): reconcile session usage from signals.json compaction tota…
SDS-CC Jul 2, 2026
a606cb3
fix(tui): budget usage panel layout so accounts table and metrics sta…
junhoyeo Jul 2, 2026
72bf666
fix(kiro): attribute workspace, model, duration, and timestamps for e…
junhoyeo Jul 2, 2026
0b454e6
fix(copilot): subtract cache reads from desktop-DB input and parse SQ…
junhoyeo Jul 2, 2026
20f6d4d
fix(workbuddy): dedup SQLite fallback against detailed usage by sessi…
junhoyeo Jul 2, 2026
d5f2c6c
fix(grok): fingerprint signals.json for caching and anchor reconcilia…
junhoyeo Jul 2, 2026
b9b7d09
fix(codebuddy): dedup mirrored extension-log sinks at second granularity
junhoyeo Jul 2, 2026
46e0197
fix(kiro): suppress session snapshots covered by execution files
junhoyeo Jul 2, 2026
31bfd16
fix(kiro): link .chat artifacts to executions by executionId and pars…
junhoyeo Jul 2, 2026
b5f752e
chore: bump version to 4.0.9
github-actions[bot] Jul 2, 2026
4d2ef66
fix(frontend): render Fable models in Opus red on profile overview (#…
junhoyeo Jul 2, 2026
98468c7
chore: bump version to 4.0.10
github-actions[bot] Jul 2, 2026
23b5a01
chore(frontend): remove dead model/color rendering code (#809)
junhoyeo Jul 3, 2026
67f4c53
fix(frontend): resolve Claude family colors before the generic claude…
junhoyeo Jul 3, 2026
1c8e9f7
fix(tui): rank model shades by Claude family/version hierarchy instea…
junhoyeo Jul 3, 2026
59421da
fix(core): saturate the per-field token folds so overflow can't panic…
Nanako0129 Jul 5, 2026
31deb7e
fix(mux): make the dedup key workspace-scoped and stable across re-pa…
Nanako0129 Jul 5, 2026
88b32ac
fix(copilot): prefer the invoke_agent span for the trace fallback age…
Nanako0129 Jul 5, 2026
2c781b6
feat(tui): add monthly usage tab with daily drill-down (#812)
asf0 Jul 5, 2026
b8156e6
fix(pi): tolerate OMP title-first session records (#807)
Mathews-Tom Jul 5, 2026
65f8f3e
fix(zcode): subtract cache/reasoning overlap from input/output (#825)
Ankairis Jul 5, 2026
0934453
feat(kiro): add workspace-session promptLogs input estimation and exe…
leecoder Jul 5, 2026
dcb053e
fix(jcode): keep journal corrections turn-neutral so new turns still …
Nanako0129 Jul 5, 2026
1cae006
test(tui): make usage_reset_button_renders_when_credit_available dete…
Mathews-Tom Jul 5, 2026
49c7a55
ci: update coverage badge [skip ci]
github-actions[bot] Jul 5, 2026
0bef076
perf(frontend): landing assets PNG→WebP, videos re-encoded VP9 WebM +…
junhoyeo Jul 6, 2026
d310797
feat(settings): add Danger Zone with self-service data and account de…
junhoyeo Jul 6, 2026
5bac6e8
chore: bump version to 4.0.11
github-actions[bot] Jul 6, 2026
6c80471
fix(pricing): strip unrecognized provider prefixes before LiteLLM loo…
junhoyeo Jul 6, 2026
8566960
docs+test(codex): confirm archived_sessions scanning/dedup covers #77…
junhoyeo Jul 6, 2026
23cf62e
fix(copilot): prefer the root invoke_agent span when a trace has nest…
junhoyeo Jul 6, 2026
3527f8f
fix(cli): saturate token field folds in the display layer (#835)
junhoyeo Jul 6, 2026
405ded4
feat(kiro): detect Kiro IDE (Windows) sess_*/session.json + messages.…
junhoyeo Jul 6, 2026
4cbc2f6
fix(claude): exclude workflow journals and count deep-nested subagent…
junhoyeo Jul 6, 2026
f4f93e4
chore: bump version to 4.1.0
github-actions[bot] Jul 6, 2026
cd394af
fix(core): discover Crush registry via CRUSH_GLOBAL_DATA and Windows …
junhoyeo Jul 7, 2026
0f84d17
fix(core): preserve OpenCode provider-reported costs through repricin…
junhoyeo Jul 7, 2026
da5e06d
fix(core): normalize empty-report totalCost from -0.0 to 0.0 (#840)
junhoyeo Jul 7, 2026
a0a5b0d
chore: bump version to 4.1.1
github-actions[bot] Jul 7, 2026
555be53
feat(cli): add --hide-zero to models/monthly/hourly reports (#842)
junhoyeo Jul 7, 2026
415a196
chore: bump version to 4.2.0
github-actions[bot] Jul 7, 2026
44db59d
feat(tui): add readable surface themes (#843)
xczllgit Jul 7, 2026
b4ff8a7
fix(tui): honor saved color theme on launch (#844)
junhoyeo Jul 7, 2026
4258514
refactor(tui): share total token table cell styling (#845)
junhoyeo Jul 7, 2026
6f62a4d
chore: bump version to 4.3.0
github-actions[bot] Jul 7, 2026
315549b
feat(kiro): parse IDE structured messages.jsonl with per-turn context…
leecoder Jul 10, 2026
d01db0a
fix(core): restore strict Clippy compatibility on Rust 1.97
junhoyeo Jul 10, 2026
eec828c
fix(profile): display last updated time in viewer's local timezone (#…
leecoder Jul 10, 2026
c1aef5e
feat(hermes): auto-discover profile databases (#848)
mijanx Jul 10, 2026
9a5aeb6
feat(models): fold configurable model aliases into one canonical mode…
PekingSpades Jul 10, 2026
57a7387
chore: bump version to 4.4.0
github-actions[bot] Jul 10, 2026
9c9a553
fix(tui): color gateway-served models by their own vendor (#853)
junhoyeo Jul 10, 2026
6224871
chore: bump version to 4.4.1
github-actions[bot] Jul 10, 2026
ae36db5
perf(cache): incremental shard cache (warm submit ~167s→~52s, cold fi…
junhoyeo Jul 12, 2026
1752636
fix(pi): attribute subagent session usage (#854)
JPFrancoia Jul 12, 2026
0097ba7
feat(clients): add Devin CLI and Desktop token usage parsing (#858)
thedavidweng Jul 12, 2026
e1755a2
docs: add CONTRIBUTING guide for adding client integrations
junhoyeo Jul 12, 2026
cd07bf7
fix(core): keep Devin usage and cache metadata aligned
junhoyeo Jul 12, 2026
3f2e10c
test(frontend): enforce complete client registry contracts in CI
junhoyeo Jul 12, 2026
62cb365
docs(contributing): document cross-registry client integration workflow
junhoyeo Jul 12, 2026
55639c5
ci: update coverage badge [skip ci]
github-actions[bot] Jul 12, 2026
b1e5b57
feat(profile): redesign public profiles for compact usage analysis (#…
junhoyeo Jul 12, 2026
6a745aa
feat(frontend): refine groups and leaderboard workflows (#859)
junhoyeo Jul 12, 2026
4cb06e2
feat(leaderboard): drop estimated time as a public metric (#860)
junhoyeo Jul 12, 2026
581c08f
feat(profile): model legend, today tooltip, newest-first toggle, clie…
junhoyeo Jul 12, 2026
97296bb
fix(profile): move "Newest first" toggle to the Usage over time chart…
junhoyeo Jul 12, 2026
3435ffc
fix(graph): correct client filter toggle inversion and stale breakdow…
junhoyeo Jul 12, 2026
dd7a470
fix(profile): repair four adversarially-found UI defects (#866)
junhoyeo Jul 12, 2026
ceef07c
docs(readme): drop redundant Supported/Status columns and sync transl…
junhoyeo Jul 12, 2026
a7a412e
chore: bump version to 4.5.0
github-actions[bot] Jul 12, 2026
2c3f302
feat(frontend): align Codex client color with the OpenAI palette (#867)
junhoyeo Jul 12, 2026
d61e40b
fix(usage): derive Codex labels from window duration (#869)
astkaasa Jul 13, 2026
07bad1e
chore: bump version to 4.5.1
github-actions[bot] Jul 13, 2026
f3bff87
feat(codex): keep account activity separate from local usage
junhoyeo Jul 13, 2026
51210ff
ci: update coverage badge [skip ci]
github-actions[bot] Jul 13, 2026
f14616b
fix(leaderboard): align mobile cost figures (#873)
junhoyeo Jul 13, 2026
0d2f0bb
fix(profile): default usage chart to chronological order (#874)
junhoyeo Jul 13, 2026
074619f
feat(copilot): parse VS Code Copilot Chat session token usage (#875)
leecoder Jul 13, 2026
7448ae8
ci: update coverage badge [skip ci]
github-actions[bot] Jul 13, 2026
e2186af
chore: bump version to 4.5.2
github-actions[bot] Jul 13, 2026
50ef057
fix(profile): distinguish token mix categories (#877)
junhoyeo Jul 13, 2026
b7277d4
fix(copilot): preserve trace-scoped parent hierarchy (#880)
Nanako0129 Jul 13, 2026
1cacd08
docs(agents): default GitHub merges to merge commits
junhoyeo Jul 14, 2026
82d9e5a
fix(submit): preserve local-date usage ahead of UTC
maysun0907 Jul 14, 2026
3587f74
fix(codex): calculate non-overlapping token durations
hermanliang Jul 14, 2026
9b2d3c3
feat(leaderboard): add client: and model: search directives
leecoder Jul 14, 2026
452ef89
fix(leaderboard): align all-time directive filtering (#884)
junhoyeo Jul 14, 2026
bfb16de
chore: bump version to 4.5.3
github-actions[bot] Jul 14, 2026
feac106
fix(claudecode): skip char-based token estimation for bare transcript…
leecoder Jul 15, 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
Binary file added .github/assets/client-devin.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/client-jcode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/assets/client-sakana.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions .github/badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions .github/workflows/build-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ jobs:
build: cargo build --release -p tokscale-cli --target x86_64-apple-darwin
strip: strip -x target/x86_64-apple-darwin/release/tokscale
bin_name: tokscale
- host: macos-latest
# Apple Silicon: build with the `apple-fm` feature so the on-device
# Apple Foundation Models summarizer is available. Requires the macOS
# 26 SDK + Swift toolchain (Xcode 26 on the macos-26 runner) to build
# the vendored foundation-models-c shim; statically linked, so the
# artifact stays a single self-contained binary. Apple Intelligence is
# Apple-Silicon-only, so this is intentionally not enabled for x86_64.
- host: macos-26
target: aarch64-apple-darwin
build: cargo build --release -p tokscale-cli --target aarch64-apple-darwin
build: cargo build --release -p tokscale-cli --target aarch64-apple-darwin --features apple-fm
strip: strip -x target/aarch64-apple-darwin/release/tokscale
bin_name: tokscale
- host: ubuntu-latest
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/frontend_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ on:
branches: [main, develop]
paths:
- "packages/frontend/**"
- "crates/tokscale-core/src/clients.rs"
- ".github/assets/**"
- "package.json"
- "bun.lock"
- ".github/workflows/frontend_ci.yml"
pull_request:
branches: [main, develop]
paths:
- "packages/frontend/**"
- "crates/tokscale-core/src/clients.rs"
- ".github/assets/**"
- "package.json"
- "bun.lock"
- ".github/workflows/frontend_ci.yml"
Expand Down Expand Up @@ -42,6 +46,9 @@ jobs:
- name: Run frontend tests
run: bun run --cwd packages/frontend test

- name: Run frontend type check
run: bun run --cwd packages/frontend typecheck

migration-replay:
name: Frontend Migration Replay
runs-on: ubuntu-latest
Expand Down
72 changes: 68 additions & 4 deletions .github/workflows/publish-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,18 @@ jobs:
bin_name: tokscale
build: cargo build --release -p tokscale-cli --target x86_64-apple-darwin
strip: strip -x target/x86_64-apple-darwin/release/tokscale
- host: macos-latest
# Apple Silicon ships with the `apple-fm` feature (on-device Apple
# Foundation Models summarizer). Needs the macOS 26 SDK + Swift
# toolchain (Xcode 26 on macos-26) to build the vendored
# foundation-models-c shim; it is statically linked so the published
# binary stays self-contained. Not enabled for x86_64 — Apple
# Intelligence is Apple-Silicon-only (those installs use the heuristic).
- host: macos-26
target: aarch64-apple-darwin
package_dir: cli-darwin-arm64
artifact_name: cli-binary-aarch64-apple-darwin
bin_name: tokscale
build: cargo build --release -p tokscale-cli --target aarch64-apple-darwin
build: cargo build --release -p tokscale-cli --target aarch64-apple-darwin --features apple-fm
strip: strip -x target/aarch64-apple-darwin/release/tokscale
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
Expand Down Expand Up @@ -267,16 +273,67 @@ jobs:
shell: bash
run: ${{ matrix.settings.strip }}

# Stage the binary plus, for the apple-fm arm64 build, the sidecar
# libFoundationModels.dylib that build.rs places next to it. The dylib is
# dlopen'd at runtime (never linked), so it must travel inside the npm
# package alongside tokscale. Other targets stage only the binary.
- name: Stage release artifact
shell: bash
run: |
mkdir -p dist
cp "target/${{ matrix.settings.target }}/release/${{ matrix.settings.bin_name }}" dist/
if [ -f "target/${{ matrix.settings.target }}/release/libFoundationModels.dylib" ]; then
cp "target/${{ matrix.settings.target }}/release/libFoundationModels.dylib" dist/
echo "staged sidecar libFoundationModels.dylib"
fi
ls -la dist

- name: Upload CLI binary artifact
uses: actions/upload-artifact@v6
with:
name: ${{ matrix.settings.artifact_name }}
path: target/${{ matrix.settings.target }}/release/${{ matrix.settings.bin_name }}
path: dist
if-no-files-found: error

smoke-release-artifacts:
name: Smoke release artifacts
needs: [bump-versions, build-cli-binary]
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- name: Download bumped release files
uses: actions/download-artifact@v6
with:
name: bumped-manifests
path: .

- name: Download CLI binary artifacts
uses: actions/download-artifact@v6
with:
pattern: cli-binary-*
path: release-artifacts

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.38

- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 20

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

- name: Smoke release package artifacts
run: bash scripts/test-release-package-artifacts.sh

prepare-release-provenance:
name: Commit release provenance
needs: [bump-versions, build-cli-binary]
needs: [bump-versions, build-cli-binary, smoke-release-artifacts]
runs-on: ubuntu-latest
outputs:
release_commit: ${{ steps.prepare.outputs.release_commit }}
Expand Down Expand Up @@ -396,6 +453,13 @@ jobs:
if [ "${{ matrix.settings.binary_name }}" = "tokscale" ]; then
chmod +x "packages/${{ matrix.settings.package_dir }}/bin/tokscale"
fi
# Ship the apple-fm sidecar dylib next to the binary when present (only
# the arm64-darwin artifact carries it). tokscale dlopen's it at runtime
# from its own directory; "files": ["bin"] already includes it.
if [ -f "artifacts/${{ matrix.settings.package_dir }}/libFoundationModels.dylib" ]; then
cp "artifacts/${{ matrix.settings.package_dir }}/libFoundationModels.dylib" "packages/${{ matrix.settings.package_dir }}/bin/libFoundationModels.dylib"
echo "shipped sidecar libFoundationModels.dylib"
fi
ls -la "packages/${{ matrix.settings.package_dir }}/bin"

- name: Publish platform package
Expand Down
13 changes: 12 additions & 1 deletion .github/workflows/test_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ on:
- 'packages/tokscale/package.json'
- 'packages/cli-*/package.json'
- 'scripts/*.sh'
- 'scripts/*.py'
- '.github/workflows/build-native.yml'
- '.github/workflows/publish-cli.yml'
- '.github/workflows/test_coverage.yml'
pull_request:
Expand All @@ -24,6 +26,8 @@ on:
- 'packages/tokscale/package.json'
- 'packages/cli-*/package.json'
- 'scripts/*.sh'
- 'scripts/*.py'
- '.github/workflows/build-native.yml'
- '.github/workflows/publish-cli.yml'
- '.github/workflows/test_coverage.yml'

Expand Down Expand Up @@ -51,6 +55,7 @@ jobs:
bash scripts/test-check-version-coherence.sh
bash scripts/test-npm-release-state.sh
bash scripts/test-prepare-release-provenance.sh
bash scripts/test-release-workflow-safety.sh
- name: Cache cargo registry
uses: actions/cache@v5
with:
Expand Down Expand Up @@ -162,7 +167,13 @@ jobs:
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add .github/badges/coverage.svg
git diff --staged --quiet || (git commit -m "ci: update coverage badge [skip ci]" && git push)
git diff --staged --quiet && exit 0
git commit -m "ci: update coverage badge [skip ci]"
for i in 1 2 3; do
git push && exit 0
git pull --rebase -X theirs origin main || exit 1
done
git push

- name: Upload coverage artifacts
uses: actions/upload-artifact@v6
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ This applies to all GitHub-content authoring through the CLI — PR bodies, issu

- Before any commit, inspect the effective Git identity (`git config user.name` / `user.email`) and remotes. If the identity does not match the contributor or expected automation account for the current branch, stop and ask for confirmation.
- Never commit as worker/agent identities such as `worker1`, `worker2`, `worker3`, or `*@example.invalid`.
- When merging pull requests through `gh`, use squash merge (`gh pr merge --squash ...`) unless the user explicitly requests another merge strategy.
- Before merging, verify the squash commit title is the intended conventional PR title and does not contain worker/agent/internal review jargon.
- When merging pull requests through `gh`, use merge commits (`gh pr merge --merge ...`) unless the user explicitly requests another merge strategy.
- Before merging, verify the merge commit title is the intended conventional PR title and does not contain worker/agent/internal review jargon.

## Commit Message Convention

Expand Down
132 changes: 132 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Contributing to Tokscale

Thanks for your interest in improving Tokscale. This guide covers the development workflow and the most common contribution — adding support for a new AI coding client. For commit-message and pull-request conventions, see [`AGENTS.md`](./AGENTS.md).

## Development setup

Tokscale is a Cargo workspace (the `tokscale` CLI and its core library) plus a Next.js web frontend.

Prerequisites: a stable Rust toolchain (`rustup` recommended) and [Bun](https://bun.sh) for the frontend and package scripts.

| Task | Command |
| --- | --- |
| Format check | `cargo fmt --all -- --check` |
| Lint (must pass with **no** warnings) | `cargo clippy --locked --workspace --all-features -- -D warnings` |
| Rust tests | `cargo test --workspace --all-features` |
| Build the CLI | `cargo build --release -p tokscale-cli` |
| Frontend dev server | `bun run dev:frontend` |
| Frontend registry contract | `bun run --cwd packages/frontend test -- __tests__/lib/clientRegistry.test.ts` |
| Frontend type check | `bun run --cwd packages/frontend typecheck` |

CI runs format, Clippy, and Rust tests on Linux, then builds the supported release targets separately. Frontend CI runs Vitest, migration replay, and the type check; it also runs when `crates/tokscale-core/src/clients.rs` or a GitHub CDN asset changes, so cross-registry client checks cannot be skipped by a Rust-only integration PR. A clean local `cargo fmt`, `cargo clippy`, and `cargo test` is the baseline for a reviewable PR.

## Repository layout

| Path | Contents |
| --- | --- |
| `crates/tokscale-core` | Client registry, per-client session parsers, scanner, aggregation, and cache |
| `crates/tokscale-cli` | CLI entrypoint, argument parsing, and the terminal UI |
| `packages/frontend` | Next.js web app: public profiles, the submission API, and the frontend client registry |
| `.github/assets` | Client logos, served to the frontend over the GitHub raw CDN |

## Adding a new client integration

A "client" is one AI coding tool whose local session logs Tokscale scans, parses, and reports (Claude Code, Codex, Cursor, and so on). A complete integration spans three areas — the Rust core, the CLI, and the web frontend — and the frontend half is required even though the Rust build passes without it. The single most common mistake is registering a client only in Rust: the CLI then scans and submits usage for it, but the server rejects every submission that includes it. See [Registry enforcement](#registry-enforcement) for why.

Work through the checklist in order.

### 1. Register the client (Rust core)

Add an entry to the `define_clients!` invocation in `crates/tokscale-core/src/clients.rs`. Indices must be sequential — use the next unused number (a compile-time assertion enforces this):

```rust
Pi = 8 => {
id: "pi", // stable id used everywhere: CLI flag, submit payload, frontend
root: PathRoot::Home, // base directory the relative path resolves against
relative: ".pi/agent/sessions", // where the client stores its session logs
pattern: "*.jsonl", // glob for session files under that directory
headless: false, // supports headless / subprocess capture
parse_local: true, // parse files locally (vs. remote-only)
submit_default: true // included in `tokscale submit` by default
},
```

The `id` string is the contract that ties every other layer together. Choose it once and reuse it verbatim.

### 2. Write the parser (Rust core)

Add `crates/tokscale-core/src/sessions/<client>.rs` with a function that returns `Vec<UnifiedMessage>`, and register the module in `crates/tokscale-core/src/sessions/mod.rs` with `pub mod <client>;`. Model it on an existing parser of the same shape — JSONL (`pi.rs`), SQLite (`opencode.rs`), or NDJSON (`devin.rs`). Parse defensively: skip malformed rows instead of panicking, and clamp token counts to non-negative values.

### 3. Wire discovery and dispatch (Rust core)

Discover the client's session files in `crates/tokscale-core/src/scanner.rs` (follow the pattern used by a similar client), then dispatch parsing inside `parse_all_messages_*` in `crates/tokscale-core/src/lib.rs`, passing the client identity so cache entries record their owner:

```rust
load_or_parse_source(
message_cache::CacheIdentity::for_client(ClientId::MyClient),
path,
&source_cache,
pricing,
sessions::myclient::parse_myclient_file,
);
```

Neither step is compile-enforced: a client that is registered but not wired here builds cleanly and silently produces no data.

### 4. Wire the CLI

In `crates/tokscale-cli/src/main.rs`, add the `ClientFilter` variant and its two mappings — the `id` string and the `ClientId` it resolves to — so `--client <id>` works. In `crates/tokscale-cli/src/tui/client_ui.rs`, add a `ClientUi { display_name, hotkey }` entry with an unused `hotkey`. `CLIENT_UI` is a fixed-size array (`[ClientUi; ClientId::COUNT]`), so the build fails until it has exactly one entry per client.

### 5. Register the client on the web frontend (required)

This is the step that is easy to miss and that breaks real usage. Add the `id` to the frontend registry:

- `packages/frontend/src/lib/types.ts` — add the `id` to `SUPPORTED_CLIENT_TYPES`. **This list gates `POST /api/submit`.** A submission that contains any client id not in this list is rejected in full, so a client missing here cannot submit at all.
- `packages/frontend/src/lib/constants.ts` — add the `id` to all three per-client registries: `SOURCE_DISPLAY_NAMES` (human-readable name), `SOURCE_LOGOS` (logo URL — see step 6), and `SOURCE_COLORS` (a chart color that reads well in both light and dark themes).

Because those three are `Record<ClientType, …>`, `tsc` fails to compile once the id is in `SUPPORTED_CLIENT_TYPES` until each has an entry — so if you start with `types.ts`, the type checker guides you through the rest.

The frontend registry contract test also reads the Rust `define_clients!` list, validates each id through the submit schema, and checks its display name, logo, and color. Frontend CI is explicitly triggered by `clients.rs`, so adding a Rust client without completing this step fails before merge.

### 6. Add the logo asset

Add `.github/assets/client-<id>.png` (or `.jpg`) and reference it from `SOURCE_LOGOS`:

```ts
"<id>": `${GITHUB_CDN_BASE}/client-<id>.png`,
```

`SOURCE_LOGOS` may point at an external URL instead, but any `GITHUB_CDN_BASE` reference must resolve to a file that exists in `.github/assets` on `main`, or the frontend renders a broken image. CLI and desktop variants of the same product may share a single asset (as `antigravity` and `antigravity-cli` do).

The frontend registry contract test checks every GitHub CDN logo against the checked-in asset directory. It is triggered by `.github/assets/**` changes as well as frontend changes.

### 7. Update user-facing documentation

Add the client to the supported-client overview and feature list in `README.md`, plus the data-location matrix when a platform-specific path matters. Mirror those user-facing updates in the maintained localized READMEs (`README.ko.md`, `README.ja.md`, and `README.zh-cn.md`).

### Registry enforcement

Some registries fail the build when they are incomplete; others fail silently at runtime. Know which is which:

| Registry / step | Enforced by | If omitted |
| --- | --- | --- |
| `define_clients!` sequential index | Rust compile-time assertion | Build fails |
| `CLIENT_UI` array | Rust fixed-size array | Build fails |
| `SOURCE_DISPLAY_NAMES` / `SOURCE_LOGOS` / `SOURCE_COLORS` | TypeScript `Record<ClientType>` + frontend registry contract test | Type check or CI test fails |
| **`SUPPORTED_CLIENT_TYPES`** | **Frontend registry contract test, triggered by Rust registry changes** | **CI fails before a server-rejected client ships** |
| Scanner + `lib.rs` dispatch | Nothing | Client is defined but scans and reports no data |
| Logo asset file | Frontend registry contract test, triggered by asset changes | CI fails for a missing GitHub CDN asset |

The scanner/dispatch row is the remaining silent integration gap. Verify it by hand.

### Verifying the integration

1. Run `cargo fmt --all -- --check`, `cargo clippy --locked --workspace --all-features -- -D warnings`, and `cargo test --workspace --all-features`.
2. Add a parser unit test with a small fixture in the client's real log format.
3. Run `tokscale --no-spinner --client <id>` against real local data and confirm the message and token counts look right.
4. Run `bun run --cwd packages/frontend test -- __tests__/lib/clientRegistry.test.ts` and `bun run --cwd packages/frontend typecheck`.
5. Update the supported-client and data-location documentation, including maintained translations.

## Commit messages and pull requests

Tokscale uses [Conventional Commits](https://www.conventionalcommits.org), and a PR title becomes its squash-merge commit message. The full rules — allowed types, atomic-commit guidance, and title restrictions — live in [`AGENTS.md`](./AGENTS.md). In short: a new client is a `feat` (for example, `feat(clients): add <Name> session parsing`), and titles should describe the change, not internal review or process labels.
Loading
Loading