Skip to content

feat(kimi): implement Kimi CLI usage tracking#840

Open
azidancorp wants to merge 5 commits intoryoppippi:mainfrom
azidancorp:main
Open

feat(kimi): implement Kimi CLI usage tracking#840
azidancorp wants to merge 5 commits intoryoppippi:mainfrom
azidancorp:main

Conversation

@azidancorp
Copy link

@azidancorp azidancorp commented Feb 5, 2026

  • Add new @ccusage/kimi CLI package for analyzing Kimi CLI sessions
  • Extend MCP server with 4 new tools: kimi-daily, kimi-monthly, kimi-session, kimi-weekly
  • Add Kimi data loader and type definitions
  • Extract reasoning tokens from ContentPart think messages (~4 chars/token
    estimate)
  • Update tests for new MCP tools
  • Support KIMI_SHARE_DIR and KIMI_MODEL_NAME environment variables
  • Update pnpm-lock.yaml with new workspace dependencies

Summary by CodeRabbit

  • New Features
    • Added Kimi CLI: daily/weekly/monthly/session usage reports (JSON or formatted table), timezone/locale filters, compact mode, and per-model cost aggregation.
  • Documentation
    • New README and CLAUDE guide with quick start, usage examples, env vars, and session/log locations.
  • Integration
    • Kimi CLI integrated into existing tooling for programmatic access.
  • Tests
    • Added unit and end-to-end tests and test config for Kimi.

@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Adds a new @ccusage/kimi CLI app and MCP integration that parses Kimi session wire logs, extracts and deduplicates token usage events (including reasoning extraction), aggregates usage by day/week/month/session, applies per-model pricing, renders table/JSON outputs, and exposes Zod-validated MCP tools invoking the CLI.

Changes

