@rubytech/create-maxy-code 0.1.602 → 0.1.603

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 (182) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +7 -0
  3. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +15 -1
  4. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  5. package/payload/platform/plugins/docs/references/telegram-guide.md +14 -0
  6. package/payload/platform/plugins/telegram/skills/configure/SKILL.md +15 -1
  7. package/payload/server/public/activity.html +6 -6
  8. package/payload/server/public/agents.html +5 -5
  9. package/payload/server/public/assets/{AdminLoginScreens-CaQqLuxZ.js → AdminLoginScreens-DI5bNlX8.js} +1 -1
  10. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.br +0 -0
  11. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.gz +0 -0
  12. package/payload/server/public/assets/{AdminShell-D8WTrqem.js → AdminShell-B-iX9ahJ.js} +1 -1
  13. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.br +0 -0
  14. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.gz +0 -0
  15. package/payload/server/public/assets/{activity-B3fiJrC2.js → activity-CqgFwANo.js} +1 -1
  16. package/payload/server/public/assets/activity-CqgFwANo.js.br +0 -0
  17. package/payload/server/public/assets/activity-CqgFwANo.js.gz +0 -0
  18. package/payload/server/public/assets/{admin-ouF-DflP.js → admin-K63n6ybW.js} +1 -1
  19. package/payload/server/public/assets/admin-K63n6ybW.js.br +0 -0
  20. package/payload/server/public/assets/admin-K63n6ybW.js.gz +0 -0
  21. package/payload/server/public/assets/{agents-C8RSXHdh.js → agents-cue5Zf8X.js} +1 -1
  22. package/payload/server/public/assets/agents-cue5Zf8X.js.br +0 -0
  23. package/payload/server/public/assets/agents-cue5Zf8X.js.gz +0 -0
  24. package/payload/server/public/assets/{browser-Dbv6-Rag.js → browser-CqDBcKwU.js} +1 -1
  25. package/payload/server/public/assets/browser-CqDBcKwU.js.br +0 -0
  26. package/payload/server/public/assets/browser-CqDBcKwU.js.gz +0 -0
  27. package/payload/server/public/assets/{calendar-vJjtsH9n.js → calendar-BgzuW5Rt.js} +1 -1
  28. package/payload/server/public/assets/calendar-BgzuW5Rt.js.br +0 -0
  29. package/payload/server/public/assets/calendar-BgzuW5Rt.js.gz +0 -0
  30. package/payload/server/public/assets/chat-HYZViu2u.js +1 -0
  31. package/payload/server/public/assets/chat-HYZViu2u.js.br +3 -0
  32. package/payload/server/public/assets/chat-HYZViu2u.js.gz +0 -0
  33. package/payload/server/public/assets/chevron-left-C5FXH9r_.js +1 -0
  34. package/payload/server/public/assets/chevron-left-C5FXH9r_.js.br +0 -0
  35. package/payload/server/public/assets/clock-DxPtyejC.js +1 -0
  36. package/payload/server/public/assets/clock-DxPtyejC.js.br +0 -0
  37. package/payload/server/public/assets/clock-DxPtyejC.js.gz +0 -0
  38. package/payload/server/public/assets/{copy-DyG7sC5o.js → copy-BNhZ0flH.js} +1 -1
  39. package/payload/server/public/assets/copy-BNhZ0flH.js.br +0 -0
  40. package/payload/server/public/assets/copy-BNhZ0flH.js.gz +0 -0
  41. package/payload/server/public/assets/data-kCBB8Z4Z.js +1 -0
  42. package/payload/server/public/assets/data-kCBB8Z4Z.js.br +0 -0
  43. package/payload/server/public/assets/data-kCBB8Z4Z.js.gz +0 -0
  44. package/payload/server/public/assets/{field-Bx6pM-vq.js → field-X4OVA3vx.js} +1 -1
  45. package/payload/server/public/assets/field-X4OVA3vx.js.br +0 -0
  46. package/payload/server/public/assets/field-X4OVA3vx.js.gz +0 -0
  47. package/payload/server/public/assets/{file-text-CpHWsMGe.js → file-text-BddO_2EI.js} +1 -1
  48. package/payload/server/public/assets/file-text-BddO_2EI.js.br +0 -0
  49. package/payload/server/public/assets/file-text-BddO_2EI.js.gz +0 -0
  50. package/payload/server/public/assets/{graph-DjOywuv_.js → graph-l7tzHqvm.js} +1 -1
  51. package/payload/server/public/assets/graph-l7tzHqvm.js.br +0 -0
  52. package/payload/server/public/assets/graph-l7tzHqvm.js.gz +0 -0
  53. package/payload/server/public/assets/{graph-labels-CGWtqa-m.js → graph-labels-CtFFq5W2.js} +1 -1
  54. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.br +0 -0
  55. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.gz +0 -0
  56. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css +1 -0
  57. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.br +0 -0
  58. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.gz +0 -0
  59. package/payload/server/public/assets/{operator-_DN0RF1R.js → operator-Dg-dwf7a.js} +1 -1
  60. package/payload/server/public/assets/operator-Dg-dwf7a.js.br +7 -0
  61. package/payload/server/public/assets/operator-Dg-dwf7a.js.gz +0 -0
  62. package/payload/server/public/assets/{page-DI4qQIK0.js → page-Ci1bfIbs.js} +1 -1
  63. package/payload/server/public/assets/page-Ci1bfIbs.js.br +0 -0
  64. package/payload/server/public/assets/page-Ci1bfIbs.js.gz +0 -0
  65. package/payload/server/public/assets/{page-zCwgrs8m.js → page-Y9JmFq0Q.js} +1 -1
  66. package/payload/server/public/assets/page-Y9JmFq0Q.js.br +0 -0
  67. package/payload/server/public/assets/page-Y9JmFq0Q.js.gz +0 -0
  68. package/payload/server/public/assets/play-BSZVGpQT.js +1 -0
  69. package/payload/server/public/assets/play-BSZVGpQT.js.br +0 -0
  70. package/payload/server/public/assets/play-BSZVGpQT.js.gz +0 -0
  71. package/payload/server/public/assets/{public-DDVWBNSH.js → public-m66FAza_.js} +1 -1
  72. package/payload/server/public/assets/public-m66FAza_.js.br +0 -0
  73. package/payload/server/public/assets/public-m66FAza_.js.gz +0 -0
  74. package/payload/server/public/assets/{rotate-ccw-xTwkf-m7.js → rotate-ccw-DTOJmOxB.js} +1 -1
  75. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.br +0 -0
  76. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.gz +0 -0
  77. package/payload/server/public/assets/{routines-Bu5MdNmG.js → routines-6fxZNacQ.js} +1 -1
  78. package/payload/server/public/assets/routines-6fxZNacQ.js.br +0 -0
  79. package/payload/server/public/assets/routines-6fxZNacQ.js.gz +0 -0
  80. package/payload/server/public/assets/{skills-DRunh5vy.js → skills-51mqx-s5.js} +1 -1
  81. package/payload/server/public/assets/skills-51mqx-s5.js.br +0 -0
  82. package/payload/server/public/assets/skills-51mqx-s5.js.gz +0 -0
  83. package/payload/server/public/assets/{tasks-DI2fznvd.js → tasks-D4y-Cwa3.js} +1 -1
  84. package/payload/server/public/assets/tasks-D4y-Cwa3.js.br +0 -0
  85. package/payload/server/public/assets/tasks-D4y-Cwa3.js.gz +0 -0
  86. package/payload/server/public/assets/{triangle-alert-B6CHZeUf.js → triangle-alert-BzCjDFts.js} +1 -1
  87. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.br +0 -0
  88. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.gz +0 -0
  89. package/payload/server/public/assets/{useCopyFeedback-6rU2IEPk.js → useCopyFeedback-BG7h37Rx.js} +1 -1
  90. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.br +2 -0
  91. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.gz +0 -0
  92. package/payload/server/public/assets/{useMediaQuery-D7A5Bzs3.js → useMediaQuery-CqwktQr_.js} +1 -1
  93. package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.br +0 -0
  94. package/payload/server/public/assets/{useMediaQuery-D7A5Bzs3.js.gz → useMediaQuery-CqwktQr_.js.gz} +0 -0
  95. package/payload/server/public/assets/{useVoiceRecorder-CptrerVA.js → useVoiceRecorder-CAZcUc1s.js} +1 -1
  96. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.br +0 -0
  97. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.gz +0 -0
  98. package/payload/server/public/assets/{wrench-DyX4C8aY.js → wrench-B2WKLLQG.js} +1 -1
  99. package/payload/server/public/assets/wrench-B2WKLLQG.js.br +0 -0
  100. package/payload/server/public/assets/wrench-B2WKLLQG.js.gz +0 -0
  101. package/payload/server/public/browser.html +5 -5
  102. package/payload/server/public/calendar.html +8 -8
  103. package/payload/server/public/chat.html +14 -14
  104. package/payload/server/public/data.html +12 -12
  105. package/payload/server/public/field.html +3 -3
  106. package/payload/server/public/graph.html +10 -10
  107. package/payload/server/public/index.html +14 -14
  108. package/payload/server/public/operator.html +15 -15
  109. package/payload/server/public/public.html +14 -14
  110. package/payload/server/public/routines.html +8 -8
  111. package/payload/server/public/skills.html +6 -6
  112. package/payload/server/public/tasks.html +7 -7
  113. package/payload/server/server.js +436 -325
  114. package/payload/server/public/assets/AdminLoginScreens-CaQqLuxZ.js.br +0 -0
  115. package/payload/server/public/assets/AdminLoginScreens-CaQqLuxZ.js.gz +0 -0
  116. package/payload/server/public/assets/AdminShell-D8WTrqem.js.br +0 -0
  117. package/payload/server/public/assets/AdminShell-D8WTrqem.js.gz +0 -0
  118. package/payload/server/public/assets/activity-B3fiJrC2.js.br +0 -0
  119. package/payload/server/public/assets/activity-B3fiJrC2.js.gz +0 -0
  120. package/payload/server/public/assets/admin-ouF-DflP.js.br +0 -0
  121. package/payload/server/public/assets/admin-ouF-DflP.js.gz +0 -0
  122. package/payload/server/public/assets/agents-C8RSXHdh.js.br +0 -0
  123. package/payload/server/public/assets/agents-C8RSXHdh.js.gz +0 -0
  124. package/payload/server/public/assets/browser-Dbv6-Rag.js.br +0 -0
  125. package/payload/server/public/assets/browser-Dbv6-Rag.js.gz +0 -0
  126. package/payload/server/public/assets/calendar-vJjtsH9n.js.br +0 -0
  127. package/payload/server/public/assets/calendar-vJjtsH9n.js.gz +0 -0
  128. package/payload/server/public/assets/chat-cqL4qPUy.js +0 -1
  129. package/payload/server/public/assets/chat-cqL4qPUy.js.br +0 -1
  130. package/payload/server/public/assets/chat-cqL4qPUy.js.gz +0 -0
  131. package/payload/server/public/assets/chevron-left-DB98DSG3.js +0 -1
  132. package/payload/server/public/assets/chevron-left-DB98DSG3.js.br +0 -0
  133. package/payload/server/public/assets/clock-4YwsYe4L.js +0 -1
  134. package/payload/server/public/assets/clock-4YwsYe4L.js.br +0 -0
  135. package/payload/server/public/assets/clock-4YwsYe4L.js.gz +0 -0
  136. package/payload/server/public/assets/copy-DyG7sC5o.js.br +0 -0
  137. package/payload/server/public/assets/copy-DyG7sC5o.js.gz +0 -0
  138. package/payload/server/public/assets/data-BAzLtx9C.js +0 -1
  139. package/payload/server/public/assets/data-BAzLtx9C.js.br +0 -0
  140. package/payload/server/public/assets/data-BAzLtx9C.js.gz +0 -0
  141. package/payload/server/public/assets/field-Bx6pM-vq.js.br +0 -0
  142. package/payload/server/public/assets/field-Bx6pM-vq.js.gz +0 -0
  143. package/payload/server/public/assets/file-text-CpHWsMGe.js.br +0 -0
  144. package/payload/server/public/assets/file-text-CpHWsMGe.js.gz +0 -0
  145. package/payload/server/public/assets/graph-DjOywuv_.js.br +0 -0
  146. package/payload/server/public/assets/graph-DjOywuv_.js.gz +0 -0
  147. package/payload/server/public/assets/graph-labels-CGWtqa-m.js.br +0 -0
  148. package/payload/server/public/assets/graph-labels-CGWtqa-m.js.gz +0 -0
  149. package/payload/server/public/assets/jsx-runtime-D75_aR1J.css +0 -1
  150. package/payload/server/public/assets/jsx-runtime-D75_aR1J.css.br +0 -0
  151. package/payload/server/public/assets/jsx-runtime-D75_aR1J.css.gz +0 -0
  152. package/payload/server/public/assets/operator-_DN0RF1R.js.br +0 -0
  153. package/payload/server/public/assets/operator-_DN0RF1R.js.gz +0 -0
  154. package/payload/server/public/assets/page-DI4qQIK0.js.br +0 -0
  155. package/payload/server/public/assets/page-DI4qQIK0.js.gz +0 -0
  156. package/payload/server/public/assets/page-zCwgrs8m.js.br +0 -0
  157. package/payload/server/public/assets/page-zCwgrs8m.js.gz +0 -0
  158. package/payload/server/public/assets/play-CHQ5a9yh.js +0 -1
  159. package/payload/server/public/assets/play-CHQ5a9yh.js.br +0 -0
  160. package/payload/server/public/assets/play-CHQ5a9yh.js.gz +0 -0
  161. package/payload/server/public/assets/public-DDVWBNSH.js.br +0 -0
  162. package/payload/server/public/assets/public-DDVWBNSH.js.gz +0 -0
  163. package/payload/server/public/assets/rotate-ccw-xTwkf-m7.js.br +0 -0
  164. package/payload/server/public/assets/rotate-ccw-xTwkf-m7.js.gz +0 -0
  165. package/payload/server/public/assets/routines-Bu5MdNmG.js.br +0 -0
  166. package/payload/server/public/assets/routines-Bu5MdNmG.js.gz +0 -0
  167. package/payload/server/public/assets/skills-DRunh5vy.js.br +0 -0
  168. package/payload/server/public/assets/skills-DRunh5vy.js.gz +0 -0
  169. package/payload/server/public/assets/tasks-DI2fznvd.js.br +0 -0
  170. package/payload/server/public/assets/tasks-DI2fznvd.js.gz +0 -0
  171. package/payload/server/public/assets/triangle-alert-B6CHZeUf.js.br +0 -0
  172. package/payload/server/public/assets/triangle-alert-B6CHZeUf.js.gz +0 -0
  173. package/payload/server/public/assets/useCopyFeedback-6rU2IEPk.js.br +0 -2
  174. package/payload/server/public/assets/useCopyFeedback-6rU2IEPk.js.gz +0 -0
  175. package/payload/server/public/assets/useMediaQuery-D7A5Bzs3.js.br +0 -0
  176. package/payload/server/public/assets/useVoiceRecorder-CptrerVA.js.br +0 -0
  177. package/payload/server/public/assets/useVoiceRecorder-CptrerVA.js.gz +0 -0
  178. package/payload/server/public/assets/wrench-DyX4C8aY.js.br +0 -0
  179. package/payload/server/public/assets/wrench-DyX4C8aY.js.gz +0 -0
  180. /package/payload/server/public/assets/{jsx-runtime-B2Q1UOSJ.js → jsx-runtime-UK6hgBWO.js} +0 -0
  181. /package/payload/server/public/assets/{jsx-runtime-B2Q1UOSJ.js.br → jsx-runtime-UK6hgBWO.js.br} +0 -0
  182. /package/payload/server/public/assets/{jsx-runtime-B2Q1UOSJ.js.gz → jsx-runtime-UK6hgBWO.js.gz} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.602",
