@rubytech/create-maxy-code 0.1.562 → 0.1.563

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 (185) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +19 -11
  3. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  4. package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +19 -5
  5. package/payload/platform/plugins/cloudflare/mcp/__tests__/authorize.test.ts +6 -0
  6. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +77 -6
  7. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-session-grant.test.ts +39 -0
  8. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-visit-status-write.test.ts +176 -0
  9. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-visits-scope.test.ts +112 -0
  10. package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +23 -0
  11. package/payload/platform/plugins/cloudflare/skills/data-portal/schema.sql +94 -0
  12. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/session.ts +31 -4
  13. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/visit-status.ts +136 -0
  14. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/visits.ts +93 -0
  15. package/payload/platform/plugins/docs/references/deployment.md +14 -8
  16. package/payload/platform/plugins/docs/references/platform.md +4 -2
  17. package/payload/platform/templates/agents/public/IDENTITY.md +3 -3
  18. package/payload/server/maxy-edge.js +302 -33
  19. package/payload/server/public/activity.html +5 -5
  20. package/payload/server/public/agents.html +4 -4
  21. package/payload/server/public/assets/{AdminLoginScreens-DLogIsJT.js → AdminLoginScreens-C6e5jf0S.js} +1 -1
  22. package/payload/server/public/assets/AdminLoginScreens-C6e5jf0S.js.br +0 -0
  23. package/payload/server/public/assets/AdminLoginScreens-C6e5jf0S.js.gz +0 -0
  24. package/payload/server/public/assets/AdminShell-DStA0lfm.js +3 -0
  25. package/payload/server/public/assets/AdminShell-DStA0lfm.js.br +0 -0
  26. package/payload/server/public/assets/AdminShell-DStA0lfm.js.gz +0 -0
  27. package/payload/server/public/assets/{activity-AVJSFESV.js → activity--yyBcNfB.js} +1 -1
  28. package/payload/server/public/assets/activity--yyBcNfB.js.br +0 -0
  29. package/payload/server/public/assets/activity--yyBcNfB.js.gz +0 -0
  30. package/payload/server/public/assets/{admin-eFgbld42.js → admin-Dr6Jwe7W.js} +1 -1
  31. package/payload/server/public/assets/admin-Dr6Jwe7W.js.br +0 -0
  32. package/payload/server/public/assets/admin-Dr6Jwe7W.js.gz +0 -0
  33. package/payload/server/public/assets/{agents-CoWLZMf7.js → agents-odyVOb5E.js} +1 -1
  34. package/payload/server/public/assets/agents-odyVOb5E.js.br +0 -0
  35. package/payload/server/public/assets/agents-odyVOb5E.js.gz +0 -0
  36. package/payload/server/public/assets/{browser-C6K66_fw.js → browser-D1K_MoHt.js} +1 -1
  37. package/payload/server/public/assets/browser-D1K_MoHt.js.br +0 -0
  38. package/payload/server/public/assets/browser-D1K_MoHt.js.gz +0 -0
  39. package/payload/server/public/assets/{calendar-Dnw_cP4b.js → calendar-jqh9U7Ic.js} +1 -1
  40. package/payload/server/public/assets/calendar-jqh9U7Ic.js.br +0 -0
  41. package/payload/server/public/assets/calendar-jqh9U7Ic.js.gz +0 -0
  42. package/payload/server/public/assets/chat-QQHBdVor.js +1 -0
  43. package/payload/server/public/assets/chat-QQHBdVor.js.br +0 -0
  44. package/payload/server/public/assets/chat-QQHBdVor.js.gz +0 -0
  45. package/payload/server/public/assets/chevron-left-DwTXgKwr.js +1 -0
  46. package/payload/server/public/assets/clock-DOmh9iKX.js +1 -0
  47. package/payload/server/public/assets/clock-DOmh9iKX.js.br +0 -0
  48. package/payload/server/public/assets/{copy-kuNM0Etw.js → copy-DkuHwkaB.js} +1 -1
  49. package/payload/server/public/assets/copy-DkuHwkaB.js.br +0 -0
  50. package/payload/server/public/assets/copy-DkuHwkaB.js.gz +0 -0
  51. package/payload/server/public/assets/data-DYmTNqrb.js +1 -0
  52. package/payload/server/public/assets/data-DYmTNqrb.js.br +0 -0
  53. package/payload/server/public/assets/data-DYmTNqrb.js.gz +0 -0
  54. package/payload/server/public/assets/{file-text-BWkobrcx.js → file-text-C6o_NRjj.js} +1 -1
  55. package/payload/server/public/assets/file-text-C6o_NRjj.js.br +0 -0
  56. package/payload/server/public/assets/file-text-C6o_NRjj.js.gz +0 -0
  57. package/payload/server/public/assets/{graph-BGjTL5Vz.js → graph-BN30v5hJ.js} +1 -1
  58. package/payload/server/public/assets/graph-BN30v5hJ.js.br +0 -0
  59. package/payload/server/public/assets/graph-BN30v5hJ.js.gz +0 -0
  60. package/payload/server/public/assets/{graph-labels-Dvc5Kw_r.js → graph-labels-DHFyNXQt.js} +1 -1
  61. package/payload/server/public/assets/graph-labels-DHFyNXQt.js.br +0 -0
  62. package/payload/server/public/assets/graph-labels-DHFyNXQt.js.gz +0 -0
  63. package/payload/server/public/assets/{operator-CzBGv_he.js → operator-DwFYA4Fp.js} +1 -1
  64. package/payload/server/public/assets/operator-DwFYA4Fp.js.br +0 -0
  65. package/payload/server/public/assets/operator-DwFYA4Fp.js.gz +0 -0
  66. package/payload/server/public/assets/{page-DaySqamH.js → page-BALVRssF.js} +1 -1
  67. package/payload/server/public/assets/page-BALVRssF.js.br +0 -0
  68. package/payload/server/public/assets/page-BALVRssF.js.gz +0 -0
  69. package/payload/server/public/assets/{page-BIY4Ku8Q.js → page-CEWIP3VF.js} +1 -1
  70. package/payload/server/public/assets/page-CEWIP3VF.js.br +0 -0
  71. package/payload/server/public/assets/page-CEWIP3VF.js.gz +0 -0
  72. package/payload/server/public/assets/play-Bg-BY_oj.js +1 -0
  73. package/payload/server/public/assets/play-Bg-BY_oj.js.br +0 -0
  74. package/payload/server/public/assets/play-Bg-BY_oj.js.gz +0 -0
  75. package/payload/server/public/assets/{public-pwDSvhBv.js → public-Ceb0n7Km.js} +1 -1
  76. package/payload/server/public/assets/public-Ceb0n7Km.js.br +0 -0
  77. package/payload/server/public/assets/public-Ceb0n7Km.js.gz +0 -0
  78. package/payload/server/public/assets/{rotate-ccw-B6s7tkEt.js → rotate-ccw-CDYdx91V.js} +1 -1
  79. package/payload/server/public/assets/rotate-ccw-CDYdx91V.js.gz +0 -0
  80. package/payload/server/public/assets/{routines-CFlyRdYg.js → routines-DwNTih0y.js} +1 -1
  81. package/payload/server/public/assets/routines-DwNTih0y.js.br +0 -0
  82. package/payload/server/public/assets/routines-DwNTih0y.js.gz +0 -0
  83. package/payload/server/public/assets/{skills-C45kfL_Q.js → skills-TIDCdOLQ.js} +1 -1
  84. package/payload/server/public/assets/skills-TIDCdOLQ.js.br +0 -0
  85. package/payload/server/public/assets/skills-TIDCdOLQ.js.gz +0 -0
  86. package/payload/server/public/assets/{tasks-BwoCTCu5.js → tasks-eTXvaWnd.js} +1 -1
  87. package/payload/server/public/assets/tasks-eTXvaWnd.js.br +0 -0
  88. package/payload/server/public/assets/tasks-eTXvaWnd.js.gz +0 -0
  89. package/payload/server/public/assets/{triangle-alert-B3bthSzx.js → triangle-alert-JwLSrj17.js} +1 -1
  90. package/payload/server/public/assets/triangle-alert-JwLSrj17.js.br +0 -0
  91. package/payload/server/public/assets/triangle-alert-JwLSrj17.js.gz +0 -0
  92. package/payload/server/public/assets/{useCopyFeedback-BzJAkFEb.js → useCopyFeedback-DjTkNw2p.js} +1 -1
  93. package/payload/server/public/assets/useCopyFeedback-DjTkNw2p.js.br +0 -0
  94. package/payload/server/public/assets/useCopyFeedback-DjTkNw2p.js.gz +0 -0
  95. package/payload/server/public/assets/useMediaQuery-BsBzbWaf.css +1 -0
  96. package/payload/server/public/assets/useMediaQuery-BsBzbWaf.css.br +0 -0
  97. package/payload/server/public/assets/useMediaQuery-BsBzbWaf.css.gz +0 -0
  98. package/payload/server/public/assets/useMediaQuery-D8VDA0RN.js +14 -0
  99. package/payload/server/public/assets/useMediaQuery-D8VDA0RN.js.br +0 -0
  100. package/payload/server/public/assets/useMediaQuery-D8VDA0RN.js.gz +0 -0
  101. package/payload/server/public/assets/{useVoiceRecorder-_qI_BAOo.js → useVoiceRecorder-B8vxObZG.js} +1 -1
  102. package/payload/server/public/assets/useVoiceRecorder-B8vxObZG.js.br +0 -0
  103. package/payload/server/public/assets/useVoiceRecorder-B8vxObZG.js.gz +0 -0
  104. package/payload/server/public/assets/{wrench-Bqux9jaw.js → wrench-DutUiRu7.js} +1 -1
  105. package/payload/server/public/assets/wrench-DutUiRu7.js.br +0 -0
  106. package/payload/server/public/assets/wrench-DutUiRu7.js.gz +0 -0
  107. package/payload/server/public/browser.html +4 -4
  108. package/payload/server/public/calendar.html +7 -7
  109. package/payload/server/public/chat.html +13 -13
  110. package/payload/server/public/data.html +11 -11
  111. package/payload/server/public/graph.html +9 -9
  112. package/payload/server/public/index.html +13 -13
  113. package/payload/server/public/operator.html +14 -14
  114. package/payload/server/public/public.html +13 -13
  115. package/payload/server/public/routines.html +7 -7
  116. package/payload/server/public/skills.html +5 -5
  117. package/payload/server/public/tasks.html +6 -6
  118. package/payload/server/server.js +1118 -636
  119. package/payload/server/public/assets/AdminLoginScreens-DLogIsJT.js.br +0 -0
  120. package/payload/server/public/assets/AdminLoginScreens-DLogIsJT.js.gz +0 -0
  121. package/payload/server/public/assets/AdminShell-B67tPTyE.js +0 -2
  122. package/payload/server/public/assets/AdminShell-B67tPTyE.js.br +0 -0
  123. package/payload/server/public/assets/AdminShell-B67tPTyE.js.gz +0 -0
  124. package/payload/server/public/assets/activity-AVJSFESV.js.br +0 -0
  125. package/payload/server/public/assets/activity-AVJSFESV.js.gz +0 -0
  126. package/payload/server/public/assets/admin-eFgbld42.js.br +0 -0
  127. package/payload/server/public/assets/admin-eFgbld42.js.gz +0 -0
  128. package/payload/server/public/assets/agents-CoWLZMf7.js.br +0 -0
  129. package/payload/server/public/assets/agents-CoWLZMf7.js.gz +0 -0
  130. package/payload/server/public/assets/browser-C6K66_fw.js.br +0 -0
  131. package/payload/server/public/assets/browser-C6K66_fw.js.gz +0 -0
  132. package/payload/server/public/assets/calendar-Dnw_cP4b.js.br +0 -0
  133. package/payload/server/public/assets/calendar-Dnw_cP4b.js.gz +0 -0
  134. package/payload/server/public/assets/chat-Cm0fkpg1.js +0 -1
  135. package/payload/server/public/assets/chat-Cm0fkpg1.js.br +0 -0
  136. package/payload/server/public/assets/chat-Cm0fkpg1.js.gz +0 -0
  137. package/payload/server/public/assets/chevron-left-CjRH-BtF.js +0 -1
  138. package/payload/server/public/assets/chevron-left-CjRH-BtF.js.br +0 -0
  139. package/payload/server/public/assets/clock-wbYEt1kM.js +0 -1
  140. package/payload/server/public/assets/clock-wbYEt1kM.js.br +0 -0
  141. package/payload/server/public/assets/clock-wbYEt1kM.js.gz +0 -0
  142. package/payload/server/public/assets/copy-kuNM0Etw.js.br +0 -0
  143. package/payload/server/public/assets/copy-kuNM0Etw.js.gz +0 -0
  144. package/payload/server/public/assets/data-c47T2NCd.js +0 -1
  145. package/payload/server/public/assets/data-c47T2NCd.js.br +0 -1
  146. package/payload/server/public/assets/data-c47T2NCd.js.gz +0 -0
  147. package/payload/server/public/assets/file-text-BWkobrcx.js.br +0 -0
  148. package/payload/server/public/assets/file-text-BWkobrcx.js.gz +0 -0
  149. package/payload/server/public/assets/graph-BGjTL5Vz.js.br +0 -0
  150. package/payload/server/public/assets/graph-BGjTL5Vz.js.gz +0 -0
  151. package/payload/server/public/assets/graph-labels-Dvc5Kw_r.js.br +0 -0
  152. package/payload/server/public/assets/graph-labels-Dvc5Kw_r.js.gz +0 -0
  153. package/payload/server/public/assets/operator-CzBGv_he.js.br +0 -0
  154. package/payload/server/public/assets/operator-CzBGv_he.js.gz +0 -0
  155. package/payload/server/public/assets/page-BIY4Ku8Q.js.br +0 -0
  156. package/payload/server/public/assets/page-BIY4Ku8Q.js.gz +0 -0
  157. package/payload/server/public/assets/page-DaySqamH.js.br +0 -0
  158. package/payload/server/public/assets/page-DaySqamH.js.gz +0 -0
  159. package/payload/server/public/assets/play-C8RA52_i.js +0 -1
  160. package/payload/server/public/assets/play-C8RA52_i.js.br +0 -0
  161. package/payload/server/public/assets/play-C8RA52_i.js.gz +0 -0
  162. package/payload/server/public/assets/public-pwDSvhBv.js.br +0 -0
  163. package/payload/server/public/assets/public-pwDSvhBv.js.gz +0 -0
  164. package/payload/server/public/assets/rotate-ccw-B6s7tkEt.js.br +0 -0
  165. package/payload/server/public/assets/rotate-ccw-B6s7tkEt.js.gz +0 -0
  166. package/payload/server/public/assets/routines-CFlyRdYg.js.br +0 -0
  167. package/payload/server/public/assets/routines-CFlyRdYg.js.gz +0 -0
  168. package/payload/server/public/assets/skills-C45kfL_Q.js.br +0 -0
  169. package/payload/server/public/assets/skills-C45kfL_Q.js.gz +0 -0
  170. package/payload/server/public/assets/tasks-BwoCTCu5.js.br +0 -0
  171. package/payload/server/public/assets/tasks-BwoCTCu5.js.gz +0 -0
  172. package/payload/server/public/assets/triangle-alert-B3bthSzx.js.br +0 -0
  173. package/payload/server/public/assets/triangle-alert-B3bthSzx.js.gz +0 -0
  174. package/payload/server/public/assets/useCopyFeedback-BzJAkFEb.js.br +0 -0
  175. package/payload/server/public/assets/useCopyFeedback-BzJAkFEb.js.gz +0 -0
  176. package/payload/server/public/assets/useMediaQuery-DJ6XeNN7.js +0 -14
  177. package/payload/server/public/assets/useMediaQuery-DJ6XeNN7.js.br +0 -0
  178. package/payload/server/public/assets/useMediaQuery-DJ6XeNN7.js.gz +0 -0
  179. package/payload/server/public/assets/useMediaQuery-DW_xRrMl.css +0 -1
  180. package/payload/server/public/assets/useMediaQuery-DW_xRrMl.css.br +0 -0
  181. package/payload/server/public/assets/useMediaQuery-DW_xRrMl.css.gz +0 -0
  182. package/payload/server/public/assets/useVoiceRecorder-_qI_BAOo.js.br +0 -0
  183. package/payload/server/public/assets/useVoiceRecorder-_qI_BAOo.js.gz +0 -0
  184. package/payload/server/public/assets/wrench-Bqux9jaw.js.br +0 -0
  185. package/payload/server/public/assets/wrench-Bqux9jaw.js.gz +0 -0
