ccstatusline 2.0.20 → 2.0.22

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.
package/README.md CHANGED
@@ -125,6 +125,7 @@
125
125
  - **🖥️ Interactive TUI** - Built-in configuration interface using React/Ink
126
126
  - **⚙️ Global Options** - Apply consistent formatting across all widgets (padding, separators, bold, background)
127
127
  - **🚀 Cross-platform** - Works seamlessly with both Bun and Node.js
128
+ - **🔧 Flexible Configuration** - Supports custom Claude Code config directory via `CLAUDE_CONFIG_DIR` environment variable
128
129
  - **📏 Smart Width Detection** - Automatically adapts to terminal width with flex separators
129
130
  - **⚡ Zero Config** - Sensible defaults that work out of the box
130
131
 
@@ -155,6 +156,15 @@ The interactive configuration tool provides a terminal UI where you can:
155
156
 
156
157
  > 💡 **Tip:** Your settings are automatically saved to `~/.config/ccstatusline/settings.json`
157
158
 
159
+ > 🔧 **Custom Claude Config:** If your Claude Code configuration is in a non-standard location, set the `CLAUDE_CONFIG_DIR` environment variable:
160
+ > ```bash
161
+ > # Linux/macOS
162
+ > export CLAUDE_CONFIG_DIR=/custom/path/to/.claude
163
+ >
164
+ > # Windows PowerShell
165
+ > $env:CLAUDE_CONFIG_DIR="C:\custom\path\.claude"
166
+ > ```
167
+
158
168
  ---
159
169
 
160
170
  ## 🪟 Windows Support
@@ -294,7 +304,11 @@ For the best experience, configure Windows Terminal with these recommended setti
294
304
  #### Claude Code Integration
295
305
  Configure ccstatusline in your Claude Code settings:
296
306
 
297
- **For Bun users** (Windows: `%USERPROFILE%\.claude\settings.json`):
307
+ **Settings Location:**
308
+ - Default: `~/.claude/settings.json` (Windows: `%USERPROFILE%\.claude\settings.json`)
309
+ - Custom: Set `CLAUDE_CONFIG_DIR` environment variable to use a different directory
310
+
311
+ **For Bun users**:
298
312
  ```json
299
313
  {
300
314
  "statusLine": "bunx ccstatusline@latest"
@@ -308,6 +322,8 @@ Configure ccstatusline in your Claude Code settings:
308
322
  }
309
323
  ```
310
324
 
325
+ > 💡 **Custom Config Directory:** If you use a non-standard Claude Code configuration directory, set the `CLAUDE_CONFIG_DIR` environment variable before running ccstatusline. The tool will automatically detect and use your custom location.
326
+
311
327
  ### Performance on Windows
312
328
 
313
329
  ccstatusline is optimized for Windows performance:
@@ -348,8 +364,8 @@ Once configured, ccstatusline automatically formats your Claude Code status line
348
364
  - **Tokens Cached** - Shows cached tokens used
349
365
  - **Tokens Total** - Shows total tokens used
350
366
  - **Context Length** - Shows current context length in tokens
351
- - **Context Percentage** - Shows percentage of context limit used (out of 200k)
352
- - **Context Percentage (usable)** - Shows percentage of usable context (out of 160k, accounting for auto-compact at 80%)
367
+ - **Context Percentage** - Shows percentage of context limit used (dynamic: 1M for Sonnet 4.5 with `[1m]` suffix, 200k otherwise)
368
+ - **Context Percentage (usable)** - Shows percentage of usable context (dynamic: 800k for Sonnet 4.5 with `[1m]` suffix, 160k otherwise, accounting for auto-compact at 80%)
353
369
  - **Terminal Width** - Shows detected terminal width (for debugging)
354
370
  - **Custom Text** - Add your own custom text to the status line
355
371
  - **Custom Command** - Execute shell commands and display their output (refreshes whenever the statusline is updated by Claude Code)
@@ -561,7 +577,7 @@ ccstatusline/
561
577
  │ │ ├── renderer.ts # Core rendering logic
562
578
  │ │ ├── powerline.ts # Powerline font utilities
563
579
  │ │ ├── colors.ts # Color definitions
