Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/ccstatusline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import chalk from 'chalk';

import { runTUI } from './tui';
import type { TokenMetrics } from './types';
import type {
SpeedMetrics,
TokenMetrics
} from './types';
import type { RenderContext } from './types/RenderContext';
import type { StatusJSON } from './types/StatusJSON';
import { StatusJSONSchema } from './types/StatusJSON';
Expand All @@ -15,6 +18,7 @@ import {
} from './utils/config';
import {
getSessionDuration,
getSpeedMetricsCollection,
getTokenMetrics
} from './utils/jsonl';
import {
Expand All @@ -23,6 +27,10 @@ import {
renderStatusLine
} from './utils/renderer';
import { advanceGlobalSeparatorIndex } from './utils/separator-index';
import {
getWidgetSpeedWindowSeconds,
isWidgetSpeedWindowEnabled
} from './utils/speed-window';
import { prefetchUsageDataIfNeeded } from './utils/usage-prefetch';

function hasSessionDurationInStatusJson(data: StatusJSON): boolean {
Expand Down Expand Up @@ -87,6 +95,17 @@ async function renderMultipleLines(data: StatusJSON) {
// Check if session clock is needed
const hasSessionClock = lines.some(line => line.some(item => item.type === 'session-clock'));

const speedWidgetTypes = new Set(['output-speed', 'input-speed', 'total-speed']);
const hasSpeedItems = lines.some(line => line.some(item => speedWidgetTypes.has(item.type)));
const requestedSpeedWindows = new Set<number>();
for (const line of lines) {
for (const item of line) {
if (speedWidgetTypes.has(item.type) && isWidgetSpeedWindowEnabled(item)) {
requestedSpeedWindows.add(getWidgetSpeedWindowSeconds(item));
}
}
}

let tokenMetrics: TokenMetrics | null = null;
if (data.transcript_path) {
tokenMetrics = await getTokenMetrics(data.transcript_path);
Expand All @@ -99,10 +118,24 @@ async function renderMultipleLines(data: StatusJSON) {

const usageData = await prefetchUsageDataIfNeeded(lines);

let speedMetrics: SpeedMetrics | null = null;
let windowedSpeedMetrics: Record<string, SpeedMetrics> | null = null;
if (hasSpeedItems && data.transcript_path) {
const speedMetricsCollection = await getSpeedMetricsCollection(data.transcript_path, {
includeSubagents: true,
windowSeconds: Array.from(requestedSpeedWindows)
});

speedMetrics = speedMetricsCollection.sessionAverage;
windowedSpeedMetrics = speedMetricsCollection.windowed;
}

// Create render context
const context: RenderContext = {
data,
tokenMetrics,
speedMetrics,
windowedSpeedMetrics,
usageData,
sessionDuration,
isPreview: false
Expand Down
3 changes: 3 additions & 0 deletions src/types/RenderContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { BlockMetrics } from '../types';

import type { SpeedMetrics } from './SpeedMetrics';
import type { StatusJSON } from './StatusJSON';
import type { TokenMetrics } from './TokenMetrics';

Expand All @@ -18,6 +19,8 @@ export interface RenderUsageData {
export interface RenderContext {
data?: StatusJSON;
tokenMetrics?: TokenMetrics | null;
speedMetrics?: SpeedMetrics | null;
windowedSpeedMetrics?: Record<string, SpeedMetrics> | null;
usageData?: RenderUsageData | null;
sessionDuration?: string | null;
blockMetrics?: BlockMetrics | null;
Expand Down
20 changes: 20 additions & 0 deletions src/types/SpeedMetrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Speed metrics for calculating token processing rates.
* Provides time-based data needed for speed calculations.
*/
export interface SpeedMetrics {
/** Active processing duration in milliseconds (sum of user request → assistant response times) */
totalDurationMs: number;

/** Total input tokens across all requests */
inputTokens: number;

/** Total output tokens across all requests */
outputTokens: number;

/** Total tokens (input + output) */
totalTokens: number;

/** Number of assistant usage entries included in speed aggregation */
requestCount: number;
}
1 change: 1 addition & 0 deletions src/types/TokenMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface TranscriptLine {
isSidechain?: boolean;
timestamp?: string;
isApiErrorMessage?: boolean;
type?: 'user' | 'assistant' | 'system' | 'progress' | 'file-history-snapshot';
}

export interface TokenMetrics {
Expand Down
3 changes: 2 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ export type { RenderContext } from './RenderContext';
export type { PowerlineFontStatus } from './PowerlineFontStatus';
export type { ClaudeSettings } from './ClaudeSettings';
export type { ColorEntry } from './ColorEntry';
export type { BlockMetrics } from './BlockMetrics';
export type { BlockMetrics } from './BlockMetrics';
export type { SpeedMetrics } from './SpeedMetrics';
Loading