Cohort / File(s) Summary
Documentation
apps/ccusage/README.md, apps/kimi/README.md, apps/kimi/CLAUDE.md
Added Kimi documentation: quick start, usage examples, log locations, token mappings, pricing, and limitations.
Package & Build Config
apps/kimi/package.json, apps/kimi/tsconfig.json, apps/kimi/tsdown.config.ts, apps/kimi/vitest.config.ts, apps/kimi/eslint.config.js
New package metadata, scripts, TypeScript config, tsdown, Vitest, and ESLint config for the Kimi app.
Constants & Shared Args
apps/kimi/src/_consts.ts, apps/kimi/src/_shared-args.ts
Defined env keys, file/name defaults, globs, timezone/locale defaults, and a shared CLI args schema.
Types
apps/kimi/src/_types.ts
Introduced TypeScript types for token deltas/events, model usage, pricing, and report rows (daily/weekly/monthly/session).
Data loader
apps/kimi/src/data-loader.ts
New streaming parser for wire.jsonl: dedupes StatusUpdate, extracts reasoning from ContentPart think messages, maps hashed workdirs, resolves models, and emits sorted LoadResult events plus missing directories.
Report builders
apps/kimi/src/daily-report.ts, apps/kimi/src/weekly-report.ts, apps/kimi/src/monthly-report.ts, apps/kimi/src/session-report.ts
Functions to bucket events by day/week/month/session, aggregate per-model usage, fetch per-model pricing, compute costs, and return formatted report rows.
CLI Commands & Entry
apps/kimi/src/commands/*.ts, apps/kimi/src/index.ts, apps/kimi/src/run.ts
Added daily/weekly/monthly/session commands, CLI entrypoint and run wiring (gunshi) with JSON/compact rendering options.
Utilities
apps/kimi/src/token-utils.ts, apps/kimi/src/date-utils.ts, apps/kimi/src/command-utils.ts, apps/kimi/src/pricing.ts, apps/kimi/src/logger.ts
Token math, cost calculation, date/key formatting, model-name normalization and pricing source, model list formatting, and logger binding.
MCP Integration & Tests
apps/mcp/src/kimi.ts, apps/mcp/src/mcp.ts, apps/mcp/package.json
Zod-validated Kimi CLI wrappers (getKimiDaily/Weekly/Monthly/Session), MCP tools added for each report, env handling, and tests updated to include Kimi tools.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/CLI
    participant Cmd as Kimi Command
    participant Loader as Data Loader
    participant Wire as wire.jsonl Files
    participant Builder as Report Builder
    participant Pricing as KimiPricingSource
    participant Output as Table/JSON

    User->>Cmd: run command (e.g. daily --json --since ...)
    Cmd->>Loader: loadTokenUsageEvents(shareDir?)
    Loader->>Wire: read & stream parse wire.jsonl
    Wire-->>Loader: lines (ContentPart / StatusUpdate)
    Loader->>Loader: dedupe, extract reasoning, map workdirs
    Loader-->>Cmd: TokenUsageEvent[]
    Cmd->>Builder: buildReport(events, {pricingSource,...})
    Builder->>Pricing: getPricing(model) for each model
    Pricing-->>Builder: ModelPricing
    Builder-->>Cmd: ReportRow[]
    Cmd->>Output: render JSON or table
    Output-->>User: display results
Loading
sequenceDiagram
    participant MCPClient as MCP Client
    participant MCPServer as MCP Server
    participant Wrapper as Kimi Wrapper (apps/mcp/src/kimi.ts)
    participant KimiCLI as Kimi CLI Process
    participant Zod as Zod Validator

    MCPClient->>MCPServer: invoke tool (kimi-daily/etc.)
    MCPServer->>Wrapper: getKimiDaily(params)
    Wrapper->>Zod: validate params
    Wrapper->>KimiCLI: spawn ccusage-kimi --json ...
    KimiCLI->>KimiCLI: load files, build report, print JSON
    KimiCLI-->>Wrapper: JSON output
    Wrapper->>Zod: parse & validate output
    Wrapper-->>MCPServer: return typed result
    MCPServer-->>MCPClient: tool response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • ryoppippi

"🐇 I hopped through wire lines bright,
I counted tokens day and night,
Per-model coins and totals told,
Weekly, monthly, sessions bold.
Hooray — Kimi's reports take flight! ✨"

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(kimi): implement Kimi CLI usage tracking' accurately and concisely summarizes the main change: implementing a new Kimi CLI package for usage analysis. It is clear, specific, and directly related to the primary objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@socket-security
Copy link

socket-security bot commented Feb 5, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedtypedoc-vitepress-theme@​1.1.2901007281100
Addedtypedoc-plugin-markdown@​4.8.11001008086100
Addedstring-width@​7.2.01001008886100
Addedtsdown@​0.16.6981009296100
Addedtypedoc@​0.28.131001009896100

View full report

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/mcp/package.json (1)

55-66: 🛠️ Refactor suggestion | 🟠 Major

Move @ccusage/kimi to devDependencies.

Per coding guidelines, all projects under apps/ ship as bundled CLIs — runtime dependencies should be listed in devDependencies (never dependencies) so the bundler owns the runtime payload.

Proposed fix
 	"dependencies": {
 		"@ccusage/codex": "workspace:*",
-		"@ccusage/kimi": "workspace:*",
 		"@hono/mcp": "catalog:runtime",
 		...
 	},
 	"devDependencies": {
 		"@ccusage/internal": "workspace:*",
+		"@ccusage/kimi": "workspace:*",
 		"@ryoppippi/eslint-config": "catalog:lint",
 		...
 	},

As per coding guidelines: "All projects under apps/ ship as bundled CLIs/binaries - list runtime dependencies in devDependencies (never dependencies) so the bundler owns the runtime payload".

🤖 Fix all issues with AI agents
In `@apps/ccusage/README.md`:
- Around line 36-38: Update the README blurb under the "### 🌙 [`@ccusage/kimi`]"
header to list "weekly" alongside "daily, monthly, and session-based" reports;
specifically, edit the sentence that currently reads "Track daily, monthly, and
session-based token usage and costs from your local `~/.kimi/sessions` logs." to
include "weekly" (and optionally reference the provided `kimi-weekly` tool) so
it reads something like "Track daily, weekly, monthly, and session-based token
usage and costs from your local `~/.kimi/sessions` logs." Ensure the change is
made in the same section containing the [`@ccusage/kimi`] heading and the
backticked path `~/.kimi/sessions`.

In `@apps/kimi/CLAUDE.md`:
- Line 150: The sentence in CLAUDE.md is self-contradictory; update the line
that reads "No weekly command: Implemented (unlike other apps)" to correctly
state that the weekly command is implemented (e.g., "Weekly command: Implemented
(unlike other apps)"), reflecting the presence of the weekly.ts command in the
codebase.

In `@apps/kimi/README.md`:
- Around line 121-125: The sponsors SVG image tag in the README (<img
src="https://cdn.jsdelivr.net/gh/ryoppippi/sponsors@main/sponsors.svg">) is
missing an alt attribute; update that <img> element to include a descriptive alt
text (e.g., alt="Project sponsors" or similar) to satisfy accessibility
guidelines and ensure screen readers convey the image purpose.

In `@apps/kimi/src/_consts.ts`:
- Around line 12-13: SESSION_GLOB is constructed incorrectly and expands to a
two-level pattern; change its definition so it matches one-level session
directories. Replace the current SESSION_GLOB = `*/${WIRE_GLOB}` with a pattern
that directly uses KIMI_WIRE_FILE_NAME (e.g., SESSION_GLOB =
`*/${KIMI_WIRE_FILE_NAME}`) or set SESSION_GLOB to the same value as WIRE_GLOB
so glob(cwd: sessionsDir) will correctly match files like
~/.kimi/sessions/{session_id}/wire.jsonl; update the constant in
apps/kimi/src/_consts.ts where WIRE_GLOB, SESSION_GLOB, and KIMI_WIRE_FILE_NAME
are defined.
🧹 Nitpick comments (10)
apps/kimi/src/command-utils.ts (1)

3-8: Type inconsistency: reasoningOutputTokens nullish coalescing vs required type.

Line 7 declares reasoningOutputTokens: number as required, but line 19 uses usage.reasoningOutputTokens ?? 0, implying it could be undefined. Either make the type optional (reasoningOutputTokens?: number) or remove the nullish coalescing if the field is always present.

♻️ Option A: Make type optional
 export type UsageGroup = {
 	inputTokens: number;
 	cachedInputTokens: number;
 	outputTokens: number;
-	reasoningOutputTokens: number;
+	reasoningOutputTokens?: number;
 };
♻️ Option B: Remove nullish coalescing
-	const rawReasoning = usage.reasoningOutputTokens ?? 0;
+	const rawReasoning = usage.reasoningOutputTokens;

Also applies to: 19-19

apps/kimi/src/token-utils.ts (1)

15-21: Consider documenting the mutation behavior.

addUsage mutates target in place rather than returning a new object. This is a valid pattern for performance, but a brief JSDoc comment would clarify intent for future maintainers.

apps/kimi/src/commands/monthly.ts (1)

36-42: Consider preserving error details in logging.

String(error) may lose stack trace information. For better debugging, consider logging the error object directly or checking if it's an Error instance.

♻️ Proposed improvement
 		} catch (error) {
-			logger.error(String(error));
+			logger.error(error instanceof Error ? error.message : String(error));
 			process.exit(1);
 		}
apps/kimi/CLAUDE.md (2)

49-55: Add language specifier to fenced code block.

The markdownlint tool flags this code block for missing a language specifier. Consider adding a language identifier (e.g., text or plaintext) to satisfy MD040.

Suggested fix
-```
+```text
 inputTokens = input_other + input_cache_read + input_cache_creation

117-119: Add language specifier to fenced code block.

Same markdownlint MD040 issue - add a language identifier.

Suggested fix
-```
+```text
 {work_directory_path}/{session_file_id}
apps/kimi/src/commands/session.ts (1)

175-177: Missing compact mode notice.

The daily command (lines 166-169 in daily.ts) displays a helpful notice when running in compact mode, informing users to expand terminal width for additional metrics. This session command lacks that notice, creating inconsistent UX.

Suggested fix
 	log(table.toString());
+
+	if (table.isCompactMode()) {
+		logger.info('\nRunning in Compact Mode');
+		logger.info('Expand terminal width to see reasoning and cache metrics');
+	}
 },
apps/kimi/src/daily-report.ts (1)

83-86: Consider parallelizing pricing lookups.

The sequential await in the loop could be parallelized for better performance when there are multiple unique models. While the impact is likely minimal (few unique models), it's a common optimization pattern.

Suggested fix
 const modelPricing = new Map<string, Awaited<ReturnType<PricingSource['getPricing']>>>();
-for (const modelName of uniqueModels) {
-	modelPricing.set(modelName, await pricingSource.getPricing(modelName));
-}
+await Promise.all(
+	Array.from(uniqueModels).map(async (modelName) => {
+		modelPricing.set(modelName, await pricingSource.getPricing(modelName));
+	}),
+);
apps/kimi/src/pricing.ts (2)

4-4: Module-level warnedModels state may affect test isolation.

The warnedModels Set persists across all KimiPricingSource instances and test runs within the same process. While this correctly deduplicates warnings in production, it means:

  1. Tests cannot verify the warning is emitted without mocking the logger
  2. If a test queries an unknown model, subsequent tests won't see the warning for that same model

Consider either:

  • Accepting this as intended behavior (warnings are one-time per process)
  • Adding a clearWarnings() method for testing purposes (unexported)

This is a minor concern since the current test uses a unique model name and the behavior is documented.

Also applies to: 65-70


12-15: IIFE for lastSegment extraction is unconventional.

The immediately-invoked function expression (IIFE) works but is unusual for this simple operation. A more idiomatic approach would be direct assignment.

Suggested simplification
-const lastSegment = (() => {
-	const idx = trimmed.lastIndexOf('/');
-	return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;
-})();
+const idx = trimmed.lastIndexOf('/');
+const lastSegment = idx >= 0 ? trimmed.slice(idx + 1) : trimmed;
apps/mcp/src/kimi.ts (1)

145-163: Wrap JSON parsing with Result.try() for consistent error handling.

JSON.parse can throw; using @praha/byethrow keeps failures consistent with project guidelines.

♻️ Suggested refactor
-import { z } from 'zod';
+import { Result } from '@praha/byethrow';
+import { z } from 'zod';
@@
 const kimiWeeklyResponseSchema = z.object({
 	weekly: z.array(kimiWeeklyRowSchema),
 	totals: kimiTotalsSchema.nullable(),
 });
+
+function parseKimiJson<T>(raw: string, schema: z.ZodType<T>): T {
+	const parsed = Result.try({
+		try: () => JSON.parse(raw) as unknown,
+		catch: (error) => error,
+	})();
+	if (Result.isFailure(parsed)) {
+		throw parsed.error;
+	}
+	return schema.parse(parsed.value);
+}
@@
 export async function getKimiDaily(parameters: z.infer<typeof kimiParametersSchema>) {
 	const raw = await runKimiCliJson('daily', parameters);
-	return kimiDailyResponseSchema.parse(JSON.parse(raw));
+	return parseKimiJson(raw, kimiDailyResponseSchema);
 }
@@
 export async function getKimiMonthly(parameters: z.infer<typeof kimiParametersSchema>) {
 	const raw = await runKimiCliJson('monthly', parameters);
-	return kimiMonthlyResponseSchema.parse(JSON.parse(raw));
+	return parseKimiJson(raw, kimiMonthlyResponseSchema);
 }
@@
 export async function getKimiSession(parameters: z.infer<typeof kimiParametersSchema>) {
 	const raw = await runKimiCliJson('session', parameters);
-	return kimiSessionResponseSchema.parse(JSON.parse(raw));
+	return parseKimiJson(raw, kimiSessionResponseSchema);
 }
@@
 export async function getKimiWeekly(parameters: z.infer<typeof kimiParametersSchema>) {
 	const raw = await runKimiCliJson('weekly', parameters);
-	return kimiWeeklyResponseSchema.parse(JSON.parse(raw));
+	return parseKimiJson(raw, kimiWeeklyResponseSchema);
 }

Comment on lines +12 to +13
export const WIRE_GLOB = `*/${KIMI_WIRE_FILE_NAME}`;
export const SESSION_GLOB = `*/${WIRE_GLOB}`;
Copy link

@coderabbitai coderabbitai bot Feb 5, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

rg -n "SESSION_GLOB|WIRE_GLOB" --type ts -C 2

Repository: ryoppippi/ccusage

Length of output: 2044


🏁 Script executed:

# Also check the directory structure for sessions and wires
find . -type f -name "*.jsonl" | head -20

Repository: ryoppippi/ccusage

Length of output: 102


🏁 Script executed:

# Check if there are any test files or fixtures that show the expected structure
find . -type d -name "*session*" -o -type d -name "*wire*" | head -20

Repository: ryoppippi/ccusage

Length of output: 43


🏁 Script executed:

# Check data-loader.ts for context on expected directory structure
sed -n '160,180p' apps/kimi/src/data-loader.ts

Repository: ryoppippi/ccusage

Length of output: 749


🏁 Script executed:

# Search for any comments or documentation about the directory structure
rg -i "session.*structure|directory.*structure|wire.*path" apps/kimi/src/ --type ts

Repository: ryoppippi/ccusage

Length of output: 43


🏁 Script executed:

# Check if there are any tests or fixtures that show the expected structure
find apps/kimi -type f \( -name "*.test.ts" -o -name "*.spec.ts" -o -name "fixture*" \) | head -10

Repository: ryoppippi/ccusage

Length of output: 43


🏁 Script executed:

# Check how sessions are created/structured by looking for mkdir or path.join patterns
rg -n "sessions|session-" apps/kimi/src/ --type ts -B 2 -A 2 | head -40

Repository: ryoppippi/ccusage

Length of output: 2291


🏁 Script executed:

# Look for any README or documentation about the data structure
find apps/kimi -type f \( -name "README*" -o -name "*.md" \)

Repository: ryoppippi/ccusage

Length of output: 100


🏁 Script executed:

# Check if the pattern actually works by looking at what files are scanned
rg -n "loadKimiEvents\|loadEvents" apps/kimi/src/ --type ts -A 5 | head -30

Repository: ryoppippi/ccusage

Length of output: 43


🏁 Script executed:

# Check the README for directory structure information
cat apps/kimi/README.md

Repository: ryoppippi/ccusage

Length of output: 6719


🏁 Script executed:

# Also check CLAUDE.md
cat apps/kimi/CLAUDE.md

Repository: ryoppippi/ccusage

Length of output: 6697


SESSION_GLOB pattern is incorrect and will not match session files.

The current definition SESSION_GLOB = \/${WIRE_GLOB}`expands to//wire.jsonl, but session files are actually located at ~/.kimi/sessions/{session_id}/wire.jsonl(one level deep). Whenglob()is called withcwd: sessionsDir, the pattern /*/wire.jsonl` looks for files two levels deep and will not match any files.

