ai-spend-agent 0.7.0 → 0.7.2

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 CHANGED
@@ -4,7 +4,7 @@ import { mkdir, readFile, rm, stat } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { basename, dirname, extname, join, resolve } from "node:path";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
- import { analyzeSpend, attributeUsageRecords, buildUsageGlance, buildActivitySnapshot, loadContextHealth, detectLocalCredentials, detectLocalPlans, redactSecrets, readSafeStateText, invalidateConnectedSpendTrustReceipt, resolveSafeScanRoot, resolveSafeStateDirectory, subscriptionPlans, unsafeScanRootReason, selectProviderFinancialHeadlineRecords, writeSafeStateText, verifyConnectedSpendTrustReceipt, verifyConnectedSourceRegistryTrustReceipt, writeConnectedSpendTrustReceipt, loadDeadContext, sampleDeadContext, latestObservedWorkingDirectory, downgradeSampleUsageEvidence, isBundledSampleUsage, loadLocalAgentUsage, loadLocalAgentFinancialUsage, loadSampleUsageData, parseUsageRecord, scanLocalUsageSignals, buildMissingSourcePrompts, confirmMapping, createProviderConnectorStub, createLocalFolderSourceRegistry, createScanAuditLog, fetchProviderUsageRecords, addApprovedSource, normalizeSourceRegistry, downgradeUntrustedSourceRegistryClaims, buildSourceStatuses, slugifySourceId, financialEvidenceForRecords, formatSourceStatuses, readActivitySnapshot, recordActivitySnapshotRefreshFailure, sourceStatusDefinitions, writeActivitySnapshot } from "@agent-finops/core";
7
+ import { analyzeSpend, attributeUsageRecords, buildUsageGlance, buildActivitySnapshot, loadContextHealth, detectLocalCredentials, detectLocalPlans, redactSecrets, readSafeStateText, invalidateConnectedSpendTrustReceipt, resolveSafeScanRoot, resolveSafeStateDirectory, subscriptionPlans, unsafeScanRootReason, selectProviderFinancialHeadlineRecords, writeSafeStateText, verifyConnectedSpendTrustReceipt, verifyConnectedSourceRegistryTrustReceipt, writeConnectedSpendTrustReceipt, loadDeadContext, sampleDeadContext, latestObservedWorkingDirectory, downgradeSampleUsageEvidence, isBundledSampleUsage, loadLocalAgentUsage, loadLocalAgentFinancialUsage, localAgentFormatDescriptors, localAgentFormatLabel, loadSampleUsageData, parseUsageRecord, scanLocalUsageSignals, buildMissingSourcePrompts, confirmMapping, createProviderConnectorStub, createLocalFolderSourceRegistry, createScanAuditLog, fetchProviderUsageRecords, addApprovedSource, normalizeSourceRegistry, downgradeUntrustedSourceRegistryClaims, buildSourceStatuses, slugifySourceId, financialEvidenceForRecords, formatSourceStatuses, readActivitySnapshot, recordActivitySnapshotRefreshFailure, sourceStatusDefinitions, writeActivitySnapshot } from "@agent-finops/core";
8
8
  import { StatuslineInstallerError, installClaudeStatusline, uninstallClaudeStatusline } from "./statuslineInstaller.js";
9
9
  import { readStatuslineCache, renderStatusline } from "./statuslineRuntime.js";
10
10
  import { generateActionPlanMarkdown, generateApplyArtifactMarkdown, generateDemoPackageMarkdown, generateHtmlReport, generateMarkdownReport, generatePlainEnglishSummary, generatePolicyConfigDraftMarkdown, generateReportCardCaption, generateReportCardSvg, generateVerificationPlanMarkdown, groupByDimensions } from "@agent-finops/report";
@@ -556,7 +556,7 @@ async function doctorSourcesCommand(args) {
556
556
  localError = sanitizeSecretishError(error instanceof Error ? error.message : String(error));
557
557
  }
558
558
  const checkedAt = now.toISOString();
