Skip to content

feat(kimi): support kimi-code alongside legacy kimi-cli - #682

Merged
junhoyeo merged 6 commits into
junhoyeo:mainfrom
chi2nagisa:feat/kimi-code-compatibility
Jun 9, 2026
Merged

feat(kimi): support kimi-code alongside legacy kimi-cli#682
junhoyeo merged 6 commits into
junhoyeo:mainfrom
chi2nagisa:feat/kimi-code-compatibility

Conversation

@chi2nagisa

@chi2nagisa chi2nagisa commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

feat(kimi): support kimi-code alongside legacy kimi-cli

This PR adds full support for Kimi Code (the new Node.js-based CLI at ~/.kimi-code/) while keeping backward compatibility with the legacy kimi-cli (Python-based, ~/.kimi/).

What's Changed

Session Parsing

  • Add parse_kimi_code_file() in sessions/kimi.rs to handle the usage.record wire format used by kimi-code
  • Add is_kimi_code_path() helper to route files to the correct parser based on path (.kimi-code vs .kimi)
  • Wire up routing in lib.rs for both parse_all_messages_with_pricing and parse_local_clients

Scanner

  • Discover sessions in ~/.kimi-code/sessions/ in addition to the legacy ~/.kimi/sessions/
  • Respect KIMI_CODE_HOME environment variable for custom data directories

Usage Query

  • Read OAuth credentials from ~/.kimi-code/credentials/kimi-code.json first, fallback to ~/.kimi/credentials/kimi-code.json
  • Token refresh writes back to the same path credentials were read from
  • Support KIMI_CODE_HOME override for credential lookup

Documentation

  • Update README (EN/ZH/KO) to list Kimi Code alongside Kimi CLI with correct paths

Coexistence Strategy

Both tools can be installed side-by-side. The implementation prioritizes kimi-code paths when both are present, falling back to legacy paths when only the old installation exists.

Testing

cargo test -p tokscale-core kimi -- --nocapture
# 28 tests passed, 0 failed

All new code paths are covered by existing or new unit tests.


Summary by cubic

Adds full support for Kimi Code (~/.kimi-code/) alongside legacy kimi-cli (~/.kimi/). The scanner, parsers, and the usage command handle both and prefer Kimi Code when present.

  • New Features

    • tokscale-core: Parse Kimi Code wire.jsonl (usage.record) via parse_kimi_code_file(), auto-routed by is_kimi_code_path().
    • tokscale-core: Scanner discovers ~/.kimi-code/sessions/ in addition to ~/.kimi/sessions/.
    • tokscale-cli: Usage reads credentials from ~/.kimi-code/credentials/kimi-code.json first and writes refreshed tokens back to the same file.
    • Documentation updated with Kimi Code paths, KIMI_CODE_HOME, and wire format (EN/ZH/KO/JA).
  • Bug Fixes

    • is_kimi_code_path() now respects KIMI_CODE_HOME, fixing parser routing for custom install paths.
    • Kimi Code parser counts only usageScope: "turn" usage.record lines to avoid session-scoped bookkeeping.

Written for commit 0d03444. Summary will update on new commits.

Review in cubic

- 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
@vercel

vercel Bot commented Jun 6, 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 9, 2026 9:14pm

Request Review

@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.

2 issues found across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread crates/tokscale-core/src/sessions/kimi.rs
Comment thread README.ko.md Outdated
chi2nagisa and others added 5 commits June 8, 2026 01:46
- 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.
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.
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
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 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.

Reviewed: kimi-code parser correctly scoped to usageScope=="turn" records (verified against upstream MoonshotAI/kimi-code source), no double-count between kimi-cli/kimi-code paths, README x4 aligned, 887 core + 595 CLI tests pass on merged tree. Merging.

@junhoyeo
junhoyeo merged commit 839ce37 into junhoyeo:main Jun 9, 2026
15 checks passed
junhoyeo added a commit that referenced this pull request Jun 9, 2026
…parsing

