ai-spend-agent 0.2.1 → 0.3.0

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 +25 -6
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -68,7 +68,9 @@ export async function runCli(argv = process.argv.slice(2)) {
68
68
  async function quickstartCommand(args) {
69
69
  const { records, mode, warnings } = await loadInstantReadData(args);
70
70
  const summary = analyzeSpend(records);
71
- const groupBy = args.groupBy ?? "model";
71
+ // For real local-log users the by-project view is the flagship table
72
+ // ("which project burns my plan"); demo/connected keep by-model.
73
+ const groupBy = args.groupBy ?? (mode === "local-logs" ? "project" : "model");
72
74
  const color = args.noColor ? false : undefined;
73
75
  // Persona: --plan override wins; otherwise read the plans the coding agents
74
76
  // themselves persisted locally (read-only, whitelisted fields, no network).
@@ -124,7 +126,10 @@ async function quickstartCommand(args) {
124
126
  mode,
125
127
  nextSteps,
126
128
  deadContext,
127
- detectedPlans
129
+ detectedPlans,
130
+ // An explicit --group-by is a drill-down question: answer with just the
131
+ // table + window instead of repeating the whole readout.
132
+ view: args.groupBy ? "breakdown" : "full"
128
133
  });
129
134
  const header = [` ${dataModeBanner(mode)}`, ...warnings.map((warning) => ` ! ${warning}`)].join("\n");
130
135
  return ok(`${header}\n${summaryText}`);
@@ -172,7 +177,10 @@ async function loadInstantReadData(args) {
172
177
  codexSessionsDir: process.env.AI_SPEND_CODEX_LOGS_DIR
173
178
  }).catch(() => undefined);
174
179
  if (logs && logs.records.length > 0) {
175
- if (persisted && persisted.records.length > 0 && persisted.mode !== "connected_provider") {
180
+ // Persisted local_logs state (written by report/apply-artifact) is the
181
+ // same data source we just re-read — superseding it silently is correct,
182
+ // not worth a scary "sample/legacy" warning.
183
+ if (persisted && persisted.records.length > 0 && persisted.mode !== "connected_provider" && persisted.mode !== "local_logs") {
176
184
  warnings.push("Ignored persisted sample/legacy state in .ai-spend-agent/spend.json — showing your real local agent logs. Run `ai-spend-agent reset` to clear it, or pass --ignore-state.");
177
185
  }
178
186
  return { records: logs.records, mode: "local-logs", warnings };
@@ -828,7 +836,12 @@ async function reportCommand(args) {
828
836
  `verification plan: ${artifactPaths.verificationPlan}`,
829
837
  `demo package: ${artifactPaths.demoPackage}`,
830
838
  `total spend: $${reportInput.summary.totalUsd.toFixed(2)}`,
831
- "privacy: local files only; no cloud upload performed"
839
+ "privacy: local files only; no cloud upload performed",
840
+ "",
841
+ "next:",
842
+ ` open ${htmlPath} view the full report in your browser`,
843
+ ` less ${markdownPath} read it in the terminal`,
844
+ " npx ai-spend-agent apply-artifact print the paste-ready coding-agent prompt"
832
845
  ].join("\n"));
833
846
  }
834
847
  catch (error) {
@@ -882,15 +895,21 @@ async function applyArtifactCommand(args) {
882
895
  try {
883
896
  const reportInput = await buildReportInput(stateDir, rootPath);
884
897
  const artifactPaths = await writeApplyArtifacts(stateDir, reportInput);
898
+ // The prompt IS the product of this command — print it so a terminal
899
+ // user can copy it right here instead of hunting for a file path.
900
+ const codingPrompt = await readFile(artifactPaths.codingPrompt, "utf8");
885
901
  return ok([
886
902
  "AI Spend Analyst Agent apply-artifact",
887
903
  `path: ${rootPath}`,
888
- `coding prompt: ${artifactPaths.codingPrompt}`,
889
904
  `action plan: ${artifactPaths.actionPlan}`,
890
905
  `policy/config draft: ${artifactPaths.policyConfigDraft}`,
891
906
  `verification plan: ${artifactPaths.verificationPlan}`,
892
907
  `demo package: ${artifactPaths.demoPackage}`,
893
- "safety: generated artifacts only; no external systems changed"
908
+ "safety: generated artifacts only; no external systems changed",
909
+ "",
910
+ `──── copy everything below into Claude Code / Codex (also saved at ${artifactPaths.codingPrompt}) ────`,
911
+ "",
912
+ codingPrompt.trimEnd()
894
913
  ].join("\n"));
895
914
  }
896
915
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-spend-agent",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Your AI spend in one view, in 90 seconds — local-first CLI for OpenAI, Anthropic, Cursor, Copilot + Claude Code/Codex session logs, with a ranked savings cut list, and flags the tools your agent loads but never uses (dead context).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,8 +49,8 @@
49
49
  "prepack": "npm run build"
50
50
  },
51
51
  "dependencies": {
52
- "@agent-finops/core": "0.2.1",
53
- "@agent-finops/report": "0.2.1",
52
+ "@agent-finops/core": "0.3.0",
53
+ "@agent-finops/report": "0.3.0",
54
54
  "yocto-spinner": "^1.2.0"
55
55
  }
56
56
  }