@agent-receipts/dashboard 0.2.6 → 0.2.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 (107) hide show
  1. package/package.json +1 -1
  2. package/standalone/apps/web/.env.production +2 -0
  3. package/standalone/apps/web/.next/BUILD_ID +1 -1
  4. package/standalone/apps/web/.next/app-build-manifest.json +47 -47
  5. package/standalone/apps/web/.next/app-path-routes-manifest.json +11 -11
  6. package/standalone/apps/web/.next/build-manifest.json +2 -2
  7. package/standalone/apps/web/.next/prerender-manifest.json +24 -24
  8. package/standalone/apps/web/.next/required-server-files.json +3 -1
  9. package/standalone/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  10. package/standalone/apps/web/.next/server/app/_not-found.html +2 -2
  11. package/standalone/apps/web/.next/server/app/_not-found.rsc +3 -3
  12. package/standalone/apps/web/.next/server/app/agents/[id]/page_client-reference-manifest.js +1 -1
  13. package/standalone/apps/web/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  14. package/standalone/apps/web/.next/server/app/agents.html +2 -2
  15. package/standalone/apps/web/.next/server/app/agents.rsc +3 -3
  16. package/standalone/apps/web/.next/server/app/api/agents/route.js +1 -1
  17. package/standalone/apps/web/.next/server/app/api/agents/route.js.nft.json +1 -1
  18. package/standalone/apps/web/.next/server/app/api/agents/route_client-reference-manifest.js +1 -1
  19. package/standalone/apps/web/.next/server/app/api/chains/[id]/route.js +1 -1
  20. package/standalone/apps/web/.next/server/app/api/chains/[id]/route.js.nft.json +1 -1
  21. package/standalone/apps/web/.next/server/app/api/chains/[id]/route_client-reference-manifest.js +1 -1
  22. package/standalone/apps/web/.next/server/app/api/cleanup/route.js +1 -1
  23. package/standalone/apps/web/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  24. package/standalone/apps/web/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  25. package/standalone/apps/web/.next/server/app/api/config/route.js +1 -1
  26. package/standalone/apps/web/.next/server/app/api/config/route.js.nft.json +1 -1
  27. package/standalone/apps/web/.next/server/app/api/config/route_client-reference-manifest.js +1 -1
  28. package/standalone/apps/web/.next/server/app/api/invoices/route.js +1 -1
  29. package/standalone/apps/web/.next/server/app/api/invoices/route.js.nft.json +1 -1
  30. package/standalone/apps/web/.next/server/app/api/invoices/route_client-reference-manifest.js +1 -1
  31. package/standalone/apps/web/.next/server/app/api/judgments/route.js +1 -1
  32. package/standalone/apps/web/.next/server/app/api/judgments/route.js.nft.json +1 -1
  33. package/standalone/apps/web/.next/server/app/api/judgments/route_client-reference-manifest.js +1 -1
  34. package/standalone/apps/web/.next/server/app/api/receipts/[id]/route.js +1 -1
  35. package/standalone/apps/web/.next/server/app/api/receipts/[id]/route.js.nft.json +1 -1
  36. package/standalone/apps/web/.next/server/app/api/receipts/[id]/route_client-reference-manifest.js +1 -1
  37. package/standalone/apps/web/.next/server/app/api/receipts/route.js +1 -1
  38. package/standalone/apps/web/.next/server/app/api/receipts/route.js.nft.json +1 -1
  39. package/standalone/apps/web/.next/server/app/api/receipts/route_client-reference-manifest.js +1 -1
  40. package/standalone/apps/web/.next/server/app/api/search/route.js +1 -1
  41. package/standalone/apps/web/.next/server/app/api/search/route.js.nft.json +1 -1
  42. package/standalone/apps/web/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  43. package/standalone/apps/web/.next/server/app/api/stats/route.js +1 -1
  44. package/standalone/apps/web/.next/server/app/api/stats/route.js.nft.json +1 -1
  45. package/standalone/apps/web/.next/server/app/api/stats/route_client-reference-manifest.js +1 -1
  46. package/standalone/apps/web/.next/server/app/api/verify/route.js +1 -1
  47. package/standalone/apps/web/.next/server/app/api/verify/route.js.nft.json +1 -1
  48. package/standalone/apps/web/.next/server/app/api/verify/route_client-reference-manifest.js +1 -1
  49. package/standalone/apps/web/.next/server/app/chains/[id]/page_client-reference-manifest.js +1 -1
  50. package/standalone/apps/web/.next/server/app/chains/page_client-reference-manifest.js +1 -1
  51. package/standalone/apps/web/.next/server/app/chains.html +2 -2
  52. package/standalone/apps/web/.next/server/app/chains.rsc +4 -4
  53. package/standalone/apps/web/.next/server/app/constraints/page_client-reference-manifest.js +1 -1
  54. package/standalone/apps/web/.next/server/app/constraints.html +2 -2
  55. package/standalone/apps/web/.next/server/app/constraints.rsc +4 -4
  56. package/standalone/apps/web/.next/server/app/index.html +2 -2
  57. package/standalone/apps/web/.next/server/app/index.rsc +3 -3
  58. package/standalone/apps/web/.next/server/app/invoices/page_client-reference-manifest.js +1 -1
  59. package/standalone/apps/web/.next/server/app/invoices.html +2 -2
  60. package/standalone/apps/web/.next/server/app/invoices.rsc +3 -3
  61. package/standalone/apps/web/.next/server/app/judgments/page_client-reference-manifest.js +1 -1
  62. package/standalone/apps/web/.next/server/app/judgments.html +2 -2
  63. package/standalone/apps/web/.next/server/app/judgments.rsc +4 -4
  64. package/standalone/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  65. package/standalone/apps/web/.next/server/app/receipts/[id]/page_client-reference-manifest.js +1 -1
  66. package/standalone/apps/web/.next/server/app/receipts/page.js +1 -1
  67. package/standalone/apps/web/.next/server/app/receipts/page_client-reference-manifest.js +1 -1
  68. package/standalone/apps/web/.next/server/app/receipts.html +2 -2
  69. package/standalone/apps/web/.next/server/app/receipts.rsc +4 -4
  70. package/standalone/apps/web/.next/server/app/settings/page.js +1 -1
  71. package/standalone/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  72. package/standalone/apps/web/.next/server/app/settings.html +2 -2
  73. package/standalone/apps/web/.next/server/app/settings.rsc +4 -4
  74. package/standalone/apps/web/.next/server/app/verify/page_client-reference-manifest.js +1 -1
  75. package/standalone/apps/web/.next/server/app/verify.html +2 -2
  76. package/standalone/apps/web/.next/server/app/verify.rsc +3 -3
  77. package/standalone/apps/web/.next/server/app-paths-manifest.json +11 -11
  78. package/standalone/apps/web/.next/server/chunks/236.js +1 -0
  79. package/standalone/apps/web/.next/server/chunks/578.js +1 -0
  80. package/standalone/apps/web/.next/server/chunks/798.js +1 -0
  81. package/standalone/apps/web/.next/server/chunks/803.js +189 -0
  82. package/standalone/apps/web/.next/server/chunks/870.js +2 -2
  83. package/standalone/apps/web/.next/server/chunks/872.js +1 -0
  84. package/standalone/apps/web/.next/server/chunks/99.js +1 -0
  85. package/standalone/apps/web/.next/server/pages/404.html +2 -2
  86. package/standalone/apps/web/.next/server/pages/500.html +1 -1
  87. package/standalone/apps/web/.next/server/pages/_error.js +2 -2
  88. package/standalone/apps/web/.next/server/server-reference-manifest.json +1 -1
  89. package/standalone/apps/web/.next/static/chunks/app/agents/[id]/{page-6072c54c4f907f32.js → page-c0e1718cad311434.js} +1 -1
  90. package/standalone/apps/web/.next/static/chunks/app/chains/{page-69ef1e730d961039.js → page-d0b634ca7d0aa92d.js} +1 -1
  91. package/standalone/apps/web/.next/static/chunks/app/constraints/{page-05d35b57f9c424db.js → page-6baf6f176d4a9e3d.js} +1 -1
  92. package/standalone/apps/web/.next/static/chunks/app/judgments/{page-9715df3ce30f24c0.js → page-22c741e87fc41908.js} +1 -1
  93. package/standalone/apps/web/.next/static/chunks/app/layout-53a87fc182f46ce0.js +1 -0
  94. package/standalone/apps/web/.next/static/chunks/app/receipts/{page-a788cdbaf3879d37.js → page-ef79c1140a9c42e6.js} +1 -1
  95. package/standalone/apps/web/.next/static/chunks/app/settings/{page-154ca65062c2628d.js → page-8f1d3f326821cc04.js} +1 -1
  96. package/standalone/apps/web/.next/static/css/{acaddf5367ce801c.css → c89a04ca9481014a.css} +1 -1
  97. package/standalone/apps/web/server.js +1 -1
  98. package/standalone/apps/web/src/lib/demo-store.ts +121 -0
  99. package/standalone/apps/web/src/lib/sdk-server.ts +46 -0
  100. package/standalone/packages/crypto/package.json +1 -1
  101. package/standalone/packages/mcp-server/dist/index.js +1738 -0
  102. package/standalone/packages/mcp-server/package.json +4 -2
  103. package/standalone/apps/web/.next/server/chunks/350.js +0 -134
  104. package/standalone/apps/web/.next/server/chunks/998.js +0 -1
  105. package/standalone/apps/web/.next/static/chunks/app/layout-66d4997939026d7c.js +0 -1
  106. /package/standalone/apps/web/.next/static/{XRffp10LMCCMingivp622 → QFwgmBDt10h_GclOFqIUT}/_buildManifest.js +0 -0
  107. /package/standalone/apps/web/.next/static/{XRffp10LMCCMingivp622 → QFwgmBDt10h_GclOFqIUT}/_ssgManifest.js +0 -0
