@rubytech/create-maxy-code 0.1.476 → 0.1.478

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1704-data-portal-standing-audit.md +673 -0
  3. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1704-data-portal-standing-audit-design.md +177 -0
  4. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1820-cpu-triage-admin-tools-design.md +97 -0
  5. package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js +44 -0
  6. package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js.map +1 -1
  7. package/payload/platform/lib/storage-broker/dist/audit.d.ts +56 -0
  8. package/payload/platform/lib/storage-broker/dist/audit.d.ts.map +1 -1
  9. package/payload/platform/lib/storage-broker/dist/audit.js +34 -0
  10. package/payload/platform/lib/storage-broker/dist/audit.js.map +1 -1
  11. package/payload/platform/lib/storage-broker/src/__tests__/audit.test.ts +70 -1
  12. package/payload/platform/lib/storage-broker/src/audit.ts +111 -0
  13. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  14. package/payload/platform/plugins/admin/PLUGIN.md +7 -1
  15. package/payload/platform/plugins/admin/mcp/dist/index.js +72 -0
  16. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  17. package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.d.ts +94 -0
  18. package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.d.ts.map +1 -0
  19. package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.js +229 -0
  20. package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.js.map +1 -0
  21. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
  22. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  23. package/payload/platform/plugins/email/PLUGIN.md +2 -1
  24. package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.d.ts +2 -0
  25. package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.d.ts.map +1 -0
  26. package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.js +92 -0
  27. package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.js.map +1 -0
  28. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js +112 -12
  29. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js.map +1 -1
  30. package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.d.ts +2 -0
  31. package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.d.ts.map +1 -0
  32. package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.js +54 -0
  33. package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.js.map +1 -0
  34. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +170 -1
  35. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
  36. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.d.ts +2 -0
  37. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.d.ts.map +1 -0
  38. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.js +86 -0
  39. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.js.map +1 -0
  40. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.d.ts +2 -0
  41. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.d.ts.map +1 -0
  42. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.js +164 -0
  43. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.js.map +1 -0
  44. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.d.ts +2 -0
  45. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.d.ts.map +1 -0
  46. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.js +82 -0
  47. package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.js.map +1 -0
  48. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +95 -0
  49. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  50. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +223 -0
  51. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  52. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.d.ts +18 -0
  53. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.d.ts.map +1 -0
  54. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.js +59 -0
  55. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.js.map +1 -0
  56. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.d.ts +48 -0
  57. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.d.ts.map +1 -0
  58. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.js +79 -0
  59. package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.js.map +1 -0
  60. package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.d.ts +44 -0
  61. package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.d.ts.map +1 -0
  62. package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.js +63 -0
  63. package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.js.map +1 -0
  64. package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.d.ts +2 -0
  65. package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.d.ts.map +1 -0
  66. package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.js +55 -0
  67. package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.js.map +1 -0
  68. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts.map +1 -1
  69. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js +64 -13
  70. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js.map +1 -1
  71. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
  72. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +11 -1
  73. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
  74. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
  75. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +16 -3
  76. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
  77. package/payload/platform/plugins/email/references/email-reference.md +36 -0
  78. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.d.ts +2 -0
  79. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.d.ts.map +1 -0
  80. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.js +18 -0
  81. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.js.map +1 -0
  82. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.d.ts +2 -0
  83. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.d.ts.map +1 -0
  84. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js +150 -0
  85. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js.map +1 -0
  86. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.d.ts +2 -0
  87. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.d.ts.map +1 -0
  88. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.js +248 -0
  89. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.js.map +1 -0
  90. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +90 -0
  91. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
  92. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +105 -0
  93. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
  94. package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.d.ts +13 -0
  95. package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.d.ts.map +1 -0
  96. package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.js +10 -0
  97. package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.js.map +1 -0
  98. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +53 -0
  99. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  100. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +88 -10
  101. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
  102. package/payload/platform/scripts/cpu-triage-run.sh +117 -0
  103. package/payload/platform/scripts/cpu-triage.sh +332 -0
  104. package/payload/platform/services/claude-session-manager/dist/activity-range.d.ts +40 -0
  105. package/payload/platform/services/claude-session-manager/dist/activity-range.d.ts.map +1 -0
  106. package/payload/platform/services/claude-session-manager/dist/activity-range.js +68 -0
  107. package/payload/platform/services/claude-session-manager/dist/activity-range.js.map +1 -0
  108. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +40 -8
  109. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
  110. package/payload/platform/services/claude-session-manager/dist/activity-rows.js +74 -7
  111. package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
  112. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  113. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
  114. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  115. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  116. package/payload/platform/services/claude-session-manager/dist/http-server.js +9 -0
  117. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  118. package/payload/server/{chunk-56WJMBQQ.js → chunk-3XLLTG6R.js} +14 -0
  119. package/payload/server/{chunk-LBCMFD4O.js → chunk-XGNRSM57.js} +129 -37
  120. package/payload/server/maxy-edge.js +1 -1
  121. package/payload/server/public/activity.html +6 -6
  122. package/payload/server/public/assets/{AdminLoginScreens-DximwPlS.js → AdminLoginScreens-DR5eLF-a.js} +1 -1
  123. package/payload/server/public/assets/AdminShell-D9zaUxPd.js +2 -0
  124. package/payload/server/public/assets/{Checkbox-DM-eHqOS.js → Checkbox-DcbbAIe5.js} +1 -1
  125. package/payload/server/public/assets/activity-C9P5NjEZ.js +1 -0
  126. package/payload/server/public/assets/{admin-CAkDnGdk.js → admin-D2KLZnQW.js} +1 -1
  127. package/payload/server/public/assets/{browser-DXl8hOoi.js → browser-CDWqEiCD.js} +1 -1
  128. package/payload/server/public/assets/{calendar-DP6hn4-6.js → calendar-BG7fOpbB.js} +1 -1
  129. package/payload/server/public/assets/chat-RyH-WYQC.js +1 -0
  130. package/payload/server/public/assets/chevron-left-DmXCr6nB.js +1 -0
  131. package/payload/server/public/assets/data-BaY_LkLR.js +1 -0
  132. package/payload/server/public/assets/{graph-CHcYoEJ5.js → graph-DRloNic4.js} +1 -1
  133. package/payload/server/public/assets/{graph-labels-CZykslZM.js → graph-labels-DD-GqS4v.js} +1 -1
  134. package/payload/server/public/assets/{maximize-2-31AZEcMS.js → maximize-2-CzDaBugs.js} +1 -1
  135. package/payload/server/public/assets/{operator-BGGpdsO_.js → operator-BZeeyait.js} +1 -1
  136. package/payload/server/public/assets/{page-BloC6ygA.js → page-B0obcg3b.js} +1 -1
  137. package/payload/server/public/assets/{page-DOeiiqbR.js → page-ef-6rRPL.js} +1 -1
  138. package/payload/server/public/assets/{public-CGgO6IZv.js → public-9D3MMOkC.js} +1 -1
  139. package/payload/server/public/assets/{rotate-ccw-BlAi6iFg.js → rotate-ccw-DXEKUhXP.js} +1 -1
  140. package/payload/server/public/assets/tasks-BB0L7e5a.js +1 -0
  141. package/payload/server/public/assets/{time-entry-format-CiUUQdq7.js → time-entry-format-CsYAjplS.js} +1 -1
  142. package/payload/server/public/assets/{triangle-alert-CVqKuLoa.js → triangle-alert-0lSBIUg-.js} +1 -1
  143. package/payload/server/public/assets/{useCopyFeedback-ksyUe_g1.js → useCopyFeedback-jTBQ2h0V.js} +1 -1
  144. package/payload/server/public/assets/{useSelectionMode-BPrBkdTd.js → useSelectionMode-BooArySZ.js} +1 -1
  145. package/payload/server/public/assets/useSubAccountSwitcher-D9knHOKq.css +1 -0
  146. package/payload/server/public/assets/{useVoiceRecorder-CTXP8oTW.js → useVoiceRecorder-PUT8q_sm.js} +1 -1
  147. package/payload/server/public/browser.html +5 -5
  148. package/payload/server/public/calendar.html +6 -6
  149. package/payload/server/public/chat.html +12 -12
  150. package/payload/server/public/data.html +11 -11
  151. package/payload/server/public/graph.html +11 -11
  152. package/payload/server/public/index.html +14 -14
  153. package/payload/server/public/operator.html +14 -14
  154. package/payload/server/public/public.html +12 -12
  155. package/payload/server/public/tasks.html +5 -5
  156. package/payload/server/server.js +325 -77
  157. package/payload/server/{src-JYPKMWJR.js → src-XQ63FPRE.js} +3 -1
  158. package/payload/server/public/assets/AdminShell-BehbH-Oa.js +0 -2
  159. package/payload/server/public/assets/activity-hDwUeQd6.js +0 -1
  160. package/payload/server/public/assets/chat-DhOfVGYM.js +0 -1
  161. package/payload/server/public/assets/chevron-left-DYNBoLii.js +0 -1
  162. package/payload/server/public/assets/data-bq8fTo_s.js +0 -1
  163. package/payload/server/public/assets/tasks-C1giFRRL.js +0 -1
  164. package/payload/server/public/assets/useSubAccountSwitcher-K4kYeN6i.css +0 -1
  165. /package/payload/server/public/assets/{useSubAccountSwitcher-DzgzTRRn.js → useSubAccountSwitcher-BZnzc5C3.js} +0 -0
