margin-meter 0.2.0 → 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/vitest.js ADDED
@@ -0,0 +1,502 @@
1
+ /**
2
+ * margin-meter/vitest — turn a vitest/jest JSON result file into outcomes.
3
+ *
4
+ * The TypeScript test-runner adapter, the analog of the Python
5
+ * `margin_meter.pytest_plugin`. A unit-test suite is already an eval harness:
6
+ * each test is a pass/fail verdict graded by code assertions against a
7
+ * known-correct expectation — a *ground-truth*, *code* grade, which is exactly
8
+ * the honest denominator Margin's outcome intake wants
9
+ * (`docs/INTEGRATION_LADDER.md` rung 2, and rung 6's grading provenance). So the
10
+ * whole of rung 2 — "their evals report pass/fail" — is available for the most
11
+ * common JS/TS grading path with no hand-written `POST`.
12
+ *
13
+ * ## One adapter, two frameworks
14
+ *
15
+ * This is a JSON-results CONSUMER, not a runtime reporter, because that reads a
16
+ * file the customer already produces and drags in no test-framework dependency —
17
+ * the same design as the promptfoo/braintrust/langsmith adapters. Both dominant
18
+ * JS test runners emit the SAME jest-compatible JSON, so one adapter covers
19
+ * both:
20
+ *
21
+ * vitest run --reporter=json --outputFile=results.json # vitest
22
+ * jest --json --outputFile=results.json # jest
23
+ *
24
+ * import { MarginMeter, vitest } from "margin-meter";
25
+ * const meter = new MarginMeter(); // MARGIN_INGEST_URL/KEY from env
26
+ * const data = JSON.parse(await readFile("results.json", "utf8"));
27
+ * await vitest.recordResults(meter, data, "my-test-suite");
28
+ *
29
+ * The mapping mirrors the pytest plugin's, on purpose — the SDKs must not drift:
30
+ *
31
+ * - `passed` ← the assertion `status`: `passed` → true, `failed` →
32
+ * false. Any other status (`skipped`/`todo`/`pending`/`disabled`) is NOT a
33
+ * verdict and is SKIPPED — recording a skip as a pass or a fail would
34
+ * fabricate an outcome the suite never produced.
35
+ * - `qualityScore` ← `1.0` / `0.0` (a binary ground-truth grade). Always
36
+ * supplied: the ingest layer discards `quality_method`/`grader_kind` on a
37
+ * scoreless outcome, so the score is what lights the grading provenance.
38
+ * - `qualityMethod`/`graderKind` ← `ground_truth`/`code`, ASSERTED, never
39
+ * inferred — a code assertion IS a ground-truth code grade, exactly as the
40
+ * pytest plugin asserts. (Unlike promptfoo/braintrust, which grade several
41
+ * ways and must derive the signature; a unit test is unambiguously code.)
42
+ * - `link` ← the assertion `fullName`, else its ancestor titles + its
43
+ * title, else the file name + row index — for traceability back to the exact
44
+ * test. Truncated to 512 (a lossy link beats a lost outcome).
45
+ * - a test FILE that crashed on load/collection (a failing file status with no
46
+ * per-test results) records no outcome — there is no honest count of the
47
+ * tests it would have produced — but it WARNS, so a fully broken run is not
48
+ * silently read as a clean one.
49
+ *
50
+ * ## The honest limit — rung 8 is not reachable here, and that is stated, not defaulted
51
+ *
52
+ * The jest/vitest JSON format carries no per-test value field, so a
53
+ * value-per-outcome numerator (rung 8) cannot ride this FILE path. Absent is
54
+ * the honest cost-per-outcome default — never coerced to `0`. The route to
55
+ * rung 8 from a test suite is the RUNTIME path (`@pytest.mark.margin_value` in
56
+ * Python), and it lives in this same module: {@link MarginVitestReporter} runs
57
+ * inside the suite and reads `task.meta.marginValue`. Use the file consumer
58
+ * when you already have a results file; use the reporter when you want value.
59
+ *
60
+ * Two design promises, same as the sibling adapters: it consumes the file the
61
+ * customer already produces (no new harness), and it is fail-safe — a delivery
62
+ * fault on one row warns and is counted, never aborting the batch.
63
+ */
64
+ // Grading provenance strings — mirror `src/margin/grading.py`, kept as literals
65
+ // so the SDK has no dependency on the server package. A unit test is always a
66
+ // code-graded ground-truth verdict, so unlike the model-graded adapters there is
67
+ // no signature to derive.
68
+ const GROUND_TRUTH = "ground_truth";
69
+ const GRADER_CODE = "code";
70
+ // `Outcome.link` is a `String(512)`; a longer link is truncated, not dropped (a
71
+ // lossy link beats a lost outcome) — same rule as the pytest adapter.
72
+ const MAX_LINK_LEN = 512;
73
+ const defaultWarn = (message) => {
74
+ // `process` may be absent in a non-Node runtime; fall back to console.
75
+ const p = globalThis
76
+ .process;
77
+ if (p && typeof p.emitWarning === "function")
78
+ p.emitWarning(message);
79
+ else
80
+ console.warn(message);
81
+ };
82
+ function isObject(x) {
83
+ return typeof x === "object" && x !== null && !Array.isArray(x);
84
+ }
85
+ /** Map a jest/vitest assertion `status` to a pass/fail verdict, or `undefined`
86
+ * when the status is not a verdict at all (`skipped`/`todo`/`pending`/
87
+ * `disabled`/unknown). A skip is neither a pass nor a fail, so it is dropped
88
+ * rather than fabricated. */
89
+ export function verdictFromStatus(status) {
90
+ if (status === "passed")
91
+ return true;
92
+ if (status === "failed")
93
+ return false;
94
+ return undefined;
95
+ }
96
+ /** A traceable link back to the exact test: the assertion's `fullName` if the
97
+ * runner wrote one, else its ancestor titles joined with its title, else the
98
+ * test file name plus the row index. */
99
+ export function linkFromAssertion(assertion, fileName, index) {
100
+ if (isObject(assertion)) {
101
+ const full = assertion.fullName;
102
+ if (typeof full === "string" && full.trim()) {
103
+ return full.trim().slice(0, MAX_LINK_LEN);
104
+ }
105
+ const parts = [];
106
+ const ancestors = assertion.ancestorTitles;
107
+ if (Array.isArray(ancestors)) {
108
+ for (const t of ancestors)
109
+ if (typeof t === "string" && t)
110
+ parts.push(t);
111
+ }
112
+ const title = assertion.title;
113
+ if (typeof title === "string" && title.trim())
114
+ parts.push(title.trim());
115
+ if (parts.length > 0)
116
+ return parts.join(" > ").slice(0, MAX_LINK_LEN);
117
+ }
118
+ const base = typeof fileName === "string" && fileName ? fileName : "vitest";
119
+ return `${base}:${index}`.slice(0, MAX_LINK_LEN);
120
+ }
121
+ /** Flatten a parsed vitest/jest JSON output to a per-test list. The canonical
122
+ * shape is `{ testResults: [{ name, assertionResults: [...] }] }` (jest's
123
+ * `--json`, vitest's `--reporter=json`); a bare array is treated as an
124
+ * already-flattened list of assertion results, for convenience and testing. */
125
+ export function extractAssertions(data) {
126
+ const out = [];
127
+ if (Array.isArray(data)) {
128
+ for (const a of data)
129
+ if (isObject(a))
130
+ out.push({ assertion: a });
131
+ return out;
132
+ }
133
+ if (!isObject(data))
134
+ return out;
135
+ const files = data.testResults;
136
+ if (!Array.isArray(files))
137
+ return out;
138
+ for (const file of files) {
139
+ if (!isObject(file))
140
+ continue;
141
+ const fileName = typeof file.name === "string" ? file.name : undefined;
142
+ const asserts = file.assertionResults;
143
+ if (!Array.isArray(asserts))
144
+ continue;
145
+ for (const a of asserts) {
146
+ if (isObject(a))
147
+ out.push({ assertion: a, fileName });
148
+ }
149
+ }
150
+ return out;
151
+ }
152
+ /** File-status values jest/vitest use to mark a suite that FAILED rather than a
153
+ * normal per-test failure. A file that crashed on load/collection emits a
154
+ * `testResults` entry with a failing status and NO `assertionResults` — the
155
+ * error lands in `message`/`failureMessage`, not a per-test verdict. */
156
+ const FAILED_FILE_STATUSES = new Set(["failed", "error"]);
157
+ /** Names of test files that failed with no per-test results — a suite that
158
+ * crashed on load/collection. These carry no recordable verdict (there is no
159
+ * honest count of tests a crashed suite "would have" produced), so they are NOT
160
+ * turned into outcomes; {@link recordResults} warns for each so a fully broken
161
+ * run is not silently read as a clean one — the whole point of an honest
162
+ * denominator. */
163
+ export function failedEmptySuites(data) {
164
+ const out = [];
165
+ if (!isObject(data))
166
+ return out;
167
+ const files = data.testResults;
168
+ if (!Array.isArray(files))
169
+ return out;
170
+ for (const file of files) {
171
+ if (!isObject(file))
172
+ continue;
173
+ const asserts = file.assertionResults;
174
+ const hasRows = Array.isArray(asserts) && asserts.some(isObject);
175
+ if (hasRows)
176
+ continue;
177
+ const status = typeof file.status === "string" ? file.status : "";
178
+ const msg = file.message ?? file.failureMessage;
179
+ const failed = FAILED_FILE_STATUSES.has(status) ||
180
+ (typeof msg === "string" && msg.trim() !== "");
181
+ if (failed) {
182
+ const name = typeof file.name === "string" && file.name ? file.name : "<unnamed suite>";
183
+ out.push(name);
184
+ }
185
+ }
186
+ return out;
187
+ }
188
+ /** Translate one code-graded test verdict into `MarginMeter.recordOutcome`
189
+ * input. The grader signature is asserted (`ground_truth`/`code`) because a
190
+ * unit test is unambiguously a code grade. `valueUsd` rides only when supplied
191
+ * (never defaulted to 0). */
192
+ export function outcomeInput(args) {
193
+ const input = {
194
+ workflowId: args.workflowId,
195
+ passed: Boolean(args.passed),
196
+ qualityScore: args.passed ? 1.0 : 0.0,
197
+ qualityMethod: GROUND_TRUTH,
198
+ graderKind: GRADER_CODE,
199
+ link: String(args.link).slice(0, MAX_LINK_LEN),
200
+ isSimulated: Boolean(args.isSimulated),
201
+ };
202
+ if (args.valueUsd !== undefined)
203
+ input.valueUsd = Number(args.valueUsd);
204
+ return input;
205
+ }
206
+ /** Full translation of one flattened assertion, or `undefined` if its status is
207
+ * not a real verdict (a skip/todo/pending is dropped, never fabricated). */
208
+ export function assertionToOutcomeInput(item, opts) {
209
+ const index = opts.index ?? 0;
210
+ const passed = verdictFromStatus(item.assertion.status);
211
+ if (passed === undefined)
212
+ return undefined;
213
+ return outcomeInput({
214
+ workflowId: opts.workflowId,
215
+ passed,
216
+ link: linkFromAssertion(item.assertion, item.fileName, index),
217
+ isSimulated: opts.isSimulated,
218
+ });
219
+ }
220
+ /** Yield `recordOutcome` inputs for every real verdict in a parsed vitest/jest
221
+ * output (any envelope shape {@link extractAssertions} understands). */
222
+ export function iterOutcomes(data, opts) {
223
+ const out = [];
224
+ const items = extractAssertions(data);
225
+ for (let i = 0; i < items.length; i++) {
226
+ const input = assertionToOutcomeInput(items[i], {
227
+ workflowId: opts.workflowId,
228
+ index: i,
229
+ isSimulated: opts.isSimulated,
230
+ });
231
+ if (input !== undefined)
232
+ out.push(input);
233
+ }
234
+ return out;
235
+ }
236
+ /** Emit an outcome per verdict in a parsed vitest/jest output through `meter`.
237
+ * Fail-safe: a delivery fault on one row warns and counts an error; it never
238
+ * aborts the batch. Non-verdict rows (skips/todos/pending) are counted as
239
+ * skipped. */
240
+ export async function recordResults(meter, data, workflowId, opts = {}) {
241
+ const onWarn = opts.onWarn ?? defaultWarn;
242
+ // A suite that crashed on load emits a failing file entry with no per-test
243
+ // rows; those produce nothing below, so warn here or a broken run reads clean.
244
+ for (const name of failedEmptySuites(data)) {
245
+ onWarn(`test file "${name}" failed with no test results (suite load/collection ` +
246
+ "error?) — its failure is NOT recorded as an outcome");
247
+ }
248
+ const items = extractAssertions(data);
249
+ let recorded = 0;
250
+ let errors = 0;
251
+ let skipped = 0;
252
+ for (let i = 0; i < items.length; i++) {
253
+ const input = assertionToOutcomeInput(items[i], {
254
+ workflowId,
255
+ index: i,
256
+ isSimulated: opts.isSimulated,
257
+ });
258
+ if (input === undefined) {
259
+ skipped++;
260
+ continue;
261
+ }
262
+ try {
263
+ await meter.recordOutcome(input);
264
+ recorded++;
265
+ }
266
+ catch (exc) {
267
+ // Never let a delivery fault abort the batch. (The meter is fail-safe by
268
+ // default and resolves rather than rejects; this guards a strict meter.)
269
+ errors++;
270
+ onWarn(`failed to record outcome for ${input.link}: ${exc.message}`);
271
+ }
272
+ }
273
+ try {
274
+ await meter.flush();
275
+ }
276
+ catch (exc) {
277
+ onWarn(`flush failed: ${exc.message}`);
278
+ }
279
+ return { recorded, errors, skipped };
280
+ }
281
+ // =========================================================================== //
282
+ // The RUNTIME reporter — the route to rung 8 (value-per-outcome) from a test
283
+ // suite, the TS analog of pytest's `@pytest.mark.margin_value(<usd>)`. The
284
+ // JSON-file consumer above cannot reach it: the results file carries no per-test
285
+ // value. A vitest reporter runs INSIDE the suite, so it can read a value a test
286
+ // attached to `task.meta`.
287
+ //
288
+ // // vitest.config.ts
289
+ // import { vitest as m } from "margin-meter";
290
+ // export default {
291
+ // test: { reporters: ["default", new m.MarginVitestReporter({ workflowId: "my-suite" })] },
292
+ // };
293
+ //
294
+ // // in a test — tag its business value (optional; absent = cost-per-outcome)
295
+ // import { getCurrentTest } from "vitest";
296
+ // test("resolves the ticket", () => { getCurrentTest().meta.marginValue = 120; /* ... */ });
297
+ // =========================================================================== //
298
+ // Value coercion — mirrors promptfoo.ts / braintrust.ts EXACTLY so a stringly-
299
+ // typed tag is treated the same across every adapter and neither SDK lets a
300
+ // non-number, non-finite, or implausibly large value through (a loss is kept, MAR-1198). A
301
+ // finite DECIMAL only: deliberately narrower than JS `Number()`, which also
302
+ // parses `0x10`/`Infinity`/`""` — a `marginValue` typo must be a DROPPED value,
303
+ // never a silent $16.
304
+ const VALUE_KEY = "marginValue";
305
+ const DECIMAL_RE = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
306
+ // Mirror `src/margin/ingest.MAX_VALUE_USD` — a value above this is rejected by
307
+ // the server, so reject it here rather than emitting a doomed row.
308
+ const MAX_VALUE_USD = 10_000_000.0;
309
+ function coerceValue(raw) {
310
+ if (typeof raw === "boolean")
311
+ throw new Error(`${VALUE_KEY} must be a number, got ${JSON.stringify(raw)}`);
312
+ let val;
313
+ if (typeof raw === "number") {
314
+ val = raw;
315
+ }
316
+ else if (typeof raw === "string") {
317
+ const s = raw.trim();
318
+ if (!DECIMAL_RE.test(s))
319
+ throw new Error(`${VALUE_KEY} must be a number, got ${JSON.stringify(raw)}`);
320
+ val = Number(s);
321
+ }
322
+ else {
323
+ throw new Error(`${VALUE_KEY} must be a number, got ${JSON.stringify(raw)}`);
324
+ }
325
+ if (!Number.isFinite(val))
326
+ throw new Error(`${VALUE_KEY} must be a finite number, got ${JSON.stringify(raw)}`);
327
+ // A loss is a real value (MAR-1198): ingest takes any finite amount within +/-MAX.
328
+ if (Math.abs(val) > MAX_VALUE_USD)
329
+ throw new Error(`${VALUE_KEY} implausible (|value| > ${MAX_VALUE_USD}), got ${val}`);
330
+ return val;
331
+ }
332
+ /** Read an opt-in `marginValue` off a task's `meta` — the value-per-outcome
333
+ * numerator (rung 8). Returns the USD amount, or `undefined` when the key is
334
+ * absent (the normal cost-per-outcome case). Throws on a malformed value
335
+ * (including an explicit `null`, i.e. present-but-malformed) so the caller can
336
+ * warn and drop it while keeping the pass/fail.
337
+ *
338
+ * An explicit `undefined` (`meta.marginValue = undefined`) is treated as absent
339
+ * — setting a meta key to `undefined` is not a value a customer meant to
340
+ * supply. This is the one intentional divergence from the file-adapters'
341
+ * `valueFrom*`, and it only ever drops-silently rather than fabricating. */
342
+ export function valueFromTaskMeta(meta) {
343
+ if (!isObject(meta))
344
+ return undefined;
345
+ if (!(VALUE_KEY in meta))
346
+ return undefined;
347
+ const raw = meta[VALUE_KEY];
348
+ if (raw === undefined)
349
+ return undefined;
350
+ return coerceValue(raw);
351
+ }
352
+ /** Map a vitest task result state to a pass/fail verdict, or `undefined` when it
353
+ * is not a verdict (`skip`/`todo`/`queued`/absent — a skipped or not-yet-run
354
+ * test is neither a pass nor a fail, so it is dropped, never fabricated). */
355
+ export function verdictFromState(state) {
356
+ if (state === "pass")
357
+ return true;
358
+ if (state === "fail")
359
+ return false;
360
+ return undefined;
361
+ }
362
+ /** Depth-first walk of a vitest task tree, yielding every LEAF test together
363
+ * with its ancestor suite names. A node is a CONTAINER (a suite, or a file
364
+ * whose `tasks` are its top-level tests) exactly when it has a `tasks` array —
365
+ * regardless of whether that array is empty — and is recursed into, never
366
+ * recorded. Everything else is a leaf test.
367
+ *
368
+ * ⛔ The container test is the PRESENCE of `tasks`, not its length. vitest emits
369
+ * a file that CRASHED on collection as a suite node with `tasks: []` AND
370
+ * `result.state: "fail"`; a length check would misread that as a failed leaf
371
+ * test and fabricate a `passed:false` code-graded outcome for a file that ran
372
+ * zero tests — the exact over-claim the file-consumer path refuses. A real test
373
+ * never carries a `tasks` property, so this classification keeps every genuine
374
+ * verdict while dropping the crashed/empty suite. */
375
+ export function walkTasks(nodes, ancestors = []) {
376
+ const out = [];
377
+ if (!Array.isArray(nodes))
378
+ return out;
379
+ for (const node of nodes) {
380
+ if (!isObject(node))
381
+ continue;
382
+ const name = typeof node.name === "string" ? node.name : "";
383
+ const children = node.tasks;
384
+ if (Array.isArray(children)) {
385
+ // A container (suite or file) — recurse; an empty one yields nothing.
386
+ out.push(...walkTasks(children, name ? [...ancestors, name] : ancestors));
387
+ continue;
388
+ }
389
+ // A leaf test (no `tasks` array). Its verdict is decided by verdictFromState.
390
+ out.push({ task: node, path: name ? [...ancestors, name] : ancestors });
391
+ }
392
+ return out;
393
+ }
394
+ /** Yield `recordOutcome` inputs for every real verdict in a vitest `files` tree
395
+ * (the argument vitest passes a reporter's `onFinished`). A test's value rides
396
+ * from `task.meta.marginValue`; a malformed value warns and drops the value,
397
+ * keeping the pass/fail. */
398
+ export function iterTaskOutcomes(files, opts) {
399
+ const onWarn = opts.onWarn ?? defaultWarn;
400
+ const out = [];
401
+ const leaves = walkTasks(files);
402
+ for (const { task, path } of leaves) {
403
+ const result = task.result;
404
+ const state = isObject(result) ? result.state : undefined;
405
+ const passed = verdictFromState(state);
406
+ if (passed === undefined)
407
+ continue;
408
+ const link = path.length > 0 ? path.join(" > ") : "vitest";
409
+ let value;
410
+ try {
411
+ value = valueFromTaskMeta(task.meta);
412
+ }
413
+ catch (exc) {
414
+ value = undefined;
415
+ onWarn(`${link}: ${exc.message}`);
416
+ }
417
+ out.push(outcomeInput({
418
+ workflowId: opts.workflowId,
419
+ passed,
420
+ link,
421
+ isSimulated: opts.isSimulated,
422
+ valueUsd: value,
423
+ }));
424
+ }
425
+ return out;
426
+ }
427
+ /** A vitest reporter that records every test as a code-graded outcome and reads
428
+ * an opt-in per-test value off `task.meta.marginValue` (rung 8). It implements
429
+ * only the `onFinished(files)` hook — the one vitest calls with the completed
430
+ * task tree — and is fail-safe: a delivery or config fault warns, and NOTHING
431
+ * it does throws into the test run. */
432
+ export class MarginVitestReporter {
433
+ opts;
434
+ /** The last batch's summary — handy for a customer's own assertions and for
435
+ * the hermetic tests. */
436
+ summary = { recorded: 0, errors: 0, skipped: 0 };
437
+ constructor(opts = {}) {
438
+ this.opts = opts;
439
+ }
440
+ resolveWorkflow() {
441
+ if (this.opts.workflowId)
442
+ return this.opts.workflowId;
443
+ const p = globalThis
444
+ .process;
445
+ const env = p?.env?.MARGIN_VITEST_WORKFLOW;
446
+ return env && env.trim() ? env.trim() : undefined;
447
+ }
448
+ async resolveMeter() {
449
+ if (this.opts.meter)
450
+ return this.opts.meter;
451
+ // Lazy dynamic import so this module has NO static runtime dependency on
452
+ // index.ts (avoids the barrel re-export cycle) and a customer only pays for
453
+ // the client when the reporter actually runs.
454
+ const mod = await import("./index.js");
455
+ return new mod.MarginMeter();
456
+ }
457
+ /** vitest's end-of-run hook. `files` is the completed task tree. */
458
+ async onFinished(files) {
459
+ const onWarn = this.opts.onWarn ?? defaultWarn;
460
+ // Reset first, so a no-op run or a caught fault reports THIS run's counts
461
+ // rather than leaving the previous batch's summary in place.
462
+ this.summary = { recorded: 0, errors: 0, skipped: 0 };
463
+ try {
464
+ const workflowId = this.resolveWorkflow();
465
+ if (!workflowId) {
466
+ onWarn("MarginVitestReporter: no workflowId (constructor option or " +
467
+ "MARGIN_VITEST_WORKFLOW) — recording nothing this run");
468
+ return;
469
+ }
470
+ const inputs = iterTaskOutcomes(files, {
471
+ workflowId,
472
+ isSimulated: this.opts.isSimulated,
473
+ onWarn,
474
+ });
475
+ const meter = await this.resolveMeter();
476
+ let recorded = 0;
477
+ let errors = 0;
478
+ for (const input of inputs) {
479
+ try {
480
+ await meter.recordOutcome(input);
481
+ recorded++;
482
+ }
483
+ catch (exc) {
484
+ errors++;
485
+ onWarn(`failed to record outcome for ${input.link}: ${exc.message}`);
486
+ }
487
+ }
488
+ try {
489
+ await meter.flush();
490
+ }
491
+ catch (exc) {
492
+ onWarn(`flush failed: ${exc.message}`);
493
+ }
494
+ this.summary = { recorded, errors, skipped: 0 };
495
+ }
496
+ catch (exc) {
497
+ // A reporter must never break the test run it observes.
498
+ onWarn(`MarginVitestReporter.onFinished failed: ${exc.message}`);
499
+ }
500
+ }
501
+ }
502
+ //# sourceMappingURL=vitest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest.js","sourceRoot":"","sources":["../src/vitest.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "margin-meter",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Tiny dependency-free client that auto-instruments OpenAI/Anthropic/Gemini and emits LLM call + outcome economics to a Margin ingest API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,16 +13,34 @@
13
13
  "default": "./dist/index.js"
14
14
  }
15
15
  },
16
- "files": ["dist", "README.md"],
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
17
20
  "scripts": {
18
21
  "build": "tsc -p tsconfig.build.json",
19
22
  "prepublishOnly": "npm run build",
20
23
  "test": "node --experimental-strip-types --test test/*.test.mjs",
21
24
  "typecheck": "tsc --noEmit"
22
25
  },
23
- "keywords": ["llm", "cost", "observability", "finops", "margin"],
26
+ "keywords": [
27
+ "llm",
28
+ "cost",
29
+ "observability",
30
+ "finops",
31
+ "margin"
32
+ ],
24
33
  "license": "MIT",
25
- "repository": { "type": "git", "url": "https://github.com/subhsubh24/Margin.ai.git", "directory": "sdk/ts" },
26
- "engines": { "node": ">=18" },
27
- "devDependencies": { "@types/node": "^20.0.0", "typescript": "^5.4.0" }
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/subhsubh24/Margin.ai.git",
37
+ "directory": "sdk/ts"
38
+ },
39
+ "engines": {
40
+ "node": ">=18"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^20.0.0",
44
+ "typescript": "^5.4.0"
45
+ }
28
46
  }