ccusage 16.1.1 → 16.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -721,6 +721,18 @@
721
721
  "markdownDescription": "Controls the visualization of the burn rate status",
722
722
  "default": "off"
723
723
  },
724
+ "costSource": {
725
+ "type": "string",
726
+ "enum": [
727
+ "auto",
728
+ "ccusage",
729
+ "cc",
730
+ "both"
731
+ ],
732
+ "description": "Session cost source: auto (prefer CC then ccusage), ccusage (always calculate), cc (always use Claude Code cost), both (show both costs)",
733
+ "markdownDescription": "Session cost source: auto (prefer CC then ccusage), ccusage (always calculate), cc (always use Claude Code cost), both (show both costs)",
734
+ "default": "auto"
735
+ },
724
736
  "cache": {
725
737
  "type": "boolean",
726
738
  "description": "Enable cache for status line output (default: true)",
@@ -733,6 +745,18 @@
733
745
  "markdownDescription": "Refresh interval in seconds for cache expiry (default: 1)",
734
746
  "default": 1
735
747
  },
748
+ "contextLowThreshold": {
749
+ "type": "string",
750
+ "description": "Context usage percentage below which status is shown in green (0-100)",
751
+ "markdownDescription": "Context usage percentage below which status is shown in green (0-100)",
752
+ "default": 50
753
+ },
754
+ "contextMediumThreshold": {
755
+ "type": "string",
756
+ "description": "Context usage percentage below which status is shown in yellow (0-100)",
757
+ "markdownDescription": "Context usage percentage below which status is shown in yellow (0-100)",
758
+ "default": 80
759
+ },
736
760
  "debug": {
737
761
  "type": "boolean",
738
762
  "description": "Show pricing mismatch information for debugging",
@@ -3015,7 +3015,28 @@ var ZodFirstPartyTypeKind;
3015
3015
  (function(ZodFirstPartyTypeKind$1) {
3016
3016
  ZodFirstPartyTypeKind$1["ZodString"] = "ZodString", ZodFirstPartyTypeKind$1["ZodNumber"] = "ZodNumber", ZodFirstPartyTypeKind$1["ZodNaN"] = "ZodNaN", ZodFirstPartyTypeKind$1["ZodBigInt"] = "ZodBigInt", ZodFirstPartyTypeKind$1["ZodBoolean"] = "ZodBoolean", ZodFirstPartyTypeKind$1["ZodDate"] = "ZodDate", ZodFirstPartyTypeKind$1["ZodSymbol"] = "ZodSymbol", ZodFirstPartyTypeKind$1["ZodUndefined"] = "ZodUndefined", ZodFirstPartyTypeKind$1["ZodNull"] = "ZodNull", ZodFirstPartyTypeKind$1["ZodAny"] = "ZodAny", ZodFirstPartyTypeKind$1["ZodUnknown"] = "ZodUnknown", ZodFirstPartyTypeKind$1["ZodNever"] = "ZodNever", ZodFirstPartyTypeKind$1["ZodVoid"] = "ZodVoid", ZodFirstPartyTypeKind$1["ZodArray"] = "ZodArray", ZodFirstPartyTypeKind$1["ZodObject"] = "ZodObject", ZodFirstPartyTypeKind$1["ZodUnion"] = "ZodUnion", ZodFirstPartyTypeKind$1["ZodDiscriminatedUnion"] = "ZodDiscriminatedUnion", ZodFirstPartyTypeKind$1["ZodIntersection"] = "ZodIntersection", ZodFirstPartyTypeKind$1["ZodTuple"] = "ZodTuple", ZodFirstPartyTypeKind$1["ZodRecord"] = "ZodRecord", ZodFirstPartyTypeKind$1["ZodMap"] = "ZodMap", ZodFirstPartyTypeKind$1["ZodSet"] = "ZodSet", ZodFirstPartyTypeKind$1["ZodFunction"] = "ZodFunction", ZodFirstPartyTypeKind$1["ZodLazy"] = "ZodLazy", ZodFirstPartyTypeKind$1["ZodLiteral"] = "ZodLiteral", ZodFirstPartyTypeKind$1["ZodEnum"] = "ZodEnum", ZodFirstPartyTypeKind$1["ZodEffects"] = "ZodEffects", ZodFirstPartyTypeKind$1["ZodNativeEnum"] = "ZodNativeEnum", ZodFirstPartyTypeKind$1["ZodOptional"] = "ZodOptional", ZodFirstPartyTypeKind$1["ZodNullable"] = "ZodNullable", ZodFirstPartyTypeKind$1["ZodDefault"] = "ZodDefault", ZodFirstPartyTypeKind$1["ZodCatch"] = "ZodCatch", ZodFirstPartyTypeKind$1["ZodPromise"] = "ZodPromise", ZodFirstPartyTypeKind$1["ZodBranded"] = "ZodBranded", ZodFirstPartyTypeKind$1["ZodPipeline"] = "ZodPipeline", ZodFirstPartyTypeKind$1["ZodReadonly"] = "ZodReadonly";
3017
3017
  })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
3018
- const stringType = ZodString.create, numberType = ZodNumber.create, nanType = ZodNaN.create, bigIntType = ZodBigInt.create, booleanType = ZodBoolean.create, dateType = ZodDate.create, symbolType = ZodSymbol.create, undefinedType = ZodUndefined.create, nullType = ZodNull.create, anyType = ZodAny.create, unknownType = ZodUnknown.create, neverType = ZodNever.create, voidType = ZodVoid.create, arrayType = ZodArray.create, objectType = ZodObject.create, strictObjectType = ZodObject.strictCreate, unionType = ZodUnion.create, discriminatedUnionType = ZodDiscriminatedUnion.create, intersectionType = ZodIntersection.create, tupleType = ZodTuple.create, recordType = ZodRecord.create, mapType = ZodMap.create, setType = ZodSet.create, functionType = ZodFunction.create, lazyType = ZodLazy.create, literalType = ZodLiteral.create, enumType = ZodEnum.create, nativeEnumType = ZodNativeEnum.create, promiseType = ZodPromise.create, effectsType = ZodEffects.create, optionalType = ZodOptional.create, nullableType = ZodNullable.create, preprocessType = ZodEffects.createWithPreprocess, pipelineType = ZodPipeline.create, modelNameSchema = stringType().min(1, "Model name cannot be empty").brand(), sessionIdSchema = stringType().min(1, "Session ID cannot be empty").brand(), requestIdSchema = stringType().min(1, "Request ID cannot be empty").brand(), messageIdSchema = stringType().min(1, "Message ID cannot be empty").brand(), isoTimestampSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/, "Invalid ISO timestamp").brand(), dailyDateSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").brand(), activityDateSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").brand(), monthlyDateSchema = stringType().regex(/^\d{4}-\d{2}$/, "Date must be in YYYY-MM format").brand(), weeklyDateSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").brand(), filterDateSchema = stringType().regex(/^\d{8}$/, "Date must be in YYYYMMDD format").brand(), projectPathSchema = stringType().min(1, "Project path cannot be empty").brand(), versionSchema = stringType().regex(/^\d+\.\d+\.\d+/, "Invalid version format").brand(), createSessionId = (value) => sessionIdSchema.parse(value), createDailyDate = (value) => dailyDateSchema.parse(value), createMonthlyDate = (value) => monthlyDateSchema.parse(value), createWeeklyDate = (value) => weeklyDateSchema.parse(value), createProjectPath = (value) => projectPathSchema.parse(value);
3018
+ const stringType = ZodString.create, numberType = ZodNumber.create, nanType = ZodNaN.create, bigIntType = ZodBigInt.create, booleanType = ZodBoolean.create, dateType = ZodDate.create, symbolType = ZodSymbol.create, undefinedType = ZodUndefined.create, nullType = ZodNull.create, anyType = ZodAny.create, unknownType = ZodUnknown.create, neverType = ZodNever.create, voidType = ZodVoid.create, arrayType = ZodArray.create, objectType = ZodObject.create, strictObjectType = ZodObject.strictCreate, unionType = ZodUnion.create, discriminatedUnionType = ZodDiscriminatedUnion.create, intersectionType = ZodIntersection.create, tupleType = ZodTuple.create, recordType = ZodRecord.create, mapType = ZodMap.create, setType = ZodSet.create, functionType = ZodFunction.create, lazyType = ZodLazy.create, literalType = ZodLiteral.create, enumType = ZodEnum.create, nativeEnumType = ZodNativeEnum.create, promiseType = ZodPromise.create, effectsType = ZodEffects.create, optionalType = ZodOptional.create, nullableType = ZodNullable.create, preprocessType = ZodEffects.createWithPreprocess, pipelineType = ZodPipeline.create, coerce = {
3019
+ string: ((arg) => ZodString.create({
3020
+ ...arg,
3021
+ coerce: true
3022
+ })),
3023
+ number: ((arg) => ZodNumber.create({
3024
+ ...arg,
3025
+ coerce: true
3026
+ })),
3027
+ boolean: ((arg) => ZodBoolean.create({
3028
+ ...arg,
3029
+ coerce: true
3030
+ })),
3031
+ bigint: ((arg) => ZodBigInt.create({
3032
+ ...arg,
3033
+ coerce: true
3034
+ })),
3035
+ date: ((arg) => ZodDate.create({
3036
+ ...arg,
3037
+ coerce: true
3038
+ }))
3039
+ }, modelNameSchema = stringType().min(1, "Model name cannot be empty").brand(), sessionIdSchema = stringType().min(1, "Session ID cannot be empty").brand(), requestIdSchema = stringType().min(1, "Request ID cannot be empty").brand(), messageIdSchema = stringType().min(1, "Message ID cannot be empty").brand(), isoTimestampSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/, "Invalid ISO timestamp").brand(), dailyDateSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").brand(), activityDateSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").brand(), monthlyDateSchema = stringType().regex(/^\d{4}-\d{2}$/, "Date must be in YYYY-MM format").brand(), weeklyDateSchema = stringType().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").brand(), filterDateSchema = stringType().regex(/^\d{8}$/, "Date must be in YYYYMMDD format").brand(), projectPathSchema = stringType().min(1, "Project path cannot be empty").brand(), versionSchema = stringType().regex(/^\d+\.\d+\.\d+/, "Invalid version format").brand(), createSessionId = (value) => sessionIdSchema.parse(value), createDailyDate = (value) => dailyDateSchema.parse(value), createMonthlyDate = (value) => monthlyDateSchema.parse(value), createWeeklyDate = (value) => weeklyDateSchema.parse(value), createProjectPath = (value) => projectPathSchema.parse(value);
3019
3040
  function createBucket(value) {
3020
3041
  return weeklyDateSchema.safeParse(value).success ? createWeeklyDate(value) : createMonthlyDate(value);
3021
3042
  }