@@ -0,0 +1,1738 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/storage/sqlite-receipt-store.ts
9
+ import { readdir, mkdir } from "fs/promises";
10
+ import { join } from "path";
11
+ import Database from "better-sqlite3";
12
+ var SORTABLE_COLUMNS = /* @__PURE__ */ new Set([
13
+ "timestamp",
14
+ "completed_at",
15
+ "cost_usd",
16
+ "latency_ms",
17
+ "tokens_in",
18
+ "tokens_out",
19
+ "confidence"
20
+ ]);
21
+ var SqliteReceiptStore = class {
22
+ constructor(dataDir) {
23
+ this.dataDir = dataDir;
24
+ this.dbPath = join(dataDir, "receipts.db");
25
+ this.receiptsDir = join(dataDir, "receipts");
26
+ }
27
+ dbPath;
28
+ receiptsDir;
29
+ db;
30
+ async init() {
31
+ await mkdir(this.dataDir, { recursive: true });
32
+ this.db = new Database(this.dbPath);
33
+ this.db.pragma("journal_mode = WAL");
34
+ this.db.pragma("foreign_keys = ON");
35
+ this.db.exec(`
36
+ CREATE TABLE IF NOT EXISTS receipts (
37
+ receipt_id TEXT PRIMARY KEY,
38
+ chain_id TEXT NOT NULL,
39
+ parent_receipt_id TEXT,
40
+ receipt_type TEXT NOT NULL,
41
+ agent_id TEXT NOT NULL,
42
+ org_id TEXT NOT NULL,
43
+ action TEXT NOT NULL,
44
+ status TEXT NOT NULL,
45
+ environment TEXT NOT NULL,
46
+ input_hash TEXT NOT NULL,
47
+ output_hash TEXT,
48
+ model TEXT,
49
+ tokens_in INTEGER,
50
+ tokens_out INTEGER,
51
+ cost_usd REAL,
52
+ latency_ms INTEGER,
53
+ confidence REAL,
54
+ timestamp TEXT NOT NULL,
55
+ completed_at TEXT,
56
+ expires_at TEXT,
57
+ tags TEXT,
58
+ data TEXT NOT NULL
59
+ );
60
+
61
+ CREATE INDEX IF NOT EXISTS idx_receipts_agent_id ON receipts(agent_id);
62
+ CREATE INDEX IF NOT EXISTS idx_receipts_chain_id ON receipts(chain_id);
63
+ CREATE INDEX IF NOT EXISTS idx_receipts_status ON receipts(status);
64
+ CREATE INDEX IF NOT EXISTS idx_receipts_action ON receipts(action);
65
+ CREATE INDEX IF NOT EXISTS idx_receipts_timestamp ON receipts(timestamp);
66
+ CREATE INDEX IF NOT EXISTS idx_receipts_environment ON receipts(environment);
67
+ CREATE INDEX IF NOT EXISTS idx_receipts_receipt_type ON receipts(receipt_type);
68
+ CREATE INDEX IF NOT EXISTS idx_receipts_expires_at ON receipts(expires_at);
69
+ CREATE INDEX IF NOT EXISTS idx_receipts_parent_receipt_id ON receipts(parent_receipt_id);
70
+ `);
71
+ await this.migrateJsonFiles();
72
+ }
73
+ async migrateJsonFiles() {
74
+ let files;
75
+ try {
76
+ files = await readdir(this.receiptsDir);
77
+ } catch {
78
+ return;
79
+ }
80
+ const jsonFiles = files.filter((f) => f.endsWith(".json") && !f.startsWith("."));
81
+ if (jsonFiles.length === 0) return;
82
+ const insert = this.db.prepare(`INSERT OR IGNORE INTO receipts (
83
+ receipt_id, chain_id, parent_receipt_id, receipt_type, agent_id, org_id,
84
+ action, status, environment, input_hash, output_hash, model,
85
+ tokens_in, tokens_out, cost_usd, latency_ms, confidence,
86
+ timestamp, completed_at, expires_at, tags, data
87
+ ) VALUES (
88
+ @receipt_id, @chain_id, @parent_receipt_id, @receipt_type, @agent_id, @org_id,
89
+ @action, @status, @environment, @input_hash, @output_hash, @model,
90
+ @tokens_in, @tokens_out, @cost_usd, @latency_ms, @confidence,
91
+ @timestamp, @completed_at, @expires_at, @tags, @data
92
+ )`);
93
+ let migrated = 0;
94
+ const tx = this.db.transaction(() => {
95
+ for (const file of jsonFiles) {
96
+ try {
97
+ const fs = __require("fs");
98
+ const raw = fs.readFileSync(join(this.receiptsDir, file), "utf-8");
99
+ const receipt = JSON.parse(raw);
100
+ insert.run(this.toRow(receipt));
101
+ migrated++;
102
+ } catch {
103
+ }
104
+ }
105
+ });
106
+ tx();
107
+ if (migrated > 0) {
108
+ console.log(`Migrated ${migrated} receipts from JSON files to SQLite`);
109
+ }
110
+ }
111
+ toRow(receipt) {
112
+ const meta = receipt.metadata;
113
+ return {
114
+ receipt_id: receipt.receipt_id,
115
+ chain_id: receipt.chain_id,
116
+ parent_receipt_id: receipt.parent_receipt_id,
117
+ receipt_type: receipt.receipt_type,
118
+ agent_id: receipt.agent_id,
119
+ org_id: receipt.org_id,
120
+ action: receipt.action,
121
+ status: receipt.status,
122
+ environment: receipt.environment,
123
+ input_hash: receipt.input_hash,
124
+ output_hash: receipt.output_hash,
125
+ model: receipt.model,
126
+ tokens_in: receipt.tokens_in,
127
+ tokens_out: receipt.tokens_out,
128
+ cost_usd: receipt.cost_usd,
129
+ latency_ms: receipt.latency_ms,
130
+ confidence: receipt.confidence,
131
+ timestamp: receipt.timestamp,
132
+ completed_at: receipt.completed_at,
133
+ expires_at: meta?.expires_at ?? null,
134
+ tags: receipt.tags ? JSON.stringify(receipt.tags) : null,
135
+ data: JSON.stringify(receipt)
136
+ };
137
+ }
138
+ async save(receipt) {
139
+ const row = this.toRow(receipt);
140
+ this.db.prepare(`INSERT OR REPLACE INTO receipts (
141
+ receipt_id, chain_id, parent_receipt_id, receipt_type, agent_id, org_id,
142
+ action, status, environment, input_hash, output_hash, model,
143
+ tokens_in, tokens_out, cost_usd, latency_ms, confidence,
144
+ timestamp, completed_at, expires_at, tags, data
145
+ ) VALUES (
146
+ @receipt_id, @chain_id, @parent_receipt_id, @receipt_type, @agent_id, @org_id,
147
+ @action, @status, @environment, @input_hash, @output_hash, @model,
148
+ @tokens_in, @tokens_out, @cost_usd, @latency_ms, @confidence,
149
+ @timestamp, @completed_at, @expires_at, @tags, @data
150
+ )`).run(row);
151
+ }
152
+ async get(receiptId) {
153
+ const row = this.db.prepare("SELECT data FROM receipts WHERE receipt_id = ?").get(receiptId);
154
+ if (!row) return null;
155
+ return JSON.parse(row.data);
156
+ }
157
+ async exists(receiptId) {
158
+ const row = this.db.prepare("SELECT 1 FROM receipts WHERE receipt_id = ?").get(receiptId);
159
+ return row !== void 0;
160
+ }
161
+ async list(filter, page = 1, limit = 50, sort = "timestamp:desc") {
162
+ const { where, params } = this.buildWhere(filter);
163
+ const countRow = this.db.prepare(`SELECT COUNT(*) as cnt FROM receipts ${where}`).get(...params);
164
+ const total = countRow.cnt;
165
+ const [sortField, sortDir] = sort.split(":");
166
+ const col = sortField === "created_at" ? "timestamp" : sortField;
167
+ const safeCol = SORTABLE_COLUMNS.has(col) ? col : "timestamp";
168
+ const dir = sortDir === "asc" ? "ASC" : "DESC";
169
+ const orderClause = `ORDER BY CASE WHEN ${safeCol} IS NULL THEN 1 ELSE 0 END, ${safeCol} ${dir}`;
170
+ const offset = (page - 1) * limit;
171
+ const rows = this.db.prepare(
172
+ `SELECT data FROM receipts ${where} ${orderClause} LIMIT ? OFFSET ?`
173
+ ).all(...params, limit, offset);
174
+ const totalPages = Math.max(1, Math.ceil(total / limit));
175
+ return {
176
+ data: rows.map((r) => JSON.parse(r.data)),
177
+ pagination: {
178
+ page,
179
+ limit,
180
+ total,
181
+ total_pages: totalPages,
182
+ has_next: page < totalPages,
183
+ has_prev: page > 1
184
+ }
185
+ };
186
+ }
187
+ async getChain(chainId) {
188
+ const result = await this.list({ chain_id: chainId }, 1, 1e3, "timestamp:asc");
189
+ return result.data;
190
+ }
191
+ async count(filter) {
192
+ const { where, params } = this.buildWhere(filter);
193
+ const row = this.db.prepare(`SELECT COUNT(*) as cnt FROM receipts ${where}`).get(...params);
194
+ return row.cnt;
195
+ }
196
+ async delete(receiptId) {
197
+ const result = this.db.prepare("DELETE FROM receipts WHERE receipt_id = ?").run(receiptId);
198
+ return result.changes > 0;
199
+ }
200
+ async cleanup() {
201
+ const now = (/* @__PURE__ */ new Date()).toISOString();
202
+ const totalRow = this.db.prepare("SELECT COUNT(*) as cnt FROM receipts").get();
203
+ const total = totalRow.cnt;
204
+ const result = this.db.prepare(
205
+ "DELETE FROM receipts WHERE expires_at IS NOT NULL AND expires_at < ?"
206
+ ).run(now);
207
+ return { deleted: result.changes, total };
208
+ }
209
+ buildWhere(filter) {
210
+ if (!filter) return { where: "", params: [] };
211
+ const conditions = [];
212
+ const params = [];
213
+ if (filter.agent_id) {
214
+ conditions.push("agent_id = ?");
215
+ params.push(filter.agent_id);
216
+ }
217
+ if (filter.action) {
218
+ conditions.push("action = ?");
219
+ params.push(filter.action);
220
+ }
221
+ if (filter.status) {
222
+ conditions.push("status = ?");
223
+ params.push(filter.status);
224
+ }
225
+ if (filter.environment) {
226
+ conditions.push("environment = ?");
227
+ params.push(filter.environment);
228
+ }
229
+ if (filter.receipt_type) {
230
+ conditions.push("receipt_type = ?");
231
+ params.push(filter.receipt_type);
232
+ }
233
+ if (filter.chain_id) {
234
+ conditions.push("chain_id = ?");
235
+ params.push(filter.chain_id);
236
+ }
237
+ if (filter.parent_receipt_id) {
238
+ conditions.push("parent_receipt_id = ?");
239
+ params.push(filter.parent_receipt_id);
240
+ }
241
+ if (filter.tag) {
242
+ conditions.push("tags LIKE ?");
243
+ params.push(`%"${filter.tag}"%`);
244
+ }
245
+ if (filter.from) {
246
+ conditions.push("timestamp >= ?");
247
+ params.push(filter.from);
248
+ }
249
+ if (filter.to) {
250
+ conditions.push("timestamp <= ?");
251
+ params.push(filter.to);
252
+ }
253
+ if (conditions.length === 0) return { where: "", params: [] };
254
+ return { where: `WHERE ${conditions.join(" AND ")}`, params };
255
+ }
256
+ };
257
+
258
+ // src/storage/receipt-store.ts
259
+ import { readdir as readdir2, readFile as readFile2, writeFile, rename, mkdir as mkdir2, unlink } from "fs/promises";
260
+ import { join as join2 } from "path";
261
+ import { randomBytes } from "crypto";
262
+ var ReceiptStore = class {
263
+ receiptsDir;
264
+ constructor(dataDir) {
265
+ this.receiptsDir = join2(dataDir, "receipts");
266
+ }
267
+ async init() {
268
+ await mkdir2(this.receiptsDir, { recursive: true });
269
+ }
270
+ async save(receipt) {
271
+ await this.init();
272
+ const filePath = join2(this.receiptsDir, `${receipt.receipt_id}.json`);
273
+ const tmpPath = join2(this.receiptsDir, `.tmp_${randomBytes(8).toString("hex")}.json`);
274
+ const data = JSON.stringify(receipt, null, 2);
275
+ await writeFile(tmpPath, data, "utf-8");
276
+ await rename(tmpPath, filePath);
277
+ }
278
+ async get(receiptId) {
279
+ try {
280
+ const filePath = join2(this.receiptsDir, `${receiptId}.json`);
281
+ const data = await readFile2(filePath, "utf-8");
282
+ return JSON.parse(data);
283
+ } catch {
284
+ return null;
285
+ }
286
+ }
287
+ async exists(receiptId) {
288
+ const receipt = await this.get(receiptId);
289
+ return receipt !== null;
290
+ }
291
+ async list(filter, page = 1, limit = 50, sort = "timestamp:desc") {
292
+ await this.init();
293
+ const files = await readdir2(this.receiptsDir);
294
+ const receiptFiles = files.filter((f) => f.endsWith(".json") && !f.startsWith("."));
295
+ let receipts = [];
296
+ for (const file of receiptFiles) {
297
+ try {
298
+ const data = await readFile2(join2(this.receiptsDir, file), "utf-8");
299
+ receipts.push(JSON.parse(data));
300
+ } catch {
301
+ }
302
+ }
303
+ if (filter) {
304
+ receipts = receipts.filter((r) => {
305
+ if (filter.agent_id && r.agent_id !== filter.agent_id) return false;
306
+ if (filter.action && r.action !== filter.action) return false;
307
+ if (filter.status && r.status !== filter.status) return false;
308
+ if (filter.environment && r.environment !== filter.environment) return false;
309
+ if (filter.receipt_type && r.receipt_type !== filter.receipt_type) return false;
310
+ if (filter.chain_id && r.chain_id !== filter.chain_id) return false;
311
+ if (filter.parent_receipt_id && r.parent_receipt_id !== filter.parent_receipt_id) return false;
312
+ if (filter.tag && (!r.tags || !r.tags.includes(filter.tag))) return false;
313
+ if (filter.from && r.timestamp < filter.from) return false;
314
+ if (filter.to && r.timestamp > filter.to) return false;
315
+ return true;
316
+ });
317
+ }
318
+ const [sortField, sortDir] = sort.split(":");
319
+ receipts.sort((a, b) => {
320
+ const aVal = a[sortField === "created_at" ? "timestamp" : sortField];
321
+ const bVal = b[sortField === "created_at" ? "timestamp" : sortField];
322
+ if (aVal === null || aVal === void 0) return 1;
323
+ if (bVal === null || bVal === void 0) return -1;
324
+ const cmp = String(aVal).localeCompare(String(bVal));
325
+ return sortDir === "desc" ? -cmp : cmp;
326
+ });
327
+ const total = receipts.length;
328
+ const totalPages = Math.max(1, Math.ceil(total / limit));
329
+ const start = (page - 1) * limit;
330
+ const paged = receipts.slice(start, start + limit);
331
+ return {
332
+ data: paged,
333
+ pagination: {
334
+ page,
335
+ limit,
336
+ total,
337
+ total_pages: totalPages,
338
+ has_next: page < totalPages,
339
+ has_prev: page > 1
340
+ }
341
+ };
342
+ }
343
+ async getChain(chainId) {
344
+ const result = await this.list({ chain_id: chainId }, 1, 1e3, "timestamp:asc");
345
+ return result.data;
346
+ }
347
+ async count(filter) {
348
+ const result = await this.list(filter, 1, 1);
349
+ return result.pagination.total;
350
+ }
351
+ async delete(receiptId) {
352
+ try {
353
+ const filePath = join2(this.receiptsDir, `${receiptId}.json`);
354
+ await unlink(filePath);
355
+ return true;
356
+ } catch {
357
+ return false;
358
+ }
359
+ }
360
+ async cleanup() {
361
+ const now = (/* @__PURE__ */ new Date()).toISOString();
362
+ const allReceipts = await this.list(void 0, 1, 1e5);
363
+ let deleted = 0;
364
+ for (const receipt of allReceipts.data) {
365
+ const expiresAt = receipt.metadata?.expires_at;
366
+ if (expiresAt && expiresAt < now) {
367
+ await this.delete(receipt.receipt_id);
368
+ deleted++;
369
+ }
370
+ }
371
+ return { deleted, total: allReceipts.data.length };
372
+ }
373
+ };
374
+
375
+ // src/storage/key-manager.ts
376
+ import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir3, chmod } from "fs/promises";
377
+ import { join as join3 } from "path";
378
+ import { generateKeyPair, getPublicKeyFromPrivate } from "@agent-receipts/crypto";
379
+ var KeyManager = class {
380
+ keysDir;
381
+ privateKey = null;
382
+ publicKey = null;
383
+ constructor(dataDir) {
384
+ this.keysDir = join3(dataDir, "keys");
385
+ }
386
+ async init() {
387
+ await mkdir3(this.keysDir, { recursive: true });
388
+ await this.loadKeys();
389
+ }
390
+ async loadKeys() {
391
+ const envKey = process.env["RECEIPT_SIGNING_PRIVATE_KEY"];
392
+ if (envKey) {
393
+ this.privateKey = envKey;
394
+ this.publicKey = getPublicKeyFromPrivate(envKey);
395
+ return;
396
+ }
397
+ const privateKeyPath = join3(this.keysDir, "private.key");
398
+ try {
399
+ this.privateKey = (await readFile3(privateKeyPath, "utf-8")).trim();
400
+ this.publicKey = getPublicKeyFromPrivate(this.privateKey);
401
+ return;
402
+ } catch {
403
+ }
404
+ const keyPair = generateKeyPair();
405
+ this.privateKey = keyPair.privateKey;
406
+ this.publicKey = keyPair.publicKey;
407
+ await writeFile2(privateKeyPath, this.privateKey, { encoding: "utf-8", mode: 384 });
408
+ await chmod(privateKeyPath, 384);
409
+ const publicKeyPath = join3(this.keysDir, "public.key");
410
+ await writeFile2(publicKeyPath, this.publicKey, "utf-8");
411
+ }
412
+ getPrivateKey() {
413
+ if (!this.privateKey) {
414
+ throw new Error("KeyManager not initialized \u2014 call init() first");
415
+ }
416
+ return this.privateKey;
417
+ }
418
+ getPublicKey() {
419
+ if (!this.publicKey) {
420
+ throw new Error("KeyManager not initialized \u2014 call init() first");
421
+ }
422
+ return this.publicKey;
423
+ }
424
+ };
425
+
426
+ // src/storage/config-manager.ts
427
+ import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
428
+ import { join as join4, dirname } from "path";
429
+ import { homedir } from "os";
430
+ var DEFAULT_CONFIG = {
431
+ agentId: "local-agent",
432
+ orgId: "local-org",
433
+ environment: "production"
434
+ };
435
+ var ConfigManager = class {
436
+ configPath;
437
+ config = { ...DEFAULT_CONFIG };
438
+ constructor(dataDir) {
439
+ this.configPath = join4(dataDir, "config.json");
440
+ }
441
+ async init() {
442
+ await mkdir4(dirname(this.configPath), { recursive: true });
443
+ await this.load();
444
+ }
445
+ async load() {
446
+ try {
447
+ const data = await readFile4(this.configPath, "utf-8");
448
+ const saved = JSON.parse(data);
449
+ this.config = { ...DEFAULT_CONFIG, ...saved };
450
+ } catch {
451
+ }
452
+ const envAgentId = process.env["AGENT_RECEIPTS_AGENT_ID"];
453
+ if (envAgentId) this.config.agentId = envAgentId;
454
+ const envOrgId = process.env["AGENT_RECEIPTS_ORG_ID"];
455
+ if (envOrgId) this.config.orgId = envOrgId;
456
+ const envEnvironment = process.env["AGENT_RECEIPTS_ENVIRONMENT"];
457
+ if (envEnvironment === "development" || envEnvironment === "production" || envEnvironment === "staging" || envEnvironment === "test") {
458
+ this.config.environment = envEnvironment;
459
+ }
460
+ }
461
+ async save() {
462
+ await mkdir4(dirname(this.configPath), { recursive: true });
463
+ await writeFile3(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
464
+ }
465
+ getConfig() {
466
+ return { ...this.config };
467
+ }
468
+ async update(partial) {
469
+ this.config = { ...this.config, ...partial };
470
+ await this.save();
471
+ }
472
+ static getDefaultDataDir() {
473
+ return process.env["AGENT_RECEIPTS_DATA_DIR"] ?? join4(homedir(), ".agent-receipts");
474
+ }
475
+ };
476
+
477
+ // src/engine/receipt-engine.ts
478
+ import { nanoid } from "nanoid";
479
+ import { ActionReceipt } from "@agent-receipts/schema";
480
+ import { signReceipt, verifyReceipt, getSignablePayload } from "@agent-receipts/crypto";
481
+
482
+ // src/hash.ts
483
+ import { createHash } from "crypto";
484
+ function deepCanonicalize(value) {
485
+ if (value === null || value === void 0) {
486
+ return value;
487
+ }
488
+ if (Array.isArray(value)) {
489
+ return value.map(deepCanonicalize);
490
+ }
491
+ if (typeof value === "object") {
492
+ const sorted = {};
493
+ for (const key of Object.keys(value).sort()) {
494
+ sorted[key] = deepCanonicalize(value[key]);
495
+ }
496
+ return sorted;
497
+ }
498
+ return value;
499
+ }
500
+ function hashData(data) {
501
+ const canonical = JSON.stringify(deepCanonicalize(data)) ?? "null";
502
+ const hash = createHash("sha256").update(canonical).digest("hex");
503
+ return `sha256:${hash}`;
504
+ }
505
+
506
+ // src/engine/json-schema-validator.ts
507
+ function validateJsonSchema(data, schema, path = "") {
508
+ const errors = [];
509
+ if (Object.keys(schema).length === 0) {
510
+ return errors;
511
+ }
512
+ if (schema.type !== void 0) {
513
+ const expectedType = schema.type;
514
+ if (!checkType(data, expectedType)) {
515
+ errors.push(`${path || "."}: expected type ${expectedType}, got ${getType(data)}`);
516
+ return errors;
517
+ }
518
+ }
519
+ if (schema.enum !== void 0) {
520
+ const allowed = schema.enum;
521
+ if (!allowed.some((v) => JSON.stringify(v) === JSON.stringify(data))) {
522
+ errors.push(`${path || "."}: value ${JSON.stringify(data)} not in enum ${JSON.stringify(allowed)}`);
523
+ }
524
+ }
525
+ if (typeof data === "string") {
526
+ if (schema.minLength !== void 0 && data.length < schema.minLength) {
527
+ errors.push(`${path || "."}: string length ${data.length} < minLength ${schema.minLength}`);
528
+ }
529
+ if (schema.maxLength !== void 0 && data.length > schema.maxLength) {
530
+ errors.push(`${path || "."}: string length ${data.length} > maxLength ${schema.maxLength}`);
531
+ }
532
+ if (schema.pattern !== void 0) {
533
+ const regex = new RegExp(schema.pattern);
534
+ if (!regex.test(data)) {
535
+ errors.push(`${path || "."}: string does not match pattern ${schema.pattern}`);
536
+ }
537
+ }
538
+ }
539
+ if (typeof data === "number") {
540
+ if (schema.minimum !== void 0 && data < schema.minimum) {
541
+ errors.push(`${path || "."}: ${data} < minimum ${schema.minimum}`);
542
+ }
543
+ if (schema.maximum !== void 0 && data > schema.maximum) {
544
+ errors.push(`${path || "."}: ${data} > maximum ${schema.maximum}`);
545
+ }
546
+ }
547
+ if (typeof data === "object" && data !== null && !Array.isArray(data)) {
548
+ const obj = data;
549
+ if (schema.required !== void 0) {
550
+ const required = schema.required;
551
+ for (const key of required) {
552
+ if (!(key in obj)) {
553
+ errors.push(`${path || "."}: missing required property "${key}"`);
554
+ }
555
+ }
556
+ }
557
+ if (schema.properties !== void 0) {
558
+ const props = schema.properties;
559
+ for (const [key, propSchema] of Object.entries(props)) {
560
+ if (key in obj) {
561
+ const propErrors = validateJsonSchema(obj[key], propSchema, `${path}.${key}`);
562
+ errors.push(...propErrors);
563
+ }
564
+ }
565
+ }
566
+ if (schema.additionalProperties === false && schema.properties !== void 0) {
567
+ const allowedKeys = new Set(Object.keys(schema.properties));
568
+ for (const key of Object.keys(obj)) {
569
+ if (!allowedKeys.has(key)) {
570
+ errors.push(`${path || "."}: additional property "${key}" not allowed`);
571
+ }
572
+ }
573
+ }
574
+ }
575
+ if (Array.isArray(data)) {
576
+ if (schema.minItems !== void 0 && data.length < schema.minItems) {
577
+ errors.push(`${path || "."}: array length ${data.length} < minItems ${schema.minItems}`);
578
+ }
579
+ if (schema.maxItems !== void 0 && data.length > schema.maxItems) {
580
+ errors.push(`${path || "."}: array length ${data.length} > maxItems ${schema.maxItems}`);
581
+ }
582
+ if (schema.items !== void 0) {
583
+ const itemSchema = schema.items;
584
+ for (let i = 0; i < data.length; i++) {
585
+ const itemErrors = validateJsonSchema(data[i], itemSchema, `${path}[${i}]`);
586
+ errors.push(...itemErrors);
587
+ }
588
+ }
589
+ }
590
+ return errors;
591
+ }
592
+ function checkType(data, expectedType) {
593
+ switch (expectedType) {
594
+ case "string":
595
+ return typeof data === "string";
596
+ case "number":
597
+ return typeof data === "number";
598
+ case "integer":
599
+ return typeof data === "number" && Number.isInteger(data);
600
+ case "boolean":
601
+ return typeof data === "boolean";
602
+ case "object":
603
+ return typeof data === "object" && data !== null && !Array.isArray(data);
604
+ case "array":
605
+ return Array.isArray(data);
606
+ case "null":
607
+ return data === null;
608
+ default:
609
+ return false;
610
+ }
611
+ }
612
+ function getType(data) {
613
+ if (data === null) return "null";
614
+ if (Array.isArray(data)) return "array";
615
+ return typeof data;
616
+ }
617
+
618
+ // src/engine/constraint-evaluator.ts
619
+ var RECEIPT_FIELD_NAMES = /* @__PURE__ */ new Set([
620
+ "receipt_id",
621
+ "parent_receipt_id",
622
+ "chain_id",
623
+ "receipt_type",
624
+ "agent_id",
625
+ "org_id",
626
+ "action",
627
+ "input_hash",
628
+ "output_hash",
629
+ "output_summary",
630
+ "model",
631
+ "tokens_in",
632
+ "tokens_out",
633
+ "cost_usd",
634
+ "latency_ms",
635
+ "tool_calls",
636
+ "timestamp",
637
+ "completed_at",
638
+ "status",
639
+ "error",
640
+ "environment",
641
+ "tags",
642
+ "constraints",
643
+ "constraint_result",
644
+ "signature",
645
+ "verify_url",
646
+ "callback_verified",
647
+ "confidence",
648
+ "metadata"
649
+ ]);
650
+ function evaluateMaxLatencyMs(receipt, constraint) {
651
+ const expected = constraint.value;
652
+ const actual = receipt.latency_ms;
653
+ if (actual === null || actual === void 0) {
654
+ return {
655
+ type: constraint.type,
656
+ passed: false,
657
+ expected,
658
+ actual: null,
659
+ message: constraint.message ?? "latency_ms is null"
660
+ };
661
+ }
662
+ return {
663
+ type: constraint.type,
664
+ passed: actual <= expected,
665
+ expected,
666
+ actual,
667
+ message: constraint.message
668
+ };
669
+ }
670
+ function evaluateMaxCostUsd(receipt, constraint) {
671
+ const expected = constraint.value;
672
+ const actual = receipt.cost_usd;
673
+ if (actual === null || actual === void 0) {
674
+ return {
675
+ type: constraint.type,
676
+ passed: false,
677
+ expected,
678
+ actual: null,
679
+ message: constraint.message ?? "cost_usd is null"
680
+ };
681
+ }
682
+ return {
683
+ type: constraint.type,
684
+ passed: actual <= expected,
685
+ expected,
686
+ actual,
687
+ message: constraint.message
688
+ };
689
+ }
690
+ function evaluateMinConfidence(receipt, constraint) {
691
+ const expected = constraint.value;
692
+ const actual = receipt.confidence;
693
+ if (actual === null || actual === void 0) {
694
+ return {
695
+ type: constraint.type,
696
+ passed: false,
697
+ expected,
698
+ actual: null,
699
+ message: constraint.message ?? "confidence is null"
700
+ };
701
+ }
702
+ return {
703
+ type: constraint.type,
704
+ passed: actual >= expected,
705
+ expected,
706
+ actual,
707
+ message: constraint.message
708
+ };
709
+ }
710
+ function evaluateRequiredFields(receipt, constraint) {
711
+ const fields = constraint.value;
712
+ if (!Array.isArray(fields)) {
713
+ return {
714
+ type: constraint.type,
715
+ passed: false,
716
+ expected: fields,
717
+ actual: null,
718
+ message: constraint.message ?? "value must be an array of field names"
719
+ };
720
+ }
721
+ const receiptRecord = receipt;
722
+ const missingFields = [];
723
+ const unknownFields = [];
724
+ for (const field of fields) {
725
+ if (!RECEIPT_FIELD_NAMES.has(field)) {
726
+ unknownFields.push(field);
727
+ } else if (receiptRecord[field] === null || receiptRecord[field] === void 0) {
728
+ missingFields.push(field);
729
+ }
730
+ }
731
+ if (unknownFields.length > 0) {
732
+ return {
733
+ type: constraint.type,
734
+ passed: false,
735
+ expected: fields,
736
+ actual: unknownFields,
737
+ message: constraint.message ?? `Unknown field(s): ${unknownFields.join(", ")}`
738
+ };
739
+ }
740
+ return {
741
+ type: constraint.type,
742
+ passed: missingFields.length === 0,
743
+ expected: fields,
744
+ actual: missingFields.length > 0 ? missingFields : fields,
745
+ message: constraint.message ?? (missingFields.length > 0 ? `Missing field(s): ${missingFields.join(", ")}` : void 0)
746
+ };
747
+ }
748
+ function evaluateStatusMustBe(receipt, constraint) {
749
+ const expected = constraint.value;
750
+ const actual = receipt.status;
751
+ const allowedStatuses = Array.isArray(expected) ? expected : [expected];
752
+ return {
753
+ type: constraint.type,
754
+ passed: allowedStatuses.includes(actual),
755
+ expected,
756
+ actual,
757
+ message: constraint.message
758
+ };
759
+ }
760
+ function evaluateOutputSchema(constraint, rawOutput) {
761
+ if (rawOutput === void 0) {
762
+ return {
763
+ type: "output_schema",
764
+ passed: false,
765
+ expected: constraint.value,
766
+ actual: null,
767
+ message: constraint.message ?? "output_schema requires raw output data \u2014 only available during track() or create()"
768
+ };
769
+ }
770
+ const schema = constraint.value;
771
+ const errors = validateJsonSchema(rawOutput, schema);
772
+ return {
773
+ type: "output_schema",
774
+ passed: errors.length === 0,
775
+ expected: schema,
776
+ actual: errors.length > 0 ? errors : rawOutput,
777
+ message: errors.length > 0 ? constraint.message ?? `Schema validation failed: ${errors.join(", ")}` : void 0
778
+ };
779
+ }
780
+ function evaluateConstraints(receipt, constraints, context) {
781
+ if (constraints.length === 0) {
782
+ return {
783
+ passed: true,
784
+ results: [],
785
+ evaluated_at: (/* @__PURE__ */ new Date()).toISOString()
786
+ };
787
+ }
788
+ const results = [];
789
+ for (const constraint of constraints) {
790
+ let result;
791
+ switch (constraint.type) {
792
+ case "max_latency_ms":
793
+ result = evaluateMaxLatencyMs(receipt, constraint);
794
+ break;
795
+ case "max_cost_usd":
796
+ result = evaluateMaxCostUsd(receipt, constraint);
797
+ break;
798
+ case "min_confidence":
799
+ result = evaluateMinConfidence(receipt, constraint);
800
+ break;
801
+ case "required_fields":
802
+ result = evaluateRequiredFields(receipt, constraint);
803
+ break;
804
+ case "status_must_be":
805
+ result = evaluateStatusMustBe(receipt, constraint);
806
+ break;
807
+ case "output_schema":
808
+ result = evaluateOutputSchema(constraint, context?.rawOutput);
809
+ break;
810
+ default:
811
+ result = {
812
+ type: constraint.type,
813
+ passed: false,
814
+ expected: constraint.value,
815
+ actual: null,
816
+ message: constraint.message ?? `Unknown constraint type: ${constraint.type}`
817
+ };
818
+ }
819
+ results.push(result);
820
+ }
821
+ return {
822
+ passed: results.every((r) => r.passed),
823
+ results,
824
+ evaluated_at: (/* @__PURE__ */ new Date()).toISOString()
825
+ };
826
+ }
827
+
828
+ // src/engine/invoice.ts
829
+ function generateInvoiceNumber() {
830
+ const now = /* @__PURE__ */ new Date();
831
+ const y = now.getFullYear();
832
+ const m = String(now.getMonth() + 1).padStart(2, "0");
833
+ const d = String(now.getDate()).padStart(2, "0");
834
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
835
+ let suffix = "";
836
+ for (let i = 0; i < 4; i++) {
837
+ suffix += chars[Math.floor(Math.random() * chars.length)];
838
+ }
839
+ return `AR-${y}${m}${d}-${suffix}`;
840
+ }
841
+ function receiptToLineItem(receipt) {
842
+ const cr = receipt.constraint_result;
843
+ return {
844
+ receipt_id: receipt.receipt_id,
845
+ action: receipt.action,
846
+ agent_id: receipt.agent_id,
847
+ timestamp: receipt.timestamp,
848
+ description: receipt.output_summary ?? `${receipt.action} by ${receipt.agent_id}`,
849
+ cost_usd: receipt.cost_usd,
850
+ latency_ms: receipt.latency_ms,
851
+ model: receipt.model,
852
+ tokens_in: receipt.tokens_in,
853
+ tokens_out: receipt.tokens_out,
854
+ constraints_passed: cr && typeof cr.passed === "boolean" ? cr.passed : null,
855
+ receipt
856
+ };
857
+ }
858
+ function groupItems(items, groupBy) {
859
+ if (groupBy === "none") {
860
+ const subtotal = items.reduce((s, i) => s + (i.cost_usd ?? 0), 0);
861
+ return [{ label: "All Items", items, subtotal_usd: subtotal, count: items.length }];
862
+ }
863
+ const map = /* @__PURE__ */ new Map();
864
+ for (const item of items) {
865
+ let key;
866
+ if (groupBy === "action") {
867
+ key = item.action;
868
+ } else if (groupBy === "agent") {
869
+ key = item.agent_id;
870
+ } else {
871
+ key = item.timestamp.slice(0, 10);
872
+ }
873
+ const group = map.get(key) ?? [];
874
+ group.push(item);
875
+ map.set(key, group);
876
+ }
877
+ const groups = [];
878
+ for (const [label, groupItems2] of map) {
879
+ const subtotal = groupItems2.reduce((s, i) => s + (i.cost_usd ?? 0), 0);
880
+ groups.push({ label, items: groupItems2, subtotal_usd: subtotal, count: groupItems2.length });
881
+ }
882
+ return groups.sort((a, b) => a.label.localeCompare(b.label));
883
+ }
884
+ function calculateSummary(items) {
885
+ let totalCost = 0;
886
+ let totalTokensIn = 0;
887
+ let totalTokensOut = 0;
888
+ let totalLatency = 0;
889
+ let constraintsEvaluated = 0;
890
+ let constraintsPassed = 0;
891
+ let constraintsFailed = 0;
892
+ for (const item of items) {
893
+ totalCost += item.cost_usd ?? 0;
894
+ totalTokensIn += item.tokens_in ?? 0;
895
+ totalTokensOut += item.tokens_out ?? 0;
896
+ totalLatency += item.latency_ms ?? 0;
897
+ if (item.constraints_passed !== null) {
898
+ constraintsEvaluated++;
899
+ if (item.constraints_passed) constraintsPassed++;
900
+ else constraintsFailed++;
901
+ }
902
+ }
903
+ return {
904
+ total_receipts: items.length,
905
+ total_cost_usd: totalCost,
906
+ avg_cost_usd: items.length > 0 ? totalCost / items.length : 0,
907
+ total_tokens_in: totalTokensIn,
908
+ total_tokens_out: totalTokensOut,
909
+ total_latency_ms: totalLatency,
910
+ avg_latency_ms: items.length > 0 ? totalLatency / items.length : 0,
911
+ constraints_evaluated: constraintsEvaluated,
912
+ constraints_passed: constraintsPassed,
913
+ constraints_failed: constraintsFailed
914
+ };
915
+ }
916
+ async function generateInvoice(store, keyManager, options) {
917
+ const result = await store.list(
918
+ { from: options.from, to: options.to, status: "completed" },
919
+ 1,
920
+ 1e5,
921
+ "timestamp:asc"
922
+ );
923
+ let receipts = result.data;
924
+ if (options.agent_ids && options.agent_ids.length > 0) {
925
+ const agentSet = new Set(options.agent_ids);
926
+ receipts = receipts.filter((r) => agentSet.has(r.agent_id));
927
+ }
928
+ if (options.actions && options.actions.length > 0) {
929
+ const actionSet = new Set(options.actions);
930
+ receipts = receipts.filter((r) => actionSet.has(r.action));
931
+ }
932
+ if (options.constraints_passed_only) {
933
+ receipts = receipts.filter((r) => {
934
+ const cr = r.constraint_result;
935
+ return !cr || cr.passed !== false;
936
+ });
937
+ }
938
+ const items = receipts.map(receiptToLineItem);
939
+ const groupBy = options.group_by ?? "none";
940
+ const groups = groupItems(items, groupBy);
941
+ const summary = calculateSummary(items);
942
+ const publicKey = keyManager.getPublicKey();
943
+ return {
944
+ invoice_number: generateInvoiceNumber(),
945
+ generated_at: (/* @__PURE__ */ new Date()).toISOString(),
946
+ period: { from: options.from, to: options.to },
947
+ client: options.client,
948
+ provider: options.provider,
949
+ groups,
950
+ summary,
951
+ public_key: publicKey,
952
+ notes: options.notes,
953
+ payment_terms: options.payment_terms
954
+ };
955
+ }
956
+
957
+ // src/engine/receipt-engine.ts
958
+ var ReceiptEngine = class {
959
+ constructor(store, keyManager, configManager) {
960
+ this.store = store;
961
+ this.keyManager = keyManager;
962
+ this.configManager = configManager;
963
+ }
964
+ async create(params) {
965
+ const config = this.configManager.getConfig();
966
+ const receiptId = `rcpt_${nanoid(12)}`;
967
+ const chainId = params.chain_id ?? `chain_${nanoid(8)}`;
968
+ const now = (/* @__PURE__ */ new Date()).toISOString();
969
+ const constraintDefs = params.constraints && params.constraints.length > 0 ? params.constraints : null;
970
+ const constraintsForStorage = constraintDefs ? { definitions: constraintDefs } : null;
971
+ let expiresAt = params.expires_at;
972
+ if (!expiresAt && params.ttl_ms) {
973
+ expiresAt = new Date(Date.now() + params.ttl_ms).toISOString();
974
+ }
975
+ const metadata = { ...params.metadata ?? {} };
976
+ if (expiresAt) {
977
+ metadata.expires_at = expiresAt;
978
+ }
979
+ const receiptData = {
980
+ receipt_id: receiptId,
981
+ parent_receipt_id: params.parent_receipt_id ?? null,
982
+ chain_id: chainId,
983
+ receipt_type: params.receipt_type ?? "action",
984
+ agent_id: config.agentId,
985
+ org_id: config.orgId,
986
+ action: params.action,
987
+ input_hash: params.input_hash,
988
+ output_hash: params.output_hash ?? null,
989
+ output_summary: params.output_summary ?? null,
990
+ model: params.model ?? null,
991
+ tokens_in: params.tokens_in ?? null,
992
+ tokens_out: params.tokens_out ?? null,
993
+ cost_usd: params.cost_usd ?? null,
994
+ latency_ms: params.latency_ms ?? null,
995
+ tool_calls: params.tool_calls ?? null,
996
+ timestamp: now,
997
+ completed_at: params.status === "completed" ? now : null,
998
+ status: params.status ?? "pending",
999
+ error: null,
1000
+ environment: config.environment,
1001
+ tags: params.tags ?? null,
1002
+ constraints: constraintsForStorage,
1003
+ constraint_result: null,
1004
+ signature: "",
1005
+ // placeholder — will be replaced
1006
+ verify_url: `local://verify/${receiptId}`,
1007
+ callback_verified: null,
1008
+ confidence: params.confidence ?? null,
1009
+ metadata
1010
+ };
1011
+ if (receiptData.status === "completed" && constraintDefs) {
1012
+ receiptData.constraint_result = evaluateConstraints(
1013
+ receiptData,
1014
+ constraintDefs,
1015
+ { rawOutput: params._rawOutput }
1016
+ );
1017
+ }
1018
+ const signable = getSignablePayload(receiptData);
1019
+ const signature = signReceipt(signable, this.keyManager.getPrivateKey());
1020
+ receiptData.signature = signature;
1021
+ const receipt = ActionReceipt.parse(receiptData);
1022
+ await this.store.save(receipt);
1023
+ return receipt;
1024
+ }
1025
+ async complete(receiptId, params) {
1026
+ const existing = await this.store.get(receiptId);
1027
+ if (!existing) {
1028
+ throw new Error(`Receipt not found: ${receiptId}`);
1029
+ }
1030
+ if (existing.status !== "pending") {
1031
+ throw new Error(`Receipt ${receiptId} is not pending (status: ${existing.status})`);
1032
+ }
1033
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1034
+ const updated = {
1035
+ ...existing,
1036
+ status: params.status,
1037
+ completed_at: now,
1038
+ output_hash: params.output_hash ?? existing.output_hash,
1039
+ output_summary: params.output_summary ?? existing.output_summary,
1040
+ model: params.model ?? existing.model,
1041
+ tokens_in: params.tokens_in ?? existing.tokens_in,
1042
+ tokens_out: params.tokens_out ?? existing.tokens_out,
1043
+ cost_usd: params.cost_usd ?? existing.cost_usd,
1044
+ latency_ms: params.latency_ms ?? existing.latency_ms,
1045
+ tool_calls: params.tool_calls ?? existing.tool_calls,
1046
+ confidence: params.confidence ?? existing.confidence,
1047
+ callback_verified: params.callback_verified ?? existing.callback_verified,
1048
+ error: params.error ?? existing.error,
1049
+ metadata: params.metadata ? { ...existing.metadata, ...params.metadata } : existing.metadata,
1050
+ constraint_result: existing.constraint_result
1051
+ };
1052
+ const storedConstraints = existing.constraints;
1053
+ const constraints = storedConstraints?.definitions ?? null;
1054
+ if (Array.isArray(constraints) && constraints.length > 0) {
1055
+ updated.constraint_result = evaluateConstraints(
1056
+ updated,
1057
+ constraints
1058
+ );
1059
+ }
1060
+ const signable = getSignablePayload(updated);
1061
+ const signature = signReceipt(signable, this.keyManager.getPrivateKey());
1062
+ updated.signature = signature;
1063
+ const receipt = ActionReceipt.parse(updated);
1064
+ await this.store.save(receipt);
1065
+ return receipt;
1066
+ }
1067
+ async track(params) {
1068
+ const inputHash = hashData(params.input);
1069
+ const outputHash = params.output !== void 0 ? hashData(params.output) : null;
1070
+ return this.create({
1071
+ action: params.action,
1072
+ input_hash: inputHash,
1073
+ output_hash: outputHash,
1074
+ output_summary: params.output_summary ?? null,
1075
+ model: params.model ?? null,
1076
+ tokens_in: params.tokens_in ?? null,
1077
+ tokens_out: params.tokens_out ?? null,
1078
+ cost_usd: params.cost_usd ?? null,
1079
+ latency_ms: params.latency_ms ?? null,
1080
+ tool_calls: params.tool_calls ?? null,
1081
+ tags: params.tags ?? null,
1082
+ confidence: params.confidence ?? null,
1083
+ metadata: params.metadata ?? {},
1084
+ parent_receipt_id: params.parent_receipt_id ?? null,
1085
+ chain_id: params.chain_id,
1086
+ status: "completed",
1087
+ constraints: params.constraints,
1088
+ expires_at: params.expires_at,
1089
+ ttl_ms: params.ttl_ms,
1090
+ _rawOutput: params.output
1091
+ });
1092
+ }
1093
+ async verify(receiptId) {
1094
+ const receipt = await this.store.get(receiptId);
1095
+ if (!receipt) {
1096
+ throw new Error(`Receipt not found: ${receiptId}`);
1097
+ }
1098
+ const signable = getSignablePayload(receipt);
1099
+ const verified = verifyReceipt(signable, receipt.signature, this.keyManager.getPublicKey());
1100
+ return { verified, receipt };
1101
+ }
1102
+ async get(receiptId) {
1103
+ return this.store.get(receiptId);
1104
+ }
1105
+ async list(filter, page, limit, sort) {
1106
+ return this.store.list(filter, page, limit, sort);
1107
+ }
1108
+ async getChain(chainId) {
1109
+ return this.store.getChain(chainId);
1110
+ }
1111
+ async getJudgments(receiptId) {
1112
+ const result = await this.store.list({
1113
+ parent_receipt_id: receiptId,
1114
+ receipt_type: "judgment"
1115
+ });
1116
+ return result.data;
1117
+ }
1118
+ async cleanup() {
1119
+ const result = await this.store.cleanup();
1120
+ return { deleted: result.deleted, remaining: result.total - result.deleted };
1121
+ }
1122
+ getPublicKey() {
1123
+ return this.keyManager.getPublicKey();
1124
+ }
1125
+ async generateInvoice(options) {
1126
+ return generateInvoice(this.store, this.keyManager, options);
1127
+ }
1128
+ };
1129
+
1130
+ // src/engine/invoice-formatters.ts
1131
+ function formatInvoiceJSON(invoice, includeReceipts = false) {
1132
+ if (!includeReceipts) {
1133
+ const stripped = {
1134
+ ...invoice,
1135
+ groups: invoice.groups.map((g) => ({
1136
+ ...g,
1137
+ items: g.items.map(({ receipt, ...rest }) => rest)
1138
+ }))
1139
+ };
1140
+ return JSON.stringify(stripped, null, 2);
1141
+ }
1142
+ return JSON.stringify(invoice, null, 2);
1143
+ }
1144
+ function formatInvoiceCSV(invoice) {
1145
+ const lines = [];
1146
+ lines.push("receipt_id,action,agent_id,timestamp,description,cost_usd,latency_ms,model,tokens_in,tokens_out,constraints_passed,group");
1147
+ for (const group of invoice.groups) {
1148
+ for (const item of group.items) {
1149
+ lines.push([
1150
+ csvEscape(item.receipt_id),
1151
+ csvEscape(item.action),
1152
+ csvEscape(item.agent_id),
1153
+ csvEscape(item.timestamp),
1154
+ csvEscape(item.description),
1155
+ item.cost_usd ?? "",
1156
+ item.latency_ms ?? "",
1157
+ csvEscape(item.model ?? ""),
1158
+ item.tokens_in ?? "",
1159
+ item.tokens_out ?? "",
1160
+ item.constraints_passed ?? "",
1161
+ csvEscape(group.label)
1162
+ ].join(","));
1163
+ }
1164
+ }
1165
+ lines.push("");
1166
+ lines.push(`# Invoice: ${invoice.invoice_number}`);
1167
+ lines.push(`# Period: ${invoice.period.from} to ${invoice.period.to}`);
1168
+ lines.push(`# Total Receipts: ${invoice.summary.total_receipts}`);
1169
+ lines.push(`# Total Cost: $${invoice.summary.total_cost_usd.toFixed(4)}`);
1170
+ return lines.join("\n");
1171
+ }
1172
+ function csvEscape(value) {
1173
+ if (value.includes(",") || value.includes('"') || value.includes("\n")) {
1174
+ return `"${value.replace(/"/g, '""')}"`;
1175
+ }
1176
+ return value;
1177
+ }
1178
+ function formatInvoiceMarkdown(invoice) {
1179
+ const lines = [];
1180
+ lines.push(`# Invoice ${invoice.invoice_number}`);
1181
+ lines.push("");
1182
+ lines.push(`**Generated:** ${invoice.generated_at}`);
1183
+ lines.push(`**Period:** ${invoice.period.from} to ${invoice.period.to}`);
1184
+ lines.push("");
1185
+ if (invoice.provider) {
1186
+ lines.push("## Provider");
1187
+ lines.push(`**${invoice.provider.name}**`);
1188
+ if (invoice.provider.email) lines.push(`Email: ${invoice.provider.email}`);
1189
+ if (invoice.provider.address) lines.push(`Address: ${invoice.provider.address}`);
1190
+ lines.push("");
1191
+ }
1192
+ if (invoice.client) {
1193
+ lines.push("## Bill To");
1194
+ lines.push(`**${invoice.client.name}**`);
1195
+ if (invoice.client.email) lines.push(`Email: ${invoice.client.email}`);
1196
+ if (invoice.client.address) lines.push(`Address: ${invoice.client.address}`);
1197
+ lines.push("");
1198
+ }
1199
+ lines.push("---");
1200
+ lines.push("");
1201
+ for (const group of invoice.groups) {
1202
+ lines.push(`### ${group.label}`);
1203
+ lines.push("");
1204
+ lines.push("| Receipt ID | Action | Agent | Description | Cost |");
1205
+ lines.push("|------------|--------|-------|-------------|------|");
1206
+ for (const item of group.items) {
1207
+ const cost = item.cost_usd !== null ? `$${item.cost_usd.toFixed(4)}` : "-";
1208
+ const desc = item.description.length > 50 ? item.description.slice(0, 47) + "..." : item.description;
1209
+ lines.push(`| \`${item.receipt_id}\` | ${item.action} | ${item.agent_id} | ${desc} | ${cost} |`);
1210
+ }
1211
+ lines.push("");
1212
+ lines.push(`**Subtotal:** $${group.subtotal_usd.toFixed(4)} (${group.count} items)`);
1213
+ lines.push("");
1214
+ }
1215
+ lines.push("---");
1216
+ lines.push("");
1217
+ lines.push("## Summary");
1218
+ lines.push("");
1219
+ lines.push(`| Metric | Value |`);
1220
+ lines.push(`|--------|-------|`);
1221
+ lines.push(`| Total Receipts | ${invoice.summary.total_receipts} |`);
1222
+ lines.push(`| Total Cost | $${invoice.summary.total_cost_usd.toFixed(4)} |`);
1223
+ lines.push(`| Avg Cost | $${invoice.summary.avg_cost_usd.toFixed(4)} |`);
1224
+ lines.push(`| Total Tokens (in) | ${invoice.summary.total_tokens_in} |`);
1225
+ lines.push(`| Total Tokens (out) | ${invoice.summary.total_tokens_out} |`);
1226
+ lines.push(`| Avg Latency | ${Math.round(invoice.summary.avg_latency_ms)}ms |`);
1227
+ if (invoice.summary.constraints_evaluated > 0) {
1228
+ lines.push(`| Constraints Passed | ${invoice.summary.constraints_passed}/${invoice.summary.constraints_evaluated} |`);
1229
+ }
1230
+ lines.push("");
1231
+ if (invoice.notes) {
1232
+ lines.push("## Notes");
1233
+ lines.push("");
1234
+ lines.push(invoice.notes);
1235
+ lines.push("");
1236
+ }
1237
+ if (invoice.payment_terms) {
1238
+ lines.push("## Payment Terms");
1239
+ lines.push("");
1240
+ lines.push(invoice.payment_terms);
1241
+ lines.push("");
1242
+ }
1243
+ lines.push("---");
1244
+ lines.push("");
1245
+ lines.push("## Verification");
1246
+ lines.push("");
1247
+ lines.push("Every line item is a cryptographically signed receipt that can be independently verified.");
1248
+ lines.push("");
1249
+ lines.push(`**Public Key:** \`${invoice.public_key}\``);
1250
+ lines.push("");
1251
+ return lines.join("\n");
1252
+ }
1253
+ function formatInvoiceHTML(invoice) {
1254
+ const providerSection = invoice.provider ? `
1255
+ <div class="party">
1256
+ <h3>From</h3>
1257
+ <p class="party-name">${esc(invoice.provider.name)}</p>
1258
+ ${invoice.provider.email ? `<p>${esc(invoice.provider.email)}</p>` : ""}
1259
+ ${invoice.provider.address ? `<p>${esc(invoice.provider.address)}</p>` : ""}
1260
+ </div>` : "";
1261
+ const clientSection = invoice.client ? `
1262
+ <div class="party">
1263
+ <h3>Bill To</h3>
1264
+ <p class="party-name">${esc(invoice.client.name)}</p>
1265
+ ${invoice.client.email ? `<p>${esc(invoice.client.email)}</p>` : ""}
1266
+ ${invoice.client.address ? `<p>${esc(invoice.client.address)}</p>` : ""}
1267
+ </div>` : "";
1268
+ const groupSections = invoice.groups.map((group) => `
1269
+ <div class="group">
1270
+ <h3>${esc(group.label)}</h3>
1271
+ <table>
1272
+ <thead>
1273
+ <tr>
1274
+ <th>Receipt ID</th>
1275
+ <th>Action</th>
1276
+ <th>Agent</th>
1277
+ <th>Description</th>
1278
+ <th>Timestamp</th>
1279
+ <th class="num">Cost</th>
1280
+ </tr>
1281
+ </thead>
1282
+ <tbody>
1283
+ ${group.items.map((item) => itemRow(item)).join("\n")}
1284
+ </tbody>
1285
+ <tfoot>
1286
+ <tr>
1287
+ <td colspan="5" class="subtotal-label">Subtotal (${group.count} items)</td>
1288
+ <td class="num subtotal-value">$${group.subtotal_usd.toFixed(4)}</td>
1289
+ </tr>
1290
+ </tfoot>
1291
+ </table>
1292
+ </div>`).join("\n");
1293
+ const constraintRow = invoice.summary.constraints_evaluated > 0 ? `<tr><td>Constraints Passed</td><td>${invoice.summary.constraints_passed}/${invoice.summary.constraints_evaluated}</td></tr>` : "";
1294
+ const notesSection = invoice.notes ? `<div class="section"><h3>Notes</h3><p>${esc(invoice.notes)}</p></div>` : "";
1295
+ const paymentSection = invoice.payment_terms ? `<div class="section"><h3>Payment Terms</h3><p>${esc(invoice.payment_terms)}</p></div>` : "";
1296
+ return `<!DOCTYPE html>
1297
+ <html lang="en">
1298
+ <head>
1299
+ <meta charset="UTF-8">
1300
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1301
+ <title>Invoice ${esc(invoice.invoice_number)}</title>
1302
+ <style>
1303
+ * { margin: 0; padding: 0; box-sizing: border-box; }
1304
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #1a1a1a; line-height: 1.5; padding: 40px; max-width: 1000px; margin: 0 auto; }
1305
+ .header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 32px; padding-bottom: 24px; border-bottom: 2px solid #e5e7eb; }
1306
+ .header h1 { font-size: 28px; font-weight: 700; color: #111; }
1307
+ .header .invoice-number { font-size: 14px; color: #6b7280; margin-top: 4px; }
1308
+ .header .meta { text-align: right; font-size: 13px; color: #6b7280; }
1309
+ .parties { display: flex; gap: 48px; margin-bottom: 32px; }
1310
+ .party h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: #9ca3af; margin-bottom: 4px; }
1311
+ .party-name { font-weight: 600; font-size: 15px; }
1312
+ .party p { font-size: 13px; color: #4b5563; }
1313
+ .group { margin-bottom: 24px; }
1314
+ .group h3 { font-size: 15px; font-weight: 600; margin-bottom: 8px; color: #374151; }
1315
+ table { width: 100%; border-collapse: collapse; font-size: 12px; }
1316
+ th { text-align: left; padding: 8px 10px; background: #f9fafb; border-bottom: 1px solid #e5e7eb; font-weight: 600; color: #374151; font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; }
1317
+ td { padding: 7px 10px; border-bottom: 1px solid #f3f4f6; color: #4b5563; }
1318
+ .num { text-align: right; font-variant-numeric: tabular-nums; }
1319
+ .receipt-id { font-family: ui-monospace, monospace; font-size: 11px; color: #6b7280; }
1320
+ .subtotal-label { text-align: right; font-weight: 600; color: #374151; }
1321
+ .subtotal-value { font-weight: 600; color: #111; }
1322
+ .summary { margin-top: 32px; padding-top: 24px; border-top: 2px solid #e5e7eb; }
1323
+ .summary h3 { font-size: 15px; font-weight: 600; margin-bottom: 12px; }
1324
+ .summary table { max-width: 360px; }
1325
+ .summary td { padding: 5px 10px; }
1326
+ .summary td:first-child { font-weight: 500; color: #374151; }
1327
+ .summary td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
1328
+ .total-row td { font-size: 16px; font-weight: 700; color: #111; border-top: 2px solid #e5e7eb; padding-top: 10px; }
1329
+ .section { margin-top: 24px; }
1330
+ .section h3 { font-size: 13px; font-weight: 600; margin-bottom: 6px; color: #374151; }
1331
+ .section p { font-size: 13px; color: #4b5563; }
1332
+ .verification { margin-top: 32px; padding: 16px; background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; }
1333
+ .verification h3 { font-size: 13px; font-weight: 600; color: #166534; margin-bottom: 6px; }
1334
+ .verification p { font-size: 12px; color: #15803d; }
1335
+ .verification code { font-family: ui-monospace, monospace; font-size: 11px; background: #dcfce7; padding: 2px 6px; border-radius: 3px; word-break: break-all; }
1336
+ .footer { margin-top: 40px; padding-top: 16px; border-top: 1px solid #e5e7eb; text-align: center; font-size: 11px; color: #9ca3af; }
1337
+ @media print {
1338
+ body { padding: 20px; }
1339
+ .verification { break-inside: avoid; }
1340
+ table { page-break-inside: auto; }
1341
+ tr { page-break-inside: avoid; }
1342
+ }
1343
+ </style>
1344
+ </head>
1345
+ <body>
1346
+ <div class="header">
1347
+ <div>
1348
+ <h1>Invoice</h1>
1349
+ <div class="invoice-number">${esc(invoice.invoice_number)}</div>
1350
+ </div>
1351
+ <div class="meta">
1352
+ <div>Generated: ${esc(formatDate(invoice.generated_at))}</div>
1353
+ <div>Period: ${esc(formatDate(invoice.period.from))} &mdash; ${esc(formatDate(invoice.period.to))}</div>
1354
+ </div>
1355
+ </div>
1356
+
1357
+ ${providerSection || clientSection ? `<div class="parties">${providerSection}${clientSection}</div>` : ""}
1358
+
1359
+ ${groupSections}
1360
+
1361
+ <div class="summary">
1362
+ <h3>Summary</h3>
1363
+ <table>
1364
+ <tr class="total-row"><td>Total Cost</td><td>$${invoice.summary.total_cost_usd.toFixed(4)}</td></tr>
1365
+ <tr><td>Total Receipts</td><td>${invoice.summary.total_receipts}</td></tr>
1366
+ <tr><td>Avg Cost per Receipt</td><td>$${invoice.summary.avg_cost_usd.toFixed(4)}</td></tr>
1367
+ <tr><td>Total Tokens (in/out)</td><td>${invoice.summary.total_tokens_in} / ${invoice.summary.total_tokens_out}</td></tr>
1368
+ <tr><td>Avg Latency</td><td>${Math.round(invoice.summary.avg_latency_ms)}ms</td></tr>
1369
+ ${constraintRow}
1370
+ </table>
1371
+ </div>
1372
+
1373
+ ${notesSection}
1374
+ ${paymentSection}
1375
+
1376
+ <div class="verification">
1377
+ <h3>Verification</h3>
1378
+ <p>Every line item is a cryptographically signed receipt that can be independently verified.</p>
1379
+ <p style="margin-top: 6px;">Public Key: <code>${esc(invoice.public_key)}</code></p>
1380
+ </div>
1381
+
1382
+ <div class="footer">
1383
+ Generated by Agent Receipts &mdash; ${esc(invoice.invoice_number)}
1384
+ </div>
1385
+ </body>
1386
+ </html>`;
1387
+ }
1388
+ function esc(s) {
1389
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1390
+ }
1391
+ function formatDate(iso) {
1392
+ try {
1393
+ return new Date(iso).toLocaleDateString("en-US", {
1394
+ year: "numeric",
1395
+ month: "short",
1396
+ day: "numeric"
1397
+ });
1398
+ } catch {
1399
+ return iso;
1400
+ }
1401
+ }
1402
+ function itemRow(item) {
1403
+ const cost = item.cost_usd !== null ? `$${item.cost_usd.toFixed(4)}` : "-";
1404
+ const desc = item.description.length > 60 ? item.description.slice(0, 57) + "..." : item.description;
1405
+ const ts = formatDate(item.timestamp);
1406
+ return ` <tr>
1407
+ <td class="receipt-id">${esc(item.receipt_id)}</td>
1408
+ <td>${esc(item.action)}</td>
1409
+ <td>${esc(item.agent_id)}</td>
1410
+ <td>${esc(desc)}</td>
1411
+ <td>${esc(ts)}</td>
1412
+ <td class="num">${cost}</td>
1413
+ </tr>`;
1414
+ }
1415
+
1416
+ // src/engine/seed.ts
1417
+ var AGENTS = ["agent-alpha", "agent-beta", "agent-gamma", "agent-delta"];
1418
+ var ACTIONS = [
1419
+ "code_review",
1420
+ "generate_code",
1421
+ "analyze_data",
1422
+ "summarize_text",
1423
+ "translate",
1424
+ "classify_intent",
1425
+ "extract_entities",
1426
+ "search_docs",
1427
+ "validate_input",
1428
+ "optimize_query",
1429
+ "draft_email",
1430
+ "parse_json",
1431
+ "run_tests",
1432
+ "deploy_service",
1433
+ "monitor_health",
1434
+ "audit_logs"
1435
+ ];
1436
+ var MODELS = [
1437
+ "claude-sonnet-4-20250514",
1438
+ "claude-haiku-4-5-20251001",
1439
+ "gpt-4o",
1440
+ "gpt-4o-mini",
1441
+ "gemini-2.0-flash"
1442
+ ];
1443
+ var TAGS_POOL = [
1444
+ "production",
1445
+ "staging",
1446
+ "dev",
1447
+ "critical",
1448
+ "batch",
1449
+ "realtime",
1450
+ "async",
1451
+ "retry",
1452
+ "cached",
1453
+ "v2"
1454
+ ];
1455
+ var OUTPUT_SUMMARIES = [
1456
+ "Successfully processed request",
1457
+ "Generated 3 code suggestions",
1458
+ "Analyzed 500 rows of data",
1459
+ "Translated document to Spanish",
1460
+ "Classified as support_request",
1461
+ "Extracted 12 named entities",
1462
+ "Found 5 relevant documents",
1463
+ "Validated all required fields",
1464
+ "Optimized query: 3.2x faster",
1465
+ "Draft ready for review",
1466
+ "Parsed 45 JSON records",
1467
+ "All 12 tests passing",
1468
+ "Deployed to production v2.1.0",
1469
+ "Health check: all systems nominal",
1470
+ "Audit complete: no anomalies",
1471
+ "Summarized 3 key findings"
1472
+ ];
1473
+ function pick(arr) {
1474
+ return arr[Math.floor(Math.random() * arr.length)];
1475
+ }
1476
+ function randInt(min, max) {
1477
+ return Math.floor(Math.random() * (max - min + 1)) + min;
1478
+ }
1479
+ function randFloat(min, max, decimals = 4) {
1480
+ return parseFloat((Math.random() * (max - min) + min).toFixed(decimals));
1481
+ }
1482
+ function weightedWeekday(baseDate, dayOffset) {
1483
+ const d = new Date(baseDate);
1484
+ d.setDate(d.getDate() - dayOffset);
1485
+ const dow = d.getDay();
1486
+ if ((dow === 0 || dow === 6) && Math.random() < 0.7) {
1487
+ d.setDate(d.getDate() + (dow === 0 ? 1 : -1));
1488
+ }
1489
+ d.setHours(randInt(8, 22), randInt(0, 59), randInt(0, 59), randInt(0, 999));
1490
+ return d;
1491
+ }
1492
+ function pickTags() {
1493
+ if (Math.random() < 0.4) return void 0;
1494
+ const count = randInt(1, 3);
1495
+ const tags = [];
1496
+ const pool = [...TAGS_POOL];
1497
+ for (let i = 0; i < count && pool.length > 0; i++) {
1498
+ const idx = Math.floor(Math.random() * pool.length);
1499
+ tags.push(pool.splice(idx, 1)[0]);
1500
+ }
1501
+ return tags;
1502
+ }
1503
+ async function seedDemoData(store, keyManager, options) {
1504
+ const configManager = new ConfigManager(store["receiptsDir"].replace(/\/receipts$/, ""));
1505
+ await configManager.init();
1506
+ const engine = new ReceiptEngine(store, keyManager, configManager);
1507
+ const targetCount = options?.count ?? randInt(80, 100);
1508
+ const now = /* @__PURE__ */ new Date();
1509
+ if (options?.clean) {
1510
+ const existing = await store.list(void 0, 1, 1e5);
1511
+ for (const r of existing.data) {
1512
+ await store.delete(r.receipt_id);
1513
+ }
1514
+ }
1515
+ const result = {
1516
+ total: 0,
1517
+ agents: {},
1518
+ chains: 0,
1519
+ judgments: 0,
1520
+ constraints: { passed: 0, failed: 0 },
1521
+ expired: 0
1522
+ };
1523
+ const allReceipts = [];
1524
+ const isSmall = targetCount < 40;
1525
+ const judgmentCount = isSmall ? 0 : 4;
1526
+ const expiredCount = isSmall ? 1 : 3;
1527
+ const futureCount = isSmall ? 1 : 5;
1528
+ const reservedCount = judgmentCount + expiredCount + futureCount;
1529
+ const chainTarget = isSmall ? Math.max(1, Math.floor(targetCount / 10)) : 12;
1530
+ const avgChainSteps = isSmall ? 3 : 4;
1531
+ const estimatedChainReceipts = chainTarget * avgChainSteps;
1532
+ const standaloneCount = Math.max(3, targetCount - reservedCount - estimatedChainReceipts);
1533
+ for (let i = 0; i < standaloneCount; i++) {
1534
+ const agent = pick(AGENTS);
1535
+ const action = pick(ACTIONS);
1536
+ const dayOffset = randInt(0, 13);
1537
+ const ts = weightedWeekday(now, dayOffset);
1538
+ if (i < 5) {
1539
+ ts.setTime(now.getTime() - randInt(6e4, 36e5));
1540
+ }
1541
+ const model = pick(MODELS);
1542
+ const tokensIn = randInt(50, 8e3);
1543
+ const tokensOut = randInt(20, 4e3);
1544
+ const latency = randInt(100, 12e3);
1545
+ const costBase = tokensIn * 3e-6 + tokensOut * 15e-6;
1546
+ const cost = parseFloat(costBase.toFixed(6));
1547
+ const useConstraints = Math.random() < 0.4;
1548
+ const constraints = useConstraints ? buildConstraints(latency, cost) : void 0;
1549
+ const tags = pickTags();
1550
+ const receipt = await engine.track({
1551
+ action,
1552
+ input: { query: `demo-input-${i}`, context: `batch-${Math.floor(i / 10)}` },
1553
+ output: { result: `demo-output-${i}`, items: randInt(1, 20) },
1554
+ model,
1555
+ tokens_in: tokensIn,
1556
+ tokens_out: tokensOut,
1557
+ cost_usd: cost,
1558
+ latency_ms: latency,
1559
+ confidence: randFloat(0.6, 0.99),
1560
+ tags,
1561
+ output_summary: pick(OUTPUT_SUMMARIES),
1562
+ constraints,
1563
+ metadata: { demo: true, generated_at: ts.toISOString() }
1564
+ });
1565
+ allReceipts.push({
1566
+ receipt_id: receipt.receipt_id,
1567
+ chain_id: receipt.chain_id,
1568
+ action: receipt.action,
1569
+ agent_id: receipt.agent_id
1570
+ });
1571
+ result.agents[receipt.agent_id] = (result.agents[receipt.agent_id] ?? 0) + 1;
1572
+ result.total++;
1573
+ if (useConstraints && receipt.constraint_result) {
1574
+ const cr = receipt.constraint_result;
1575
+ if (cr.passed) result.constraints.passed++;
1576
+ else result.constraints.failed++;
1577
+ }
1578
+ }
1579
+ const chainBudget = Math.max(chainTarget * 5, targetCount - standaloneCount - reservedCount);
1580
+ const chainCount = chainTarget;
1581
+ let chainReceiptsUsed = 0;
1582
+ for (let c = 0; c < chainCount && chainReceiptsUsed < chainBudget; c++) {
1583
+ const steps = randInt(3, Math.min(7, chainBudget - chainReceiptsUsed));
1584
+ const agent = pick(AGENTS);
1585
+ const baseAction = pick(ACTIONS);
1586
+ let parentId;
1587
+ let chainId;
1588
+ for (let s = 0; s < steps; s++) {
1589
+ const dayOffset = randInt(0, 10);
1590
+ const latency = randInt(200, 8e3);
1591
+ const tokensIn = randInt(100, 5e3);
1592
+ const tokensOut = randInt(50, 3e3);
1593
+ const cost = parseFloat((tokensIn * 3e-6 + tokensOut * 15e-6).toFixed(6));
1594
+ const useConstraints = Math.random() < 0.4;
1595
+ const constraints = useConstraints ? buildConstraints(latency, cost) : void 0;
1596
+ const receipt = await engine.track({
1597
+ action: `${baseAction}_step${s + 1}`,
1598
+ input: { step: s + 1, chain_step: `chain-${c}-step-${s}` },
1599
+ output: { step_result: `completed step ${s + 1}` },
1600
+ model: pick(MODELS),
1601
+ tokens_in: tokensIn,
1602
+ tokens_out: tokensOut,
1603
+ cost_usd: cost,
1604
+ latency_ms: latency,
1605
+ confidence: randFloat(0.7, 0.98),
1606
+ tags: pickTags(),
1607
+ output_summary: `Step ${s + 1} of ${steps} completed`,
1608
+ parent_receipt_id: parentId,
1609
+ chain_id: chainId,
1610
+ constraints,
1611
+ metadata: { demo: true }
1612
+ });
1613
+ if (s === 0) chainId = receipt.chain_id;
1614
+ parentId = receipt.receipt_id;
1615
+ allReceipts.push({
1616
+ receipt_id: receipt.receipt_id,
1617
+ chain_id: receipt.chain_id,
1618
+ action: receipt.action,
1619
+ agent_id: receipt.agent_id
1620
+ });
1621
+ result.agents[receipt.agent_id] = (result.agents[receipt.agent_id] ?? 0) + 1;
1622
+ result.total++;
1623
+ chainReceiptsUsed++;
1624
+ if (useConstraints && receipt.constraint_result) {
1625
+ const cr = receipt.constraint_result;
1626
+ if (cr.passed) result.constraints.passed++;
1627
+ else result.constraints.failed++;
1628
+ }
1629
+ }
1630
+ result.chains++;
1631
+ }
1632
+ const judgmentTargets = allReceipts.slice(5, 5 + judgmentCount);
1633
+ for (const target of judgmentTargets) {
1634
+ const pending = await engine.create({
1635
+ receipt_type: "judgment",
1636
+ action: "judge",
1637
+ input_hash: hashData({ receipt_id: target.receipt_id }),
1638
+ parent_receipt_id: target.receipt_id,
1639
+ chain_id: target.chain_id,
1640
+ status: "pending",
1641
+ metadata: { rubric_version: "1.0", demo: true }
1642
+ });
1643
+ const verdict = pick(["pass", "pass", "partial", "fail"]);
1644
+ const score = verdict === "pass" ? randFloat(0.8, 0.98) : verdict === "partial" ? randFloat(0.5, 0.79) : randFloat(0.2, 0.49);
1645
+ await engine.complete(pending.receipt_id, {
1646
+ status: "completed",
1647
+ output_hash: hashData({ verdict, score }),
1648
+ output_summary: `${verdict.toUpperCase()} (${score.toFixed(2)})`,
1649
+ confidence: randFloat(0.75, 0.95),
1650
+ metadata: {
1651
+ rubric_version: "1.0",
1652
+ demo: true,
1653
+ judgment: {
1654
+ verdict,
1655
+ score,
1656
+ criteria_results: [
1657
+ { criterion: "accuracy", score: randFloat(0.5, 1), passed: Math.random() > 0.3, reasoning: "Evaluated accuracy of output" },
1658
+ { criterion: "completeness", score: randFloat(0.4, 1), passed: Math.random() > 0.3, reasoning: "Checked completeness of response" },
1659
+ { criterion: "clarity", score: randFloat(0.6, 1), passed: Math.random() > 0.2, reasoning: "Assessed clarity and readability" }
1660
+ ],
1661
+ overall_reasoning: `Evaluation of ${target.action}: ${verdict === "pass" ? "Meets quality standards" : verdict === "partial" ? "Partially meets standards, improvements needed" : "Does not meet minimum quality threshold"}`,
1662
+ rubric_version: "1.0"
1663
+ }
1664
+ }
1665
+ });
1666
+ result.total += 2;
1667
+ result.judgments++;
1668
+ }
1669
+ result.total = result.total - judgmentCount;
1670
+ for (let i = 0; i < expiredCount; i++) {
1671
+ const daysAgo = randInt(2, 7);
1672
+ const expiredAt = new Date(now.getTime() - daysAgo * 864e5).toISOString();
1673
+ await engine.track({
1674
+ action: pick(ACTIONS),
1675
+ input: { expired_demo: i },
1676
+ output: { result: "expired result" },
1677
+ model: pick(MODELS),
1678
+ tokens_in: randInt(100, 2e3),
1679
+ tokens_out: randInt(50, 1e3),
1680
+ cost_usd: randFloat(1e-4, 0.01),
1681
+ latency_ms: randInt(200, 5e3),
1682
+ expires_at: expiredAt,
1683
+ metadata: { demo: true }
1684
+ });
1685
+ result.total++;
1686
+ result.expired++;
1687
+ }
1688
+ for (let i = 0; i < futureCount; i++) {
1689
+ const daysAhead = randInt(1, 30);
1690
+ const expiresAt = new Date(now.getTime() + daysAhead * 864e5).toISOString();
1691
+ await engine.track({
1692
+ action: pick(ACTIONS),
1693
+ input: { future_expiry_demo: i },
1694
+ output: { result: "future expiring result" },
1695
+ model: pick(MODELS),
1696
+ tokens_in: randInt(100, 3e3),
1697
+ tokens_out: randInt(50, 1500),
1698
+ cost_usd: randFloat(1e-4, 0.02),
1699
+ latency_ms: randInt(150, 6e3),
1700
+ expires_at: expiresAt,
1701
+ tags: ["expiring"],
1702
+ metadata: { demo: true }
1703
+ });
1704
+ result.total++;
1705
+ }
1706
+ return result;
1707
+ }
1708
+ function buildConstraints(latencyMs, costUsd) {
1709
+ const constraints = [];
1710
+ const latencyThreshold = Math.random() < 0.3 ? Math.floor(latencyMs * 0.5) : Math.floor(latencyMs * 2);
1711
+ constraints.push({ type: "max_latency_ms", value: latencyThreshold });
1712
+ if (Math.random() < 0.6) {
1713
+ const costThreshold = Math.random() < 0.2 ? costUsd * 0.5 : costUsd * 3;
1714
+ constraints.push({ type: "max_cost_usd", value: parseFloat(costThreshold.toFixed(6)) });
1715
+ }
1716
+ if (Math.random() < 0.3) {
1717
+ constraints.push({ type: "min_confidence", value: randFloat(0.6, 0.9) });
1718
+ }
1719
+ return constraints;
1720
+ }
1721
+ export {
1722
+ ConfigManager,
1723
+ ReceiptStore as JsonReceiptStore,
1724
+ KeyManager,
1725
+ ReceiptEngine,
1726
+ SqliteReceiptStore as ReceiptStore,
1727
+ SqliteReceiptStore,
1728
+ evaluateConstraints,
1729
+ formatInvoiceCSV,
1730
+ formatInvoiceHTML,
1731
+ formatInvoiceJSON,
1732
+ formatInvoiceMarkdown,
1733
+ generateInvoice,
1734
+ hashData,
1735
+ seedDemoData,
1736
+ validateJsonSchema
1737
+ };
1738
+ //# sourceMappingURL=index.js.map