Skip to content

Conversation

@infonobody
Copy link

@infonobody infonobody commented Jun 19, 2025

The watch command provides real-time monitoring within the current active block. It displays a live dashboard showing:

CleanShot 2025-06-19 _23 11 27

Key Features:

  • Time countdown bar - Shows remaining time in the current block with color-coded warnings (green/yellow/red)
  • Cost usage bar - Visualizes spending by model type (Opus/Sonnet/Haiku) with projections
  • Live statistics - Current tokens and costs with estimated end-of-block totals
  • Interactive controls - Toggle detailed views with keyboard shortcuts (T/C/P)
  • Session summary - Shows duration, tokens used, and cost when exiting

Visual Elements:

  • Progress bars use colored blocks (■) to show usage
  • Models are color-coded: Opus (blue), Sonnet (cyan), Haiku (magenta)

Smart Features:

  • Automatically adjusts update frequency based on activity (5s to 60s intervals)
  • Projects total usage based on current burn rate
  • Warns when approaching time limits
  • Tracks usage changes during the monitoring session

This tool is perfect for developers who want to keep an eye on their Claude Code usage in real-time, helping them stay within budget and manage their token consumption
effectively.

Summary by CodeRabbit

  • New Features

    • Introduced a new "watch" CLI command for real-time monitoring of session usage, showing tokens, costs, burn rates, and time remaining with interactive controls.
    • Added detailed token, cost, and burn rate breakdown tables with color-coded progress bars and projections.
    • Implemented adaptive refresh intervals and keyboard shortcuts to toggle detailed views and exit monitoring mode.
    • Added session summary display upon exiting watch mode.
  • Improvements

    • Enhanced model name formatting to support legacy formats for clearer usage categorization.

@coderabbitai
Copy link

coderabbitai bot commented Jun 19, 2025

Walkthrough

A new CLI subcommand "watch" has been introduced, providing real-time monitoring of session usage statistics with interactive terminal controls. Supporting utilities were updated to recognize an additional legacy model name format. New modules were added for progress bar rendering, session tracking, burn rate analysis, detailed table display, adaptive scheduling, keyboard input handling, and dynamic watch display updates. Existing commands and behaviors remain unchanged.

Changes

File(s) Change Summary
src/commands/index.ts Registered a new CLI subcommand "watch" by importing and adding watchCommand to the subCommands map.
src/commands/watch.ts Added a new CLI command "watch" for interactive real-time session usage monitoring with adaptive display features.
src/utils.internal.ts Added formatDuration and clearScreen utilities; enhanced formatModelName to support legacy model name format.
src/progress-bar.internal.ts Added progress bar utilities for model cost usage with color-coded segments and projections.
src/session-blocks.internal.ts Added burn rate analysis over multiple time periods with new calculation functions and constants.
src/session-tracker.internal.ts Added session tracker to manage initial token and cost values for session summaries.
src/table-display.internal.ts Added functions to create and display detailed token, cost, and burn rate tables for session blocks.
src/types.internal.ts Added ModelTypes, ModelType, and DisplayOptions types for model categorization and display toggles.
src/watch-display.internal.ts Added display logic for active session blocks with adaptive refresh intervals, progress bars, and detailed views.
src/watch-input.internal.ts Added keyboard input handling and cleanup routines for toggling display options and exiting watch mode.
src/watch-scheduler.internal.ts Added adaptive scheduler to manage variable-interval asynchronous updates for the watch display.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant WatchCommand
    participant SessionData

    User->>CLI: Run "watch" command
    CLI->>WatchCommand: Initialize and start watch
    loop Every interval
        WatchCommand->>SessionData: Load latest session block data
        SessionData-->>WatchCommand: Return usage stats
        WatchCommand->>CLI: Update terminal display
        User->>WatchCommand: Toggle display or exit (key input)
    end
    WatchCommand->>CLI: Display session summary on exit
Loading

Suggested reviewers

  • ryoppippi

Poem

A rabbit peers at stats in real time,
Watching tokens and costs as they climb.
With toggles and bars,
And colors like stars,
The session’s a warren—efficient, sublime!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @infonobody, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the CLI's capabilities by adding a real-time monitoring tool for active Claude session blocks. The new watch command provides developers with an immediate, interactive overview of their AI usage, helping them manage resources and stay within budget through dynamic visualizations and detailed statistics.