@@ -481,6 +481,19 @@ async function reconcilePages(deps) {
481
481
  phantoms: [...regSet].filter((name) => !cfSet.has(name))
482
482
  };
483
483
  }
484
+ function reconcileDataPortal(objects, rows, nowMs) {
485
+ const objectKeys = new Set(objects.map((o) => o.key));
486
+ const rowKeys = new Set(rows.map((r) => r.objectKey));
487
+ const uningestedMs = rows.filter((r) => r.ingested === 0).map((r) => Date.parse(r.uploadedAt)).filter((ms) => !Number.isNaN(ms));
488
+ const oldestMs = uningestedMs.reduce((min, ms) => ms < min ? ms : min, Infinity);
489
+ return {
490
+ distinctObjects: objectKeys.size,
491
+ distinctRows: rowKeys.size,
492
+ orphanObjects: [...objectKeys].filter((k) => !rowKeys.has(k)),
493
+ phantomRows: [...rowKeys].filter((k) => !objectKeys.has(k)),
494
+ oldestUningestedHrs: uningestedMs.length === 0 ? null : (nowMs - oldestMs) / 36e5
495
+ };
496
+ }
484
497
 
485
498
  // ../lib/storage-broker/src/remediate.ts
486
499
  var STRIP_KEYS = [
@@ -523,6 +536,7 @@ export {
523
536
  makeHousePagesExec,
524
537
  reconcileStorage,
525
538
  reconcilePages,
539
+ reconcileDataPortal,
526
540
  validateMapping,
527
541
  stripAccountWideTokens
528
542
  };
@@ -2658,9 +2658,77 @@ var serve = (options, listeningListener) => {
2658
2658
  };
2659
2659
 
2660
2660
  // server/loop-registry.ts
2661
+ import { readFileSync } from "fs";
2661
2662
  var TAG = "[loop-registry]";
2662
2663
  var STALL_INTERVALS = 3;
2663
2664
  var entries = /* @__PURE__ */ new Map();
2665
+ var defaultCpuIo = {
2666
+ ownCpuUs: () => {
2667
+ const u = process.cpuUsage();
2668
+ return u.user + u.system;
2669
+ },
2670
+ childCpuUs: (pid) => readPidCpuUs(pid)
2671
+ };
2672
+ var cpuIo = defaultCpuIo;
2673
+ function parsePidStatCpuUs(raw2) {
2674
+ const close = raw2.lastIndexOf(")");
2675
+ if (close === -1) return null;
2676
+ const after = raw2.slice(close + 2).split(" ");
2677
+ const utime = Number(after[11]);
2678
+ const stime = Number(after[12]);
2679
+ if (!Number.isFinite(utime) || !Number.isFinite(stime)) return null;
2680
+ return (utime + stime) / 100 * 1e6;
2681
+ }
2682
+ function readPidCpuUs(pid) {
2683
+ if (process.platform !== "linux") return null;
2684
+ try {
2685
+ return parsePidStatCpuUs(readFileSync(`/proc/${pid}/stat`, "utf8"));
2686
+ } catch {
2687
+ return null;
2688
+ }
2689
+ }
2690
+ function sampleCpu(nowMs = Date.now()) {
2691
+ for (const e of entries.values()) {
2692
+ if (!e.cpuAttributable) {
2693
+ e.cpuPct = null;
2694
+ continue;
2695
+ }
2696
+ let childUs = 0;
2697
+ for (const pid of [...e.children]) {
2698
+ const us = cpuIo.childCpuUs(pid);
2699
+ if (us === null) {
2700
+ e.children.delete(pid);
2701
+ continue;
2702
+ }
2703
+ childUs += us;
2704
+ }
2705
+ e.lastChildCpuUs = Math.max(e.lastChildCpuUs, childUs);
2706
+ const totalUs = e.cumulativeCpuUs + e.lastChildCpuUs;
2707
+ const p = e.prior;
2708
+ if (p) {
2709
+ const wallUs = (nowMs - p.atMs) * 1e3;
2710
+ e.cpuPct = wallUs > 0 && totalUs >= p.cpuUs ? (totalUs - p.cpuUs) / wallUs * 100 : null;
2711
+ } else {
2712
+ e.cpuPct = null;
2713
+ }
2714
+ e.prior = { cpuUs: totalUs, atMs: nowMs };
2715
+ }
2716
+ }
2717
+ var processPrior = null;
2718
+ function sampleProcessCpu(nowMs = Date.now()) {
2719
+ const cpuUs = cpuIo.ownCpuUs();
2720
+ let processPct = null;
2721
+ if (processPrior) {
2722
+ const wallUs = (nowMs - processPrior.atMs) * 1e3;
2723
+ if (wallUs > 0) processPct = (cpuUs - processPrior.cpuUs) / wallUs * 100;
2724
+ }
2725
+ processPrior = { cpuUs, atMs: nowMs };
2726
+ const rows = [...entries.values()];
2727
+ const measured = rows.filter((e) => e.cpuPct !== null);
2728
+ const attributedPct = measured.length === 0 ? null : measured.reduce((sum, e) => sum + (e.cpuPct ?? 0), 0);
2729
+ const unattributedPct = processPct === null || attributedPct === null ? null : Math.max(0, processPct - attributedPct);
2730
+ return { processPct, attributedPct, unattributedPct };
2731
+ }
2664
2732
  function messageOf(err) {
2665
2733
  return err instanceof Error ? err.message : String(err);
2666
2734
  }
@@ -2682,6 +2750,7 @@ function finish(e, startedAt, cpuStart, cpuAttributable, note, err) {
2682
2750
  e.lastOutcome = "ok";
2683
2751
  e.lastError = null;
2684
2752
  e.lastNote = typeof note === "string" && note.length > 0 ? note : null;
2753
+ e.lastSuccessMs = Date.now();
2685
2754
  e.successCount += 1;
2686
2755
  e.consecutiveFailures = 0;
2687
2756
  }
@@ -2695,20 +2764,29 @@ function invoke(e) {
2695
2764
  e.lastStartMs = Date.now();
2696
2765
  const startedAt = e.lastStartMs;
2697
2766
  const cpuStart = process.cpuUsage();
2767
+ const ownStartUs = cpuIo.ownCpuUs();
2768
+ const ctx = {
2769
+ child: (pid) => {
2770
+ if (typeof pid === "number" && Number.isFinite(pid)) e.children.add(pid);
2771
+ }
2772
+ };
2698
2773
  let result;
2699
2774
  try {
2700
- result = e.spec.run();
2775
+ result = e.spec.run(ctx);
2701
2776
  } catch (err) {
2777
+ e.cumulativeCpuUs += Math.max(0, cpuIo.ownCpuUs() - ownStartUs);
2702
2778
  finish(e, startedAt, cpuStart, true, null, err);
2703
2779
  return;
2704
2780
  }
2705
2781
  if (result instanceof Promise) {
2782
+ e.cpuAttributable = false;
2706
2783
  result.then(
2707
2784
  (note) => finish(e, startedAt, cpuStart, false, note, null),
2708
2785
  (err) => finish(e, startedAt, cpuStart, false, null, err)
2709
2786
  );
2710
2787
  return;
2711
2788
  }
2789
+ e.cumulativeCpuUs += Math.max(0, cpuIo.ownCpuUs() - ownStartUs);
2712
2790
  finish(e, startedAt, cpuStart, true, result, null);
2713
2791
  }
2714
2792
  function registerLoop(spec) {
@@ -2719,6 +2797,7 @@ function registerLoop(spec) {
2719
2797
  spec,
2720
2798
  armedAtMs: Date.now(),
2721
2799
  lastStartMs: null,
2800
+ lastSuccessMs: null,
2722
2801
  lastDurationMs: null,
2723
2802
  lastCpuMs: null,
2724
2803
  lastOutcome: null,
@@ -2728,7 +2807,13 @@ function registerLoop(spec) {
2728
2807
  successCount: 0,
2729
2808
  consecutiveFailures: 0,
2730
2809
  running: false,
2731
- timers: []
2810
+ timers: [],
2811
+ cumulativeCpuUs: 0,
2812
+ cpuAttributable: true,
2813
+ children: /* @__PURE__ */ new Set(),
2814
+ lastChildCpuUs: 0,
2815
+ prior: null,
2816
+ cpuPct: null
2732
2817
  };
2733
2818
  entries.set(spec.name, e);
2734
2819
  const interval = setInterval(() => invoke(e), spec.intervalMs);
@@ -2754,7 +2839,9 @@ function registerLoop(spec) {
2754
2839
  };
2755
2840
  }
2756
2841
  function stateOf(e, nowMs) {
2757
- if (e.lastStartMs === null) return "never-run";
2842
+ if (e.lastStartMs === null) {
2843
+ return nowMs - e.armedAtMs < e.spec.intervalMs ? "waiting" : "never-run";
2844
+ }
2758
2845
  const overdue = nowMs - e.lastStartMs > e.spec.intervalMs * STALL_INTERVALS;
2759
2846
  if (overdue) return "stalled";
2760
2847
  if (e.running) return "running";
@@ -2774,8 +2861,11 @@ function listLoops(nowMs = Date.now()) {
2774
2861
  detached: e.spec.detached === true,
2775
2862
  armedAtMs: e.armedAtMs,
2776
2863
  lastStartMs: e.lastStartMs,
2864
+ lastSuccessMs: e.lastSuccessMs,
2777
2865
  lastDurationMs: e.lastDurationMs,
2778
2866
  lastCpuMs: e.lastCpuMs,
2867
+ cpuPct: e.cpuPct,
2868
+ cpuAttributable: e.cpuAttributable,
2779
2869
  lastOutcome: e.lastOutcome,
2780
2870
  lastError: e.lastError,
2781
2871
  lastNote: e.lastNote,
@@ -2794,7 +2884,7 @@ function armedCount() {
2794
2884
  // app/lib/paths.ts
2795
2885
  import { homedir } from "os";
2796
2886
  import { resolve, join } from "path";
2797
- import { existsSync, readFileSync } from "fs";
2887
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
2798
2888
  var configDirName = ".maxy";
2799
2889
  var commercialMode = false;
2800
2890
  var bundleMode = "none";
@@ -2810,7 +2900,7 @@ if (platformRoot) {
2810
2900
  if (existsSync(brandPath)) {
2811
2901
  let brand;
2812
2902
  try {
2813
- brand = JSON.parse(readFileSync(brandPath, "utf-8"));
2903
+ brand = JSON.parse(readFileSync2(brandPath, "utf-8"));
2814
2904
  } catch (err) {
2815
2905
  const detail = (err instanceof Error ? err.message : String(err)).slice(0, 160);
2816
2906
  console.error(`[paths] error reason=brand-config-missing path=${brandPath} detail="parse failed: ${detail.replace(/"/g, "'")}"`);
@@ -2926,7 +3016,7 @@ function websockifyLog(event, fields = {}) {
2926
3016
 
2927
3017
  // ../lib/admin-access-password/src/index.ts
2928
3018
  import { scrypt, randomBytes, timingSafeEqual } from "crypto";
2929
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, renameSync, unlinkSync, appendFileSync as appendFileSync2, mkdirSync as mkdirSync2 } from "fs";
3019
+ import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync, renameSync, unlinkSync, appendFileSync as appendFileSync2, mkdirSync as mkdirSync2 } from "fs";
2930
3020
  import { dirname } from "path";
2931
3021
  var SCRYPT_N = 16384;
2932
3022
  var SCRYPT_R = 8;
@@ -2982,7 +3072,7 @@ async function matchesHash(password, stored) {
2982
3072
  }
2983
3073
  function readUsers(usersFile) {
2984
3074
  if (!existsSync2(usersFile)) return [];
2985
- const raw2 = readFileSync2(usersFile, "utf-8").trim();
3075
+ const raw2 = readFileSync3(usersFile, "utf-8").trim();
2986
3076
  if (!raw2) return [];
2987
3077
  const parsed = JSON.parse(raw2);
2988
3078
  if (!Array.isArray(parsed)) throw new Error("users.json is not an array");
@@ -3054,7 +3144,7 @@ function accessStoreUnreadable(usersFile) {
3054
3144
  }
3055
3145
  function migrateLegacyRemotePassword(usersFile, legacyFile, ownerUserId, audit) {
3056
3146
  if (!existsSync2(legacyFile)) return "noop-no-legacy";
3057
- const legacy = readFileSync2(legacyFile, "utf-8").trim();
3147
+ const legacy = readFileSync3(legacyFile, "utf-8").trim();
3058
3148
  const users = readUsers(usersFile);
3059
3149
  const idx = users.findIndex((u) => u.userId === ownerUserId);
3060
3150
  if (idx === -1) return "noop-no-owner";
@@ -3076,7 +3166,7 @@ function migrateLegacyRemotePassword(usersFile, legacyFile, ownerUserId, audit)
3076
3166
  }
3077
3167
  function readLegacyRemoteHash(legacyFile) {
3078
3168
  if (!existsSync2(legacyFile)) return null;
3079
- const raw2 = readFileSync2(legacyFile, "utf-8").trim();
3169
+ const raw2 = readFileSync3(legacyFile, "utf-8").trim();
3080
3170
  return raw2.includes(":") ? raw2 : null;
3081
3171
  }
3082
3172
 
@@ -3095,7 +3185,7 @@ function isPasswordValid(password) {
3095
3185
 
3096
3186
  // app/lib/remote-auth.ts
3097
3187
  import { scrypt as scrypt2, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2, createHmac } from "crypto";
3098
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
3188
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
3099
3189
  import { dirname as dirname2 } from "path";
3100
3190
  var SCRYPT_N2 = 16384;
3101
3191
  var SCRYPT_R2 = 8;
@@ -3141,7 +3231,7 @@ var cachedSecret = null;
3141
3231
  function getSecret() {
3142
3232
  if (cachedSecret) return cachedSecret;
3143
3233
  try {
3144
- const hex2 = readFileSync3(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
3234
+ const hex2 = readFileSync4(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
3145
3235
  if (hex2.length === SECRET_BYTES * 2) {
3146
3236
  cachedSecret = Buffer.from(hex2, "hex");
3147
3237
  return cachedSecret;
@@ -3154,7 +3244,7 @@ function getSecret() {
3154
3244
  writeFileSync2(REMOTE_SESSION_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
3155
3245
  } catch {
3156
3246
  }
3157
- const hex = readFileSync3(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
3247
+ const hex = readFileSync4(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
3158
3248
  cachedSecret = Buffer.from(hex, "hex");
3159
3249
  return cachedSecret;
3160
3250
  }
@@ -3819,13 +3909,13 @@ function classifyHost(host, operatorDomains2, isPublicHost) {
3819
3909
  import { watchFile } from "fs";
3820
3910
 
3821
3911
  // app/lib/operator-domains.ts
3822
- import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
3912
+ import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
3823
3913
  import { dirname as dirname3, resolve as resolve3 } from "path";
3824
3914
  var OPERATOR_DOMAINS_PATH = resolve3(MAXY_DIR, "operator-domains.json");
3825
3915
  function loadOperatorDomains() {
3826
3916
  if (!existsSync3(OPERATOR_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
3827
3917
  try {
3828
- const parsed = JSON.parse(readFileSync4(OPERATOR_DOMAINS_PATH, "utf-8"));
3918
+ const parsed = JSON.parse(readFileSync5(OPERATOR_DOMAINS_PATH, "utf-8"));
3829
3919
  if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
3830
3920
  return new Set(parsed.filter((h) => typeof h === "string"));
3831
3921
  } catch {
@@ -3852,11 +3942,11 @@ function getOperatorDomains() {
3852
3942
 
3853
3943
  // app/lib/claude-agent/account.ts
3854
3944
  import { resolve as resolve4 } from "path";
3855
- import { readFileSync as readFileSync6, readdirSync, existsSync as existsSync5, statSync } from "fs";
3945
+ import { readFileSync as readFileSync7, readdirSync, existsSync as existsSync5, statSync } from "fs";
3856
3946
 
3857
3947
  // ../lib/brand-templating/src/index.ts
3858
3948
  import { join as join2 } from "path";
3859
- import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
3949
+ import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
3860
3950
  var PLACEHOLDER = "{{productName}}";
3861
3951
  var cachedProductName = null;
3862
3952
  function brandJsonPath() {
@@ -3876,7 +3966,7 @@ function getBrandProductName() {
3876
3966
  }
3877
3967
  let parsed;
3878
3968
  try {
3879
- parsed = JSON.parse(readFileSync5(path, "utf-8"));
3969
+ parsed = JSON.parse(readFileSync6(path, "utf-8"));
3880
3970
  } catch (err) {
3881
3971
  throw new Error(
3882
3972
  `[skill-loader] brand.json unreadable at ${path}: ${err instanceof Error ? err.message : String(err)}`
@@ -3940,7 +4030,7 @@ function listValidAccounts() {
3940
4030
  }
3941
4031
  let config;
3942
4032
  try {
3943
- config = JSON.parse(readFileSync6(configPath, "utf-8"));
4033
+ config = JSON.parse(readFileSync7(configPath, "utf-8"));
3944
4034
  } catch {
3945
4035
  console.error(
3946
4036
  `[platform] accounts-state CORRUPT-JSON id=${entry.name} \u2014 account.json failed to parse; treating as stub`
@@ -3959,7 +4049,7 @@ function resolveAccount() {
3959
4049
  let usersJsonUserId = null;
3960
4050
  if (existsSync5(USERS_FILE)) {
3961
4051
  try {
3962
- const raw2 = readFileSync6(USERS_FILE, "utf-8").trim();
4052
+ const raw2 = readFileSync7(USERS_FILE, "utf-8").trim();
3963
4053
  if (raw2) {
3964
4054
  const users = JSON.parse(raw2);
3965
4055
  if (users.length > 0) {
@@ -3975,7 +4065,7 @@ function resolveAccount() {
3975
4065
  if (!entry.isDirectory()) continue;
3976
4066
  const configPath = resolve4(ACCOUNTS_DIR, entry.name, "account.json");
3977
4067
  if (!existsSync5(configPath)) continue;
3978
- const raw2 = readFileSync6(configPath, "utf-8");
4068
+ const raw2 = readFileSync7(configPath, "utf-8");
3979
4069
  let config;
3980
4070
  try {
3981
4071
  config = JSON.parse(raw2);
@@ -4010,7 +4100,7 @@ function resolveAccount() {
4010
4100
  function readAgentFile(accountDir, agentName, filename) {
4011
4101
  const filePath = resolve4(accountDir, "agents", agentName, filename);
4012
4102
  if (!existsSync5(filePath)) return null;
4013
- const raw2 = readFileSync6(filePath, "utf-8");
4103
+ const raw2 = readFileSync7(filePath, "utf-8");
4014
4104
  if (filename.endsWith(".md")) {
4015
4105
  return substituteBrandPlaceholders(raw2, filePath);
4016
4106
  }
@@ -4039,7 +4129,7 @@ function resolveDefaultAgentSlug(accountDir) {
4039
4129
  }
4040
4130
  let config;
4041
4131
  try {
4042
- config = JSON.parse(readFileSync6(configPath, "utf-8"));
4132
+ config = JSON.parse(readFileSync7(configPath, "utf-8"));
4043
4133
  } catch (err) {
4044
4134
  console.error("[agent-resolve] failed to read account.json:", err);
4045
4135
  return null;
@@ -4114,14 +4204,14 @@ function resolveAgentConfig(accountDir, agentName) {
4114
4204
  const knowledgeMtime = statSync(knowledgePath).mtimeMs;
4115
4205
  const summaryMtime = statSync(summaryPath).mtimeMs;
4116
4206
  if (summaryMtime >= knowledgeMtime) {
4117
- knowledge = readFileSync6(summaryPath, "utf-8");
4207
+ knowledge = readFileSync7(summaryPath, "utf-8");
4118
4208
  } else {
4119
4209
  console.warn(`[agent-config] ${agentName}: KNOWLEDGE-SUMMARY.md is stale (KNOWLEDGE.md is newer) \u2014 using full knowledge`);
4120
- knowledge = readFileSync6(knowledgePath, "utf-8");
4210
+ knowledge = readFileSync7(knowledgePath, "utf-8");
4121
4211
  }
4122
4212
  knowledgeBaked = true;
4123
4213
  } else if (hasKnowledge) {
4124
- knowledge = readFileSync6(knowledgePath, "utf-8");
4214
+ knowledge = readFileSync7(knowledgePath, "utf-8");
4125
4215
  knowledgeBaked = true;
4126
4216
  }
4127
4217
  let budget = null;
@@ -4215,7 +4305,7 @@ function getSessionKeyBySessionId(_sessionId) {
4215
4305
  // app/lib/claude-agent/plugin-manifest.ts
4216
4306
  import { resolve as resolve5, join as join3 } from "path";
4217
4307
  import {
4218
- readFileSync as readFileSync7,
4308
+ readFileSync as readFileSync8,
4219
4309
  writeFileSync as writeFileSync4,
4220
4310
  readdirSync as readdirSync2,
4221
4311
  existsSync as existsSync6,
@@ -4237,7 +4327,7 @@ function readBundleSubPlugins(bundlePath) {
4237
4327
  if (!existsSync6(bundlePath)) return [];
4238
4328
  let raw2;
4239
4329
  try {
4240
- raw2 = readFileSync7(bundlePath, "utf-8");
4330
+ raw2 = readFileSync8(bundlePath, "utf-8");
4241
4331
  } catch {
4242
4332
  return [];
4243
4333
  }
@@ -4310,8 +4400,8 @@ function reapDuplicateFlatPremiumSubs(bundles, stagingRoot, pluginsDir) {
4310
4400
  const flatDir = resolve5(pluginsDir, sub);
4311
4401
  const flatManifest = resolve5(flatDir, "PLUGIN.md");
4312
4402
  if (!existsSync6(premiumManifest) || !existsSync6(flatManifest)) continue;
4313
- const premiumSha = createHash2("sha256").update(readFileSync7(premiumManifest)).digest("hex");
4314
- const flatSha = createHash2("sha256").update(readFileSync7(flatManifest)).digest("hex");
4403
+ const premiumSha = createHash2("sha256").update(readFileSync8(premiumManifest)).digest("hex");
4404
+ const flatSha = createHash2("sha256").update(readFileSync8(flatManifest)).digest("hex");
4315
4405
  if (isBundle) {
4316
4406
  if (premiumSha === flatSha) {
4317
4407
  try {
@@ -4373,7 +4463,7 @@ function reconcileEnabledPlugins(accountDir, config, accountId) {
4373
4463
  const merged = [...currentSet];
4374
4464
  const configPath = resolve5(accountDir, "account.json");
4375
4465
  try {
4376
- const raw2 = readFileSync7(configPath, "utf-8");
4466
+ const raw2 = readFileSync8(configPath, "utf-8");
4377
4467
  const parsed = JSON.parse(raw2);
4378
4468
  parsed.enabledPlugins = merged;
4379
4469
  writeFileSync4(configPath, JSON.stringify(parsed, null, 2) + "\n");
@@ -4409,7 +4499,7 @@ function cleanupLeakedPremiumSubs(accountDir, config, accountId) {
4409
4499
  if (removed.length === 0) return;
4410
4500
  const configPath = resolve5(accountDir, "account.json");
4411
4501
  try {
4412
- const raw2 = readFileSync7(configPath, "utf-8");
4502
+ const raw2 = readFileSync8(configPath, "utf-8");
4413
4503
  const parsed = JSON.parse(raw2);
4414
4504
  parsed.enabledPlugins = kept;
4415
4505
  writeFileSync4(configPath, JSON.stringify(parsed, null, 2) + "\n");
@@ -4460,7 +4550,7 @@ function requirePortEnv(envName, options = {}) {
4460
4550
  // app/lib/neo4j-store.ts
4461
4551
  import neo4j from "neo4j-driver";
4462
4552
  import { randomUUID } from "crypto";
4463
- import { readFileSync as readFileSync8, readdirSync as readdirSync3, existsSync as existsSync7, openSync, readSync, closeSync, statSync as statSync3 } from "fs";
4553
+ import { readFileSync as readFileSync9, readdirSync as readdirSync3, existsSync as existsSync7, openSync, readSync, closeSync, statSync as statSync3 } from "fs";
4464
4554
  import { resolve as resolve6 } from "path";
4465
4555
  var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "..");
4466
4556
  var driver = null;
@@ -4468,7 +4558,7 @@ function readPassword() {
4468
4558
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
4469
4559
  const passwordFile = resolve6(PLATFORM_ROOT3, "config/.neo4j-password");
4470
4560
  try {
4471
- return readFileSync8(passwordFile, "utf-8").trim();
4561
+ return readFileSync9(passwordFile, "utf-8").trim();
4472
4562
  } catch {
4473
4563
  throw new Error(
4474
4564
  `Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
@@ -5585,7 +5675,7 @@ function loadEnabledPluginProfileKeys(accountId) {
5585
5675
  if (!existsSync7(accountFile)) return {};
5586
5676
  let enabled;
5587
5677
  try {
5588
- const raw2 = readFileSync8(accountFile, "utf-8");
5678
+ const raw2 = readFileSync9(accountFile, "utf-8");
5589
5679
  const parsed = JSON.parse(raw2);
5590
5680
  enabled = Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : [];
5591
5681
  } catch (err) {
@@ -5600,7 +5690,7 @@ function loadEnabledPluginProfileKeys(accountId) {
5600
5690
  if (!existsSync7(manifestPath)) continue;
5601
5691
  let manifest;
5602
5692
  try {
5603
- manifest = readFileSync8(manifestPath, "utf-8");
5693
+ manifest = readFileSync9(manifestPath, "utf-8");
5604
5694
  } catch {
5605
5695
  continue;
5606
5696
  }
@@ -5858,11 +5948,11 @@ async function projectAgent(accountId, accountDir, slug) {
5858
5948
  );
5859
5949
  return;
5860
5950
  }
5861
- config = JSON.parse(readFileSync8(configPath, "utf-8"));
5951
+ config = JSON.parse(readFileSync9(configPath, "utf-8"));
5862
5952
  for (const { filename, role } of AGENT_FILE_ROLES) {
5863
5953
  const filePath = resolve6(agentDir, filename);
5864
5954
  if (!existsSync7(filePath)) continue;
5865
- const body = readFileSync8(filePath, "utf-8");
5955
+ const body = readFileSync9(filePath, "utf-8");
5866
5956
  presentRoles.push({ role, body, edge: ROLE_TO_EDGE[role] });
5867
5957
  }
5868
5958
  } catch (err) {
@@ -6112,6 +6202,8 @@ export {
6112
6202
  Hono2 as Hono,
6113
6203
  getRequestListener,
6114
6204
  serve,
6205
+ sampleCpu,
6206
+ sampleProcessCpu,
6115
6207
  registerLoop,
6116
6208
  listLoops,
6117
6209
  armedCount,
@@ -16,7 +16,7 @@ import {
16
16
  sanitizeClientCorrId,
17
17
  vncLog,
18
18
  websockifyLog
19
- } from "./chunk-LBCMFD4O.js";
19
+ } from "./chunk-XGNRSM57.js";
20
20
  import "./chunk-PFF6I7KP.js";
21
21
 
22
22
  // server/edge.ts
@@ -5,13 +5,13 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Activity — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/activity-hDwUeQd6.js"></script>
8
+ <script type="module" crossorigin src="/assets/activity-C9P5NjEZ.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-TPjIAO9U.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-DzgzTRRn.js">
11
- <link rel="modulepreload" crossorigin href="/assets/useSelectionMode-BPrBkdTd.js">
12
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-BehbH-Oa.js">
13
- <link rel="modulepreload" crossorigin href="/assets/triangle-alert-CVqKuLoa.js">
14
- <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-K4kYeN6i.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-BZnzc5C3.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/useSelectionMode-BooArySZ.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-D9zaUxPd.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/triangle-alert-0lSBIUg-.js">
14
+ <link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-D9knHOKq.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -1 +1 @@
1
- import{o as e}from"./chunk-TPjIAO9U.js";import{C as t,D as n,S as r,b as i,v as a}from"./useSubAccountSwitcher-DzgzTRRn.js";import{E as o}from"./useVoiceRecorder-CTXP8oTW.js";import{v as s,y as c}from"./AdminShell-BehbH-Oa.js";import{t as l}from"./Checkbox-DM-eHqOS.js";var u=`admin-landing-redirected`,d=`/graph`;function f(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var p=e(n(),1);function m(e=`admin`){let[n,r]=(0,p.useState)(`loading`),[i,a]=(0,p.useState)(``),[s,l]=(0,p.useState)(``),[m,h]=(0,p.useState)(``),[g,_]=(0,p.useState)(!1),[v,y]=(0,p.useState)(!1),[b,x]=(0,p.useState)(!1),[S,C]=(0,p.useState)(!1),[w,T]=(0,p.useState)(!1),[E,D]=(0,p.useState)(null),[O,k]=(0,p.useState)(null),[A,j]=(0,p.useState)(void 0),[M,N]=(0,p.useState)(null),[P,F]=(0,p.useState)(void 0),[I,L]=(0,p.useState)(null),[R,z]=(0,p.useState)(null),[B,V]=(0,p.useState)(void 0),H=(0,p.useRef)(void 0),[U,W]=(0,p.useState)(!1),[G,K]=(0,p.useState)(!0);(0,p.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&W(!0)}).catch(()=>{})},[]);let q=(0,p.useRef)(null),J=(0,p.useRef)(null);(0,p.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let n=await t.json();D(n.session_key),z(n.sessionId??null),j(n.businessName),N(n.role??null),F(n.userName===void 0?null:n.userName),L(n.avatar??null);let i=o(n.thinkingView);return H.current=i,V(i),r(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(n=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check returned ${i.status} after retries`),r(`set-pin`);return}let a=await i.json();if(!a.pin_configured){r(`set-pin`);return}K(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}if(!a.claude_authenticated){r(`connect-claude`);return}}if(await e())return;r(`enter-pin`)}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check failed:`,e),r(`set-pin`)}}t()},[]),(0,p.useEffect)(()=>{n===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[n]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let t=!1;try{t=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:n,alreadyRedirected:t,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[n,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(n!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();K(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let n=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(n===`remote-auth-required`){t(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${n}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[n,E]),(0,p.useEffect)(()=>{n===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),r(`enter-pin`))}).catch(()=>{})},[n]);async function X(e,n){y(!0);try{let i=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...n?{accountId:n}:{}})});if(!i.ok){let e=await i.json().catch(()=>({}));if(i.status===401&&e?.code===`remote-auth-required`){t(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await i.json();D(s.session_key),z(s.sessionId??null),j(s.businessName),N(s.role??null),F(s.userName===void 0?null:s.userName),L(s.avatar??null);let c=o(s.thinkingView);H.current=c,V(c);try{sessionStorage.setItem(`maxy-admin-session-key`,s.session_key)}catch{}a(``),r(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}}let Z=(0,p.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let n=s.trim();if(!n){h(`Please enter your name.`);return}if(i.length<4){h(`PIN must be at least 4 characters.`);return}let o=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:n})});if(!e.ok){let n=await e.json().catch(()=>({}));if(e.status===401&&n?.code===`remote-auth-required`){t(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();t.pin_configured&&t.claude_authenticated?r(`enter-pin`):t.pin_configured?r(`connect-claude`):h(n.error||`Failed to set PIN.`)}else r(`enter-pin`)}catch{r(`enter-pin`)}return}h(n.error||`Failed to set PIN.`);return}let i=await fetch(`/api/health`);if((i.ok?await i.json():null)?.claude_authenticated){await X(o);return}a(``),r(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[i,v,s]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(i)},[i]),ee=(0,p.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;K(!1),D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}return r(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,p.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}a(``),h(``),r(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:n,setAppState:r,pin:i,setPin:a,operatorName:s,setOperatorName:l,pinError:m,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:R,setSessionId:z,expandAll:B,setExpandAll:V,expandAllDefaultRef:H,remoteAuthEnabled:U,claudeConnected:G,pinInputRef:q,setPinFormRef:J,handleSetPin:Z,handleLogin:Q,handleDisconnect:ee,handleLogout:$}}var h=r();function g({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,p.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,h.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,h.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function _(e){let{pin:t,setPin:n,showPin:r,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:_}=e;return(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,a.productName]}),(0,h.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,a.productName,` who you are, then choose a PIN.`]}),(0,h.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,h.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!t||!m.trim(),loading:c,"aria-label":`Set PIN`,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(l,{checked:r,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:t,setPin:n,showPin:r,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:m}=e;return(0,h.jsxs)(`div`,{className:`connect-page`,children:[p&&m&&(0,h.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:m,children:`Sign out`}),(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`h1`,{className:`connect-title`,children:a.productName}),(0,h.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r,autoFocus:!0}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!t,loading:c,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(`div`,{className:`pin-options`,children:(0,h.jsx)(l,{checked:r,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:t,setAuthPolling:n,authLoading:r,setAuthLoading:o,pinError:c,setPinError:l,setAppState:u}=e,[d,f]=(0,p.useState)(!1),[m,g]=(0,p.useState)(!1),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(``);async function C(){S(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:y})})).json();e.accepted?(S(`Code submitted. Finishing sign-in…`),b(``)):S(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),S(`Could not submit code.`)}}async function w(){g(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}g(!1)}async function T(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){n(!0),f(!0),o(!1),v(e.transport||``);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function E(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!1),l(``)}return t||d?(0,h.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,h.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[t?(0,h.jsx)(`button`,{onClick:E,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,h.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,h.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,h.jsx)(`p`,{className:`chat-intro`,children:t?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!t&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:r,children:r?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),t&&_===`native`&&(0,h.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,h.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,h.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,h.jsx)(`input`,{type:`text`,value:y,onChange:e=>b(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,h.jsx)(s,{variant:`primary`,onClick:C,disabled:!y.trim(),children:`Submit`})]}),x&&(0,h.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:x})]})]}),(0,h.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,h.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:c})]}):(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsxs)(`div`,{className:`connect-logos`,children:[(0,h.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,h.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,h.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,h.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`span`,{className:`connect-logo-label`,children:a.productName})]})]}),(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,a.productName]}),(0,h.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:r,children:r?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,h.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,h.jsx)(`button`,{onClick:w,disabled:m,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:m?`Launching…`:`Open browser first`}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function b({auth:e}){return e.appState===`loading`?(0,h.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,h.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,h.jsx)(y,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,h.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):null}export{m as n,b as t};
1
+ import{o as e}from"./chunk-TPjIAO9U.js";import{C as t,D as n,S as r,b as i,v as a}from"./useSubAccountSwitcher-BZnzc5C3.js";import{E as o}from"./useVoiceRecorder-PUT8q_sm.js";import{v as s,y as c}from"./AdminShell-D9zaUxPd.js";import{t as l}from"./Checkbox-DcbbAIe5.js";var u=`admin-landing-redirected`,d=`/graph`;function f(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var p=e(n(),1);function m(e=`admin`){let[n,r]=(0,p.useState)(`loading`),[i,a]=(0,p.useState)(``),[s,l]=(0,p.useState)(``),[m,h]=(0,p.useState)(``),[g,_]=(0,p.useState)(!1),[v,y]=(0,p.useState)(!1),[b,x]=(0,p.useState)(!1),[S,C]=(0,p.useState)(!1),[w,T]=(0,p.useState)(!1),[E,D]=(0,p.useState)(null),[O,k]=(0,p.useState)(null),[A,j]=(0,p.useState)(void 0),[M,N]=(0,p.useState)(null),[P,F]=(0,p.useState)(void 0),[I,L]=(0,p.useState)(null),[R,z]=(0,p.useState)(null),[B,V]=(0,p.useState)(void 0),H=(0,p.useRef)(void 0),[U,W]=(0,p.useState)(!1),[G,K]=(0,p.useState)(!0);(0,p.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&W(!0)}).catch(()=>{})},[]);let q=(0,p.useRef)(null),J=(0,p.useRef)(null);(0,p.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let n=await t.json();D(n.session_key),z(n.sessionId??null),j(n.businessName),N(n.role??null),F(n.userName===void 0?null:n.userName),L(n.avatar??null);let i=o(n.thinkingView);return H.current=i,V(i),r(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(n=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check returned ${i.status} after retries`),r(`set-pin`);return}let a=await i.json();if(!a.pin_configured){r(`set-pin`);return}K(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}if(!a.claude_authenticated){r(`connect-claude`);return}}if(await e())return;r(`enter-pin`)}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check failed:`,e),r(`set-pin`)}}t()},[]),(0,p.useEffect)(()=>{n===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[n]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let t=!1;try{t=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:n,alreadyRedirected:t,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[n,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(n!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();K(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let n=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(n===`remote-auth-required`){t(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${n}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[n,E]),(0,p.useEffect)(()=>{n===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),r(`enter-pin`))}).catch(()=>{})},[n]);async function X(e,n){y(!0);try{let i=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...n?{accountId:n}:{}})});if(!i.ok){let e=await i.json().catch(()=>({}));if(i.status===401&&e?.code===`remote-auth-required`){t(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await i.json();D(s.session_key),z(s.sessionId??null),j(s.businessName),N(s.role??null),F(s.userName===void 0?null:s.userName),L(s.avatar??null);let c=o(s.thinkingView);H.current=c,V(c);try{sessionStorage.setItem(`maxy-admin-session-key`,s.session_key)}catch{}a(``),r(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}}let Z=(0,p.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let n=s.trim();if(!n){h(`Please enter your name.`);return}if(i.length<4){h(`PIN must be at least 4 characters.`);return}let o=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:n})});if(!e.ok){let n=await e.json().catch(()=>({}));if(e.status===401&&n?.code===`remote-auth-required`){t(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();t.pin_configured&&t.claude_authenticated?r(`enter-pin`):t.pin_configured?r(`connect-claude`):h(n.error||`Failed to set PIN.`)}else r(`enter-pin`)}catch{r(`enter-pin`)}return}h(n.error||`Failed to set PIN.`);return}let i=await fetch(`/api/health`);if((i.ok?await i.json():null)?.claude_authenticated){await X(o);return}a(``),r(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[i,v,s]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(i)},[i]),ee=(0,p.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;K(!1),D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}return r(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,p.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}a(``),h(``),r(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:n,setAppState:r,pin:i,setPin:a,operatorName:s,setOperatorName:l,pinError:m,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:R,setSessionId:z,expandAll:B,setExpandAll:V,expandAllDefaultRef:H,remoteAuthEnabled:U,claudeConnected:G,pinInputRef:q,setPinFormRef:J,handleSetPin:Z,handleLogin:Q,handleDisconnect:ee,handleLogout:$}}var h=r();function g({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,p.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,h.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,h.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function _(e){let{pin:t,setPin:n,showPin:r,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:_}=e;return(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,a.productName]}),(0,h.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,a.productName,` who you are, then choose a PIN.`]}),(0,h.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,h.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!t||!m.trim(),loading:c,"aria-label":`Set PIN`,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(l,{checked:r,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:t,setPin:n,showPin:r,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:m}=e;return(0,h.jsxs)(`div`,{className:`connect-page`,children:[p&&m&&(0,h.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:m,children:`Sign out`}),(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`h1`,{className:`connect-title`,children:a.productName}),(0,h.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r,autoFocus:!0}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!t,loading:c,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(`div`,{className:`pin-options`,children:(0,h.jsx)(l,{checked:r,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:t,setAuthPolling:n,authLoading:r,setAuthLoading:o,pinError:c,setPinError:l,setAppState:u}=e,[d,f]=(0,p.useState)(!1),[m,g]=(0,p.useState)(!1),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(``);async function C(){S(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:y})})).json();e.accepted?(S(`Code submitted. Finishing sign-in…`),b(``)):S(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),S(`Could not submit code.`)}}async function w(){g(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}g(!1)}async function T(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){n(!0),f(!0),o(!1),v(e.transport||``);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function E(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!1),l(``)}return t||d?(0,h.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,h.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[t?(0,h.jsx)(`button`,{onClick:E,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,h.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,h.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,h.jsx)(`p`,{className:`chat-intro`,children:t?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!t&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:r,children:r?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),t&&_===`native`&&(0,h.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,h.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,h.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,h.jsx)(`input`,{type:`text`,value:y,onChange:e=>b(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,h.jsx)(s,{variant:`primary`,onClick:C,disabled:!y.trim(),children:`Submit`})]}),x&&(0,h.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:x})]})]}),(0,h.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,h.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:c})]}):(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsxs)(`div`,{className:`connect-logos`,children:[(0,h.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,h.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,h.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,h.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,h.jsx)(`img`,{src:i,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`span`,{className:`connect-logo-label`,children:a.productName})]})]}),(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,a.productName]}),(0,h.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:r,children:r?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,h.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,h.jsx)(`button`,{onClick:w,disabled:m,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:m?`Launching…`:`Open browser first`}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function b({auth:e}){return e.appState===`loading`?(0,h.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,h.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,h.jsx)(y,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,h.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):null}export{m as n,b as t};