3
+ "version": "0.1.603",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -72,6 +72,13 @@ FOR (d:DefinedTerm) ON (d.category);
72
72
  CREATE INDEX person_status IF NOT EXISTS
73
73
  FOR (p:Person) ON (p.status);
74
74
 
75
+ // Person.telegramUserId — the key an inbound Telegram turn resolves the
76
+ // speaker's name by (Task 2705). Composite with accountId because the lookup is
77
+ // always account-scoped and neither property is indexed alone: without this the
78
+ // read is a label scan over every Person in the database, on a message path.
79
+ CREATE INDEX person_account_telegram_user_id IF NOT EXISTS
80
+ FOR (p:Person) ON (p.accountId, p.telegramUserId);
81
+
75
82
  // Review (schema:Review) — competitor comparison assessments
76
83
  CREATE INDEX review_item_reviewed IF NOT EXISTS
77
84
  FOR (r:Review) ON (r.itemReviewed);
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:e4040096c05f9e3fb874192816e5dfba38bb5d72f70c6ecc95a3ba7e03c246e0
4
+ content-hash: sha256:2a7e28897d543df02b543552d72a457eca3956ab090a4bc5b886b487eb950d3e
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -2945,6 +2945,20 @@ store, so what Maxy tells you and what actually arrived cannot drift apart.
2945
2945
 
