@rubytech/create-maxy-code 0.1.319 → 0.1.320
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/base-toolchain-deps.test.js +67 -0
- package/dist/index.js +7 -1
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-style/dist/index.js +15 -0
- package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-style/src/index.ts +16 -0
- package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-write/dist/index.js +3 -0
- package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-write/src/index.ts +3 -0
- package/payload/platform/lib/models/dist/index.d.ts +8 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +13 -1
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +17 -0
- package/payload/platform/neo4j/schema.cypher +103 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +33 -4
- package/payload/platform/plugins/docs/references/admin-ui.md +21 -1
- package/payload/platform/plugins/docs/references/neo4j.md +9 -0
- package/payload/platform/plugins/docs/references/plugins-guide.md +2 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js +28 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js +7 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js +19 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js.map +1 -1
- package/payload/platform/plugins/memory/references/schema-knowledge-work.md +80 -0
- package/payload/platform/plugins/projects/PLUGIN.md +11 -0
- package/payload/platform/plugins/projects/references/meeting-to-tasks.md +34 -0
- package/payload/platform/plugins/projects/references/prioritization.md +43 -0
- package/payload/platform/plugins/projects/references/risk-premortem.md +34 -0
- package/payload/platform/plugins/projects/references/sprint.md +5 -1
- package/payload/platform/plugins/projects/references/stakeholder-map.md +43 -0
- package/payload/platform/scripts/installer-device-verify.sh +38 -0
- package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.d.ts +3 -1
- package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +2 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +2 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/premium-plugins/venture-studio/PLUGIN.md +12 -3
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/SKILL.md +14 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/competitive-battlecard.md +37 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/competitor-analysis.md +32 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/monetization-strategy.md +35 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/pricing-strategy.md +37 -0
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/strategy-frameworks.md +46 -0
- package/payload/premium-plugins/venture-studio/skills/legal-essentials/SKILL.md +65 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/SKILL.md +6 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-sizing.md +58 -0
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/strategy-red-team.md +41 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-CrdmA3KA.js → AdminLoginScreens-D_e5PYXv.js} +1 -1
- package/payload/server/public/assets/AdminShell-Dc23yALw.js +1 -0
- package/payload/server/public/assets/{Checkbox-DXisJRUK.js → Checkbox-BHxSr_cA.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-BqNOXEu8.js +9 -0
- package/payload/server/public/assets/OperatorConversations-pu50BU11.css +1 -0
- package/payload/server/public/assets/admin-DE55chV9.js +1 -0
- package/payload/server/public/assets/{browser-Bxx8w8BA.js → browser-C1Dp1UxB.js} +1 -1
- package/payload/server/public/assets/chat-BLQDFyDL.js +1 -0
- package/payload/server/public/assets/data-D_L6g-L_.js +1 -0
- package/payload/server/public/assets/graph-labels-C2r7zl8O.js +1 -0
- package/payload/server/public/assets/{graph-B59N222f.js → graph-ticN9QbK.js} +3 -3
- package/payload/server/public/assets/{operator-DpRAhwQN.js → operator-COIYJFG7.js} +1 -1
- package/payload/server/public/assets/{page-Ehjc9b9V.js → page-CsOGSSSb.js} +2 -2
- package/payload/server/public/assets/{public-BcqXGSaE.js → public-CjT_WNkz.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 +85 -7
- package/payload/server/public/assets/AdminShell-0meAFBva.js +0 -1
- package/payload/server/public/assets/OperatorConversations-DBy2G8q3.js +0 -9
- package/payload/server/public/assets/OperatorConversations-DvRXfq3q.css +0 -1
- package/payload/server/public/assets/admin-DX5lZxWt.js +0 -1
- package/payload/server/public/assets/chat-CT9YrNtI.js +0 -1
- package/payload/server/public/assets/data-B9NtsXgF.js +0 -1
- package/payload/server/public/assets/graph-labels-70w-1ov0.js +0 -1
- /package/payload/server/{chunk-NCRJQEZ3.js → chunk-GRKG3KNN.js} +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Monetization Strategy
|
|
2
|
+
|
|
3
|
+
The method for turning a product into a revenue model: how the business makes money, from whom, over what time, and how that compounds. Pricing (`pricing-strategy.md`) sets the number on one tier; monetization sets the **shape of revenue across the whole relationship and the whole market**. Output lands in `04-financials/` and feeds business-plan §6 "The Business Model" and the prospectus.
|
|
4
|
+
|
|
5
|
+
## What this produces
|
|
6
|
+
The revenue architecture: the streams, the wedge→upsell path, the expansion mechanics, and the future network/platform revenue — each tied to evidence and reconciled against the financial model. Apply `internal-workings-scrub.md` before anything reaches a public document.
|
|
7
|
+
|
|
8
|
+
## Citation discipline (binding)
|
|
9
|
+
Every quantitative claim — attach/expansion rates, comparable monetization multiples, market spend that a future stream taps — is a **sourced claim**. Route benchmarks (typical net revenue retention, attach rates, comparable take-rates) through the `research-assistant` specialist with `deep-research`. Mark anything unsourced `source pending — route to research-assistant`. Projected expansion rates must cite a comparable or be flagged as an assumption, never stated as fact.
|
|
10
|
+
|
|
11
|
+
## Process
|
|
12
|
+
|
|
13
|
+
### 1. Map the revenue streams
|
|
14
|
+
List every way money comes in, now and planned: subscription, usage, services, and any future network-effect or platform-take revenue. For each, state whether it exists today or is a forward bet, and what gates it (the milestone that turns it on).
|
|
15
|
+
|
|
16
|
+
### 2. Define the wedge → upsell path
|
|
17
|
+
The narrowest unit of value (the wedge) earns trust and the right to sell the high-value product. State the mechanic: what the wedge delivers, what triggers the upsell, and the expected path from wedge ACV to full ACV. This is the monetization thesis — it must match the GTM "horse before cart" logic in business-plan §7.
|
|
18
|
+
|
|
19
|
+
### 3. Choose the expansion engine
|
|
20
|
+
How does revenue per customer grow without a new sale? Seat expansion, usage growth, tier upgrade, cross-sell. Name the one that dominates and tie it to a sourced or evidenced retention/expansion assumption. Land-and-expand only counts if the expand step has evidence.
|
|
21
|
+
|
|
22
|
+
### 4. Sequence future streams to milestones
|
|
23
|
+
Network-effect or platform revenue is real only when its gating milestone is named (e.g. "federation revenue turns on once N accounts are live"). Put it on the model as a forward stream with its trigger, not as day-one revenue.
|
|
24
|
+
|
|
25
|
+
### 5. Reconcile to the model
|
|
26
|
+
The streams and rates here must roll up to the ARR trajectory in business-plan §12 and the SOM in §4. If monetization implies a number the model doesn't show, one is wrong — reconcile explicitly (see the sibling `zero-to-prototype/references/market-sizing.md` reconciliation discipline).
|
|
27
|
+
|
|
28
|
+
## Output
|
|
29
|
+
`04-financials/` working notes → business-plan §6 and the prospectus. Each stream: status (live/forward), mechanic, gating milestone, and a citation for every benchmark.
|
|
30
|
+
|
|
31
|
+
## Common failures
|
|
32
|
+
- Counting forward network revenue as if it were live.
|
|
33
|
+
- An "expand" motion with no evidence the expand step happens.
|
|
34
|
+
- Attach/retention rates asserted, not sourced or evidenced.
|
|
35
|
+
- Monetization that contradicts the ARR line in the financial model.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Pricing Strategy
|
|
2
|
+
|
|
3
|
+
The method for setting a defensible price for the wedge and the full product. Output lands in `04-financials/` (unit economics) and feeds business-plan §6 "The Business Model" and the prospectus. Apply the `internal-workings-scrub.md` doctrine to anything that reaches a public document.
|
|
4
|
+
|
|
5
|
+
## What this produces
|
|
6
|
+
A price (or price band) per tier, with the **basis** stated: what the price is anchored to, why a buyer pays it, and what it implies for ACV, gross margin, and the LTV:CAC the financial model depends on.
|
|
7
|
+
|
|
8
|
+
## Citation discipline (binding)
|
|
9
|
+
Pricing is built from numbers — competitor prices, willingness-to-pay signals, cost-to-serve, comparable ACVs. Every such number is a **sourced claim**, not a guess. Route competitor pricing, comparable contract values, and willingness-to-pay benchmarks through the `research-assistant` specialist (with `deep-research` / `data-research`); quote the citation. Any figure you cannot source is written `source pending — route to research-assistant`. A price defended by invented competitor numbers is a failed price.
|
|
10
|
+
|
|
11
|
+
## Process
|
|
12
|
+
|
|
13
|
+
### 1. Choose the pricing basis
|
|
14
|
+
Pick the anchor deliberately — they produce very different numbers:
|
|
15
|
+
- **Cost-plus** — cost-to-serve plus a margin. Floor only; never the headline for software.
|
|
16
|
+
- **Competitor-anchored** — relative to the sourced price of the closest alternative (including "the status quo / doing nothing", which often has a real cost).
|
|
17
|
+
- **Value-based** — a share of the quantified value the buyer gets (time saved × loaded cost, revenue gained, risk avoided). The strongest basis when the value is sourced and legible to the buyer.
|
|
18
|
+
|
|
19
|
+
Most seed-stage pricing is value-based with a competitor-anchored sanity check.
|
|
20
|
+
|
|
21
|
+
### 2. Quantify value and willingness to pay
|
|
22
|
+
State the buyer's gain in their units, sourced or evidenced from discovery (the sibling `zero-to-prototype/references/commitment-signals.md` and `mom-test.md`). Price as a fraction of that gain that still leaves the buyer clearly ahead. Cross-check against willingness-to-pay signals from real conversations, not assertion.
|
|
23
|
+
|
|
24
|
+
### 3. Set the structure
|
|
25
|
+
Decide the model (per-seat, usage, flat subscription, tiered) and the tiers. Keep tiers to the few a founder can explain in one breath. Name the wedge price (the narrow public-by-default entry) and the upsell price separately — the wedge→upsell path is the monetization thesis, detailed in `monetization-strategy.md`.
|
|
26
|
+
|
|
27
|
+
### 4. Reconcile to unit economics
|
|
28
|
+
The chosen price must produce an ACV that makes the model work: **LTV:CAC ≥ 3:1** target, **gross margin ≥ 70%** steady-state (the data-room's standing targets). If the price can't clear these with defensible CAC and churn, the price, the segment, or the cost structure is wrong — say which. Compute-cost pass-through follows the data-room doctrine: never mark up LLM compute; the customer pays the provider directly.
|
|
29
|
+
|
|
30
|
+
## Output
|
|
31
|
+
`04-financials/` working notes → business-plan §6 and the prospectus. Each tier: price, basis, ACV implication, and a citation for every external figure.
|
|
32
|
+
|
|
33
|
+
## Common failures
|
|
34
|
+
- Cost-plus pricing for value-dense software — leaves money on the table.
|
|
35
|
+
- Competitor prices asserted from memory instead of sourced.
|
|
36
|
+
- Tiers a buyer can't tell apart.
|
|
37
|
+
- A price that quietly breaks the LTV:CAC the financial model assumes.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Strategy Frameworks — SWOT, PESTLE, Porter's Five Forces, Ansoff
|
|
2
|
+
|
|
3
|
+
Four classic strategy lenses in one file, each a structured way to reason about the market and the company's position. They feed the business plan's market and strategy sections (business-plan §4 "The Market", §7 "Go-to-Market", §8 "Competition") and the prospectus narrative. Output lands in `08-market/` working notes. Apply `internal-workings-scrub.md` before anything reaches a public document.
|
|
4
|
+
|
|
5
|
+
## When to use which
|
|
6
|
+
- **SWOT** — a fast internal/external snapshot before a strategy discussion. Weakest of the four on its own; strongest as a summary after the others.
|
|
7
|
+
- **PESTLE** — when the macro environment (regulation, technology shifts, economics) materially shapes the opportunity. Essential where a regulatory tailwind is part of the thesis.
|
|
8
|
+
- **Porter's Five Forces** — when the question is industry attractiveness and where structural profit pools sit.
|
|
9
|
+
- **Ansoff** — when the question is growth direction: which product/market expansion to pursue next.
|
|
10
|
+
|
|
11
|
+
Pick the lens that answers the live question; don't run all four for completeness.
|
|
12
|
+
|
|
13
|
+
## Citation discipline (binding)
|
|
14
|
+
Each lens pulls in external facts — market growth, regulatory change, supplier concentration, competitor moves, market sizes for adjacencies. Every such fact is a **sourced claim**, routed through the `research-assistant` specialist with `deep-research`. Mark unsourced inputs `source pending — route to research-assistant`. A PESTLE bullet asserting a regulation that doesn't exist, or a Five Forces claim about supplier power with no evidence, is worse than no analysis.
|
|
15
|
+
|
|
16
|
+
## SWOT
|
|
17
|
+
Four quadrants. **Strengths / Weaknesses** are internal and present; **Opportunities / Threats** are external and forward. Discipline: each entry must be specific and, if external, sourced. "Strong team" is filler; "founder shipped the same substrate at prior company" is a strength. Use SWOT to *summarise* after deeper analysis, then derive 2–3 strategic moves from the interactions (e.g. Strength × Opportunity).
|
|
18
|
+
|
|
19
|
+
## PESTLE
|
|
20
|
+
Six external factors: **Political, Economic, Social, Technological, Legal, Environmental.** For each, state the factor, whether it's a tailwind or headwind, and the sourced evidence. Most factors won't move the business — name the two or three that do and why. The Legal factor connects to the data room's compliance section (business-plan §10) and, for legal artefacts, to the `legal-essentials` skill.
|
|
21
|
+
|
|
22
|
+
## Porter's Five Forces
|
|
23
|
+
Rate each force (low/medium/high) **with the reason and evidence**:
|
|
24
|
+
- **Competitive rivalry** — how many, how fierce, on what basis.
|
|
25
|
+
- **Threat of new entrants** — how high are the barriers (capital, regulation, data, network effects)?
|
|
26
|
+
- **Supplier power** — concentration and switching cost of your key inputs (including the foundation-model provider).
|
|
27
|
+
- **Buyer power** — concentration and switching cost of your customers.
|
|
28
|
+
- **Threat of substitutes** — including the status quo / doing nothing.
|
|
29
|
+
The output is a view of where profit pools are defensible and which force you must actively manage.
|
|
30
|
+
|
|
31
|
+
## Ansoff Matrix
|
|
32
|
+
Two axes — existing/new product × existing/new market — give four growth strategies:
|
|
33
|
+
- **Market penetration** (existing product, existing market) — lowest risk.
|
|
34
|
+
- **Market development** (existing product, new market) — the domestic-adjacency / international-upside moves.
|
|
35
|
+
- **Product development** (new product, existing market) — the upsell path.
|
|
36
|
+
- **Diversification** (new product, new market) — highest risk, rarely the seed-stage move.
|
|
37
|
+
Use it to sequence expansion: name which quadrant the next 12 months target and why, tying to the monetization expansion engine (`monetization-strategy.md`) and SOM trajectory (the sibling `zero-to-prototype/references/market-sizing.md`).
|
|
38
|
+
|
|
39
|
+
## Output
|
|
40
|
+
`08-market/` working notes → business-plan §4/§7/§8 and prospectus. Each lens: the structured analysis, sourced external inputs, and the 2–3 strategic implications drawn from it (a framework with no "so what" is wasted).
|
|
41
|
+
|
|
42
|
+
## Common failures
|
|
43
|
+
- Running all four for completeness instead of the one that answers the question.
|
|
44
|
+
- Generic bullets ("strong brand") with no specificity or source.
|
|
45
|
+
- Stopping at the grid without deriving strategic moves.
|
|
46
|
+
- Asserting macro/regulatory facts (PESTLE, Five Forces) without citation.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: legal-essentials
|
|
3
|
+
description: |
|
|
4
|
+
Draft the two corporate-legal documents a founding business needs first: a
|
|
5
|
+
non-disclosure agreement (mutual or one-way) and a privacy policy (UK GDPR +
|
|
6
|
+
PECR aware). UK-domiciled by default. Use when the operator says "draft an NDA",
|
|
7
|
+
"I need a confidentiality agreement", "draft a privacy policy", "GDPR policy",
|
|
8
|
+
or "cookie / data-protection notice". Produces drafts for solicitor review, not
|
|
9
|
+
legal advice. Outputs land in the data room's 02-corporate-legal/ section.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Legal Essentials
|
|
13
|
+
|
|
14
|
+
Drafts the first two corporate-legal artefacts a founding business needs: an **NDA** and a **privacy policy**. Both land in `02-corporate-legal/` of the data room. UK-domiciled by default, matching the `investor-data-room` jurisdiction.
|
|
15
|
+
|
|
16
|
+
## Binding constraints (read first)
|
|
17
|
+
|
|
18
|
+
- **These are drafts for solicitor review, not legal advice.** Every document produced carries the disclaimer below, verbatim, at the top. The agent never tells the operator a document is "ready to sign" or "legally sufficient".
|
|
19
|
+
- **Never invent company particulars.** Legal entity name, company number, registered office, director names, jurisdiction, data-controller contact, retention periods — these are **operator-supplied or left as a clearly-marked placeholder** (e.g. `[REGISTERED COMPANY NAME]`, `[COMPANY NUMBER]`, `[REGISTERED OFFICE ADDRESS]`). A guessed company number or address is a defect, not a convenience. If the data room has a populated `02-corporate-legal/` entity record (or `03-cap-table/`), read the particulars from there; otherwise placeholder them and tell the operator which fields they must fill.
|
|
20
|
+
- **No fabricated legal facts.** Do not assert that a clause "satisfies" a regulation or that a retention period "is required by law" unless that is a sourced, well-established requirement. Where a jurisdiction-specific fact is needed and uncertain, mark it for solicitor confirmation rather than stating it.
|
|
21
|
+
- **Operator-triggered, not auto-seeded.** This skill fires when the operator asks for an NDA or privacy policy. It is not pre-seeded as a scaffold task; when the operator wants one, `work-create` a Task under the business's Project (per the venture-studio "new artefact → work-create a Task" pattern), then produce the artefact into `02-corporate-legal/`.
|
|
22
|
+
|
|
23
|
+
## Standard disclaimer (top of every output)
|
|
24
|
+
|
|
25
|
+
> **Draft for review.** This document is a starting-point draft generated for the operator. It is not legal advice and has not been reviewed by a qualified solicitor. Have it reviewed by a solicitor in the relevant jurisdiction before relying on it or asking anyone to sign it. Fields in `[SQUARE BRACKETS]` must be completed before use.
|
|
26
|
+
|
|
27
|
+
## NDA
|
|
28
|
+
|
|
29
|
+
Ask the operator one routing question first: **mutual** (both sides disclose) or **one-way** (only one side discloses). Default to mutual for partnership and investor conversations; one-way when the operator is the sole discloser (e.g. showing a contractor confidential material).
|
|
30
|
+
|
|
31
|
+
Draft into `02-corporate-legal/nda.md` (or the operator's chosen name) with these clauses, UK-default:
|
|
32
|
+
|
|
33
|
+
- **Parties** — placeholders for both parties' legal name, company number, registered office.
|
|
34
|
+
- **Purpose** — the specific permitted purpose of disclosure (operator supplies; do not invent a deal).
|
|
35
|
+
- **Definition of Confidential Information** — what is covered and the standard carve-outs (already public, independently developed, already known, required by law to disclose).
|
|
36
|
+
- **Obligations** — use only for the purpose, protect with reasonable care, restrict to need-to-know recipients bound by equivalent terms.
|
|
37
|
+
- **Term and survival** — duration of the agreement and how long confidentiality survives termination (placeholder the operator confirms).
|
|
38
|
+
- **Return/destruction** of materials on request.
|
|
39
|
+
- **No licence / no obligation to proceed** — disclosure grants no IP licence and no obligation to enter a deal.
|
|
40
|
+
- **Governing law and jurisdiction** — England & Wales by default; placeholder if elsewhere.
|
|
41
|
+
- **Signatures** — blocks for both parties; do not pre-fill names.
|
|
42
|
+
|
|
43
|
+
Keep it proportionate — a founding-stage NDA, not an enterprise master agreement. Flag any clause where the operator's situation needs a solicitor's tailoring.
|
|
44
|
+
|
|
45
|
+
## Privacy policy
|
|
46
|
+
|
|
47
|
+
Draft into `02-corporate-legal/privacy-policy.md`, aware of **UK GDPR**, the **Data Protection Act 2018**, and **PECR** (the cookies/electronic-marketing rules). Cover:
|
|
48
|
+
|
|
49
|
+
- **Who we are** — data controller identity and contact (placeholders for company name, number, registered office, and a data-protection contact email).
|
|
50
|
+
- **What personal data we collect** — by category, tied to how the business actually collects it (operator describes; do not invent data flows).
|
|
51
|
+
- **Lawful basis** for each processing purpose (consent / contract / legitimate interests / legal obligation) — state the basis per purpose; mark for solicitor confirmation where the basis is genuinely arguable.
|
|
52
|
+
- **How we use it / purposes.**
|
|
53
|
+
- **Sharing** — processors and third parties, including any international transfers and the safeguard relied on.
|
|
54
|
+
- **Retention** — how long, by category. Placeholder the periods the operator must set; do not assert a statutory period that isn't established.
|
|
55
|
+
- **Data-subject rights** under UK GDPR (access, rectification, erasure, restriction, portability, objection) and how to exercise them.
|
|
56
|
+
- **Cookies and similar technologies (PECR)** — what is set, consent mechanism for non-essential cookies.
|
|
57
|
+
- **Automated decision-making** — include a section only if the business does ADM/profiling; if so, note the UK GDPR Article 22 position and route detailed compliance to `investor-data-room`'s `compliance-research-checklist.md`. If the business does not, say so plainly.
|
|
58
|
+
- **Complaints / ICO** — right to complain to the Information Commissioner's Office.
|
|
59
|
+
- **Changes and effective date** — placeholder date.
|
|
60
|
+
|
|
61
|
+
Where a specific compliance question is genuinely uncertain (e.g. whether a transfer mechanism applies), mark it for solicitor confirmation rather than asserting an answer. For deeper regulatory research (DMCC, ICO ADM, EU AI Act), dispatch the `research-assistant` specialist with `deep-research` rather than asserting the position from memory.
|
|
62
|
+
|
|
63
|
+
## Output
|
|
64
|
+
|
|
65
|
+
Both artefacts land in `02-corporate-legal/`. Each opens with the standard disclaimer, uses `[SQUARE BRACKET]` placeholders for every company particular and jurisdiction-specific value the operator must supply, and ends with a short "before you use this" note listing the fields to complete and the recommendation to have a solicitor review it.
|
|
@@ -105,6 +105,8 @@ Based on discovery, recommend frameworks from this matrix:
|
|
|
105
105
|
- → **5 Whys** or **JTBD** for understanding the core problem
|
|
106
106
|
- → **Market Type Framework** for realistic expectations
|
|
107
107
|
- → **Pre-mortem** for risk identification
|
|
108
|
+
- → **Strategy Red-Team** to rank load-bearing assumptions by cheapest disconfirming test (references/strategy-red-team.md)
|
|
109
|
+
- → **Market Sizing** for a sourced TAM/SAM/SOM (references/market-sizing.md)
|
|
108
110
|
|
|
109
111
|
**Goal: Find and understand customers**
|
|
110
112
|
- → **Mom Test** for customer conversations (references/mom-test.md)
|
|
@@ -261,6 +263,8 @@ For go-to-market planning:
|
|
|
261
263
|
|
|
262
264
|
| If you need to... | Use these frameworks |
|
|
263
265
|
|-------------------|---------------------|
|
|
266
|
+
| Size the market | Market Sizing (TAM/SAM/SOM) |
|
|
267
|
+
| Stress-test the plan | Strategy Red-Team, Pre-mortem |
|
|
264
268
|
| Understand the problem | 5 Whys, JTBD, Problem Validation |
|
|
265
269
|
| Find customers | Earlyvangelist, Boolean Search, Persona |
|
|
266
270
|
| Interview customers | Mom Test, Commitment Signals |
|
|
@@ -326,6 +330,8 @@ All frameworks are in `references/` directory:
|
|
|
326
330
|
| Landing Page | `landing-page.md` |
|
|
327
331
|
| OG Images | `og-images.md` |
|
|
328
332
|
| PRD | `prd.md` |
|
|
333
|
+
| Market Sizing (TAM/SAM/SOM) | `market-sizing.md` |
|
|
334
|
+
| Strategy Red-Team | `strategy-red-team.md` |
|
|
329
335
|
|
|
330
336
|
## Notes
|
|
331
337
|
|
package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-sizing.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Market Sizing — TAM / SAM / SOM
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Produce a defensible market size — TAM, SAM, SOM — built **two independent ways** (top-down and bottom-up) and reconciled, so the number survives investor scrutiny instead of collapsing under the first "where did that come from?".
|
|
5
|
+
|
|
6
|
+
## When to Use
|
|
7
|
+
- Sizing the opportunity for the business plan's market section (`08-market/` and business-plan §4 "The Market").
|
|
8
|
+
- Pressure-testing whether a wedge sits in a market large enough to matter.
|
|
9
|
+
- Setting a market-share trajectory the financial model has to reconcile against.
|
|
10
|
+
|
|
11
|
+
## Definitions (use these exactly)
|
|
12
|
+
- **TAM (Total Addressable Market):** total annual revenue if every possible buyer in the defined geography bought the category.
|
|
13
|
+
- **SAM (Serviceable Addressable Market):** the slice of TAM your product, channel, and geography can actually serve today.
|
|
14
|
+
- **SOM (Serviceable Obtainable Market):** the slice of SAM you can realistically win in the plan's horizon (typically a 3–5 year share of SAM).
|
|
15
|
+
|
|
16
|
+
State the geography and the year for every figure. A TAM with no geography and no date is not a number.
|
|
17
|
+
|
|
18
|
+
## Citation discipline (binding)
|
|
19
|
+
Every quantitative input — population counts, buyer counts, average contract value, category spend, growth rate — is a **claim that must trace to a source**. Do not invent figures. Route every figure through the `research-assistant` specialist (with `deep-research` / `data-research`); it returns the figure with a citation the artefact quotes verbatim. Any number you cannot yet source is written as `source pending — route to research-assistant`, never as a plausible-looking guess. A sizing with bare numbers is a failed sizing.
|
|
20
|
+
|
|
21
|
+
## Process
|
|
22
|
+
|
|
23
|
+
### 1. Top-down construction
|
|
24
|
+
Start from a published category total and narrow it with sourced filters.
|
|
25
|
+
|
|
26
|
+
1. Find the broadest credible category-spend figure for the geography (industry report, government statistic, analyst house). **Cite it.**
|
|
27
|
+
2. Apply successive narrowing filters — segment, firmographic, geography, addressability — each filter a **sourced or explicitly-assumed** percentage. Label every assumption.
|
|
28
|
+
3. The result after filters is your top-down SAM; the unfiltered total is the top-down TAM.
|
|
29
|
+
|
|
30
|
+
Record each step as `figure × filter (source) = subtotal` so the chain is auditable.
|
|
31
|
+
|
|
32
|
+
### 2. Bottom-up construction
|
|
33
|
+
Build the number from unit economics, independent of the top-down chain.
|
|
34
|
+
|
|
35
|
+
1. Count the addressable buyers (`research-assistant` returns the count + source).
|
|
36
|
+
2. Multiply by annual contract value (ACV) you can defend — from your own pricing (the sibling `investor-data-room/references/pricing-strategy.md`) or sourced comparables.
|
|
37
|
+
3. `buyers × ACV = bottom-up SAM`. Extending the buyer count to the whole category gives bottom-up TAM.
|
|
38
|
+
|
|
39
|
+
Bottom-up is the more credible of the two for SOM because it ties directly to what you charge.
|
|
40
|
+
|
|
41
|
+
### 3. Reconciliation (the step that makes it defensible)
|
|
42
|
+
Put the two SAM figures side by side.
|
|
43
|
+
|
|
44
|
+
- If they agree within roughly the same order of magnitude, state both and use the **bottom-up** figure as the headline (it is grounded in ACV).
|
|
45
|
+
- If they diverge, **explain the divergence explicitly**: which filter or which buyer-count assumption drives the gap, and which number you are standing behind and why. An unreconciled gap is the single most common reason a sizing gets torn apart in diligence.
|
|
46
|
+
- Never average the two to hide a gap. Reconcile or pick, with the reason stated.
|
|
47
|
+
|
|
48
|
+
### 4. SOM and trajectory
|
|
49
|
+
SOM is a **sourced or stated** share of SAM over the plan horizon. Tie it to the market-share path in the financial model (business-plan §12) — the SOM here and the ARR target there must describe the same line. If they don't, one of them is wrong.
|
|
50
|
+
|
|
51
|
+
## Output
|
|
52
|
+
Lands in `08-market/` (working) and business-plan §4 "The Market". Format: TAM / SAM / SOM each with geography, year, a one-line method note (top-down vs bottom-up), and a citation per figure. The reconciliation paragraph is part of the deliverable, not an optional extra.
|
|
53
|
+
|
|
54
|
+
## Common failures
|
|
55
|
+
- A single top-down number with no bottom-up check — looks authoritative, survives nothing.
|
|
56
|
+
- Percentages with no source ("we assume 10% are addressable") presented as fact.
|
|
57
|
+
- TAM inflated by widening the geography late, untethered from SOM.
|
|
58
|
+
- SOM that the financial model's ARR contradicts.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Strategy Red-Team — rank assumptions by cheapest disconfirming test
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Before a fundraise, surface the assumptions the whole plan rests on, then **rank them by how cheaply you could prove them wrong**. The goal is not a risk list — `pre-mortem.md` already produces one. The goal is a test queue: the order in which to spend the next few days disconfirming the beliefs that would kill the company first and cost least to check.
|
|
5
|
+
|
|
6
|
+
## When to Use
|
|
7
|
+
- Final pass before the data room goes to investors.
|
|
8
|
+
- When the plan "feels" strong and nobody can say what would break it — the dangerous state.
|
|
9
|
+
- After a pivot, to re-test the new load-bearing assumptions.
|
|
10
|
+
|
|
11
|
+
## How this differs from pre-mortem
|
|
12
|
+
Pre-mortem imagines failure and works backwards to causes. Red-team takes the **current plan as written** and attacks its load-bearing assumptions, then sequences the attacks by cost-to-disconfirm. Pre-mortem is divergent (surface risks); red-team is convergent (what do I test first, this week).
|
|
13
|
+
|
|
14
|
+
## Process
|
|
15
|
+
|
|
16
|
+
### 1. Extract load-bearing assumptions
|
|
17
|
+
Read the plan and list the beliefs that, if false, sink it. Force each into the form: **"We are betting that [X]."** A belief that, when negated, leaves the plan intact is not load-bearing — drop it. Typical homes: demand exists at the claimed intensity; the wedge converts to the upsell; the market is as large as sized; the channel reaches the buyer; the unit economics hold; the regulatory read is correct.
|
|
18
|
+
|
|
19
|
+
### 2. Score each assumption on two axes
|
|
20
|
+
- **Blast radius** — if this is false, how much of the plan dies? (fatal / major / containable)
|
|
21
|
+
- **Cost to disconfirm** — what is the *cheapest* test that could prove it false? (a day of desk research / ten customer calls / a paid pilot / unknowable pre-launch)
|
|
22
|
+
|
|
23
|
+
The cheapest disconfirming test, not the cheapest confirming one. Confirmation is easy and lies; you are looking for the fastest way to find out you're wrong.
|
|
24
|
+
|
|
25
|
+
### 3. Rank: fatal-and-cheap first
|
|
26
|
+
Sort by blast radius descending, then by cost-to-disconfirm ascending. The top of the list is **fatal assumptions you can test cheaply this week**. That is where the next few days go. Fatal-but-expensive-to-test assumptions get flagged as standing risks (and named in the business plan's risk table); containable assumptions wait.
|
|
27
|
+
|
|
28
|
+
### 4. Define the test, not the worry
|
|
29
|
+
For each top-ranked assumption, write the concrete disconfirming test: who you talk to, what number you pull, what result would kill the belief. "Talk to customers" is not a test. "Ask 10 self-employed agents whether they'd pay £X/month before launch; fewer than 3 yes = belief dead" is a test.
|
|
30
|
+
|
|
31
|
+
## Citation discipline (binding)
|
|
32
|
+
Where a disconfirming test is "pull the figure and check it" (market size, growth rate, comparable pricing), route that figure through the `research-assistant` specialist with `deep-research` — the cheapest disconfirming test for a quantitative assumption is often a sourced number, not a customer call. Do not assert the assumption is confirmed or refuted on an unsourced figure; cite it or mark it `source pending — route to research-assistant`.
|
|
33
|
+
|
|
34
|
+
## Output
|
|
35
|
+
A ranked table — assumption / blast radius / cheapest disconfirming test / kill-criterion — feeding pre-fundraise validation. The fatal-and-cheap rows become the immediate test queue; the fatal-and-expensive rows feed the business plan's risks-and-mitigations section.
|
|
36
|
+
|
|
37
|
+
## Common failures
|
|
38
|
+
- Listing risks instead of betting-statements — you can't test "competition" but you can test "we bet incumbents can't match data sovereignty within 12 months".
|
|
39
|
+
- Ranking by likelihood instead of blast-radius × cost — you end up testing cheap, survivable things.
|
|
40
|
+
- Designing confirming tests that can only succeed.
|
|
41
|
+
- Stopping at the worry without a kill-criterion.
|
package/payload/server/public/assets/{AdminLoginScreens-CrdmA3KA.js → AdminLoginScreens-D_e5PYXv.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./chunk-Pqm5yXtL.js";import{E as t,L as n,N as r,b as i,v as a,y as o}from"./OperatorConversations-DBy2G8q3.js";import{i as s}from"./admin-types-CJrGd46U.js";import{d as c,v as l}from"./AdminShell-0meAFBva.js";import{t as u}from"./Checkbox-DXisJRUK.js";var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(n(),1);function h(e=`admin`){let[t,n]=(0,m.useState)(`loading`),[i,a]=(0,m.useState)(``),[o,c]=(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 r=await t.json();D(r.session_key),R(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=s(r.thinkingView);return G.current=i,W(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}if(!a.claude_authenticated){n(`connect-claude`);return}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[t,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(t!==`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`){n(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){r(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,m.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&n(`enter-pin`)}).catch(()=>{})},[t]);async function Z(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){h((await r.json().catch(()=>({}))).error||`Invalid PIN`);return}let i=await r.json();if(i.accounts&&!i.session_key){console.log(`[admin] account picker shown: userId=${i.userId} accountCount=${i.accounts.length}`),B(i.accounts),n(`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(``),n(`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 r=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:r,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 r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`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(r);return}a(``),n(`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 l())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 n(`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(``),n(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:t,setAppState:n,pin:i,setPin:a,operatorName:o,setOperatorName:c,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(``),n(`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=i();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:i,pinLoading:s,pinError:l,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:o,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,a.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,a.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)(c,{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:()=>i(e=>!e),label:`Show PIN`})]}),l&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:l})]})})}function y(e){let{pin:t,setPin:n,showPin:r,setShowPin:i,pinLoading:s,pinError:l,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:o,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:a.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)(c,{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:()=>i(e=>!e),label:`Show PIN`}),(0,g.jsx)(c,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),l&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:l})]})]})}function b(e){let{accounts:n,loading:r,error:i,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:o,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:a.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:n.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)(t,{className:`account-picker-spinner`,size:16})]},e.accountId))}),i&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:i})]})})}function x(e){let{authPolling:t,setAuthPolling:n,authLoading:r,setAuthLoading:i,pinError:s,setPinError:l,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}h(!1)}async function v(){i(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){n(!0),f(!0),i(!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}l(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}i(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!1),l(``)}return t||d?(0,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)(c,{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:o,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:a.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,a.productName]}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,g.jsx)(c,{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{D as t,P as n,R as r,b as i,x as a,y as o}from"./OperatorConversations-BqNOXEu8.js";import{i as s}from"./admin-types-CJrGd46U.js";import{d as c,v as l}from"./AdminShell-Dc23yALw.js";import{t as u}from"./Checkbox-BHxSr_cA.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[t,r]=(0,m.useState)(`loading`),[i,a]=(0,m.useState)(``),[o,c]=(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)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[t,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(t!==`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 t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){n(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,m.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&r(`enter-pin`)}).catch(()=>{})},[t]);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 l())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:t,setAppState:r,pin:i,setPin:a,operatorName:o,setOperatorName:c,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:l,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)(c,{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`})]}),l&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:l})]})})}function y(e){let{pin:t,setPin:n,showPin:r,setShowPin:a,pinLoading:s,pinError:l,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)(c,{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)(c,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),l&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:l})]})]})}function b(e){let{accounts:n,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:n.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)(t,{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:l,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}h(!1)}async function v(){a(!0),l(``);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}l(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}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),l(``)}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)(c,{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)(c,{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,C as n,E as r,L as i,N as a,R as o,T as s,f as c,g as l,h as u,k as d,m as f,p,t as m,v as h,x as g,y as ee}from"./OperatorConversations-BqNOXEu8.js";async function te(){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`}]]),_=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`}]]),v=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`}]]),re=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`}]]),y=a(`ellipsis`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`19`,cy:`12`,r:`1`,key:`1wjl8i`}],[`circle`,{cx:`5`,cy:`12`,r:`1`,key:`1pcz8c`}]]),b=a(`file-text`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]]),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`}]]),ae=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`}]]),oe=a(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),se=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`}]]),ce=a(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),S=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`}]]),C=e(o(),1),w=g(),le={sm:14,md:16,lg:18},T={sm:30,md:38,lg:46};function E({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=le[t],h={...e===`send`?{width:T[t],height:T[t]}:{},...u},g=Object.keys(h).length>0;return(0,w.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,w.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,w.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,w.jsx)(n,{size:m})]}),i&&(0,w.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var D=`maxy-shell-side-px`;function O(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function k(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-O());return Math.min(Math.max(e,248),n)}function A(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(D);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 k(t)}catch{}return 264}function ue({targetSelector:e=`.platform`}){let t=(0,C.useRef)(null),[n,r]=(0,C.useState)(()=>A()),i=(0,C.useRef)(n);(0,C.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,C.useCallback)(()=>{r(e=>{let t=k(e);return t===e?e:t})},[]);(0,C.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(k(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(D,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=k(264);r(e);try{window.localStorage.removeItem(D)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,w.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var de=i();function j({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,C.useRef)(null),[s,c]=(0,C.useState)({position:`fixed`,visibility:`hidden`}),l=(0,C.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,C.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,C.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,de.createPortal)((0,w.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function fe({action:e,disabled:t,open:n,onToggle:r,onClose:i}){let a=(0,C.useRef)(null);return(0,w.jsxs)(w.Fragment,{children:[(0,w.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,w.jsx)(j,{anchorRef:a,onClose:i,className:e.panelClassName,role:`dialog`,ariaLabel:e.label,children:e.panel()})]})}function pe({actions:e,disabled:t,collapsed:n}){let[r,i]=(0,C.useState)(null),[a,o]=(0,C.useState)(!1),[s,c]=(0,C.useState)(null),l=(0,C.useRef)(null);(0,C.useEffect)(()=>{i(null),o(!1),c(null)},[n]);let u=(0,C.useCallback)(()=>{o(!1),c(null)},[]);return n?(0,w.jsxs)(`div`,{className:`conv-actions`,children:[(0,w.jsx)(`button`,{ref:l,type:`button`,className:`conv-action conv-actions-overflow`,onClick:()=>o(e=>!e),disabled:t,"aria-haspopup":`menu`,"aria-expanded":a,"aria-label":`Session actions`,title:`Session actions`,children:(0,w.jsx)(y,{size:12})}),a&&(0,w.jsx)(j,{anchorRef:l,onClose:u,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,w.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,w.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`dialog`,"aria-expanded":s===e.key,disabled:t,onClick:()=>c(t=>t===e.key?null:e.key),children:[e.icon,(0,w.jsx)(`span`,{children:e.menuLabel})]}),s===e.key&&(0,w.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,w.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),u()},children:[e.icon,(0,w.jsx)(`span`,{children:e.menuLabel})]},e.key))})]}):(0,w.jsx)(`div`,{className:`conv-actions`,children:e.map(e=>e.panel?(0,w.jsx)(fe,{action:e,disabled:t,open:r===e.key,onToggle:()=>i(t=>t===e.key?null:e.key),onClose:()=>i(null)},e.key):(0,w.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 M=`claude-opus-4-8[1m]`,N=`claude-sonnet-4-6`,P=`claude-haiku-4-5`,me={[M]:`Opus 4.8 (1M context)`,[N]:`Sonnet 4.6`,[P]:`Haiku 4.5`};function F(e){return me[e]??e}function I(e){return e.replace(/\[1m\]$/,``)}var L=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`];function he(e){return L.includes(e)}var R=[`low`,`medium`,`high`,`xhigh`];[...L],[...R];var z=[M,N,P],B={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},ge=L.map(e=>({value:e,label:B[e]??e})),V={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},H=R.map(e=>({value:e,label:V[e]??e}));function _e(e){if(e){let t=z.find(t=>I(t)===I(e));if(t)return t}return M}function ve({row:e,adminFetch:t,onError:n}){let[r,i]=(0,C.useState)(()=>_e(e.model)),[a,o]=(0,C.useState)(``),[s,c]=(0,C.useState)(``),[l,u]=(0,C.useState)(!1),d=(0,C.useRef)(!1);(0,C.useEffect)(()=>{i(_e(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,w.jsxs)(w.Fragment,{children:[(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Model`}),(0,w.jsx)(`select`,{"data-kind":`model`,value:r,disabled:l,onChange:e=>i(e.target.value),children:z.map(e=>(0,w.jsx)(`option`,{value:e,children:F(e)},e))})]}),(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Mode`}),(0,w.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:l,onChange:e=>o(e.target.value),children:[(0,w.jsx)(`option`,{value:``,children:`Keep current`}),ge.map(e=>(0,w.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Effort`}),(0,w.jsxs)(`select`,{"data-kind":`effort`,value:s,disabled:l,onChange:e=>c(e.target.value),children:[(0,w.jsx)(`option`,{value:``,children:`Keep current`}),H.map(e=>(0,w.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,w.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:l,"aria-busy":l,onClick:()=>void f(),children:`Re-seat`})]})}var ye=[`whatsapp`,`telegram`];function U(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 W(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function be(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,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete session`,children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`span`,{children:`Delete this conversation?`}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,w.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,w.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,w.jsx)(E,{variant:`danger`,size:`sm`,style:{flex:1},onClick:t,children:`Delete`}),(0,w.jsx)(E,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:n,children:`Cancel`})]})]})}):null}var G=`auth-refresh-failed`;function Se({error:e,onClose:t}){if(!e)return null;let n=e.reason===G,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,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`span`,{children:r}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,w.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function Ce(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,C.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,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,w.jsx)(`span`,{children:`Claude Code`}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,w.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,w.jsxs)(w.Fragment,{children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:p>0?W(p):`—`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:U(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.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 be(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}var K=`https://claude.ai/code`,we=200,Te=[500,1e3,1500,2e3,2500,3e3,3e3];function Ee(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:`${K}/${r}`};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function De(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function Oe(e){let{businessName:i,cacheKey:a,role:o,userName:l,userAvatar:m,onSelectProjects:g,onSelectPeople:te,onSelectTasks:y,onSelectAgents:le,onCloseMobileDrawer:T,collapsed:E,selectedWhatsappId:D,onSelectWhatsappConversation:O,initialWhatsappSurface:k=!1}=e,A=h(a),ue=(0,C.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,w.jsx)(se,{size:12}),panelClassName:`reseat-panel`,panel:()=>(0,w.jsx)(ve,{row:e,adminFetch:A,onError:e=>H({message:e,failed:!0})})}),[A]),de=ee.productName,j=typeof l==`string`?l:l===null?`name unavailable`:i||de,fe=(j.trim().charAt(0)||`?`).toUpperCase(),[M,N]=(0,C.useState)(k?`whatsapp`:`sessions`),[P,me]=(0,C.useState)([]),[F,I]=(0,C.useState)(!1),[L,he]=(0,C.useState)(null),[R,z]=(0,C.useState)(!1),[B,ge]=(0,C.useState)(`file`),[V,H]=(0,C.useState)(null),[_e,U]=(0,C.useState)(null),[W,be]=(0,C.useState)([]),[G,Ce]=(0,C.useState)(!1),[K,Oe]=(0,C.useState)(null),[ke,q]=(0,C.useState)(!1),[J,Ne]=(0,C.useState)(!1),[Y,Pe]=(0,C.useState)(!1),[Fe,Ie]=(0,C.useState)(null),[Le,Re]=(0,C.useState)(new Set),[ze,Be]=(0,C.useState)(null),[Ve,He]=(0,C.useState)(new Set),[Ue,We]=(0,C.useState)(new Set),[Ge,Ke]=(0,C.useState)(new Set),[qe,Je]=(0,C.useState)(null),[Ye,X]=(0,C.useState)(``),[Xe,Ze]=(0,C.useState)(!1),[Z,Qe]=(0,C.useState)(!1),$e=(0,C.useRef)(null),et=(0,C.useRef)(0),[tt,nt]=(0,C.useState)(0);(0,C.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()},[M]);let rt=tt>0&&tt<400,[it,at]=(0,C.useState)([]),[ot,st]=(0,C.useState)(!1),[ct,lt]=(0,C.useState)(null),[ut,dt]=(0,C.useState)(`whatsapp`),ft=(0,C.useCallback)(e=>{if(T(),!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}`),c(a,e.downloadPath,e.downloadRoot??`data`),H({message:`Downloading ${e.name}`,failed:!1})},[a,T]);(0,C.useEffect)(()=>{if(!V)return;let e=setTimeout(()=>H(null),2500);return()=>clearTimeout(e)},[V]);let pt=(0,C.useCallback)(async()=>{if(a){z(!0),he(null);try{let e=await A(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);me((await e.json()).artefacts??[]),I(!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,A]),Q=(0,C.useCallback)(async()=>{if(!a)return null;let e=++et.current;q(!0),Oe(null);try{let t=await A(`/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),Ie(n.accountId??null),Ce(!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&&Oe(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===et.current&&q(!1)}},[a,A]),mt=(0,C.useCallback)(async()=>{if(a){lt(null);try{let e=await A(`/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,A]);(0,C.useEffect)(()=>{!a||G||Q()},[a,G,Q]),(0,C.useEffect)(()=>{if(!a)return;let e=null;return mt(),e=setInterval(()=>{mt()},Ae),()=>{e!==null&&clearInterval(e)}},[a,mt]),(0,C.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,je))}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,C.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=()=>{O(null),N(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${F?P.length:0} collapsed=${E}`),pt()},$=1.5,vt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),pt()},yt=()=>{O(null),N(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${G?W.length:0} collapsed=${E}`),G||Q()},bt=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Q()},xt=e=>{N(`whatsapp`),dt(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${ht.get(e)?.length??0} collapsed=${E}`)},St=(0,C.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 A(`/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=Ee(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`?(T(),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})}},[A,T,Ve]),Ct=(0,C.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=Te.length;n++){await new Promise(e=>setTimeout(e,Te[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,C.useCallback)(async()=>{if(Z)return;Qe(!0);let e=window.open(``,`_blank`);try{let t=await A(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),n=await t.json().catch(()=>({})),r=Ee(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)}},[A,Z,Ct]),Tt=(0,C.useCallback)((e,t)=>{e.stopPropagation(),Be(t)},[]),Et=(0,C.useCallback)(async e=>{if(!Le.has(e.sessionId)){Re(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await A(`/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})}}},[A,Le,Q]),Dt=(0,C.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 A(`/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})}}},[A,Ue,Q]),Ot=(0,C.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 A(`/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})}}},[A,Ge,Q]),kt=(0,C.useCallback)(async e=>{let t=Ye.trim();if(!t){H({message:`Title can’t be empty`,failed:!0});return}if(t.length>we){H({message:`Title too long (max ${we})`,failed:!0});return}Ze(!0);try{let n=await A(`/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)}},[A,Ye,Q]);return(0,w.jsxs)(`aside`,{className:`side`,children:[(0,w.jsx)(`div`,{className:`side-new-session-row`,children:(0,w.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:wt,disabled:Z,"aria-busy":Z,children:[(0,w.jsx)(oe,{size:14}),(0,w.jsx)(`span`,{children:Z?`Spawning…`:`New session`})]})}),(0,w.jsxs)(`nav`,{className:`side-nav`,children:[(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),te(),T()},children:[(0,w.jsx)(S,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`People`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),le(),T()},children:[(0,w.jsx)(v,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Agents`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),g(),T()},children:[(0,w.jsx)(re,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Projects`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),y(),T()},children:[(0,w.jsx)(x,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`artefacts`?` active`:``}`,onClick:_t,children:[(0,w.jsx)(b,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`sessions`?` active`:``}`,onClick:yt,children:[(0,w.jsx)(ie,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,w.jsx)(`span`,{className:`kbd`})]}),ot&&ye.filter(e=>ht.get(e).length>0).map(e=>(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`whatsapp`&&ut===e?` active`:``}`,onClick:()=>xt(e),children:[(0,w.jsx)(f,{channel:e,size:16}),(0,w.jsx)(`span`,{className:`label`,children:gt[e]}),(0,w.jsx)(`span`,{className:`kbd`})]},e)),ct&&(0,w.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,w.jsx)(`span`,{className:`label`,children:ct})})]}),M===`artefacts`&&(0,w.jsxs)(`div`,{className:`side-list`,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:`Artefacts`}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:vt,disabled:R,children:(0,w.jsx)(s,{size:12,className:R?`spinning`:void 0})}),(0,w.jsx)(`span`,{children:R?`…`:String(P.length)})]})]}),L&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:L}),F&&!L&&P.length>0&&(()=>{let e=P.filter(e=>e.kind===`agent-template`).length,t=P.length-e;return(0,w.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:P.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,w.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,w.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),F&&!L&&P.length===0&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),P.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?v:b,i=De(e.updatedAt),a=e.downloadPath!==null;return(0,w.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,w.jsx)(r,{size:14,className:`conv-icon`,"data-kind":n?`agent`:`file`,"aria-label":n?`agent template`:`file`}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsx)(`span`,{className:`conv-name-line`,children:(0,w.jsx)(`span`,{className:`conv-name`,children:e.name})}),i&&(0,w.jsx)(`span`,{className:`conv-timestamp`,children:i})]}),a&&(0,w.jsx)(t,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),M===`sessions`&&(()=>{let e=W.filter(e=>J?!0:!e.isSubagent).filter(e=>Y?!0:!e.archived),t=W.some(e=>e.isSubagent),i=W.some(e=>e.archived);return(0,w.jsxs)(`div`,{className:`side-list`,ref:$e,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:`Sessions`}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:bt,disabled:ke,children:(0,w.jsx)(s,{size:12,className:ke?`spinning`:void 0})}),(0,w.jsx)(`span`,{children:ke?`…`:String(e.length)})]})]}),Fe&&(0,w.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,w.jsx)(`code`,{children:Fe})}),(t||i)&&(0,w.jsxs)(`div`,{className:`artefact-filter-chips`,children:[t&&(0,w.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${J?` active`:``}`,"aria-pressed":J,onClick:()=>Ne(e=>!e),title:J?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),i&&(0,w.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${Y?` active`:``}`,"aria-pressed":Y,onClick:()=>Pe(e=>!e),title:Y?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),K&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:K}),G&&!K&&e.length===0&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let t=De(e.startedAt),i=Ve.has(e.sessionId),a=Le.has(e.sessionId),o=Ue.has(e.sessionId),s=Ge.has(e.sessionId),c=i||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,w.jsx)(d,{size:12}),busy:i,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,w.jsx)(ae,{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,w.jsx)(ce,{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,w.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,w.jsx)(_,{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,w.jsx)(r,{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,w.jsx)(n,{size:12}),danger:!0,busy:a,onClick:t=>{Tt(t,e)}},ue({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})];return(0,w.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,w.jsxs)(`div`,{className:`conv-main-static`,children:[(0,w.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,w.jsx)(u,{channel:e.channel,size:13}),qe===e.sessionId?(0,w.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,w.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,w.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,w.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,w.jsxs)(`span`,{children:[` · `,t]})]})]})]}),(0,w.jsx)(pe,{actions:l,disabled:c,collapsed:rt})]},e.sessionId)})]})})(),M===`whatsapp`&&(0,w.jsxs)(`div`,{className:`side-list`,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:gt[ut]}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{mt()},children:(0,w.jsx)(s,{size:12})}),(0,w.jsx)(`span`,{children:String(ht.get(ut).length)})]})]}),ht.get(ut).map(e=>{let t=De(e.lastMessageAt);return(0,w.jsxs)(`div`,{className:`conv conv-with-actions${D===e.sessionId?` active`:``}`,children:[(0,w.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{O(e),T()},title:e.title,children:[(0,w.jsx)(f,{channel:e.channel,size:14}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsxs)(`span`,{className:`conv-name-line`,children:[(0,w.jsx)(`span`,{className:`conv-name`,children:p(e)}),e.role===`public`&&(0,w.jsx)(`span`,{className:`conv-tag conv-tag-public`,children:`Public`})]}),t&&(0,w.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),(0,w.jsx)(pe,{actions:[ue({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1,collapsed:rt})]},e.sessionId)})]}),(0,w.jsx)(Me,{}),(0,w.jsxs)(`div`,{className:`side-foot`,children:[(0,w.jsx)(`div`,{className:`avatar`,children:m?(0,w.jsx)(`img`,{src:m,alt:j}):fe}),(0,w.jsxs)(`div`,{className:`who`,children:[(0,w.jsx)(`span`,{className:`name`,children:j}),(0,w.jsx)(`span`,{className:`role`,children:o??`operator`})]})]}),V&&(0,w.jsx)(`div`,{className:`copy-toast${V.failed?` copy-toast-failed`:``}`,role:`status`,children:V.message}),(0,w.jsx)(Se,{error:_e,onClose:()=>U(null)}),(0,w.jsx)(xe,{target:ze,onCancel:()=>Be(null),onConfirm:()=>{let e=ze;Be(null),e&&Et(e)}})]})}var ke=5e3,Ae=3e4,je=3e4;function Me(){let[e,t]=(0,C.useState)(null);if((0,C.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()},ke))}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,w.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,w.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,w.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,w.jsx)(`div`,{className:`system-stats__bar`,children:(0,w.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,w.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,w.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,w.jsx)(`div`,{className:`system-stats__bar`,children:(0,w.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var q=`admin-sidebar-collapsed`,J=`admin-sidebar-drawer-open`;function Ne(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(q)===`1`}catch{return!1}}function Y(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(q,`1`):window.sessionStorage.removeItem(q)}catch{}}function Pe(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(J)===`1`}catch{return!1}}function Fe(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(J,`1`):window.sessionStorage.removeItem(J)}catch{}}var Ie=720;function Le(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.sessionId)}&projectDir=${encodeURIComponent(t.projectDir)}`}}function Re(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}}function ze(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`chat`?`/chat`:`/browser`}function Be(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,userName:s,userAvatar:c,role:u,children:d,footer:f}=e,[p,h]=(0,C.useState)(()=>Ne()),[g,ee]=(0,C.useState)(()=>Pe()),[te,ne]=(0,C.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${Ie}px)`).matches),[_,v]=(0,C.useState)(()=>typeof window>`u`?null:Re(window.location.pathname,window.location.search)),[re]=(0,C.useState)(()=>_!==null);(0,C.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${Ie}px)`),t=e=>ne(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let y=(0,C.useCallback)(e=>{Y(e),h(e)},[]),b=(0,C.useCallback)(e=>{Fe(e),ee(e)},[]);(0,C.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=${g}`)},[]),(0,C.useEffect)(()=>{typeof window>`u`||!_||(console.info(`[admin-ui] wa-hydrate route=/ sessionId=${_.sessionId.slice(0,8)}`),window.history.replaceState(null,``,`/`))},[]);let ie=(0,C.useCallback)(e=>{if(e===null){v(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=Le(t,e);console.info(`[admin-ui] wa-open route=${t} via=${n.via} sessionId=${e.sessionId.slice(0,8)}`),n.via===`in-place`?v(e):window.location.href=n.href},[]),x=te?g:!p,ae=(0,C.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${Ie}px)`).matches){let e=g;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,g,y,b]),oe=(0,C.useCallback)(e=>{let t=ze(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),[se,ce]=(0,C.useState)(`chat`),[S,le]=(0,C.useState)([]);(0,C.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||le(t.conversations??[])}).catch(()=>{}),()=>{e=!0}},[r,t]);let T=(0,C.useMemo)(()=>[...new Set(S.map(e=>e.channel))],[S]),E={collapsed:p,mobileDrawerOpen:g,sidebarOpen:x,onToggleSidebar:ae,setMobileDrawerOpen:b,selectedWhatsapp:_,onClearWhatsapp:()=>v(null)};return r===`operator`?(0,w.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,w.jsx)(l,{businessName:n,variant:r,onNavigate:oe,conversationsCount:S.length,conversationsChannels:T,onOpenConversations:()=>ce(`conversations`),onToggleSidebar:ae,sidebarOpen:x,onLogout:i,onDisconnect:a,disconnecting:o}),(0,w.jsx)(`div`,{className:`platform platform-operator`,children:se===`conversations`?(0,w.jsx)(m,{conversations:S,sessionKey:t??``,onBack:()=>ce(`chat`)}):typeof d==`function`?d(E):d}),f]}):(0,w.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,w.jsx)(l,{businessName:n,variant:r,onNavigate:oe,onToggleSidebar:ae,sidebarOpen:x,onLogout:i,onDisconnect:a,disconnecting:o}),(0,w.jsxs)(`div`,{className:`platform${g?` menu-open`:``}${p?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,w.jsx)(Oe,{businessName:n,cacheKey:t,role:u??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:g,selectedWhatsappId:_?.sessionId??null,onSelectWhatsappConversation:ie,initialWhatsappSurface:re}),!te&&(0,w.jsx)(ue,{}),typeof d==`function`?d(E):d]}),g&&(0,w.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>b(!1)}),f]})}export{v as _,M as a,I as c,E as d,S as f,b as g,x as h,P as i,he as l,oe as m,Ce as n,L as o,se as p,R as r,N as s,Be as t,F as u,te as v};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{x as e}from"./OperatorConversations-BqNOXEu8.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};
|