monora-ai 2.1.0 → 2.1.4

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 (193) hide show
  1. package/README.md +339 -158
  2. package/dist/aims_governance.d.ts +238 -0
  3. package/dist/aims_governance.d.ts.map +1 -0
  4. package/dist/aims_governance.js +922 -0
  5. package/dist/alerts.d.ts +16 -0
  6. package/dist/alerts.d.ts.map +1 -1
  7. package/dist/alerts.js +16 -0
  8. package/dist/api.d.ts +6 -0
  9. package/dist/api.d.ts.map +1 -1
  10. package/dist/api.js +6 -0
  11. package/dist/assessment.d.ts +85 -0
  12. package/dist/assessment.d.ts.map +1 -1
  13. package/dist/assessment.js +525 -13
  14. package/dist/attribution.d.ts +44 -3
  15. package/dist/attribution.d.ts.map +1 -1
  16. package/dist/attribution.js +197 -10
  17. package/dist/autodetect.d.ts +68 -0
  18. package/dist/autodetect.d.ts.map +1 -1
  19. package/dist/autodetect.js +639 -0
  20. package/dist/bias.d.ts +130 -0
  21. package/dist/bias.d.ts.map +1 -0
  22. package/dist/bias.js +223 -0
  23. package/dist/cli/diagnostics.d.ts +5 -1
  24. package/dist/cli/diagnostics.d.ts.map +1 -1
  25. package/dist/cli/diagnostics.js +23 -6
  26. package/dist/cli/doctor.d.ts +25 -0
  27. package/dist/cli/doctor.d.ts.map +1 -0
  28. package/dist/cli/doctor.js +381 -0
  29. package/dist/cli/fix.d.ts +16 -0
  30. package/dist/cli/fix.d.ts.map +1 -0
  31. package/dist/cli/fix.js +284 -0
  32. package/dist/cli/init.d.ts +57 -0
  33. package/dist/cli/init.d.ts.map +1 -0
  34. package/dist/cli/init.js +205 -0
  35. package/dist/cli.js +1564 -177
  36. package/dist/complianceConsolidation.d.ts +17 -0
  37. package/dist/complianceConsolidation.d.ts.map +1 -0
  38. package/dist/complianceConsolidation.js +68 -0
  39. package/dist/complianceTargets.d.ts +111 -0
  40. package/dist/complianceTargets.d.ts.map +1 -0
  41. package/dist/complianceTargets.js +521 -0
  42. package/dist/config.d.ts +261 -16
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +381 -32
  45. package/dist/config_migrations.d.ts.map +1 -1
  46. package/dist/config_migrations.js +38 -1
  47. package/dist/config_schema.d.ts +2490 -1035
  48. package/dist/config_schema.d.ts.map +1 -1
  49. package/dist/config_schema.js +233 -64
  50. package/dist/context.d.ts +34 -0
  51. package/dist/context.d.ts.map +1 -1
  52. package/dist/context.js +118 -7
  53. package/dist/control_backbone.d.ts +128 -0
  54. package/dist/control_backbone.d.ts.map +1 -0
  55. package/dist/control_backbone.js +826 -0
  56. package/dist/data-governance.d.ts +187 -0
  57. package/dist/data-governance.d.ts.map +1 -0
  58. package/dist/data-governance.js +424 -0
  59. package/dist/dataResidency.d.ts +44 -0
  60. package/dist/dataResidency.d.ts.map +1 -0
  61. package/dist/dataResidency.js +203 -0
  62. package/dist/dispatcher.d.ts.map +1 -1
  63. package/dist/dispatcher.js +17 -5
  64. package/dist/evidence_store.d.ts +103 -0
  65. package/dist/evidence_store.d.ts.map +1 -0
  66. package/dist/evidence_store.js +459 -0
  67. package/dist/executiveSummary.d.ts +15 -0
  68. package/dist/executiveSummary.d.ts.map +1 -1
  69. package/dist/executiveSummary.js +135 -22
  70. package/dist/identity.d.ts +143 -0
  71. package/dist/identity.d.ts.map +1 -0
  72. package/dist/identity.js +231 -0
  73. package/dist/impact-assessment.d.ts +350 -0
  74. package/dist/impact-assessment.d.ts.map +1 -0
  75. package/dist/impact-assessment.js +580 -0
  76. package/dist/index.d.ts +21 -4
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +254 -5
  79. package/dist/instrumentation.d.ts +1 -1
  80. package/dist/instrumentation.d.ts.map +1 -1
  81. package/dist/instrumentation.js +123 -22
  82. package/dist/integrations/anthropic.d.ts +3 -0
  83. package/dist/integrations/anthropic.d.ts.map +1 -1
  84. package/dist/integrations/anthropic.js +282 -80
  85. package/dist/integrations/governance.d.ts +33 -0
  86. package/dist/integrations/governance.d.ts.map +1 -0
  87. package/dist/integrations/governance.js +208 -0
  88. package/dist/integrations/langchain.d.ts +4 -0
  89. package/dist/integrations/langchain.d.ts.map +1 -1
  90. package/dist/integrations/langchain.js +362 -142
  91. package/dist/integrations/openai.d.ts +9 -0
  92. package/dist/integrations/openai.d.ts.map +1 -1
  93. package/dist/integrations/openai.js +673 -73
  94. package/dist/iso42001_consolidation.d.ts +16 -0
  95. package/dist/iso42001_consolidation.d.ts.map +1 -0
  96. package/dist/iso42001_consolidation.js +413 -0
  97. package/dist/iso42001_workflows.d.ts +263 -0
  98. package/dist/iso42001_workflows.d.ts.map +1 -0
  99. package/dist/iso42001_workflows.js +781 -0
  100. package/dist/lifecycle.d.ts +299 -0
  101. package/dist/lifecycle.d.ts.map +1 -0
  102. package/dist/lifecycle.js +624 -0
  103. package/dist/lineage.d.ts +2 -2
  104. package/dist/lineage.d.ts.map +1 -1
  105. package/dist/lineage.js +9 -16
  106. package/dist/middleware/express.d.ts.map +1 -1
  107. package/dist/middleware/express.js +18 -3
  108. package/dist/middleware/nextjs.js +2 -2
  109. package/dist/model.d.ts +143 -0
  110. package/dist/model.d.ts.map +1 -0
  111. package/dist/model.js +371 -0
  112. package/dist/onboarding.d.ts +42 -0
  113. package/dist/onboarding.d.ts.map +1 -0
  114. package/dist/onboarding.js +1075 -0
  115. package/dist/oversight.d.ts +264 -0
  116. package/dist/oversight.d.ts.map +1 -0
  117. package/dist/oversight.js +497 -0
  118. package/dist/presets.js +7 -7
  119. package/dist/quotas.d.ts +171 -0
  120. package/dist/quotas.d.ts.map +1 -0
  121. package/dist/quotas.js +259 -0
  122. package/dist/register.d.ts +13 -0
  123. package/dist/register.d.ts.map +1 -0
  124. package/dist/register.js +99 -0
  125. package/dist/registry.d.ts +1 -0
  126. package/dist/registry.d.ts.map +1 -1
  127. package/dist/registry.js +7 -0
  128. package/dist/registryData.json +43 -6
  129. package/dist/report.d.ts +2 -1
  130. package/dist/report.d.ts.map +1 -1
  131. package/dist/report.js +189 -2
  132. package/dist/reporting.d.ts +125 -0
  133. package/dist/reporting.d.ts.map +1 -1
  134. package/dist/reporting.js +192 -2
  135. package/dist/resources.d.ts +285 -0
  136. package/dist/resources.d.ts.map +1 -0
  137. package/dist/resources.js +643 -0
  138. package/dist/risk.d.ts +120 -0
  139. package/dist/risk.d.ts.map +1 -0
  140. package/dist/risk.js +220 -0
  141. package/dist/runtime.d.ts +74 -0
  142. package/dist/runtime.d.ts.map +1 -1
  143. package/dist/runtime.js +416 -18
  144. package/dist/schemaInference.d.ts +92 -0
  145. package/dist/schemaInference.d.ts.map +1 -0
  146. package/dist/schemaInference.js +466 -0
  147. package/dist/schema_validation.js +2 -2
  148. package/dist/schemas/config.schema.json +118 -4
  149. package/dist/security_report.js +4 -4
  150. package/dist/signing.d.ts +1 -1
  151. package/dist/signing.d.ts.map +1 -1
  152. package/dist/signing.js +4 -0
  153. package/dist/sinks/file.d.ts +19 -1
  154. package/dist/sinks/file.d.ts.map +1 -1
  155. package/dist/sinks/file.js +82 -13
  156. package/dist/sinks/https.d.ts +10 -0
  157. package/dist/sinks/https.d.ts.map +1 -1
  158. package/dist/sinks/https.js +76 -16
  159. package/dist/sinks/stdout.d.ts +1 -0
  160. package/dist/sinks/stdout.d.ts.map +1 -1
  161. package/dist/sinks/stdout.js +12 -1
  162. package/dist/spec.d.ts +159 -0
  163. package/dist/spec.d.ts.map +1 -0
  164. package/dist/spec.js +391 -0
  165. package/dist/stakeholders.d.ts +199 -0
  166. package/dist/stakeholders.d.ts.map +1 -0
  167. package/dist/stakeholders.js +398 -0
  168. package/dist/standards.d.ts.map +1 -1
  169. package/dist/standards.js +160 -2
  170. package/dist/standards_ingest.d.ts.map +1 -1
  171. package/dist/standards_ingest.js +1 -4
  172. package/dist/telemetry.d.ts +16 -2
  173. package/dist/telemetry.d.ts.map +1 -1
  174. package/dist/telemetry.js +77 -14
  175. package/dist/templates/controls/gdpr_control_catalog.json +261 -0
  176. package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
  177. package/dist/templates/controls/soc2_control_catalog.json +163 -0
  178. package/dist/templates/standards/iso42001_claims.json +72 -0
  179. package/dist/traced_emitter.d.ts.map +1 -1
  180. package/dist/traced_emitter.js +19 -9
  181. package/dist/trust_package.d.ts +20 -1
  182. package/dist/trust_package.d.ts.map +1 -1
  183. package/dist/trust_package.js +90 -2
  184. package/dist/verify.d.ts.map +1 -1
  185. package/dist/verify.js +9 -2
  186. package/dist/wal.d.ts.map +1 -1
  187. package/dist/wal.js +2 -1
  188. package/package.json +14 -1
  189. package/scripts/postinstall.js +105 -210
  190. package/templates/controls/gdpr_control_catalog.json +261 -0
  191. package/templates/controls/iso42001_control_catalog.json +1443 -0
  192. package/templates/controls/soc2_control_catalog.json +163 -0
  193. package/templates/standards/iso42001_claims.json +72 -0