@@ -30,9 +30,9 @@ import "./chunk-HYQNUVGO.js";
30
30
  // server/edge.ts
31
31
  import { createServer, request as httpRequest } from "http";
32
32
  import { createConnection as createConnection3 } from "net";
33
- import { readFileSync as readFileSync4, existsSync as existsSync4, watchFile } from "fs";
33
+ import { readFileSync as readFileSync5, existsSync as existsSync4, watchFile } from "fs";
34
34
  import { homedir } from "os";
35
- import { join as join4 } from "path";
35
+ import { join as join3 } from "path";
36
36
 
37
37
  // server/ws-proxy.ts
38
38
  import { createConnection } from "net";
@@ -544,10 +544,6 @@ Content-Length: 0\r
544
544
  socket.destroy();
545
545
  }
546
546
 
547
- // server/routes/admin/version.ts
548
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
549
- import { resolve, join as join2 } from "path";
550
-
551
547
  // server/lib/client-error-count.ts
552
548
  import { existsSync, readFileSync, statSync, openSync, readSync, closeSync } from "fs";
553
549
  import { join } from "path";
@@ -592,11 +588,12 @@ function countClientErrors24h() {
592
588
  return count;
593
589
  }
594
590
 
595
- // server/routes/admin/version.ts
591
+ // server/lib/brand-config.ts
592
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
593
+ import { resolve } from "path";
596
594
  var PLATFORM_ROOT = process.env.MAXY_PLATFORM_ROOT ?? resolve(process.cwd(), "..");
