@absolutejs/voice 0.0.22-beta.153 → 0.0.22-beta.155

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.
@@ -468,6 +468,298 @@ var createVoiceDeliveryRuntime = (path = "/api/voice-delivery-runtime", options
468
468
  tick: store.tick
469
469
  };
470
470
  };
471
+ // src/client/opsActionCenter.ts
472
+ var recordVoiceOpsActionResult = async (result, options = {}) => {
473
+ if (options.auditPath === false) {
474
+ return;
475
+ }
476
+ const path = options.auditPath ?? "/api/voice/ops-actions/audit";
477
+ const fetchImpl = options.fetch ?? globalThis.fetch;
478
+ const response = await fetchImpl(path, {
479
+ body: JSON.stringify(result),
480
+ headers: {
481
+ "Content-Type": "application/json"
482
+ },
483
+ method: "POST"
484
+ });
485
+ if (!response.ok) {
486
+ throw new Error(`Voice ops action audit failed: HTTP ${response.status}`);
487
+ }
488
+ };
489
+ var createVoiceOpsActionCenterActions = (options = {}) => {
490
+ const deliveryRuntimePath = options.deliveryRuntimePath ?? "/api/voice-delivery-runtime";
491
+ const actions = [];
492
+ if (options.includeProductionReadiness !== false) {
493
+ actions.push({
494
+ description: "Refresh the production readiness report.",
495
+ id: "production-readiness",
496
+ label: "Refresh readiness",
497
+ method: "GET",
498
+ path: options.productionReadinessPath ?? "/api/production-readiness"
499
+ });
500
+ }
501
+ if (options.includeDeliveryRuntime !== false) {
502
+ actions.push({
503
+ description: "Drain pending and failed audit/trace deliveries.",
504
+ id: "delivery-runtime.tick",
505
+ label: "Tick delivery workers",
506
+ method: "POST",
507
+ path: `${deliveryRuntimePath.replace(/\/$/, "")}/tick`
508
+ }, {
509
+ description: "Move reviewed dead letters back to live delivery queues.",
510
+ id: "delivery-runtime.requeue-dead-letters",
511
+ label: "Requeue dead letters",
512
+ method: "POST",
513
+ path: `${deliveryRuntimePath.replace(/\/$/, "")}/requeue-dead-letters`
514
+ });
515
+ }
516
+ if (options.includeTurnLatencyProof !== false) {
517
+ actions.push({
518
+ description: "Run the synthetic turn latency proof.",
519
+ id: "turn-latency.proof",
520
+ label: "Run latency proof",
521
+ method: "POST",
522
+ path: options.turnLatencyProofPath ?? "/api/turn-latency/proof"
523
+ });
524
+ }
525
+ if (options.includeProviderSimulation !== false) {
526
+ const pathPrefix = options.providerSimulationPathPrefix ?? "/api/stt-simulate";
527
+ for (const provider of options.providers ?? []) {
528
+ actions.push({
529
+ description: `Simulate ${provider} provider failure.`,
530
+ id: `provider.${provider}.failure`,
531
+ label: `Simulate ${provider} failure`,
532
+ method: "POST",
533
+ path: `${pathPrefix}/failure?provider=${encodeURIComponent(provider)}`
534
+ }, {
535
+ description: `Mark ${provider} provider recovered.`,
536
+ id: `provider.${provider}.recovery`,
537
+ label: `Recover ${provider}`,
538
+ method: "POST",
539
+ path: `${pathPrefix}/recovery?provider=${encodeURIComponent(provider)}`
540
+ });
541
+ }
542
+ }
543
+ return actions;
544
+ };
545
+ var runVoiceOpsAction = async (action, options = {}) => {
546
+ const fetchImpl = options.fetch ?? globalThis.fetch;
547
+ const response = await fetchImpl(action.path, {
548
+ method: action.method ?? "POST"
549
+ });
550
+ const body = await response.json().catch(() => null);
551
+ if (!response.ok) {
552
+ const message = body && typeof body === "object" && "error" in body ? String(body.error) : `Voice ops action "${action.id}" failed: HTTP ${response.status}`;
553
+ throw new Error(message);
554
+ }
555
+ return {
556
+ actionId: action.id,
557
+ body,
558
+ ok: response.ok,
559
+ ranAt: Date.now(),
560
+ status: response.status
561
+ };
562
+ };
563
+ var createVoiceOpsActionCenterStore = (options = {}) => {
564
+ const listeners = new Set;
565
+ let closed = false;
566
+ let timer;
567
+ let snapshot = {
568
+ actions: options.actions ?? createVoiceOpsActionCenterActions(),
569
+ error: null,
570
+ isRunning: false
571
+ };
572
+ const emit = () => {
573
+ for (const listener of listeners) {
574
+ listener();
575
+ }
576
+ };
577
+ const setActions = (actions) => {
578
+ snapshot = { ...snapshot, actions, updatedAt: Date.now() };
579
+ emit();
580
+ };
581
+ const run = async (actionId) => {
582
+ if (closed) {
583
+ return snapshot.lastResult;
584
+ }
585
+ const action = snapshot.actions.find((item) => item.id === actionId);
586
+ if (!action) {
587
+ throw new Error(`Voice ops action "${actionId}" is not configured.`);
588
+ }
589
+ if (action.disabled) {
590
+ throw new Error(`Voice ops action "${actionId}" is disabled.`);
591
+ }
592
+ snapshot = {
593
+ ...snapshot,
594
+ error: null,
595
+ isRunning: true,
596
+ runningActionId: action.id
597
+ };
598
+ emit();
599
+ try {
600
+ const result = await runVoiceOpsAction(action, options);
601
+ await options.onActionResult?.(result);
602
+ await recordVoiceOpsActionResult(result, options);
603
+ snapshot = {
604
+ ...snapshot,
605
+ error: null,
606
+ isRunning: false,
607
+ lastResult: result,
608
+ runningActionId: undefined,
609
+ updatedAt: Date.now()
610
+ };
611
+ emit();
612
+ return result;
613
+ } catch (error) {
614
+ const result = {
615
+ actionId: action.id,
616
+ body: null,
617
+ error: error instanceof Error ? error.message : String(error),
618
+ ok: false,
619
+ ranAt: Date.now(),
620
+ status: 0
621
+ };
622
+ await options.onActionResult?.(result);
623
+ await recordVoiceOpsActionResult(result, options).catch(() => {});
624
+ snapshot = {
625
+ ...snapshot,
626
+ error: error instanceof Error ? error.message : String(error),
627
+ isRunning: false,
628
+ runningActionId: undefined
629
+ };
630
+ emit();
631
+ throw error;
632
+ }
633
+ };
634
+ const close = () => {
635
+ closed = true;
636
+ if (timer) {
637
+ clearInterval(timer);
638
+ timer = undefined;
639
+ }
640
+ listeners.clear();
641
+ };
642
+ if (options.intervalMs && options.intervalMs > 0) {
643
+ timer = setInterval(() => {
644
+ emit();
645
+ }, options.intervalMs);
646
+ }
647
+ return {
648
+ close,
649
+ getServerSnapshot: () => snapshot,
650
+ getSnapshot: () => snapshot,
651
+ run,
652
+ setActions,
653
+ subscribe: (listener) => {
654
+ listeners.add(listener);
655
+ return () => {
656
+ listeners.delete(listener);
657
+ };
658
+ }
659
+ };
660
+ };
661
+
662
+ // src/client/opsActionCenterWidget.ts
663
+ var DEFAULT_TITLE2 = "Voice Ops Action Center";
664
+ var DEFAULT_DESCRIPTION2 = "Run production voice proofs and operator actions from one primitive panel.";
665
+ var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
666
+ var createVoiceOpsActionCenterViewModel = (snapshot, options = {}) => {
667
+ const status = snapshot.error ? "error" : snapshot.isRunning ? "running" : snapshot.lastResult ? "completed" : "ready";
668
+ return {
669
+ actions: snapshot.actions.map((action) => ({
670
+ description: action.description ?? "",
671
+ disabled: Boolean(action.disabled || snapshot.isRunning),
672
+ id: action.id,
673
+ isRunning: snapshot.runningActionId === action.id,
674
+ label: action.label
675
+ })),
676
+ description: options.description ?? DEFAULT_DESCRIPTION2,
677
+ error: snapshot.error,
678
+ isRunning: snapshot.isRunning,
679
+ label: status === "error" ? "Needs attention" : status === "running" ? "Running" : status === "completed" ? "Action completed" : "Ready",
680
+ lastResultLabel: snapshot.lastResult ? `${snapshot.lastResult.actionId} returned HTTP ${snapshot.lastResult.status}` : "No action has run yet.",
681
+ status,
682
+ title: options.title ?? DEFAULT_TITLE2
683
+ };
684
+ };
685
+ var renderVoiceOpsActionCenterHTML = (snapshot, options = {}) => {
686
+ const model = createVoiceOpsActionCenterViewModel(snapshot, options);
687
+ const actions = model.actions.map((action) => `<button type="button" data-absolute-voice-ops-action="${escapeHtml2(action.id)}"${action.disabled ? " disabled" : ""}>
688
+ ${escapeHtml2(action.isRunning ? "Working..." : action.label)}
689
+ </button>`).join("");
690
+ return `<section class="absolute-voice-ops-action-center absolute-voice-ops-action-center--${escapeHtml2(model.status)}">
691
+ <header class="absolute-voice-ops-action-center__header">
692
+ <span class="absolute-voice-ops-action-center__eyebrow">${escapeHtml2(model.title)}</span>
693
+ <strong class="absolute-voice-ops-action-center__label">${escapeHtml2(model.label)}</strong>
694
+ </header>
695
+ <p class="absolute-voice-ops-action-center__description">${escapeHtml2(model.description)}</p>
696
+ <div class="absolute-voice-ops-action-center__actions">${actions}</div>
697
+ <p class="absolute-voice-ops-action-center__result">${escapeHtml2(model.lastResultLabel)}</p>
698
+ ${model.error ? `<p class="absolute-voice-ops-action-center__error">${escapeHtml2(model.error)}</p>` : ""}
699
+ </section>`;
700
+ };
701
+ var getVoiceOpsActionCenterCSS = () => `.absolute-voice-ops-action-center{border:1px solid #d5cbb8;border-radius:20px;background:#fffaf1;color:#17130b;padding:18px;box-shadow:0 18px 40px rgba(58,42,16,.12);font-family:inherit}.absolute-voice-ops-action-center--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-ops-action-center__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-ops-action-center__eyebrow{color:#725d37;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-ops-action-center__label{font-size:28px;line-height:1}.absolute-voice-ops-action-center__description,.absolute-voice-ops-action-center__result{color:#5b4b2f;margin:12px 0 0}.absolute-voice-ops-action-center__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-ops-action-center__actions button{background:#7c4a03;border:0;border-radius:999px;color:#fff8e8;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-ops-action-center__actions button:disabled{cursor:not-allowed;opacity:.5}.absolute-voice-ops-action-center__error{color:#9f1239;font-weight:700}`;
702
+ var mountVoiceOpsActionCenter = (element, options = {}) => {
703
+ const store = createVoiceOpsActionCenterStore(options);
704
+ const render = () => {
705
+ element.innerHTML = renderVoiceOpsActionCenterHTML(store.getSnapshot(), options);
706
+ };
707
+ const unsubscribe = store.subscribe(render);
708
+ const handleClick = (event) => {
709
+ const target = event.target;
710
+ if (!(target instanceof Element)) {
711
+ return;
712
+ }
713
+ const action = target.closest("[data-absolute-voice-ops-action]");
714
+ const actionId = action?.getAttribute("data-absolute-voice-ops-action");
715
+ if (actionId) {
716
+ store.run(actionId).catch(() => {});
717
+ }
718
+ };
719
+ element.addEventListener?.("click", handleClick);
720
+ render();
721
+ return {
722
+ close: () => {
723
+ element.removeEventListener?.("click", handleClick);
724
+ unsubscribe();
725
+ store.close();
726
+ },
727
+ run: store.run
728
+ };
729
+ };
730
+ var defineVoiceOpsActionCenterElement = (tagName = "absolute-voice-ops-action-center", options = {}) => {
731
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
732
+ return;
733
+ }
734
+ customElements.define(tagName, class AbsoluteVoiceOpsActionCenterElement extends HTMLElement {
735
+ mounted;
736
+ connectedCallback() {
737
+ this.mounted = mountVoiceOpsActionCenter(this, {
738
+ ...options,
739
+ description: this.getAttribute("description") ?? options.description,
740
+ title: this.getAttribute("title") ?? options.title
741
+ });
742
+ }
743
+ disconnectedCallback() {
744
+ this.mounted?.close();
745
+ this.mounted = undefined;
746
+ }
747
+ });
748
+ };
749
+
750
+ // src/svelte/createVoiceOpsActionCenter.ts
751
+ var createVoiceOpsActionCenter = (options = {}) => {
752
+ const store = createVoiceOpsActionCenterStore(options);
753
+ return {
754
+ close: store.close,
755
+ getHTML: () => renderVoiceOpsActionCenterHTML(store.getSnapshot(), options),
756
+ getSnapshot: store.getSnapshot,
757
+ getViewModel: () => createVoiceOpsActionCenterViewModel(store.getSnapshot(), options),
758
+ run: store.run,
759
+ setActions: store.setActions,
760
+ subscribe: store.subscribe
761
+ };
762
+ };
471
763
  // src/client/opsStatus.ts