@@ -3043,6 +3064,13 @@ const CostModes = [
3043
3064
  current_dir: stringType(),
3044
3065
  project_dir: stringType()
3045
3066
  }),
3046
- version: stringType().optional()
3067
+ version: stringType().optional(),
3068
+ cost: objectType({
3069
+ total_cost_usd: numberType(),
3070
+ total_duration_ms: numberType().optional(),
3071
+ total_api_duration_ms: numberType().optional(),
3072
+ total_lines_added: numberType().optional(),
3073
+ total_lines_removed: numberType().optional()
3074
+ }).optional()
3047
3075
  });
3048
- export { CostModes, SortOrders, ZodFirstPartyTypeKind, ZodOptional, ZodType, activityDateSchema, arrayType, booleanType, createBucket, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, createWeeklyDate, dailyDateSchema, discriminatedUnionType, enumType, filterDateSchema, isoTimestampSchema, literalType, messageIdSchema, modelNameSchema, modelPricingSchema, monthlyDateSchema, numberType, objectType, optionalType, projectPathSchema, recordType, requestIdSchema, sessionIdSchema, statuslineHookJsonSchema, stringType, unionType, unknownType, versionSchema, weeklyDateSchema };
3076
+ export { CostModes, SortOrders, ZodFirstPartyTypeKind, ZodOptional, ZodType, activityDateSchema, arrayType, booleanType, coerce, createBucket, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, createWeeklyDate, dailyDateSchema, discriminatedUnionType, enumType, filterDateSchema, isoTimestampSchema, literalType, messageIdSchema, modelNameSchema, modelPricingSchema, monthlyDateSchema, numberType, objectType, optionalType, projectPathSchema, recordType, requestIdSchema, sessionIdSchema, statuslineHookJsonSchema, stringType, unionType, unknownType, versionSchema, weeklyDateSchema };
@@ -1,5 +1,5 @@
1
1
  import "./pricing-fetcher-BgDfBZ05.js";
2
- import { DailyUsage, MonthlyUsage, SessionUsage, WeeklyUsage } from "./data-loader--Ga8BPdt.js";
2
+ import { DailyUsage, MonthlyUsage, SessionUsage, WeeklyUsage } from "./data-loader-DewcQaMm.js";
3
3
 
4
4
  //#region src/_token-utils.d.ts
5
5
 
@@ -1,4 +1,4 @@
1
1
  import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
2
- import "./_types-BbEk8t2a.js";
2
+ import "./_types-DIdtMJ6V.js";
3
3
  import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
4
4
  export { calculateTotals, createTotalsObject, getTotalTokens };
@@ -1,7 +1,7 @@
1
- import { CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, CONTEXT_LOW_THRESHOLD_ENV, CONTEXT_MEDIUM_THRESHOLD_ENV, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_CONTEXT_USAGE_THRESHOLDS, DEFAULT_RECENT_DAYS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, isFailure, isPromise, isSuccess, require_usingCtx } from "./pricing-fetcher-_0Pbb-06.js";
1
+ import { CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_RECENT_DAYS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, __commonJSMin, __require, __toESM, isFailure, isPromise, isSuccess, require_usingCtx } from "./pricing-fetcher-CoBMgxFA.js";
2
2
  import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
3
- import { activityDateSchema, arrayType, booleanType, createBucket, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, createWeeklyDate, dailyDateSchema, isoTimestampSchema, messageIdSchema, modelNameSchema, monthlyDateSchema, numberType, objectType, projectPathSchema, requestIdSchema, sessionIdSchema, stringType, unionType, versionSchema, weeklyDateSchema } from "./_types-BbEk8t2a.js";
4
- import { logger } from "./logger-4mOJMzU6.js";
3
+ import { activityDateSchema, arrayType, booleanType, createBucket, createDailyDate, createMonthlyDate, createProjectPath, createSessionId, createWeeklyDate, dailyDateSchema, isoTimestampSchema, messageIdSchema, modelNameSchema, monthlyDateSchema, numberType, objectType, projectPathSchema, requestIdSchema, sessionIdSchema, stringType, unionType, versionSchema, weeklyDateSchema } from "./_types-DIdtMJ6V.js";
4
+ import { logger } from "./logger-DKCIi_ai.js";
5
5
  import a, { readFile } from "node:fs/promises";
