tledger 0.1.2 → 0.1.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/LICENSE +21 -0
- package/README.md +36 -3
- package/bin/token-ledger.mjs +44 -15
- package/package.json +3 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jskoiz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -5,17 +5,31 @@ usage. It ranks projects, shows model and cache mix, and adds reset-cycle
|
|
|
5
5
|
context without sending usage data anywhere. Codex Auto Review is shown
|
|
6
6
|
separately with its token total, distinct-turn share, and cached-input share.
|
|
7
7
|
|
|
8
|
+
Token Ledger reads Codex history stored on the computer where it runs. It does
|
|
9
|
+
not sign in, fetch account-wide usage, or combine activity from other machines.
|
|
10
|
+
|
|
8
11
|

|
|
9
12
|
|
|
10
13
|
_The screenshot is generated from an intentionally synthetic fixture._
|
|
11
14
|
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
Token Ledger requires Node.js 22.13 or newer and npm. Install a supported LTS
|
|
18
|
+
release from [nodejs.org](https://nodejs.org/en/download) if either command is
|
|
19
|
+
missing, then confirm the versions in a new terminal:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
node --version
|
|
23
|
+
npm --version
|
|
24
|
+
```
|
|
25
|
+
|
|
12
26
|
## Install
|
|
13
27
|
|
|
14
|
-
Token Ledger
|
|
15
|
-
dependencies.
|
|
28
|
+
Token Ledger has no runtime npm dependencies and runs no installation script.
|
|
16
29
|
|
|
17
30
|
```bash
|
|
18
31
|
npm install --global tledger
|
|
32
|
+
tledger --help
|
|
19
33
|
```
|
|
20
34
|
|
|
21
35
|
## Use
|
|
@@ -30,7 +44,8 @@ tledger week 2026-08-05
|
|
|
30
44
|
|
|
31
45
|
The local timezone and top 10 projects are selected automatically. The default
|
|
32
46
|
view is interactive in a terminal; use arrow keys or `j`/`k` to move and `q` or
|
|
33
|
-
Escape to exit.
|
|
47
|
+
Escape to exit. If the selected period is empty, Token Ledger reports the most
|
|
48
|
+
recent local activity date and prints the exact command for opening it.
|
|
34
49
|
|
|
35
50
|
Useful options:
|
|
36
51
|
|
|
@@ -51,6 +66,20 @@ Useful options:
|
|
|
51
66
|
--help Show complete CLI help
|
|
52
67
|
```
|
|
53
68
|
|
|
69
|
+
## Update or uninstall
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm install --global tledger@latest
|
|
73
|
+
npm uninstall --global tledger
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Uninstalling the npm package leaves the privacy-reduced cache at
|
|
77
|
+
`~/.token-ledger/token-ledger-snapshot.json`. Remove that directory separately
|
|
78
|
+
only when you also want the next installation to perform a completely fresh
|
|
79
|
+
scan.
|
|
80
|
+
|
|
81
|
+
## Local data and privacy
|
|
82
|
+
|
|
54
83
|
By default, Token Ledger reads `CODEX_HOME` or `~/.codex` and keeps a
|
|
55
84
|
privacy-reduced cache at `~/.token-ledger/token-ledger-snapshot.json`. It checks
|
|
56
85
|
source freshness automatically. Fresh scans use a bounded pool of up to four
|
|
@@ -68,3 +97,7 @@ npm test
|
|
|
68
97
|
npm run demo
|
|
69
98
|
npm pack --dry-run
|
|
70
99
|
```
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
[MIT](LICENSE)
|
package/bin/token-ledger.mjs
CHANGED
|
@@ -382,6 +382,48 @@ function sourceLabel(snapshotPath, snapshot) {
|
|
|
382
382
|
return `${cleanLabel(basename(snapshotPath), "snapshot")} · captured ${generated}`;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
+
function latestActivityDateString(snapshot, timeZone) {
|
|
386
|
+
let latestTimestamp = Number.NEGATIVE_INFINITY;
|
|
387
|
+
for (const event of snapshot.events ?? []) {
|
|
388
|
+
const timestamp = new Date(event.timestamp).getTime();
|
|
389
|
+
if (Number.isFinite(timestamp) && timestamp > latestTimestamp) {
|
|
390
|
+
latestTimestamp = timestamp;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (!Number.isFinite(latestTimestamp)) return null;
|
|
394
|
+
return dateStringFromParts(numericDateParts({
|
|
395
|
+
value: new Date(latestTimestamp),
|
|
396
|
+
timeZone,
|
|
397
|
+
}));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function displayCalendarDate(dateString) {
|
|
401
|
+
const [year, month, day] = dateString.split("-").map(Number);
|
|
402
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
403
|
+
month: "long",
|
|
404
|
+
day: "numeric",
|
|
405
|
+
year: "numeric",
|
|
406
|
+
timeZone: "UTC",
|
|
407
|
+
}).format(new Date(Date.UTC(year, month - 1, day)));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function emptyState(options, snapshot, bounds) {
|
|
411
|
+
const rangeDescription = options.range === "week"
|
|
412
|
+
? `${bounds.startDateString} through ${bounds.endDateString}`
|
|
413
|
+
: bounds.dateString;
|
|
414
|
+
const lines = [
|
|
415
|
+
`No model-call events found for ${rangeDescription} (${bounds.timeZone}).`,
|
|
416
|
+
"Token Ledger reads only Codex history stored on this computer.",
|
|
417
|
+
];
|
|
418
|
+
const latestDate = latestActivityDateString(snapshot, bounds.timeZone);
|
|
419
|
+
if (latestDate) {
|
|
420
|
+
lines.push(`Latest local activity: ${displayCalendarDate(latestDate)}.`);
|
|
421
|
+
lines.push(`Try: tledger ${options.range} ${latestDate}`);
|
|
422
|
+
}
|
|
423
|
+
lines.push(`Source: ${sourceLabel(options.input, snapshot)}`);
|
|
424
|
+
return lines.join("\n");
|
|
425
|
+
}
|
|
426
|
+
|
|
385
427
|
async function readSnapshot(snapshotPath) {
|
|
386
428
|
let parsed;
|
|
387
429
|
try {
|
|
@@ -489,13 +531,7 @@ export async function run(options) {
|
|
|
489
531
|
const snapshot = await loadSnapshot(options);
|
|
490
532
|
const events = filterDayEvents(snapshot, bounds);
|
|
491
533
|
if (events.length === 0) {
|
|
492
|
-
|
|
493
|
-
? `${bounds.startDateString} through ${bounds.endDateString}`
|
|
494
|
-
: bounds.dateString;
|
|
495
|
-
return [
|
|
496
|
-
`No model-call events found for ${rangeDescription} (${bounds.timeZone}).`,
|
|
497
|
-
`Source: ${sourceLabel(options.input, snapshot)}`,
|
|
498
|
-
].join("\n");
|
|
534
|
+
return emptyState(options, snapshot, bounds);
|
|
499
535
|
}
|
|
500
536
|
const allRows = aggregateProjects(snapshot, events, options);
|
|
501
537
|
const rows = allRows.slice(0, options.top);
|
|
@@ -519,14 +555,7 @@ async function runInteractive(options) {
|
|
|
519
555
|
const snapshot = await loadSnapshot(options);
|
|
520
556
|
const events = filterDayEvents(snapshot, bounds);
|
|
521
557
|
if (events.length === 0) {
|
|
522
|
-
|
|
523
|
-
? `${bounds.startDateString} through ${bounds.endDateString}`
|
|
524
|
-
: bounds.dateString;
|
|
525
|
-
process.stdout.write([
|
|
526
|
-
`No model-call events found for ${rangeDescription} (${bounds.timeZone}).`,
|
|
527
|
-
`Source: ${sourceLabel(options.input, snapshot)}`,
|
|
528
|
-
"",
|
|
529
|
-
].join("\n"));
|
|
558
|
+
process.stdout.write(`${emptyState(options, snapshot, bounds)}\n`);
|
|
530
559
|
return;
|
|
531
560
|
}
|
|
532
561
|
const allRows = aggregateProjects(snapshot, events, options);
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tledger",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A local-only terminal dashboard for Codex token usage",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"codex",
|
|
7
8
|
"cli",
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
"files": [
|
|
25
26
|
"bin/",
|
|
26
27
|
"lib/",
|
|
28
|
+
"LICENSE",
|
|
27
29
|
"README.md"
|
|
28
30
|
],
|
|
29
31
|
"bin": {
|