597
595
  var DEFAULT_HOSTNAME = "maxy";
598
596
  var DEFAULT_NPM_PACKAGE = "@rubytech/create-maxy";
599
- var FETCH_TIMEOUT_MS = 5e3;
600
597
  var fallbackLogged = /* @__PURE__ */ new Set();
601
598
  function logFallbackOnce(reason, field, usingDefault) {
602
599
  const key = `${reason}:${field}`;
@@ -605,7 +602,7 @@ function logFallbackOnce(reason, field, usingDefault) {
605
602
  console.log(`[admin/version] brand-config-fallback reason=${reason} field=${field} using=${usingDefault}`);
606
603
  }
607
604
  function resolveBrandConfig() {
608
- const brandJsonPath = join2(PLATFORM_ROOT, "config", "brand.json");
605
+ const brandJsonPath = resolve(PLATFORM_ROOT, "config", "brand.json");
609
606
  if (!existsSync2(brandJsonPath)) {
610
607
  logFallbackOnce("file-missing", "hostname", DEFAULT_HOSTNAME);
611
608
  logFallbackOnce("file-missing", "npm.packageName", DEFAULT_NPM_PACKAGE);
@@ -633,12 +630,18 @@ function resolveBrandConfig() {
633
630
  }
634
631
  return { hostname, npmPackage };
635
632
  }
636
- var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
637
- function readInstalled(versionFile) {
633
+ function resolveVersionFile(hostname) {
634
+ return resolve(PLATFORM_ROOT, `config/.${hostname}-version`);
635
+ }
636
+ function readInstalledVersion(versionFile) {
638
637
  if (!existsSync2(versionFile)) return "unknown";
639
638
  const content = readFileSync2(versionFile, "utf-8").trim();
640
639
  return content || "unknown";
641
640
  }
641
+
642
+ // server/routes/admin/version.ts
643
+ var FETCH_TIMEOUT_MS = 5e3;
644
+ var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
642
645
  async function fetchLatest(npmPackage) {
643
646
  const registryUrl = `https://registry.npmjs.org/${npmPackage}/latest`;
644
647
  try {
@@ -678,8 +681,8 @@ function isNewer(latest, installed) {
678
681
  var app = new Hono();
679
682
  app.get("/", async (c) => {
680
683
  const { hostname, npmPackage } = resolveBrandConfig();
681
- const versionFile = resolve(PLATFORM_ROOT, `config/.${hostname}-version`);
682
- const installed = readInstalled(versionFile);
684
+ const versionFile = resolveVersionFile(hostname);
685
+ const installed = readInstalledVersion(versionFile);
683
686
  const latest = await fetchLatest(npmPackage);
684
687
  const updateAvailable = installed !== "unknown" && latest !== null && isNewer(latest, installed);
685
688
  const outcome = installed === "unknown" ? "stale-version-file" : latest === null ? "fetch-failed" : "ok";
@@ -704,11 +707,267 @@ app.post("/alert-surfaced", async (c) => {
704
707
  });
705
708
  var version_default = app;
706
709
 
710
+ // server/routes/admin/actions.ts
711
+ import { spawn, spawnSync } from "child_process";
712
+ import { mkdirSync, readdirSync, readFileSync as readFileSync3, statSync as statSync2, writeFileSync } from "fs";
713
+ import { randomUUID } from "crypto";
714
+ import { resolve as resolve2 } from "path";
715
+ var TAG = "[admin-action]";
716
+ var ACTIONS_DIR = resolve2(LOG_DIR, "actions");
717
+ var EXIT_MARKER = "[action-exit] code=";
718
+ function isValidActionId(id) {
719
+ return /^[0-9a-f]{8}$/.test(id);
720
+ }
721
+ function isValidPackageName(pkg) {
722
+ return /^(@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(pkg) && pkg.length <= 214;
723
+ }
724
+ function logPathFor(actionId) {
725
+ return resolve2(ACTIONS_DIR, `${actionId}.log`);
726
+ }
727
+ function sidecarPathFor(actionId) {
728
+ return resolve2(ACTIONS_DIR, `${actionId}.json`);
729
+ }
730
+ function buildUpgradeArgv(opts) {
731
+ const script = `npx -y ${opts.pkg}@latest >> ${opts.logPath} 2>&1; echo "${EXIT_MARKER}$?" >> ${opts.logPath}`;
732
+ return [
733
+ "--user",
734
+ `--unit=${opts.unit}`,
735
+ "--collect",
736
+ `--setenv=PATH=${opts.path}`,
737
+ "/bin/sh",
738
+ "-c",
739
+ script
740
+ ];
741
+ }
742
+ function systemdRunPresent() {
743
+ const probe = spawnSync("systemd-run", ["--version"], { stdio: "ignore" });
744
+ return probe.status === 0;
745
+ }
746
+ function logCensus() {
747
+ let logs = 0;
748
+ let oldestAgeH = 0;
749
+ try {
750
+ const now = Date.now();
751
+ for (const f of readdirSync(ACTIONS_DIR)) {
752
+ if (!f.endsWith(".log")) continue;
753
+ logs++;
754
+ const ageH = (now - statSync2(resolve2(ACTIONS_DIR, f)).mtimeMs) / 36e5;
755
+ if (ageH > oldestAgeH) oldestAgeH = ageH;
756
+ }
757
+ } catch {
758
+ }
759
+ const listed = spawnSync("systemctl", ["--user", "list-units", "--no-legend", "maxy-action-*"], {
760
+ encoding: "utf-8"
761
+ });
762
+ const out = (listed.stdout ?? "").trim();
763
+ const units = out ? out.split("\n").length : 0;
764
+ console.log(`[action-census] units=${units} logs=${logs} oldestAgeH=${oldestAgeH.toFixed(1)}`);
765
+ }
766
+ function readExitCode(logText) {
767
+ const idx = logText.lastIndexOf(EXIT_MARKER);
768
+ if (idx === -1) return null;
769
+ const tail = logText.slice(idx + EXIT_MARKER.length).trim();
770
+ const code = Number.parseInt(tail, 10);
771
+ return Number.isNaN(code) ? null : code;
772
+ }
773
+ function readLog(actionId) {
774
+ try {
775
+ return readFileSync3(logPathFor(actionId), "utf-8");
776
+ } catch {
777
+ return "";
778
+ }
779
+ }
780
+ var app2 = new Hono();
781
+ app2.post("/upgrade", (c) => {
782
+ const actionId = randomUUID().replace(/-/g, "").slice(0, 8);
783
+ const { hostname, npmPackage } = resolveBrandConfig();
784
+ console.log(`${TAG} op=request actionId=${actionId} action=upgrade pkg=${npmPackage}`);
785
+ logCensus();
786
+ if (!isValidPackageName(npmPackage)) {
787
+ console.error(`${TAG} op=preflight actionId=${actionId} reason=malformed-package pkg=${JSON.stringify(npmPackage)}`);
788
+ return c.json({ ok: false, reason: "malformed-package-name" }, 500);
789
+ }
790
+ const present = systemdRunPresent();
791
+ console.log(`${TAG} op=preflight actionId=${actionId} systemdRun=${present ? "present" : "absent"}`);
792
+ if (!present) {
793
+ return c.json({ ok: false, reason: "systemd-run-absent" }, 501);
794
+ }
795
+ const versionBefore = readInstalledVersion(resolveVersionFile(hostname));
796
+ const unit = `maxy-action-${actionId}`;
797
+ const logPath = logPathFor(actionId);
798
+ mkdirSync(ACTIONS_DIR, { recursive: true });
799
+ const sidecar = {
800
+ actionId,
801
+ action: "upgrade",
802
+ pkg: npmPackage,
803
+ unit,
804
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
805
+ versionBefore,
806
+ hostname
807
+ };
808
+ writeFileSync(sidecarPathFor(actionId), JSON.stringify(sidecar), "utf-8");
809
+ const argv = buildUpgradeArgv({ unit, pkg: npmPackage, logPath, path: process.env.PATH ?? "" });
810
+ console.log(`${TAG} op=argv actionId=${actionId} argv=${JSON.stringify(argv)}`);
811
+ const child = spawn("systemd-run", argv, { detached: true, stdio: "ignore" });
812
+ child.unref();
813
+ console.log(`${TAG} op=unit-started actionId=${actionId} unit=${unit} logPath=${logPath}`);
814
+ return c.json({ actionId }, 202);
815
+ });
816
+ app2.get("/latest", (c) => {
817
+ let names = [];
818
+ try {
819
+ names = readdirSync(ACTIONS_DIR).filter((f) => f.endsWith(".json"));
820
+ } catch {
821
+ }
822
+ if (names.length === 0) return c.json({ action: null });
823
+ let newestName = null;
824
+ let newestMs = -1;
825
+ for (const n of names) {
826
+ try {
827
+ const ms = statSync2(resolve2(ACTIONS_DIR, n)).mtimeMs;
828
+ if (ms > newestMs) {
829
+ newestMs = ms;
830
+ newestName = n;
831
+ }
832
+ } catch {
833
+ }
834
+ }
835
+ if (!newestName) return c.json({ action: null });
836
+ let newest;
837
+ try {
838
+ newest = JSON.parse(readFileSync3(resolve2(ACTIONS_DIR, newestName), "utf-8"));
839
+ } catch (err) {
840
+ console.error(`${TAG} op=latest-unreadable file=${newestName} detail=${String(err)}`);
841
+ return c.json({ action: null });
842
+ }
843
+ const exitCode = readExitCode(readLog(newest.actionId));
844
+ return c.json({ action: { ...newest, running: exitCode === null, exitCode } });
845
+ });
846
+ app2.get("/:actionId/stream", (c) => {
847
+ const actionId = c.req.param("actionId");
848
+ if (!isValidActionId(actionId)) {
849
+ console.error(`${TAG} op=stream-reject actionId=${JSON.stringify(actionId)} reason=malformed`);
850
+ return c.json({ ok: false, reason: "malformed-action-id" }, 400);
851
+ }
852
+ const encoder = new TextEncoder();
853
+ const startedAt = Date.now();
854
+ let offset = Number.parseInt(c.req.header("last-event-id") ?? "0", 10);
855
+ if (!Number.isFinite(offset) || offset < 0) offset = 0;
856
+ let closed = false;
857
+ let timer = null;
858
+ let heartbeat = null;
859
+ let sawOutput = offset > 0;
860
+ const NO_OUTPUT_DEADLINE_MS = 3e4;
861
+ const teardown = (reason) => {
862
+ if (closed) return;
863
+ closed = true;
864
+ if (timer) clearInterval(timer);
865
+ if (heartbeat) clearInterval(heartbeat);
866
+ console.log(
867
+ `${TAG} op=stream-close actionId=${actionId} ranMs=${Date.now() - startedAt} bytes=${offset} reason=${reason}`
868
+ );
869
+ };
870
+ const stream = new ReadableStream({
871
+ start(controller) {
872
+ console.log(`${TAG} op=stream-open actionId=${actionId} fromOffset=${offset}`);
873
+ const tick = () => {
874
+ if (closed) return;
875
+ try {
876
+ const text = readLog(actionId);
877
+ if (text.length > offset) {
878
+ const slice = text.slice(offset);
879
+ offset = text.length;
880
+ if (!sawOutput) {
881
+ sawOutput = true;
882
+ console.log(
883
+ `${TAG} op=first-output actionId=${actionId} waitedMs=${Date.now() - startedAt} head=${JSON.stringify(slice.slice(0, 200))}`
884
+ );
885
+ }
886
+ const lines = slice.split("\n");
887
+ if (lines[lines.length - 1] === "") lines.pop();
888
+ const frame = `id: ${offset}
889
+ ` + lines.map((l) => `data: ${l}`).join("\n") + "\n\n";
890
+ controller.enqueue(encoder.encode(frame));
891
+ } else if (!sawOutput && Date.now() - startedAt > NO_OUTPUT_DEADLINE_MS) {
892
+ sawOutput = true;
893
+ console.error(`${TAG} op=no-output actionId=${actionId} waitedMs=${Date.now() - startedAt}`);
894
+ }
895
+ const code = readExitCode(text);
896
+ if (code !== null) {
897
+ let sidecar = null;
898
+ try {
899
+ sidecar = JSON.parse(readFileSync3(sidecarPathFor(actionId), "utf-8"));
900
+ } catch {
901
+ }
902
+ const versionAfter = sidecar ? readInstalledVersion(resolveVersionFile(sidecar.hostname)) : "unknown";
903
+ const versionBefore = sidecar?.versionBefore ?? "unknown";
904
+ const changed = versionBefore !== "unknown" && versionAfter !== "unknown" && versionBefore !== versionAfter;
905
+ console.log(`${TAG} op=exit actionId=${actionId} ranMs=${Date.now() - startedAt} code=${code}`);
906
+ console.log(
907
+ `${TAG} op=version-check actionId=${actionId} before=${versionBefore} after=${versionAfter} changed=${changed}`
908
+ );
909
+ controller.enqueue(
910
+ encoder.encode(
911
+ `event: done
912
+ data: ${JSON.stringify({ code, versionBefore, versionAfter, changed })}
913
+
914
+ `
915
+ )
916
+ );
917
+ teardown("action-exited");
918
+ try {
919
+ controller.close();
920
+ } catch {
921
+ }
922
+ }
923
+ } catch (err) {
924
+ teardown(`tail-failed:${String(err)}`);
925
+ try {
926
+ controller.close();
927
+ } catch {
928
+ }
929
+ }
930
+ };
931
+ timer = setInterval(tick, 500);
932
+ tick();
933
+ heartbeat = setInterval(() => {
934
+ try {
935
+ controller.enqueue(encoder.encode(": ping\n\n"));
936
+ } catch {
937
+ teardown("heartbeat-enqueue-failed");
938
+ try {
939
+ controller.close();
940
+ } catch {
941
+ }
942
+ }
943
+ }, 2e4);
944
+ c.req.raw.signal.addEventListener("abort", () => {
945
+ teardown("client-aborted");
946
+ try {
947
+ controller.close();
948
+ } catch {
949
+ }
950
+ });
951
+ },
952
+ cancel() {
953
+ teardown("client-closed");
954
+ }
955
+ });
956
+ return new Response(stream, {
957
+ headers: {
958
+ "Content-Type": "text/event-stream",
959
+ "Cache-Control": "no-cache",
960
+ Connection: "keep-alive"
961
+ }
962
+ });
963
+ });
964
+ var actions_default = app2;
965
+
707
966
  // server/edge-admin.ts
708
967
  function createEdgeAdminApp(opts) {
709
- const app2 = new Hono();
710
- app2.use("*", clientIpMiddleware);
711
- app2.use("*", async (c, next) => {
968
+ const app3 = new Hono();
969
+ app3.use("*", clientIpMiddleware);
970
+ app3.use("*", async (c, next) => {
712
971
  const start = Date.now();
713
972
  console.log(
714
973
  `[edge-admin] ts=${(/* @__PURE__ */ new Date()).toISOString()} inbound method=${c.req.method} path=${c.req.path} allowlist-branch=edge-admin`
@@ -718,14 +977,26 @@ function createEdgeAdminApp(opts) {
718
977
  `[edge-admin] ts=${(/* @__PURE__ */ new Date()).toISOString()} outcome method=${c.req.method} path=${c.req.path} status=${c.res.status} duration_ms=${Date.now() - start}`
719
978
  );
720
979
  });
721
- app2.use("*", requireAdminCookie(opts.isPublicHost));
722
- app2.route("/api/admin/version", version_default);
723
- return app2;
980
+ app3.use("*", requireAdminCookie(opts.isPublicHost));
981
+ app3.route("/api/admin/version", version_default);
982
+ app3.route("/api/admin/actions", actions_default);
983
+ return app3;
984
+ }
985
+
986
+ // server/edge-admin-path.ts
987
+ var EDGE_ADMIN_PREFIXES = [
988
+ "/api/admin/actions",
989
+ "/api/admin/version"
990
+ ];
991
+ function isEdgeAdminPath(url) {
992
+ const q = url.indexOf("?");
993
+ const pathname = q === -1 ? url : url.slice(0, q);
994
+ return EDGE_ADMIN_PREFIXES.some((p) => pathname.startsWith(p));
724
995
  }
725
996
 
726
997
  // server/edge-fallback.ts
727
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
728
- import { extname, join as join3 } from "path";
998
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
999
+ import { extname, join as join2 } from "path";
729
1000
 
730
1001
  // server/lib/proxy-log-path.ts
731
1002
  function proxyPathname(url) {
@@ -761,7 +1032,7 @@ function inlineAsset(filePath) {
761
1032
  if (!existsSync3(filePath)) return null;
762
1033
  const mime = MIME_BY_EXT[extname(filePath).toLowerCase()];
763
1034
  if (!mime) return null;
764
- const bytes = readFileSync3(filePath);
1035
+ const bytes = readFileSync4(filePath);
765
1036
  return `data:${mime};base64,${bytes.toString("base64")}`;
766
1037
  }
767
1038
  function readString(value, fallback) {
@@ -770,9 +1041,9 @@ function readString(value, fallback) {
770
1041
  function loadBrand(brandJsonPath, assetsDir = "") {
771
1042
  if (!brandJsonPath || !existsSync3(brandJsonPath)) return { ...BRAND_DEFAULTS };
772
1043
  try {
773
- const parsed = JSON.parse(readFileSync3(brandJsonPath, "utf-8"));
1044
+ const parsed = JSON.parse(readFileSync4(brandJsonPath, "utf-8"));
774
1045
  const logoFile = typeof parsed.assets?.logo === "string" ? parsed.assets.logo : null;
775
- const logoDataUri = logoFile && assetsDir ? inlineAsset(join3(assetsDir, logoFile)) : null;
1046
+ const logoDataUri = logoFile && assetsDir ? inlineAsset(join2(assetsDir, logoFile)) : null;
776
1047
  return {
777
1048
  configDir: readString(parsed.configDir, BRAND_DEFAULTS.configDir),
778
1049
  productName: readString(parsed.productName, BRAND_DEFAULTS.productName),
@@ -875,14 +1146,14 @@ function buildHoldingPage(brand) {
875
1146
 
876
1147
  // server/edge.ts
877
1148
  var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT || "";
878
- var BRAND_JSON_PATH = PLATFORM_ROOT2 ? join4(PLATFORM_ROOT2, "config", "brand.json") : "";
879
- var BRAND_ASSETS_DIR = PLATFORM_ROOT2 ? join4(PLATFORM_ROOT2, "..", "server", "public", "brand") : "";
1149
+ var BRAND_JSON_PATH = PLATFORM_ROOT2 ? join3(PLATFORM_ROOT2, "config", "brand.json") : "";
1150
+ var BRAND_ASSETS_DIR = PLATFORM_ROOT2 ? join3(PLATFORM_ROOT2, "..", "server", "public", "brand") : "";
880
1151
  var BRAND = loadBrand(BRAND_JSON_PATH, BRAND_ASSETS_DIR);
881
- var ALIAS_DOMAINS_PATH = join4(homedir(), BRAND.configDir, "alias-domains.json");
1152
+ var ALIAS_DOMAINS_PATH = join3(homedir(), BRAND.configDir, "alias-domains.json");
882
1153
  function loadAliasDomains() {
883
1154
  try {
884
1155
  if (!existsSync4(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
885
- const parsed = JSON.parse(readFileSync4(ALIAS_DOMAINS_PATH, "utf-8"));
1156
+ const parsed = JSON.parse(readFileSync5(ALIAS_DOMAINS_PATH, "utf-8"));
886
1157
  if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
887
1158
  return new Set(parsed.filter((h) => typeof h === "string"));
888
1159
  } catch {
@@ -1031,11 +1302,9 @@ function forwardUpgrade(req, clientSocket, head) {
1031
1302
  }
1032
1303
  var edgeAdminApp = createEdgeAdminApp({ isPublicHost });
1033
1304
  var edgeAdminHandler = getRequestListener(edgeAdminApp.fetch);
1034
- function isEdgeAdminPath(url) {
1035
- const q = url.indexOf("?");
1036
- const pathname = q === -1 ? url : url.slice(0, q);
1037
- return pathname.startsWith("/api/admin/actions") || pathname.startsWith("/api/admin/version");
1038
- }
1305
+ console.log(
1306
+ `[edge] admin-dispatch actions=${isEdgeAdminPath("/api/admin/actions/deadbeef/stream")} version=${isEdgeAdminPath("/api/admin/version")}`
1307
+ );
1039
1308
  var server = createServer((req, res) => {
1040
1309
  if (isEdgeAdminPath(req.url ?? "")) {
1041
1310
  edgeAdminHandler(req, res);
@@ -5,12 +5,12 @@
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-AVJSFESV.js"></script>
8
+ <script type="module" crossorigin src="/assets/activity--yyBcNfB.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CltuBf4Z.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-DJ6XeNN7.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-B67tPTyE.js">
12
- <link rel="modulepreload" crossorigin href="/assets/triangle-alert-B3bthSzx.js">
13
- <link rel="stylesheet" crossorigin href="/assets/useMediaQuery-DW_xRrMl.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-D8VDA0RN.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DStA0lfm.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/triangle-alert-JwLSrj17.js">
13
+ <link rel="stylesheet" crossorigin href="/assets/useMediaQuery-BsBzbWaf.css">
14
14
  <link rel="stylesheet" href="/brand-defaults.css">
15
15
  </head>
16
16
  <body>
@@ -5,11 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Agents — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/agents-CoWLZMf7.js"></script>
8
+ <script type="module" crossorigin src="/assets/agents-odyVOb5E.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CltuBf4Z.js">
10
- <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-DJ6XeNN7.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-B67tPTyE.js">
12
- <link rel="stylesheet" crossorigin href="/assets/useMediaQuery-DW_xRrMl.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-D8VDA0RN.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-DStA0lfm.js">
12
+ <link rel="stylesheet" crossorigin href="/assets/useMediaQuery-BsBzbWaf.css">
13
13
  <link rel="stylesheet" href="/brand-defaults.css">
14
14
  </head>
15
15
  <body>
@@ -1 +1 @@
1
- import{o as e}from"./chunk-CltuBf4Z.js";import{O as t,Q as n,ct as r,et as i,it as a,nt as o}from"./useMediaQuery-DJ6XeNN7.js";import{A as s}from"./useVoiceRecorder-_qI_BAOo.js";import{A as c,O as l,k as u,p as d}from"./AdminShell-B67tPTyE.js";var f=e(r(),1);function p(e=`admin`){let[t,n]=(0,f.useState)(`loading`),[r,i]=(0,f.useState)(``),[o,l]=(0,f.useState)(``),[u,d]=(0,f.useState)(``),[p,m]=(0,f.useState)(!1),[h,g]=(0,f.useState)(!1),[_,v]=(0,f.useState)(!1),[y,b]=(0,f.useState)(!1),[x,S]=(0,f.useState)(!1),[C,w]=(0,f.useState)(null),[T,E]=(0,f.useState)(null),[D,O]=(0,f.useState)(void 0),[k,A]=(0,f.useState)(null),[j,M]=(0,f.useState)(void 0),[N,P]=(0,f.useState)(null),[F,I]=(0,f.useState)(null),[L,R]=(0,f.useState)(void 0),z=(0,f.useRef)(void 0),[B,V]=(0,f.useState)(!1),[H,U]=(0,f.useState)(!0);(0,f.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&V(!0)}).catch(()=>{})},[]);let W=(0,f.useRef)(null),G=(0,f.useRef)(null);(0,f.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 r=await t.json();w(r.session_key),I(r.sessionId??null),O(r.businessName),A(r.role??null),M(r.userName===void 0?null:r.userName),P(r.avatar??null);let i=s(r.thinkingView);return z.current=i,R(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}U(!!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){n(`connect-claude`);return}}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,f.useEffect)(()=>{t===`chat`&&C&&fetch(`/api/admin/claude-info?session_key=${encodeURIComponent(C)}`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&E(e)}).catch(()=>{})},[t,C]);let K=(0,f.useRef)(null);(0,f.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();U(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(C)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(C)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){a(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),K.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,C]),(0,f.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(U(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function q(e,t){g(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){a(`enter-pin`,`/api/admin/session`);return}d(e.error||`Invalid PIN`);return}let o=await r.json();w(o.session_key),I(o.sessionId??null),O(o.businessName),A(o.role??null),M(o.userName===void 0?null:o.userName),P(o.avatar??null);let c=s(o.thinkingView);z.current=c,R(c);try{sessionStorage.setItem(`maxy-admin-session-key`,o.session_key)}catch{}i(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}}let J=(0,f.useCallback)(async e=>{if(e.preventDefault(),h)return;d(``);let t=o.trim();if(!t){d(`Please enter your name.`);return}if(r.length<4){d(`PIN must be at least 4 characters.`);return}let s=r;g(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:s,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){a(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){try{let e=await fetch(`/api/health`);if(e.ok){let r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):d(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}d(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await q(s);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}},[r,h,o]),Y=(0,f.useCallback)(async e=>{e.preventDefault(),d(``),await q(r)},[r]),X=(0,f.useCallback)(async()=>{S(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;U(!1),w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return n(`connect-claude`),!0}finally{S(!1)}},[]),Z=(0,f.useCallback)(()=>{w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}i(``),d(``),n(`enter-pin`)},[]);return(0,f.useEffect)(()=>{K.current=Z},[Z]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:o,setOperatorName:l,pinError:u,setPinError:d,showPin:p,setShowPin:m,pinLoading:h,authPolling:_,setAuthPolling:v,authLoading:y,setAuthLoading:b,disconnecting:x,cacheKey:C,setCacheKey:w,claudeInfo:T,setClaudeInfo:E,businessName:D,role:k,userName:j,userAvatar:N,sessionId:F,setSessionId:I,expandAll:L,setExpandAll:R,expandAllDefaultRef:z,remoteAuthEnabled:B,claudeConnected:H,pinInputRef:W,setPinFormRef:G,handleSetPin:J,handleLogin:Y,handleDisconnect:X,handleLogout:Z}}var m=o();function h({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,f.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,m.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,m.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 g(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:g,setOperatorName:_}=e;return(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,n.productName]}),(0,m.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,n.productName,` who you are, then choose a PIN.`]}),(0,m.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:g,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,m.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t||!g.trim(),loading:s,"aria-label":`Set PIN`,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function _(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:g}=e;return(0,m.jsxs)(`div`,{className:`connect-page`,children:[p&&g&&(0,m.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:g,children:`Sign out`}),(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`h1`,{className:`connect-title`,children:n.productName}),(0,m.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t,loading:s,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(`div`,{className:`pin-options`,children:(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})]})}function v(e){let{authPolling:t,setAuthPolling:r,authLoading:a,setAuthLoading:o,pinError:s,setPinError:c,setAppState:u}=e,[p,h]=(0,f.useState)(!1),[g,_]=(0,f.useState)(!1),[v,y]=(0,f.useState)(``),[b,x]=(0,f.useState)(``),[S,C]=(0,f.useState)(``),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(null),[O,k]=(0,f.useState)(!1);(0,f.useEffect)(()=>{try{D(sessionStorage.getItem(`maxy-admin-session-key`))}catch{}k(!0)},[]);async function A(){C(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:b})})).json();e.accepted?(C(`Code submitted. Finishing sign-in…`),x(``)):C(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),C(`Could not submit code.`)}}async function j(){_(!0),c(``);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?h(!0):e.error&&c(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),c(`Could not launch browser.`)}_(!1)}async function M(){o(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){r(!0),h(!0),o(!1),y(e.transport||``);for(let e=0;e<120;e++){await new Promise(e=>setTimeout(e,2e3));let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json();if(typeof e.authTargetId==`string`&&T(e.authTargetId),e.authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}}c(`Timed out waiting for sign-in. Try again.`),r(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function N(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),r(!1),c(``)}return t||p?(0,m.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,m.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,m.jsx)(`button`,{onClick:N,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,m.jsx)(`button`,{onClick:()=>h(!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,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,m.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,m.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,m.jsx)(`div`,{style:{marginTop:`12px`},children:(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),t&&v===`native`&&(0,m.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,m.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,m.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,m.jsx)(`input`,{type:`text`,value:b,onChange:e=>x(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,m.jsx)(l,{variant:`primary`,onClick:A,disabled:!b.trim(),children:`Submit`})]}),S&&(0,m.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:S})]})]}),(0,m.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:O&&(0,m.jsx)(d,{preferTargetId:w,cacheKey:E,chrome:!1})}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsxs)(`div`,{className:`connect-logos`,children:[(0,m.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,m.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,m.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,m.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`span`,{className:`connect-logo-label`,children:n.productName})]})]}),(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,n.productName]}),(0,m.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,m.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,m.jsx)(`button`,{onClick:j,disabled:g,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:g?`Launching…`:`Open browser first`}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function y({auth:e}){return e.appState===`loading`?(0,m.jsx)(t,{surface:`gate`}):e.appState===`set-pin`?(0,m.jsx)(g,{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,m.jsx)(v,{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,m.jsx)(_,{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:()=>{window.location.href=`/__remote-auth/logout`}}):null}export{p as n,y as t};
1
+ import{o as e}from"./chunk-CltuBf4Z.js";import{O as t,Q as n,ct as r,et as i,it as a,nt as o}from"./useMediaQuery-D8VDA0RN.js";import{A as s}from"./useVoiceRecorder-B8vxObZG.js";import{A as c,O as l,k as u,p as d}from"./AdminShell-DStA0lfm.js";var f=e(r(),1);function p(e=`admin`){let[t,n]=(0,f.useState)(`loading`),[r,i]=(0,f.useState)(``),[o,l]=(0,f.useState)(``),[u,d]=(0,f.useState)(``),[p,m]=(0,f.useState)(!1),[h,g]=(0,f.useState)(!1),[_,v]=(0,f.useState)(!1),[y,b]=(0,f.useState)(!1),[x,S]=(0,f.useState)(!1),[C,w]=(0,f.useState)(null),[T,E]=(0,f.useState)(null),[D,O]=(0,f.useState)(void 0),[k,A]=(0,f.useState)(null),[j,M]=(0,f.useState)(void 0),[N,P]=(0,f.useState)(null),[F,I]=(0,f.useState)(null),[L,R]=(0,f.useState)(void 0),z=(0,f.useRef)(void 0),[B,V]=(0,f.useState)(!1),[H,U]=(0,f.useState)(!0);(0,f.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&V(!0)}).catch(()=>{})},[]);let W=(0,f.useRef)(null),G=(0,f.useRef)(null);(0,f.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 r=await t.json();w(r.session_key),I(r.sessionId??null),O(r.businessName),A(r.role??null),M(r.userName===void 0?null:r.userName),P(r.avatar??null);let i=s(r.thinkingView);return z.current=i,R(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}U(!!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){n(`connect-claude`);return}}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,f.useEffect)(()=>{t===`chat`&&C&&fetch(`/api/admin/claude-info?session_key=${encodeURIComponent(C)}`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&E(e)}).catch(()=>{})},[t,C]);let K=(0,f.useRef)(null);(0,f.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();U(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(C)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(C)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){a(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),K.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,C]),(0,f.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(U(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function q(e,t){g(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){a(`enter-pin`,`/api/admin/session`);return}d(e.error||`Invalid PIN`);return}let o=await r.json();w(o.session_key),I(o.sessionId??null),O(o.businessName),A(o.role??null),M(o.userName===void 0?null:o.userName),P(o.avatar??null);let c=s(o.thinkingView);z.current=c,R(c);try{sessionStorage.setItem(`maxy-admin-session-key`,o.session_key)}catch{}i(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}}let J=(0,f.useCallback)(async e=>{if(e.preventDefault(),h)return;d(``);let t=o.trim();if(!t){d(`Please enter your name.`);return}if(r.length<4){d(`PIN must be at least 4 characters.`);return}let s=r;g(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:s,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){a(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){try{let e=await fetch(`/api/health`);if(e.ok){let r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):d(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}d(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await q(s);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}},[r,h,o]),Y=(0,f.useCallback)(async e=>{e.preventDefault(),d(``),await q(r)},[r]),X=(0,f.useCallback)(async()=>{S(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;U(!1),w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return n(`connect-claude`),!0}finally{S(!1)}},[]),Z=(0,f.useCallback)(()=>{w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}i(``),d(``),n(`enter-pin`)},[]);return(0,f.useEffect)(()=>{K.current=Z},[Z]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:o,setOperatorName:l,pinError:u,setPinError:d,showPin:p,setShowPin:m,pinLoading:h,authPolling:_,setAuthPolling:v,authLoading:y,setAuthLoading:b,disconnecting:x,cacheKey:C,setCacheKey:w,claudeInfo:T,setClaudeInfo:E,businessName:D,role:k,userName:j,userAvatar:N,sessionId:F,setSessionId:I,expandAll:L,setExpandAll:R,expandAllDefaultRef:z,remoteAuthEnabled:B,claudeConnected:H,pinInputRef:W,setPinFormRef:G,handleSetPin:J,handleLogin:Y,handleDisconnect:X,handleLogout:Z}}var m=o();function h({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,f.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,m.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,m.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 g(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:g,setOperatorName:_}=e;return(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,n.productName]}),(0,m.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,n.productName,` who you are, then choose a PIN.`]}),(0,m.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:g,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,m.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t||!g.trim(),loading:s,"aria-label":`Set PIN`,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function _(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:g}=e;return(0,m.jsxs)(`div`,{className:`connect-page`,children:[p&&g&&(0,m.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:g,children:`Sign out`}),(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`h1`,{className:`connect-title`,children:n.productName}),(0,m.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t,loading:s,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(`div`,{className:`pin-options`,children:(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})]})}function v(e){let{authPolling:t,setAuthPolling:r,authLoading:a,setAuthLoading:o,pinError:s,setPinError:c,setAppState:u}=e,[p,h]=(0,f.useState)(!1),[g,_]=(0,f.useState)(!1),[v,y]=(0,f.useState)(``),[b,x]=(0,f.useState)(``),[S,C]=(0,f.useState)(``),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(null),[O,k]=(0,f.useState)(!1);(0,f.useEffect)(()=>{try{D(sessionStorage.getItem(`maxy-admin-session-key`))}catch{}k(!0)},[]);async function A(){C(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:b})})).json();e.accepted?(C(`Code submitted. Finishing sign-in…`),x(``)):C(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),C(`Could not submit code.`)}}async function j(){_(!0),c(``);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?h(!0):e.error&&c(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),c(`Could not launch browser.`)}_(!1)}async function M(){o(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){r(!0),h(!0),o(!1),y(e.transport||``);for(let e=0;e<120;e++){await new Promise(e=>setTimeout(e,2e3));let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json();if(typeof e.authTargetId==`string`&&T(e.authTargetId),e.authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}}c(`Timed out waiting for sign-in. Try again.`),r(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function N(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),r(!1),c(``)}return t||p?(0,m.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,m.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,m.jsx)(`button`,{onClick:N,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,m.jsx)(`button`,{onClick:()=>h(!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,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,m.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,m.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,m.jsx)(`div`,{style:{marginTop:`12px`},children:(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),t&&v===`native`&&(0,m.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,m.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,m.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,m.jsx)(`input`,{type:`text`,value:b,onChange:e=>x(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,m.jsx)(l,{variant:`primary`,onClick:A,disabled:!b.trim(),children:`Submit`})]}),S&&(0,m.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:S})]})]}),(0,m.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:O&&(0,m.jsx)(d,{preferTargetId:w,cacheKey:E,chrome:!1})}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsxs)(`div`,{className:`connect-logos`,children:[(0,m.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,m.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,m.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,m.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`span`,{className:`connect-logo-label`,children:n.productName})]})]}),(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,n.productName]}),(0,m.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,m.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,m.jsx)(`button`,{onClick:j,disabled:g,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:g?`Launching…`:`Open browser first`}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function y({auth:e}){return e.appState===`loading`?(0,m.jsx)(t,{surface:`gate`}):e.appState===`set-pin`?(0,m.jsx)(g,{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,m.jsx)(v,{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,m.jsx)(_,{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:()=>{window.location.href=`/__remote-auth/logout`}}):null}export{p as n,y as t};