package/dist/report.d.ts CHANGED
@@ -2,8 +2,9 @@
2
2
  * CLI report generation utilities.
3
3
  */
4
4
  import { MonoraConfig } from './config';
5
+ import { ModelRegistryConfig } from './registry';
5
6
  export declare function loadJsonl(path: string): Array<Record<string, any>>;
6
- export declare function buildReport(events: Array<Record<string, any>>, policies?: MonoraConfig['policies']): Record<string, any>;
7
+ export declare function buildReport(events: Array<Record<string, any>>, policies?: MonoraConfig['policies'], registryConfig?: ModelRegistryConfig): Record<string, any>;
7
8
  export declare function buildUsageSummary(events: Array<Record<string, any>>): Record<string, any>;
8
9
  export declare function writeJson(path: string, report: Record<string, any>): void;
9
10
  export declare function writeMarkdown(path: string, report: Record<string, any>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAKxC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAelE;AAqJD,wBAAgB,WAAW,CACzB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAClC,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA6PrB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA4EzF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAEzE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAsD7E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CA4DnF"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAiB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAKhE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAelE;AAmPD,wBAAgB,WAAW,CACzB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAClC,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,EACnC,cAAc,CAAC,EAAE,mBAAmB,GACnC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA8RrB;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA2GzF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAEzE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CA6E7E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAmFnF"}