Highlights

  • New watch Command: Introduced a new watch command that provides real-time, interactive monitoring of your active Claude session block usage directly in the terminal. This helps users keep track of their token consumption and costs.
  • Live Dashboard & Visualizations: The watch command displays a live dashboard featuring a time countdown bar with color-coded warnings, and a cost usage bar visualizing spending by model type (Opus, Sonnet, Haiku). It also shows current and projected token/cost statistics.
  • Interactive Controls & Adaptive Updates: Users can toggle detailed views for token breakdown, cost breakdown, and burn rate analysis using keyboard shortcuts (T, C, P). The display automatically adjusts its update frequency (5s to 60s) based on activity, ensuring an efficient monitoring experience.
  • Session Summary: Upon exiting the watch command, a summary of the session's duration, tokens used, and cost incurred during the monitoring period is displayed.
  • Improved Model Name Formatting: The utility function for formatting model names has been enhanced to correctly parse and display older Claude model name conventions, ensuring consistency across the application.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a watch command for real-time monitoring of Claude Code usage. The implementation includes dynamic progress bars, cost estimations, and interactive controls. I've provided suggestions for minor code cleanup in watch.ts and utils.internal.ts to improve maintainability.

* @param _allBlocks - All blocks for historical comparison
* @returns Burn rate analysis object
*/
function calculateBurnRateAnalysis(block: SessionBlock, _allBlocks: SessionBlock[]): BurnRateAnalysis {
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The _allBlocks parameter is unused. Consider removing it to avoid confusion, or add a comment explaining its intended future use.

Comment on lines 561 to 563
if (firstEntry == null || lastEntry == null) {
return nullResult;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The null check for firstEntry and lastEntry is redundant because the function returns early if sortedEntries.length < 2. This if block can be removed.

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: 0

🧹 Nitpick comments (2)
src/commands/watch.ts (2)

10-12: Improve import consistency for better code style.

Consider using top-level type-only imports instead of inline type specifiers for consistency with the project's linting rules.

Apply this diff to improve import style:

-	type LoadedUsageEntry,
+	type LoadedUsageEntry,
 	projectBlockUsage,
-	type SessionBlock,
+	type SessionBlock,

And add a separate type import:

+import type { LoadedUsageEntry, SessionBlock } from '../session-blocks.internal.ts';
 import {
 	calculateBurnRate,
 	DEFAULT_SESSION_DURATION_HOURS,
-	type LoadedUsageEntry,
 	projectBlockUsage,
-	type SessionBlock,
 } from '../session-blocks.internal.ts';

314-322: Cost breakdown estimation limitation.

The proportional cost calculation assumes equal cost per token across all token types (input, output, cache create, cache read), which may not reflect actual pricing differences. However, this is a reasonable approximation given that detailed cost breakdowns aren't available in the source data.

Consider adding a comment to document this limitation:

 		// Calculate individual cost components
-		// We need to estimate the cost breakdown since we only have total costUSD
+		// We need to estimate the cost breakdown since we only have total costUSD
+		// Note: This assumes equal cost per token across all types, which may not be accurate
 		const totalTokens = entry.usage.inputTokens + entry.usage.outputTokens + entry.usage.cacheCreationInputTokens + entry.usage.cacheReadInputTokens;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2f4b7b and 50d6a78.

📒 Files selected for processing (3)
  • src/commands/index.ts (2 hunks)
  • src/commands/watch.ts (1 hunks)
  • src/utils.internal.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/commands/index.ts (1)
src/commands/watch.ts (1)
  • watchCommand (706-912)
🪛 ESLint
src/commands/watch.ts

[error] 10-10: Prefer using a top-level type-only import instead of inline type specifiers.

(import/consistent-type-specifier-style)


[error] 12-12: Prefer using a top-level type-only import instead of inline type specifiers.

(import/consistent-type-specifier-style)


[error] 182-182: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 182-182: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 182-182: Unsafe member access .blue on an error typed value.

(ts/no-unsafe-member-access)


[error] 183-183: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 183-183: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 183-183: Unsafe member access .cyan on an error typed value.

(ts/no-unsafe-member-access)


[error] 184-184: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 184-184: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 184-184: Unsafe member access .magenta on an error typed value.

(ts/no-unsafe-member-access)


[error] 185-185: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 185-185: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 185-185: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 197-197: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 197-197: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 205-205: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 211-211: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 211-211: Unsafe member access .blue on an error typed value.

(ts/no-unsafe-member-access)


[error] 215-215: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 215-215: Unsafe member access .cyan on an error typed value.

(ts/no-unsafe-member-access)


[error] 219-219: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 219-219: Unsafe member access .magenta on an error typed value.

(ts/no-unsafe-member-access)


[error] 221-221: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 221-221: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 222-222: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 223-223: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 230-234: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 230-234: Unsafe construction of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 264-264: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 264-264: Unsafe member access .push on an error typed value.

(ts/no-unsafe-member-access)


[error] 281-281: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 281-281: Unsafe member access .push on an error typed value.

(ts/no-unsafe-member-access)


[error] 282-282: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 282-282: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 283-283: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 283-283: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 284-284: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 284-284: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 285-285: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 285-285: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 286-286: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 286-286: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 287-287: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 287-287: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 291-291: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 291-291: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 291-291: Unsafe member access .toString on an error typed value.

(ts/no-unsafe-member-access)


[error] 298-302: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 298-302: Unsafe construction of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 339-339: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 339-339: Unsafe member access .push on an error typed value.

(ts/no-unsafe-member-access)


[error] 356-356: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 356-356: Unsafe member access .push on an error typed value.

(ts/no-unsafe-member-access)


[error] 357-357: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 357-357: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 358-358: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 358-358: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 359-359: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 359-359: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 360-360: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 360-360: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 361-361: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 361-361: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 362-362: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 362-362: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 366-366: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 366-366: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 366-366: Unsafe member access .toString on an error typed value.

(ts/no-unsafe-member-access)


[error] 373-377: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 373-377: Unsafe construction of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 383-383: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 383-383: Unsafe member access .push on an error typed value.

(ts/no-unsafe-member-access)


[error] 389-389: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 389-389: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 389-389: Unsafe member access .toString on an error typed value.

(ts/no-unsafe-member-access)


[error] 429-429: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 429-429: Unsafe member access .green on an error typed value.

(ts/no-unsafe-member-access)


[error] 429-429: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 429-429: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 448-448: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 448-448: Unsafe member access .stdout on an error typed value.

(ts/no-unsafe-member-access)


[error] 601-601: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 601-601: Unsafe member access .green on an error typed value.

(ts/no-unsafe-member-access)


[error] 603-603: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 603-603: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 606-606: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 606-606: Unsafe member access .yellow on an error typed value.

(ts/no-unsafe-member-access)


[error] 613-613: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 613-613: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 614-614: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 617-617: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 676-676: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 677-677: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 681-681: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 686-686: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 691-691: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 694-694: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 703-703: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 706-912: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 706-706: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 709-717: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 721-721: Unsafe member access .level on an error typed value.

(ts/no-unsafe-member-access)


[error] 724-724: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 724-724: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 727-727: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 727-727: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 728-728: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 728-728: Unsafe member access .error on an error typed value.

(ts/no-unsafe-member-access)


[error] 729-729: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 729-729: Unsafe member access .exit on an error typed value.

(ts/no-unsafe-member-access)


[error] 749-749: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 749-749: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 750-750: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 750-750: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 753-753: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 754-754: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 754-754: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 761-761: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 761-761: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 761-761: Unsafe member access .yellow on an error typed value.

(ts/no-unsafe-member-access)


[error] 762-762: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 763-763: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 813-813: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 813-813: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 813-813: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 814-814: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 814-814: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 814-814: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 815-815: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 816-816: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 825-831: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 825-825: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 829-829: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 829-829: Unsafe member access .error on an error typed value.

(ts/no-unsafe-member-access)


[error] 837-837: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 837-837: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 838-838: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 838-838: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 839-839: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 839-839: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 842-842: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 843-843: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 843-843: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 844-844: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 844-844: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 871-871: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 871-871: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 871-871: Unsafe member access .cyan on an error typed value.

(ts/no-unsafe-member-access)


[error] 872-872: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 872-872: Unsafe member access .exit on an error typed value.

(ts/no-unsafe-member-access)


[error] 902-902: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 902-902: Unsafe member access .error on an error typed value.

(ts/no-unsafe-member-access)


[error] 907-907: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 907-907: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 910-910: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 910-910: Unsafe member access .on on an error typed value.

(ts/no-unsafe-member-access)

🔇 Additional comments (5)
src/commands/index.ts (1)

9-9: Clean integration of the new watch command.

The import and registration follow the established pattern and integrate seamlessly with the existing CLI structure.

Also applies to: 19-19

src/utils.internal.ts (1)

235-240: Good backward compatibility enhancement.

The addition properly handles legacy model name formats while maintaining the existing functionality. The regex pattern correctly captures and reorders the components from the old claude-<major>-<minor>-<type>-<date> format.

src/commands/watch.ts (3)

151-176: Robust progress bar width calculation.

The proportional width distribution logic handles edge cases well, including rounding adjustments to prevent overflow and minimum width guarantees for visibility. The implementation ensures visual consistency across different usage patterns.


836-911: Excellent resource management and user experience.

The implementation demonstrates thorough attention to detail:

  • Proper terminal state management with raw mode setup/cleanup
  • Comprehensive keyboard input handling for interactive controls
  • Graceful cleanup with meaningful session summaries
  • Robust error handling throughout the lifecycle

The user experience is well-designed with clear exit strategies and informative feedback.


706-912: Well-architected real-time monitoring solution.

This watch command implementation successfully delivers the PR objectives with:

  • Adaptive monitoring: Intelligent update intervals based on activity levels
  • Rich visualizations: Color-coded progress bars and detailed breakdowns
  • Interactive controls: User-friendly toggles for different views
  • Comprehensive tracking: Session summaries and burn rate analysis

The architecture demonstrates good separation of concerns and provides a professional monitoring experience for Claude usage tracking.

Copy link
Owner

@ryoppippi ryoppippi left a comment

Choose a reason for hiding this comment

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

@infonobody This PR looks neat! I need a test BTW

Also please create a file including logic and avoid implementing logic in command file.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jun 19, 2025

Open in StackBlitz

npm i https://pkg.pr.new/ryoppippi/ccusage@120

commit: 06680c4

- Remove unused _allBlocks parameter from function signature
- Update JSDoc to remove parameter documentation
- Update function call site to not pass unused parameter

Addresses PR feedback about unused parameter causing confusion.
- Extract cleanup logic into createCleanupHandler function
- Extract keyboard input handling into setupKeyboardHandling function
- Modify variable declarations to use reference objects for extracted functions
- Reduce complexity of main run function by separating concerns

This addresses PR feedback about high cyclomatic complexity by breaking
down the large function into smaller, focused functions.
- Extract session tracking into createSessionTracker function
- Extract main update logic into createUpdateDisplay function
- Create proper type definitions for configuration and state management
- Further reduce complexity of main run function

This completes the refactoring to address PR feedback about high
cyclomatic complexity by breaking down the large run function into
smaller, focused, reusable functions.
- Move formatDuration and clearScreen from watch.ts to utils.internal.ts
- Add comprehensive tests for formatDuration function
- Improve error handling with explicit type annotations
- Clean up inline duration formatting logic
- Move DisplayOptions and ModelType from watch.ts to types.internal.ts
- Define ModelTypes constant array for better type safety
- Remove duplicate type definitions to improve maintainability
- Extract display logic to watch-display.internal.ts (328 lines)
- Extract input/keyboard handling to watch-input.internal.ts (110 lines)
- Extract adaptive scheduler to watch-scheduler.internal.ts (40 lines)
- Reduce watch.ts from 512 to 82 lines for better maintainability
- Each module now has single responsibility
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: 2

🧹 Nitpick comments (3)
src/commands/watch.ts (1)

8-8: Prefer top-level type-only imports for consistency

Split the mixed import into separate type-only and regular imports for better clarity and consistency.

-import { createUpdateDisplay, UPDATE_INTERVALS, type UpdateDisplayConfig, type UpdateDisplayState } from '../watch-display.internal.ts';
+import type { UpdateDisplayConfig, UpdateDisplayState } from '../watch-display.internal.ts';
+import { createUpdateDisplay, UPDATE_INTERVALS } from '../watch-display.internal.ts';
src/progress-bar.internal.ts (1)

18-29: Consider case-insensitive model type detection

The current implementation only matches lowercase model names. Consider making it case-insensitive to handle variations like "Opus", "OPUS", etc.

 export function getModelType(model: string): ModelType | null {
-    if (model.includes('opus')) {
+    const modelLower = model.toLowerCase();
+    if (modelLower.includes('opus')) {
         return 'opus';
     }
-    if (model.includes('sonnet')) {
+    if (modelLower.includes('sonnet')) {
         return 'sonnet';
     }
-    if (model.includes('haiku')) {
+    if (modelLower.includes('haiku')) {
         return 'haiku';
     }
     return null;
 }
src/watch-display.internal.ts (1)

82-196: Consider breaking down displayActiveBlock into smaller functions

This function has multiple responsibilities and is quite long. Consider extracting some logic into separate functions for better maintainability and testability.

For example, you could extract:

  • Time progress bar display (lines 92-109)
  • Cost calculation and display (lines 111-142)
  • Statistics display (lines 144-169)
  • Optional tables display (lines 172-185)

This would make the main function more readable and each piece more testable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50d6a78 and 06680c4.

📒 Files selected for processing (10)
  • src/commands/watch.ts (1 hunks)
  • src/progress-bar.internal.ts (1 hunks)
  • src/session-blocks.internal.ts (2 hunks)
  • src/session-tracker.internal.ts (1 hunks)
  • src/table-display.internal.ts (1 hunks)
  • src/types.internal.ts (1 hunks)
  • src/utils.internal.ts (3 hunks)
  • src/watch-display.internal.ts (1 hunks)
  • src/watch-input.internal.ts (1 hunks)
  • src/watch-scheduler.internal.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/types.internal.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/watch-input.internal.ts (4)
src/session-blocks.internal.ts (1)
  • SessionBlock (38-49)
src/utils.internal.ts (4)
  • clearScreen (244-246)
  • formatDuration (227-239)
  • formatNumber (208-210)
  • formatCurrency (217-219)
src/logger.ts (1)
  • log (14-14)
src/types.internal.ts (1)
  • DisplayOptions (143-147)
src/progress-bar.internal.ts (2)
src/types.internal.ts (1)
  • ModelType (138-138)
src/logger.ts (1)
  • log (14-14)
🪛 ESLint
src/watch-scheduler.internal.ts

[error] 16-16: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 19-25: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 19-19: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 23-23: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 23-23: Unsafe member access .error on an error typed value.

(ts/no-unsafe-member-access)


[error] 34-34: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)

src/watch-input.internal.ts

[error] 28-28: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-30: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 30-30: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 31-31: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 31-31: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 52-52: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 52-52: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 52-52: Unsafe member access .cyan on an error typed value.

(ts/no-unsafe-member-access)


[error] 53-53: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 53-53: Unsafe member access .exit on an error typed value.

(ts/no-unsafe-member-access)


[error] 69-69: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 69-69: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 70-70: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 70-70: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 71-71: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 71-71: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 100-100: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 100-100: Unsafe member access .error on an error typed value.

(ts/no-unsafe-member-access)


[error] 105-105: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 105-105: Unsafe member access .stdin on an error typed value.

(ts/no-unsafe-member-access)


[error] 108-108: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 108-108: Unsafe member access .on on an error typed value.

(ts/no-unsafe-member-access)

src/table-display.internal.ts

[error] 120-127: Unsafe argument of type any[] assigned to a parameter of type TableRow.

(ts/no-unsafe-argument)


[error] 121-121: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 121-121: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 122-122: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 122-122: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 123-123: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 123-123: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 124-124: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 124-124: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 125-125: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 125-125: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 126-126: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 126-126: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 179-186: Unsafe argument of type any[] assigned to a parameter of type TableRow.

(ts/no-unsafe-argument)


[error] 180-180: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 180-180: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 181-181: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 181-181: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 182-182: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 182-182: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 183-183: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 183-183: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 184-184: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 184-184: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 185-185: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 185-185: Unsafe member access .bold on an error typed value.

(ts/no-unsafe-member-access)


[error] 212-216: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 212-216: Unsafe construction of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 222-222: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 222-222: Unsafe member access .push on an error typed value.

(ts/no-unsafe-member-access)


[error] 235-235: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 236-236: Unsafe return of a value of type error.

(ts/no-unsafe-return)


[error] 236-236: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 236-236: Unsafe member access .toString on an error typed value.

(ts/no-unsafe-member-access)

src/watch-display.internal.ts

[error] 93-93: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 93-93: Unsafe member access .green on an error typed value.

(ts/no-unsafe-member-access)


[error] 95-95: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 95-95: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 98-98: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 98-98: Unsafe member access .yellow on an error typed value.

(ts/no-unsafe-member-access)


[error] 105-105: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 105-105: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 106-106: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 109-109: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 168-168: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 169-169: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 173-173: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 174-174: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 178-178: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 179-179: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 183-183: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 184-184: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 186-186: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 195-195: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 272-272: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 272-272: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 272-272: Unsafe member access .yellow on an error typed value.

(ts/no-unsafe-member-access)


[error] 273-273: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 274-274: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 321-321: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 321-321: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 321-321: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 322-322: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 322-322: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 322-322: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 323-323: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 324-324: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)

src/progress-bar.internal.ts

[error] 50-50: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 50-50: Unsafe member access .green on an error typed value.

(ts/no-unsafe-member-access)


[error] 50-50: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 50-50: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 79-79: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 141-141: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 141-141: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 141-141: Unsafe member access .blue on an error typed value.

(ts/no-unsafe-member-access)


[error] 142-142: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 142-142: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 142-142: Unsafe member access .cyan on an error typed value.

(ts/no-unsafe-member-access)


[error] 143-143: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 143-143: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 143-143: Unsafe member access .magenta on an error typed value.

(ts/no-unsafe-member-access)


[error] 144-144: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 144-144: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 144-144: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 156-156: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 156-156: Unsafe member access .red on an error typed value.

(ts/no-unsafe-member-access)


[error] 164-164: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 170-170: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 170-170: Unsafe member access .blue on an error typed value.

(ts/no-unsafe-member-access)


[error] 174-174: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 174-174: Unsafe member access .cyan on an error typed value.

(ts/no-unsafe-member-access)


[error] 178-178: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 178-178: Unsafe member access .magenta on an error typed value.

(ts/no-unsafe-member-access)


[error] 180-180: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 180-180: Unsafe member access .gray on an error typed value.

(ts/no-unsafe-member-access)


[error] 181-181: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 182-182: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)

src/commands/watch.ts

[error] 8-8: Prefer using a top-level type-only import instead of inline type specifiers.

(import/consistent-type-specifier-style)


[error] 8-8: Prefer using a top-level type-only import instead of inline type specifiers.

(import/consistent-type-specifier-style)


[error] 12-82: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 12-12: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 15-23: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 27-27: Unsafe member access .level on an error typed value.

(ts/no-unsafe-member-access)


[error] 30-30: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 30-30: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 31-31: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 31-31: Unsafe member access .error on an error typed value.

(ts/no-unsafe-member-access)


[error] 32-32: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 32-32: Unsafe member access .exit on an error typed value.

(ts/no-unsafe-member-access)


[error] 51-51: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 51-51: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 52-52: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 52-52: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 53-53: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 53-53: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 54-54: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 54-54: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)


[error] 55-55: Unsafe assignment of an any value.

(ts/no-unsafe-assignment)


[error] 55-55: Unsafe member access .values on an any value.

(ts/no-unsafe-member-access)

src/utils.internal.ts

[error] 245-245: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 245-245: Unsafe member access .stdout on an error typed value.

(ts/no-unsafe-member-access)


[error] 336-336: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 337-337: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 338-338: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 338-338: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 338-338: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 339-339: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 339-339: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 339-339: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 340-340: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 340-340: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 340-340: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 343-343: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 344-344: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 344-344: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 344-344: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 345-345: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 345-345: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 345-345: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 346-346: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 346-346: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 346-346: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 349-349: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 350-350: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 350-350: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 350-350: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 351-351: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 351-351: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 351-351: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 352-352: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 352-352: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 352-352: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 355-355: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 356-356: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 356-356: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 356-356: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 357-357: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 357-357: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 357-357: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 358-358: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 358-358: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 358-358: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 359-359: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 359-359: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 359-359: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 362-362: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 363-363: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 363-363: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 363-363: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 364-364: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 364-364: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 364-364: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 365-365: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 365-365: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 365-365: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)


