ai-spend-agent 0.9.11 → 0.9.13
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 +73 -51
- package/dist/index.js +10 -10
- package/dist/telemetry.d.ts +2 -2
- package/dist/telemetry.js +4 -4
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,58 +1,80 @@
|
|
|
1
|
-
# ai-spend-agent
|
|
1
|
+
# ai-spend-agent — Tilden’s free AI spend CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Inspect Claude Code and Codex activity locally, see its estimated value at
|
|
4
|
+
published API rates, and identify what deserves a closer look. Optional provider
|
|
5
|
+
reports add billing evidence; estimates and reported costs stay separate.
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
npx aibill init
|
|
7
|
-
npx aibill
|
|
8
|
-
npx ai-spend-agent
|
|
9
|
-
# short alias
|
|
10
|
-
npx aibill
|
|
8
|
+
npx aibill@latest init
|
|
9
|
+
npx aibill@latest --full
|
|
11
10
|
```
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
12
|
+
Requires Node.js 22+. Free and MIT-licensed; no account or provider key is
|
|
13
|
+
needed for local analysis. `aibill` and `ai-spend-agent` run the same CLI.
|
|
14
|
+
Run from a project directory: `init` reviews the last 30 days of supported
|
|
15
|
+
machine-wide records, uses that project for local state, and seeds the private
|
|
16
|
+
Claude Code/Codex status cache. It does not change Claude settings or connect
|
|
17
|
+
Workspace. Missing evidence stays missing; `--sample` explicitly selects a demo.
|
|
18
|
+
|
|
19
|
+
Local values are API-equivalent estimates, not subscription charges or invoices.
|
|
20
|
+
Claude Code/Codex readers are live-verified; Gemini CLI is experimental and
|
|
21
|
+
fixture-verified, supported only in financial CLI/report/local MCP surfaces.
|
|
22
|
+
Gemini does not feed statusline, Glance, Context Health, Apply or plan/runway.
|
|
23
|
+
`npx aibill@latest doctor --sources` shows reader validation separately from
|
|
24
|
+
each number’s financial label and coverage.
|
|
25
|
+
|
|
26
|
+
## Choose a next step
|
|
27
|
+
|
|
28
|
+
- `npx aibill@latest context`: inspect context evidence.
|
|
29
|
+
- `npx aibill@latest improve`: guide one reversible token experiment; a result
|
|
30
|
+
requires matched completed sessions and user-declared quality, not a claim
|
|
31
|
+
of cash savings or ROI.
|
|
32
|
+
- `npx aibill@latest statusline install`: optionally install the cache-only
|
|
33
|
+
Claude Code status line. Remove it with `statusline uninstall`.
|
|
34
|
+
- `npx aibill@latest connect openai` or `connect anthropic`: register local
|
|
35
|
+
provider setup and print the separate `sync-provider` command. Only an
|
|
36
|
+
explicit sync reads the provider, using the required admin environment
|
|
37
|
+
credential reference. Cursor/Copilot connectors remain fixture-verified beta
|
|
38
|
+
pending real-account acceptance.
|
|
39
|
+
|
|
40
|
+
## Use standalone or connect to Workspace
|
|
41
|
+
|
|
42
|
+
Use the free CLI on its own, or keep working locally and connect it to your
|
|
43
|
+
invited [Tilden Workspace](https://asktilden.com/docs/workspace) for a shared
|
|
44
|
+
spending review. Start with `npx aibill@latest workspace connect`, complete the
|
|
45
|
+
browser enrollment and sharing consent, then run
|
|
46
|
+
`npx aibill@latest workspace push` to preview and approve a share. The browser
|
|
47
|
+
does not need to stay open for later pushes while the machine’s grant and
|
|
48
|
+
sharing consent remain valid. Shared facts include eligible
|
|
49
|
+
Claude Code/Codex sessions, tokens and project labels where available, plus
|
|
50
|
+
hashed identities; they exclude raw prompts, transcript contents, full paths,
|
|
51
|
+
raw session IDs and dollar amounts. Local provider records are not uploaded.
|
|
52
|
+
Hosted provider connections are set up separately.
|
|
53
|
+
|
|
54
|
+
Read [Workspace setup and limits](https://github.com/futurastudio/ai-spend-agent/blob/main/docs/WORKSPACE.md)
|
|
55
|
+
before pairing. [Join the Tilden waitlist](https://asktilden.com/?ref=npm-cli#beta)
|
|
56
|
+
for updates and access invitations; joining does not grant immediate access.
|
|
57
|
+
|
|
58
|
+
## Privacy
|
|
59
|
+
|
|
60
|
+
Default transcript analysis runs locally. Reports remain local until shared.
|
|
61
|
+
Explicit Workspace pushes send only the approved facts. Local MCP results go
|
|
62
|
+
to the AI client you configure and follow its data policy. Explicit provider
|
|
63
|
+
sync uses the referenced credential only with that provider’s read-only API;
|
|
33
64
|
aibill never sits in the inference path and never stores, prints, or proxies provider credentials.
|
|
65
|
+
Workspace pairing uses separate private local device credentials.
|
|
66
|
+
|
|
67
|
+
**Telemetry: command counts, disclosed at first run.** Events begin
|
|
68
|
+
only after the first interactive notice. They include a random installation ID
|
|
69
|
+
and operational fields. Events can be linked to the same installation, but do
|
|
70
|
+
not include your arguments, paths, prompts, project names,
|
|
71
|
+
dollar amounts or email. `npx aibill telemetry off` disables them; so do
|
|
72
|
+
`DO_NOT_TRACK`, `CI` or `AI_SPEND_NO_TELEMETRY` when non-empty.
|
|
73
|
+
`npx aibill telemetry` shows the exact last payload.
|
|
74
|
+
[Full telemetry disclosure](https://github.com/futurastudio/ai-spend-agent/blob/main/docs/TELEMETRY.md).
|
|
75
|
+
The optional signup command sends its displayed email/ref payload only after
|
|
76
|
+
confirmation; `outcome github` explicitly uses the installed `gh` CLI.
|
|
34
77
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
anonymous, never your arguments, paths, content, dollars, or your email.
|
|
39
|
-
Nothing is sent before a one-time notice has been printed on an interactive
|
|
40
|
-
run, so a machine that has never seen that notice (CI, scripts, pipes) never
|
|
41
|
-
sends anything. One command turns it off — `aibill telemetry off` (or
|
|
42
|
-
`DO_NOT_TRACK`, `CI`, or `AI_SPEND_NO_TELEMETRY`) — `aibill telemetry` prints
|
|
43
|
-
the exact last payload verbatim, and while it is on every receipt says so in
|
|
44
|
-
place of "nothing uploaded". Full scope and the never-list:
|
|
45
|
-
[`docs/TELEMETRY.md`](https://github.com/futurastudio/ai-spend-agent/blob/main/docs/TELEMETRY.md).
|
|
46
|
-
|
|
47
|
-
Connector validation (`live_verified`, `fixture_verified`, `untested`, or
|
|
48
|
-
`failed`) and each number's financial evidence (`verified`, `estimated`,
|
|
49
|
-
`detected_unverified`, or `missing`) are separate status axes. Run `npx aibill
|
|
50
|
-
doctor --sources` to see both with freshness and the last sanitized error.
|
|
51
|
-
The source registry also records read-boundary approval separately; an approved
|
|
52
|
-
local folder is permission to scan, not verified financial evidence.
|
|
53
|
-
|
|
54
|
-
See the repository
|
|
55
|
-
[README](https://github.com/futurastudio/ai-spend-agent#readme) for commands,
|
|
56
|
-
privacy boundaries, supported sources, and public-beta limitations.
|
|
57
|
-
|
|
58
|
-
MIT licensed.
|
|
78
|
+
[Full guide](https://github.com/futurastudio/ai-spend-agent#readme) ·
|
|
79
|
+
[Source coverage](https://asktilden.com/docs/sources) ·
|
|
80
|
+
[Command reference](https://github.com/futurastudio/ai-spend-agent/blob/main/docs/CLI_REFERENCE.md)
|
package/dist/index.js
CHANGED
|
@@ -592,7 +592,7 @@ function quickstartNextSteps(mode, detected) {
|
|
|
592
592
|
command: "npx aibill --group-by project",
|
|
593
593
|
description: "see which project has the most observed activity"
|
|
594
594
|
});
|
|
595
|
-
steps.push("
|
|
595
|
+
steps.push("Review supported AI spend in Tilden Workspace with our team’s help. The pilot has one owner seat. CLI sharing is optional and explicit; register interest: https://asktilden.com/?ref=aibill-workspace#beta");
|
|
596
596
|
if (mode === "demo") {
|
|
597
597
|
// Static pointer only — sample output is built for recordings and
|
|
598
598
|
// screenshots, so it never prompts (capture design moments map).
|
|
@@ -1256,7 +1256,7 @@ async function signupCommand(args, runtime) {
|
|
|
1256
1256
|
};
|
|
1257
1257
|
}
|
|
1258
1258
|
/**
|
|
1259
|
-
* `aibill telemetry [on|off]` — inspect or switch
|
|
1259
|
+
* `aibill telemetry [on|off]` — inspect or switch installation-linked command-count
|
|
1260
1260
|
* telemetry. Status shows the EXACT last payload verbatim; state is
|
|
1261
1261
|
* fail-closed (corrupt/readonly ⇒ off).
|
|
1262
1262
|
*/
|
|
@@ -1315,8 +1315,8 @@ async function telemetryCommand(args, runtime) {
|
|
|
1315
1315
|
};
|
|
1316
1316
|
}
|
|
1317
1317
|
return ok([
|
|
1318
|
-
"telemetry on ·
|
|
1319
|
-
`counted: command name, version, os, arch, ci flag, duration bucket, ok flag, timestamp`,
|
|
1318
|
+
"telemetry on · installation-linked command counts only",
|
|
1319
|
+
`counted: random installation ID, command name, version, os, arch, ci flag, duration bucket, ok flag, timestamp`,
|
|
1320
1320
|
"never: arguments, paths, file contents, project names, or your email",
|
|
1321
1321
|
"events start with your next run · see payloads anytime: npx aibill telemetry"
|
|
1322
1322
|
].join("\n"));
|
|
@@ -1338,12 +1338,12 @@ async function telemetryCommand(args, runtime) {
|
|
|
1338
1338
|
else {
|
|
1339
1339
|
lines.push(`status: on · noticed ${read.state.noticedAt}`);
|
|
1340
1340
|
}
|
|
1341
|
-
lines.push("counted: command name, version, os, arch, ci flag, duration bucket, ok flag, timestamp", "never: arguments, paths, file contents, project names, or your email");
|
|
1341
|
+
lines.push("counted: random installation ID, command name, version, os, arch, ci flag, duration bucket, ok flag, timestamp", "never: arguments, paths, file contents, project names, or your email");
|
|
1342
1342
|
if (read.kind === "ok" && read.state.lastPayload !== undefined) {
|
|
1343
|
-
lines.push("last payload
|
|
1343
|
+
lines.push("last attempted payload (verbatim; delivery unconfirmed):", read.state.lastPayload);
|
|
1344
1344
|
}
|
|
1345
1345
|
else {
|
|
1346
|
-
lines.push("last payload
|
|
1346
|
+
lines.push("last attempted payload: none");
|
|
1347
1347
|
}
|
|
1348
1348
|
lines.push("switch: npx aibill telemetry on · npx aibill telemetry off");
|
|
1349
1349
|
return ok(lines.join("\n"));
|
|
@@ -3401,10 +3401,10 @@ const providerAdminEnvHint = {
|
|
|
3401
3401
|
};
|
|
3402
3402
|
function providerSyncSetupCommand(provider, adminRef) {
|
|
3403
3403
|
if (provider === "cursor") {
|
|
3404
|
-
return `npx aibill sync-provider --provider cursor --auth-reference ${adminRef} --account-id <team-label
|
|
3404
|
+
return `npx aibill sync-provider --provider cursor --auth-reference ${adminRef} --account-id '<team-label>'`;
|
|
3405
3405
|
}
|
|
3406
3406
|
if (provider === "github-copilot") {
|
|
3407
|
-
return `npx aibill sync-provider --provider github-copilot --auth-reference ${adminRef} --org <organization
|
|
3407
|
+
return `npx aibill sync-provider --provider github-copilot --auth-reference ${adminRef} --org '<organization>'`;
|
|
3408
3408
|
}
|
|
3409
3409
|
const thirtyDaysAgoUnix = Math.floor(Date.now() / 1_000) - 30 * 24 * 60 * 60;
|
|
3410
3410
|
return `npx aibill sync-provider --provider ${provider} --auth-reference ${adminRef} --start-time ${thirtyDaysAgoUnix}`;
|
|
@@ -7461,7 +7461,7 @@ function helpText(telemetryDisclosure) {
|
|
|
7461
7461
|
" statusline expand Print every subscription with committed price, runways, and 7d API-equivalent",
|
|
7462
7462
|
" signup <email> [--ref <token>] Join the launch list · email only · the exact payload is shown before send",
|
|
7463
7463
|
" [--never] Never ask again (nothing is sent) [--forget] Clear local signup state",
|
|
7464
|
-
" telemetry [on|off] Show
|
|
7464
|
+
" telemetry [on|off] Show installation-linked command-count status + the exact last payload · switch it",
|
|
7465
7465
|
" doctor [--sources] Launch diagnostics; --sources shows validation, evidence, freshness, and errors",
|
|
7466
7466
|
" reset [--path <dir>] Clear persisted spend state (so sample state can't mask real logs)",
|
|
7467
7467
|
" --ignore-state On the default/quickstart run, ignore persisted spend.json for this run",
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
/**
|
|
3
|
-
* CLI telemetry —
|
|
3
|
+
* CLI telemetry — installation-linked command counts, notice-before-first-byte.
|
|
4
4
|
*
|
|
5
5
|
* Consent model (founder decision 2026-08-24, disclosed opt-out):
|
|
6
6
|
* - Run 1 (interactive) prints a three-line notice AFTER the output and
|
|
@@ -55,7 +55,7 @@ export type TelemetryEvent = {
|
|
|
55
55
|
* incident — "command not found").
|
|
56
56
|
*/
|
|
57
57
|
export declare const telemetryDisclosureLine: string;
|
|
58
|
-
export declare const telemetryNoticeLines: readonly ["aibill counts
|
|
58
|
+
export declare const telemetryNoticeLines: readonly ["aibill counts commands by random installation ID — no arguments, paths or content", `turn off: ${string}`, `see payloads: ${string}`];
|
|
59
59
|
export declare function telemetryOsLabel(platform?: string): TelemetryOs;
|
|
60
60
|
export declare function telemetryArchLabel(arch?: string): TelemetryArch;
|
|
61
61
|
export declare function telemetryDurationBucket(durationMs: number): TelemetryDurationBucket;
|
package/dist/telemetry.js
CHANGED
|
@@ -5,7 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { aibillCommandV0 } from "@agent-finops/core";
|
|
7
7
|
/**
|
|
8
|
-
* CLI telemetry —
|
|
8
|
+
* CLI telemetry — installation-linked command counts, notice-before-first-byte.
|
|
9
9
|
*
|
|
10
10
|
* Consent model (founder decision 2026-08-24, disclosed opt-out):
|
|
11
11
|
* - Run 1 (interactive) prints a three-line notice AFTER the output and
|
|
@@ -69,9 +69,9 @@ export const telemetryCommands = [
|
|
|
69
69
|
* npx form): npx users have no bare `aibill` on PATH (0.9.2 founder
|
|
70
70
|
* incident — "command not found").
|
|
71
71
|
*/
|
|
72
|
-
export const telemetryDisclosureLine = `
|
|
72
|
+
export const telemetryDisclosureLine = `installation-linked command counts shared · ${aibillCommandV0("telemetry off")}`;
|
|
73
73
|
export const telemetryNoticeLines = [
|
|
74
|
-
"aibill counts
|
|
74
|
+
"aibill counts commands by random installation ID — no arguments, paths or content",
|
|
75
75
|
`turn off: ${aibillCommandV0("telemetry off")}`,
|
|
76
76
|
`see payloads: ${aibillCommandV0("telemetry")}`
|
|
77
77
|
];
|
|
@@ -318,7 +318,7 @@ export async function openCliTelemetry(options = {}) {
|
|
|
318
318
|
return;
|
|
319
319
|
// `glance` is a machine-invoked poll (the Glance menu-bar app spawns
|
|
320
320
|
// it every ~30s), not a human command — counting it is noise by
|
|
321
|
-
// definition and would flood the
|
|
321
|
+
// definition and would flood the installation-linked command counts (~2,880
|
|
322
322
|
// events/day/user). Never emit for it, notice or not; the label
|
|
323
323
|
// still exists in the map so any stray event is at least honest.
|
|
324
324
|
if (telemetryCommandForArgv(input.argv) === "glance")
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-spend-agent",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.13",
|
|
4
4
|
"funding": "https://asktilden.com",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Tilden\u2019s free CLI for local coding-agent usage and optional provider cost reports. Estimates, reported costs and missing coverage stay separate.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"prepack": "npm run build"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@agent-finops/core": "0.9.
|
|
59
|
-
"@agent-finops/report": "0.9.
|
|
58
|
+
"@agent-finops/core": "0.9.13",
|
|
59
|
+
"@agent-finops/report": "0.9.13",
|
|
60
60
|
"yocto-spinner": "^1.2.0"
|
|
61
61
|
}
|
|
62
62
|
}
|