@rubytech/create-maxy 1.0.802 → 1.0.804
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/index.js +1 -13
- package/package.json +1 -1
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -2
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +7 -5
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +65 -186
- package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +2 -2
- package/payload/server/public/assets/{admin-Sa301b8q.js → admin-B41Gr-FL.js} +1 -1
- package/payload/server/public/index.html +1 -1
- package/payload/platform/plugins/cloudflare/scripts/_cdp-authorize-matcher.mjs +0 -74
- package/payload/platform/plugins/cloudflare/scripts/_cdp-authorize.mjs +0 -284
package/dist/index.js
CHANGED
|
@@ -1760,22 +1760,10 @@ function installTunnelScripts() {
|
|
|
1760
1760
|
const setupSrc = join(INSTALL_DIR, "platform/plugins/cloudflare/scripts/setup-tunnel.sh");
|
|
1761
1761
|
const resetSrc = join(INSTALL_DIR, "platform/plugins/cloudflare/scripts/reset-tunnel.sh");
|
|
1762
1762
|
const listSrc = join(INSTALL_DIR, "platform/plugins/cloudflare/scripts/list-cf-domains.sh");
|
|
1763
|
-
// _cdp-authorize.mjs is invoked by setup-tunnel.sh via `node <path>` and
|
|
1764
|
-
// resolved via readlink -f → same dir as the script. It does NOT get a
|
|
1765
|
-
// $HOME symlink — it's a helper, not a top-level operator command. We do
|
|
1766
|
-
// chmod +x defensively so `ls -l` and any ad-hoc `~/setup-tunnel.sh` copy
|
|
1767
|
-
// flow sees it as executable (Task 588).
|
|
1768
|
-
//
|
|
1769
|
-
// _cdp-authorize-matcher.mjs is imported by _cdp-authorize.mjs (Task 855)
|
|
1770
|
-
// — the tri-state matcher's MATCH_EXPR + findMatch live in this side
|
|
1771
|
-
// module so JSDOM tests run identical logic to the live page. chmod +x
|
|
1772
|
-
// is defensive symmetry; the file is read by Node, not exec'd.
|
|
1773
|
-
const cdpAuthorizeSrc = join(INSTALL_DIR, "platform/plugins/cloudflare/scripts/_cdp-authorize.mjs");
|
|
1774
|
-
const cdpMatcherSrc = join(INSTALL_DIR, "platform/plugins/cloudflare/scripts/_cdp-authorize-matcher.mjs");
|
|
1775
1763
|
const setupLink = resolve(process.env.HOME ?? "/root", "setup-tunnel.sh");
|
|
1776
1764
|
const resetLink = resolve(process.env.HOME ?? "/root", "reset-tunnel.sh");
|
|
1777
1765
|
const listLink = resolve(process.env.HOME ?? "/root", "list-cf-domains.sh");
|
|
1778
|
-
for (const src of [setupSrc, resetSrc, listSrc
|
|
1766
|
+
for (const src of [setupSrc, resetSrc, listSrc]) {
|
|
1779
1767
|
try {
|
|
1780
1768
|
chmodSync(src, 0o755);
|
|
1781
1769
|
}
|
package/package.json
CHANGED
|
@@ -30,9 +30,8 @@ The plugin registers no agent-facing MCP tools (Task 554). Every Cloudflare oper
|
|
|
30
30
|
|
|
31
31
|
| Script | Purpose |
|
|
32
32
|
|---|---|
|
|
33
|
-
| [`scripts/setup-tunnel.sh`](scripts/setup-tunnel.sh) | Autonomous end-to-end setup: OAuth login, tunnel create, DNS route, config + state, service restart, post-restart verification. Invocation: `~/setup-tunnel.sh <brand> <port> <admin-hostname> [<public-hostname>] [<apex-hostname>]`. Apex hostnames print an `ACTION REQUIRED` block for the dashboard record the CLI cannot create. Task
|
|
33
|
+
| [`scripts/setup-tunnel.sh`](scripts/setup-tunnel.sh) | Autonomous end-to-end setup: OAuth login, tunnel create, DNS route, config + state, service restart, post-restart verification. Invocation: `~/setup-tunnel.sh <brand> <port> <admin-hostname> [<public-hostname>] [<apex-hostname>]`. Apex hostnames print an `ACTION REQUIRED` block for the dashboard record the CLI cannot create. Step 1 (Task 858 — wrappers faithfully relay third-party CLI) spawns `cloudflared tunnel login`, extracts the argotunnel URL from its stdout, mechanically opens it on the Pi VNC chromium (`DISPLAY=${DISPLAY:-:99} /usr/bin/chromium <url> &`), then polls for `~/.cloudflared/cert.pem` while the operator clicks the zone row + Authorize on the VNC. 180 s budget with a 2-second `step=oauth-login result=awaiting-cert` heartbeat. No CDP auto-click, no DOM matcher. |
|
|
34
34
|
| [`scripts/reset-tunnel.sh`](scripts/reset-tunnel.sh) | Deletes every tunnel on the brand's CF account and wipes `${CFG_DIR}`. Does not touch the platform service, stray CNAMEs, or token-mode connectors — those require dashboard cleanup or `pkill`. Invocation: `~/reset-tunnel.sh <brand>`. No polling blocks — every long-wait is bounded by `cloudflared`'s network round-trip, so no heartbeat contract applies. |
|
|
35
|
-
| [`scripts/_cdp-authorize.mjs`](scripts/_cdp-authorize.mjs) | Node 22 ESM helper driving the Cloudflare argotunnel Authorize click via CDP WebSocket. Self-contained (native `fetch` + `WebSocket`), invoked by `setup-tunnel.sh` with the target id returned from the `PUT /json/new?<url>` step. Exits 0 on successful click; 1 on `authorize-button-not-found` (the happy-path loud failure when the VNC browser isn't signed into Cloudflare); 2/3/4/5 on CDP/protocol errors. Emits one `cdp-authorize result=<…> reason=<…>` line to stdout per invocation, teed into the stream log under the `[setup-tunnel:cdp-click]` tag. |
|
|
36
35
|
|
|
37
36
|
### Skills
|
|
38
37
|
|
|
@@ -131,17 +131,19 @@ ls /tmp/.X11-unix/
|
|
|
131
131
|
|
|
132
132
|
You should see `X99`. If not, start VNC before retrying Step 1.
|
|
133
133
|
|
|
134
|
-
###
|
|
134
|
+
### States the consent page can render
|
|
135
135
|
|
|
136
|
-
The dashboard at `dash.cloudflare.com/argotunnel?...`
|
|
136
|
+
The dashboard at `dash.cloudflare.com/argotunnel?...` is `cloudflared`'s native consent surface. The automation wrapper does not inspect or auto-click it; the operator drives every variation manually on the VNC.
|
|
137
137
|
|
|
138
|
-
1. **Pre-authorize — the Authorize button is visible.**
|
|
138
|
+
1. **Pre-authorize — the Authorize button is visible.** Single-zone account. Click **Authorize**. Cloudflare's callback fires and `~/.cloudflared/cert.pem` lands a second or two later. Continue with the `mv` above.
|
|
139
139
|
|
|
140
|
-
2. **
|
|
140
|
+
2. **Multi-zone picker — "Please select the zone you want to add a Tunnel to" with a list of zones.** Multi-zone account. Click the zone row you want first; the page renders the Authorize button. Click **Authorize**. Same callback path as state 1.
|
|
141
|
+
|
|
142
|
+
3. **Post-success — "Cloudflared has installed a certificate" modal.** The bound account already has a cert authorised for the zones the dashboard knows about. The OAuth callback is idempotent — navigating to a fresh `cloudflared tunnel login` URL still fires the callback, so `~/.cloudflared/cert.pem` will land. Wait a second or two, then run the `mv`.
|
|
141
143
|
|
|
142
144
|
If the cert *also* exists at `${CFG_DIR}/cert.pem` from a prior partial run, Step 1 is already complete — skip to Step 2.
|
|
143
145
|
|
|
144
|
-
|
|
146
|
+
4. **Blank or button-less — neither the Authorize button nor the success modal is on the page.** The browser may be mid-load, signed out of Cloudflare, blocking on captcha, or showing some other state. Sign in to Cloudflare in the same browser, navigate back to the URL `cloudflared tunnel login` printed, and complete the click manually. If the URL has expired, kill `cloudflared` (`Ctrl+C`) and re-run Step 1 to get a fresh URL.
|
|
145
147
|
|
|
146
148
|
---
|
|
147
149
|
|
|
@@ -14,13 +14,16 @@
|
|
|
14
14
|
# hostnames. The script writes the ingress rule for them but prints an
|
|
15
15
|
# explicit ACTION REQUIRED message naming the manual dashboard step.
|
|
16
16
|
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# URL
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
17
|
+
# Step 1 owns the browser-spawn deterministically. The wrapper extracts
|
|
18
|
+
# cloudflared's argotunnel URL from its stdout (regex below) and the moment
|
|
19
|
+
# the URL surfaces, mechanically opens it on the Pi's VNC chromium via
|
|
20
|
+
# `DISPLAY=${DISPLAY:-:99} /usr/bin/chromium <url> &` — no reliance on
|
|
21
|
+
# cloudflared's optimistic xdg-open, no CDP auto-click, no DOM matcher.
|
|
22
|
+
# The operator clicks the zone row + Authorize on the VNC themselves.
|
|
23
|
+
# This is the wrappers-faithfully-relay-third-party-cli doctrine (Task 858);
|
|
24
|
+
# any layer that auto-clicks Authorize for the operator is forbidden.
|
|
25
|
+
# cloudflared's stdout+stderr is teed line-by-line into STREAM_LOG_PATH so
|
|
26
|
+
# the chat UI's server-side tailer renders live progress in-turn.
|
|
24
27
|
|
|
25
28
|
set -euo pipefail
|
|
26
29
|
|
|
@@ -62,37 +65,43 @@ mkdir -p "${CFG_DIR}"
|
|
|
62
65
|
# --------------------------------------------------------------------------
|
|
63
66
|
# Step 1: OAuth login. Corresponds to runbook Step 1.
|
|
64
67
|
#
|
|
65
|
-
# Step 1 is a state machine over
|
|
66
|
-
# cert path
|
|
68
|
+
# Step 1 is a state machine over two observable variables — brand-scoped
|
|
69
|
+
# cert path and default cert path:
|
|
67
70
|
#
|
|
68
71
|
# ${CFG_DIR}/cert.pem present → Step 1 already done; skip.
|
|
69
72
|
# ${CFG_DIR}/cert.pem missing AND
|
|
70
73
|
# ~/.cloudflared/cert.pem present → pre-flight: a prior run
|
|
71
74
|
# reached the OAuth callback
|
|
72
75
|
# but failed before the mv;
|
|
73
|
-
# promote and skip
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
# poll for cert.pem,
|
|
76
|
+
# promote and skip cloudflared.
|
|
77
|
+
# both missing → spawn cloudflared, surface
|
|
78
|
+
# the URL on the Pi VNC,
|
|
79
|
+
# wait for the operator's
|
|
80
|
+
# click, poll for cert.pem,
|
|
81
|
+
# mv.
|
|
78
82
|
#
|
|
79
|
-
# Control flow when both certs are missing (Task
|
|
80
|
-
#
|
|
81
|
-
#
|
|
83
|
+
# Control flow when both certs are missing (Task 858 — wrappers faithfully
|
|
84
|
+
# relay third-party CLI):
|
|
85
|
+
# 1. Spawn cloudflared with stdout+stderr teed line-by-line to
|
|
82
86
|
# $STREAM_LOG_PATH with prefix [script:setup-tunnel:cloudflared]
|
|
83
87
|
# (Task 605's chat-surface namespace — see _stream-log.sh header).
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
88
|
+
# 2. Extract the authorize URL with a tolerant regex as it streams.
|
|
89
|
+
# 3. The instant the URL is extracted, mechanically open it on the Pi
|
|
90
|
+
# VNC chromium via `DISPLAY=${DISPLAY:-:99} /usr/bin/chromium <url> &`.
|
|
91
|
+
# Fire-and-forget — chromium is already running with CDP enabled at
|
|
92
|
+
# :9222, so the invocation IPCs the URL into the running instance as
|
|
93
|
+
# a new tab. The spawn is intentionally NOT tracked in the EXIT trap:
|
|
94
|
+
# it is a sibling open, not a child of cloudflared, and an orphaned
|
|
95
|
+
# late-arriving tab is harmless. Replaces cloudflared's own optimistic
|
|
96
|
+
# xdg-open which does not reliably target VNC :99 in this environment.
|
|
97
|
+
# 4. Emit `step=browser-spawn` and `step=browser-drive mode=operator-click`
|
|
98
|
+
# so the stream log records the surface state.
|
|
99
|
+
# 5. Wait for ~/.cloudflared/cert.pem to land (180 s budget — operator
|
|
100
|
+
# must click the zone row + Authorize on VNC).
|
|
101
|
+
# 6. Move cert.pem into the brand-scoped path.
|
|
93
102
|
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
103
|
+
# No CDP auto-click. No DOM matcher. No consent-page driver of any kind.
|
|
104
|
+
# Every failure branch exits 1 loudly naming the cause.
|
|
96
105
|
# --------------------------------------------------------------------------
|
|
97
106
|
|
|
98
107
|
# Pre-flight cert-promotion (Task 855). When ${CFG_DIR}/cert.pem is missing
|
|
@@ -131,20 +140,6 @@ fi
|
|
|
131
140
|
if [ ! -f "${CFG_DIR}/cert.pem" ]; then
|
|
132
141
|
phase_line setup-tunnel step=oauth-login cert_path="${CFG_DIR}/cert.pem" display="${DISPLAY:-:99}"
|
|
133
142
|
|
|
134
|
-
# CDP precheck — if Chromium DevTools is answering, we'll drive the
|
|
135
|
-
# Authorize click for the operator. If it isn't (action runner on a
|
|
136
|
-
# device without VNC — Task 664), we fall back to the ActionLogPanel
|
|
137
|
-
# URL-to-button flow: extract the URL, emit it as `OAUTH_URL: <url>`,
|
|
138
|
-
# and wait for cert.pem to land from the operator's own browser click.
|
|
139
|
-
CDP_AVAILABLE=1
|
|
140
|
-
if ! curl -sf --max-time 2 "http://127.0.0.1:9222/json/version" > /dev/null 2>&1; then
|
|
141
|
-
phase_line setup-tunnel step=oauth-login cdp=unavailable \
|
|
142
|
-
endpoint=http://127.0.0.1:9222 mode=operator-browser-fallback
|
|
143
|
-
CDP_AVAILABLE=0
|
|
144
|
-
else
|
|
145
|
-
phase_line setup-tunnel step=oauth-login cdp=ok
|
|
146
|
-
fi
|
|
147
|
-
|
|
148
143
|
URL_FILE="$(mktemp -t maxy-setup-tunnel-url.XXXXXX)"
|
|
149
144
|
LAST_LINE_FILE="$(mktemp -t maxy-setup-tunnel-last.XXXXXX)"
|
|
150
145
|
: > "${URL_FILE}"
|
|
@@ -210,154 +205,38 @@ if [ ! -f "${CFG_DIR}/cert.pem" ]; then
|
|
|
210
205
|
phase_line setup-tunnel step=browser-drive url_extracted=1
|
|
211
206
|
|
|
212
207
|
# Emit the URL on stdout in a shape ActionLogPanel's regex captures.
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
#
|
|
217
|
-
# available even when CDP succeeds — same-URL clicks are idempotent.
|
|
208
|
+
# The button is a redundant re-spawn fallback — by the time the chat-side
|
|
209
|
+
# ActionLogPanel renders, the page is already on the Pi VNC chromium per
|
|
210
|
+
# the spawn below. Button click POSTs to /api/admin/device-browser/navigate
|
|
211
|
+
# to re-target the same URL on the VNC; same end-effect as this spawn.
|
|
218
212
|
printf 'OAUTH_URL: %s\n' "${AUTH_URL}"
|
|
219
213
|
|
|
220
|
-
#
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
#
|
|
229
|
-
#
|
|
230
|
-
#
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
kill "${CF_PIPELINE_PID}" 2>/dev/null || true
|
|
239
|
-
phase_line setup-tunnel step=browser-drive result=error reason=cdp-put-failed
|
|
240
|
-
echo "ERROR: CDP PUT /json/new?<url> returned empty — Chromium rejected the navigate." >&2
|
|
241
|
-
exit 1
|
|
242
|
-
fi
|
|
243
|
-
# Extract the CDP target id so _cdp-authorize.mjs can open a debugger
|
|
244
|
-
# WebSocket against the correct tab. The PUT response is a JSON object
|
|
245
|
-
# describing the newly-created target; `.id` is the only stable field
|
|
246
|
-
# across Chromium versions that works for `/json/list` lookup.
|
|
247
|
-
CDP_TARGET_ID="$(printf '%s' "${CDP_RESP}" | jq -r '.id // empty' 2>/dev/null || true)"
|
|
248
|
-
if [ -z "${CDP_TARGET_ID}" ]; then
|
|
249
|
-
kill "${CF_PIPELINE_PID}" 2>/dev/null || true
|
|
250
|
-
phase_line setup-tunnel step=browser-drive result=error reason=cdp-target-id-missing \
|
|
251
|
-
resp_head="$(printf '%s' "${CDP_RESP}" | head -c 200)"
|
|
252
|
-
echo "ERROR: CDP PUT /json/new?<url> returned a body without an .id field — Chromium protocol drift?" >&2
|
|
253
|
-
exit 1
|
|
254
|
-
fi
|
|
255
|
-
phase_line setup-tunnel step=browser-drive result=accepted target_id="${CDP_TARGET_ID}"
|
|
256
|
-
|
|
257
|
-
# Task 588: drive the Authorize click via CDP WebSocket instead of waiting
|
|
258
|
-
# for a human. The helper shares a directory with this script; same
|
|
259
|
-
# readlink-resolve pattern as _stream-log.sh so the symlink install path
|
|
260
|
-
# (packages/create-maxy installs ~/setup-tunnel.sh as a symlink) doesn't
|
|
261
|
-
# point dirname at $HOME.
|
|
262
|
-
AUTH_HELPER="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/_cdp-authorize.mjs"
|
|
263
|
-
if [ ! -x "${AUTH_HELPER}" ]; then
|
|
264
|
-
kill "${CF_PIPELINE_PID}" 2>/dev/null || true
|
|
265
|
-
phase_line setup-tunnel step=browser-drive result=error reason=cdp-helper-missing \
|
|
266
|
-
path="${AUTH_HELPER}"
|
|
267
|
-
echo "ERROR: _cdp-authorize.mjs helper missing or not executable at ${AUTH_HELPER}" >&2
|
|
268
|
-
exit 1
|
|
269
|
-
fi
|
|
270
|
-
# tee_subprocess_capture pipes the helper's `cdp-authorize result=…` line
|
|
271
|
-
# into the stream log under the setup-tunnel:cdp-click tag (live-tailable)
|
|
272
|
-
# AND through this shell's stdout so the wrapper can capture it for the
|
|
273
|
-
# tri-state reason discriminator (Task 855). The helper writes exactly
|
|
274
|
-
# one such line per invocation and exits; the shape is its contract:
|
|
275
|
-
# `cdp-authorize result=<ok|error> reason=<token> [k=v …]`.
|
|
276
|
-
# The wrapper's awk takes the LAST `cdp-authorize result=ok ` line so that
|
|
277
|
-
# any future emit() additions cannot mis-route the discriminator — the
|
|
278
|
-
# success line is always the last one before exit.
|
|
279
|
-
HELPER_OUT="$(mktemp -t maxy-cdp-authorize-out.XXXXXX)"
|
|
280
|
-
if tee_subprocess_capture setup-tunnel:cdp-click -- \
|
|
281
|
-
node "${AUTH_HELPER}" "${CDP_TARGET_ID}" \
|
|
282
|
-
> "${HELPER_OUT}"; then
|
|
283
|
-
HELPER_REASON="$(awk '/^cdp-authorize result=ok / {m=$0} END {if (m) {match(m, /reason=[a-z0-9-]+/); print substr(m, RSTART+7, RLENGTH-7)}}' "${HELPER_OUT}")"
|
|
284
|
-
rm -f "${HELPER_OUT}"
|
|
285
|
-
case "${HELPER_REASON}" in
|
|
286
|
-
clicked)
|
|
287
|
-
phase_line setup-tunnel step=browser-drive result=ok \
|
|
288
|
-
reason=clicked target_id="${CDP_TARGET_ID}"
|
|
289
|
-
;;
|
|
290
|
-
cert-already-installed)
|
|
291
|
-
# The dashboard rendered the Success modal — the bound account
|
|
292
|
-
# already has a cert. The OAuth callback URL was exercised by this
|
|
293
|
-
# navigation, so the in-flight cloudflared subprocess receives the
|
|
294
|
-
# idempotent callback and writes ~/.cloudflared/cert.pem; the poll
|
|
295
|
-
# below picks it up.
|
|
296
|
-
phase_line setup-tunnel step=browser-drive result=ok \
|
|
297
|
-
reason=cert-already-installed target_id="${CDP_TARGET_ID}"
|
|
298
|
-
;;
|
|
299
|
-
*)
|
|
300
|
-
# Helper exited 0 but emitted a reason this wrapper does not
|
|
301
|
-
# recognise — protocol drift between helper and wrapper. Loud-fail
|
|
302
|
-
# rather than silently fall through to the cert-poll, which would
|
|
303
|
-
# mask the cause if the cert never lands.
|
|
304
|
-
kill "${CF_PIPELINE_PID}" 2>/dev/null || true
|
|
305
|
-
phase_line setup-tunnel step=browser-drive result=error \
|
|
306
|
-
reason=helper-unknown-success-reason raw="${HELPER_REASON:-empty}"
|
|
307
|
-
echo "ERROR: CDP helper exited 0 with unrecognised reason: ${HELPER_REASON:-empty}" >&2
|
|
308
|
-
echo " Expected reason=clicked or reason=cert-already-installed." >&2
|
|
309
|
-
echo " Helper / wrapper protocol drift — investigate stream log." >&2
|
|
310
|
-
exit 1
|
|
311
|
-
;;
|
|
312
|
-
esac
|
|
313
|
-
else
|
|
314
|
-
CLICK_RC=$?
|
|
315
|
-
rm -f "${HELPER_OUT}"
|
|
316
|
-
kill "${CF_PIPELINE_PID}" 2>/dev/null || true
|
|
317
|
-
# Helper exit codes (mapped 1:1 to reason= so stream-log grep is precise;
|
|
318
|
-
# a catch-all reason would defeat the observability contract):
|
|
319
|
-
# 1 = authorize-button-not-found (loud — neither button nor success
|
|
320
|
-
# modal matched before BUTTON_POLL_TIMEOUT_MS; the form surfaces
|
|
321
|
-
# a verbatim quote of references/dashboard-guide.md "Authorise a
|
|
322
|
-
# new tunnel" so the operator can recover without SSH).
|
|
323
|
-
# 2 = cdp-ws-unreachable, 3 = target-not-found, 4 = click-evaluate-threw,
|
|
324
|
-
# 5 = protocol-error. All are final — no retry, no silent fallback.
|
|
325
|
-
case "${CLICK_RC}" in
|
|
326
|
-
1) CLICK_REASON=authorize-button-not-found ;;
|
|
327
|
-
2) CLICK_REASON=cdp-ws-unreachable ;;
|
|
328
|
-
3) CLICK_REASON=target-not-found ;;
|
|
329
|
-
4) CLICK_REASON=click-evaluate-threw ;;
|
|
330
|
-
5) CLICK_REASON=protocol-error ;;
|
|
331
|
-
*) CLICK_REASON="unknown-exit-${CLICK_RC}" ;;
|
|
332
|
-
esac
|
|
333
|
-
phase_line setup-tunnel step=browser-drive result=error \
|
|
334
|
-
reason="${CLICK_REASON}" click_rc="${CLICK_RC}"
|
|
335
|
-
echo "ERROR: CDP-driven Authorize click failed (helper exit=${CLICK_RC}, reason=${CLICK_REASON})." >&2
|
|
336
|
-
if [ "${CLICK_REASON}" = "authorize-button-not-found" ]; then
|
|
337
|
-
echo " The dashboard did not present an Authorize button or a Success modal." >&2
|
|
338
|
-
echo " The form will surface the dashboard click-path for manual recovery." >&2
|
|
339
|
-
else
|
|
340
|
-
echo " The CDP helper failed before reaching a terminal page state." >&2
|
|
341
|
-
echo " Re-run setup — or run ~/reset-tunnel.sh first if state is corrupt." >&2
|
|
342
|
-
fi
|
|
343
|
-
exit 1
|
|
344
|
-
fi
|
|
345
|
-
fi # end CDP-available branch (Task 664)
|
|
214
|
+
# Mechanically open the URL on the Pi VNC chromium (Task 858). Chromium
|
|
215
|
+
# is already running on :99 with CDP enabled (vnc.sh start_chrome at boot);
|
|
216
|
+
# invoking `/usr/bin/chromium <url>` against a running instance IPCs the
|
|
217
|
+
# URL into it as a new tab. Fire-and-forget — the spawn is intentionally
|
|
218
|
+
# NOT tracked in cleanup_oauth's EXIT trap because it is a sibling open,
|
|
219
|
+
# not a child of cloudflared, and an orphaned late-arriving tab is harmless.
|
|
220
|
+
# Replaces cloudflared's own optimistic xdg-open, which does not reliably
|
|
221
|
+
# target VNC :99 in this environment.
|
|
222
|
+
#
|
|
223
|
+
# Binary path: /usr/bin/chromium is the canonical runtime binary on every
|
|
224
|
+
# supported distro (Bookworm + Noble — see vnc.sh and packages/create-maxy/
|
|
225
|
+
# src/apt-resolve.ts). The Ubuntu transitional `chromium-browser` does not
|
|
226
|
+
# exist on Bookworm Pis, so using the absolute path is the only spelling
|
|
227
|
+
# that survives both distros.
|
|
228
|
+
DISPLAY="${DISPLAY:-:99}" /usr/bin/chromium "${AUTH_URL}" >/dev/null 2>&1 &
|
|
229
|
+
phase_line setup-tunnel step=browser-spawn result=ok \
|
|
230
|
+
display="${DISPLAY:-:99}" url_extracted=1
|
|
231
|
+
phase_line setup-tunnel step=browser-drive mode=operator-click url="${AUTH_URL}"
|
|
346
232
|
|
|
347
233
|
# Wait for cert.pem to land — cloudflared writes to ~/.cloudflared/cert.pem
|
|
348
|
-
# regardless of --origincert, so watch the canonical location.
|
|
349
|
-
#
|
|
350
|
-
#
|
|
351
|
-
# 2-second heartbeat inside the loop is the observability contract
|
|
352
|
-
#
|
|
353
|
-
|
|
354
|
-
# Task 664: operator-click path (no CDP) needs a human-paced window;
|
|
355
|
-
# CDP auto-click stays on the 20s round-trip budget.
|
|
356
|
-
if [ "${CDP_AVAILABLE}" -eq 0 ]; then
|
|
357
|
-
LOGIN_TIMEOUT="${SETUP_TUNNEL_LOGIN_TIMEOUT:-180}"
|
|
358
|
-
else
|
|
359
|
-
LOGIN_TIMEOUT="${SETUP_TUNNEL_LOGIN_TIMEOUT:-20}"
|
|
360
|
-
fi
|
|
234
|
+
# regardless of --origincert, so watch the canonical location. The wait is
|
|
235
|
+
# human-paced: the operator must click the zone row + Authorize on the VNC.
|
|
236
|
+
# 180 s default budget; SETUP_TUNNEL_LOGIN_TIMEOUT overrides for testing.
|
|
237
|
+
# The 2-second heartbeat inside the loop is the observability contract —
|
|
238
|
+
# no form-spawned script is allowed a silent poll of more than ~2 s.
|
|
239
|
+
LOGIN_TIMEOUT="${SETUP_TUNNEL_LOGIN_TIMEOUT:-180}"
|
|
361
240
|
LOGIN_WAIT=0
|
|
362
241
|
while [ ! -f "${HOME}/.cloudflared/cert.pem" ]; do
|
|
363
242
|
if ! kill -0 "${CF_PIPELINE_PID}" 2>/dev/null; then
|
|
@@ -22,7 +22,7 @@ Any Cloudflare action outside these four surfaces is a discipline violation —
|
|
|
22
22
|
|
|
23
23
|
Use this when the operator wants Cloudflare set up (or re-set up) end-to-end on the device. The script handles OAuth login, tunnel creation, DNS routing for each subdomain, config.yml + tunnel.state, and dispatches the `${BRAND}.service` restart to a transient `systemd-run` unit (Task 558) — all in one invocation. The restart fires a few seconds after the script exits so the script does not kill its own cgroup when invoked via the Bash tool; the chat UI receives a `server_shutdown` SSE frame and reconnects automatically. Post-restart hostname verification is out of scope for the script (connector is not up when the script exits) — verify via the next admin turn or manually with `curl -I https://<hostname>`. Apex hostnames cannot be routed by the CLI; when one is passed, the script prints an `ACTION REQUIRED` block naming the exact dashboard record to edit.
|
|
24
24
|
|
|
25
|
-
Step 1's OAuth flow is a state machine over
|
|
25
|
+
Step 1's OAuth flow is a state machine over two observable variables: the brand-scoped cert path (`${CFG_DIR}/cert.pem`) and the OAuth-default cert path (`~/.cloudflared/cert.pem`). When the brand-scoped cert is missing but the default-path cert is present from any prior partial run, the wrapper promotes it (`mv`) and emits `step=oauth-login result=ok reason=cert-promoted-from-default-path` without re-spawning cloudflared. When both are missing, the wrapper spawns `cloudflared tunnel login`, extracts the argotunnel URL from its stdout, and the instant the URL surfaces, mechanically opens it on the Pi's VNC chromium (`DISPLAY=${DISPLAY:-:99} /usr/bin/chromium <url> &`) — emitting `step=browser-spawn result=ok` and `step=browser-drive mode=operator-click`. The operator clicks the zone row + Authorize on the VNC; cloudflared's callback writes `~/.cloudflared/cert.pem`; the wrapper's cert-poll (180 s budget) picks it up and `mv`s it to the brand-scoped path. There is no CDP auto-click, no DOM matcher, no consent-page driver — the wrapper's job is to faithfully relay `cloudflared tunnel login`, never to layer automation on top (Task 858, doctrine `feedback_wrappers_faithfully_relay_third_party_cli`).
|
|
26
26
|
|
|
27
27
|
### How inputs reach the script
|
|
28
28
|
|
|
@@ -52,7 +52,7 @@ The agent does not invoke the script directly during onboarding — the endpoint
|
|
|
52
52
|
|
|
53
53
|
The endpoint returns `{ ok: false, field: "script", message, output }` and the form surfaces the error inline. Relay the output to the user, name the exit code, and cite `references/reset-guide.md` for the next action. Offer to re-render the form after any manual steps the script's error output named. Do not attempt a second invocation outside the form, a Playwright-driven dashboard inspection, or an alternative `cloudflared` command sequence. The discipline rule below applies.
|
|
54
54
|
|
|
55
|
-
When the failure reason is `
|
|
55
|
+
When the failure reason is `timeout-waiting-cert` (Task 858 — operator did not click Authorize within the 180 s budget), the form surfaces the timeout and the operator can re-submit. The page is still on the Pi VNC; the operator can click Authorize there and the next form submit will complete via the cert-promotion pre-flight (the cert lands in `~/.cloudflared/cert.pem` after consent, and the wrapper's `mv` runs on the next invocation). Do not suggest `~/reset-tunnel.sh` — the cert path is intact and a fresh attempt is the only remediation needed.
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
@@ -340,7 +340,7 @@ Please report this to https://github.com/markedjs/marked.`,e){let e=`<p>An error
|
|
|
340
340
|
border: 1px solid rgba(0,0,0,0.1); }
|
|
341
341
|
td { padding: 6px 10px; border: 1px solid rgba(0,0,0,0.1); }
|
|
342
342
|
`;function _T({data:e,onSubmit:t,submitted:n,isStreaming:r}){let{title:a,columns:o,rows:s,filePath:c,brandName:l,brandLogo:u}=e??{},d=a??`Grid`,[f,p]=(0,B.useState)(o??[`Column 1`]),[m,h]=(0,B.useState)(()=>{let e=s??[[``]];return e.length>0?e:[[``]]}),[g,_]=(0,B.useState)(null),[v,y]=(0,B.useState)(``),b=(0,B.useRef)(null),[x,S]=(0,B.useState)(()=>(o??[`Column 1`]).map(()=>pT)),C=(0,B.useRef)(null),[T,E]=(0,B.useState)(`idle`),D=(0,B.useRef)(null),O=(0,B.useRef)(null),k=(0,B.useRef)(JSON.stringify({columns:o,rows:s}));(0,B.useEffect)(()=>{let e=JSON.stringify({columns:o,rows:s});e!==k.current&&(k.current=e,o&&p(o),s&&(h(s.length>0?s:[[``]]),S(e=>{let t=o?.length??e.length;return t>e.length?[...e,...Array(t-e.length).fill(pT)]:e.slice(0,t)})))},[o,s]);let A=(0,B.useCallback)(()=>{D.current&&clearTimeout(D.current),D.current=setTimeout(()=>{E(`saving`),t(JSON.stringify({action:`save`,columns:f,rows:m,...c?{filePath:c}:{}})),O.current&&clearTimeout(O.current),E(`saved`),O.current=setTimeout(()=>E(`idle`),2e3)},500)},[f,m,c,t]);(0,B.useEffect)(()=>()=>{D.current&&clearTimeout(D.current),O.current&&clearTimeout(O.current)},[]);let j=Uw({title:d,isStreaming:r,channelName:`maxy-grid-editor`,renderPopout:(0,B.useCallback)((e,t)=>{let n=e.document;n.open(),n.close(),n.title=t;let r=n.createElement(`style`);r.textContent=gT,n.head.appendChild(r);let i=n.createElement(`div`);i.className=`title`,i.textContent=t,n.body.appendChild(i);let a=n.createElement(`table`),o=n.createElement(`thead`),s=n.createElement(`tr`);for(let e of f){let t=n.createElement(`th`);t.textContent=e,s.appendChild(t)}o.appendChild(s),a.appendChild(o);let c=n.createElement(`tbody`);for(let e of m){let t=n.createElement(`tr`);for(let r of e){let e=n.createElement(`td`);e.textContent=r,t.appendChild(e)}c.appendChild(t)}a.appendChild(c),n.body.appendChild(a)},[f,m])}),M=Ww({onSubmit:t}),N=(0,B.useCallback)((e,t)=>{_({row:e,col:t}),y(m[e]?.[t]??``),setTimeout(()=>b.current?.focus(),0)},[m]),P=(0,B.useCallback)(()=>{if(!g)return;let{row:e,col:t}=g;h(n=>{let r=n.map(e=>[...e]);return r[e]&&(r[e][t]=v),r}),_(null),A()},[g,v,A]),ee=(0,B.useCallback)(()=>{_(null)},[]),te=(0,B.useCallback)(e=>{if(g)if(e.key===`Tab`){e.preventDefault(),P();let{row:t,col:n}=g,r=n+1;if(r<f.length)N(t,r);else{let e=t+1;e>=m.length&&h(e=>[...e,Array(f.length).fill(``)]),N(Math.min(e,m.length),0)}}else if(e.key===`Enter`){e.preventDefault(),P();let{row:t,col:n}=g,r=t+1;r>=m.length&&h(e=>[...e,Array(f.length).fill(``)]),N(Math.min(r,m.length),n)}else e.key===`Escape`&&ee()},[g,f.length,m.length,P,N,ee]),ne=(0,B.useCallback)(()=>{h(e=>[...e,Array(f.length).fill(``)]),A()},[f.length,A]),F=(0,B.useCallback)(e=>{h(t=>t.length<=1?[Array(f.length).fill(``)]:t.filter((t,n)=>n!==e)),g?.row===e&&_(null),A()},[f.length,g,A]),I=(0,B.useCallback)(e=>{let t=e.clipboardData.getData(`text/plain`);if(!t||!g)return;let n=t.split(`
|
|
343
|
-
`).filter(e=>e.trim());if(n.length<=1&&!n[0]?.includes(` `)&&!n[0]?.includes(`,`))return;e.preventDefault();let r=n.slice(0,dT).map(mT);n.length>dT&&console.warn(`Grid editor: paste truncated from ${n.length} to ${dT} rows`);let{row:i,col:a}=g;h(e=>{let t=e.map(e=>[...e]);for(let e=0;e<r.length;e++){let n=i+e;for(;n>=t.length;)t.push(Array(f.length).fill(``));for(let i=0;i<r[e].length;i++){let o=a+i;o<f.length&&(t[n][o]=r[e][i])}}return t}),A()},[g,f.length,A]),re=(0,B.useCallback)(()=>{let e=hT(f,m),t=new Blob([e],{type:`text/csv;charset=utf-8;`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`${d.replace(/[^a-zA-Z0-9]/g,`_`)}.csv`,r.click(),URL.revokeObjectURL(n)},[f,m,d]),ie=(0,B.useCallback)(()=>{$w({title:d,content:eT(f,m),brandName:l,brandLogo:u})},[d,f,m,l,u]),ae=(0,B.useCallback)((e,t)=>{t.preventDefault(),C.current={colIndex:e,startX:t.clientX,startWidth:x[e]};let n=null,r=e=>{C.current&&(n&&cancelAnimationFrame(n),n=requestAnimationFrame(()=>{if(!C.current)return;let t=e.clientX-C.current.startX,n=Math.max(fT,C.current.startWidth+t);S(e=>{let t=[...e];return t[C.current.colIndex]=n,t})}))},i=()=>{C.current=null,n&&cancelAnimationFrame(n),window.removeEventListener(`mousemove`,r),window.removeEventListener(`mouseup`,i)};window.addEventListener(`mousemove`,r),window.addEventListener(`mouseup`,i)},[x]),se=(0,B.useCallback)(()=>{g&&M.openCommentInput()},[g,M]),ce=(0,B.useCallback)(()=>{if(!g)return;let e=m[g.row]?.[g.col]??``;M.submitComment(e,{row:g.row,column:g.col})},[g,m,M]);if(n)return(0,V.jsxs)(`div`,{className:`editor-base grid-editor grid-editor--submitted`,children:[(0,V.jsxs)(`div`,{className:`editor-base__bar`,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),(0,V.jsx)(`div`,{className:`editor-base__actions`,children:(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Submitted`})})]}),(0,V.jsx)(`div`,{className:`grid-editor__body`,children:(0,V.jsx)(`div`,{className:`grid-editor__table-wrap`,children:(0,V.jsxs)(`table`,{className:`grid-editor__table`,role:`grid`,"aria-label":d,children:[(0,V.jsx)(`thead`,{children:(0,V.jsx)(`tr`,{children:f.map((e,t)=>(0,V.jsx)(`th`,{className:`grid-editor__col-header`,style:{width:x[t]},children:e},t))})}),(0,V.jsx)(`tbody`,{children:m.map((e,t)=>(0,V.jsx)(`tr`,{children:e.map((e,t)=>(0,V.jsx)(`td`,{className:`grid-editor__cell`,role:`gridcell`,style:{width:x[t]},children:(0,V.jsx)(`span`,{className:`grid-editor__cell-text`,children:e})},t))},t))})]})})})]});let le=typeof window<`u`&&window.innerWidth<640,ue=typeof BroadcastChannel<`u`,de=(0,V.jsxs)(`div`,{className:`editor-base__actions`,children:[T===`saving`&&(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Saving...`}),T===`saved`&&(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Saved`}),M.pendingComments.length>0&&(0,V.jsxs)(w,{variant:`ghost`,size:`sm`,onClick:M.sendComments,children:[`Send `,M.pendingComments.length,` comment`,M.pendingComments.length>1?`s`:``]}),g&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:$e,onClick:se,"aria-label":`Comment on cell`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:L,onClick:re,"aria-label":`Download CSV`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Le,onClick:ie,"aria-label":`Export PDF`}),!le&&ue&&!j.poppedOut&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Fe,onClick:j.handlePopout,"aria-label":`Pop out`}),!j.fullscreen&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Qe,onClick:j.handleFullscreen,"aria-label":`Full screen`}),j.fullscreen&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:nt,onClick:j.exitFullscreen,"aria-label":`Exit full screen`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:rt,onClick:j.handleMinimise,"aria-label":`Minimise`})]}),fe=(0,V.jsxs)(`div`,{className:`grid-editor__table-wrap`,onPaste:I,children:[M.showCommentInput?(0,V.jsxs)(`div`,{className:`grid-editor__comment-popover`,children:[(0,V.jsx)(`input`,{ref:M.commentInputRef,type:`text`,value:M.commentText,onChange:e=>M.setCommentText(e.target.value),onKeyDown:e=>{e.key===`Enter`&&ce(),e.key===`Escape`&&M.cancelComment()},placeholder:`Add a comment...`,className:`doc-editor__comment-input`,"aria-label":`Add comment on cell`}),(0,V.jsxs)(`div`,{className:`doc-editor__comment-actions`,children:[(0,V.jsx)(w,{variant:`primary`,size:`sm`,onClick:ce,disabled:!M.commentText.trim(),children:`Add`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:oe,onClick:M.cancelComment,"aria-label":`Cancel`})]})]}):null,(0,V.jsxs)(`table`,{className:`grid-editor__table`,role:`grid`,"aria-label":d,children:[(0,V.jsx)(`thead`,{children:(0,V.jsxs)(`tr`,{children:[(0,V.jsx)(`th`,{className:`grid-editor__row-header`}),f.map((e,t)=>(0,V.jsxs)(`th`,{className:`grid-editor__col-header`,style:{width:x[t]},children:[e,(0,V.jsx)(`div`,{className:`grid-editor__resize-handle`,onMouseDown:e=>ae(t,e),role:`separator`,"aria-orientation":`vertical`})]},t))]})}),(0,V.jsx)(`tbody`,{children:m.map((e,t)=>(0,V.jsxs)(`tr`,{children:[(0,V.jsxs)(`td`,{className:`grid-editor__row-header`,children:[(0,V.jsx)(`span`,{className:`grid-editor__row-num`,children:t+1}),m.length>1&&(0,V.jsx)(`button`,{className:`grid-editor__row-delete`,onClick:()=>F(t),"aria-label":`Delete row ${t+1}`,children:(0,V.jsx)(i,{size:12})})]}),e.map((e,n)=>{let r=g?.row===t&&g?.col===n;return(0,V.jsx)(`td`,{className:`grid-editor__cell ${r?`grid-editor__cell--active`:``}`,onClick:()=>!r&&N(t,n),role:`gridcell`,"aria-selected":r,style:{width:x[n]},children:r?(0,V.jsx)(`input`,{ref:b,type:`text`,className:`grid-editor__cell-input`,value:v,onChange:e=>y(e.target.value),onKeyDown:te,onBlur:P,"aria-label":`${f[n]} row ${t+1}`}):(0,V.jsx)(`span`,{className:`grid-editor__cell-text`,children:e})},n)})]},t))})]}),(0,V.jsxs)(`button`,{className:`grid-editor__add-row`,onClick:ne,"aria-label":`Add row`,children:[(0,V.jsx)(Oe,{size:14}),(0,V.jsx)(`span`,{children:`Add row`})]})]});return j.fullscreen?(0,V.jsxs)(`div`,{className:`editor-base-fullscreen`,children:[(0,V.jsxs)(`div`,{className:`editor-base-fullscreen__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base-fullscreen__title`,children:d}),de]}),(0,V.jsx)(`div`,{className:`editor-base-fullscreen__body`,style:{maxWidth:`none`},children:fe})]}):j.poppedOut?(0,V.jsx)(`div`,{className:`editor-base editor-base--popout`,children:(0,V.jsxs)(`div`,{className:`editor-base__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),(0,V.jsxs)(`div`,{className:`editor-base__actions`,children:[(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Popped out`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:dt,onClick:j.handlePopIn,"aria-label":`Pop back in`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:rt,onClick:j.handleMinimise,"aria-label":`Close`})]})]})}):j.minimised?(0,V.jsx)(`div`,{className:`editor-base editor-base--minimised`,onClick:j.handleExpand,role:`button`,tabIndex:0,onKeyDown:e=>e.key===`Enter`&&j.handleExpand(),children:(0,V.jsxs)(`div`,{className:`editor-base__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),(0,V.jsxs)(`div`,{className:`editor-base__actions`,onClick:e=>e.stopPropagation(),children:[!le&&ue&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Fe,onClick:j.handlePopout,"aria-label":`Pop out`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Qe,onClick:j.handleFullscreen,"aria-label":`Full screen`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:ct,onClick:j.handleExpand,"aria-label":`Expand`})]})]})}):(0,V.jsxs)(`div`,{className:`editor-base grid-editor`,children:[(0,V.jsxs)(`div`,{className:`editor-base__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),de]}),(0,V.jsx)(`div`,{className:`grid-editor__body`,children:fe})]})}var vT=Object.defineProperty,yT=Object.getOwnPropertySymbols,bT=Object.prototype.hasOwnProperty,xT=Object.prototype.propertyIsEnumerable,ST=(e,t,n)=>t in e?vT(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,CT=(e,t)=>{for(var n in t||={})bT.call(t,n)&&ST(e,n,t[n]);if(yT)for(var n of yT(t))xT.call(t,n)&&ST(e,n,t[n]);return e},wT=(e,t)=>{var n={};for(var r in e)bT.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&yT)for(var r of yT(e))t.indexOf(r)<0&&xT.call(e,r)&&(n[r]=e[r]);return n},TT;(e=>{let t=class t{constructor(e,n,r,a){if(this.version=e,this.errorCorrectionLevel=n,this.modules=[],this.isFunction=[],e<t.MIN_VERSION||e>t.MAX_VERSION)throw RangeError(`Version value out of range`);if(a<-1||a>7)throw RangeError(`Mask value out of range`);this.size=e*4+17;let o=[];for(let e=0;e<this.size;e++)o.push(!1);for(let e=0;e<this.size;e++)this.modules.push(o.slice()),this.isFunction.push(o.slice());this.drawFunctionPatterns();let s=this.addEccAndInterleave(r);if(this.drawCodewords(s),a==-1){let e=1e9;for(let t=0;t<8;t++){this.applyMask(t),this.drawFormatBits(t);let n=this.getPenaltyScore();n<e&&(a=t,e=n),this.applyMask(t)}}i(0<=a&&a<=7),this.mask=a,this.applyMask(a),this.drawFormatBits(a),this.isFunction=[]}static encodeText(n,r){let i=e.QrSegment.makeSegments(n);return t.encodeSegments(i,r)}static encodeBinary(n,r){let i=e.QrSegment.makeBytes(n);return t.encodeSegments([i],r)}static encodeSegments(e,r,a=1,s=40,c=-1,l=!0){if(!(t.MIN_VERSION<=a&&a<=s&&s<=t.MAX_VERSION)||c<-1||c>7)throw RangeError(`Invalid value`);let u,d;for(u=a;;u++){let n=t.getNumDataCodewords(u,r)*8,i=o.getTotalBits(e,u);if(i<=n){d=i;break}if(u>=s)throw RangeError(`Data too long`)}for(let e of[t.Ecc.MEDIUM,t.Ecc.QUARTILE,t.Ecc.HIGH])l&&d<=t.getNumDataCodewords(u,e)*8&&(r=e);let f=[];for(let t of e){n(t.mode.modeBits,4,f),n(t.numChars,t.mode.numCharCountBits(u),f);for(let e of t.getData())f.push(e)}i(f.length==d);let p=t.getNumDataCodewords(u,r)*8;i(f.length<=p),n(0,Math.min(4,p-f.length),f),n(0,(8-f.length%8)%8,f),i(f.length%8==0);for(let e=236;f.length<p;e^=253)n(e,8,f);let m=[];for(;m.length*8<f.length;)m.push(0);return f.forEach((e,t)=>m[t>>>3]|=e<<7-(t&7)),new t(u,r,m,c)}getModule(e,t){return 0<=e&&e<this.size&&0<=t&&t<this.size&&this.modules[t][e]}getModules(){return this.modules}drawFunctionPatterns(){for(let e=0;e<this.size;e++)this.setFunctionModule(6,e,e%2==0),this.setFunctionModule(e,6,e%2==0);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);let e=this.getAlignmentPatternPositions(),t=e.length;for(let n=0;n<t;n++)for(let r=0;r<t;r++)n==0&&r==0||n==0&&r==t-1||n==t-1&&r==0||this.drawAlignmentPattern(e[n],e[r]);this.drawFormatBits(0),this.drawVersion()}drawFormatBits(e){let t=this.errorCorrectionLevel.formatBits<<3|e,n=t;for(let e=0;e<10;e++)n=n<<1^(n>>>9)*1335;let a=(t<<10|n)^21522;i(a>>>15==0);for(let e=0;e<=5;e++)this.setFunctionModule(8,e,r(a,e));this.setFunctionModule(8,7,r(a,6)),this.setFunctionModule(8,8,r(a,7)),this.setFunctionModule(7,8,r(a,8));for(let e=9;e<15;e++)this.setFunctionModule(14-e,8,r(a,e));for(let e=0;e<8;e++)this.setFunctionModule(this.size-1-e,8,r(a,e));for(let e=8;e<15;e++)this.setFunctionModule(8,this.size-15+e,r(a,e));this.setFunctionModule(8,this.size-8,!0)}drawVersion(){if(this.version<7)return;let e=this.version;for(let t=0;t<12;t++)e=e<<1^(e>>>11)*7973;let t=this.version<<12|e;i(t>>>18==0);for(let e=0;e<18;e++){let n=r(t,e),i=this.size-11+e%3,a=Math.floor(e/3);this.setFunctionModule(i,a,n),this.setFunctionModule(a,i,n)}}drawFinderPattern(e,t){for(let n=-4;n<=4;n++)for(let r=-4;r<=4;r++){let i=Math.max(Math.abs(r),Math.abs(n)),a=e+r,o=t+n;0<=a&&a<this.size&&0<=o&&o<this.size&&this.setFunctionModule(a,o,i!=2&&i!=4)}}drawAlignmentPattern(e,t){for(let n=-2;n<=2;n++)for(let r=-2;r<=2;r++)this.setFunctionModule(e+r,t+n,Math.max(Math.abs(r),Math.abs(n))!=1)}setFunctionModule(e,t,n){this.modules[t][e]=n,this.isFunction[t][e]=!0}addEccAndInterleave(e){let n=this.version,r=this.errorCorrectionLevel;if(e.length!=t.getNumDataCodewords(n,r))throw RangeError(`Invalid argument`);let a=t.NUM_ERROR_CORRECTION_BLOCKS[r.ordinal][n],o=t.ECC_CODEWORDS_PER_BLOCK[r.ordinal][n],s=Math.floor(t.getNumRawDataModules(n)/8),c=a-s%a,l=Math.floor(s/a),u=[],d=t.reedSolomonComputeDivisor(o);for(let n=0,r=0;n<a;n++){let i=e.slice(r,r+l-o+(n<c?0:1));r+=i.length;let a=t.reedSolomonComputeRemainder(i,d);n<c&&i.push(0),u.push(i.concat(a))}let f=[];for(let e=0;e<u[0].length;e++)u.forEach((t,n)=>{(e!=l-o||n>=c)&&f.push(t[e])});return i(f.length==s),f}drawCodewords(e){if(e.length!=Math.floor(t.getNumRawDataModules(this.version)/8))throw RangeError(`Invalid argument`);let n=0;for(let t=this.size-1;t>=1;t-=2){t==6&&(t=5);for(let i=0;i<this.size;i++)for(let a=0;a<2;a++){let o=t-a,s=t+1&2?i:this.size-1-i;!this.isFunction[s][o]&&n<e.length*8&&(this.modules[s][o]=r(e[n>>>3],7-(n&7)),n++)}}i(n==e.length*8)}applyMask(e){if(e<0||e>7)throw RangeError(`Mask value out of range`);for(let t=0;t<this.size;t++)for(let n=0;n<this.size;n++){let r;switch(e){case 0:r=(n+t)%2==0;break;case 1:r=t%2==0;break;case 2:r=n%3==0;break;case 3:r=(n+t)%3==0;break;case 4:r=(Math.floor(n/3)+Math.floor(t/2))%2==0;break;case 5:r=n*t%2+n*t%3==0;break;case 6:r=(n*t%2+n*t%3)%2==0;break;case 7:r=((n+t)%2+n*t%3)%2==0;break;default:throw Error(`Unreachable`)}!this.isFunction[t][n]&&r&&(this.modules[t][n]=!this.modules[t][n])}}getPenaltyScore(){let e=0;for(let n=0;n<this.size;n++){let r=!1,i=0,a=[0,0,0,0,0,0,0];for(let o=0;o<this.size;o++)this.modules[n][o]==r?(i++,i==5?e+=t.PENALTY_N1:i>5&&e++):(this.finderPenaltyAddHistory(i,a),r||(e+=this.finderPenaltyCountPatterns(a)*t.PENALTY_N3),r=this.modules[n][o],i=1);e+=this.finderPenaltyTerminateAndCount(r,i,a)*t.PENALTY_N3}for(let n=0;n<this.size;n++){let r=!1,i=0,a=[0,0,0,0,0,0,0];for(let o=0;o<this.size;o++)this.modules[o][n]==r?(i++,i==5?e+=t.PENALTY_N1:i>5&&e++):(this.finderPenaltyAddHistory(i,a),r||(e+=this.finderPenaltyCountPatterns(a)*t.PENALTY_N3),r=this.modules[o][n],i=1);e+=this.finderPenaltyTerminateAndCount(r,i,a)*t.PENALTY_N3}for(let n=0;n<this.size-1;n++)for(let r=0;r<this.size-1;r++){let i=this.modules[n][r];i==this.modules[n][r+1]&&i==this.modules[n+1][r]&&i==this.modules[n+1][r+1]&&(e+=t.PENALTY_N2)}let n=0;for(let e of this.modules)n=e.reduce((e,t)=>e+(t?1:0),n);let r=this.size*this.size,a=Math.ceil(Math.abs(n*20-r*10)/r)-1;return i(0<=a&&a<=9),e+=a*t.PENALTY_N4,i(0<=e&&e<=2568888),e}getAlignmentPatternPositions(){if(this.version==1)return[];{let e=Math.floor(this.version/7)+2,t=this.version==32?26:Math.ceil((this.version*4+4)/(e*2-2))*2,n=[6];for(let r=this.size-7;n.length<e;r-=t)n.splice(1,0,r);return n}}static getNumRawDataModules(e){if(e<t.MIN_VERSION||e>t.MAX_VERSION)throw RangeError(`Version number out of range`);let n=(16*e+128)*e+64;if(e>=2){let t=Math.floor(e/7)+2;n-=(25*t-10)*t-55,e>=7&&(n-=36)}return i(208<=n&&n<=29648),n}static getNumDataCodewords(e,n){return Math.floor(t.getNumRawDataModules(e)/8)-t.ECC_CODEWORDS_PER_BLOCK[n.ordinal][e]*t.NUM_ERROR_CORRECTION_BLOCKS[n.ordinal][e]}static reedSolomonComputeDivisor(e){if(e<1||e>255)throw RangeError(`Degree out of range`);let n=[];for(let t=0;t<e-1;t++)n.push(0);n.push(1);let r=1;for(let i=0;i<e;i++){for(let e=0;e<n.length;e++)n[e]=t.reedSolomonMultiply(n[e],r),e+1<n.length&&(n[e]^=n[e+1]);r=t.reedSolomonMultiply(r,2)}return n}static reedSolomonComputeRemainder(e,n){let r=n.map(e=>0);for(let i of e){let e=i^r.shift();r.push(0),n.forEach((n,i)=>r[i]^=t.reedSolomonMultiply(n,e))}return r}static reedSolomonMultiply(e,t){if(e>>>8||t>>>8)throw RangeError(`Byte out of range`);let n=0;for(let r=7;r>=0;r--)n=n<<1^(n>>>7)*285,n^=(t>>>r&1)*e;return i(n>>>8==0),n}finderPenaltyCountPatterns(e){let t=e[1];i(t<=this.size*3);let n=t>0&&e[2]==t&&e[3]==t*3&&e[4]==t&&e[5]==t;return(n&&e[0]>=t*4&&e[6]>=t?1:0)+(n&&e[6]>=t*4&&e[0]>=t?1:0)}finderPenaltyTerminateAndCount(e,t,n){return e&&(this.finderPenaltyAddHistory(t,n),t=0),t+=this.size,this.finderPenaltyAddHistory(t,n),this.finderPenaltyCountPatterns(n)}finderPenaltyAddHistory(e,t){t[0]==0&&(e+=this.size),t.pop(),t.unshift(e)}};t.MIN_VERSION=1,t.MAX_VERSION=40,t.PENALTY_N1=3,t.PENALTY_N2=3,t.PENALTY_N3=40,t.PENALTY_N4=10,t.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],t.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],e.QrCode=t;function n(e,t,n){if(t<0||t>31||e>>>t)throw RangeError(`Value out of range`);for(let r=t-1;r>=0;r--)n.push(e>>>r&1)}function r(e,t){return(e>>>t&1)!=0}function i(e){if(!e)throw Error(`Assertion error`)}let a=class e{constructor(e,t,n){if(this.mode=e,this.numChars=t,this.bitData=n,t<0)throw RangeError(`Invalid argument`);this.bitData=n.slice()}static makeBytes(t){let r=[];for(let e of t)n(e,8,r);return new e(e.Mode.BYTE,t.length,r)}static makeNumeric(t){if(!e.isNumeric(t))throw RangeError(`String contains non-numeric characters`);let r=[];for(let e=0;e<t.length;){let i=Math.min(t.length-e,3);n(parseInt(t.substring(e,e+i),10),i*3+1,r),e+=i}return new e(e.Mode.NUMERIC,t.length,r)}static makeAlphanumeric(t){if(!e.isAlphanumeric(t))throw RangeError(`String contains unencodable characters in alphanumeric mode`);let r=[],i;for(i=0;i+2<=t.length;i+=2){let a=e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(i))*45;a+=e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(i+1)),n(a,11,r)}return i<t.length&&n(e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(i)),6,r),new e(e.Mode.ALPHANUMERIC,t.length,r)}static makeSegments(t){return t==``?[]:e.isNumeric(t)?[e.makeNumeric(t)]:e.isAlphanumeric(t)?[e.makeAlphanumeric(t)]:[e.makeBytes(e.toUtf8ByteArray(t))]}static makeEci(t){let r=[];if(t<0)throw RangeError(`ECI assignment value out of range`);if(t<128)n(t,8,r);else if(t<16384)n(2,2,r),n(t,14,r);else if(t<1e6)n(6,3,r),n(t,21,r);else throw RangeError(`ECI assignment value out of range`);return new e(e.Mode.ECI,0,r)}static isNumeric(t){return e.NUMERIC_REGEX.test(t)}static isAlphanumeric(t){return e.ALPHANUMERIC_REGEX.test(t)}getData(){return this.bitData.slice()}static getTotalBits(e,t){let n=0;for(let r of e){let e=r.mode.numCharCountBits(t);if(r.numChars>=1<<e)return 1/0;n+=4+e+r.bitData.length}return n}static toUtf8ByteArray(e){e=encodeURI(e);let t=[];for(let n=0;n<e.length;n++)e.charAt(n)==`%`?(t.push(parseInt(e.substring(n+1,n+3),16)),n+=2):t.push(e.charCodeAt(n));return t}};a.NUMERIC_REGEX=/^[0-9]*$/,a.ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,a.ALPHANUMERIC_CHARSET=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:`;let o=a;e.QrSegment=a})(TT||={}),(e=>{(e=>{let t=class{constructor(e,t){this.ordinal=e,this.formatBits=t}};t.LOW=new t(0,1),t.MEDIUM=new t(1,0),t.QUARTILE=new t(2,3),t.HIGH=new t(3,2),e.Ecc=t})(e.QrCode||={})})(TT||={}),(e=>{(e=>{let t=class{constructor(e,t){this.modeBits=e,this.numBitsCharCount=t}numCharCountBits(e){return this.numBitsCharCount[Math.floor((e+7)/17)]}};t.NUMERIC=new t(1,[10,12,14]),t.ALPHANUMERIC=new t(2,[9,11,13]),t.BYTE=new t(4,[8,16,16]),t.KANJI=new t(8,[8,10,12]),t.ECI=new t(7,[0,0,0]),e.Mode=t})(e.QrSegment||={})})(TT||={});var ET=TT,DT={L:ET.QrCode.Ecc.LOW,M:ET.QrCode.Ecc.MEDIUM,Q:ET.QrCode.Ecc.QUARTILE,H:ET.QrCode.Ecc.HIGH},OT=128,kT=`L`,AT=`#FFFFFF`,jT=`#000000`,MT=!1,NT=1,PT=4,FT=0,IT=.1;function LT(e,t=0){let n=[];return e.forEach(function(e,r){let i=null;e.forEach(function(a,o){if(!a&&i!==null){n.push(`M${i+t} ${r+t}h${o-i}v1H${i+t}z`),i=null;return}if(o===e.length-1){if(!a)return;i===null?n.push(`M${o+t},${r+t} h1v1H${o+t}z`):n.push(`M${i+t},${r+t} h${o+1-i}v1H${i+t}z`);return}a&&i===null&&(i=o)})}),n.join(``)}function RT(e,t){return e.slice().map((e,n)=>n<t.y||n>=t.y+t.h?e:e.map((e,n)=>n<t.x||n>=t.x+t.w?e:!1))}function zT(e,t,n,r){if(r==null)return null;let i=e.length+n*2,a=Math.floor(t*IT),o=i/t,s=(r.width||a)*o,c=(r.height||a)*o,l=r.x==null?e.length/2-s/2:r.x*o,u=r.y==null?e.length/2-c/2:r.y*o,d=r.opacity==null?1:r.opacity,f=null;if(r.excavate){let e=Math.floor(l),t=Math.floor(u);f={x:e,y:t,w:Math.ceil(s+l-e),h:Math.ceil(c+u-t)}}let p=r.crossOrigin;return{x:l,y:u,h:c,w:s,excavation:f,opacity:d,crossOrigin:p}}function BT(e,t){return t==null?e?PT:FT:Math.max(Math.floor(t),0)}function VT({value:e,level:t,minVersion:n,includeMargin:r,marginSize:i,imageSettings:a,size:o,boostLevel:s}){let c=B.useMemo(()=>{let r=(Array.isArray(e)?e:[e]).reduce((e,t)=>(e.push(...ET.QrSegment.makeSegments(t)),e),[]);return ET.QrCode.encodeSegments(r,DT[t],n,void 0,void 0,s)},[e,t,n,s]),{cells:l,margin:u,numCells:d,calculatedImageSettings:f}=B.useMemo(()=>{let e=c.getModules(),t=BT(r,i);return{cells:e,margin:t,numCells:e.length+t*2,calculatedImageSettings:zT(e,o,t,a)}},[c,o,a,r,i]);return{qrcode:c,margin:u,cells:l,numCells:d,calculatedImageSettings:f}}var HT=function(){try{new Path2D().addPath(new Path2D)}catch{return!1}return!0}(),UT=B.forwardRef(function(e,t){let n=e,{value:r,size:i=OT,level:a=kT,bgColor:o=AT,fgColor:s=jT,includeMargin:c=MT,minVersion:l=NT,boostLevel:u,marginSize:d,imageSettings:f}=n,p=wT(n,[`value`,`size`,`level`,`bgColor`,`fgColor`,`includeMargin`,`minVersion`,`boostLevel`,`marginSize`,`imageSettings`]),{style:m}=p,h=wT(p,[`style`]),g=f?.src,_=B.useRef(null),v=B.useRef(null),y=B.useCallback(e=>{_.current=e,typeof t==`function`?t(e):t&&(t.current=e)},[t]),[b,x]=B.useState(!1),{margin:S,cells:C,numCells:w,calculatedImageSettings:T}=VT({value:r,level:a,minVersion:l,boostLevel:u,includeMargin:c,marginSize:d,imageSettings:f,size:i});B.useEffect(()=>{if(_.current!=null){let e=_.current,t=e.getContext(`2d`);if(!t)return;let n=C,r=v.current,a=T!=null&&r!==null&&r.complete&&r.naturalHeight!==0&&r.naturalWidth!==0;a&&T.excavation!=null&&(n=RT(C,T.excavation));let c=window.devicePixelRatio||1;e.height=e.width=i*c;let l=i/w*c;t.scale(l,l),t.fillStyle=o,t.fillRect(0,0,w,w),t.fillStyle=s,HT?t.fill(new Path2D(LT(n,S))):C.forEach(function(e,n){e.forEach(function(e,r){e&&t.fillRect(r+S,n+S,1,1)})}),T&&(t.globalAlpha=T.opacity),a&&t.drawImage(r,T.x+S,T.y+S,T.w,T.h)}}),B.useEffect(()=>{x(!1)},[g]);let E=CT({height:i,width:i},m),D=null;return g!=null&&(D=B.createElement(`img`,{src:g,key:g,style:{display:`none`},onLoad:()=>{x(!0)},ref:v,crossOrigin:T?.crossOrigin})),B.createElement(B.Fragment,null,B.createElement(`canvas`,CT({style:E,height:i,width:i,ref:y,role:`img`},h)),D)});UT.displayName=`QRCodeCanvas`;var WT=B.forwardRef(function(e,t){let n=e,{value:r,size:i=OT,level:a=kT,bgColor:o=AT,fgColor:s=jT,includeMargin:c=MT,minVersion:l=NT,boostLevel:u,title:d,marginSize:f,imageSettings:p}=n,m=wT(n,[`value`,`size`,`level`,`bgColor`,`fgColor`,`includeMargin`,`minVersion`,`boostLevel`,`title`,`marginSize`,`imageSettings`]),{margin:h,cells:g,numCells:_,calculatedImageSettings:v}=VT({value:r,level:a,minVersion:l,boostLevel:u,includeMargin:c,marginSize:f,imageSettings:p,size:i}),y=g,b=null;p!=null&&v!=null&&(v.excavation!=null&&(y=RT(g,v.excavation)),b=B.createElement(`image`,{href:p.src,height:v.h,width:v.w,x:v.x+h,y:v.y+h,preserveAspectRatio:`none`,opacity:v.opacity,crossOrigin:v.crossOrigin}));let x=LT(y,h);return B.createElement(`svg`,CT({height:i,width:i,viewBox:`0 0 ${_} ${_}`,ref:t,role:`img`},m),!!d&&B.createElement(`title`,null,d),B.createElement(`path`,{fill:o,d:`M0,0 h${_}v${_}H0z`,shapeRendering:`crispEdges`}),B.createElement(`path`,{fill:s,d:x,shapeRendering:`crispEdges`}),b)});WT.displayName=`QRCodeSVG`;function GT({data:e,onSubmit:t,submitted:n}){let r=e,i=(0,B.useRef)(!1),a=r?.value?.trim()??``;return(0,B.useEffect)(()=>{a&&!n&&!i.current&&(i.current=!0,t(``))},[a,n,t]),a?(0,V.jsxs)(`div`,{className:`qr-code`,children:[(0,V.jsx)(`div`,{className:`qr-code__canvas`,children:(0,V.jsx)(WT,{value:a,size:240,level:`M`,bgColor:`#ffffff`,fgColor:`#000000`})}),r?.label&&(0,V.jsx)(`div`,{className:`qr-code__label`,children:r.label})]}):(0,V.jsx)(`div`,{className:`qr-code qr-code--error`,children:`No QR data provided. Try again or ask the agent to generate a new QR code.`})}function KT(e){return e===0?`0 B`:e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function qT(e){return e.startsWith(`image/`)?(0,V.jsx)(ze,{size:18}):e===`application/pdf`?(0,V.jsx)(c,{size:18}):e===`text/calendar`?(0,V.jsx)(Te,{size:18}):e.startsWith(`text/`)?(0,V.jsx)(E,{size:18}):e===`application/zip`||e===`application/x-zip-compressed`?(0,V.jsx)(Ie,{size:18}):(0,V.jsx)(le,{size:18})}function JT({data:e,onSubmit:t,submitted:n,sessionKey:r}){let i=e,a=(0,B.useRef)(!1),o=!!(i?.attachmentId&&i?.filename);(0,B.useEffect)(()=>{o&&!n&&!a.current&&(a.current=!0,t(JSON.stringify({_lifecycle:!0,component:`file-attachment`,event:`rendered`,attachmentId:i.attachmentId,filename:i.filename})))},[o,n,t,i]);let s=(0,B.useCallback)(()=>{if(!i?.attachmentId||!r)return;let e=`/api/admin/attachment/${i.attachmentId}?session_key=${encodeURIComponent(r)}`,t=document.createElement(`a`);t.href=e,t.download=i.filename,t.click()},[i,r]);return o?(0,V.jsx)(O,{submitted:!1,submittedLabel:`Downloaded`,actions:[{label:`Download`,variant:`primary`,onClick:s,disabled:!r}],children:(0,V.jsxs)(`div`,{className:`file-attachment`,children:[(0,V.jsx)(`div`,{className:`file-attachment__icon`,children:qT(i.mimeType)}),(0,V.jsxs)(`div`,{className:`file-attachment__info`,children:[(0,V.jsx)(`div`,{className:`file-attachment__name`,title:i.filename,children:i.filename}),(0,V.jsxs)(`div`,{className:`file-attachment__meta`,children:[KT(i.sizeBytes),` · `,i.mimeType]})]}),(0,V.jsx)(`button`,{className:`file-attachment__download`,onClick:s,disabled:!r,title:`Download file`,children:(0,V.jsx)(L,{size:16})})]})}):null}var YT=/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/,XT=/^[a-z0-9-]$/;function ZT(e){return e?YT.test(e):!1}function QT(e){let t=e.toLowerCase(),n=``;for(let e of t)XT.test(e)&&(n+=e);for(;n.startsWith(`-`);)n=n.slice(1);return n}function $T(e){return[{key:`length`,label:`At least 8 characters`,met:e.length>=8},{key:`number`,label:`Contains a number`,met:/\d/.test(e)},{key:`special`,label:`Contains a special character`,met:/[^A-Za-z0-9]/.test(e)},{key:`whitespace`,label:`No spaces`,met:e.length>0&&!/\s/.test(e)}]}var eE=/https:\/\/dash\.cloudflare\.com\/argotunnel\?[^\s]+/,tE=/^OAUTH_URL:\s*(\S+)/,nE=/result=error\s+reason=([a-z0-9-]+)/;function rE(e){let t=e.match(tE);if(t)return t[1];let n=e.match(eE);return n?n[0]:null}function iE(e){let t=e.match(nE);return t?t[1]:null}var aE=/\[(\d+)\/(\d+)\]/,oE=2e3,sE=9e4;function cE(e){if(!e)return null;let t=e.match(aE);return t?parseInt(t[1],10):null}function lE({actionId:e,sessionKey:t,onExit:n,maxLines:r=1e3,selfRestart:i}){let[a,o]=(0,B.useState)([]),[s,c]=(0,B.useState)(null),[u,d]=(0,B.useState)(null),[f,p]=(0,B.useState)(null),[m,h]=(0,B.useState)(null),[g,_]=(0,B.useState)(!1),[v,y]=(0,B.useState)(null),b=(0,B.useRef)(null),x=(0,B.useRef)(null),S=(0,B.useRef)(0),C=(0,B.useRef)(null),w=(0,B.useRef)(null),T=(0,B.useRef)(null),E=(0,B.useRef)(null),D=(0,B.useRef)(null),O=(0,B.useRef)(null),k=(0,B.useRef)(n);k.current=n;let A=(0,B.useCallback)(()=>{D.current&&=(clearInterval(D.current),null),O.current&&=(clearTimeout(O.current),null)},[]),j=(0,B.useCallback)(e=>{e&&(b.current=e,y(e))},[]),M=(0,B.useCallback)(()=>{let n=S.current>0?`&from=${S.current}`:``,a=new EventSource(`/api/admin/actions/${encodeURIComponent(e)}/stream?session_key=${encodeURIComponent(t)}${n}`);C.current=a,a.addEventListener(`line`,e=>{try{let t=JSON.parse(e.data);if(S.current=t.byteOffset,o(e=>{let n=[...e,t];return n.length>r&&n.splice(0,n.length-r),n}),!m){let e=rE(t.text);e&&h(e)}let n=t.text.match(aE);n&&j(n[0]);let i=iE(t.text);i&&(x.current=i),p(null)}catch(e){console.error(`[ActionLogPanel] line parse failed:`,e)}}),a.addEventListener(`heartbeat`,e=>{try{let t=JSON.parse(e.data);T.current=t,c(t),j(t.last_phase),p(null)}catch(e){console.error(`[ActionLogPanel] heartbeat parse failed:`,e)}}),a.addEventListener(`exit`,e=>{try{let t=JSON.parse(e.data);d(t),k.current?.(t,x.current)}catch(e){console.error(`[ActionLogPanel] exit parse failed:`,e)}finally{a.close(),C.current=null,A(),_(!1)}}),a.onerror=()=>{if(u)return;a.close(),C.current=null;let e=cE(b.current);if(i&&e!==null&&e>=i.atPhase&&E.current!==null){console.log(`[ActionLogPanel] SSE drop during self-restart window (phase=${b.current}) — banner suppressed`),p(null),_(!0),N();return}p(`Connection lost — reconnecting…`),setTimeout(()=>{u||M()},1500)}},[e,t,r,i?.atPhase,A]);function N(){A(),D.current=setInterval(async()=>{try{let e=await fetch(`/api/admin/version`,{cache:`no-store`});if(!e.ok)return;let t=(await e.json())?.installed,n=E.current;t&&n&&t!==n&&(console.log(`[ActionLogPanel] admin-server version changed ${n}→${t} — reconnecting stream`),A(),_(!1),E.current=t,M())}catch{}},oE),O.current=setTimeout(()=>{console.log(`[ActionLogPanel] self-restart window timeout (${sE}ms) — reverting to error banner`),A(),_(!1),p(`New version did not come up — reconnecting…`),setTimeout(()=>{u||M()},1500)},sE)}(0,B.useEffect)(()=>(M(),()=>{C.current?.close(),C.current=null,A()}),[M,A]),(0,B.useEffect)(()=>{if(!i)return;let e=!1;return(async()=>{try{let t=await fetch(`/api/admin/version`,{cache:`no-store`});if(!t.ok)return;let n=await t.json();!e&&typeof n?.installed==`string`&&(E.current=n.installed)}catch{}})(),()=>{e=!0}},[e,i?.atPhase]),(0,B.useEffect)(()=>{let e=w.current;e&&e.scrollHeight-e.scrollTop-e.clientHeight<80&&(e.scrollTop=e.scrollHeight)},[a]);let P=e=>new Date(e).toLocaleTimeString(void 0,{hour12:!1}),ee=s?Math.floor(s.elapsed_since_last_line_ms/1e3):0,te=!u&&(f!==null||g),ne=te?`#666`:void 0,F=!u&&!te&&s&&ee>=5;return(0,V.jsxs)(`div`,{className:`action-log-panel`,style:{display:`flex`,flexDirection:`column`,height:`100%`,background:`#0a0a0a`,color:`#e8e8e8`,borderRadius:4,overflow:`hidden`,fontFamily:`ui-monospace, monospace`,fontSize:12},children:[(0,V.jsxs)(`div`,{style:{padding:`6px 10px`,borderBottom:`1px solid #222`,display:`flex`,gap:12,alignItems:`center`,flexWrap:`wrap`,fontSize:11},children:[(0,V.jsx)(`span`,{style:{color:`#888`},children:`action:`}),(0,V.jsx)(`span`,{children:e}),s&&(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{style:{color:`#888`,marginLeft:`auto`},children:`state:`}),(0,V.jsx)(`span`,{style:{color:ne},children:s.systemd_state}),v&&(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{style:{color:`#888`},children:`phase:`}),(0,V.jsx)(`span`,{style:{color:ne},children:v})]}),te&&(0,V.jsx)(`span`,{style:{color:`#888`,fontStyle:`italic`},children:`(stale)`}),F&&(0,V.jsxs)(`span`,{style:{color:`#e4a657`,display:`inline-flex`,alignItems:`center`,gap:4},children:[(0,V.jsx)(l,{size:11}),` silent `,ee,`s`]})]})]}),m&&!u&&(0,V.jsxs)(`div`,{style:{padding:`8px 10px`,borderBottom:`1px solid #222`,background:`#1b1f2b`,display:`flex`,alignItems:`center`,gap:8},children:[(0,V.jsx)(`span`,{style:{color:`#cbd5f5`},children:`Cloudflare needs you to authorise this device.`}),(0,V.jsxs)(`a`,{href:m,target:`_blank`,rel:`noopener noreferrer`,style:{marginLeft:`auto`,color:`#fff`,background:`#f6821f`,padding:`4px 10px`,borderRadius:3,textDecoration:`none`,display:`inline-flex`,alignItems:`center`,gap:6},children:[`Authorise in Cloudflare `,(0,V.jsx)(Fe,{size:12})]})]}),f&&!g&&(0,V.jsxs)(`div`,{style:{padding:`6px 10px`,background:`#3a2b10`,color:`#ffc987`,display:`flex`,alignItems:`center`,gap:8},children:[(0,V.jsx)(ge,{size:12,className:`spin`}),` `,f]}),g&&(0,V.jsxs)(`div`,{style:{padding:`6px 10px`,background:`#132319`,color:`#9aeab0`,display:`flex`,alignItems:`center`,gap:8},children:[(0,V.jsx)(ge,{size:12,className:`spin`}),` Waiting for new version…`]}),(0,V.jsxs)(`div`,{ref:w,style:{flex:1,overflow:`auto`,padding:`6px 10px`,lineHeight:1.45,whiteSpace:`pre-wrap`,wordBreak:`break-word`},children:[a.length===0&&!u&&(0,V.jsx)(`div`,{style:{color:`#888`},children:`Waiting for output…`}),a.map(e=>(0,V.jsxs)(`div`,{style:{display:`flex`,gap:10,color:e.stream===`stderr`?`#ff9999`:`#e8e8e8`},children:[(0,V.jsx)(`span`,{style:{color:`#666`,flexShrink:0},children:P(e.ts)}),(0,V.jsx)(`span`,{children:e.text})]},e.byteOffset))]}),u&&(0,V.jsxs)(`div`,{style:{padding:`8px 10px`,borderTop:`1px solid #222`,background:u.code===0?`#14331b`:`#3a1717`,color:u.code===0?`#9aeab0`:`#ff9999`,display:`flex`,alignItems:`center`,gap:8},children:[u.code===0?(0,V.jsx)(De,{size:13}):(0,V.jsx)(l,{size:13}),(0,V.jsxs)(`span`,{children:[u.code===0?`Completed`:`Failed (exit ${u.code})`,` · `,Math.round(u.duration_ms/1e3),`s`]})]})]})}var uE={title:`Authorise the tunnel in your own browser`,intro:`The Pi's browser couldn't drive the Cloudflare consent page automatically. Open the dashboard in your own browser and follow these steps:`,steps:[`The "Authorize Cloudflare Tunnel" page shows every zone on the currently-active account.`,`Click the zone you want the tunnel to be able to route DNS for.`,`Click Authorize. The browser closes or shows "You can close this page."`,`Return here and click "Try again" — the cert will land and setup will continue.`],footnote:`If the account shown in the top-left of the dashboard is not the one that owns your zone, click the account-name dropdown first and switch accounts before authorising.`},dE=18e4,fE=4096;function pE(e){let t=new TextEncoder().encode(e);return t.length<=fE?e:`${new TextDecoder(`utf-8`,{fatal:!1}).decode(t.slice(0,fE))}\n… ${t.length-fE} bytes truncated (total ${t.length} bytes)`}function mE({data:e,onSubmit:t,submitted:n,sessionKey:r}){let i=e,[a,o]=(0,B.useState)({status:`loading`}),[s,c]=(0,B.useState)(``),[l,u]=(0,B.useState)(``),[d,f]=(0,B.useState)(``),[p,m]=(0,B.useState)(``),[h,g]=(0,B.useState)(``),[_,v]=(0,B.useState)(``),[y,b]=(0,B.useState)(!1),[x,S]=(0,B.useState)(!1),[C,w]=(0,B.useState)(!1),[T,E]=(0,B.useState)(null),[D,k]=(0,B.useState)(null),[A,j]=(0,B.useState)(null),M=(0,B.useRef)(null),N=(0,B.useRef)(new Set),P=(0,B.useCallback)(async()=>{if(!r){o({status:`error`,field:`session`,message:`No session key available — refresh the page.`});return}o({status:`loading`});try{let e=await(await fetch(`/api/admin/cloudflare/domains?session_key=${encodeURIComponent(r)}`,{method:`GET`,headers:{Accept:`application/json`}})).json();if(!e.ok){o({status:`error`,field:e.field,message:e.message,output:e.output,correlationId:e.correlationId,streamLogPath:e.streamLogPath});return}if(e.domains.length===0){o({status:`empty`});return}o({status:`populated`,domains:e.domains}),u(t=>t||e.domains[0]),m(t=>t||e.domains[0])}catch(e){o({status:`error`,field:`script`,message:e instanceof Error?e.message:`Network error loading domains.`})}},[r]);(0,B.useEffect)(()=>{P()},[P]),(0,B.useEffect)(()=>()=>{M.current&&clearTimeout(M.current)},[]);let ee=a.status===`populated`?a.domains:[],te=e=>{n||x||(c(QT(e)),j(null))},ne=e=>{n||x||(f(QT(e)),j(null))},F=ZT(s)&&l.length>0,I=d!==``,re=!I||ZT(d)&&p.length>0,ie=F?`${s.replace(/-+$/,``)}.${l}`:``,ae=I&&re?`${d.replace(/-+$/,``)}.${p}`:``,oe=!(ae&&ae===ie),se=$T(_),L=se.every(e=>e.met),ce=a.status===`populated`&&F&&re&&oe&&L&&!x,le=s!==``&&!ZT(s)?`Use lowercase letters, numbers, and hyphens. Start and end with a letter or number.`:null,ue=I&&!ZT(d)?`Use lowercase letters, numbers, and hyphens. Start and end with a letter or number.`:oe?null:`Public address must differ from the admin address.`,de=A?.field===`admin`?A.message:null,fe=A?.field===`public`?A.message:null,pe=A?.field===`password`?A.message:null,me=A?.field===`script`||A?.field===`request`?A.message:null,he=()=>{w(!1),j(null),S(!1)},ge=async()=>{if(!ce)return;if(!r){j({field:`request`,message:`No session key available — refresh the page.`});return}S(!0),j(null),w(!1);let e=new AbortController;M.current=setTimeout(()=>{e.abort(),w(!0)},dE);let n={session_key:r,adminLabel:s.replace(/-+$/,``),adminDomain:l,password:_};I&&(n.publicLabel=d.replace(/-+$/,``),n.publicDomain=p),h&&(n.apex=h);try{let r=await fetch(`/api/admin/cloudflare/setup`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(n),signal:e.signal});M.current&&clearTimeout(M.current),M.current=null;let i=await r.json();if(!i.ok){j({field:i.field,message:i.message,output:i.output,correlationId:i.correlationId,streamLogPath:i.streamLogPath});let e=i.streamLogPath?`\n\nstream log: ${i.streamLogPath}`:``;t(i.output&&i.output.length>0?`Cloudflare setup failed: ${i.message}\n\n${i.output}${e}`:`Cloudflare setup failed: ${i.message}${e}`),S(!1);return}if(i.actionId){E(i.actionId);return}t(i.output)}catch(t){if(M.current&&clearTimeout(M.current),M.current=null,e.signal.aborted)return;j({field:`script`,message:t instanceof Error?t.message:`Network error — try again.`}),S(!1)}},_e=(0,B.useMemo)(()=>s?`${s}.${l||`your-domain`}`:`your-name.${l||`your-domain`}`,[s,l]);if(a.status===`loading`)return(0,V.jsx)(O,{submitted:!1,actions:[],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[i?.title&&(0,V.jsx)(`div`,{className:`form-input__title`,children:i.title}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`Reading the domains on your Cloudflare account…`})]})});if(a.status===`empty`)return(0,V.jsx)(O,{submitted:!1,actions:[{label:`Retry`,variant:`primary`,onClick:P}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:`No domains on this Cloudflare account`}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`Add a domain in the Cloudflare dashboard first, then click Retry.`}),(0,V.jsxs)(`ol`,{className:`form-input__field-desc`,style:{margin:0,paddingLeft:20},children:[(0,V.jsxs)(`li`,{children:[`With the correct account active (top-left), click `,(0,V.jsx)(`strong`,{children:`Websites`}),` in the left-hand sidebar.`]}),(0,V.jsxs)(`li`,{children:[`Click the `,(0,V.jsx)(`strong`,{children:`Add a site`}),` button.`]}),(0,V.jsxs)(`li`,{children:[`Enter the bare domain (e.g. `,(0,V.jsx)(`code`,{children:`example.com`}),`) and click `,(0,V.jsx)(`strong`,{children:`Continue`}),`.`]}),(0,V.jsxs)(`li`,{children:[`Review Cloudflare's imported DNS records — preserve website (`,(0,V.jsx)(`code`,{children:`A`}),`), email (`,(0,V.jsx)(`code`,{children:`MX`}),`), and verification (`,(0,V.jsx)(`code`,{children:`TXT`}),`) entries.`]}),(0,V.jsx)(`li`,{children:`Copy Cloudflare's two nameservers and set them on your domain registrar.`}),(0,V.jsxs)(`li`,{children:[`Return to Cloudflare and click `,(0,V.jsx)(`strong`,{children:`Check nameservers`}),`. Wait for the zone to show `,(0,V.jsx)(`strong`,{children:`Active`}),`.`]})]})]})});if(a.status===`error`){let e=a.field===`dashboard`,t=e?`Not signed into Cloudflare on this device`:`Could not read domains from Cloudflare`,n=e?`Sign in again at the Cloudflare dashboard in the VNC browser, then click Retry. If the VNC browser is not open, ask me to run vnc.sh restart.`:a.message;return(0,V.jsx)(O,{submitted:!1,actions:[{label:`Retry`,variant:`primary`,onClick:P}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:t}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:n}),a.output&&a.output.length>0&&(0,V.jsx)(`pre`,{style:{marginTop:8,padding:8,maxHeight:280,overflow:`auto`,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:12,lineHeight:1.4,whiteSpace:`pre-wrap`,wordBreak:`break-word`,background:`var(--surface-2, rgba(0,0,0,0.04))`,borderRadius:4},children:pE(a.output)}),(a.correlationId||a.streamLogPath)&&(0,V.jsxs)(`div`,{style:{marginTop:8,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:11,color:`var(--text-secondary)`,wordBreak:`break-all`},children:[a.correlationId&&(0,V.jsxs)(`div`,{children:[`conversationId: `,a.correlationId]}),a.streamLogPath&&(0,V.jsxs)(`div`,{children:[`stream log: `,a.streamLogPath]})]})]})})}return D?(0,V.jsx)(O,{submitted:!1,actions:[{label:`Try again`,variant:`primary`,onClick:()=>{k(null),E(null),j(null),S(!1),w(!1)}}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:D.card.title}),(0,V.jsx)(`div`,{className:`form-input__desc`,style:{whiteSpace:`pre-wrap`},children:D.card.intro}),(0,V.jsx)(`ol`,{style:{marginTop:10,paddingLeft:20,lineHeight:1.6},children:D.card.steps.map((e,t)=>(0,V.jsx)(`li`,{children:e},t))}),D.card.footnote&&(0,V.jsx)(`div`,{style:{marginTop:10,fontStyle:`italic`,color:`#666`},children:D.card.footnote})]})}):T&&r?(0,V.jsx)(O,{submitted:!1,actions:[],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[i?.title&&(0,V.jsx)(`div`,{className:`form-input__title`,children:i.title}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`Cloudflare setup in progress — keep this panel open until it completes.`}),(0,V.jsx)(`div`,{style:{marginTop:10,height:360},children:(0,V.jsx)(lE,{actionId:T,sessionKey:r,onExit:(e,n)=>{if(N.current.has(T)){console.log(`[CloudflareSetupForm] suppressed duplicate completion dispatch actionId=${T}`);return}if(N.current.add(T),e.code===0){t(`Cloudflare setup completed (actionId: ${T}).`);return}if(n===`authorize-button-not-found`){k({card:uE,actionId:T,exitCode:e.code});return}t(`Cloudflare setup failed with exit code ${e.code} (actionId: ${T}).`)}})})]})}):C?(0,V.jsx)(O,{submitted:!1,actions:[{label:`Reset form`,variant:`ghost`,onClick:he}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:`Setup is taking longer than expected`}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`The request is still running on the device — check the chat for live progress. Do not resubmit. If the script fails, the error will appear in chat and you can retry from there.`})]})}):(0,V.jsx)(O,{submitted:n,submittedLabel:`Submitting…`,actions:[{label:x?`Setting up…`:i?.submitLabel??`Set up Cloudflare`,variant:`primary`,disabled:!ce,onClick:ge}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[i?.title&&(0,V.jsx)(`div`,{className:`form-input__title`,children:i.title}),i?.description&&(0,V.jsx)(`div`,{className:`form-input__desc`,children:i.description}),(0,V.jsxs)(`div`,{className:`form-input__fields`,children:[(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-admin-label`,children:[`Admin address`,(0,V.jsx)(`span`,{className:`form-input__required`,children:`*`})]}),(0,V.jsxs)(`div`,{className:`tunnel-route__row`,children:[(0,V.jsx)(`input`,{id:`cf-admin-label`,className:`form-input__input tunnel-route__input`,type:`text`,autoCapitalize:`none`,autoComplete:`off`,autoCorrect:`off`,spellCheck:!1,placeholder:`your-name`,value:s,onChange:e=>te(e.target.value),disabled:n||x}),(0,V.jsx)(hE,{id:`cf-admin-domain`,value:l,options:ee,onChange:u,disabled:n||x})]}),(0,V.jsx)(`div`,{className:`form-input__field-desc`,children:`Where you access your platform remotely, via your main domain.`}),(0,V.jsxs)(`div`,{className:`form-input__field-desc`,children:[`Preview: `,(0,V.jsx)(`span`,{className:`tunnel-route__preview`,children:_e})]}),(de||le)&&(0,V.jsx)(`div`,{className:`tunnel-route__error`,children:de??le})]}),(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-public-label`,children:[`Public address`,(0,V.jsx)(`span`,{className:`tunnel-route__optional`,children:`Optional`})]}),(0,V.jsxs)(`div`,{className:`tunnel-route__row`,children:[(0,V.jsx)(`input`,{id:`cf-public-label`,className:`form-input__input tunnel-route__input`,type:`text`,autoCapitalize:`none`,autoComplete:`off`,autoCorrect:`off`,spellCheck:!1,placeholder:`leave empty to skip`,value:d,onChange:e=>ne(e.target.value),disabled:n||x}),(0,V.jsx)(hE,{id:`cf-public-domain`,value:p,options:ee,onChange:m,disabled:n||x||!I})]}),(0,V.jsx)(`div`,{className:`form-input__field-desc`,children:`Where visitors engage with your public agents, via your main domain. Leave empty for admin-only access.`}),(fe||ue)&&(0,V.jsx)(`div`,{className:`tunnel-route__error`,children:fe??ue})]}),(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-apex`,children:[`Proxy apex`,(0,V.jsx)(`span`,{className:`tunnel-route__optional`,children:`Optional`})]}),(0,V.jsxs)(`select`,{id:`cf-apex`,className:`form-input__input`,value:h,onChange:e=>g(e.target.value),disabled:n||x,children:[(0,V.jsx)(`option`,{value:``,children:`None`}),ee.map(e=>(0,V.jsx)(`option`,{value:e,children:e},e))]}),(0,V.jsx)(`div`,{className:`form-input__field-desc`,children:`Alternative domain for public agent visitors.`})]}),(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-password`,children:[`Admin password`,(0,V.jsx)(`span`,{className:`form-input__required`,children:`*`})]}),(0,V.jsxs)(`div`,{className:`tunnel-route__row`,children:[(0,V.jsx)(`input`,{id:`cf-password`,className:`form-input__input tunnel-route__input`,type:y?`text`:`password`,autoCapitalize:`none`,autoComplete:`new-password`,autoCorrect:`off`,spellCheck:!1,value:_,onChange:e=>{v(e.target.value),j(null)},disabled:n||x}),(0,V.jsx)(`button`,{type:`button`,className:`tunnel-route__suffix`,onClick:()=>b(e=>!e),disabled:n||x,style:{cursor:`pointer`,border:`none`,background:`inherit`},"aria-label":y?`Hide password`:`Show password`,children:y?`Hide`:`Show`})]}),(0,V.jsx)(`ul`,{className:`form-input__field-desc`,style:{margin:0,paddingLeft:16},children:se.map(e=>(0,V.jsxs)(`li`,{style:{color:e.met?`var(--text)`:`var(--text-secondary)`},children:[e.met?`✓`:`○`,` `,e.label]},e.key))}),pe&&(0,V.jsx)(`div`,{className:`tunnel-route__error`,children:pe})]}),me&&(0,V.jsxs)(`div`,{className:`tunnel-route__error`,role:`alert`,children:[(0,V.jsx)(`div`,{children:me}),A?.output&&A.output.length>0&&(0,V.jsx)(`pre`,{style:{marginTop:8,padding:8,maxHeight:280,overflow:`auto`,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:12,lineHeight:1.4,whiteSpace:`pre-wrap`,wordBreak:`break-word`,background:`var(--surface-2, rgba(0,0,0,0.04))`,borderRadius:4},children:pE(A.output)}),(A?.correlationId||A?.streamLogPath)&&(0,V.jsxs)(`div`,{style:{marginTop:8,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:11,color:`var(--text-secondary)`,wordBreak:`break-all`},children:[A.correlationId&&(0,V.jsxs)(`div`,{children:[`conversationId: `,A.correlationId]}),A.streamLogPath&&(0,V.jsxs)(`div`,{children:[`stream log: `,A.streamLogPath]})]})]})]})]})})}function hE({id:e,value:t,options:n,onChange:r,disabled:i}){return(0,V.jsx)(`select`,{id:e,className:`tunnel-route__suffix`,value:t,onChange:e=>r(e.target.value),disabled:i,style:{cursor:i?`default`:`pointer`,border:`none`},children:n.map(e=>(0,V.jsxs)(`option`,{value:e,children:[`.`,e]},e))})}var gE={"single-select":b,"multi-select":P,confirm:Gt,"info-card":Kt,"action-list":qt,form:Jt,progress:Xt,"browser-viewer":Qt,"rich-content-editor":uT,"grid-editor":_T,"qr-code":GT,"file-attachment":JT,"action-buttons":j,"cloudflare-setup-form":mE,"output-style":b,"thinking-view":b,"plugin-selector":P};function _E(e){let{data:t,filePath:n,onOpen:r}=e,i=n.split(`/`).pop()||n||`document.md`,a=(i.split(`.`).pop()||`doc`).toUpperCase().slice(0,6),o=n||i,s=(0,B.useRef)(!1);return(0,B.useEffect)(()=>{s.current||(s.current=!0,r({docId:o,name:i,content:t.content??``}))},[o,i,t.content,r]),(0,V.jsx)(`div`,{className:`component-card artefact-ref-card`,children:(0,V.jsxs)(`button`,{type:`button`,className:`artefact-ref-button`,onClick:()=>r({docId:o,name:i,content:t.content??``}),children:[(0,V.jsx)(`span`,{className:`artefact-ref-icon`,children:(0,V.jsx)(c,{size:16})}),(0,V.jsxs)(`span`,{className:`artefact-ref-meta`,children:[(0,V.jsx)(`span`,{className:`artefact-ref-name`,children:i}),(0,V.jsxs)(`span`,{className:`artefact-ref-tag`,children:[a,` · open in artefact pane`]})]}),(0,V.jsx)(`span`,{className:`artefact-ref-open`,children:(0,V.jsx)(Fe,{size:14})})]})})}function vE({name:e,data:t,onSubmit:n,submitted:r,isStreaming:i,sessionKey:a,onOpenArtefact:o}){if(e===`document-editor`&&o){let e=t??{};return(0,V.jsx)(_E,{data:e,filePath:e.filePath||e.title||`document.md`,onOpen:o})}if(e===`document-editor`)return(0,V.jsx)(Jw,{data:t,onSubmit:n,submitted:r,isStreaming:i});let s=gE[e];return s?(0,V.jsx)(s,{data:t,onSubmit:n,submitted:r,isStreaming:i,sessionKey:a}):(console.warn(`[ComponentRenderer] Unknown component: "${e}". Registered: ${Object.keys(gE).join(`, `)}`),(0,V.jsx)(`div`,{className:`component-card component-card--error`,children:(0,V.jsxs)(`p`,{style:{fontFamily:`var(--font-body)`,fontSize:12,color:`var(--text-secondary)`},children:[`Component “`,e,`” is not available. This may require a platform update.`]})}))}var yE=/\b(?:fail|error|unable|could not|cannot|CAPTCHA|SIGN_IN_REQUIRED)\b/i;function bE(e){let t=new Date(e),n=new Date,r=String(t.getHours()).padStart(2,`0`),i=String(t.getMinutes()).padStart(2,`0`);return t.toDateString()===n.toDateString()?`${r}:${i}`:`${String(t.getDate()).padStart(2,`0`)}-${String(t.getMonth()+1).padStart(2,`0`)}-${t.getFullYear()} ${r}:${i}`}var xE=[pt,ut,be,ct,Ne];function SE({size:e=13}){let[t,n]=(0,B.useState)(0);(0,B.useEffect)(()=>{let e=setInterval(()=>n(e=>(e+1)%8),300);return()=>clearInterval(e)},[]);let r=t<=4?t:8-t,i=xE[r];return(0,V.jsx)(i,{size:e,className:`star-loader star-frame-${r}`})}var CE=[`Thinking`,`Reasoning`,`Analyzing`,`Considering`,`Reflecting`,`Evaluating`,`Weighing`,`Synthesizing`,`Processing`,`Exploring`,`Examining`,`Assessing`,`Reviewing`,`Contemplating`,`Deliberating`],wE=60,TE=1500;function EE(){let e=(0,B.useRef)(-1),t=(0,B.useRef)(void 0),[n,r]=(0,B.useState)(()=>{let t=Math.floor(Math.random()*CE.length);return e.current=t,CE[t]+`…`});return(0,B.useEffect)(()=>{let n=!1;function i(){let t;do t=Math.floor(Math.random()*CE.length);while(t===e.current&&CE.length>1);return e.current=t,t}function a(){if(n)return;let e=CE[i()]+`…`,o=0;function s(){n||(o++,r(e.slice(0,o)),o<e.length?t.current=setTimeout(s,wE):t.current=setTimeout(a,TE))}t.current=setTimeout(s,wE)}return t.current=setTimeout(a,TE),()=>{n=!0,clearTimeout(t.current)}},[]),(0,V.jsx)(`span`,{className:`tl-thinking-typewriter`,children:n})}function DE(e,t){let n=e=>String(e??``);switch(e){case`Read`:return`Read ${n(t.file_path??t.path)}`;case`Write`:return`Write ${n(t.file_path??t.path)}`;case`Edit`:return`Edit ${n(t.file_path??t.path)}`;case`Bash`:return n(t.description??String(t.command??``).slice(0,70));case`Glob`:return`Glob ${n(t.pattern)}`;case`Grep`:return`Grep "${n(t.pattern)}" in ${n(t.path??`.`)}`;case`WebFetch`:return`Fetch ${n(t.url)}`;case`Agent`:return n(t.description??t.task??`Subagent`);case`Skill`:return n(t.skill??`Skill`);default:{let r=e.match(/^mcp__[^_]+__(.+)$/),i=r?r[1]:e,a=Object.keys(t)[0];return a?`${i}: ${n(t[a]).slice(0,50)}`:i}}}function OE({name:e,size:t=12}){let n=e.match(/^mcp__[^_]+__(.+)$/);switch(n?n[1]:e){case`Read`:return(0,V.jsx)(c,{size:t});case`Write`:return(0,V.jsx)(Ve,{size:t});case`Edit`:return(0,V.jsx)(Be,{size:t});case`Bash`:return(0,V.jsx)(mt,{size:t});case`Glob`:case`Grep`:return(0,V.jsx)(de,{size:t});case`WebFetch`:return(0,V.jsx)(D,{size:t});case`Agent`:return(0,V.jsx)(Ce,{size:t});case`Skill`:return(0,V.jsx)(ut,{size:t});case`memory-search`:return(0,V.jsx)(Me,{size:t});case`memory-write`:return(0,V.jsx)(je,{size:t});case`task-list`:return(0,V.jsx)(R,{size:t});case`task-create`:return(0,V.jsx)(ke,{size:t});case`contact-create`:return(0,V.jsx)(ht,{size:t});default:return(0,V.jsx)(_t,{size:t})}}function kE(e){let t=new Map,n=new Map;return e.forEach((e,r)=>{if(e.type===`tool_use`){let t=n.get(e.name)??[];t.push(r),n.set(e.name,t)}else if(e.type===`tool_result`){let i=n.get(e.name);i?.length&&t.set(i.shift(),r)}}),t}function AE(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function jE(e){let t=``;switch(e.type){case`text`:case`thinking`:t=e.content??``;break;case`tool_use`:t=JSON.stringify(e.input??{});break;case`tool_result`:t=e.output??``;break;case`subagent_start`:t=e.task??``;break;case`subagent_end`:t=e.result??``;break;case`component`:t=JSON.stringify(e.data??{});break;case`status`:t=e.message??``;break;default:return 0}return Math.ceil(t.length/4)}function ME(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 NE(e){if(e<60)return`${e.toFixed(1)}s`;let t=Math.floor(e/60),n=e%60;return n>=.1?`${t}m ${Math.floor(n)}s`:`${t}m`}function PE({icon:e,isPending:t,isError:n,doneClass:r=`tl-done`,summary:i,detail:a,tokens:o,elapsed:s,isLast:c,expanded:l,onToggle:u,selectCheck:d}){let f=!!a;return(0,V.jsxs)(`div`,{className:`tl-step`,children:[d,(0,V.jsxs)(`div`,{className:`tl-col`,children:[(0,V.jsx)(`div`,{className:`tl-icon${t?` tl-pending`:n?` tl-error`:` ${r}`}`,children:e}),!c&&(0,V.jsx)(`div`,{className:`tl-line tl-line-grow`})]}),(0,V.jsxs)(`div`,{className:`tl-body`,children:[(0,V.jsxs)(`div`,{className:`tl-row`,onClick:f?()=>{window.getSelection()?.toString()||u()}:void 0,style:{cursor:f?`pointer`:`default`},children:[(0,V.jsx)(`span`,{className:`tl-summary`,children:i}),o>0&&(0,V.jsxs)(`span`,{className:`tl-step-tokens`,children:[(0,V.jsx)(vt,{size:9}),AE(o)]}),(0,V.jsx)(`span`,{className:`tl-step-elapsed`,children:NE(s)}),f&&(0,V.jsx)(`span`,{className:`tl-chevron`,children:l?(0,V.jsx)(p,{size:10}):(0,V.jsx)(Ee,{size:10})})]}),f&&l&&(0,V.jsx)(`pre`,{className:`tl-detail`,children:a})]})]})}function FE({events:e,isStreaming:t,elapsedSeconds:n,streamStartMs:r,expandAll:i,onCompactNow:a,isCompacting:o,sessionCompacted:s,onComponentSubmit:c,submittedComponents:l,timestamp:u,selectionMode:d,selectedItems:f,onToggleItem:m,sessionKey:g,onOpenArtefact:_}){let[v,y]=(0,B.useState)(new Set),[b,S]=(0,B.useState)(!t),C=(0,B.useRef)(t);(0,B.useEffect)(()=>{C.current&&!t&&S(!0),!C.current&&t&&S(!1),C.current=t},[t]);let T=(0,B.useRef)(new Map),E=(0,B.useRef)(0),[D,O]=(0,B.useState)(Date.now());(0,B.useEffect)(()=>{let t=Date.now();for(let n=E.current;n<e.length;n++)T.current.has(n)||T.current.set(n,t);E.current=e.length},[e]),(0,B.useEffect)(()=>{if(!t)return;let e=setInterval(()=>O(Date.now()),100);return()=>clearInterval(e)},[t]);let k=e=>{y(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},A=(e,t)=>{let n=e===ae[0]?.i&&r?r:T.current.get(e)??D,i=t===void 0?D:T.current.get(t)??D;return Math.max(0,(i-n)/1e3)},j=kE(e),M=new Set(j.values()),N=e.map((e,t)=>({e,i:t})).filter(({e})=>e.type===`text`),P=new Set(t?[]:e.map((e,t)=>({e,i:t})).filter(({e})=>e.type===`component`).map(({i:e})=>e)),ee=e=>e.type===`component`&&[`browser-viewer`,`qr-code`].includes(e.name);function ne(e){if(!d||t||!u)return null;let n=`${u}_${e}`;return(0,V.jsx)(`div`,{className:`tl-select-check`,onClick:e=>e.stopPropagation(),children:(0,V.jsx)(_e,{checked:f?.has(n)??!1,onChange:()=>m?.(n)})})}let F=e.findLast(e=>e.type===`usage`),I=e.findLast(e=>e.type===`history_usage`),re=e.findLast(e=>e.type===`status`),ie=e.some(e=>e.type===`subagent_start`),ae=e.map((e,t)=>({e,i:t})).filter(({e,i:n})=>e.type!==`text`&&e.type!==`usage`&&e.type!==`rate_limit`&&e.type!==`history_usage`&&e.type!==`status`&&e.type!==`done`&&e.type!==`subagent_progress`&&!M.has(n)&&!P.has(n)&&!(t&&e.type===`component`&&!ee(e))&&!(e.type===`tool_use`&&e.name===`Agent`&&ie)),se=new Map;for(let e=0;e<ae.length-1;e++)se.set(ae[e].i,ae[e+1].i);let L=(()=>{let e=[],t=!1,n=0;for(let{e:r}of ae)if(n+=jE(r),r.type===`thinking`)t=!0;else if(r.type===`tool_use`){let t=r.name;e.includes(t)||e.push(t)}let r=[`${ae.length} step${ae.length===1?``:`s`}`];if(e.length>0){let t=e.slice(0,3),n=e.length-t.length;r.push(t.join(`, `)+(n>0?` +${n}`:``))}return{text:r.join(` · `),hasThinking:t,tokenSum:n}})(),ce=F?.peak_request_pct==null?F?.context_window?Math.round((F.input_tokens+F.cache_creation_tokens+F.cache_read_tokens)/F.context_window*100):null:Math.round(F.peak_request_pct*100),le=ae.length>0,ue=N.length>0,de=new Set(ae.map(e=>e.i)),fe=new Set(N.map(e=>e.i)),pe=[];for(let t=0;t<e.length;t++){let n=e[t],r=null;if(de.has(t)?r=`steps`:fe.has(t)&&(r=`text`),!r)continue;let i=pe[pe.length-1];i&&i.role===r?i.items.push({e:n,i:t}):pe.push({role:r,items:[{e:n,i:t}]})}let me=N.length>0?N[N.length-1].i:-1;function he(n,r,a,o){let s=o===a.length-1;if(n.type===`thinking`){let e=i===void 0?!v.has(r):i,t=se.get(r);return(0,V.jsxs)(`div`,{className:`tl-step`,children:[ne(r),(0,V.jsxs)(`div`,{className:`tl-col`,children:[(0,V.jsx)(`div`,{className:`tl-icon tl-dim`,children:(0,V.jsx)(qe,{size:11})}),!s&&(0,V.jsx)(`div`,{className:`tl-line tl-line-grow`})]}),(0,V.jsx)(`div`,{className:`tl-body`,children:(0,V.jsxs)(`div`,{className:`tl-row tl-row-top`,onClick:()=>{window.getSelection()?.toString()||k(r)},style:{cursor:`pointer`},children:[(0,V.jsx)(`div`,{className:`tl-thinking-col`,children:e?(0,V.jsx)(`div`,{className:`tl-thinking-body`,children:n.content}):(0,V.jsxs)(`span`,{className:`tl-summary tl-thinking-label`,children:[n.content.slice(0,80),n.content.length>80?`…`:``]})}),jE(n)>0&&(0,V.jsxs)(`span`,{className:`tl-step-tokens`,children:[(0,V.jsx)(vt,{size:9}),AE(jE(n))]}),(0,V.jsx)(`span`,{className:`tl-step-elapsed`,children:NE(A(r,t))}),(0,V.jsx)(`span`,{className:`tl-chevron`,children:e?(0,V.jsx)(p,{size:10}):(0,V.jsx)(Ee,{size:10})})]})})]},r)}if(n.type===`status`)return(0,V.jsx)(`div`,{className:`tl-status`,children:n.message},r);if(n.type===`tool_use`){let t=j.get(r),a=t===void 0?void 0:e[t],o=a===void 0,c=a?.type===`tool_result`&&!!a.error,l=o?(0,V.jsx)(Ze,{size:11,className:`tl-spinner`}):c?(0,V.jsx)(oe,{size:11}):(0,V.jsx)(OE,{name:n.name,size:11}),u=n,d=a?.type===`tool_result`?`Input:
|
|
343
|
+
`).filter(e=>e.trim());if(n.length<=1&&!n[0]?.includes(` `)&&!n[0]?.includes(`,`))return;e.preventDefault();let r=n.slice(0,dT).map(mT);n.length>dT&&console.warn(`Grid editor: paste truncated from ${n.length} to ${dT} rows`);let{row:i,col:a}=g;h(e=>{let t=e.map(e=>[...e]);for(let e=0;e<r.length;e++){let n=i+e;for(;n>=t.length;)t.push(Array(f.length).fill(``));for(let i=0;i<r[e].length;i++){let o=a+i;o<f.length&&(t[n][o]=r[e][i])}}return t}),A()},[g,f.length,A]),re=(0,B.useCallback)(()=>{let e=hT(f,m),t=new Blob([e],{type:`text/csv;charset=utf-8;`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`${d.replace(/[^a-zA-Z0-9]/g,`_`)}.csv`,r.click(),URL.revokeObjectURL(n)},[f,m,d]),ie=(0,B.useCallback)(()=>{$w({title:d,content:eT(f,m),brandName:l,brandLogo:u})},[d,f,m,l,u]),ae=(0,B.useCallback)((e,t)=>{t.preventDefault(),C.current={colIndex:e,startX:t.clientX,startWidth:x[e]};let n=null,r=e=>{C.current&&(n&&cancelAnimationFrame(n),n=requestAnimationFrame(()=>{if(!C.current)return;let t=e.clientX-C.current.startX,n=Math.max(fT,C.current.startWidth+t);S(e=>{let t=[...e];return t[C.current.colIndex]=n,t})}))},i=()=>{C.current=null,n&&cancelAnimationFrame(n),window.removeEventListener(`mousemove`,r),window.removeEventListener(`mouseup`,i)};window.addEventListener(`mousemove`,r),window.addEventListener(`mouseup`,i)},[x]),se=(0,B.useCallback)(()=>{g&&M.openCommentInput()},[g,M]),ce=(0,B.useCallback)(()=>{if(!g)return;let e=m[g.row]?.[g.col]??``;M.submitComment(e,{row:g.row,column:g.col})},[g,m,M]);if(n)return(0,V.jsxs)(`div`,{className:`editor-base grid-editor grid-editor--submitted`,children:[(0,V.jsxs)(`div`,{className:`editor-base__bar`,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),(0,V.jsx)(`div`,{className:`editor-base__actions`,children:(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Submitted`})})]}),(0,V.jsx)(`div`,{className:`grid-editor__body`,children:(0,V.jsx)(`div`,{className:`grid-editor__table-wrap`,children:(0,V.jsxs)(`table`,{className:`grid-editor__table`,role:`grid`,"aria-label":d,children:[(0,V.jsx)(`thead`,{children:(0,V.jsx)(`tr`,{children:f.map((e,t)=>(0,V.jsx)(`th`,{className:`grid-editor__col-header`,style:{width:x[t]},children:e},t))})}),(0,V.jsx)(`tbody`,{children:m.map((e,t)=>(0,V.jsx)(`tr`,{children:e.map((e,t)=>(0,V.jsx)(`td`,{className:`grid-editor__cell`,role:`gridcell`,style:{width:x[t]},children:(0,V.jsx)(`span`,{className:`grid-editor__cell-text`,children:e})},t))},t))})]})})})]});let le=typeof window<`u`&&window.innerWidth<640,ue=typeof BroadcastChannel<`u`,de=(0,V.jsxs)(`div`,{className:`editor-base__actions`,children:[T===`saving`&&(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Saving...`}),T===`saved`&&(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Saved`}),M.pendingComments.length>0&&(0,V.jsxs)(w,{variant:`ghost`,size:`sm`,onClick:M.sendComments,children:[`Send `,M.pendingComments.length,` comment`,M.pendingComments.length>1?`s`:``]}),g&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:$e,onClick:se,"aria-label":`Comment on cell`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:L,onClick:re,"aria-label":`Download CSV`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Le,onClick:ie,"aria-label":`Export PDF`}),!le&&ue&&!j.poppedOut&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Fe,onClick:j.handlePopout,"aria-label":`Pop out`}),!j.fullscreen&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Qe,onClick:j.handleFullscreen,"aria-label":`Full screen`}),j.fullscreen&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:nt,onClick:j.exitFullscreen,"aria-label":`Exit full screen`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:rt,onClick:j.handleMinimise,"aria-label":`Minimise`})]}),fe=(0,V.jsxs)(`div`,{className:`grid-editor__table-wrap`,onPaste:I,children:[M.showCommentInput?(0,V.jsxs)(`div`,{className:`grid-editor__comment-popover`,children:[(0,V.jsx)(`input`,{ref:M.commentInputRef,type:`text`,value:M.commentText,onChange:e=>M.setCommentText(e.target.value),onKeyDown:e=>{e.key===`Enter`&&ce(),e.key===`Escape`&&M.cancelComment()},placeholder:`Add a comment...`,className:`doc-editor__comment-input`,"aria-label":`Add comment on cell`}),(0,V.jsxs)(`div`,{className:`doc-editor__comment-actions`,children:[(0,V.jsx)(w,{variant:`primary`,size:`sm`,onClick:ce,disabled:!M.commentText.trim(),children:`Add`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:oe,onClick:M.cancelComment,"aria-label":`Cancel`})]})]}):null,(0,V.jsxs)(`table`,{className:`grid-editor__table`,role:`grid`,"aria-label":d,children:[(0,V.jsx)(`thead`,{children:(0,V.jsxs)(`tr`,{children:[(0,V.jsx)(`th`,{className:`grid-editor__row-header`}),f.map((e,t)=>(0,V.jsxs)(`th`,{className:`grid-editor__col-header`,style:{width:x[t]},children:[e,(0,V.jsx)(`div`,{className:`grid-editor__resize-handle`,onMouseDown:e=>ae(t,e),role:`separator`,"aria-orientation":`vertical`})]},t))]})}),(0,V.jsx)(`tbody`,{children:m.map((e,t)=>(0,V.jsxs)(`tr`,{children:[(0,V.jsxs)(`td`,{className:`grid-editor__row-header`,children:[(0,V.jsx)(`span`,{className:`grid-editor__row-num`,children:t+1}),m.length>1&&(0,V.jsx)(`button`,{className:`grid-editor__row-delete`,onClick:()=>F(t),"aria-label":`Delete row ${t+1}`,children:(0,V.jsx)(i,{size:12})})]}),e.map((e,n)=>{let r=g?.row===t&&g?.col===n;return(0,V.jsx)(`td`,{className:`grid-editor__cell ${r?`grid-editor__cell--active`:``}`,onClick:()=>!r&&N(t,n),role:`gridcell`,"aria-selected":r,style:{width:x[n]},children:r?(0,V.jsx)(`input`,{ref:b,type:`text`,className:`grid-editor__cell-input`,value:v,onChange:e=>y(e.target.value),onKeyDown:te,onBlur:P,"aria-label":`${f[n]} row ${t+1}`}):(0,V.jsx)(`span`,{className:`grid-editor__cell-text`,children:e})},n)})]},t))})]}),(0,V.jsxs)(`button`,{className:`grid-editor__add-row`,onClick:ne,"aria-label":`Add row`,children:[(0,V.jsx)(Oe,{size:14}),(0,V.jsx)(`span`,{children:`Add row`})]})]});return j.fullscreen?(0,V.jsxs)(`div`,{className:`editor-base-fullscreen`,children:[(0,V.jsxs)(`div`,{className:`editor-base-fullscreen__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base-fullscreen__title`,children:d}),de]}),(0,V.jsx)(`div`,{className:`editor-base-fullscreen__body`,style:{maxWidth:`none`},children:fe})]}):j.poppedOut?(0,V.jsx)(`div`,{className:`editor-base editor-base--popout`,children:(0,V.jsxs)(`div`,{className:`editor-base__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),(0,V.jsxs)(`div`,{className:`editor-base__actions`,children:[(0,V.jsx)(`span`,{className:`editor-base__status`,children:`Popped out`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:dt,onClick:j.handlePopIn,"aria-label":`Pop back in`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:rt,onClick:j.handleMinimise,"aria-label":`Close`})]})]})}):j.minimised?(0,V.jsx)(`div`,{className:`editor-base editor-base--minimised`,onClick:j.handleExpand,role:`button`,tabIndex:0,onKeyDown:e=>e.key===`Enter`&&j.handleExpand(),children:(0,V.jsxs)(`div`,{className:`editor-base__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),(0,V.jsxs)(`div`,{className:`editor-base__actions`,onClick:e=>e.stopPropagation(),children:[!le&&ue&&(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Fe,onClick:j.handlePopout,"aria-label":`Pop out`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:Qe,onClick:j.handleFullscreen,"aria-label":`Full screen`}),(0,V.jsx)(w,{variant:`ghost`,size:`sm`,icon:ct,onClick:j.handleExpand,"aria-label":`Expand`})]})]})}):(0,V.jsxs)(`div`,{className:`editor-base grid-editor`,children:[(0,V.jsxs)(`div`,{className:`editor-base__bar`,...j.dragBarProps,children:[(0,V.jsx)(`span`,{className:`editor-base__title`,children:d}),de]}),(0,V.jsx)(`div`,{className:`grid-editor__body`,children:fe})]})}var vT=Object.defineProperty,yT=Object.getOwnPropertySymbols,bT=Object.prototype.hasOwnProperty,xT=Object.prototype.propertyIsEnumerable,ST=(e,t,n)=>t in e?vT(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,CT=(e,t)=>{for(var n in t||={})bT.call(t,n)&&ST(e,n,t[n]);if(yT)for(var n of yT(t))xT.call(t,n)&&ST(e,n,t[n]);return e},wT=(e,t)=>{var n={};for(var r in e)bT.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&yT)for(var r of yT(e))t.indexOf(r)<0&&xT.call(e,r)&&(n[r]=e[r]);return n},TT;(e=>{let t=class t{constructor(e,n,r,a){if(this.version=e,this.errorCorrectionLevel=n,this.modules=[],this.isFunction=[],e<t.MIN_VERSION||e>t.MAX_VERSION)throw RangeError(`Version value out of range`);if(a<-1||a>7)throw RangeError(`Mask value out of range`);this.size=e*4+17;let o=[];for(let e=0;e<this.size;e++)o.push(!1);for(let e=0;e<this.size;e++)this.modules.push(o.slice()),this.isFunction.push(o.slice());this.drawFunctionPatterns();let s=this.addEccAndInterleave(r);if(this.drawCodewords(s),a==-1){let e=1e9;for(let t=0;t<8;t++){this.applyMask(t),this.drawFormatBits(t);let n=this.getPenaltyScore();n<e&&(a=t,e=n),this.applyMask(t)}}i(0<=a&&a<=7),this.mask=a,this.applyMask(a),this.drawFormatBits(a),this.isFunction=[]}static encodeText(n,r){let i=e.QrSegment.makeSegments(n);return t.encodeSegments(i,r)}static encodeBinary(n,r){let i=e.QrSegment.makeBytes(n);return t.encodeSegments([i],r)}static encodeSegments(e,r,a=1,s=40,c=-1,l=!0){if(!(t.MIN_VERSION<=a&&a<=s&&s<=t.MAX_VERSION)||c<-1||c>7)throw RangeError(`Invalid value`);let u,d;for(u=a;;u++){let n=t.getNumDataCodewords(u,r)*8,i=o.getTotalBits(e,u);if(i<=n){d=i;break}if(u>=s)throw RangeError(`Data too long`)}for(let e of[t.Ecc.MEDIUM,t.Ecc.QUARTILE,t.Ecc.HIGH])l&&d<=t.getNumDataCodewords(u,e)*8&&(r=e);let f=[];for(let t of e){n(t.mode.modeBits,4,f),n(t.numChars,t.mode.numCharCountBits(u),f);for(let e of t.getData())f.push(e)}i(f.length==d);let p=t.getNumDataCodewords(u,r)*8;i(f.length<=p),n(0,Math.min(4,p-f.length),f),n(0,(8-f.length%8)%8,f),i(f.length%8==0);for(let e=236;f.length<p;e^=253)n(e,8,f);let m=[];for(;m.length*8<f.length;)m.push(0);return f.forEach((e,t)=>m[t>>>3]|=e<<7-(t&7)),new t(u,r,m,c)}getModule(e,t){return 0<=e&&e<this.size&&0<=t&&t<this.size&&this.modules[t][e]}getModules(){return this.modules}drawFunctionPatterns(){for(let e=0;e<this.size;e++)this.setFunctionModule(6,e,e%2==0),this.setFunctionModule(e,6,e%2==0);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);let e=this.getAlignmentPatternPositions(),t=e.length;for(let n=0;n<t;n++)for(let r=0;r<t;r++)n==0&&r==0||n==0&&r==t-1||n==t-1&&r==0||this.drawAlignmentPattern(e[n],e[r]);this.drawFormatBits(0),this.drawVersion()}drawFormatBits(e){let t=this.errorCorrectionLevel.formatBits<<3|e,n=t;for(let e=0;e<10;e++)n=n<<1^(n>>>9)*1335;let a=(t<<10|n)^21522;i(a>>>15==0);for(let e=0;e<=5;e++)this.setFunctionModule(8,e,r(a,e));this.setFunctionModule(8,7,r(a,6)),this.setFunctionModule(8,8,r(a,7)),this.setFunctionModule(7,8,r(a,8));for(let e=9;e<15;e++)this.setFunctionModule(14-e,8,r(a,e));for(let e=0;e<8;e++)this.setFunctionModule(this.size-1-e,8,r(a,e));for(let e=8;e<15;e++)this.setFunctionModule(8,this.size-15+e,r(a,e));this.setFunctionModule(8,this.size-8,!0)}drawVersion(){if(this.version<7)return;let e=this.version;for(let t=0;t<12;t++)e=e<<1^(e>>>11)*7973;let t=this.version<<12|e;i(t>>>18==0);for(let e=0;e<18;e++){let n=r(t,e),i=this.size-11+e%3,a=Math.floor(e/3);this.setFunctionModule(i,a,n),this.setFunctionModule(a,i,n)}}drawFinderPattern(e,t){for(let n=-4;n<=4;n++)for(let r=-4;r<=4;r++){let i=Math.max(Math.abs(r),Math.abs(n)),a=e+r,o=t+n;0<=a&&a<this.size&&0<=o&&o<this.size&&this.setFunctionModule(a,o,i!=2&&i!=4)}}drawAlignmentPattern(e,t){for(let n=-2;n<=2;n++)for(let r=-2;r<=2;r++)this.setFunctionModule(e+r,t+n,Math.max(Math.abs(r),Math.abs(n))!=1)}setFunctionModule(e,t,n){this.modules[t][e]=n,this.isFunction[t][e]=!0}addEccAndInterleave(e){let n=this.version,r=this.errorCorrectionLevel;if(e.length!=t.getNumDataCodewords(n,r))throw RangeError(`Invalid argument`);let a=t.NUM_ERROR_CORRECTION_BLOCKS[r.ordinal][n],o=t.ECC_CODEWORDS_PER_BLOCK[r.ordinal][n],s=Math.floor(t.getNumRawDataModules(n)/8),c=a-s%a,l=Math.floor(s/a),u=[],d=t.reedSolomonComputeDivisor(o);for(let n=0,r=0;n<a;n++){let i=e.slice(r,r+l-o+(n<c?0:1));r+=i.length;let a=t.reedSolomonComputeRemainder(i,d);n<c&&i.push(0),u.push(i.concat(a))}let f=[];for(let e=0;e<u[0].length;e++)u.forEach((t,n)=>{(e!=l-o||n>=c)&&f.push(t[e])});return i(f.length==s),f}drawCodewords(e){if(e.length!=Math.floor(t.getNumRawDataModules(this.version)/8))throw RangeError(`Invalid argument`);let n=0;for(let t=this.size-1;t>=1;t-=2){t==6&&(t=5);for(let i=0;i<this.size;i++)for(let a=0;a<2;a++){let o=t-a,s=t+1&2?i:this.size-1-i;!this.isFunction[s][o]&&n<e.length*8&&(this.modules[s][o]=r(e[n>>>3],7-(n&7)),n++)}}i(n==e.length*8)}applyMask(e){if(e<0||e>7)throw RangeError(`Mask value out of range`);for(let t=0;t<this.size;t++)for(let n=0;n<this.size;n++){let r;switch(e){case 0:r=(n+t)%2==0;break;case 1:r=t%2==0;break;case 2:r=n%3==0;break;case 3:r=(n+t)%3==0;break;case 4:r=(Math.floor(n/3)+Math.floor(t/2))%2==0;break;case 5:r=n*t%2+n*t%3==0;break;case 6:r=(n*t%2+n*t%3)%2==0;break;case 7:r=((n+t)%2+n*t%3)%2==0;break;default:throw Error(`Unreachable`)}!this.isFunction[t][n]&&r&&(this.modules[t][n]=!this.modules[t][n])}}getPenaltyScore(){let e=0;for(let n=0;n<this.size;n++){let r=!1,i=0,a=[0,0,0,0,0,0,0];for(let o=0;o<this.size;o++)this.modules[n][o]==r?(i++,i==5?e+=t.PENALTY_N1:i>5&&e++):(this.finderPenaltyAddHistory(i,a),r||(e+=this.finderPenaltyCountPatterns(a)*t.PENALTY_N3),r=this.modules[n][o],i=1);e+=this.finderPenaltyTerminateAndCount(r,i,a)*t.PENALTY_N3}for(let n=0;n<this.size;n++){let r=!1,i=0,a=[0,0,0,0,0,0,0];for(let o=0;o<this.size;o++)this.modules[o][n]==r?(i++,i==5?e+=t.PENALTY_N1:i>5&&e++):(this.finderPenaltyAddHistory(i,a),r||(e+=this.finderPenaltyCountPatterns(a)*t.PENALTY_N3),r=this.modules[o][n],i=1);e+=this.finderPenaltyTerminateAndCount(r,i,a)*t.PENALTY_N3}for(let n=0;n<this.size-1;n++)for(let r=0;r<this.size-1;r++){let i=this.modules[n][r];i==this.modules[n][r+1]&&i==this.modules[n+1][r]&&i==this.modules[n+1][r+1]&&(e+=t.PENALTY_N2)}let n=0;for(let e of this.modules)n=e.reduce((e,t)=>e+(t?1:0),n);let r=this.size*this.size,a=Math.ceil(Math.abs(n*20-r*10)/r)-1;return i(0<=a&&a<=9),e+=a*t.PENALTY_N4,i(0<=e&&e<=2568888),e}getAlignmentPatternPositions(){if(this.version==1)return[];{let e=Math.floor(this.version/7)+2,t=this.version==32?26:Math.ceil((this.version*4+4)/(e*2-2))*2,n=[6];for(let r=this.size-7;n.length<e;r-=t)n.splice(1,0,r);return n}}static getNumRawDataModules(e){if(e<t.MIN_VERSION||e>t.MAX_VERSION)throw RangeError(`Version number out of range`);let n=(16*e+128)*e+64;if(e>=2){let t=Math.floor(e/7)+2;n-=(25*t-10)*t-55,e>=7&&(n-=36)}return i(208<=n&&n<=29648),n}static getNumDataCodewords(e,n){return Math.floor(t.getNumRawDataModules(e)/8)-t.ECC_CODEWORDS_PER_BLOCK[n.ordinal][e]*t.NUM_ERROR_CORRECTION_BLOCKS[n.ordinal][e]}static reedSolomonComputeDivisor(e){if(e<1||e>255)throw RangeError(`Degree out of range`);let n=[];for(let t=0;t<e-1;t++)n.push(0);n.push(1);let r=1;for(let i=0;i<e;i++){for(let e=0;e<n.length;e++)n[e]=t.reedSolomonMultiply(n[e],r),e+1<n.length&&(n[e]^=n[e+1]);r=t.reedSolomonMultiply(r,2)}return n}static reedSolomonComputeRemainder(e,n){let r=n.map(e=>0);for(let i of e){let e=i^r.shift();r.push(0),n.forEach((n,i)=>r[i]^=t.reedSolomonMultiply(n,e))}return r}static reedSolomonMultiply(e,t){if(e>>>8||t>>>8)throw RangeError(`Byte out of range`);let n=0;for(let r=7;r>=0;r--)n=n<<1^(n>>>7)*285,n^=(t>>>r&1)*e;return i(n>>>8==0),n}finderPenaltyCountPatterns(e){let t=e[1];i(t<=this.size*3);let n=t>0&&e[2]==t&&e[3]==t*3&&e[4]==t&&e[5]==t;return(n&&e[0]>=t*4&&e[6]>=t?1:0)+(n&&e[6]>=t*4&&e[0]>=t?1:0)}finderPenaltyTerminateAndCount(e,t,n){return e&&(this.finderPenaltyAddHistory(t,n),t=0),t+=this.size,this.finderPenaltyAddHistory(t,n),this.finderPenaltyCountPatterns(n)}finderPenaltyAddHistory(e,t){t[0]==0&&(e+=this.size),t.pop(),t.unshift(e)}};t.MIN_VERSION=1,t.MAX_VERSION=40,t.PENALTY_N1=3,t.PENALTY_N2=3,t.PENALTY_N3=40,t.PENALTY_N4=10,t.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],t.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],e.QrCode=t;function n(e,t,n){if(t<0||t>31||e>>>t)throw RangeError(`Value out of range`);for(let r=t-1;r>=0;r--)n.push(e>>>r&1)}function r(e,t){return(e>>>t&1)!=0}function i(e){if(!e)throw Error(`Assertion error`)}let a=class e{constructor(e,t,n){if(this.mode=e,this.numChars=t,this.bitData=n,t<0)throw RangeError(`Invalid argument`);this.bitData=n.slice()}static makeBytes(t){let r=[];for(let e of t)n(e,8,r);return new e(e.Mode.BYTE,t.length,r)}static makeNumeric(t){if(!e.isNumeric(t))throw RangeError(`String contains non-numeric characters`);let r=[];for(let e=0;e<t.length;){let i=Math.min(t.length-e,3);n(parseInt(t.substring(e,e+i),10),i*3+1,r),e+=i}return new e(e.Mode.NUMERIC,t.length,r)}static makeAlphanumeric(t){if(!e.isAlphanumeric(t))throw RangeError(`String contains unencodable characters in alphanumeric mode`);let r=[],i;for(i=0;i+2<=t.length;i+=2){let a=e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(i))*45;a+=e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(i+1)),n(a,11,r)}return i<t.length&&n(e.ALPHANUMERIC_CHARSET.indexOf(t.charAt(i)),6,r),new e(e.Mode.ALPHANUMERIC,t.length,r)}static makeSegments(t){return t==``?[]:e.isNumeric(t)?[e.makeNumeric(t)]:e.isAlphanumeric(t)?[e.makeAlphanumeric(t)]:[e.makeBytes(e.toUtf8ByteArray(t))]}static makeEci(t){let r=[];if(t<0)throw RangeError(`ECI assignment value out of range`);if(t<128)n(t,8,r);else if(t<16384)n(2,2,r),n(t,14,r);else if(t<1e6)n(6,3,r),n(t,21,r);else throw RangeError(`ECI assignment value out of range`);return new e(e.Mode.ECI,0,r)}static isNumeric(t){return e.NUMERIC_REGEX.test(t)}static isAlphanumeric(t){return e.ALPHANUMERIC_REGEX.test(t)}getData(){return this.bitData.slice()}static getTotalBits(e,t){let n=0;for(let r of e){let e=r.mode.numCharCountBits(t);if(r.numChars>=1<<e)return 1/0;n+=4+e+r.bitData.length}return n}static toUtf8ByteArray(e){e=encodeURI(e);let t=[];for(let n=0;n<e.length;n++)e.charAt(n)==`%`?(t.push(parseInt(e.substring(n+1,n+3),16)),n+=2):t.push(e.charCodeAt(n));return t}};a.NUMERIC_REGEX=/^[0-9]*$/,a.ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,a.ALPHANUMERIC_CHARSET=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:`;let o=a;e.QrSegment=a})(TT||={}),(e=>{(e=>{let t=class{constructor(e,t){this.ordinal=e,this.formatBits=t}};t.LOW=new t(0,1),t.MEDIUM=new t(1,0),t.QUARTILE=new t(2,3),t.HIGH=new t(3,2),e.Ecc=t})(e.QrCode||={})})(TT||={}),(e=>{(e=>{let t=class{constructor(e,t){this.modeBits=e,this.numBitsCharCount=t}numCharCountBits(e){return this.numBitsCharCount[Math.floor((e+7)/17)]}};t.NUMERIC=new t(1,[10,12,14]),t.ALPHANUMERIC=new t(2,[9,11,13]),t.BYTE=new t(4,[8,16,16]),t.KANJI=new t(8,[8,10,12]),t.ECI=new t(7,[0,0,0]),e.Mode=t})(e.QrSegment||={})})(TT||={});var ET=TT,DT={L:ET.QrCode.Ecc.LOW,M:ET.QrCode.Ecc.MEDIUM,Q:ET.QrCode.Ecc.QUARTILE,H:ET.QrCode.Ecc.HIGH},OT=128,kT=`L`,AT=`#FFFFFF`,jT=`#000000`,MT=!1,NT=1,PT=4,FT=0,IT=.1;function LT(e,t=0){let n=[];return e.forEach(function(e,r){let i=null;e.forEach(function(a,o){if(!a&&i!==null){n.push(`M${i+t} ${r+t}h${o-i}v1H${i+t}z`),i=null;return}if(o===e.length-1){if(!a)return;i===null?n.push(`M${o+t},${r+t} h1v1H${o+t}z`):n.push(`M${i+t},${r+t} h${o+1-i}v1H${i+t}z`);return}a&&i===null&&(i=o)})}),n.join(``)}function RT(e,t){return e.slice().map((e,n)=>n<t.y||n>=t.y+t.h?e:e.map((e,n)=>n<t.x||n>=t.x+t.w?e:!1))}function zT(e,t,n,r){if(r==null)return null;let i=e.length+n*2,a=Math.floor(t*IT),o=i/t,s=(r.width||a)*o,c=(r.height||a)*o,l=r.x==null?e.length/2-s/2:r.x*o,u=r.y==null?e.length/2-c/2:r.y*o,d=r.opacity==null?1:r.opacity,f=null;if(r.excavate){let e=Math.floor(l),t=Math.floor(u);f={x:e,y:t,w:Math.ceil(s+l-e),h:Math.ceil(c+u-t)}}let p=r.crossOrigin;return{x:l,y:u,h:c,w:s,excavation:f,opacity:d,crossOrigin:p}}function BT(e,t){return t==null?e?PT:FT:Math.max(Math.floor(t),0)}function VT({value:e,level:t,minVersion:n,includeMargin:r,marginSize:i,imageSettings:a,size:o,boostLevel:s}){let c=B.useMemo(()=>{let r=(Array.isArray(e)?e:[e]).reduce((e,t)=>(e.push(...ET.QrSegment.makeSegments(t)),e),[]);return ET.QrCode.encodeSegments(r,DT[t],n,void 0,void 0,s)},[e,t,n,s]),{cells:l,margin:u,numCells:d,calculatedImageSettings:f}=B.useMemo(()=>{let e=c.getModules(),t=BT(r,i);return{cells:e,margin:t,numCells:e.length+t*2,calculatedImageSettings:zT(e,o,t,a)}},[c,o,a,r,i]);return{qrcode:c,margin:u,cells:l,numCells:d,calculatedImageSettings:f}}var HT=function(){try{new Path2D().addPath(new Path2D)}catch{return!1}return!0}(),UT=B.forwardRef(function(e,t){let n=e,{value:r,size:i=OT,level:a=kT,bgColor:o=AT,fgColor:s=jT,includeMargin:c=MT,minVersion:l=NT,boostLevel:u,marginSize:d,imageSettings:f}=n,p=wT(n,[`value`,`size`,`level`,`bgColor`,`fgColor`,`includeMargin`,`minVersion`,`boostLevel`,`marginSize`,`imageSettings`]),{style:m}=p,h=wT(p,[`style`]),g=f?.src,_=B.useRef(null),v=B.useRef(null),y=B.useCallback(e=>{_.current=e,typeof t==`function`?t(e):t&&(t.current=e)},[t]),[b,x]=B.useState(!1),{margin:S,cells:C,numCells:w,calculatedImageSettings:T}=VT({value:r,level:a,minVersion:l,boostLevel:u,includeMargin:c,marginSize:d,imageSettings:f,size:i});B.useEffect(()=>{if(_.current!=null){let e=_.current,t=e.getContext(`2d`);if(!t)return;let n=C,r=v.current,a=T!=null&&r!==null&&r.complete&&r.naturalHeight!==0&&r.naturalWidth!==0;a&&T.excavation!=null&&(n=RT(C,T.excavation));let c=window.devicePixelRatio||1;e.height=e.width=i*c;let l=i/w*c;t.scale(l,l),t.fillStyle=o,t.fillRect(0,0,w,w),t.fillStyle=s,HT?t.fill(new Path2D(LT(n,S))):C.forEach(function(e,n){e.forEach(function(e,r){e&&t.fillRect(r+S,n+S,1,1)})}),T&&(t.globalAlpha=T.opacity),a&&t.drawImage(r,T.x+S,T.y+S,T.w,T.h)}}),B.useEffect(()=>{x(!1)},[g]);let E=CT({height:i,width:i},m),D=null;return g!=null&&(D=B.createElement(`img`,{src:g,key:g,style:{display:`none`},onLoad:()=>{x(!0)},ref:v,crossOrigin:T?.crossOrigin})),B.createElement(B.Fragment,null,B.createElement(`canvas`,CT({style:E,height:i,width:i,ref:y,role:`img`},h)),D)});UT.displayName=`QRCodeCanvas`;var WT=B.forwardRef(function(e,t){let n=e,{value:r,size:i=OT,level:a=kT,bgColor:o=AT,fgColor:s=jT,includeMargin:c=MT,minVersion:l=NT,boostLevel:u,title:d,marginSize:f,imageSettings:p}=n,m=wT(n,[`value`,`size`,`level`,`bgColor`,`fgColor`,`includeMargin`,`minVersion`,`boostLevel`,`title`,`marginSize`,`imageSettings`]),{margin:h,cells:g,numCells:_,calculatedImageSettings:v}=VT({value:r,level:a,minVersion:l,boostLevel:u,includeMargin:c,marginSize:f,imageSettings:p,size:i}),y=g,b=null;p!=null&&v!=null&&(v.excavation!=null&&(y=RT(g,v.excavation)),b=B.createElement(`image`,{href:p.src,height:v.h,width:v.w,x:v.x+h,y:v.y+h,preserveAspectRatio:`none`,opacity:v.opacity,crossOrigin:v.crossOrigin}));let x=LT(y,h);return B.createElement(`svg`,CT({height:i,width:i,viewBox:`0 0 ${_} ${_}`,ref:t,role:`img`},m),!!d&&B.createElement(`title`,null,d),B.createElement(`path`,{fill:o,d:`M0,0 h${_}v${_}H0z`,shapeRendering:`crispEdges`}),B.createElement(`path`,{fill:s,d:x,shapeRendering:`crispEdges`}),b)});WT.displayName=`QRCodeSVG`;function GT({data:e,onSubmit:t,submitted:n}){let r=e,i=(0,B.useRef)(!1),a=r?.value?.trim()??``;return(0,B.useEffect)(()=>{a&&!n&&!i.current&&(i.current=!0,t(``))},[a,n,t]),a?(0,V.jsxs)(`div`,{className:`qr-code`,children:[(0,V.jsx)(`div`,{className:`qr-code__canvas`,children:(0,V.jsx)(WT,{value:a,size:240,level:`M`,bgColor:`#ffffff`,fgColor:`#000000`})}),r?.label&&(0,V.jsx)(`div`,{className:`qr-code__label`,children:r.label})]}):(0,V.jsx)(`div`,{className:`qr-code qr-code--error`,children:`No QR data provided. Try again or ask the agent to generate a new QR code.`})}function KT(e){return e===0?`0 B`:e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function qT(e){return e.startsWith(`image/`)?(0,V.jsx)(ze,{size:18}):e===`application/pdf`?(0,V.jsx)(c,{size:18}):e===`text/calendar`?(0,V.jsx)(Te,{size:18}):e.startsWith(`text/`)?(0,V.jsx)(E,{size:18}):e===`application/zip`||e===`application/x-zip-compressed`?(0,V.jsx)(Ie,{size:18}):(0,V.jsx)(le,{size:18})}function JT({data:e,onSubmit:t,submitted:n,sessionKey:r}){let i=e,a=(0,B.useRef)(!1),o=!!(i?.attachmentId&&i?.filename);(0,B.useEffect)(()=>{o&&!n&&!a.current&&(a.current=!0,t(JSON.stringify({_lifecycle:!0,component:`file-attachment`,event:`rendered`,attachmentId:i.attachmentId,filename:i.filename})))},[o,n,t,i]);let s=(0,B.useCallback)(()=>{if(!i?.attachmentId||!r)return;let e=`/api/admin/attachment/${i.attachmentId}?session_key=${encodeURIComponent(r)}`,t=document.createElement(`a`);t.href=e,t.download=i.filename,t.click()},[i,r]);return o?(0,V.jsx)(O,{submitted:!1,submittedLabel:`Downloaded`,actions:[{label:`Download`,variant:`primary`,onClick:s,disabled:!r}],children:(0,V.jsxs)(`div`,{className:`file-attachment`,children:[(0,V.jsx)(`div`,{className:`file-attachment__icon`,children:qT(i.mimeType)}),(0,V.jsxs)(`div`,{className:`file-attachment__info`,children:[(0,V.jsx)(`div`,{className:`file-attachment__name`,title:i.filename,children:i.filename}),(0,V.jsxs)(`div`,{className:`file-attachment__meta`,children:[KT(i.sizeBytes),` · `,i.mimeType]})]}),(0,V.jsx)(`button`,{className:`file-attachment__download`,onClick:s,disabled:!r,title:`Download file`,children:(0,V.jsx)(L,{size:16})})]})}):null}var YT=/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/,XT=/^[a-z0-9-]$/;function ZT(e){return e?YT.test(e):!1}function QT(e){let t=e.toLowerCase(),n=``;for(let e of t)XT.test(e)&&(n+=e);for(;n.startsWith(`-`);)n=n.slice(1);return n}function $T(e){return[{key:`length`,label:`At least 8 characters`,met:e.length>=8},{key:`number`,label:`Contains a number`,met:/\d/.test(e)},{key:`special`,label:`Contains a special character`,met:/[^A-Za-z0-9]/.test(e)},{key:`whitespace`,label:`No spaces`,met:e.length>0&&!/\s/.test(e)}]}var eE=/https:\/\/dash\.cloudflare\.com\/argotunnel\?[^\s]+/,tE=/^OAUTH_URL:\s*(\S+)/,nE=/result=error\s+reason=([a-z0-9-]+)/;function rE(e){let t=e.match(tE);if(t)return t[1];let n=e.match(eE);return n?n[0]:null}function iE(e){let t=e.match(nE);return t?t[1]:null}var aE=/\[(\d+)\/(\d+)\]/,oE=2e3,sE=9e4;function cE(e){if(!e)return null;let t=e.match(aE);return t?parseInt(t[1],10):null}function lE({actionId:e,sessionKey:t,onExit:n,maxLines:r=1e3,selfRestart:i}){let[a,o]=(0,B.useState)([]),[s,c]=(0,B.useState)(null),[u,d]=(0,B.useState)(null),[f,p]=(0,B.useState)(null),[m,h]=(0,B.useState)(null),[g,_]=(0,B.useState)({phase:`idle`}),[v,y]=(0,B.useState)(!1),[b,x]=(0,B.useState)(null),S=(0,B.useRef)(null),C=(0,B.useRef)(null),w=(0,B.useRef)(0),T=(0,B.useRef)(null),E=(0,B.useRef)(null),O=(0,B.useRef)(null),k=(0,B.useRef)(null),A=(0,B.useRef)(null),j=(0,B.useRef)(null),M=(0,B.useRef)(n);M.current=n;let N=(0,B.useCallback)(()=>{A.current&&=(clearInterval(A.current),null),j.current&&=(clearTimeout(j.current),null)},[]),P=(0,B.useCallback)(e=>{e&&(S.current=e,x(e))},[]),ee=(0,B.useCallback)(async()=>{if(m){_({phase:`respawning`});try{let e=await fetch(`/api/admin/device-browser/navigate`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({url:m,intent:`open Cloudflare authorisation page`,hostname:``})}),t=await e.json().catch(()=>({}));if(e.ok&&t.ok){_({phase:`respawned`}),window.setTimeout(()=>_({phase:`idle`}),2500);return}_({phase:`failed`,reason:(t.navigateResult??t.detail??`navigation failed`).slice(0,80)})}catch(e){_({phase:`failed`,reason:(e instanceof Error?e.message:String(e)).slice(0,80)})}}},[m]),te=(0,B.useCallback)(()=>{let n=w.current>0?`&from=${w.current}`:``,a=new EventSource(`/api/admin/actions/${encodeURIComponent(e)}/stream?session_key=${encodeURIComponent(t)}${n}`);T.current=a,a.addEventListener(`line`,e=>{try{let t=JSON.parse(e.data);if(w.current=t.byteOffset,o(e=>{let n=[...e,t];return n.length>r&&n.splice(0,n.length-r),n}),!m){let e=rE(t.text);e&&h(e)}let n=t.text.match(aE);n&&P(n[0]);let i=iE(t.text);i&&(C.current=i),p(null)}catch(e){console.error(`[ActionLogPanel] line parse failed:`,e)}}),a.addEventListener(`heartbeat`,e=>{try{let t=JSON.parse(e.data);O.current=t,c(t),P(t.last_phase),p(null)}catch(e){console.error(`[ActionLogPanel] heartbeat parse failed:`,e)}}),a.addEventListener(`exit`,e=>{try{let t=JSON.parse(e.data);d(t),M.current?.(t,C.current)}catch(e){console.error(`[ActionLogPanel] exit parse failed:`,e)}finally{a.close(),T.current=null,N(),y(!1)}}),a.onerror=()=>{if(u)return;a.close(),T.current=null;let e=cE(S.current);if(i&&e!==null&&e>=i.atPhase&&k.current!==null){console.log(`[ActionLogPanel] SSE drop during self-restart window (phase=${S.current}) — banner suppressed`),p(null),y(!0),ne();return}p(`Connection lost — reconnecting…`),setTimeout(()=>{u||te()},1500)}},[e,t,r,i?.atPhase,N]);function ne(){N(),A.current=setInterval(async()=>{try{let e=await fetch(`/api/admin/version`,{cache:`no-store`});if(!e.ok)return;let t=(await e.json())?.installed,n=k.current;t&&n&&t!==n&&(console.log(`[ActionLogPanel] admin-server version changed ${n}→${t} — reconnecting stream`),N(),y(!1),k.current=t,te())}catch{}},oE),j.current=setTimeout(()=>{console.log(`[ActionLogPanel] self-restart window timeout (${sE}ms) — reverting to error banner`),N(),y(!1),p(`New version did not come up — reconnecting…`),setTimeout(()=>{u||te()},1500)},sE)}(0,B.useEffect)(()=>(te(),()=>{T.current?.close(),T.current=null,N()}),[te,N]),(0,B.useEffect)(()=>{if(!i)return;let e=!1;return(async()=>{try{let t=await fetch(`/api/admin/version`,{cache:`no-store`});if(!t.ok)return;let n=await t.json();!e&&typeof n?.installed==`string`&&(k.current=n.installed)}catch{}})(),()=>{e=!0}},[e,i?.atPhase]),(0,B.useEffect)(()=>{let e=E.current;e&&e.scrollHeight-e.scrollTop-e.clientHeight<80&&(e.scrollTop=e.scrollHeight)},[a]);let F=e=>new Date(e).toLocaleTimeString(void 0,{hour12:!1}),I=s?Math.floor(s.elapsed_since_last_line_ms/1e3):0,re=!u&&(f!==null||v),ie=re?`#666`:void 0,ae=!u&&!re&&s&&I>=5;return(0,V.jsxs)(`div`,{className:`action-log-panel`,style:{display:`flex`,flexDirection:`column`,height:`100%`,background:`#0a0a0a`,color:`#e8e8e8`,borderRadius:4,overflow:`hidden`,fontFamily:`ui-monospace, monospace`,fontSize:12},children:[(0,V.jsxs)(`div`,{style:{padding:`6px 10px`,borderBottom:`1px solid #222`,display:`flex`,gap:12,alignItems:`center`,flexWrap:`wrap`,fontSize:11},children:[(0,V.jsx)(`span`,{style:{color:`#888`},children:`action:`}),(0,V.jsx)(`span`,{children:e}),s&&(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{style:{color:`#888`,marginLeft:`auto`},children:`state:`}),(0,V.jsx)(`span`,{style:{color:ie},children:s.systemd_state}),b&&(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{style:{color:`#888`},children:`phase:`}),(0,V.jsx)(`span`,{style:{color:ie},children:b})]}),re&&(0,V.jsx)(`span`,{style:{color:`#888`,fontStyle:`italic`},children:`(stale)`}),ae&&(0,V.jsxs)(`span`,{style:{color:`#e4a657`,display:`inline-flex`,alignItems:`center`,gap:4},children:[(0,V.jsx)(l,{size:11}),` silent `,I,`s`]})]})]}),m&&!u&&(0,V.jsxs)(`div`,{style:{padding:`8px 10px`,borderBottom:`1px solid #222`,background:`#1b1f2b`,display:`flex`,alignItems:`center`,gap:8,flexWrap:`wrap`},children:[(0,V.jsx)(`span`,{style:{color:`#cbd5f5`},children:`Authorise this device on the Pi’s browser — click the zone, then Authorize.`}),(0,V.jsxs)(`button`,{type:`button`,onClick:ee,disabled:g.phase===`respawning`,style:{marginLeft:`auto`,color:`#fff`,background:`#f6821f`,padding:`4px 10px`,borderRadius:3,border:`none`,cursor:g.phase===`respawning`?`wait`:`pointer`,display:`inline-flex`,alignItems:`center`,gap:6,fontSize:11,opacity:g.phase===`respawning`?.7:1},title:`Re-opens the Cloudflare page on the Pi's VNC browser`,children:[(0,V.jsx)(D,{size:12}),g.phase===`respawning`?`Re-opening on Pi…`:g.phase===`respawned`?`Re-opened on Pi`:`Re-open on Pi browser`]}),g.phase===`failed`&&(0,V.jsxs)(`span`,{style:{width:`100%`,color:`#ffc987`,fontSize:11,marginTop:4},children:[`Could not re-open on Pi: `,g.reason,`. The page should still be on the Pi VNC from the initial spawn.`]})]}),f&&!v&&(0,V.jsxs)(`div`,{style:{padding:`6px 10px`,background:`#3a2b10`,color:`#ffc987`,display:`flex`,alignItems:`center`,gap:8},children:[(0,V.jsx)(ge,{size:12,className:`spin`}),` `,f]}),v&&(0,V.jsxs)(`div`,{style:{padding:`6px 10px`,background:`#132319`,color:`#9aeab0`,display:`flex`,alignItems:`center`,gap:8},children:[(0,V.jsx)(ge,{size:12,className:`spin`}),` Waiting for new version…`]}),(0,V.jsxs)(`div`,{ref:E,style:{flex:1,overflow:`auto`,padding:`6px 10px`,lineHeight:1.45,whiteSpace:`pre-wrap`,wordBreak:`break-word`},children:[a.length===0&&!u&&(0,V.jsx)(`div`,{style:{color:`#888`},children:`Waiting for output…`}),a.map(e=>(0,V.jsxs)(`div`,{style:{display:`flex`,gap:10,color:e.stream===`stderr`?`#ff9999`:`#e8e8e8`},children:[(0,V.jsx)(`span`,{style:{color:`#666`,flexShrink:0},children:F(e.ts)}),(0,V.jsx)(`span`,{children:e.text})]},e.byteOffset))]}),u&&(0,V.jsxs)(`div`,{style:{padding:`8px 10px`,borderTop:`1px solid #222`,background:u.code===0?`#14331b`:`#3a1717`,color:u.code===0?`#9aeab0`:`#ff9999`,display:`flex`,alignItems:`center`,gap:8},children:[u.code===0?(0,V.jsx)(De,{size:13}):(0,V.jsx)(l,{size:13}),(0,V.jsxs)(`span`,{children:[u.code===0?`Completed`:`Failed (exit ${u.code})`,` · `,Math.round(u.duration_ms/1e3),`s`]})]})]})}var uE={title:`Authorise the tunnel in your own browser`,intro:`The Pi's browser couldn't drive the Cloudflare consent page automatically. Open the dashboard in your own browser and follow these steps:`,steps:[`The "Authorize Cloudflare Tunnel" page shows every zone on the currently-active account.`,`Click the zone you want the tunnel to be able to route DNS for.`,`Click Authorize. The browser closes or shows "You can close this page."`,`Return here and click "Try again" — the cert will land and setup will continue.`],footnote:`If the account shown in the top-left of the dashboard is not the one that owns your zone, click the account-name dropdown first and switch accounts before authorising.`},dE=18e4,fE=4096;function pE(e){let t=new TextEncoder().encode(e);return t.length<=fE?e:`${new TextDecoder(`utf-8`,{fatal:!1}).decode(t.slice(0,fE))}\n… ${t.length-fE} bytes truncated (total ${t.length} bytes)`}function mE({data:e,onSubmit:t,submitted:n,sessionKey:r}){let i=e,[a,o]=(0,B.useState)({status:`loading`}),[s,c]=(0,B.useState)(``),[l,u]=(0,B.useState)(``),[d,f]=(0,B.useState)(``),[p,m]=(0,B.useState)(``),[h,g]=(0,B.useState)(``),[_,v]=(0,B.useState)(``),[y,b]=(0,B.useState)(!1),[x,S]=(0,B.useState)(!1),[C,w]=(0,B.useState)(!1),[T,E]=(0,B.useState)(null),[D,k]=(0,B.useState)(null),[A,j]=(0,B.useState)(null),M=(0,B.useRef)(null),N=(0,B.useRef)(new Set),P=(0,B.useCallback)(async()=>{if(!r){o({status:`error`,field:`session`,message:`No session key available — refresh the page.`});return}o({status:`loading`});try{let e=await(await fetch(`/api/admin/cloudflare/domains?session_key=${encodeURIComponent(r)}`,{method:`GET`,headers:{Accept:`application/json`}})).json();if(!e.ok){o({status:`error`,field:e.field,message:e.message,output:e.output,correlationId:e.correlationId,streamLogPath:e.streamLogPath});return}if(e.domains.length===0){o({status:`empty`});return}o({status:`populated`,domains:e.domains}),u(t=>t||e.domains[0]),m(t=>t||e.domains[0])}catch(e){o({status:`error`,field:`script`,message:e instanceof Error?e.message:`Network error loading domains.`})}},[r]);(0,B.useEffect)(()=>{P()},[P]),(0,B.useEffect)(()=>()=>{M.current&&clearTimeout(M.current)},[]);let ee=a.status===`populated`?a.domains:[],te=e=>{n||x||(c(QT(e)),j(null))},ne=e=>{n||x||(f(QT(e)),j(null))},F=ZT(s)&&l.length>0,I=d!==``,re=!I||ZT(d)&&p.length>0,ie=F?`${s.replace(/-+$/,``)}.${l}`:``,ae=I&&re?`${d.replace(/-+$/,``)}.${p}`:``,oe=!(ae&&ae===ie),se=$T(_),L=se.every(e=>e.met),ce=a.status===`populated`&&F&&re&&oe&&L&&!x,le=s!==``&&!ZT(s)?`Use lowercase letters, numbers, and hyphens. Start and end with a letter or number.`:null,ue=I&&!ZT(d)?`Use lowercase letters, numbers, and hyphens. Start and end with a letter or number.`:oe?null:`Public address must differ from the admin address.`,de=A?.field===`admin`?A.message:null,fe=A?.field===`public`?A.message:null,pe=A?.field===`password`?A.message:null,me=A?.field===`script`||A?.field===`request`?A.message:null,he=()=>{w(!1),j(null),S(!1)},ge=async()=>{if(!ce)return;if(!r){j({field:`request`,message:`No session key available — refresh the page.`});return}S(!0),j(null),w(!1);let e=new AbortController;M.current=setTimeout(()=>{e.abort(),w(!0)},dE);let n={session_key:r,adminLabel:s.replace(/-+$/,``),adminDomain:l,password:_};I&&(n.publicLabel=d.replace(/-+$/,``),n.publicDomain=p),h&&(n.apex=h);try{let r=await fetch(`/api/admin/cloudflare/setup`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(n),signal:e.signal});M.current&&clearTimeout(M.current),M.current=null;let i=await r.json();if(!i.ok){j({field:i.field,message:i.message,output:i.output,correlationId:i.correlationId,streamLogPath:i.streamLogPath});let e=i.streamLogPath?`\n\nstream log: ${i.streamLogPath}`:``;t(i.output&&i.output.length>0?`Cloudflare setup failed: ${i.message}\n\n${i.output}${e}`:`Cloudflare setup failed: ${i.message}${e}`),S(!1);return}if(i.actionId){E(i.actionId);return}t(i.output)}catch(t){if(M.current&&clearTimeout(M.current),M.current=null,e.signal.aborted)return;j({field:`script`,message:t instanceof Error?t.message:`Network error — try again.`}),S(!1)}},_e=(0,B.useMemo)(()=>s?`${s}.${l||`your-domain`}`:`your-name.${l||`your-domain`}`,[s,l]);if(a.status===`loading`)return(0,V.jsx)(O,{submitted:!1,actions:[],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[i?.title&&(0,V.jsx)(`div`,{className:`form-input__title`,children:i.title}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`Reading the domains on your Cloudflare account…`})]})});if(a.status===`empty`)return(0,V.jsx)(O,{submitted:!1,actions:[{label:`Retry`,variant:`primary`,onClick:P}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:`No domains on this Cloudflare account`}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`Add a domain in the Cloudflare dashboard first, then click Retry.`}),(0,V.jsxs)(`ol`,{className:`form-input__field-desc`,style:{margin:0,paddingLeft:20},children:[(0,V.jsxs)(`li`,{children:[`With the correct account active (top-left), click `,(0,V.jsx)(`strong`,{children:`Websites`}),` in the left-hand sidebar.`]}),(0,V.jsxs)(`li`,{children:[`Click the `,(0,V.jsx)(`strong`,{children:`Add a site`}),` button.`]}),(0,V.jsxs)(`li`,{children:[`Enter the bare domain (e.g. `,(0,V.jsx)(`code`,{children:`example.com`}),`) and click `,(0,V.jsx)(`strong`,{children:`Continue`}),`.`]}),(0,V.jsxs)(`li`,{children:[`Review Cloudflare's imported DNS records — preserve website (`,(0,V.jsx)(`code`,{children:`A`}),`), email (`,(0,V.jsx)(`code`,{children:`MX`}),`), and verification (`,(0,V.jsx)(`code`,{children:`TXT`}),`) entries.`]}),(0,V.jsx)(`li`,{children:`Copy Cloudflare's two nameservers and set them on your domain registrar.`}),(0,V.jsxs)(`li`,{children:[`Return to Cloudflare and click `,(0,V.jsx)(`strong`,{children:`Check nameservers`}),`. Wait for the zone to show `,(0,V.jsx)(`strong`,{children:`Active`}),`.`]})]})]})});if(a.status===`error`){let e=a.field===`dashboard`,t=e?`Not signed into Cloudflare on this device`:`Could not read domains from Cloudflare`,n=e?`Sign in again at the Cloudflare dashboard in the VNC browser, then click Retry. If the VNC browser is not open, ask me to run vnc.sh restart.`:a.message;return(0,V.jsx)(O,{submitted:!1,actions:[{label:`Retry`,variant:`primary`,onClick:P}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:t}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:n}),a.output&&a.output.length>0&&(0,V.jsx)(`pre`,{style:{marginTop:8,padding:8,maxHeight:280,overflow:`auto`,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:12,lineHeight:1.4,whiteSpace:`pre-wrap`,wordBreak:`break-word`,background:`var(--surface-2, rgba(0,0,0,0.04))`,borderRadius:4},children:pE(a.output)}),(a.correlationId||a.streamLogPath)&&(0,V.jsxs)(`div`,{style:{marginTop:8,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:11,color:`var(--text-secondary)`,wordBreak:`break-all`},children:[a.correlationId&&(0,V.jsxs)(`div`,{children:[`conversationId: `,a.correlationId]}),a.streamLogPath&&(0,V.jsxs)(`div`,{children:[`stream log: `,a.streamLogPath]})]})]})})}return D?(0,V.jsx)(O,{submitted:!1,actions:[{label:`Try again`,variant:`primary`,onClick:()=>{k(null),E(null),j(null),S(!1),w(!1)}}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:D.card.title}),(0,V.jsx)(`div`,{className:`form-input__desc`,style:{whiteSpace:`pre-wrap`},children:D.card.intro}),(0,V.jsx)(`ol`,{style:{marginTop:10,paddingLeft:20,lineHeight:1.6},children:D.card.steps.map((e,t)=>(0,V.jsx)(`li`,{children:e},t))}),D.card.footnote&&(0,V.jsx)(`div`,{style:{marginTop:10,fontStyle:`italic`,color:`#666`},children:D.card.footnote})]})}):T&&r?(0,V.jsx)(O,{submitted:!1,actions:[],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[i?.title&&(0,V.jsx)(`div`,{className:`form-input__title`,children:i.title}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`Cloudflare setup in progress — keep this panel open until it completes.`}),(0,V.jsx)(`div`,{style:{marginTop:10,height:360},children:(0,V.jsx)(lE,{actionId:T,sessionKey:r,onExit:(e,n)=>{if(N.current.has(T)){console.log(`[CloudflareSetupForm] suppressed duplicate completion dispatch actionId=${T}`);return}if(N.current.add(T),e.code===0){t(`Cloudflare setup completed (actionId: ${T}).`);return}if(n===`authorize-button-not-found`){k({card:uE,actionId:T,exitCode:e.code});return}t(`Cloudflare setup failed with exit code ${e.code} (actionId: ${T}).`)}})})]})}):C?(0,V.jsx)(O,{submitted:!1,actions:[{label:`Reset form`,variant:`ghost`,onClick:he}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[(0,V.jsx)(`div`,{className:`form-input__title`,children:`Setup is taking longer than expected`}),(0,V.jsx)(`div`,{className:`form-input__desc`,children:`The request is still running on the device — check the chat for live progress. Do not resubmit. If the script fails, the error will appear in chat and you can retry from there.`})]})}):(0,V.jsx)(O,{submitted:n,submittedLabel:`Submitting…`,actions:[{label:x?`Setting up…`:i?.submitLabel??`Set up Cloudflare`,variant:`primary`,disabled:!ce,onClick:ge}],children:(0,V.jsxs)(`div`,{className:`form-input`,children:[i?.title&&(0,V.jsx)(`div`,{className:`form-input__title`,children:i.title}),i?.description&&(0,V.jsx)(`div`,{className:`form-input__desc`,children:i.description}),(0,V.jsxs)(`div`,{className:`form-input__fields`,children:[(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-admin-label`,children:[`Admin address`,(0,V.jsx)(`span`,{className:`form-input__required`,children:`*`})]}),(0,V.jsxs)(`div`,{className:`tunnel-route__row`,children:[(0,V.jsx)(`input`,{id:`cf-admin-label`,className:`form-input__input tunnel-route__input`,type:`text`,autoCapitalize:`none`,autoComplete:`off`,autoCorrect:`off`,spellCheck:!1,placeholder:`your-name`,value:s,onChange:e=>te(e.target.value),disabled:n||x}),(0,V.jsx)(hE,{id:`cf-admin-domain`,value:l,options:ee,onChange:u,disabled:n||x})]}),(0,V.jsx)(`div`,{className:`form-input__field-desc`,children:`Where you access your platform remotely, via your main domain.`}),(0,V.jsxs)(`div`,{className:`form-input__field-desc`,children:[`Preview: `,(0,V.jsx)(`span`,{className:`tunnel-route__preview`,children:_e})]}),(de||le)&&(0,V.jsx)(`div`,{className:`tunnel-route__error`,children:de??le})]}),(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-public-label`,children:[`Public address`,(0,V.jsx)(`span`,{className:`tunnel-route__optional`,children:`Optional`})]}),(0,V.jsxs)(`div`,{className:`tunnel-route__row`,children:[(0,V.jsx)(`input`,{id:`cf-public-label`,className:`form-input__input tunnel-route__input`,type:`text`,autoCapitalize:`none`,autoComplete:`off`,autoCorrect:`off`,spellCheck:!1,placeholder:`leave empty to skip`,value:d,onChange:e=>ne(e.target.value),disabled:n||x}),(0,V.jsx)(hE,{id:`cf-public-domain`,value:p,options:ee,onChange:m,disabled:n||x||!I})]}),(0,V.jsx)(`div`,{className:`form-input__field-desc`,children:`Where visitors engage with your public agents, via your main domain. Leave empty for admin-only access.`}),(fe||ue)&&(0,V.jsx)(`div`,{className:`tunnel-route__error`,children:fe??ue})]}),(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-apex`,children:[`Proxy apex`,(0,V.jsx)(`span`,{className:`tunnel-route__optional`,children:`Optional`})]}),(0,V.jsxs)(`select`,{id:`cf-apex`,className:`form-input__input`,value:h,onChange:e=>g(e.target.value),disabled:n||x,children:[(0,V.jsx)(`option`,{value:``,children:`None`}),ee.map(e=>(0,V.jsx)(`option`,{value:e,children:e},e))]}),(0,V.jsx)(`div`,{className:`form-input__field-desc`,children:`Alternative domain for public agent visitors.`})]}),(0,V.jsxs)(`div`,{className:`form-input__field`,children:[(0,V.jsxs)(`label`,{className:`form-input__label`,htmlFor:`cf-password`,children:[`Admin password`,(0,V.jsx)(`span`,{className:`form-input__required`,children:`*`})]}),(0,V.jsxs)(`div`,{className:`tunnel-route__row`,children:[(0,V.jsx)(`input`,{id:`cf-password`,className:`form-input__input tunnel-route__input`,type:y?`text`:`password`,autoCapitalize:`none`,autoComplete:`new-password`,autoCorrect:`off`,spellCheck:!1,value:_,onChange:e=>{v(e.target.value),j(null)},disabled:n||x}),(0,V.jsx)(`button`,{type:`button`,className:`tunnel-route__suffix`,onClick:()=>b(e=>!e),disabled:n||x,style:{cursor:`pointer`,border:`none`,background:`inherit`},"aria-label":y?`Hide password`:`Show password`,children:y?`Hide`:`Show`})]}),(0,V.jsx)(`ul`,{className:`form-input__field-desc`,style:{margin:0,paddingLeft:16},children:se.map(e=>(0,V.jsxs)(`li`,{style:{color:e.met?`var(--text)`:`var(--text-secondary)`},children:[e.met?`✓`:`○`,` `,e.label]},e.key))}),pe&&(0,V.jsx)(`div`,{className:`tunnel-route__error`,children:pe})]}),me&&(0,V.jsxs)(`div`,{className:`tunnel-route__error`,role:`alert`,children:[(0,V.jsx)(`div`,{children:me}),A?.output&&A.output.length>0&&(0,V.jsx)(`pre`,{style:{marginTop:8,padding:8,maxHeight:280,overflow:`auto`,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:12,lineHeight:1.4,whiteSpace:`pre-wrap`,wordBreak:`break-word`,background:`var(--surface-2, rgba(0,0,0,0.04))`,borderRadius:4},children:pE(A.output)}),(A?.correlationId||A?.streamLogPath)&&(0,V.jsxs)(`div`,{style:{marginTop:8,fontFamily:`var(--font-mono, ui-monospace, monospace)`,fontSize:11,color:`var(--text-secondary)`,wordBreak:`break-all`},children:[A.correlationId&&(0,V.jsxs)(`div`,{children:[`conversationId: `,A.correlationId]}),A.streamLogPath&&(0,V.jsxs)(`div`,{children:[`stream log: `,A.streamLogPath]})]})]})]})]})})}function hE({id:e,value:t,options:n,onChange:r,disabled:i}){return(0,V.jsx)(`select`,{id:e,className:`tunnel-route__suffix`,value:t,onChange:e=>r(e.target.value),disabled:i,style:{cursor:i?`default`:`pointer`,border:`none`},children:n.map(e=>(0,V.jsxs)(`option`,{value:e,children:[`.`,e]},e))})}var gE={"single-select":b,"multi-select":P,confirm:Gt,"info-card":Kt,"action-list":qt,form:Jt,progress:Xt,"browser-viewer":Qt,"rich-content-editor":uT,"grid-editor":_T,"qr-code":GT,"file-attachment":JT,"action-buttons":j,"cloudflare-setup-form":mE,"output-style":b,"thinking-view":b,"plugin-selector":P};function _E(e){let{data:t,filePath:n,onOpen:r}=e,i=n.split(`/`).pop()||n||`document.md`,a=(i.split(`.`).pop()||`doc`).toUpperCase().slice(0,6),o=n||i,s=(0,B.useRef)(!1);return(0,B.useEffect)(()=>{s.current||(s.current=!0,r({docId:o,name:i,content:t.content??``}))},[o,i,t.content,r]),(0,V.jsx)(`div`,{className:`component-card artefact-ref-card`,children:(0,V.jsxs)(`button`,{type:`button`,className:`artefact-ref-button`,onClick:()=>r({docId:o,name:i,content:t.content??``}),children:[(0,V.jsx)(`span`,{className:`artefact-ref-icon`,children:(0,V.jsx)(c,{size:16})}),(0,V.jsxs)(`span`,{className:`artefact-ref-meta`,children:[(0,V.jsx)(`span`,{className:`artefact-ref-name`,children:i}),(0,V.jsxs)(`span`,{className:`artefact-ref-tag`,children:[a,` · open in artefact pane`]})]}),(0,V.jsx)(`span`,{className:`artefact-ref-open`,children:(0,V.jsx)(Fe,{size:14})})]})})}function vE({name:e,data:t,onSubmit:n,submitted:r,isStreaming:i,sessionKey:a,onOpenArtefact:o}){if(e===`document-editor`&&o){let e=t??{};return(0,V.jsx)(_E,{data:e,filePath:e.filePath||e.title||`document.md`,onOpen:o})}if(e===`document-editor`)return(0,V.jsx)(Jw,{data:t,onSubmit:n,submitted:r,isStreaming:i});let s=gE[e];return s?(0,V.jsx)(s,{data:t,onSubmit:n,submitted:r,isStreaming:i,sessionKey:a}):(console.warn(`[ComponentRenderer] Unknown component: "${e}". Registered: ${Object.keys(gE).join(`, `)}`),(0,V.jsx)(`div`,{className:`component-card component-card--error`,children:(0,V.jsxs)(`p`,{style:{fontFamily:`var(--font-body)`,fontSize:12,color:`var(--text-secondary)`},children:[`Component “`,e,`” is not available. This may require a platform update.`]})}))}var yE=/\b(?:fail|error|unable|could not|cannot|CAPTCHA|SIGN_IN_REQUIRED)\b/i;function bE(e){let t=new Date(e),n=new Date,r=String(t.getHours()).padStart(2,`0`),i=String(t.getMinutes()).padStart(2,`0`);return t.toDateString()===n.toDateString()?`${r}:${i}`:`${String(t.getDate()).padStart(2,`0`)}-${String(t.getMonth()+1).padStart(2,`0`)}-${t.getFullYear()} ${r}:${i}`}var xE=[pt,ut,be,ct,Ne];function SE({size:e=13}){let[t,n]=(0,B.useState)(0);(0,B.useEffect)(()=>{let e=setInterval(()=>n(e=>(e+1)%8),300);return()=>clearInterval(e)},[]);let r=t<=4?t:8-t,i=xE[r];return(0,V.jsx)(i,{size:e,className:`star-loader star-frame-${r}`})}var CE=[`Thinking`,`Reasoning`,`Analyzing`,`Considering`,`Reflecting`,`Evaluating`,`Weighing`,`Synthesizing`,`Processing`,`Exploring`,`Examining`,`Assessing`,`Reviewing`,`Contemplating`,`Deliberating`],wE=60,TE=1500;function EE(){let e=(0,B.useRef)(-1),t=(0,B.useRef)(void 0),[n,r]=(0,B.useState)(()=>{let t=Math.floor(Math.random()*CE.length);return e.current=t,CE[t]+`…`});return(0,B.useEffect)(()=>{let n=!1;function i(){let t;do t=Math.floor(Math.random()*CE.length);while(t===e.current&&CE.length>1);return e.current=t,t}function a(){if(n)return;let e=CE[i()]+`…`,o=0;function s(){n||(o++,r(e.slice(0,o)),o<e.length?t.current=setTimeout(s,wE):t.current=setTimeout(a,TE))}t.current=setTimeout(s,wE)}return t.current=setTimeout(a,TE),()=>{n=!0,clearTimeout(t.current)}},[]),(0,V.jsx)(`span`,{className:`tl-thinking-typewriter`,children:n})}function DE(e,t){let n=e=>String(e??``);switch(e){case`Read`:return`Read ${n(t.file_path??t.path)}`;case`Write`:return`Write ${n(t.file_path??t.path)}`;case`Edit`:return`Edit ${n(t.file_path??t.path)}`;case`Bash`:return n(t.description??String(t.command??``).slice(0,70));case`Glob`:return`Glob ${n(t.pattern)}`;case`Grep`:return`Grep "${n(t.pattern)}" in ${n(t.path??`.`)}`;case`WebFetch`:return`Fetch ${n(t.url)}`;case`Agent`:return n(t.description??t.task??`Subagent`);case`Skill`:return n(t.skill??`Skill`);default:{let r=e.match(/^mcp__[^_]+__(.+)$/),i=r?r[1]:e,a=Object.keys(t)[0];return a?`${i}: ${n(t[a]).slice(0,50)}`:i}}}function OE({name:e,size:t=12}){let n=e.match(/^mcp__[^_]+__(.+)$/);switch(n?n[1]:e){case`Read`:return(0,V.jsx)(c,{size:t});case`Write`:return(0,V.jsx)(Ve,{size:t});case`Edit`:return(0,V.jsx)(Be,{size:t});case`Bash`:return(0,V.jsx)(mt,{size:t});case`Glob`:case`Grep`:return(0,V.jsx)(de,{size:t});case`WebFetch`:return(0,V.jsx)(D,{size:t});case`Agent`:return(0,V.jsx)(Ce,{size:t});case`Skill`:return(0,V.jsx)(ut,{size:t});case`memory-search`:return(0,V.jsx)(Me,{size:t});case`memory-write`:return(0,V.jsx)(je,{size:t});case`task-list`:return(0,V.jsx)(R,{size:t});case`task-create`:return(0,V.jsx)(ke,{size:t});case`contact-create`:return(0,V.jsx)(ht,{size:t});default:return(0,V.jsx)(_t,{size:t})}}function kE(e){let t=new Map,n=new Map;return e.forEach((e,r)=>{if(e.type===`tool_use`){let t=n.get(e.name)??[];t.push(r),n.set(e.name,t)}else if(e.type===`tool_result`){let i=n.get(e.name);i?.length&&t.set(i.shift(),r)}}),t}function AE(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function jE(e){let t=``;switch(e.type){case`text`:case`thinking`:t=e.content??``;break;case`tool_use`:t=JSON.stringify(e.input??{});break;case`tool_result`:t=e.output??``;break;case`subagent_start`:t=e.task??``;break;case`subagent_end`:t=e.result??``;break;case`component`:t=JSON.stringify(e.data??{});break;case`status`:t=e.message??``;break;default:return 0}return Math.ceil(t.length/4)}function ME(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 NE(e){if(e<60)return`${e.toFixed(1)}s`;let t=Math.floor(e/60),n=e%60;return n>=.1?`${t}m ${Math.floor(n)}s`:`${t}m`}function PE({icon:e,isPending:t,isError:n,doneClass:r=`tl-done`,summary:i,detail:a,tokens:o,elapsed:s,isLast:c,expanded:l,onToggle:u,selectCheck:d}){let f=!!a;return(0,V.jsxs)(`div`,{className:`tl-step`,children:[d,(0,V.jsxs)(`div`,{className:`tl-col`,children:[(0,V.jsx)(`div`,{className:`tl-icon${t?` tl-pending`:n?` tl-error`:` ${r}`}`,children:e}),!c&&(0,V.jsx)(`div`,{className:`tl-line tl-line-grow`})]}),(0,V.jsxs)(`div`,{className:`tl-body`,children:[(0,V.jsxs)(`div`,{className:`tl-row`,onClick:f?()=>{window.getSelection()?.toString()||u()}:void 0,style:{cursor:f?`pointer`:`default`},children:[(0,V.jsx)(`span`,{className:`tl-summary`,children:i}),o>0&&(0,V.jsxs)(`span`,{className:`tl-step-tokens`,children:[(0,V.jsx)(vt,{size:9}),AE(o)]}),(0,V.jsx)(`span`,{className:`tl-step-elapsed`,children:NE(s)}),f&&(0,V.jsx)(`span`,{className:`tl-chevron`,children:l?(0,V.jsx)(p,{size:10}):(0,V.jsx)(Ee,{size:10})})]}),f&&l&&(0,V.jsx)(`pre`,{className:`tl-detail`,children:a})]})]})}function FE({events:e,isStreaming:t,elapsedSeconds:n,streamStartMs:r,expandAll:i,onCompactNow:a,isCompacting:o,sessionCompacted:s,onComponentSubmit:c,submittedComponents:l,timestamp:u,selectionMode:d,selectedItems:f,onToggleItem:m,sessionKey:g,onOpenArtefact:_}){let[v,y]=(0,B.useState)(new Set),[b,S]=(0,B.useState)(!t),C=(0,B.useRef)(t);(0,B.useEffect)(()=>{C.current&&!t&&S(!0),!C.current&&t&&S(!1),C.current=t},[t]);let T=(0,B.useRef)(new Map),E=(0,B.useRef)(0),[D,O]=(0,B.useState)(Date.now());(0,B.useEffect)(()=>{let t=Date.now();for(let n=E.current;n<e.length;n++)T.current.has(n)||T.current.set(n,t);E.current=e.length},[e]),(0,B.useEffect)(()=>{if(!t)return;let e=setInterval(()=>O(Date.now()),100);return()=>clearInterval(e)},[t]);let k=e=>{y(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},A=(e,t)=>{let n=e===ae[0]?.i&&r?r:T.current.get(e)??D,i=t===void 0?D:T.current.get(t)??D;return Math.max(0,(i-n)/1e3)},j=kE(e),M=new Set(j.values()),N=e.map((e,t)=>({e,i:t})).filter(({e})=>e.type===`text`),P=new Set(t?[]:e.map((e,t)=>({e,i:t})).filter(({e})=>e.type===`component`).map(({i:e})=>e)),ee=e=>e.type===`component`&&[`browser-viewer`,`qr-code`].includes(e.name);function ne(e){if(!d||t||!u)return null;let n=`${u}_${e}`;return(0,V.jsx)(`div`,{className:`tl-select-check`,onClick:e=>e.stopPropagation(),children:(0,V.jsx)(_e,{checked:f?.has(n)??!1,onChange:()=>m?.(n)})})}let F=e.findLast(e=>e.type===`usage`),I=e.findLast(e=>e.type===`history_usage`),re=e.findLast(e=>e.type===`status`),ie=e.some(e=>e.type===`subagent_start`),ae=e.map((e,t)=>({e,i:t})).filter(({e,i:n})=>e.type!==`text`&&e.type!==`usage`&&e.type!==`rate_limit`&&e.type!==`history_usage`&&e.type!==`status`&&e.type!==`done`&&e.type!==`subagent_progress`&&!M.has(n)&&!P.has(n)&&!(t&&e.type===`component`&&!ee(e))&&!(e.type===`tool_use`&&e.name===`Agent`&&ie)),se=new Map;for(let e=0;e<ae.length-1;e++)se.set(ae[e].i,ae[e+1].i);let L=(()=>{let e=[],t=!1,n=0;for(let{e:r}of ae)if(n+=jE(r),r.type===`thinking`)t=!0;else if(r.type===`tool_use`){let t=r.name;e.includes(t)||e.push(t)}let r=[`${ae.length} step${ae.length===1?``:`s`}`];if(e.length>0){let t=e.slice(0,3),n=e.length-t.length;r.push(t.join(`, `)+(n>0?` +${n}`:``))}return{text:r.join(` · `),hasThinking:t,tokenSum:n}})(),ce=F?.peak_request_pct==null?F?.context_window?Math.round((F.input_tokens+F.cache_creation_tokens+F.cache_read_tokens)/F.context_window*100):null:Math.round(F.peak_request_pct*100),le=ae.length>0,ue=N.length>0,de=new Set(ae.map(e=>e.i)),fe=new Set(N.map(e=>e.i)),pe=[];for(let t=0;t<e.length;t++){let n=e[t],r=null;if(de.has(t)?r=`steps`:fe.has(t)&&(r=`text`),!r)continue;let i=pe[pe.length-1];i&&i.role===r?i.items.push({e:n,i:t}):pe.push({role:r,items:[{e:n,i:t}]})}let me=N.length>0?N[N.length-1].i:-1;function he(n,r,a,o){let s=o===a.length-1;if(n.type===`thinking`){let e=i===void 0?!v.has(r):i,t=se.get(r);return(0,V.jsxs)(`div`,{className:`tl-step`,children:[ne(r),(0,V.jsxs)(`div`,{className:`tl-col`,children:[(0,V.jsx)(`div`,{className:`tl-icon tl-dim`,children:(0,V.jsx)(qe,{size:11})}),!s&&(0,V.jsx)(`div`,{className:`tl-line tl-line-grow`})]}),(0,V.jsx)(`div`,{className:`tl-body`,children:(0,V.jsxs)(`div`,{className:`tl-row tl-row-top`,onClick:()=>{window.getSelection()?.toString()||k(r)},style:{cursor:`pointer`},children:[(0,V.jsx)(`div`,{className:`tl-thinking-col`,children:e?(0,V.jsx)(`div`,{className:`tl-thinking-body`,children:n.content}):(0,V.jsxs)(`span`,{className:`tl-summary tl-thinking-label`,children:[n.content.slice(0,80),n.content.length>80?`…`:``]})}),jE(n)>0&&(0,V.jsxs)(`span`,{className:`tl-step-tokens`,children:[(0,V.jsx)(vt,{size:9}),AE(jE(n))]}),(0,V.jsx)(`span`,{className:`tl-step-elapsed`,children:NE(A(r,t))}),(0,V.jsx)(`span`,{className:`tl-chevron`,children:e?(0,V.jsx)(p,{size:10}):(0,V.jsx)(Ee,{size:10})})]})})]},r)}if(n.type===`status`)return(0,V.jsx)(`div`,{className:`tl-status`,children:n.message},r);if(n.type===`tool_use`){let t=j.get(r),a=t===void 0?void 0:e[t],o=a===void 0,c=a?.type===`tool_result`&&!!a.error,l=o?(0,V.jsx)(Ze,{size:11,className:`tl-spinner`}):c?(0,V.jsx)(oe,{size:11}):(0,V.jsx)(OE,{name:n.name,size:11}),u=n,d=a?.type===`tool_result`?`Input:
|
|
344
344
|
${JSON.stringify(u.input,null,2)}
|
|
345
345
|
|
|
346
346
|
Result:
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/admin-
|
|
8
|
+
<script type="module" crossorigin src="/assets/admin-B41Gr-FL.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-DD-I1_y5.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-DJER3a7U.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/preload-helper-qlgyTAkD.js">
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// Tri-state DOM matcher for the Cloudflare argotunnel consent page (Task 855).
|
|
2
|
-
//
|
|
3
|
-
// `dash.cloudflare.com/argotunnel?...` legitimately renders three observable
|
|
4
|
-
// states for our flow:
|
|
5
|
-
//
|
|
6
|
-
// 1. Pre-authorize — a <button> or <input type="submit"> whose trimmed text
|
|
7
|
-
// matches /^(authorize|connect)$/i (and is not disabled). Click it; the
|
|
8
|
-
// callback fires, cloudflared writes ~/.cloudflared/cert.pem.
|
|
9
|
-
//
|
|
10
|
-
// 2. Post-success — the dashboard renders a Success modal containing the
|
|
11
|
-
// stable substring "Cloudflared has installed a certificate". This shape
|
|
12
|
-
// is reached when the user already authorised this account before (or
|
|
13
|
-
// did so manually in VNC between cloudflared spawn and helper poll).
|
|
14
|
-
// The OAuth callback is idempotent on the cert side: when the helper
|
|
15
|
-
// sees this state, the running cloudflared subprocess will still write
|
|
16
|
-
// ~/.cloudflared/cert.pem because the callback URL is exercised by the
|
|
17
|
-
// navigation. The wrapper drops into the existing cert-poll afterwards.
|
|
18
|
-
//
|
|
19
|
-
// 3. Neither — the page is mid-load, blank, or in some other state. The
|
|
20
|
-
// caller polls again until BUTTON_POLL_TIMEOUT_MS, then exits 1.
|
|
21
|
-
//
|
|
22
|
-
// The matcher returns a discriminated union from a single DOM read:
|
|
23
|
-
//
|
|
24
|
-
// { kind: 'button', descriptor: {tag,text,disabled} } | { kind: 'success' } | null
|
|
25
|
-
//
|
|
26
|
-
// PRIORITY: button > success modal. Page transitions can briefly render both
|
|
27
|
-
// (e.g. during the success animation). If a clickable Authorize button exists,
|
|
28
|
-
// click it — the click produces a fresh callback regardless of any leftover
|
|
29
|
-
// modal text. Only when no button is present do we trust the modal as the
|
|
30
|
-
// terminal state.
|
|
31
|
-
//
|
|
32
|
-
// EXPORTED SHAPES:
|
|
33
|
-
//
|
|
34
|
-
// * findMatch(doc) — JS function form. Used by JSDOM-based unit tests
|
|
35
|
-
// (platform/ui/scripts/__tests__/cdp-authorize-matcher.test.ts) so future
|
|
36
|
-
// matcher edits replay against captured DOM fixtures offline (Success
|
|
37
|
-
// criterion 8 of Task 855).
|
|
38
|
-
//
|
|
39
|
-
// * MATCH_EXPR — string form, evaluated by Chrome DevTools Protocol's
|
|
40
|
-
// Runtime.evaluate in _cdp-authorize.mjs's polling loop. Built from
|
|
41
|
-
// findMatch.toString() so the live page and the tests run identical
|
|
42
|
-
// logic — single source of truth.
|
|
43
|
-
//
|
|
44
|
-
// CONTRACT — DO NOT loosen the success-modal anchor. Tighter anchors regress
|
|
45
|
-
// on Cloudflare copy edits; "Cloudflared has installed a certificate" is the
|
|
46
|
-
// load-bearing claim of the modal. Wider anchors (e.g. matching just
|
|
47
|
-
// "certificate") would false-positive on the pre-authorize page.
|
|
48
|
-
|
|
49
|
-
export function findMatch(doc) {
|
|
50
|
-
const candidates = Array.from(doc.querySelectorAll('button, input[type="submit"]'));
|
|
51
|
-
const match = candidates.find((el) => {
|
|
52
|
-
const text = (el.textContent ?? el.value ?? '').trim();
|
|
53
|
-
return /^(authorize|connect)$/i.test(text) && !el.disabled;
|
|
54
|
-
});
|
|
55
|
-
if (match) {
|
|
56
|
-
const descriptor = {
|
|
57
|
-
tag: match.tagName.toLowerCase(),
|
|
58
|
-
text: (match.textContent ?? match.value ?? '').trim().slice(0, 40),
|
|
59
|
-
disabled: Boolean(match.disabled),
|
|
60
|
-
};
|
|
61
|
-
match.click();
|
|
62
|
-
return { kind: 'button', descriptor };
|
|
63
|
-
}
|
|
64
|
-
// textContent over innerText: jsdom's innerText is partial; the dashboard's
|
|
65
|
-
// success-modal text is plain DOM content (not visibility-gated by CSS for
|
|
66
|
-
// anyone reading the page) so textContent finds it on both runtimes.
|
|
67
|
-
const bodyText = doc.body ? doc.body.textContent || '' : '';
|
|
68
|
-
if (bodyText.includes('Cloudflared has installed a certificate')) {
|
|
69
|
-
return { kind: 'success' };
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export const MATCH_EXPR = `(${findMatch.toString()})(document)`;
|
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Drive the Cloudflare argotunnel consent page to a deterministic terminal
|
|
3
|
-
// state via CDP WebSocket. Originally Task 588 (Authorize click from code,
|
|
4
|
-
// collapsing a 180 s human-latency window). Task 855 widens the contract to
|
|
5
|
-
// three states because the dashboard does not always render a button — once
|
|
6
|
-
// the bound account has authorized this device's zones, navigating the same
|
|
7
|
-
// (or a fresh) consent URL renders a Success modal verbatim, and the
|
|
8
|
-
// pre-855 helper conflated "no button visible yet" with "no button will
|
|
9
|
-
// ever appear" and exited error.
|
|
10
|
-
//
|
|
11
|
-
// Protocol: Chrome DevTools Protocol over WebSocket
|
|
12
|
-
// (https://chromedevtools.github.io/devtools-protocol/):
|
|
13
|
-
// 1. GET http://127.0.0.1:9222/json/list → find the target with matching id;
|
|
14
|
-
// extract webSocketDebuggerUrl.
|
|
15
|
-
// 2. Open WS, enable Page + Runtime domains.
|
|
16
|
-
// 3. Wait for Page.loadEventFired (or observe document.readyState==='complete').
|
|
17
|
-
// 4. Poll Runtime.evaluate every 200 ms for up to ~3 s, evaluating the
|
|
18
|
-
// tri-state matcher from _cdp-authorize-matcher.mjs. The matcher
|
|
19
|
-
// returns one of:
|
|
20
|
-
// - { kind:'button', descriptor } — Authorize/Connect button found,
|
|
21
|
-
// click() fired in-page; emit
|
|
22
|
-
// reason=clicked, exit 0.
|
|
23
|
-
// - { kind:'success' } — Success modal text detected
|
|
24
|
-
// ("Cloudflared has installed a
|
|
25
|
-
// certificate"); cert is bound to
|
|
26
|
-
// the account. Emit reason=
|
|
27
|
-
// cert-already-installed, exit 0.
|
|
28
|
-
// Caller's existing cert-poll picks
|
|
29
|
-
// up the cert (callback is
|
|
30
|
-
// idempotent on this navigation).
|
|
31
|
-
// - null — Neither anchor matched yet; loop.
|
|
32
|
-
// After BUTTON_POLL_TIMEOUT_MS with no terminal match, emit
|
|
33
|
-
// reason=authorize-button-not-found, exit 1.
|
|
34
|
-
//
|
|
35
|
-
// Exit codes:
|
|
36
|
-
// 0 - terminal success (reason=clicked OR reason=cert-already-installed)
|
|
37
|
-
// 1 - authorize-button-not-found (loud failure — button AND modal absent)
|
|
38
|
-
// 2 - cdp-ws-unreachable or node-websocket-unavailable
|
|
39
|
-
// 3 - target-not-found (the target_id isn't in /json/list)
|
|
40
|
-
// 4 - click-evaluate-threw (Runtime.evaluate returned wasThrown=true)
|
|
41
|
-
// 5 - protocol-error (malformed CDP response)
|
|
42
|
-
//
|
|
43
|
-
// Stdout contract (read by setup-tunnel.sh's awk-based reason parser):
|
|
44
|
-
// cdp-authorize result=<ok|error> reason=<…> elapsed_ms=<…> [detail=<…>]
|
|
45
|
-
// Exactly ONE such line per invocation; the wrapper takes the LAST
|
|
46
|
-
// `result=ok` line via awk so future debug-line additions cannot mis-route.
|
|
47
|
-
|
|
48
|
-
import { MATCH_EXPR } from './_cdp-authorize-matcher.mjs';
|
|
49
|
-
|
|
50
|
-
const CDP_HOST = '127.0.0.1';
|
|
51
|
-
const CDP_PORT = 9222;
|
|
52
|
-
const HTTP_TIMEOUT_MS = 3000;
|
|
53
|
-
const BUTTON_POLL_TIMEOUT_MS = 3000;
|
|
54
|
-
const BUTTON_POLL_INTERVAL_MS = 200;
|
|
55
|
-
const LOAD_WAIT_TIMEOUT_MS = 5000;
|
|
56
|
-
const WS_CONNECT_TIMEOUT_MS = 3000;
|
|
57
|
-
const RESULT_WAIT_TIMEOUT_MS = 3000;
|
|
58
|
-
|
|
59
|
-
function emit(result, reason, extra = {}) {
|
|
60
|
-
const parts = [`cdp-authorize result=${result} reason=${reason}`];
|
|
61
|
-
for (const [k, v] of Object.entries(extra)) {
|
|
62
|
-
if (v === undefined || v === null) continue;
|
|
63
|
-
const s = String(v).replace(/\s+/g, ' ');
|
|
64
|
-
parts.push(`${k}="${s.slice(0, 200)}"`);
|
|
65
|
-
}
|
|
66
|
-
process.stdout.write(parts.join(' ') + '\n');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function die(code, reason, extra) {
|
|
70
|
-
emit('error', reason, extra);
|
|
71
|
-
process.exit(code);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (typeof WebSocket === 'undefined') {
|
|
75
|
-
die(2, 'node-websocket-unavailable', {
|
|
76
|
-
detail: `Node ${process.version} has no global WebSocket — upgrade to Node 22+`,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const targetId = process.argv[2];
|
|
81
|
-
if (!targetId) {
|
|
82
|
-
die(2, 'missing-target-id', { detail: 'usage: _cdp-authorize.mjs <target-id>' });
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const started = Date.now();
|
|
86
|
-
|
|
87
|
-
async function fetchTargets() {
|
|
88
|
-
const ac = new AbortController();
|
|
89
|
-
const timer = setTimeout(() => ac.abort(), HTTP_TIMEOUT_MS);
|
|
90
|
-
try {
|
|
91
|
-
const res = await fetch(`http://${CDP_HOST}:${CDP_PORT}/json/list`, { signal: ac.signal });
|
|
92
|
-
if (!res.ok) throw new Error(`/json/list returned ${res.status}`);
|
|
93
|
-
return await res.json();
|
|
94
|
-
} finally {
|
|
95
|
-
clearTimeout(timer);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let targets;
|
|
100
|
-
try {
|
|
101
|
-
targets = await fetchTargets();
|
|
102
|
-
} catch (err) {
|
|
103
|
-
die(2, 'cdp-ws-unreachable', { detail: err instanceof Error ? err.message : String(err) });
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const target = Array.isArray(targets) ? targets.find((t) => t && t.id === targetId) : undefined;
|
|
107
|
-
if (!target || typeof target.webSocketDebuggerUrl !== 'string') {
|
|
108
|
-
die(3, 'target-not-found', { target_id: targetId, count: Array.isArray(targets) ? targets.length : -1 });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Open WebSocket. Native Node 22 global.
|
|
112
|
-
let ws;
|
|
113
|
-
try {
|
|
114
|
-
ws = new WebSocket(target.webSocketDebuggerUrl);
|
|
115
|
-
} catch (err) {
|
|
116
|
-
die(2, 'cdp-ws-unreachable', { detail: err instanceof Error ? err.message : String(err) });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// WS open with race guards. Three outcomes are possible:
|
|
120
|
-
// 1. `open` fires before `error` / timeout → resolve and continue.
|
|
121
|
-
// 2. `error` fires before `open` → reject; caller emits die() and exits.
|
|
122
|
-
// 3. Timeout fires before either → reject; caller emits die() and exits.
|
|
123
|
-
// The `.once` on `open`/`error` listeners handles the race where both fire
|
|
124
|
-
// in quick succession (some proxy-protocol mismatches can emit `error`
|
|
125
|
-
// before the open event is dispatched). The catch below awaits the die()
|
|
126
|
-
// call and then `throw`s to guarantee execution does not fall through to
|
|
127
|
-
// the Page.enable call with a dead socket — even if a future refactor
|
|
128
|
-
// removes process.exit() from die().
|
|
129
|
-
try {
|
|
130
|
-
await new Promise((resolveOpen, rejectOpen) => {
|
|
131
|
-
const timer = setTimeout(() => rejectOpen(new Error('ws open timeout')), WS_CONNECT_TIMEOUT_MS);
|
|
132
|
-
ws.addEventListener('open', () => { clearTimeout(timer); resolveOpen(); }, { once: true });
|
|
133
|
-
ws.addEventListener('error', (e) => { clearTimeout(timer); rejectOpen(new Error(`ws error: ${e.message ?? 'unknown'}`)); }, { once: true });
|
|
134
|
-
});
|
|
135
|
-
} catch (err) {
|
|
136
|
-
die(2, 'cdp-ws-unreachable', { detail: err instanceof Error ? err.message : String(err) });
|
|
137
|
-
throw err; // unreachable — die() exits, but guards the type system and future refactors.
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Message router: CDP replies come back keyed by the `id` we sent. Events
|
|
141
|
-
// arrive with no `id` but a `method` (e.g. "Page.loadEventFired").
|
|
142
|
-
let nextId = 1;
|
|
143
|
-
const pending = new Map();
|
|
144
|
-
const eventListeners = new Map();
|
|
145
|
-
|
|
146
|
-
ws.addEventListener('message', (evt) => {
|
|
147
|
-
let msg;
|
|
148
|
-
try {
|
|
149
|
-
msg = JSON.parse(typeof evt.data === 'string' ? evt.data : evt.data.toString());
|
|
150
|
-
} catch {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
if (typeof msg.id === 'number' && pending.has(msg.id)) {
|
|
154
|
-
const { resolveIt, rejectIt } = pending.get(msg.id);
|
|
155
|
-
pending.delete(msg.id);
|
|
156
|
-
if (msg.error) rejectIt(new Error(`CDP error: ${msg.error.message ?? JSON.stringify(msg.error)}`));
|
|
157
|
-
else resolveIt(msg.result);
|
|
158
|
-
} else if (typeof msg.method === 'string') {
|
|
159
|
-
const listeners = eventListeners.get(msg.method);
|
|
160
|
-
if (listeners) for (const l of listeners) l(msg.params);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
ws.addEventListener('close', () => {
|
|
165
|
-
for (const { rejectIt } of pending.values()) {
|
|
166
|
-
rejectIt(new Error('ws closed while awaiting response'));
|
|
167
|
-
}
|
|
168
|
-
pending.clear();
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
function send(method, params = {}) {
|
|
172
|
-
const id = nextId++;
|
|
173
|
-
return new Promise((resolveIt, rejectIt) => {
|
|
174
|
-
const timer = setTimeout(() => {
|
|
175
|
-
pending.delete(id);
|
|
176
|
-
rejectIt(new Error(`CDP ${method} timed out after ${RESULT_WAIT_TIMEOUT_MS}ms`));
|
|
177
|
-
}, RESULT_WAIT_TIMEOUT_MS);
|
|
178
|
-
pending.set(id, {
|
|
179
|
-
resolveIt: (r) => { clearTimeout(timer); resolveIt(r); },
|
|
180
|
-
rejectIt: (e) => { clearTimeout(timer); rejectIt(e); },
|
|
181
|
-
});
|
|
182
|
-
ws.send(JSON.stringify({ id, method, params }));
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function onEvent(method, listener) {
|
|
187
|
-
let set = eventListeners.get(method);
|
|
188
|
-
if (!set) { set = new Set(); eventListeners.set(method, set); }
|
|
189
|
-
set.add(listener);
|
|
190
|
-
return () => set.delete(listener);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Enable the two domains we need. Page.enable fires events; Runtime.enable
|
|
194
|
-
// lets us run expressions in the page context.
|
|
195
|
-
try {
|
|
196
|
-
await send('Page.enable');
|
|
197
|
-
await send('Runtime.enable');
|
|
198
|
-
} catch (err) {
|
|
199
|
-
die(5, 'protocol-error', { detail: err.message });
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Wait for load — if the page is already loaded (navigated before this helper
|
|
203
|
-
// ran), Page.loadEventFired may never fire again; poll document.readyState
|
|
204
|
-
// as a fallback. The first of the two to resolve wins.
|
|
205
|
-
async function waitForLoad() {
|
|
206
|
-
const loadFired = new Promise((resolveIt) => {
|
|
207
|
-
const off = onEvent('Page.loadEventFired', () => { off(); resolveIt('loadEvent'); });
|
|
208
|
-
});
|
|
209
|
-
const readyStatePoll = (async () => {
|
|
210
|
-
const deadline = Date.now() + LOAD_WAIT_TIMEOUT_MS;
|
|
211
|
-
while (Date.now() < deadline) {
|
|
212
|
-
try {
|
|
213
|
-
const r = await send('Runtime.evaluate', {
|
|
214
|
-
expression: 'document.readyState',
|
|
215
|
-
returnByValue: true,
|
|
216
|
-
});
|
|
217
|
-
if (r?.result?.value === 'complete' || r?.result?.value === 'interactive') return 'readyState';
|
|
218
|
-
} catch { /* keep polling */ }
|
|
219
|
-
await new Promise((res) => setTimeout(res, 200));
|
|
220
|
-
}
|
|
221
|
-
throw new Error('load-wait-timeout');
|
|
222
|
-
})();
|
|
223
|
-
return Promise.race([loadFired, readyStatePoll]);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
try {
|
|
227
|
-
await waitForLoad();
|
|
228
|
-
} catch (err) {
|
|
229
|
-
die(1, 'page-load-timeout', { detail: err.message, elapsed_ms: Date.now() - started });
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Poll the consent page until one of the three terminal states resolves.
|
|
233
|
-
// MATCH_EXPR is built from _cdp-authorize-matcher.mjs's findMatch so the
|
|
234
|
-
// JSDOM unit tests and the live CDP path execute literally identical logic.
|
|
235
|
-
const matchDeadline = Date.now() + BUTTON_POLL_TIMEOUT_MS;
|
|
236
|
-
let matched = null;
|
|
237
|
-
while (Date.now() < matchDeadline) {
|
|
238
|
-
let r;
|
|
239
|
-
try {
|
|
240
|
-
r = await send('Runtime.evaluate', {
|
|
241
|
-
expression: MATCH_EXPR,
|
|
242
|
-
returnByValue: true,
|
|
243
|
-
awaitPromise: false,
|
|
244
|
-
});
|
|
245
|
-
} catch (err) {
|
|
246
|
-
die(5, 'protocol-error', { detail: err.message });
|
|
247
|
-
}
|
|
248
|
-
if (r?.exceptionDetails) {
|
|
249
|
-
die(4, 'click-evaluate-threw', {
|
|
250
|
-
detail: r.exceptionDetails.text ?? 'unknown exception',
|
|
251
|
-
elapsed_ms: Date.now() - started,
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
const val = r?.result?.value;
|
|
255
|
-
if (val && typeof val === 'object' && (val.kind === 'button' || val.kind === 'success')) {
|
|
256
|
-
matched = val;
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
await new Promise((res) => setTimeout(res, BUTTON_POLL_INTERVAL_MS));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (!matched) {
|
|
263
|
-
die(1, 'authorize-button-not-found', { elapsed_ms: Date.now() - started });
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (matched.kind === 'button') {
|
|
267
|
-
const d = matched.descriptor ?? {};
|
|
268
|
-
emit('ok', 'clicked', {
|
|
269
|
-
tag: d.tag,
|
|
270
|
-
text: d.text,
|
|
271
|
-
elapsed_ms: Date.now() - started,
|
|
272
|
-
});
|
|
273
|
-
} else {
|
|
274
|
-
// matched.kind === 'success' — Success modal text is on the page; the
|
|
275
|
-
// bound account already has a cert. Caller drops into the cert-poll loop;
|
|
276
|
-
// the in-flight cloudflared subprocess receives the idempotent callback
|
|
277
|
-
// and writes ~/.cloudflared/cert.pem.
|
|
278
|
-
emit('ok', 'cert-already-installed', {
|
|
279
|
-
elapsed_ms: Date.now() - started,
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
try { ws.close(); } catch { /* best-effort */ }
|
|
284
|
-
process.exit(0);
|