472
764
  var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
473
765
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -548,8 +840,8 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
548
840
  };
549
841
 
550
842
  // src/client/opsStatusWidget.ts
551
- var DEFAULT_TITLE2 = "Voice Ops Status";
552
- var DEFAULT_DESCRIPTION2 = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
843
+ var DEFAULT_TITLE3 = "Voice Ops Status";
844
+ var DEFAULT_DESCRIPTION3 = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
553
845
  var SURFACE_LABELS = {
554
846
  handoffs: "Handoffs",
555
847
  providers: "Providers",
@@ -557,7 +849,7 @@ var SURFACE_LABELS = {
557
849
  sessions: "Sessions",
558
850
  workflows: "Workflows"
559
851
  };
560
- var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
852
+ var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
561
853
  var readNumber = (value, key) => value && typeof value === "object" && (key in value) ? Number(value[key] ?? 0) : 0;
562
854
  var surfaceDetail = (surface) => {
563
855
  const total = readNumber(surface, "total");
@@ -597,7 +889,7 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
597
889
  };
598
890
  });
599
891
  return {
600
- description: options.description ?? DEFAULT_DESCRIPTION2,
892
+ description: options.description ?? DEFAULT_DESCRIPTION3,
601
893
  error: snapshot.error,
602
894
  isLoading: snapshot.isLoading,
603
895
  label: getVoiceOpsStatusLabel(report, snapshot.error),
@@ -605,31 +897,31 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
605
897
  passed: report?.passed ?? 0,
606
898
  status: snapshot.error ? "error" : report ? report.status : snapshot.isLoading ? "loading" : "loading",
607
899
  surfaces,
608
- title: options.title ?? DEFAULT_TITLE2,
900
+ title: options.title ?? DEFAULT_TITLE3,
609
901
  total: report?.total ?? 0,
610
902
  updatedAt: snapshot.updatedAt
611
903
  };