2946
2946
  If Maxy ever says a Telegram message cannot be sent, ask it to check that list first.
2947
2947
 
2948
+ ### How your bot knows who is talking to it
2949
+
2950
+ Allowing someone's Telegram ID lets them message the bot. It does not tell the bot who they are: an
2951
+ ID is a number, and the only other name available is whatever that person's own Telegram profile is
2952
+ called, which is often a device or account label rather than a person.
2953
+
2954
+ Maxy reads the name from your contacts. When a Telegram ID is saved on someone's contact
2955
+ record, every message from that ID arrives with their name attached, so you get a proper greeting and
2956
+ Maxy knows whose request it is handling. When it is not saved, it falls back to the
2957
+ Telegram profile name and will tell you plainly that it cannot put a name to the sender.
2958
+
2959
+ Ask Maxy to save the Telegram ID against the contact. It is one change to one contact, and
2960
+ it takes effect on the very next message.
2961
+
2948
2962
  ## Getting a Chat ID
2949
2963
 
2950
2964
  To message a specific person or group, Maxy needs their chat ID. The easiest way:
@@ -9,6 +9,12 @@ Invoked by the admin agent directly.
9
9
 
10
10
  This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
11
11
 
12
+ ## 2026-08-13 (0.1.603)
13
+
14
+ - Your Telegram assistant now knows who it is talking to. When someone's Telegram ID is saved on their contact record, every message from them arrives with their name attached, instead of the assistant seeing only a number or whatever that person's Telegram profile happens to be called.
15
+ - Setting up an admin bot now asks who each allowed ID belongs to, and saves the answer against the contact, so the names you give are kept rather than lost.
16
+ - An hourly check reports any allowed Telegram ID that is not yet matched to a contact, so a missed one is noticed without anyone having to message the bot.
17
+
12
18
  ## 2026-08-13 (0.1.602)
