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 +20 -4
- package/dist/ccstatusline.js +143 -124
- package/package.json +1 -1
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
|
-
**
|
|
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 (
|
|
352
|
-
- **Context Percentage (usable)** - Shows percentage of usable context (
|
|
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
|
package/dist/ccstatusline.js
CHANGED
|
@@ -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()
|
|
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()
|
|
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()
|
|
1275
|
-
var Scheduler = __toESM(require_scheduler()
|
|
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()
|
|
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()
|
|
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()
|
|
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()
|
|
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()
|
|
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
|
|
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
|
-
|
|
39313
|
+
const settingsPath = getClaudeSettingsPath();
|
|
39314
|
+
if (!fs2.existsSync(settingsPath)) {
|
|
39290
39315
|
return {};
|
|
39291
39316
|
}
|
|
39292
|
-
const content = await readFile(
|
|
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
|
|
39324
|
+
const settingsPath = getClaudeSettingsPath();
|
|
39325
|
+
const dir = path.dirname(settingsPath);
|
|
39300
39326
|
await mkdir(dir, { recursive: true });
|
|
39301
|
-
await writeFile(
|
|
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 = [
|
|
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 ?
|
|
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.
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
55382
|
-
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
58978
|
-
|
|
58979
|
-
|
|
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(
|
|
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 =
|
|
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
|
|
59187
|
-
blockMetrics = getBlockMetrics(
|
|
59204
|
+
if (hasBlockTimer) {
|
|
59205
|
+
blockMetrics = getBlockMetrics();
|
|
59206
|
+
}
|
|
59188
59207
|
const context = {
|
|
59189
59208
|
data,
|
|
59190
59209
|
tokenMetrics,
|