6
6
  import path, { posix } from "node:path";
7
7
  import process$1 from "node:process";
@@ -2201,23 +2201,6 @@ function getClaudePaths() {
2201
2201
  - Or set ${CLAUDE_CONFIG_DIR_ENV} environment variable to valid directory path(s) containing a '${CLAUDE_PROJECTS_DIR_NAME}' subdirectory`.trim());
2202
2202
  return paths;
2203
2203
  }
2204
- function getContextUsageThresholds() {
2205
- const lowThresholdStr = process$1.env[CONTEXT_LOW_THRESHOLD_ENV], mediumThresholdStr = process$1.env[CONTEXT_MEDIUM_THRESHOLD_ENV];
2206
- let lowThreshold = DEFAULT_CONTEXT_USAGE_THRESHOLDS.LOW, mediumThreshold = DEFAULT_CONTEXT_USAGE_THRESHOLDS.MEDIUM;
2207
- if (lowThresholdStr != null) {
2208
- const parsed = Number.parseInt(lowThresholdStr, 10);
2209
- if (!Number.isNaN(parsed)) lowThreshold = Math.max(0, Math.min(100, parsed));
2210
- }
2211
- if (mediumThresholdStr != null) {
2212
- const parsed = Number.parseInt(mediumThresholdStr, 10);
2213
- if (!Number.isNaN(parsed)) mediumThreshold = Math.max(0, Math.min(100, parsed));
2214
- }
2215
- if (lowThreshold >= mediumThreshold) lowThreshold = DEFAULT_CONTEXT_USAGE_THRESHOLDS.LOW, mediumThreshold = DEFAULT_CONTEXT_USAGE_THRESHOLDS.MEDIUM;
2216
- return {
2217
- LOW: lowThreshold,
2218
- MEDIUM: mediumThreshold
2219
- };
2220
- }
2221
2204
  function extractProjectFromPath(jsonlPath) {
2222
2205
  const normalizedPath = jsonlPath.replace(/[/\\]/g, path.sep), segments = normalizedPath.split(path.sep), projectsIndex = segments.findIndex((segment) => segment === CLAUDE_PROJECTS_DIR_NAME);
2223
2206
  if (projectsIndex === -1 || projectsIndex + 1 >= segments.length) return "unknown";
@@ -2761,4 +2744,4 @@ async function loadSessionBlockData(options) {
2761
2744
  _usingCtx6.d();
2762
2745
  }
2763
2746
  }
2764
- export { DEFAULT_SESSION_DURATION_HOURS, bucketUsageSchema, calculateBurnRate, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, filterRecentBlocks, formatDate, formatDateCompact, getClaudePaths, getContextUsageThresholds, getEarliestTimestamp, getUsageLimitResetTime, glob, globUsageFiles, identifySessionBlocks, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, projectBlockUsage, sessionUsageSchema, sortFilesByTimestamp, toArray, transcriptMessageSchema, transcriptUsageSchema, uniq, unwrap, usageDataSchema, weeklyUsageSchema };
2747
+ export { DEFAULT_SESSION_DURATION_HOURS, bucketUsageSchema, calculateBurnRate, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, filterRecentBlocks, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, glob, globUsageFiles, identifySessionBlocks, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, projectBlockUsage, sessionUsageSchema, sortFilesByTimestamp, toArray, transcriptMessageSchema, transcriptUsageSchema, uniq, unwrap, usageDataSchema, weeklyUsageSchema };
@@ -66,16 +66,6 @@ type SessionBlock = {
66
66
  * @returns Array of valid Claude data directory paths
67
67
  */
68
68
  declare function getClaudePaths(): string[];
69
- /**
70
- * Get context usage percentage thresholds for color coding
71
- * Can be configured via environment variables or uses defaults
72
- * Validates and clamps values to 0-100 range and enforces LOW < MEDIUM ordering
73
- * @returns Context usage thresholds with LOW and MEDIUM percentages
74
- */
75
- declare function getContextUsageThresholds(): {
76
- readonly LOW: number;
77
- readonly MEDIUM: number;
78
- };
79
69
  /**
80
70
  * Extract project name from Claude JSONL file path
81
71
  * @param jsonlPath - Absolute path to JSONL file
@@ -806,4 +796,4 @@ declare function calculateContextTokens(transcriptPath: string, modelId?: string
806
796
  */
807
797
  declare function loadSessionBlockData(options?: LoadOptions): Promise<SessionBlock[]>;
808
798
  //#endregion
809
- export { BucketUsage, DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, WeeklyUsage, bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getContextUsageThresholds, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema };
799
+ export { BucketUsage, DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, WeeklyUsage, bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema };
@@ -1,3 +1,3 @@
1
1
  import "./pricing-fetcher-BgDfBZ05.js";
2
- import { BucketUsage, DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, WeeklyUsage, bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getContextUsageThresholds, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema } from "./data-loader--Ga8BPdt.js";
3
- export { BucketUsage, DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, WeeklyUsage, bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getContextUsageThresholds, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema };
2
+ import { BucketUsage, DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, WeeklyUsage, bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema } from "./data-loader-DewcQaMm.js";
3
+ export { BucketUsage, DailyUsage, DateFilter, GlobResult, LoadOptions, ModelBreakdown, MonthlyUsage, SessionUsage, UsageData, WeeklyUsage, bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema };
@@ -1,6 +1,6 @@
1
- import "./pricing-fetcher-_0Pbb-06.js";
1
+ import "./pricing-fetcher-CoBMgxFA.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
- import "./_types-BbEk8t2a.js";
4
- import { bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getContextUsageThresholds, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema } from "./data-loader-BR0q3F1S.js";
5
- import "./logger-4mOJMzU6.js";
6
- export { bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getContextUsageThresholds, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema };
3
+ import "./_types-DIdtMJ6V.js";
4
+ import { bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema } from "./data-loader-C7KK9Yu0.js";
5
+ import "./logger-DKCIi_ai.js";
6
+ export { bucketUsageSchema, calculateContextTokens, calculateCostForEntry, createUniqueHash, dailyUsageSchema, extractProjectFromPath, formatDate, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, loadBucketUsageData, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, modelBreakdownSchema, monthlyUsageSchema, sessionUsageSchema, sortFilesByTimestamp, transcriptMessageSchema, transcriptUsageSchema, usageDataSchema, weeklyUsageSchema };
@@ -1,6 +1,6 @@
1
- import { CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-_0Pbb-06.js";
2
- import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-BR0q3F1S.js";
3
- import { logger } from "./logger-4mOJMzU6.js";
1
+ import { CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, PricingFetcher, USAGE_DATA_GLOB_PATTERN, __toESM, isFailure, require_usingCtx, try_ } from "./pricing-fetcher-CoBMgxFA.js";
2
+ import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-C7KK9Yu0.js";
3
+ import { logger } from "./logger-DKCIi_ai.js";
4
4
  import { readFile } from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  var import_usingCtx = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
package/dist/debug.js CHANGED
@@ -1,7 +1,7 @@
1
- import "./pricing-fetcher-_0Pbb-06.js";
1
+ import "./pricing-fetcher-CoBMgxFA.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
- import "./_types-BbEk8t2a.js";
4
- import "./data-loader-BR0q3F1S.js";
5
- import "./logger-4mOJMzU6.js";
6
- import { detectMismatches, printMismatchReport } from "./debug-eBOoUv_j.js";
3
+ import "./_types-DIdtMJ6V.js";
4
+ import "./data-loader-C7KK9Yu0.js";
5
+ import "./logger-DKCIi_ai.js";
6
+ import { detectMismatches, printMismatchReport } from "./debug-BOv8jTQu.js";
7
7
  export { detectMismatches, printMismatchReport };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CONFIG_FILE_NAME, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, WEEK_DAYS, __commonJSMin, __require, __toESM, inspect, inspectError, isFailure, isSuccess, map, pipe, require_usingCtx, succeed, try_ } from "./pricing-fetcher-_0Pbb-06.js";
2
+ import { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CONFIG_FILE_NAME, DEFAULT_CONTEXT_USAGE_THRESHOLDS, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, WEEK_DAYS, __commonJSMin, __require, __toESM, andThen, fail, inspect, inspectError, isFailure, isSuccess, map, pipe, require_usingCtx, succeed, try_ } from "./pricing-fetcher-CoBMgxFA.js";
3
3
  import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
4
- import { CostModes, SortOrders, filterDateSchema, statuslineHookJsonSchema } from "./_types-BbEk8t2a.js";
4
+ import { CostModes, SortOrders, coerce, filterDateSchema, statuslineHookJsonSchema } from "./_types-DIdtMJ6V.js";
5
5
  import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
6
- import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateContextTokens, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getContextUsageThresholds, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, projectBlockUsage, sortFilesByTimestamp, toArray, uniq, unwrap, usageDataSchema } from "./data-loader-BR0q3F1S.js";
7
- import { description, log, logger, name, version } from "./logger-4mOJMzU6.js";
8
- import { detectMismatches, printMismatchReport } from "./debug-eBOoUv_j.js";
9
- import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-BsLzYwL8.js";
6
+ import { DEFAULT_SESSION_DURATION_HOURS, calculateBurnRate, calculateContextTokens, calculateCostForEntry, createUniqueHash, filterRecentBlocks, formatDateCompact, getClaudePaths, getEarliestTimestamp, getUsageLimitResetTime, globUsageFiles, identifySessionBlocks, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData, loadSessionUsageById, loadWeeklyUsageData, projectBlockUsage, sortFilesByTimestamp, toArray, uniq, unwrap, usageDataSchema } from "./data-loader-C7KK9Yu0.js";
7
+ import { description, log, logger, name, version } from "./logger-DKCIi_ai.js";
8
+ import { detectMismatches, printMismatchReport } from "./debug-BOv8jTQu.js";
9
+ import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DDHqWuGb.js";
10
10
  import a, { readFile, stat } from "node:fs/promises";
11
11
  import path, { join } from "node:path";
12
12
  import process$1 from "node:process";
@@ -817,7 +817,7 @@ var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
817
817
  };
818
818
  };
819
819
  module.exports = createColors(), module.exports.createColors = createColors;
820
- })), import_picocolors$8 = /* @__PURE__ */ __toESM(require_picocolors(), 1), import_usingCtx$3 = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
820
+ })), import_picocolors$8 = /* @__PURE__ */ __toESM(require_picocolors(), 1), import_usingCtx$4 = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
821
821
  function extractExplicitArgs(tokens) {
822
822
  const explicit = {};
823
823
  for (const token of tokens) if (typeof token === "object" && token !== null) {
@@ -2467,7 +2467,7 @@ function stringWidth(string, options = {}) {
2467
2467
  }
2468
2468
  return width;
2469
2469
  }
2470
- var import_usingCtx$2 = /* @__PURE__ */ __toESM(require_usingCtx(), 1), ResponsiveTable = class {
2470
+ var import_usingCtx$3 = /* @__PURE__ */ __toESM(require_usingCtx(), 1), ResponsiveTable = class {
2471
2471
  head;
2472
2472
  rows = [];
2473
2473
  colAligns;
@@ -2603,62 +2603,173 @@ async function getFileModifiedTime(filePath) {
2603
2603
  catch: (error) => error
2604
2604
  }), map((stats) => stats.mtime.getTime()), unwrap(0));
2605
2605
  }
2606
- var LiveMonitor = class {
2607
- config;
2608
- fetcher = null;
2609
- lastFileTimestamps = /* @__PURE__ */ new Map();
2610
- processedHashes = /* @__PURE__ */ new Set();
2611
- allEntries = [];
2612
- constructor(config) {
2613
- if (this.config = config, config.mode !== "display") this.fetcher = new PricingFetcher();
2614
- }
2615
- [Symbol.dispose]() {
2616
- this.fetcher?.[Symbol.dispose]();
2617
- }
2618
- async getActiveBlock() {
2619
- const results = await globUsageFiles(this.config.claudePaths), allFiles = results.map((r) => r.file);
2620
- if (allFiles.length === 0) return null;
2621
- const filesToRead = [];
2622
- for (const file of allFiles) {
2623
- const timestamp$1 = await getEarliestTimestamp(file), lastTimestamp = this.lastFileTimestamps.get(file);
2624
- if (timestamp$1 != null && (lastTimestamp == null || timestamp$1.getTime() > lastTimestamp)) filesToRead.push(file), this.lastFileTimestamps.set(file, timestamp$1.getTime());
2625
- }
2626
- if (filesToRead.length > 0) {
2627
- const sortedFiles = await sortFilesByTimestamp(filesToRead);
2628
- for (const file of sortedFiles) {
2629
- const content = await readFile(file, "utf-8").catch(() => {
2630
- return "";
2631
- }), lines = content.trim().split("\n").filter((line) => line.length > 0);
2632
- for (const line of lines) try {
2633
- const parsed = JSON.parse(line), result = usageDataSchema.safeParse(parsed);
2634
- if (!result.success) continue;
2635
- const data = result.data, uniqueHash = createUniqueHash(data);
2636
- if (uniqueHash != null && this.processedHashes.has(uniqueHash)) continue;
2637
- if (uniqueHash != null) this.processedHashes.add(uniqueHash);
2638
- const costUSD = await (this.config.mode === "display" ? Promise.resolve(data.costUSD ?? 0) : calculateCostForEntry(data, this.config.mode, this.fetcher)), usageLimitResetTime = getUsageLimitResetTime(data);
2639
- this.allEntries.push({
2640
- timestamp: new Date(data.timestamp),
2641
- usage: {
2642
- inputTokens: data.message.usage.input_tokens ?? 0,
2643
- outputTokens: data.message.usage.output_tokens ?? 0,
2644
- cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0,
2645
- cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0
2646
- },
2647
- costUSD,
2648
- model: data.message.model ?? "<synthetic>",
2649
- version: data.version,
2650
- usageLimitResetTime: usageLimitResetTime ?? void 0
2651
- });
2652
- } catch {}
2606
+ var Node = class {
2607
+ value;
2608
+ next;
2609
+ constructor(value$1) {
2610
+ this.value = value$1;
2611
+ }
2612
+ }, Queue = class {
2613
+ #head;
2614
+ #tail;
2615
+ #size;
2616
+ constructor() {
2617
+ this.clear();
2618
+ }
2619
+ enqueue(value$1) {
2620
+ const node = new Node(value$1);
2621
+ if (this.#head) this.#tail.next = node, this.#tail = node;
2622
+ else this.#head = node, this.#tail = node;
2623
+ this.#size++;
2624
+ }
2625
+ dequeue() {
2626
+ const current = this.#head;
2627
+ if (current) return this.#head = this.#head.next, this.#size--, current.value;
2628
+ }
2629
+ peek() {
2630
+ if (this.#head) return this.#head.value;
2631
+ }
2632
+ clear() {
2633
+ this.#head = void 0, this.#tail = void 0, this.#size = 0;
2634
+ }
2635
+ get size() {
2636
+ return this.#size;
2637
+ }
2638
+ *[Symbol.iterator]() {
2639
+ let current = this.#head;
2640
+ while (current) yield current.value, current = current.next;
2641
+ }
2642
+ *drain() {
2643
+ while (this.#head) yield this.dequeue();
2644
+ }
2645
+ };
2646
+ function pLimit(concurrency) {
2647
+ validateConcurrency(concurrency);
2648
+ const queue = new Queue();
2649
+ let activeCount = 0;
2650
+ const resumeNext = () => {
2651
+ if (activeCount < concurrency && queue.size > 0) activeCount++, queue.dequeue()();
2652
+ }, next = () => {
2653
+ activeCount--, resumeNext();
2654
+ }, run$1 = async (function_, resolve, arguments_) => {
2655
+ const result = (async () => function_(...arguments_))();
2656
+ resolve(result);
2657
+ try {
2658
+ await result;
2659
+ } catch {}
2660
+ next();
2661
+ }, enqueue = (function_, resolve, arguments_) => {
2662
+ if (new Promise((internalResolve) => {
2663
+ queue.enqueue(internalResolve);
2664
+ }).then(run$1.bind(void 0, function_, resolve, arguments_)), activeCount < concurrency) resumeNext();
2665
+ }, generator = (function_, ...arguments_) => new Promise((resolve) => {
2666
+ enqueue(function_, resolve, arguments_);
2667
+ });
2668
+ return Object.defineProperties(generator, {
2669
+ activeCount: { get: () => activeCount },
2670
+ pendingCount: { get: () => queue.size },
2671
+ clearQueue: { value() {
2672
+ queue.clear();
2673
+ } },
2674
+ concurrency: {
2675
+ get: () => concurrency,
2676
+ set(newConcurrency) {
2677
+ validateConcurrency(newConcurrency), concurrency = newConcurrency, queueMicrotask(() => {
2678
+ while (activeCount < concurrency && queue.size > 0) resumeNext();
2679
+ });
2653
2680
  }
2681
+ },
2682
+ map: { async value(array, function_) {
2683
+ const promises = array.map((value$1, index) => this(function_, value$1, index));
2684
+ return Promise.all(promises);
2685
+ } }
2686
+ }), generator;
2687
+ }
2688
+ function validateConcurrency(concurrency) {
2689
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) throw new TypeError("Expected `concurrency` to be a number from 1 and up");
2690
+ }
2691
+ var import_usingCtx$2 = /* @__PURE__ */ __toESM(require_usingCtx(), 1);
2692
+ const RETENTION_HOURS = 24, FILE_CONCURRENCY = 5;
2693
+ async function isRecentFile(filePath, cutoffTime) {
2694
+ return pipe(try_({
2695
+ try: stat(filePath),
2696
+ catch: (error) => error
2697
+ }), map((fileStats) => fileStats.mtime >= cutoffTime), unwrap(false));
2698
+ }
2699
+ function createLiveMonitorState(config) {
2700
+ const fetcher = config.mode !== "display" ? new PricingFetcher() : null;
2701
+ return {
2702
+ fetcher,
2703
+ lastFileTimestamps: /* @__PURE__ */ new Map(),
2704
+ processedHashes: /* @__PURE__ */ new Set(),
2705
+ allEntries: [],
2706
+ [Symbol.dispose]() {
2707
+ fetcher?.[Symbol.dispose]();
2654
2708
  }
2655
- const blocks = identifySessionBlocks(this.allEntries, this.config.sessionDurationHours), sortedBlocks = this.config.order === "asc" ? blocks : blocks.reverse();
2656
- return sortedBlocks.find((block) => block.isActive) ?? null;
2709
+ };
2710
+ }
2711
+ function clearLiveMonitorCache(state) {
2712
+ state.lastFileTimestamps.clear(), state.processedHashes.clear(), state.allEntries = [];
2713
+ }
2714
+ function cleanupOldEntries(state, cutoffTime) {
2715
+ const initialCount = state.allEntries.length;
2716
+ if (state.allEntries = state.allEntries.filter((entry) => entry.timestamp >= cutoffTime), initialCount - state.allEntries.length > 100) state.processedHashes.clear();
2717
+ }
2718
+ async function processFileContent(state, config, content, cutoffTime) {
2719
+ const lines = content.trim().split("\n").filter((line) => line.length > 0);
2720
+ for (const line of lines) {
2721
+ const dataResult = pipe(try_({
2722
+ try: () => JSON.parse(line),
2723
+ catch: (error) => error
2724
+ })(), andThen((data$1) => {
2725
+ const parseResult = usageDataSchema.safeParse(data$1);
2726
+ return parseResult.success ? succeed(parseResult.data) : fail(parseResult.error);
2727
+ }));
2728
+ if (isFailure(dataResult)) continue;
2729
+ const data = unwrap(dataResult), entryTime = new Date(data.timestamp);
2730
+ if (entryTime < cutoffTime) continue;
2731
+ const uniqueHash = createUniqueHash(data);
2732
+ if (uniqueHash != null && state.processedHashes.has(uniqueHash)) continue;
2733
+ if (uniqueHash != null) state.processedHashes.add(uniqueHash);
2734
+ const costUSD = await (config.mode === "display" ? Promise.resolve(data.costUSD ?? 0) : calculateCostForEntry(data, config.mode, state.fetcher)), usageLimitResetTime = getUsageLimitResetTime(data);
2735
+ state.allEntries.push({
2736
+ timestamp: entryTime,
2737
+ usage: {
2738
+ inputTokens: data.message.usage.input_tokens ?? 0,
2739
+ outputTokens: data.message.usage.output_tokens ?? 0,
2740
+ cacheCreationInputTokens: data.message.usage.cache_creation_input_tokens ?? 0,
2741
+ cacheReadInputTokens: data.message.usage.cache_read_input_tokens ?? 0
2742
+ },
2743
+ costUSD,
2744
+ model: data.message.model ?? "<synthetic>",
2745
+ version: data.version,
2746
+ usageLimitResetTime: usageLimitResetTime ?? void 0
2747
+ });
2657
2748
  }
2658
- clearCache() {
2659
- this.lastFileTimestamps.clear(), this.processedHashes.clear(), this.allEntries = [];
2749
+ }
2750
+ async function getActiveBlock(state, config) {
2751
+ const cutoffTime = /* @__PURE__ */ new Date(Date.now() - RETENTION_HOURS * 60 * 60 * 1e3), results = await globUsageFiles(config.claudePaths), allFiles = results.map((r) => r.file);
2752
+ if (allFiles.length === 0) return null;
2753
+ const candidateFiles = [];
2754
+ for (const file of allFiles) if (await isRecentFile(file, cutoffTime)) candidateFiles.push(file);
2755
+ const filesToRead = [];
2756
+ for (const file of candidateFiles) {
2757
+ const timestamp$1 = await getEarliestTimestamp(file), lastTimestamp = state.lastFileTimestamps.get(file);
2758
+ if (timestamp$1 != null && (lastTimestamp == null || timestamp$1.getTime() > lastTimestamp)) filesToRead.push(file), state.lastFileTimestamps.set(file, timestamp$1.getTime());
2660
2759
  }
2661
- };
2760
+ if (cleanupOldEntries(state, cutoffTime), filesToRead.length > 0) {
2761
+ const sortedFiles = await sortFilesByTimestamp(filesToRead), fileLimit = pLimit(FILE_CONCURRENCY), fileResults = await Promise.allSettled(sortedFiles.map(async (file) => fileLimit(async () => ({
2762
+ file,
2763
+ content: await readFile(file, "utf-8")
2764
+ }))));
2765
+ for (const result of fileResults) if (result.status === "fulfilled") {
2766
+ const { content } = result.value;
2767
+ await processFileContent(state, config, content, cutoffTime);
2768
+ }
2769
+ }
2770
+ const blocks = identifySessionBlocks(state.allEntries, config.sessionDurationHours), sortedBlocks = config.order === "asc" ? blocks : blocks.reverse();
2771
+ return sortedBlocks.find((block) => block.isActive) ?? null;
2772
+ }
2662
2773
  function delay(ms, options = {}) {
2663
2774
  const { signal, persistent = true } = options;
2664
2775
  return signal?.aborted ? Promise.reject(signal.reason) : new Promise((resolve, reject) => {
@@ -3044,16 +3155,16 @@ async function startLiveMonitoring(config) {
3044
3155
  var _usingCtx = (0, import_usingCtx$1.default)();
3045
3156
  const terminal = new TerminalManager(), abortController = new AbortController();
3046
3157
  let lastRenderTime = 0;
3047
- const cleanup = () => {
3048
- if (abortController.abort(), terminal.cleanup(), terminal.clearScreen(), logger.info("Live monitoring stopped."), process$1.exitCode == null) process$1.exit(0);
3049
- };
3050
- process$1.on("SIGINT", cleanup), process$1.on("SIGTERM", cleanup), terminal.enterAlternateScreen(), terminal.enableSyncMode(), terminal.clearScreen(), terminal.hideCursor();
3051
- const monitor = _usingCtx.u(new LiveMonitor({
3158
+ const monitorConfig = {
3052
3159
  claudePaths: config.claudePaths,
3053
3160
  sessionDurationHours: config.sessionDurationHours,
3054
3161
  mode: config.mode,
3055
3162
  order: config.order
3056
- })), monitoringResult = await try_({
3163
+ }, monitorState = _usingCtx.u(createLiveMonitorState(monitorConfig)), cleanup = () => {
3164
+ if (abortController.abort(), terminal.cleanup(), terminal.clearScreen(), logger.info("Live monitoring stopped."), process$1.exitCode == null) process$1.exit(0);
3165
+ };
3166
+ process$1.on("SIGINT", cleanup), process$1.on("SIGTERM", cleanup), terminal.enterAlternateScreen(), terminal.enableSyncMode(), terminal.clearScreen(), terminal.hideCursor();
3167
+ const monitoringResult = await try_({
3057
3168
  try: async () => {
3058
3169
  while (!abortController.signal.aborted) {
3059
3170
  const now = Date.now(), timeSinceLastRender = now - lastRenderTime;
@@ -3061,8 +3172,8 @@ async function startLiveMonitoring(config) {
3061
3172
  await delayWithAbort(MIN_RENDER_INTERVAL_MS - timeSinceLastRender, abortController.signal);
3062
3173
  continue;
3063
3174
  }
3064
- const activeBlock = await monitor.getActiveBlock();
3065
- if (monitor.clearCache(), activeBlock == null) {
3175
+ const activeBlock = await getActiveBlock(monitorState, monitorConfig);
3176
+ if (clearLiveMonitorCache(monitorState), activeBlock == null) {
3066
3177
  await renderWaitingState(terminal, config, abortController.signal);
3067
3178
  continue;
3068
3179
  }
@@ -5214,7 +5325,12 @@ const visualBurnRateChoices = [
5214
5325
  "emoji",
5215
5326
  "text",
5216
5327
  "emoji-text"
5217
- ], statuslineCommand = define({
5328
+ ], costSourceChoices = [
5329
+ "auto",
5330
+ "ccusage",
5331
+ "cc",
5332
+ "both"
5333
+ ], contextThresholdSchema = coerce.number().int().min(0, "Context threshold must be at least 0").max(100, "Context threshold must be at most 100"), statuslineCommand = define({
5218
5334
  name: "statusline",
5219
5335
  description: "Display compact status line for Claude Code hooks with hybrid time+file caching (Beta)",
5220
5336
  toKebab: true,
@@ -5232,6 +5348,14 @@ const visualBurnRateChoices = [
5232
5348
  negatable: false,
5233
5349
  toKebab: true
5234
5350
  },
5351
+ costSource: {
5352
+ type: "enum",
5353
+ choices: costSourceChoices,
5354
+ description: "Session cost source: auto (prefer CC then ccusage), ccusage (always calculate), cc (always use Claude Code cost), both (show both costs)",
5355
+ default: "auto",
5356
+ negatable: false,
5357
+ toKebab: true
5358
+ },
5235
5359
  cache: {
5236
5360
  type: "boolean",
5237
5361
  description: "Enable cache for status line output (default: true)",
@@ -5242,11 +5366,23 @@ const visualBurnRateChoices = [
5242
5366
  description: `Refresh interval in seconds for cache expiry (default: ${DEFAULT_REFRESH_INTERVAL_SECONDS})`,
5243
5367
  default: DEFAULT_REFRESH_INTERVAL_SECONDS
5244
5368
  },
5369
+ contextLowThreshold: {
5370
+ type: "custom",
5371
+ description: "Context usage percentage below which status is shown in green (0-100)",
5372
+ parse: (value$1) => contextThresholdSchema.parse(value$1),
5373
+ default: DEFAULT_CONTEXT_USAGE_THRESHOLDS.LOW
5374
+ },
5375
+ contextMediumThreshold: {
5376
+ type: "custom",
5377
+ description: "Context usage percentage below which status is shown in yellow (0-100)",
5378
+ parse: (value$1) => contextThresholdSchema.parse(value$1),
5379
+ default: DEFAULT_CONTEXT_USAGE_THRESHOLDS.MEDIUM
5380
+ },
5245
5381
  config: sharedArgs.config,
5246
5382
  debug: sharedArgs.debug
5247
5383
  },
5248
5384
  async run(ctx) {
5249
- logger.level = 0;
5385
+ if (logger.level = 0, ctx.values.contextLowThreshold >= ctx.values.contextMediumThreshold) throw new Error(`Context low threshold (${ctx.values.contextLowThreshold}) must be less than medium threshold (${ctx.values.contextMediumThreshold})`);
5250
5386
  const config = loadConfig(ctx.values.config, ctx.values.debug), mergedOptions = mergeConfigWithArgs(ctx, config, ctx.values.debug), refreshInterval = mergedOptions.refreshInterval, stdin$2 = await getStdin();
5251
5387
  if (stdin$2.length === 0) log("❌ No input provided"), process$1.exit(1);
5252
5388
  const hookDataJson = JSON.parse(stdin$2.trim()), hookDataParseResult = statuslineHookJsonSchema.safeParse(hookDataJson);
@@ -5299,33 +5435,55 @@ const visualBurnRateChoices = [
5299
5435
  }
5300
5436
  const mainProcessingResult = pipe(await try_({
5301
5437
  try: async () => {
5302
- const sessionCost = await pipe(try_({
5303
- try: loadSessionUsageById(sessionId, {
5304
- mode: "auto",
5305
- offline: mergedOptions.offline
5306
- }),
5307
- catch: (error) => error
5308
- }), map((sessionCost$1) => sessionCost$1?.totalCost), inspectError((error) => logger.error("Failed to load session data:", error)), unwrap(void 0)), today = /* @__PURE__ */ new Date(), todayStr = today.toISOString().split("T")[0]?.replace(/-/g, "") ?? "", todayCost = await pipe(try_({
5309
- try: loadDailyUsageData({
5438
+ const { sessionCost, ccCost, ccusageCost } = await (async () => {
5439
+ const costSource = ctx.values.costSource, getCcusageCost = async () => {
5440
+ return pipe(try_({
5441
+ try: async () => loadSessionUsageById(sessionId, {
5442
+ mode: "auto",
5443
+ offline: mergedOptions.offline
5444
+ }),
5445
+ catch: (error) => error
5446
+ })(), map((sessionCost$1) => sessionCost$1?.totalCost), inspectError((error) => logger.error("Failed to load session data:", error)), unwrap(void 0));
5447
+ };
5448
+ if (costSource === "both") {
5449
+ const ccCost$1 = hookData.cost?.total_cost_usd, ccusageCost$1 = await getCcusageCost();
5450
+ return {
5451
+ ccCost: ccCost$1,
5452
+ ccusageCost: ccusageCost$1
5453
+ };
5454
+ }
5455
+ if (costSource === "cc") return { sessionCost: hookData.cost?.total_cost_usd };
5456
+ if (costSource === "ccusage") {
5457
+ const cost = await getCcusageCost();
5458
+ return { sessionCost: cost };
5459
+ }
5460
+ if (costSource === "auto") {
5461
+ if (hookData.cost?.total_cost_usd != null) return { sessionCost: hookData.cost.total_cost_usd };
5462
+ const cost = await getCcusageCost();
5463
+ return { sessionCost: cost };
5464
+ }
5465
+ return {};
5466
+ })(), today = /* @__PURE__ */ new Date(), todayStr = today.toISOString().split("T")[0]?.replace(/-/g, "") ?? "", todayCost = await pipe(try_({
5467
+ try: async () => loadDailyUsageData({
5310
5468
  since: todayStr,
5311
5469
  until: todayStr,
5312
5470
  mode: "auto",
5313
5471
  offline: mergedOptions.offline
5314
5472
  }),
5315
5473
  catch: (error) => error
5316
- }), map((dailyData) => {
5474
+ })(), map((dailyData) => {
5317
5475
  if (dailyData.length > 0) {
5318
5476
  const totals = calculateTotals(dailyData);
5319
5477
  return totals.totalCost;
5320
5478
  }
5321
5479
  return 0;
5322
5480
  }), inspectError((error) => logger.error("Failed to load daily data:", error)), unwrap(0)), { blockInfo, burnRateInfo } = await pipe(try_({
5323
- try: loadSessionBlockData({
5481
+ try: async () => loadSessionBlockData({
5324
5482
  mode: "auto",
5325
5483
  offline: mergedOptions.offline
5326
5484
  }),
5327
5485
  catch: (error) => error
5328
- }), map((blocks) => {
5486
+ })(), map((blocks) => {
5329
5487
  if (blocks.length === 0) return {
5330
5488
  blockInfo: "No active block",
5331
5489
  burnRateInfo: ""
@@ -5371,11 +5529,17 @@ const visualBurnRateChoices = [
5371
5529
  })), contextInfo = await pipe(try_({
5372
5530
  try: calculateContextTokens(hookData.transcript_path, hookData.model.id, mergedOptions.offline),
5373
5531
  catch: (error) => error
5374
- }), inspectError((error) => logger.debug(`Failed to calculate context tokens: ${error instanceof Error ? error.message : String(error)}`)), map((ctx$1) => {
5375
- if (ctx$1 == null) return void 0;
5376
- const thresholds = getContextUsageThresholds(), color = ctx$1.percentage < thresholds.LOW ? import_picocolors$1.default.green : ctx$1.percentage < thresholds.MEDIUM ? import_picocolors$1.default.yellow : import_picocolors$1.default.red, coloredPercentage = color(`${ctx$1.percentage}%`), tokenDisplay = ctx$1.inputTokens.toLocaleString();
5532
+ }), inspectError((error) => logger.debug(`Failed to calculate context tokens: ${error instanceof Error ? error.message : String(error)}`)), map((contextResult) => {
5533
+ if (contextResult == null) return void 0;
5534
+ const color = contextResult.percentage < ctx.values.contextLowThreshold ? import_picocolors$1.default.green : contextResult.percentage < ctx.values.contextMediumThreshold ? import_picocolors$1.default.yellow : import_picocolors$1.default.red, coloredPercentage = color(`${contextResult.percentage}%`), tokenDisplay = contextResult.inputTokens.toLocaleString();
5377
5535
  return `${tokenDisplay} (${coloredPercentage})`;
5378
- }), unwrap(void 0)), modelName = hookData.model.display_name, sessionDisplay = sessionCost != null ? formatCurrency(sessionCost) : "N/A", statusLine = `🤖 ${modelName} | 💰 ${sessionDisplay} session / ${formatCurrency(todayCost)} today / ${blockInfo}${burnRateInfo} | 🧠 ${contextInfo ?? "N/A"}`;
5536
+ }), unwrap(void 0)), modelName = hookData.model.display_name, sessionDisplay = (() => {
5537
+ if (ccCost != null || ccusageCost != null) {
5538
+ const ccDisplay = ccCost != null ? formatCurrency(ccCost) : "N/A", ccusageDisplay = ccusageCost != null ? formatCurrency(ccusageCost) : "N/A";
5539
+ return `(${ccDisplay} cc / ${ccusageDisplay} ccusage)`;
5540
+ }
5541
+ return sessionCost != null ? formatCurrency(sessionCost) : "N/A";
5542
+ })(), statusLine = `🤖 ${modelName} | 💰 ${sessionDisplay} session / ${formatCurrency(todayCost)} today / ${blockInfo}${burnRateInfo} | 🧠 ${contextInfo ?? "N/A"}`;
5379
5543
  return statusLine;
5380
5544
  },
5381
5545
  catch: (error) => error
@@ -761,7 +761,7 @@ function _getDefaultLogLevel() {
761
761
  return g ? LogLevels.debug : R ? LogLevels.warn : LogLevels.info;
762
762
  }
763
763
  const consola = createConsola$1();
764
- var name = "ccusage", version = "16.1.1", description = "Usage analysis tool for Claude Code";
764
+ var name = "ccusage", version = "16.2.0", description = "Usage analysis tool for Claude Code";
765
765
  const logger = consola.withTag(name);
766
766
  if (process$1.env.LOG_LEVEL != null) {
767
767
  const level = Number.parseInt(process$1.env.LOG_LEVEL, 10);
package/dist/logger.js CHANGED
@@ -1,2 +1,2 @@
1
- import { log, logger } from "./logger-4mOJMzU6.js";
1
+ import { log, logger } from "./logger-DKCIi_ai.js";
2
2
  export { log, logger };
@@ -1,9 +1,9 @@
1
- import { __commonJSMin, __toESM, require_usingCtx } from "./pricing-fetcher-_0Pbb-06.js";
1
+ import { __commonJSMin, __toESM, require_usingCtx } from "./pricing-fetcher-CoBMgxFA.js";
2
2
  import { getTotalTokens } from "./_token-utils-WjkbrjKv.js";
3
- import { ZodFirstPartyTypeKind, ZodOptional, ZodType, arrayType, booleanType, discriminatedUnionType, enumType, filterDateSchema, literalType, numberType, objectType, optionalType, recordType, stringType, unionType, unknownType } from "./_types-BbEk8t2a.js";
3
+ import { ZodFirstPartyTypeKind, ZodOptional, ZodType, arrayType, booleanType, discriminatedUnionType, enumType, filterDateSchema, literalType, numberType, objectType, optionalType, recordType, stringType, unionType, unknownType } from "./_types-DIdtMJ6V.js";
4
4
  import { calculateTotals, createTotalsObject } from "./calculate-cost-BDqO4yWA.js";
5
- import { getClaudePaths, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData } from "./data-loader-BR0q3F1S.js";
6
- import { name, version } from "./logger-4mOJMzU6.js";
5
+ import { getClaudePaths, loadDailyUsageData, loadMonthlyUsageData, loadSessionBlockData, loadSessionData } from "./data-loader-C7KK9Yu0.js";
6
+ import { name, version } from "./logger-DKCIi_ai.js";
7
7
  import process from "node:process";
8
8
  const LATEST_PROTOCOL_VERSION = "2025-06-18", SUPPORTED_PROTOCOL_VERSIONS = [
9
9
  LATEST_PROTOCOL_VERSION,
package/dist/mcp.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./pricing-fetcher-BgDfBZ05.js";
2
- import { LoadOptions } from "./data-loader--Ga8BPdt.js";
2
+ import { LoadOptions } from "./data-loader-DewcQaMm.js";
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { Hono } from "hono/tiny";
5
5
 
package/dist/mcp.js CHANGED
@@ -1,8 +1,8 @@
1
- import "./pricing-fetcher-_0Pbb-06.js";
1
+ import "./pricing-fetcher-CoBMgxFA.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
- import "./_types-BbEk8t2a.js";
3
+ import "./_types-DIdtMJ6V.js";
4
4
  import "./calculate-cost-BDqO4yWA.js";
5
- import "./data-loader-BR0q3F1S.js";
6
- import "./logger-4mOJMzU6.js";
7
- import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-BsLzYwL8.js";
5
+ import "./data-loader-C7KK9Yu0.js";
6
+ import "./logger-DKCIi_ai.js";
7
+ import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-DDHqWuGb.js";
8
8
  export { createMcpHttpApp, createMcpServer, startMcpServerStdio };
@@ -1,5 +1,5 @@
1
- import { modelPricingSchema } from "./_types-BbEk8t2a.js";
2
- import { logger } from "./logger-4mOJMzU6.js";
1
+ import { modelPricingSchema } from "./_types-DIdtMJ6V.js";
2
+ import { logger } from "./logger-DKCIi_ai.js";
3
3
  import { createRequire } from "node:module";
4
4
  import path from "node:path";
5
5
  import F, { homedir } from "node:os";
@@ -99,7 +99,7 @@ const LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/m
99
99
  }, DEFAULT_CONTEXT_USAGE_THRESHOLDS = {
100
100
  LOW: 50,
101
101
  MEDIUM: 80
102
- }, CONTEXT_LOW_THRESHOLD_ENV = "CCUSAGE_CONTEXT_LOW_THRESHOLD", CONTEXT_MEDIUM_THRESHOLD_ENV = "CCUSAGE_CONTEXT_MEDIUM_THRESHOLD", WEEK_DAYS = [
102
+ }, WEEK_DAYS = [
103
103
  "sunday",
104
104
  "monday",
105
105
  "tuesday",
@@ -292,9 +292,9 @@ var require_usingCtx = /* @__PURE__ */ __commonJSMin(((exports, module) => {
292
292
  "output_cost_per_token": 15e-6,
293
293
  "cache_creation_input_token_cost": 375e-8,
294
294
  "cache_read_input_token_cost": 3e-7,
295
- "max_tokens": 64e3,
296
- "max_input_tokens": 2e5,
297
- "max_output_tokens": 64e3
295
+ "max_tokens": 1e6,
296
+ "max_input_tokens": 1e6,
297
+ "max_output_tokens": 1e6
298
298
  },
299
299
  "claude-3-7-sonnet-latest": {
300
300
  "input_cost_per_token": 3e-6,
@@ -399,4 +399,4 @@ var require_usingCtx = /* @__PURE__ */ __commonJSMin(((exports, module) => {
399
399
  return cost;
400
400
  }
401
401
  };
402
- export { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, CONFIG_FILE_NAME, CONTEXT_LOW_THRESHOLD_ENV, CONTEXT_MEDIUM_THRESHOLD_ENV, DEBUG_MATCH_THRESHOLD_PERCENT, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_CONTEXT_USAGE_THRESHOLDS, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, WEEK_DAYS, __commonJSMin, __require, __toESM, inspect, inspectError, isFailure, isPromise, isSuccess, map, pipe, require_usingCtx, succeed, try_ };
402
+ export { BLOCKS_COMPACT_WIDTH_THRESHOLD, BLOCKS_DEFAULT_TERMINAL_WIDTH, BLOCKS_WARNING_THRESHOLD, BURN_RATE_THRESHOLDS, CLAUDE_CONFIG_DIR_ENV, CLAUDE_PROJECTS_DIR_NAME, CONFIG_FILE_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, DEFAULT_CLAUDE_CODE_PATH, DEFAULT_CLAUDE_CONFIG_PATH, DEFAULT_CONTEXT_USAGE_THRESHOLDS, DEFAULT_RECENT_DAYS, DEFAULT_REFRESH_INTERVAL_SECONDS, MAX_REFRESH_INTERVAL_SECONDS, MCP_DEFAULT_PORT, MIN_REFRESH_INTERVAL_SECONDS, MIN_RENDER_INTERVAL_MS, PricingFetcher, USAGE_DATA_GLOB_PATTERN, USER_HOME_DIR, WEEK_DAYS, __commonJSMin, __require, __toESM, andThen, fail, inspect, inspectError, isFailure, isPromise, isSuccess, map, pipe, require_usingCtx, succeed, try_ };
@@ -1,4 +1,4 @@
1
- import { PricingFetcher } from "./pricing-fetcher-_0Pbb-06.js";
2
- import "./_types-BbEk8t2a.js";
3
- import "./logger-4mOJMzU6.js";
1
+ import { PricingFetcher } from "./pricing-fetcher-CoBMgxFA.js";
2
+ import "./_types-DIdtMJ6V.js";
3
+ import "./logger-DKCIi_ai.js";
4
4
  export { PricingFetcher };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccusage",
3
- "version": "16.1.1",
3
+ "version": "16.2.0",
4
4
  "description": "Usage analysis tool for Claude Code",
5
5
  "homepage": "https://github.com/ryoppippi/ccusage#readme",
6
6
  "bugs": {