ai-spend-agent 0.5.6 → 0.5.8
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/dist/index.js +33 -19
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
6
6
|
import { analyzeSpend, attributeUsageRecords, buildUsageGlance, loadContextHealth, detectLocalCredentials, detectLocalPlans, redactSecrets, readSafeStateText, resolveSafeScanRoot, resolveSafeStateDirectory, subscriptionPlans, unsafeScanRootReason, selectProviderFinancialHeadlineRecords, writeSafeStateText, loadDeadContext, sampleDeadContext, loadLocalAgentUsage, loadSampleUsageData, scanLocalUsageSignals, buildMissingSourcePrompts, confirmMapping, createProviderConnectorStub, createLocalFolderSourceRegistry, createScanAuditLog, fetchProviderUsageRecords, addApprovedSource, slugifySourceId } from "@agent-finops/core";
|
|
7
7
|
import { generateActionPlanMarkdown, generateApplyArtifactMarkdown, generateDemoPackageMarkdown, generateHtmlReport, generateMarkdownReport, generatePlainEnglishSummary, generatePolicyConfigDraftMarkdown, generateReportCardCaption, generateReportCardSvg, generateVerificationPlanMarkdown, groupByDimensions } from "@agent-finops/report";
|
|
8
8
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
9
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
10
|
+
return ok(await cliVersion());
|
|
11
|
+
}
|
|
9
12
|
if (argv.includes("--help") || argv.includes("-h") || argv[0] === "help") {
|
|
10
13
|
return ok(helpText());
|
|
11
14
|
}
|
|
@@ -91,7 +94,12 @@ async function quickstartCommand(args) {
|
|
|
91
94
|
// Persona: --plan override wins; otherwise read the plans the coding agents
|
|
92
95
|
// themselves persisted locally (read-only, whitelisted fields, no network).
|
|
93
96
|
let detectedPlans;
|
|
94
|
-
if (args.
|
|
97
|
+
if (args.sample) {
|
|
98
|
+
// An explicit sample run must be deterministic and safe to record/share.
|
|
99
|
+
// Never mix the developer's real local plan into illustrative output.
|
|
100
|
+
detectedPlans = [];
|
|
101
|
+
}
|
|
102
|
+
else if (args.plan) {
|
|
95
103
|
const override = planOverrideFromFlag(args.plan);
|
|
96
104
|
if (!override) {
|
|
97
105
|
return {
|
|
@@ -111,7 +119,12 @@ async function quickstartCommand(args) {
|
|
|
111
119
|
}
|
|
112
120
|
// Surface auto-detected credentials so the user knows their next 2-min step,
|
|
113
121
|
// without ever printing a raw secret.
|
|
114
|
-
|
|
122
|
+
// Sample output is designed for demos, docs, and screenshots. Keeping local
|
|
123
|
+
// credential discovery out of that path prevents even redacted machine-
|
|
124
|
+
// specific hints from leaking into a recording.
|
|
125
|
+
const detection = args.sample
|
|
126
|
+
? { credentials: [], scannedFiles: [] }
|
|
127
|
+
: await detectLocalCredentials({ cwd: resolve(args.path) });
|
|
115
128
|
const nextSteps = quickstartNextSteps(mode, detection.credentials);
|
|
116
129
|
// Dead-context cost, globalized across the user's whole Claude Code setup
|
|
117
130
|
// (all projects' MCP + user-scope skills/agents/commands, vs. every
|
|
@@ -396,7 +409,7 @@ async function doctorCommand(args) {
|
|
|
396
409
|
? "your local agent logs (estimated at API-equivalent rates)"
|
|
397
410
|
: "demo sample (illustrative)";
|
|
398
411
|
const lines = [
|
|
399
|
-
"
|
|
412
|
+
"aibill doctor",
|
|
400
413
|
`node version: ${process.version}`,
|
|
401
414
|
`cli version: ${await cliVersion()}`,
|
|
402
415
|
"local-first mode: enabled (no cloud upload, no telemetry)",
|
|
@@ -434,7 +447,7 @@ async function resetCommand(args) {
|
|
|
434
447
|
if (!isNodeError(error, "ENOENT"))
|
|
435
448
|
throw error;
|
|
436
449
|
return ok([
|
|
437
|
-
"
|
|
450
|
+
"aibill reset",
|
|
438
451
|
`path: ${rootPath}`,
|
|
439
452
|
"nothing to clear (no persisted spend state found)",
|
|
440
453
|
"next run will re-read your real local agent logs (or demo sample if none)."
|
|
@@ -454,7 +467,7 @@ async function resetCommand(args) {
|
|
|
454
467
|
}
|
|
455
468
|
}
|
|
456
469
|
return ok([
|
|
457
|
-
"
|
|
470
|
+
"aibill reset",
|
|
458
471
|
`path: ${rootPath}`,
|
|
459
472
|
removed.length > 0 ? `cleared: ${removed.join(", ")}` : "nothing to clear (no persisted spend state found)",
|
|
460
473
|
"next run will re-read your real local agent logs (or demo sample if none)."
|
|
@@ -466,7 +479,7 @@ async function initCommand(args) {
|
|
|
466
479
|
await mkdir(stateDir, { recursive: true });
|
|
467
480
|
const registry = createLocalFolderSourceRegistry(rootPath);
|
|
468
481
|
await writeJson(join(stateDir, "manifest.json"), {
|
|
469
|
-
product: "
|
|
482
|
+
product: "aibill",
|
|
470
483
|
mode: "local-first-demo",
|
|
471
484
|
cloudUpload: false,
|
|
472
485
|
cronJobsEnabled: false,
|
|
@@ -490,7 +503,7 @@ async function initCommand(args) {
|
|
|
490
503
|
}
|
|
491
504
|
]));
|
|
492
505
|
return ok([
|
|
493
|
-
"
|
|
506
|
+
"aibill init",
|
|
494
507
|
`path: ${rootPath}`,
|
|
495
508
|
"demo mode: local-first sample workflow",
|
|
496
509
|
"cloud upload: disabled",
|
|
@@ -567,7 +580,7 @@ async function scanCommand(args) {
|
|
|
567
580
|
await writeJson(join(stateDir, "discovery.json"), discovery);
|
|
568
581
|
await writeJson(join(stateDir, "missing-sources.json"), missingSourcePrompts);
|
|
569
582
|
const lines = [
|
|
570
|
-
"
|
|
583
|
+
"aibill scan",
|
|
571
584
|
`path: ${rootPath}`,
|
|
572
585
|
"source registry: .ai-spend-agent/sources.json",
|
|
573
586
|
"audit log: .ai-spend-agent/audit-log.json",
|
|
@@ -776,7 +789,7 @@ async function addSourceCommand(args) {
|
|
|
776
789
|
detail: `${args.sourceType} approved via CLI add-source.`
|
|
777
790
|
});
|
|
778
791
|
return ok([
|
|
779
|
-
"
|
|
792
|
+
"aibill add-source",
|
|
780
793
|
`source added: ${id}`,
|
|
781
794
|
`type: ${args.sourceType}`,
|
|
782
795
|
`path: ${sourcePath}`,
|
|
@@ -789,7 +802,7 @@ async function listSourcesCommand(args) {
|
|
|
789
802
|
const stateDir = join(rootPath, ".ai-spend-agent");
|
|
790
803
|
const registry = await readSourceRegistry(stateDir, rootPath);
|
|
791
804
|
const lines = [
|
|
792
|
-
"
|
|
805
|
+
"aibill sources",
|
|
793
806
|
`approved sources: ${registry.approvedSources.length}`
|
|
794
807
|
];
|
|
795
808
|
for (const source of registry.approvedSources) {
|
|
@@ -847,7 +860,7 @@ async function connectCommand(args) {
|
|
|
847
860
|
const detection = await detectLocalCredentials({ cwd: rootPath });
|
|
848
861
|
const detected = detection.credentials.find((credential) => credential.provider === provider);
|
|
849
862
|
const lines = [
|
|
850
|
-
"
|
|
863
|
+
"aibill connect",
|
|
851
864
|
`connector stub: ${source.id}`,
|
|
852
865
|
`provider: ${provider}`,
|
|
853
866
|
`type: ${type}`,
|
|
@@ -980,7 +993,7 @@ async function syncProviderCommand(args) {
|
|
|
980
993
|
detail: `${args.provider} provider connector synced ${result.records.length} evidence records with ${result.coverage} coverage. Auth reference only; no raw secrets stored.`
|
|
981
994
|
});
|
|
982
995
|
return ok([
|
|
983
|
-
"
|
|
996
|
+
"aibill sync-provider",
|
|
984
997
|
`provider: ${result.provider}`,
|
|
985
998
|
`source: ${result.source.id}`,
|
|
986
999
|
`verification: ${result.source.verification}`,
|
|
@@ -1032,7 +1045,7 @@ async function confirmMappingCommand(args) {
|
|
|
1032
1045
|
detail: `${args.provider} mapped to ${[args.team, args.project, args.workflow].filter(Boolean).join(" / ")}`
|
|
1033
1046
|
});
|
|
1034
1047
|
return ok([
|
|
1035
|
-
"
|
|
1048
|
+
"aibill confirm-mapping",
|
|
1036
1049
|
`mapping confirmed: ${mapping.id}`,
|
|
1037
1050
|
`provider: ${mapping.provider}`,
|
|
1038
1051
|
`target: ${[mapping.team, mapping.project, mapping.workflow].filter(Boolean).join(" / ")}`,
|
|
@@ -1051,7 +1064,7 @@ async function reportCommand(args) {
|
|
|
1051
1064
|
await writeLocalReportFile(htmlPath, generateHtmlReport(reportInput), stateDir);
|
|
1052
1065
|
const artifactPaths = await writeApplyArtifacts(stateDir, reportInput);
|
|
1053
1066
|
return ok([
|
|
1054
|
-
"
|
|
1067
|
+
"aibill report",
|
|
1055
1068
|
`path: ${rootPath}`,
|
|
1056
1069
|
`markdown: ${markdownPath}`,
|
|
1057
1070
|
`html: ${htmlPath}`,
|
|
@@ -1136,7 +1149,7 @@ async function applyArtifactCommand(args) {
|
|
|
1136
1149
|
// user can copy it right here instead of hunting for a file path.
|
|
1137
1150
|
const codingPrompt = await readFile(artifactPaths.codingPrompt, "utf8");
|
|
1138
1151
|
return ok([
|
|
1139
|
-
"
|
|
1152
|
+
"aibill apply-artifact",
|
|
1140
1153
|
`path: ${rootPath}`,
|
|
1141
1154
|
`action plan: ${artifactPaths.actionPlan}`,
|
|
1142
1155
|
`policy/config draft: ${artifactPaths.policyConfigDraft}`,
|
|
@@ -1618,13 +1631,13 @@ function helpText() {
|
|
|
1618
1631
|
"aibill — your AI cost and usage evidence in one private view",
|
|
1619
1632
|
"",
|
|
1620
1633
|
"Run with no command for an instant, zero-key demo:",
|
|
1621
|
-
" ai-spend-agent Show
|
|
1634
|
+
" ai-spend-agent Show available AI cost/value evidence (sample or local data)",
|
|
1622
1635
|
" ai-spend-agent --group-by agent Drill down by source|model|client|project|agent|user|workspace|apiKey",
|
|
1623
1636
|
" ai-spend-agent --plan <id> Declare your plan when auto-detection can't (claude-max-5x|claude-max-20x|claude-pro|chatgpt-plus|chatgpt-pro)",
|
|
1624
1637
|
"",
|
|
1625
|
-
"
|
|
1626
|
-
" ai-spend-agent connect openai
|
|
1627
|
-
" ai-spend-agent connect anthropic
|
|
1638
|
+
"Add official provider-reported cost (ADMIN/owner-gated):",
|
|
1639
|
+
" ai-spend-agent connect openai Requires an org-owner Admin key",
|
|
1640
|
+
" ai-spend-agent connect anthropic Requires an Admin key",
|
|
1628
1641
|
" ai-spend-agent connect cursor Upgrade: requires a Cursor team-admin key (Business plan)",
|
|
1629
1642
|
" ai-spend-agent connect github-copilot Upgrade: requires a GitHub billing-admin token",
|
|
1630
1643
|
" ai-spend-agent sync-provider ... Pull provider cost/usage evidence via a local env: reference (never a raw key)",
|
|
@@ -1634,6 +1647,7 @@ function helpText() {
|
|
|
1634
1647
|
" [--cycles N] [--group-by ...] --cycles 0 runs forever; default 1 (cron-friendly)",
|
|
1635
1648
|
"",
|
|
1636
1649
|
"Other commands:",
|
|
1650
|
+
" --version, -v Print the package version without reading local data",
|
|
1637
1651
|
" init [--path <dir>] Initialize local state",
|
|
1638
1652
|
" doctor Launch-grade diagnostics: data mode, logs found, provider keys, warnings",
|
|
1639
1653
|
" reset [--path <dir>] Clear persisted spend state (so sample state can't mask real logs)",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-spend-agent",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Local-first financial
|
|
3
|
+
"version": "0.5.8",
|
|
4
|
+
"description": "Local-first financial accountability CLI for Claude Code and Codex work, cost evidence, attribution, runway, provenance, and Context Health.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"prepack": "npm run build"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@agent-finops/core": "0.5.
|
|
58
|
-
"@agent-finops/report": "0.5.
|
|
57
|
+
"@agent-finops/core": "0.5.8",
|
|
58
|
+
"@agent-finops/report": "0.5.8",
|
|
59
59
|
"yocto-spinner": "^1.2.0"
|
|
60
60
|
}
|
|
61
61
|
}
|