feat: add Codebuff local session support - #454
Merged
Merged
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
junhoyeo
approved these changes
Apr 26, 2026
junhoyeo
force-pushed
the
feat/codebuff-sessions
branch
from
April 26, 2026 03:25
f97a148 to
fa40cbe
Compare
junhoyeo
approved these changes
Apr 26, 2026
Owner
There was a problem hiding this comment.
Thanks for the contribution, @anandghegde! Codebuff support is a great addition. Approving — will squash merge after #464 lands.
Adds Codebuff (formerly Manicode) as a new first-class tokscale client.
Codebuff persists chat history under
$CODEBUFF_DATA_DIR/projects/<project>/chats/<chatId>/chat-messages.json
with the default root at ~/.config/manicode. Dev and staging channels
(manicode-dev, manicode-staging) use the same layout and are walked
automatically when present.
core:
- sessions/codebuff.rs: new parser. Emits a UnifiedMessage per assistant
message that carries token usage. Usage is extracted (in order) from
metadata.usage, metadata.codebuff.usage, and the stashed
metadata.runState.sessionState.mainAgentState.messageHistory[] (where
OpenRouter-routed calls land their token counts). Accepts both camelCase
and snake_case token keys so that different upstream providers (Anthropic
SDK, OpenAI/OpenRouter, Codebuff's own shape) parse cleanly. Session id
encodes channel + project + chatId so per-channel breakdowns remain
distinct after aggregation. Credits are read from message.credits.
- clients.rs: register ClientId::Codebuff (id=18) with
PathRoot::EnvVar { var: "CODEBUFF_DATA_DIR", fallback_relative:
".config/manicode" }; pattern "chat-messages.json".
- scanner.rs: recognise the new exact-match file pattern and add a
custom scan block that either honours CODEBUFF_DATA_DIR or walks the
three known channel roots.
- lib.rs: wire parse_codebuff_file into both the cached-parse and
parse_local_clients dispatch loops.
cli / tui:
- main.rs: --codebuff flag on the global ClientFlags plus updated
build_client_filter, capitalize_client and existing test fixtures.
- commands/wrapped.rs: Codebuff entries for client_display_name,
client_logo_url and default_clients (the Wrapped aggregation picks
Codebuff up automatically once registered).
- tui/client_ui.rs, tui/data/mod.rs, tui/mod.rs, tui/ui/widgets.rs:
display name, hotkey 'b', brand color #7C3AED, and test_data_loading
coverage for the new client.
tests:
- tests/codebuff.rs: end-to-end parse covering the three usage
extraction paths, snake/camel schemas, and the empty/non-array
inputs path.
- 7 new unit tests inside sessions/codebuff.rs plus 1 new client_id
assertion and 1 env-var assertion in clients.rs.
docs:
- README.md: new row in the supported clients table plus the
--codebuff example block and prose list update.
Verified locally: cargo test --workspace (968 tests, 0 failures)
and cargo clippy --workspace --all-targets -- -D warnings clean.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Three follow-up fixes on the initial Codebuff integration.
1. wrapped.rs — client_logo_url("Codebuff") used to point at
https://tokscale.ai/assets/logos/codebuff.png, which has not been
uploaded to the tokscale CDN yet and returns 404. Replace with the
(verified) CodebuffAI GitHub organisation avatar. Matches the logo
already used in the README table row.
2. scanner.rs — a CODEBUFF_DATA_DIR that was set to an empty or
whitespace-only string used to be captured by the outer
`if let Some(root) = env_override` branch, pass the inner
`.trim().is_empty()` guard as a no-op, and then fall out of the
block without queueing any scan tasks. Callers exporting an empty
override (common in shells that inherit CODEBUFF_DATA_DIR= from a
parent process) would see Codebuff silently disabled. Rework the
override detection to trim+filter first, so whitespace values now
fall through to the three default channel roots.
3. sessions/codebuff.rs — the previous chat-id→timestamp bridge did
`chat_id.replace('-', ":")`, but the chatId encodes the chat's
ISO-8601 timestamp as `2025-12-14T10-00-00.000Z` where the `-`
separators appear in BOTH the date (YYYY-MM-DD) and the time
(HH-MM-SS) portions. Global replacement corrupted the date to
`2025:12:14T...`, RFC3339 parsing failed, and chat_id_ts silently
fell back to 0 — which meant every assistant message missing its own
timestamp/createdAt/metadata.timestamp was reported at the file
mtime rather than the chat time. Introduce parse_chat_id_to_millis
which only flips the first two `-` *after* the `T`.
Regression coverage:
- sessions/codebuff.rs: parse_chat_id_to_millis happy path + broken
global-replace comparison + garbage input.
- tests/codebuff.rs: end-to-end chat-id fallback (no per-message
timestamp) asserts the parsed UnifiedMessage.timestamp is the
chat-id-derived epoch, not the file mtime.
- scanner.rs: three new #[serial] tests for the Codebuff env logic —
default three-channel walk, whitespace env falls back to defaults,
and non-empty env selects only the override root.
Verified: cargo test --workspace (972 passed, 0 failed) and
cargo clippy --workspace --all-targets -- -D warnings clean.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
… dedup keys The previous fallback hardcoded 'anthropic' when a token-bearing message had no recognizable model hint, skewing per-provider stats since Codebuff routes calls through multiple providers. Falls back to 'unknown' instead. Also adds a stable dedup_key derived from the upstream ChatMessage.id (or a deterministic fallback combining session, timestamp, model, and token shape) so the same chat history scanned from multiple roots no longer double-counts.
…and update client count test
The reverse history walk in extract_usage_from_run_state used the ? operator
on entry.get("providerOptions"), which exited the entire function on the
first assistant entry without providerOptions. That silently dropped valid
usage data carried by earlier entries. Replaced with let-else so the loop
continues to the next candidate.
Also updates test_client_all in tui/data to reflect that ClientId::ALL now
contains 20 entries (Goose at index 18, Codebuff at 19) after both clients
landed on main.
junhoyeo
force-pushed
the
feat/codebuff-sessions
branch
from
April 26, 2026 04:18
2667412 to
ea19bf7
Compare
junhoyeo
added a commit
that referenced
this pull request
Apr 26, 2026
…nd client filter UX (#467) Pre-release correctness and security fixes across the four PRs landed this cycle (#464, #454, #359, #355). ## Antigravity Trust boundary around the local language-server RPC was too loose: - Bound RPC body sizes at 16 MiB (Content-Length, chunked, and read-to-end paths) - Verify process identity by checking the executable path (`lsof` on macOS, `/proc/<pid>/exe` on Linux); accept paths containing either `antigravity` or `language_server` since some Antigravity-flavored servers launch from generic `language_server` binaries with `--app_data_dir antigravity` - Probe candidate endpoints with a real RPC call and JSON-shape check (probe body capped at 4 KiB) instead of trusting any 200 response; consume HTTP headers before reading body so the cap applies to the JSON body alone - Lock concurrent syncs on a per-cache PID lock file with bounded retry (3 attempts) instead of unbounded recursion. Eviction is gated on PID liveness only — long-running syncs no longer get stomped on by age-based timeouts. - Enforce manifest version on load: future versions abort, older versions start fresh - Recover corrupted manifests by moving them aside as `manifest.json.corrupt-<ts>` instead of failing every subsequent sync ## Codebuff Parser correctness around silent data loss: - Accumulate run-state usage across the full reverse `messageHistory` walk instead of returning on the first signal-bearing entry. Previously a newest assistant entry carrying only a model id would short-circuit the walk and silently drop real token counts on earlier entries. - Include the source-array ordinal in the fallback dedup key so two id-less assistant messages with identical session/timestamp/model/tokens no longer collapse into a single record - Reject non-positive numeric timestamps in the shared `parse_timestamp_value`/`parse_timestamp_str` helpers so messages with `timestamp: 0` or negative epochs fall through to chat-id / file-mtime fallback chain ## TUI + parsing User-visible client-filter UX: - Move `SYNTHETIC_HOTKEY` from `'x'` to `'n'`. `'x'` collided with Mux's hotkey, and the dispatch order made the displayed `[x]` for Synthetic purely cosmetic - Enable `ignore_case` on `--client/-c` so `OPENCODE`, `Codebuff`, and `antigravity` all parse as the same canonical filter ## Test results - `cargo test -p tokscale-cli` — 415 unit + 83 integration, all pass - `cargo test -p tokscale-core` — 566 unit + 10 codebuff + 3 hermes, all pass - `cargo check --workspace` — clean Each fix has a regression test where applicable.
junhoyeo
added a commit
that referenced
this pull request
Apr 26, 2026
The Korean, Japanese, and Simplified Chinese READMEs were not updated when Codebuff (#454), Goose (#457), and Antigravity (#355) landed. The English README also picked up missing Goose and Antigravity entries during this sweep. Sync all four to the same client list, settings table, Windows locations, Data Sources sections, and `tokscale antigravity` command documentation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Codebuff (formerly Manicode) as a new first-class tokscale client, alongside Amp / Droid / Pi / Hermes / Mux / Kimi / Qwen / Kilo / KiloCode / RooCode / Crush.
Data Source
Codebuff persists per-chat history at:
chatIdis the chat's ISO-8601 timestamp with:replaced by-for filesystem safety (e.g.2025-12-14T10-00-00.000Z). Dev and staging channels (manicode-dev,manicode-staging) use the same layout and are walked automatically when present.Token / Credit Extraction
Assistant-message usage can land in several places depending on routing. The parser tries, in order:
metadata.usage— direct provider.metadata.codebuff.usage— Codebuff-tagged payload.metadata.runState.sessionState.mainAgentState.messageHistory[*].providerOptions— where RunState-stashed OpenRouter calls record totals underproviderOptions.usageorproviderOptions.codebuff.usage.Both camelCase and snake_case shapes are accepted (
inputTokens/input_tokens/promptTokens, etc.). Credits are read frommessage.credits.Environment
CODEBUFF_DATA_DIR— override the base directory. Point it at a single channel root such as~/.config/manicode-dev.Changes
core
sessions/codebuff.rs— new parser with 7 unit testsclients.rs— registerClientId::Codebuff(id=18)scanner.rs—chat-messages.jsonpattern + multi-channel scan blocklib.rs— dispatch in both cached-parse andparse_local_clientsloopscli / tui
--codebuffflag onClientFlags'b', brand color#7C3AED, per-client teststests
tests/codebuff.rs— 3 integration tests (3 usage paths, empty/non-array)docs
--codebuffexample + prose list updateVerification
Notes
capitalize_client("codebuff")→"Codebuff".github/assets/client-codebuff.pngon request.@ccusage/codebuff(currently under review in ryoppippi/ccusage#954) uses the same extraction approach and can serve as a cross-reference for the data shape.Summary by cubic
Adds Codebuff (formerly Manicode) as a first-class local client with channel-aware scanning and a resilient parser that extracts token usage from multiple paths. Integrates into CLI/TUI and fixes env handling, timestamps, provider inference, and dedup to avoid double-counting.
New Features
ClientId::Codebuffscanning~/.config/manicode{,-dev,-staging}orCODEBUFF_DATA_DIR; targetsprojects/<project>/chats/<chatId>/chat-messages.json.metadata.usage,metadata.codebuff.usage, ormetadata.runState...messageHistory[*].providerOptions(camel/snake); readscredits; session id ischannel/project/chatId; provider inferred from model. Wired into cached and local parsing.--codebuffflag, default inclusion, display name/logo, hotkeyb, brand color#7C3AED. README and tests updated.Bug Fixes
CODEBUFF_DATA_DIRtrims/ignores empty values and falls back to default channels; scanner walks all three channels by default.unknownprovider; added stable dedup keys to prevent double-counting.providerOptionsis missing; logo URL switched to the Codebuff GitHub avatar.Written for commit ea19bf7. Summary will update on new commits.