ccusage 16.1.2 → 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.
@@ -745,6 +745,18 @@
745
745
  "markdownDescription": "Refresh interval in seconds for cache expiry (default: 1)",
746
746
  "default": 1
747
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
+ },
748
760
  "debug": {
749
761
  "type": "boolean",
750
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
  }
@@ -3052,4 +3073,4 @@ const CostModes = [
3052
3073
  total_lines_removed: numberType().optional()
3053
3074
  }).optional()
3054
3075
  });
3055
- 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-BXB_jFi9.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-BrJoueZ1.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-BXB_jFi9.js";
4
- import { logger } from "./logger-vSpPcCiQ.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-BrJoueZ1.js";
1
+ import "./pricing-fetcher-CoBMgxFA.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
- import "./_types-BXB_jFi9.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-DUaYLdYR.js";
5
- import "./logger-vSpPcCiQ.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-BrJoueZ1.js";
2
- import { getClaudePaths, glob, unwrap, usageDataSchema } from "./data-loader-DUaYLdYR.js";
3
- import { logger } from "./logger-vSpPcCiQ.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-BrJoueZ1.js";
1
+ import "./pricing-fetcher-CoBMgxFA.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
- import "./_types-BXB_jFi9.js";
4
- import "./data-loader-DUaYLdYR.js";
5
- import "./logger-vSpPcCiQ.js";
6
- import { detectMismatches, printMismatchReport } from "./debug-hX9iI1FE.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-BrJoueZ1.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-BXB_jFi9.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-DUaYLdYR.js";
7
- import { description, log, logger, name, version } from "./logger-vSpPcCiQ.js";
8
- import { detectMismatches, printMismatchReport } from "./debug-hX9iI1FE.js";
9
- import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-D343KJOh.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
  }
@@ -5219,7 +5330,7 @@ const visualBurnRateChoices = [
5219
5330
  "ccusage",
5220
5331
  "cc",
5221
5332
  "both"
5222
- ], statuslineCommand = define({
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({
5223
5334
  name: "statusline",
5224
5335
  description: "Display compact status line for Claude Code hooks with hybrid time+file caching (Beta)",
5225
5336
  toKebab: true,
@@ -5255,11 +5366,23 @@ const visualBurnRateChoices = [
5255
5366
  description: `Refresh interval in seconds for cache expiry (default: ${DEFAULT_REFRESH_INTERVAL_SECONDS})`,
5256
5367
  default: DEFAULT_REFRESH_INTERVAL_SECONDS
5257
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
+ },
5258
5381
  config: sharedArgs.config,
5259
5382
  debug: sharedArgs.debug
5260
5383
  },
5261
5384
  async run(ctx) {
5262
- 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})`);
5263
5386
  const config = loadConfig(ctx.values.config, ctx.values.debug), mergedOptions = mergeConfigWithArgs(ctx, config, ctx.values.debug), refreshInterval = mergedOptions.refreshInterval, stdin$2 = await getStdin();
5264
5387
  if (stdin$2.length === 0) log("❌ No input provided"), process$1.exit(1);
5265
5388
  const hookDataJson = JSON.parse(stdin$2.trim()), hookDataParseResult = statuslineHookJsonSchema.safeParse(hookDataJson);
@@ -5406,9 +5529,9 @@ const visualBurnRateChoices = [
5406
5529
  })), contextInfo = await pipe(try_({
5407
5530
  try: calculateContextTokens(hookData.transcript_path, hookData.model.id, mergedOptions.offline),
5408
5531
  catch: (error) => error
5409
- }), inspectError((error) => logger.debug(`Failed to calculate context tokens: ${error instanceof Error ? error.message : String(error)}`)), map((ctx$1) => {
5410
- if (ctx$1 == null) return void 0;
5411
- 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();
5412
5535
  return `${tokenDisplay} (${coloredPercentage})`;
5413
5536
  }), unwrap(void 0)), modelName = hookData.model.display_name, sessionDisplay = (() => {
5414
5537
  if (ccCost != null || ccusageCost != null) {
@@ -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.2", 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-vSpPcCiQ.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-BrJoueZ1.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-BXB_jFi9.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-DUaYLdYR.js";
6
- import { name, version } from "./logger-vSpPcCiQ.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-BrJoueZ1.js";
1
+ import "./pricing-fetcher-CoBMgxFA.js";
2
2
  import "./_token-utils-WjkbrjKv.js";
3
- import "./_types-BXB_jFi9.js";
3
+ import "./_types-DIdtMJ6V.js";
4
4
  import "./calculate-cost-BDqO4yWA.js";
5
- import "./data-loader-DUaYLdYR.js";
6
- import "./logger-vSpPcCiQ.js";
7
- import { createMcpHttpApp, createMcpServer, startMcpServerStdio } from "./mcp-D343KJOh.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-BXB_jFi9.js";
2
- import { logger } from "./logger-vSpPcCiQ.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",
@@ -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-BrJoueZ1.js";
2
- import "./_types-BXB_jFi9.js";
3
- import "./logger-vSpPcCiQ.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.2",
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": {