@owloops/claude-powerline 1.5.1 → 1.5.3
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 +22 -15
- package/dist/index.js +212 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
|
|
53
53
|
- **Vim-style powerline** with proper arrows and segments
|
|
54
54
|
- **Real-time session tracking** with costs and tokens
|
|
55
|
-
- **Billing window tracking** with 5-hour
|
|
55
|
+
- **Billing window tracking** with 5-hour blocks and burn rates
|
|
56
56
|
- **Daily usage monitoring** with budget alerts
|
|
57
|
-
- **Performance metrics** with response times
|
|
57
|
+
- **Performance metrics** with response times
|
|
58
58
|
- **Context monitoring** showing tokens used and auto-compact threshold
|
|
59
59
|
- **Git integration** with branch, status, ahead/behind counts
|
|
60
60
|
|
|
@@ -222,7 +222,7 @@ Configuration priority (top overrides bottom):
|
|
|
222
222
|
"segments": {
|
|
223
223
|
"directory": {
|
|
224
224
|
"enabled": true,
|
|
225
|
-
"
|
|
225
|
+
"showBasename": false
|
|
226
226
|
},
|
|
227
227
|
"git": {
|
|
228
228
|
"enabled": true,
|
|
@@ -237,7 +237,7 @@ Configuration priority (top overrides bottom):
|
|
|
237
237
|
},
|
|
238
238
|
"model": { "enabled": true },
|
|
239
239
|
"session": { "enabled": true, "type": "tokens" },
|
|
240
|
-
"block": { "enabled": true, "type": "cost" },
|
|
240
|
+
"block": { "enabled": true, "type": "cost", "burnType": "cost" },
|
|
241
241
|
"today": { "enabled": true, "type": "cost" },
|
|
242
242
|
"context": { "enabled": true },
|
|
243
243
|
"tmux": { "enabled": true },
|
|
@@ -246,9 +246,7 @@ Configuration priority (top overrides bottom):
|
|
|
246
246
|
"showResponseTime": true,
|
|
247
247
|
"showLastResponseTime": false,
|
|
248
248
|
"showDuration": true,
|
|
249
|
-
"showMessageCount": true
|
|
250
|
-
"showCostBurnRate": false,
|
|
251
|
-
"showTokenBurnRate": false
|
|
249
|
+
"showMessageCount": true
|
|
252
250
|
}
|
|
253
251
|
}
|
|
254
252
|
}
|
|
@@ -259,7 +257,7 @@ Configuration priority (top overrides bottom):
|
|
|
259
257
|
|
|
260
258
|
### Segment Details
|
|
261
259
|
|
|
262
|
-
- **directory**: Current working directory name (supports `
|
|
260
|
+
- **directory**: Current working directory name (supports `showBasename` option)
|
|
263
261
|
- **git**: Branch, status, and extensive repository information (see Git Configuration below)
|
|
264
262
|
- **model**: Current Claude model being used
|
|
265
263
|
- **session**: Token usage and costs for current session
|
|
@@ -274,7 +272,7 @@ Configuration priority (top overrides bottom):
|
|
|
274
272
|
```json
|
|
275
273
|
"directory": {
|
|
276
274
|
"enabled": true,
|
|
277
|
-
"
|
|
275
|
+
"showBasename": false // Show only folder name instead of full path
|
|
278
276
|
}
|
|
279
277
|
```
|
|
280
278
|
|
|
@@ -315,9 +313,7 @@ The metrics segment displays performance analytics from your Claude sessions:
|
|
|
315
313
|
"showResponseTime": true, // Average response time (`⧖ 3.2s`)
|
|
316
314
|
"showLastResponseTime": false, // Last response time (`Δ 2.8s`)
|
|
317
315
|
"showDuration": true, // Session duration (`⧗ 28m`)
|
|
318
|
-
"showMessageCount": true
|
|
319
|
-
"showCostBurnRate": false, // Cost per hour (`⟢ $1.20/h`)
|
|
320
|
-
"showTokenBurnRate": false // Tokens per hour (`⟢ 450K/h`)
|
|
316
|
+
"showMessageCount": true // User message count (`⟐ 93`)
|
|
321
317
|
}
|
|
322
318
|
```
|
|
323
319
|
|
|
@@ -327,8 +323,6 @@ The metrics segment displays performance analytics from your Claude sessions:
|
|
|
327
323
|
- `showLastResponseTime`: Time for the last response (shows `0.0s` while waiting)
|
|
328
324
|
- `showDuration`: Total time since session started
|
|
329
325
|
- `showMessageCount`: Number of user messages sent
|
|
330
|
-
- `showCostBurnRate`: Spending rate per hour
|
|
331
|
-
- `showTokenBurnRate`: Token consumption rate per hour
|
|
332
326
|
|
|
333
327
|

|
|
334
328
|
|
|
@@ -369,6 +363,19 @@ The powerline includes three complementary usage segments:
|
|
|
369
363
|
|
|
370
364
|
- `cost`: Show cost + time (`$0.05 (2h 30m left)`)
|
|
371
365
|
- `tokens`: Show tokens + time (`1.2K tokens (2h 30m left)`)
|
|
366
|
+
- `both`: Show both cost and tokens + time
|
|
367
|
+
- `time`: Show only time remaining
|
|
368
|
+
|
|
369
|
+
**Block burn rates** (configured with `burnType`):
|
|
370
|
+
|
|
371
|
+
```json
|
|
372
|
+
"block": { "enabled": true, "type": "cost", "burnType": "cost" }
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
- `cost`: Show cost burn rate (`$0.05 | $1.20/h (2h 30m left)`)
|
|
376
|
+
- `tokens`: Show token burn rate (`1.2K | 450K/h (2h 30m left)`)
|
|
377
|
+
- `both`: Show both burn rates
|
|
378
|
+
- `none`: Hide burn rates
|
|
372
379
|
|
|
373
380
|
**Budget Configuration:**
|
|
374
381
|
|
|
@@ -415,7 +422,7 @@ To prevent segment cutoff, configure multiple lines:
|
|
|
415
422
|
{
|
|
416
423
|
"segments": {
|
|
417
424
|
"session": { "enabled": true, "type": "tokens" },
|
|
418
|
-
"block": { "enabled": true, "type": "cost" },
|
|
425
|
+
"block": { "enabled": true, "type": "cost", "burnType": "cost" },
|
|
419
426
|
"today": { "enabled": true, "type": "cost" },
|
|
420
427
|
"context": { "enabled": true },
|
|
421
428
|
"tmux": { "enabled": false },
|
package/dist/index.js
CHANGED
|
@@ -858,6 +858,14 @@ async function getFileModificationDate(filePath) {
|
|
|
858
858
|
return null;
|
|
859
859
|
}
|
|
860
860
|
}
|
|
861
|
+
function createUniqueHash(entry) {
|
|
862
|
+
const messageId = entry.message?.id || (typeof entry.raw.message === "object" && entry.raw.message !== null && "id" in entry.raw.message ? entry.raw.message.id : void 0);
|
|
863
|
+
const requestId = "requestId" in entry.raw ? entry.raw.requestId : void 0;
|
|
864
|
+
if (!messageId || !requestId) {
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
return `${messageId}:${requestId}`;
|
|
868
|
+
}
|
|
861
869
|
async function parseJsonlFile(filePath) {
|
|
862
870
|
try {
|
|
863
871
|
const content = await readFile(filePath, "utf-8");
|
|
@@ -890,6 +898,7 @@ async function loadEntriesFromProjects(timeFilter, fileFilter, sortFiles = false
|
|
|
890
898
|
const entries = [];
|
|
891
899
|
const claudePaths = getClaudePaths();
|
|
892
900
|
const projectPaths = await findProjectPaths(claudePaths);
|
|
901
|
+
const processedHashes = /* @__PURE__ */ new Set();
|
|
893
902
|
const allFiles = [];
|
|
894
903
|
for (const projectPath of projectPaths) {
|
|
895
904
|
try {
|
|
@@ -922,6 +931,14 @@ async function loadEntriesFromProjects(timeFilter, fileFilter, sortFiles = false
|
|
|
922
931
|
for (const filePath of allFiles) {
|
|
923
932
|
const fileEntries = await parseJsonlFile(filePath);
|
|
924
933
|
for (const entry of fileEntries) {
|
|
934
|
+
const uniqueHash = createUniqueHash(entry);
|
|
935
|
+
if (uniqueHash && processedHashes.has(uniqueHash)) {
|
|
936
|
+
debug(`Skipping duplicate entry: ${uniqueHash}`);
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
if (uniqueHash) {
|
|
940
|
+
processedHashes.add(uniqueHash);
|
|
941
|
+
}
|
|
925
942
|
if (!timeFilter || timeFilter(entry)) {
|
|
926
943
|
entries.push(entry);
|
|
927
944
|
}
|
|
@@ -1612,7 +1629,7 @@ var SegmentRenderer = class {
|
|
|
1612
1629
|
fgColor: colors.contextFg
|
|
1613
1630
|
};
|
|
1614
1631
|
}
|
|
1615
|
-
renderMetrics(metricsInfo, colors, config) {
|
|
1632
|
+
renderMetrics(metricsInfo, colors, _blockInfo, config) {
|
|
1616
1633
|
if (!metricsInfo) {
|
|
1617
1634
|
return {
|
|
1618
1635
|
text: `${this.symbols.metrics_response} new`,
|
|
@@ -1638,14 +1655,6 @@ var SegmentRenderer = class {
|
|
|
1638
1655
|
`${this.symbols.metrics_messages} ${metricsInfo.messageCount}`
|
|
1639
1656
|
);
|
|
1640
1657
|
}
|
|
1641
|
-
if (config?.showCostBurnRate && metricsInfo.costBurnRate !== null) {
|
|
1642
|
-
const burnRate = metricsInfo.costBurnRate < 1 ? `${(metricsInfo.costBurnRate * 100).toFixed(0)}\xA2/h` : `$${metricsInfo.costBurnRate.toFixed(2)}/h`;
|
|
1643
|
-
parts.push(`${this.symbols.metrics_burn} ${burnRate}`);
|
|
1644
|
-
}
|
|
1645
|
-
if (config?.showTokenBurnRate && metricsInfo.tokenBurnRate !== null) {
|
|
1646
|
-
const tokenRate = formatTokens(Math.round(metricsInfo.tokenBurnRate));
|
|
1647
|
-
parts.push(`${this.symbols.metrics_burn} ${tokenRate}/h`);
|
|
1648
|
-
}
|
|
1649
1658
|
if (parts.length === 0) {
|
|
1650
1659
|
return {
|
|
1651
1660
|
text: `${this.symbols.metrics_response} active`,
|
|
@@ -1659,25 +1668,57 @@ var SegmentRenderer = class {
|
|
|
1659
1668
|
fgColor: colors.metricsFg
|
|
1660
1669
|
};
|
|
1661
1670
|
}
|
|
1662
|
-
renderBlock(blockInfo, colors,
|
|
1671
|
+
renderBlock(blockInfo, colors, config) {
|
|
1663
1672
|
let displayText;
|
|
1664
1673
|
if (blockInfo.cost === null && blockInfo.tokens === null) {
|
|
1665
1674
|
displayText = "No active block";
|
|
1666
1675
|
} else {
|
|
1676
|
+
const type = config?.type || "cost";
|
|
1677
|
+
const burnType = config?.burnType;
|
|
1667
1678
|
const timeStr = blockInfo.timeRemaining !== null ? (() => {
|
|
1668
1679
|
const hours = Math.floor(blockInfo.timeRemaining / 60);
|
|
1669
1680
|
const minutes = blockInfo.timeRemaining % 60;
|
|
1670
1681
|
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
1671
1682
|
})() : null;
|
|
1683
|
+
let mainContent;
|
|
1672
1684
|
switch (type) {
|
|
1673
1685
|
case "cost":
|
|
1674
|
-
|
|
1686
|
+
mainContent = formatCost(blockInfo.cost);
|
|
1675
1687
|
break;
|
|
1676
1688
|
case "tokens":
|
|
1677
|
-
|
|
1689
|
+
mainContent = formatTokens(blockInfo.tokens);
|
|
1690
|
+
break;
|
|
1691
|
+
case "both":
|
|
1692
|
+
mainContent = `${formatCost(blockInfo.cost)} / ${formatTokens(blockInfo.tokens)}`;
|
|
1693
|
+
break;
|
|
1694
|
+
case "time":
|
|
1695
|
+
mainContent = timeStr || "N/A";
|
|
1678
1696
|
break;
|
|
1679
1697
|
default:
|
|
1680
|
-
|
|
1698
|
+
mainContent = formatCost(blockInfo.cost);
|
|
1699
|
+
}
|
|
1700
|
+
let burnContent = "";
|
|
1701
|
+
if (burnType && burnType !== "none") {
|
|
1702
|
+
switch (burnType) {
|
|
1703
|
+
case "cost":
|
|
1704
|
+
const costBurnRate = blockInfo.burnRate !== null ? blockInfo.burnRate < 1 ? `${(blockInfo.burnRate * 100).toFixed(0)}\xA2/h` : `$${blockInfo.burnRate.toFixed(2)}/h` : "N/A";
|
|
1705
|
+
burnContent = ` | ${costBurnRate}`;
|
|
1706
|
+
break;
|
|
1707
|
+
case "tokens":
|
|
1708
|
+
const tokenBurnRate = blockInfo.tokenBurnRate !== null ? `${formatTokens(Math.round(blockInfo.tokenBurnRate))}/h` : "N/A";
|
|
1709
|
+
burnContent = ` | ${tokenBurnRate}`;
|
|
1710
|
+
break;
|
|
1711
|
+
case "both":
|
|
1712
|
+
const costBurn = blockInfo.burnRate !== null ? blockInfo.burnRate < 1 ? `${(blockInfo.burnRate * 100).toFixed(0)}\xA2/h` : `$${blockInfo.burnRate.toFixed(2)}/h` : "N/A";
|
|
1713
|
+
const tokenBurn = blockInfo.tokenBurnRate !== null ? `${formatTokens(Math.round(blockInfo.tokenBurnRate))}/h` : "N/A";
|
|
1714
|
+
burnContent = ` | ${costBurn} / ${tokenBurn}`;
|
|
1715
|
+
break;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
if (type === "time") {
|
|
1719
|
+
displayText = mainContent;
|
|
1720
|
+
} else {
|
|
1721
|
+
displayText = timeStr ? `${mainContent}${burnContent} (${timeStr} left)` : `${mainContent}${burnContent}`;
|
|
1681
1722
|
}
|
|
1682
1723
|
}
|
|
1683
1724
|
return {
|
|
@@ -1770,73 +1811,185 @@ function convertToUsageEntry(entry) {
|
|
|
1770
1811
|
};
|
|
1771
1812
|
}
|
|
1772
1813
|
var BlockProvider = class {
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
const
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1814
|
+
sessionDurationHours = 5;
|
|
1815
|
+
floorToHour(timestamp) {
|
|
1816
|
+
const floored = new Date(timestamp);
|
|
1817
|
+
floored.setUTCMinutes(0, 0, 0);
|
|
1818
|
+
return floored;
|
|
1819
|
+
}
|
|
1820
|
+
identifySessionBlocks(entries) {
|
|
1821
|
+
if (entries.length === 0) return [];
|
|
1822
|
+
const sessionDurationMs = this.sessionDurationHours * 60 * 60 * 1e3;
|
|
1823
|
+
const blocks = [];
|
|
1824
|
+
const sortedEntries = [...entries].sort(
|
|
1825
|
+
(a, b) => a.timestamp.getTime() - b.timestamp.getTime()
|
|
1783
1826
|
);
|
|
1827
|
+
let currentBlockStart = null;
|
|
1828
|
+
let currentBlockEntries = [];
|
|
1829
|
+
for (const entry of sortedEntries) {
|
|
1830
|
+
const entryTime = entry.timestamp;
|
|
1831
|
+
if (currentBlockStart == null) {
|
|
1832
|
+
currentBlockStart = this.floorToHour(entryTime);
|
|
1833
|
+
currentBlockEntries = [entry];
|
|
1834
|
+
} else {
|
|
1835
|
+
const timeSinceBlockStart = entryTime.getTime() - currentBlockStart.getTime();
|
|
1836
|
+
const lastEntry = currentBlockEntries[currentBlockEntries.length - 1];
|
|
1837
|
+
if (lastEntry == null) {
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
const lastEntryTime = lastEntry.timestamp;
|
|
1841
|
+
const timeSinceLastEntry = entryTime.getTime() - lastEntryTime.getTime();
|
|
1842
|
+
if (timeSinceBlockStart > sessionDurationMs || timeSinceLastEntry > sessionDurationMs) {
|
|
1843
|
+
blocks.push(currentBlockEntries);
|
|
1844
|
+
currentBlockStart = this.floorToHour(entryTime);
|
|
1845
|
+
currentBlockEntries = [entry];
|
|
1846
|
+
} else {
|
|
1847
|
+
currentBlockEntries.push(entry);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
if (currentBlockStart != null && currentBlockEntries.length > 0) {
|
|
1852
|
+
blocks.push(currentBlockEntries);
|
|
1853
|
+
}
|
|
1854
|
+
return blocks;
|
|
1855
|
+
}
|
|
1856
|
+
createBlockInfo(startTime, entries) {
|
|
1857
|
+
const now = /* @__PURE__ */ new Date();
|
|
1858
|
+
const sessionDurationMs = this.sessionDurationHours * 60 * 60 * 1e3;
|
|
1859
|
+
const endTime = new Date(startTime.getTime() + sessionDurationMs);
|
|
1860
|
+
const lastEntry = entries[entries.length - 1];
|
|
1861
|
+
const actualEndTime = lastEntry != null ? lastEntry.timestamp : startTime;
|
|
1862
|
+
const isActive = now.getTime() - actualEndTime.getTime() < sessionDurationMs && now < endTime;
|
|
1863
|
+
return { block: entries, isActive };
|
|
1864
|
+
}
|
|
1865
|
+
findActiveBlock(blocks) {
|
|
1866
|
+
for (let i = blocks.length - 1; i >= 0; i--) {
|
|
1867
|
+
const block = blocks[i];
|
|
1868
|
+
if (!block || block.length === 0) continue;
|
|
1869
|
+
const firstEntry = block[0];
|
|
1870
|
+
if (!firstEntry) continue;
|
|
1871
|
+
const blockStartTime = this.floorToHour(firstEntry.timestamp);
|
|
1872
|
+
const blockInfo = this.createBlockInfo(blockStartTime, block);
|
|
1873
|
+
if (blockInfo.isActive) {
|
|
1874
|
+
return blockInfo.block;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
return null;
|
|
1878
|
+
}
|
|
1879
|
+
async loadUsageEntries() {
|
|
1880
|
+
debug(`Block segment: Loading entries for dynamic session blocks`);
|
|
1881
|
+
const dayAgo = /* @__PURE__ */ new Date();
|
|
1882
|
+
dayAgo.setDate(dayAgo.getDate() - 1);
|
|
1784
1883
|
const fileFilter = (_filePath, modTime) => {
|
|
1785
|
-
return modTime >=
|
|
1884
|
+
return modTime >= dayAgo;
|
|
1786
1885
|
};
|
|
1787
1886
|
const parsedEntries = await loadEntriesFromProjects(
|
|
1788
1887
|
void 0,
|
|
1789
1888
|
fileFilter,
|
|
1790
1889
|
true
|
|
1791
1890
|
);
|
|
1792
|
-
const
|
|
1793
|
-
let entriesInBlock = 0;
|
|
1891
|
+
const allUsageEntries = [];
|
|
1794
1892
|
for (const entry of parsedEntries) {
|
|
1795
|
-
if (entry.message?.usage
|
|
1893
|
+
if (entry.message?.usage) {
|
|
1796
1894
|
const usageEntry = convertToUsageEntry(entry);
|
|
1797
1895
|
if (!usageEntry.costUSD && entry.raw) {
|
|
1798
1896
|
usageEntry.costUSD = await PricingService.calculateCostForEntry(
|
|
1799
1897
|
entry.raw
|
|
1800
1898
|
);
|
|
1801
1899
|
}
|
|
1802
|
-
|
|
1803
|
-
|
|
1900
|
+
allUsageEntries.push(usageEntry);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
const sessionBlocks = this.identifySessionBlocks(allUsageEntries);
|
|
1904
|
+
debug(`Block segment: Found ${sessionBlocks.length} session blocks`);
|
|
1905
|
+
const activeBlock = this.findActiveBlock(sessionBlocks);
|
|
1906
|
+
if (activeBlock && activeBlock.length > 0) {
|
|
1907
|
+
debug(
|
|
1908
|
+
`Block segment: Found active block with ${activeBlock.length} entries`
|
|
1909
|
+
);
|
|
1910
|
+
const blockStart = activeBlock[0];
|
|
1911
|
+
const blockEnd = activeBlock[activeBlock.length - 1];
|
|
1912
|
+
if (blockStart && blockEnd) {
|
|
1913
|
+
debug(
|
|
1914
|
+
`Block segment: Active block from ${blockStart.timestamp.toISOString()} to ${blockEnd.timestamp.toISOString()}`
|
|
1915
|
+
);
|
|
1804
1916
|
}
|
|
1917
|
+
return activeBlock;
|
|
1918
|
+
} else {
|
|
1919
|
+
debug(`Block segment: No active block found`);
|
|
1920
|
+
return [];
|
|
1805
1921
|
}
|
|
1806
|
-
debug(`Block segment: Found ${entriesInBlock} entries in current block`);
|
|
1807
|
-
return usageEntries;
|
|
1808
1922
|
}
|
|
1809
1923
|
async getActiveBlockInfo() {
|
|
1810
1924
|
try {
|
|
1811
1925
|
const entries = await this.loadUsageEntries();
|
|
1812
1926
|
if (entries.length === 0) {
|
|
1813
1927
|
debug("Block segment: No entries in current block");
|
|
1814
|
-
return {
|
|
1928
|
+
return {
|
|
1929
|
+
cost: null,
|
|
1930
|
+
tokens: null,
|
|
1931
|
+
timeRemaining: null,
|
|
1932
|
+
burnRate: null,
|
|
1933
|
+
tokenBurnRate: null
|
|
1934
|
+
};
|
|
1815
1935
|
}
|
|
1816
1936
|
const totalCost = entries.reduce((sum, entry) => sum + entry.costUSD, 0);
|
|
1817
1937
|
const totalTokens = entries.reduce((sum, entry) => {
|
|
1818
1938
|
return sum + entry.usage.inputTokens + entry.usage.outputTokens + entry.usage.cacheCreationInputTokens + entry.usage.cacheReadInputTokens;
|
|
1819
1939
|
}, 0);
|
|
1820
1940
|
const now = /* @__PURE__ */ new Date();
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1941
|
+
let timeRemaining = null;
|
|
1942
|
+
if (entries.length > 0) {
|
|
1943
|
+
const firstEntry = entries[0];
|
|
1944
|
+
if (firstEntry) {
|
|
1945
|
+
const sessionDurationMs = this.sessionDurationHours * 60 * 60 * 1e3;
|
|
1946
|
+
const blockStartTime = this.floorToHour(firstEntry.timestamp);
|
|
1947
|
+
const sessionEndTime = new Date(
|
|
1948
|
+
blockStartTime.getTime() + sessionDurationMs
|
|
1949
|
+
);
|
|
1950
|
+
timeRemaining = Math.max(
|
|
1951
|
+
0,
|
|
1952
|
+
Math.round((sessionEndTime.getTime() - now.getTime()) / (1e3 * 60))
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
let burnRate = null;
|
|
1957
|
+
let tokenBurnRate = null;
|
|
1958
|
+
if (entries.length >= 1 && (totalCost > 0 || totalTokens > 0)) {
|
|
1959
|
+
const timestamps = entries.map((entry) => entry.timestamp).sort((a, b) => a.getTime() - b.getTime());
|
|
1960
|
+
const firstEntry = timestamps[0];
|
|
1961
|
+
const lastEntry = timestamps[timestamps.length - 1];
|
|
1962
|
+
if (firstEntry && lastEntry) {
|
|
1963
|
+
const durationMinutes = (lastEntry.getTime() - firstEntry.getTime()) / (1e3 * 60);
|
|
1964
|
+
if (durationMinutes > 0) {
|
|
1965
|
+
if (totalCost > 0) {
|
|
1966
|
+
burnRate = totalCost / durationMinutes * 60;
|
|
1967
|
+
}
|
|
1968
|
+
if (totalTokens > 0) {
|
|
1969
|
+
tokenBurnRate = totalTokens / durationMinutes * 60;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1829
1974
|
debug(
|
|
1830
|
-
`Block segment: $${totalCost.toFixed(2)}, ${totalTokens} tokens, ${timeRemaining}m remaining`
|
|
1975
|
+
`Block segment: $${totalCost.toFixed(2)}, ${totalTokens} tokens, ${timeRemaining}m remaining, burn rate: ${burnRate ? "$" + burnRate.toFixed(2) + "/hr" : "N/A"}`
|
|
1831
1976
|
);
|
|
1832
1977
|
return {
|
|
1833
1978
|
cost: totalCost,
|
|
1834
1979
|
tokens: totalTokens,
|
|
1835
|
-
timeRemaining
|
|
1980
|
+
timeRemaining,
|
|
1981
|
+
burnRate,
|
|
1982
|
+
tokenBurnRate
|
|
1836
1983
|
};
|
|
1837
1984
|
} catch (error) {
|
|
1838
1985
|
debug("Error getting active block info:", error);
|
|
1839
|
-
return {
|
|
1986
|
+
return {
|
|
1987
|
+
cost: null,
|
|
1988
|
+
tokens: null,
|
|
1989
|
+
timeRemaining: null,
|
|
1990
|
+
burnRate: null,
|
|
1991
|
+
tokenBurnRate: null
|
|
1992
|
+
};
|
|
1840
1993
|
}
|
|
1841
1994
|
}
|
|
1842
1995
|
};
|
|
@@ -1848,10 +2001,6 @@ function formatDate(date) {
|
|
|
1848
2001
|
const day = String(date.getDate()).padStart(2, "0");
|
|
1849
2002
|
return `${year}-${month}-${day}`;
|
|
1850
2003
|
}
|
|
1851
|
-
function isToday(date) {
|
|
1852
|
-
const today = /* @__PURE__ */ new Date();
|
|
1853
|
-
return formatDate(date) === formatDate(today);
|
|
1854
|
-
}
|
|
1855
2004
|
function getTotalTokens(usage) {
|
|
1856
2005
|
return usage.inputTokens + usage.outputTokens + usage.cacheCreationInputTokens + usage.cacheReadInputTokens;
|
|
1857
2006
|
}
|
|
@@ -1872,13 +2021,13 @@ var TodayProvider = class {
|
|
|
1872
2021
|
cache = /* @__PURE__ */ new Map();
|
|
1873
2022
|
CACHE_TTL = 3e5;
|
|
1874
2023
|
async loadTodayEntries() {
|
|
1875
|
-
const
|
|
1876
|
-
|
|
1877
|
-
debug(
|
|
1878
|
-
|
|
1879
|
-
);
|
|
2024
|
+
const today = /* @__PURE__ */ new Date();
|
|
2025
|
+
const todayDateString = formatDate(today);
|
|
2026
|
+
debug(`Today segment: Loading entries for date ${todayDateString}`);
|
|
2027
|
+
const weekAgo = /* @__PURE__ */ new Date();
|
|
2028
|
+
weekAgo.setDate(weekAgo.getDate() - 7);
|
|
1880
2029
|
const fileFilter = (_filePath, modTime) => {
|
|
1881
|
-
return modTime >=
|
|
2030
|
+
return modTime >= weekAgo;
|
|
1882
2031
|
};
|
|
1883
2032
|
const parsedEntries = await loadEntriesFromProjects(
|
|
1884
2033
|
void 0,
|
|
@@ -1888,11 +2037,8 @@ var TodayProvider = class {
|
|
|
1888
2037
|
const todayEntries = [];
|
|
1889
2038
|
let entriesFound = 0;
|
|
1890
2039
|
for (const entry of parsedEntries) {
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
break;
|
|
1894
|
-
}
|
|
1895
|
-
if (entry.message?.usage && isToday(entry.timestamp)) {
|
|
2040
|
+
const entryDateString = formatDate(entry.timestamp);
|
|
2041
|
+
if (entryDateString === todayDateString && entry.message?.usage) {
|
|
1896
2042
|
const todayEntry = convertToTodayEntry(entry);
|
|
1897
2043
|
if (!todayEntry.costUSD && entry.raw) {
|
|
1898
2044
|
todayEntry.costUSD = await PricingService.calculateCostForEntry(
|
|
@@ -1903,7 +2049,9 @@ var TodayProvider = class {
|
|
|
1903
2049
|
entriesFound++;
|
|
1904
2050
|
}
|
|
1905
2051
|
}
|
|
1906
|
-
debug(
|
|
2052
|
+
debug(
|
|
2053
|
+
`Today segment: Found ${entriesFound} entries for today (${todayDateString})`
|
|
2054
|
+
);
|
|
1907
2055
|
return todayEntries;
|
|
1908
2056
|
}
|
|
1909
2057
|
async getTodayEntries() {
|
|
@@ -2131,12 +2279,13 @@ var PowerlineRenderer = class {
|
|
|
2131
2279
|
return this.segmentRenderer.renderMetrics(
|
|
2132
2280
|
metricsInfo,
|
|
2133
2281
|
colors,
|
|
2282
|
+
blockInfo,
|
|
2134
2283
|
metricsConfig
|
|
2135
2284
|
);
|
|
2136
2285
|
case "block":
|
|
2137
2286
|
if (!blockInfo) return null;
|
|
2138
|
-
const
|
|
2139
|
-
return this.segmentRenderer.renderBlock(blockInfo, colors,
|
|
2287
|
+
const blockConfig = segment.config;
|
|
2288
|
+
return this.segmentRenderer.renderBlock(blockInfo, colors, blockConfig);
|
|
2140
2289
|
case "today":
|
|
2141
2290
|
if (!todayInfo) return null;
|
|
2142
2291
|
const todayType = segment.config?.type || "cost";
|
|
@@ -2282,7 +2431,7 @@ var DEFAULT_CONFIG = {
|
|
|
2282
2431
|
model: { enabled: true },
|
|
2283
2432
|
session: { enabled: true, type: "tokens" },
|
|
2284
2433
|
today: { enabled: false, type: "cost" },
|
|
2285
|
-
block: { enabled: true, type: "cost" },
|
|
2434
|
+
block: { enabled: true, type: "cost", burnType: "cost" },
|
|
2286
2435
|
tmux: { enabled: false },
|
|
2287
2436
|
context: { enabled: true },
|
|
2288
2437
|
metrics: {
|
|
@@ -2290,9 +2439,7 @@ var DEFAULT_CONFIG = {
|
|
|
2290
2439
|
showResponseTime: true,
|
|
2291
2440
|
showLastResponseTime: false,
|
|
2292
2441
|
showDuration: true,
|
|
2293
|
-
showMessageCount: true
|
|
2294
|
-
showCostBurnRate: false,
|
|
2295
|
-
showTokenBurnRate: false
|
|
2442
|
+
showMessageCount: true
|
|
2296
2443
|
}
|
|
2297
2444
|
}
|
|
2298
2445
|
}
|