564
- │ │ └── claude-settings.ts # Claude Code integration
580
+ │ │ └── claude-settings.ts # Claude Code integration (supports CLAUDE_CONFIG_DIR)
565
581
  │ └── types/ # TypeScript type definitions
566
582
  │ ├── Settings.ts
567
583
  │ ├── Widget.ts
@@ -818,7 +818,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
818
818
 
819
819
  // node_modules/react/index.js
820
820
  var require_react = __commonJS((exports, module) => {
821
- var react_development = __toESM(require_react_development(), 1);
821
+ var react_development = __toESM(require_react_development());
822
822
  if (false) {} else {
823
823
  module.exports = react_development;
824
824
  }
@@ -1263,7 +1263,7 @@ var require_scheduler_development = __commonJS((exports) => {
1263
1263
 
1264
1264
  // node_modules/react-reconciler/node_modules/scheduler/index.js
1265
1265
  var require_scheduler = __commonJS((exports, module) => {
1266
- var scheduler_development = __toESM(require_scheduler_development(), 1);
1266
+ var scheduler_development = __toESM(require_scheduler_development());
1267
1267
  if (false) {} else {
1268
1268
  module.exports = scheduler_development;
1269
1269
  }
@@ -1271,8 +1271,8 @@ var require_scheduler = __commonJS((exports, module) => {
1271
1271
 
1272
1272
  // node_modules/react-reconciler/cjs/react-reconciler.development.js
1273
1273
  var require_react_reconciler_development = __commonJS((exports, module) => {
1274
- var React = __toESM(require_react(), 1);
1275
- var Scheduler = __toESM(require_scheduler(), 1);
1274
+ var React = __toESM(require_react());
1275
+ var Scheduler = __toESM(require_scheduler());
1276
1276
  module.exports = function($$$config) {
1277
1277
  function findHook(fiber, id) {
1278
1278
  for (fiber = fiber.memoizedState;fiber !== null && 0 < id; )
@@ -28235,7 +28235,7 @@ var require_react_is_development = __commonJS((exports) => {
28235
28235
 
28236
28236
  // node_modules/react-is/index.js
28237
28237
  var require_react_is = __commonJS((exports, module) => {
28238
- var react_is_development = __toESM(require_react_is_development(), 1);
28238
+ var react_is_development = __toESM(require_react_is_development());
28239
28239
  if (false) {} else {
28240
28240
  module.exports = react_is_development;
28241
28241
  }
@@ -28376,7 +28376,7 @@ var require_checkPropTypes = __commonJS((exports, module) => {
28376
28376
 
28377
28377
  // node_modules/prop-types/factoryWithTypeCheckers.js
28378
28378
  var require_factoryWithTypeCheckers = __commonJS((exports, module) => {
28379
- var ReactIs = __toESM(require_react_is(), 1);
28379
+ var ReactIs = __toESM(require_react_is());
28380
28380
  var assign = require_object_assign();
28381
28381
  var ReactPropTypesSecret = require_ReactPropTypesSecret();
28382
28382
  var has = require_has();
@@ -28800,7 +28800,7 @@ Valid keys: ` + JSON.stringify(Object.keys(shapeTypes), null, " "));
28800
28800
 
28801
28801
  // node_modules/prop-types/index.js
28802
28802
  var require_prop_types = __commonJS((exports, module) => {
28803
- var ReactIs = __toESM(require_react_is(), 1);
28803
+ var ReactIs = __toESM(require_react_is());
28804
28804
  if (true) {
28805
28805
  throwOnDirectAccess = true;
28806
28806
  module.exports = require_factoryWithTypeCheckers()(ReactIs.isElement, throwOnDirectAccess);
@@ -31641,7 +31641,7 @@ var require_gradient_string = __commonJS((exports, module) => {
31641
31641
 
31642
31642
  // node_modules/react/cjs/react-jsx-dev-runtime.development.js
31643
31643
  var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
31644
- var React14 = __toESM(require_react(), 1);
31644
+ var React14 = __toESM(require_react());
31645
31645
  (function() {
31646
31646
  function getComponentNameFromType(type) {
31647
31647
  if (type == null)
@@ -31855,7 +31855,7 @@ React keys must be passed directly to JSX without using spread:
31855
31855
 
31856
31856
  // node_modules/react/jsx-dev-runtime.js
31857
31857
  var require_jsx_dev_runtime = __commonJS((exports, module) => {
31858
- var react_jsx_dev_runtime_development = __toESM(require_react_jsx_dev_runtime_development(), 1);
31858
+ var react_jsx_dev_runtime_development = __toESM(require_react_jsx_dev_runtime_development());
31859
31859
  if (false) {} else {
31860
31860
  module.exports = react_jsx_dev_runtime_development;
31861
31861
  }
@@ -39283,26 +39283,56 @@ import * as path from "path";
39283
39283
  var readFile = fs2.promises.readFile;
39284
39284
  var writeFile = fs2.promises.writeFile;
39285
39285
  var mkdir = fs2.promises.mkdir;
39286
- var CLAUDE_SETTINGS_PATH = path.join(os2.homedir(), ".claude", "settings.json");
39286
+ var CCSTATUSLINE_COMMANDS = {
39287
+ NPM: "npx -y ccstatusline@latest",
39288
+ BUNX: "bunx -y ccstatusline@latest",
39289
+ SELF_MANAGED: "ccstatusline"
39290
+ };
39291
+ function getClaudeConfigDir() {
39292
+ const envConfigDir = process.env.CLAUDE_CONFIG_DIR;
39293
+ if (envConfigDir) {
39294
+ try {
39295
+ const resolvedPath = path.resolve(envConfigDir);
39296
+ if (fs2.existsSync(resolvedPath)) {
39297
+ const stats = fs2.statSync(resolvedPath);
39298
+ if (stats.isDirectory()) {
39299
+ return resolvedPath;
39300
+ }
39301
+ } else {
39302
+ return resolvedPath;
39303
+ }
39304
+ } catch {}
39305
+ }
39306
+ return path.join(os2.homedir(), ".claude");
39307
+ }
39308
+ function getClaudeSettingsPath() {
39309
+ return path.join(getClaudeConfigDir(), "settings.json");
39310
+ }
39287
39311
  async function loadClaudeSettings() {
39288
39312
  try {
39289
- if (!fs2.existsSync(CLAUDE_SETTINGS_PATH)) {
39313
+ const settingsPath = getClaudeSettingsPath();
39314
+ if (!fs2.existsSync(settingsPath)) {
39290
39315
  return {};
39291
39316
  }
39292
- const content = await readFile(CLAUDE_SETTINGS_PATH, "utf-8");
39317
+ const content = await readFile(settingsPath, "utf-8");
39293
39318
  return JSON.parse(content);
39294
39319
  } catch {
39295
39320
  return {};
39296
39321
  }
39297
39322
  }
39298
39323
  async function saveClaudeSettings(settings) {
39299
- const dir = path.dirname(CLAUDE_SETTINGS_PATH);
39324
+ const settingsPath = getClaudeSettingsPath();
39325
+ const dir = path.dirname(settingsPath);
39300
39326
  await mkdir(dir, { recursive: true });
39301
- await writeFile(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf-8");
39327
+ await writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
39302
39328
  }
39303
39329
  async function isInstalled() {
39304
39330
  const settings = await loadClaudeSettings();
39305
- const validCommands = ["npx -y ccstatusline@latest", "bunx -y ccstatusline@latest"];
39331
+ const validCommands = [
39332
+ CCSTATUSLINE_COMMANDS.NPM,
39333
+ CCSTATUSLINE_COMMANDS.BUNX,
39334
+ CCSTATUSLINE_COMMANDS.SELF_MANAGED
39335
+ ];
39306
39336
  return validCommands.includes(settings.statusLine?.command ?? "") && (settings.statusLine?.padding === 0 || settings.statusLine?.padding === undefined);
39307
39337
  }
39308
39338
  function isBunxAvailable() {
@@ -39318,7 +39348,7 @@ async function installStatusLine(useBunx = false) {
39318
39348
  const settings = await loadClaudeSettings();
39319
39349
  settings.statusLine = {
39320
39350
  type: "command",
39321
- command: useBunx ? "bunx -y ccstatusline@latest" : "npx -y ccstatusline@latest",
39351
+ command: useBunx ? CCSTATUSLINE_COMMANDS.BUNX : CCSTATUSLINE_COMMANDS.NPM,
39322
39352
  padding: 0
39323
39353
  };
39324
39354
  await saveClaudeSettings(settings);
@@ -51375,7 +51405,7 @@ import { execSync as execSync3 } from "child_process";
51375
51405
  import * as fs5 from "fs";
51376
51406
  import * as path4 from "path";
51377
51407
  var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src/utils";
51378
- var PACKAGE_VERSION = "2.0.20";
51408
+ var PACKAGE_VERSION = "2.0.22";
51379
51409
  function getPackageVersion() {
51380
51410
  if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
51381
51411
  return PACKAGE_VERSION;
@@ -52493,6 +52523,33 @@ class GitWorktreeWidget {
52493
52523
  return true;
52494
52524
  }
52495
52525
  }
52526
+ // src/utils/model-context.ts
52527
+ function getContextConfig(modelId) {
52528
+ const defaultConfig = {
52529
+ maxTokens: 200000,
52530
+ usableTokens: 160000
52531
+ };
52532
+ if (!modelId)
52533
+ return defaultConfig;
52534
+ if (modelId.includes("claude-sonnet-4-5") && modelId.toLowerCase().includes("[1m]")) {
52535
+ return {
52536
+ maxTokens: 1e6,
52537
+ usableTokens: 800000
52538
+ };
52539
+ }
52540
+ return defaultConfig;
52541
+ }
52542
+
52543
+ // src/utils/context-percentage.ts
52544
+ function calculateContextPercentage(context) {
52545
+ if (!context.tokenMetrics) {
52546
+ return 0;
52547
+ }
52548
+ const modelId = context.data?.model?.id;
52549
+ const contextConfig = getContextConfig(modelId);
52550
+ return Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100);
52551
+ }
52552
+
52496
52553
  // src/utils/renderer.ts
52497
52554
  var ANSI_REGEX = new RegExp(`\\x1b\\[[0-9;]*m`, "g");
52498
52555
  function formatTokens(count) {
@@ -52545,7 +52602,7 @@ function renderPowerlineStatusLine(widgets, settings, context, lineIndex = 0, gl
52545
52602
  terminalWidth = detectedWidth - 40;
52546
52603
  } else if (flexMode === "full-until-compact") {
52547
52604
  const threshold = settings.compactThreshold;
52548
- const contextPercentage = context.tokenMetrics ? Math.min(100, context.tokenMetrics.contextLength / 200000 * 100) : 0;
52605
+ const contextPercentage = calculateContextPercentage(context);
52549
52606
  if (contextPercentage >= threshold) {
52550
52607
  terminalWidth = detectedWidth - 40;
52551
52608
  } else {
@@ -52919,7 +52976,7 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
52919
52976
  terminalWidth = detectedWidth - 40;
52920
52977
  } else if (flexMode === "full-until-compact") {
52921
52978
  const threshold = settings.compactThreshold;
52922
- const contextPercentage = context.tokenMetrics ? Math.min(100, context.tokenMetrics.contextLength / 200000 * 100) : 0;
52979
+ const contextPercentage = calculateContextPercentage(context);
52923
52980
  if (contextPercentage >= threshold) {
52924
52981
  terminalWidth = detectedWidth - 40;
52925
52982
  } else {
@@ -53309,7 +53366,7 @@ class ContextPercentageWidget {
53309
53366
  return "blue";
53310
53367
  }
53311
53368
  getDescription() {
53312
- return "Shows percentage of context window used or remaining (of 200k tokens)";
53369
+ return "Shows percentage of context window used or remaining";
53313
53370
  }
53314
53371
  getDisplayName() {
53315
53372
  return "Context %";
@@ -53344,7 +53401,9 @@ class ContextPercentageWidget {
53344
53401
  const previewValue = isInverse ? "90.7%" : "9.3%";
53345
53402
  return item.rawValue ? previewValue : `Ctx: ${previewValue}`;
53346
53403
  } else if (context.tokenMetrics) {
53347
- const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / 200000 * 100);
53404
+ const modelId = context.data?.model?.id;
53405
+ const contextConfig = getContextConfig(modelId);
53406
+ const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100);
53348
53407
  const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
53349
53408
  return item.rawValue ? `${displayPercentage.toFixed(1)}%` : `Ctx: ${displayPercentage.toFixed(1)}%`;
53350
53409
  }
@@ -53368,7 +53427,7 @@ class ContextPercentageUsableWidget {
53368
53427
  return "green";
53369
53428
  }
53370
53429
  getDescription() {
53371
- return "Shows percentage of usable context window used or remaining (of 160k tokens before auto-compact)";
53430
+ return "Shows percentage of usable context window used or remaining (80% of max before auto-compact)";
53372
53431
  }
53373
53432
  getDisplayName() {
53374
53433
  return "Context % (usable)";
@@ -53403,7 +53462,9 @@ class ContextPercentageUsableWidget {
53403
53462
  const previewValue = isInverse ? "88.4%" : "11.6%";
53404
53463
  return item.rawValue ? previewValue : `Ctx(u): ${previewValue}`;
53405
53464
  } else if (context.tokenMetrics) {
53406
- const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / 160000 * 100);
53465
+ const modelId = context.data?.model?.id;
53466
+ const contextConfig = getContextConfig(modelId);
53467
+ const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / contextConfig.usableTokens * 100);
53407
53468
  const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
53408
53469
  return item.rawValue ? `${displayPercentage.toFixed(1)}%` : `Ctx(u): ${displayPercentage.toFixed(1)}%`;
53409
53470
  }
@@ -55378,8 +55439,12 @@ var InstallMenu = ({
55378
55439
  marginTop: 2,
55379
55440
  children: /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
55380
55441
  dimColor: true,
55381
- children: "The selected command will be written to ~/.claude/settings.json"
55382
- }, undefined, false, undefined, this)
55442
+ children: [
55443
+ "The selected command will be written to",
55444
+ " ",
55445
+ getClaudeSettingsPath()
55446
+ ]
55447
+ }, undefined, true, undefined, this)
55383
55448
  }, undefined, false, undefined, this),
55384
55449
  /* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
55385
55450
  marginTop: 1,
@@ -57742,6 +57807,41 @@ var App2 = () => {
57742
57807
  })();
57743
57808
  }
57744
57809
  });
57810
+ const handleInstallSelection = import_react45.useCallback((command, displayName, useBunx) => {
57811
+ getExistingStatusLine().then((existing) => {
57812
+ const isAlreadyInstalled = [CCSTATUSLINE_COMMANDS.NPM, CCSTATUSLINE_COMMANDS.BUNX, CCSTATUSLINE_COMMANDS.SELF_MANAGED].includes(existing ?? "");
57813
+ let message;
57814
+ if (existing && !isAlreadyInstalled) {
57815
+ message = `This will modify ${getClaudeSettingsPath()}
57816
+
57817
+ A status line is already configured: "${existing}"
57818
+ Replace it with ${command}?`;
57819
+ } else if (isAlreadyInstalled) {
57820
+ message = `ccstatusline is already installed in ${getClaudeSettingsPath()}
57821
+ Update it with ${command}?`;
57822
+ } else {
57823
+ message = `This will modify ${getClaudeSettingsPath()} to add ccstatusline with ${displayName}.
57824
+ Continue?`;
57825
+ }
57826
+ setConfirmDialog({
57827
+ message,
57828
+ action: async () => {
57829
+ await installStatusLine(useBunx);
57830
+ setIsClaudeInstalled(true);
57831
+ setExistingStatusLine(command);
57832
+ setScreen("main");
57833
+ setConfirmDialog(null);
57834
+ }
57835
+ });
57836
+ setScreen("confirm");
57837
+ });
57838
+ }, []);
57839
+ const handleNpxInstall = import_react45.useCallback(() => {
57840
+ handleInstallSelection(CCSTATUSLINE_COMMANDS.NPM, "npx", false);
57841
+ }, [handleInstallSelection]);
57842
+ const handleBunxInstall = import_react45.useCallback(() => {
57843
+ handleInstallSelection(CCSTATUSLINE_COMMANDS.BUNX, "bunx", true);
57844
+ }, [handleInstallSelection]);
57745
57845
  if (!settings) {
57746
57846
  return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
57747
57847
  children: "Loading settings..."
@@ -57750,7 +57850,7 @@ var App2 = () => {
57750
57850
  const handleInstallUninstall = () => {
57751
57851
  if (isClaudeInstalled) {
57752
57852
  setConfirmDialog({
57753
- message: "This will remove ccstatusline from ~/.claude/settings.json. Continue?",
57853
+ message: `This will remove ccstatusline from ${getClaudeSettingsPath()}. Continue?`,
57754
57854
  action: async () => {
57755
57855
  await uninstallStatusLine();
57756
57856
  setIsClaudeInstalled(false);
@@ -57964,64 +58064,8 @@ var App2 = () => {
57964
58064
  screen === "install" && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(InstallMenu, {
57965
58065
  bunxAvailable: isBunxAvailable(),
57966
58066
  existingStatusLine,
57967
- onSelectNpx: () => {
57968
- getExistingStatusLine().then((existing) => {
57969
- const isAlreadyInstalled = ["npx -y ccstatusline@latest", "bunx -y ccstatusline@latest"].includes(existing ?? "");
57970
- let message;
57971
- if (existing && !isAlreadyInstalled) {
57972
- message = `This will modify ~/.claude/settings.json
57973
-
57974
- A status line is already configured: "${existing}"
57975
- Replace it with npx -y ccstatusline@latest?`;
57976
- } else if (isAlreadyInstalled) {
57977
- message = `ccstatusline is already installed in ~/.claude/settings.json
57978
- Update it with npx -y ccstatusline@latest?`;
57979
- } else {
57980
- message = `This will modify ~/.claude/settings.json to add ccstatusline with npx.
57981
- Continue?`;
57982
- }
57983
- setConfirmDialog({
57984
- message,
57985
- action: async () => {
57986
- await installStatusLine(false);
57987
- setIsClaudeInstalled(true);
57988
- setExistingStatusLine("npx -y ccstatusline@latest");
57989
- setScreen("main");
57990
- setConfirmDialog(null);
57991
- }
57992
- });
57993
- setScreen("confirm");
57994
- });
57995
- },
57996
- onSelectBunx: () => {
57997
- getExistingStatusLine().then((existing) => {
57998
- const isAlreadyInstalled = ["npx -y ccstatusline@latest", "bunx -y ccstatusline@latest"].includes(existing ?? "");
57999
- let message;
58000
- if (existing && !isAlreadyInstalled) {
58001
- message = `This will modify ~/.claude/settings.json
58002
-
58003
- A status line is already configured: "${existing}"
58004
- Replace it with bunx -y ccstatusline@latest?`;
58005
- } else if (isAlreadyInstalled) {
58006
- message = `ccstatusline is already installed in ~/.claude/settings.json
58007
- Update it with bunx -y ccstatusline@latest?`;
58008
- } else {
58009
- message = `This will modify ~/.claude/settings.json to add ccstatusline with bunx.
58010
- Continue?`;
58011
- }
58012
- setConfirmDialog({
58013
- message,
58014
- action: async () => {
58015
- await installStatusLine(true);
58016
- setIsClaudeInstalled(true);
58017
- setExistingStatusLine("bunx -y ccstatusline@latest");
58018
- setScreen("main");
58019
- setConfirmDialog(null);
58020
- }
58021
- });
58022
- setScreen("confirm");
58023
- });
58024
- },
58067
+ onSelectNpx: handleNpxInstall,
58068
+ onSelectBunx: handleBunxInstall,
58025
58069
  onCancel: () => {
58026
58070
  setScreen("main");
58027
58071
  }
@@ -58096,7 +58140,7 @@ import path5, { posix } from "path";
58096
58140
 
58097
58141
  // node_modules/fdir/dist/index.mjs
58098
58142
  import { createRequire as createRequire2 } from "module";
58099
- import { basename as basename2, dirname as dirname2, normalize, relative, resolve, sep } from "path";
58143
+ import { basename as basename2, dirname as dirname2, normalize, relative, resolve as resolve2, sep } from "path";
58100
58144
  import * as nativeFs from "fs";
58101
58145
  var __require2 = /* @__PURE__ */ createRequire2(import.meta.url);
58102
58146
  function cleanPath(path5) {
@@ -58117,7 +58161,7 @@ function normalizePath(path5, options) {
58117
58161
  const { resolvePaths, normalizePath: normalizePath$1, pathSeparator } = options;
58118
58162
  const pathNeedsCleaning = process.platform === "win32" && path5.includes("/") || path5.startsWith(".");
58119
58163
  if (resolvePaths)
58120
- path5 = resolve(path5);
58164
+ path5 = resolve2(path5);
58121
58165
  if (normalizePath$1 || pathNeedsCleaning)
58122
58166
  path5 = cleanPath(path5);
58123
58167
  if (path5 === ".")
@@ -58879,7 +58923,7 @@ function globSync(patternsOrOptions, options) {
58879
58923
  import { promisify } from "util";
58880
58924
  var readFile4 = promisify(fs6.readFile);
58881
58925
  var readFileSync4 = fs6.readFileSync;
58882
- var statSync3 = fs6.statSync;
58926
+ var statSync4 = fs6.statSync;
58883
58927
  async function getSessionDuration(transcriptPath) {
58884
58928
  try {
58885
58929
  if (!fs6.existsSync(transcriptPath)) {
@@ -58974,40 +59018,12 @@ async function getTokenMetrics(transcriptPath) {
58974
59018
  return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
58975
59019
  }
58976
59020
  }
58977
- function getBlockMetrics(transcriptPath) {
58978
- if (!transcriptPath || typeof transcriptPath !== "string") {
58979
- return null;
58980
- }
58981
- let claudePath = null;
58982
- if (process.platform === "win32") {
58983
- const homeDir = process.env.USERPROFILE ?? process.env.HOME;
58984
- if (homeDir) {
58985
- claudePath = path6.join(homeDir, ".claude");
58986
- if (!fs6.existsSync(claudePath)) {
58987
- return null;
58988
- }
58989
- }
58990
- } else {
58991
- let currentPath = path6.dirname(transcriptPath);
58992
- const visitedPaths = new Set;
58993
- while (currentPath && !visitedPaths.has(currentPath)) {
58994
- visitedPaths.add(currentPath);
58995
- const baseName = path6.basename(currentPath);
58996
- if (baseName === ".claude") {
58997
- claudePath = currentPath;
58998
- break;
58999
- }
59000
- const parentPath = path6.dirname(currentPath);
59001
- if (parentPath === currentPath) {
59002
- break;
59003
- }
59004
- currentPath = parentPath;
59005
- }
59006
- }
59007
- if (!claudePath)
59021
+ function getBlockMetrics() {
59022
+ const claudeDir = getClaudeConfigDir();
59023
+ if (!claudeDir)
59008
59024
  return null;
59009
59025
  try {
59010
- return findMostRecentBlockStartTime(claudePath);
59026
+ return findMostRecentBlockStartTime(claudeDir);
59011
59027
  } catch {
59012
59028
  return null;
59013
59029
  }
@@ -59023,7 +59039,7 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
59023
59039
  if (files.length === 0)
59024
59040
  return null;
59025
59041
  const filesWithStats = files.map((file2) => {
59026
- const stats = statSync3(file2);
59042
+ const stats = statSync4(file2);
59027
59043
  return { file: file2, mtime: stats.mtime };
59028
59044
  });
59029
59045
  filesWithStats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
@@ -59177,14 +59193,17 @@ async function renderMultipleLines(data) {
59177
59193
  const hasSessionClock = lines.some((line) => line.some((item) => item.type === "session-clock"));
59178
59194
  const hasBlockTimer = lines.some((line) => line.some((item) => item.type === "block-timer"));
59179
59195
  let tokenMetrics = null;
59180
- if (hasTokenItems && data.transcript_path)
59196
+ if (hasTokenItems && data.transcript_path) {
59181
59197
  tokenMetrics = await getTokenMetrics(data.transcript_path);
59198
+ }
59182
59199
  let sessionDuration = null;
59183
- if (hasSessionClock && data.transcript_path)
59200
+ if (hasSessionClock && data.transcript_path) {
59184
59201
  sessionDuration = await getSessionDuration(data.transcript_path);
59202
+ }
59185
59203
  let blockMetrics = null;
59186
- if (hasBlockTimer && data.transcript_path)
59187
- blockMetrics = getBlockMetrics(data.transcript_path);
59204
+ if (hasBlockTimer) {
59205
+ blockMetrics = getBlockMetrics();
59206
+ }
59188
59207
  const context = {
59189
59208
  data,
59190
59209
  tokenMetrics,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",