Change SESSION_GLOB to match the actual structure: */${KIMI_WIRE_FILE_NAME} (same as WIRE_GLOB) or restructure the definition to avoid string interpolation issues.

🤖 Prompt for AI Agents
In `@apps/kimi/src/_consts.ts` around lines 12 - 13, SESSION_GLOB is constructed
incorrectly and expands to a two-level pattern; change its definition so it
matches one-level session directories. Replace the current SESSION_GLOB =
`*/${WIRE_GLOB}` with a pattern that directly uses KIMI_WIRE_FILE_NAME (e.g.,
SESSION_GLOB = `*/${KIMI_WIRE_FILE_NAME}`) or set SESSION_GLOB to the same value
as WIRE_GLOB so glob(cwd: sessionsDir) will correctly match files like
~/.kimi/sessions/{session_id}/wire.jsonl; update the constant in
apps/kimi/src/_consts.ts where WIRE_GLOB, SESSION_GLOB, and KIMI_WIRE_FILE_NAME
are defined.

Copy link
Author

Choose a reason for hiding this comment

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

This seems to be inaccurate - this is the actual path structure on my current .kimi:

~/.kimi/sessions/138fb6b4331c5ba58fbc2498965ac4c7/7781ea1b-3dd7-4348-9b87-70243ed62887$ ls context.jsonl wire.jsonl