13
19
 
14
20
  - Voice and video sends from the webchat composer are now accepted the moment the upload lands, instead of holding the confirmation until transcription completes.
@@ -124,6 +124,20 @@ store, so what {{productName}} tells you and what actually arrived cannot drift
124
124
 
125
125
  If {{productName}} ever says a Telegram message cannot be sent, ask it to check that list first.
126
126
 
127
+ ### How your bot knows who is talking to it
128
+
129
+ Allowing someone's Telegram ID lets them message the bot. It does not tell the bot who they are: an
130
+ ID is a number, and the only other name available is whatever that person's own Telegram profile is
131
+ called, which is often a device or account label rather than a person.
132
+
133
+ {{productName}} reads the name from your contacts. When a Telegram ID is saved on someone's contact
134
+ record, every message from that ID arrives with their name attached, so you get a proper greeting and
135
+ {{productName}} knows whose request it is handling. When it is not saved, it falls back to the
136
+ Telegram profile name and will tell you plainly that it cannot put a name to the sender.
137
+
138
+ Ask {{productName}} to save the Telegram ID against the contact. It is one change to one contact, and
139
+ it takes effect on the very next message.
140
+
127
141
  ## Getting a Chat ID
128
142
 
129
143
  To message a specific person or group, {{productName}} needs their chat ID. The easiest way:
