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.
Files changed (2) hide show
  1. package/dist/index.js +33 -19
  2. 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.plan) {
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
- const detection = await detectLocalCredentials({ cwd: resolve(args.path) });
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
- "AI Spend Analyst doctor",
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
- "AI Spend Analyst reset",
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
- "AI Spend Analyst reset",
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: "AI Spend Analyst Agent",
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
- "AI Spend Analyst Agent init",
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
- "AI Spend Analyst Agent scan",
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
- "AI Spend Analyst Agent add-source",
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
- "AI Spend Analyst Agent sources",
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
- "AI Spend Analyst Agent connect",
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
- "AI Spend Analyst Agent sync-provider",
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
- "AI Spend Analyst Agent confirm-mapping",
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
- "AI Spend Analyst Agent report",
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
- "AI Spend Analyst Agent apply-artifact",
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 where your AI money goes (sample/auto-detected data)",
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
- "Connect your real spend (cost data is ADMIN/owner-gated):",
1626
- " ai-spend-agent connect openai Self-serve in ~2 min with an org-owner Admin key",
1627
- " ai-spend-agent connect anthropic Self-serve in ~2 min with an Admin key",
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.6",
4
- "description": "Local-first financial intelligence CLI for Claude Code and Codex activity, provider-reported cost, attribution, runway, provenance, and Context Health.",
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.6",
58
- "@agent-finops/report": "0.5.6",
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
  }