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.
- package/dist/index.js +25 -6
- 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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
53
|
-
"@agent-finops/report": "0.
|
|
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
|
}
|