Replace the KIMI_CODE_HOME env read inside is_kimi_code_path() with a
structural check: kimi-code always writes
<root>/sessions/WORKSPACE/SESSION/agents/AGENT/wire.jsonl while legacy
kimi-cli writes <root>/sessions/GROUP/UUID/wire.jsonl, so the grandparent
component being `agents` identifies the format regardless of scan root.
This removes the only production env read among the sessions/* parsers
and drops the serial_test requirement from kimi.rs.

Also merge the field-identical KimiCodeUsage into TokenUsage via serde
aliases (snake_case names stay canonical, camelCase added as aliases —
purely additive for legacy parsing), extract the shared clamp/skip-zero
logic into TokenUsage::to_breakdown(), collapse the duplicated
load_or_parse_source routing branch in lib.rs into a single fn-pointer
call, tighten kimi-code test assertions, repoint the model-normalization
test at normalize_kimi_code_model with edge cases, and fix the
"| Kimi Code|" spacing and "``` json" fence typos across all four
READMEs.

Constraint: behavior must be preserved exactly; slop cleanup of PR #682 only
Constraint: scanner walks both kimi roots matching file_name == "wire.jsonl" at any depth, so routed paths always carry the client-created layout
Rejected: keep env read in parser | only parser with a production env read; ignored use_env_roots and forced serial tests
Rejected: pass format flag from scanner to parser | larger plumbing change for the same routing decision
Confidence: high
Scope-risk: narrow
Directive: the agents/ grandparent check relies on kimi-code's on-disk layout; if kimi-code ever changes its session tree, update is_kimi_code_path and the module docs together
Not-tested: a legacy kimi-cli session whose GROUP directory is literally named "agents" (would now route to the kimi-code parser; not a real kimi-cli layout)
pinion05 added a commit to pinion05/tokscale that referenced this pull request Jun 23, 2026
…parsing

Replace the KIMI_CODE_HOME env read inside is_kimi_code_path() with a
structural check: kimi-code always writes
<root>/sessions/WORKSPACE/SESSION/agents/AGENT/wire.jsonl while legacy
kimi-cli writes <root>/sessions/GROUP/UUID/wire.jsonl, so the grandparent
component being `agents` identifies the format regardless of scan root.
This removes the only production env read among the sessions/* parsers
and drops the serial_test requirement from kimi.rs.

Also merge the field-identical KimiCodeUsage into TokenUsage via serde
aliases (snake_case names stay canonical, camelCase added as aliases —
purely additive for legacy parsing), extract the shared clamp/skip-zero
logic into TokenUsage::to_breakdown(), collapse the duplicated
load_or_parse_source routing branch in lib.rs into a single fn-pointer
call, tighten kimi-code test assertions, repoint the model-normalization
test at normalize_kimi_code_model with edge cases, and fix the
"| Kimi Code|" spacing and "``` json" fence typos across all four
READMEs.

Constraint: behavior must be preserved exactly; slop cleanup of PR junhoyeo#682 only
Constraint: scanner walks both kimi roots matching file_name == "wire.jsonl" at any depth, so routed paths always carry the client-created layout
Rejected: keep env read in parser | only parser with a production env read; ignored use_env_roots and forced serial tests
Rejected: pass format flag from scanner to parser | larger plumbing change for the same routing decision
Confidence: high
Scope-risk: narrow
Directive: the agents/ grandparent check relies on kimi-code's on-disk layout; if kimi-code ever changes its session tree, update is_kimi_code_path and the module docs together
Not-tested: a legacy kimi-cli session whose GROUP directory is literally named "agents" (would now route to the kimi-code parser; not a real kimi-cli layout)
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>
t1000040 pushed a commit to tmobi-internal/tokscale that referenced this pull request Jun 30, 2026
…parsing

Replace the KIMI_CODE_HOME env read inside is_kimi_code_path() with a
structural check: kimi-code always writes
<root>/sessions/WORKSPACE/SESSION/agents/AGENT/wire.jsonl while legacy
kimi-cli writes <root>/sessions/GROUP/UUID/wire.jsonl, so the grandparent
component being `agents` identifies the format regardless of scan root.
This removes the only production env read among the sessions/* parsers
and drops the serial_test requirement from kimi.rs.

Also merge the field-identical KimiCodeUsage into TokenUsage via serde
aliases (snake_case names stay canonical, camelCase added as aliases —
purely additive for legacy parsing), extract the shared clamp/skip-zero
logic into TokenUsage::to_breakdown(), collapse the duplicated
load_or_parse_source routing branch in lib.rs into a single fn-pointer
call, tighten kimi-code test assertions, repoint the model-normalization
test at normalize_kimi_code_model with edge cases, and fix the
"| Kimi Code|" spacing and "``` json" fence typos across all four
READMEs.

Constraint: behavior must be preserved exactly; slop cleanup of PR junhoyeo#682 only
Constraint: scanner walks both kimi roots matching file_name == "wire.jsonl" at any depth, so routed paths always carry the client-created layout
Rejected: keep env read in parser | only parser with a production env read; ignored use_env_roots and forced serial tests
Rejected: pass format flag from scanner to parser | larger plumbing change for the same routing decision
Confidence: high
Scope-risk: narrow
Directive: the agents/ grandparent check relies on kimi-code's on-disk layout; if kimi-code ever changes its session tree, update is_kimi_code_path and the module docs together
Not-tested: a legacy kimi-cli session whose GROUP directory is literally named "agents" (would now route to the kimi-code parser; not a real kimi-cli layout)
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