612
904
  };
613
905
  var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
614
906
  const model = createVoiceOpsStatusViewModel(snapshot, options);
615
- const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml2(surface.status)}">
616
- <span>${escapeHtml2(surface.label)}</span>
617
- <strong>${escapeHtml2(surface.detail)}</strong>
907
+ const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml3(surface.status)}">
908
+ <span>${escapeHtml3(surface.label)}</span>
909
+ <strong>${escapeHtml3(surface.detail)}</strong>
618
910
  </li>`).join("") : '<li class="absolute-voice-ops-status__surface"><span>Status</span><strong>Waiting for first check</strong></li>';
619
- const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml2(link.href)}">${escapeHtml2(link.label)}</a>`).join("")}</nav>` : "";
620
- return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml2(model.status)}">
911
+ const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml3(link.href)}">${escapeHtml3(link.label)}</a>`).join("")}</nav>` : "";
912
+ return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml3(model.status)}">
621
913
  <header class="absolute-voice-ops-status__header">
622
- <span class="absolute-voice-ops-status__eyebrow">${escapeHtml2(model.title)}</span>
623
- <strong class="absolute-voice-ops-status__label">${escapeHtml2(model.label)}</strong>
914
+ <span class="absolute-voice-ops-status__eyebrow">${escapeHtml3(model.title)}</span>
915
+ <strong class="absolute-voice-ops-status__label">${escapeHtml3(model.label)}</strong>
624
916
  </header>
625
- <p class="absolute-voice-ops-status__description">${escapeHtml2(model.description)}</p>
917
+ <p class="absolute-voice-ops-status__description">${escapeHtml3(model.description)}</p>
626
918
  <div class="absolute-voice-ops-status__summary">
627
919
  <span>${model.passed} passing</span>
628
920
  <span>${Math.max(model.total - model.passed, 0)} failing</span>
629
921
  <span>${model.total} checks</span>
630
922
  </div>
631
923
  <ul class="absolute-voice-ops-status__surfaces">${surfaces}</ul>
632
- ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml2(model.error)}</p>` : ""}
924
+ ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml3(model.error)}</p>` : ""}
633
925
  ${links}
634
926
  </section>`;
635
927
  };
@@ -764,7 +1056,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
764
1056
  };
765
1057
 
766
1058
  // src/client/providerSimulationControlsWidget.ts
767
- var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1059
+ var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
768
1060
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
769
1061
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
770
1062
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -784,18 +1076,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
784
1076
  };
785
1077
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
786
1078
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
787
- const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml3(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml3(provider.provider)} ${escapeHtml3(formatKind(options.kind))} failure</button>`).join("");
788
- const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml3(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml3(provider.provider)} recovered</button>`).join("");
1079
+ const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml4(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml4(provider.provider)} ${escapeHtml4(formatKind(options.kind))} failure</button>`).join("");
1080
+ const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml4(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml4(provider.provider)} recovered</button>`).join("");
789
1081
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
790
1082
  <header class="absolute-voice-provider-simulation__header">
791
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
792
- <strong class="absolute-voice-provider-simulation__label">${escapeHtml3(model.label)}</strong>
1083
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml4(model.title)}</span>
1084
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml4(model.label)}</strong>
793
1085
  </header>
794
- <p class="absolute-voice-provider-simulation__description">${escapeHtml3(model.description)}</p>
795
- ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml3(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
1086
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml4(model.description)}</p>
1087
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml4(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
796
1088
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
797
- ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml3(snapshot.error)}</p>` : ""}
798
- ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml3(model.resultText)}</pre>` : ""}
1089
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml4(snapshot.error)}</p>` : ""}
1090
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml4(model.resultText)}</pre>` : ""}
799
1091
  </section>`;
800
1092
  };
801
1093
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -950,9 +1242,9 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
950
1242
  };
951
1243
 
952
1244
  // src/client/providerCapabilitiesWidget.ts
953
- var DEFAULT_TITLE3 = "Provider Capabilities";
954
- var DEFAULT_DESCRIPTION3 = "Configured, selected, and healthy voice providers for this deployment.";
955
- var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1245
+ var DEFAULT_TITLE4 = "Provider Capabilities";
1246
+ var DEFAULT_DESCRIPTION4 = "Configured, selected, and healthy voice providers for this deployment.";
1247
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
956
1248
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
957
1249
  var formatKind2 = (kind) => kind.toUpperCase();
958
1250
  var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -996,36 +1288,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
996
1288
  const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
997
1289
  return {
998
1290
  capabilities,
999
- description: options.description ?? DEFAULT_DESCRIPTION3,
1291
+ description: options.description ?? DEFAULT_DESCRIPTION4,
1000
1292
  error: snapshot.error,
1001
1293
  isLoading: snapshot.isLoading,
1002
1294
  label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
1003
1295
  status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1004
- title: options.title ?? DEFAULT_TITLE3,
1296
+ title: options.title ?? DEFAULT_TITLE4,
1005
1297
  updatedAt: snapshot.updatedAt
1006
1298
  };
1007
1299
  };
1008
1300
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
1009
1301
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
1010
- const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml4(capability.status)}">
1302
+ const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml5(capability.status)}">
1011
1303
  <header>
1012
- <strong>${escapeHtml4(capability.label)}</strong>
1013
- <span>${escapeHtml4(formatStatus(capability.status))}</span>
1304
+ <strong>${escapeHtml5(capability.label)}</strong>
1305
+ <span>${escapeHtml5(formatStatus(capability.status))}</span>
1014
1306
  </header>
1015
- <p>${escapeHtml4(capability.detail)}</p>
1307
+ <p>${escapeHtml5(capability.detail)}</p>
1016
1308
  <dl>${capability.rows.map((row) => `<div>
