@rubytech/create-sitedesk-code 0.1.401 → 0.1.404
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/cloudflare/bin/__tests__/cf-token.test.sh +96 -1
- package/payload/platform/plugins/cloudflare/bin/cf-token.sh +24 -8
- package/payload/platform/plugins/cloudflare/references/api.md +3 -1
- package/payload/platform/plugins/web-designer/skills/web-design/references/placeholders.md +19 -2
- package/payload/platform/plugins/web-designer/skills/web-design/templates/index.html +12 -12
- package/payload/platform/scripts/check-no-esm-require.mjs +3 -0
- package/payload/premium-plugins/sitedesk/BUNDLE.md +6 -4
- package/payload/premium-plugins/sitedesk/PLUGIN.md +2 -2
- package/payload/premium-plugins/sitedesk/agents/sitedesk--media-producer.md +18 -7
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/.claude-plugin/plugin.json +1 -1
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/PLUGIN.md +30 -26
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/README.md +26 -36
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/commands/make-media.md +2 -2
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/SKILL.md +52 -75
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/SKILL.md +52 -120
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/references/sources.md +17 -52
- package/payload/server/public/assets/{AdminLoginScreens-rlk263u9.js → AdminLoginScreens-BzErD9Zo.js} +1 -1
- package/payload/server/public/assets/AdminShell-BihejKg_.js +1 -0
- package/payload/server/public/assets/{Checkbox-Chz6bfy-.js → Checkbox-Ds004CBE.js} +1 -1
- package/payload/server/public/assets/{Transcript-Bsx-bGgY.js → Transcript-CgaMQKgY.js} +1 -1
- package/payload/server/public/assets/{admin-BnZH758N.js → admin-BSuRtMws.js} +1 -1
- package/payload/server/public/assets/{browser-CIrfyZWe.js → browser-BO2eR_YY.js} +1 -1
- package/payload/server/public/assets/{calendar-D6Z8Kmrn.js → calendar-12QuR_oh.js} +1 -1
- package/payload/server/public/assets/chat-Qpyg5t65.js +1 -0
- package/payload/server/public/assets/chevron-left-DBUeR2CX.js +1 -0
- package/payload/server/public/assets/data-Ch5bne41.js +1 -0
- package/payload/server/public/assets/{graph-XZJZHzvv.js → graph-CDOJZepc.js} +1 -1
- package/payload/server/public/assets/{graph-labels-Cabqmf35.js → graph-labels-6HKBjyXX.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DPe-Noig.js → maximize-2-DWmyXX8h.js} +1 -1
- package/payload/server/public/assets/{operator-BM_CDyCb.js → operator-D-s7jVnf.js} +1 -1
- package/payload/server/public/assets/{page-CMIbXzSg.js → page-BcxrdxYL.js} +1 -1
- package/payload/server/public/assets/{page-E7I5sEVt.js → page-rDhp8G9q.js} +1 -1
- package/payload/server/public/assets/{public-CrdWCSk2.js → public-zK67N3z2.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-Dwtj0NJ7.js → rotate-ccw-BzBJxqBN.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-B-GuP1jj.css +1 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +5 -5
- package/payload/server/public/chat.html +9 -9
- package/payload/server/public/data.html +8 -8
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +11 -11
- package/payload/server/public/operator.html +11 -11
- package/payload/server/public/public.html +9 -9
- package/payload/server/server.js +32 -32
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/brand-extract/SKILL.md +0 -86
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/make-media/SKILL.md +0 -75
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/make-media/references/intake-and-questions.md +0 -74
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/references/placeholders.md +0 -96
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/references/sections.md +0 -48
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/templates/index.html +0 -1004
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/microsite/templates/llms.txt +0 -32
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/references/pii-strip.md +0 -64
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/templates/og.html +0 -92
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/templates/social-posts.md +0 -47
- package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/templates/socials.html +0 -87
- package/payload/server/public/assets/AdminShell-C5vWTy2n.js +0 -1
- package/payload/server/public/assets/chat-h7SytZHx.js +0 -1
- package/payload/server/public/assets/chevron-left-DSTeS1_g.js +0 -1
- package/payload/server/public/assets/data-CL7CyX1C.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-BH-YjP0H.css +0 -1
- /package/payload/server/public/assets/{useSubAccountSwitcher-BVCMAnWK.js → useSubAccountSwitcher-Bg0RH3Gk.js} +0 -0
|
@@ -4,10 +4,10 @@ argument-hint: <images-dir-or-zip> [website-url] [social-links] [notes…]
|
|
|
4
4
|
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, Skill, AskUserQuestion
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Build the media deliverable end-to-end on the inputs below, orchestrating the steps yourself.
|
|
8
8
|
|
|
9
9
|
Inputs: $ARGUMENTS
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Route: `web-designer:brand-extract` (website + logo + tokens + company facts) → ask the operator for every field still missing → `microsite` (drives `web-designer:web-design` with the construction framing to build the single-page site into `<output>/site/`) → `socials` in `microsite` mode (renders the Open Graph + social tiles, gallery and captions into `<output>/site/socials/` via `web-designer:socials`).
|
|
12
12
|
|
|
13
13
|
Never invent a fact. Where the website and the operator's notes do not supply a value, ask for it before building. Stop at the finished site + social bundle and report the paths.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: microsite
|
|
3
|
-
description: Build
|
|
3
|
+
description: Build SiteDesk's construction micro-site by driving the shared web-designer builder with construction framing. Runs web-designer:web-design against the brand pack, the operator's copy and their curated photos, supplying the construction schema, UK geography, and the trade-shaped section labels as inputs. Owns no template — the single source is web-designer's. Use after brand-extract, or directly when the brand pack and copy already exist. Trigger phrases include "build the microsite", "lay out the landing page", "turn this brand + photos into a one-page site".
|
|
4
4
|
allowed-tools:
|
|
5
|
+
- Skill
|
|
5
6
|
- Bash
|
|
6
7
|
- Read
|
|
7
8
|
- Write
|
|
@@ -12,77 +13,53 @@ allowed-tools:
|
|
|
12
13
|
|
|
13
14
|
# microsite
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
actual photo — the template's alts are exemplar and must not survive as-is if they
|
|
66
|
-
don't match the picture.
|
|
67
|
-
|
|
68
|
-
### The 2000px rule
|
|
69
|
-
|
|
70
|
-
Never `Read` an image whose longest edge exceeds 2000px — measure first, preview a
|
|
71
|
-
downscaled `/tmp` copy if larger, delete it. Optimise to webp: body tier ~1300px
|
|
72
|
-
q82; hero tier source-resolution q88; the founder portrait kept tall.
|
|
73
|
-
|
|
74
|
-
## Verify every page state
|
|
75
|
-
|
|
76
|
-
Serve `site/` over a local HTTP server and check, at a 1280px desktop and a 390px
|
|
77
|
-
mobile viewport: no horizontal overflow, no broken images, the hero rotates, the
|
|
78
|
-
drawer opens with every link, the sticky sub-nav reveals on scroll, the back-to-top
|
|
79
|
-
appears and works, and both JSON-LD blocks are valid JSON once substituted. Bottom
|
|
80
|
-
-align paired images and equal-height cards where the layout calls for it.
|
|
81
|
-
|
|
82
|
-
## Completion criteria
|
|
83
|
-
|
|
84
|
-
- `site/index.html` and `site/llms.txt` exist with zero surviving `{{ }}`.
|
|
85
|
-
- Every referenced image resolves; alts describe the real photos.
|
|
86
|
-
- Desktop + mobile verified; hero, drawer, sub-nav, back-to-top all work.
|
|
87
|
-
- JSON-LD (`GeneralContractor`/`LocalBusiness`/the right `SCHEMA_TYPE`, plus
|
|
88
|
-
`FAQPage`) parses and matches the visible copy.
|
|
16
|
+
SiteDesk's construction micro-site is the shared `web-designer` site with
|
|
17
|
+
construction framing supplied as input. This skill owns **no template**: it drives
|
|
18
|
+
`web-designer:web-design`, which holds the one canonical template, substitution
|
|
19
|
+
contract, image convention, and page-state verification. Do not copy or hand-build
|
|
20
|
+
any HTML here.
|
|
21
|
+
|
|
22
|
+
## Method
|
|
23
|
+
|
|
24
|
+
Run `web-designer:web-design` (after `web-designer:brand-extract` has produced the
|
|
25
|
+
brand pack) against the curated photos and the operator's copy. Fill web-design's
|
|
26
|
+
tokens as it specifies, with these SiteDesk construction values for the framing
|
|
27
|
+
tokens it exposes:
|
|
28
|
+
|
|
29
|
+
**Schema and geography**
|
|
30
|
+
- `SCHEMA_TYPE` — `GeneralContractor`, or `HomeAndConstructionBusiness` for a
|
|
31
|
+
broader building firm; a narrower schema.org construction subtype when one fits.
|
|
32
|
+
- `COUNTRY_CODE` — `GB`.
|
|
33
|
+
- `PAGE_LANG` — `en-GB`.
|
|
34
|
+
- `COMPANY_NUMBER_LABEL` — `UK company number`.
|
|
35
|
+
|
|
36
|
+
**Section framing (the seven web-design label tokens)**
|
|
37
|
+
- `NAV_STORY_LABEL` — `Our story`
|
|
38
|
+
- `NAV_OFFER_LABEL` — `What we build`
|
|
39
|
+
- `NAV_HOW_LABEL` — `Our craft`
|
|
40
|
+
- `OFFER_EYEBROW` — `What we build`
|
|
41
|
+
- `HOW_EYEBROW` — `Ground to finish`
|
|
42
|
+
- `OFFER_SECTION_ID` — `build`
|
|
43
|
+
- `HOW_SECTION_ID` — `craft`
|
|
44
|
+
|
|
45
|
+
**Copy framing** — write the offer block (`BUILD_*`) as what the firm builds, and
|
|
46
|
+
the process block (`CRAFT_*`) as how a job runs ground to finish. The founder
|
|
47
|
+
section and its "latest update" cards read in the trade's voice — a real job, a
|
|
48
|
+
site the firm is on — never invented. Every copy and photo fact is the operator's;
|
|
49
|
+
a fact you cannot source is a gap you flag, not one you make up.
|
|
50
|
+
|
|
51
|
+
## Verify and report
|
|
52
|
+
|
|
53
|
+
`web-designer:web-design` owns the completion checks (zero surviving `{{ }}`, every
|
|
54
|
+
image resolves, desktop + mobile render, hero/drawer/sub-nav/back-to-top work, both
|
|
55
|
+
JSON-LD blocks parse). Confirm the built site shows the construction framing — the
|
|
56
|
+
nav reads `Our story` / `What we build` / `Our craft`, and the JSON-LD `@type` is
|
|
57
|
+
the construction schema — then report the built `site/` path and any gaps.
|
|
58
|
+
|
|
59
|
+
## What this does not do
|
|
60
|
+
|
|
61
|
+
- It ships no template and no placeholder or section reference — those live in
|
|
62
|
+
`web-designer:web-design`.
|
|
63
|
+
- It runs no brand extraction or intake of its own — `web-designer:brand-extract`
|
|
64
|
+
produces the brand pack and the pipeline gathers the copy.
|
|
65
|
+
- It does not deploy, and it does not render social tiles — that is `socials`.
|
|
@@ -1,133 +1,65 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: socials
|
|
3
|
-
description: Render share-ready Open Graph and social tiles plus
|
|
3
|
+
description: Render share-ready Open Graph and social tiles plus captions for a SiteDesk subject — a brand micro-site, a job's progress, a valuation cycle, or a bespoke topic. The micro-site and bespoke subjects delegate straight to web-designer:socials. The job and valuation subjects are SiteDesk-specific: they read the job's progress from carried job state under a strict money boundary, stage a brand-safe brief, and render it through web-designer:socials in bespoke mode. Never posts — the bundle is for operator review. Trigger phrases include "social tiles for this job", "og images for the site", "valuation-cycle tiles for <job>", "social collateral for <business>".
|
|
4
4
|
allowed-tools:
|
|
5
|
+
- Skill
|
|
5
6
|
- Bash
|
|
6
7
|
- Read
|
|
7
8
|
- Write
|
|
8
9
|
- Edit
|
|
9
10
|
- Glob
|
|
10
11
|
- Grep
|
|
11
|
-
- mcp__plugin_browser_browser__browser-render
|
|
12
|
-
- mcp__plugin_browser_browser__browser-navigate
|
|
13
|
-
- mcp__plugin_browser_browser__browser-evaluate
|
|
14
|
-
- mcp__plugin_browser_browser__browser-resize
|
|
15
|
-
- mcp__plugin_browser_browser__browser-screenshot
|
|
16
|
-
- mcp__plugin_browser_browser__browser-wait-for
|
|
17
12
|
---
|
|
18
13
|
|
|
19
14
|
# socials
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
so the webfonts have landed before capture,
|
|
72
|
-
- `browser-screenshot` to `<output>/socials/og-F-H.png`.
|
|
73
|
-
A **person** hero (`isPerson: true`) renders **portrait only** — a landscape or
|
|
74
|
-
square crop cuts off the head.
|
|
75
|
-
4. `Read` each finished PNG to confirm it rendered: logo legible, copy readable,
|
|
76
|
-
scrim adequate. A **sub-20KB** file is a blank page (server not running, wrong
|
|
77
|
-
port, or the page threw) — diagnose before re-running, never ship it.
|
|
78
|
-
|
|
79
|
-
## 4. Captions — all five platforms, plain register
|
|
80
|
-
|
|
81
|
-
Build `<output>/social-posts.md` from [`templates/social-posts.md`](templates/social-posts.md):
|
|
82
|
-
one block per tile, with copy for **Instagram, LinkedIn, TikTok, Facebook, and X**.
|
|
83
|
-
Write every line in the plain register (the `plainly` skill): no em-dashes, no
|
|
84
|
-
inflation vocabulary, no "it's not X, it's Y", no rhetorical openers, no emoji faking
|
|
85
|
-
enthusiasm. For a `piiBearing` subject, no caption names the client, the address or
|
|
86
|
-
postcode, any figure, any individual, or any email sender.
|
|
87
|
-
|
|
88
|
-
## 5. Gallery, and (microsite only) the og:image
|
|
89
|
-
|
|
90
|
-
Build `<output>/socials.html` from [`templates/socials.html`](templates/socials.html):
|
|
91
|
-
repeat the group block once per tile key. For a **person** hero (`isPerson: true`),
|
|
92
|
-
write only the portrait `<div class="tile">` cell for that key — delete the landscape
|
|
93
|
-
and square cells, since those files are never rendered for a person.
|
|
94
|
-
|
|
95
|
-
The OG snippet (`<div class="snippet">…</div>`) is **microsite only**. In `microsite`
|
|
96
|
-
mode, keep it, render the tiles into the site's `site/socials/`, and set the site's
|
|
97
|
-
`og:image`/`twitter:image` to `<WEBSITE_URL>socials/og-landscape-main.png` (a true
|
|
98
|
-
1200×628 card beats a raw hero for link previews; `WEBSITE_URL` is the site's absolute
|
|
99
|
-
URL from the brand pack). For a **job/valuation/bespoke** bundle there is no site to
|
|
100
|
-
wire — **delete the whole `<div class="snippet">` block** from the copied template
|
|
101
|
-
before substituting, so no `WEBSITE_URL` token survives.
|
|
102
|
-
|
|
103
|
-
## Output contract
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
<output>/
|
|
107
|
-
og.html # the resolved render page (kept for re-runs)
|
|
108
|
-
socials/
|
|
109
|
-
og-landscape-<key>.png og-square-<key>.png og-portrait-<key>.png # per tile
|
|
110
|
-
og-portrait-<person-key>.png # a person hero: portrait only
|
|
111
|
-
socials.html # gallery: each tile at size, download links
|
|
112
|
-
social-posts.md # captions per tile, all five platforms
|
|
113
|
-
redaction-report.md # piiBearing subjects only — the standing reconciliation
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Completion criteria
|
|
117
|
-
|
|
118
|
-
- Every tile exists at its exact pixel size; a person tile is portrait only.
|
|
119
|
-
- Captions cover all five platforms; `socials.html` previews each tile with a working
|
|
120
|
-
download link.
|
|
121
|
-
- For a `piiBearing` subject, `redaction-report.md` is present and accounts for
|
|
122
|
-
**every** source photo and text field; no output names the client, the address, a
|
|
123
|
-
figure, an individual, or an email sender.
|
|
124
|
-
- In `microsite` mode, the site's `og:image`/`twitter:image` point at the landscape
|
|
125
|
-
main tile.
|
|
126
|
-
- `Read` each finished PNG — file size alone is not proof.
|
|
127
|
-
|
|
128
|
-
## When NOT to use
|
|
129
|
-
|
|
130
|
-
- The operator wants to **post** — this skill never posts; it produces a reviewable
|
|
131
|
-
bundle and stops.
|
|
132
|
-
- The deliverable is the micro-site itself → `microsite`. The full marketing run
|
|
133
|
-
(site + tiles) → `make-media`, which calls this skill in `microsite` mode.
|
|
16
|
+
SiteDesk renders tiles for four subjects: `microsite`, `bespoke`, `job`, and
|
|
17
|
+
`valuation`. The **render core is web-designer's** — this skill owns no tile
|
|
18
|
+
template, gallery, caption, or PII-gate machinery. It owns one thing: turning a
|
|
19
|
+
SiteDesk **job** or **valuation** into a brand-safe brief that `web-designer:socials`
|
|
20
|
+
can render. You **never post**; the bundle is for the operator to review.
|
|
21
|
+
|
|
22
|
+
## microsite and bespoke — delegate
|
|
23
|
+
|
|
24
|
+
Run `web-designer:socials` directly in the same mode on the same subject. For a
|
|
25
|
+
built `site/`, that is `microsite` mode (it also wires the site's `og:image`); for
|
|
26
|
+
an operator-chosen topic with the operator's own photos and notes, that is `bespoke`
|
|
27
|
+
mode (its PII gate runs unless the operator declares the material brand-safe). Add
|
|
28
|
+
nothing here — web-designer owns the whole run.
|
|
29
|
+
|
|
30
|
+
## job and valuation — resolve, then render as bespoke
|
|
31
|
+
|
|
32
|
+
These read the operator's live job state, so SiteDesk owns the read under a strict
|
|
33
|
+
money boundary; the rendering is still web-designer's.
|
|
34
|
+
|
|
35
|
+
1. **Resolve the job under the money boundary.** Read the job folder per
|
|
36
|
+
[`references/sources.md`](references/sources.md) — the `job` adapter for a
|
|
37
|
+
whole-job milestone, the `valuation` adapter for this cycle's progress. Read only
|
|
38
|
+
the allowed non-money progress fields; **never** the money fields or the issued
|
|
39
|
+
`valuations/` documents. `sources.md` is the exact contract; it is the one place
|
|
40
|
+
the money boundary is written.
|
|
41
|
+
2. **Stage a brand-safe brief.** Write the resolved subject to a staging folder as a
|
|
42
|
+
bespoke brief: a `topic`, headline and sub candidates from the strongest progress
|
|
43
|
+
lines, `copyFacts` limited to neutral context (a stage name, a trade, a month, a
|
|
44
|
+
town — never a figure or a client identifier), and the `source/` photos as
|
|
45
|
+
candidate images. No money field and no client identifier reaches the brief.
|
|
46
|
+
3. **Render through web-designer.** Run `web-designer:socials` in `bespoke` mode on
|
|
47
|
+
the staged brief. Its PII gate runs over the staged images and copy as a second
|
|
48
|
+
check and writes the redaction report; `web-designer:socials` never reads the job
|
|
49
|
+
folder or `state.json`. State the resolved subject back before rendering — e.g.
|
|
50
|
+
"Resolving job 1737 in valuation mode, this period's progress."
|
|
51
|
+
|
|
52
|
+
## The money boundary is absolute
|
|
53
|
+
|
|
54
|
+
No tile, caption, or brief SiteDesk produces from a job may carry a contract,
|
|
55
|
+
valuation, or payment figure, any `pctComplete` value, or any client identifier.
|
|
56
|
+
The progress is the story; the figures never leave the job folder. This boundary is
|
|
57
|
+
enforced at the read in step 1 (only non-money fields are ever read) and re-checked
|
|
58
|
+
by web-designer's gate at step 3.
|
|
59
|
+
|
|
60
|
+
## What this does not do
|
|
61
|
+
|
|
62
|
+
- It ships no render template, gallery, caption set, or PII-gate reference — those
|
|
63
|
+
live in `web-designer:socials`.
|
|
64
|
+
- It never posts, never deploys, and never reads a money field or a `valuations/`
|
|
65
|
+
document.
|
package/payload/premium-plugins/sitedesk/plugins/sitedesk-media/skills/socials/references/sources.md
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
# socials — source adapters
|
|
1
|
+
# socials — SiteDesk job source adapters
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
SiteDesk owns two subject adapters: `job` and `valuation`. Both read the operator's
|
|
4
|
+
live job state and resolve it to the normalized intermediate below, which
|
|
5
|
+
`web-designer:socials` renders in `bespoke` mode. The `microsite` and `bespoke`
|
|
6
|
+
adapters are web-designer's — this file does not repeat them.
|
|
7
|
+
|
|
8
|
+
This file is the one place SiteDesk's **money boundary** is written. It is the
|
|
9
|
+
contract for what a job tile may and may not carry.
|
|
7
10
|
|
|
8
11
|
## The normalized intermediate
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
Each adapter resolves its subject to the shape `web-designer:socials` bespoke mode
|
|
14
|
+
consumes:
|
|
11
15
|
|
|
12
16
|
```
|
|
13
17
|
{
|
|
@@ -16,40 +20,16 @@ Every adapter resolves its subject to this shape:
|
|
|
16
20
|
subCandidates, // [string] — supporting lines, paired to headlines
|
|
17
21
|
copyFacts, // { eyebrow, specs[], domain, phone } — overlay scalars
|
|
18
22
|
candidateImages, // [{ key, path, isPerson }] — vetted backgrounds
|
|
19
|
-
piiBearing // boolean —
|
|
23
|
+
piiBearing // boolean — job and valuation are always true
|
|
20
24
|
}
|
|
21
25
|
```
|
|
22
26
|
|
|
23
|
-
`candidateImages[].key` becomes the tile `hero` and the filename suffix
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
this reaches a template.
|
|
28
|
-
|
|
29
|
-
## Adapters
|
|
30
|
-
|
|
31
|
-
### `microsite` — `piiBearing: false`
|
|
32
|
-
|
|
33
|
-
Reads a built `site/` directory (the output of `microsite`): the brand pack
|
|
34
|
-
(`brand.md` tokens, `images/logo.png`) and the curated hero photos at the fixed
|
|
35
|
-
paths the micro-site uses:
|
|
36
|
-
|
|
37
|
-
| key | image | leads with |
|
|
38
|
-
|---|---|---|
|
|
39
|
-
| `main` | `images/hero-01.webp` | the firm's lead line |
|
|
40
|
-
| `interior` | `images/hero-03.webp` | a finishes line |
|
|
41
|
-
| `build` | `images/hero-06.webp` | a process line |
|
|
42
|
-
| `founder` | `images/founder-portrait.webp` | "meet the…" — **`isPerson: true`, portrait only** |
|
|
43
|
-
|
|
44
|
-
`copyFacts` for `microsite` is the brand pack's own credential cells (sector,
|
|
45
|
-
trades, areas, years) plus `domain`, `phone`, and the site's full `WEBSITE_URL` (the
|
|
46
|
-
microsite-only og:image wiring needs the absolute URL, not just the domain).
|
|
27
|
+
`candidateImages[].key` becomes the tile `hero` and the filename suffix.
|
|
28
|
+
`isPerson: true` marks a hero that must render portrait only. `piiBearing: true`
|
|
29
|
+
means web-designer's PII gate runs over the staged brief before any of it reaches a
|
|
30
|
+
template.
|
|
47
31
|
|
|
48
|
-
|
|
49
|
-
skipped. This is the path `make-media` calls as its final stage; it also wires the
|
|
50
|
-
site's `og:image`/`twitter:image` to the landscape `main` tile.
|
|
51
|
-
|
|
52
|
-
### `job` — `piiBearing: true`
|
|
32
|
+
## `job` — `piiBearing: true`
|
|
53
33
|
|
|
54
34
|
A whole-job progress milestone. Topic = the site/job overall. Reads the job folder
|
|
55
35
|
`{ACCOUNT_DIR}/jobs/{jobId}/`:
|
|
@@ -72,25 +52,10 @@ client should never see on a public tile. `lines[].id` and `variations[].number`
|
|
|
72
52
|
**keys only** — use them to select a line, never as copy on a tile or caption (an
|
|
73
53
|
operator may have keyed a line with a client name or address fragment).
|
|
74
54
|
|
|
75
|
-
|
|
55
|
+
## `valuation` — `piiBearing: true`
|
|
76
56
|
|
|
77
57
|
The current valuation cycle's progress. Same job folder and the **same non-money
|
|
78
58
|
fields** as `job`, but framed to **this period**: the lines and variations whose
|
|
79
59
|
`pctComplete` advanced this cycle. Topic = "this period's progress on the job". The
|
|
80
60
|
same money-field and `valuations/`-document exclusions apply — read the progress,
|
|
81
61
|
never the figures.
|
|
82
|
-
|
|
83
|
-
### `bespoke` — `piiBearing: true` (operator may waive)
|
|
84
|
-
|
|
85
|
-
An operator-chosen topic with the operator's own photos and notes. The operator
|
|
86
|
-
supplies the topic, the headline/sub ideas, and the candidate images. The PII gate
|
|
87
|
-
runs by default; the operator may declare the material brand-safe (their own
|
|
88
|
-
marketing photos, no client identifiable) to skip it — that declaration is the only
|
|
89
|
-
way the gate is waived for a bespoke subject.
|
|
90
|
-
|
|
91
|
-
## Adding a subject later
|
|
92
|
-
|
|
93
|
-
A new subject kind (quote, timesheet, testimonial, …) is a new adapter section here:
|
|
94
|
-
name what it reads, how it maps to the normalized intermediate, and its `piiBearing`
|
|
95
|
-
value. No new skill, no new render core, no new caption register. If the source can
|
|
96
|
-
carry client data, set `piiBearing: true` and the existing gate covers it.
|
package/payload/server/public/assets/{AdminLoginScreens-rlk263u9.js → AdminLoginScreens-BzErD9Zo.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./chunk-CAM3fms7.js";import{A as t,L as n,M as r,N as i,O as a}from"./useSubAccountSwitcher-BVCMAnWK.js";import{i as o}from"./admin-types-hioowVct.js";import{b as s,x as c}from"./AdminShell-C5vWTy2n.js";import{t as l}from"./Checkbox-Chz6bfy-.js";var u=`admin-landing-redirected`,d=`/graph`;function f(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var p=e(n(),1);function m(e=`admin`){let[t,n]=(0,p.useState)(`loading`),[r,a]=(0,p.useState)(``),[s,l]=(0,p.useState)(``),[m,h]=(0,p.useState)(``),[g,_]=(0,p.useState)(!1),[v,y]=(0,p.useState)(!1),[b,x]=(0,p.useState)(!1),[S,C]=(0,p.useState)(!1),[w,T]=(0,p.useState)(!1),[E,D]=(0,p.useState)(null),[O,k]=(0,p.useState)(null),[A,j]=(0,p.useState)(void 0),[M,N]=(0,p.useState)(null),[P,F]=(0,p.useState)(void 0),[I,L]=(0,p.useState)(null),[R,z]=(0,p.useState)(null),[B,V]=(0,p.useState)(void 0),H=(0,p.useRef)(void 0),[U,W]=(0,p.useState)(!1),[G,K]=(0,p.useState)(!0);(0,p.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&W(!0)}).catch(()=>{})},[]);let q=(0,p.useRef)(null),J=(0,p.useRef)(null);(0,p.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let r=await t.json();D(r.session_key),z(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=o(r.thinkingView);return H.current=i,V(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}K(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}if(!a.claude_authenticated){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,p.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[t,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();K(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){i(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,p.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function X(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){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){i(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await r.json();D(s.session_key),z(s.sessionId??null),j(s.businessName),N(s.role??null),F(s.userName===void 0?null:s.userName),L(s.avatar??null);let c=o(s.thinkingView);H.current=c,V(c);try{sessionStorage.setItem(`maxy-admin-session-key`,s.session_key)}catch{}a(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}}let Z=(0,p.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=s.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let o=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){i(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let 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 r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await X(o);return}a(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,s]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(r)},[r]),ee=(0,p.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;K(!1),D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}return n(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,p.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}a(``),h(``),n(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:t,setAppState:n,pin:r,setPin:a,operatorName:s,setOperatorName:l,pinError:m,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:R,setSessionId:z,expandAll:B,setExpandAll:V,expandAllDefaultRef:H,remoteAuthEnabled:U,claudeConnected:G,pinInputRef:q,setPinFormRef:J,handleSetPin:Z,handleLogin:Q,handleDisconnect:ee,handleLogout:$}}var h=r();function g({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,p.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,h.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,h.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function _(e){let{pin:n,setPin:r,showPin:i,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:_}=e;return(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:t,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,a.productName]}),(0,h.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,a.productName,` who you are, then choose a PIN.`]}),(0,h.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,h.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:n,onChange:r,onComplete:()=>{},showPin:i}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n||!m.trim(),loading:c,"aria-label":`Set PIN`,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(l,{checked:i,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:n,setPin:r,showPin:i,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:m}=e;return(0,h.jsxs)(`div`,{className:`connect-page`,children:[p&&m&&(0,h.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:m,children:`Sign out`}),(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:t,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`h1`,{className:`connect-title`,children:a.productName}),(0,h.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:n,onChange:r,onComplete:()=>{},showPin:i,autoFocus:!0}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n,loading:c,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(`div`,{className:`pin-options`,children:(0,h.jsx)(l,{checked:i,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:n,setAuthPolling:r,authLoading:i,setAuthLoading:o,pinError:c,setPinError:l,setAppState:u}=e,[d,f]=(0,p.useState)(!1),[m,g]=(0,p.useState)(!1),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(``);async function C(){S(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:y})})).json();e.accepted?(S(`Code submitted. Finishing sign-in…`),b(``)):S(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),S(`Could not submit code.`)}}async function w(){g(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}g(!1)}async function T(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){r(!0),f(!0),o(!1),v(e.transport||``);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),r(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function E(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),r(!1),l(``)}return n||d?(0,h.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,h.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[n?(0,h.jsx)(`button`,{onClick:E,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,h.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,h.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,h.jsx)(`p`,{className:`chat-intro`,children:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:i,children:i?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),n&&_===`native`&&(0,h.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,h.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,h.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,h.jsx)(`input`,{type:`text`,value:y,onChange:e=>b(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,h.jsx)(s,{variant:`primary`,onClick:C,disabled:!y.trim(),children:`Submit`})]}),x&&(0,h.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:x})]})]}),(0,h.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,h.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:c})]}):(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsxs)(`div`,{className:`connect-logos`,children:[(0,h.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,h.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,h.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,h.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,h.jsx)(`img`,{src:t,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`span`,{className:`connect-logo-label`,children:a.productName})]})]}),(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,a.productName]}),(0,h.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:i,children:i?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,h.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,h.jsx)(`button`,{onClick:w,disabled:m,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:m?`Launching…`:`Open browser first`}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function b({auth:e}){return e.appState===`loading`?(0,h.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,h.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,h.jsx)(y,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,h.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):null}export{m as n,b as t};
|
|
1
|
+
import{o as e}from"./chunk-CAM3fms7.js";import{A as t,L as n,M as r,N as i,O as a}from"./useSubAccountSwitcher-Bg0RH3Gk.js";import{i as o}from"./admin-types-hioowVct.js";import{b as s,x as c}from"./AdminShell-BihejKg_.js";import{t as l}from"./Checkbox-Ds004CBE.js";var u=`admin-landing-redirected`,d=`/graph`;function f(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var p=e(n(),1);function m(e=`admin`){let[t,n]=(0,p.useState)(`loading`),[r,a]=(0,p.useState)(``),[s,l]=(0,p.useState)(``),[m,h]=(0,p.useState)(``),[g,_]=(0,p.useState)(!1),[v,y]=(0,p.useState)(!1),[b,x]=(0,p.useState)(!1),[S,C]=(0,p.useState)(!1),[w,T]=(0,p.useState)(!1),[E,D]=(0,p.useState)(null),[O,k]=(0,p.useState)(null),[A,j]=(0,p.useState)(void 0),[M,N]=(0,p.useState)(null),[P,F]=(0,p.useState)(void 0),[I,L]=(0,p.useState)(null),[R,z]=(0,p.useState)(null),[B,V]=(0,p.useState)(void 0),H=(0,p.useRef)(void 0),[U,W]=(0,p.useState)(!1),[G,K]=(0,p.useState)(!0);(0,p.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&W(!0)}).catch(()=>{})},[]);let q=(0,p.useRef)(null),J=(0,p.useRef)(null);(0,p.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let r=await t.json();D(r.session_key),z(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=o(r.thinkingView);return H.current=i,V(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}K(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}if(!a.claude_authenticated){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,p.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,p.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(u)===`1`}catch{}if(f({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(u,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${d}`),window.location.replace(d)}},[t,e]);let Y=(0,p.useRef)(null);(0,p.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();K(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){i(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),Y.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,p.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(K(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function X(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){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){i(`enter-pin`,`/api/admin/session`);return}h(e.error||`Invalid PIN`);return}let s=await r.json();D(s.session_key),z(s.sessionId??null),j(s.businessName),N(s.role??null),F(s.userName===void 0?null:s.userName),L(s.avatar??null);let c=o(s.thinkingView);H.current=c,V(c);try{sessionStorage.setItem(`maxy-admin-session-key`,s.session_key)}catch{}a(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}}let Z=(0,p.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=s.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let o=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){i(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let 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 r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await X(o);return}a(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,s]),Q=(0,p.useCallback)(async e=>{e.preventDefault(),h(``),await X(r)},[r]),ee=(0,p.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;K(!1),D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}return n(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,p.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(u)}catch{}a(``),h(``),n(`enter-pin`)},[]);return(0,p.useEffect)(()=>{Y.current=$},[$]),{appState:t,setAppState:n,pin:r,setPin:a,operatorName:s,setOperatorName:l,pinError:m,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:R,setSessionId:z,expandAll:B,setExpandAll:V,expandAllDefaultRef:H,remoteAuthEnabled:U,claudeConnected:G,pinInputRef:q,setPinFormRef:J,handleSetPin:Z,handleLogin:Q,handleDisconnect:ee,handleLogout:$}}var h=r();function g({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,p.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,h.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,h.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function _(e){let{pin:n,setPin:r,showPin:i,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:_}=e;return(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:t,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,a.productName]}),(0,h.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,a.productName,` who you are, then choose a PIN.`]}),(0,h.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,h.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:n,onChange:r,onComplete:()=>{},showPin:i}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n||!m.trim(),loading:c,"aria-label":`Set PIN`,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(l,{checked:i,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function v(e){let{pin:n,setPin:r,showPin:i,setShowPin:o,pinLoading:c,pinError:u,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:m}=e;return(0,h.jsxs)(`div`,{className:`connect-page`,children:[p&&m&&(0,h.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:m,children:`Sign out`}),(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsx)(`img`,{src:t,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`h1`,{className:`connect-title`,children:a.productName}),(0,h.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,h.jsxs)(`div`,{className:`pin-input-row`,children:[(0,h.jsx)(g,{inputRef:d,value:n,onChange:r,onComplete:()=>{},showPin:i,autoFocus:!0}),(0,h.jsx)(s,{variant:`send`,type:`submit`,disabled:!n,loading:c,children:(0,h.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,h.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,h.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,h.jsx)(`div`,{className:`pin-options`,children:(0,h.jsx)(l,{checked:i,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),u&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function y(e){let{authPolling:n,setAuthPolling:r,authLoading:i,setAuthLoading:o,pinError:c,setPinError:l,setAppState:u}=e,[d,f]=(0,p.useState)(!1),[m,g]=(0,p.useState)(!1),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(``);async function C(){S(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:y})})).json();e.accepted?(S(`Code submitted. Finishing sign-in…`),b(``)):S(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),S(`Could not submit code.`)}}async function w(){g(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}g(!1)}async function T(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){r(!0),f(!0),o(!1),v(e.transport||``);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),r(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function E(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),r(!1),l(``)}return n||d?(0,h.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,h.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[n?(0,h.jsx)(`button`,{onClick:E,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,h.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,h.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,h.jsx)(`p`,{className:`chat-intro`,children:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,h.jsx)(`div`,{style:{marginTop:`12px`},children:(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:i,children:i?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),n&&_===`native`&&(0,h.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,h.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,h.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,h.jsx)(`input`,{type:`text`,value:y,onChange:e=>b(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,h.jsx)(s,{variant:`primary`,onClick:C,disabled:!y.trim(),children:`Submit`})]}),x&&(0,h.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:x})]})]}),(0,h.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,h.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:c})]}):(0,h.jsx)(`div`,{className:`connect-page`,children:(0,h.jsxs)(`div`,{className:`connect-content`,children:[(0,h.jsxs)(`div`,{className:`connect-logos`,children:[(0,h.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,h.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,h.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,h.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,h.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,h.jsx)(`img`,{src:t,alt:a.productName,className:`connect-logo connect-logo--maxy`}),!a.logoContainsName&&(0,h.jsx)(`span`,{className:`connect-logo-label`,children:a.productName})]})]}),(0,h.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,a.productName]}),(0,h.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,h.jsx)(s,{variant:`primary`,onClick:T,disabled:i,children:i?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,h.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,h.jsx)(`button`,{onClick:w,disabled:m,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:m?`Launching…`:`Open browser first`}),c&&(0,h.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function b({auth:e}){return e.appState===`loading`?(0,h.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,h.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,h.jsx)(y,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,h.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):null}export{m as n,b as t};
|