ccusage 20.0.10 → 20.0.12
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 +27 -19
- package/package.json +16 -9
- package/src/cli.js +218 -0
- package/dist/cli.js +0 -3
package/README.md
CHANGED
|
@@ -23,6 +23,27 @@
|
|
|
23
23
|
|
|
24
24
|
> Analyze coding (agent) CLI token usage and costs from local data.
|
|
25
25
|
|
|
26
|
+
## Major Sponsors
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<a href="https://coderabbit.link/ryoppippi">
|
|
30
|
+
<picture>
|
|
31
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/ccusage/ccusage@main/docs/public/coderabbit-logo-dark.svg">
|
|
32
|
+
<img src="https://cdn.jsdelivr.net/gh/ccusage/ccusage@main/docs/public/coderabbit-logo.svg" alt="CodeRabbit" width="320">
|
|
33
|
+
</picture>
|
|
34
|
+
</a>
|
|
35
|
+
|
|
36
|
+
<a href="https://blacksmith.sh">
|
|
37
|
+
<img src="https://cdn.jsdelivr.net/gh/ccusage/ccusage@main/docs/public/blacksmith.png" alt="Blacksmith" width="320">
|
|
38
|
+
</a>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx ccusage@latest
|
|
45
|
+
```
|
|
46
|
+
|
|
26
47
|
## Supported Sources
|
|
27
48
|
|
|
28
49
|
ccusage reads local usage data from coding agent CLIs and turns it into daily, weekly, monthly, and session reports.
|
|
@@ -49,21 +70,21 @@ Use `ccusage daily`, `ccusage weekly`, `ccusage monthly`, or `ccusage session` t
|
|
|
49
70
|
|
|
50
71
|
## Installation
|
|
51
72
|
|
|
52
|
-
###
|
|
73
|
+
### Package Runners
|
|
53
74
|
|
|
54
75
|
You can run ccusage directly without a global installation:
|
|
55
76
|
|
|
56
77
|
```bash
|
|
57
|
-
#
|
|
58
|
-
|
|
78
|
+
# npm
|
|
79
|
+
npx ccusage@latest
|
|
59
80
|
|
|
60
81
|
# Nix
|
|
61
82
|
nix run github:ccusage/ccusage -- daily
|
|
62
83
|
|
|
63
84
|
# Alternative package runners
|
|
85
|
+
bunx ccusage
|
|
64
86
|
pnpm dlx ccusage
|
|
65
87
|
pnpx ccusage
|
|
66
|
-
npx ccusage@latest
|
|
67
88
|
|
|
68
89
|
# PR preview builds
|
|
69
90
|
bunx -p https://pkg.pr.new/ccusage/ccusage@<pr-number> ccusage --offline
|
|
@@ -166,7 +187,7 @@ cd ccusage
|
|
|
166
187
|
direnv allow
|
|
167
188
|
```
|
|
168
189
|
|
|
169
|
-
The dev shell provides the pinned `pnpm`, Rust toolchain, GitHub CLI, git hooks, generated local agent skills, and project utilities from `flake.nix`.
|
|
190
|
+
The dev shell provides the pinned `pnpm`, Rust toolchain, GitHub CLI, git hooks, generated local agent skills, package tooling, and project utilities from `flake.nix`. Run `pnpm install --frozen-lockfile` only when a task needs workspace `node_modules`.
|
|
170
191
|
|
|
171
192
|
Run project tasks with `just` from inside the Nix environment (`just --list` shows every recipe):
|
|
172
193
|
|
|
@@ -198,20 +219,7 @@ The scheduled `update pricing` workflow runs the same update and validation, the
|
|
|
198
219
|
|
|
199
220
|
</details>
|
|
200
221
|
|
|
201
|
-
## Sponsors
|
|
202
|
-
|
|
203
|
-
<p align="center">
|
|
204
|
-
<strong>Sponsored by</strong>
|
|
205
|
-
</p>
|
|
206
|
-
|
|
207
|
-
<p align="center">
|
|
208
|
-
<a href="https://coderabbit.link/ryoppippi">
|
|
209
|
-
<picture>
|
|
210
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/ccusage/ccusage@main/docs/public/coderabbit-logo-dark.svg">
|
|
211
|
-
<img src="https://cdn.jsdelivr.net/gh/ccusage/ccusage@main/docs/public/coderabbit-logo.svg" alt="CodeRabbit" width="320">
|
|
212
|
-
</picture>
|
|
213
|
-
</a>
|
|
214
|
-
</p>
|
|
222
|
+
## GitHub Sponsors
|
|
215
223
|
|
|
216
224
|
<p align="center">
|
|
217
225
|
<a href="https://github.com/sponsors/ryoppippi">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccusage",
|
|
3
|
-
"version": "20.0.
|
|
3
|
+
"version": "20.0.12",
|
|
4
4
|
"description": "Analyze coding (agent) CLI token usage and costs from local data",
|
|
5
5
|
"homepage": "https://github.com/ccusage/ccusage#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -15,19 +15,26 @@
|
|
|
15
15
|
},
|
|
16
16
|
"funding": "https://github.com/sponsors/ryoppippi",
|
|
17
17
|
"bin": {
|
|
18
|
-
"ccusage": "./
|
|
18
|
+
"ccusage": "./src/cli.js"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"config-schema.json",
|
|
22
|
-
"
|
|
22
|
+
"src/cli.js"
|
|
23
23
|
],
|
|
24
24
|
"type": "module",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^24.10.1",
|
|
27
|
+
"publint": "^0.3.12"
|
|
28
|
+
},
|
|
25
29
|
"optionalDependencies": {
|
|
26
|
-
"@ccusage/ccusage-darwin-arm64": "20.0.
|
|
27
|
-
"@ccusage/ccusage-darwin-x64": "20.0.
|
|
28
|
-
"@ccusage/ccusage-linux-arm64": "20.0.
|
|
29
|
-
"@ccusage/ccusage-
|
|
30
|
-
"@ccusage/ccusage-
|
|
31
|
-
"@ccusage/ccusage-win32-
|
|
30
|
+
"@ccusage/ccusage-darwin-arm64": "20.0.12",
|
|
31
|
+
"@ccusage/ccusage-darwin-x64": "20.0.12",
|
|
32
|
+
"@ccusage/ccusage-linux-arm64": "20.0.12",
|
|
33
|
+
"@ccusage/ccusage-win32-arm64": "20.0.12",
|
|
34
|
+
"@ccusage/ccusage-linux-x64": "20.0.12",
|
|
35
|
+
"@ccusage/ccusage-win32-x64": "20.0.12"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "scripts/ensure-native-binary.nu && publint"
|
|
32
39
|
}
|
|
33
40
|
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-check
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { chmodSync, realpathSync, statSync } from 'node:fs';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {{ args: string[]; command: string } | { errorMessage: string }} CliRuntime
|
|
13
|
+
* @typedef {{ mode: number }} FileMode
|
|
14
|
+
* @typedef {{ error?: Error; signal?: NodeJS.Signals | null; status: number | null }} NativeSpawnResult
|
|
15
|
+
* @typedef {(command: string, args: string[]) => Promise<NativeSpawnResult>} NativeSpawner
|
|
16
|
+
* @typedef {{ argvEntry?: string; moduleUrl: string; realpathPath?: (path: string) => string }} MainModuleOptions
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} [platform]
|
|
21
|
+
* @param {string} [arch]
|
|
22
|
+
* @returns {string | undefined}
|
|
23
|
+
*/
|
|
24
|
+
function getNativePackageName(platform = process.platform, arch = process.arch) {
|
|
25
|
+
if (platform === 'darwin') {
|
|
26
|
+
if (arch === 'arm64') {
|
|
27
|
+
return '@ccusage/ccusage-darwin-arm64';
|
|
28
|
+
}
|
|
29
|
+
if (arch === 'x64') {
|
|
30
|
+
return '@ccusage/ccusage-darwin-x64';
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (platform === 'linux') {
|
|
36
|
+
if (arch === 'arm64') {
|
|
37
|
+
return '@ccusage/ccusage-linux-arm64';
|
|
38
|
+
}
|
|
39
|
+
if (arch === 'x64') {
|
|
40
|
+
return '@ccusage/ccusage-linux-x64';
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (platform === 'win32') {
|
|
46
|
+
if (arch === 'arm64') {
|
|
47
|
+
return '@ccusage/ccusage-win32-arm64';
|
|
48
|
+
}
|
|
49
|
+
if (arch === 'x64') {
|
|
50
|
+
return '@ccusage/ccusage-win32-x64';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {string} [platform]
|
|
59
|
+
* @returns {string}
|
|
60
|
+
*/
|
|
61
|
+
function getNativeBinarySubpath(platform = process.platform) {
|
|
62
|
+
return platform === 'win32' ? 'bin/ccusage.exe' : 'bin/ccusage';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {{ arch?: string; platform?: string; resolvePath?: (id: string) => string }} [options]
|
|
67
|
+
* @returns {string | undefined}
|
|
68
|
+
*/
|
|
69
|
+
function resolveNativeBinary({
|
|
70
|
+
arch = process.arch,
|
|
71
|
+
platform = process.platform,
|
|
72
|
+
resolvePath = (id) => require.resolve(id),
|
|
73
|
+
} = {}) {
|
|
74
|
+
const packageName = getNativePackageName(platform, arch);
|
|
75
|
+
if (packageName == null) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
return resolvePath(`${packageName}/${getNativeBinarySubpath(platform)}`);
|
|
81
|
+
} catch {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {{ arch?: string; argv: string[]; nativeBinaryPath?: string | null; platform?: string }} options
|
|
88
|
+
* @returns {CliRuntime}
|
|
89
|
+
*/
|
|
90
|
+
function resolveCliRuntime({
|
|
91
|
+
argv,
|
|
92
|
+
arch = process.arch,
|
|
93
|
+
nativeBinaryPath = resolveNativeBinary(),
|
|
94
|
+
platform = process.platform,
|
|
95
|
+
}) {
|
|
96
|
+
if (nativeBinaryPath != null) {
|
|
97
|
+
return {
|
|
98
|
+
args: argv,
|
|
99
|
+
command: nativeBinaryPath,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
errorMessage: `ccusage native binary is not available for ${platform}-${arch}. Reinstall ccusage so optional native dependencies are installed.\n`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {unknown} error
|
|
110
|
+
* @returns {string}
|
|
111
|
+
*/
|
|
112
|
+
function errorMessage(error) {
|
|
113
|
+
return error instanceof Error ? error.message : String(error);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @param {{ binaryPath: string; chmodPath?: (path: string, mode: number) => void; platform?: string; statPath?: (path: string) => FileMode }} options
|
|
118
|
+
* @returns {string | undefined}
|
|
119
|
+
*/
|
|
120
|
+
function ensureNativeBinaryExecutable({
|
|
121
|
+
binaryPath,
|
|
122
|
+
chmodPath = chmodSync,
|
|
123
|
+
platform = process.platform,
|
|
124
|
+
statPath = statSync,
|
|
125
|
+
}) {
|
|
126
|
+
if (platform === 'win32') {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const mode = statPath(binaryPath).mode;
|
|
132
|
+
if ((mode & 0o111) !== 0) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
chmodPath(binaryPath, 0o755);
|
|
136
|
+
return undefined;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
return `ccusage native binary is not executable: ${errorMessage(error)}\n`;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @param {MainModuleOptions} options
|
|
144
|
+
* @returns {boolean}
|
|
145
|
+
*/
|
|
146
|
+
function isMainModule({ argvEntry = process.argv[1], moduleUrl, realpathPath = realpathSync }) {
|
|
147
|
+
if (argvEntry == null) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const modulePath = fileURLToPath(moduleUrl);
|
|
152
|
+
try {
|
|
153
|
+
return realpathPath(modulePath) === realpathPath(argvEntry);
|
|
154
|
+
} catch {
|
|
155
|
+
return modulePath === argvEntry;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @returns {NativeSpawner}
|
|
161
|
+
*/
|
|
162
|
+
function createNativeSpawner() {
|
|
163
|
+
return async (command, args) =>
|
|
164
|
+
new Promise((resolve) => {
|
|
165
|
+
const child = spawn(command, args, { stdio: 'inherit' });
|
|
166
|
+
child.on('error', (error) => {
|
|
167
|
+
resolve({
|
|
168
|
+
error,
|
|
169
|
+
signal: null,
|
|
170
|
+
status: null,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
child.on('exit', (status, signal) => {
|
|
174
|
+
resolve({
|
|
175
|
+
signal,
|
|
176
|
+
status,
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @param {string[]} argv
|
|
184
|
+
* @param {NativeSpawner} [spawnNative]
|
|
185
|
+
* @returns {Promise<number>}
|
|
186
|
+
*/
|
|
187
|
+
async function runCli(argv, spawnNative = createNativeSpawner()) {
|
|
188
|
+
const runtime = resolveCliRuntime({ argv });
|
|
189
|
+
if ('errorMessage' in runtime) {
|
|
190
|
+
process.stderr.write(runtime.errorMessage);
|
|
191
|
+
return 1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const executableError = ensureNativeBinaryExecutable({
|
|
195
|
+
binaryPath: runtime.command,
|
|
196
|
+
});
|
|
197
|
+
if (executableError != null) {
|
|
198
|
+
process.stderr.write(executableError);
|
|
199
|
+
return 1;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const result = await spawnNative(runtime.command, runtime.args);
|
|
203
|
+
if (result.error != null) {
|
|
204
|
+
process.stderr.write(`${result.error.message}\n`);
|
|
205
|
+
return 1;
|
|
206
|
+
}
|
|
207
|
+
if (result.signal != null) {
|
|
208
|
+
process.kill(process.pid, result.signal);
|
|
209
|
+
return 1;
|
|
210
|
+
}
|
|
211
|
+
return result.status ?? 1;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (isMainModule({ moduleUrl: import.meta.url })) {
|
|
215
|
+
process.exitCode = await runCli(process.argv.slice(2));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export { ensureNativeBinaryExecutable, isMainModule, resolveCliRuntime, resolveNativeBinary };
|
package/dist/cli.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{createRequire as e}from"node:module";import{spawn as t}from"node:child_process";import{chmodSync as n,statSync as r}from"node:fs";import i from"node:process";const a=e(import.meta.url);function o(e=i.platform,t=i.arch){if(e===`darwin`)return t===`arm64`?`@ccusage/ccusage-darwin-arm64`:t===`x64`?`@ccusage/ccusage-darwin-x64`:void 0;if(e===`linux`)return t===`arm64`?`@ccusage/ccusage-linux-arm64`:t===`x64`?`@ccusage/ccusage-linux-x64`:void 0;if(e===`win32`){if(t===`arm64`)return`@ccusage/ccusage-win32-arm64`;if(t===`x64`)return`@ccusage/ccusage-win32-x64`}}function s(e=i.platform){return e===`win32`?`bin/ccusage.exe`:`bin/ccusage`}function c({arch:e=i.arch,platform:t=i.platform,resolvePath:n=e=>a.resolve(e)}={}){let r=o(t,e);if(r!=null)try{return n(`${r}/${s(t)}`)}catch{return}}function l({argv:e,arch:t=i.arch,nativeBinaryPath:n=c(),platform:r=i.platform}){return n==null?{errorMessage:`ccusage native binary is not available for ${r}-${t}. Reinstall ccusage so optional native dependencies are installed.\n`}:{args:e,command:n}}function u(e){return e instanceof Error?e.message:String(e)}function d({binaryPath:e,chmodPath:t=n,platform:a=i.platform,statPath:o=r}){if(a!==`win32`)try{if(o(e).mode&73)return;t(e,493);return}catch(e){return`ccusage native binary is not executable: ${u(e)}\n`}}function f(){return async(e,n)=>new Promise(r=>{let i=t(e,n,{stdio:`inherit`});i.on(`error`,e=>{r({error:e,signal:null,status:null})}),i.on(`exit`,(e,t)=>{r({signal:t,status:e})})})}async function p(e,t=f()){let n=l({argv:e});if(`errorMessage`in n)return i.stderr.write(n.errorMessage),1;let r=d({binaryPath:n.command});if(r!=null)return i.stderr.write(r),1;let a=await t(n.command,n.args);return a.error==null?a.signal==null?a.status??1:(i.kill(i.pid,a.signal),1):(i.stderr.write(`${a.error.message}\n`),1)}i.exitCode=await p(i.argv.slice(2));export{};
|
|
3
|
-
//# sourceMappingURL=cli.js.map
|