1017
- <dt>${escapeHtml4(row.label)}</dt>
1018
- <dd>${escapeHtml4(row.value)}</dd>
1309
+ <dt>${escapeHtml5(row.label)}</dt>
1310
+ <dd>${escapeHtml5(row.value)}</dd>
1019
1311
  </div>`).join("")}</dl>
1020
1312
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
1021
- return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml4(model.status)}">
1313
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml5(model.status)}">
1022
1314
  <header class="absolute-voice-provider-capabilities__header">
1023
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml4(model.title)}</span>
1024
- <strong class="absolute-voice-provider-capabilities__label">${escapeHtml4(model.label)}</strong>
1315
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml5(model.title)}</span>
1316
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml5(model.label)}</strong>
1025
1317
  </header>
1026
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml4(model.description)}</p>
1318
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml5(model.description)}</p>
1027
1319
  ${capabilities}
1028
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml4(model.error)}</p>` : ""}
1320
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml5(model.error)}</p>` : ""}
1029
1321
  </section>`;
1030
1322
  };
1031
1323
  var getVoiceProviderCapabilitiesCSS = () => `.absolute-voice-provider-capabilities{border:1px solid #bfd7ea;border-radius:20px;background:#f6fbff;color:#08131f;padding:18px;box-shadow:0 18px 40px rgba(14,51,78,.12);font-family:inherit}.absolute-voice-provider-capabilities--error,.absolute-voice-provider-capabilities--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-capabilities__header,.absolute-voice-provider-capabilities__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-capabilities__eyebrow{color:#255f85;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-capabilities__label{font-size:24px;line-height:1}.absolute-voice-provider-capabilities__description,.absolute-voice-provider-capabilities__provider p,.absolute-voice-provider-capabilities__provider dt,.absolute-voice-provider-capabilities__empty{color:#405467}.absolute-voice-provider-capabilities__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-capabilities__provider{background:#fff;border:1px solid #d7e7f3;border-radius:16px;padding:14px}.absolute-voice-provider-capabilities__provider--selected,.absolute-voice-provider-capabilities__provider--healthy{border-color:#86efac}.absolute-voice-provider-capabilities__provider--degraded,.absolute-voice-provider-capabilities__provider--rate-limited,.absolute-voice-provider-capabilities__provider--suppressed,.absolute-voice-provider-capabilities__provider--unconfigured{border-color:#f2a7a7}.absolute-voice-provider-capabilities__provider p{margin:10px 0}.absolute-voice-provider-capabilities__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-capabilities__provider div{background:#f6fbff;border:1px solid #d7e7f3;border-radius:12px;padding:8px}.absolute-voice-provider-capabilities__provider dt{font-size:12px}.absolute-voice-provider-capabilities__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-capabilities__empty{margin:14px 0 0}.absolute-voice-provider-capabilities__error{color:#9f1239;font-weight:700}`;
@@ -1798,9 +2090,9 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
1798
2090
  };
1799
2091
 
1800
2092
  // src/client/providerStatusWidget.ts
1801
- var DEFAULT_TITLE4 = "Voice Providers";
1802
- var DEFAULT_DESCRIPTION4 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
1803
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2093
+ var DEFAULT_TITLE5 = "Voice Providers";
2094
+ var DEFAULT_DESCRIPTION5 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
2095
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1804
2096
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1805
2097
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
1806
2098
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -1844,37 +2136,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
1844
2136
  const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
1845
2137
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
1846
2138
  return {
1847
- description: options.description ?? DEFAULT_DESCRIPTION4,
2139
+ description: options.description ?? DEFAULT_DESCRIPTION5,
1848
2140
  error: snapshot.error,
1849
2141
  isLoading: snapshot.isLoading,
1850
2142
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
1851
2143
  providers,
1852
2144
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1853
- title: options.title ?? DEFAULT_TITLE4,
2145
+ title: options.title ?? DEFAULT_TITLE5,
1854
2146
  updatedAt: snapshot.updatedAt
1855
2147
  };
1856
2148
  };
1857
2149
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
1858
2150
  const model = createVoiceProviderStatusViewModel(snapshot, options);
1859
- const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml5(provider.status)}">
2151
+ const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml6(provider.status)}">
1860
2152
  <header>
