@rubytech/create-maxy-code 0.1.324 → 0.1.326
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/lib/models/dist/index.d.ts +9 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +17 -3
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +17 -2
- package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +13 -7
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
- package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +9 -3
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/slides/skills/deck-system/SKILL.md +2 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +30 -10
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +1 -1
- package/payload/premium-plugins/management-consulting/.claude-plugin/plugin.json +1 -1
- package/payload/premium-plugins/management-consulting/PLUGIN.md +3 -2
- package/payload/premium-plugins/management-consulting/skills/pitch-deck/SKILL.md +142 -0
- package/payload/server/public/assets/{AdminLoginScreens-BaNHSvDG.js → AdminLoginScreens-DNsCEyvZ.js} +1 -1
- package/payload/server/public/assets/AdminShell-DqyjA9x-.js +1 -0
- package/payload/server/public/assets/{Checkbox-BoljWa0z.js → Checkbox-C3WNcLH8.js} +1 -1
- package/payload/server/public/assets/{OperatorConversations-DL9372pQ.css → OperatorConversations-BQudGb45.css} +1 -1
- package/payload/server/public/assets/{admin-DgGttnBt.js → admin-3jmCp4G3.js} +1 -1
- package/payload/server/public/assets/{browser-BLoa93fm.js → browser-DarU3c-V.js} +1 -1
- package/payload/server/public/assets/chat-CG-r6QZ2.js +1 -0
- package/payload/server/public/assets/{data-BK_ggj-z.js → data-4jByS_fv.js} +1 -1
- package/payload/server/public/assets/{graph-iNIIHeRn.js → graph-CylZ1wV1.js} +1 -1
- package/payload/server/public/assets/{graph-labels-IeLlsqB1.js → graph-labels-hGbD_0qZ.js} +1 -1
- package/payload/server/public/assets/{operator-plsrZHSk.js → operator-DgGt6Hc0.js} +1 -1
- package/payload/server/public/assets/page-Dl3SpCO3.js +30 -0
- package/payload/server/public/assets/{public-CuMZDmDF.js → public-8hwaomIS.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/chat.html +5 -5
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/operator.html +7 -7
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +5 -1
- package/payload/server/public/assets/AdminShell-6Iq4co_0.js +0 -1
- package/payload/server/public/assets/chat-BJ4229vV.js +0 -1
- package/payload/server/public/assets/page-BOQHw8Fa.js +0 -30
- /package/payload/server/public/assets/{OperatorConversations-yKFxglvV.js → OperatorConversations-BqFmHTF1.js} +0 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pitch-deck
|
|
3
|
+
description: Composes a management-consulting slide deck in the operator's own house voice. Three modes: a new-business or credentials pitch that wins the work, a client findings or recommendation deck that drives a decision, and a thought-leadership deck that positions a point of view. Use for a consulting pitch deck, a capabilities or credentials deck, a client findings deck, a recommendation or steering-committee deck, a board strategy deck, or a thought-leadership or point-of-view deck. Owns the consulting deck method (answer-first pyramid, SCQA/SCR, MECE, full-sentence action titles) and runs every line of prose through plain English and the house voice before it is drafted. Not a founder fundraise deck; that is `venture-studio:investor-data-room`. Not a generic renderer for arbitrary HTML slides; that is `admin:deck-pages`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pitch Deck
|
|
7
|
+
|
|
8
|
+
The consulting bundle's terminal visual deliverable. The sibling skills diagnose, map, choose, and govern; this skill turns their outputs into a deck that earns a decision or wins the work. It owns the method and the voice. It composes only from facts the operator already curated, and it never invents a financial number.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
Pick the mode from the brief. All three live in this one skill.
|
|
13
|
+
|
|
14
|
+
| Mode | Use it when | Engine |
|
|
15
|
+
|------|-------------|--------|
|
|
16
|
+
| **A: new-business / credentials pitch** | The goal is to win the work: a capabilities deck, a credentials pitch, a "why us" deck for a prospect | Fixed spine + domain-themed middle + optional sections (below) |
|
|
17
|
+
| **B: client findings / recommendation** | The goal is to drive a decision: a findings deck, a recommendation, a steering-committee or board deck | SCR, reusing `slides:deck-system` `STORYTELLING-mbb.md` |
|
|
18
|
+
| **C: thought-leadership / topic** | The goal is to position a point of view: an industry report, a trends deck, a conference talk | Content-led with a short credentials tail |
|
|
19
|
+
|
|
20
|
+
### When not to use
|
|
21
|
+
|
|
22
|
+
- **Founder fundraise deck** (seed/Series raise, investor pitch under the founder's own name) routes to `venture-studio:investor-data-room`.
|
|
23
|
+
- **"Save this HTML as a deck", arbitrary fixed-dimension slide layout, a deck the operator already wrote** routes to `admin:deck-pages` (the format spec and generic slide renderer).
|
|
24
|
+
|
|
25
|
+
## Where this runs
|
|
26
|
+
|
|
27
|
+
This skill composes on the **admin seat**. The voice tools it depends on are admin-allowlisted, so a specialist cannot run the voice gate. The output of this skill is a **render brief**: the composed slide content (action titles, body, charts, footnotes) plus the style card and exemplars from the voice mirror. The admin agent hands that brief to `specialists:content-producer`, which renders it through `slides:deck-system` and exports the PDF. This skill writes no renderer and runs no browser tool.
|
|
28
|
+
|
|
29
|
+
## The method (all three modes)
|
|
30
|
+
|
|
31
|
+
The generation contract. Apply it before and during every mode.
|
|
32
|
+
|
|
33
|
+
- **Ghost deck first.** Write the full action-title string for the whole deck before any body, chart, or theme. The titles alone are the deck. Build the body only once the title string tells the story.
|
|
34
|
+
- **Answer first (Pyramid).** Lead with the recommendation or the core message. Everything after it is support. The recommendation sits at the top; three to five arguments below it; evidence below each.
|
|
35
|
+
- **SCQA / SCR opening.** Open on common ground (Situation), name the tension (Complication / Question), then the answer (Resolution / Answer). Mode B runs this across the whole deck; Modes A and C use it to open.
|
|
36
|
+
- **MECE grouping.** Every breakdown (findings, services, segments, causes) has parts that do not overlap and together leave no gap. If two points say the same thing, merge them.
|
|
37
|
+
- **Action titles.** Every slide headline is a full-sentence conclusion, not a topic label. "The European market contracted 12% in Q3", not "Market overview". If you cannot write the action title, the slide has no point yet; find the point first.
|
|
38
|
+
- **One message per slide, vertical logic.** Each slide makes exactly one point. The body proves the title and nothing else. Cut anything that does not.
|
|
39
|
+
- **"So what" prune.** For every slide, answer "so what?". A slide that survives only as background is appendix material or is cut.
|
|
40
|
+
- **Reverse-storyboard the horizontal logic.** Read the action titles top to bottom as a list, with no bodies and no charts. They must tell one coherent story and the recommendation must feel inevitable by the end. If the line of titles jumps or repeats, fix the titles before touching the bodies.
|
|
41
|
+
- **Source footnote on every data slide.** Every slide that carries a number shows where the number came from: a graph node, a named publication, or the operator's own figures. A numbered slide with no source line is a defect.
|
|
42
|
+
- **Never invent numbers.** Figures come only from the operator's data or from a sibling skill's output. If a number is missing, leave a visible gap and ask for it; do not fill it.
|
|
43
|
+
|
|
44
|
+
## Prose pipeline (runs before any slide copy is drafted)
|
|
45
|
+
|
|
46
|
+
Non-negotiable, and it runs before the first word of slide prose. A method-less or voice-less deck reads as generic AI consulting copy under the operator's own business name, which is worse than no deck.
|
|
47
|
+
|
|
48
|
+
### 1. Plain English
|
|
49
|
+
|
|
50
|
+
The first prose action of the turn is `skill-load skillName=plainly`. Apply it to every prose payload this skill emits: action titles, the executive-summary lines, slide body, captions, and the summary you return to the admin agent. Recursive plain English: an explanation may not itself contain a term that needs explaining. No consulting jargon survives the polish.
|
|
51
|
+
|
|
52
|
+
### 2. Voice mirror (hard gate)
|
|
53
|
+
|
|
54
|
+
A deck ships under the business name, so it uses the **house voice**, not any one person's personal voice. Before drafting any prose, call `voice-retrieve-conditioning` with `format: "article"`, `length: "long"`, `scope: "org"`, and `topic` set to the engagement domain (for example "operating-model redesign for a regional bank"). The tool itself emits `[voice-retrieve] scope=org format=article status=<s> styleCardBytes=<n> exemplarCount=<k>`; you do not write that line.
|
|
55
|
+
|
|
56
|
+
Then gate on `status`. This diverges from the sibling composers, which silently degrade to a default register; this skill stops instead.
|
|
57
|
+
|
|
58
|
+
- **`ok`** (a style card and/or exemplars came back) conditions every prose payload on the style card and exemplars, then drafts. Output carries the style card's favoured terms and avoids its taboos.
|
|
59
|
+
- **`no-data` | `error`** stops. **Draft no slide prose.** Tell the operator the deck voice is not established and offer two routes: (a) establish the house voice through the voice-mirror skill (backfill or distil their own writing) then re-run, or (b) supply the deck prose themselves, which this skill will then only structure and polish through plain English, never generate.
|
|
60
|
+
|
|
61
|
+
A `scope: "org"` request returns only `ok`, `no-data`, or `error`; `fallback-org` arises solely on a personal-scope request, so it does not occur here. If it ever does, treat it as `ok` since it still carries an org style card.
|
|
62
|
+
|
|
63
|
+
Emit one decision line after the gate, so the choice is logged rather than inferred:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
[pitch-deck] voice-gate status=<ok|no-data|error> action=<conditioned|stopped|operator-prose>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`conditioned` when you drafted on a style card, `stopped` when the gate halted drafting, `operator-prose` when the operator supplied the prose and you only structured and polished it.
|
|
70
|
+
|
|
71
|
+
## Mode A: new-business / credentials pitch
|
|
72
|
+
|
|
73
|
+
Win the work. A fixed spine appears in every deck of this kind; a short domain-themed middle and an optional section set flex the deck to 11–14 slides for the engagement.
|
|
74
|
+
|
|
75
|
+
**Spine (always present, in order):** Cover, Contents, Introduction, Philosophy / Approach, **Services**, *[domain-themed middle]*, **Case Studies**, **Performance Metrics (KPIs)**, **Team**, Contact.
|
|
76
|
+
|
|
77
|
+
**Domain-themed middle (2–5 slides):** the firm's specialty rendered as its own steps: methodology, process, strategy, operational-excellence, or risk steps. A risk advisory firm shows its risk method here; a transformation firm shows its delivery method.
|
|
78
|
+
|
|
79
|
+
**Optional sections (toggle to reach 11–14 slides):** Market Analysis, Testimonials, Industry Experience / Expertise, Why-Choose / CTA.
|
|
80
|
+
|
|
81
|
+
Select the middle and the optionals from the brief. Do not hard-code one slide list; compose the spine plus the sections the engagement needs.
|
|
82
|
+
|
|
83
|
+
## Mode B: client findings / recommendation
|
|
84
|
+
|
|
85
|
+
Drive a decision. This mode reuses the SCR engine in `slides:deck-system` `STORYTELLING-mbb.md`; read that file and follow it. Do not restate SCR here.
|
|
86
|
+
|
|
87
|
+
**Shape:** Title / Agenda, then a one-page **Executive summary** (SCR, Resolution leading at 60–70% of the message, a bold takeaway over indented supporting numbers), then Situation, Complication, Findings (MECE, action-titled, one chart per finding), Recommendation, Implementation roadmap (Gantt), Next steps, Appendix. The executive summary is written first and rewritten last; a reader who sees only that slide knows the recommendation, the reasoning, and the next step.
|
|
88
|
+
|
|
89
|
+
## Mode C: thought-leadership / topic
|
|
90
|
+
|
|
91
|
+
Position a point of view. Content-led demand generation, with no client-specific recommendation and no commercial sell; that is what separates it from Modes B and A.
|
|
92
|
+
|
|
93
|
+
**Shape:** Cover, Overview, a hook (a single headline statistic), topic sections (trends, then data, then implications, then challenges, then what to do: transformation / adaptation / innovation), a short About-us / Values credentials tail, Contact / CTA.
|
|
94
|
+
|
|
95
|
+
## Chart kit
|
|
96
|
+
|
|
97
|
+
Match the chart to the message. `slides:deck-system` ships no consulting-chart component, so build these on-token using its freestyle rules (stay on the theme's colours, fonts, and spacing; name the class; keep the CSS inline). Lead with them in Mode B; they are available to all modes.
|
|
98
|
+
|
|
99
|
+
| Chart | Use it for |
|
|
100
|
+
|-------|-----------|
|
|
101
|
+
| **Waterfall / bridge** | A measure moving between two points (a cost or margin walk) |
|
|
102
|
+
| **Marimekko / Mekko** | Segment × share in one view (market structure) |
|
|
103
|
+
| **2×2, including BCG growth-share** | Prioritisation or portfolio choices |
|
|
104
|
+
| **Gantt** | A phased roadmap with owners and dates |
|
|
105
|
+
|
|
106
|
+
## Bridge from the analysis skills
|
|
107
|
+
|
|
108
|
+
The deck composes the outputs of the other consulting skills. Numbers come from those outputs or the operator's data only.
|
|
109
|
+
|
|
110
|
+
| Sibling output | Lands in |
|
|
111
|
+
|----------------|----------|
|
|
112
|
+
| `situation-assessment` | Situation |
|
|
113
|
+
| `market-mapping` / `profit-pool-analysis` | Findings / Market Analysis + a Mekko |
|
|
114
|
+
| `strategic-options` | Recommendation + a 2×2 |
|
|
115
|
+
| `business-case-builder` | Economics + a waterfall |
|
|
116
|
+
| `transformation-roadmap` | Implementation + a Gantt |
|
|
117
|
+
| `narrative-builder` / `stakeholder-alignment` | Executive summary + pre-wire |
|
|
118
|
+
|
|
119
|
+
## Render handoff
|
|
120
|
+
|
|
121
|
+
When `slides` is enabled, the render path is `slides:deck-system`: it carries 25 HTML components, the design tokens, the themes, and the PDF export. Hand `content-producer` the composed render brief and let it render through `deck-system`; the PDF exports via the existing path. There is no new renderer.
|
|
122
|
+
|
|
123
|
+
When `slides` is not enabled, say so and fall back to the always-present `admin:deck-pages` format spec for a slide-based PDF. Never return a blank turn because a dependency is absent.
|
|
124
|
+
|
|
125
|
+
Implement open frameworks in the operator's own brand. Never embed a named firm's branded template or assets.
|
|
126
|
+
|
|
127
|
+
## Quality bar
|
|
128
|
+
|
|
129
|
+
- The action-title string alone tells the whole story (reverse-storyboard passes).
|
|
130
|
+
- Every data slide carries a source line, and every number traces to the brief or a sibling output.
|
|
131
|
+
- The executive summary (Mode B) stands alone on one slide.
|
|
132
|
+
- Mode A lands at 11–14 slides by toggling the optional sections, not by padding.
|
|
133
|
+
- Every prose payload passed through plain English; nothing reads as generic AI consulting copy.
|
|
134
|
+
- The voice gate decided before any prose was drafted, and the decision is logged.
|
|
135
|
+
|
|
136
|
+
## Observability
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
[pitch-deck] voice-gate status=<ok|no-data|error> action=<conditioned|stopped|operator-prose>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The `[voice-retrieve] …` line is emitted by the voice tool itself. A render or export failure surfaces through `content-producer`'s existing `[tool-failure-diag]` line. A misroute is visible as the **absence** of a `skill-load skillName=pitch-deck` line in a consulting-deck turn; the safeguard is that every deck claimant routes consulting-deck intent here.
|
package/payload/server/public/assets/{AdminLoginScreens-BaNHSvDG.js → AdminLoginScreens-DNsCEyvZ.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./chunk-Pqm5yXtL.js";import{L as t,O as n,V as r,b as i,x as a,y as o}from"./OperatorConversations-yKFxglvV.js";import{i as s}from"./admin-types-CJrGd46U.js";import{g as c,l}from"./AdminShell-6Iq4co_0.js";import{t as u}from"./Checkbox-BoljWa0z.js";var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(r(),1);function h(e=`admin`){let[n,r]=(0,m.useState)(`loading`),[i,a]=(0,m.useState)(``),[o,l]=(0,m.useState)(``),[u,h]=(0,m.useState)(``),[g,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(!1),[b,x]=(0,m.useState)(!1),[S,C]=(0,m.useState)(!1),[w,T]=(0,m.useState)(!1),[E,D]=(0,m.useState)(null),[O,k]=(0,m.useState)(null),[A,j]=(0,m.useState)(void 0),[M,N]=(0,m.useState)(null),[P,F]=(0,m.useState)(void 0),[I,L]=(0,m.useState)(null),[ee,R]=(0,m.useState)(null),[z,B]=(0,m.useState)([]),[V,H]=(0,m.useState)(!1),[U,W]=(0,m.useState)(void 0),G=(0,m.useRef)(void 0),[K,q]=(0,m.useState)(!1);(0,m.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&q(!0)}).catch(()=>{})},[]);let J=(0,m.useRef)(null),Y=(0,m.useRef)(null);(0,m.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let n=await t.json();D(n.session_key),R(n.sessionId??null),j(n.businessName),N(n.role??null),F(n.userName===void 0?null:n.userName),L(n.avatar??null);let i=s(n.thinkingView);return G.current=i,W(i),r(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(n=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check returned ${i.status} after retries`),r(`set-pin`);return}let a=await i.json();if(!a.pin_configured){r(`set-pin`);return}if(!a.claude_authenticated){r(`connect-claude`);return}if(await e())return;r(`enter-pin`)}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check failed:`,e),r(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{n===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[n]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let t=!1;try{t=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:n,alreadyRedirected:t,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[n,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(n!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();if(t.auth_status===`dead`||t.auth_status===`missing`){r(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let n=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(n===`remote-auth-required`){t(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${n}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[n,E]),(0,m.useEffect)(()=>{n===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&r(`enter-pin`)}).catch(()=>{})},[n]);async function Z(e,t){y(!0);try{let n=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!n.ok){h((await n.json().catch(()=>({}))).error||`Invalid PIN`);return}let i=await n.json();if(i.accounts&&!i.session_key){console.log(`[admin] account picker shown: userId=${i.userId} accountCount=${i.accounts.length}`),B(i.accounts),r(`account-picker`);return}D(i.session_key),R(i.sessionId??null),j(i.businessName),N(i.role??null),F(i.userName===void 0?null:i.userName),L(i.avatar??null);let o=s(i.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,i.session_key)}catch{}a(``),r(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1),H(!1)}}let Q=(0,m.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=o.trim();if(!t){h(`Please enter your name.`);return}if(i.length<4){h(`PIN must be at least 4 characters.`);return}let n=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:n,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let n=await e.json();n.pin_configured&&n.claude_authenticated?r(`enter-pin`):n.pin_configured?r(`connect-claude`):h(t.error||`Failed to set PIN.`)}else r(`enter-pin`)}catch{r(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let i=await fetch(`/api/health`);if((i.ok?await i.json():null)?.claude_authenticated){await Z(n);return}a(``),r(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[i,v,o]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(i)},[i]),ne=(0,m.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}return r(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,m.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}a(``),h(``),r(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:n,setAppState:r,pin:i,setPin:a,operatorName:o,setOperatorName:l,pinError:u,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:ee,setSessionId:R,accounts:z,accountPickerLoading:V,expandAll:U,setExpandAll:W,expandAllDefaultRef:G,remoteAuthEnabled:K,pinInputRef:J,setPinFormRef:Y,handleSetPin:Q,handleLogin:te,handleAccountSelect:(0,m.useCallback)(async e=>{H(!0),h(``),await Z(i,e)},[i]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!i){h(`Enter your current PIN first.`);return}y(!0),h(``);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`DELETE`,headers:{"Content-Type":`application/json`},body:JSON.stringify({currentPin:i})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}a(``),h(``),r(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[i])}}var g=a();function _({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,m.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,g.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,g.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 v(e){let{pin:t,setPin:n,showPin:r,setShowPin:a,pinLoading:s,pinError:c,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:h}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,o.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,o.productName,` who you are, then choose a PIN.`]}),(0,g.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>h(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,g.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!t||!m.trim(),loading:s,"aria-label":`Set PIN`,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsx)(u,{checked:r,onChange:()=>a(e=>!e),label:`Show PIN`})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function y(e){let{pin:t,setPin:n,showPin:r,setShowPin:a,pinLoading:s,pinError:c,pinInputRef:d,onSubmit:f,onChangePin:p,remoteAuthEnabled:m,onSignOutRemote:h}=e;return(0,g.jsxs)(`div`,{className:`connect-page`,children:[m&&h&&(0,g.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:h,children:`Sign out`}),(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:o.productName}),(0,g.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r,autoFocus:!0}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!t,loading:s,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsxs)(`div`,{className:`pin-options`,children:[(0,g.jsx)(u,{checked:r,onChange:()=>a(e=>!e),label:`Show PIN`}),(0,g.jsx)(l,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})]})}function b(e){let{accounts:t,loading:r,error:a,onSelect:s}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:o.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:t.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:r,type:`button`,children:[(0,g.jsx)(`span`,{className:`account-picker-name`,children:e.businessName||e.accountId}),(0,g.jsx)(`span`,{className:`account-picker-role`,children:e.role}),r&&(0,g.jsx)(n,{className:`account-picker-spinner`,size:16})]},e.accountId))}),a&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:a})]})})}function x(e){let{authPolling:t,setAuthPolling:n,authLoading:r,setAuthLoading:a,pinError:s,setPinError:c,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!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?f(!0):e.error&&c(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),c(`Could not launch browser.`)}h(!1)}async function v(){a(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){n(!0),f(!0),a(!1);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}c(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}a(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!1),c(``)}return t||d?(0,g.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,g.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,g.jsx)(`button`,{onClick:y,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,g.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,g.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,g.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,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:r,children:r?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})})]}),(0,g.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,g.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsxs)(`div`,{className:`connect-logos`,children:[(0,g.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,g.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,g.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,g.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:o.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,o.productName]}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:r,children:r?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,g.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,g.jsx)(`button`,{onClick:_,disabled:p,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:p?`Launching…`:`Open browser first`}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function S({auth:e}){return e.appState===`loading`?(0,g.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,g.jsx)(v,{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,g.jsx)(x,{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,g.jsx)(y,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,onChangePin:e.handleChangePin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):e.appState===`account-picker`?(0,g.jsx)(b,{accounts:e.accounts,loading:e.accountPickerLoading,error:e.pinError,onSelect:e.handleAccountSelect}):null}export{h as n,S as t};
|
|
1
|
+
import{o as e}from"./chunk-Pqm5yXtL.js";import{L as t,O as n,V as r,b as i,x as a,y as o}from"./OperatorConversations-BqFmHTF1.js";import{i as s}from"./admin-types-CJrGd46U.js";import{h as c,l}from"./AdminShell-DqyjA9x-.js";import{t as u}from"./Checkbox-C3WNcLH8.js";var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(r(),1);function h(e=`admin`){let[n,r]=(0,m.useState)(`loading`),[i,a]=(0,m.useState)(``),[o,l]=(0,m.useState)(``),[u,h]=(0,m.useState)(``),[g,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(!1),[b,x]=(0,m.useState)(!1),[S,C]=(0,m.useState)(!1),[w,T]=(0,m.useState)(!1),[E,D]=(0,m.useState)(null),[O,k]=(0,m.useState)(null),[A,j]=(0,m.useState)(void 0),[M,N]=(0,m.useState)(null),[P,F]=(0,m.useState)(void 0),[I,L]=(0,m.useState)(null),[ee,R]=(0,m.useState)(null),[z,B]=(0,m.useState)([]),[V,H]=(0,m.useState)(!1),[U,W]=(0,m.useState)(void 0),G=(0,m.useRef)(void 0),[K,q]=(0,m.useState)(!1);(0,m.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&q(!0)}).catch(()=>{})},[]);let J=(0,m.useRef)(null),Y=(0,m.useRef)(null);(0,m.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let n=await t.json();D(n.session_key),R(n.sessionId??null),j(n.businessName),N(n.role??null),F(n.userName===void 0?null:n.userName),L(n.avatar??null);let i=s(n.thinkingView);return G.current=i,W(i),r(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(n=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check returned ${i.status} after retries`),r(`set-pin`);return}let a=await i.json();if(!a.pin_configured){r(`set-pin`);return}if(!a.claude_authenticated){r(`connect-claude`);return}if(await e())return;r(`enter-pin`)}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check failed:`,e),r(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{n===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[n]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let t=!1;try{t=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:n,alreadyRedirected:t,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[n,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(n!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();if(t.auth_status===`dead`||t.auth_status===`missing`){r(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let n=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(n===`remote-auth-required`){t(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${n}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[n,E]),(0,m.useEffect)(()=>{n===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&r(`enter-pin`)}).catch(()=>{})},[n]);async function Z(e,t){y(!0);try{let n=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!n.ok){h((await n.json().catch(()=>({}))).error||`Invalid PIN`);return}let i=await n.json();if(i.accounts&&!i.session_key){console.log(`[admin] account picker shown: userId=${i.userId} accountCount=${i.accounts.length}`),B(i.accounts),r(`account-picker`);return}D(i.session_key),R(i.sessionId??null),j(i.businessName),N(i.role??null),F(i.userName===void 0?null:i.userName),L(i.avatar??null);let o=s(i.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,i.session_key)}catch{}a(``),r(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1),H(!1)}}let Q=(0,m.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=o.trim();if(!t){h(`Please enter your name.`);return}if(i.length<4){h(`PIN must be at least 4 characters.`);return}let n=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:n,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let n=await e.json();n.pin_configured&&n.claude_authenticated?r(`enter-pin`):n.pin_configured?r(`connect-claude`):h(t.error||`Failed to set PIN.`)}else r(`enter-pin`)}catch{r(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let i=await fetch(`/api/health`);if((i.ok?await i.json():null)?.claude_authenticated){await Z(n);return}a(``),r(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[i,v,o]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(i)},[i]),ne=(0,m.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}return r(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,m.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}a(``),h(``),r(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:n,setAppState:r,pin:i,setPin:a,operatorName:o,setOperatorName:l,pinError:u,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:ee,setSessionId:R,accounts:z,accountPickerLoading:V,expandAll:U,setExpandAll:W,expandAllDefaultRef:G,remoteAuthEnabled:K,pinInputRef:J,setPinFormRef:Y,handleSetPin:Q,handleLogin:te,handleAccountSelect:(0,m.useCallback)(async e=>{H(!0),h(``),await Z(i,e)},[i]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!i){h(`Enter your current PIN first.`);return}y(!0),h(``);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`DELETE`,headers:{"Content-Type":`application/json`},body:JSON.stringify({currentPin:i})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}a(``),h(``),r(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[i])}}var g=a();function _({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,m.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,g.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,g.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 v(e){let{pin:t,setPin:n,showPin:r,setShowPin:a,pinLoading:s,pinError:c,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:h}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,o.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,o.productName,` who you are, then choose a PIN.`]}),(0,g.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>h(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,g.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!t||!m.trim(),loading:s,"aria-label":`Set PIN`,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsx)(u,{checked:r,onChange:()=>a(e=>!e),label:`Show PIN`})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function y(e){let{pin:t,setPin:n,showPin:r,setShowPin:a,pinLoading:s,pinError:c,pinInputRef:d,onSubmit:f,onChangePin:p,remoteAuthEnabled:m,onSignOutRemote:h}=e;return(0,g.jsxs)(`div`,{className:`connect-page`,children:[m&&h&&(0,g.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:h,children:`Sign out`}),(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:o.productName}),(0,g.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r,autoFocus:!0}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!t,loading:s,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsxs)(`div`,{className:`pin-options`,children:[(0,g.jsx)(u,{checked:r,onChange:()=>a(e=>!e),label:`Show PIN`}),(0,g.jsx)(l,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})]})}function b(e){let{accounts:t,loading:r,error:a,onSelect:s}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:o.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:t.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:r,type:`button`,children:[(0,g.jsx)(`span`,{className:`account-picker-name`,children:e.businessName||e.accountId}),(0,g.jsx)(`span`,{className:`account-picker-role`,children:e.role}),r&&(0,g.jsx)(n,{className:`account-picker-spinner`,size:16})]},e.accountId))}),a&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:a})]})})}function x(e){let{authPolling:t,setAuthPolling:n,authLoading:r,setAuthLoading:a,pinError:s,setPinError:c,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!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?f(!0):e.error&&c(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),c(`Could not launch browser.`)}h(!1)}async function v(){a(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){n(!0),f(!0),a(!1);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}c(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}a(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!1),c(``)}return t||d?(0,g.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,g.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,g.jsx)(`button`,{onClick:y,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,g.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,g.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,g.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,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:r,children:r?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})})]}),(0,g.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,g.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsxs)(`div`,{className:`connect-logos`,children:[(0,g.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,g.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,g.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,g.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:o.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,o.productName]}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:r,children:r?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,g.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,g.jsx)(`button`,{onClick:_,disabled:p,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:p?`Launching…`:`Open browser first`}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function S({auth:e}){return e.appState===`loading`?(0,g.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,g.jsx)(v,{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,g.jsx)(x,{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,g.jsx)(y,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,onChangePin:e.handleChangePin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):e.appState===`account-picker`?(0,g.jsx)(b,{accounts:e.accounts,loading:e.accountPickerLoading,error:e.pinError,onSelect:e.handleAccountSelect}):null}export{h as n,S as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{o as e}from"./chunk-Pqm5yXtL.js";import{A as t,B as n,C as r,E as i,I as a,M as o,N as s,T as c,V as l,f as u,g as d,h as f,j as p,m,p as h,t as g,v as ee,x as _,y as te}from"./OperatorConversations-BqFmHTF1.js";async function v(){try{let e=await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`logout`})});return e.ok?(await e.json().catch(()=>({})))?.logged_out===!0:(console.error(`[admin-ui] claude-logout http-status=${e.status}`),!1)}catch(e){return console.error(`[admin-ui] claude-logout fetch failed: ${e instanceof Error?e.message:String(e)}`),!1}}var ne=a(`archive-restore`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h2`,key:`tvwodi`}],[`path`,{d:`M20 8v11a2 2 0 0 1-2 2h-2`,key:`1gkqxj`}],[`path`,{d:`m9 15 3-3 3 3`,key:`1pd0qc`}],[`path`,{d:`M12 12v9`,key:`192myk`}]]),re=a(`archive`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8`,key:`1s80jp`}],[`path`,{d:`M10 12h4`,key:`a56b0p`}]]),y=a(`bot`,[[`path`,{d:`M12 8V4H8`,key:`hb8ula`}],[`rect`,{width:`16`,height:`12`,x:`4`,y:`8`,rx:`2`,key:`enze0r`}],[`path`,{d:`M2 14h2`,key:`vft8re`}],[`path`,{d:`M20 14h2`,key:`4cs60a`}],[`path`,{d:`M15 13v2`,key:`1xurst`}],[`path`,{d:`M9 13v2`,key:`rq6x2g`}]]),b=a(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),ie=a(`history`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}],[`path`,{d:`M12 7v5l4 2`,key:`1fdv2h`}]]),x=a(`list-todo`,[[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}],[`path`,{d:`m3 17 2 2 4-4`,key:`1jhpwq`}],[`rect`,{x:`3`,y:`4`,width:`6`,height:`6`,rx:`1`,key:`cif1o7`}]]),S=a(`message-square`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}]]),ae=a(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),oe=a(`sliders-horizontal`,[[`path`,{d:`M10 5H3`,key:`1qgfaw`}],[`path`,{d:`M12 19H3`,key:`yhmn1j`}],[`path`,{d:`M14 3v4`,key:`1sua03`}],[`path`,{d:`M16 17v4`,key:`1q0r14`}],[`path`,{d:`M21 12h-9`,key:`1o4lsq`}],[`path`,{d:`M21 19h-5`,key:`1rlt1p`}],[`path`,{d:`M21 5h-7`,key:`1oszz2`}],[`path`,{d:`M8 10v4`,key:`tgpxqk`}],[`path`,{d:`M8 12H3`,key:`a7s4jb`}]]),se=a(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),C=a(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),w=e(l(),1),T=_(),ce={sm:14,md:16,lg:18},E={sm:30,md:38,lg:46};function D({variant:e=`primary`,size:t=`md`,icon:n,iconPosition:r=`leading`,loading:i=!1,fullWidth:a=!1,disabled:o=!1,type:s=`button`,onClick:c,"aria-label":l,style:u,className:d,children:f}){let p=[`btn`,`btn--${e}`,t===`md`?``:`btn--${t}`,a?`btn--full`:``,d].filter(Boolean).join(` `),m=ce[t],h={...e===`send`?{width:E[t],height:E[t]}:{},...u},g=Object.keys(h).length>0;return(0,T.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,T.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,T.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,T.jsx)(n,{size:m})]}),i&&(0,T.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var O=`maxy-shell-side-px`;function k(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function A(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-k());return Math.min(Math.max(e,248),n)}function j(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(O);if(!e)return 264;let t=parseInt(e,10);if(!Number.isFinite(t))return console.warn(`[admin-ui] sidebar-width-parse-failed stored=${JSON.stringify(e)} fallback=264`),264;if(t>=248)return A(t)}catch{}return 264}function le({targetSelector:e=`.platform`}){let t=(0,w.useRef)(null),[n,r]=(0,w.useState)(()=>j()),i=(0,w.useRef)(n);(0,w.useLayoutEffect)(()=>{let t=document.querySelector(e);!t||!(t instanceof HTMLElement)||(t.style.setProperty(`--side-px`,`${n}px`),i.current=n)},[n,e]);let a=(0,w.useCallback)(()=>{r(e=>{let t=A(e);return t===e?e:t})},[]);(0,w.useEffect)(()=>{a(),window.addEventListener(`resize`,a);let t=document.querySelector(e),n=null;return t instanceof HTMLElement&&(n=new MutationObserver(a),n.observe(t,{attributes:!0,attributeFilter:[`data-artefact`,`class`]})),()=>{window.removeEventListener(`resize`,a),n?.disconnect()}},[a,e]);let o=e=>{e.preventDefault();let n=t.current;if(!n)return;n.setPointerCapture(e.pointerId),n.classList.add(`dragging`);let a=!1,o=e=>{a=!0,r(A(Math.round(e.clientX)))},s=()=>{if(n.releasePointerCapture(e.pointerId),n.classList.remove(`dragging`),window.removeEventListener(`pointermove`,o),window.removeEventListener(`pointerup`,s),!a)return;let t=i.current;try{window.localStorage.setItem(O,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=A(264);r(e);try{window.localStorage.removeItem(O)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,T.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var ue=n();function M({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,w.useRef)(null),[s,c]=(0,w.useState)({position:`fixed`,visibility:`hidden`}),l=(0,w.useCallback)(()=>{let t=e.current,n=o.current;if(!t||!n)return;let r=t.getBoundingClientRect(),i=n.getBoundingClientRect(),a=r.right-i.width;a<4&&(a=4);let s=window.innerHeight-r.bottom<i.height+8&&r.top>i.height+8?r.top-i.height:r.bottom;c({position:`fixed`,left:a,top:s,visibility:`visible`})},[e]);return(0,w.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,w.useEffect)(()=>{let n=e=>{e.key===`Escape`&&t()},r=n=>{let r=n.target;e.current?.contains(r)||o.current?.contains(r)||t()},i=n=>{let r=e.current;r&&n.target instanceof Node&&n.target.contains(r)&&t()},a=()=>t();return document.addEventListener(`keydown`,n),document.addEventListener(`pointerdown`,r),window.addEventListener(`scroll`,i,!0),window.addEventListener(`resize`,a),()=>{document.removeEventListener(`keydown`,n),document.removeEventListener(`pointerdown`,r),window.removeEventListener(`scroll`,i,!0),window.removeEventListener(`resize`,a)}},[e,t]),(0,ue.createPortal)((0,T.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function de({action:e,disabled:t,open:n,onToggle:r,onClose:i}){let a=(0,w.useRef)(null);return(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`button`,{ref:a,type:`button`,className:`conv-action`,onClick:r,disabled:t,"aria-haspopup":`dialog`,"aria-expanded":n,"aria-label":e.label,title:e.title,children:e.icon}),n&&(0,T.jsx)(M,{anchorRef:a,onClose:i,className:e.panelClassName,role:`dialog`,ariaLabel:e.label,children:e.panel()})]})}function fe({actions:e,disabled:t,collapsed:n}){let[r,i]=(0,w.useState)(null),[a,s]=(0,w.useState)(!1),[c,l]=(0,w.useState)(null),u=(0,w.useRef)(null);(0,w.useEffect)(()=>{i(null),s(!1),l(null)},[n]);let d=(0,w.useCallback)(()=>{s(!1),l(null)},[]);return n?(0,T.jsxs)(`div`,{className:`conv-actions`,children:[(0,T.jsx)(`button`,{ref:u,type:`button`,className:`conv-action conv-actions-overflow`,onClick:()=>s(e=>!e),disabled:t,"aria-haspopup":`menu`,"aria-expanded":a,"aria-label":`Session actions`,title:`Session actions`,children:(0,T.jsx)(o,{size:12})}),a&&(0,T.jsx)(M,{anchorRef:u,onClose:d,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,T.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,T.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`dialog`,"aria-expanded":c===e.key,disabled:t,onClick:()=>l(t=>t===e.key?null:e.key),children:[e.icon,(0,T.jsx)(`span`,{children:e.menuLabel})]}),c===e.key&&(0,T.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,T.jsxs)(`button`,{type:`button`,role:`menuitem`,className:e.danger?`conv-action-danger`:void 0,"aria-busy":e.busy,disabled:t,onClick:t=>{e.onClick?.(t),d()},children:[e.icon,(0,T.jsx)(`span`,{children:e.menuLabel})]},e.key))})]}):(0,T.jsx)(`div`,{className:`conv-actions`,children:e.map(e=>e.panel?(0,T.jsx)(de,{action:e,disabled:t,open:r===e.key,onToggle:()=>i(t=>t===e.key?null:e.key),onClose:()=>i(null)},e.key):(0,T.jsx)(`button`,{type:`button`,className:e.danger?`conv-action conv-action-danger`:`conv-action`,onClick:e.onClick,disabled:t,"aria-busy":e.busy,"aria-label":e.label,title:e.title,children:e.icon},e.key))})}var N=`claude-opus-4-8[1m]`,P=`claude-sonnet-4-6`,F=`claude-haiku-4-5`,pe={[N]:`Opus 4.8 (1M context)`,[P]:`Sonnet 4.6`,[F]:`Haiku 4.5`};function I(e){return pe[e]??e}var me=[N,P,F];function L(e){return e.replace(/\[1m\]$/,``)}function he(e){return me.find(t=>L(t)===L(e))??e}var R=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`],z=[`low`,`medium`,`high`,`xhigh`];[...R],[...z],[...z];var B=[N,P,F],ge={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},V=R.map(e=>({value:e,label:ge[e]??e})),H={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},_e=z.map(e=>({value:e,label:H[e]??e}));function U(e){if(e){let t=B.find(t=>L(t)===L(e));if(t)return t}return N}function ve({row:e,adminFetch:t,onError:n}){let[r,i]=(0,w.useState)(()=>U(e.model)),[a,o]=(0,w.useState)(``),[s,c]=(0,w.useState)(``),[l,u]=(0,w.useState)(!1),d=(0,w.useRef)(!1);(0,w.useEffect)(()=>{i(U(e.model))},[e.model]);let f=async()=>{if(!d.current){d.current=!0,u(!0);try{let i=await t(`/api/admin/session-reseat`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({fromSessionId:e.sessionId,model:r,...a?{permissionMode:a}:{},...s?{effort:s}:{}})});if(!i.ok){n(`Could not re-seat ${e.title} (status ${i.status})`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} status=${i.status}`),d.current=!1,u(!1);return}let o=await i.json().catch(()=>({}));o.target?window.location.assign(o.target):(n(`Re-seat of ${e.title} returned no target`),d.current=!1,u(!1))}catch(t){n(`Could not re-seat ${e.title} (network error)`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} error=${t instanceof Error?t.message:String(t)}`),d.current=!1,u(!1)}}};return(0,T.jsxs)(T.Fragment,{children:[(0,T.jsxs)(`label`,{className:`reseat-field`,children:[(0,T.jsx)(`span`,{children:`Model`}),(0,T.jsx)(`select`,{"data-kind":`model`,value:r,disabled:l,onChange:e=>i(e.target.value),children:B.map(e=>(0,T.jsx)(`option`,{value:e,children:I(e)},e))})]}),(0,T.jsxs)(`label`,{className:`reseat-field`,children:[(0,T.jsx)(`span`,{children:`Mode`}),(0,T.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:l,onChange:e=>o(e.target.value),children:[(0,T.jsx)(`option`,{value:``,children:`Keep current`}),V.map(e=>(0,T.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,T.jsxs)(`label`,{className:`reseat-field`,children:[(0,T.jsx)(`span`,{children:`Effort`}),(0,T.jsxs)(`select`,{"data-kind":`effort`,value:s,disabled:l,onChange:e=>c(e.target.value),children:[(0,T.jsx)(`option`,{value:``,children:`Keep current`}),_e.map(e=>(0,T.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,T.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:l,"aria-busy":l,onClick:()=>void f(),children:`Re-seat`})]})}var ye=[`whatsapp`,`telegram`];function W(e){if(e<60)return`${e}s`;let t=Math.floor(e/60),n=e%60;return n>0?`${t}m ${n}s`:`${t}m`}function be(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function G(e){if(navigator.clipboard)try{return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}function xe({target:e,onConfirm:t,onCancel:n}){return e?(0,T.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,T.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete session`,children:[(0,T.jsxs)(`div`,{className:`claude-info-header`,children:[(0,T.jsx)(`span`,{children:`Delete this conversation?`}),(0,T.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,T.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[`This permanently removes the transcript. It is not moved to Archive and cannot be recovered.`,e.live&&(0,T.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,T.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,T.jsx)(D,{variant:`danger`,size:`sm`,style:{flex:1},onClick:t,children:`Delete`}),(0,T.jsx)(D,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:n,children:`Cancel`})]})]})}):null}var Se=`auth-refresh-failed`;function Ce({error:e,onClose:t}){if(!e)return null;let n=e.reason===Se,r=n?`Claude sign-in expired`:`Session didn’t open`,i=n?`Your claude.ai login has expired. Re-authenticate to resume sessions.`:`The session did not bind within 60 seconds, so there is no live conversation to open.`;return(0,T.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,T.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,T.jsxs)(`div`,{className:`claude-info-header`,children:[(0,T.jsx)(`span`,{children:r}),(0,T.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,T.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,T.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,T.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function we(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,w.useState)(null);if(!t)return null;let u=i.flatMap(e=>e.events?.filter(e=>e.type===`usage`)??[]),d=u.at(-1),f=d?.peak_request_pct==null?d?.context_window?Math.round((d.input_tokens+d.cache_creation_tokens+d.cache_read_tokens)/d.context_window*100):0:Math.round(d.peak_request_pct*100),p=u.reduce((e,t)=>e+t.input_tokens+t.cache_creation_tokens+t.cache_read_tokens+t.output_tokens,0),m=i.flatMap(e=>e.events?.filter(e=>e.type===`rate_limit`)??[]).at(-1),h=u.reduce((e,t)=>e+(t.total_cost_usd??0),0),g=r?.account?.subscriptionType,ee=e=>{let t=e*1e3-Date.now();if(t<=0)return`now`;let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4);return n>0?`${n}h ${r}m`:`${r}m`};return(0,T.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,T.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,T.jsxs)(`div`,{className:`claude-info-header`,children:[(0,T.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,T.jsx)(`span`,{children:`Claude Code`}),(0,T.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,T.jsxs)(`div`,{className:`claude-info-section`,children:[(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,T.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,T.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,T.jsxs)(T.Fragment,{children:[(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,T.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,T.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,T.jsxs)(`div`,{className:`claude-info-section`,children:[(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:p>0?be(p):`—`})]}),(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,T.jsx)(`span`,{className:`claude-info-value`,children:W(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,T.jsxs)(`div`,{className:`claude-info-row`,children:[(0,T.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,T.jsx)(`button`,{type:`button`,className:`claude-info-value claude-info-id-copy`,title:`${e} (${o?`flushed`:`pre-flush`}) — click to copy`,onClick:async()=>{l(await G(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}var Te=`https://claude.ai/code`,Ee=200,De=[500,1e3,1500,2e3,2500,3e3,3e3];function Oe(e,t,n){if(e&&n.target)return{kind:`navigate`,url:n.target};let r=n.slug??n.bridgeSessionId??null;if(e&&r)return{kind:`navigate`,url:`${Te}/${r}`};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function ke(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function K(e){let{businessName:n,cacheKey:a,role:o,userName:l,userAvatar:d,onSelectProjects:g,onSelectPeople:_,onSelectTasks:v,onSelectAgents:ce,onCloseMobileDrawer:E,collapsed:D,selectedWhatsappId:O,onSelectWhatsappConversation:k,initialWhatsappSurface:A=!1}=e,j=ee(a),le=(0,w.useCallback)(e=>({key:`reseat`,label:`Re-seat session ${e.title} (model, mode, effort)`,menuLabel:`Re-seat`,title:`Re-seat — move this session onto a chosen model, mode, and effort`,icon:(0,T.jsx)(oe,{size:12}),panelClassName:`reseat-panel`,panel:()=>(0,T.jsx)(ve,{row:e,adminFetch:j,onError:e=>H({message:e,failed:!0})})}),[j]),ue=te.productName,M=typeof l==`string`?l:l===null?`name unavailable`:n||ue,de=(M.trim().charAt(0)||`?`).toUpperCase(),[N,P]=(0,w.useState)(A?`whatsapp`:`sessions`),[F,pe]=(0,w.useState)([]),[I,me]=(0,w.useState)(!1),[L,he]=(0,w.useState)(null),[R,z]=(0,w.useState)(!1),[B,ge]=(0,w.useState)(`file`),[V,H]=(0,w.useState)(null),[_e,U]=(0,w.useState)(null),[W,be]=(0,w.useState)([]),[G,Se]=(0,w.useState)(!1),[we,Te]=(0,w.useState)(null),[K,Ae]=(0,w.useState)(!1),[q,Pe]=(0,w.useState)(!1),[J,Fe]=(0,w.useState)(!1),[Ie,Le]=(0,w.useState)(null),[Y,Re]=(0,w.useState)(new Set),[ze,Be]=(0,w.useState)(null),[Ve,He]=(0,w.useState)(new Set),[Ue,We]=(0,w.useState)(new Set),[Ge,Ke]=(0,w.useState)(new Set),[qe,Je]=(0,w.useState)(null),[Ye,X]=(0,w.useState)(``),[Xe,Ze]=(0,w.useState)(!1),[Z,Qe]=(0,w.useState)(!1),$e=(0,w.useRef)(null),et=(0,w.useRef)(0),[tt,nt]=(0,w.useState)(0);(0,w.useEffect)(()=>{let e=$e.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(e=>{let t=e[0]?.contentRect.width??0;nt(e=>Math.abs(e-t)<1?e:t)});return t.observe(e),()=>t.disconnect()},[N]);let rt=tt>0&&tt<400,[it,at]=(0,w.useState)([]),[ot,st]=(0,w.useState)(!1),[ct,lt]=(0,w.useState)(null),[ut,dt]=(0,w.useState)(`whatsapp`),ft=(0,w.useCallback)(e=>{if(E(),!a){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=no-cache-key`),H({message:`Session not ready — try again`,failed:!0});return}if(!e.downloadPath){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=not-downloadable`),H({message:`${e.name} can’t be downloaded`,failed:!0});return}console.info(`[admin-ui] artefact-download id=${e.id} root=${e.downloadRoot??`data`} path=${e.downloadPath}`),u(a,e.downloadPath,e.downloadRoot??`data`),H({message:`Downloading ${e.name}`,failed:!1})},[a,E]);(0,w.useEffect)(()=>{if(!V)return;let e=setTimeout(()=>H(null),2500);return()=>clearTimeout(e)},[V]);let pt=(0,w.useCallback)(async()=>{if(a){z(!0),he(null);try{let e=await j(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);pe((await e.json()).artefacts??[]),me(!0)}catch(e){let t=e instanceof Error?e.message:String(e);he(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{z(!1)}}},[a,j]),Q=(0,w.useCallback)(async()=>{if(!a)return null;let e=++et.current;Ae(!0),Te(null);try{let t=await j(`/api/admin/sidebar-sessions`);if(!t.ok)throw Error(`status ${t.status}`);let n=await t.json(),r=n.sessions??[];return e===et.current?(be(r),Le(n.accountId??null),Se(!0),r):(console.info(`[admin-ui] sidebar-sessions-stale-response-dropped token=${e}`),r)}catch(t){let n=t instanceof Error?t.message:String(t);return e===et.current&&Te(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===et.current&&Ae(!1)}},[a,j]),mt=(0,w.useCallback)(async()=>{if(a){lt(null);try{let e=await j(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);at((await e.json()).conversations??[]),st(!0)}catch(e){let t=e instanceof Error?e.message:String(e);lt(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[a,j]);(0,w.useEffect)(()=>{!a||G||Q()},[a,G,Q]),(0,w.useEffect)(()=>{if(!a)return;let e=null;return mt(),e=setInterval(()=>{mt()},je),()=>{e!==null&&clearInterval(e)}},[a,mt]),(0,w.useEffect)(()=>{if(!a)return;let e=null;function t(){console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=poll`),Q()}function n(){e===null&&(e=setInterval(t,Me))}function r(){e!==null&&(clearInterval(e),e=null)}function i(){document.hidden?r():(t(),n())}return document.hidden||n(),document.addEventListener(`visibilitychange`,i),()=>{r(),document.removeEventListener(`visibilitychange`,i)}},[a,Q]);let ht=(0,w.useMemo)(()=>{let e=new Map;for(let t of ye)e.set(t,[]);for(let t of it)e.get(t.channel)?.push(t);for(let t of ye)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[it]),gt={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},_t=()=>{k(null),P(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${I?F.length:0} collapsed=${D}`),pt()},$=1.5,vt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),pt()},yt=()=>{k(null),P(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${G?W.length:0} collapsed=${D}`),G||Q()},bt=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Q()},xt=e=>{P(`whatsapp`),dt(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${ht.get(e)?.length??0} collapsed=${D}`)},St=(0,w.useCallback)(async e=>{if(Ve.has(e.sessionId))return;He(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await j(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,name:e.title||e.sessionId})}),r=await n.json().catch(()=>({})),i=Oe(n.ok,n.status,{...r,sessionId:r.sessionId??e.sessionId});console.info(`[admin-ui] sidebar-session-resume sessionId=${e.sessionId} status=${n.status} outcome=${i.kind} slug=${r.slug??r.bridgeSessionId??`none`}`),i.kind===`navigate`?(E(),t?t.location.href=i.url:window.open(i.url,`_blank`)):(t?.close(),console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} status=${n.status} reason=${i.reason}`),U(i))}catch(n){t?.close();let r=n instanceof Error?n.message:String(n);console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} error=${r}`),U({sessionId:e.sessionId,reason:r})}finally{He(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[j,E,Ve]),Ct=(0,w.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=De.length;n++){await new Promise(e=>setTimeout(e,De[n-1]));let r=await Q();if(r&&r.some(t=>t.sessionId===e)){console.info(`[admin-ui] sidebar-new-session-converged sessionId=${t} via=retry attempts=${n}`);return}}console.error(`[admin-ui] sidebar-new-session-converge-timeout sessionId=${t}`)},[Q]),wt=(0,w.useCallback)(async()=>{if(Z)return;Qe(!0);let e=window.open(``,`_blank`);try{let t=await j(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),n=await t.json().catch(()=>({})),r=Oe(t.ok,t.status,n);console.info(`[admin-ui] sidebar-new-session-spawned status=${t.status} outcome=${r.kind} slug=${n.slug??n.bridgeSessionId??`none`}`),r.kind===`navigate`?(e?e.location.href=r.url:window.open(r.url,`_blank`),n.sessionId?Ct(n.sessionId):console.error(`[admin-ui] sidebar-new-session-converge-skipped reason=no-session-id`)):(e?.close(),console.error(`[admin-ui] sidebar-new-session-failed status=${t.status} reason=${r.reason}`),U(r))}catch(t){e?.close();let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-new-session-failed error=${n}`),U({sessionId:null,reason:n})}finally{Qe(!1)}},[j,Z,Ct]),Tt=(0,w.useCallback)((e,t)=>{e.stopPropagation(),Be(t)},[]),Et=(0,w.useCallback)(async e=>{if(!Y.has(e.sessionId)){Re(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await j(`/api/admin/session-delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId})});if(!t.ok){let n=await t.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} status=${t.status} error=${n.error??`unknown`}`),H({message:`Delete failed: ${n.error??`status ${t.status}`}`,failed:!0});return}let n=await t.json();console.info(`[admin-ui] sidebar-session-delete sessionId=${e.sessionId} live=${e.live} confirmed=true pidKilled=${n.pidKilled??`?`} deleted=${n.deleted??`?`}`),be(t=>t.filter(t=>t.sessionId!==e.sessionId)),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} error=${n}`),H({message:`Delete failed: ${n}`,failed:!0})}finally{Re(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}}},[j,Y,Q]),Dt=(0,w.useCallback)(async(e,t)=>{if(e.stopPropagation(),!Ue.has(t.sessionId)){We(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await j(`/api/admin/session-stop`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId})});if(!e.ok){let n=await e.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} status=${e.status} error=${n.error??`unknown`}`),H({message:`Stop failed: ${n.error??`status ${e.status}`}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-stop sessionId=${t.sessionId}`),Q()}catch(e){let n=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} error=${n}`),H({message:`Stop failed: ${n}`,failed:!0})}finally{We(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[j,Ue,Q]),Ot=(0,w.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!Ge.has(t.sessionId)){Ke(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await j(`/api/admin/session-archive`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId,mode:n})});if(!e.ok){let r=await e.json().catch(()=>({})),i=r.detail??r.error??`status ${e.status}`;console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} status=${e.status} error=${r.error??`unknown`}`),H({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${i}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-archive sessionId=${t.sessionId} mode=${n}`),Q()}catch(e){let r=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} error=${r}`),H({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${r}`,failed:!0})}finally{Ke(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[j,Ge,Q]),kt=(0,w.useCallback)(async e=>{let t=Ye.trim();if(!t){H({message:`Title can’t be empty`,failed:!0});return}if(t.length>Ee){H({message:`Title too long (max ${Ee})`,failed:!0});return}Ze(!0);try{let n=await j(`/api/admin/session-rename`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,title:t})});if(!n.ok){let t=await n.json().catch(()=>({})),r=t.reason??t.error??`status ${n.status}`;console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${r}`),H({message:`Rename failed: ${r}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=ok`),Je(null),X(``),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${n}`),H({message:`Rename failed: ${n}`,failed:!0})}finally{Ze(!1)}},[j,Ye,Q]);return(0,T.jsxs)(`aside`,{className:`side`,children:[(0,T.jsx)(`div`,{className:`side-new-session-row`,children:(0,T.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:wt,disabled:Z,"aria-busy":Z,children:[(0,T.jsx)(ae,{size:14}),(0,T.jsx)(`span`,{children:Z?`Spawning…`:`New session`})]})}),(0,T.jsxs)(`nav`,{className:`side-nav`,children:[(0,T.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),_(),E()},children:[(0,T.jsx)(C,{size:20,strokeWidth:$}),(0,T.jsx)(`span`,{className:`label`,children:`People`}),(0,T.jsx)(`span`,{className:`kbd`})]}),(0,T.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),ce(),E()},children:[(0,T.jsx)(y,{size:20,strokeWidth:$}),(0,T.jsx)(`span`,{className:`label`,children:`Agents`}),(0,T.jsx)(`span`,{className:`kbd`})]}),(0,T.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),g(),E()},children:[(0,T.jsx)(b,{size:20,strokeWidth:$}),(0,T.jsx)(`span`,{className:`label`,children:`Projects`}),(0,T.jsx)(`span`,{className:`kbd`})]}),(0,T.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),v(),E()},children:[(0,T.jsx)(x,{size:20,strokeWidth:$}),(0,T.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,T.jsx)(`span`,{className:`kbd`})]}),(0,T.jsxs)(`button`,{type:`button`,className:`nav-row${N===`artefacts`?` active`:``}`,onClick:_t,children:[(0,T.jsx)(t,{size:20,strokeWidth:$}),(0,T.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,T.jsx)(`span`,{className:`kbd`})]}),(0,T.jsxs)(`button`,{type:`button`,className:`nav-row${N===`sessions`?` active`:``}`,onClick:yt,children:[(0,T.jsx)(ie,{size:20,strokeWidth:$}),(0,T.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,T.jsx)(`span`,{className:`kbd`})]}),ot&&ye.filter(e=>ht.get(e).length>0).map(e=>(0,T.jsxs)(`button`,{type:`button`,className:`nav-row${N===`whatsapp`&&ut===e?` active`:``}`,onClick:()=>xt(e),children:[(0,T.jsx)(m,{channel:e,size:16}),(0,T.jsx)(`span`,{className:`label`,children:gt[e]}),(0,T.jsx)(`span`,{className:`kbd`})]},e)),ct&&(0,T.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,T.jsx)(`span`,{className:`label`,children:ct})})]}),N===`artefacts`&&(0,T.jsxs)(`div`,{className:`side-list`,children:[(0,T.jsxs)(`div`,{className:`group-head`,children:[(0,T.jsx)(`span`,{children:`Artefacts`}),(0,T.jsxs)(`span`,{className:`group-head-meta`,children:[(0,T.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:vt,disabled:R,children:(0,T.jsx)(c,{size:12,className:R?`spinning`:void 0})}),(0,T.jsx)(`span`,{children:R?`…`:String(F.length)})]})]}),L&&(0,T.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:L}),I&&!L&&F.length>0&&(()=>{let e=F.filter(e=>e.kind===`agent-template`).length,t=F.length-e;return(0,T.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:F.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,T.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${B===e.key?` active`:``}`,onClick:()=>ge(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,T.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),I&&!L&&F.length===0&&(0,T.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),F.filter(e=>B===`all`?!0:B===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let n=e.kind===`agent-template`,r=n?y:t,i=ke(e.updatedAt),a=e.downloadPath!==null;return(0,T.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>ft(e),disabled:!a,style:a?void 0:{cursor:`default`},title:a?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,T.jsx)(r,{size:14,className:`conv-icon`,"data-kind":n?`agent`:`file`,"aria-label":n?`agent template`:`file`}),(0,T.jsxs)(`span`,{className:`conv-stack`,children:[(0,T.jsx)(`span`,{className:`conv-name-line`,children:(0,T.jsx)(`span`,{className:`conv-name`,children:e.name})}),i&&(0,T.jsx)(`span`,{className:`conv-timestamp`,children:i})]}),a&&(0,T.jsx)(s,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),N===`sessions`&&(()=>{let e=W.filter(e=>q?!0:!e.isSubagent).filter(e=>J?!0:!e.archived),t=W.some(e=>e.isSubagent),n=W.some(e=>e.archived);return(0,T.jsxs)(`div`,{className:`side-list`,ref:$e,children:[(0,T.jsxs)(`div`,{className:`group-head`,children:[(0,T.jsx)(`span`,{children:`Sessions`}),(0,T.jsxs)(`span`,{className:`group-head-meta`,children:[(0,T.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:bt,disabled:K,children:(0,T.jsx)(c,{size:12,className:K?`spinning`:void 0})}),(0,T.jsx)(`span`,{children:K?`…`:String(e.length)})]})]}),Ie&&(0,T.jsx)(`div`,{className:`side-account-id`,title:`This install's accountId. The first 8 characters match the truncated UUID label on the live Remote Control daemon entry in claude.ai/code.`,children:(0,T.jsx)(`code`,{children:Ie})}),(t||n)&&(0,T.jsxs)(`div`,{className:`artefact-filter-chips`,children:[t&&(0,T.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${q?` active`:``}`,"aria-pressed":q,onClick:()=>Pe(e=>!e),title:q?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),n&&(0,T.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${J?` active`:``}`,"aria-pressed":J,onClick:()=>Fe(e=>!e),title:J?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),we&&(0,T.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:we}),G&&!we&&e.length===0&&(0,T.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let t=ke(e.startedAt),n=Ve.has(e.sessionId),a=Y.has(e.sessionId),o=Ue.has(e.sessionId),s=Ge.has(e.sessionId),c=n||a||o||s,l=[{key:`open`,label:`Resume session ${e.title} in claude.ai/code`,menuLabel:`Resume in claude.ai/code`,title:`Resume in a fresh local Remote Control PTY`,icon:(0,T.jsx)(p,{size:12}),busy:n,onClick:()=>{St(e)}},{key:`message`,label:`Open session ${e.title} in admin webchat`,menuLabel:`Open in webchat`,title:`Open in admin webchat (/chat) — sending resumes this session`,icon:(0,T.jsx)(S,{size:12}),onClick:()=>{window.location.assign(`/chat?session=${e.sessionId}`)}},...e.live?[{key:`stop`,label:`Stop session ${e.title}`,menuLabel:`Stop`,title:`Stop session process (keeps the conversation, can resume later)`,icon:(0,T.jsx)(se,{size:12}),busy:o,onClick:t=>{Dt(t,e)}}]:[],e.archived?{key:`unarchive`,label:`Unarchive session ${e.title}`,menuLabel:`Unarchive`,title:`Unarchive (move back to the active list)`,icon:(0,T.jsx)(ne,{size:12}),busy:s,onClick:t=>{Ot(t,e,`unarchive`)}}:{key:`archive`,label:`Archive session ${e.title}`,menuLabel:`Archive`,title:`Archive (hide from the list, keeps the conversation resumable)`,icon:(0,T.jsx)(re,{size:12}),busy:s,onClick:t=>{Ot(t,e,`archive`)}},{key:`rename`,label:`Rename session ${e.title}`,menuLabel:`Rename`,title:`Rename this session`,icon:(0,T.jsx)(i,{size:12}),busy:Xe&&qe===e.sessionId,onClick:t=>{t.stopPropagation(),Je(e.sessionId),X(e.personName??e.title)}},{key:`delete`,label:`Delete session ${e.title}`,menuLabel:`Delete`,title:`Delete session (stops the process, removes the conversation)`,icon:(0,T.jsx)(r,{size:12}),danger:!0,busy:a,onClick:t=>{Tt(t,e)}},le({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})];return(0,T.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,T.jsxs)(`div`,{className:`conv-main-static`,children:[(0,T.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,T.jsxs)(`span`,{className:`conv-stack`,children:[(0,T.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,T.jsx)(f,{channel:e.channel,size:13}),qe===e.sessionId?(0,T.jsx)(`input`,{className:`conv-name conv-name-edit`,autoFocus:!0,value:Ye,disabled:Xe,"aria-label":`New title for session ${e.title}`,onChange:e=>X(e.target.value),onClick:e=>e.stopPropagation(),onKeyDown:t=>{t.key===`Enter`?(t.preventDefault(),kt(e)):t.key===`Escape`&&(t.preventDefault(),Je(null),X(``))},onBlur:()=>{qe===e.sessionId&&!Xe&&(Je(null),X(``))}}):(0,T.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,T.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,T.jsx)(`code`,{className:`conv-session-id`,title:`First 8 characters of this session's id — distinguishes rows with identical auto-titles. The resume/delete buttons act on the full id.`,children:e.sessionId.slice(0,8)}),t&&(0,T.jsxs)(`span`,{children:[` · `,t]})]})]})]}),(0,T.jsx)(fe,{actions:l,disabled:c,collapsed:rt})]},e.sessionId)})]})})(),N===`whatsapp`&&(0,T.jsxs)(`div`,{className:`side-list`,children:[(0,T.jsxs)(`div`,{className:`group-head`,children:[(0,T.jsx)(`span`,{children:gt[ut]}),(0,T.jsxs)(`span`,{className:`group-head-meta`,children:[(0,T.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{mt()},children:(0,T.jsx)(c,{size:12})}),(0,T.jsx)(`span`,{children:String(ht.get(ut).length)})]})]}),ht.get(ut).map(e=>{let t=ke(e.lastMessageAt);return(0,T.jsxs)(`div`,{className:`conv conv-with-actions${O===e.sessionId?` active`:``}`,children:[(0,T.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{k(e),E()},title:e.title,children:[(0,T.jsx)(m,{channel:e.channel,size:14}),(0,T.jsxs)(`span`,{className:`conv-stack`,children:[(0,T.jsxs)(`span`,{className:`conv-name-line`,children:[(0,T.jsx)(`span`,{className:`conv-name`,children:h(e)}),e.role===`public`&&(0,T.jsx)(`span`,{className:`conv-tag conv-tag-public`,children:`Public`})]}),t&&(0,T.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),(0,T.jsx)(fe,{actions:[le({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1,collapsed:rt})]},e.sessionId)})]}),(0,T.jsx)(Ne,{}),(0,T.jsxs)(`div`,{className:`side-foot`,children:[(0,T.jsx)(`div`,{className:`avatar`,children:d?(0,T.jsx)(`img`,{src:d,alt:M}):de}),(0,T.jsxs)(`div`,{className:`who`,children:[(0,T.jsx)(`span`,{className:`name`,children:M}),(0,T.jsx)(`span`,{className:`role`,children:o??`operator`})]})]}),V&&(0,T.jsx)(`div`,{className:`copy-toast${V.failed?` copy-toast-failed`:``}`,role:`status`,children:V.message}),(0,T.jsx)(Ce,{error:_e,onClose:()=>U(null)}),(0,T.jsx)(xe,{target:ze,onCancel:()=>Be(null),onConfirm:()=>{let e=ze;Be(null),e&&Et(e)}})]})}var Ae=5e3,je=3e4,Me=3e4;function Ne(){let[e,t]=(0,w.useState)(null);if((0,w.useEffect)(()=>{let e=!1,n=null;async function r(){try{let n=await fetch(`/api/admin/system-stats`);if(!n.ok){console.error(`[admin-ui] system-stats-fetch-failed status=${n.status}`);return}let r=await n.json();e||t(r)}catch(e){console.error(`[admin-ui] system-stats-fetch-failed reason=${e instanceof Error?e.message:String(e)}`)}}function i(){n===null&&(r(),n=setInterval(()=>{r()},Ae))}function a(){n!==null&&(clearInterval(n),n=null)}function o(){document.hidden?a():i()}return document.hidden||i(),document.addEventListener(`visibilitychange`,o),()=>{e=!0,a(),document.removeEventListener(`visibilitychange`,o)}},[]),!e||e.platform===`darwin`)return null;let n=e.cpuPct,r=e.memUsedPct,i=n!==null&&n>=.9,a=n!==null&&n>=.98,o=r!==null&&r>=.9,s=r!==null&&r>=.98,c=i||o,l=a||s,u=e=>e===null?`—`:`${Math.round(e*100)}%`,d=e=>{if(e===null)return{width:`0%`,background:`var(--text-tertiary)`};let t=Math.min(1,Math.max(0,e)),n=Math.round(140*(1-t));return{width:`${Math.round(t*100)}%`,background:`hsl(${n}, 65%, 45%)`}},f=[`system-stats`];return c&&f.push(`system-stats--warn`),l&&f.push(`system-stats--crit`),(0,T.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,T.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,T.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,T.jsx)(`div`,{className:`system-stats__bar`,children:(0,T.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,T.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,T.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,T.jsx)(`div`,{className:`system-stats__bar`,children:(0,T.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var q=`admin-sidebar-collapsed`,Pe=`admin-sidebar-drawer-open`;function J(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(q)===`1`}catch{return!1}}function Fe(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(q,`1`):window.sessionStorage.removeItem(q)}catch{}}function Ie(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(Pe)===`1`}catch{return!1}}function Le(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(Pe,`1`):window.sessionStorage.removeItem(Pe)}catch{}}var Y=720;function Re(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.sessionId)}&projectDir=${encodeURIComponent(t.projectDir)}`}}function ze(e,t){if(e!==`/`)return null;let n=new URLSearchParams(t),r=n.get(`wa`),i=n.get(`projectDir`);return!r||!i?null:{sessionId:r,projectDir:i,title:``,senderId:null,startedAt:``,channel:`whatsapp`,role:`admin`,operatorName:null,whatsappName:null,lastMessageAt:null,modelGated:!1,model:null}}function Be(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`chat`?`/chat`:`/browser`}function Ve(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,userName:s,userAvatar:c,role:l,children:u,footer:f}=e,[p,m]=(0,w.useState)(()=>J()),[h,ee]=(0,w.useState)(()=>Ie()),[_,te]=(0,w.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${Y}px)`).matches),[v,ne]=(0,w.useState)(()=>typeof window>`u`?null:ze(window.location.pathname,window.location.search)),[re]=(0,w.useState)(()=>v!==null);(0,w.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${Y}px)`),t=e=>te(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let y=(0,w.useCallback)(e=>{Fe(e),m(e)},[]),b=(0,w.useCallback)(e=>{Le(e),ee(e)},[]);(0,w.useEffect)(()=>{if(typeof window>`u`)return;let e=window.location?.pathname??``;console.info(`[admin-ui] shell-mount route=${e} variant=${r} sidebar=${r===`operator`?`none`:`present`} collapsed=${p} drawer=${h}`)},[]),(0,w.useEffect)(()=>{typeof window>`u`||!v||(console.info(`[admin-ui] wa-hydrate route=/ sessionId=${v.sessionId.slice(0,8)}`),window.history.replaceState(null,``,`/`))},[]);let ie=(0,w.useCallback)(e=>{if(e===null){ne(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=Re(t,e);console.info(`[admin-ui] wa-open route=${t} via=${n.via} sessionId=${e.sessionId.slice(0,8)}`),n.via===`in-place`?ne(e):window.location.href=n.href},[]),x=_?h:!p,S=(0,w.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${Y}px)`).matches){let e=h;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),b(!e)}else{let e=p;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),y(!e)}},[p,h,y,b]),ae=(0,w.useCallback)(e=>{let t=Be(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),[oe,se]=(0,w.useState)(`chat`),[C,ce]=(0,w.useState)([]);(0,w.useEffect)(()=>{if(r!==`operator`||!t)return;let e=!1;return fetch(`/api/whatsapp-reader/conversations?session_key=${encodeURIComponent(t)}`).then(e=>e.ok?e.json():{conversations:[]}).then(t=>{e||ce(t.conversations??[])}).catch(()=>{}),()=>{e=!0}},[r,t]);let E=(0,w.useMemo)(()=>[...new Set(C.map(e=>e.channel))],[C]),D={collapsed:p,mobileDrawerOpen:h,sidebarOpen:x,onToggleSidebar:S,setMobileDrawerOpen:b,selectedWhatsapp:v,onClearWhatsapp:()=>ne(null)};return r===`operator`?(0,T.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,T.jsx)(d,{businessName:n,variant:r,onNavigate:ae,conversationsCount:C.length,conversationsChannels:E,onOpenConversations:()=>se(`conversations`),onToggleSidebar:S,sidebarOpen:x,onLogout:i,onDisconnect:a,disconnecting:o}),(0,T.jsx)(`div`,{className:`platform platform-operator`,children:oe===`conversations`?(0,T.jsx)(g,{conversations:C,sessionKey:t??``,onBack:()=>se(`chat`)}):typeof u==`function`?u(D):u}),f]}):(0,T.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,T.jsx)(d,{businessName:n,variant:r,onNavigate:ae,onToggleSidebar:S,sidebarOpen:x,onLogout:i,onDisconnect:a,disconnecting:o}),(0,T.jsxs)(`div`,{className:`platform${h?` menu-open`:``}${p?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,T.jsx)(K,{businessName:n,cacheKey:t,role:l??null,userName:s,userAvatar:c??null,onSelectProjects:()=>{window.location.href=`/graph?label=Project`},onSelectPeople:()=>{window.location.href=`/graph?label=Person`},onSelectTasks:()=>{window.location.href=`/graph?label=Task`},onSelectAgents:()=>{window.location.href=`/graph?label=Agent`},onCloseMobileDrawer:()=>b(!1),collapsed:p,mobileDrawerOpen:h,selectedWhatsappId:v?.sessionId??null,onSelectWhatsappConversation:ie,initialWhatsappSurface:re}),!_&&(0,T.jsx)(le,{}),typeof u==`function`?u(D):u]}),h&&(0,T.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>b(!1)}),f]})}export{N as a,I as c,oe as d,ae as f,v as h,F as i,D as l,y as m,Oe as n,P as o,x as p,we as r,he as s,Ve as t,C as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{x as e}from"./OperatorConversations-
|
|
1
|
+
import{x as e}from"./OperatorConversations-BqFmHTF1.js";var t=e();function n({checked:e,onChange:n,label:r,disabled:i}){return(0,t.jsxs)(`label`,{className:`maxy-checkbox${i?` maxy-checkbox--disabled`:``}`,children:[(0,t.jsx)(`input`,{type:`checkbox`,checked:e,onChange:e=>n(e.target.checked),disabled:i}),(0,t.jsx)(`span`,{className:`maxy-checkbox__box`,children:`✱`}),r&&(0,t.jsx)(`span`,{className:`maxy-checkbox__label`,children:r})]})}export{n as t};
|