Also checked with three agents which agree its a false positive

Copy link

Choose a reason for hiding this comment

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

@azidancorp, you're absolutely right—I apologize for the false positive!

The pattern SESSION_GLOB = */*/wire.jsonl is indeed correct for the actual directory structure. When glob runs with cwd: sessionsDir (~/.kimi/sessions), it needs to match:

{hash}/{session_id}/wire.jsonl

which is exactly two directory levels, so */*/wire.jsonl matches perfectly.

Thank you for verifying with the actual filesystem and multiple agents—I appreciate the thorough validation!


🧠 Learnings used
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/opencode/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:17.625Z
Learning: Applies to apps/opencode/**/*.{ts,tsx,js,jsx} : Data discovery relies on `OPENCODE_DATA_DIR` environment variable with default path `~/.local/share/opencode`

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.548Z
Learning: Applies to **/*.ts : Only export constants, functions, and types that are actually used by other modules - do not export internal/private constants used only within the same file

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.548Z
Learning: Applies to **/*.ts : Use UPPER_SNAKE_CASE for constants (e.g., `DEFAULT_CLAUDE_CODE_PATH`)

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.548Z
Learning: For apps, use the app directory name in commit scope (e.g., `feat(ccusage):`, `fix(mcp):`)

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.548Z
Learning: For packages, use the package directory name in commit scope (e.g., `feat(terminal):`, `fix(ui):`)

