Skip to content

feat(clients): add gajae-code (gjc) as a tracked client - #685

Merged
junhoyeo merged 12 commits into
junhoyeo:mainfrom
seungminio:feat/track-gjc-client
Jun 8, 2026
Merged

feat(clients): add gajae-code (gjc) as a tracked client#685
junhoyeo merged 12 commits into
junhoyeo:mainfrom
seungminio:feat/track-gjc-client

Conversation

@seungminio

@seungminio seungminio commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds gajae-code (gjc) as a tracked client so tokscale can report token usage and cost from gjc agent sessions.

gjc stores JSONL session transcripts under ~/.gjc/agent/sessions/<project-slug>/*.jsonl (with depth-2 per-pass sub-agent children <slug>/<session>/N-*.jsonl). Each assistant message carries an authoritative per-message usage.cost object in USD.

What's included:

  • Registry: ClientId::Gjc = 26 (COUNT → 27), rooted at GJC_CODING_AGENT_DIR with a ~/.gjc/agent fallback and sessions relative path. Additive — no existing client index, ordering, or count changes.
  • Parser (sessions/gjc.rs): assistant-only JSONL parsing; reuses the embedded usage.cost.total (USD) verbatim when present, recomputing from tokens only when absent; codebuff-style message dedup (<session>:<message-id> with a deterministic fallback); per-line skip-on-error; session header and service_tier_change lines are ignored.
  • Cost precedence (A1): the cached parse cluster applies the Hermes guard (if cost <= 0.0 { reprice }) so gjc's authoritative cost is preserved for priceable models and only recomputed when missing.
  • Scanner: a dedicated discovery block resolving GJC_CODING_AGENT_DIRGJC_CONFIG_DIR/PI_CONFIG_DIR$XDG_DATA_HOME/gjc/sessions (flattened, Linux/macOS) → ~/.gjc/agent/sessions, gated on env-root strategy and pushing every existence-gated root (overlap collapses via dedup). WalkDir covers depth-1 and depth-2 transcripts.
  • CLI & presentation: --client gjc filter, Gajae-Code display name across the TUI client list (hotkey g), wrapped report, and brand color.
  • Docs: gjc added to all four READMEs (English + zh-cn/ja/ko) across the supported-clients table, multi-platform sentence, --client values, source filtering list, Windows path table, and a per-client data-format subsection.

What was tested

All green on a full workspace build:

  • cargo build --workspace
  • cargo clippy --workspace (clean)
  • cargo test --package tokscale-core — 871 lib tests + 4 gjc integration tests
  • cargo test --package tokscale-core --test gjc — end-to-end cost-precedence (embedded cost preserved; absent cost recomputed), workspace-key from dash-encoded slug, recursive depth-1/depth-2 discovery, and message dedup across replayed files
  • cargo test --package tokscale-cli — 590 bin + 118 integration tests, including a real-binary --client gjc end-to-end test, empty-data cleanliness, and filter isolation
  • cargo test --package tokscale-core clients::tests::test_client_id_count (→ 27), plus test_client_all, test_client_key, test_client_filter_gjc_round_trip

Notes

  • Cost reuse: gjc emits an authoritative per-message USD cost, so for priceable models gjc rows report gjc's cost rather than a recomputed LiteLLM figure. This trades cross-client comparability for fidelity to the number gjc shows the user; recompute still kicks in for any model without an embedded cost.
  • Env/XDG support: discovery honors GJC_CODING_AGENT_DIR, GJC_CONFIG_DIR, PI_CONFIG_DIR, and the $XDG_DATA_HOME/gjc redirect (which flattens the agent/ segment) on Linux/macOS; --home disables all env-derived roots.
  • No logo asset is bundled, so the supported-clients table uses a text-only name cell (matching existing text-only rows like Kiro/Warp).

Summary by cubic

Add gjc (gajae-code) as a tracked client. Tokscale now parses gjc JSONL sessions, preserves embedded per‑message USD cost, and supports --client gjc in the CLI and TUI.

  • New Features

    • Registered ClientId::Gjc with *.jsonl under GJC_CODING_AGENT_DIR (fallback ~/.gjc/agent/sessions).
    • Scanner resolves GJC_CODING_AGENT_DIRGJC_CONFIG_DIR/PI_CONFIG_DIR$XDG_DATA_HOME/gjc/sessions → home; pushes all existing roots with cross-root dedup; walks depth‑1 and depth‑2 transcripts.
    • JSONL parser: assistant‑only; reuses usage.cost.total (USD) when present and reprices only when missing; per‑message dedup by <session>:<message-id>; skips service_tier_change and bad lines.
    • CLI/TUI: --client gjc filter (legacy --gjc hidden), display name “Gajae‑Code”, hotkey g, and branded color.
  • Docs

    • Added Gajae‑Code to all READMEs: supported clients tables (with logo), --client values, source filtering lists, Windows path table, and a per‑client JSONL format section.
    • Fixed the gajae‑code repo link to https://github.com/Yeachan-Heo/gajae-code in all READMEs.

Written for commit 1f2d0a8. Summary will update on new commits.

Review in cubic

seungminio added 10 commits June 7, 2026 22:42
- Register Gjc=26 in define_clients! (COUNT->27) with EnvVar root
  GJC_CODING_AGENT_DIR + fallback .gjc/agent, relative sessions (N2)
- Add sessions/gjc.rs JSONL parser: assistant-only, A1 embedded
  usage.cost.total reuse, codebuff-style dedup keys, per-line skip
- Wire pub mod gjc; add parser + clients unit tests, count 26->27
Empty file, header-only, malformed-line-between-valid, missing
model/provider/usage, negative token clamp, negative/absent cost
fallback, dedup-key replay collapse, unicode/encoded cwd.
- Cached cluster: gjc_outcomes via non-repricing parse_gjc_file + A1
  Hermes guard (reprice only when cost<=0.0) + should_keep_deduped_message;
  never routes through load_or_parse_source/apply_pricing_to_messages.
- Non-cached cluster: gjc_msgs dedup + counts.set(Gjc) + extend.
Proves A1 holds through the lib.rs Hermes guard: embedded
usage.cost.total wins for a priceable model; absent-cost message is
recomputed. The N1 gate \u2014 fails if cached cluster repriced.
- Add ClientId::Gjc to the generic-loop continue skip set (N3,
  load-bearing against env-set over-collection).
- Dedicated discovery block resolving agent-sessions root in
  precedence: GJC_CODING_AGENT_DIR -> GJC_CONFIG_DIR/PI_CONFIG_DIR
  -> $XDG_DATA_HOME/gjc (flattened) -> ~/.gjc/agent/sessions, each
  gated on use_env_roots, pushing EVERY existence-gated root via
  push_unique_scan_task (N4, not first-match). WalkDir+*.jsonl covers
  depth-1 and depth-2.
- Tests: depth1+depth2, home-fallback when env disabled, env override,
  multi-root dedup.
- ClientFilter::Gjc + as_filter_str/to_client_id/from_client_id arms,
  hidden legacy --gjc flag, enumerated lists, capitalize_client, and
  test_client_filter_gjc_round_trip (item f).
- CLIENT_UI 27th literal (Gajae-Code, hotkey g), wrapped
  client_display_name, widgets red-claw brand color; data/mod
  test_client_all 26->27 + test_client_key hotkey g (item g).
- provider_identity regression test for gjc provider passthrough (item h).
GJC_CONFIG_DIR/PI_CONFIG_DIR roots, XDG flattened redirect,
multi-root push-all (N4), use_env_roots=false suppression,
nonexistent root no-panic.
Real binary invocation: gjc fixture surfaces under --client gjc,
empty-data is clean, and --client claude does not leak gjc rows.
- G8: cwd-header drives workspace key/label over dash-encoded slug;
  normalize_workspace_key/workspace_label_from_key contract.
- G9a: depth-1 and depth-2 transcripts both discovered.
- G9b: replayed session+message id deduped to one (defensive guard).
Supported-clients table (text-only name cell), multi-platform
sentence, --client possible values, source filtering list, Windows
path table, and per-client JSONL data-format subsection. Inserted
before the synthetic meta-client entry; translations for zh-cn/ja/ko.
@vercel

vercel Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
tokscale Ignored Ignored Preview Jun 7, 2026 2:32pm

Request Review

Replace the text-only name cell with the gjc logo image across all
four READMEs.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 17 files

Re-trigger cubic

@junhoyeo junhoyeo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks a lot! cc @Yeachan-Heo Congrats!

@junhoyeo
junhoyeo merged commit 1492b96 into junhoyeo:main Jun 8, 2026
14 of 15 checks passed
junhoyeo added a commit that referenced this pull request Jun 8, 2026
* fix(frontend): register gjc client in submission validation and display constants

The clientRegistry vitest enumerates every define_clients! entry in
crates/tokscale-core/src/clients.rs and asserts each one validates as
a submission and has a display name, logo URL, and color. PR #685
added gjc to the Rust macro but the frontend constants were never
updated, so the next push to main broke Frontend CI.

Added gjc to:
- SUPPORTED_CLIENT_TYPES in types.ts (drives the zod enum that
  validateSubmission uses)
- SOURCE_DISPLAY_NAMES ("Gajae Code")
- SOURCE_LOGOS ($GITHUB_CDN_BASE/client-gjc.png — the asset itself
  is pending in .github/assets/)
- SOURCE_COLORS (#FF6B6B)

Confidence: high
Scope-risk: narrow
Directive: When a new client is added to the Rust define_clients!
  macro, the same id must be added to the four frontend registries
  in the same PR. The vitest above is the gate.
Not-tested: visual rendering of the gjc logo (asset not yet uploaded)

* chore: apply cargo fmt across the workspace

cargo fmt --check has been failing on main since #685 (Test & Coverage
runs on 1492b96, b43dc5f, e644f96 all red). The drift came in over
multiple PRs that touched scanner.rs, main.rs, sessions/gjc.rs and
tests, where the formatter would have wrapped or reflowed slightly
differently than the manually-written form.

Ran cargo fmt --all once to bring the whole tree into agreement with
rustfmt 1.8.0-stable. No behavioral change.

Confidence: high
Scope-risk: narrow
Directive: Run cargo fmt --all locally before pushing any Rust change,
  or rely on the CI gate to catch it before merge — drift compounds
  silently across PRs otherwise.
Not-tested: nothing — pure formatting
junhoyeo added a commit to chi2nagisa/tokscale that referenced this pull request Jun 9, 2026
cargo fmt over the kimi-code changes from junhoyeo#682 plus the merged
scanner.rs, and replace three .len() >= 1 assertions on the Gjc scan
results (from junhoyeo#685 on main, only linted under --all-targets) with
!is_empty() so cargo clippy --all-targets -- -D warnings passes.
junhoyeo added a commit that referenced this pull request Jun 9, 2026
* feat(kimi): support kimi-code alongside legacy kimi-cli

- Parse kimi-code wire.jsonl format (usage.record lines) from
  ~/.kimi-code/sessions/{workspace}/{session}/agents/{agent}/wire.jsonl
- Route parser selection via is_kimi_code_path() in lib.rs
- Scanner discovers both ~/.kimi/sessions (legacy) and ~/.kimi-code/sessions
- Usage query reads credentials from ~/.kimi-code first, fallback to ~/.kimi
- Respect KIMI_CODE_HOME environment variable for custom data directories
- Update README to reflect Kimi Code support

* fix(kimi): respect KIMI_CODE_HOME in parser routing and docs

- is_kimi_code_path() now checks KIMI_CODE_HOME env var in addition
  to the literal .kimi-code path segment, fixing mis-routing for
  custom installation directories.
- Add serial_test-guarded test for custom KIMI_CODE_HOME paths.
- Update README (EN/ZH/KO) to document the KIMI_CODE_HOME override.

* docs(readme.ja): add kimi-code data path and wire format

Mirror the kimi-code documentation added to README.md, README.ko.md,
and README.zh-cn.md in #682, which missed the Japanese translation:
client table row, cross-platform path table row, and the Kimi Code
wire.jsonl format section.

* fix(kimi): count only turn-scoped usage.record lines

kimi-code tags every usage.record with usageScope: "turn" for per-step
LLM calls made inside a user turn, and "session" for non-turn
bookkeeping such as context compaction rollups. Upstream's own tooling
(apps/vis context-projector) treats a missing usageScope as
session-scoped, so the parser now requires an explicit "turn" before
counting a record.

Constraint: all public kimi-code releases always write usageScope on usage.record lines
Rejected: counting records with a missing usageScope | upstream attributes them to the session scope, not a turn
Rejected: also counting session-scoped compaction usage | review verdict for #682 was to count turn-scoped usage only
Confidence: high
Scope-risk: narrow
Not-tested: real wire.jsonl files containing compaction-emitted session-scoped records

* style: rustfmt kimi additions and fix clippy len_zero in scanner tests

cargo fmt over the kimi-code changes from #682 plus the merged
scanner.rs, and replace three .len() >= 1 assertions on the Gjc scan
results (from #685 on main, only linted under --all-targets) with
!is_empty() so cargo clippy --all-targets -- -D warnings passes.

---------

Co-authored-by: Junho Yeo <i@junho.io>
t1000040 pushed a commit to tmobi-internal/tokscale that referenced this pull request Jun 30, 2026
* feat(kimi): support kimi-code alongside legacy kimi-cli

- Parse kimi-code wire.jsonl format (usage.record lines) from
  ~/.kimi-code/sessions/{workspace}/{session}/agents/{agent}/wire.jsonl
- Route parser selection via is_kimi_code_path() in lib.rs
- Scanner discovers both ~/.kimi/sessions (legacy) and ~/.kimi-code/sessions
- Usage query reads credentials from ~/.kimi-code first, fallback to ~/.kimi
- Respect KIMI_CODE_HOME environment variable for custom data directories
- Update README to reflect Kimi Code support

* fix(kimi): respect KIMI_CODE_HOME in parser routing and docs

- is_kimi_code_path() now checks KIMI_CODE_HOME env var in addition
  to the literal .kimi-code path segment, fixing mis-routing for
  custom installation directories.
- Add serial_test-guarded test for custom KIMI_CODE_HOME paths.
- Update README (EN/ZH/KO) to document the KIMI_CODE_HOME override.

* docs(readme.ja): add kimi-code data path and wire format

Mirror the kimi-code documentation added to README.md, README.ko.md,
and README.zh-cn.md in junhoyeo#682, which missed the Japanese translation:
client table row, cross-platform path table row, and the Kimi Code
wire.jsonl format section.

* fix(kimi): count only turn-scoped usage.record lines

kimi-code tags every usage.record with usageScope: "turn" for per-step
LLM calls made inside a user turn, and "session" for non-turn
bookkeeping such as context compaction rollups. Upstream's own tooling
(apps/vis context-projector) treats a missing usageScope as
session-scoped, so the parser now requires an explicit "turn" before
counting a record.

Constraint: all public kimi-code releases always write usageScope on usage.record lines
Rejected: counting records with a missing usageScope | upstream attributes them to the session scope, not a turn
Rejected: also counting session-scoped compaction usage | review verdict for junhoyeo#682 was to count turn-scoped usage only
Confidence: high
Scope-risk: narrow
Not-tested: real wire.jsonl files containing compaction-emitted session-scoped records

* style: rustfmt kimi additions and fix clippy len_zero in scanner tests

cargo fmt over the kimi-code changes from junhoyeo#682 plus the merged
scanner.rs, and replace three .len() >= 1 assertions on the Gjc scan
results (from junhoyeo#685 on main, only linted under --all-targets) with
!is_empty() so cargo clippy --all-targets -- -D warnings passes.

---------

Co-authored-by: Junho Yeo <i@junho.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants