@absolutejs/voice 0.0.22-beta.152 → 0.0.22-beta.154

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue/index.js CHANGED
@@ -374,10 +374,355 @@ var VoiceOpsStatus = defineComponent({
374
374
  };
375
375
  }
376
376
  });
377
- // src/vue/VoiceDeliveryRuntime.ts
377
+ // src/vue/VoiceOpsActionCenter.ts
378
378
  import { defineComponent as defineComponent2, h as h2 } from "vue";
379
379
 
380
+ // src/client/opsActionCenter.ts
381
+ var createVoiceOpsActionCenterActions = (options = {}) => {
382
+ const deliveryRuntimePath = options.deliveryRuntimePath ?? "/api/voice-delivery-runtime";
383
+ const actions = [];
384
+ if (options.includeProductionReadiness !== false) {
385
+ actions.push({
386
+ description: "Refresh the production readiness report.",
387
+ id: "production-readiness",
388
+ label: "Refresh readiness",
389
+ method: "GET",
390
+ path: options.productionReadinessPath ?? "/api/production-readiness"
391
+ });
392
+ }
393
+ if (options.includeDeliveryRuntime !== false) {
394
+ actions.push({
395
+ description: "Drain pending and failed audit/trace deliveries.",
396
+ id: "delivery-runtime.tick",
397
+ label: "Tick delivery workers",
398
+ method: "POST",
399
+ path: `${deliveryRuntimePath.replace(/\/$/, "")}/tick`
400
+ }, {
401
+ description: "Move reviewed dead letters back to live delivery queues.",
402
+ id: "delivery-runtime.requeue-dead-letters",
403
+ label: "Requeue dead letters",
404
+ method: "POST",
405
+ path: `${deliveryRuntimePath.replace(/\/$/, "")}/requeue-dead-letters`
406
+ });
407
+ }
408
+ if (options.includeTurnLatencyProof !== false) {
409
+ actions.push({
410
+ description: "Run the synthetic turn latency proof.",
411
+ id: "turn-latency.proof",
412
+ label: "Run latency proof",
413
+ method: "POST",
414
+ path: options.turnLatencyProofPath ?? "/api/turn-latency/proof"
415
+ });
416
+ }
417
+ if (options.includeProviderSimulation !== false) {
418
+ const pathPrefix = options.providerSimulationPathPrefix ?? "/api/stt-simulate";
419
+ for (const provider of options.providers ?? []) {
420
+ actions.push({
421
+ description: `Simulate ${provider} provider failure.`,
422
+ id: `provider.${provider}.failure`,
423
+ label: `Simulate ${provider} failure`,
424
+ method: "POST",
425
+ path: `${pathPrefix}/failure?provider=${encodeURIComponent(provider)}`
426
+ }, {
427
+ description: `Mark ${provider} provider recovered.`,
428
+ id: `provider.${provider}.recovery`,
429
+ label: `Recover ${provider}`,
430
+ method: "POST",
431
+ path: `${pathPrefix}/recovery?provider=${encodeURIComponent(provider)}`
432
+ });
433
+ }
434
+ }
435
+ return actions;
436
+ };
437
+ var runVoiceOpsAction = async (action, options = {}) => {
438
+ const fetchImpl = options.fetch ?? globalThis.fetch;
439
+ const response = await fetchImpl(action.path, {
440
+ method: action.method ?? "POST"
441
+ });
442
+ const body = await response.json().catch(() => null);
443
+ if (!response.ok) {
444
+ const message = body && typeof body === "object" && "error" in body ? String(body.error) : `Voice ops action "${action.id}" failed: HTTP ${response.status}`;
445
+ throw new Error(message);
446
+ }
447
+ return {
448
+ actionId: action.id,
449
+ body,
450
+ ok: response.ok,
451
+ ranAt: Date.now(),
452
+ status: response.status
453
+ };
454
+ };
455
+ var createVoiceOpsActionCenterStore = (options = {}) => {
456
+ const listeners = new Set;
457
+ let closed = false;
458
+ let timer;
459
+ let snapshot = {
460
+ actions: options.actions ?? createVoiceOpsActionCenterActions(),
461
+ error: null,
462
+ isRunning: false
463
+ };
464
+ const emit = () => {
465
+ for (const listener of listeners) {
466
+ listener();
467
+ }
468
+ };
469
+ const setActions = (actions) => {
470
+ snapshot = { ...snapshot, actions, updatedAt: Date.now() };
471
+ emit();
472
+ };
473
+ const run = async (actionId) => {
474
+ if (closed) {
475
+ return snapshot.lastResult;
476
+ }
477
+ const action = snapshot.actions.find((item) => item.id === actionId);
478
+ if (!action) {
479
+ throw new Error(`Voice ops action "${actionId}" is not configured.`);
480
+ }
481
+ if (action.disabled) {
482
+ throw new Error(`Voice ops action "${actionId}" is disabled.`);
483
+ }
484
+ snapshot = {
485
+ ...snapshot,
486
+ error: null,
487
+ isRunning: true,
488
+ runningActionId: action.id
489
+ };
490
+ emit();
491
+ try {
492
+ const result = await runVoiceOpsAction(action, options);
493
+ snapshot = {
494
+ ...snapshot,
495
+ error: null,
496
+ isRunning: false,
497
+ lastResult: result,
498
+ runningActionId: undefined,
499
+ updatedAt: Date.now()
500
+ };
501
+ emit();
502
+ return result;
503
+ } catch (error) {
504
+ snapshot = {
505
+ ...snapshot,
506
+ error: error instanceof Error ? error.message : String(error),
507
+ isRunning: false,
508
+ runningActionId: undefined
509
+ };
510
+ emit();
511
+ throw error;
512
+ }
513
+ };
514
+ const close = () => {
515
+ closed = true;
516
+ if (timer) {
517
+ clearInterval(timer);
518
+ timer = undefined;
519
+ }
520
+ listeners.clear();
521
+ };
522
+ if (options.intervalMs && options.intervalMs > 0) {
523
+ timer = setInterval(() => {
524
+ emit();
525
+ }, options.intervalMs);
526
+ }
527
+ return {
528
+ close,
529
+ getServerSnapshot: () => snapshot,
530
+ getSnapshot: () => snapshot,
531
+ run,
532
+ setActions,
533
+ subscribe: (listener) => {
534
+ listeners.add(listener);
535
+ return () => {
536
+ listeners.delete(listener);
537
+ };
538
+ }
539
+ };
540
+ };
541
+
542
+ // src/client/opsActionCenterWidget.ts
543
+ var DEFAULT_TITLE2 = "Voice Ops Action Center";
544
+ var DEFAULT_DESCRIPTION2 = "Run production voice proofs and operator actions from one primitive panel.";
545
+ var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
546
+ var createVoiceOpsActionCenterViewModel = (snapshot, options = {}) => {
547
+ const status = snapshot.error ? "error" : snapshot.isRunning ? "running" : snapshot.lastResult ? "completed" : "ready";
548
+ return {
549
+ actions: snapshot.actions.map((action) => ({
550
+ description: action.description ?? "",
551
+ disabled: Boolean(action.disabled || snapshot.isRunning),
552
+ id: action.id,
553
+ isRunning: snapshot.runningActionId === action.id,
554
+ label: action.label
555
+ })),
556
+ description: options.description ?? DEFAULT_DESCRIPTION2,
557
+ error: snapshot.error,
558
+ isRunning: snapshot.isRunning,
559
+ label: status === "error" ? "Needs attention" : status === "running" ? "Running" : status === "completed" ? "Action completed" : "Ready",
560
+ lastResultLabel: snapshot.lastResult ? `${snapshot.lastResult.actionId} returned HTTP ${snapshot.lastResult.status}` : "No action has run yet.",
561
+ status,
562
+ title: options.title ?? DEFAULT_TITLE2
563
+ };
564
+ };
565
+ var renderVoiceOpsActionCenterHTML = (snapshot, options = {}) => {
566
+ const model = createVoiceOpsActionCenterViewModel(snapshot, options);
567
+ const actions = model.actions.map((action) => `<button type="button" data-absolute-voice-ops-action="${escapeHtml2(action.id)}"${action.disabled ? " disabled" : ""}>
568
+ ${escapeHtml2(action.isRunning ? "Working..." : action.label)}
569
+ </button>`).join("");
570
+ return `<section class="absolute-voice-ops-action-center absolute-voice-ops-action-center--${escapeHtml2(model.status)}">
571
+ <header class="absolute-voice-ops-action-center__header">
572
+ <span class="absolute-voice-ops-action-center__eyebrow">${escapeHtml2(model.title)}</span>
573
+ <strong class="absolute-voice-ops-action-center__label">${escapeHtml2(model.label)}</strong>
574
+ </header>
575
+ <p class="absolute-voice-ops-action-center__description">${escapeHtml2(model.description)}</p>
576
+ <div class="absolute-voice-ops-action-center__actions">${actions}</div>
577
+ <p class="absolute-voice-ops-action-center__result">${escapeHtml2(model.lastResultLabel)}</p>
578
+ ${model.error ? `<p class="absolute-voice-ops-action-center__error">${escapeHtml2(model.error)}</p>` : ""}
579
+ </section>`;
580
+ };
581
+ 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}`;
582
+ var mountVoiceOpsActionCenter = (element, options = {}) => {
583
+ const store = createVoiceOpsActionCenterStore(options);
584
+ const render = () => {
585
+ element.innerHTML = renderVoiceOpsActionCenterHTML(store.getSnapshot(), options);
586
+ };
587
+ const unsubscribe = store.subscribe(render);
588
+ const handleClick = (event) => {
589
+ const target = event.target;
590
+ if (!(target instanceof Element)) {
591
+ return;
592
+ }
593
+ const action = target.closest("[data-absolute-voice-ops-action]");
594
+ const actionId = action?.getAttribute("data-absolute-voice-ops-action");
595
+ if (actionId) {
596
+ store.run(actionId).catch(() => {});
597
+ }
598
+ };
599
+ element.addEventListener?.("click", handleClick);
600
+ render();
601
+ return {
602
+ close: () => {
603
+ element.removeEventListener?.("click", handleClick);
604
+ unsubscribe();
605
+ store.close();
606
+ },
607
+ run: store.run
608
+ };
609
+ };
610
+ var defineVoiceOpsActionCenterElement = (tagName = "absolute-voice-ops-action-center", options = {}) => {
611
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
612
+ return;
613
+ }
614
+ customElements.define(tagName, class AbsoluteVoiceOpsActionCenterElement extends HTMLElement {
615
+ mounted;
616
+ connectedCallback() {
617
+ this.mounted = mountVoiceOpsActionCenter(this, {
618
+ ...options,
619
+ description: this.getAttribute("description") ?? options.description,
620
+ title: this.getAttribute("title") ?? options.title
621
+ });
622
+ }
623
+ disconnectedCallback() {
624
+ this.mounted?.close();
625
+ this.mounted = undefined;
626
+ }
627
+ });
628
+ };
629
+
630
+ // src/vue/useVoiceOpsActionCenter.ts
631
+ import { onUnmounted as onUnmounted2, ref as ref2, shallowRef as shallowRef2 } from "vue";
632
+ function useVoiceOpsActionCenter(options = {}) {
633
+ const store = createVoiceOpsActionCenterStore(options);
634
+ const actions = shallowRef2([]);
635
+ const error = ref2(null);
636
+ const isRunning = ref2(false);
637
+ const lastResult = shallowRef2(undefined);
638
+ const runningActionId = ref2(undefined);
639
+ const updatedAt = ref2(undefined);
640
+ const sync = () => {
641
+ const snapshot = store.getSnapshot();
642
+ actions.value = snapshot.actions;
643
+ error.value = snapshot.error;
644
+ isRunning.value = snapshot.isRunning;
645
+ lastResult.value = snapshot.lastResult;
646
+ runningActionId.value = snapshot.runningActionId;
647
+ updatedAt.value = snapshot.updatedAt;
648
+ };
649
+ const unsubscribe = store.subscribe(sync);
650
+ sync();
651
+ onUnmounted2(() => {
652
+ unsubscribe();
653
+ store.close();
654
+ });
655
+ return {
656
+ actions,
657
+ error,
658
+ isRunning,
659
+ lastResult,
660
+ run: store.run,
661
+ runningActionId,
662
+ setActions: store.setActions,
663
+ updatedAt
664
+ };
665
+ }
666
+
667
+ // src/vue/VoiceOpsActionCenter.ts
668
+ var VoiceOpsActionCenter = defineComponent2({
669
+ name: "VoiceOpsActionCenter",
670
+ props: {
671
+ actions: Array,
672
+ description: String,
673
+ title: String
674
+ },
675
+ setup(props) {
676
+ const options = {
677
+ actions: props.actions,
678
+ description: props.description,
679
+ title: props.title
680
+ };
681
+ const center = useVoiceOpsActionCenter(options);
682
+ return () => {
683
+ const model = createVoiceOpsActionCenterViewModel({
684
+ actions: center.actions.value,
685
+ error: center.error.value,
686
+ isRunning: center.isRunning.value,
687
+ lastResult: center.lastResult.value,
688
+ runningActionId: center.runningActionId.value,
689
+ updatedAt: center.updatedAt.value
690
+ }, options);
691
+ return h2("section", {
692
+ class: [
693
+ "absolute-voice-ops-action-center",
694
+ `absolute-voice-ops-action-center--${model.status}`
695
+ ]
696
+ }, [
697
+ h2("header", { class: "absolute-voice-ops-action-center__header" }, [
698
+ h2("span", { class: "absolute-voice-ops-action-center__eyebrow" }, model.title),
699
+ h2("strong", { class: "absolute-voice-ops-action-center__label" }, model.label)
700
+ ]),
701
+ h2("p", { class: "absolute-voice-ops-action-center__description" }, model.description),
702
+ h2("div", { class: "absolute-voice-ops-action-center__actions" }, model.actions.map((action) => h2("button", {
703
+ disabled: action.disabled,
704
+ key: action.id,
705
+ onClick: () => {
706
+ center.run(action.id).catch(() => {});
707
+ },
708
+ type: "button"
709
+ }, action.isRunning ? "Working..." : action.label))),
710
+ h2("p", { class: "absolute-voice-ops-action-center__result" }, model.lastResultLabel),
711
+ model.error ? h2("p", { class: "absolute-voice-ops-action-center__error" }, model.error) : null
712
+ ]);
713
+ };
714
+ }
715
+ });
716
+ // src/vue/VoiceDeliveryRuntime.ts
717
+ import { defineComponent as defineComponent3, h as h3 } from "vue";
718
+
380
719
  // src/client/deliveryRuntime.ts
720
+ var getDefaultActionPath = (path, action, options) => {
721
+ if (action === "tick") {
722
+ return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
723
+ }
724
+ return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
725
+ };
381
726
  var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
382
727
  const fetchImpl = options.fetch ?? globalThis.fetch;
383
728
  const response = await fetchImpl(path);
@@ -386,11 +731,29 @@ var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", opt
386
731
  }
387
732
  return await response.json();
388
733
  };
734
+ var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
735
+ const fetchImpl = options.fetch ?? globalThis.fetch;
736
+ const response = await fetchImpl(getDefaultActionPath(path, action, options), {
737
+ method: "POST"
738
+ });
739
+ if (!response.ok) {
740
+ throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
741
+ }
742
+ const body = await response.json();
743
+ return {
744
+ action,
745
+ result: body.result,
746
+ summary: body.summary,
747
+ updatedAt: Date.now()
748
+ };
749
+ };
389
750
  var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
390
751
  const listeners = new Set;
391
752
  let closed = false;
392
753
  let timer;
393
754
  let snapshot = {
755
+ actionError: null,
756
+ actionStatus: "idle",
394
757
  error: null,
395
758
  isLoading: false
396
759
  };
@@ -412,6 +775,7 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
412
775
  try {
413
776
  const report = await fetchVoiceDeliveryRuntime(path, options);
414
777
  snapshot = {
778
+ ...snapshot,
415
779
  error: null,
416
780
  isLoading: false,
417
781
  report,
@@ -429,6 +793,37 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
429
793
  throw error;
430
794
  }
431
795
  };
796
+ const runAction = async (action) => {
797
+ if (closed) {
798
+ return snapshot.lastAction;
799
+ }
800
+ snapshot = {
801
+ ...snapshot,
802
+ actionError: null,
803
+ actionStatus: "running"
804
+ };
805
+ emit();
806
+ try {
807
+ const result = await runVoiceDeliveryRuntimeAction(action, path, options);
808
+ snapshot = {
809
+ ...snapshot,
810
+ actionError: null,
811
+ actionStatus: "completed",
812
+ lastAction: result
813
+ };
814
+ emit();
815
+ await refresh();
816
+ return result;
817
+ } catch (error) {
818
+ snapshot = {
819
+ ...snapshot,
820
+ actionError: error instanceof Error ? error.message : String(error),
821
+ actionStatus: "failed"
822
+ };
823
+ emit();
824
+ throw error;
825
+ }
826
+ };
432
827
  const close = () => {
433
828
  closed = true;
434
829
  if (timer) {
@@ -446,7 +841,9 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
446
841
  close,
447
842
  getServerSnapshot: () => snapshot,
448
843
  getSnapshot: () => snapshot,
844
+ requeueDeadLetters: () => runAction("requeue-dead-letters"),
449
845
  refresh,
846
+ tick: () => runAction("tick"),
450
847
  subscribe: (listener) => {
451
848
  listeners.add(listener);
452
849
  return () => {
@@ -457,9 +854,9 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
457
854
  };
458
855
 
459
856
  // src/client/deliveryRuntimeWidget.ts
460
- var DEFAULT_TITLE2 = "Voice Delivery Runtime";
461
- var DEFAULT_DESCRIPTION2 = "Audit and trace delivery worker health from your AbsoluteJS voice app.";
462
- var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
857
+ var DEFAULT_TITLE3 = "Voice Delivery Runtime";
858
+ var DEFAULT_DESCRIPTION3 = "Audit and trace delivery worker health from your AbsoluteJS voice app.";
859
+ var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
463
860
  var createSurface = (id, summary) => {
464
861
  if (!summary) {
465
862
  return {
@@ -493,45 +890,70 @@ var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
493
890
  ];
494
891
  const hasWarnings = surfaces.some((surface) => surface.status === "warn");
495
892
  return {
496
- description: options.description ?? DEFAULT_DESCRIPTION2,
893
+ description: options.description ?? DEFAULT_DESCRIPTION3,
497
894
  error: snapshot.error,
895
+ actionError: snapshot.actionError,
896
+ actionStatus: snapshot.actionStatus,
498
897
  isLoading: snapshot.isLoading,
499
898
  isRunning: Boolean(report?.isRunning),
500
899
  label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
501
900
  status: snapshot.error ? "error" : report ? hasWarnings ? "warn" : "pass" : "loading",
502
901
  surfaces,
503
- title: options.title ?? DEFAULT_TITLE2,
902
+ title: options.title ?? DEFAULT_TITLE3,
504
903
  updatedAt: snapshot.updatedAt
505
904
  };
506
905
  };
507
906
  var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
508
907
  const model = createVoiceDeliveryRuntimeViewModel(snapshot, options);
509
- const surfaces = model.surfaces.map((surface) => `<li class="absolute-voice-delivery-runtime__surface absolute-voice-delivery-runtime__surface--${escapeHtml2(surface.status)}">
510
- <span>${escapeHtml2(surface.label)}</span>
511
- <strong>${escapeHtml2(surface.detail)}</strong>
908
+ const surfaces = model.surfaces.map((surface) => `<li class="absolute-voice-delivery-runtime__surface absolute-voice-delivery-runtime__surface--${escapeHtml3(surface.status)}">
909
+ <span>${escapeHtml3(surface.label)}</span>
910
+ <strong>${escapeHtml3(surface.detail)}</strong>
512
911
  <small>${String(surface.failed)} failed &middot; ${String(surface.deadLettered)} dead-lettered</small>
513
912
  </li>`).join("");
514
- return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml2(model.status)}">
913
+ const actions = options.includeActions === false ? "" : `<div class="absolute-voice-delivery-runtime__actions">
914
+ <button type="button" data-absolute-voice-delivery-runtime-action="tick">${model.actionStatus === "running" ? "Working..." : "Tick workers"}</button>
915
+ <button type="button" data-absolute-voice-delivery-runtime-action="requeue-dead-letters"${model.surfaces.some((surface) => surface.deadLettered > 0) ? "" : " disabled"}>Requeue dead letters</button>
916
+ </div>`;
917
+ const actionError = model.actionError ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml3(model.actionError)}</p>` : "";
918
+ return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml3(model.status)}">
515
919
  <header class="absolute-voice-delivery-runtime__header">
516
- <span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml2(model.title)}</span>
517
- <strong class="absolute-voice-delivery-runtime__label">${escapeHtml2(model.label)}</strong>
920
+ <span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml3(model.title)}</span>
921
+ <strong class="absolute-voice-delivery-runtime__label">${escapeHtml3(model.label)}</strong>
518
922
  </header>
519
- <p class="absolute-voice-delivery-runtime__description">${escapeHtml2(model.description)}</p>
923
+ <p class="absolute-voice-delivery-runtime__description">${escapeHtml3(model.description)}</p>
520
924
  <ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
521
- ${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml2(model.error)}</p>` : ""}
925
+ ${actions}
926
+ ${actionError}
927
+ ${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml3(model.error)}</p>` : ""}
522
928
  </section>`;
523
929
  };
524
- var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
930
+ var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-delivery-runtime__actions button{background:#134e2d;border:0;border-radius:999px;color:#f6fff9;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-delivery-runtime__actions button:disabled{cursor:not-allowed;opacity:.48}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
525
931
  var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
526
932
  const store = createVoiceDeliveryRuntimeStore(path, options);
527
933
  const render = () => {
528
934
  element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
529
935
  };
530
936
  const unsubscribe = store.subscribe(render);
937
+ const handleClick = (event) => {
938
+ const target = event.target;
939
+ if (!(target instanceof Element)) {
940
+ return;
941
+ }
942
+ const action = target.closest("[data-absolute-voice-delivery-runtime-action]");
943
+ const actionName = action?.getAttribute("data-absolute-voice-delivery-runtime-action");
944
+ if (actionName === "tick") {
945
+ store.tick().catch(() => {});
946
+ }
947
+ if (actionName === "requeue-dead-letters") {
948
+ store.requeueDeadLetters().catch(() => {});
949
+ }
950
+ };
951
+ element.addEventListener?.("click", handleClick);
531
952
  render();
532
953
  store.refresh().catch(() => {});
533
954
  return {
534
955
  close: () => {
956
+ element.removeEventListener?.("click", handleClick);
535
957
  unsubscribe();
536
958
  store.close();
537
959
  },
@@ -560,15 +982,19 @@ var defineVoiceDeliveryRuntimeElement = (tagName = "absolute-voice-delivery-runt
560
982
  };
561
983
 
562
984
  // src/vue/useVoiceDeliveryRuntime.ts
563
- import { onUnmounted as onUnmounted2, ref as ref2, shallowRef as shallowRef2 } from "vue";
985
+ import { onUnmounted as onUnmounted3, ref as ref3, shallowRef as shallowRef3 } from "vue";
564
986
  function useVoiceDeliveryRuntime(path = "/api/voice-delivery-runtime", options = {}) {
565
987
  const store = createVoiceDeliveryRuntimeStore(path, options);
566
- const error = ref2(null);
567
- const isLoading = ref2(false);
568
- const report = shallowRef2(undefined);
569
- const updatedAt = ref2(undefined);
988
+ const actionError = ref3(null);
989
+ const actionStatus = ref3("idle");
990
+ const error = ref3(null);
991
+ const isLoading = ref3(false);
992
+ const report = shallowRef3(undefined);
993
+ const updatedAt = ref3(undefined);
570
994
  const sync = () => {
571
995
  const snapshot = store.getSnapshot();
996
+ actionError.value = snapshot.actionError;
997
+ actionStatus.value = snapshot.actionStatus;
572
998
  error.value = snapshot.error;
573
999
  isLoading.value = snapshot.isLoading;
574
1000
  report.value = snapshot.report;
@@ -579,24 +1005,32 @@ function useVoiceDeliveryRuntime(path = "/api/voice-delivery-runtime", options =
579
1005
  if (typeof window !== "undefined") {
580
1006
  store.refresh().catch(() => {});
581
1007
  }
582
- onUnmounted2(() => {
1008
+ onUnmounted3(() => {
583
1009
  unsubscribe();
584
1010
  store.close();
585
1011
  });
586
1012
  return {
1013
+ actionError,
1014
+ actionStatus,
587
1015
  error,
588
1016
  isLoading,
1017
+ requeueDeadLetters: store.requeueDeadLetters,
589
1018
  refresh: store.refresh,
590
1019
  report,
1020
+ tick: store.tick,
591
1021
  updatedAt
592
1022
  };
593
1023
  }
594
1024
 
595
1025
  // src/vue/VoiceDeliveryRuntime.ts
596
- var VoiceDeliveryRuntime = defineComponent2({
1026
+ var VoiceDeliveryRuntime = defineComponent3({
597
1027
  name: "VoiceDeliveryRuntime",
598
1028
  props: {
599
1029
  description: String,
1030
+ includeActions: {
1031
+ default: true,
1032
+ type: Boolean
1033
+ },
600
1034
  intervalMs: Number,
601
1035
  path: {
602
1036
  default: "/api/voice-delivery-runtime",
@@ -614,39 +1048,59 @@ var VoiceDeliveryRuntime = defineComponent2({
614
1048
  return () => {
615
1049
  const model = createVoiceDeliveryRuntimeViewModel({
616
1050
  error: runtime.error.value,
1051
+ actionError: runtime.actionError.value,
1052
+ actionStatus: runtime.actionStatus.value,
617
1053
  isLoading: runtime.isLoading.value,
618
1054
  report: runtime.report.value,
619
1055
  updatedAt: runtime.updatedAt.value
620
1056
  }, options);
621
- return h2("section", {
1057
+ const hasDeadLetters = model.surfaces.some((surface) => surface.deadLettered > 0);
1058
+ return h3("section", {
622
1059
  class: [
623
1060
  "absolute-voice-delivery-runtime",
624
1061
  `absolute-voice-delivery-runtime--${model.status}`
625
1062
  ]
626
1063
  }, [
627
- h2("header", { class: "absolute-voice-delivery-runtime__header" }, [
628
- h2("span", { class: "absolute-voice-delivery-runtime__eyebrow" }, model.title),
629
- h2("strong", { class: "absolute-voice-delivery-runtime__label" }, model.label)
1064
+ h3("header", { class: "absolute-voice-delivery-runtime__header" }, [
1065
+ h3("span", { class: "absolute-voice-delivery-runtime__eyebrow" }, model.title),
1066
+ h3("strong", { class: "absolute-voice-delivery-runtime__label" }, model.label)
630
1067
  ]),
631
- h2("p", { class: "absolute-voice-delivery-runtime__description" }, model.description),
632
- h2("ul", { class: "absolute-voice-delivery-runtime__surfaces" }, model.surfaces.map((surface) => h2("li", {
1068
+ h3("p", { class: "absolute-voice-delivery-runtime__description" }, model.description),
1069
+ h3("ul", { class: "absolute-voice-delivery-runtime__surfaces" }, model.surfaces.map((surface) => h3("li", {
633
1070
  class: [
634
1071
  "absolute-voice-delivery-runtime__surface",
635
1072
  `absolute-voice-delivery-runtime__surface--${surface.status}`
636
1073
  ],
637
1074
  key: surface.id
638
1075
  }, [
639
- h2("span", surface.label),
640
- h2("strong", surface.detail),
641
- h2("small", `${surface.failed} failed / ${surface.deadLettered} dead-lettered`)
1076
+ h3("span", surface.label),
1077
+ h3("strong", surface.detail),
1078
+ h3("small", `${surface.failed} failed / ${surface.deadLettered} dead-lettered`)
642
1079
  ]))),
643
- model.error ? h2("p", { class: "absolute-voice-delivery-runtime__error" }, model.error) : null
1080
+ props.includeActions ? h3("div", { class: "absolute-voice-delivery-runtime__actions" }, [
1081
+ h3("button", {
1082
+ disabled: model.actionStatus === "running",
1083
+ onClick: () => {
1084
+ runtime.tick().catch(() => {});
1085
+ },
1086
+ type: "button"
1087
+ }, model.actionStatus === "running" ? "Working..." : "Tick workers"),
1088
+ h3("button", {
1089
+ disabled: model.actionStatus === "running" || !hasDeadLetters,
1090
+ onClick: () => {
1091
+ runtime.requeueDeadLetters().catch(() => {});
1092
+ },
1093
+ type: "button"
1094
+ }, "Requeue dead letters")
1095
+ ]) : null,
1096
+ model.actionError ? h3("p", { class: "absolute-voice-delivery-runtime__error" }, model.actionError) : null,
1097
+ model.error ? h3("p", { class: "absolute-voice-delivery-runtime__error" }, model.error) : null
644
1098
  ]);
645
1099
  };
646
1100
  }
647
1101
  });
648
1102
  // src/vue/VoiceProviderSimulationControls.ts
649
- import { computed, defineComponent as defineComponent3, h as h3 } from "vue";
1103
+ import { computed, defineComponent as defineComponent4, h as h4 } from "vue";
650
1104
 
651
1105
  // src/client/providerSimulationControls.ts
652
1106
  var postSimulation = async (pathPrefix, mode, provider, fetchImpl) => {
@@ -728,7 +1182,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
728
1182
  };
729
1183
 
730
1184
  // src/client/providerSimulationControlsWidget.ts
731
- var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1185
+ var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
732
1186
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
733
1187
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
734
1188
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -748,18 +1202,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
748
1202
  };
749
1203
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
750
1204
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
751
- 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("");
752
- 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("");
1205
+ 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("");
1206
+ 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("");
753
1207
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
754
1208
  <header class="absolute-voice-provider-simulation__header">
755
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
756
- <strong class="absolute-voice-provider-simulation__label">${escapeHtml3(model.label)}</strong>
1209
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml4(model.title)}</span>
1210
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml4(model.label)}</strong>
757
1211
  </header>
758
- <p class="absolute-voice-provider-simulation__description">${escapeHtml3(model.description)}</p>
759
- ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml3(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
1212
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml4(model.description)}</p>
1213
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml4(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
760
1214
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
761
- ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml3(snapshot.error)}</p>` : ""}
762
- ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml3(model.resultText)}</pre>` : ""}
1215
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml4(snapshot.error)}</p>` : ""}
1216
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml4(model.resultText)}</pre>` : ""}
763
1217
  </section>`;
764
1218
  };
765
1219
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -825,15 +1279,15 @@ var defineVoiceProviderSimulationControlsElement = (tagName = "absolute-voice-pr
825
1279
  };
826
1280
 
827
1281
  // src/vue/useVoiceProviderSimulationControls.ts
828
- import { onUnmounted as onUnmounted3, ref as ref3 } from "vue";
1282
+ import { onUnmounted as onUnmounted4, ref as ref4 } from "vue";
829
1283
  function useVoiceProviderSimulationControls(options) {
830
1284
  const store = createVoiceProviderSimulationControlsStore(options);
831
- const error = ref3(null);
832
- const isRunning = ref3(false);
833
- const lastResult = ref3(null);
834
- const mode = ref3(null);
835
- const provider = ref3(null);
836
- const updatedAt = ref3(undefined);
1285
+ const error = ref4(null);
1286
+ const isRunning = ref4(false);
1287
+ const lastResult = ref4(null);
1288
+ const mode = ref4(null);
1289
+ const provider = ref4(null);
1290
+ const updatedAt = ref4(undefined);
837
1291
  const sync = () => {
838
1292
  const snapshot = store.getSnapshot();
839
1293
  error.value = snapshot.error;
@@ -845,7 +1299,7 @@ function useVoiceProviderSimulationControls(options) {
845
1299
  };
846
1300
  const unsubscribe = store.subscribe(sync);
847
1301
  sync();
848
- onUnmounted3(() => {
1302
+ onUnmounted4(() => {
849
1303
  unsubscribe();
850
1304
  store.close();
851
1305
  });
@@ -861,7 +1315,7 @@ function useVoiceProviderSimulationControls(options) {
861
1315
  }
862
1316
 
863
1317
  // src/vue/VoiceProviderSimulationControls.ts
864
- var VoiceProviderSimulationControls = defineComponent3({
1318
+ var VoiceProviderSimulationControls = defineComponent4({
865
1319
  name: "VoiceProviderSimulationControls",
866
1320
  props: {
867
1321
  class: { default: "", type: String },
@@ -903,40 +1357,40 @@ var VoiceProviderSimulationControls = defineComponent3({
903
1357
  const run = (provider, mode) => {
904
1358
  controls.run(provider, mode).catch(() => {});
905
1359
  };
906
- return () => h3("section", {
1360
+ return () => h4("section", {
907
1361
  class: [
908
1362
  "absolute-voice-provider-simulation",
909
1363
  `absolute-voice-provider-simulation--${controls.error.value ? "error" : controls.isRunning.value ? "running" : "ready"}`,
910
1364
  props.class
911
1365
  ]
912
1366
  }, [
913
- h3("header", { class: "absolute-voice-provider-simulation__header" }, [
914
- h3("span", { class: "absolute-voice-provider-simulation__eyebrow" }, model.value.title),
915
- h3("strong", { class: "absolute-voice-provider-simulation__label" }, model.value.label)
1367
+ h4("header", { class: "absolute-voice-provider-simulation__header" }, [
1368
+ h4("span", { class: "absolute-voice-provider-simulation__eyebrow" }, model.value.title),
1369
+ h4("strong", { class: "absolute-voice-provider-simulation__label" }, model.value.label)
916
1370
  ]),
917
- h3("p", { class: "absolute-voice-provider-simulation__description" }, model.value.description),
918
- model.value.canSimulateFailure ? null : h3("p", { class: "absolute-voice-provider-simulation__empty" }, props.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure."),
919
- h3("div", { class: "absolute-voice-provider-simulation__actions" }, [
920
- ...model.value.failureProviders.map((provider) => h3("button", {
1371
+ h4("p", { class: "absolute-voice-provider-simulation__description" }, model.value.description),
1372
+ model.value.canSimulateFailure ? null : h4("p", { class: "absolute-voice-provider-simulation__empty" }, props.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure."),
1373
+ h4("div", { class: "absolute-voice-provider-simulation__actions" }, [
1374
+ ...model.value.failureProviders.map((provider) => h4("button", {
921
1375
  disabled: !model.value.canSimulateFailure || controls.isRunning.value,
922
1376
  key: `fail-${provider.provider}`,
923
1377
  onClick: () => run(provider.provider, "failure"),
924
1378
  type: "button"
925
1379
  }, `Simulate ${provider.provider} ${props.kind.toUpperCase()} failure`)),
926
- ...model.value.providers.map((provider) => h3("button", {
1380
+ ...model.value.providers.map((provider) => h4("button", {
927
1381
  disabled: controls.isRunning.value,
928
1382
  key: `recover-${provider.provider}`,
929
1383
  onClick: () => run(provider.provider, "recovery"),
930
1384
  type: "button"
931
1385
  }, `Mark ${provider.provider} recovered`))
932
1386
  ]),
933
- controls.error.value ? h3("p", { class: "absolute-voice-provider-simulation__error" }, controls.error.value) : null,
934
- model.value.resultText ? h3("pre", { class: "absolute-voice-provider-simulation__result" }, model.value.resultText) : null
1387
+ controls.error.value ? h4("p", { class: "absolute-voice-provider-simulation__error" }, controls.error.value) : null,
1388
+ model.value.resultText ? h4("pre", { class: "absolute-voice-provider-simulation__result" }, model.value.resultText) : null
935
1389
  ]);
936
1390
  }
937
1391
  });
938
1392
  // src/vue/VoiceProviderCapabilities.ts
939
- import { computed as computed2, defineComponent as defineComponent4, h as h4 } from "vue";
1393
+ import { computed as computed2, defineComponent as defineComponent5, h as h5 } from "vue";
940
1394
 
941
1395
  // src/client/providerCapabilities.ts
942
1396
  var fetchVoiceProviderCapabilities = async (path = "/api/provider-capabilities", options = {}) => {
@@ -1018,9 +1472,9 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
1018
1472
  };
1019
1473
 
1020
1474
  // src/client/providerCapabilitiesWidget.ts
1021
- var DEFAULT_TITLE3 = "Provider Capabilities";
1022
- var DEFAULT_DESCRIPTION3 = "Configured, selected, and healthy voice providers for this deployment.";
1023
- var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1475
+ var DEFAULT_TITLE4 = "Provider Capabilities";
1476
+ var DEFAULT_DESCRIPTION4 = "Configured, selected, and healthy voice providers for this deployment.";
1477
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1024
1478
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1025
1479
  var formatKind2 = (kind) => kind.toUpperCase();
1026
1480
  var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -1064,36 +1518,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
1064
1518
  const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
1065
1519
  return {
1066
1520
  capabilities,
1067
- description: options.description ?? DEFAULT_DESCRIPTION3,
1521
+ description: options.description ?? DEFAULT_DESCRIPTION4,
1068
1522
  error: snapshot.error,
1069
1523
  isLoading: snapshot.isLoading,
1070
1524
  label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
1071
1525
  status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1072
- title: options.title ?? DEFAULT_TITLE3,
1526
+ title: options.title ?? DEFAULT_TITLE4,
1073
1527
  updatedAt: snapshot.updatedAt
1074
1528
  };
1075
1529
  };
1076
1530
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
1077
1531
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
1078
- 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)}">
1532
+ 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)}">
1079
1533
  <header>
1080
- <strong>${escapeHtml4(capability.label)}</strong>
1081
- <span>${escapeHtml4(formatStatus(capability.status))}</span>
1534
+ <strong>${escapeHtml5(capability.label)}</strong>
1535
+ <span>${escapeHtml5(formatStatus(capability.status))}</span>
1082
1536
  </header>
1083
- <p>${escapeHtml4(capability.detail)}</p>
1537
+ <p>${escapeHtml5(capability.detail)}</p>
1084
1538
  <dl>${capability.rows.map((row) => `<div>
1085
- <dt>${escapeHtml4(row.label)}</dt>
1086
- <dd>${escapeHtml4(row.value)}</dd>
1539
+ <dt>${escapeHtml5(row.label)}</dt>
1540
+ <dd>${escapeHtml5(row.value)}</dd>
1087
1541
  </div>`).join("")}</dl>
1088
1542
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
1089
- return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml4(model.status)}">
1543
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml5(model.status)}">
1090
1544
  <header class="absolute-voice-provider-capabilities__header">
1091
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml4(model.title)}</span>
1092
- <strong class="absolute-voice-provider-capabilities__label">${escapeHtml4(model.label)}</strong>
1545
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml5(model.title)}</span>
1546
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml5(model.label)}</strong>
1093
1547
  </header>
1094
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml4(model.description)}</p>
1548
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml5(model.description)}</p>
1095
1549
  ${capabilities}
1096
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml4(model.error)}</p>` : ""}
1550
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml5(model.error)}</p>` : ""}
1097
1551
  </section>`;
1098
1552
  };
1099
1553
  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}`;
@@ -1135,13 +1589,13 @@ var defineVoiceProviderCapabilitiesElement = (tagName = "absolute-voice-provider
1135
1589
  };
1136
1590
 
1137
1591
  // src/vue/useVoiceProviderCapabilities.ts
1138
- import { onUnmounted as onUnmounted4, shallowRef as shallowRef3 } from "vue";
1592
+ import { onUnmounted as onUnmounted5, shallowRef as shallowRef4 } from "vue";
1139
1593
  function useVoiceProviderCapabilities(path = "/api/provider-capabilities", options = {}) {
1140
1594
  const store = createVoiceProviderCapabilitiesStore(path, options);
1141
- const error = shallowRef3(null);
1142
- const isLoading = shallowRef3(false);
1143
- const report = shallowRef3();
1144
- const updatedAt = shallowRef3(undefined);
1595
+ const error = shallowRef4(null);
1596
+ const isLoading = shallowRef4(false);
1597
+ const report = shallowRef4();
1598
+ const updatedAt = shallowRef4(undefined);
1145
1599
  const sync = () => {
1146
1600
  const snapshot = store.getSnapshot();
1147
1601
  error.value = snapshot.error;
@@ -1152,7 +1606,7 @@ function useVoiceProviderCapabilities(path = "/api/provider-capabilities", optio
1152
1606
  const unsubscribe = store.subscribe(sync);
1153
1607
  sync();
1154
1608
  store.refresh().catch(() => {});
1155
- onUnmounted4(() => {
1609
+ onUnmounted5(() => {
1156
1610
  unsubscribe();
1157
1611
  store.close();
1158
1612
  });
@@ -1166,7 +1620,7 @@ function useVoiceProviderCapabilities(path = "/api/provider-capabilities", optio
1166
1620
  }
1167
1621
 
1168
1622
  // src/vue/VoiceProviderCapabilities.ts
1169
- var VoiceProviderCapabilities = defineComponent4({
1623
+ var VoiceProviderCapabilities = defineComponent5({
1170
1624
  name: "VoiceProviderCapabilities",
1171
1625
  props: {
1172
1626
  class: {
@@ -1203,41 +1657,41 @@ var VoiceProviderCapabilities = defineComponent4({
1203
1657
  report: capabilities.report.value,
1204
1658
  updatedAt: capabilities.updatedAt.value
1205
1659
  }, options));
1206
- return () => h4("section", {
1660
+ return () => h5("section", {
1207
1661
  class: [
1208
1662
  "absolute-voice-provider-capabilities",
1209
1663
  `absolute-voice-provider-capabilities--${model.value.status}`,
1210
1664
  props.class
1211
1665
  ]
1212
1666
  }, [
1213
- h4("header", { class: "absolute-voice-provider-capabilities__header" }, [
1214
- h4("span", { class: "absolute-voice-provider-capabilities__eyebrow" }, model.value.title),
1215
- h4("strong", { class: "absolute-voice-provider-capabilities__label" }, model.value.label)
1667
+ h5("header", { class: "absolute-voice-provider-capabilities__header" }, [
1668
+ h5("span", { class: "absolute-voice-provider-capabilities__eyebrow" }, model.value.title),
1669
+ h5("strong", { class: "absolute-voice-provider-capabilities__label" }, model.value.label)
1216
1670
  ]),
1217
- h4("p", { class: "absolute-voice-provider-capabilities__description" }, model.value.description),
1218
- model.value.capabilities.length ? h4("div", { class: "absolute-voice-provider-capabilities__providers" }, model.value.capabilities.map((capability) => h4("article", {
1671
+ h5("p", { class: "absolute-voice-provider-capabilities__description" }, model.value.description),
1672
+ model.value.capabilities.length ? h5("div", { class: "absolute-voice-provider-capabilities__providers" }, model.value.capabilities.map((capability) => h5("article", {
1219
1673
  class: [
1220
1674
  "absolute-voice-provider-capabilities__provider",
1221
1675
  `absolute-voice-provider-capabilities__provider--${capability.status}`
1222
1676
  ],
1223
1677
  key: `${capability.kind}:${capability.provider}`
1224
1678
  }, [
1225
- h4("header", [
1226
- h4("strong", capability.label),
1227
- h4("span", capability.status)
1679
+ h5("header", [
1680
+ h5("strong", capability.label),
1681
+ h5("span", capability.status)
1228
1682
  ]),
1229
- h4("p", capability.detail),
1230
- h4("dl", capability.rows.map((row) => h4("div", { key: row.label }, [
1231
- h4("dt", row.label),
1232
- h4("dd", row.value)
1683
+ h5("p", capability.detail),
1684
+ h5("dl", capability.rows.map((row) => h5("div", { key: row.label }, [
1685
+ h5("dt", row.label),
1686
+ h5("dd", row.value)
1233
1687
  ])))
1234
- ]))) : h4("p", { class: "absolute-voice-provider-capabilities__empty" }, "Configure provider capabilities to see deployment coverage."),
1235
- model.value.error ? h4("p", { class: "absolute-voice-provider-capabilities__error" }, model.value.error) : null
1688
+ ]))) : h5("p", { class: "absolute-voice-provider-capabilities__empty" }, "Configure provider capabilities to see deployment coverage."),
1689
+ model.value.error ? h5("p", { class: "absolute-voice-provider-capabilities__error" }, model.value.error) : null
1236
1690
  ]);
1237
1691
  }
1238
1692
  });
1239
1693
  // src/vue/VoiceProviderStatus.ts
1240
- import { computed as computed3, defineComponent as defineComponent5, h as h5 } from "vue";
1694
+ import { computed as computed3, defineComponent as defineComponent6, h as h6 } from "vue";
1241
1695
 
1242
1696
  // src/client/providerStatus.ts
1243
1697
  var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
@@ -1320,9 +1774,9 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
1320
1774
  };
1321
1775
 
1322
1776
  // src/client/providerStatusWidget.ts
1323
- var DEFAULT_TITLE4 = "Voice Providers";
1324
- var DEFAULT_DESCRIPTION4 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
1325
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1777
+ var DEFAULT_TITLE5 = "Voice Providers";
1778
+ var DEFAULT_DESCRIPTION5 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
1779
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1326
1780
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1327
1781
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
1328
1782
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -1366,37 +1820,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
1366
1820
  const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
1367
1821
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
1368
1822
  return {
1369
- description: options.description ?? DEFAULT_DESCRIPTION4,
1823
+ description: options.description ?? DEFAULT_DESCRIPTION5,
1370
1824
  error: snapshot.error,
1371
1825
  isLoading: snapshot.isLoading,
1372
1826
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
1373
1827
  providers,
1374
1828
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1375
- title: options.title ?? DEFAULT_TITLE4,
1829
+ title: options.title ?? DEFAULT_TITLE5,
1376
1830
  updatedAt: snapshot.updatedAt
1377
1831
  };
1378
1832
  };
1379
1833
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
1380
1834
  const model = createVoiceProviderStatusViewModel(snapshot, options);
1381
- 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)}">
1835
+ 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)}">
1382
1836
  <header>
1383
- <strong>${escapeHtml5(provider.label)}</strong>
1384
- <span>${escapeHtml5(formatStatus2(provider.status))}</span>
1837
+ <strong>${escapeHtml6(provider.label)}</strong>
1838
+ <span>${escapeHtml6(formatStatus2(provider.status))}</span>
1385
1839
  </header>
1386
- <p>${escapeHtml5(provider.detail)}</p>
1840
+ <p>${escapeHtml6(provider.detail)}</p>
1387
1841
  <dl>${provider.rows.map((row) => `<div>
1388
- <dt>${escapeHtml5(row.label)}</dt>
1389
- <dd>${escapeHtml5(row.value)}</dd>
1842
+ <dt>${escapeHtml6(row.label)}</dt>
1843
+ <dd>${escapeHtml6(row.value)}</dd>
1390
1844
  </div>`).join("")}</dl>
1391
1845
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
1392
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml5(model.status)}">
1846
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml6(model.status)}">
1393
1847
  <header class="absolute-voice-provider-status__header">
1394
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
1395
- <strong class="absolute-voice-provider-status__label">${escapeHtml5(model.label)}</strong>
1848
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml6(model.title)}</span>
1849
+ <strong class="absolute-voice-provider-status__label">${escapeHtml6(model.label)}</strong>
1396
1850
  </header>
1397
- <p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
1851
+ <p class="absolute-voice-provider-status__description">${escapeHtml6(model.description)}</p>
1398
1852
  ${providers}
1399
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml5(model.error)}</p>` : ""}
1853
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml6(model.error)}</p>` : ""}
1400
1854
  </section>`;
1401
1855
  };
1402
1856
  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}`;
@@ -1438,13 +1892,13 @@ var defineVoiceProviderStatusElement = (tagName = "absolute-voice-provider-statu
1438
1892
  };
1439
1893
 
1440
1894
  // src/vue/useVoiceProviderStatus.ts
1441
- import { onUnmounted as onUnmounted5, ref as ref4, shallowRef as shallowRef4 } from "vue";
1895
+ import { onUnmounted as onUnmounted6, ref as ref5, shallowRef as shallowRef5 } from "vue";
1442
1896
  function useVoiceProviderStatus(path = "/api/provider-status", options = {}) {
1443
1897
  const store = createVoiceProviderStatusStore(path, options);
1444
- const error = ref4(null);
1445
- const isLoading = ref4(false);
1446
- const providers = shallowRef4([]);
1447
- const updatedAt = ref4(undefined);
1898
+ const error = ref5(null);
1899
+ const isLoading = ref5(false);
1900
+ const providers = shallowRef5([]);
1901
+ const updatedAt = ref5(undefined);
1448
1902
  const sync = () => {
1449
1903
  const snapshot = store.getSnapshot();
1450
1904
  error.value = snapshot.error;
@@ -1455,7 +1909,7 @@ function useVoiceProviderStatus(path = "/api/provider-status", options = {}) {
1455
1909
  const unsubscribe = store.subscribe(sync);
1456
1910
  sync();
1457
1911
  store.refresh().catch(() => {});
1458
- onUnmounted5(() => {
1912
+ onUnmounted6(() => {
1459
1913
  unsubscribe();
1460
1914
  store.close();
1461
1915
  });
@@ -1469,7 +1923,7 @@ function useVoiceProviderStatus(path = "/api/provider-status", options = {}) {
1469
1923
  }
1470
1924
 
1471
1925
  // src/vue/VoiceProviderStatus.ts
1472
- var VoiceProviderStatus = defineComponent5({
1926
+ var VoiceProviderStatus = defineComponent6({
1473
1927
  name: "VoiceProviderStatus",
1474
1928
  props: {
1475
1929
  class: {
@@ -1506,41 +1960,41 @@ var VoiceProviderStatus = defineComponent5({
1506
1960
  providers: status.providers.value,
1507
1961
  updatedAt: status.updatedAt.value
1508
1962
  }, options));
1509
- return () => h5("section", {
1963
+ return () => h6("section", {
1510
1964
  class: [
1511
1965
  "absolute-voice-provider-status",
1512
1966
  `absolute-voice-provider-status--${model.value.status}`,
1513
1967
  props.class
1514
1968
  ]
1515
1969
  }, [
1516
- h5("header", { class: "absolute-voice-provider-status__header" }, [
1517
- h5("span", { class: "absolute-voice-provider-status__eyebrow" }, model.value.title),
1518
- h5("strong", { class: "absolute-voice-provider-status__label" }, model.value.label)
1970
+ h6("header", { class: "absolute-voice-provider-status__header" }, [
1971
+ h6("span", { class: "absolute-voice-provider-status__eyebrow" }, model.value.title),
1972
+ h6("strong", { class: "absolute-voice-provider-status__label" }, model.value.label)
1519
1973
  ]),
1520
- h5("p", { class: "absolute-voice-provider-status__description" }, model.value.description),
1521
- model.value.providers.length ? h5("div", { class: "absolute-voice-provider-status__providers" }, model.value.providers.map((provider) => h5("article", {
1974
+ h6("p", { class: "absolute-voice-provider-status__description" }, model.value.description),
1975
+ model.value.providers.length ? h6("div", { class: "absolute-voice-provider-status__providers" }, model.value.providers.map((provider) => h6("article", {
1522
1976
  class: [
1523
1977
  "absolute-voice-provider-status__provider",
1524
1978
  `absolute-voice-provider-status__provider--${provider.status}`
1525
1979
  ],
1526
1980
  key: provider.provider
1527
1981
  }, [
1528
- h5("header", [
1529
- h5("strong", provider.label),
1530
- h5("span", provider.status)
1982
+ h6("header", [
1983
+ h6("strong", provider.label),
1984
+ h6("span", provider.status)
1531
1985
  ]),
1532
- h5("p", provider.detail),
1533
- h5("dl", provider.rows.map((row) => h5("div", { key: row.label }, [
1534
- h5("dt", row.label),
1535
- h5("dd", row.value)
1986
+ h6("p", provider.detail),
1987
+ h6("dl", provider.rows.map((row) => h6("div", { key: row.label }, [
1988
+ h6("dt", row.label),
1989
+ h6("dd", row.value)
1536
1990
  ])))
1537
- ]))) : h5("p", { class: "absolute-voice-provider-status__empty" }, "Run voice traffic to see provider health."),
1538
- model.value.error ? h5("p", { class: "absolute-voice-provider-status__error" }, model.value.error) : null
1991
+ ]))) : h6("p", { class: "absolute-voice-provider-status__empty" }, "Run voice traffic to see provider health."),
1992
+ model.value.error ? h6("p", { class: "absolute-voice-provider-status__error" }, model.value.error) : null
1539
1993
  ]);
1540
1994
  }
1541
1995
  });
1542
1996
  // src/vue/VoiceRoutingStatus.ts
1543
- import { computed as computed4, defineComponent as defineComponent6, h as h6 } from "vue";
1997
+ import { computed as computed4, defineComponent as defineComponent7, h as h7 } from "vue";
1544
1998
 
1545
1999
  // src/client/routingStatus.ts
1546
2000
  var fetchVoiceRoutingStatus = async (path = "/api/routing/latest", options = {}) => {
@@ -1623,9 +2077,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
1623
2077
  };
1624
2078
 
1625
2079
  // src/client/routingStatusWidget.ts
1626
- var DEFAULT_TITLE5 = "Voice Routing";
1627
- var DEFAULT_DESCRIPTION5 = "Latest provider routing decision from the self-hosted trace store.";
1628
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2080
+ var DEFAULT_TITLE6 = "Voice Routing";
2081
+ var DEFAULT_DESCRIPTION6 = "Latest provider routing decision from the self-hosted trace store.";
2082
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1629
2083
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
1630
2084
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1631
2085
  const decision = snapshot.decision;
@@ -1649,30 +2103,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1649
2103
  ] : [];
1650
2104
  return {
1651
2105
  decision,
1652
- description: options.description ?? DEFAULT_DESCRIPTION5,
2106
+ description: options.description ?? DEFAULT_DESCRIPTION6,
1653
2107
  error: snapshot.error,
1654
2108
  isLoading: snapshot.isLoading,
1655
2109
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
1656
2110
  rows,
1657
2111
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
1658
- title: options.title ?? DEFAULT_TITLE5,
2112
+ title: options.title ?? DEFAULT_TITLE6,
1659
2113
  updatedAt: snapshot.updatedAt
1660
2114
  };
1661
2115
  };
1662
2116
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
1663
2117
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
1664
2118
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
1665
- <span>${escapeHtml6(row.label)}</span>
1666
- <strong>${escapeHtml6(row.value)}</strong>
2119
+ <span>${escapeHtml7(row.label)}</span>
2120
+ <strong>${escapeHtml7(row.value)}</strong>
1667
2121
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
1668
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml6(model.status)}">
2122
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml7(model.status)}">
1669
2123
  <header class="absolute-voice-routing-status__header">
1670
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml6(model.title)}</span>
1671
- <strong class="absolute-voice-routing-status__label">${escapeHtml6(model.label)}</strong>
2124
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml7(model.title)}</span>
2125
+ <strong class="absolute-voice-routing-status__label">${escapeHtml7(model.label)}</strong>
1672
2126
  </header>
1673
- <p class="absolute-voice-routing-status__description">${escapeHtml6(model.description)}</p>
2127
+ <p class="absolute-voice-routing-status__description">${escapeHtml7(model.description)}</p>
1674
2128
  ${rows}
1675
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml6(model.error)}</p>` : ""}
2129
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml7(model.error)}</p>` : ""}
1676
2130
  </section>`;
1677
2131
  };
1678
2132
  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}`;
@@ -1714,13 +2168,13 @@ var defineVoiceRoutingStatusElement = (tagName = "absolute-voice-routing-status"
1714
2168
  };
1715
2169
 
1716
2170
  // src/vue/useVoiceRoutingStatus.ts
1717
- import { onUnmounted as onUnmounted6, ref as ref5, shallowRef as shallowRef5 } from "vue";
2171
+ import { onUnmounted as onUnmounted7, ref as ref6, shallowRef as shallowRef6 } from "vue";
1718
2172
  function useVoiceRoutingStatus(path = "/api/routing/latest", options = {}) {
1719
2173
  const store = createVoiceRoutingStatusStore(path, options);
1720
- const decision = shallowRef5(null);
1721
- const error = ref5(null);
1722
- const isLoading = ref5(false);
1723
- const updatedAt = ref5(undefined);
2174
+ const decision = shallowRef6(null);
2175
+ const error = ref6(null);
2176
+ const isLoading = ref6(false);
2177
+ const updatedAt = ref6(undefined);
1724
2178
  const sync = () => {
1725
2179
  const snapshot = store.getSnapshot();
1726
2180
  decision.value = snapshot.decision;
@@ -1731,7 +2185,7 @@ function useVoiceRoutingStatus(path = "/api/routing/latest", options = {}) {
1731
2185
  const unsubscribe = store.subscribe(sync);
1732
2186
  sync();
1733
2187
  store.refresh().catch(() => {});
1734
- onUnmounted6(() => {
2188
+ onUnmounted7(() => {
1735
2189
  unsubscribe();
1736
2190
  store.close();
1737
2191
  });
@@ -1745,7 +2199,7 @@ function useVoiceRoutingStatus(path = "/api/routing/latest", options = {}) {
1745
2199
  }
1746
2200
 
1747
2201
  // src/vue/VoiceRoutingStatus.ts
1748
- var VoiceRoutingStatus = defineComponent6({
2202
+ var VoiceRoutingStatus = defineComponent7({
1749
2203
  name: "VoiceRoutingStatus",
1750
2204
  props: {
1751
2205
  class: {
@@ -1782,28 +2236,28 @@ var VoiceRoutingStatus = defineComponent6({
1782
2236
  isLoading: status.isLoading.value,
1783
2237
  updatedAt: status.updatedAt.value
1784
2238
  }, options));
1785
- return () => h6("section", {
2239
+ return () => h7("section", {
1786
2240
  class: [
1787
2241
  "absolute-voice-routing-status",
1788
2242
  `absolute-voice-routing-status--${model.value.status}`,
1789
2243
  props.class
1790
2244
  ]
1791
2245
  }, [
1792
- h6("header", { class: "absolute-voice-routing-status__header" }, [
1793
- h6("span", { class: "absolute-voice-routing-status__eyebrow" }, model.value.title),
1794
- h6("strong", { class: "absolute-voice-routing-status__label" }, model.value.label)
2246
+ h7("header", { class: "absolute-voice-routing-status__header" }, [
2247
+ h7("span", { class: "absolute-voice-routing-status__eyebrow" }, model.value.title),
2248
+ h7("strong", { class: "absolute-voice-routing-status__label" }, model.value.label)
1795
2249
  ]),
1796
- h6("p", { class: "absolute-voice-routing-status__description" }, model.value.description),
1797
- model.value.rows.length ? h6("div", { class: "absolute-voice-routing-status__grid" }, model.value.rows.map((row) => h6("div", { key: row.label }, [
1798
- h6("span", row.label),
1799
- h6("strong", row.value)
1800
- ]))) : h6("p", { class: "absolute-voice-routing-status__empty" }, "Start a voice session to see the selected provider."),
1801
- model.value.error ? h6("p", { class: "absolute-voice-routing-status__error" }, model.value.error) : null
2250
+ h7("p", { class: "absolute-voice-routing-status__description" }, model.value.description),
2251
+ model.value.rows.length ? h7("div", { class: "absolute-voice-routing-status__grid" }, model.value.rows.map((row) => h7("div", { key: row.label }, [
2252
+ h7("span", row.label),
2253
+ h7("strong", row.value)
2254
+ ]))) : h7("p", { class: "absolute-voice-routing-status__empty" }, "Start a voice session to see the selected provider."),
2255
+ model.value.error ? h7("p", { class: "absolute-voice-routing-status__error" }, model.value.error) : null
1802
2256
  ]);
1803
2257
  }
1804
2258
  });
1805
2259
  // src/vue/VoiceTurnLatency.ts
1806
- import { computed as computed5, defineComponent as defineComponent7, h as h7 } from "vue";
2260
+ import { computed as computed5, defineComponent as defineComponent8, h as h8 } from "vue";
1807
2261
 
1808
2262
  // src/client/turnLatency.ts
1809
2263
  var fetchVoiceTurnLatency = async (path = "/api/turn-latency", options = {}) => {
@@ -1909,10 +2363,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
1909
2363
  };
1910
2364
 
1911
2365
  // src/client/turnLatencyWidget.ts
1912
- var DEFAULT_TITLE6 = "Turn Latency";
1913
- var DEFAULT_DESCRIPTION6 = "Per-turn timing from first transcript to commit and assistant response start.";
2366
+ var DEFAULT_TITLE7 = "Turn Latency";
2367
+ var DEFAULT_DESCRIPTION7 = "Per-turn timing from first transcript to commit and assistant response start.";
1914
2368
  var DEFAULT_PROOF_LABEL = "Run latency proof";
1915
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2369
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1916
2370
  var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
1917
2371
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
1918
2372
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -1926,39 +2380,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
1926
2380
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
1927
2381
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
1928
2382
  return {
1929
- description: options.description ?? DEFAULT_DESCRIPTION6,
2383
+ description: options.description ?? DEFAULT_DESCRIPTION7,
1930
2384
  error: snapshot.error,
1931
2385
  isLoading: snapshot.isLoading,
1932
2386
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
1933
2387
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
1934
2388
  showProofAction: Boolean(options.proofPath),
1935
2389
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1936
- title: options.title ?? DEFAULT_TITLE6,
2390
+ title: options.title ?? DEFAULT_TITLE7,
1937
2391
  turns,
1938
2392
  updatedAt: snapshot.updatedAt
1939
2393
  };
1940
2394
  };
1941
2395
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
1942
2396
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
1943
- 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--${escapeHtml7(turn.status)}">
2397
+ 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)}">
1944
2398
  <header>
1945
- <strong>${escapeHtml7(turn.label)}</strong>
1946
- <span>${escapeHtml7(turn.status)}</span>
2399
+ <strong>${escapeHtml8(turn.label)}</strong>
2400
+ <span>${escapeHtml8(turn.status)}</span>
1947
2401
  </header>
1948
2402
  <dl>${turn.rows.map((row) => `<div>
1949
- <dt>${escapeHtml7(row.label)}</dt>
1950
- <dd>${escapeHtml7(row.value)}</dd>
2403
+ <dt>${escapeHtml8(row.label)}</dt>
2404
+ <dd>${escapeHtml8(row.value)}</dd>
1951
2405
  </div>`).join("")}</dl>
1952
2406
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
1953
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml7(model.status)}">
2407
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml8(model.status)}">
1954
2408
  <header class="absolute-voice-turn-latency__header">
1955
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml7(model.title)}</span>
1956
- <strong class="absolute-voice-turn-latency__label">${escapeHtml7(model.label)}</strong>
2409
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
2410
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml8(model.label)}</strong>
1957
2411
  </header>
1958
- <p class="absolute-voice-turn-latency__description">${escapeHtml7(model.description)}</p>
1959
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml7(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2412
+ <p class="absolute-voice-turn-latency__description">${escapeHtml8(model.description)}</p>
2413
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml8(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
1960
2414
  ${turns}
1961
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml7(model.error)}</p>` : ""}
2415
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml8(model.error)}</p>` : ""}
1962
2416
  </section>`;
1963
2417
  };
1964
2418
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -2009,13 +2463,13 @@ var defineVoiceTurnLatencyElement = (tagName = "absolute-voice-turn-latency") =>
2009
2463
  };
2010
2464
 
2011
2465
  // src/vue/useVoiceTurnLatency.ts
2012
- import { onUnmounted as onUnmounted7, shallowRef as shallowRef6 } from "vue";
2466
+ import { onUnmounted as onUnmounted8, shallowRef as shallowRef7 } from "vue";
2013
2467
  function useVoiceTurnLatency(path = "/api/turn-latency", options = {}) {
2014
2468
  const store = createVoiceTurnLatencyStore(path, options);
2015
- const error = shallowRef6(null);
2016
- const isLoading = shallowRef6(false);
2017
- const report = shallowRef6();
2018
- const updatedAt = shallowRef6(undefined);
2469
+ const error = shallowRef7(null);
2470
+ const isLoading = shallowRef7(false);
2471
+ const report = shallowRef7();
2472
+ const updatedAt = shallowRef7(undefined);
2019
2473
  const sync = () => {
2020
2474
  const snapshot = store.getSnapshot();
2021
2475
  error.value = snapshot.error;
@@ -2026,7 +2480,7 @@ function useVoiceTurnLatency(path = "/api/turn-latency", options = {}) {
2026
2480
  const unsubscribe = store.subscribe(sync);
2027
2481
  sync();
2028
2482
  store.refresh().catch(() => {});
2029
- onUnmounted7(() => {
2483
+ onUnmounted8(() => {
2030
2484
  unsubscribe();
2031
2485
  store.close();
2032
2486
  });
@@ -2041,7 +2495,7 @@ function useVoiceTurnLatency(path = "/api/turn-latency", options = {}) {
2041
2495
  }
2042
2496
 
2043
2497
  // src/vue/VoiceTurnLatency.ts
2044
- var VoiceTurnLatency = defineComponent7({
2498
+ var VoiceTurnLatency = defineComponent8({
2045
2499
  name: "VoiceTurnLatency",
2046
2500
  props: {
2047
2501
  class: { default: "", type: String },
@@ -2067,47 +2521,47 @@ var VoiceTurnLatency = defineComponent7({
2067
2521
  report: latency.report.value,
2068
2522
  updatedAt: latency.updatedAt.value
2069
2523
  }, options));
2070
- return () => h7("section", {
2524
+ return () => h8("section", {
2071
2525
  class: [
2072
2526
  "absolute-voice-turn-latency",
2073
2527
  `absolute-voice-turn-latency--${model.value.status}`,
2074
2528
  props.class
2075
2529
  ]
2076
2530
  }, [
2077
- h7("header", { class: "absolute-voice-turn-latency__header" }, [
2078
- h7("span", { class: "absolute-voice-turn-latency__eyebrow" }, model.value.title),
2079
- h7("strong", { class: "absolute-voice-turn-latency__label" }, model.value.label)
2531
+ h8("header", { class: "absolute-voice-turn-latency__header" }, [
2532
+ h8("span", { class: "absolute-voice-turn-latency__eyebrow" }, model.value.title),
2533
+ h8("strong", { class: "absolute-voice-turn-latency__label" }, model.value.label)
2080
2534
  ]),
2081
- h7("p", { class: "absolute-voice-turn-latency__description" }, model.value.description),
2082
- model.value.showProofAction ? h7("button", {
2535
+ h8("p", { class: "absolute-voice-turn-latency__description" }, model.value.description),
2536
+ model.value.showProofAction ? h8("button", {
2083
2537
  class: "absolute-voice-turn-latency__proof",
2084
2538
  onClick: () => {
2085
2539
  latency.runProof().catch(() => {});
2086
2540
  },
2087
2541
  type: "button"
2088
2542
  }, model.value.proofLabel) : null,
2089
- model.value.turns.length ? h7("div", { class: "absolute-voice-turn-latency__turns" }, model.value.turns.map((turn) => h7("article", {
2543
+ model.value.turns.length ? h8("div", { class: "absolute-voice-turn-latency__turns" }, model.value.turns.map((turn) => h8("article", {
2090
2544
  class: [
2091
2545
  "absolute-voice-turn-latency__turn",
2092
2546
  `absolute-voice-turn-latency__turn--${turn.status}`
2093
2547
  ],
2094
2548
  key: `${turn.sessionId}:${turn.turnId}`
2095
2549
  }, [
2096
- h7("header", [
2097
- h7("strong", turn.label),
2098
- h7("span", turn.status)
2550
+ h8("header", [
2551
+ h8("strong", turn.label),
2552
+ h8("span", turn.status)
2099
2553
  ]),
2100
- h7("dl", turn.rows.map((row) => h7("div", { key: row.label }, [
2101
- h7("dt", row.label),
2102
- h7("dd", row.value)
2554
+ h8("dl", turn.rows.map((row) => h8("div", { key: row.label }, [
2555
+ h8("dt", row.label),
2556
+ h8("dd", row.value)
2103
2557
  ])))
2104
- ]))) : h7("p", { class: "absolute-voice-turn-latency__empty" }, "Complete a voice turn to see latency diagnostics."),
2105
- model.value.error ? h7("p", { class: "absolute-voice-turn-latency__error" }, model.value.error) : null
2558
+ ]))) : h8("p", { class: "absolute-voice-turn-latency__empty" }, "Complete a voice turn to see latency diagnostics."),
2559
+ model.value.error ? h8("p", { class: "absolute-voice-turn-latency__error" }, model.value.error) : null
2106
2560
  ]);
2107
2561
  }
2108
2562
  });
2109
2563
  // src/vue/VoiceTurnQuality.ts
2110
- import { computed as computed6, defineComponent as defineComponent8, h as h8 } from "vue";
2564
+ import { computed as computed6, defineComponent as defineComponent9, h as h9 } from "vue";
2111
2565
 
2112
2566
  // src/client/turnQuality.ts
2113
2567
  var fetchVoiceTurnQuality = async (path = "/api/turn-quality", options = {}) => {
@@ -2189,9 +2643,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
2189
2643
  };
2190
2644
 
2191
2645
  // src/client/turnQualityWidget.ts
2192
- var DEFAULT_TITLE7 = "Turn Quality";
2193
- var DEFAULT_DESCRIPTION7 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2194
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2646
+ var DEFAULT_TITLE8 = "Turn Quality";
2647
+ var DEFAULT_DESCRIPTION8 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2648
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2195
2649
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2196
2650
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2197
2651
  var getTurnDetail = (turn) => {
@@ -2229,37 +2683,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2229
2683
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2230
2684
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2231
2685
  return {
2232
- description: options.description ?? DEFAULT_DESCRIPTION7,
2686
+ description: options.description ?? DEFAULT_DESCRIPTION8,
2233
2687
  error: snapshot.error,
2234
2688
  isLoading: snapshot.isLoading,
2235
2689
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2236
2690
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2237
- title: options.title ?? DEFAULT_TITLE7,
2691
+ title: options.title ?? DEFAULT_TITLE8,
2238
2692
  turns,
2239
2693
  updatedAt: snapshot.updatedAt
2240
2694
  };
2241
2695
  };
2242
2696
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2243
2697
  const model = createVoiceTurnQualityViewModel(snapshot, options);
2244
- 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--${escapeHtml8(turn.status)}">
2698
+ 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)}">
2245
2699
  <header>
2246
- <strong>${escapeHtml8(turn.label)}</strong>
2247
- <span>${escapeHtml8(turn.status)}</span>
2700
+ <strong>${escapeHtml9(turn.label)}</strong>
2701
+ <span>${escapeHtml9(turn.status)}</span>
2248
2702
  </header>
2249
- <p>${escapeHtml8(turn.detail)}</p>
2703
+ <p>${escapeHtml9(turn.detail)}</p>
2250
2704
  <dl>${turn.rows.map((row) => `<div>
2251
- <dt>${escapeHtml8(row.label)}</dt>
2252
- <dd>${escapeHtml8(row.value)}</dd>
2705
+ <dt>${escapeHtml9(row.label)}</dt>
2706
+ <dd>${escapeHtml9(row.value)}</dd>
2253
2707
  </div>`).join("")}</dl>
2254
2708
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
2255
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml8(model.status)}">
2709
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml9(model.status)}">
2256
2710
  <header class="absolute-voice-turn-quality__header">
2257
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml8(model.title)}</span>
2258
- <strong class="absolute-voice-turn-quality__label">${escapeHtml8(model.label)}</strong>
2711
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml9(model.title)}</span>
2712
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml9(model.label)}</strong>
2259
2713
  </header>
2260
- <p class="absolute-voice-turn-quality__description">${escapeHtml8(model.description)}</p>
2714
+ <p class="absolute-voice-turn-quality__description">${escapeHtml9(model.description)}</p>
2261
2715
  ${turns}
2262
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml8(model.error)}</p>` : ""}
2716
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml9(model.error)}</p>` : ""}
2263
2717
  </section>`;
2264
2718
  };
2265
2719
  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}`;
@@ -2301,13 +2755,13 @@ var defineVoiceTurnQualityElement = (tagName = "absolute-voice-turn-quality") =>
2301
2755
  };
2302
2756
 
2303
2757
  // src/vue/useVoiceTurnQuality.ts
2304
- import { onUnmounted as onUnmounted8, shallowRef as shallowRef7 } from "vue";
2758
+ import { onUnmounted as onUnmounted9, shallowRef as shallowRef8 } from "vue";
2305
2759
  function useVoiceTurnQuality(path = "/api/turn-quality", options = {}) {
2306
2760
  const store = createVoiceTurnQualityStore(path, options);
2307
- const error = shallowRef7(null);
2308
- const isLoading = shallowRef7(false);
2309
- const report = shallowRef7();
2310
- const updatedAt = shallowRef7(undefined);
2761
+ const error = shallowRef8(null);
2762
+ const isLoading = shallowRef8(false);
2763
+ const report = shallowRef8();
2764
+ const updatedAt = shallowRef8(undefined);
2311
2765
  const sync = () => {
2312
2766
  const snapshot = store.getSnapshot();
2313
2767
  error.value = snapshot.error;
@@ -2318,7 +2772,7 @@ function useVoiceTurnQuality(path = "/api/turn-quality", options = {}) {
2318
2772
  const unsubscribe = store.subscribe(sync);
2319
2773
  sync();
2320
2774
  store.refresh().catch(() => {});
2321
- onUnmounted8(() => {
2775
+ onUnmounted9(() => {
2322
2776
  unsubscribe();
2323
2777
  store.close();
2324
2778
  });
@@ -2326,7 +2780,7 @@ function useVoiceTurnQuality(path = "/api/turn-quality", options = {}) {
2326
2780
  }
2327
2781
 
2328
2782
  // src/vue/VoiceTurnQuality.ts
2329
- var VoiceTurnQuality = defineComponent8({
2783
+ var VoiceTurnQuality = defineComponent9({
2330
2784
  name: "VoiceTurnQuality",
2331
2785
  props: {
2332
2786
  class: { default: "", type: String },
@@ -2348,41 +2802,41 @@ var VoiceTurnQuality = defineComponent8({
2348
2802
  report: quality.report.value,
2349
2803
  updatedAt: quality.updatedAt.value
2350
2804
  }, options));
2351
- return () => h8("section", {
2805
+ return () => h9("section", {
2352
2806
  class: [
2353
2807
  "absolute-voice-turn-quality",
2354
2808
  `absolute-voice-turn-quality--${model.value.status}`,
2355
2809
  props.class
2356
2810
  ]
2357
2811
  }, [
2358
- h8("header", { class: "absolute-voice-turn-quality__header" }, [
2359
- h8("span", { class: "absolute-voice-turn-quality__eyebrow" }, model.value.title),
2360
- h8("strong", { class: "absolute-voice-turn-quality__label" }, model.value.label)
2812
+ h9("header", { class: "absolute-voice-turn-quality__header" }, [
2813
+ h9("span", { class: "absolute-voice-turn-quality__eyebrow" }, model.value.title),
2814
+ h9("strong", { class: "absolute-voice-turn-quality__label" }, model.value.label)
2361
2815
  ]),
2362
- h8("p", { class: "absolute-voice-turn-quality__description" }, model.value.description),
2363
- model.value.turns.length ? h8("div", { class: "absolute-voice-turn-quality__turns" }, model.value.turns.map((turn) => h8("article", {
2816
+ h9("p", { class: "absolute-voice-turn-quality__description" }, model.value.description),
2817
+ model.value.turns.length ? h9("div", { class: "absolute-voice-turn-quality__turns" }, model.value.turns.map((turn) => h9("article", {
2364
2818
  class: [
2365
2819
  "absolute-voice-turn-quality__turn",
2366
2820
  `absolute-voice-turn-quality__turn--${turn.status}`
2367
2821
  ],
2368
2822
  key: `${turn.sessionId}:${turn.turnId}`
2369
2823
  }, [
2370
- h8("header", [
2371
- h8("strong", turn.label),
2372
- h8("span", turn.status)
2824
+ h9("header", [
2825
+ h9("strong", turn.label),
2826
+ h9("span", turn.status)
2373
2827
  ]),
2374
- h8("p", turn.detail),
2375
- h8("dl", turn.rows.map((row) => h8("div", { key: row.label }, [
2376
- h8("dt", row.label),
2377
- h8("dd", row.value)
2828
+ h9("p", turn.detail),
2829
+ h9("dl", turn.rows.map((row) => h9("div", { key: row.label }, [
2830
+ h9("dt", row.label),
2831
+ h9("dd", row.value)
2378
2832
  ])))
2379
- ]))) : h8("p", { class: "absolute-voice-turn-quality__empty" }, "Complete a voice turn to see STT quality diagnostics."),
2380
- model.value.error ? h8("p", { class: "absolute-voice-turn-quality__error" }, model.value.error) : null
2833
+ ]))) : h9("p", { class: "absolute-voice-turn-quality__empty" }, "Complete a voice turn to see STT quality diagnostics."),
2834
+ model.value.error ? h9("p", { class: "absolute-voice-turn-quality__error" }, model.value.error) : null
2381
2835
  ]);
2382
2836
  }
2383
2837
  });
2384
2838
  // src/vue/useVoiceCampaignDialerProof.ts
2385
- import { onUnmounted as onUnmounted9, shallowRef as shallowRef8 } from "vue";
2839
+ import { onUnmounted as onUnmounted10, shallowRef as shallowRef9 } from "vue";
2386
2840
 
2387
2841
  // src/client/campaignDialerProof.ts
2388
2842
  var fetchVoiceCampaignDialerProofStatus = async (path = "/api/voice/campaigns/dialer-proof", options = {}) => {
@@ -2505,11 +2959,11 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
2505
2959
  // src/vue/useVoiceCampaignDialerProof.ts
2506
2960
  function useVoiceCampaignDialerProof(path = "/api/voice/campaigns/dialer-proof", options = {}) {
2507
2961
  const store = createVoiceCampaignDialerProofStore(path, options);
2508
- const error = shallowRef8(null);
2509
- const isLoading = shallowRef8(false);
2510
- const report = shallowRef8();
2511
- const status = shallowRef8();
2512
- const updatedAt = shallowRef8(undefined);
2962
+ const error = shallowRef9(null);
2963
+ const isLoading = shallowRef9(false);
2964
+ const report = shallowRef9();
2965
+ const status = shallowRef9();
2966
+ const updatedAt = shallowRef9(undefined);
2513
2967
  const sync = () => {
2514
2968
  const snapshot = store.getSnapshot();
2515
2969
  error.value = snapshot.error;
@@ -2523,7 +2977,7 @@ function useVoiceCampaignDialerProof(path = "/api/voice/campaigns/dialer-proof",
2523
2977
  if (typeof window !== "undefined") {
2524
2978
  store.refresh().catch(() => {});
2525
2979
  }
2526
- onUnmounted9(() => {
2980
+ onUnmounted10(() => {
2527
2981
  unsubscribe();
2528
2982
  store.close();
2529
2983
  });
@@ -2538,7 +2992,7 @@ function useVoiceCampaignDialerProof(path = "/api/voice/campaigns/dialer-proof",
2538
2992
  };
2539
2993
  }
2540
2994
  // src/vue/useVoiceStream.ts
2541
- import { onUnmounted as onUnmounted10, ref as ref6, shallowRef as shallowRef9 } from "vue";
2995
+ import { onUnmounted as onUnmounted11, ref as ref7, shallowRef as shallowRef10 } from "vue";
2542
2996
 
2543
2997
  // src/client/actions.ts
2544
2998
  var normalizeErrorMessage = (value) => {
@@ -3183,16 +3637,16 @@ var createVoiceStream = (path, options = {}) => {
3183
3637
  // src/vue/useVoiceStream.ts
3184
3638
  function useVoiceStream(path, options = {}) {
3185
3639
  const stream = createVoiceStream(path, options);
3186
- const assistantAudio = shallowRef9([]);
3187
- const assistantTexts = shallowRef9([]);
3188
- const call = shallowRef9(null);
3189
- const error = ref6(null);
3190
- const isConnected = ref6(false);
3191
- const partial = ref6("");
3192
- const reconnect = shallowRef9(stream.reconnect);
3193
- const sessionId = ref6(stream.sessionId);
3194
- const status = ref6(stream.status);
3195
- const turns = shallowRef9([]);
3640
+ const assistantAudio = shallowRef10([]);
3641
+ const assistantTexts = shallowRef10([]);
3642
+ const call = shallowRef10(null);
3643
+ const error = ref7(null);
3644
+ const isConnected = ref7(false);
3645
+ const partial = ref7("");
3646
+ const reconnect = shallowRef10(stream.reconnect);
3647
+ const sessionId = ref7(stream.sessionId);
3648
+ const status = ref7(stream.status);
3649
+ const turns = shallowRef10([]);
3196
3650
  const sync = () => {
3197
3651
  assistantAudio.value = [...stream.assistantAudio];
3198
3652
  assistantTexts.value = [...stream.assistantTexts];
@@ -3211,7 +3665,7 @@ function useVoiceStream(path, options = {}) {
3211
3665
  unsubscribe();
3212
3666
  stream.close();
3213
3667
  };
3214
- onUnmounted10(destroy);
3668
+ onUnmounted11(destroy);
3215
3669
  return {
3216
3670
  assistantAudio,
3217
3671
  assistantTexts,
@@ -3230,7 +3684,7 @@ function useVoiceStream(path, options = {}) {
3230
3684
  };
3231
3685
  }
3232
3686
  // src/vue/useVoiceController.ts
3233
- import { onUnmounted as onUnmounted11, ref as ref7, shallowRef as shallowRef10 } from "vue";
3687
+ import { onUnmounted as onUnmounted12, ref as ref8, shallowRef as shallowRef11 } from "vue";
3234
3688
 
3235
3689
  // src/client/htmx.ts
3236
3690
  var DEFAULT_EVENT_NAME = "voice-refresh";
@@ -3876,17 +4330,17 @@ var createVoiceController = (path, options = {}) => {
3876
4330
  // src/vue/useVoiceController.ts
3877
4331
  function useVoiceController(path, options = {}) {
3878
4332
  const controller = createVoiceController(path, options);
3879
- const assistantAudio = shallowRef10([]);
3880
- const assistantTexts = shallowRef10([]);
3881
- const error = ref7(null);
3882
- const isConnected = ref7(false);
3883
- const isRecording = ref7(false);
3884
- const partial = ref7("");
3885
- const reconnect = shallowRef10(controller.reconnect);
3886
- const recordingError = ref7(null);
3887
- const sessionId = ref7(controller.sessionId);
3888
- const status = ref7(controller.status);
3889
- const turns = shallowRef10([]);
4333
+ const assistantAudio = shallowRef11([]);
4334
+ const assistantTexts = shallowRef11([]);
4335
+ const error = ref8(null);
4336
+ const isConnected = ref8(false);
4337
+ const isRecording = ref8(false);
4338
+ const partial = ref8("");
4339
+ const reconnect = shallowRef11(controller.reconnect);
4340
+ const recordingError = ref8(null);
4341
+ const sessionId = ref8(controller.sessionId);
4342
+ const status = ref8(controller.status);
4343
+ const turns = shallowRef11([]);
3890
4344
  const sync = () => {
3891
4345
  assistantAudio.value = [...controller.assistantAudio];
3892
4346
  assistantTexts.value = [...controller.assistantTexts];
@@ -3906,7 +4360,7 @@ function useVoiceController(path, options = {}) {
3906
4360
  unsubscribe();
3907
4361
  controller.close();
3908
4362
  };
3909
- onUnmounted11(destroy);
4363
+ onUnmounted12(destroy);
3910
4364
  return {
3911
4365
  assistantAudio,
3912
4366
  assistantTexts,
@@ -3929,7 +4383,7 @@ function useVoiceController(path, options = {}) {
3929
4383
  };
3930
4384
  }
3931
4385
  // src/vue/useVoiceTraceTimeline.ts
3932
- import { onUnmounted as onUnmounted12, ref as ref8, shallowRef as shallowRef11 } from "vue";
4386
+ import { onUnmounted as onUnmounted13, ref as ref9, shallowRef as shallowRef12 } from "vue";
3933
4387
 
3934
4388
  // src/client/traceTimeline.ts
3935
4389
  var fetchVoiceTraceTimeline = async (path = "/api/voice-traces", options = {}) => {
@@ -4014,10 +4468,10 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
4014
4468
  // src/vue/useVoiceTraceTimeline.ts
4015
4469
  function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
4016
4470
  const store = createVoiceTraceTimelineStore(path, options);
4017
- const error = ref8(null);
4018
- const isLoading = ref8(false);
4019
- const report = shallowRef11(null);
4020
- const updatedAt = ref8(undefined);
4471
+ const error = ref9(null);
4472
+ const isLoading = ref9(false);
4473
+ const report = shallowRef12(null);
4474
+ const updatedAt = ref9(undefined);
4021
4475
  const sync = () => {
4022
4476
  const snapshot = store.getSnapshot();
4023
4477
  error.value = snapshot.error;
@@ -4028,7 +4482,7 @@ function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
4028
4482
  const unsubscribe = store.subscribe(sync);
4029
4483
  sync();
4030
4484
  store.refresh().catch(() => {});
4031
- onUnmounted12(() => {
4485
+ onUnmounted13(() => {
4032
4486
  unsubscribe();
4033
4487
  store.close();
4034
4488
  });
@@ -4041,7 +4495,7 @@ function useVoiceTraceTimeline(path = "/api/voice-traces", options = {}) {
4041
4495
  };
4042
4496
  }
4043
4497
  // src/vue/useVoiceWorkflowStatus.ts
4044
- import { onUnmounted as onUnmounted13, ref as ref9, shallowRef as shallowRef12 } from "vue";
4498
+ import { onUnmounted as onUnmounted14, ref as ref10, shallowRef as shallowRef13 } from "vue";
4045
4499
 
4046
4500
  // src/client/workflowStatus.ts
4047
4501
  var fetchVoiceWorkflowStatus = async (path = "/evals/scenarios/json", options = {}) => {
@@ -4125,10 +4579,10 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
4125
4579
  // src/vue/useVoiceWorkflowStatus.ts
4126
4580
  function useVoiceWorkflowStatus(path = "/evals/scenarios/json", options = {}) {
4127
4581
  const store = createVoiceWorkflowStatusStore(path, options);
4128
- const error = ref9(null);
4129
- const isLoading = ref9(false);
4130
- const report = shallowRef12(undefined);
4131
- const updatedAt = ref9(undefined);
4582
+ const error = ref10(null);
4583
+ const isLoading = ref10(false);
4584
+ const report = shallowRef13(undefined);
4585
+ const updatedAt = ref10(undefined);
4132
4586
  const sync = () => {
4133
4587
  const snapshot = store.getSnapshot();
4134
4588
  error.value = snapshot.error;
@@ -4141,7 +4595,7 @@ function useVoiceWorkflowStatus(path = "/evals/scenarios/json", options = {}) {
4141
4595
  if (typeof window !== "undefined") {
4142
4596
  store.refresh().catch(() => {});
4143
4597
  }
4144
- onUnmounted13(() => {
4598
+ onUnmounted14(() => {
4145
4599
  unsubscribe();
4146
4600
  store.close();
4147
4601
  });
@@ -4164,6 +4618,7 @@ export {
4164
4618
  useVoiceProviderSimulationControls,
4165
4619
  useVoiceProviderCapabilities,
4166
4620
  useVoiceOpsStatus,
4621
+ useVoiceOpsActionCenter,
4167
4622
  useVoiceDeliveryRuntime,
4168
4623
  useVoiceController,
4169
4624
  useVoiceCampaignDialerProof,
@@ -4174,5 +4629,6 @@ export {
4174
4629
  VoiceProviderSimulationControls,
4175
4630
  VoiceProviderCapabilities,
4176
4631
  VoiceOpsStatus,
4632
+ VoiceOpsActionCenter,
4177
4633
  VoiceDeliveryRuntime
4178
4634
  };