azidancorp and others added 3 commits February 5, 2026 12:55
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/kimi/CLAUDE.md`:
- Around line 138-141: The three consecutive bullets in CLAUDE.md start with the
same phrase "Tests verify …", which reduces readability; update one or two of
them to vary the phrasing while preserving meaning—e.g., change the second
bullet ("Tests verify token field mapping from Kimi's wire format") to "Verifies
token field mapping from Kimi's wire format" and the third ("Tests verify work
directory hash mapping and deduplication logic") to "Checks work directory hash
mapping and deduplication logic", keeping the first bullet unchanged; ensure the
wording still accurately reflects the tests' intent.
🧹 Nitpick comments (1)
apps/kimi/README.md (1)

2-2: Use relative paths for images stored in /docs/public/.

These two images are served from docs/public but use absolute CDN URLs. Per the markdown guideline, switch to relative paths.
As per coding guidelines: "Use relative image paths like /screenshot.png for images stored in /docs/public/."

🔧 Suggested fix
-    <img src="https://cdn.jsdelivr.net/gh/ryoppippi/ccusage@main/docs/public/logo.svg" alt="ccusage logo" width="256" height="256">
+    <img src="/logo.svg" alt="ccusage logo" width="256" height="256">
-        <img src="https://cdn.jsdelivr.net/gh/ryoppippi/ccusage@main/docs/public/ccusage_thumbnail.png" alt="ccusage: The Claude Code cost scorecard that went viral" width="600">
+        <img src="/ccusage_thumbnail.png" alt="ccusage: The Claude Code cost scorecard that went viral" width="600">

Also applies to: 117-117

Comment on lines +138 to +141
- Tests rely on `fs-fixture` with `using` to ensure cleanup.
- Tests verify token field mapping from Kimi's wire format.
- Tests verify work directory hash mapping and deduplication logic.
- Tests verify pricing lookup for known models and fallback for unknown models.
Copy link

@coderabbitai coderabbitai bot Feb 5, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reduce repeated “Tests verify …” sentence starts for readability.

These three bullets begin identically; rephrase one or two to improve flow.

🧰 Tools
🪛 LanguageTool

[style] ~140-~140: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ield mapping from Kimi's wire format. - Tests verify work directory hash mapping and ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~141-~141: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hash mapping and deduplication logic. - Tests verify pricing lookup for known models ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🤖 Prompt for AI Agents
In `@apps/kimi/CLAUDE.md` around lines 138 - 141, The three consecutive bullets in
CLAUDE.md start with the same phrase "Tests verify …", which reduces
readability; update one or two of them to vary the phrasing while preserving
meaning—e.g., change the second bullet ("Tests verify token field mapping from
Kimi's wire format") to "Verifies token field mapping from Kimi's wire format"
and the third ("Tests verify work directory hash mapping and deduplication
logic") to "Checks work directory hash mapping and deduplication logic", keeping
the first bullet unchanged; ensure the wording still accurately reflects the
tests' intent.

Copy link
Author

Choose a reason for hiding this comment

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

Seems fine as is, leaving this one.
Ive added the three other suggested commits, and rejected the false positive for wire.json paths

Copy link

Choose a reason for hiding this comment

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

@azidancorp, understood! Thanks for addressing the other suggestions. 👍


🧠 Learnings used
Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : In tests, use current Claude 4 models (sonnet-4, opus-4)

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.548Z
Learning: The data loading architecture follows a clear separation of concerns: Data Loading (data-loader.ts), Token Aggregation (calculate-cost.ts), Command Execution (commands/), and CLI Entry (index.ts)

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: apps/ccusage/CLAUDE.md:0-0
Timestamp: 2025-09-18T16:06:37.474Z
Learning: Applies to apps/ccusage/src/**/*.ts : Use `fs-fixture` with `createFixture()` to simulate Claude data in tests

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.548Z
Learning: For apps, use the app directory name in commit scope (e.g., `feat(ccusage):`, `fix(mcp):`)

Learnt from: CR
Repo: ryoppippi/ccusage PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T12:22:39.548Z
Learning: For packages, use the package directory name in commit scope (e.g., `feat(terminal):`, `fix(ui):`)

@azidancorp
Copy link
Author

I havent registered or published anything on npm for this, link in the readme wont work until then

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/kimi/README.md`:
- Around line 7-8: The README currently includes an npm badge/link for
`@ccusage/kimi` which will 404 until the package is published; update the
README.md to either remove the npm badge/link lines referencing `@ccusage/kimi` or
replace them with a “Coming soon — package not yet published” note (leave the
existing socket.dev badge if desired) so users aren’t led to a broken npm page;
look for the badge markup containing "@ccusage/kimi" to locate and change the
lines.

Comment on lines +7 to +8
<a href="https://socket.dev/api/npm/package/@ccusage/kimi"><img src="https://socket.dev/api/badge/npm/package/@ccusage/kimi" alt="Socket Badge" /></a>
<a href="https://npmjs.com/package/@ccusage/kimi"><img src="https://img.shields.io/npm/v/@ccusage/kimi?color=yellow" alt="npm version" /></a>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

NPM badge/link will be broken until the package is published.

Given the package isn’t registered yet, the badge and link will likely 404. Consider adding a “coming soon” note or removing the npm badge/link until publication to avoid confusion.

🤖 Prompt for AI Agents
In `@apps/kimi/README.md` around lines 7 - 8, The README currently includes an npm
badge/link for `@ccusage/kimi` which will 404 until the package is published;
update the README.md to either remove the npm badge/link lines referencing
`@ccusage/kimi` or replace them with a “Coming soon — package not yet published”
note (leave the existing socket.dev badge if desired) so users aren’t led to a
broken npm page; look for the badge markup containing "@ccusage/kimi" to locate
and change the lines.

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.

1 participant