1861
- <strong>${escapeHtml5(provider.label)}</strong>
1862
- <span>${escapeHtml5(formatStatus2(provider.status))}</span>
2153
+ <strong>${escapeHtml6(provider.label)}</strong>
2154
+ <span>${escapeHtml6(formatStatus2(provider.status))}</span>
1863
2155
  </header>
1864
- <p>${escapeHtml5(provider.detail)}</p>
2156
+ <p>${escapeHtml6(provider.detail)}</p>
1865
2157
  <dl>${provider.rows.map((row) => `<div>
1866
- <dt>${escapeHtml5(row.label)}</dt>
1867
- <dd>${escapeHtml5(row.value)}</dd>
2158
+ <dt>${escapeHtml6(row.label)}</dt>
2159
+ <dd>${escapeHtml6(row.value)}</dd>
1868
2160
  </div>`).join("")}</dl>
1869
2161
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
1870
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml5(model.status)}">
2162
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml6(model.status)}">
1871
2163
  <header class="absolute-voice-provider-status__header">
1872
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
1873
- <strong class="absolute-voice-provider-status__label">${escapeHtml5(model.label)}</strong>
2164
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml6(model.title)}</span>
2165
+ <strong class="absolute-voice-provider-status__label">${escapeHtml6(model.label)}</strong>
1874
2166
  </header>
1875
- <p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
2167
+ <p class="absolute-voice-provider-status__description">${escapeHtml6(model.description)}</p>
1876
2168
  ${providers}
1877
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml5(model.error)}</p>` : ""}
2169
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml6(model.error)}</p>` : ""}
1878
2170
  </section>`;
1879
2171
  };
1880
2172
  var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
@@ -2005,9 +2297,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
2005
2297
  };
2006
2298
 
2007
2299
  // src/client/routingStatusWidget.ts
2008
- var DEFAULT_TITLE5 = "Voice Routing";
2009
- var DEFAULT_DESCRIPTION5 = "Latest provider routing decision from the self-hosted trace store.";
2010
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2300
+ var DEFAULT_TITLE6 = "Voice Routing";
2301
+ var DEFAULT_DESCRIPTION6 = "Latest provider routing decision from the self-hosted trace store.";
2302
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2011
2303
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
2012
2304
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2013
2305
  const decision = snapshot.decision;
@@ -2031,30 +2323,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2031
2323
  ] : [];
2032
2324
  return {
2033
2325
  decision,
2034
- description: options.description ?? DEFAULT_DESCRIPTION5,
2326
+ description: options.description ?? DEFAULT_DESCRIPTION6,
2035
2327
  error: snapshot.error,
2036
2328
  isLoading: snapshot.isLoading,
2037
2329
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
2038
2330
  rows,
2039
2331
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
2040
- title: options.title ?? DEFAULT_TITLE5,
2332
+ title: options.title ?? DEFAULT_TITLE6,
2041
2333
  updatedAt: snapshot.updatedAt
2042
2334
  };
2043
2335
  };
2044
2336
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
2045
2337
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
2046
2338
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
2047
- <span>${escapeHtml6(row.label)}</span>
2048
- <strong>${escapeHtml6(row.value)}</strong>
2339
+ <span>${escapeHtml7(row.label)}</span>
2340
+ <strong>${escapeHtml7(row.value)}</strong>
2049
2341
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
2050
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml6(model.status)}">
2342
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml7(model.status)}">
2051
2343
  <header class="absolute-voice-routing-status__header">
2052
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml6(model.title)}</span>
2053
- <strong class="absolute-voice-routing-status__label">${escapeHtml6(model.label)}</strong>
2344
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml7(model.title)}</span>
2345
+ <strong class="absolute-voice-routing-status__label">${escapeHtml7(model.label)}</strong>
2054
2346
  </header>
2055
- <p class="absolute-voice-routing-status__description">${escapeHtml6(model.description)}</p>
2347
+ <p class="absolute-voice-routing-status__description">${escapeHtml7(model.description)}</p>
2056
2348
  ${rows}
2057
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml6(model.error)}</p>` : ""}
2349
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml7(model.error)}</p>` : ""}
2058
2350
  </section>`;
2059
2351
  };
2060
2352
  var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
@@ -2185,9 +2477,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
2185
2477
  };
2186
2478
 
2187
2479
  // src/client/traceTimelineWidget.ts
2188
- var DEFAULT_TITLE6 = "Voice Traces";
2189
- var DEFAULT_DESCRIPTION6 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2190
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2480
+ var DEFAULT_TITLE7 = "Voice Traces";
2481
+ var DEFAULT_DESCRIPTION7 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2482
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2191
2483
  var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
2192
2484
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
2193
2485
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -2201,34 +2493,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
2201
2493
  const failed = sessions.filter((session) => session.status === "failed").length;
2202
2494
  const warnings = sessions.filter((session) => session.status === "warning").length;
2203
2495
  return {
2204
- description: options.description ?? DEFAULT_DESCRIPTION6,
2496
+ description: options.description ?? DEFAULT_DESCRIPTION7,
2205
2497
  error: snapshot.error,
2206
2498
  isLoading: snapshot.isLoading,
2207
2499
  label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
2208
2500
  sessions,
2209
2501
  status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
2210
- title: options.title ?? DEFAULT_TITLE6,
2502
+ title: options.title ?? DEFAULT_TITLE7,
2211
2503
  updatedAt: snapshot.updatedAt
2212
2504
  };