559
- for (const id of ["claude-code", "codex"]) {
559
+ for (const { id } of localAgentFormatDescriptors) {
560
560
  const records = (localLogs?.records ?? []).filter((record) => record.agentId === id);
561
561
  const evidence = financialEvidenceForRecords(records);
562
562
  const scan = localLogs?.sourceScans.find((entry) => entry.agent === id);
@@ -704,12 +704,12 @@ function localAgentDiagnosticSummary(diagnostics) {
704
704
  const unsupportedCount = unsupported
705
705
  .reduce((total, diagnostic) => total + diagnostic.count, 0);
706
706
  if (unsupportedCount > 0) {
707
- messages.push(`${unsupportedCount} ${unsupported[0].agent === "codex" ? "Codex" : "Claude Code"} token snapshot(s) lacked the input/output components required for pricing.`);
707
+ messages.push(`${unsupportedCount} ${localAgentFormatLabel(unsupported[0].agent)} token snapshot(s) lacked the input/output components required for pricing.`);
708
708
  }
709
709
  const malformedCount = malformed
710
710
  .reduce((total, diagnostic) => total + diagnostic.count, 0);
711
711
  if (malformedCount > 0) {
712
- messages.push(`${malformedCount} malformed JSONL line(s) were skipped in ${malformed[0].agent === "codex" ? "Codex" : "Claude Code"} transcripts.`);
712
+ messages.push(`${malformedCount} malformed JSONL line(s) were skipped in ${localAgentFormatLabel(malformed[0].agent)} transcripts.`);
713
713
  }
714
714
  return messages.length > 0 ? messages.join(" ") : undefined;
715
715
  }
@@ -1529,10 +1529,7 @@ function formatInitReceipt(input) {
1529
1529
  return `${plan.agent}: ${known} (${plan.billing})`;
1530
1530
  }).join("; ")
1531
1531
  : "none detected (billing mode remains unresolved)";
1532
- const sourceLines = (input.logs?.sourceScans ?? [
1533
- emptyInitSourceScan("claude-code"),
1534
- emptyInitSourceScan("codex")
1535
- ]).map((scan) => {
1532
+ const sourceLines = (input.logs?.sourceScans ?? localAgentFormatDescriptors.map((descriptor) => (emptyInitSourceScan(descriptor.id)))).map((scan) => {
1536
1533
  const agentRecords = records.filter((record) => record.agentId === scan.agent);
1537
1534
  const priced = agentRecords.filter((record) => typeof record.amountUsd === "number").length;
1538
1535
  const skipped = scan.filesSkippedBeforeWindow ?? 0;
@@ -228,9 +228,23 @@ export async function uninstallClaudeStatusline(options) {
228
228
  delete nextSettings.statusLine;
229
229
  }
230
230
  const removeSettingsFile = !receipt.priorFileExisted && Object.keys(nextSettings).length === 0;
231
+ let exactSettingsBackup;
232
+ if (receipt.priorFileExisted) {
233
+ const priorRaw = decodeUtf8Strict(backups.settings.bytes, "invalid-receipt", "The exact settings backup is not valid UTF-8.");
234
+ const priorSettings = parseJson(priorRaw, "invalid-receipt", "The exact settings backup is not strict finite JSON.");
235
+ if (!isJsonObject(priorSettings))
236
+ throw invalidReceiptShape();
237
+ const expectedInstalledSettings = cloneJson(priorSettings);
238
+ expectedInstalledSettings.statusLine = cloneJson(receipt.installedStatusLine);
239
+ const expectedInstalledBytes = serializeBoundedJson(expectedInstalledSettings, MAX_SETTINGS_BYTES, "invalid-receipt", "installed Claude settings");
240
+ if (bytesEqual(existing.bytes, expectedInstalledBytes)) {
241
+ exactSettingsBackup = backups.settings.bytes;
242
+ }
243
+ }
231
244
  const nextSettingsBytes = removeSettingsFile
232
245
  ? undefined
233
- : serializeBoundedJson(nextSettings, MAX_SETTINGS_BYTES, "unsafe-settings-file", "Claude settings");
246
+ : exactSettingsBackup ??
247
+ serializeBoundedJson(nextSettings, MAX_SETTINGS_BYTES, "unsafe-settings-file", "Claude settings");
234
248
  const settingsMutation = mutation(paths.settingsPath, existing, nextSettingsBytes, existing.mode ?? 0o600, false, "concurrent-edit");
235
249
  let runnerMutation;
236
250
  let runnerRemoved = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-spend-agent",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
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",
@@ -54,8 +54,8 @@
54
54
  "prepack": "npm run build"
55
55
  },
56
56
  "dependencies": {
57
- "@agent-finops/core": "0.7.0",
58
- "@agent-finops/report": "0.7.0",
57
+ "@agent-finops/core": "0.7.2",
58
+ "@agent-finops/report": "0.7.2",
59
59
  "yocto-spinner": "^1.2.0"
60
60
  }
61
61
  }