@@ -56,7 +56,7 @@ Skip this step entirely when the account already has a working admin bot: use `t
56
56
 
57
57
  Ask which role this bot serves (see `references/setup-guide.md` "Admin Bot vs Public Bot"). The role is stated by the operator, never worked out from anything else: it decides which spawn path the bot's messages take.
58
58
 
59
- - **Admin bot** — only the numeric Telegram user IDs the operator names for THIS bot may message it; everything else is denied. Collect those IDs (`references/setup-guide.md` "Finding Your Telegram User ID"). It answers as the admin agent.
59
+ - **Admin bot** — only the numeric Telegram user IDs the operator names for THIS bot may message it; everything else is denied. Collect those IDs (`references/setup-guide.md` "Finding Your Telegram User ID"), and collect **who each one is**. The ID is what admits them; the name is what the agent greets them by, and it reaches the turn only through a contact record (Step 4b). An ID nobody is named for is still admitted. It answers as the admin agent.
60
60
  - **Public bot** — customer-facing; choose a DM policy (`open`, `allowlist`, or `disabled`), for `allowlist` the allowed numeric IDs, and **which of this account's agents answers on it**. Call `account-manage` to list the account's agents and let the operator pick one. The agent must be active; the register tool refuses an inactive or unknown slug.
61
61
  - **Specialist bot** — a bot bound to one of the account's own specialist cards, so messaging it runs that specialist with its own prompt and its own tools instead of the admin seat. Collect two things: **which card** (the file name under the account's `specialists/agents/`, without `.md` — that is the name the spawn resolves, not the card's title) and **who may message it** (numeric IDs). Both are required: there is no open policy for this role, because the session carries the card's own tool surface rather than the public zero-tool ringfence.
62
62
 
@@ -100,6 +100,20 @@ The chat is what is admitted, not its members: once a group is allowlisted, anyo
100
100
 
101
101
  A group is one conversation, not one per member: everyone in the room shares a single thread and a single session, and each turn names who spoke.
102
102
 
103
+ ### Step 4b — Bind each admitted ID to the person it belongs to
104
+
105
+ Only for an admin bot, and only for the IDs the operator named someone for.
106
+
107
+ `adminUsers` is an access list of numbers. It says who may message the bot, never who they are, and it holds no name field. The agent learns a sender's name from the account's own contact record: the turn resolves the sender's numeric ID against `:Person.telegramUserId` and greets them by that name, falling back to whatever the sender's Telegram profile calls itself when nothing matches. An ID left unbound therefore produces the old behaviour, where the agent cannot say who is typing.
108
+
109
+ For each ID with a name, in this order:
110
+
111
+ - `contact-lookup` by that name. On exactly one match, `contact-update` that node with `telegramUserId` set to the numeric ID. That is the whole binding.
112
+ - On several matches, report them to the operator and bind nothing. Picking between two people would name every future turn after a guess.
113
+ - On no match, `contact-create` with the name, `telegramUserId`, `source: telegram`, and a relationship to the account's Organization found via `memory-search`. When the account has no Organization to link to, create nothing: say the ID is admitted but unbound, and that the person needs a contact record first.
114
+
115
+ Then tell the operator which IDs are bound and which are not. `[telegram-audit] op=identity-census` reconciles the same thing hourly, so an ID that was missed is reported without anyone messaging the bot.
116
+
103
117
  ## Setting a bot up in a channel
104
118
 
105
119
  The outcome is that a post in an allowlisted channel reaches the agent, that the agent can post to
@@ -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-B3fiJrC2.js"></script>
8
+ <script type="module" crossorigin src="/assets/activity-CqgFwANo.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-BycB0eMI.js">
10
- <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-B2Q1UOSJ.js">
11
- <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-D7A5Bzs3.js">
12
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-D8WTrqem.js">
13
- <link rel="modulepreload" crossorigin href="/assets/triangle-alert-B6CHZeUf.js">
14
- <link rel="stylesheet" crossorigin href="/assets/jsx-runtime-D75_aR1J.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-UK6hgBWO.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-CqwktQr_.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-B-iX9ahJ.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/triangle-alert-BzCjDFts.js">
14
+ <link rel="stylesheet" crossorigin href="/assets/jsx-runtime-bq0g4NlA.css">
15
15
  <link rel="stylesheet" crossorigin href="/assets/useMediaQuery-DXAuc8G-.css">
16
16
  <link rel="stylesheet" href="/brand-defaults.css">
17
17
  </head>
@@ -5,12 +5,12 @@
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-C8RSXHdh.js"></script>
8
+ <script type="module" crossorigin src="/assets/agents-cue5Zf8X.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-BycB0eMI.js">
10
- <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-B2Q1UOSJ.js">
11
- <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-D7A5Bzs3.js">
12
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-D8WTrqem.js">
13
- <link rel="stylesheet" crossorigin href="/assets/jsx-runtime-D75_aR1J.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-UK6hgBWO.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/useMediaQuery-CqwktQr_.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-B-iX9ahJ.js">
13
+ <link rel="stylesheet" crossorigin href="/assets/jsx-runtime-bq0g4NlA.css">
14
14
  <link rel="stylesheet" crossorigin href="/assets/useMediaQuery-DXAuc8G-.css">
15
15
  <link rel="stylesheet" href="/brand-defaults.css">
16
16
  </head>
@@ -1 +1 @@
1
- import{o as e}from"./chunk-BycB0eMI.js";import{i as t,t as n}from"./jsx-runtime-B2Q1UOSJ.js";import{O as r,Q as i,et as a,rt as o}from"./useMediaQuery-D7A5Bzs3.js";import{j as s}from"./useVoiceRecorder-CptrerVA.js";import{A as c,O as l,k as u,p as d}from"./AdminShell-D8WTrqem.js";var f=e(t(),1);function p(e=`admin`){let[t,n]=(0,f.useState)(`loading`),[r,i]=(0,f.useState)(``),[a,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`){o(`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`){o(`enter-pin`,`/api/admin/session`);return}d(e.error||`Invalid PIN`);return}let a=await r.json();w(a.session_key),I(a.sessionId??null),O(a.businessName),A(a.role??null),M(a.userName===void 0?null:a.userName),P(a.avatar??null);let c=s(a.thinkingView);z.current=c,R(c);try{sessionStorage.setItem(`maxy-admin-session-key`,a.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=a.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`){o(`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,a]),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:a,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=n();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:n,showPin:r,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:a,alt:i.productName,className:`connect-logo connect-logo--maxy`}),!i.logoContainsName&&(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,i.productName]}),(0,m.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,i.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:n,onComplete:()=>{},showPin:r}),(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:r,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function _(e){let{pin:t,setPin:n,showPin:r,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:a,alt:i.productName,className:`connect-logo connect-logo--maxy`}),!i.logoContainsName&&(0,m.jsx)(`h1`,{className:`connect-title`,children:i.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:n,onComplete:()=>{},showPin:r,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:r,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:n,authLoading:r,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),A=(0,f.useRef)(0);(0,f.useEffect)(()=>{try{D(sessionStorage.getItem(`maxy-admin-session-key`))}catch{}k(!0)},[]);async function j(){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 M(){_(!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 N(){let e=++A.current;o(!0),c(``);try{let t=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(t.started){n(!0),h(!0),o(!1),y(t.transport||``);for(let t=0;t<120;t++){if(await new Promise(e=>setTimeout(e,2e3)),A.current!==e)return;let t=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json();if(typeof t.authTargetId==`string`&&T(t.authTargetId),t.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.`),n(!1)}else t.error&&c(t.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function P(){A.current++,await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!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:P,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:N,disabled:r,children:r?(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:j,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:a,alt:i.productName,className:`connect-logo connect-logo--maxy`}),!i.logoContainsName&&(0,m.jsx)(`span`,{className:`connect-logo-label`,children:i.productName})]})]}),(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,i.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:N,disabled:r,children:r?(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:M,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)(r,{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-BycB0eMI.js";import{i as t,t as n}from"./jsx-runtime-UK6hgBWO.js";import{O as r,Q as i,et as a,rt as o}from"./useMediaQuery-CqwktQr_.js";import{j as s}from"./useVoiceRecorder-CAZcUc1s.js";import{A as c,O as l,k as u,p as d}from"./AdminShell-B-iX9ahJ.js";var f=e(t(),1);function p(e=`admin`){let[t,n]=(0,f.useState)(`loading`),[r,i]=(0,f.useState)(``),[a,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`){o(`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`){o(`enter-pin`,`/api/admin/session`);return}d(e.error||`Invalid PIN`);return}let a=await r.json();w(a.session_key),I(a.sessionId??null),O(a.businessName),A(a.role??null),M(a.userName===void 0?null:a.userName),P(a.avatar??null);let c=s(a.thinkingView);z.current=c,R(c);try{sessionStorage.setItem(`maxy-admin-session-key`,a.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=a.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`){o(`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,a]),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:a,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=n();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:n,showPin:r,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:a,alt:i.productName,className:`connect-logo connect-logo--maxy`}),!i.logoContainsName&&(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,i.productName]}),(0,m.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,i.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:n,onComplete:()=>{},showPin:r}),(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:r,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function _(e){let{pin:t,setPin:n,showPin:r,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:a,alt:i.productName,className:`connect-logo connect-logo--maxy`}),!i.logoContainsName&&(0,m.jsx)(`h1`,{className:`connect-title`,children:i.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:n,onComplete:()=>{},showPin:r,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:r,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:n,authLoading:r,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),A=(0,f.useRef)(0);(0,f.useEffect)(()=>{try{D(sessionStorage.getItem(`maxy-admin-session-key`))}catch{}k(!0)},[]);async function j(){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 M(){_(!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 N(){let e=++A.current;o(!0),c(``);try{let t=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(t.started){n(!0),h(!0),o(!1),y(t.transport||``);for(let t=0;t<120;t++){if(await new Promise(e=>setTimeout(e,2e3)),A.current!==e)return;let t=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json();if(typeof t.authTargetId==`string`&&T(t.authTargetId),t.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.`),n(!1)}else t.error&&c(t.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function P(){A.current++,await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!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:P,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:N,disabled:r,children:r?(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:j,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:a,alt:i.productName,className:`connect-logo connect-logo--maxy`}),!i.logoContainsName&&(0,m.jsx)(`span`,{className:`connect-logo-label`,children:i.productName})]})]}),(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,i.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:N,disabled:r,children:r?(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:M,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)(r,{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};