tokenometer 0.0.1
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 +55 -0
- package/dist/args.d.ts +14 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +112 -0
- package/dist/args.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/render.d.ts +4 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +46 -0
- package/dist/render.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# tokenometer
|
|
2
|
+
|
|
3
|
+
> Empirical token-cost benchmarking for LLM prompts. Tells you what your prompt actually costs across Claude, GPT-4o, and Gemini, in every format.
|
|
4
|
+
|
|
5
|
+
[**Live playground: tokenometer.vercel.app**](https://tokenometer.vercel.app) · [Source](https://github.com/faraa2m/tokenometer) · MIT
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx tokenometer ./prompt.md --model claude-opus-4-7,gpt-4o
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
model format tokens est. cost tokenizer
|
|
13
|
+
--------------- -------- ------ --------- --------------
|
|
14
|
+
claude-opus-4-7 json ~78 $0.001170 cl100k_base
|
|
15
|
+
claude-opus-4-7 yaml ~84 $0.001260 cl100k_base
|
|
16
|
+
gpt-4o json 77 $0.000192 o200k_base
|
|
17
|
+
gpt-4o yaml 83 $0.000208 o200k_base
|
|
18
|
+
|
|
19
|
+
Cheapest: gpt-4o as json ($0.000192)
|
|
20
|
+
Priciest: claude-opus-4-7 as yaml ($0.001260, 6.74x more)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A leading `~` marks an approximate count (offline mode for Claude / Gemini, since neither vendor publishes a public tokenizer).
|
|
24
|
+
|
|
25
|
+
## Empirical mode
|
|
26
|
+
|
|
27
|
+
For exact, vendor-billed counts on Claude and Gemini, set the right env var and pass `--empirical`. The tool calls the providers' free `countTokens` endpoints — no charge.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ANTHROPIC_API_KEY=… GOOGLE_API_KEY=… \
|
|
31
|
+
npx tokenometer ./prompt.md --empirical
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Why not just `tiktoken`?
|
|
35
|
+
|
|
36
|
+
`tiktoken`'s `cl100k_base` (the encoding most "Claude tokenizer" libraries fall back on) **under-counts Opus 4.7 by a median of +62%** across a 10-prompt benchmark. Sonnet 4.6 and Haiku 4.5 are closer (~17%). Format choice is a wash. Model choice swings cost by 12×. See [README](https://github.com/faraa2m/tokenometer#findings-anthropic-n150-cells-across-10-prompt-shapes) for the dataset findings.
|
|
37
|
+
|
|
38
|
+
## Flags
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
tokenometer <file> [options]
|
|
42
|
+
echo "prompt" | tokenometer - [options]
|
|
43
|
+
|
|
44
|
+
--model <id[,id…]> Default: claude-opus-4-7
|
|
45
|
+
--format <fmt[,fmt…]> Default: all (json,yaml,xml,markdown,text)
|
|
46
|
+
--empirical Use provider countTokens APIs (free, exact)
|
|
47
|
+
--max-spend <usd> Hard ceiling for empirical mode (default 0.05)
|
|
48
|
+
--offline Force offline (overrides --empirical)
|
|
49
|
+
-h, --help
|
|
50
|
+
-v, --version
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
MIT
|
package/dist/args.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Format } from '@tokenometer/core';
|
|
2
|
+
export interface ParsedArgs {
|
|
3
|
+
empirical: boolean;
|
|
4
|
+
formats: Format[];
|
|
5
|
+
help: boolean;
|
|
6
|
+
inputPaths: string[];
|
|
7
|
+
maxSpend: number;
|
|
8
|
+
modelIds: string[];
|
|
9
|
+
offline: boolean;
|
|
10
|
+
version: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const HELP_TEXT: string;
|
|
13
|
+
export declare const parseArgs: (argv: readonly string[]) => ParsedArgs;
|
|
14
|
+
//# sourceMappingURL=args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,SAAS,QAsBrB,CAAC;AAKF,eAAO,MAAM,SAAS,GAAI,MAAM,SAAS,MAAM,EAAE,KAAG,UAmFnD,CAAC"}
|
package/dist/args.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { KNOWN_MODELS, allFormats, isFormat } from '@tokenometer/core';
|
|
2
|
+
export const HELP_TEXT = `tokenometer — empirical token-cost benchmarking for LLM prompts
|
|
3
|
+
|
|
4
|
+
USAGE
|
|
5
|
+
tokenometer <file> [options]
|
|
6
|
+
echo "prompt" | tokenometer - [options]
|
|
7
|
+
|
|
8
|
+
OPTIONS
|
|
9
|
+
--model <id[,id...]> Comma-separated model ids (default: claude-opus-4-7).
|
|
10
|
+
Known: ${KNOWN_MODELS.join(', ')}
|
|
11
|
+
--format <fmt[,fmt...]> Comma-separated formats (default: all).
|
|
12
|
+
Known: ${allFormats().join(', ')}
|
|
13
|
+
--empirical Run sample API calls and report real charges.
|
|
14
|
+
Requires the matching <PROVIDER>_API_KEY env var.
|
|
15
|
+
--max-spend <usd> Hard ceiling for empirical mode (default: 0.05).
|
|
16
|
+
--offline Force offline mode (overrides --empirical).
|
|
17
|
+
-h, --help Show this help.
|
|
18
|
+
-v, --version Show CLI version.
|
|
19
|
+
|
|
20
|
+
EXAMPLES
|
|
21
|
+
tokenometer ./prompt.md
|
|
22
|
+
tokenometer ./prompt.md --model claude-opus-4-7,gpt-4o
|
|
23
|
+
tokenometer ./prompt.md --format yaml,json --empirical --max-spend 0.01
|
|
24
|
+
`;
|
|
25
|
+
const DEFAULT_MODELS = ['claude-opus-4-7'];
|
|
26
|
+
const DEFAULT_MAX_SPEND_USD = 0.05;
|
|
27
|
+
export const parseArgs = (argv) => {
|
|
28
|
+
const result = {
|
|
29
|
+
empirical: false,
|
|
30
|
+
formats: [...allFormats()],
|
|
31
|
+
help: false,
|
|
32
|
+
inputPaths: [],
|
|
33
|
+
maxSpend: DEFAULT_MAX_SPEND_USD,
|
|
34
|
+
modelIds: [...DEFAULT_MODELS],
|
|
35
|
+
offline: false,
|
|
36
|
+
version: false,
|
|
37
|
+
};
|
|
38
|
+
let modelsSet = false;
|
|
39
|
+
let formatsSet = false;
|
|
40
|
+
for (let i = 0; i < argv.length; i++) {
|
|
41
|
+
const arg = argv[i];
|
|
42
|
+
if (!arg)
|
|
43
|
+
continue;
|
|
44
|
+
if (arg === '-h' || arg === '--help') {
|
|
45
|
+
result.help = true;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (arg === '-v' || arg === '--version') {
|
|
49
|
+
result.version = true;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (arg === '--empirical') {
|
|
53
|
+
result.empirical = true;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (arg === '--offline') {
|
|
57
|
+
result.offline = true;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (arg === '--model') {
|
|
61
|
+
const next = argv[++i];
|
|
62
|
+
if (!next)
|
|
63
|
+
throw new Error('--model requires a value');
|
|
64
|
+
result.modelIds = next
|
|
65
|
+
.split(',')
|
|
66
|
+
.map((s) => s.trim())
|
|
67
|
+
.filter(Boolean);
|
|
68
|
+
modelsSet = true;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (arg === '--format') {
|
|
72
|
+
const next = argv[++i];
|
|
73
|
+
if (!next)
|
|
74
|
+
throw new Error('--format requires a value');
|
|
75
|
+
const formats = next
|
|
76
|
+
.split(',')
|
|
77
|
+
.map((s) => s.trim())
|
|
78
|
+
.filter(Boolean);
|
|
79
|
+
for (const fmt of formats) {
|
|
80
|
+
if (!isFormat(fmt)) {
|
|
81
|
+
throw new Error(`Unknown format "${fmt}". Known: ${allFormats().join(', ')}.`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
result.formats = formats;
|
|
85
|
+
formatsSet = true;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (arg === '--max-spend') {
|
|
89
|
+
const next = argv[++i];
|
|
90
|
+
if (!next)
|
|
91
|
+
throw new Error('--max-spend requires a value');
|
|
92
|
+
const parsed = Number.parseFloat(next);
|
|
93
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
94
|
+
throw new Error(`--max-spend must be a positive number, got "${next}".`);
|
|
95
|
+
}
|
|
96
|
+
result.maxSpend = parsed;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (arg.startsWith('--')) {
|
|
100
|
+
throw new Error(`Unknown flag: ${arg}`);
|
|
101
|
+
}
|
|
102
|
+
result.inputPaths.push(arg);
|
|
103
|
+
}
|
|
104
|
+
if (!modelsSet && result.modelIds.length === 0) {
|
|
105
|
+
result.modelIds = [...DEFAULT_MODELS];
|
|
106
|
+
}
|
|
107
|
+
if (!formatsSet && result.formats.length === 0) {
|
|
108
|
+
result.formats = [...allFormats()];
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=args.js.map
|
package/dist/args.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAkCA,eAAO,MAAM,IAAI,GAAU,MAAM,SAAS,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAsDlE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { tokenizeMatrix, tokenizeMatrixEmpirical } from '@tokenometer/core';
|
|
4
|
+
import { HELP_TEXT, parseArgs } from './args.js';
|
|
5
|
+
import { renderSummary, renderTable } from './render.js';
|
|
6
|
+
const VERSION = '0.0.1';
|
|
7
|
+
const readEnv = () => {
|
|
8
|
+
const env = {};
|
|
9
|
+
const { ANTHROPIC_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY } = process.env;
|
|
10
|
+
if (ANTHROPIC_API_KEY)
|
|
11
|
+
env.anthropicApiKey = ANTHROPIC_API_KEY;
|
|
12
|
+
const googleKey = GOOGLE_API_KEY ?? GEMINI_API_KEY;
|
|
13
|
+
if (googleKey)
|
|
14
|
+
env.googleApiKey = googleKey;
|
|
15
|
+
return env;
|
|
16
|
+
};
|
|
17
|
+
const readStdin = async () => {
|
|
18
|
+
const chunks = [];
|
|
19
|
+
for await (const chunk of process.stdin) {
|
|
20
|
+
chunks.push(chunk);
|
|
21
|
+
}
|
|
22
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
23
|
+
};
|
|
24
|
+
const readPrompt = async (paths) => {
|
|
25
|
+
if (paths.length === 0 || paths[0] === '-') {
|
|
26
|
+
return readStdin();
|
|
27
|
+
}
|
|
28
|
+
const contents = await Promise.all(paths.map((p) => readFile(p, 'utf8')));
|
|
29
|
+
return contents.join('\n');
|
|
30
|
+
};
|
|
31
|
+
export const main = async (argv) => {
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = parseArgs(argv);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
process.stderr.write(`${err.message}\n\n${HELP_TEXT}`);
|
|
38
|
+
return 2;
|
|
39
|
+
}
|
|
40
|
+
if (parsed.help) {
|
|
41
|
+
process.stdout.write(HELP_TEXT);
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
if (parsed.version) {
|
|
45
|
+
process.stdout.write(`tokenometer ${VERSION}\n`);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
let prompt;
|
|
49
|
+
try {
|
|
50
|
+
prompt = await readPrompt(parsed.inputPaths);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
process.stderr.write(`Failed to read input: ${err.message}\n`);
|
|
54
|
+
return 1;
|
|
55
|
+
}
|
|
56
|
+
if (!prompt.trim()) {
|
|
57
|
+
process.stderr.write('Empty prompt — nothing to measure.\n');
|
|
58
|
+
return 1;
|
|
59
|
+
}
|
|
60
|
+
const useEmpirical = parsed.empirical && !parsed.offline;
|
|
61
|
+
const results = useEmpirical
|
|
62
|
+
? await tokenizeMatrixEmpirical({
|
|
63
|
+
env: readEnv(),
|
|
64
|
+
formats: parsed.formats,
|
|
65
|
+
modelIds: parsed.modelIds,
|
|
66
|
+
prompt,
|
|
67
|
+
})
|
|
68
|
+
: tokenizeMatrix({
|
|
69
|
+
formats: parsed.formats,
|
|
70
|
+
modelIds: parsed.modelIds,
|
|
71
|
+
prompt,
|
|
72
|
+
});
|
|
73
|
+
process.stdout.write(`${renderTable(results)}\n`);
|
|
74
|
+
const summary = renderSummary(results);
|
|
75
|
+
if (summary)
|
|
76
|
+
process.stdout.write(`${summary}\n`);
|
|
77
|
+
if (useEmpirical) {
|
|
78
|
+
process.stdout.write('\n(empirical: Anthropic / Google counts via provider countTokens API; OpenAI via tiktoken o200k_base)\n');
|
|
79
|
+
}
|
|
80
|
+
return 0;
|
|
81
|
+
};
|
|
82
|
+
const scriptUrl = `file://${process.argv[1]}`;
|
|
83
|
+
if (import.meta.url === scriptUrl) {
|
|
84
|
+
main(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
|
|
85
|
+
process.stderr.write(`Unexpected error: ${err.stack ?? String(err)}\n`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAcxD,eAAO,MAAM,WAAW,GAAI,SAAS,SAAS,cAAc,EAAE,KAAG,MA8BhE,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,SAAS,cAAc,EAAE,KAAG,MAOlE,CAAC"}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const padRight = (value, width) => value.length >= width ? value : value + ' '.repeat(width - value.length);
|
|
2
|
+
const padLeft = (value, width) => value.length >= width ? value : ' '.repeat(width - value.length) + value;
|
|
3
|
+
const formatCost = (usd) => {
|
|
4
|
+
if (usd >= 0.01)
|
|
5
|
+
return `$${usd.toFixed(4)}`;
|
|
6
|
+
if (usd >= 0.000001)
|
|
7
|
+
return `$${usd.toFixed(6)}`;
|
|
8
|
+
return `$${usd.toExponential(2)}`;
|
|
9
|
+
};
|
|
10
|
+
export const renderTable = (results) => {
|
|
11
|
+
if (results.length === 0)
|
|
12
|
+
return '(no results)';
|
|
13
|
+
const headers = ['model', 'format', 'tokens', 'est. cost'];
|
|
14
|
+
const rows = results.map((r) => [
|
|
15
|
+
r.model,
|
|
16
|
+
r.format,
|
|
17
|
+
`${r.approximate ? '~' : ' '}${r.inputTokens.toLocaleString()}`,
|
|
18
|
+
formatCost(r.inputCost),
|
|
19
|
+
]);
|
|
20
|
+
const widths = headers.map((h, colIdx) => {
|
|
21
|
+
const maxRowWidth = rows.reduce((acc, row) => Math.max(acc, row[colIdx]?.length ?? 0), 0);
|
|
22
|
+
return Math.max(h.length, maxRowWidth);
|
|
23
|
+
});
|
|
24
|
+
const headerLine = headers.map((h, i) => padRight(h, widths[i] ?? h.length)).join(' ');
|
|
25
|
+
const separator = headers.map((_, i) => '-'.repeat(widths[i] ?? 0)).join(' ');
|
|
26
|
+
const dataLines = rows.map((row) => row
|
|
27
|
+
.map((cell, i) => {
|
|
28
|
+
const isNumeric = i >= 2;
|
|
29
|
+
return isNumeric
|
|
30
|
+
? padLeft(cell, widths[i] ?? cell.length)
|
|
31
|
+
: padRight(cell, widths[i] ?? cell.length);
|
|
32
|
+
})
|
|
33
|
+
.join(' '));
|
|
34
|
+
return [headerLine, separator, ...dataLines].join('\n');
|
|
35
|
+
};
|
|
36
|
+
export const renderSummary = (results) => {
|
|
37
|
+
if (results.length === 0)
|
|
38
|
+
return '';
|
|
39
|
+
const cheapest = [...results].sort((a, b) => a.inputCost - b.inputCost)[0];
|
|
40
|
+
const priciest = [...results].sort((a, b) => b.inputCost - a.inputCost)[0];
|
|
41
|
+
if (!cheapest || !priciest || cheapest === priciest)
|
|
42
|
+
return '';
|
|
43
|
+
const ratio = priciest.inputCost / Math.max(cheapest.inputCost, Number.EPSILON);
|
|
44
|
+
return `\nCheapest: ${cheapest.model} as ${cheapest.format} (${formatCost(cheapest.inputCost)})\nPriciest: ${priciest.model} as ${priciest.format} (${formatCost(priciest.inputCost)}, ${ratio.toFixed(2)}x more)`;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tokenometer",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Empirical token-cost benchmarking CLI for LLM prompts. Tells you what your prompt actually costs across Claude, GPT-4o, and Gemini, in every format.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Faraazuddin Mohammed <mohdfaraaz1@gmail.com>",
|
|
7
|
+
"homepage": "https://tokenometer.vercel.app",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/faraa2m/tokenometer.git",
|
|
11
|
+
"directory": "packages/cli"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/faraa2m/tokenometer/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai",
|
|
18
|
+
"anthropic",
|
|
19
|
+
"claude",
|
|
20
|
+
"cli",
|
|
21
|
+
"cost",
|
|
22
|
+
"gemini",
|
|
23
|
+
"gpt",
|
|
24
|
+
"llm",
|
|
25
|
+
"openai",
|
|
26
|
+
"prompt",
|
|
27
|
+
"token",
|
|
28
|
+
"tokenizer"
|
|
29
|
+
],
|
|
30
|
+
"type": "module",
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"bin": {
|
|
34
|
+
"tokenometer": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/index.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": ["dist", "README.md"],
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public",
|
|
45
|
+
"registry": "https://registry.npmjs.org/"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc -b",
|
|
49
|
+
"clean": "rm -rf dist"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@tokenometer/core": "0.0.1"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^22.10.5",
|
|
56
|
+
"typescript": "^5.7.2",
|
|
57
|
+
"vitest": "^3.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|