2213
2505
  };
2214
2506
  var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
2215
2507
  const model = createVoiceTraceTimelineViewModel(snapshot, options);
2216
- const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml7(session.status)}">
2508
+ const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml8(session.status)}">
2217
2509
  <header>
2218
- <strong>${escapeHtml7(session.sessionId)}</strong>
2219
- <span>${escapeHtml7(session.status)}</span>
2510
+ <strong>${escapeHtml8(session.sessionId)}</strong>
2511
+ <span>${escapeHtml8(session.status)}</span>
2220
2512
  </header>
2221
- <p>${escapeHtml7(session.label)} \xB7 ${escapeHtml7(session.durationLabel)} \xB7 ${escapeHtml7(session.providerLabel)}</p>
2222
- <a href="${escapeHtml7(session.detailHref)}">Open timeline</a>
2513
+ <p>${escapeHtml8(session.label)} \xB7 ${escapeHtml8(session.durationLabel)} \xB7 ${escapeHtml8(session.providerLabel)}</p>
2514
+ <a href="${escapeHtml8(session.detailHref)}">Open timeline</a>
2223
2515
  </article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
2224
- return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml7(model.status)}">
2516
+ return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml8(model.status)}">
2225
2517
  <header class="absolute-voice-trace-timeline__header">
2226
- <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml7(model.title)}</span>
2227
- <strong class="absolute-voice-trace-timeline__label">${escapeHtml7(model.label)}</strong>
2518
+ <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml8(model.title)}</span>
2519
+ <strong class="absolute-voice-trace-timeline__label">${escapeHtml8(model.label)}</strong>
2228
2520
  </header>
2229
- <p class="absolute-voice-trace-timeline__description">${escapeHtml7(model.description)}</p>
2521
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml8(model.description)}</p>
2230
2522
  ${sessions}
2231
- ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml7(model.error)}</p>` : ""}
2523
+ ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml8(model.error)}</p>` : ""}
2232
2524
  </section>`;
2233
2525
  };
2234
2526
  var getVoiceTraceTimelineCSS = () => `.absolute-voice-trace-timeline{border:1px solid #bad7d3;border-radius:20px;background:#f3fffb;color:#09201c;padding:18px;box-shadow:0 18px 40px rgba(9,32,28,.12);font-family:inherit}.absolute-voice-trace-timeline--error,.absolute-voice-trace-timeline--failed{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-trace-timeline--warning{border-color:#fbbf24;background:#fffaf0}.absolute-voice-trace-timeline__header,.absolute-voice-trace-timeline__session header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-trace-timeline__eyebrow{color:#17665b;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-trace-timeline__label{font-size:24px;line-height:1}.absolute-voice-trace-timeline__description,.absolute-voice-trace-timeline__session p,.absolute-voice-trace-timeline__empty{color:#35544f}.absolute-voice-trace-timeline__sessions{display:grid;gap:12px;margin-top:14px}.absolute-voice-trace-timeline__session{background:#fff;border:1px solid #cfe7e2;border-radius:16px;padding:14px}.absolute-voice-trace-timeline__session--failed{border-color:#f2a7a7}.absolute-voice-trace-timeline__session--warning{border-color:#fbbf24}.absolute-voice-trace-timeline__session p{margin:10px 0}.absolute-voice-trace-timeline__session a{color:#0f766e;font-weight:800}.absolute-voice-trace-timeline__empty{margin:14px 0 0}.absolute-voice-trace-timeline__error{color:#9f1239;font-weight:700}`;
@@ -2385,10 +2677,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2385
2677
  };
2386
2678
 
2387
2679
  // src/client/turnLatencyWidget.ts
2388
- var DEFAULT_TITLE7 = "Turn Latency";
2389
- var DEFAULT_DESCRIPTION7 = "Per-turn timing from first transcript to commit and assistant response start.";
2680
+ var DEFAULT_TITLE8 = "Turn Latency";
2681
+ var DEFAULT_DESCRIPTION8 = "Per-turn timing from first transcript to commit and assistant response start.";
2390
2682
  var DEFAULT_PROOF_LABEL = "Run latency proof";
2391
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2683
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2392
2684
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
2393
2685
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2394
2686
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -2402,39 +2694,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2402
2694
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2403
2695
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2404
2696
  return {
2405
- description: options.description ?? DEFAULT_DESCRIPTION7,
2697
+ description: options.description ?? DEFAULT_DESCRIPTION8,
2406
2698
  error: snapshot.error,
2407
2699
  isLoading: snapshot.isLoading,
2408
2700
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
2409
2701
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
2410
2702
  showProofAction: Boolean(options.proofPath),
2411
2703
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2412
- title: options.title ?? DEFAULT_TITLE7,
2704
+ title: options.title ?? DEFAULT_TITLE8,
2413
2705
  turns,
2414
2706
  updatedAt: snapshot.updatedAt
2415
2707
  };
2416
2708
  };