[error] 369-369: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 370-370: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 371-371: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 371-371: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 371-371: Unsafe member access .toBe on an error typed value.

(ts/no-unsafe-member-access)

🔇 Additional comments (9)
src/utils.internal.ts (3)

221-246: Excellent implementation of utility functions.

The formatDuration and clearScreen functions are well-implemented with clear logic and appropriate ANSI escape codes for terminal control.


262-267: Good addition of legacy model name format support.

The extension to support the older claude-(major)-(minor)-(type)-date format maintains backward compatibility while correctly extracting and reordering components.


336-374: Comprehensive test coverage for new functions.

The test suite covers all important edge cases including:

  • Duration formatting with hours/minutes/seconds
  • Edge cases for time boundaries
  • Seconds handling for sub-minute durations
  • Function existence verification for clearScreen
src/session-blocks.internal.ts (2)

68-85: Well-defined types and constants.

The BurnRateAnalysis type provides clear structure for different time periods, and the TIME_CONSTANTS object centralizes time interval definitions for maintainability.


324-394: Robust burn rate calculation implementation.

The functions properly handle edge cases:

  • Empty entries return null appropriately
  • Proper sorting ensures correct time calculations
  • Duration validation prevents division by zero
  • Separate token type calculations provide granular metrics

The mathematical logic is correct for calculating tokens per minute across different periods.