package/dist/report.js CHANGED
@@ -43,6 +43,7 @@ exports.writeJson = writeJson;
43
43
  exports.writeMarkdown = writeMarkdown;
44
44
  exports.writeUsageMarkdown = writeUsageMarkdown;
45
45
  const fs = __importStar(require("fs"));
46
+ const registry_1 = require("./registry");
46
47
  const logger_1 = require("./logger");
47
48
  function loadJsonl(path) {
48
49
  const events = [];
@@ -164,6 +165,83 @@ function extractUsage(body) {
164
165
  }
165
166
  return null;
166
167
  }
168
+ function coerceCost(value) {
169
+ if (value === null || value === undefined) {
170
+ return null;
171
+ }
172
+ const numberValue = Number(value);
173
+ return Number.isFinite(numberValue) ? numberValue : null;
174
+ }
175
+ function extractUsagePayload(body) {
176
+ const response = body.response;
177
+ if (response && typeof response === 'object' && response.usage && typeof response.usage === 'object') {
178
+ return response.usage;
179
+ }
180
+ if (body.usage && typeof body.usage === 'object') {
181
+ return body.usage;
182
+ }
183
+ if (body.token_usage && typeof body.token_usage === 'object') {
184
+ return body.token_usage;
185
+ }
186
+ return null;
187
+ }
188
+ function estimateCostFromPricing(pricing, usage) {
189
+ if (!pricing || typeof pricing !== 'object' || !usage) {
190
+ return null;
191
+ }
192
+ const unit = String(pricing.unit || '1k_tokens').toLowerCase();
193
+ let scale = 1000;
194
+ if (unit === '1m_tokens' || unit === '1m' || unit === 'per_1m') {
195
+ scale = 1000000;
196
+ }
197
+ else if (unit === 'token' || unit === 'per_token') {
198
+ scale = 1;
199
+ }
200
+ const totalRate = coerceCost(pricing.cost_per_1k_tokens ||
201
+ pricing.total_cost_per_1k ||
202
+ pricing.cost_per_1m_tokens ||
203
+ pricing.total_cost_per_1m);
204
+ const promptRate = coerceCost(pricing.prompt_cost_per_1k ||
205
+ pricing.input_cost_per_1k ||
206
+ pricing.prompt_cost_per_1m ||
207
+ pricing.input_cost_per_1m);
208
+ const completionRate = coerceCost(pricing.completion_cost_per_1k ||
209
+ pricing.output_cost_per_1k ||
210
+ pricing.completion_cost_per_1m ||
211
+ pricing.output_cost_per_1m);
212
+ if (totalRate !== null) {
213
+ return (usage.total / scale) * totalRate;
214
+ }
215
+ if (promptRate === null && completionRate === null) {
216
+ return null;
217
+ }
218
+ let cost = 0;
219
+ if (promptRate !== null) {
220
+ cost += (usage.prompt / scale) * promptRate;
221
+ }
222
+ if (completionRate !== null) {
223
+ cost += (usage.completion / scale) * completionRate;
224
+ }
225
+ return cost;
226
+ }
227
+ function estimateCost(body, model, usage, registry) {
228
+ const usagePayload = extractUsagePayload(body);
229
+ if (usagePayload) {
230
+ for (const key of ['total_cost', 'cost', 'estimated_cost', 'total_cost_usd', 'cost_usd']) {
231
+ const value = usagePayload[key];
232
+ const cost = coerceCost(value);
233
+ if (cost !== null) {
234
+ return cost;
235
+ }
236
+ }
237
+ }
238
+ if (!registry || !model) {
239
+ return null;
240
+ }
241
+ const metadata = registry.getModelMetadata(model);
242
+ const pricing = metadata && typeof metadata === 'object' ? metadata.pricing : null;
243
+ return estimateCostFromPricing(pricing, usage);
244
+ }
167
245
  function classifyPolicyViolation(policyName) {
168
246
  const lowered = policyName.toLowerCase();
169
247
  if (lowered.includes('unknown_model')) {
@@ -194,8 +272,9 @@ function matchesAny(patterns, model, used) {
194
272
  }
195
273
  return false;
196
274
  }
197
- function buildReport(events, policies) {
275
+ function buildReport(events, policies, registryConfig) {
198
276
  const filteredEvents = events.filter((event) => event.event_type !== 'trust_summary');
277
+ const registry = new registry_1.ModelRegistry(registryConfig || {});
199
278
  const traceIds = new Set();
200
279
  const timestamps = [];
201
280
  const byEventType = {};
@@ -210,6 +289,12 @@ function buildReport(events, policies) {
210
289
  missing_usage_events: 0,
211
290
  missing_usage_models: [],
212
291
  };
292
+ const costUsage = {
293
+ total_cost_usd: 0,
294
+ by_model: {},
295
+ missing_cost_events: 0,
296
+ missing_cost_models: [],
297
+ };
213
298
  const violations = [];
214
299
  const errors = [];
215
300
  const modelsUsed = new Set();
@@ -218,9 +303,12 @@ function buildReport(events, policies) {
218
303
  const allowedModelsUsed = new Set();
219
304
  const usedAllowlistPatterns = new Set();
220
305
  const missingUsageModels = new Set();
306
+ const missingCostModels = new Set();
221
307
  let missingUsageEvents = 0;
308
+ let missingCostEvents = 0;
222
309
  const modelEventIds = {};
223
310
  const missingUsageEventIds = [];
311
+ const missingCostEventIds = [];
224
312
  const unknownViolationEventIds = {};
225
313
  const forbiddenViolationEventIds = {};
226
314
  for (const event of filteredEvents) {
@@ -292,8 +380,9 @@ function buildReport(events, policies) {
292
380
  }
293
381
  modelEventIds[model].push(event.event_id);
294
382
  }
383
+ let usage = null;
295
384
  if (!isBlocked) {
296
- const usage = extractUsage(body);
385
+ usage = extractUsage(body);
297
386
  if (!usage) {
298
387
  missingUsageEvents += 1;
299
388
  if (model) {
@@ -315,6 +404,25 @@ function buildReport(events, policies) {
315
404
  }
316
405
  }
317
406
  }
407
+ if (!isBlocked) {
408
+ const cost = estimateCost(body, model, usage, registry);
409
+ if (cost === null) {
410
+ missingCostEvents += 1;
411
+ missingCostEventIds.push(event.event_id);
412
+ if (model) {
413
+ missingCostModels.add(model);
414
+ }
415
+ }
416
+ else {
417
+ costUsage.total_cost_usd += cost;
418
+ if (model) {
419
+ if (!costUsage.by_model[model]) {
420
+ costUsage.by_model[model] = { estimated_cost_usd: 0 };
421
+ }
422
+ costUsage.by_model[model].estimated_cost_usd += cost;
423
+ }
424
+ }
425
+ }
318
426
  }
319
427
  if (body.error) {
320
428
  errors.push({
@@ -368,6 +476,8 @@ function buildReport(events, policies) {
368
476
  }
369
477
  tokenUsage.missing_usage_events = missingUsageEvents;
370
478
  tokenUsage.missing_usage_models = Array.from(missingUsageModels).sort();
479
+ costUsage.missing_cost_events = missingCostEvents;
480
+ costUsage.missing_cost_models = Array.from(missingCostModels).sort();
371
481
  const unusedAllowlistPatterns = allowlistPatterns.length > 0
372
482
  ? allowlistPatterns
373
483
  .map(([raw]) => raw)
@@ -413,6 +523,7 @@ function buildReport(events, policies) {
413
523
  violations,
414
524
  errors,
415
525
  token_usage: tokenUsage,
526
+ cost_usage: costUsage,
416
527
  model_compliance: {
417
528
  allowed_models_used: Array.from(allowedModelsUsed).sort(),
418
529
  forbidden_models_blocked: Array.from(forbiddenModelsBlocked).sort(),
@@ -427,17 +538,23 @@ function buildReport(events, policies) {
427
538
  forbidden_models: forbiddenModelsEvidence,
428
539
  errors,
429
540
  missing_usage_events: dedupe(missingUsageEventIds),
541
+ missing_cost_events: dedupe(missingCostEventIds),
430
542
  },
431
543
  };
432
544
  }
433
545
  function buildUsageSummary(events) {
434
546
  const filteredEvents = events.filter((event) => event.event_type !== 'trust_summary');
547
+ const registry = new registry_1.ModelRegistry({});
435
548
  const traceIds = new Set();
436
549
  const timestamps = [];
437
550
  const dailyCounts = {};
438
551
  const apiByType = {};
439
552
  const apiStatusCounts = {};
440
553
  const modelCounts = {};
554
+ const costByModel = {};
555
+ let totalCostUsd = 0;
556
+ let missingCostEvents = 0;
557
+ const missingCostModels = new Set();
441
558
  let sdkInits = 0;
442
559
  for (const event of filteredEvents) {
443
560
  if (event.trace_id) {
@@ -465,6 +582,22 @@ function buildUsageSummary(events) {
465
582
  if (model) {
466
583
  modelCounts[model] = (modelCounts[model] || 0) + 1;
467
584
  }
585
+ if (status !== 'policy_violation') {
586
+ const usage = extractUsage(body);
587
+ const cost = estimateCost(body, model, usage, registry);
588
+ if (cost === null) {
589
+ missingCostEvents += 1;
590
+ if (model) {
591
+ missingCostModels.add(model);
592
+ }
593
+ }
594
+ else {
595
+ totalCostUsd += cost;
596
+ if (model) {
597
+ costByModel[model] = (costByModel[model] || 0) + cost;
598
+ }
599
+ }
600
+ }
468
601
  }
469
602
  }
470
603
  }
@@ -484,6 +617,10 @@ function buildUsageSummary(events) {
484
617
  .sort(([, a], [, b]) => b - a)
485
618
  .slice(0, 5)
486
619
  .map(([model, count]) => ({ model, count }));
620
+ const topCostModels = Object.entries(costByModel)
621
+ .sort(([, a], [, b]) => b - a)
622
+ .slice(0, 5)
623
+ .map(([model, cost]) => ({ model, estimated_cost_usd: cost }));
487
624
  return {
488
625
  period: { start, end },
489
626
  total_events: filteredEvents.length,
@@ -498,6 +635,13 @@ function buildUsageSummary(events) {
498
635
  active_days: Object.keys(dailyCounts).length,
499
636
  daily_activity: dailyActivity,
500
637
  top_models: topModels,
638
+ cost_usage: {
639
+ total_cost_usd: totalCostUsd,
640
+ by_model: costByModel,
641
+ missing_cost_events: missingCostEvents,
642
+ missing_cost_models: Array.from(missingCostModels).sort(),
643
+ },
644
+ top_cost_models: topCostModels,
501
645
  };
502
646
  }
503
647
  function writeJson(path, report) {
@@ -522,6 +666,29 @@ function writeMarkdown(path, report) {
522
666
  for (const [model, count] of Object.entries(report.by_model || {})) {
523
667
  lines.push(`- ${model}: ${count} calls`);
524
668
  }
669
+ const costUsage = report.cost_usage || {};
670
+ if (Object.keys(costUsage).length > 0) {
671
+ const totalCost = typeof costUsage.total_cost_usd === 'number'
672
+ ? costUsage.total_cost_usd.toFixed(6)
673
+ : 'N/A';
674
+ lines.push('');
675
+ lines.push('## Cost Usage');
676
+ lines.push(`- Total estimated cost (USD): ${totalCost}`);
677
+ const byModelCost = costUsage.by_model || {};
678
+ const sortedModels = Object.entries(byModelCost)
679
+ .sort(([, a], [, b]) => (b.estimated_cost_usd || 0) - (a.estimated_cost_usd || 0))
680
+ .slice(0, 5);
681
+ if (sortedModels.length > 0) {
682
+ lines.push('- By model:');
683
+ for (const [model, data] of sortedModels) {
684
+ const costData = data;
685
+ const costValue = costData && typeof costData.estimated_cost_usd === 'number'
686
+ ? costData.estimated_cost_usd.toFixed(6)
687
+ : '0.000000';
688
+ lines.push(` - ${model}: ${costValue}`);
689
+ }
690
+ }
691
+ }
525
692
  const violations = report.violations || [];
526
693
  lines.push('');
527
694
  lines.push(`## Policy Violations (${violations.length})`);
@@ -584,6 +751,26 @@ function writeUsageMarkdown(path, summary) {
584
751
  lines.push(` - ${status}: ${count}`);
585
752
  }
586
753
  }
754
+ const costUsage = summary.cost_usage || {};
755
+ if (Object.keys(costUsage).length > 0) {
756
+ const totalCost = typeof costUsage.total_cost_usd === 'number'
757
+ ? costUsage.total_cost_usd.toFixed(6)
758
+ : 'N/A';
759
+ lines.push('');
760
+ lines.push('## Cost Usage');
761
+ lines.push(`- Total estimated cost (USD): ${totalCost}`);
762
+ const topCostModels = summary.top_cost_models || [];
763
+ if (topCostModels.length > 0) {
764
+ lines.push('- Top models by cost:');
765
+ for (const entry of topCostModels) {
766
+ const model = entry.model;
767
+ const costValue = typeof entry.estimated_cost_usd === 'number'
768
+ ? entry.estimated_cost_usd.toFixed(6)
769
+ : '0.000000';
770
+ lines.push(` - ${model}: ${costValue}`);
771
+ }
772
+ }
773
+ }
587
774
  lines.push('');
588
775
  lines.push('## Daily Activity');
589
776
  const dailyActivity = summary.daily_activity || [];
@@ -3,6 +3,131 @@
3
3
  */
4
4
  import { MonoraConfig } from './config';
5
5
  export declare const TRUST_SUMMARY_EVENT_TYPE = "trust_summary";
6
+ export declare const COMPLIANCE_DRIFT_EVENT_TYPE = "compliance_drift";
7
+ /**
8
+ * Compliance score snapshot for monitoring.
9
+ */
10
+ export interface ComplianceScoreSnapshot {
11
+ traceId: string;
12
+ score: number;
13
+ grade: string;
14
+ timestamp: string;
15
+ framework?: string;
16
+ }
17
+ /**
18
+ * Compliance drift event data.
19
+ */
20
+ export interface ComplianceDriftEvent {
21
+ eventType: typeof COMPLIANCE_DRIFT_EVENT_TYPE;
22
+ previousScore: number;
23
+ currentScore: number;
24
+ scoreDelta: number;
25
+ previousGrade: string;
26
+ currentGrade: string;
27
+ traceId: string;
28
+ previousTraceId: string;
29
+ timestamp: string;
30
+ driftDirection: 'improved' | 'degraded' | 'stable';
31
+ threshold: number;
32
+ }
33
+ /**
34
+ * Callback for compliance drift events.
35
+ */
36
+ export type ComplianceDriftCallback = (event: ComplianceDriftEvent) => void;
37
+ /**
38
+ * Options for compliance monitoring.
39
+ */
40
+ export interface ComplianceMonitorOptions {
41
+ /** Score change threshold to trigger drift event (default: 5) */
42
+ driftThreshold?: number;
43
+ /** Maximum number of snapshots to retain (default: 100) */
44
+ maxSnapshots?: number;
45
+ /** Framework to monitor (optional, monitors all if not set) */
46
+ framework?: string;
47
+ /** Callback for drift events */
48
+ onDrift?: ComplianceDriftCallback;
49
+ }
50
+ /**
51
+ * Continuous compliance monitoring for tracking score changes.
52
+ *
53
+ * Monitors compliance scores across traces and emits drift events
54
+ * when scores change significantly.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const monitor = new ComplianceMonitor({
59
+ * driftThreshold: 5,
60
+ * onDrift: (event) => {
61
+ * if (event.driftDirection === 'degraded') {
62
+ * console.warn(`Compliance degraded: ${event.scoreDelta} points`);
63
+ * }
64
+ * },
65
+ * });
66
+ *
67
+ * // Record score after each trace
68
+ * monitor.recordScore('trace_1', 85, 'B');
69
+ * monitor.recordScore('trace_2', 78, 'C'); // Triggers drift event
70
+ * ```
71
+ */
72
+ export declare class ComplianceMonitor {
73
+ private snapshots;
74
+ private driftThreshold;
75
+ private maxSnapshots;
76
+ private framework?;
77
+ private onDrift?;
78
+ private driftCallbacks;
79
+ constructor(options?: ComplianceMonitorOptions);
80
+ /**
81
+ * Record a compliance score snapshot.
82
+ *
83
+ * @param traceId - Trace identifier
84
+ * @param score - Compliance score (0-100)
85
+ * @param grade - Grade letter (A-F)
86
+ * @param framework - Optional framework name
87
+ * @returns Drift event if threshold exceeded, null otherwise
88
+ */
89
+ recordScore(traceId: string, score: number, grade: string, framework?: string): ComplianceDriftEvent | null;
90
+ /**
91
+ * Get the latest score snapshot.
92
+ */
93
+ getLatestSnapshot(): ComplianceScoreSnapshot | null;
94
+ /**
95
+ * Get all score snapshots.
96
+ */
97
+ getSnapshots(): ComplianceScoreSnapshot[];
98
+ /**
99
+ * Get score trend (average change over recent snapshots).
100
+ *
101
+ * @param windowSize - Number of recent snapshots to consider (default: 5)
102
+ */
103
+ getScoreTrend(windowSize?: number): {
104
+ trend: 'improving' | 'degrading' | 'stable';
105
+ avgChange: number;
106
+ };
107
+ /**
108
+ * Get compliance statistics.
109
+ */
110
+ getStatistics(): {
111
+ currentScore: number | null;
112
+ averageScore: number;
113
+ minScore: number;
114
+ maxScore: number;
115
+ snapshotCount: number;
116
+ trend: 'improving' | 'degrading' | 'stable';
117
+ };
118
+ /**
119
+ * Register a callback for drift events.
120
+ *
121
+ * @param callback - Function to call on drift
122
+ * @returns Unsubscribe function
123
+ */
124
+ onDriftEvent(callback: ComplianceDriftCallback): () => void;
125
+ /**
126
+ * Clear all snapshots.
127
+ */
128
+ reset(): void;
129
+ private notifyDrift;
130
+ }
6
131
  interface RegistryMetadata {
7
132
  version?: string;
8
133
  hash?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"reporting.d.ts","sourceRoot":"","sources":["../src/reporting.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAWxC,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AAWxD,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC,CAAC;CACJ;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,aAAa,CAAsD;IAC3E,OAAO,CAAC,cAAc,CAAkC;gBAE5C,MAAM,EAAE,YAAY;IAWhC,SAAS,IAAI,OAAO;IAIpB,sBAAsB,IAAI,OAAO;IAIjC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAoB7C,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI;IAWlE;;;OAGG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAI9B,aAAa,CACX,OAAO,EAAE,MAAM,EACf,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,IAAI,GACzC;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,GAAG,IAAI;CAwH3C"}
1
+ {"version":3,"file":"reporting.d.ts","sourceRoot":"","sources":["../src/reporting.ts"],"names":[],"mappings":"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"}
package/dist/reporting.js CHANGED
@@ -36,7 +36,7 @@ var __importStar = (this && this.__importStar) || (function () {
36
36
  };
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.TraceReportManager = exports.TRUST_SUMMARY_EVENT_TYPE = void 0;
39
+ exports.TraceReportManager = exports.ComplianceMonitor = exports.COMPLIANCE_DRIFT_EVENT_TYPE = exports.TRUST_SUMMARY_EVENT_TYPE = void 0;
40
40
  const crypto = __importStar(require("crypto"));
41
41
  const fs = __importStar(require("fs"));
42
42
  const path = __importStar(require("path"));
@@ -47,6 +47,196 @@ const report_1 = require("./report");
47
47
  const security_report_1 = require("./security_report");
48
48
  const verify_1 = require("./verify");
49
49
  exports.TRUST_SUMMARY_EVENT_TYPE = 'trust_summary';
50
+ exports.COMPLIANCE_DRIFT_EVENT_TYPE = 'compliance_drift';
51
+ /**
52
+ * Continuous compliance monitoring for tracking score changes.
53
+ *
54
+ * Monitors compliance scores across traces and emits drift events
55
+ * when scores change significantly.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const monitor = new ComplianceMonitor({
60
+ * driftThreshold: 5,
61
+ * onDrift: (event) => {
62
+ * if (event.driftDirection === 'degraded') {
63
+ * console.warn(`Compliance degraded: ${event.scoreDelta} points`);
64
+ * }
65
+ * },
66
+ * });
67
+ *
68
+ * // Record score after each trace
69
+ * monitor.recordScore('trace_1', 85, 'B');
70
+ * monitor.recordScore('trace_2', 78, 'C'); // Triggers drift event
71
+ * ```
72
+ */
73
+ class ComplianceMonitor {
74
+ constructor(options = {}) {
75
+ this.snapshots = [];
76
+ this.driftCallbacks = [];
77
+ this.driftThreshold = options.driftThreshold ?? 5;
78
+ this.maxSnapshots = options.maxSnapshots ?? 100;
79
+ this.framework = options.framework;
80
+ this.onDrift = options.onDrift;
81
+ }
82
+ /**
83
+ * Record a compliance score snapshot.
84
+ *
85
+ * @param traceId - Trace identifier
86
+ * @param score - Compliance score (0-100)
87
+ * @param grade - Grade letter (A-F)
88
+ * @param framework - Optional framework name
89
+ * @returns Drift event if threshold exceeded, null otherwise
90
+ */
91
+ recordScore(traceId, score, grade, framework) {
92
+ const snapshot = {
93
+ traceId,
94
+ score,
95
+ grade,
96
+ timestamp: new Date().toISOString(),
97
+ framework,
98
+ };
99
+ const previousSnapshot = this.getLatestSnapshot();
100
+ this.snapshots.push(snapshot);
101
+ // Trim old snapshots
102
+ if (this.snapshots.length > this.maxSnapshots) {
103
+ this.snapshots = this.snapshots.slice(-this.maxSnapshots);
104
+ }
105
+ // Check for drift
106
+ if (previousSnapshot) {
107
+ const scoreDelta = score - previousSnapshot.score;
108
+ const absDelta = Math.abs(scoreDelta);
109
+ if (absDelta >= this.driftThreshold) {
110
+ const driftEvent = {
111
+ eventType: exports.COMPLIANCE_DRIFT_EVENT_TYPE,
112
+ previousScore: previousSnapshot.score,
113
+ currentScore: score,
114
+ scoreDelta,
115
+ previousGrade: previousSnapshot.grade,
116
+ currentGrade: grade,
117
+ traceId,
118
+ previousTraceId: previousSnapshot.traceId,
119
+ timestamp: snapshot.timestamp,
120
+ driftDirection: scoreDelta > 0 ? 'improved' : scoreDelta < 0 ? 'degraded' : 'stable',
121
+ threshold: this.driftThreshold,
122
+ };
123
+ // Notify callbacks
124
+ this.notifyDrift(driftEvent);
125
+ return driftEvent;
126
+ }
127
+ }
128
+ return null;
129
+ }
130
+ /**
131
+ * Get the latest score snapshot.
132
+ */
133
+ getLatestSnapshot() {
134
+ return this.snapshots.length > 0 ? this.snapshots[this.snapshots.length - 1] : null;
135
+ }
136
+ /**
137
+ * Get all score snapshots.
138
+ */
139
+ getSnapshots() {
140
+ return [...this.snapshots];
141
+ }
142
+ /**
143
+ * Get score trend (average change over recent snapshots).
144
+ *
145
+ * @param windowSize - Number of recent snapshots to consider (default: 5)
146
+ */
147
+ getScoreTrend(windowSize = 5) {
148
+ if (this.snapshots.length < 2) {
149
+ return { trend: 'stable', avgChange: 0 };
150
+ }
151
+ const recentSnapshots = this.snapshots.slice(-windowSize);
152
+ if (recentSnapshots.length < 2) {
153
+ return { trend: 'stable', avgChange: 0 };
154
+ }
155
+ let totalChange = 0;
156
+ for (let i = 1; i < recentSnapshots.length; i++) {
157
+ totalChange += recentSnapshots[i].score - recentSnapshots[i - 1].score;
158
+ }
159
+ const avgChange = totalChange / (recentSnapshots.length - 1);
160
+ let trend;
161
+ if (avgChange > 1) {
162
+ trend = 'improving';
163
+ }
164
+ else if (avgChange < -1) {
165
+ trend = 'degrading';
166
+ }
167
+ else {
168
+ trend = 'stable';
169
+ }
170
+ return { trend, avgChange: Number(avgChange.toFixed(2)) };
171
+ }
172
+ /**
173
+ * Get compliance statistics.
174
+ */
175
+ getStatistics() {
176
+ if (this.snapshots.length === 0) {
177
+ return {
178
+ currentScore: null,
179
+ averageScore: 0,
180
+ minScore: 0,
181
+ maxScore: 0,
182
+ snapshotCount: 0,
183
+ trend: 'stable',
184
+ };
185
+ }
186
+ const scores = this.snapshots.map((s) => s.score);
187
+ const sum = scores.reduce((a, b) => a + b, 0);
188
+ return {
189
+ currentScore: scores[scores.length - 1],
190
+ averageScore: Number((sum / scores.length).toFixed(2)),
191
+ minScore: Math.min(...scores),
192
+ maxScore: Math.max(...scores),
193
+ snapshotCount: this.snapshots.length,
194
+ trend: this.getScoreTrend().trend,
195
+ };
196
+ }
197
+ /**
198
+ * Register a callback for drift events.
199
+ *
200
+ * @param callback - Function to call on drift
201
+ * @returns Unsubscribe function
202
+ */
203
+ onDriftEvent(callback) {
204
+ this.driftCallbacks.push(callback);
205
+ return () => {
206
+ const index = this.driftCallbacks.indexOf(callback);
207
+ if (index !== -1) {
208
+ this.driftCallbacks.splice(index, 1);
209
+ }
210
+ };
211
+ }
212
+ /**
213
+ * Clear all snapshots.
214
+ */
215
+ reset() {
216
+ this.snapshots = [];
217
+ }
218
+ notifyDrift(event) {
219
+ // Call constructor callback
220
+ if (this.onDrift) {
221
+ try {
222
+ this.onDrift(event);
223
+ }
224
+ catch {
225
+ // Ignore callback errors
226
+ }
227
+ }
228
+ // Call registered callbacks
229
+ for (const callback of this.driftCallbacks) {
230
+ try {
231
+ callback(event);
232
+ }
233
+ catch {
234
+ // Ignore callback errors
235
+ }
236
+ }
237
+ }
238
+ }
239
+ exports.ComplianceMonitor = ComplianceMonitor;
50
240
  class TraceReportManager {
51
241
  constructor(config) {
52
242
  this.eventsByTrace = new Map();
@@ -113,7 +303,7 @@ class TraceReportManager {
113
303
  this.eventsByTrace.delete(traceId);
114
304
  const dropped = this.droppedByTrace.get(traceId) || 0;
115
305
  this.droppedByTrace.delete(traceId);
116
- const report = (0, report_1.buildReport)(events, this.config.policies || {});
306
+ const report = (0, report_1.buildReport)(events, this.config.policies || {}, this.config.registry);
117
307
  const artifacts = [];
118
308
  const reportPaths = {};
119
309
  let reportDir = resolveReportDir(this.outputDir, traceId);