2417
2709
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
2418
2710
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
2419
- const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml8(turn.status)}">
2711
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml9(turn.status)}">
2420
2712
  <header>
2421
- <strong>${escapeHtml8(turn.label)}</strong>
2422
- <span>${escapeHtml8(turn.status)}</span>
2713
+ <strong>${escapeHtml9(turn.label)}</strong>
2714
+ <span>${escapeHtml9(turn.status)}</span>
2423
2715
  </header>
2424
2716
  <dl>${turn.rows.map((row) => `<div>
2425
- <dt>${escapeHtml8(row.label)}</dt>
2426
- <dd>${escapeHtml8(row.value)}</dd>
2717
+ <dt>${escapeHtml9(row.label)}</dt>
2718
+ <dd>${escapeHtml9(row.value)}</dd>
2427
2719
  </div>`).join("")}</dl>
2428
2720
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
2429
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml8(model.status)}">
2721
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml9(model.status)}">
2430
2722
  <header class="absolute-voice-turn-latency__header">
2431
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
2432
- <strong class="absolute-voice-turn-latency__label">${escapeHtml8(model.label)}</strong>
2723
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml9(model.title)}</span>
2724
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml9(model.label)}</strong>
2433
2725
  </header>
2434
- <p class="absolute-voice-turn-latency__description">${escapeHtml8(model.description)}</p>
2435
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml8(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2726
+ <p class="absolute-voice-turn-latency__description">${escapeHtml9(model.description)}</p>
2727
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml9(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2436
2728
  ${turns}
2437
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml8(model.error)}</p>` : ""}
2729
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml9(model.error)}</p>` : ""}
2438
2730
  </section>`;
2439
2731
  };
2440
2732
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -2573,9 +2865,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
2573
2865
  };
2574
2866
 
2575
2867
  // src/client/turnQualityWidget.ts
2576
- var DEFAULT_TITLE8 = "Turn Quality";
2577
- var DEFAULT_DESCRIPTION8 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2578
- var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2868
+ var DEFAULT_TITLE9 = "Turn Quality";
2869
+ var DEFAULT_DESCRIPTION9 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2870
+ var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2579
2871
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2580
2872
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2581
2873
  var getTurnDetail = (turn) => {
@@ -2613,37 +2905,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2613
2905
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2614
2906
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2615
2907
  return {
2616
- description: options.description ?? DEFAULT_DESCRIPTION8,
2908
+ description: options.description ?? DEFAULT_DESCRIPTION9,
2617
2909
  error: snapshot.error,
2618
2910
  isLoading: snapshot.isLoading,
2619
2911
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2620
2912
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2621
- title: options.title ?? DEFAULT_TITLE8,
2913
+ title: options.title ?? DEFAULT_TITLE9,
2622
2914
  turns,
2623
2915
  updatedAt: snapshot.updatedAt
2624
2916
  };
2625
2917
  };
2626
2918
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2627
2919
  const model = createVoiceTurnQualityViewModel(snapshot, options);
2628
- const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml9(turn.status)}">
2920
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml10(turn.status)}">
2629
2921
  <header>
2630
- <strong>${escapeHtml9(turn.label)}</strong>
2631
- <span>${escapeHtml9(turn.status)}</span>
2922
+ <strong>${escapeHtml10(turn.label)}</strong>
2923
+ <span>${escapeHtml10(turn.status)}</span>
2632
2924
  </header>
2633
- <p>${escapeHtml9(turn.detail)}</p>
2925
+ <p>${escapeHtml10(turn.detail)}</p>
2634
2926
  <dl>${turn.rows.map((row) => `<div>
2635
- <dt>${escapeHtml9(row.label)}</dt>
2636
- <dd>${escapeHtml9(row.value)}</dd>
2927
+ <dt>${escapeHtml10(row.label)}</dt>
2928
+ <dd>${escapeHtml10(row.value)}</dd>
2637
2929
  </div>`).join("")}</dl>
2638
2930
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
2639
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml9(model.status)}">
2931
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml10(model.status)}">
2640
2932
  <header class="absolute-voice-turn-quality__header">
2641
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml9(model.title)}</span>
2642
- <strong class="absolute-voice-turn-quality__label">${escapeHtml9(model.label)}</strong>
2933
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml10(model.title)}</span>
2934
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml10(model.label)}</strong>
2643
2935
  </header>
2644
- <p class="absolute-voice-turn-quality__description">${escapeHtml9(model.description)}</p>
2936
+ <p class="absolute-voice-turn-quality__description">${escapeHtml10(model.description)}</p>
2645
2937
  ${turns}
2646
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml9(model.error)}</p>` : ""}
2938
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml10(model.error)}</p>` : ""}
2647
2939
  </section>`;
2648
2940
  };
2649
2941
  var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;
@@ -3425,6 +3717,7 @@ export {
3425
3717
  createVoiceProviderSimulationControls,
3426
3718
  createVoiceProviderCapabilities,
3427
3719
  createVoiceOpsStatus,
3720
+ createVoiceOpsActionCenter,
3428
3721
  createVoiceDeliveryRuntime,
3429
3722
  createVoiceController,
3430
3723
  createVoiceCampaignDialerProof