src/watch-scheduler.internal.ts (1)

8-40: Well-designed adaptive scheduler.

The implementation provides:

  • Clean separation of concerns with configurable update function
  • Proper error handling that doesn't stop the scheduler
  • Recursive scheduling that waits for completion before next cycle
  • Clean start/stop lifecycle management

The exposed intervalId allows external control while maintaining encapsulation.

src/table-display.internal.ts (3)

29-72: Solid token and cost breakdown calculations.

The functions properly aggregate data by model and handle the cost estimation challenge well. Since only total cost is available per entry, using proportional distribution based on token counts is a reasonable approximation.


77-131: Well-structured table creation with proper formatting.

The tokens table implementation:

  • Uses responsive table design for terminal compatibility
  • Properly sorts models for consistent display
  • Includes totals row when multiple models are present
  • Applies appropriate formatting and alignment

211-237: Clean period burn rate table implementation.

The period table provides clear visualization of burn rates across different time spans with proper null handling and formatting.

Comment on lines +29 to +35
setStartValues(tokens: number, cost: number) {
// Only set values once at the beginning of the session
if (startTokens === 0 && startCost === 0) {
startTokens = tokens;
startCost = cost;
}
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the one-time initialization logic.

The current implementation only allows setting values once when both startTokens and startCost are 0. This could prevent legitimate re-initialization and may not work correctly if either the initial tokens or cost is actually 0.

Consider using a boolean flag instead:

export function createSessionTracker(): SessionTracker {
	let startTokens = 0;
	let startCost = 0;
+	let initialized = false;

	return {
		get startTokens() {
			return startTokens;
		},
		get startCost() {
			return startCost;
		},
		setStartValues(tokens: number, cost: number) {
-			// Only set values once at the beginning of the session
-			if (startTokens === 0 && startCost === 0) {
+			if (!initialized) {
				startTokens = tokens;
				startCost = cost;
+				initialized = true;
			}
		},
	};
}
🤖 Prompt for AI Agents
In src/session-tracker.internal.ts around lines 29 to 35, the current logic to
set startTokens and startCost only if both are zero can fail if either value is
legitimately zero, preventing proper initialization. Replace this check with a
boolean flag that tracks whether the start values have been set, and use this
flag to ensure the values are only initialized once regardless of their numeric
values.

Comment on lines +27 to +29
if (intervalId.current != null) {
clearTimeout(intervalId.current);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use clearInterval instead of clearTimeout for consistency

The parameter is named intervalId which suggests it contains a timer interval ID, but the code uses clearTimeout. For consistency and correctness, use clearInterval instead.

-if (intervalId.current != null) {
-    clearTimeout(intervalId.current);
-}
+if (intervalId.current != null) {
+    clearInterval(intervalId.current);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (intervalId.current != null) {
clearTimeout(intervalId.current);
}
if (intervalId.current != null) {
clearInterval(intervalId.current);
}
🧰 Tools
🪛 ESLint

[error] 28-28: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)

🤖 Prompt for AI Agents
In src/watch-input.internal.ts around lines 27 to 29, the code uses clearTimeout
to clear a timer stored in intervalId.current, but since the variable name
suggests it is an interval ID, replace clearTimeout with clearInterval to
correctly clear the interval timer.

@infonobody
Copy link
Author

@infonobody This PR looks neat! I need a test BTW

Also please create a file including logic and avoid implementing logic in command file.

Done.

Now the command file only operates on logic, with some reusable logic split into existing files, and other logic written in components based on their respective responsibilities.

Just fix some little display issues, I didn't change any features and flow.

You can modify anything if you want. Thanks.

@ryoppippi
Copy link
Owner

ryoppippi commented Jun 20, 2025

@infonobody
Ok thanks.
I've tried this PR and it looks good. Thank you.
I would like to ask you for a few more things.

  • The main branch has changed a lot and I'd like you to follow the changes.
  • Maybe add a -watch flag to the blocks command instead of a separate watch command

overall this PR is so good

@a-c-m
Copy link
Contributor

a-c-m commented Jun 20, 2025

Ha, congrats on the PR, annoyingly i just created one for adding --live on blocks, but this one may be better.

#126

Sorry - i didn't spot this sooner. Happy to abandon my PR if this one is better.

@ryoppippi
Copy link
Owner

Actually I'm always wondering if we have to add watch feature. If there is an extra feature we should otherwise just use via watch or viddy commands

#61

Hmm it is hard to choose. both #126 and #120 look good

Anyway, I'm a little bit tired of maintaining ccusage this week. I'll review both of them prob next week
Thank you both of you guys @a-c-m @infonobody

@infonobody
Copy link
Author

@ryoppippi
Thank you for your reply.

  • The main branch has changed a lot and I'd like you to follow the changes.
  • Maybe add a -watch flag to the blocks command instead of a separate watch command

OK. I'm happy you like it.
I can finish this work in a day, but I hope this is the last change. (Because I have limited time recently)

Why I choice write new command and code in one file in the first commit?
In fact, adding a block -watch flag is my original goal, but I considered the following reasons.

  • I don't know when this PR will be merged, this is the way least likely to cause conflicts (project is actively developing)
  • If PR is not accepted, I can use in my local, and keep upgrading with main without code conflicts
  • The current version is not perfect and is not compatible with current block flags (like token-limit, because use token estimate is incorrect, opus is 5x cost)

If this version implements -watch flag, please merge as soon as possible to prevent conflict in other contributor's work

So, there are two different strategies we can choose before I start

  1. Quickly finish the work, merge first, then refactor in another PR
  2. Reduce code complexity, Close this PR, create a new PR that only has core feature (will only have process bar and burn rate) table and smart feature in another PR)

via watch or viddy commands

Two commands aren't built-in on macOS, maybe not everyone wants to install just for use ccusage

@infonobody
Copy link
Author

@a-c-m
It's unfortunate that we came up with the same idea.

Your PR also meets my needs.
If it had been implemented a bit earlier, I wouldn't have spent time working on this PR.

@ryoppippi
Copy link
Owner

ryoppippi commented Jun 20, 2025

Well I'll take a rest and come back in a couple of days!
This week is too much rushing for me and ccusage

@ryoppippi
Copy link
Owner

ryoppippi commented Jun 20, 2025

Thank you both so much for your contributions! I took some time to consider both designs, and honestly, it was a very close call — both had their strengths, and it was hard to choose between them.

In the end, I decided to go with @a-c-m’s design, which I personally preferred a bit more. I’m really sorry @infonobody — I truly appreciate the time and effort you put into this. I hope you’ll consider contributing again in the future.

Also, as noted in #126, we may still need to add some info per models, so there could be more opportunities to collaborate.

Thanks again! 🙏

@ryoppippi ryoppippi closed this Jun 20, 2025
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.

3 participants