@tokenzero/cli 0.1.5 → 0.1.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/bin/tokenzero.mjs +111 -3
- package/package.json +1 -1
package/bin/tokenzero.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
// cli/src/main.ts
|
|
5
5
|
import fs2 from "node:fs";
|
|
6
|
+
import os from "node:os";
|
|
6
7
|
import path2 from "node:path";
|
|
7
8
|
import crypto2 from "node:crypto";
|
|
8
9
|
import readline from "node:readline/promises";
|
|
@@ -666,7 +667,7 @@ function canonical(obj) {
|
|
|
666
667
|
}
|
|
667
668
|
|
|
668
669
|
// cli/src/main.ts
|
|
669
|
-
var VERSION = "0.1.
|
|
670
|
+
var VERSION = "0.1.6";
|
|
670
671
|
var BAKED_URL = true ? "https://tokenzero.sh" : "__TOKENZERO_DEFAULT_URL__";
|
|
671
672
|
function parseArgs(argv) {
|
|
672
673
|
const a = { _: [], flags: {} };
|
|
@@ -875,9 +876,11 @@ ${bold("Your code")}`);
|
|
|
875
876
|
}
|
|
876
877
|
if (a.flags["github-action"]) await setupGithubAction(root, a);
|
|
877
878
|
if (a.flags.mcp) await setupMcp(root, base, a);
|
|
879
|
+
if (a.flags["agent-rules"]) await setupAgentRules(root, base, a);
|
|
880
|
+
if (key && wsId) saveCreds({ workspace_id: wsId, api_key: key, url: base });
|
|
878
881
|
out(`
|
|
879
882
|
${bold("Next")}`);
|
|
880
|
-
if (wsId) out(` dashboard ${base}/dashboard?workspace=${wsId}`);
|
|
883
|
+
if (wsId) out(` dashboard ${base}/dashboard?workspace=${wsId}${key ? "#key=" + redactKey(key, key) : ""}`);
|
|
881
884
|
out(` usage ${selfCmd(base)} usage`);
|
|
882
885
|
if (wsId) out(` badge turn on public stats in the dashboard, then: [](${base}/dashboard?workspace=${wsId})`);
|
|
883
886
|
if (!a.flags["github-action"]) out(` PR checks ${selfCmd(base)} init --github-action`);
|
|
@@ -944,6 +947,103 @@ ${bold("MCP")} ${dim("(audit_repo_token_waste, optimize_prompt_payload, calculat
|
|
|
944
947
|
}
|
|
945
948
|
}
|
|
946
949
|
}
|
|
950
|
+
var AGENT_RULES_MARKER = "<!-- tokenzero-agent-rules -->";
|
|
951
|
+
function credsPath() {
|
|
952
|
+
return path2.join(process.env.TOKENZERO_CONFIG_DIR || path2.join(os.homedir(), ".config", "tokenzero"), "credentials.json");
|
|
953
|
+
}
|
|
954
|
+
function saveCreds(c2) {
|
|
955
|
+
try {
|
|
956
|
+
const p = credsPath();
|
|
957
|
+
fs2.mkdirSync(path2.dirname(p), { recursive: true, mode: 448 });
|
|
958
|
+
fs2.writeFileSync(p, JSON.stringify({ ...c2, updated_at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n", { mode: 384 });
|
|
959
|
+
} catch {
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
function loadCreds() {
|
|
963
|
+
try {
|
|
964
|
+
return JSON.parse(fs2.readFileSync(credsPath(), "utf8"));
|
|
965
|
+
} catch {
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
async function setupAgentRules(root, base, a) {
|
|
970
|
+
out(`
|
|
971
|
+
${bold("Agent Rules")} ${dim("(AGENTS.md FinOps & MCP routing rules)")}`);
|
|
972
|
+
const file = path2.join(root, "AGENTS.md");
|
|
973
|
+
const existing = fs2.existsSync(file) ? fs2.readFileSync(file, "utf8") : "";
|
|
974
|
+
if (existing.includes(AGENT_RULES_MARKER)) {
|
|
975
|
+
out(dim(" AGENTS.md: already includes TokenZero FinOps rules"));
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const block = [
|
|
979
|
+
AGENT_RULES_MARKER,
|
|
980
|
+
"## TokenZero LLM FinOps & MCP Gateway",
|
|
981
|
+
`- **1-Line BYOK Gateway:** Point \`OPENAI_BASE_URL=${base}/v1\` and \`ANTHROPIC_BASE_URL=${base}\` (with \`X-TokenZero-Key\` or \`/w/<key>/v1\`). Provider keys pass straight through and are never stored.`,
|
|
982
|
+
`- **MCP Tools:** Run \`npx -y @tokenzero/mcp\` or connect HTTP MCP at \`${base}/mcp\` for \`audit_repo_token_waste\`, \`calculate_model_arbitrage\`, \`optimize_prompt_payload\`, and \`provision_workspace\`.`,
|
|
983
|
+
`- **Local Audit:** Run \`npx -y @tokenzero/cli audit\` before opening PRs that add or modify LLM calls.`
|
|
984
|
+
].join("\n") + "\n";
|
|
985
|
+
if (await confirm(" Add TokenZero FinOps & MCP rules to AGENTS.md?", a)) {
|
|
986
|
+
const sep = existing && !existing.endsWith("\n") ? "\n\n" : existing ? "\n" : "";
|
|
987
|
+
fs2.writeFileSync(file, existing + sep + block);
|
|
988
|
+
out(green(" \u2713 wrote AGENTS.md"));
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
async function cmdSignup(a) {
|
|
992
|
+
const base = baseUrl(a);
|
|
993
|
+
if (!base) {
|
|
994
|
+
err(red("No gateway URL. Pass --url https://\u2026 or set TOKENZERO_URL."));
|
|
995
|
+
process.exitCode = 2;
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const name = a.flags.name || path2.basename(process.cwd()) || "cli-signup";
|
|
999
|
+
const r = await api(base, "/v1/workspaces", { method: "POST", body: JSON.stringify({ name }) });
|
|
1000
|
+
if (r.status !== 201 && r.status !== 200) {
|
|
1001
|
+
err(red(`signup failed (${r.status}): ${JSON.stringify(r.body).slice(0, 200)}`));
|
|
1002
|
+
process.exitCode = 1;
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
const wsId = r.body.workspace?.id ?? r.body.workspace_id ?? r.body.id;
|
|
1006
|
+
const key = r.body.key ?? r.body.api_key;
|
|
1007
|
+
saveCreds({ workspace_id: wsId, api_key: key, url: base });
|
|
1008
|
+
const payload = {
|
|
1009
|
+
workspace_id: wsId,
|
|
1010
|
+
api_key: key,
|
|
1011
|
+
dashboard_url: `${base}/dashboard?workspace=${wsId}`,
|
|
1012
|
+
one_click_dashboard_url: `${base}/dashboard?workspace=${wsId}#key=${key}`,
|
|
1013
|
+
openai_base_url: `${base}/w/${key}/v1`,
|
|
1014
|
+
anthropic_base_url: `${base}/w/${key}`,
|
|
1015
|
+
mcp_url: `${base}/mcp`,
|
|
1016
|
+
badge_svg_url: `${base}/v1/badge/${wsId}.svg`
|
|
1017
|
+
};
|
|
1018
|
+
if (a.flags.json) {
|
|
1019
|
+
out(JSON.stringify(payload, null, 2));
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
out(`${bold("TokenZero Workspace Provisioned (0-Click / No Form)")}`);
|
|
1023
|
+
out(` workspace_id ${cyan(wsId)}`);
|
|
1024
|
+
out(` api_key ${green(key)}`);
|
|
1025
|
+
out(` 1-click dash ${cyan(payload.one_click_dashboard_url)}`);
|
|
1026
|
+
out(` OPENAI_BASE_URL ${payload.openai_base_url}`);
|
|
1027
|
+
out(` ANTHROPIC_BASE_URL ${payload.anthropic_base_url}`);
|
|
1028
|
+
out(dim(` Saved credentials to ${credsPath()}`));
|
|
1029
|
+
}
|
|
1030
|
+
async function cmdDashboard(a) {
|
|
1031
|
+
const saved = loadCreds();
|
|
1032
|
+
const base = baseUrl(a) || saved?.url || "https://tokenzero.sh";
|
|
1033
|
+
const key = a.flags.key || process.env.TOKENZERO_KEY || saved?.api_key || "";
|
|
1034
|
+
const wsId = saved?.workspace_id || "";
|
|
1035
|
+
if (!key && !wsId) {
|
|
1036
|
+
err(red("No saved workspace credentials. Run `npx -y @tokenzero/cli signup` or `tokenzero init` first."));
|
|
1037
|
+
process.exitCode = 2;
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
const url = `${base}/dashboard${wsId ? "?workspace=" + wsId : ""}${key ? "#key=" + key : ""}`;
|
|
1041
|
+
if (a.flags.json) {
|
|
1042
|
+
out(JSON.stringify({ workspace_id: wsId || null, dashboard_url: url }, null, 2));
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
out(url);
|
|
1046
|
+
}
|
|
947
1047
|
async function cmdAudit(a) {
|
|
948
1048
|
const root = path2.resolve(a._[1] ?? ".");
|
|
949
1049
|
let report;
|
|
@@ -1059,7 +1159,11 @@ async function cmdVerify(a) {
|
|
|
1059
1159
|
function help() {
|
|
1060
1160
|
out(`${bold("tokenzero")} v${VERSION} \u2014 cut your LLM bill with a BYOK gateway
|
|
1061
1161
|
|
|
1062
|
-
${bold("tokenzero
|
|
1162
|
+
${bold("tokenzero signup")} [--name NAME] [--json]
|
|
1163
|
+
Instant 1-command workspace & API key provisioning (no form, saves to ~/.config/tokenzero).
|
|
1164
|
+
${bold("tokenzero dashboard")} [--json]
|
|
1165
|
+
Print your 1-click auto-unlock dashboard URL (#key= fragment, never sent in HTTP headers).
|
|
1166
|
+
${bold("tokenzero init")} [dir] [--url URL] [--name NAME] [--yes] [--no-env] [--mcp] [--github-action] [--agent-rules]
|
|
1063
1167
|
Audit locally, create a workspace, point OPENAI_BASE_URL / ANTHROPIC_BASE_URL at the gateway.
|
|
1064
1168
|
${bold("tokenzero audit")} [dir] [--json | --format markdown] [--diff file|-] [--fail-over PCT]
|
|
1065
1169
|
Static token-waste audit. Runs locally; nothing is uploaded. --fail-over makes it a CI gate.
|
|
@@ -1078,6 +1182,10 @@ async function main() {
|
|
|
1078
1182
|
const cmd = a._[0];
|
|
1079
1183
|
if (a.flags.version || cmd === "version") return out(VERSION);
|
|
1080
1184
|
switch (cmd) {
|
|
1185
|
+
case "signup":
|
|
1186
|
+
return cmdSignup(a);
|
|
1187
|
+
case "dashboard":
|
|
1188
|
+
return cmdDashboard(a);
|
|
1081
1189
|
case "init":
|
|
1082
1190
|
return cmdInit(a);
|
|
1083
1191
|
case "audit":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenzero/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "TokenZero CLI: connect a project to the TokenZero BYOK gateway, audit LLM token waste locally, check usage and verify signed savings receipts.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|