ccstatusline 2.0.4 → 2.0.6

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 ccstatusline contributors
3
+ Copyright (c) 2025 Matthew Breedlove (https://github.com/sirmalloc)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,8 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
22
+
23
+ ---
24
+ Original author: Matthew Breedlove (https://github.com/sirmalloc)
25
+ Official repository: https://github.com/sirmalloc/ccstatusline
package/README.md CHANGED
@@ -343,7 +343,7 @@ Contributions are welcome! Please feel free to submit a Pull Request.
343
343
  ## 🔗 Related Projects
344
344
 
345
345
  - [tweakcc](https://github.com/Piebald-AI/tweakcc) - Customize Claude Code themes, thinking verbs, and more.
346
- - [ccusage](https://github.com/samuelint/ccusage) - Track and display Claude Code usage metrics.
346
+ - [ccusage](https://github.com/ryoppippi/ccusage) - Track and display Claude Code usage metrics.
347
347
 
348
348
  ---
349
349
 
@@ -51035,7 +51035,7 @@ import { execSync as execSync3 } from "child_process";
51035
51035
  import * as fs5 from "fs";
51036
51036
  import * as path4 from "path";
51037
51037
  var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src/utils";
51038
- var PACKAGE_VERSION = "2.0.4";
51038
+ var PACKAGE_VERSION = "2.0.6";
51039
51039
  function getPackageVersion() {
51040
51040
  if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
51041
51041
  return PACKAGE_VERSION;
@@ -51949,7 +51949,7 @@ class GitBranchWidget {
51949
51949
  }
51950
51950
  getGitBranch() {
51951
51951
  try {
51952
- const branch = execSync4("git branch --show-current 2>/dev/null", {
51952
+ const branch = execSync4("git branch --show-current", {
51953
51953
  encoding: "utf8",
51954
51954
  stdio: ["pipe", "pipe", "ignore"]
51955
51955
  }).trim();
@@ -51995,11 +51995,11 @@ class GitChangesWidget {
51995
51995
  try {
51996
51996
  let totalInsertions = 0;
51997
51997
  let totalDeletions = 0;
51998
- const unstagedStat = execSync5("git diff --shortstat 2>/dev/null", {
51998
+ const unstagedStat = execSync5("git diff --shortstat", {
51999
51999
  encoding: "utf8",
52000
52000
  stdio: ["pipe", "pipe", "ignore"]
52001
52001
  }).trim();
52002
- const stagedStat = execSync5("git diff --cached --shortstat 2>/dev/null", {
52002
+ const stagedStat = execSync5("git diff --cached --shortstat", {
52003
52003
  encoding: "utf8",
52004
52004
  stdio: ["pipe", "pipe", "ignore"]
52005
52005
  }).trim();
@@ -53243,20 +53243,27 @@ class BlockTimerWidget {
53243
53243
  render(item, context, settings) {
53244
53244
  const displayMode = item.metadata?.display ?? "time";
53245
53245
  if (context.isPreview) {
53246
+ const prefix = item.rawValue ? "" : "Block ";
53246
53247
  if (displayMode === "progress") {
53247
- return "Block [██████████████████████░░░░░░░░] 73.9%";
53248
+ return `${prefix}[██████████████████████░░░░░░░░] 73.9%`;
53248
53249
  } else if (displayMode === "progress-short") {
53249
- return "Block [███████░░░░░░░░] 73.9%";
53250
+ return `${prefix}[███████░░░░░░░░] 73.9%`;
53250
53251
  }
53251
53252
  return item.rawValue ? "3hr 45m" : "Block: 3hr 45m";
53252
53253
  }
53253
- const blockInfo = context.blockMetrics;
53254
- if (!blockInfo) {
53255
- return null;
53254
+ const blockMetrics = context.blockMetrics;
53255
+ if (!blockMetrics) {
53256
+ if (displayMode === "progress" || displayMode === "progress-short") {
53257
+ const barWidth = displayMode === "progress" ? 32 : 16;
53258
+ const emptyBar = "░".repeat(barWidth);
53259
+ return item.rawValue ? `[${emptyBar}] 0%` : `Block [${emptyBar}] 0%`;
53260
+ } else {
53261
+ return item.rawValue ? "0hr 0m" : "Block: 0hr 0m";
53262
+ }
53256
53263
  }
53257
53264
  try {
53258
53265
  const now = new Date;
53259
- const elapsedMs = now.getTime() - blockInfo.startTime.getTime();
53266
+ const elapsedMs = now.getTime() - blockMetrics.startTime.getTime();
53260
53267
  const sessionDurationMs = 5 * 60 * 60 * 1000;
53261
53268
  const progress = Math.min(elapsedMs / sessionDurationMs, 1);
53262
53269
  const percentage = (progress * 100).toFixed(1);
@@ -56945,13 +56952,15 @@ Continue?`;
56945
56952
  },
56946
56953
  onInstallFonts: () => {
56947
56954
  setInstallingFonts(true);
56948
- installPowerlineFonts().then((result) => {
56949
- setInstallingFonts(false);
56950
- setFontInstallMessage(result.message);
56951
- checkPowerlineFontsAsync().then((asyncStatus) => {
56952
- setPowerlineFontStatus(asyncStatus);
56955
+ setTimeout(() => {
56956
+ installPowerlineFonts().then((result) => {
56957
+ setInstallingFonts(false);
56958
+ setFontInstallMessage(result.message);
56959
+ checkPowerlineFontsAsync().then((asyncStatus) => {
56960
+ setPowerlineFontStatus(asyncStatus);
56961
+ });
56953
56962
  });
56954
- });
56963
+ }, 50);
56955
56964
  },
56956
56965
  installingFonts,
56957
56966
  fontInstallMessage,
@@ -57887,9 +57896,8 @@ function getBlockMetrics(transcriptPath) {
57887
57896
  }
57888
57897
  currentPath = path6.dirname(currentPath);
57889
57898
  }
57890
- if (!claudePath) {
57899
+ if (!claudePath)
57891
57900
  return null;
57892
- }
57893
57901
  try {
57894
57902
  return findMostRecentBlockStartTime(claudePath);
57895
57903
  } catch {
@@ -57901,44 +57909,65 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
57901
57909
  const now = new Date;
57902
57910
  const pattern = path6.join(rootDir, "projects", "**", "*.jsonl").replace(/\\/g, "/");
57903
57911
  const files = globSync([pattern]);
57904
- if (files.length === 0) {
57912
+ if (files.length === 0)
57905
57913
  return null;
57906
- }
57907
57914
  const filesWithStats = files.map((file2) => {
57908
57915
  const stats = statSync3(file2);
57909
57916
  return { file: file2, mtime: stats.mtime };
57910
57917
  });
57911
57918
  filesWithStats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
57912
- const timestamps = [];
57913
- const cutoffTime = new Date(now.getTime() - 20 * 60 * 60 * 1000);
57914
- for (const { file: file2, mtime } of filesWithStats) {
57915
- if (mtime.getTime() < cutoffTime.getTime()) {
57916
- break;
57919
+ const lookbackChunks = [
57920
+ 10,
57921
+ 20,
57922
+ 48
57923
+ ];
57924
+ let timestamps = [];
57925
+ let mostRecentTimestamp = null;
57926
+ let continuousWorkStart = null;
57927
+ let foundSessionGap = false;
57928
+ for (const lookbackHours of lookbackChunks) {
57929
+ const cutoffTime = new Date(now.getTime() - lookbackHours * 60 * 60 * 1000);
57930
+ timestamps = [];
57931
+ for (const { file: file2, mtime } of filesWithStats) {
57932
+ if (mtime.getTime() < cutoffTime.getTime()) {
57933
+ break;
57934
+ }
57935
+ const fileTimestamps = getAllTimestampsFromFile(file2);
57936
+ timestamps.push(...fileTimestamps);
57917
57937
  }
57918
- const fileTimestamps = getAllTimestampsFromFile(file2);
57919
- timestamps.push(...fileTimestamps);
57920
- }
57921
- if (timestamps.length === 0) {
57922
- return null;
57923
- }
57924
- timestamps.sort((a, b) => b.getTime() - a.getTime());
57925
- const mostRecentTimestamp = timestamps[0];
57926
- if (!mostRecentTimestamp) {
57927
- return null;
57928
- }
57929
- let continuousWorkStart = mostRecentTimestamp;
57930
- for (let i = 1;i < timestamps.length; i++) {
57931
- const currentTimestamp = timestamps[i];
57932
- const previousTimestamp = timestamps[i - 1];
57933
- if (!currentTimestamp || !previousTimestamp) {
57938
+ if (timestamps.length === 0) {
57934
57939
  continue;
57935
57940
  }
57936
- const gap = previousTimestamp.getTime() - currentTimestamp.getTime();
57937
- const oneHourMs = 60 * 60 * 1000;
57938
- if (gap > oneHourMs) {
57941
+ timestamps.sort((a, b) => b.getTime() - a.getTime());
57942
+ if (!mostRecentTimestamp && timestamps[0]) {
57943
+ mostRecentTimestamp = timestamps[0];
57944
+ const timeSinceLastActivity = now.getTime() - mostRecentTimestamp.getTime();
57945
+ if (timeSinceLastActivity > sessionDurationMs) {
57946
+ return null;
57947
+ }
57948
+ }
57949
+ continuousWorkStart = mostRecentTimestamp;
57950
+ for (let i = 1;i < timestamps.length; i++) {
57951
+ const currentTimestamp = timestamps[i];
57952
+ const previousTimestamp = timestamps[i - 1];
57953
+ if (!currentTimestamp || !previousTimestamp)
57954
+ continue;
57955
+ const gap = previousTimestamp.getTime() - currentTimestamp.getTime();
57956
+ if (gap >= sessionDurationMs) {
57957
+ foundSessionGap = true;
57958
+ break;
57959
+ }
57960
+ continuousWorkStart = currentTimestamp;
57961
+ }
57962
+ if (foundSessionGap) {
57963
+ break;
57964
+ }
57965
+ if (lookbackHours === lookbackChunks[lookbackChunks.length - 1]) {
57939
57966
  break;
57940
57967
  }
57941
- continuousWorkStart = currentTimestamp;
57968
+ }
57969
+ if (!mostRecentTimestamp || !continuousWorkStart) {
57970
+ return null;
57942
57971
  }
57943
57972
  const flooredWorkStart = floorToHour(continuousWorkStart);
57944
57973
  const totalWorkTime = now.getTime() - flooredWorkStart.getTime();
@@ -57947,13 +57976,15 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
57947
57976
  const completedBlocks = Math.floor(totalWorkTime / sessionDurationMs);
57948
57977
  blockStart = new Date(flooredWorkStart.getTime() + completedBlocks * sessionDurationMs);
57949
57978
  }
57950
- const timeSinceActivity = now.getTime() - mostRecentTimestamp.getTime();
57951
57979
  const blockEnd = new Date(blockStart.getTime() + sessionDurationMs);
57952
- const isActive = timeSinceActivity < sessionDurationMs && now < blockEnd;
57980
+ const inBlockWindow = now.getTime() >= blockStart.getTime() && now.getTime() <= blockEnd.getTime();
57981
+ const activityInThisBlock = mostRecentTimestamp.getTime() >= blockStart.getTime() && mostRecentTimestamp.getTime() <= now.getTime();
57982
+ const isActive = inBlockWindow && activityInThisBlock;
57983
+ if (!isActive)
57984
+ return null;
57953
57985
  return {
57954
57986
  startTime: blockStart,
57955
- lastActivity: mostRecentTimestamp,
57956
- isActive
57987
+ lastActivity: mostRecentTimestamp
57957
57988
  };
57958
57989
  }
57959
57990
  function getAllTimestampsFromFile(filePath) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",
@@ -37,9 +37,11 @@
37
37
  "patch-package": "^8.0.0",
38
38
  "react": "^19.1.1",
39
39
  "react-devtools-core": "^6.1.5",
40
+ "strip-ansi": "^7.1.0",
40
41
  "tinyglobby": "^0.2.14",
41
42
  "typescript": "^5.9.2",
42
- "typescript-eslint": "^8.39.1"
43
+ "typescript-eslint": "^8.39.1",
44
+ "zod": "^4.0.17"
43
45
  },
44
46
  "keywords": [
45
47
  "claude",
@@ -59,9 +61,5 @@
59
61
  },
60
62
  "trustedDependencies": [
61
63
  "unrs-resolver"
62
- ],
63
- "dependencies": {
64
- "strip-ansi": "^7.1.0",
65
- "zod": "^4.0.17"
66
- }
64
+ ]
67
65
  }