From f5f13829c5cb368cfe84a9571fe9961d11ce13a8 Mon Sep 17 00:00:00 2001 From: Zackery Bartolome Date: Thu, 1 Oct 2026 12:37:20 -0400 Subject: [PATCH 1/2] Close auth scopes and reject stale or malformed operations (#660) (#661) (#662) (#663) (#664) (#665) (#666) (#667) (#668) (#669) --- CHANGELOG.md | 18 ++++ examples/worker/src/d1-storage.ts | 32 +++++-- src/execute.ts | 15 ++++ src/operator-ui/app/store.ts | 6 +- src/operator-ui/generated.ts | 2 +- src/registry.ts | 27 +++--- src/routes/credentials.ts | 27 +++--- src/routes/oauth.ts | 139 ++++++++++++++++-------------- src/runtime/run.ts | 7 +- src/storage/memory.ts | 9 +- test/browser/operator-ui.spec.ts | 16 ++++ test/d1-storage-example.test.ts | 9 ++ test/downstream-oauth.test.ts | 29 +++++++ test/execute.test.ts | 20 +++++ test/operator-store.test.ts | 35 ++++++++ test/registry.test.ts | 34 ++++++++ test/runtime.test.ts | 24 ++++++ test/storage-contract.ts | 13 +++ test/ui-credentials.test.ts | 30 +++++++ 19 files changed, 395 insertions(+), 97 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0a5990f..6e47c81c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,12 @@ rotations during legacy migration, and hardens file snapshots and operator recovery. Artifact quotas now reserve 8 KiB for frame metadata, reducing the available content allowance by 4 KiB, and apply to historical snapshots too. +A third pass prevents dispatch after cancellation, rejects malformed executor +replies, and closes connector scopes after human auth operations. OAuth handoffs +claim ownership atomically when storage supports it. Activity reads now recover +from malformed pages and ignore superseded pagination, and memory and D1 storage +reject invalid expiry values. + ### Changed - Pin Effect to `4.0.0`, replacing `4.0.0-rc.117`, and align the optional @@ -25,6 +31,18 @@ available content allowance by 4 KiB, and apply to historical snapshots too. ### Fixed +- Refuse already-aborted deadline operations and preserve explicit `null` + cancellation reasons (#660) (#661). +- Return structured failures for malformed executor replies (#662). +- Close callback and credential-test connector scopes after their final use, + keeping cleanup bounded and best-effort (#663) (#664). +- Prevent concurrent OAuth state handoffs from replacing another owner on + storage that supports atomic claims (#665). +- Show retryable Activity errors for unreadable pages and discard superseded + pagination responses (#666) (#667). +- Reject invalid TTLs in memory and D1 storage before mutation, and match NUL + bytes literally in D1 list prefixes (#668) (#669). + - Enforce catalog count and byte ceilings even when discovery is invalidated while the listing is in flight (#644). - Retain OAuth cleanup lineage after uncertain storage commits, preserve diff --git a/examples/worker/src/d1-storage.ts b/examples/worker/src/d1-storage.ts index 9bda7d4b..b4d868a3 100644 --- a/examples/worker/src/d1-storage.ts +++ b/examples/worker/src/d1-storage.ts @@ -18,8 +18,17 @@ import type { KVStorage } from "@zackbart/connecta"; export function d1Storage(db: D1Database): KVStorage { // Every statement that tests liveness binds the current time as ?2. const live = "(expires_at_ms IS NULL OR expires_at_ms > ?2)"; - const expiresAt = (now: number, ttlSeconds?: number) => - ttlSeconds ? now + ttlSeconds * 1000 : null; + const expiresAt = (now: number, ttlSeconds?: number): number | null => { + if (ttlSeconds !== undefined && !Number.isFinite(ttlSeconds)) { + throw new RangeError("ttlSeconds must produce a finite expiration timestamp"); + } + if (!ttlSeconds) return null; + const expiry = now + ttlSeconds * 1000; + if (!Number.isFinite(expiry)) { + throw new RangeError("ttlSeconds must produce a finite expiration timestamp"); + } + return expiry; + }; const changed = (result: D1Result) => result.meta.changes > 0; return { async get(key) { @@ -31,6 +40,7 @@ export function d1Storage(db: D1Database): KVStorage { }, async set(key, value, opts) { const now = Date.now(); + const expiry = expiresAt(now, opts?.ttlSeconds); await db.batch([ db .prepare( @@ -46,7 +56,7 @@ export function d1Storage(db: D1Database): KVStorage { ON CONFLICT (key) DO UPDATE SET value = excluded.value, expires_at_ms = excluded.expires_at_ms`, ) - .bind(key, value, expiresAt(now, opts?.ttlSeconds)), + .bind(key, value, expiry), ]); }, async delete(key) { @@ -56,7 +66,7 @@ export function d1Storage(db: D1Database): KVStorage { const { results } = await db .prepare( `SELECT key FROM connecta_kv - WHERE key >= ?1 AND substr(key, 1, length(?1)) = ?1 AND ${live}`, + WHERE key >= ?1 AND substr(CAST(key AS BLOB), 1, length(CAST(?1 AS BLOB))) = CAST(?1 AS BLOB) AND ${live}`, ) .bind(prefix, Date.now()) .all<{ key: string }>(); @@ -84,7 +94,19 @@ export function d1Storage(db: D1Database): KVStorage { .run(), ); } - const expiry = expiresAt(now, opts?.ttlSeconds); + let expiry: number | null; + try { + expiry = expiresAt(now, opts?.ttlSeconds); + } catch (error) { + // Invalid write options do not change a failed comparison's result. + // Ordinary claims still use one atomic statement without this read. + const current = await db + .prepare(`SELECT value FROM connecta_kv WHERE key = ?1 AND ${live}`) + .bind(key, now) + .first<{ value: string }>(); + if ((current?.value ?? null) !== expected) return false; + throw error; + } if (expected === null) { // Insert, or take over a row that has expired. A live row makes the // upsert's WHERE false, so nothing changes and the claim is refused. diff --git a/src/execute.ts b/src/execute.ts index d7564e06..f4a9c37f 100644 --- a/src/execute.ts +++ b/src/execute.ts @@ -1447,7 +1447,22 @@ function finishedRun( outcome: ExecuteResult, { emitted, diagnostics, invocationFailures }: RunReport, ): ToolResult { + if (outcome === null || typeof outcome !== "object" || Array.isArray(outcome)) { + return failureResponse("Executor failed: expected an ExecuteResult object.", { + emitted, + diagnostics, + code: "executor_failed", + }); + } const logs = executeLogs(outcome.logs); + if (outcome.error !== undefined && typeof outcome.error !== "string") { + return failureResponse("Executor failed: ExecuteResult.error must be a string.", { + logs, + emitted, + diagnostics, + code: "executor_failed", + }); + } if (outcome.error !== undefined) { // Executor bridges necessarily reduce thrown host errors to strings. // Match that terminal string back to the request-local typed failure so diff --git a/src/operator-ui/app/store.ts b/src/operator-ui/app/store.ts index 320a685e..d1035a92 100644 --- a/src/operator-ui/app/store.ts +++ b/src/operator-ui/app/store.ts @@ -617,9 +617,12 @@ export function testCredential(connector: string): Promise { /* Activity ---------------------------------------------------------------- */ +let activityRevision = 0; export async function loadActivity(reset: boolean): Promise { if (!state.data?.activityEnabled) return; - const current = fence(); + const identityCurrent = fence(); + const revision = ++activityRevision; + const current = () => identityCurrent() && revision === activityRevision; set({ activityPhase: "loading", activityNotice: null, @@ -636,6 +639,7 @@ export async function loadActivity(reset: boolean): Promise { current, ); if (!current()) return; + if (!payload || !Array.isArray(payload.events)) throw new RequestFailure("refused"); set({ activityPhase: "ready", activityEvents: [ diff --git a/src/operator-ui/generated.ts b/src/operator-ui/generated.ts index 0ce05c24..88c8c7fd 100644 --- a/src/operator-ui/generated.ts +++ b/src/operator-ui/generated.ts @@ -1,4 +1,4 @@ // Generated by scripts/build-operator-ui.mjs. Do not edit. // Source: src/operator-ui/app/main.tsx and src/operator-ui/browser.css. export const OPERATOR_UI_CSS: string = "/* src/operator-ui/tokens.css */\n:root {\n color-scheme: light;\n --accent: #2f5fe0;\n --radius: 10px;\n --sans:\n ui-sans-serif,\n system-ui,\n -apple-system,\n \"Segoe UI\",\n Roboto,\n \"Helvetica Neue\",\n Arial,\n sans-serif;\n --mono:\n ui-monospace,\n \"SF Mono\",\n Menlo,\n Monaco,\n \"Cascadia Code\",\n Consolas,\n monospace;\n --bg: #f6f7f9;\n --surface: #ffffff;\n --surface-2: #f1f3f6;\n --border: #e2e5ea;\n --border-strong: #cdd2da;\n --text: #131820;\n --muted: #5b6472;\n --ok: #12734a;\n --warn: #9a5b06;\n --danger: #bb3226;\n --on-accent: #ffffff;\n --link: var(--accent);\n --tint: color-mix(in srgb, var(--accent) 8%, var(--surface));\n --shell: 68rem;\n --pad: 1.25rem;\n --gap: 1rem;\n}\n@media (prefers-color-scheme: dark) {\n html:not([data-scheme=light]) {\n color-scheme: dark;\n }\n}\nhtml[data-scheme=dark] {\n color-scheme: dark;\n}\n@media (prefers-color-scheme: dark) {\n html:not([data-scheme=light]) {\n --bg: #0d1016;\n --surface: #151a21;\n --surface-2: #1c222c;\n --border: #262d39;\n --border-strong: #38414f;\n --text: #e6eaf1;\n --muted: #97a1b2;\n --ok: #4cc48c;\n --warn: #e2a33f;\n --danger: #f4776c;\n --link: color-mix(in srgb, var(--accent) 55%, #ffffff);\n --tint: color-mix(in srgb, var(--accent) 16%, var(--surface));\n }\n}\nhtml[data-scheme=dark] {\n --bg: #0d1016;\n --surface: #151a21;\n --surface-2: #1c222c;\n --border: #262d39;\n --border-strong: #38414f;\n --text: #e6eaf1;\n --muted: #97a1b2;\n --ok: #4cc48c;\n --warn: #e2a33f;\n --danger: #f4776c;\n --link: color-mix(in srgb, var(--accent) 55%, #ffffff);\n --tint: color-mix(in srgb, var(--accent) 16%, var(--surface));\n}\n\n/* src/operator-ui/page.css */\n* {\n box-sizing: border-box;\n}\nhtml {\n background: var(--bg);\n color: var(--text);\n font-family: var(--sans);\n font-size: 16px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\nbody {\n margin: 0;\n min-height: 100vh;\n}\n:is(h1, h2, h3, p, ul, ol) {\n margin: 0;\n padding: 0;\n}\n:is(h1, h2, h3) {\n font-weight: 600;\n line-height: 1.3;\n}\nh1 {\n font-size: 1.5rem;\n letter-spacing: -.01em;\n}\nh2 {\n font-size: 1rem;\n}\n:is(ul, ol) {\n list-style: none;\n}\na {\n color: var(--link);\n text-decoration-thickness: 1px;\n text-underline-offset: 2px;\n}\nbutton,\ninput {\n font: inherit;\n}\n:is(a, button, input, summary):focus-visible {\n border-radius: calc(var(--radius) / 2);\n outline: 2px solid var(--link);\n outline-offset: 2px;\n}\n.skip-link {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n left: var(--pad);\n padding: .5rem .75rem;\n position: fixed;\n top: -4rem;\n z-index: 10;\n}\n.skip-link:focus {\n top: var(--pad);\n}\n.shell {\n margin: 0 auto;\n max-width: var(--shell);\n padding-left: var(--pad);\n padding-right: var(--pad);\n}\n.cap,\n.meta {\n color: var(--muted);\n font-size: .875rem;\n}\n.mono {\n font-family: var(--mono);\n font-size: .8125rem;\n}\n.visually-hidden {\n clip-path: inset(50%);\n height: 1px;\n overflow: hidden;\n position: absolute;\n white-space: nowrap;\n width: 1px;\n}\n.masthead {\n align-items: center;\n background: var(--surface);\n border-bottom: 1px solid var(--border);\n display: flex;\n gap: var(--gap);\n justify-content: space-between;\n max-width: none;\n padding-bottom: .75rem;\n padding-top: .75rem;\n position: sticky;\n top: 0;\n z-index: 5;\n}\n.masthead-inner {\n align-items: center;\n display: flex;\n gap: var(--gap);\n justify-content: space-between;\n margin: 0 auto;\n max-width: var(--shell);\n width: 100%;\n}\n.mast-nav,\n.mast-actions,\n.page-nav,\n.session-actions {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n gap: .25rem;\n}\n.mast-nav {\n gap: var(--gap);\n}\n.mast-actions {\n gap: var(--gap);\n}\n.navlink {\n background: none;\n border: 0;\n border-radius: calc(var(--radius) - 2px);\n color: var(--muted);\n cursor: pointer;\n font-size: .9375rem;\n padding: .35rem .6rem;\n text-decoration: none;\n}\n.navlink:hover {\n background: var(--surface-2);\n color: var(--text);\n}\n.navlink[aria-current=page] {\n background: var(--tint);\n color: var(--link);\n font-weight: 500;\n}\n.brand,\n.product {\n padding-left: 0;\n padding-right: 0;\n text-decoration: none;\n}\n.brand {\n color: var(--text);\n font-weight: 600;\n}\n.brand:hover,\n.product:hover {\n background: none;\n}\n.product {\n color: var(--muted);\n}\n.page {\n padding-bottom: 4rem;\n padding-top: 2rem;\n}\n.lead {\n margin-bottom: 1.5rem;\n}\n.lead-copy {\n color: var(--muted);\n display: grid;\n gap: .5rem;\n margin-top: .35rem;\n}\n.lead-copy p {\n max-width: 60ch;\n}\n.btn {\n background: var(--surface);\n border: 1px solid var(--border-strong);\n border-radius: calc(var(--radius) - 2px);\n color: var(--text);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n font-size: .875rem;\n gap: .35rem;\n padding: .35rem .7rem;\n text-decoration: none;\n white-space: nowrap;\n}\n.btn:hover {\n background: var(--surface-2);\n}\n.btn:disabled {\n cursor: not-allowed;\n opacity: .55;\n}\n.btn.primary {\n background: var(--accent);\n border-color: var(--accent);\n color: var(--on-accent);\n}\n.btn.primary:hover {\n background: color-mix(in srgb, var(--accent) 88%, black);\n}\n.btn.danger {\n color: var(--danger);\n}\n.btn.danger:hover {\n background: color-mix(in srgb, var(--danger) 10%, var(--surface));\n}\n.btn.quiet {\n background: none;\n border-color: var(--border);\n color: var(--muted);\n}\n.btn.quiet:hover {\n background: var(--surface-2);\n color: var(--text);\n}\n.badge {\n align-items: center;\n background: var(--surface-2);\n border-radius: 999px;\n color: var(--muted);\n display: inline-flex;\n font-size: .75rem;\n gap: .3rem;\n line-height: 1.6;\n padding: .1rem .5rem;\n white-space: nowrap;\n}\n.badge.ok {\n background: color-mix(in srgb, var(--ok) 12%, var(--surface));\n color: var(--ok);\n}\n.badge.warn {\n background: color-mix(in srgb, var(--warn) 14%, var(--surface));\n color: var(--warn);\n}\n.badge.danger {\n background: color-mix(in srgb, var(--danger) 12%, var(--surface));\n color: var(--danger);\n}\n.badge.accent {\n background: var(--tint);\n color: var(--link);\n}\n.msg {\n background: color-mix(in srgb, var(--danger) 8%, var(--surface));\n border: 1px solid color-mix(in srgb, var(--danger) 28%, var(--surface));\n border-radius: calc(var(--radius) - 2px);\n color: var(--danger);\n font-size: .875rem;\n padding: .5rem .75rem;\n}\n.status-page {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n display: grid;\n gap: .75rem;\n margin: 1.5rem auto 0;\n max-width: 34rem;\n padding: 1.5rem;\n}\n.status-head {\n align-items: center;\n display: flex;\n gap: .6rem;\n}\n.status-mark {\n align-items: center;\n background: var(--surface-2);\n border-radius: 50%;\n color: var(--muted);\n display: inline-flex;\n flex: none;\n height: 2rem;\n justify-content: center;\n width: 2rem;\n}\n.status-mark svg {\n height: 1.25rem;\n width: 1.25rem;\n}\n.status-mark.ok {\n background: color-mix(in srgb, var(--ok) 14%, var(--surface));\n color: var(--ok);\n}\n.status-mark.danger {\n background: color-mix(in srgb, var(--danger) 12%, var(--surface));\n color: var(--danger);\n}\n.status-label {\n color: var(--muted);\n font-size: .875rem;\n font-weight: 600;\n}\n.status-label.ok {\n color: var(--ok);\n}\n.status-label.danger {\n color: var(--danger);\n}\n.status-page h1 {\n overflow-wrap: anywhere;\n}\n.status-copy {\n color: var(--muted);\n}\n.status-actions {\n display: flex;\n flex-wrap: wrap;\n gap: .5rem;\n margin-top: .25rem;\n}\n.status-details {\n border-top: 1px solid var(--border);\n color: var(--muted);\n font-size: .875rem;\n margin-top: .25rem;\n padding-top: .75rem;\n}\n.status-details > summary {\n cursor: pointer;\n width: fit-content;\n}\n.status-details > p {\n margin-top: .5rem;\n}\n.status-details pre {\n background: var(--surface-2);\n border: 1px solid var(--border);\n border-radius: calc(var(--radius) / 2);\n color: var(--text);\n font-family: var(--mono);\n font-size: .75rem;\n line-height: 1.55;\n margin: .5rem 0 0;\n max-height: 18rem;\n overflow: auto;\n overflow-wrap: anywhere;\n padding: .5rem .6rem;\n white-space: pre-wrap;\n}\n@media (max-width: 40rem) {\n :root {\n --pad: 1rem;\n }\n .status-page {\n margin-top: 0;\n padding: 1.25rem var(--pad);\n }\n}\n\n/* src/operator-ui/browser.css */\n.masthead-inner {\n min-height: calc(.9375rem * 1.5 + .7rem);\n}\ninput:not([type=checkbox], [type=radio], [type=hidden]) {\n background: var(--surface);\n border: 1px solid var(--border-strong);\n border-radius: calc(var(--radius) - 2px);\n color: var(--text);\n min-height: 2.25rem;\n padding: .3rem .6rem;\n width: 100%;\n}\ninput::placeholder {\n color: var(--muted);\n}\n.row {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n gap: .5rem;\n}\n.row input:not([type=checkbox], [type=radio]) {\n flex: 1 1 14rem;\n width: auto;\n}\ninput:disabled {\n opacity: .6;\n}\n.check {\n align-items: center;\n cursor: pointer;\n display: inline-flex;\n gap: .4rem;\n}\n.check input {\n accent-color: var(--accent);\n margin: 0;\n}\n.actions {\n display: flex;\n flex-wrap: wrap;\n gap: .5rem;\n}\n.dot {\n border-radius: 50%;\n display: inline-block;\n flex: none;\n height: .5rem;\n width: .5rem;\n background: var(--muted);\n}\n.dot.ok,\n.dot.success,\n.dot.approved {\n background: var(--ok);\n}\n.dot.auth_required,\n.dot.warn,\n.dot.paused {\n background: var(--warn);\n}\n.dot.error,\n.dot.timeout {\n background: var(--danger);\n}\n.dot.loading {\n background: var(--border-strong);\n}\n.section {\n display: grid;\n gap: .75rem;\n margin-top: 1.75rem;\n}\n.section-head {\n align-items: baseline;\n display: flex;\n gap: var(--gap);\n justify-content: space-between;\n}\n.unavailable {\n background: var(--surface);\n border: 1px dashed var(--border-strong);\n border-radius: var(--radius);\n color: var(--muted);\n padding: 1.5rem var(--pad);\n}\n.state-block {\n align-items: center;\n background: var(--surface);\n border: 1px dashed var(--border-strong);\n border-radius: var(--radius);\n color: var(--muted);\n display: flex;\n flex-direction: column;\n gap: .5rem;\n padding: 1.75rem var(--pad);\n text-align: center;\n}\n.state-block.error {\n border-color: color-mix(in srgb, var(--danger) 35%, var(--border));\n border-style: solid;\n}\n.state-title {\n color: var(--text);\n font-weight: 600;\n}\n.state-copy {\n max-width: 52ch;\n}\n.state-block .btn {\n margin-top: .25rem;\n}\n.collection {\n display: grid;\n gap: .75rem;\n}\n.msg.warn {\n background: color-mix(in srgb, var(--warn) 9%, var(--surface));\n border-color: color-mix(in srgb, var(--warn) 32%, var(--surface));\n color: var(--text);\n}\n.error-notice {\n color: var(--danger);\n}\n.notice:empty {\n block-size: 0;\n margin: 0;\n}\n.summary {\n color: var(--muted);\n font-size: .875rem;\n}\n.summary .sep {\n opacity: .5;\n}\n.summary .warn {\n color: var(--warn);\n}\n.summary .danger {\n color: var(--danger);\n}\n.endpoint {\n align-items: center;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n display: flex;\n gap: .75rem;\n justify-content: space-between;\n padding: .5rem .5rem .5rem .75rem;\n}\n.endpoint code {\n flex: 1 1 auto;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n.endpoints,\n.endpoint-block {\n display: grid;\n gap: .35rem;\n}\n.endpoints {\n gap: .6rem;\n}\n.endpoint-label {\n flex: none;\n}\n.setup-list {\n display: grid;\n gap: .6rem;\n margin-top: .5rem;\n}\n.setup-item {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: calc(var(--radius) - 2px);\n display: grid;\n gap: .35rem;\n padding: .5rem .6rem .6rem .75rem;\n}\n.setup-head {\n align-items: center;\n display: flex;\n gap: .5rem;\n justify-content: space-between;\n}\n.setup-code,\n.fix-prompt-text {\n background: var(--surface-2);\n border-radius: calc(var(--radius) / 2);\n color: var(--text);\n font-family: var(--mono);\n font-size: .75rem;\n line-height: 1.55;\n margin: 0;\n overflow-wrap: anywhere;\n padding: .5rem .6rem;\n white-space: pre-wrap;\n}\n.fix-prompt {\n align-items: baseline;\n display: flex;\n flex-wrap: wrap;\n gap: .35rem .75rem;\n}\n.fix-prompt > details {\n flex: 1 1 12rem;\n}\n.fix-prompt > details[open] {\n flex-basis: 100%;\n}\n.fix-prompt-preview > .meta {\n margin-top: .4rem;\n}\n.fix-prompt-preview .fix-prompt-text {\n border: 1px solid var(--border);\n margin-top: .4rem;\n max-height: 18rem;\n overflow: auto;\n}\n.rows {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n overflow: hidden;\n}\n.rows > * + * {\n border-top: 1px solid var(--border);\n}\n.conn.open > .conn-head {\n background: var(--surface-2);\n}\n.conn-head {\n align-items: center;\n display: flex;\n gap: .75rem;\n justify-content: space-between;\n padding: .7rem var(--pad);\n position: relative;\n}\n.conn-head:hover {\n background: var(--surface-2);\n}\n.conn-main {\n align-items: center;\n display: flex;\n gap: .6rem;\n min-width: 0;\n}\n.conn-name {\n font-size: 1rem;\n font-weight: 500;\n overflow-wrap: anywhere;\n}\n.conn-toggle {\n background: none;\n border: 0;\n color: var(--text);\n cursor: pointer;\n font: inherit;\n padding: 0;\n text-align: left;\n}\n.conn-toggle::after {\n content: \"\";\n inset: 0;\n position: absolute;\n}\n.conn-toggle:focus-visible {\n outline: none;\n}\n.conn-toggle:focus-visible::after {\n border-radius: calc(var(--radius) - 2px);\n outline: 2px solid var(--link);\n outline-offset: -2px;\n}\n.conn-id {\n color: var(--muted);\n}\n.conn-badges {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n gap: .35rem;\n justify-content: flex-end;\n}\n.conn-caret {\n border-right: 1.5px solid var(--muted);\n border-bottom: 1.5px solid var(--muted);\n flex: none;\n height: .4rem;\n rotate: -45deg;\n transform-origin: center;\n width: .4rem;\n}\n.conn.open .conn-caret {\n rotate: 45deg;\n}\n.conn-body {\n background: var(--surface);\n border-top: 1px solid var(--border);\n display: grid;\n gap: .75rem;\n padding: var(--pad);\n}\n.conn-body[hidden] {\n display: none;\n}\n.conn-note {\n color: var(--muted);\n max-width: 70ch;\n}\n.subcard {\n background: var(--surface-2);\n border: 1px solid var(--border);\n border-radius: calc(var(--radius) - 2px);\n display: grid;\n gap: .5rem;\n padding: .75rem;\n}\n.subcard-head {\n align-items: baseline;\n display: flex;\n flex-wrap: wrap;\n gap: .5rem;\n justify-content: space-between;\n}\n.subcard-head h3 {\n font-size: .9375rem;\n}\n.confirm {\n background: color-mix(in srgb, var(--danger) 6%, var(--surface));\n border: 1px solid color-mix(in srgb, var(--danger) 28%, var(--surface));\n border-radius: calc(var(--radius) - 2px);\n display: grid;\n gap: .5rem;\n padding: .6rem .75rem;\n}\n.confirm p {\n max-width: 70ch;\n}\ndetails > .subcard,\ndetails > .tool-list {\n margin-top: .5rem;\n}\n.tool-list {\n display: grid;\n gap: .4rem;\n max-height: 22rem;\n overflow: auto;\n}\n.filter {\n flex: 0 1 18rem;\n min-width: 10rem;\n width: auto;\n}\n.connector-drift {\n display: grid;\n gap: .15rem;\n}\n.tool {\n display: grid;\n gap: .1rem;\n border-left: 2px solid var(--border-strong);\n padding-left: .6rem;\n}\n.tool code {\n font-family: var(--mono);\n font-size: .8125rem;\n overflow-wrap: anywhere;\n}\n.tool-head {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n gap: .25rem .5rem;\n}\n.tool-legend {\n margin-bottom: .15rem;\n}\n.td {\n color: var(--muted);\n font-size: .8125rem;\n}\ndetails > summary {\n cursor: pointer;\n}\n.disclosure {\n color: var(--link);\n font-size: .875rem;\n list-style: none;\n}\n.disclosure::-webkit-details-marker {\n display: none;\n}\n.disclosure::before {\n content: \"▸ \";\n}\ndetails[open] > .disclosure::before {\n content: \"▾ \";\n}\n.drift-counts {\n display: grid;\n gap: .5rem;\n grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));\n margin-top: .5rem;\n}\n.drift-count {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: calc(var(--radius) - 2px);\n display: grid;\n gap: .1rem;\n padding: .4rem .6rem;\n}\n.drift-count.flagged {\n border-color: color-mix(in srgb, var(--warn) 45%, var(--surface));\n}\n.drift-count-value {\n font-size: 1.125rem;\n font-weight: 600;\n}\n.drift-count.flagged .drift-count-value {\n color: var(--warn);\n}\n.drift-count-label {\n color: var(--muted);\n font-size: .75rem;\n}\n.credential-fields,\n.credential-field-summary {\n display: grid;\n gap: .5rem;\n}\n.credential-field {\n display: grid;\n gap: .25rem;\n}\n.credential-field label {\n color: var(--muted);\n font-size: .8125rem;\n}\n.credential-field-summary > div {\n display: flex;\n gap: .5rem;\n justify-content: space-between;\n}\n.credential-form {\n display: grid;\n gap: .5rem;\n}\n.credential-form .actions {\n justify-content: flex-end;\n}\n.activity-list {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n overflow: hidden;\n}\n.activity-list > * + * {\n border-top: 1px solid var(--border);\n}\n.activity-item {\n align-items: center;\n display: grid;\n gap: .5rem var(--gap);\n grid-template-columns: minmax(0, 14rem) minmax(0, 1fr) auto;\n padding: .6rem var(--pad);\n}\n.activity-stamp {\n align-items: center;\n display: flex;\n gap: .6rem;\n min-width: 0;\n}\n.activity-time {\n display: block;\n font-size: .8125rem;\n}\n.activity-actor {\n color: var(--muted);\n font-size: .8125rem;\n}\n.activity-actor-id {\n color: var(--muted);\n}\n.activity-address {\n font-family: var(--mono);\n font-size: .8125rem;\n overflow-wrap: anywhere;\n}\n.activity-detail {\n color: var(--muted);\n font-size: .8125rem;\n}\n.activity-result {\n display: grid;\n gap: .15rem;\n justify-items: end;\n}\n.activity-more {\n justify-self: start;\n}\n.artifact-row {\n align-items: center;\n display: grid;\n gap: .25rem var(--gap);\n grid-template-columns: minmax(0, 1fr) auto;\n padding: .6rem var(--pad);\n}\n.artifact-row .artifact-title {\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n.artifact-row .artifact-meta,\n.artifact-meta {\n color: var(--muted);\n font-size: .8125rem;\n}\n.artifact-badges {\n display: flex;\n flex-wrap: wrap;\n gap: .35rem;\n justify-content: flex-end;\n}\n.artifact-head {\n display: grid;\n gap: .35rem;\n margin-bottom: .75rem;\n}\n.navlink.inline {\n font-size: inherit;\n padding: 0 .2rem;\n}\n.artifact-banner {\n background: color-mix(in srgb, var(--warn) 12%, var(--surface));\n border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--border));\n border-radius: var(--radius);\n color: var(--text);\n padding: .5rem .75rem;\n}\n.artifact-frame {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n display: block;\n height: calc(100vh - 14rem);\n min-height: 28rem;\n width: 100%;\n}\n.gate-form {\n max-width: 36rem;\n}\n@media (max-width: 40rem) {\n .masthead {\n position: static;\n }\n .masthead-inner {\n flex-wrap: wrap;\n row-gap: .35rem;\n }\n #operatorNav,\n #operatorNav .mast-actions {\n display: contents;\n }\n .session-actions {\n margin-left: auto;\n }\n .page-nav {\n flex: 1 0 100%;\n flex-wrap: nowrap;\n margin-left: -.6rem;\n order: 3;\n overflow-x: auto;\n }\n .conn-head {\n align-items: flex-start;\n flex-direction: column;\n gap: .4rem;\n }\n .conn-badges {\n justify-content: flex-start;\n }\n .endpoint {\n flex-wrap: wrap;\n }\n .section-head {\n flex-wrap: wrap;\n }\n .filter {\n flex: 1 1 100%;\n }\n .activity-item {\n grid-template-columns: minmax(0, 1fr);\n }\n .activity-result {\n justify-items: start;\n }\n .artifact-row {\n grid-template-columns: minmax(0, 1fr);\n }\n .artifact-badges {\n justify-content: flex-start;\n }\n}\n.token-create,\n.token-reveal {\n margin-bottom: 24px;\n}\n.token-create > label {\n display: block;\n margin-bottom: 8px;\n}\n.token-create input {\n flex: 1;\n min-width: 0;\n}\n.token-reveal {\n border: 1px solid var(--rule);\n padding: 20px;\n}\n.token-reveal-head,\n.token-card-head {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n}\n.token-secret {\n overflow-wrap: anywhere;\n margin: 12px 0;\n}\n.token-card {\n border-top: 1px solid var(--rule);\n padding: 20px 0;\n}\n.token-card.revoked {\n color: var(--muted);\n}\n"; -export const OPERATOR_UI_SCRIPT: string = "\"use strict\";\n(() => {\n // node_modules/preact/dist/preact.module.js\n var n;\n var l;\n var u;\n var t;\n var i;\n var r;\n var o;\n var e;\n var f;\n var c;\n var a;\n var s;\n var h;\n var p;\n var v;\n var y;\n var d = {};\n var w = [];\n var _ = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;\n var g = Array.isArray;\n function m(n2, l3) {\n for (var u4 in l3) n2[u4] = l3[u4];\n return n2;\n }\n function b(n2) {\n n2 && n2.parentNode && n2.parentNode.removeChild(n2);\n }\n function k(l3, u4, t3) {\n var i3, r3, o3, e3 = {};\n for (o3 in u4) \"key\" == o3 ? i3 = u4[o3] : \"ref\" == o3 ? r3 = u4[o3] : e3[o3] = u4[o3];\n if (arguments.length > 2 && (e3.children = arguments.length > 3 ? n.call(arguments, 2) : t3), \"function\" == typeof l3 && null != l3.defaultProps) for (o3 in l3.defaultProps) void 0 === e3[o3] && (e3[o3] = l3.defaultProps[o3]);\n return x(l3, e3, i3, r3, null);\n }\n function x(n2, t3, i3, r3, o3) {\n var e3 = { type: n2, props: t3, key: i3, ref: r3, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: null == o3 ? ++u : o3, __i: -1, __u: 0 };\n return null == o3 && null != l.vnode && l.vnode(e3), e3;\n }\n function S(n2) {\n return n2.children;\n }\n function C(n2, l3) {\n this.props = n2, this.context = l3;\n }\n function $(n2, l3) {\n if (null == l3) return n2.__ ? $(n2.__, n2.__i + 1) : null;\n for (var u4; l3 < n2.__k.length; l3++) if (null != (u4 = n2.__k[l3]) && null != u4.__e) return u4.__e;\n return \"function\" == typeof n2.type ? $(n2) : null;\n }\n function I(n2) {\n if (n2.__P && n2.__d) {\n var u4 = n2.__v, t3 = u4.__e, i3 = [], r3 = [], o3 = m({}, u4);\n o3.__v = u4.__v + 1, l.vnode && l.vnode(o3), q(n2.__P, o3, u4, n2.__n, n2.__P.namespaceURI, 32 & u4.__u ? [t3] : null, i3, null == t3 ? $(u4) : t3, !!(32 & u4.__u), r3), o3.__v = u4.__v, o3.__.__k[o3.__i] = o3, D(i3, o3, r3), u4.__e = u4.__ = null, o3.__e != t3 && P(o3);\n }\n }\n function P(n2) {\n if (null != (n2 = n2.__) && null != n2.__c) return n2.__e = n2.__c.base = null, n2.__k.some(function(l3) {\n if (null != l3 && null != l3.__e) return n2.__e = n2.__c.base = l3.__e;\n }), P(n2);\n }\n function A(n2) {\n (!n2.__d && (n2.__d = true) && i.push(n2) && !H.__r++ || r != l.debounceRendering) && ((r = l.debounceRendering) || o)(H);\n }\n function H() {\n try {\n for (var n2, l3 = 1; i.length; ) i.length > l3 && i.sort(e), n2 = i.shift(), l3 = i.length, I(n2);\n } finally {\n i.length = H.__r = 0;\n }\n }\n function L(n2, l3, u4, t3, i3, r3, o3, e3, f4, c3, a3) {\n var s3, h3, p3, v3, y3, _3, g2 = t3 && t3.__k || w, m3 = l3.length;\n for (f4 = T(u4, l3, g2, f4, m3), s3 = 0; s3 < m3; s3++) null != (p3 = u4.__k[s3]) && (h3 = -1 != p3.__i && g2[p3.__i] || d, p3.__i = s3, _3 = q(n2, p3, h3, i3, r3, o3, e3, f4, c3, a3), v3 = p3.__e, p3.ref && h3.ref != p3.ref && (h3.ref && J(h3.ref, null, p3), a3.push(p3.ref, p3.__c || v3, p3)), null == y3 && null != v3 && (y3 = v3), 4 & p3.__u ? (f4 = j(p3, f4, n2), h3.__e && (h3.__e = null)) : \"function\" == typeof p3.type && void 0 !== _3 ? f4 = _3 : v3 && (f4 = v3.nextSibling), p3.__u &= -7);\n return u4.__e = y3, f4;\n }\n function T(n2, l3, u4, t3, i3) {\n var r3, o3, e3, f4, c3, a3 = u4.length, s3 = a3, h3 = 0;\n for (n2.__k = new Array(i3), r3 = 0; r3 < i3; r3++) null != (o3 = l3[r3]) && \"boolean\" != typeof o3 && \"function\" != typeof o3 ? (\"string\" == typeof o3 || \"number\" == typeof o3 || \"bigint\" == typeof o3 || o3.constructor == String ? o3 = n2.__k[r3] = x(null, o3, null, null, null) : g(o3) ? o3 = n2.__k[r3] = x(S, { children: o3 }, null, null, null) : void 0 === o3.constructor && o3.__b > 0 ? o3 = n2.__k[r3] = x(o3.type, o3.props, o3.key, o3.ref ? o3.ref : null, o3.__v) : n2.__k[r3] = o3, f4 = r3 + h3, o3.__ = n2, o3.__b = n2.__b + 1, e3 = null, -1 != (c3 = o3.__i = O(o3, u4, f4, s3)) && (s3--, (e3 = u4[c3]) && (e3.__u |= 2)), null == e3 || null == e3.__v ? (-1 == c3 && (i3 > a3 ? h3-- : i3 < a3 && h3++), \"function\" != typeof o3.type && (o3.__u |= 4)) : c3 != f4 && (c3 == f4 - 1 ? h3-- : c3 == f4 + 1 ? h3++ : (c3 > f4 ? h3-- : h3++, o3.__u |= 4))) : n2.__k[r3] = null;\n if (s3) for (r3 = 0; r3 < a3; r3++) null != (e3 = u4[r3]) && 0 == (2 & e3.__u) && (e3.__e == t3 && (t3 = $(e3)), K(e3, e3));\n return t3;\n }\n function j(n2, l3, u4) {\n var t3, i3;\n if (\"function\" == typeof n2.type) {\n for (t3 = n2.__k, i3 = 0; t3 && i3 < t3.length; i3++) t3[i3] && (t3[i3].__ = n2, l3 = j(t3[i3], l3, u4));\n return l3;\n }\n n2.__e != l3 && (l3 && n2.type && !l3.parentNode && (l3 = $(n2)), l3 = u4.insertBefore(n2.__e, l3 || null));\n do {\n l3 = l3 && l3.nextSibling;\n } while (null != l3 && 8 == l3.nodeType);\n return l3;\n }\n function O(n2, l3, u4, t3) {\n var i3, r3, o3, e3 = n2.key, f4 = n2.type, c3 = l3[u4], a3 = null != c3 && 0 == (2 & c3.__u);\n if (null === c3 && null == e3 || a3 && e3 == c3.key && f4 == c3.type) return u4;\n if (t3 > (a3 ? 1 : 0)) {\n for (i3 = u4 - 1, r3 = u4 + 1; i3 >= 0 || r3 < l3.length; ) if (null != (c3 = l3[o3 = i3 >= 0 ? i3-- : r3++]) && 0 == (2 & c3.__u) && e3 == c3.key && f4 == c3.type) return o3;\n }\n return -1;\n }\n function z(n2, l3, u4) {\n \"-\" == l3[0] ? n2.setProperty(l3, null == u4 ? \"\" : u4) : n2[l3] = null == u4 ? \"\" : \"number\" != typeof u4 || _.test(l3) ? u4 : u4 + \"px\";\n }\n function N(n2, l3, u4, t3, i3) {\n var r3, o3;\n n: if (\"style\" == l3) if (\"string\" == typeof u4) n2.style.cssText = u4;\n else {\n if (\"string\" == typeof t3 && (n2.style.cssText = t3 = \"\"), t3) for (l3 in t3) u4 && l3 in u4 || z(n2.style, l3, \"\");\n if (u4) for (l3 in u4) t3 && u4[l3] == t3[l3] || z(n2.style, l3, u4[l3]);\n }\n else if (\"o\" == l3[0] && \"n\" == l3[1]) r3 = l3 != (l3 = l3.replace(s, \"$1\")), o3 = l3.toLowerCase(), l3 = o3 in n2 || \"onFocusOut\" == l3 || \"onFocusIn\" == l3 ? o3.slice(2) : l3.slice(2), n2.l || (n2.l = {}), n2.l[l3 + r3] = u4, u4 ? t3 ? u4[a] = t3[a] : (u4[a] = h, n2.addEventListener(l3, r3 ? v : p, r3)) : n2.removeEventListener(l3, r3 ? v : p, r3);\n else {\n if (\"http://www.w3.org/2000/svg\" == i3) l3 = l3.replace(/xlink(H|:h)/, \"h\").replace(/sName$/, \"s\");\n else if (\"width\" != l3 && \"height\" != l3 && \"href\" != l3 && \"list\" != l3 && \"form\" != l3 && \"tabIndex\" != l3 && \"download\" != l3 && \"rowSpan\" != l3 && \"colSpan\" != l3 && \"role\" != l3 && \"popover\" != l3 && l3 in n2) try {\n n2[l3] = null == u4 ? \"\" : u4;\n break n;\n } catch (n3) {\n }\n \"function\" == typeof u4 || (null == u4 || false === u4 && \"-\" != l3[4] ? n2.removeAttribute(l3) : n2.setAttribute(l3, \"popover\" == l3 && 1 == u4 ? \"\" : u4));\n }\n }\n function V(n2) {\n return function(u4) {\n if (this.l) {\n var t3 = this.l[u4.type + n2];\n if (null == u4[c]) u4[c] = h++;\n else if (u4[c] < t3[a]) return;\n return t3(l.event ? l.event(u4) : u4);\n }\n };\n }\n function q(n2, u4, t3, i3, r3, o3, e3, f4, c3, a3) {\n var s3, h3, p3, v3, y3, d3, _3, k3, x2, M, I2, P2, A3, H2, T3, j3, F = u4.type;\n if (void 0 !== u4.constructor) return null;\n 128 & t3.__u && (c3 = !!(32 & t3.__u), o3 = [f4 = u4.__e = t3.__e]), (s3 = l.__b) && s3(u4);\n n: if (\"function\" == typeof F) {\n h3 = e3.length;\n try {\n if (x2 = u4.props, M = F.prototype && F.prototype.render, I2 = (s3 = F.contextType) && i3[s3.__c], P2 = s3 ? I2 ? I2.props.value : s3.__ : i3, t3.__c ? k3 = (p3 = u4.__c = t3.__c).__ = p3.__E : (M ? u4.__c = p3 = new F(x2, P2) : (u4.__c = p3 = new C(x2, P2), p3.constructor = F, p3.render = Q), I2 && I2.sub(p3), p3.state || (p3.state = {}), p3.__n = i3, v3 = p3.__d = true, p3.__h = [], p3._sb = []), M && null == p3.__s && (p3.__s = p3.state), M && null != F.getDerivedStateFromProps && (p3.__s == p3.state && (p3.__s = m({}, p3.__s)), m(p3.__s, F.getDerivedStateFromProps(x2, p3.__s))), y3 = p3.props, d3 = p3.state, p3.__v = u4, v3) M && null == F.getDerivedStateFromProps && null != p3.componentWillMount && p3.componentWillMount(), M && null != p3.componentDidMount && p3.__h.push(p3.componentDidMount);\n else {\n if (M && null == F.getDerivedStateFromProps && x2 !== y3 && null != p3.componentWillReceiveProps && p3.componentWillReceiveProps(x2, P2), u4.__v == t3.__v || !p3.__e && null != p3.shouldComponentUpdate && false === p3.shouldComponentUpdate(x2, p3.__s, P2)) {\n u4.__v != t3.__v && (p3.props = x2, p3.state = p3.__s, p3.__d = false), u4.__e = t3.__e, u4.__k = t3.__k, u4.__k.some(function(n3) {\n n3 && (n3.__ = u4);\n }), w.push.apply(p3.__h, p3._sb), p3._sb = [], p3.__h.length && e3.push(p3), f4 = $(t3);\n break n;\n }\n null != p3.componentWillUpdate && p3.componentWillUpdate(x2, p3.__s, P2), M && null != p3.componentDidUpdate && p3.__h.push(function() {\n p3.componentDidUpdate(y3, d3, _3);\n });\n }\n if (p3.context = P2, p3.props = x2, p3.__P = n2, p3.__e = false, A3 = l.__r, H2 = 0, M) p3.state = p3.__s, p3.__d = false, A3 && A3(u4), s3 = p3.render(p3.props, p3.state, p3.context), w.push.apply(p3.__h, p3._sb), p3._sb = [];\n else do {\n p3.__d = false, A3 && A3(u4), s3 = p3.render(p3.props, p3.state, p3.context), p3.state = p3.__s;\n } while (p3.__d && ++H2 < 25);\n p3.state = p3.__s, null != p3.getChildContext && (i3 = m(m({}, i3), p3.getChildContext())), M && !v3 && null != p3.getSnapshotBeforeUpdate && (_3 = p3.getSnapshotBeforeUpdate(y3, d3)), T3 = null != s3 && s3.type === S && null == s3.key ? E(s3.props.children) : s3, f4 = L(n2, g(T3) ? T3 : [T3], u4, t3, i3, r3, o3, e3, f4, c3, a3), p3.base = u4.__e, u4.__u &= -161, p3.__h.length && e3.push(p3), k3 && (p3.__E = p3.__ = null);\n } catch (n3) {\n if (e3.length = h3, u4.__v = null, c3 || null != o3) {\n if (n3.then) {\n for (u4.__u |= c3 ? 160 : 128; f4 && 8 == f4.nodeType && f4.nextSibling; ) f4 = f4.nextSibling;\n null != o3 && (o3[o3.indexOf(f4)] = null), u4.__e = f4;\n } else if (null != o3) for (j3 = o3.length; j3--; ) b(o3[j3]);\n } else u4.__e = t3.__e;\n null == u4.__k && (u4.__k = t3.__k || []), n3.then || B(u4), l.__e(n3, u4, t3);\n }\n } else null == o3 && u4.__v == t3.__v ? (u4.__k = t3.__k, u4.__e = t3.__e) : f4 = u4.__e = G(t3.__e, u4, t3, i3, r3, o3, e3, c3, a3);\n return (s3 = l.diffed) && s3(u4), 128 & u4.__u ? void 0 : f4;\n }\n function B(n2) {\n n2 && (n2.__c && (n2.__c.__e = true), n2.__k && n2.__k.some(B));\n }\n function D(n2, u4, t3) {\n for (var i3 = 0; i3 < t3.length; i3++) J(t3[i3], t3[++i3], t3[++i3]);\n l.__c && l.__c(u4, n2), n2.some(function(u5) {\n try {\n n2 = u5.__h, u5.__h = [], n2.some(function(n3) {\n n3.call(u5);\n });\n } catch (n3) {\n l.__e(n3, u5.__v);\n }\n });\n }\n function E(n2) {\n return \"object\" != typeof n2 || null == n2 || n2.__b > 0 ? n2 : g(n2) ? n2.map(E) : void 0 !== n2.constructor ? null : m({}, n2);\n }\n function G(u4, t3, i3, r3, o3, e3, f4, c3, a3) {\n var s3, h3, p3, v3, y3, w3, _3, m3 = i3.props || d, k3 = t3.props, x2 = t3.type;\n if (\"svg\" == x2 ? o3 = \"http://www.w3.org/2000/svg\" : \"math\" == x2 ? o3 = \"http://www.w3.org/1998/Math/MathML\" : o3 || (o3 = \"http://www.w3.org/1999/xhtml\"), null != e3) {\n for (s3 = 0; s3 < e3.length; s3++) if ((y3 = e3[s3]) && \"setAttribute\" in y3 == !!x2 && (x2 ? y3.localName == x2 : 3 == y3.nodeType)) {\n u4 = y3, e3[s3] = null;\n break;\n }\n }\n if (null == u4) {\n if (null == x2) return document.createTextNode(k3);\n u4 = document.createElementNS(o3, x2, k3.is && k3), c3 && (l.__m && l.__m(t3, e3), c3 = false), e3 = null;\n }\n if (null == x2) m3 === k3 || c3 && u4.data == k3 || (u4.data = k3);\n else {\n if (e3 = \"textarea\" == x2 && null != k3.defaultValue ? null : e3 && n.call(u4.childNodes), !c3 && null != e3) for (m3 = {}, s3 = 0; s3 < u4.attributes.length; s3++) m3[(y3 = u4.attributes[s3]).name] = y3.value;\n for (s3 in m3) y3 = m3[s3], \"dangerouslySetInnerHTML\" == s3 ? p3 = y3 : \"children\" == s3 || s3 in k3 || \"value\" == s3 && \"defaultValue\" in k3 || \"checked\" == s3 && \"defaultChecked\" in k3 || N(u4, s3, null, y3, o3);\n for (s3 in k3) y3 = k3[s3], \"children\" == s3 ? v3 = y3 : \"dangerouslySetInnerHTML\" == s3 ? h3 = y3 : \"value\" == s3 ? w3 = y3 : \"checked\" == s3 ? _3 = y3 : c3 && \"function\" != typeof y3 || m3[s3] === y3 || N(u4, s3, y3, m3[s3], o3);\n if (h3) c3 || p3 && (h3.__html == p3.__html || h3.__html == u4.innerHTML) || (u4.innerHTML = h3.__html), t3.__k = [];\n else if (p3 && (u4.innerHTML = \"\"), L(\"template\" == t3.type ? u4.content : u4, g(v3) ? v3 : [v3], t3, i3, r3, \"foreignObject\" == x2 ? \"http://www.w3.org/1999/xhtml\" : o3, e3, f4, e3 ? e3[0] : i3.__k && $(i3, 0), c3, a3), null != e3) for (s3 = e3.length; s3--; ) b(e3[s3]);\n c3 && \"textarea\" != x2 || (s3 = \"value\", \"progress\" == x2 && null == w3 ? u4.removeAttribute(\"value\") : null != w3 && (w3 !== u4[s3] || \"progress\" == x2 && !w3 || \"option\" == x2 && w3 != m3[s3]) && N(u4, s3, w3, m3[s3], o3), s3 = \"checked\", null != _3 && _3 != u4[s3] && N(u4, s3, _3, m3[s3], o3));\n }\n return u4;\n }\n function J(n2, u4, t3) {\n try {\n if (\"function\" == typeof n2) {\n var i3 = \"function\" == typeof n2.__u;\n i3 && n2.__u(), i3 && null == u4 || (n2.__u = n2(u4));\n } else n2.current = u4;\n } catch (n3) {\n l.__e(n3, t3);\n }\n }\n function K(n2, u4, t3) {\n var i3, r3;\n if (l.unmount && l.unmount(n2), (i3 = n2.ref) && (i3.current && i3.current != n2.__e || J(i3, null, u4)), null != (i3 = n2.__c)) {\n if (i3.componentWillUnmount) try {\n i3.componentWillUnmount();\n } catch (n3) {\n l.__e(n3, u4);\n }\n i3.base = i3.__P = i3.__n = null;\n }\n if (i3 = n2.__k) for (r3 = 0; r3 < i3.length; r3++) i3[r3] && K(i3[r3], u4, t3 || \"function\" != typeof n2.type);\n t3 || b(n2.__e), n2.__c = n2.__ = n2.__e = void 0;\n }\n function Q(n2, l3, u4) {\n return this.constructor(n2, u4);\n }\n function R(u4, t3, i3) {\n var r3, o3, e3, f4;\n t3 == document && (t3 = document.documentElement), l.__ && l.__(u4, t3), o3 = (r3 = \"function\" == typeof i3) ? null : i3 && i3.__k || t3.__k, e3 = [], f4 = [], q(t3, u4 = (!r3 && i3 || t3).__k = k(S, null, [u4]), o3 || d, d, t3.namespaceURI, !r3 && i3 ? [i3] : o3 ? null : t3.firstChild ? n.call(t3.childNodes) : null, e3, !r3 && i3 ? i3 : o3 ? o3.__e : t3.firstChild, r3, f4), D(e3, u4, f4), u4.props.children = null;\n }\n n = w.slice, l = { __e: function(n2, l3, u4, t3) {\n for (var i3, r3, o3; l3 = l3.__; ) if ((i3 = l3.__c) && !i3.__) try {\n if ((r3 = i3.constructor) && null != r3.getDerivedStateFromError && (i3.setState(r3.getDerivedStateFromError(n2)), o3 = i3.__d), null != i3.componentDidCatch && (i3.componentDidCatch(n2, t3 || {}), o3 = i3.__d), o3) return i3.__E = i3;\n } catch (l4) {\n n2 = l4;\n }\n throw n2;\n } }, u = 0, t = function(n2) {\n return null != n2 && void 0 === n2.constructor;\n }, C.prototype.setState = function(n2, l3) {\n var u4;\n u4 = null != this.__s && this.__s != this.state ? this.__s : this.__s = m({}, this.state), \"function\" == typeof n2 && (n2 = n2(m({}, u4), this.props)), n2 && m(u4, n2), null != n2 && this.__v && (l3 && this._sb.push(l3), A(this));\n }, C.prototype.forceUpdate = function(n2) {\n this.__v && (this.__e = true, n2 && this.__h.push(n2), A(this));\n }, C.prototype.render = S, i = [], o = \"function\" == typeof Promise ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, e = function(n2, l3) {\n return n2.__v.__b - l3.__v.__b;\n }, H.__r = 0, f = Math.random().toString(8), c = \"__d\" + f, a = \"__a\" + f, s = /(PointerCapture)$|Capture$/i, h = 0, p = V(false), v = V(true), y = 0;\n\n // node_modules/preact/hooks/dist/hooks.module.js\n var t2;\n var r2;\n var u2;\n var i2;\n var o2 = 0;\n var f2 = [];\n var c2 = l;\n var e2 = c2.__b;\n var a2 = c2.__r;\n var v2 = c2.diffed;\n var l2 = c2.__c;\n var m2 = c2.unmount;\n var p2 = c2.__;\n function s2(n2, t3) {\n c2.__h && c2.__h(r2, n2, o2 || t3), o2 = 0;\n var u4 = r2.__H || (r2.__H = { __: [], __h: [] });\n return n2 >= u4.__.length && u4.__.push({}), u4.__[n2];\n }\n function d2(n2) {\n return o2 = 1, y2(D2, n2);\n }\n function y2(n2, u4, i3) {\n var o3 = s2(t2++, 2);\n if (o3.t = n2, !o3.__c && (o3.__ = [i3 ? i3(u4) : D2(void 0, u4), function(n3) {\n var t3 = o3.__N ? o3.__N[0] : o3.__[0], r3 = o3.t(t3, n3);\n t3 !== r3 && (o3.__N = [r3, o3.__[1]], o3.__c.setState({}));\n }], o3.__c = r2, !r2.__f)) {\n var f4 = function(n3, t3, r3) {\n if (!o3.__c.__H) return true;\n var u5 = false, i4 = o3.__c.props !== n3;\n if (o3.__c.__H.__.some(function(n4) {\n if (n4.__N) {\n u5 = true;\n var t4 = n4.__[0];\n n4.__ = n4.__N, n4.__N = void 0, t4 !== n4.__[0] && (i4 = true);\n }\n }), c3) {\n var f5 = c3.call(this, n3, t3, r3);\n return u5 ? f5 || i4 : f5;\n }\n return !u5 || i4;\n };\n r2.__f = true;\n var c3 = r2.shouldComponentUpdate, e3 = r2.componentWillUpdate;\n r2.componentWillUpdate = function(n3, t3, r3) {\n if (this.__e) {\n var u5 = c3;\n c3 = void 0, f4(n3, t3, r3), c3 = u5;\n }\n e3 && e3.call(this, n3, t3, r3);\n }, r2.shouldComponentUpdate = f4;\n }\n return o3.__N || o3.__;\n }\n function h2(n2, u4) {\n var i3 = s2(t2++, 3);\n !c2.__s && C2(i3.__H, u4) && (i3.__ = n2, i3.u = u4, r2.__H.__h.push(i3));\n }\n function _2(n2, u4) {\n var i3 = s2(t2++, 4);\n !c2.__s && C2(i3.__H, u4) && (i3.__ = n2, i3.u = u4, r2.__h.push(i3));\n }\n function A2(n2) {\n return o2 = 5, T2(function() {\n return { current: n2 };\n }, []);\n }\n function T2(n2, r3) {\n var u4 = s2(t2++, 7);\n return C2(u4.__H, r3) && (u4.__ = n2(), u4.__H = r3, u4.__h = n2), u4.__;\n }\n function j2() {\n for (var n2; n2 = f2.shift(); ) {\n var t3 = n2.__H;\n if (n2.__P && t3) try {\n t3.__h.some(z2), t3.__h.some(B2), t3.__h = [];\n } catch (r3) {\n t3.__h = [], c2.__e(r3, n2.__v);\n }\n }\n }\n c2.__b = function(n2) {\n r2 = null, e2 && e2(n2);\n }, c2.__ = function(n2, t3) {\n n2 && t3.__k && t3.__k.__m && (n2.__m = t3.__k.__m), p2 && p2(n2, t3);\n }, c2.__r = function(n2) {\n a2 && a2(n2), t2 = 0;\n var i3 = (r2 = n2.__c).__H;\n i3 && (u2 === r2 ? (i3.__h = [], r2.__h = [], i3.__.some(function(n3) {\n n3.__N && (n3.__ = n3.__N), n3.u = n3.__N = void 0;\n })) : (i3.__h.some(z2), i3.__h.some(B2), i3.__h = [], t2 = 0)), u2 = r2;\n }, c2.diffed = function(n2) {\n v2 && v2(n2);\n var t3 = n2.__c;\n t3 && t3.__H && (t3.__H.__h.length && (1 !== f2.push(t3) && i2 === c2.requestAnimationFrame || ((i2 = c2.requestAnimationFrame) || w2)(j2)), t3.__H.__.some(function(n3) {\n n3.u && (n3.__H = n3.u, n3.u = void 0);\n })), u2 = r2 = null;\n }, c2.__c = function(n2, t3) {\n t3.some(function(n3) {\n try {\n n3.__h.some(z2), n3.__h = n3.__h.filter(function(n4) {\n return !n4.__ || B2(n4);\n });\n } catch (r3) {\n t3.some(function(n4) {\n n4.__h && (n4.__h = []);\n }), t3 = [], c2.__e(r3, n3.__v);\n }\n }), l2 && l2(n2, t3);\n }, c2.unmount = function(n2) {\n m2 && m2(n2);\n var t3, r3 = n2.__c;\n r3 && r3.__H && (r3.__H.__.some(function(n3) {\n try {\n z2(n3);\n } catch (n4) {\n t3 = n4;\n }\n }), r3.__H = void 0, t3 && c2.__e(t3, r3.__v));\n };\n var k2 = \"function\" == typeof requestAnimationFrame;\n function w2(n2) {\n var t3, r3 = function() {\n clearTimeout(u4), k2 && cancelAnimationFrame(t3), setTimeout(n2);\n }, u4 = setTimeout(r3, 35);\n k2 && (t3 = requestAnimationFrame(r3));\n }\n function z2(n2) {\n var t3 = r2, u4 = n2.__c;\n \"function\" == typeof u4 && (n2.__c = void 0, u4()), r2 = t3;\n }\n function B2(n2) {\n var t3 = r2;\n n2.__c = n2.__(), r2 = t3;\n }\n function C2(n2, t3) {\n return !n2 || n2.length !== t3.length || t3.some(function(t4, r3) {\n return t4 !== n2[r3];\n });\n }\n function D2(n2, t3) {\n return \"function\" == typeof t3 ? t3(n2) : t3;\n }\n\n // src/operator-ui/view.ts\n var OPERATOR_PAGES = [\n \"connections\",\n \"tokens\",\n \"activity\",\n \"artifacts\"\n ];\n var PAGE_META = {\n tokens: { path: \"/tokens\", label: \"Access tokens\" },\n connections: { path: \"/\", label: \"Connections\" },\n activity: { path: \"/activity\", label: \"Activity\" },\n artifacts: { path: \"/artifacts\", label: \"Artifacts\" },\n artifact: { path: \"/artifacts\", label: \"Artifact\" }\n };\n function pageDescription(page, productDescription2) {\n if (page === \"activity\") {\n return \"Every connector tool call, by who made it and how it ended. Arguments and results are never stored.\";\n }\n if (isArtifactPage(page)) {\n return \"Pages agents published for the team. Each one keeps every version.\";\n }\n return productDescription2;\n }\n function checkingCopy(page) {\n if (page === \"artifact\") return \"Loading artifact…\";\n if (page === \"artifacts\") return \"Loading artifacts…\";\n return \"Checking your session…\";\n }\n function pageForPath(path) {\n if (path.startsWith(\"/artifacts/\")) return \"artifact\";\n const match = OPERATOR_PAGES.find((page) => PAGE_META[page].path === path);\n return match ?? \"connections\";\n }\n function isArtifactPage(page) {\n return page === \"artifacts\" || page === \"artifact\";\n }\n function artifactViewRequest(pathname, search) {\n const match = /^\\/artifacts\\/([a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?)(?:\\/v\\/(\\d{1,9}))?$/.exec(pathname);\n if (!match?.[1]) return void 0;\n const params = new URLSearchParams();\n if (match[2]) {\n params.set(\"v\", match[2]);\n for (const pin of new URLSearchParams(search).getAll(\"d\")) params.append(\"d\", pin);\n }\n const query = params.toString();\n return `/artifacts/_api/view/${match[1]}${query ? `?${query}` : \"\"}`;\n }\n function info(message) {\n return { message, tone: \"info\" };\n }\n function failure(message, fix) {\n return fix ? { message, tone: \"error\", fix } : { message, tone: \"error\" };\n }\n var REFUSED_COPY = {\n oauth_disconnect: \"Disconnect didn't finish. If the service refused it, the deployment's log has its reply.\",\n oauth_reconnect: \"Authorization couldn't start. If the service refused it, the deployment's log has its reply.\",\n credential_test: \"The credential test couldn't run.\"\n };\n function oauthDoneNotice(action, answer, opened = true) {\n if (action === \"oauth_disconnect\") {\n return info(\"Disconnected. Connect again whenever you are ready.\");\n }\n if (answer?.state === \"ok\") return info(\"Connected.\");\n return info(\n opened ? \"Finish authorizing in the new tab. This page updates when you come back.\" : \"Your browser blocked the new tab. Open the authorization page from the link here.\"\n );\n }\n function credentialTestNotice(connectorId, answer) {\n return answer?.ok === true ? info(\"Credential is valid.\") : failure(\n \"Credential test failed: the service rejected the stored credential, or the test couldn't reach it. The deployment's log has the service's reply.\",\n { kind: \"credential_test_failed\", connectorId }\n );\n }\n function refusedNotice(action, connectorId, problem) {\n if (action === \"credential_test\" && (problem === \"credential_required\" || problem === \"credential_mismatch\")) {\n return failure(PROBLEM_COPY[problem], { kind: problem, connectorId });\n }\n return failure(REFUSED_COPY[action], {\n kind: action === \"credential_test\" ? \"credential_test_failed\" : \"oauth_action_failed\",\n connectorId\n });\n }\n function credentialRefusedCopy(action, status, problem) {\n if (problem === \"credential_mismatch\") return PROBLEM_COPY.credential_mismatch;\n const verb = action === \"credential_save\" ? \"saved\" : \"removed\";\n if (status === 400 || status === 413 || status === 415) {\n return action === \"credential_save\" ? \"The credential wasn't saved: a value is empty or not in the expected format. Check it and save again.\" : \"The credential wasn't removed. Refresh the page and try again.\";\n }\n if (status === 404) {\n return \"This connector no longer has a credential slot. Refresh the page to see its current setup.\";\n }\n if (status === 503) {\n return `Credential storage isn't configured on this deployment, so nothing was ${verb}.`;\n }\n return `The credential wasn't ${verb}. Try again; if it keeps failing, the deployment's log has the reason.`;\n }\n function actionFailedNotice(action, connectorId, facts, productName2) {\n if (facts.kind === \"session\") {\n return failure(\"Your session has ended. Sign in again, then retry.\");\n }\n if (facts.kind === \"forbidden\") {\n return failure(\"You don't have permission to change this connection's authentication.\");\n }\n if (facts.kind === \"network\") {\n return failure(`Couldn't reach ${productName2}. Check your connection and try again.`);\n }\n if (action === \"credential_save\" || action === \"credential_remove\") {\n return failure(credentialRefusedCopy(action, facts.status, facts.problem));\n }\n return refusedNotice(action, connectorId, facts.problem);\n }\n function connectorLoadFailureCopy(failure2, productName2) {\n return failure2 === \"session\" ? \"Your session wasn't accepted while loading this connector. Sign in again to see its status.\" : `Couldn't reach ${productName2} to load this connector. Check your connection, then refresh it.`;\n }\n function loadFailureCopy(failure2, productName2) {\n return {\n title: `Couldn't reach ${productName2}`,\n body: failure2 === \"network\" ? \"Your browser couldn't connect. Check your connection, then retry.\" : \"The deployment answered with an error. Retry in a moment; if it keeps failing, the deployment's log has the reason.\"\n };\n }\n function collectionFailureCopy(collection, facts, productName2) {\n if (facts.kind === \"network\") {\n return `Couldn't reach ${productName2}. Check your connection, then retry.`;\n }\n if (facts.kind === \"session\") return \"Your session has ended. Sign in again to see this page.\";\n if (facts.kind === \"forbidden\" || facts.status === 404) {\n if (collection === \"artifact\") return \"There is no artifact here, or this identity can't open it.\";\n return collection === \"activity\" ? \"Activity isn't available to this identity.\" : \"Artifacts aren't available to this identity.\";\n }\n return \"The deployment answered with an error. Retry in a moment; if it keeps failing, the deployment's log has the reason.\";\n }\n function confirmCopy(action, name) {\n if (action === \"oauth_disconnect\") {\n return {\n question: `Disconnect ${name}? Its stored grant and any pending authorization are removed, and its tools stop working until it is connected again.`,\n confirm: \"Disconnect\"\n };\n }\n if (action === \"oauth_restart\") {\n return {\n question: `Reconnect ${name}? Its current grant stops working until you finish authorizing in the new tab.`,\n confirm: \"Reconnect\"\n };\n }\n return {\n question: `Remove ${name}'s credential? The connector stops authenticating until a replacement is added.`,\n confirm: \"Remove\"\n };\n }\n function accessTokenUnavailableCopy(capability) {\n return capability === void 0 ? \"Access tokens are not configured for this deployment.\" : \"Token management requires an interactive sign-in and explicit permission.\";\n }\n function initialState(page) {\n return {\n page,\n generation: 0,\n session: \"loading\",\n gate: null,\n refreshing: false,\n loadFailure: null,\n pendingFocus: null,\n focusIfLost: null,\n ...identityScopedState()\n };\n }\n function identityScopedState() {\n return {\n data: null,\n connectorFilter: \"\",\n oauthNotice: null,\n oauthNoticeFor: null,\n oauthBusy: null,\n oauthBlocked: null,\n confirming: null,\n connectorFailures: {},\n credentialNotice: null,\n credentialNoticeFor: null,\n credentialEditing: null,\n credentialBusy: null,\n tokenPhase: \"idle\",\n tokenNotice: null,\n tokens: [],\n createdToken: null,\n tokenRenaming: null,\n tokenBusy: false,\n activityPhase: \"idle\",\n activityNotice: null,\n activityEvents: [],\n activityCursor: null,\n activitySearch: \"\",\n artifactPhase: \"idle\",\n artifactNotice: null,\n artifactRows: [],\n artifactCursor: null,\n artifactQuery: \"\",\n artifactArchived: false,\n artifactView: null\n };\n }\n function resetIdentity(state2, gate2 = null) {\n return {\n ...state2,\n generation: state2.generation + 1,\n session: \"gated\",\n gate: gate2,\n refreshing: false,\n loadFailure: null,\n pendingFocus: null,\n focusIfLost: null,\n ...identityScopedState()\n };\n }\n function withPage(state2, page) {\n return {\n ...state2,\n page,\n createdToken: null,\n tokenRenaming: null,\n tokenNotice: null,\n credentialEditing: null,\n credentialNotice: null,\n credentialNoticeFor: null,\n confirming: null\n };\n }\n function connectorStatusLabel(status, problem) {\n if (status === \"loading\") return \"Loading details\";\n if (status === \"ok\") return \"Connected\";\n if (status === \"auth_required\") {\n return problem === \"credential_required\" ? \"Credential needed\" : \"Authorization needed\";\n }\n return \"Unavailable\";\n }\n function toolCountLabel(count) {\n return `${count} ${count === 1 ? \"tool\" : \"tools\"}`;\n }\n function connectorStatusTone(status) {\n if (status === \"ok\") return \"ok\";\n if (status === \"auth_required\") return \"warn\";\n if (status === \"loading\") return \"neutral\";\n return \"danger\";\n }\n function summarizeConnectors(connectors) {\n const summary = {\n total: connectors.length,\n connected: 0,\n attention: 0,\n credentials: 0,\n unavailable: 0,\n loading: 0,\n tools: 0,\n drifting: 0\n };\n for (const connector of connectors) {\n if (connector.status === \"ok\") summary.connected += 1;\n else if (connector.status === \"auth_required\") {\n if (connector.problem === \"credential_required\") summary.credentials += 1;\n else summary.attention += 1;\n } else if (connector.status === \"loading\") summary.loading += 1;\n else summary.unavailable += 1;\n summary.tools += connector.toolCount || 0;\n if (driftState(connector.catalogDrift) === \"warning\") summary.drifting += 1;\n }\n return summary;\n }\n function connectorSummaryParts(summary) {\n if (summary.total > 0 && summary.loading === summary.total) {\n return [\n {\n text: `Checking ${summary.total} connector${summary.total === 1 ? \"\" : \"s\"}…`,\n tone: \"neutral\"\n }\n ];\n }\n return [\n { text: `${summary.connected} connected`, tone: \"neutral\" },\n ...summary.attention ? [\n {\n text: `${summary.attention} need${summary.attention === 1 ? \"s\" : \"\"} authorization`,\n tone: \"warn\"\n }\n ] : [],\n ...summary.credentials ? [\n {\n text: `${summary.credentials} need${summary.credentials === 1 ? \"s\" : \"\"} a credential`,\n tone: \"warn\"\n }\n ] : [],\n ...summary.unavailable ? [{ text: `${summary.unavailable} unavailable`, tone: \"danger\" }] : [],\n { text: toolCountLabel(summary.tools), tone: \"neutral\" },\n ...summary.loading ? [{ text: `${summary.loading} still loading`, tone: \"neutral\" }] : []\n ];\n }\n var TOOL_SAFETY_BADGE = {\n runs_in_programs: {\n label: \"runs in programs\",\n tone: \"ok\",\n title: \"Explicitly read-only: execute_code programs may call it without asking.\"\n },\n exempt: {\n label: \"exempt from approval\",\n tone: \"neutral\",\n title: \"Not read-only, but this deployment's config lets programs call it without pausing. Each call still counts against the write budget and appears in activity; call_tool still refuses it.\"\n },\n needs_approval: {\n label: \"asks for approval\",\n tone: \"warn\",\n title: \"Not explicitly read-only: a program pauses for resume_execution, and a direct call crosses call_destructive_tool — either way the host asks first.\"\n }\n };\n var PROBLEM_COPY = {\n connector_unavailable: \"Unavailable: its status check or catalog load failed, or did not finish in time. The deployment's log has the downstream error.\",\n oauth_required: \"Needs OAuth authorization: no grant is stored, or the stored grant expired or was revoked.\",\n credential_required: \"Needs a credential: nothing usable is stored in its credential slot.\",\n auth_required: \"Needs authorization. Its secret lives in deployment configuration, not on this page.\",\n credential_mismatch: \"The stored credential does not match the fields this connector declares, so it cannot be used.\",\n catalog_failed: \"Connected, but its tool catalog could not be loaded, so none of its tools are served.\"\n };\n function problemCopy(problem) {\n return problem ? PROBLEM_COPY[problem] ?? null : null;\n }\n function problemTone(problem) {\n return problem === \"oauth_required\" || problem === \"credential_required\" || problem === \"auth_required\" ? \"warn\" : \"danger\";\n }\n function authScopeLabel(scope) {\n return scope === \"personal\" ? \"personal auth\" : \"shared auth\";\n }\n function permissionLabel(connector) {\n if (connector.permissions?.manageSharedAuth) {\n return \"You can manage shared authentication for this connection.\";\n }\n if (connector.permissions?.connectPersonal) {\n return \"You can connect your own account to this connection.\";\n }\n return \"Authentication for this connection is managed by your deployment.\";\n }\n var DRIFT_CATEGORIES = [\n { key: \"unclassifiedTools\", label: \"Unclassified\" },\n { key: \"unservedTools\", label: \"Unserved\" },\n { key: \"annotationConflicts\", label: \"Annotation conflicts\" },\n { key: \"schemaChanges\", label: \"Schema changes\" }\n ];\n function driftTotal(drift) {\n if (!drift) return 0;\n return DRIFT_CATEGORIES.reduce((sum, { key }) => sum + (drift[key] || 0), 0);\n }\n function driftState(drift) {\n if (!drift) return \"unavailable\";\n return driftTotal(drift) > 0 ? \"warning\" : \"clean\";\n }\n function driftCounts(drift) {\n if (!drift) return [];\n return DRIFT_CATEGORIES.map(({ key, label }) => ({\n key,\n label,\n count: drift[key] || 0\n }));\n }\n function driftSummary(drift) {\n const state2 = driftState(drift);\n if (state2 === \"unavailable\") {\n return \"No catalog refresh observed yet in this runtime.\";\n }\n const observed = formatDate(drift?.observedAt);\n const when = observed ? ` · observed ${observed}` : \"\";\n if (state2 === \"clean\") return `Matches the reviewed manifest${when}`;\n const total = driftTotal(drift);\n return `${total} difference${total === 1 ? \"\" : \"s\"} from the reviewed manifest${when}`;\n }\n function safeHttpHref(url) {\n if (!url) return null;\n try {\n const protocol = new URL(url).protocol;\n return protocol === \"http:\" || protocol === \"https:\" ? url : null;\n } catch {\n return null;\n }\n }\n function formatDate(value) {\n if (!value) return \"\";\n const date = new Date(value);\n return Number.isNaN(date.valueOf()) ? \"\" : date.toLocaleString(void 0, { dateStyle: \"medium\", timeStyle: \"short\" });\n }\n var ACTOR_KINDS = {\n clerk: \"Clerk\",\n bearer: \"Bearer token\",\n \"cloudflare-access\": \"Cloudflare Access\",\n anonymous: \"Anonymous\"\n };\n function actorKindLabel(kind) {\n if (!kind) return \"Unknown caller\";\n return ACTOR_KINDS[kind] ?? kind;\n }\n function actorLabel(actor) {\n if (!actor?.kind) return \"Unknown caller\";\n const who = actor.label || actor.id;\n const kind = actorKindLabel(actor.kind);\n return who ? `${who} (${kind})` : kind;\n }\n function actorStableId(actor) {\n if (!actor?.id) return null;\n if (!actor.label && !actor.namespace) return null;\n return actor.namespace ? `${actor.namespace} · ${actor.id}` : actor.id;\n }\n function activityMatches(event, query) {\n const q2 = query.trim().toLowerCase();\n if (!q2) return true;\n return [\n event.address,\n event.connectorId,\n event.toolName,\n event.source,\n event.outcome,\n event.errorCode,\n event.friction,\n event.actor?.kind,\n event.actor?.id,\n event.actor?.namespace,\n event.actor?.label,\n activityOutcomeBadge(event.outcome).label,\n activityDetail(event),\n actorKindLabel(event.actor?.kind)\n ].some((value) => String(value ?? \"\").toLowerCase().includes(q2));\n }\n function filterActivity(events, query) {\n return events.filter((event) => activityMatches(event, query));\n }\n function activitySummary(events) {\n if (events.length === 0) return \"\";\n const tools = new Set(events.map((event) => event.address)).size;\n return `${events.length} loaded call${events.length === 1 ? \"\" : \"s\"} · ${tools} tool${tools === 1 ? \"\" : \"s\"}`;\n }\n var ACTIVITY_OUTCOMES = [\n \"success\",\n \"error\",\n \"timeout\",\n \"cancelled\",\n \"paused\",\n \"approved\"\n ];\n function activityOutcomeClass(outcome) {\n return ACTIVITY_OUTCOMES.includes(outcome) ? outcome : \"error\";\n }\n var OUTCOME_BADGE = {\n success: { label: \"Succeeded\", tone: \"ok\" },\n error: { label: \"Failed\", tone: \"danger\" },\n timeout: { label: \"Timed out\", tone: \"danger\" },\n cancelled: { label: \"Cancelled\", tone: \"neutral\" },\n paused: { label: \"Waiting for approval\", tone: \"warn\" },\n approved: { label: \"Approved\", tone: \"ok\" }\n };\n function activityOutcomeBadge(outcome) {\n return OUTCOME_BADGE[outcome] ?? { label: \"Failed\", tone: \"danger\" };\n }\n var SOURCE_LABELS = {\n execute_code: \"In a program\",\n call_tool: \"Direct call\",\n call_destructive_tool: \"Direct call, approved by the host\",\n resume_execution: \"Resumed program\",\n batch_call: \"Batch call\"\n };\n var REASON_LABELS = {\n tool_not_found: \"tool not found\",\n unknown_address: \"tool not found\",\n unknown_tool: \"tool not found\",\n ambiguous_tool_alias: \"ambiguous tool name\",\n schema_retry: \"arguments didn't match the schema\",\n invalid_args: \"arguments didn't match the schema\",\n destructive_reroute: \"needed host approval\",\n destructive_tool_requires_approval: \"needed host approval\",\n approval_required: \"needed approval\",\n auth_required: \"needed authorization\",\n result_too_large: \"result too large to return inline\",\n timeout: \"timed out\"\n };\n function reasonLabel(code) {\n return REASON_LABELS[code] ?? code.replaceAll(\"_\", \" \");\n }\n function activityDetail(event) {\n const parts = [SOURCE_LABELS[event.source] ?? event.source];\n if (event.approval === \"tool\") parts.push(\"approved for the rest of the run\");\n if (event.approval === \"call\") parts.push(\"approved for this call\");\n if (event.attempts > 1) parts.push(`${event.attempts} attempts`);\n const reasons = [event.friction, event.errorCode].filter((code) => Boolean(code)).map(reasonLabel);\n for (const reason of new Set(reasons)) parts.push(reason);\n return parts.join(\" · \");\n }\n function artifactRefreshBadge(last) {\n return last?.status === \"failed\" ? { label: \"Refresh failed\", tone: \"danger\" } : null;\n }\n function credentialProblemCopy(problem) {\n if (problem === \"credential_mismatch\") return PROBLEM_COPY.credential_mismatch;\n if (problem === \"credential_unreadable\") {\n return \"The stored credential can't be read, so it can't be used. Replace it, or remove it and add a new one.\";\n }\n return \"The stored credential can't be used. Replace it, or remove it and add a new one.\";\n }\n function credentialStateLabel(credential) {\n if (!credential.configured) return \"not configured\";\n const masked = credential.fields?.length ? \"configured\" : `configured · ••••${credential.lastFour ?? \"\"}`;\n return credential.updatedAt ? `${masked} · updated ${formatDate(credential.updatedAt)}` : masked;\n }\n function gateCopy(kind, signedIn) {\n if (kind === \"cloudflare-access\") {\n return \"Cloudflare Access admitted this browser, but the current identity cannot open deployment-wide operator pages.\";\n }\n if (kind !== \"clerk\") {\n return \"Paste an operator bearer token to open this page. Nothing is requested until you do.\";\n }\n return signedIn ? \"Signed in with Clerk, but this account cannot open deployment-wide operator pages.\" : \"Sign in with Clerk to open this operator page.\";\n }\n\n // src/operator-ui/app/config.ts\n var auth = AUTH;\n var mcpUrl = MCP_URL;\n var initialPage = INITIAL_PAGE;\n var homeUrl = HOME_URL;\n var titleSuffix = TITLE_SUFFIX;\n var productName = PRODUCT_NAME;\n var productDescription = PRODUCT_DESCRIPTION;\n var productOperatorLabel = PRODUCT_OPERATOR_LABEL;\n var TOKEN_KEY = \"connecta:token\";\n\n // src/fix-prompt.ts\n var CONNECTOR_ID_RE = /^[a-z0-9_-]+$/;\n function renderFixPrompt(spec, connectorId) {\n const id = connectorId !== void 0 && CONNECTOR_ID_RE.test(connectorId) ? connectorId : void 0;\n return [\n \"Diagnose and fix a problem in this connecta deployment (the @zackbart/connecta package). It is configured as code: connectors, credential slots, OAuth clients, pools, and inbound auth are declared in the deployment's source and environment, so the fix belongs there and not in the operator page.\",\n `Problem: ${spec.problem}` + (id ? `\nConnector id: ${id}` : \"\"),\n `Where to look:\n${spec.steps.map((step) => `- ${step}`).join(\"\\n\")}`,\n \"This prompt deliberately carries no error text, tokens, or URLs. Find the underlying cause in the deployment's own logs (lines prefixed [connecta]) or by reproducing the failure locally. Never put a secret in source, a log line, or your reply: secrets belong in the deployment's environment or its credential vault.\",\n \"Make the smallest change that fixes it, then verify it by redeploying and refreshing the connection on the operator Connections page. If the fix needs something you cannot do yourself — a provider console setting, a secret only the operator holds — name that exact step instead.\"\n ].join(\"\\n\\n\");\n }\n\n // src/operator-ui/fix-prompts.ts\n var CATALOGUE = {\n connector_unavailable: {\n problem: \"A connector is unavailable: its status check or catalog load failed, or did not finish before the operator page's deadline.\",\n steps: [\n \"Confirm the connector's downstream URL or API base in the deployment config, and that the deployment can reach it from where it runs.\",\n \"Check the credentials or headers the connector sends; a rejected credential often surfaces as a failed status rather than as an authorization prompt.\",\n \"If the downstream is slow rather than down, review the connector's timeouts and the deployment's discovery.probeTimeoutMs.\"\n ]\n },\n oauth_required: {\n problem: \"A downstream OAuth connector needs authorization: no grant is stored, or the stored grant expired or was revoked and could not be refreshed.\",\n steps: [\n \"Reauthorize from the operator page (Connect account or Reconnect OAuth) or with authorize_connector; this needs no code change if the grant simply lapsed.\",\n \"If it needs reauthorizing again soon after, check that the OAuth client requests offline access or a refresh token, and that the storage holding OAuth tokens persists across restarts and is shared by every instance.\",\n \"If authorization cannot start at all, check the connector's OAuth client configuration and the deployment's publicUrl, which forms the /oauth/callback/ redirect URI.\"\n ]\n },\n credential_required: {\n problem: \"A connector with an operator-managed credential slot has no usable credential stored.\",\n steps: [\n \"An operator with credential administration can add the credential on the operator page; that needs no code change.\",\n \"If nobody can, grant credential administration through the deployment's identity config (credentialAdministration for shared auth, personalConnection for personal auth), which is denied by default.\",\n \"Check that the connector's credential declaration (label and fields) matches what the downstream actually needs.\"\n ]\n },\n auth_required: {\n problem: \"A connector reports that it needs authorization, and its secret lives in deployment configuration rather than in an operator-managed slot.\",\n steps: [\n \"Find where the connector's secret is read (usually an environment variable or Worker secret passed into the connector config) and confirm it is set in the running environment.\",\n \"Rotate the secret at the provider if it expired or was revoked, then update the deployment's environment, not its source.\",\n \"If operators should manage this secret from the page instead, declare a credential slot on the connector and configure a credential vault.\"\n ]\n },\n credential_mismatch: {\n problem: \"The credential stored for a connector does not match the fields the connector currently declares, so it cannot be used.\",\n steps: [\n \"If the connector's credential fields changed on purpose, re-enter the credential on the operator page so the stored fields match.\",\n \"If they changed by accident, restore the previous field names in the connector's credential declaration.\"\n ]\n },\n credential_unreadable: {\n problem: \"A stored credential exists but could not be read or decrypted.\",\n steps: [\n \"Check that the credential vault's encryption key in the deployment environment is the one the credential was stored with; a rotated or missing key makes every stored value unreadable.\",\n \"Check the storage adapter backing the vault is reachable from the deployment.\",\n \"If the key was lost, remove and re-add the credential on the operator page; the old value cannot be recovered.\"\n ]\n },\n credential_test_failed: {\n problem: \"The test for a stored connector credential failed: the downstream rejected it, or the test could not reach the downstream.\",\n steps: [\n \"Confirm the stored value is current at the provider (not rotated, revoked, or scoped too narrowly), and replace it on the operator page if not.\",\n \"Check that the connector's credential test targets the same API base and auth scheme its tool calls use.\"\n ]\n },\n oauth_action_failed: {\n problem: \"Restarting or disconnecting a connector's downstream OAuth from the operator page failed.\",\n steps: [\n \"Check that the connector implements startAuth and disconnectAuth, and that the storage holding its OAuth state is writable.\",\n \"Check the connector's OAuth client configuration, including the authorization server it discovers or is given.\",\n \"Confirm the operator has the config-derived permission for this action (credentialAdministration for shared auth, personalConnection for personal auth).\"\n ]\n },\n catalog_failed: {\n problem: \"A connector reports itself connected, but loading its tool catalog failed, so none of its tools are being served.\",\n steps: [\n \"Check that the downstream still serves a complete tools list; connecta refuses a partial catalog rather than serving part of it.\",\n \"Check for tools the connector cannot accept: invalid schemas, missing descriptions, or names that collide.\",\n \"Pin or upgrade the @zackbart/connecta version if a maintained provider's catalog changed shape underneath it.\"\n ]\n },\n catalog_drift: {\n problem: \"A hosted provider's live catalog differs from the reviewed manifest shipped with connecta: new unclassified tools, unserved tools, annotation conflicts, or schema changes.\",\n steps: [\n \"Unclassified tools are withheld until a release classifies them. Check whether a newer @zackbart/connecta release has, and upgrade if so.\",\n \"If a tool the deployment depends on is now unserved or changed shape, review callers of it before upgrading.\",\n \"Report drift the release does not cover as an issue on the connecta repository, naming the provider and the kinds of drift but no tool data.\"\n ]\n }\n };\n function fixPrompt(kind, connectorId) {\n return renderFixPrompt(CATALOGUE[kind], connectorId);\n }\n var FIX_PROMPT_KINDS = Object.keys(CATALOGUE);\n\n // src/operator-ui/app/store.ts\n var state = initialState(initialPage);\n var listeners = /* @__PURE__ */ new Set();\n function getState() {\n return state;\n }\n function subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n }\n function set(patch) {\n state = { ...state, ...patch };\n for (const listener of listeners) listener();\n }\n function fence() {\n const generation = state.generation;\n return () => generation === state.generation;\n }\n function sessionToken() {\n if (auth.kind === \"cloudflare-access\") return Promise.resolve(void 0);\n return auth.kind === \"clerk\" ? Promise.resolve(window.Clerk?.session?.getToken() ?? null) : Promise.resolve(localStorage.getItem(TOKEN_KEY));\n }\n function requestHeaders(token, body = false) {\n return {\n ...token ? { Authorization: `Bearer ${token}` } : {},\n ...body ? { \"Content-Type\": \"application/json\" } : {}\n };\n }\n var NAV_HINT_KEY = \"connecta:nav\";\n function rememberNav(data) {\n try {\n sessionStorage.setItem(\n NAV_HINT_KEY,\n JSON.stringify({ activity: data.activityEnabled, artifacts: Boolean(data.artifactsEnabled) })\n );\n } catch {\n }\n }\n function forgetNav() {\n try {\n sessionStorage.removeItem(NAV_HINT_KEY);\n } catch {\n }\n }\n function navHint() {\n try {\n const hint = JSON.parse(sessionStorage.getItem(NAV_HINT_KEY) ?? \"null\");\n return { activity: hint?.activity === true, artifacts: hint?.artifacts === true };\n } catch {\n return { activity: false, artifacts: false };\n }\n }\n function gate(notice = null) {\n forgetNav();\n awaitingAuthorization.clear();\n state = resetIdentity(state, notice);\n for (const listener of listeners) listener();\n }\n var RequestFailure = class extends Error {\n kind;\n status;\n problem;\n constructor(kind, status, problem) {\n super(`Operator request failed: ${kind}`);\n this.kind = kind;\n this.status = status;\n this.problem = problem;\n }\n };\n function factsOf(error) {\n return error instanceof RequestFailure ? error : { kind: \"refused\" };\n }\n async function operatorRequest(path, method, current, body) {\n let token;\n try {\n token = await sessionToken();\n } catch {\n throw new RequestFailure(\"session\");\n }\n if (!current()) throw new RequestFailure(\"session\");\n if (!token && auth.kind !== \"cloudflare-access\") throw new RequestFailure(\"session\");\n let res;\n try {\n res = await fetch(path, {\n method,\n headers: requestHeaders(token, Boolean(body)),\n credentials: \"same-origin\",\n ...body ? { body: JSON.stringify(body) } : {}\n });\n } catch {\n throw new RequestFailure(\"network\");\n }\n if (res.status === 204) return null;\n let payload = {};\n try {\n payload = await res.json();\n } catch {\n }\n if (res.status === 401) throw new RequestFailure(\"session\", 401);\n if (res.status === 403) throw new RequestFailure(\"forbidden\", 403);\n if (!res.ok) throw new RequestFailure(\"refused\", res.status, payload.problem);\n return payload;\n }\n function unreachable(loadFailure) {\n set({ session: \"ready\", gate: null, refreshing: false, loadFailure });\n }\n var dataRevision = 0;\n async function loadData() {\n const identityCurrent = fence();\n const revision = ++dataRevision;\n const current = () => identityCurrent() && revision === dataRevision;\n set(state.session === \"ready\" ? { refreshing: true, loadFailure: null } : { loadFailure: null });\n let token;\n try {\n token = await sessionToken();\n } catch {\n if (!current()) return;\n return gate(failure(\"Your sign-in session couldn't be read. Sign in again.\"));\n }\n if (!current()) return;\n if (!token && auth.kind !== \"cloudflare-access\") return gate(null);\n let res;\n try {\n res = await fetch(\"/ui/data\", {\n headers: requestHeaders(token),\n credentials: \"same-origin\"\n });\n } catch {\n if (!current()) return;\n return unreachable(\"network\");\n }\n if (!current()) return;\n if (res.status === 401 || res.status === 403) {\n if (auth.kind === \"clerk\") {\n return gate(\n failure(\n res.status === 403 ? `This Clerk account can't open ${productName}'s operator pages.` : \"Your Clerk session wasn't accepted. Sign out, then sign in again.\"\n )\n );\n }\n if (auth.kind === \"cloudflare-access\") {\n return gate(\n failure(\"Cloudflare Access let this browser in, but this identity isn't an operator here.\")\n );\n }\n localStorage.removeItem(TOKEN_KEY);\n return gate(failure(\"That token wasn't accepted. Paste a valid operator token.\"));\n }\n if (!res.ok) return unreachable(\"server\");\n let data;\n try {\n data = await res.json();\n } catch {\n if (!current()) return;\n return unreachable(\"server\");\n }\n if (!current()) return;\n if (!data || !Array.isArray(data.connectors)) return unreachable(\"server\");\n set({ data, session: \"ready\", gate: null, refreshing: false, loadFailure: null });\n rememberNav(data);\n void loadConnectorDetails(data, current, token);\n }\n async function mutate(options) {\n const current = fence();\n if (options.reload) detailRevisions.set(options.reload, (detailRevisions.get(options.reload) ?? 0) + 1);\n set(options.busy);\n try {\n const payload = await options.request(current);\n if (!current()) return options.abandoned?.();\n set(options.done(payload));\n if (options.reload) void refreshConnector(options.reload);\n } catch (error) {\n if (!current()) return options.abandoned?.();\n set(options.failed(factsOf(error)));\n if (options.reload) void refreshConnector(options.reload);\n }\n }\n function focusHandled() {\n if (state.pendingFocus !== null || state.focusIfLost !== null) {\n set({ pendingFocus: null, focusIfLost: null });\n }\n }\n function setPage(page, focus = false) {\n state = withPage(state, page);\n if (focus) {\n state = {\n ...state,\n pendingFocus: state.session === \"ready\" ? `${page}Heading` : \"gateHeading\"\n };\n }\n for (const listener of listeners) listener();\n }\n function navigate(page, href) {\n history.pushState({ operatorPage: page }, \"\", href);\n setPage(page, true);\n }\n function setConnectorFilter(connectorFilter) {\n set({ connectorFilter });\n }\n function setActivitySearch(activitySearch) {\n set({ activitySearch });\n }\n function signInWithBearer(value) {\n gate(null);\n localStorage.setItem(TOKEN_KEY, value);\n void loadCurrent().then(() => {\n if (state.session === \"ready\") set({ pendingFocus: `${state.page}Heading` });\n });\n }\n function forgetBearer() {\n localStorage.removeItem(TOKEN_KEY);\n gate(null);\n set({ pendingFocus: \"token\" });\n }\n function askConfirm(connectorId, action) {\n set({ confirming: { connectorId, action }, pendingFocus: `confirm-cancel-${connectorId}` });\n }\n function cancelConfirm(returnFocusTo) {\n set({ confirming: null, pendingFocus: returnFocusTo });\n }\n function oauthStartPath(connector, mode) {\n return `/ui/oauth/${encodeURIComponent(connector)}?mode=${mode}`;\n }\n var awaitingAuthorization = /* @__PURE__ */ new Set();\n function openBlankTab() {\n let tab = null;\n try {\n tab = window.open(\"\", \"_blank\");\n } catch {\n return null;\n }\n if (!tab) return null;\n try {\n tab.document.title = \"Opening authorization…\";\n tab.document.body.textContent = \"Opening the authorization page…\";\n } catch {\n }\n return tab;\n }\n function oauthNoticePatch(connector, notice) {\n return {\n oauthBusy: null,\n oauthNotice: notice,\n oauthNoticeFor: connector,\n focusIfLost: `oauthNotice-${connector}`\n };\n }\n function startOAuth(connector, mode) {\n const tab = openBlankTab();\n return mutate({\n request: (current) => operatorRequest(oauthStartPath(connector, mode), \"POST\", current),\n busy: {\n oauthBusy: connector,\n oauthNotice: null,\n oauthNoticeFor: connector,\n oauthBlocked: null,\n confirming: null\n },\n done: (payload) => {\n const url = safeHttpHref(payload?.authorizationUrl);\n if (!url) {\n tab?.close();\n if (payload?.state === \"ok\") {\n return oauthNoticePatch(connector, oauthDoneNotice(\"oauth_reconnect\", payload));\n }\n return oauthNoticePatch(connector, refusedNotice(\"oauth_reconnect\", connector));\n }\n if (tab) {\n tab.opener = null;\n tab.location.replace(url);\n }\n awaitingAuthorization.add(connector);\n return {\n ...state.data ? {\n data: {\n ...state.data,\n connectors: state.data.connectors.map(\n (c3) => c3.id === connector ? { ...c3, status: \"auth_required\", tools: [], toolCount: 0, authorizationUrl: url } : c3\n )\n }\n } : {},\n ...oauthNoticePatch(connector, oauthDoneNotice(\"oauth_reconnect\", payload, Boolean(tab))),\n oauthBlocked: tab ? null : connector\n };\n },\n // Signed out or switched mid-request: the tab it opened goes too, rather\n // than sitting on \"Opening…\" with nothing left to send it anywhere.\n abandoned: () => tab?.close(),\n // The route's words never reach this notice (see `refusedNotice`).\n failed: (facts) => {\n tab?.close();\n return oauthNoticePatch(\n connector,\n actionFailedNotice(\"oauth_reconnect\", connector, facts, productName)\n );\n },\n reload: connector\n });\n }\n function disconnectOAuth(connector) {\n return mutate({\n request: (current) => operatorRequest(`/ui/oauth/${encodeURIComponent(connector)}`, \"DELETE\", current),\n busy: {\n oauthBusy: connector,\n oauthNotice: null,\n oauthNoticeFor: connector,\n oauthBlocked: null,\n confirming: null\n },\n done: () => ({\n ...state.data ? {\n data: {\n ...state.data,\n connectors: state.data.connectors.map((c3) => {\n if (c3.id !== connector) return c3;\n const { authorizationUrl: _old, ...rest } = c3;\n return { ...rest, status: \"auth_required\", tools: [], toolCount: 0 };\n })\n }\n } : {},\n ...oauthNoticePatch(connector, oauthDoneNotice(\"oauth_disconnect\", null))\n }),\n failed: (facts) => oauthNoticePatch(\n connector,\n actionFailedNotice(\"oauth_disconnect\", connector, facts, productName)\n ),\n reload: connector\n });\n }\n function editCredential(connector) {\n set({ credentialEditing: connector, credentialNotice: null, credentialNoticeFor: null });\n }\n function refuseCredential(connector, copy) {\n set({ credentialNotice: failure(copy), credentialNoticeFor: connector });\n }\n function credentialMutation(connector, action, request, done, reload = true) {\n const land = (patch) => ({\n credentialBusy: null,\n credentialNoticeFor: connector,\n focusIfLost: `credentialNotice-${connector}`,\n ...patch\n });\n return mutate({\n request,\n busy: {\n credentialBusy: connector,\n credentialNotice: null,\n credentialNoticeFor: connector,\n confirming: null\n },\n done: (payload) => land(done(payload)),\n failed: (facts) => land({ credentialNotice: actionFailedNotice(action, connector, facts, productName) }),\n reload: reload ? connector : void 0\n });\n }\n function saveCredential(connector, body) {\n return credentialMutation(\n connector,\n \"credential_save\",\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"PUT\",\n current,\n body\n ),\n () => ({ credentialEditing: null, credentialNotice: info(\"Credential saved.\") })\n );\n }\n function removeCredential(connector) {\n return credentialMutation(\n connector,\n \"credential_remove\",\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"DELETE\",\n current\n ),\n () => ({ credentialNotice: info(\"Credential removed.\") })\n );\n }\n function testCredential(connector) {\n return credentialMutation(\n connector,\n \"credential_test\",\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}/test`,\n \"POST\",\n current\n ),\n (payload) => ({ credentialNotice: credentialTestNotice(connector, payload) }),\n false\n );\n }\n async function loadActivity(reset) {\n if (!state.data?.activityEnabled) return;\n const current = fence();\n set({\n activityPhase: \"loading\",\n activityNotice: null,\n ...reset ? { activityEvents: [], activityCursor: null } : {}\n });\n const params = new URLSearchParams({ limit: \"50\" });\n if (!reset && state.activityCursor) {\n params.set(\"cursor\", state.activityCursor);\n }\n try {\n const payload = await operatorRequest(\n `/ui/activity?${params}`,\n \"GET\",\n current\n );\n if (!current()) return;\n set({\n activityPhase: \"ready\",\n activityEvents: [\n ...reset ? [] : state.activityEvents,\n ...payload?.events ?? []\n ],\n activityCursor: payload?.nextCursor ?? null\n });\n } catch (error) {\n if (!current()) return;\n set({\n activityPhase: \"error\",\n activityNotice: failure(collectionFailureCopy(\"activity\", factsOf(error), productName))\n });\n }\n }\n async function artifactRead(path, current, collection) {\n let token;\n try {\n token = await sessionToken();\n } catch {\n if (current()) gate(failure(\"Your sign-in session couldn't be read. Sign in again.\"));\n return void 0;\n }\n if (!current()) return void 0;\n if (!token && auth.kind !== \"cloudflare-access\") {\n gate(null);\n return void 0;\n }\n let res;\n try {\n res = await fetch(path, { headers: requestHeaders(token), credentials: \"same-origin\" });\n } catch {\n if (current()) {\n set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(collectionFailureCopy(collection, { kind: \"network\" }, productName))\n });\n }\n return void 0;\n }\n if (!current()) return void 0;\n if (res.status === 401) {\n if (auth.kind !== \"clerk\" && auth.kind !== \"cloudflare-access\") {\n localStorage.removeItem(TOKEN_KEY);\n gate(failure(\"That token wasn't accepted. Paste a valid operator token.\"));\n } else {\n gate(failure(\"Your session wasn't accepted. Sign out, then sign in again.\"));\n }\n return void 0;\n }\n if (res.status === 403) {\n gate(failure(\"This deployment doesn't open artifact pages to this identity.\"));\n return void 0;\n }\n return res;\n }\n var artifactRevision = 0;\n async function loadArtifacts(reset) {\n const identityCurrent = fence();\n const revision = ++artifactRevision;\n const current = () => identityCurrent() && revision === artifactRevision;\n set({\n artifactPhase: \"loading\",\n artifactNotice: null,\n ...reset ? { artifactRows: [], artifactCursor: null } : {}\n });\n const params = new URLSearchParams();\n if (state.artifactQuery.trim()) params.set(\"q\", state.artifactQuery.trim());\n if (state.artifactArchived) params.set(\"archived\", \"1\");\n if (!reset && state.artifactCursor) params.set(\"cursor\", state.artifactCursor);\n const query = params.toString();\n const res = await artifactRead(`/artifacts/_api/list${query ? `?${query}` : \"\"}`, current, \"artifacts\");\n if (!res || !current()) return;\n if (!res.ok) {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(\n collectionFailureCopy(\"artifacts\", { kind: \"refused\", status: res.status }, productName)\n )\n });\n }\n let payload;\n try {\n payload = await res.json();\n } catch {\n payload = null;\n }\n if (!current()) return;\n if (!payload || !Array.isArray(payload.artifacts)) {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(collectionFailureCopy(\"artifacts\", { kind: \"refused\" }, productName))\n });\n }\n set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"ready\",\n artifactRows: [...reset ? [] : state.artifactRows, ...payload.artifacts ?? []],\n artifactCursor: payload.nextCursor ?? null\n });\n }\n var artifactFrameConfined = false;\n function markArtifactFrameConfined() {\n artifactFrameConfined = true;\n }\n async function loadArtifactView() {\n if (artifactFrameConfined) {\n window.location.reload();\n return;\n }\n const current = fence();\n const request = artifactViewRequest(window.location.pathname, window.location.search);\n set({ artifactPhase: \"loading\", artifactNotice: null });\n if (!request) {\n return set({\n session: \"ready\",\n artifactPhase: \"error\",\n artifactNotice: failure(\"There is no artifact at this address.\")\n });\n }\n const res = await artifactRead(request, current, \"artifact\");\n if (!res || !current()) return;\n if (!res.ok) {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(\n collectionFailureCopy(\"artifact\", { kind: \"refused\", status: res.status }, productName)\n )\n });\n }\n let view = null;\n try {\n view = await res.json();\n } catch {\n view = null;\n }\n if (!current()) return;\n if (!view || typeof view.document !== \"string\") {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(\"The artifact couldn't be read. Retry in a moment.\")\n });\n }\n set({ session: \"ready\", gate: null, artifactPhase: \"ready\", artifactView: view });\n }\n function setArtifactQuery(artifactQuery) {\n set({ artifactQuery });\n }\n function setArtifactArchived(artifactArchived) {\n set({ artifactArchived });\n void loadArtifacts(true);\n }\n function loadCurrent() {\n if (state.page === \"artifacts\") return loadArtifacts(true);\n if (state.page === \"artifact\") return loadArtifactView();\n return loadData();\n }\n function retryLoad() {\n set({\n pendingFocus: state.page === \"connections\" ? \"connectorLedgerHeading\" : `${state.page}Heading`\n });\n return loadCurrent();\n }\n function retryCollection() {\n set({ pendingFocus: `${state.page}Heading` });\n if (state.page === \"activity\") return loadActivity(true);\n if (state.page === \"artifact\") return loadArtifactView();\n return loadArtifacts(true);\n }\n function signIn() {\n window.Clerk?.redirectToSignIn({\n signInFallbackRedirectUrl: window.location.href,\n signUpFallbackRedirectUrl: window.location.href\n });\n }\n function signOut() {\n if (auth.kind === \"cloudflare-access\") {\n gate(null);\n window.location.assign(\"/cdn-cgi/access/logout\");\n return;\n }\n const clerk = window.Clerk;\n gate(null);\n void clerk?.signOut({ redirectUrl: window.location.href });\n }\n var returnTimer;\n var lastReturnPass = 0;\n var RETURN_DEBOUNCE_MS = 150;\n var RETURN_MIN_INTERVAL_MS = 2e3;\n function onReturn() {\n if (typeof document !== \"undefined\" && document.visibilityState === \"hidden\") return;\n if (returnTimer !== void 0) return;\n returnTimer = setTimeout(() => {\n returnTimer = void 0;\n const now = Date.now();\n if (now - lastReturnPass < RETURN_MIN_INTERVAL_MS) return;\n lastReturnPass = now;\n recheckAuthorization();\n }, RETURN_DEBOUNCE_MS);\n }\n function recheckAuthorization() {\n if (state.session !== \"ready\" || !state.data) return;\n for (const connector of state.data.connectors) {\n if (state.oauthBusy === connector.id) continue;\n const authorizesElsewhere = connector.status === \"auth_required\" && (connector.oauth === true || Boolean(connector.authorizationUrl));\n if (authorizesElsewhere || awaitingAuthorization.has(connector.id)) {\n void refreshConnector(connector.id, true);\n }\n }\n }\n async function boot() {\n const onPop = () => setPage(pageForPath(window.location.pathname), true);\n window.addEventListener(\"popstate\", onPop);\n window.addEventListener(\"focus\", onReturn);\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", onReturn);\n }\n if (auth.kind === \"clerk\") {\n const clerk = window.Clerk;\n if (!clerk) {\n return gate(failure(\"Clerk couldn't load. Check your connection and try again.\"));\n }\n try {\n await clerk.load({\n ...auth.signInUrl ? { signInUrl: auth.signInUrl } : {},\n ...auth.signUpUrl ? { signUpUrl: auth.signUpUrl } : {},\n signInFallbackRedirectUrl: window.location.href,\n signUpFallbackRedirectUrl: window.location.href,\n afterSignOutUrl: window.location.href\n });\n let sessionId = clerk.session?.id ?? null;\n clerk.addListener((resources) => {\n const next = resources.session?.id ?? null;\n if (next === sessionId) return;\n sessionId = next;\n gate(null);\n void loadCurrent();\n });\n } catch {\n return gate(failure(\"Clerk couldn't start. Reload the page to try again.\"));\n }\n }\n await loadCurrent();\n }\n async function readConnector(id, token) {\n let response;\n try {\n response = await fetch(`/ui/connectors/${encodeURIComponent(id)}`, {\n headers: requestHeaders(token),\n credentials: \"same-origin\"\n });\n } catch {\n return { kind: \"local\", failure: \"network\" };\n }\n if (response.status === 401 || response.status === 403) {\n return { kind: \"local\", failure: \"session\" };\n }\n if (!response.ok) return { kind: \"downstream\" };\n try {\n return { kind: \"detail\", detail: await response.json() };\n } catch {\n return { kind: \"downstream\" };\n }\n }\n function withoutKey(record, key) {\n const { [key]: _gone, ...rest } = record;\n return rest;\n }\n function applyDetail(id, outcome) {\n if (!state.data) return;\n const patch = {};\n const connectors = state.data.connectors.map((c3) => {\n if (c3.id !== id) return c3;\n if (outcome.kind === \"detail\") {\n const { detail } = outcome;\n return detail.status === \"auth_required\" && c3.authorizationUrl && !detail.authorizationUrl ? { ...detail, authorizationUrl: c3.authorizationUrl } : detail;\n }\n const { problem: _problem, ...rest } = c3;\n return outcome.kind === \"downstream\" ? { ...rest, status: \"error\", problem: \"connector_unavailable\" } : { ...rest, status: \"error\" };\n });\n patch.connectorFailures = outcome.kind === \"local\" ? { ...state.connectorFailures, [id]: outcome.failure } : withoutKey(state.connectorFailures, id);\n if (outcome.kind === \"detail\" && outcome.detail.status === \"ok\" && awaitingAuthorization.delete(id)) {\n if (state.oauthNoticeFor === id) {\n patch.oauthNotice = info(\"Connected.\");\n patch.oauthBlocked = null;\n }\n }\n set({ ...patch, data: { ...state.data, connectors } });\n }\n var detailGeneration = 0;\n var detailRevisions = /* @__PURE__ */ new Map();\n async function loadConnectorDetails(data, current, token) {\n const generation = ++detailGeneration;\n let next = 0;\n const worker = async () => {\n while (next < data.connectors.length && current() && generation === detailGeneration) {\n const connector = data.connectors[next++];\n const revision = (detailRevisions.get(connector.id) ?? 0) + 1;\n detailRevisions.set(connector.id, revision);\n const outcome = await readConnector(connector.id, token);\n if (!current() || generation !== detailGeneration || !state.data) return;\n if (detailRevisions.get(connector.id) !== revision) continue;\n applyDetail(connector.id, outcome);\n }\n };\n await Promise.all(Array.from({ length: Math.min(4, data.connectors.length) }, worker));\n }\n async function refreshConnector(id, quiet = false) {\n const current = fence();\n const revision = (detailRevisions.get(id) ?? 0) + 1;\n detailRevisions.set(id, revision);\n if (!quiet && state.data) {\n set({\n data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...c3, status: \"loading\" } : c3) },\n connectorFailures: withoutKey(state.connectorFailures, id)\n });\n }\n let token;\n try {\n token = await sessionToken();\n } catch {\n if (!current() || quiet || detailRevisions.get(id) !== revision) return;\n return applyDetail(id, { kind: \"local\", failure: \"session\" });\n }\n if (!current()) return;\n const outcome = await readConnector(id, token);\n if (!current() || !state.data || detailRevisions.get(id) !== revision) return;\n if (quiet && outcome.kind !== \"detail\") return;\n applyDetail(id, outcome);\n }\n var tokenRevision = 0;\n async function loadAccessTokens() {\n const identityCurrent = fence();\n const revision = ++tokenRevision;\n const current = () => identityCurrent() && revision === tokenRevision;\n const existing = new Map(state.tokens.map((token) => [token.id, token]));\n set({ tokenPhase: \"loading\", tokenNotice: null });\n try {\n const payload = await operatorRequest(\"/ui/access-tokens\", \"GET\", current);\n if (!current()) return;\n if (!Array.isArray(payload?.accessTokens)) throw new Error(\"The access token collection was not returned.\");\n const tokens = payload.accessTokens;\n const changed = state.tokens.filter((token) => existing.get(token.id) !== token);\n const changedIds = new Set(changed.map((token) => token.id));\n set({ tokenPhase: \"ready\", tokens: [\n ...changed,\n ...tokens.filter((token) => !changedIds.has(token.id))\n ] });\n } catch {\n if (!current()) return;\n set({\n tokenPhase: \"error\",\n tokenNotice: failure(\n \"Access tokens could not be loaded.\"\n )\n });\n }\n }\n function tokenFailure(tokenNotice) {\n return { tokenBusy: false, tokenNotice, pendingFocus: \"tokenNotice\" };\n }\n function createAccessToken(name) {\n if (state.tokenBusy) return Promise.resolve(false);\n if (!name) {\n set(tokenFailure(failure(\"Name the MCP client before creating a token.\")));\n return Promise.resolve(false);\n }\n let created = false;\n return mutate({\n request: (current) => operatorRequest(\"/ui/access-tokens\", \"POST\", current, { name }),\n busy: { tokenBusy: true, tokenNotice: null },\n done: (payload) => {\n const issued = payload?.accessToken;\n if (!payload?.token || !issued) {\n throw new Error(\"The created token was not returned.\");\n }\n created = true;\n return {\n tokenBusy: false,\n tokenPhase: \"ready\",\n tokens: [\n issued,\n ...state.tokens.filter((token) => token.id !== issued.id)\n ],\n createdToken: state.page === \"tokens\" ? payload.token : null,\n tokenNotice: info(\"Access token created.\"),\n pendingFocus: state.page === \"tokens\" ? \"tokenRevealHeading\" : null\n };\n },\n failed: () => tokenFailure(failure(\"Access token could not be created. Check the name, capacity, and storage.\"))\n }).then(() => created);\n }\n function dismissCreatedToken() {\n set({ createdToken: null });\n }\n function renameAccessToken(id) {\n set({ tokenRenaming: id });\n }\n function accessTokenMutation(id, method, body, success, fallback) {\n return mutate({\n request: (current) => operatorRequest(\n `/ui/access-tokens/${encodeURIComponent(id)}`,\n method,\n current,\n body\n ),\n busy: { tokenBusy: true, tokenNotice: null },\n done: (payload) => ({\n tokenBusy: false,\n tokenRenaming: null,\n tokenNotice: info(success),\n pendingFocus: \"tokenNotice\",\n ...payload?.accessToken ? {\n tokens: state.tokens.map(\n (token) => token.id === id ? payload.accessToken : token\n )\n } : {}\n }),\n failed: () => tokenFailure(failure(fallback))\n });\n }\n function saveAccessTokenName(id, name) {\n return accessTokenMutation(\n id,\n \"PUT\",\n { name },\n \"Access token renamed.\",\n \"Access token could not be renamed.\"\n );\n }\n function revokeAccessToken(id) {\n const named = state.tokens.find((token) => token.id === id);\n const confirmed = window.confirm(\n `Revoke ${named?.name || \"this access token\"}? Its MCP client will immediately lose access.`\n );\n if (!confirmed) return Promise.resolve();\n return accessTokenMutation(\n id,\n \"DELETE\",\n void 0,\n \"Access token revoked.\",\n \"Access token could not be revoked.\"\n );\n }\n\n // node_modules/preact/jsx-runtime/dist/jsxRuntime.module.js\n var f3 = 0;\n function u3(e3, t3, n2, o3, i3, u4) {\n t3 || (t3 = {});\n var a3, c3, p3 = t3;\n if (\"ref\" in p3) for (c3 in p3 = {}, t3) \"ref\" == c3 ? a3 = t3[c3] : p3[c3] = t3[c3];\n var l3 = { type: e3, props: p3, key: n2, ref: a3, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: --f3, __i: -1, __u: 0, __source: i3, __self: u4 };\n if (\"function\" == typeof e3 && (a3 = e3.defaultProps)) for (c3 in a3) void 0 === p3[c3] && (p3[c3] = a3[c3]);\n return l.vnode && l.vnode(l3), l3;\n }\n\n // src/operator-ui/app/parts.tsx\n function NoticeLine({\n id,\n notice,\n className = \"meta\"\n }) {\n return /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\n \"p\",\n {\n id,\n class: notice?.tone === \"error\" ? `notice ${className} error-notice` : `notice ${className}`,\n role: notice?.tone === \"error\" ? \"alert\" : \"status\",\n \"aria-live\": \"polite\",\n tabIndex: -1,\n children: notice ? notice.message : null\n }\n ),\n notice?.tone === \"error\" && notice.fix ? /* @__PURE__ */ u3(FixPrompt, { kind: notice.fix.kind, connectorId: notice.fix.connectorId }) : null\n ] });\n }\n function FixPrompt({\n kind,\n connectorId,\n name\n }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"fix-prompt\", \"data-fix-prompt\": kind, children: [\n /* @__PURE__ */ u3(FixPromptButton, { kind, connectorId, ...name ? { name } : {} }),\n /* @__PURE__ */ u3(FixPromptPreview, { kind, connectorId })\n ] });\n }\n function FixPromptButton({\n kind,\n connectorId,\n name\n }) {\n return /* @__PURE__ */ u3(\n CopyButton,\n {\n value: fixPrompt(kind, connectorId),\n label: \"Copy fix prompt\",\n class: \"btn quiet\",\n ariaLabel: `Copy fix prompt for ${name ?? connectorId}`\n }\n );\n }\n function FixPromptPreview({\n kind,\n connectorId,\n standalone\n }) {\n return /* @__PURE__ */ u3(\"details\", { class: \"fix-prompt-preview\", ...standalone ? { \"data-fix-prompt\": kind } : {}, children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: \"Preview prompt\" }),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: \"Fixed text for a coding agent working on this deployment. It carries no error details or secrets.\" }),\n /* @__PURE__ */ u3(\"pre\", { class: \"fix-prompt-text\", children: fixPrompt(kind, connectorId) })\n ] });\n }\n function Badge({\n tone = \"neutral\",\n children\n }) {\n return /* @__PURE__ */ u3(\"span\", { class: tone === \"neutral\" ? \"badge\" : `badge ${tone}`, children });\n }\n function StateBlock({\n title,\n children,\n tone = \"neutral\",\n action,\n id\n }) {\n return /* @__PURE__ */ u3(\n \"div\",\n {\n class: tone === \"error\" ? \"state-block error\" : \"state-block\",\n role: tone === \"error\" ? \"alert\" : \"status\",\n ...id ? { id } : {},\n children: [\n title ? /* @__PURE__ */ u3(\"p\", { class: \"state-title\", children: title }) : null,\n children ? /* @__PURE__ */ u3(\"p\", { class: \"state-copy\", children }) : null,\n action ? /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n onClick: action.onClick,\n ...action.id ? { id: action.id } : {},\n children: action.label\n }\n ) : null\n ]\n }\n );\n }\n function LoadFailure({ state: state2 }) {\n if (!state2.loadFailure) return null;\n const copy = loadFailureCopy(state2.loadFailure, productName);\n return /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"loadFailure\",\n tone: \"error\",\n title: copy.title,\n action: { label: \"Retry\", onClick: () => void retryLoad(), id: \"retryLoad\" },\n children: copy.body\n }\n );\n }\n function Empty({ children }) {\n return /* @__PURE__ */ u3(StateBlock, { children });\n }\n function Unavailable({ children }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"unavailable\", children });\n }\n function ConfirmBar({\n id,\n question,\n confirm,\n onConfirm,\n onCancel\n }) {\n return /* @__PURE__ */ u3(\n \"div\",\n {\n class: \"confirm\",\n role: \"group\",\n \"aria-labelledby\": `confirm-question-${id}`,\n onKeyDown: (event) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n onCancel();\n },\n children: [\n /* @__PURE__ */ u3(\"p\", { id: `confirm-question-${id}`, children: question }),\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n /* @__PURE__ */ u3(\"button\", { class: \"btn danger\", type: \"button\", onClick: onConfirm, children: confirm }),\n /* @__PURE__ */ u3(\n \"button\",\n {\n id: `confirm-cancel-${id}`,\n class: \"btn quiet\",\n type: \"button\",\n onClick: onCancel,\n children: \"Cancel\"\n }\n )\n ] })\n ]\n }\n );\n }\n function focusableId(...ids) {\n for (const id of ids) {\n const element = document.getElementById(id);\n if (element && !element.disabled) return id;\n }\n return ids[ids.length - 1] ?? \"\";\n }\n function PageLink({\n page,\n class: className,\n current,\n children\n }) {\n const href = PAGE_META[page].path;\n return /* @__PURE__ */ u3(\n \"a\",\n {\n class: className,\n href,\n ...current ? { \"aria-current\": \"page\" } : {},\n onClick: (event) => {\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return;\n }\n event.preventDefault();\n navigate(page, href);\n },\n children\n }\n );\n }\n function CopyButton({\n value,\n label,\n class: className = \"btn\",\n ariaLabel,\n id\n }) {\n const [status, setStatus] = d2(\"idle\");\n h2(() => {\n if (status === \"idle\") return;\n const timer = window.setTimeout(() => setStatus(\"idle\"), 1600);\n return () => window.clearTimeout(timer);\n }, [status]);\n return /* @__PURE__ */ u3(\n \"button\",\n {\n class: className,\n type: \"button\",\n ...id ? { id } : {},\n ...ariaLabel && status === \"idle\" ? { \"aria-label\": ariaLabel } : {},\n onClick: () => {\n const write = navigator.clipboard?.writeText(value) ?? Promise.reject(new Error(\"no clipboard\"));\n write.then(\n () => setStatus(\"copied\"),\n () => setStatus(\"failed\")\n );\n },\n children: status === \"copied\" ? \"Copied\" : status === \"failed\" ? \"Copy failed\" : label\n }\n );\n }\n\n // src/operator-ui/app/tokens.tsx\n function CreateForm({ busy }) {\n const [name, setName] = d2(\"\");\n return /* @__PURE__ */ u3(\n \"form\",\n {\n id: \"tokenCreateForm\",\n class: \"token-create\",\n onSubmit: (event) => {\n event.preventDefault();\n void createAccessToken(name.trim()).then((created) => {\n if (created) setName(\"\");\n });\n },\n children: [\n /* @__PURE__ */ u3(\"label\", { for: \"tokenName\", children: \"Client name\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"row\", children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"tokenName\",\n type: \"text\",\n maxLength: 80,\n placeholder: \"Claude desktop, ChatGPT production…\",\n autocomplete: \"off\",\n value: name,\n onInput: (event) => setName(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { id: \"createToken\", class: \"btn\", type: \"submit\", disabled: busy, children: busy ? \"Creating…\" : \"Create token\" })\n ] })\n ]\n }\n );\n }\n function Reveal({ token }) {\n return /* @__PURE__ */ u3(\n \"section\",\n {\n id: \"tokenReveal\",\n class: \"token-reveal\",\n \"aria-labelledby\": \"tokenRevealHeading\",\n children: [\n /* @__PURE__ */ u3(\"div\", { class: \"token-reveal-head\", children: [\n /* @__PURE__ */ u3(\"h2\", { id: \"tokenRevealHeading\", tabIndex: -1, children: \"Copy this token now\" }),\n /* @__PURE__ */ u3(\"span\", { class: \"cap\", children: \"Shown once\" })\n ] }),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: \"Store it in the MCP client before leaving this page. It cannot be displayed again.\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"endpoint-row token-secret\", children: [\n /* @__PURE__ */ u3(\"code\", { id: \"createdToken\", class: \"mono\", children: token }),\n /* @__PURE__ */ u3(CopyButton, { value: token, label: \"Copy token\" })\n ] }),\n /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"button\", onClick: dismissCreatedToken, children: \"I stored it\" })\n ]\n }\n );\n }\n function TokenCard({\n token,\n renaming,\n busy\n }) {\n const [name, setName] = d2(token.name);\n const revoked = Boolean(token.revokedAt);\n return /* @__PURE__ */ u3(\n \"section\",\n {\n class: revoked ? \"token-card revoked\" : \"token-card\",\n \"aria-labelledby\": `access-token-${token.id}`,\n children: [\n /* @__PURE__ */ u3(\"div\", { class: \"token-card-head\", children: [\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"h2\", { id: `access-token-${token.id}`, children: token.name }),\n /* @__PURE__ */ u3(\"p\", { class: \"mono\", children: [\n token.tokenPrefix,\n \"…\"\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"cap\", children: revoked ? `Revoked ${formatDate(token.revokedAt)}` : `Created ${formatDate(token.createdAt)}` })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"credential-actions\", children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n disabled: busy,\n onClick: () => {\n setName(token.name);\n renameAccessToken(renaming ? null : token.id);\n },\n children: \"Rename\"\n }\n ),\n revoked ? null : /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn danger\",\n type: \"button\",\n disabled: busy,\n onClick: () => void revokeAccessToken(token.id),\n children: \"Revoke\"\n }\n )\n ] }),\n renaming ? /* @__PURE__ */ u3(\n \"form\",\n {\n class: \"credential-form\",\n onSubmit: (event) => {\n event.preventDefault();\n const next = name.trim();\n if (next) void saveAccessTokenName(token.id, next);\n },\n children: [\n /* @__PURE__ */ u3(\"label\", { class: \"visually-hidden\", for: `token-name-${token.id}`, children: \"Token name\" }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: `token-name-${token.id}`,\n type: \"text\",\n maxLength: 80,\n autocomplete: \"off\",\n value: name,\n onInput: (event) => setName(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"submit\", disabled: busy, children: \"Save name\" }),\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n disabled: busy,\n onClick: () => renameAccessToken(null),\n children: \"Cancel\"\n }\n )\n ]\n }\n ) : null\n ]\n }\n );\n }\n function TokensPage({ state: state2 }) {\n const available = state2.data?.accessTokenManagement === \"available\";\n return /* @__PURE__ */ u3(\"section\", { id: \"tokensView\", children: /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"tokensHeading\", class: \"\", tabIndex: -1, children: \"Access tokens\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { class: \"activity-copy\", children: \"Create named Bearer tokens for MCP clients. Each secret is shown once; revoke it when that client should lose access.\" }),\n /* @__PURE__ */ u3(NoticeLine, { id: \"tokenNotice\", notice: state2.tokenNotice }),\n !available ? /* @__PURE__ */ u3(Unavailable, { children: accessTokenUnavailableCopy(state2.data?.accessTokenManagement) }) : /* @__PURE__ */ u3(\"div\", { id: \"tokenAvailable\", children: [\n state2.createdToken ? /* @__PURE__ */ u3(Reveal, { token: state2.createdToken }) : /* @__PURE__ */ u3(CreateForm, { busy: state2.tokenBusy }),\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"tokenList\",\n class: \"token-ledger\",\n \"aria-busy\": state2.tokenPhase === \"loading\" ? \"true\" : \"false\",\n children: state2.tokenPhase === \"loading\" ? /* @__PURE__ */ u3(Empty, { children: \"Loading access tokens…\" }) : state2.tokenPhase === \"error\" ? /* @__PURE__ */ u3(\"p\", { class: \"empty\", children: /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n onClick: () => void loadAccessTokens(),\n children: \"Try loading access tokens again\"\n }\n ) }) : state2.tokens.length === 0 ? /* @__PURE__ */ u3(Empty, { children: \"No access tokens yet. Name the first MCP client above.\" }) : state2.tokens.map((token) => /* @__PURE__ */ u3(\n TokenCard,\n {\n token,\n renaming: state2.tokenRenaming === token.id,\n busy: state2.tokenBusy\n },\n token.id\n ))\n }\n )\n ] })\n ] })\n ] }) });\n }\n\n // src/operator-ui/app/activity.tsx\n function ActivityRow({ event }) {\n const outcome = activityOutcomeClass(event.outcome);\n const badge = activityOutcomeBadge(event.outcome);\n const stableId = actorStableId(event.actor);\n return /* @__PURE__ */ u3(\"article\", { class: `activity-item ${outcome}`, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"activity-stamp\", children: [\n /* @__PURE__ */ u3(\"span\", { class: `dot ${outcome}`, \"aria-hidden\": \"true\" }),\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"time\", { class: \"activity-time\", dateTime: event.occurredAt, children: formatDate(event.occurredAt) }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-actor\", children: actorLabel(event.actor) }),\n stableId ? /* @__PURE__ */ u3(\"div\", { class: \"activity-actor-id mono\", children: stableId }) : null\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"div\", { class: \"activity-address\", children: event.address }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-detail\", children: activityDetail(event) })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-result\", children: [\n /* @__PURE__ */ u3(Badge, { tone: badge.tone, children: badge.label }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-detail\", children: [\n event.durationMs,\n \" ms\"\n ] })\n ] })\n ] });\n }\n function ActivityPage({ state: state2 }) {\n const data = state2.data;\n const enabled = Boolean(data?.activityEnabled);\n const loading = state2.activityPhase === \"loading\";\n const visible = filterActivity(state2.activityEvents, state2.activitySearch);\n const summary = activitySummary(state2.activityEvents);\n const failed = state2.activityPhase === \"error\";\n return /* @__PURE__ */ u3(\"section\", { id: \"activityView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"activityHeading\", tabIndex: -1, children: \"Activity\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: /* @__PURE__ */ u3(\"p\", { children: pageDescription(\"activity\", productDescription) }) })\n ] }),\n !data ? (\n // Whether Activity is open to this identity is in /ui/data, which\n // has not answered yet — or could not.\n state2.loadFailure ? /* @__PURE__ */ u3(LoadFailure, { state: state2 }) : /* @__PURE__ */ u3(StateBlock, { children: \"Loading activity…\" })\n ) : !enabled ? /* @__PURE__ */ u3(Unavailable, { children: [\n \"Activity history is not configured. Add an\",\n \" \",\n /* @__PURE__ */ u3(\"span\", { class: \"mono\", children: \"activity.store\" }),\n \" with a list reader to enable this page.\"\n ] }) : /* @__PURE__ */ u3(\"div\", { id: \"activityAvailable\", class: \"collection\", children: [\n failed && state2.activityEvents.length === 0 ? null : /* @__PURE__ */ u3(\"div\", { class: \"row\", children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"activitySearch\",\n type: \"search\",\n placeholder: \"Search user, tool, or outcome…\",\n \"aria-label\": \"Search loaded activity\",\n value: state2.activitySearch,\n onInput: (event) => setActivitySearch(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\n \"button\",\n {\n id: \"refreshActivity\",\n class: \"btn\",\n type: \"button\",\n disabled: loading,\n onClick: () => void loadActivity(true),\n children: loading ? \"Loading…\" : \"Refresh\"\n }\n )\n ] }),\n /* @__PURE__ */ u3(\"p\", { id: \"activitySummary\", class: \"meta\", \"aria-live\": \"polite\", children: summary }),\n state2.activityEvents.length === 0 ? loading ? /* @__PURE__ */ u3(StateBlock, { children: \"Loading activity…\" }) : failed ? /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"activityError\",\n tone: \"error\",\n title: \"Activity couldn't be loaded\",\n action: { label: \"Retry\", onClick: () => void retryCollection() },\n children: state2.activityNotice?.message\n }\n ) : /* @__PURE__ */ u3(StateBlock, { children: state2.activitySearch.trim() ? \"No loaded activity matches this search.\" : \"No connector tool calls recorded yet.\" }) : visible.length === 0 ? /* @__PURE__ */ u3(StateBlock, { children: \"No loaded activity matches this search.\" }) : /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"activityList\",\n class: \"activity-list\",\n \"aria-busy\": loading ? \"true\" : \"false\",\n children: visible.map((event, index) => /* @__PURE__ */ u3(\n ActivityRow,\n {\n event\n },\n `${event.occurredAt}-${event.address}-${index}`\n ))\n }\n ),\n state2.activityEvents.length > 0 ? /* @__PURE__ */ u3(NoticeLine, { id: \"activityNotice\", notice: state2.activityNotice }) : null,\n state2.activityCursor ? /* @__PURE__ */ u3(\n \"button\",\n {\n id: \"moreActivity\",\n class: \"btn activity-more\",\n type: \"button\",\n disabled: loading,\n onClick: () => void loadActivity(false),\n children: loading ? \"Loading…\" : \"Load older\"\n }\n ) : null\n ] })\n ] });\n }\n\n // src/operator-ui/app/artifacts.tsx\n function ArtifactRow({ row }) {\n const refresh = artifactRefreshBadge(row.freshness?.last);\n return /* @__PURE__ */ u3(\"article\", { class: \"artifact-row\", children: [\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"a\", { class: \"artifact-title\", href: `/artifacts/${row.id}`, children: row.title }),\n /* @__PURE__ */ u3(\"div\", { class: \"artifact-meta\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"mono\", children: row.id }),\n \" · version \",\n row.viewVersion,\n \" · updated\",\n \" \",\n /* @__PURE__ */ u3(\"time\", { dateTime: row.updatedAt, children: formatDate(row.updatedAt) }),\n \" by \",\n row.updatedBy.label\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"artifact-badges\", children: [\n /* @__PURE__ */ u3(Badge, { children: row.kind === \"markdown\" ? \"Markdown\" : \"HTML\" }),\n row.freshness?.state === \"stale\" ? /* @__PURE__ */ u3(Badge, { tone: \"warn\", children: \"Stale data\" }) : row.freshness?.state === \"current\" ? /* @__PURE__ */ u3(Badge, { children: \"Current data\" }) : null,\n refresh ? /* @__PURE__ */ u3(Badge, { tone: refresh.tone, children: refresh.label }) : null,\n row.archived ? /* @__PURE__ */ u3(Badge, { tone: \"warn\", children: \"Archived\" }) : null\n ] })\n ] });\n }\n function ArtifactsPage({ state: state2 }) {\n const loading = state2.artifactPhase === \"loading\";\n const rows = state2.artifactRows;\n return /* @__PURE__ */ u3(\"section\", { id: \"artifactsView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"artifactsHeading\", tabIndex: -1, children: \"Artifacts\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: /* @__PURE__ */ u3(\"p\", { children: pageDescription(\"artifacts\", productDescription) }) })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"collection\", children: [\n /* @__PURE__ */ u3(\n \"form\",\n {\n class: \"row\",\n onSubmit: (event) => {\n event.preventDefault();\n void loadArtifacts(true);\n },\n children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"artifactSearch\",\n type: \"search\",\n placeholder: \"Search titles…\",\n \"aria-label\": \"Search artifact titles\",\n value: state2.artifactQuery,\n onInput: (event) => setArtifactQuery(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { id: \"searchArtifacts\", class: \"btn\", type: \"submit\", disabled: loading, children: \"Search\" }),\n /* @__PURE__ */ u3(\"label\", { class: \"check artifact-meta\", children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"showArchived\",\n type: \"checkbox\",\n checked: state2.artifactArchived,\n onChange: (event) => setArtifactArchived(event.currentTarget.checked)\n }\n ),\n \" \",\n \"Show archived\"\n ] })\n ]\n }\n ),\n state2.artifactPhase === \"error\" && rows.length === 0 ? /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"artifactError\",\n tone: \"error\",\n title: \"Artifacts couldn't be loaded\",\n action: { label: \"Retry\", onClick: () => void retryCollection() },\n children: state2.artifactNotice?.message\n }\n ) : rows.length === 0 ? /* @__PURE__ */ u3(StateBlock, { children: loading ? \"Loading artifacts…\" : state2.artifactQuery.trim() ? \"No artifact title matches this search.\" : \"No artifacts yet. Ask an agent to publish one.\" }) : /* @__PURE__ */ u3(\"div\", { id: \"artifactList\", class: \"activity-list\", \"aria-busy\": loading ? \"true\" : \"false\", children: rows.map((row) => /* @__PURE__ */ u3(ArtifactRow, { row }, row.id)) }),\n rows.length > 0 ? /* @__PURE__ */ u3(NoticeLine, { id: \"artifactNotice\", notice: state2.artifactNotice }) : null,\n state2.artifactCursor ? /* @__PURE__ */ u3(\n \"button\",\n {\n id: \"moreArtifacts\",\n class: \"btn activity-more\",\n type: \"button\",\n disabled: loading,\n onClick: () => void loadArtifacts(false),\n children: loading ? \"Loading…\" : \"Load more\"\n }\n ) : null\n ] })\n ] });\n }\n function ArtifactFrame({ view }) {\n const frame = A2(null);\n _2(() => {\n const element = frame.current;\n if (!element) return;\n const onMessage = (event) => {\n if (event.source !== element.contentWindow || event.origin !== \"null\") return;\n const data = event.data;\n if (!data || data.type !== \"ready\") return;\n window.removeEventListener(\"message\", onMessage);\n const policy = document.createElement(\"meta\");\n policy.httpEquiv = \"Content-Security-Policy\";\n policy.content = \"frame-src 'none'\";\n document.head.append(policy);\n markArtifactFrameConfined();\n element.contentWindow?.postMessage({ type: \"document\", html: view.document }, \"*\");\n };\n window.addEventListener(\"message\", onMessage);\n return () => window.removeEventListener(\"message\", onMessage);\n }, [view.document]);\n return /* @__PURE__ */ u3(\n \"iframe\",\n {\n ref: frame,\n id: \"artifactFrame\",\n class: \"artifact-frame\",\n title: view.title,\n sandbox: \"allow-scripts\",\n referrerpolicy: \"no-referrer\",\n src: \"/artifacts/_frame\"\n }\n );\n }\n function ArtifactPage({ state: state2 }) {\n const view = state2.artifactView;\n const failed = state2.artifactPhase === \"error\";\n return /* @__PURE__ */ u3(\"section\", { id: \"artifactView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"artifact-head\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"artifactHeading\", tabIndex: -1, children: view?.title ?? \"Artifact\" }),\n view ? /* @__PURE__ */ u3(\"div\", { class: \"artifact-meta\", id: \"artifactMeta\", children: [\n view.snapshot ? \"Snapshot of \" : \"\",\n \"version \",\n view.view.version,\n view.snapshot && view.view.version !== view.latestViewVersion ? ` (latest is ${view.latestViewVersion})` : \"\",\n \" \",\n \"· updated \",\n /* @__PURE__ */ u3(\"time\", { dateTime: view.view.at, children: formatDate(view.view.at) }),\n \" by\",\n \" \",\n view.view.by.label,\n \" ·\",\n \" \",\n /* @__PURE__ */ u3(\"a\", { href: \"/artifacts\", children: \"All artifacts\" }),\n view.snapshot ? /* @__PURE__ */ u3(S, { children: [\n \" \",\n \"· \",\n /* @__PURE__ */ u3(\"a\", { href: view.url, children: \"Current version\" })\n ] }) : /* @__PURE__ */ u3(S, { children: [\n \" \",\n \"·\",\n \" \",\n /* @__PURE__ */ u3(\n CopyButton,\n {\n id: \"copySnapshot\",\n class: \"navlink inline\",\n value: view.snapshotUrl,\n label: \"Copy snapshot link\"\n }\n )\n ] })\n ] }) : null,\n view?.archived ? /* @__PURE__ */ u3(\"div\", { id: \"archivedBanner\", class: \"artifact-banner\", role: \"status\", children: \"This artifact is archived. It keeps every version, and an agent can restore it.\" }) : null,\n !view?.snapshot && view?.freshness?.state === \"stale\" ? /* @__PURE__ */ u3(\"div\", { id: \"staleBanner\", class: \"artifact-banner\", role: \"status\", children: [\n \"Data may be out of date. The last refresh \",\n view.freshness.last?.status === \"failed\" ? \"failed\" : \"is overdue\",\n \"; the last good document is still shown.\"\n ] }) : null,\n !view && !failed ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: pageDescription(\"artifact\", productDescription) }) : null\n ] }),\n view ? /* @__PURE__ */ u3(ArtifactFrame, { view }, view.snapshotUrl) : failed ? /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"artifactError\",\n tone: \"error\",\n title: \"This artifact couldn't be opened\",\n action: { label: \"Retry\", onClick: () => void retryCollection() },\n children: state2.artifactNotice?.message\n }\n ) : /* @__PURE__ */ u3(StateBlock, { children: \"Loading artifact…\" })\n ] });\n }\n\n // src/operator-ui/app/credentials.tsx\n function CredentialForm({\n connector,\n credential,\n busy\n }) {\n const fields = credential.fields ?? [];\n const [values, setValues] = d2({});\n const single = fields.length === 0;\n const inputId = `credential-input-${connector}`;\n const submit = () => {\n if (single) {\n const value = (values.value ?? \"\").trim();\n if (!value) return refuseCredential(connector, \"Paste a credential before saving.\");\n return void saveCredential(connector, { value });\n }\n const entries = {};\n for (const field of fields) {\n const value = (values[field.name] ?? \"\").trim();\n if (!value) {\n return refuseCredential(\n connector,\n \"Complete every credential field before saving.\"\n );\n }\n entries[field.name] = value;\n }\n void saveCredential(connector, { values: entries });\n };\n return /* @__PURE__ */ u3(\"div\", { class: \"credential-form\", \"data-credential-form\": connector, children: [\n single ? /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\"label\", { class: \"visually-hidden\", for: inputId, children: credential.label }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: inputId,\n type: \"password\",\n \"aria-label\": credential.label,\n placeholder: credential.placeholder || \"Paste credential\",\n autocomplete: \"new-password\",\n autocapitalize: \"none\",\n spellcheck: false,\n value: values.value ?? \"\",\n onInput: (event) => setValues({ value: event.currentTarget.value })\n }\n )\n ] }) : /* @__PURE__ */ u3(\"div\", { class: \"credential-fields\", children: fields.map((field, index) => {\n const id = `credential-input-${connector}-${index}`;\n return /* @__PURE__ */ u3(\"div\", { class: \"credential-field\", children: [\n /* @__PURE__ */ u3(\"label\", { for: id, children: field.label }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id,\n type: field.inputType || \"password\",\n placeholder: field.placeholder || field.label,\n autocomplete: (field.inputType ?? \"password\") === \"password\" ? \"new-password\" : \"off\",\n autocapitalize: \"none\",\n spellcheck: false,\n value: values[field.name] ?? \"\",\n onInput: (event) => setValues({\n ...values,\n [field.name]: event.currentTarget.value\n })\n }\n )\n ] }, field.name);\n }) }),\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n /* @__PURE__ */ u3(\"button\", { class: \"btn primary\", type: \"button\", disabled: busy, onClick: submit, children: busy ? \"Saving…\" : \"Save\" }),\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn quiet\",\n type: \"button\",\n disabled: busy,\n onClick: () => editCredential(null),\n children: \"Cancel\"\n }\n )\n ] })\n ] });\n }\n function CredentialCard({\n connector,\n credential,\n editing,\n busy,\n confirming,\n notice\n }) {\n const name = connector.title || connector.id;\n const configured = Boolean(credential.configured);\n const removable = configured || Boolean(credential.removable);\n return /* @__PURE__ */ u3(\n \"section\",\n {\n class: \"subcard\",\n id: `credential-${connector.id}`,\n \"aria-labelledby\": `credential-title-${connector.id}`,\n children: [\n /* @__PURE__ */ u3(\"div\", { class: \"subcard-head\", children: [\n /* @__PURE__ */ u3(\"h3\", { id: `credential-title-${connector.id}`, children: credential.label }),\n /* @__PURE__ */ u3(\"span\", { class: \"meta\", children: credentialStateLabel(credential) })\n ] }),\n credential.description ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: credential.description }) : null,\n credential.fields?.length ? /* @__PURE__ */ u3(\"div\", { class: \"credential-field-summary\", children: credential.fields.map((field) => /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"span\", { children: field.label }),\n /* @__PURE__ */ u3(\"span\", { class: \"meta\", children: field.configured ? `configured · ••••${field.lastFour ?? \"\"}${field.updatedAt ? ` · updated ${formatDate(field.updatedAt)}` : \"\"}` : \"not configured\" })\n ] }, field.name)) }) : null,\n credential.error ? /* @__PURE__ */ u3(\"p\", { class: \"msg\", children: credentialProblemCopy(credential.problem) }) : null,\n credential.error && credential.problem ? /* @__PURE__ */ u3(\n FixPrompt,\n {\n kind: credential.problem,\n connectorId: connector.id,\n name: connector.title || connector.id\n }\n ) : null,\n credential.notice ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: credential.notice }) : null,\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: removable ? \"btn\" : \"btn primary\",\n type: \"button\",\n \"aria-expanded\": editing ? \"true\" : \"false\",\n disabled: busy,\n onClick: () => editCredential(editing ? null : connector.id),\n children: removable ? \"Replace\" : \"Add credential\"\n }\n ),\n configured && credential.testable ? /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n disabled: busy,\n onClick: () => void testCredential(connector.id),\n children: busy ? \"Working…\" : \"Test\"\n }\n ) : null,\n removable ? /* @__PURE__ */ u3(\n \"button\",\n {\n id: `remove-credential-${connector.id}`,\n class: \"btn danger\",\n type: \"button\",\n disabled: busy,\n onClick: () => askConfirm(connector.id, \"credential_remove\"),\n children: \"Remove\"\n }\n ) : null\n ] }),\n confirming ? /* @__PURE__ */ u3(\n ConfirmBar,\n {\n id: connector.id,\n ...confirmCopy(\"credential_remove\", name),\n onConfirm: () => void removeCredential(connector.id),\n onCancel: () => cancelConfirm(\n focusableId(`remove-credential-${connector.id}`, `conn-toggle-${connector.id}`)\n )\n }\n ) : null,\n editing ? /* @__PURE__ */ u3(\n CredentialForm,\n {\n connector: connector.id,\n credential,\n busy\n }\n ) : null,\n /* @__PURE__ */ u3(NoticeLine, { id: `credentialNotice-${connector.id}`, notice })\n ]\n }\n );\n }\n\n // src/operator-ui/model.ts\n function filterUiConnectors(connectors, query) {\n const q2 = query.trim().toLowerCase();\n const filtered = [];\n for (const connector of connectors) {\n const connectorText = [\n connector.id,\n connector.title,\n connector.description,\n connector.status\n ].join(\" \").toLowerCase();\n const connectorMatches = Boolean(q2 && connectorText.includes(q2));\n const tools = connector.tools.filter(\n (tool) => !q2 || connectorMatches || `${tool.name} ${tool.description ?? \"\"}`.toLowerCase().includes(q2)\n );\n if (q2 && tools.length === 0 && !connectorMatches) continue;\n filtered.push({ connector, tools });\n }\n return filtered;\n }\n\n // src/operator-ui/setup-commands.ts\n function clientServerName(serverName, pool) {\n const base = (serverName ?? \"\").toLowerCase().replace(/[^a-z0-9_-]+/g, \"-\").replace(/-{2,}/g, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 48) || \"connecta\";\n return pool ? `${base}-${pool}` : base;\n }\n function poolEndpointUrl(mcpUrl2, pool) {\n return `${mcpUrl2.replace(/\\/+$/, \"\")}/${encodeURIComponent(pool)}`;\n }\n function shellWord(value) {\n return /^[A-Za-z0-9_./:@%+=,~-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\"'\"'`)}'`;\n }\n function clientSetupCommands(name, url) {\n return [\n {\n id: \"claude\",\n label: \"Claude Code\",\n text: `claude mcp add --transport http ${shellWord(name)} ${shellWord(url)}`\n },\n {\n id: \"codex\",\n label: \"Codex\",\n text: `codex mcp add ${shellWord(name)} --url ${shellWord(url)}`\n },\n {\n id: \"json\",\n label: \"JSON config\",\n text: JSON.stringify(\n { mcpServers: { [name]: { type: \"http\", url } } },\n null,\n 2\n )\n }\n ];\n }\n\n // src/operator-ui/app/connections.tsx\n var DRIFT_HEADING = {\n clean: \"Catalog drift · none\",\n warning: \"Catalog drift · review\",\n unavailable: \"Catalog drift · not observed\"\n };\n function DriftPanel({ connector }) {\n const drift = connector.catalogDrift;\n const state2 = driftState(drift);\n return /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: `drift-${connector.id}`,\n class: `connector-drift ${state2}`,\n \"data-drift\": state2,\n children: [\n /* @__PURE__ */ u3(\"p\", { class: \"cap\", children: DRIFT_HEADING[state2] }),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: driftSummary(drift) }),\n state2 === \"unavailable\" ? null : /* @__PURE__ */ u3(\"ul\", { class: \"drift-counts\", children: driftCounts(drift).map(({ key, label, count }) => /* @__PURE__ */ u3(\"li\", { class: count > 0 ? \"drift-count flagged\" : \"drift-count\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"drift-count-value\", children: count }),\n /* @__PURE__ */ u3(\"span\", { class: \"drift-count-label\", children: label })\n ] }, key)) })\n ]\n }\n ),\n state2 === \"warning\" ? /* @__PURE__ */ u3(\n FixPrompt,\n {\n kind: \"catalog_drift\",\n connectorId: connector.id,\n name: connector.title || connector.id\n }\n ) : null\n ] });\n }\n function SafetyBadge({ safety }) {\n const badge = safety ? TOOL_SAFETY_BADGE[safety] : void 0;\n if (!badge) return null;\n return /* @__PURE__ */ u3(\"span\", { class: \"tool-safety\", title: badge.title, \"data-safety\": safety, children: /* @__PURE__ */ u3(Badge, { tone: badge.tone, children: badge.label }) });\n }\n function Endpoint({\n url,\n name,\n label,\n primary\n }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"endpoint-block\", \"data-endpoint\": name, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"endpoint\", children: [\n label ? /* @__PURE__ */ u3(\"span\", { class: \"endpoint-label cap\", children: label }) : null,\n /* @__PURE__ */ u3(\"code\", { ...primary ? { id: \"mcpUrl\" } : {}, class: \"mono\", children: url }),\n /* @__PURE__ */ u3(\n CopyButton,\n {\n value: url,\n label: \"Copy URL\",\n ...label ? { ariaLabel: `Copy URL for ${label}` } : {}\n }\n )\n ] }),\n /* @__PURE__ */ u3(\"details\", { class: \"setup\", children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: [\n \"Client setup\",\n label ? ` · ${label}` : \"\"\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"setup-list\", children: [\n clientSetupCommands(name, url).map((command) => /* @__PURE__ */ u3(\"div\", { class: \"setup-item\", \"data-setup\": command.id, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"setup-head\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"cap\", children: command.label }),\n /* @__PURE__ */ u3(\n CopyButton,\n {\n value: command.text,\n label: \"Copy\",\n class: \"btn quiet\",\n ariaLabel: `Copy ${command.label} setup${label ? ` for ${label}` : \"\"}`\n }\n )\n ] }),\n /* @__PURE__ */ u3(\"pre\", { class: \"setup-code\", children: command.text })\n ] }, command.id)),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: \"No token is included. Clients sign in through this deployment's inbound auth.\" })\n ] })\n ] })\n ] });\n }\n function AuthActions({\n connector,\n name,\n manage,\n state: state2\n }) {\n const id = connector.id;\n const authorization = safeHttpHref(connector.authorizationUrl);\n const busy = state2.oauthBusy === id;\n if (connector.status === \"loading\") return null;\n if (!connector.oauth || !manage) {\n return authorization && connector.status !== \"ok\" ? /* @__PURE__ */ u3(\"a\", { class: \"btn primary\", href: authorization, target: \"_blank\", rel: \"noopener noreferrer\", children: \"Authorize connector\" }) : null;\n }\n if (state2.oauthBlocked === id && authorization) {\n return /* @__PURE__ */ u3(\n \"a\",\n {\n id: `authorize-${id}`,\n class: \"btn primary\",\n href: authorization,\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n children: \"Open authorization page\"\n }\n );\n }\n if (connector.status !== \"ok\") {\n const needsAuth = connector.status === \"auth_required\";\n return /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `connect-${id}`,\n class: needsAuth ? \"btn primary\" : \"btn\",\n \"aria-label\": `${needsAuth ? \"Connect\" : \"Reconnect\"} ${name}`,\n disabled: busy,\n onClick: () => void startOAuth(id, \"continue\"),\n children: busy ? \"Opening…\" : needsAuth ? \"Connect account\" : \"Reconnect\"\n }\n );\n }\n const switching = connector.authScope === \"personal\";\n return /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `reconnect-${id}`,\n class: \"btn\",\n \"aria-label\": `${switching ? \"Switch account for\" : \"Reconnect\"} ${name}`,\n disabled: busy,\n onClick: () => askConfirm(id, \"oauth_restart\"),\n children: busy ? \"Working…\" : switching ? \"Switch account\" : \"Reconnect\"\n }\n ),\n /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `disconnect-${id}`,\n class: \"btn danger\",\n \"aria-label\": `Disconnect ${name}`,\n disabled: busy,\n onClick: () => askConfirm(id, \"oauth_disconnect\"),\n children: \"Disconnect\"\n }\n )\n ] });\n }\n function ConnectorRow({\n connector,\n tools,\n forceOpen,\n state: state2\n }) {\n const [open, setOpen] = d2(false);\n const shown = open || forceOpen;\n const id = connector.id;\n const name = connector.title || id;\n const drift = driftState(connector.catalogDrift);\n const manage = Boolean(\n connector.permissions?.manageSharedAuth || connector.permissions?.connectPersonal\n );\n const local = state2.connectorFailures[id];\n const problem = connector.status === \"loading\" || local ? null : problemCopy(connector.problem);\n const confirming = state2.confirming?.connectorId === id ? state2.confirming : null;\n const oauthConfirm = confirming && confirming.action !== \"credential_remove\" ? confirming : null;\n const statusLabel = local ? \"Couldn't load\" : connectorStatusLabel(connector.status, connector.problem);\n const fixKind = problem && connector.problem && problemTone(connector.problem) === \"danger\" && connector.problem !== connector.credential?.problem ? connector.problem : null;\n const statusTone = local ? \"warn\" : connectorStatusTone(connector.status);\n return /* @__PURE__ */ u3(\"div\", { class: shown ? \"conn open\" : \"conn\", \"data-connector\": id, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"conn-head\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"conn-main\", children: [\n /* @__PURE__ */ u3(\"span\", { class: `dot ${local ? \"warn\" : connector.status}`, \"aria-hidden\": \"true\" }),\n /* @__PURE__ */ u3(\"h2\", { class: \"conn-name\", children: /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `conn-toggle-${id}`,\n class: \"conn-toggle\",\n \"aria-expanded\": shown ? \"true\" : \"false\",\n \"aria-controls\": `conn-body-${id}`,\n \"aria-describedby\": `conn-state-${id}`,\n onClick: () => setOpen(!shown),\n children: name\n }\n ) }),\n connector.title ? /* @__PURE__ */ u3(\"span\", { class: \"conn-id mono\", children: id }) : null\n ] }),\n /* @__PURE__ */ u3(\"span\", { class: \"conn-badges\", id: `conn-state-${id}`, children: [\n drift === \"warning\" ? /* @__PURE__ */ u3(Badge, { tone: \"warn\", children: \"drift\" }) : null,\n /* @__PURE__ */ u3(Badge, { children: authScopeLabel(connector.authScope) }),\n /* @__PURE__ */ u3(Badge, { children: connector.status === \"loading\" ? \"tools not loaded\" : toolCountLabel(connector.toolCount) }),\n /* @__PURE__ */ u3(Badge, { tone: statusTone, children: statusLabel }),\n /* @__PURE__ */ u3(\"span\", { class: \"conn-caret\", \"aria-hidden\": \"true\" })\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"conn-body\", id: `conn-body-${id}`, hidden: !shown, children: [\n connector.description ? /* @__PURE__ */ u3(\"p\", { class: \"conn-note\", children: connector.description }) : null,\n problem && connector.problem ? /* @__PURE__ */ u3(\n \"p\",\n {\n class: problemTone(connector.problem) === \"warn\" ? \"msg warn\" : \"msg\",\n \"data-problem\": connector.problem,\n children: problem\n }\n ) : null,\n local ? /* @__PURE__ */ u3(\"p\", { class: \"msg warn\", \"data-load-failure\": local, children: connectorLoadFailureCopy(local, productName) }) : null,\n connector.authorizationUrl && !safeHttpHref(connector.authorizationUrl) ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: [\n \"Authorization URL: \",\n connector.authorizationUrl\n ] }) : null,\n manage ? null : /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: permissionLabel(connector) }),\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n local ? null : /* @__PURE__ */ u3(AuthActions, { connector, name, manage, state: state2 }),\n fixKind ? /* @__PURE__ */ u3(FixPromptButton, { kind: fixKind, connectorId: id, name }) : null,\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: local ? \"btn primary\" : \"btn quiet\",\n type: \"button\",\n \"aria-label\": `Refresh ${name}`,\n disabled: connector.status === \"loading\",\n onClick: () => void refreshConnector(id),\n children: \"Refresh\"\n }\n )\n ] }),\n fixKind ? /* @__PURE__ */ u3(FixPromptPreview, { kind: fixKind, connectorId: id, standalone: true }) : null,\n oauthConfirm ? /* @__PURE__ */ u3(\n ConfirmBar,\n {\n id,\n ...confirmCopy(oauthConfirm.action, name),\n onConfirm: () => {\n if (oauthConfirm.action === \"oauth_restart\") void startOAuth(id, \"restart\");\n else void disconnectOAuth(id);\n },\n onCancel: () => cancelConfirm(\n focusableId(\n oauthConfirm.action === \"oauth_restart\" ? `reconnect-${id}` : `disconnect-${id}`,\n `conn-toggle-${id}`\n )\n )\n }\n ) : null,\n /* @__PURE__ */ u3(\n NoticeLine,\n {\n id: `oauthNotice-${id}`,\n notice: state2.oauthNoticeFor === id ? state2.oauthNotice : null\n }\n ),\n connector.credential ? /* @__PURE__ */ u3(\n CredentialCard,\n {\n connector,\n credential: connector.credential,\n editing: state2.credentialEditing === id,\n busy: state2.credentialBusy === id,\n confirming: confirming?.action === \"credential_remove\",\n notice: state2.credentialNoticeFor === id ? state2.credentialNotice : null\n }\n ) : null,\n tools.length ? /* @__PURE__ */ u3(\"details\", { open: forceOpen, children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: [\n \"Tools (\",\n tools.length,\n \")\"\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"tool-list\", children: [\n tools.some((tool) => tool.safety) ? /* @__PURE__ */ u3(\"p\", { class: \"meta tool-legend\", children: \"Read-only tools run inside execute_code programs. Everything else asks the host first: a program pauses for resume_execution, and a direct call goes through call_destructive_tool — unless this deployment's config exempts the tool, in which case programs call it unasked.\" }) : null,\n tools.map((tool) => /* @__PURE__ */ u3(\"div\", { class: \"tool\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"tool-head\", children: [\n /* @__PURE__ */ u3(\"code\", { children: tool.address }),\n /* @__PURE__ */ u3(SafetyBadge, { safety: tool.safety })\n ] }),\n tool.description ? /* @__PURE__ */ u3(\"span\", { class: \"td\", children: tool.description }) : null\n ] }, tool.address))\n ] })\n ] }) : null,\n /* @__PURE__ */ u3(\"details\", { children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: \"Diagnostics\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"subcard\", children: [\n /* @__PURE__ */ u3(DriftPanel, { connector }),\n connector.catalogAccess ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: [\n \"Agents last read its catalog\",\n \" \",\n connector.catalogAccess.state === \"stale\" ? \"from a stale cache\" : \"fresh\",\n \" · \",\n formatDate(connector.catalogAccess.observedAt)\n ] }) : null\n ] })\n ] })\n ] })\n ] });\n }\n function Endpoints({\n pools,\n serverName\n }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"endpoints\", children: [\n /* @__PURE__ */ u3(\n Endpoint,\n {\n url: mcpUrl,\n name: clientServerName(serverName),\n primary: true,\n ...pools.length ? { label: \"All tools\" } : {}\n }\n ),\n pools.map((pool) => /* @__PURE__ */ u3(\n Endpoint,\n {\n url: poolEndpointUrl(mcpUrl, pool),\n name: clientServerName(serverName, pool),\n label: `Pool · ${pool}`\n },\n pool\n ))\n ] });\n }\n function SummaryLine({ connectors }) {\n const parts = connectorSummaryParts(summarizeConnectors(connectors));\n return /* @__PURE__ */ u3(\"p\", { class: \"summary\", id: \"connectorSummary\", children: parts.map((part, index) => /* @__PURE__ */ u3(\"span\", { children: [\n index > 0 ? /* @__PURE__ */ u3(\"span\", { class: \"sep\", children: \" · \" }) : null,\n /* @__PURE__ */ u3(\"span\", { class: part.tone === \"neutral\" ? \"\" : part.tone, children: part.text })\n ] }, part.text)) });\n }\n function ConnectionsPage({ state: state2 }) {\n const data = state2.data;\n const query = state2.connectorFilter.trim();\n const filtered = data ? filterUiConnectors(data.connectors, query) : [];\n return /* @__PURE__ */ u3(\"section\", { id: \"connectionsView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"connectionsHeading\", tabIndex: -1, children: \"Connections\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { children: \"Point an MCP client at this endpoint to reach the tools below.\" }),\n /* @__PURE__ */ u3(Endpoints, { pools: data?.pools ?? [], serverName: data?.serverInfo?.name }),\n /* @__PURE__ */ u3(\"p\", { class: \"cap\", id: \"serverInfo\", children: data ? `${data.serverInfo?.name || productName} v${data.connectaVersion || \"?\"}` : productOperatorLabel }),\n data ? /* @__PURE__ */ u3(SummaryLine, { connectors: data.connectors }) : null\n ] })\n ] }),\n /* @__PURE__ */ u3(\"section\", { class: \"section\", \"aria-labelledby\": \"connectorLedgerHeading\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"section-head\", children: [\n /* @__PURE__ */ u3(\"h2\", { id: \"connectorLedgerHeading\", tabIndex: -1, children: \"Connectors\" }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"filter\",\n type: \"search\",\n class: \"filter\",\n placeholder: \"Filter connectors or tools…\",\n \"aria-label\": \"Filter connectors or tools\",\n value: state2.connectorFilter,\n disabled: !data,\n onInput: (event) => setConnectorFilter(event.currentTarget.value)\n }\n )\n ] }),\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"list\",\n class: !data || filtered.length === 0 ? \"\" : \"rows\",\n \"aria-busy\": state2.refreshing || !data && !state2.loadFailure ? \"true\" : \"false\",\n children: !data ? state2.loadFailure ? /* @__PURE__ */ u3(LoadFailure, { state: state2 }) : /* @__PURE__ */ u3(Empty, { children: \"Loading connectors…\" }) : filtered.length === 0 ? /* @__PURE__ */ u3(Empty, { children: query ? \"No connectors or tools match this filter.\" : \"No connectors are declared in this deployment.\" }) : filtered.map(({ connector, tools }) => /* @__PURE__ */ u3(\n ConnectorRow,\n {\n connector,\n tools,\n forceOpen: Boolean(query),\n state: state2\n },\n connector.id\n ))\n }\n )\n ] })\n ] });\n }\n\n // src/operator-ui/app/main.tsx\n function useOperatorState() {\n const [, bump] = y2((count) => count + 1, 0);\n const snapshot = getState();\n _2(() => {\n const unsubscribe = subscribe(() => bump(void 0));\n if (getState() !== snapshot) bump(void 0);\n return unsubscribe;\n }, []);\n return snapshot;\n }\n function visiblePages(state2) {\n const hint = state2.data ? null : navHint();\n return OPERATOR_PAGES.filter((page) => {\n if (page === \"tokens\") return state2.data?.accessTokenManagement === \"available\";\n if (page === \"activity\") return hint ? hint.activity : Boolean(state2.data?.activityEnabled);\n if (page === \"artifacts\") {\n return isArtifactPage(state2.page) || (hint ? hint.artifacts : Boolean(state2.data?.artifactsEnabled));\n }\n return true;\n });\n }\n function OperatorNav() {\n const state2 = useOperatorState();\n if (state2.session !== \"ready\") return null;\n const onArtifactPage = isArtifactPage(state2.page);\n return /* @__PURE__ */ u3(\"div\", { class: \"mast-actions\", children: [\n /* @__PURE__ */ u3(\"nav\", { class: \"page-nav\", \"aria-label\": \"Operator pages\", children: visiblePages(state2).map(\n (page) => (\n // Crossing between artifact pages and the rest is a full navigation:\n // with a dedicated artifact origin, the two live on different hosts.\n page === \"artifacts\" || onArtifactPage ? /* @__PURE__ */ u3(\n \"a\",\n {\n class: \"navlink\",\n href: page === \"artifacts\" ? PAGE_META.artifacts.path : new URL(PAGE_META[page].path, new URL(homeUrl, window.location.href)).href,\n ...state2.page === page ? { \"aria-current\": \"page\" } : {},\n children: PAGE_META[page].label\n },\n page\n ) : /* @__PURE__ */ u3(\n PageLink,\n {\n page,\n class: \"navlink\",\n current: state2.page === page,\n children: PAGE_META[page].label\n },\n page\n )\n )\n ) }),\n /* @__PURE__ */ u3(\"div\", { class: \"session-actions\", \"aria-label\": \"Session actions\", children: auth.kind === \"clerk\" || auth.kind === \"cloudflare-access\" ? /* @__PURE__ */ u3(\"button\", { class: \"navlink\", type: \"button\", onClick: signOut, children: \"Sign out\" }) : /* @__PURE__ */ u3(\"button\", { class: \"navlink\", type: \"button\", onClick: forgetBearer, children: \"Change token\" }) })\n ] });\n }\n function Gate({ state: state2 }) {\n const [token, setToken] = d2(\"\");\n const signedIn = auth.kind === \"clerk\" && Boolean(window.Clerk?.user);\n const loading = state2.session === \"loading\";\n return /* @__PURE__ */ u3(\"section\", { id: \"gate\", class: \"gate lead\", \"aria-busy\": loading ? \"true\" : \"false\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"gateHeading\", tabIndex: -1, children: PAGE_META[state2.page].label }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { children: pageDescription(state2.page, productDescription) }),\n loading ? /* @__PURE__ */ u3(StateBlock, { id: \"gateCopy\", children: checkingCopy(state2.page) }) : /* @__PURE__ */ u3(\"p\", { id: \"gateCopy\", class: \"meta\", children: gateCopy(auth.kind, signedIn) }),\n loading ? null : auth.kind === \"clerk\" ? /* @__PURE__ */ u3(\"div\", { id: \"clerkGate\", class: \"actions\", children: signedIn ? /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"button\", onClick: signOut, children: \"Sign out\" }) : /* @__PURE__ */ u3(\"button\", { id: \"signin\", class: \"btn primary\", type: \"button\", onClick: signIn, children: \"Team sign in\" }) }) : auth.kind === \"cloudflare-access\" ? /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"button\", onClick: signOut, children: \"Sign out of Cloudflare Access\" }) }) : /* @__PURE__ */ u3(\n \"form\",\n {\n id: \"tokenGate\",\n class: \"row gate-form\",\n onSubmit: (event) => {\n event.preventDefault();\n const value = token.trim();\n if (!value) return;\n setToken(\"\");\n signInWithBearer(value);\n },\n children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"token\",\n type: \"password\",\n placeholder: \"Bearer token\",\n autocomplete: \"off\",\n \"aria-label\": \"Bearer token\",\n value: token,\n onInput: (event) => setToken(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { id: \"save\", class: \"btn primary\", type: \"submit\", children: \"Open operator pages\" })\n ]\n }\n ),\n /* @__PURE__ */ u3(NoticeLine, { id: \"err\", notice: state2.gate, className: \"\" })\n ] })\n ] });\n }\n function CurrentPage({ state: state2 }) {\n if (state2.page === \"tokens\") return /* @__PURE__ */ u3(TokensPage, { state: state2 });\n if (state2.page === \"activity\") return /* @__PURE__ */ u3(ActivityPage, { state: state2 });\n if (state2.page === \"artifacts\") return /* @__PURE__ */ u3(ArtifactsPage, { state: state2 });\n if (state2.page === \"artifact\") return /* @__PURE__ */ u3(ArtifactPage, { state: state2 });\n return /* @__PURE__ */ u3(ConnectionsPage, { state: state2 });\n }\n function OperatorApp() {\n const state2 = useOperatorState();\n const ready = state2.session === \"ready\";\n h2(() => {\n const label = state2.page === \"artifact\" && state2.artifactView ? state2.artifactView.title : PAGE_META[state2.page].label;\n document.title = `${label} — ${titleSuffix}`;\n }, [state2.page, state2.artifactView]);\n h2(() => {\n if (!ready) return;\n if (state2.page === \"tokens\" && state2.data?.accessTokenManagement === \"available\" && state2.tokenPhase === \"idle\") {\n void loadAccessTokens();\n }\n if (state2.page === \"activity\" && state2.data?.activityEnabled && state2.activityPhase === \"idle\") {\n void loadActivity(true);\n }\n });\n h2(() => {\n if (!state2.pendingFocus && !state2.focusIfLost) return;\n if (state2.pendingFocus) {\n document.getElementById(state2.pendingFocus)?.focus();\n } else if (state2.focusIfLost) {\n const active = document.activeElement;\n const lost = !active || active === document.body || !active.isConnected || active.disabled === true;\n if (lost) document.getElementById(state2.focusIfLost)?.focus();\n }\n focusHandled();\n }, [state2.pendingFocus, state2.focusIfLost]);\n return ready ? /* @__PURE__ */ u3(\"div\", { id: \"app\", children: /* @__PURE__ */ u3(CurrentPage, { state: state2 }) }) : /* @__PURE__ */ u3(Gate, { state: state2 });\n }\n function mount(id, view) {\n const host = document.getElementById(id);\n if (!host) return;\n host.textContent = \"\";\n R(view, host);\n }\n mount(\"operatorNav\", /* @__PURE__ */ u3(OperatorNav, {}));\n mount(\"operatorContent\", /* @__PURE__ */ u3(OperatorApp, {}));\n void boot();\n})();\n"; +export const OPERATOR_UI_SCRIPT: string = "\"use strict\";\n(() => {\n // node_modules/preact/dist/preact.module.js\n var n;\n var l;\n var u;\n var t;\n var i;\n var r;\n var o;\n var e;\n var f;\n var c;\n var a;\n var s;\n var h;\n var p;\n var v;\n var y;\n var d = {};\n var w = [];\n var _ = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;\n var g = Array.isArray;\n function m(n2, l3) {\n for (var u4 in l3) n2[u4] = l3[u4];\n return n2;\n }\n function b(n2) {\n n2 && n2.parentNode && n2.parentNode.removeChild(n2);\n }\n function k(l3, u4, t3) {\n var i3, r3, o3, e3 = {};\n for (o3 in u4) \"key\" == o3 ? i3 = u4[o3] : \"ref\" == o3 ? r3 = u4[o3] : e3[o3] = u4[o3];\n if (arguments.length > 2 && (e3.children = arguments.length > 3 ? n.call(arguments, 2) : t3), \"function\" == typeof l3 && null != l3.defaultProps) for (o3 in l3.defaultProps) void 0 === e3[o3] && (e3[o3] = l3.defaultProps[o3]);\n return x(l3, e3, i3, r3, null);\n }\n function x(n2, t3, i3, r3, o3) {\n var e3 = { type: n2, props: t3, key: i3, ref: r3, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: null == o3 ? ++u : o3, __i: -1, __u: 0 };\n return null == o3 && null != l.vnode && l.vnode(e3), e3;\n }\n function S(n2) {\n return n2.children;\n }\n function C(n2, l3) {\n this.props = n2, this.context = l3;\n }\n function $(n2, l3) {\n if (null == l3) return n2.__ ? $(n2.__, n2.__i + 1) : null;\n for (var u4; l3 < n2.__k.length; l3++) if (null != (u4 = n2.__k[l3]) && null != u4.__e) return u4.__e;\n return \"function\" == typeof n2.type ? $(n2) : null;\n }\n function I(n2) {\n if (n2.__P && n2.__d) {\n var u4 = n2.__v, t3 = u4.__e, i3 = [], r3 = [], o3 = m({}, u4);\n o3.__v = u4.__v + 1, l.vnode && l.vnode(o3), q(n2.__P, o3, u4, n2.__n, n2.__P.namespaceURI, 32 & u4.__u ? [t3] : null, i3, null == t3 ? $(u4) : t3, !!(32 & u4.__u), r3), o3.__v = u4.__v, o3.__.__k[o3.__i] = o3, D(i3, o3, r3), u4.__e = u4.__ = null, o3.__e != t3 && P(o3);\n }\n }\n function P(n2) {\n if (null != (n2 = n2.__) && null != n2.__c) return n2.__e = n2.__c.base = null, n2.__k.some(function(l3) {\n if (null != l3 && null != l3.__e) return n2.__e = n2.__c.base = l3.__e;\n }), P(n2);\n }\n function A(n2) {\n (!n2.__d && (n2.__d = true) && i.push(n2) && !H.__r++ || r != l.debounceRendering) && ((r = l.debounceRendering) || o)(H);\n }\n function H() {\n try {\n for (var n2, l3 = 1; i.length; ) i.length > l3 && i.sort(e), n2 = i.shift(), l3 = i.length, I(n2);\n } finally {\n i.length = H.__r = 0;\n }\n }\n function L(n2, l3, u4, t3, i3, r3, o3, e3, f4, c3, a3) {\n var s3, h3, p3, v3, y3, _3, g2 = t3 && t3.__k || w, m3 = l3.length;\n for (f4 = T(u4, l3, g2, f4, m3), s3 = 0; s3 < m3; s3++) null != (p3 = u4.__k[s3]) && (h3 = -1 != p3.__i && g2[p3.__i] || d, p3.__i = s3, _3 = q(n2, p3, h3, i3, r3, o3, e3, f4, c3, a3), v3 = p3.__e, p3.ref && h3.ref != p3.ref && (h3.ref && J(h3.ref, null, p3), a3.push(p3.ref, p3.__c || v3, p3)), null == y3 && null != v3 && (y3 = v3), 4 & p3.__u ? (f4 = j(p3, f4, n2), h3.__e && (h3.__e = null)) : \"function\" == typeof p3.type && void 0 !== _3 ? f4 = _3 : v3 && (f4 = v3.nextSibling), p3.__u &= -7);\n return u4.__e = y3, f4;\n }\n function T(n2, l3, u4, t3, i3) {\n var r3, o3, e3, f4, c3, a3 = u4.length, s3 = a3, h3 = 0;\n for (n2.__k = new Array(i3), r3 = 0; r3 < i3; r3++) null != (o3 = l3[r3]) && \"boolean\" != typeof o3 && \"function\" != typeof o3 ? (\"string\" == typeof o3 || \"number\" == typeof o3 || \"bigint\" == typeof o3 || o3.constructor == String ? o3 = n2.__k[r3] = x(null, o3, null, null, null) : g(o3) ? o3 = n2.__k[r3] = x(S, { children: o3 }, null, null, null) : void 0 === o3.constructor && o3.__b > 0 ? o3 = n2.__k[r3] = x(o3.type, o3.props, o3.key, o3.ref ? o3.ref : null, o3.__v) : n2.__k[r3] = o3, f4 = r3 + h3, o3.__ = n2, o3.__b = n2.__b + 1, e3 = null, -1 != (c3 = o3.__i = O(o3, u4, f4, s3)) && (s3--, (e3 = u4[c3]) && (e3.__u |= 2)), null == e3 || null == e3.__v ? (-1 == c3 && (i3 > a3 ? h3-- : i3 < a3 && h3++), \"function\" != typeof o3.type && (o3.__u |= 4)) : c3 != f4 && (c3 == f4 - 1 ? h3-- : c3 == f4 + 1 ? h3++ : (c3 > f4 ? h3-- : h3++, o3.__u |= 4))) : n2.__k[r3] = null;\n if (s3) for (r3 = 0; r3 < a3; r3++) null != (e3 = u4[r3]) && 0 == (2 & e3.__u) && (e3.__e == t3 && (t3 = $(e3)), K(e3, e3));\n return t3;\n }\n function j(n2, l3, u4) {\n var t3, i3;\n if (\"function\" == typeof n2.type) {\n for (t3 = n2.__k, i3 = 0; t3 && i3 < t3.length; i3++) t3[i3] && (t3[i3].__ = n2, l3 = j(t3[i3], l3, u4));\n return l3;\n }\n n2.__e != l3 && (l3 && n2.type && !l3.parentNode && (l3 = $(n2)), l3 = u4.insertBefore(n2.__e, l3 || null));\n do {\n l3 = l3 && l3.nextSibling;\n } while (null != l3 && 8 == l3.nodeType);\n return l3;\n }\n function O(n2, l3, u4, t3) {\n var i3, r3, o3, e3 = n2.key, f4 = n2.type, c3 = l3[u4], a3 = null != c3 && 0 == (2 & c3.__u);\n if (null === c3 && null == e3 || a3 && e3 == c3.key && f4 == c3.type) return u4;\n if (t3 > (a3 ? 1 : 0)) {\n for (i3 = u4 - 1, r3 = u4 + 1; i3 >= 0 || r3 < l3.length; ) if (null != (c3 = l3[o3 = i3 >= 0 ? i3-- : r3++]) && 0 == (2 & c3.__u) && e3 == c3.key && f4 == c3.type) return o3;\n }\n return -1;\n }\n function z(n2, l3, u4) {\n \"-\" == l3[0] ? n2.setProperty(l3, null == u4 ? \"\" : u4) : n2[l3] = null == u4 ? \"\" : \"number\" != typeof u4 || _.test(l3) ? u4 : u4 + \"px\";\n }\n function N(n2, l3, u4, t3, i3) {\n var r3, o3;\n n: if (\"style\" == l3) if (\"string\" == typeof u4) n2.style.cssText = u4;\n else {\n if (\"string\" == typeof t3 && (n2.style.cssText = t3 = \"\"), t3) for (l3 in t3) u4 && l3 in u4 || z(n2.style, l3, \"\");\n if (u4) for (l3 in u4) t3 && u4[l3] == t3[l3] || z(n2.style, l3, u4[l3]);\n }\n else if (\"o\" == l3[0] && \"n\" == l3[1]) r3 = l3 != (l3 = l3.replace(s, \"$1\")), o3 = l3.toLowerCase(), l3 = o3 in n2 || \"onFocusOut\" == l3 || \"onFocusIn\" == l3 ? o3.slice(2) : l3.slice(2), n2.l || (n2.l = {}), n2.l[l3 + r3] = u4, u4 ? t3 ? u4[a] = t3[a] : (u4[a] = h, n2.addEventListener(l3, r3 ? v : p, r3)) : n2.removeEventListener(l3, r3 ? v : p, r3);\n else {\n if (\"http://www.w3.org/2000/svg\" == i3) l3 = l3.replace(/xlink(H|:h)/, \"h\").replace(/sName$/, \"s\");\n else if (\"width\" != l3 && \"height\" != l3 && \"href\" != l3 && \"list\" != l3 && \"form\" != l3 && \"tabIndex\" != l3 && \"download\" != l3 && \"rowSpan\" != l3 && \"colSpan\" != l3 && \"role\" != l3 && \"popover\" != l3 && l3 in n2) try {\n n2[l3] = null == u4 ? \"\" : u4;\n break n;\n } catch (n3) {\n }\n \"function\" == typeof u4 || (null == u4 || false === u4 && \"-\" != l3[4] ? n2.removeAttribute(l3) : n2.setAttribute(l3, \"popover\" == l3 && 1 == u4 ? \"\" : u4));\n }\n }\n function V(n2) {\n return function(u4) {\n if (this.l) {\n var t3 = this.l[u4.type + n2];\n if (null == u4[c]) u4[c] = h++;\n else if (u4[c] < t3[a]) return;\n return t3(l.event ? l.event(u4) : u4);\n }\n };\n }\n function q(n2, u4, t3, i3, r3, o3, e3, f4, c3, a3) {\n var s3, h3, p3, v3, y3, d3, _3, k3, x2, M, I2, P2, A3, H2, T3, j3, F = u4.type;\n if (void 0 !== u4.constructor) return null;\n 128 & t3.__u && (c3 = !!(32 & t3.__u), o3 = [f4 = u4.__e = t3.__e]), (s3 = l.__b) && s3(u4);\n n: if (\"function\" == typeof F) {\n h3 = e3.length;\n try {\n if (x2 = u4.props, M = F.prototype && F.prototype.render, I2 = (s3 = F.contextType) && i3[s3.__c], P2 = s3 ? I2 ? I2.props.value : s3.__ : i3, t3.__c ? k3 = (p3 = u4.__c = t3.__c).__ = p3.__E : (M ? u4.__c = p3 = new F(x2, P2) : (u4.__c = p3 = new C(x2, P2), p3.constructor = F, p3.render = Q), I2 && I2.sub(p3), p3.state || (p3.state = {}), p3.__n = i3, v3 = p3.__d = true, p3.__h = [], p3._sb = []), M && null == p3.__s && (p3.__s = p3.state), M && null != F.getDerivedStateFromProps && (p3.__s == p3.state && (p3.__s = m({}, p3.__s)), m(p3.__s, F.getDerivedStateFromProps(x2, p3.__s))), y3 = p3.props, d3 = p3.state, p3.__v = u4, v3) M && null == F.getDerivedStateFromProps && null != p3.componentWillMount && p3.componentWillMount(), M && null != p3.componentDidMount && p3.__h.push(p3.componentDidMount);\n else {\n if (M && null == F.getDerivedStateFromProps && x2 !== y3 && null != p3.componentWillReceiveProps && p3.componentWillReceiveProps(x2, P2), u4.__v == t3.__v || !p3.__e && null != p3.shouldComponentUpdate && false === p3.shouldComponentUpdate(x2, p3.__s, P2)) {\n u4.__v != t3.__v && (p3.props = x2, p3.state = p3.__s, p3.__d = false), u4.__e = t3.__e, u4.__k = t3.__k, u4.__k.some(function(n3) {\n n3 && (n3.__ = u4);\n }), w.push.apply(p3.__h, p3._sb), p3._sb = [], p3.__h.length && e3.push(p3), f4 = $(t3);\n break n;\n }\n null != p3.componentWillUpdate && p3.componentWillUpdate(x2, p3.__s, P2), M && null != p3.componentDidUpdate && p3.__h.push(function() {\n p3.componentDidUpdate(y3, d3, _3);\n });\n }\n if (p3.context = P2, p3.props = x2, p3.__P = n2, p3.__e = false, A3 = l.__r, H2 = 0, M) p3.state = p3.__s, p3.__d = false, A3 && A3(u4), s3 = p3.render(p3.props, p3.state, p3.context), w.push.apply(p3.__h, p3._sb), p3._sb = [];\n else do {\n p3.__d = false, A3 && A3(u4), s3 = p3.render(p3.props, p3.state, p3.context), p3.state = p3.__s;\n } while (p3.__d && ++H2 < 25);\n p3.state = p3.__s, null != p3.getChildContext && (i3 = m(m({}, i3), p3.getChildContext())), M && !v3 && null != p3.getSnapshotBeforeUpdate && (_3 = p3.getSnapshotBeforeUpdate(y3, d3)), T3 = null != s3 && s3.type === S && null == s3.key ? E(s3.props.children) : s3, f4 = L(n2, g(T3) ? T3 : [T3], u4, t3, i3, r3, o3, e3, f4, c3, a3), p3.base = u4.__e, u4.__u &= -161, p3.__h.length && e3.push(p3), k3 && (p3.__E = p3.__ = null);\n } catch (n3) {\n if (e3.length = h3, u4.__v = null, c3 || null != o3) {\n if (n3.then) {\n for (u4.__u |= c3 ? 160 : 128; f4 && 8 == f4.nodeType && f4.nextSibling; ) f4 = f4.nextSibling;\n null != o3 && (o3[o3.indexOf(f4)] = null), u4.__e = f4;\n } else if (null != o3) for (j3 = o3.length; j3--; ) b(o3[j3]);\n } else u4.__e = t3.__e;\n null == u4.__k && (u4.__k = t3.__k || []), n3.then || B(u4), l.__e(n3, u4, t3);\n }\n } else null == o3 && u4.__v == t3.__v ? (u4.__k = t3.__k, u4.__e = t3.__e) : f4 = u4.__e = G(t3.__e, u4, t3, i3, r3, o3, e3, c3, a3);\n return (s3 = l.diffed) && s3(u4), 128 & u4.__u ? void 0 : f4;\n }\n function B(n2) {\n n2 && (n2.__c && (n2.__c.__e = true), n2.__k && n2.__k.some(B));\n }\n function D(n2, u4, t3) {\n for (var i3 = 0; i3 < t3.length; i3++) J(t3[i3], t3[++i3], t3[++i3]);\n l.__c && l.__c(u4, n2), n2.some(function(u5) {\n try {\n n2 = u5.__h, u5.__h = [], n2.some(function(n3) {\n n3.call(u5);\n });\n } catch (n3) {\n l.__e(n3, u5.__v);\n }\n });\n }\n function E(n2) {\n return \"object\" != typeof n2 || null == n2 || n2.__b > 0 ? n2 : g(n2) ? n2.map(E) : void 0 !== n2.constructor ? null : m({}, n2);\n }\n function G(u4, t3, i3, r3, o3, e3, f4, c3, a3) {\n var s3, h3, p3, v3, y3, w3, _3, m3 = i3.props || d, k3 = t3.props, x2 = t3.type;\n if (\"svg\" == x2 ? o3 = \"http://www.w3.org/2000/svg\" : \"math\" == x2 ? o3 = \"http://www.w3.org/1998/Math/MathML\" : o3 || (o3 = \"http://www.w3.org/1999/xhtml\"), null != e3) {\n for (s3 = 0; s3 < e3.length; s3++) if ((y3 = e3[s3]) && \"setAttribute\" in y3 == !!x2 && (x2 ? y3.localName == x2 : 3 == y3.nodeType)) {\n u4 = y3, e3[s3] = null;\n break;\n }\n }\n if (null == u4) {\n if (null == x2) return document.createTextNode(k3);\n u4 = document.createElementNS(o3, x2, k3.is && k3), c3 && (l.__m && l.__m(t3, e3), c3 = false), e3 = null;\n }\n if (null == x2) m3 === k3 || c3 && u4.data == k3 || (u4.data = k3);\n else {\n if (e3 = \"textarea\" == x2 && null != k3.defaultValue ? null : e3 && n.call(u4.childNodes), !c3 && null != e3) for (m3 = {}, s3 = 0; s3 < u4.attributes.length; s3++) m3[(y3 = u4.attributes[s3]).name] = y3.value;\n for (s3 in m3) y3 = m3[s3], \"dangerouslySetInnerHTML\" == s3 ? p3 = y3 : \"children\" == s3 || s3 in k3 || \"value\" == s3 && \"defaultValue\" in k3 || \"checked\" == s3 && \"defaultChecked\" in k3 || N(u4, s3, null, y3, o3);\n for (s3 in k3) y3 = k3[s3], \"children\" == s3 ? v3 = y3 : \"dangerouslySetInnerHTML\" == s3 ? h3 = y3 : \"value\" == s3 ? w3 = y3 : \"checked\" == s3 ? _3 = y3 : c3 && \"function\" != typeof y3 || m3[s3] === y3 || N(u4, s3, y3, m3[s3], o3);\n if (h3) c3 || p3 && (h3.__html == p3.__html || h3.__html == u4.innerHTML) || (u4.innerHTML = h3.__html), t3.__k = [];\n else if (p3 && (u4.innerHTML = \"\"), L(\"template\" == t3.type ? u4.content : u4, g(v3) ? v3 : [v3], t3, i3, r3, \"foreignObject\" == x2 ? \"http://www.w3.org/1999/xhtml\" : o3, e3, f4, e3 ? e3[0] : i3.__k && $(i3, 0), c3, a3), null != e3) for (s3 = e3.length; s3--; ) b(e3[s3]);\n c3 && \"textarea\" != x2 || (s3 = \"value\", \"progress\" == x2 && null == w3 ? u4.removeAttribute(\"value\") : null != w3 && (w3 !== u4[s3] || \"progress\" == x2 && !w3 || \"option\" == x2 && w3 != m3[s3]) && N(u4, s3, w3, m3[s3], o3), s3 = \"checked\", null != _3 && _3 != u4[s3] && N(u4, s3, _3, m3[s3], o3));\n }\n return u4;\n }\n function J(n2, u4, t3) {\n try {\n if (\"function\" == typeof n2) {\n var i3 = \"function\" == typeof n2.__u;\n i3 && n2.__u(), i3 && null == u4 || (n2.__u = n2(u4));\n } else n2.current = u4;\n } catch (n3) {\n l.__e(n3, t3);\n }\n }\n function K(n2, u4, t3) {\n var i3, r3;\n if (l.unmount && l.unmount(n2), (i3 = n2.ref) && (i3.current && i3.current != n2.__e || J(i3, null, u4)), null != (i3 = n2.__c)) {\n if (i3.componentWillUnmount) try {\n i3.componentWillUnmount();\n } catch (n3) {\n l.__e(n3, u4);\n }\n i3.base = i3.__P = i3.__n = null;\n }\n if (i3 = n2.__k) for (r3 = 0; r3 < i3.length; r3++) i3[r3] && K(i3[r3], u4, t3 || \"function\" != typeof n2.type);\n t3 || b(n2.__e), n2.__c = n2.__ = n2.__e = void 0;\n }\n function Q(n2, l3, u4) {\n return this.constructor(n2, u4);\n }\n function R(u4, t3, i3) {\n var r3, o3, e3, f4;\n t3 == document && (t3 = document.documentElement), l.__ && l.__(u4, t3), o3 = (r3 = \"function\" == typeof i3) ? null : i3 && i3.__k || t3.__k, e3 = [], f4 = [], q(t3, u4 = (!r3 && i3 || t3).__k = k(S, null, [u4]), o3 || d, d, t3.namespaceURI, !r3 && i3 ? [i3] : o3 ? null : t3.firstChild ? n.call(t3.childNodes) : null, e3, !r3 && i3 ? i3 : o3 ? o3.__e : t3.firstChild, r3, f4), D(e3, u4, f4), u4.props.children = null;\n }\n n = w.slice, l = { __e: function(n2, l3, u4, t3) {\n for (var i3, r3, o3; l3 = l3.__; ) if ((i3 = l3.__c) && !i3.__) try {\n if ((r3 = i3.constructor) && null != r3.getDerivedStateFromError && (i3.setState(r3.getDerivedStateFromError(n2)), o3 = i3.__d), null != i3.componentDidCatch && (i3.componentDidCatch(n2, t3 || {}), o3 = i3.__d), o3) return i3.__E = i3;\n } catch (l4) {\n n2 = l4;\n }\n throw n2;\n } }, u = 0, t = function(n2) {\n return null != n2 && void 0 === n2.constructor;\n }, C.prototype.setState = function(n2, l3) {\n var u4;\n u4 = null != this.__s && this.__s != this.state ? this.__s : this.__s = m({}, this.state), \"function\" == typeof n2 && (n2 = n2(m({}, u4), this.props)), n2 && m(u4, n2), null != n2 && this.__v && (l3 && this._sb.push(l3), A(this));\n }, C.prototype.forceUpdate = function(n2) {\n this.__v && (this.__e = true, n2 && this.__h.push(n2), A(this));\n }, C.prototype.render = S, i = [], o = \"function\" == typeof Promise ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, e = function(n2, l3) {\n return n2.__v.__b - l3.__v.__b;\n }, H.__r = 0, f = Math.random().toString(8), c = \"__d\" + f, a = \"__a\" + f, s = /(PointerCapture)$|Capture$/i, h = 0, p = V(false), v = V(true), y = 0;\n\n // node_modules/preact/hooks/dist/hooks.module.js\n var t2;\n var r2;\n var u2;\n var i2;\n var o2 = 0;\n var f2 = [];\n var c2 = l;\n var e2 = c2.__b;\n var a2 = c2.__r;\n var v2 = c2.diffed;\n var l2 = c2.__c;\n var m2 = c2.unmount;\n var p2 = c2.__;\n function s2(n2, t3) {\n c2.__h && c2.__h(r2, n2, o2 || t3), o2 = 0;\n var u4 = r2.__H || (r2.__H = { __: [], __h: [] });\n return n2 >= u4.__.length && u4.__.push({}), u4.__[n2];\n }\n function d2(n2) {\n return o2 = 1, y2(D2, n2);\n }\n function y2(n2, u4, i3) {\n var o3 = s2(t2++, 2);\n if (o3.t = n2, !o3.__c && (o3.__ = [i3 ? i3(u4) : D2(void 0, u4), function(n3) {\n var t3 = o3.__N ? o3.__N[0] : o3.__[0], r3 = o3.t(t3, n3);\n t3 !== r3 && (o3.__N = [r3, o3.__[1]], o3.__c.setState({}));\n }], o3.__c = r2, !r2.__f)) {\n var f4 = function(n3, t3, r3) {\n if (!o3.__c.__H) return true;\n var u5 = false, i4 = o3.__c.props !== n3;\n if (o3.__c.__H.__.some(function(n4) {\n if (n4.__N) {\n u5 = true;\n var t4 = n4.__[0];\n n4.__ = n4.__N, n4.__N = void 0, t4 !== n4.__[0] && (i4 = true);\n }\n }), c3) {\n var f5 = c3.call(this, n3, t3, r3);\n return u5 ? f5 || i4 : f5;\n }\n return !u5 || i4;\n };\n r2.__f = true;\n var c3 = r2.shouldComponentUpdate, e3 = r2.componentWillUpdate;\n r2.componentWillUpdate = function(n3, t3, r3) {\n if (this.__e) {\n var u5 = c3;\n c3 = void 0, f4(n3, t3, r3), c3 = u5;\n }\n e3 && e3.call(this, n3, t3, r3);\n }, r2.shouldComponentUpdate = f4;\n }\n return o3.__N || o3.__;\n }\n function h2(n2, u4) {\n var i3 = s2(t2++, 3);\n !c2.__s && C2(i3.__H, u4) && (i3.__ = n2, i3.u = u4, r2.__H.__h.push(i3));\n }\n function _2(n2, u4) {\n var i3 = s2(t2++, 4);\n !c2.__s && C2(i3.__H, u4) && (i3.__ = n2, i3.u = u4, r2.__h.push(i3));\n }\n function A2(n2) {\n return o2 = 5, T2(function() {\n return { current: n2 };\n }, []);\n }\n function T2(n2, r3) {\n var u4 = s2(t2++, 7);\n return C2(u4.__H, r3) && (u4.__ = n2(), u4.__H = r3, u4.__h = n2), u4.__;\n }\n function j2() {\n for (var n2; n2 = f2.shift(); ) {\n var t3 = n2.__H;\n if (n2.__P && t3) try {\n t3.__h.some(z2), t3.__h.some(B2), t3.__h = [];\n } catch (r3) {\n t3.__h = [], c2.__e(r3, n2.__v);\n }\n }\n }\n c2.__b = function(n2) {\n r2 = null, e2 && e2(n2);\n }, c2.__ = function(n2, t3) {\n n2 && t3.__k && t3.__k.__m && (n2.__m = t3.__k.__m), p2 && p2(n2, t3);\n }, c2.__r = function(n2) {\n a2 && a2(n2), t2 = 0;\n var i3 = (r2 = n2.__c).__H;\n i3 && (u2 === r2 ? (i3.__h = [], r2.__h = [], i3.__.some(function(n3) {\n n3.__N && (n3.__ = n3.__N), n3.u = n3.__N = void 0;\n })) : (i3.__h.some(z2), i3.__h.some(B2), i3.__h = [], t2 = 0)), u2 = r2;\n }, c2.diffed = function(n2) {\n v2 && v2(n2);\n var t3 = n2.__c;\n t3 && t3.__H && (t3.__H.__h.length && (1 !== f2.push(t3) && i2 === c2.requestAnimationFrame || ((i2 = c2.requestAnimationFrame) || w2)(j2)), t3.__H.__.some(function(n3) {\n n3.u && (n3.__H = n3.u, n3.u = void 0);\n })), u2 = r2 = null;\n }, c2.__c = function(n2, t3) {\n t3.some(function(n3) {\n try {\n n3.__h.some(z2), n3.__h = n3.__h.filter(function(n4) {\n return !n4.__ || B2(n4);\n });\n } catch (r3) {\n t3.some(function(n4) {\n n4.__h && (n4.__h = []);\n }), t3 = [], c2.__e(r3, n3.__v);\n }\n }), l2 && l2(n2, t3);\n }, c2.unmount = function(n2) {\n m2 && m2(n2);\n var t3, r3 = n2.__c;\n r3 && r3.__H && (r3.__H.__.some(function(n3) {\n try {\n z2(n3);\n } catch (n4) {\n t3 = n4;\n }\n }), r3.__H = void 0, t3 && c2.__e(t3, r3.__v));\n };\n var k2 = \"function\" == typeof requestAnimationFrame;\n function w2(n2) {\n var t3, r3 = function() {\n clearTimeout(u4), k2 && cancelAnimationFrame(t3), setTimeout(n2);\n }, u4 = setTimeout(r3, 35);\n k2 && (t3 = requestAnimationFrame(r3));\n }\n function z2(n2) {\n var t3 = r2, u4 = n2.__c;\n \"function\" == typeof u4 && (n2.__c = void 0, u4()), r2 = t3;\n }\n function B2(n2) {\n var t3 = r2;\n n2.__c = n2.__(), r2 = t3;\n }\n function C2(n2, t3) {\n return !n2 || n2.length !== t3.length || t3.some(function(t4, r3) {\n return t4 !== n2[r3];\n });\n }\n function D2(n2, t3) {\n return \"function\" == typeof t3 ? t3(n2) : t3;\n }\n\n // src/operator-ui/view.ts\n var OPERATOR_PAGES = [\n \"connections\",\n \"tokens\",\n \"activity\",\n \"artifacts\"\n ];\n var PAGE_META = {\n tokens: { path: \"/tokens\", label: \"Access tokens\" },\n connections: { path: \"/\", label: \"Connections\" },\n activity: { path: \"/activity\", label: \"Activity\" },\n artifacts: { path: \"/artifacts\", label: \"Artifacts\" },\n artifact: { path: \"/artifacts\", label: \"Artifact\" }\n };\n function pageDescription(page, productDescription2) {\n if (page === \"activity\") {\n return \"Every connector tool call, by who made it and how it ended. Arguments and results are never stored.\";\n }\n if (isArtifactPage(page)) {\n return \"Pages agents published for the team. Each one keeps every version.\";\n }\n return productDescription2;\n }\n function checkingCopy(page) {\n if (page === \"artifact\") return \"Loading artifact…\";\n if (page === \"artifacts\") return \"Loading artifacts…\";\n return \"Checking your session…\";\n }\n function pageForPath(path) {\n if (path.startsWith(\"/artifacts/\")) return \"artifact\";\n const match = OPERATOR_PAGES.find((page) => PAGE_META[page].path === path);\n return match ?? \"connections\";\n }\n function isArtifactPage(page) {\n return page === \"artifacts\" || page === \"artifact\";\n }\n function artifactViewRequest(pathname, search) {\n const match = /^\\/artifacts\\/([a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?)(?:\\/v\\/(\\d{1,9}))?$/.exec(pathname);\n if (!match?.[1]) return void 0;\n const params = new URLSearchParams();\n if (match[2]) {\n params.set(\"v\", match[2]);\n for (const pin of new URLSearchParams(search).getAll(\"d\")) params.append(\"d\", pin);\n }\n const query = params.toString();\n return `/artifacts/_api/view/${match[1]}${query ? `?${query}` : \"\"}`;\n }\n function info(message) {\n return { message, tone: \"info\" };\n }\n function failure(message, fix) {\n return fix ? { message, tone: \"error\", fix } : { message, tone: \"error\" };\n }\n var REFUSED_COPY = {\n oauth_disconnect: \"Disconnect didn't finish. If the service refused it, the deployment's log has its reply.\",\n oauth_reconnect: \"Authorization couldn't start. If the service refused it, the deployment's log has its reply.\",\n credential_test: \"The credential test couldn't run.\"\n };\n function oauthDoneNotice(action, answer, opened = true) {\n if (action === \"oauth_disconnect\") {\n return info(\"Disconnected. Connect again whenever you are ready.\");\n }\n if (answer?.state === \"ok\") return info(\"Connected.\");\n return info(\n opened ? \"Finish authorizing in the new tab. This page updates when you come back.\" : \"Your browser blocked the new tab. Open the authorization page from the link here.\"\n );\n }\n function credentialTestNotice(connectorId, answer) {\n return answer?.ok === true ? info(\"Credential is valid.\") : failure(\n \"Credential test failed: the service rejected the stored credential, or the test couldn't reach it. The deployment's log has the service's reply.\",\n { kind: \"credential_test_failed\", connectorId }\n );\n }\n function refusedNotice(action, connectorId, problem) {\n if (action === \"credential_test\" && (problem === \"credential_required\" || problem === \"credential_mismatch\")) {\n return failure(PROBLEM_COPY[problem], { kind: problem, connectorId });\n }\n return failure(REFUSED_COPY[action], {\n kind: action === \"credential_test\" ? \"credential_test_failed\" : \"oauth_action_failed\",\n connectorId\n });\n }\n function credentialRefusedCopy(action, status, problem) {\n if (problem === \"credential_mismatch\") return PROBLEM_COPY.credential_mismatch;\n const verb = action === \"credential_save\" ? \"saved\" : \"removed\";\n if (status === 400 || status === 413 || status === 415) {\n return action === \"credential_save\" ? \"The credential wasn't saved: a value is empty or not in the expected format. Check it and save again.\" : \"The credential wasn't removed. Refresh the page and try again.\";\n }\n if (status === 404) {\n return \"This connector no longer has a credential slot. Refresh the page to see its current setup.\";\n }\n if (status === 503) {\n return `Credential storage isn't configured on this deployment, so nothing was ${verb}.`;\n }\n return `The credential wasn't ${verb}. Try again; if it keeps failing, the deployment's log has the reason.`;\n }\n function actionFailedNotice(action, connectorId, facts, productName2) {\n if (facts.kind === \"session\") {\n return failure(\"Your session has ended. Sign in again, then retry.\");\n }\n if (facts.kind === \"forbidden\") {\n return failure(\"You don't have permission to change this connection's authentication.\");\n }\n if (facts.kind === \"network\") {\n return failure(`Couldn't reach ${productName2}. Check your connection and try again.`);\n }\n if (action === \"credential_save\" || action === \"credential_remove\") {\n return failure(credentialRefusedCopy(action, facts.status, facts.problem));\n }\n return refusedNotice(action, connectorId, facts.problem);\n }\n function connectorLoadFailureCopy(failure2, productName2) {\n return failure2 === \"session\" ? \"Your session wasn't accepted while loading this connector. Sign in again to see its status.\" : `Couldn't reach ${productName2} to load this connector. Check your connection, then refresh it.`;\n }\n function loadFailureCopy(failure2, productName2) {\n return {\n title: `Couldn't reach ${productName2}`,\n body: failure2 === \"network\" ? \"Your browser couldn't connect. Check your connection, then retry.\" : \"The deployment answered with an error. Retry in a moment; if it keeps failing, the deployment's log has the reason.\"\n };\n }\n function collectionFailureCopy(collection, facts, productName2) {\n if (facts.kind === \"network\") {\n return `Couldn't reach ${productName2}. Check your connection, then retry.`;\n }\n if (facts.kind === \"session\") return \"Your session has ended. Sign in again to see this page.\";\n if (facts.kind === \"forbidden\" || facts.status === 404) {\n if (collection === \"artifact\") return \"There is no artifact here, or this identity can't open it.\";\n return collection === \"activity\" ? \"Activity isn't available to this identity.\" : \"Artifacts aren't available to this identity.\";\n }\n return \"The deployment answered with an error. Retry in a moment; if it keeps failing, the deployment's log has the reason.\";\n }\n function confirmCopy(action, name) {\n if (action === \"oauth_disconnect\") {\n return {\n question: `Disconnect ${name}? Its stored grant and any pending authorization are removed, and its tools stop working until it is connected again.`,\n confirm: \"Disconnect\"\n };\n }\n if (action === \"oauth_restart\") {\n return {\n question: `Reconnect ${name}? Its current grant stops working until you finish authorizing in the new tab.`,\n confirm: \"Reconnect\"\n };\n }\n return {\n question: `Remove ${name}'s credential? The connector stops authenticating until a replacement is added.`,\n confirm: \"Remove\"\n };\n }\n function accessTokenUnavailableCopy(capability) {\n return capability === void 0 ? \"Access tokens are not configured for this deployment.\" : \"Token management requires an interactive sign-in and explicit permission.\";\n }\n function initialState(page) {\n return {\n page,\n generation: 0,\n session: \"loading\",\n gate: null,\n refreshing: false,\n loadFailure: null,\n pendingFocus: null,\n focusIfLost: null,\n ...identityScopedState()\n };\n }\n function identityScopedState() {\n return {\n data: null,\n connectorFilter: \"\",\n oauthNotice: null,\n oauthNoticeFor: null,\n oauthBusy: null,\n oauthBlocked: null,\n confirming: null,\n connectorFailures: {},\n credentialNotice: null,\n credentialNoticeFor: null,\n credentialEditing: null,\n credentialBusy: null,\n tokenPhase: \"idle\",\n tokenNotice: null,\n tokens: [],\n createdToken: null,\n tokenRenaming: null,\n tokenBusy: false,\n activityPhase: \"idle\",\n activityNotice: null,\n activityEvents: [],\n activityCursor: null,\n activitySearch: \"\",\n artifactPhase: \"idle\",\n artifactNotice: null,\n artifactRows: [],\n artifactCursor: null,\n artifactQuery: \"\",\n artifactArchived: false,\n artifactView: null\n };\n }\n function resetIdentity(state2, gate2 = null) {\n return {\n ...state2,\n generation: state2.generation + 1,\n session: \"gated\",\n gate: gate2,\n refreshing: false,\n loadFailure: null,\n pendingFocus: null,\n focusIfLost: null,\n ...identityScopedState()\n };\n }\n function withPage(state2, page) {\n return {\n ...state2,\n page,\n createdToken: null,\n tokenRenaming: null,\n tokenNotice: null,\n credentialEditing: null,\n credentialNotice: null,\n credentialNoticeFor: null,\n confirming: null\n };\n }\n function connectorStatusLabel(status, problem) {\n if (status === \"loading\") return \"Loading details\";\n if (status === \"ok\") return \"Connected\";\n if (status === \"auth_required\") {\n return problem === \"credential_required\" ? \"Credential needed\" : \"Authorization needed\";\n }\n return \"Unavailable\";\n }\n function toolCountLabel(count) {\n return `${count} ${count === 1 ? \"tool\" : \"tools\"}`;\n }\n function connectorStatusTone(status) {\n if (status === \"ok\") return \"ok\";\n if (status === \"auth_required\") return \"warn\";\n if (status === \"loading\") return \"neutral\";\n return \"danger\";\n }\n function summarizeConnectors(connectors) {\n const summary = {\n total: connectors.length,\n connected: 0,\n attention: 0,\n credentials: 0,\n unavailable: 0,\n loading: 0,\n tools: 0,\n drifting: 0\n };\n for (const connector of connectors) {\n if (connector.status === \"ok\") summary.connected += 1;\n else if (connector.status === \"auth_required\") {\n if (connector.problem === \"credential_required\") summary.credentials += 1;\n else summary.attention += 1;\n } else if (connector.status === \"loading\") summary.loading += 1;\n else summary.unavailable += 1;\n summary.tools += connector.toolCount || 0;\n if (driftState(connector.catalogDrift) === \"warning\") summary.drifting += 1;\n }\n return summary;\n }\n function connectorSummaryParts(summary) {\n if (summary.total > 0 && summary.loading === summary.total) {\n return [\n {\n text: `Checking ${summary.total} connector${summary.total === 1 ? \"\" : \"s\"}…`,\n tone: \"neutral\"\n }\n ];\n }\n return [\n { text: `${summary.connected} connected`, tone: \"neutral\" },\n ...summary.attention ? [\n {\n text: `${summary.attention} need${summary.attention === 1 ? \"s\" : \"\"} authorization`,\n tone: \"warn\"\n }\n ] : [],\n ...summary.credentials ? [\n {\n text: `${summary.credentials} need${summary.credentials === 1 ? \"s\" : \"\"} a credential`,\n tone: \"warn\"\n }\n ] : [],\n ...summary.unavailable ? [{ text: `${summary.unavailable} unavailable`, tone: \"danger\" }] : [],\n { text: toolCountLabel(summary.tools), tone: \"neutral\" },\n ...summary.loading ? [{ text: `${summary.loading} still loading`, tone: \"neutral\" }] : []\n ];\n }\n var TOOL_SAFETY_BADGE = {\n runs_in_programs: {\n label: \"runs in programs\",\n tone: \"ok\",\n title: \"Explicitly read-only: execute_code programs may call it without asking.\"\n },\n exempt: {\n label: \"exempt from approval\",\n tone: \"neutral\",\n title: \"Not read-only, but this deployment's config lets programs call it without pausing. Each call still counts against the write budget and appears in activity; call_tool still refuses it.\"\n },\n needs_approval: {\n label: \"asks for approval\",\n tone: \"warn\",\n title: \"Not explicitly read-only: a program pauses for resume_execution, and a direct call crosses call_destructive_tool — either way the host asks first.\"\n }\n };\n var PROBLEM_COPY = {\n connector_unavailable: \"Unavailable: its status check or catalog load failed, or did not finish in time. The deployment's log has the downstream error.\",\n oauth_required: \"Needs OAuth authorization: no grant is stored, or the stored grant expired or was revoked.\",\n credential_required: \"Needs a credential: nothing usable is stored in its credential slot.\",\n auth_required: \"Needs authorization. Its secret lives in deployment configuration, not on this page.\",\n credential_mismatch: \"The stored credential does not match the fields this connector declares, so it cannot be used.\",\n catalog_failed: \"Connected, but its tool catalog could not be loaded, so none of its tools are served.\"\n };\n function problemCopy(problem) {\n return problem ? PROBLEM_COPY[problem] ?? null : null;\n }\n function problemTone(problem) {\n return problem === \"oauth_required\" || problem === \"credential_required\" || problem === \"auth_required\" ? \"warn\" : \"danger\";\n }\n function authScopeLabel(scope) {\n return scope === \"personal\" ? \"personal auth\" : \"shared auth\";\n }\n function permissionLabel(connector) {\n if (connector.permissions?.manageSharedAuth) {\n return \"You can manage shared authentication for this connection.\";\n }\n if (connector.permissions?.connectPersonal) {\n return \"You can connect your own account to this connection.\";\n }\n return \"Authentication for this connection is managed by your deployment.\";\n }\n var DRIFT_CATEGORIES = [\n { key: \"unclassifiedTools\", label: \"Unclassified\" },\n { key: \"unservedTools\", label: \"Unserved\" },\n { key: \"annotationConflicts\", label: \"Annotation conflicts\" },\n { key: \"schemaChanges\", label: \"Schema changes\" }\n ];\n function driftTotal(drift) {\n if (!drift) return 0;\n return DRIFT_CATEGORIES.reduce((sum, { key }) => sum + (drift[key] || 0), 0);\n }\n function driftState(drift) {\n if (!drift) return \"unavailable\";\n return driftTotal(drift) > 0 ? \"warning\" : \"clean\";\n }\n function driftCounts(drift) {\n if (!drift) return [];\n return DRIFT_CATEGORIES.map(({ key, label }) => ({\n key,\n label,\n count: drift[key] || 0\n }));\n }\n function driftSummary(drift) {\n const state2 = driftState(drift);\n if (state2 === \"unavailable\") {\n return \"No catalog refresh observed yet in this runtime.\";\n }\n const observed = formatDate(drift?.observedAt);\n const when = observed ? ` · observed ${observed}` : \"\";\n if (state2 === \"clean\") return `Matches the reviewed manifest${when}`;\n const total = driftTotal(drift);\n return `${total} difference${total === 1 ? \"\" : \"s\"} from the reviewed manifest${when}`;\n }\n function safeHttpHref(url) {\n if (!url) return null;\n try {\n const protocol = new URL(url).protocol;\n return protocol === \"http:\" || protocol === \"https:\" ? url : null;\n } catch {\n return null;\n }\n }\n function formatDate(value) {\n if (!value) return \"\";\n const date = new Date(value);\n return Number.isNaN(date.valueOf()) ? \"\" : date.toLocaleString(void 0, { dateStyle: \"medium\", timeStyle: \"short\" });\n }\n var ACTOR_KINDS = {\n clerk: \"Clerk\",\n bearer: \"Bearer token\",\n \"cloudflare-access\": \"Cloudflare Access\",\n anonymous: \"Anonymous\"\n };\n function actorKindLabel(kind) {\n if (!kind) return \"Unknown caller\";\n return ACTOR_KINDS[kind] ?? kind;\n }\n function actorLabel(actor) {\n if (!actor?.kind) return \"Unknown caller\";\n const who = actor.label || actor.id;\n const kind = actorKindLabel(actor.kind);\n return who ? `${who} (${kind})` : kind;\n }\n function actorStableId(actor) {\n if (!actor?.id) return null;\n if (!actor.label && !actor.namespace) return null;\n return actor.namespace ? `${actor.namespace} · ${actor.id}` : actor.id;\n }\n function activityMatches(event, query) {\n const q2 = query.trim().toLowerCase();\n if (!q2) return true;\n return [\n event.address,\n event.connectorId,\n event.toolName,\n event.source,\n event.outcome,\n event.errorCode,\n event.friction,\n event.actor?.kind,\n event.actor?.id,\n event.actor?.namespace,\n event.actor?.label,\n activityOutcomeBadge(event.outcome).label,\n activityDetail(event),\n actorKindLabel(event.actor?.kind)\n ].some((value) => String(value ?? \"\").toLowerCase().includes(q2));\n }\n function filterActivity(events, query) {\n return events.filter((event) => activityMatches(event, query));\n }\n function activitySummary(events) {\n if (events.length === 0) return \"\";\n const tools = new Set(events.map((event) => event.address)).size;\n return `${events.length} loaded call${events.length === 1 ? \"\" : \"s\"} · ${tools} tool${tools === 1 ? \"\" : \"s\"}`;\n }\n var ACTIVITY_OUTCOMES = [\n \"success\",\n \"error\",\n \"timeout\",\n \"cancelled\",\n \"paused\",\n \"approved\"\n ];\n function activityOutcomeClass(outcome) {\n return ACTIVITY_OUTCOMES.includes(outcome) ? outcome : \"error\";\n }\n var OUTCOME_BADGE = {\n success: { label: \"Succeeded\", tone: \"ok\" },\n error: { label: \"Failed\", tone: \"danger\" },\n timeout: { label: \"Timed out\", tone: \"danger\" },\n cancelled: { label: \"Cancelled\", tone: \"neutral\" },\n paused: { label: \"Waiting for approval\", tone: \"warn\" },\n approved: { label: \"Approved\", tone: \"ok\" }\n };\n function activityOutcomeBadge(outcome) {\n return OUTCOME_BADGE[outcome] ?? { label: \"Failed\", tone: \"danger\" };\n }\n var SOURCE_LABELS = {\n execute_code: \"In a program\",\n call_tool: \"Direct call\",\n call_destructive_tool: \"Direct call, approved by the host\",\n resume_execution: \"Resumed program\",\n batch_call: \"Batch call\"\n };\n var REASON_LABELS = {\n tool_not_found: \"tool not found\",\n unknown_address: \"tool not found\",\n unknown_tool: \"tool not found\",\n ambiguous_tool_alias: \"ambiguous tool name\",\n schema_retry: \"arguments didn't match the schema\",\n invalid_args: \"arguments didn't match the schema\",\n destructive_reroute: \"needed host approval\",\n destructive_tool_requires_approval: \"needed host approval\",\n approval_required: \"needed approval\",\n auth_required: \"needed authorization\",\n result_too_large: \"result too large to return inline\",\n timeout: \"timed out\"\n };\n function reasonLabel(code) {\n return REASON_LABELS[code] ?? code.replaceAll(\"_\", \" \");\n }\n function activityDetail(event) {\n const parts = [SOURCE_LABELS[event.source] ?? event.source];\n if (event.approval === \"tool\") parts.push(\"approved for the rest of the run\");\n if (event.approval === \"call\") parts.push(\"approved for this call\");\n if (event.attempts > 1) parts.push(`${event.attempts} attempts`);\n const reasons = [event.friction, event.errorCode].filter((code) => Boolean(code)).map(reasonLabel);\n for (const reason of new Set(reasons)) parts.push(reason);\n return parts.join(\" · \");\n }\n function artifactRefreshBadge(last) {\n return last?.status === \"failed\" ? { label: \"Refresh failed\", tone: \"danger\" } : null;\n }\n function credentialProblemCopy(problem) {\n if (problem === \"credential_mismatch\") return PROBLEM_COPY.credential_mismatch;\n if (problem === \"credential_unreadable\") {\n return \"The stored credential can't be read, so it can't be used. Replace it, or remove it and add a new one.\";\n }\n return \"The stored credential can't be used. Replace it, or remove it and add a new one.\";\n }\n function credentialStateLabel(credential) {\n if (!credential.configured) return \"not configured\";\n const masked = credential.fields?.length ? \"configured\" : `configured · ••••${credential.lastFour ?? \"\"}`;\n return credential.updatedAt ? `${masked} · updated ${formatDate(credential.updatedAt)}` : masked;\n }\n function gateCopy(kind, signedIn) {\n if (kind === \"cloudflare-access\") {\n return \"Cloudflare Access admitted this browser, but the current identity cannot open deployment-wide operator pages.\";\n }\n if (kind !== \"clerk\") {\n return \"Paste an operator bearer token to open this page. Nothing is requested until you do.\";\n }\n return signedIn ? \"Signed in with Clerk, but this account cannot open deployment-wide operator pages.\" : \"Sign in with Clerk to open this operator page.\";\n }\n\n // src/operator-ui/app/config.ts\n var auth = AUTH;\n var mcpUrl = MCP_URL;\n var initialPage = INITIAL_PAGE;\n var homeUrl = HOME_URL;\n var titleSuffix = TITLE_SUFFIX;\n var productName = PRODUCT_NAME;\n var productDescription = PRODUCT_DESCRIPTION;\n var productOperatorLabel = PRODUCT_OPERATOR_LABEL;\n var TOKEN_KEY = \"connecta:token\";\n\n // src/fix-prompt.ts\n var CONNECTOR_ID_RE = /^[a-z0-9_-]+$/;\n function renderFixPrompt(spec, connectorId) {\n const id = connectorId !== void 0 && CONNECTOR_ID_RE.test(connectorId) ? connectorId : void 0;\n return [\n \"Diagnose and fix a problem in this connecta deployment (the @zackbart/connecta package). It is configured as code: connectors, credential slots, OAuth clients, pools, and inbound auth are declared in the deployment's source and environment, so the fix belongs there and not in the operator page.\",\n `Problem: ${spec.problem}` + (id ? `\nConnector id: ${id}` : \"\"),\n `Where to look:\n${spec.steps.map((step) => `- ${step}`).join(\"\\n\")}`,\n \"This prompt deliberately carries no error text, tokens, or URLs. Find the underlying cause in the deployment's own logs (lines prefixed [connecta]) or by reproducing the failure locally. Never put a secret in source, a log line, or your reply: secrets belong in the deployment's environment or its credential vault.\",\n \"Make the smallest change that fixes it, then verify it by redeploying and refreshing the connection on the operator Connections page. If the fix needs something you cannot do yourself — a provider console setting, a secret only the operator holds — name that exact step instead.\"\n ].join(\"\\n\\n\");\n }\n\n // src/operator-ui/fix-prompts.ts\n var CATALOGUE = {\n connector_unavailable: {\n problem: \"A connector is unavailable: its status check or catalog load failed, or did not finish before the operator page's deadline.\",\n steps: [\n \"Confirm the connector's downstream URL or API base in the deployment config, and that the deployment can reach it from where it runs.\",\n \"Check the credentials or headers the connector sends; a rejected credential often surfaces as a failed status rather than as an authorization prompt.\",\n \"If the downstream is slow rather than down, review the connector's timeouts and the deployment's discovery.probeTimeoutMs.\"\n ]\n },\n oauth_required: {\n problem: \"A downstream OAuth connector needs authorization: no grant is stored, or the stored grant expired or was revoked and could not be refreshed.\",\n steps: [\n \"Reauthorize from the operator page (Connect account or Reconnect OAuth) or with authorize_connector; this needs no code change if the grant simply lapsed.\",\n \"If it needs reauthorizing again soon after, check that the OAuth client requests offline access or a refresh token, and that the storage holding OAuth tokens persists across restarts and is shared by every instance.\",\n \"If authorization cannot start at all, check the connector's OAuth client configuration and the deployment's publicUrl, which forms the /oauth/callback/ redirect URI.\"\n ]\n },\n credential_required: {\n problem: \"A connector with an operator-managed credential slot has no usable credential stored.\",\n steps: [\n \"An operator with credential administration can add the credential on the operator page; that needs no code change.\",\n \"If nobody can, grant credential administration through the deployment's identity config (credentialAdministration for shared auth, personalConnection for personal auth), which is denied by default.\",\n \"Check that the connector's credential declaration (label and fields) matches what the downstream actually needs.\"\n ]\n },\n auth_required: {\n problem: \"A connector reports that it needs authorization, and its secret lives in deployment configuration rather than in an operator-managed slot.\",\n steps: [\n \"Find where the connector's secret is read (usually an environment variable or Worker secret passed into the connector config) and confirm it is set in the running environment.\",\n \"Rotate the secret at the provider if it expired or was revoked, then update the deployment's environment, not its source.\",\n \"If operators should manage this secret from the page instead, declare a credential slot on the connector and configure a credential vault.\"\n ]\n },\n credential_mismatch: {\n problem: \"The credential stored for a connector does not match the fields the connector currently declares, so it cannot be used.\",\n steps: [\n \"If the connector's credential fields changed on purpose, re-enter the credential on the operator page so the stored fields match.\",\n \"If they changed by accident, restore the previous field names in the connector's credential declaration.\"\n ]\n },\n credential_unreadable: {\n problem: \"A stored credential exists but could not be read or decrypted.\",\n steps: [\n \"Check that the credential vault's encryption key in the deployment environment is the one the credential was stored with; a rotated or missing key makes every stored value unreadable.\",\n \"Check the storage adapter backing the vault is reachable from the deployment.\",\n \"If the key was lost, remove and re-add the credential on the operator page; the old value cannot be recovered.\"\n ]\n },\n credential_test_failed: {\n problem: \"The test for a stored connector credential failed: the downstream rejected it, or the test could not reach the downstream.\",\n steps: [\n \"Confirm the stored value is current at the provider (not rotated, revoked, or scoped too narrowly), and replace it on the operator page if not.\",\n \"Check that the connector's credential test targets the same API base and auth scheme its tool calls use.\"\n ]\n },\n oauth_action_failed: {\n problem: \"Restarting or disconnecting a connector's downstream OAuth from the operator page failed.\",\n steps: [\n \"Check that the connector implements startAuth and disconnectAuth, and that the storage holding its OAuth state is writable.\",\n \"Check the connector's OAuth client configuration, including the authorization server it discovers or is given.\",\n \"Confirm the operator has the config-derived permission for this action (credentialAdministration for shared auth, personalConnection for personal auth).\"\n ]\n },\n catalog_failed: {\n problem: \"A connector reports itself connected, but loading its tool catalog failed, so none of its tools are being served.\",\n steps: [\n \"Check that the downstream still serves a complete tools list; connecta refuses a partial catalog rather than serving part of it.\",\n \"Check for tools the connector cannot accept: invalid schemas, missing descriptions, or names that collide.\",\n \"Pin or upgrade the @zackbart/connecta version if a maintained provider's catalog changed shape underneath it.\"\n ]\n },\n catalog_drift: {\n problem: \"A hosted provider's live catalog differs from the reviewed manifest shipped with connecta: new unclassified tools, unserved tools, annotation conflicts, or schema changes.\",\n steps: [\n \"Unclassified tools are withheld until a release classifies them. Check whether a newer @zackbart/connecta release has, and upgrade if so.\",\n \"If a tool the deployment depends on is now unserved or changed shape, review callers of it before upgrading.\",\n \"Report drift the release does not cover as an issue on the connecta repository, naming the provider and the kinds of drift but no tool data.\"\n ]\n }\n };\n function fixPrompt(kind, connectorId) {\n return renderFixPrompt(CATALOGUE[kind], connectorId);\n }\n var FIX_PROMPT_KINDS = Object.keys(CATALOGUE);\n\n // src/operator-ui/app/store.ts\n var state = initialState(initialPage);\n var listeners = /* @__PURE__ */ new Set();\n function getState() {\n return state;\n }\n function subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n }\n function set(patch) {\n state = { ...state, ...patch };\n for (const listener of listeners) listener();\n }\n function fence() {\n const generation = state.generation;\n return () => generation === state.generation;\n }\n function sessionToken() {\n if (auth.kind === \"cloudflare-access\") return Promise.resolve(void 0);\n return auth.kind === \"clerk\" ? Promise.resolve(window.Clerk?.session?.getToken() ?? null) : Promise.resolve(localStorage.getItem(TOKEN_KEY));\n }\n function requestHeaders(token, body = false) {\n return {\n ...token ? { Authorization: `Bearer ${token}` } : {},\n ...body ? { \"Content-Type\": \"application/json\" } : {}\n };\n }\n var NAV_HINT_KEY = \"connecta:nav\";\n function rememberNav(data) {\n try {\n sessionStorage.setItem(\n NAV_HINT_KEY,\n JSON.stringify({ activity: data.activityEnabled, artifacts: Boolean(data.artifactsEnabled) })\n );\n } catch {\n }\n }\n function forgetNav() {\n try {\n sessionStorage.removeItem(NAV_HINT_KEY);\n } catch {\n }\n }\n function navHint() {\n try {\n const hint = JSON.parse(sessionStorage.getItem(NAV_HINT_KEY) ?? \"null\");\n return { activity: hint?.activity === true, artifacts: hint?.artifacts === true };\n } catch {\n return { activity: false, artifacts: false };\n }\n }\n function gate(notice = null) {\n forgetNav();\n awaitingAuthorization.clear();\n state = resetIdentity(state, notice);\n for (const listener of listeners) listener();\n }\n var RequestFailure = class extends Error {\n kind;\n status;\n problem;\n constructor(kind, status, problem) {\n super(`Operator request failed: ${kind}`);\n this.kind = kind;\n this.status = status;\n this.problem = problem;\n }\n };\n function factsOf(error) {\n return error instanceof RequestFailure ? error : { kind: \"refused\" };\n }\n async function operatorRequest(path, method, current, body) {\n let token;\n try {\n token = await sessionToken();\n } catch {\n throw new RequestFailure(\"session\");\n }\n if (!current()) throw new RequestFailure(\"session\");\n if (!token && auth.kind !== \"cloudflare-access\") throw new RequestFailure(\"session\");\n let res;\n try {\n res = await fetch(path, {\n method,\n headers: requestHeaders(token, Boolean(body)),\n credentials: \"same-origin\",\n ...body ? { body: JSON.stringify(body) } : {}\n });\n } catch {\n throw new RequestFailure(\"network\");\n }\n if (res.status === 204) return null;\n let payload = {};\n try {\n payload = await res.json();\n } catch {\n }\n if (res.status === 401) throw new RequestFailure(\"session\", 401);\n if (res.status === 403) throw new RequestFailure(\"forbidden\", 403);\n if (!res.ok) throw new RequestFailure(\"refused\", res.status, payload.problem);\n return payload;\n }\n function unreachable(loadFailure) {\n set({ session: \"ready\", gate: null, refreshing: false, loadFailure });\n }\n var dataRevision = 0;\n async function loadData() {\n const identityCurrent = fence();\n const revision = ++dataRevision;\n const current = () => identityCurrent() && revision === dataRevision;\n set(state.session === \"ready\" ? { refreshing: true, loadFailure: null } : { loadFailure: null });\n let token;\n try {\n token = await sessionToken();\n } catch {\n if (!current()) return;\n return gate(failure(\"Your sign-in session couldn't be read. Sign in again.\"));\n }\n if (!current()) return;\n if (!token && auth.kind !== \"cloudflare-access\") return gate(null);\n let res;\n try {\n res = await fetch(\"/ui/data\", {\n headers: requestHeaders(token),\n credentials: \"same-origin\"\n });\n } catch {\n if (!current()) return;\n return unreachable(\"network\");\n }\n if (!current()) return;\n if (res.status === 401 || res.status === 403) {\n if (auth.kind === \"clerk\") {\n return gate(\n failure(\n res.status === 403 ? `This Clerk account can't open ${productName}'s operator pages.` : \"Your Clerk session wasn't accepted. Sign out, then sign in again.\"\n )\n );\n }\n if (auth.kind === \"cloudflare-access\") {\n return gate(\n failure(\"Cloudflare Access let this browser in, but this identity isn't an operator here.\")\n );\n }\n localStorage.removeItem(TOKEN_KEY);\n return gate(failure(\"That token wasn't accepted. Paste a valid operator token.\"));\n }\n if (!res.ok) return unreachable(\"server\");\n let data;\n try {\n data = await res.json();\n } catch {\n if (!current()) return;\n return unreachable(\"server\");\n }\n if (!current()) return;\n if (!data || !Array.isArray(data.connectors)) return unreachable(\"server\");\n set({ data, session: \"ready\", gate: null, refreshing: false, loadFailure: null });\n rememberNav(data);\n void loadConnectorDetails(data, current, token);\n }\n async function mutate(options) {\n const current = fence();\n if (options.reload) detailRevisions.set(options.reload, (detailRevisions.get(options.reload) ?? 0) + 1);\n set(options.busy);\n try {\n const payload = await options.request(current);\n if (!current()) return options.abandoned?.();\n set(options.done(payload));\n if (options.reload) void refreshConnector(options.reload);\n } catch (error) {\n if (!current()) return options.abandoned?.();\n set(options.failed(factsOf(error)));\n if (options.reload) void refreshConnector(options.reload);\n }\n }\n function focusHandled() {\n if (state.pendingFocus !== null || state.focusIfLost !== null) {\n set({ pendingFocus: null, focusIfLost: null });\n }\n }\n function setPage(page, focus = false) {\n state = withPage(state, page);\n if (focus) {\n state = {\n ...state,\n pendingFocus: state.session === \"ready\" ? `${page}Heading` : \"gateHeading\"\n };\n }\n for (const listener of listeners) listener();\n }\n function navigate(page, href) {\n history.pushState({ operatorPage: page }, \"\", href);\n setPage(page, true);\n }\n function setConnectorFilter(connectorFilter) {\n set({ connectorFilter });\n }\n function setActivitySearch(activitySearch) {\n set({ activitySearch });\n }\n function signInWithBearer(value) {\n gate(null);\n localStorage.setItem(TOKEN_KEY, value);\n void loadCurrent().then(() => {\n if (state.session === \"ready\") set({ pendingFocus: `${state.page}Heading` });\n });\n }\n function forgetBearer() {\n localStorage.removeItem(TOKEN_KEY);\n gate(null);\n set({ pendingFocus: \"token\" });\n }\n function askConfirm(connectorId, action) {\n set({ confirming: { connectorId, action }, pendingFocus: `confirm-cancel-${connectorId}` });\n }\n function cancelConfirm(returnFocusTo) {\n set({ confirming: null, pendingFocus: returnFocusTo });\n }\n function oauthStartPath(connector, mode) {\n return `/ui/oauth/${encodeURIComponent(connector)}?mode=${mode}`;\n }\n var awaitingAuthorization = /* @__PURE__ */ new Set();\n function openBlankTab() {\n let tab = null;\n try {\n tab = window.open(\"\", \"_blank\");\n } catch {\n return null;\n }\n if (!tab) return null;\n try {\n tab.document.title = \"Opening authorization…\";\n tab.document.body.textContent = \"Opening the authorization page…\";\n } catch {\n }\n return tab;\n }\n function oauthNoticePatch(connector, notice) {\n return {\n oauthBusy: null,\n oauthNotice: notice,\n oauthNoticeFor: connector,\n focusIfLost: `oauthNotice-${connector}`\n };\n }\n function startOAuth(connector, mode) {\n const tab = openBlankTab();\n return mutate({\n request: (current) => operatorRequest(oauthStartPath(connector, mode), \"POST\", current),\n busy: {\n oauthBusy: connector,\n oauthNotice: null,\n oauthNoticeFor: connector,\n oauthBlocked: null,\n confirming: null\n },\n done: (payload) => {\n const url = safeHttpHref(payload?.authorizationUrl);\n if (!url) {\n tab?.close();\n if (payload?.state === \"ok\") {\n return oauthNoticePatch(connector, oauthDoneNotice(\"oauth_reconnect\", payload));\n }\n return oauthNoticePatch(connector, refusedNotice(\"oauth_reconnect\", connector));\n }\n if (tab) {\n tab.opener = null;\n tab.location.replace(url);\n }\n awaitingAuthorization.add(connector);\n return {\n ...state.data ? {\n data: {\n ...state.data,\n connectors: state.data.connectors.map(\n (c3) => c3.id === connector ? { ...c3, status: \"auth_required\", tools: [], toolCount: 0, authorizationUrl: url } : c3\n )\n }\n } : {},\n ...oauthNoticePatch(connector, oauthDoneNotice(\"oauth_reconnect\", payload, Boolean(tab))),\n oauthBlocked: tab ? null : connector\n };\n },\n // Signed out or switched mid-request: the tab it opened goes too, rather\n // than sitting on \"Opening…\" with nothing left to send it anywhere.\n abandoned: () => tab?.close(),\n // The route's words never reach this notice (see `refusedNotice`).\n failed: (facts) => {\n tab?.close();\n return oauthNoticePatch(\n connector,\n actionFailedNotice(\"oauth_reconnect\", connector, facts, productName)\n );\n },\n reload: connector\n });\n }\n function disconnectOAuth(connector) {\n return mutate({\n request: (current) => operatorRequest(`/ui/oauth/${encodeURIComponent(connector)}`, \"DELETE\", current),\n busy: {\n oauthBusy: connector,\n oauthNotice: null,\n oauthNoticeFor: connector,\n oauthBlocked: null,\n confirming: null\n },\n done: () => ({\n ...state.data ? {\n data: {\n ...state.data,\n connectors: state.data.connectors.map((c3) => {\n if (c3.id !== connector) return c3;\n const { authorizationUrl: _old, ...rest } = c3;\n return { ...rest, status: \"auth_required\", tools: [], toolCount: 0 };\n })\n }\n } : {},\n ...oauthNoticePatch(connector, oauthDoneNotice(\"oauth_disconnect\", null))\n }),\n failed: (facts) => oauthNoticePatch(\n connector,\n actionFailedNotice(\"oauth_disconnect\", connector, facts, productName)\n ),\n reload: connector\n });\n }\n function editCredential(connector) {\n set({ credentialEditing: connector, credentialNotice: null, credentialNoticeFor: null });\n }\n function refuseCredential(connector, copy) {\n set({ credentialNotice: failure(copy), credentialNoticeFor: connector });\n }\n function credentialMutation(connector, action, request, done, reload = true) {\n const land = (patch) => ({\n credentialBusy: null,\n credentialNoticeFor: connector,\n focusIfLost: `credentialNotice-${connector}`,\n ...patch\n });\n return mutate({\n request,\n busy: {\n credentialBusy: connector,\n credentialNotice: null,\n credentialNoticeFor: connector,\n confirming: null\n },\n done: (payload) => land(done(payload)),\n failed: (facts) => land({ credentialNotice: actionFailedNotice(action, connector, facts, productName) }),\n reload: reload ? connector : void 0\n });\n }\n function saveCredential(connector, body) {\n return credentialMutation(\n connector,\n \"credential_save\",\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"PUT\",\n current,\n body\n ),\n () => ({ credentialEditing: null, credentialNotice: info(\"Credential saved.\") })\n );\n }\n function removeCredential(connector) {\n return credentialMutation(\n connector,\n \"credential_remove\",\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"DELETE\",\n current\n ),\n () => ({ credentialNotice: info(\"Credential removed.\") })\n );\n }\n function testCredential(connector) {\n return credentialMutation(\n connector,\n \"credential_test\",\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}/test`,\n \"POST\",\n current\n ),\n (payload) => ({ credentialNotice: credentialTestNotice(connector, payload) }),\n false\n );\n }\n var activityRevision = 0;\n async function loadActivity(reset) {\n if (!state.data?.activityEnabled) return;\n const identityCurrent = fence();\n const revision = ++activityRevision;\n const current = () => identityCurrent() && revision === activityRevision;\n set({\n activityPhase: \"loading\",\n activityNotice: null,\n ...reset ? { activityEvents: [], activityCursor: null } : {}\n });\n const params = new URLSearchParams({ limit: \"50\" });\n if (!reset && state.activityCursor) {\n params.set(\"cursor\", state.activityCursor);\n }\n try {\n const payload = await operatorRequest(\n `/ui/activity?${params}`,\n \"GET\",\n current\n );\n if (!current()) return;\n if (!payload || !Array.isArray(payload.events)) throw new RequestFailure(\"refused\");\n set({\n activityPhase: \"ready\",\n activityEvents: [\n ...reset ? [] : state.activityEvents,\n ...payload?.events ?? []\n ],\n activityCursor: payload?.nextCursor ?? null\n });\n } catch (error) {\n if (!current()) return;\n set({\n activityPhase: \"error\",\n activityNotice: failure(collectionFailureCopy(\"activity\", factsOf(error), productName))\n });\n }\n }\n async function artifactRead(path, current, collection) {\n let token;\n try {\n token = await sessionToken();\n } catch {\n if (current()) gate(failure(\"Your sign-in session couldn't be read. Sign in again.\"));\n return void 0;\n }\n if (!current()) return void 0;\n if (!token && auth.kind !== \"cloudflare-access\") {\n gate(null);\n return void 0;\n }\n let res;\n try {\n res = await fetch(path, { headers: requestHeaders(token), credentials: \"same-origin\" });\n } catch {\n if (current()) {\n set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(collectionFailureCopy(collection, { kind: \"network\" }, productName))\n });\n }\n return void 0;\n }\n if (!current()) return void 0;\n if (res.status === 401) {\n if (auth.kind !== \"clerk\" && auth.kind !== \"cloudflare-access\") {\n localStorage.removeItem(TOKEN_KEY);\n gate(failure(\"That token wasn't accepted. Paste a valid operator token.\"));\n } else {\n gate(failure(\"Your session wasn't accepted. Sign out, then sign in again.\"));\n }\n return void 0;\n }\n if (res.status === 403) {\n gate(failure(\"This deployment doesn't open artifact pages to this identity.\"));\n return void 0;\n }\n return res;\n }\n var artifactRevision = 0;\n async function loadArtifacts(reset) {\n const identityCurrent = fence();\n const revision = ++artifactRevision;\n const current = () => identityCurrent() && revision === artifactRevision;\n set({\n artifactPhase: \"loading\",\n artifactNotice: null,\n ...reset ? { artifactRows: [], artifactCursor: null } : {}\n });\n const params = new URLSearchParams();\n if (state.artifactQuery.trim()) params.set(\"q\", state.artifactQuery.trim());\n if (state.artifactArchived) params.set(\"archived\", \"1\");\n if (!reset && state.artifactCursor) params.set(\"cursor\", state.artifactCursor);\n const query = params.toString();\n const res = await artifactRead(`/artifacts/_api/list${query ? `?${query}` : \"\"}`, current, \"artifacts\");\n if (!res || !current()) return;\n if (!res.ok) {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(\n collectionFailureCopy(\"artifacts\", { kind: \"refused\", status: res.status }, productName)\n )\n });\n }\n let payload;\n try {\n payload = await res.json();\n } catch {\n payload = null;\n }\n if (!current()) return;\n if (!payload || !Array.isArray(payload.artifacts)) {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(collectionFailureCopy(\"artifacts\", { kind: \"refused\" }, productName))\n });\n }\n set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"ready\",\n artifactRows: [...reset ? [] : state.artifactRows, ...payload.artifacts ?? []],\n artifactCursor: payload.nextCursor ?? null\n });\n }\n var artifactFrameConfined = false;\n function markArtifactFrameConfined() {\n artifactFrameConfined = true;\n }\n async function loadArtifactView() {\n if (artifactFrameConfined) {\n window.location.reload();\n return;\n }\n const current = fence();\n const request = artifactViewRequest(window.location.pathname, window.location.search);\n set({ artifactPhase: \"loading\", artifactNotice: null });\n if (!request) {\n return set({\n session: \"ready\",\n artifactPhase: \"error\",\n artifactNotice: failure(\"There is no artifact at this address.\")\n });\n }\n const res = await artifactRead(request, current, \"artifact\");\n if (!res || !current()) return;\n if (!res.ok) {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(\n collectionFailureCopy(\"artifact\", { kind: \"refused\", status: res.status }, productName)\n )\n });\n }\n let view = null;\n try {\n view = await res.json();\n } catch {\n view = null;\n }\n if (!current()) return;\n if (!view || typeof view.document !== \"string\") {\n return set({\n session: \"ready\",\n gate: null,\n artifactPhase: \"error\",\n artifactNotice: failure(\"The artifact couldn't be read. Retry in a moment.\")\n });\n }\n set({ session: \"ready\", gate: null, artifactPhase: \"ready\", artifactView: view });\n }\n function setArtifactQuery(artifactQuery) {\n set({ artifactQuery });\n }\n function setArtifactArchived(artifactArchived) {\n set({ artifactArchived });\n void loadArtifacts(true);\n }\n function loadCurrent() {\n if (state.page === \"artifacts\") return loadArtifacts(true);\n if (state.page === \"artifact\") return loadArtifactView();\n return loadData();\n }\n function retryLoad() {\n set({\n pendingFocus: state.page === \"connections\" ? \"connectorLedgerHeading\" : `${state.page}Heading`\n });\n return loadCurrent();\n }\n function retryCollection() {\n set({ pendingFocus: `${state.page}Heading` });\n if (state.page === \"activity\") return loadActivity(true);\n if (state.page === \"artifact\") return loadArtifactView();\n return loadArtifacts(true);\n }\n function signIn() {\n window.Clerk?.redirectToSignIn({\n signInFallbackRedirectUrl: window.location.href,\n signUpFallbackRedirectUrl: window.location.href\n });\n }\n function signOut() {\n if (auth.kind === \"cloudflare-access\") {\n gate(null);\n window.location.assign(\"/cdn-cgi/access/logout\");\n return;\n }\n const clerk = window.Clerk;\n gate(null);\n void clerk?.signOut({ redirectUrl: window.location.href });\n }\n var returnTimer;\n var lastReturnPass = 0;\n var RETURN_DEBOUNCE_MS = 150;\n var RETURN_MIN_INTERVAL_MS = 2e3;\n function onReturn() {\n if (typeof document !== \"undefined\" && document.visibilityState === \"hidden\") return;\n if (returnTimer !== void 0) return;\n returnTimer = setTimeout(() => {\n returnTimer = void 0;\n const now = Date.now();\n if (now - lastReturnPass < RETURN_MIN_INTERVAL_MS) return;\n lastReturnPass = now;\n recheckAuthorization();\n }, RETURN_DEBOUNCE_MS);\n }\n function recheckAuthorization() {\n if (state.session !== \"ready\" || !state.data) return;\n for (const connector of state.data.connectors) {\n if (state.oauthBusy === connector.id) continue;\n const authorizesElsewhere = connector.status === \"auth_required\" && (connector.oauth === true || Boolean(connector.authorizationUrl));\n if (authorizesElsewhere || awaitingAuthorization.has(connector.id)) {\n void refreshConnector(connector.id, true);\n }\n }\n }\n async function boot() {\n const onPop = () => setPage(pageForPath(window.location.pathname), true);\n window.addEventListener(\"popstate\", onPop);\n window.addEventListener(\"focus\", onReturn);\n if (typeof document !== \"undefined\") {\n document.addEventListener(\"visibilitychange\", onReturn);\n }\n if (auth.kind === \"clerk\") {\n const clerk = window.Clerk;\n if (!clerk) {\n return gate(failure(\"Clerk couldn't load. Check your connection and try again.\"));\n }\n try {\n await clerk.load({\n ...auth.signInUrl ? { signInUrl: auth.signInUrl } : {},\n ...auth.signUpUrl ? { signUpUrl: auth.signUpUrl } : {},\n signInFallbackRedirectUrl: window.location.href,\n signUpFallbackRedirectUrl: window.location.href,\n afterSignOutUrl: window.location.href\n });\n let sessionId = clerk.session?.id ?? null;\n clerk.addListener((resources) => {\n const next = resources.session?.id ?? null;\n if (next === sessionId) return;\n sessionId = next;\n gate(null);\n void loadCurrent();\n });\n } catch {\n return gate(failure(\"Clerk couldn't start. Reload the page to try again.\"));\n }\n }\n await loadCurrent();\n }\n async function readConnector(id, token) {\n let response;\n try {\n response = await fetch(`/ui/connectors/${encodeURIComponent(id)}`, {\n headers: requestHeaders(token),\n credentials: \"same-origin\"\n });\n } catch {\n return { kind: \"local\", failure: \"network\" };\n }\n if (response.status === 401 || response.status === 403) {\n return { kind: \"local\", failure: \"session\" };\n }\n if (!response.ok) return { kind: \"downstream\" };\n try {\n return { kind: \"detail\", detail: await response.json() };\n } catch {\n return { kind: \"downstream\" };\n }\n }\n function withoutKey(record, key) {\n const { [key]: _gone, ...rest } = record;\n return rest;\n }\n function applyDetail(id, outcome) {\n if (!state.data) return;\n const patch = {};\n const connectors = state.data.connectors.map((c3) => {\n if (c3.id !== id) return c3;\n if (outcome.kind === \"detail\") {\n const { detail } = outcome;\n return detail.status === \"auth_required\" && c3.authorizationUrl && !detail.authorizationUrl ? { ...detail, authorizationUrl: c3.authorizationUrl } : detail;\n }\n const { problem: _problem, ...rest } = c3;\n return outcome.kind === \"downstream\" ? { ...rest, status: \"error\", problem: \"connector_unavailable\" } : { ...rest, status: \"error\" };\n });\n patch.connectorFailures = outcome.kind === \"local\" ? { ...state.connectorFailures, [id]: outcome.failure } : withoutKey(state.connectorFailures, id);\n if (outcome.kind === \"detail\" && outcome.detail.status === \"ok\" && awaitingAuthorization.delete(id)) {\n if (state.oauthNoticeFor === id) {\n patch.oauthNotice = info(\"Connected.\");\n patch.oauthBlocked = null;\n }\n }\n set({ ...patch, data: { ...state.data, connectors } });\n }\n var detailGeneration = 0;\n var detailRevisions = /* @__PURE__ */ new Map();\n async function loadConnectorDetails(data, current, token) {\n const generation = ++detailGeneration;\n let next = 0;\n const worker = async () => {\n while (next < data.connectors.length && current() && generation === detailGeneration) {\n const connector = data.connectors[next++];\n const revision = (detailRevisions.get(connector.id) ?? 0) + 1;\n detailRevisions.set(connector.id, revision);\n const outcome = await readConnector(connector.id, token);\n if (!current() || generation !== detailGeneration || !state.data) return;\n if (detailRevisions.get(connector.id) !== revision) continue;\n applyDetail(connector.id, outcome);\n }\n };\n await Promise.all(Array.from({ length: Math.min(4, data.connectors.length) }, worker));\n }\n async function refreshConnector(id, quiet = false) {\n const current = fence();\n const revision = (detailRevisions.get(id) ?? 0) + 1;\n detailRevisions.set(id, revision);\n if (!quiet && state.data) {\n set({\n data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...c3, status: \"loading\" } : c3) },\n connectorFailures: withoutKey(state.connectorFailures, id)\n });\n }\n let token;\n try {\n token = await sessionToken();\n } catch {\n if (!current() || quiet || detailRevisions.get(id) !== revision) return;\n return applyDetail(id, { kind: \"local\", failure: \"session\" });\n }\n if (!current()) return;\n const outcome = await readConnector(id, token);\n if (!current() || !state.data || detailRevisions.get(id) !== revision) return;\n if (quiet && outcome.kind !== \"detail\") return;\n applyDetail(id, outcome);\n }\n var tokenRevision = 0;\n async function loadAccessTokens() {\n const identityCurrent = fence();\n const revision = ++tokenRevision;\n const current = () => identityCurrent() && revision === tokenRevision;\n const existing = new Map(state.tokens.map((token) => [token.id, token]));\n set({ tokenPhase: \"loading\", tokenNotice: null });\n try {\n const payload = await operatorRequest(\"/ui/access-tokens\", \"GET\", current);\n if (!current()) return;\n if (!Array.isArray(payload?.accessTokens)) throw new Error(\"The access token collection was not returned.\");\n const tokens = payload.accessTokens;\n const changed = state.tokens.filter((token) => existing.get(token.id) !== token);\n const changedIds = new Set(changed.map((token) => token.id));\n set({ tokenPhase: \"ready\", tokens: [\n ...changed,\n ...tokens.filter((token) => !changedIds.has(token.id))\n ] });\n } catch {\n if (!current()) return;\n set({\n tokenPhase: \"error\",\n tokenNotice: failure(\n \"Access tokens could not be loaded.\"\n )\n });\n }\n }\n function tokenFailure(tokenNotice) {\n return { tokenBusy: false, tokenNotice, pendingFocus: \"tokenNotice\" };\n }\n function createAccessToken(name) {\n if (state.tokenBusy) return Promise.resolve(false);\n if (!name) {\n set(tokenFailure(failure(\"Name the MCP client before creating a token.\")));\n return Promise.resolve(false);\n }\n let created = false;\n return mutate({\n request: (current) => operatorRequest(\"/ui/access-tokens\", \"POST\", current, { name }),\n busy: { tokenBusy: true, tokenNotice: null },\n done: (payload) => {\n const issued = payload?.accessToken;\n if (!payload?.token || !issued) {\n throw new Error(\"The created token was not returned.\");\n }\n created = true;\n return {\n tokenBusy: false,\n tokenPhase: \"ready\",\n tokens: [\n issued,\n ...state.tokens.filter((token) => token.id !== issued.id)\n ],\n createdToken: state.page === \"tokens\" ? payload.token : null,\n tokenNotice: info(\"Access token created.\"),\n pendingFocus: state.page === \"tokens\" ? \"tokenRevealHeading\" : null\n };\n },\n failed: () => tokenFailure(failure(\"Access token could not be created. Check the name, capacity, and storage.\"))\n }).then(() => created);\n }\n function dismissCreatedToken() {\n set({ createdToken: null });\n }\n function renameAccessToken(id) {\n set({ tokenRenaming: id });\n }\n function accessTokenMutation(id, method, body, success, fallback) {\n return mutate({\n request: (current) => operatorRequest(\n `/ui/access-tokens/${encodeURIComponent(id)}`,\n method,\n current,\n body\n ),\n busy: { tokenBusy: true, tokenNotice: null },\n done: (payload) => ({\n tokenBusy: false,\n tokenRenaming: null,\n tokenNotice: info(success),\n pendingFocus: \"tokenNotice\",\n ...payload?.accessToken ? {\n tokens: state.tokens.map(\n (token) => token.id === id ? payload.accessToken : token\n )\n } : {}\n }),\n failed: () => tokenFailure(failure(fallback))\n });\n }\n function saveAccessTokenName(id, name) {\n return accessTokenMutation(\n id,\n \"PUT\",\n { name },\n \"Access token renamed.\",\n \"Access token could not be renamed.\"\n );\n }\n function revokeAccessToken(id) {\n const named = state.tokens.find((token) => token.id === id);\n const confirmed = window.confirm(\n `Revoke ${named?.name || \"this access token\"}? Its MCP client will immediately lose access.`\n );\n if (!confirmed) return Promise.resolve();\n return accessTokenMutation(\n id,\n \"DELETE\",\n void 0,\n \"Access token revoked.\",\n \"Access token could not be revoked.\"\n );\n }\n\n // node_modules/preact/jsx-runtime/dist/jsxRuntime.module.js\n var f3 = 0;\n function u3(e3, t3, n2, o3, i3, u4) {\n t3 || (t3 = {});\n var a3, c3, p3 = t3;\n if (\"ref\" in p3) for (c3 in p3 = {}, t3) \"ref\" == c3 ? a3 = t3[c3] : p3[c3] = t3[c3];\n var l3 = { type: e3, props: p3, key: n2, ref: a3, __k: null, __: null, __b: 0, __e: null, __c: null, constructor: void 0, __v: --f3, __i: -1, __u: 0, __source: i3, __self: u4 };\n if (\"function\" == typeof e3 && (a3 = e3.defaultProps)) for (c3 in a3) void 0 === p3[c3] && (p3[c3] = a3[c3]);\n return l.vnode && l.vnode(l3), l3;\n }\n\n // src/operator-ui/app/parts.tsx\n function NoticeLine({\n id,\n notice,\n className = \"meta\"\n }) {\n return /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\n \"p\",\n {\n id,\n class: notice?.tone === \"error\" ? `notice ${className} error-notice` : `notice ${className}`,\n role: notice?.tone === \"error\" ? \"alert\" : \"status\",\n \"aria-live\": \"polite\",\n tabIndex: -1,\n children: notice ? notice.message : null\n }\n ),\n notice?.tone === \"error\" && notice.fix ? /* @__PURE__ */ u3(FixPrompt, { kind: notice.fix.kind, connectorId: notice.fix.connectorId }) : null\n ] });\n }\n function FixPrompt({\n kind,\n connectorId,\n name\n }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"fix-prompt\", \"data-fix-prompt\": kind, children: [\n /* @__PURE__ */ u3(FixPromptButton, { kind, connectorId, ...name ? { name } : {} }),\n /* @__PURE__ */ u3(FixPromptPreview, { kind, connectorId })\n ] });\n }\n function FixPromptButton({\n kind,\n connectorId,\n name\n }) {\n return /* @__PURE__ */ u3(\n CopyButton,\n {\n value: fixPrompt(kind, connectorId),\n label: \"Copy fix prompt\",\n class: \"btn quiet\",\n ariaLabel: `Copy fix prompt for ${name ?? connectorId}`\n }\n );\n }\n function FixPromptPreview({\n kind,\n connectorId,\n standalone\n }) {\n return /* @__PURE__ */ u3(\"details\", { class: \"fix-prompt-preview\", ...standalone ? { \"data-fix-prompt\": kind } : {}, children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: \"Preview prompt\" }),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: \"Fixed text for a coding agent working on this deployment. It carries no error details or secrets.\" }),\n /* @__PURE__ */ u3(\"pre\", { class: \"fix-prompt-text\", children: fixPrompt(kind, connectorId) })\n ] });\n }\n function Badge({\n tone = \"neutral\",\n children\n }) {\n return /* @__PURE__ */ u3(\"span\", { class: tone === \"neutral\" ? \"badge\" : `badge ${tone}`, children });\n }\n function StateBlock({\n title,\n children,\n tone = \"neutral\",\n action,\n id\n }) {\n return /* @__PURE__ */ u3(\n \"div\",\n {\n class: tone === \"error\" ? \"state-block error\" : \"state-block\",\n role: tone === \"error\" ? \"alert\" : \"status\",\n ...id ? { id } : {},\n children: [\n title ? /* @__PURE__ */ u3(\"p\", { class: \"state-title\", children: title }) : null,\n children ? /* @__PURE__ */ u3(\"p\", { class: \"state-copy\", children }) : null,\n action ? /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n onClick: action.onClick,\n ...action.id ? { id: action.id } : {},\n children: action.label\n }\n ) : null\n ]\n }\n );\n }\n function LoadFailure({ state: state2 }) {\n if (!state2.loadFailure) return null;\n const copy = loadFailureCopy(state2.loadFailure, productName);\n return /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"loadFailure\",\n tone: \"error\",\n title: copy.title,\n action: { label: \"Retry\", onClick: () => void retryLoad(), id: \"retryLoad\" },\n children: copy.body\n }\n );\n }\n function Empty({ children }) {\n return /* @__PURE__ */ u3(StateBlock, { children });\n }\n function Unavailable({ children }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"unavailable\", children });\n }\n function ConfirmBar({\n id,\n question,\n confirm,\n onConfirm,\n onCancel\n }) {\n return /* @__PURE__ */ u3(\n \"div\",\n {\n class: \"confirm\",\n role: \"group\",\n \"aria-labelledby\": `confirm-question-${id}`,\n onKeyDown: (event) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n onCancel();\n },\n children: [\n /* @__PURE__ */ u3(\"p\", { id: `confirm-question-${id}`, children: question }),\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n /* @__PURE__ */ u3(\"button\", { class: \"btn danger\", type: \"button\", onClick: onConfirm, children: confirm }),\n /* @__PURE__ */ u3(\n \"button\",\n {\n id: `confirm-cancel-${id}`,\n class: \"btn quiet\",\n type: \"button\",\n onClick: onCancel,\n children: \"Cancel\"\n }\n )\n ] })\n ]\n }\n );\n }\n function focusableId(...ids) {\n for (const id of ids) {\n const element = document.getElementById(id);\n if (element && !element.disabled) return id;\n }\n return ids[ids.length - 1] ?? \"\";\n }\n function PageLink({\n page,\n class: className,\n current,\n children\n }) {\n const href = PAGE_META[page].path;\n return /* @__PURE__ */ u3(\n \"a\",\n {\n class: className,\n href,\n ...current ? { \"aria-current\": \"page\" } : {},\n onClick: (event) => {\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return;\n }\n event.preventDefault();\n navigate(page, href);\n },\n children\n }\n );\n }\n function CopyButton({\n value,\n label,\n class: className = \"btn\",\n ariaLabel,\n id\n }) {\n const [status, setStatus] = d2(\"idle\");\n h2(() => {\n if (status === \"idle\") return;\n const timer = window.setTimeout(() => setStatus(\"idle\"), 1600);\n return () => window.clearTimeout(timer);\n }, [status]);\n return /* @__PURE__ */ u3(\n \"button\",\n {\n class: className,\n type: \"button\",\n ...id ? { id } : {},\n ...ariaLabel && status === \"idle\" ? { \"aria-label\": ariaLabel } : {},\n onClick: () => {\n const write = navigator.clipboard?.writeText(value) ?? Promise.reject(new Error(\"no clipboard\"));\n write.then(\n () => setStatus(\"copied\"),\n () => setStatus(\"failed\")\n );\n },\n children: status === \"copied\" ? \"Copied\" : status === \"failed\" ? \"Copy failed\" : label\n }\n );\n }\n\n // src/operator-ui/app/tokens.tsx\n function CreateForm({ busy }) {\n const [name, setName] = d2(\"\");\n return /* @__PURE__ */ u3(\n \"form\",\n {\n id: \"tokenCreateForm\",\n class: \"token-create\",\n onSubmit: (event) => {\n event.preventDefault();\n void createAccessToken(name.trim()).then((created) => {\n if (created) setName(\"\");\n });\n },\n children: [\n /* @__PURE__ */ u3(\"label\", { for: \"tokenName\", children: \"Client name\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"row\", children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"tokenName\",\n type: \"text\",\n maxLength: 80,\n placeholder: \"Claude desktop, ChatGPT production…\",\n autocomplete: \"off\",\n value: name,\n onInput: (event) => setName(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { id: \"createToken\", class: \"btn\", type: \"submit\", disabled: busy, children: busy ? \"Creating…\" : \"Create token\" })\n ] })\n ]\n }\n );\n }\n function Reveal({ token }) {\n return /* @__PURE__ */ u3(\n \"section\",\n {\n id: \"tokenReveal\",\n class: \"token-reveal\",\n \"aria-labelledby\": \"tokenRevealHeading\",\n children: [\n /* @__PURE__ */ u3(\"div\", { class: \"token-reveal-head\", children: [\n /* @__PURE__ */ u3(\"h2\", { id: \"tokenRevealHeading\", tabIndex: -1, children: \"Copy this token now\" }),\n /* @__PURE__ */ u3(\"span\", { class: \"cap\", children: \"Shown once\" })\n ] }),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: \"Store it in the MCP client before leaving this page. It cannot be displayed again.\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"endpoint-row token-secret\", children: [\n /* @__PURE__ */ u3(\"code\", { id: \"createdToken\", class: \"mono\", children: token }),\n /* @__PURE__ */ u3(CopyButton, { value: token, label: \"Copy token\" })\n ] }),\n /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"button\", onClick: dismissCreatedToken, children: \"I stored it\" })\n ]\n }\n );\n }\n function TokenCard({\n token,\n renaming,\n busy\n }) {\n const [name, setName] = d2(token.name);\n const revoked = Boolean(token.revokedAt);\n return /* @__PURE__ */ u3(\n \"section\",\n {\n class: revoked ? \"token-card revoked\" : \"token-card\",\n \"aria-labelledby\": `access-token-${token.id}`,\n children: [\n /* @__PURE__ */ u3(\"div\", { class: \"token-card-head\", children: [\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"h2\", { id: `access-token-${token.id}`, children: token.name }),\n /* @__PURE__ */ u3(\"p\", { class: \"mono\", children: [\n token.tokenPrefix,\n \"…\"\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"cap\", children: revoked ? `Revoked ${formatDate(token.revokedAt)}` : `Created ${formatDate(token.createdAt)}` })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"credential-actions\", children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n disabled: busy,\n onClick: () => {\n setName(token.name);\n renameAccessToken(renaming ? null : token.id);\n },\n children: \"Rename\"\n }\n ),\n revoked ? null : /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn danger\",\n type: \"button\",\n disabled: busy,\n onClick: () => void revokeAccessToken(token.id),\n children: \"Revoke\"\n }\n )\n ] }),\n renaming ? /* @__PURE__ */ u3(\n \"form\",\n {\n class: \"credential-form\",\n onSubmit: (event) => {\n event.preventDefault();\n const next = name.trim();\n if (next) void saveAccessTokenName(token.id, next);\n },\n children: [\n /* @__PURE__ */ u3(\"label\", { class: \"visually-hidden\", for: `token-name-${token.id}`, children: \"Token name\" }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: `token-name-${token.id}`,\n type: \"text\",\n maxLength: 80,\n autocomplete: \"off\",\n value: name,\n onInput: (event) => setName(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"submit\", disabled: busy, children: \"Save name\" }),\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n disabled: busy,\n onClick: () => renameAccessToken(null),\n children: \"Cancel\"\n }\n )\n ]\n }\n ) : null\n ]\n }\n );\n }\n function TokensPage({ state: state2 }) {\n const available = state2.data?.accessTokenManagement === \"available\";\n return /* @__PURE__ */ u3(\"section\", { id: \"tokensView\", children: /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"tokensHeading\", class: \"\", tabIndex: -1, children: \"Access tokens\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { class: \"activity-copy\", children: \"Create named Bearer tokens for MCP clients. Each secret is shown once; revoke it when that client should lose access.\" }),\n /* @__PURE__ */ u3(NoticeLine, { id: \"tokenNotice\", notice: state2.tokenNotice }),\n !available ? /* @__PURE__ */ u3(Unavailable, { children: accessTokenUnavailableCopy(state2.data?.accessTokenManagement) }) : /* @__PURE__ */ u3(\"div\", { id: \"tokenAvailable\", children: [\n state2.createdToken ? /* @__PURE__ */ u3(Reveal, { token: state2.createdToken }) : /* @__PURE__ */ u3(CreateForm, { busy: state2.tokenBusy }),\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"tokenList\",\n class: \"token-ledger\",\n \"aria-busy\": state2.tokenPhase === \"loading\" ? \"true\" : \"false\",\n children: state2.tokenPhase === \"loading\" ? /* @__PURE__ */ u3(Empty, { children: \"Loading access tokens…\" }) : state2.tokenPhase === \"error\" ? /* @__PURE__ */ u3(\"p\", { class: \"empty\", children: /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n onClick: () => void loadAccessTokens(),\n children: \"Try loading access tokens again\"\n }\n ) }) : state2.tokens.length === 0 ? /* @__PURE__ */ u3(Empty, { children: \"No access tokens yet. Name the first MCP client above.\" }) : state2.tokens.map((token) => /* @__PURE__ */ u3(\n TokenCard,\n {\n token,\n renaming: state2.tokenRenaming === token.id,\n busy: state2.tokenBusy\n },\n token.id\n ))\n }\n )\n ] })\n ] })\n ] }) });\n }\n\n // src/operator-ui/app/activity.tsx\n function ActivityRow({ event }) {\n const outcome = activityOutcomeClass(event.outcome);\n const badge = activityOutcomeBadge(event.outcome);\n const stableId = actorStableId(event.actor);\n return /* @__PURE__ */ u3(\"article\", { class: `activity-item ${outcome}`, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"activity-stamp\", children: [\n /* @__PURE__ */ u3(\"span\", { class: `dot ${outcome}`, \"aria-hidden\": \"true\" }),\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"time\", { class: \"activity-time\", dateTime: event.occurredAt, children: formatDate(event.occurredAt) }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-actor\", children: actorLabel(event.actor) }),\n stableId ? /* @__PURE__ */ u3(\"div\", { class: \"activity-actor-id mono\", children: stableId }) : null\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"div\", { class: \"activity-address\", children: event.address }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-detail\", children: activityDetail(event) })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-result\", children: [\n /* @__PURE__ */ u3(Badge, { tone: badge.tone, children: badge.label }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-detail\", children: [\n event.durationMs,\n \" ms\"\n ] })\n ] })\n ] });\n }\n function ActivityPage({ state: state2 }) {\n const data = state2.data;\n const enabled = Boolean(data?.activityEnabled);\n const loading = state2.activityPhase === \"loading\";\n const visible = filterActivity(state2.activityEvents, state2.activitySearch);\n const summary = activitySummary(state2.activityEvents);\n const failed = state2.activityPhase === \"error\";\n return /* @__PURE__ */ u3(\"section\", { id: \"activityView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"activityHeading\", tabIndex: -1, children: \"Activity\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: /* @__PURE__ */ u3(\"p\", { children: pageDescription(\"activity\", productDescription) }) })\n ] }),\n !data ? (\n // Whether Activity is open to this identity is in /ui/data, which\n // has not answered yet — or could not.\n state2.loadFailure ? /* @__PURE__ */ u3(LoadFailure, { state: state2 }) : /* @__PURE__ */ u3(StateBlock, { children: \"Loading activity…\" })\n ) : !enabled ? /* @__PURE__ */ u3(Unavailable, { children: [\n \"Activity history is not configured. Add an\",\n \" \",\n /* @__PURE__ */ u3(\"span\", { class: \"mono\", children: \"activity.store\" }),\n \" with a list reader to enable this page.\"\n ] }) : /* @__PURE__ */ u3(\"div\", { id: \"activityAvailable\", class: \"collection\", children: [\n failed && state2.activityEvents.length === 0 ? null : /* @__PURE__ */ u3(\"div\", { class: \"row\", children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"activitySearch\",\n type: \"search\",\n placeholder: \"Search user, tool, or outcome…\",\n \"aria-label\": \"Search loaded activity\",\n value: state2.activitySearch,\n onInput: (event) => setActivitySearch(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\n \"button\",\n {\n id: \"refreshActivity\",\n class: \"btn\",\n type: \"button\",\n disabled: loading,\n onClick: () => void loadActivity(true),\n children: loading ? \"Loading…\" : \"Refresh\"\n }\n )\n ] }),\n /* @__PURE__ */ u3(\"p\", { id: \"activitySummary\", class: \"meta\", \"aria-live\": \"polite\", children: summary }),\n state2.activityEvents.length === 0 ? loading ? /* @__PURE__ */ u3(StateBlock, { children: \"Loading activity…\" }) : failed ? /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"activityError\",\n tone: \"error\",\n title: \"Activity couldn't be loaded\",\n action: { label: \"Retry\", onClick: () => void retryCollection() },\n children: state2.activityNotice?.message\n }\n ) : /* @__PURE__ */ u3(StateBlock, { children: state2.activitySearch.trim() ? \"No loaded activity matches this search.\" : \"No connector tool calls recorded yet.\" }) : visible.length === 0 ? /* @__PURE__ */ u3(StateBlock, { children: \"No loaded activity matches this search.\" }) : /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"activityList\",\n class: \"activity-list\",\n \"aria-busy\": loading ? \"true\" : \"false\",\n children: visible.map((event, index) => /* @__PURE__ */ u3(\n ActivityRow,\n {\n event\n },\n `${event.occurredAt}-${event.address}-${index}`\n ))\n }\n ),\n state2.activityEvents.length > 0 ? /* @__PURE__ */ u3(NoticeLine, { id: \"activityNotice\", notice: state2.activityNotice }) : null,\n state2.activityCursor ? /* @__PURE__ */ u3(\n \"button\",\n {\n id: \"moreActivity\",\n class: \"btn activity-more\",\n type: \"button\",\n disabled: loading,\n onClick: () => void loadActivity(false),\n children: loading ? \"Loading…\" : \"Load older\"\n }\n ) : null\n ] })\n ] });\n }\n\n // src/operator-ui/app/artifacts.tsx\n function ArtifactRow({ row }) {\n const refresh = artifactRefreshBadge(row.freshness?.last);\n return /* @__PURE__ */ u3(\"article\", { class: \"artifact-row\", children: [\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"a\", { class: \"artifact-title\", href: `/artifacts/${row.id}`, children: row.title }),\n /* @__PURE__ */ u3(\"div\", { class: \"artifact-meta\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"mono\", children: row.id }),\n \" · version \",\n row.viewVersion,\n \" · updated\",\n \" \",\n /* @__PURE__ */ u3(\"time\", { dateTime: row.updatedAt, children: formatDate(row.updatedAt) }),\n \" by \",\n row.updatedBy.label\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"artifact-badges\", children: [\n /* @__PURE__ */ u3(Badge, { children: row.kind === \"markdown\" ? \"Markdown\" : \"HTML\" }),\n row.freshness?.state === \"stale\" ? /* @__PURE__ */ u3(Badge, { tone: \"warn\", children: \"Stale data\" }) : row.freshness?.state === \"current\" ? /* @__PURE__ */ u3(Badge, { children: \"Current data\" }) : null,\n refresh ? /* @__PURE__ */ u3(Badge, { tone: refresh.tone, children: refresh.label }) : null,\n row.archived ? /* @__PURE__ */ u3(Badge, { tone: \"warn\", children: \"Archived\" }) : null\n ] })\n ] });\n }\n function ArtifactsPage({ state: state2 }) {\n const loading = state2.artifactPhase === \"loading\";\n const rows = state2.artifactRows;\n return /* @__PURE__ */ u3(\"section\", { id: \"artifactsView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"artifactsHeading\", tabIndex: -1, children: \"Artifacts\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: /* @__PURE__ */ u3(\"p\", { children: pageDescription(\"artifacts\", productDescription) }) })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"collection\", children: [\n /* @__PURE__ */ u3(\n \"form\",\n {\n class: \"row\",\n onSubmit: (event) => {\n event.preventDefault();\n void loadArtifacts(true);\n },\n children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"artifactSearch\",\n type: \"search\",\n placeholder: \"Search titles…\",\n \"aria-label\": \"Search artifact titles\",\n value: state2.artifactQuery,\n onInput: (event) => setArtifactQuery(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { id: \"searchArtifacts\", class: \"btn\", type: \"submit\", disabled: loading, children: \"Search\" }),\n /* @__PURE__ */ u3(\"label\", { class: \"check artifact-meta\", children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"showArchived\",\n type: \"checkbox\",\n checked: state2.artifactArchived,\n onChange: (event) => setArtifactArchived(event.currentTarget.checked)\n }\n ),\n \" \",\n \"Show archived\"\n ] })\n ]\n }\n ),\n state2.artifactPhase === \"error\" && rows.length === 0 ? /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"artifactError\",\n tone: \"error\",\n title: \"Artifacts couldn't be loaded\",\n action: { label: \"Retry\", onClick: () => void retryCollection() },\n children: state2.artifactNotice?.message\n }\n ) : rows.length === 0 ? /* @__PURE__ */ u3(StateBlock, { children: loading ? \"Loading artifacts…\" : state2.artifactQuery.trim() ? \"No artifact title matches this search.\" : \"No artifacts yet. Ask an agent to publish one.\" }) : /* @__PURE__ */ u3(\"div\", { id: \"artifactList\", class: \"activity-list\", \"aria-busy\": loading ? \"true\" : \"false\", children: rows.map((row) => /* @__PURE__ */ u3(ArtifactRow, { row }, row.id)) }),\n rows.length > 0 ? /* @__PURE__ */ u3(NoticeLine, { id: \"artifactNotice\", notice: state2.artifactNotice }) : null,\n state2.artifactCursor ? /* @__PURE__ */ u3(\n \"button\",\n {\n id: \"moreArtifacts\",\n class: \"btn activity-more\",\n type: \"button\",\n disabled: loading,\n onClick: () => void loadArtifacts(false),\n children: loading ? \"Loading…\" : \"Load more\"\n }\n ) : null\n ] })\n ] });\n }\n function ArtifactFrame({ view }) {\n const frame = A2(null);\n _2(() => {\n const element = frame.current;\n if (!element) return;\n const onMessage = (event) => {\n if (event.source !== element.contentWindow || event.origin !== \"null\") return;\n const data = event.data;\n if (!data || data.type !== \"ready\") return;\n window.removeEventListener(\"message\", onMessage);\n const policy = document.createElement(\"meta\");\n policy.httpEquiv = \"Content-Security-Policy\";\n policy.content = \"frame-src 'none'\";\n document.head.append(policy);\n markArtifactFrameConfined();\n element.contentWindow?.postMessage({ type: \"document\", html: view.document }, \"*\");\n };\n window.addEventListener(\"message\", onMessage);\n return () => window.removeEventListener(\"message\", onMessage);\n }, [view.document]);\n return /* @__PURE__ */ u3(\n \"iframe\",\n {\n ref: frame,\n id: \"artifactFrame\",\n class: \"artifact-frame\",\n title: view.title,\n sandbox: \"allow-scripts\",\n referrerpolicy: \"no-referrer\",\n src: \"/artifacts/_frame\"\n }\n );\n }\n function ArtifactPage({ state: state2 }) {\n const view = state2.artifactView;\n const failed = state2.artifactPhase === \"error\";\n return /* @__PURE__ */ u3(\"section\", { id: \"artifactView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"artifact-head\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"artifactHeading\", tabIndex: -1, children: view?.title ?? \"Artifact\" }),\n view ? /* @__PURE__ */ u3(\"div\", { class: \"artifact-meta\", id: \"artifactMeta\", children: [\n view.snapshot ? \"Snapshot of \" : \"\",\n \"version \",\n view.view.version,\n view.snapshot && view.view.version !== view.latestViewVersion ? ` (latest is ${view.latestViewVersion})` : \"\",\n \" \",\n \"· updated \",\n /* @__PURE__ */ u3(\"time\", { dateTime: view.view.at, children: formatDate(view.view.at) }),\n \" by\",\n \" \",\n view.view.by.label,\n \" ·\",\n \" \",\n /* @__PURE__ */ u3(\"a\", { href: \"/artifacts\", children: \"All artifacts\" }),\n view.snapshot ? /* @__PURE__ */ u3(S, { children: [\n \" \",\n \"· \",\n /* @__PURE__ */ u3(\"a\", { href: view.url, children: \"Current version\" })\n ] }) : /* @__PURE__ */ u3(S, { children: [\n \" \",\n \"·\",\n \" \",\n /* @__PURE__ */ u3(\n CopyButton,\n {\n id: \"copySnapshot\",\n class: \"navlink inline\",\n value: view.snapshotUrl,\n label: \"Copy snapshot link\"\n }\n )\n ] })\n ] }) : null,\n view?.archived ? /* @__PURE__ */ u3(\"div\", { id: \"archivedBanner\", class: \"artifact-banner\", role: \"status\", children: \"This artifact is archived. It keeps every version, and an agent can restore it.\" }) : null,\n !view?.snapshot && view?.freshness?.state === \"stale\" ? /* @__PURE__ */ u3(\"div\", { id: \"staleBanner\", class: \"artifact-banner\", role: \"status\", children: [\n \"Data may be out of date. The last refresh \",\n view.freshness.last?.status === \"failed\" ? \"failed\" : \"is overdue\",\n \"; the last good document is still shown.\"\n ] }) : null,\n !view && !failed ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: pageDescription(\"artifact\", productDescription) }) : null\n ] }),\n view ? /* @__PURE__ */ u3(ArtifactFrame, { view }, view.snapshotUrl) : failed ? /* @__PURE__ */ u3(\n StateBlock,\n {\n id: \"artifactError\",\n tone: \"error\",\n title: \"This artifact couldn't be opened\",\n action: { label: \"Retry\", onClick: () => void retryCollection() },\n children: state2.artifactNotice?.message\n }\n ) : /* @__PURE__ */ u3(StateBlock, { children: \"Loading artifact…\" })\n ] });\n }\n\n // src/operator-ui/app/credentials.tsx\n function CredentialForm({\n connector,\n credential,\n busy\n }) {\n const fields = credential.fields ?? [];\n const [values, setValues] = d2({});\n const single = fields.length === 0;\n const inputId = `credential-input-${connector}`;\n const submit = () => {\n if (single) {\n const value = (values.value ?? \"\").trim();\n if (!value) return refuseCredential(connector, \"Paste a credential before saving.\");\n return void saveCredential(connector, { value });\n }\n const entries = {};\n for (const field of fields) {\n const value = (values[field.name] ?? \"\").trim();\n if (!value) {\n return refuseCredential(\n connector,\n \"Complete every credential field before saving.\"\n );\n }\n entries[field.name] = value;\n }\n void saveCredential(connector, { values: entries });\n };\n return /* @__PURE__ */ u3(\"div\", { class: \"credential-form\", \"data-credential-form\": connector, children: [\n single ? /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\"label\", { class: \"visually-hidden\", for: inputId, children: credential.label }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: inputId,\n type: \"password\",\n \"aria-label\": credential.label,\n placeholder: credential.placeholder || \"Paste credential\",\n autocomplete: \"new-password\",\n autocapitalize: \"none\",\n spellcheck: false,\n value: values.value ?? \"\",\n onInput: (event) => setValues({ value: event.currentTarget.value })\n }\n )\n ] }) : /* @__PURE__ */ u3(\"div\", { class: \"credential-fields\", children: fields.map((field, index) => {\n const id = `credential-input-${connector}-${index}`;\n return /* @__PURE__ */ u3(\"div\", { class: \"credential-field\", children: [\n /* @__PURE__ */ u3(\"label\", { for: id, children: field.label }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id,\n type: field.inputType || \"password\",\n placeholder: field.placeholder || field.label,\n autocomplete: (field.inputType ?? \"password\") === \"password\" ? \"new-password\" : \"off\",\n autocapitalize: \"none\",\n spellcheck: false,\n value: values[field.name] ?? \"\",\n onInput: (event) => setValues({\n ...values,\n [field.name]: event.currentTarget.value\n })\n }\n )\n ] }, field.name);\n }) }),\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n /* @__PURE__ */ u3(\"button\", { class: \"btn primary\", type: \"button\", disabled: busy, onClick: submit, children: busy ? \"Saving…\" : \"Save\" }),\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn quiet\",\n type: \"button\",\n disabled: busy,\n onClick: () => editCredential(null),\n children: \"Cancel\"\n }\n )\n ] })\n ] });\n }\n function CredentialCard({\n connector,\n credential,\n editing,\n busy,\n confirming,\n notice\n }) {\n const name = connector.title || connector.id;\n const configured = Boolean(credential.configured);\n const removable = configured || Boolean(credential.removable);\n return /* @__PURE__ */ u3(\n \"section\",\n {\n class: \"subcard\",\n id: `credential-${connector.id}`,\n \"aria-labelledby\": `credential-title-${connector.id}`,\n children: [\n /* @__PURE__ */ u3(\"div\", { class: \"subcard-head\", children: [\n /* @__PURE__ */ u3(\"h3\", { id: `credential-title-${connector.id}`, children: credential.label }),\n /* @__PURE__ */ u3(\"span\", { class: \"meta\", children: credentialStateLabel(credential) })\n ] }),\n credential.description ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: credential.description }) : null,\n credential.fields?.length ? /* @__PURE__ */ u3(\"div\", { class: \"credential-field-summary\", children: credential.fields.map((field) => /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"span\", { children: field.label }),\n /* @__PURE__ */ u3(\"span\", { class: \"meta\", children: field.configured ? `configured · ••••${field.lastFour ?? \"\"}${field.updatedAt ? ` · updated ${formatDate(field.updatedAt)}` : \"\"}` : \"not configured\" })\n ] }, field.name)) }) : null,\n credential.error ? /* @__PURE__ */ u3(\"p\", { class: \"msg\", children: credentialProblemCopy(credential.problem) }) : null,\n credential.error && credential.problem ? /* @__PURE__ */ u3(\n FixPrompt,\n {\n kind: credential.problem,\n connectorId: connector.id,\n name: connector.title || connector.id\n }\n ) : null,\n credential.notice ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: credential.notice }) : null,\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: removable ? \"btn\" : \"btn primary\",\n type: \"button\",\n \"aria-expanded\": editing ? \"true\" : \"false\",\n disabled: busy,\n onClick: () => editCredential(editing ? null : connector.id),\n children: removable ? \"Replace\" : \"Add credential\"\n }\n ),\n configured && credential.testable ? /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n disabled: busy,\n onClick: () => void testCredential(connector.id),\n children: busy ? \"Working…\" : \"Test\"\n }\n ) : null,\n removable ? /* @__PURE__ */ u3(\n \"button\",\n {\n id: `remove-credential-${connector.id}`,\n class: \"btn danger\",\n type: \"button\",\n disabled: busy,\n onClick: () => askConfirm(connector.id, \"credential_remove\"),\n children: \"Remove\"\n }\n ) : null\n ] }),\n confirming ? /* @__PURE__ */ u3(\n ConfirmBar,\n {\n id: connector.id,\n ...confirmCopy(\"credential_remove\", name),\n onConfirm: () => void removeCredential(connector.id),\n onCancel: () => cancelConfirm(\n focusableId(`remove-credential-${connector.id}`, `conn-toggle-${connector.id}`)\n )\n }\n ) : null,\n editing ? /* @__PURE__ */ u3(\n CredentialForm,\n {\n connector: connector.id,\n credential,\n busy\n }\n ) : null,\n /* @__PURE__ */ u3(NoticeLine, { id: `credentialNotice-${connector.id}`, notice })\n ]\n }\n );\n }\n\n // src/operator-ui/model.ts\n function filterUiConnectors(connectors, query) {\n const q2 = query.trim().toLowerCase();\n const filtered = [];\n for (const connector of connectors) {\n const connectorText = [\n connector.id,\n connector.title,\n connector.description,\n connector.status\n ].join(\" \").toLowerCase();\n const connectorMatches = Boolean(q2 && connectorText.includes(q2));\n const tools = connector.tools.filter(\n (tool) => !q2 || connectorMatches || `${tool.name} ${tool.description ?? \"\"}`.toLowerCase().includes(q2)\n );\n if (q2 && tools.length === 0 && !connectorMatches) continue;\n filtered.push({ connector, tools });\n }\n return filtered;\n }\n\n // src/operator-ui/setup-commands.ts\n function clientServerName(serverName, pool) {\n const base = (serverName ?? \"\").toLowerCase().replace(/[^a-z0-9_-]+/g, \"-\").replace(/-{2,}/g, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 48) || \"connecta\";\n return pool ? `${base}-${pool}` : base;\n }\n function poolEndpointUrl(mcpUrl2, pool) {\n return `${mcpUrl2.replace(/\\/+$/, \"\")}/${encodeURIComponent(pool)}`;\n }\n function shellWord(value) {\n return /^[A-Za-z0-9_./:@%+=,~-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\"'\"'`)}'`;\n }\n function clientSetupCommands(name, url) {\n return [\n {\n id: \"claude\",\n label: \"Claude Code\",\n text: `claude mcp add --transport http ${shellWord(name)} ${shellWord(url)}`\n },\n {\n id: \"codex\",\n label: \"Codex\",\n text: `codex mcp add ${shellWord(name)} --url ${shellWord(url)}`\n },\n {\n id: \"json\",\n label: \"JSON config\",\n text: JSON.stringify(\n { mcpServers: { [name]: { type: \"http\", url } } },\n null,\n 2\n )\n }\n ];\n }\n\n // src/operator-ui/app/connections.tsx\n var DRIFT_HEADING = {\n clean: \"Catalog drift · none\",\n warning: \"Catalog drift · review\",\n unavailable: \"Catalog drift · not observed\"\n };\n function DriftPanel({ connector }) {\n const drift = connector.catalogDrift;\n const state2 = driftState(drift);\n return /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: `drift-${connector.id}`,\n class: `connector-drift ${state2}`,\n \"data-drift\": state2,\n children: [\n /* @__PURE__ */ u3(\"p\", { class: \"cap\", children: DRIFT_HEADING[state2] }),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: driftSummary(drift) }),\n state2 === \"unavailable\" ? null : /* @__PURE__ */ u3(\"ul\", { class: \"drift-counts\", children: driftCounts(drift).map(({ key, label, count }) => /* @__PURE__ */ u3(\"li\", { class: count > 0 ? \"drift-count flagged\" : \"drift-count\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"drift-count-value\", children: count }),\n /* @__PURE__ */ u3(\"span\", { class: \"drift-count-label\", children: label })\n ] }, key)) })\n ]\n }\n ),\n state2 === \"warning\" ? /* @__PURE__ */ u3(\n FixPrompt,\n {\n kind: \"catalog_drift\",\n connectorId: connector.id,\n name: connector.title || connector.id\n }\n ) : null\n ] });\n }\n function SafetyBadge({ safety }) {\n const badge = safety ? TOOL_SAFETY_BADGE[safety] : void 0;\n if (!badge) return null;\n return /* @__PURE__ */ u3(\"span\", { class: \"tool-safety\", title: badge.title, \"data-safety\": safety, children: /* @__PURE__ */ u3(Badge, { tone: badge.tone, children: badge.label }) });\n }\n function Endpoint({\n url,\n name,\n label,\n primary\n }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"endpoint-block\", \"data-endpoint\": name, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"endpoint\", children: [\n label ? /* @__PURE__ */ u3(\"span\", { class: \"endpoint-label cap\", children: label }) : null,\n /* @__PURE__ */ u3(\"code\", { ...primary ? { id: \"mcpUrl\" } : {}, class: \"mono\", children: url }),\n /* @__PURE__ */ u3(\n CopyButton,\n {\n value: url,\n label: \"Copy URL\",\n ...label ? { ariaLabel: `Copy URL for ${label}` } : {}\n }\n )\n ] }),\n /* @__PURE__ */ u3(\"details\", { class: \"setup\", children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: [\n \"Client setup\",\n label ? ` · ${label}` : \"\"\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"setup-list\", children: [\n clientSetupCommands(name, url).map((command) => /* @__PURE__ */ u3(\"div\", { class: \"setup-item\", \"data-setup\": command.id, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"setup-head\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"cap\", children: command.label }),\n /* @__PURE__ */ u3(\n CopyButton,\n {\n value: command.text,\n label: \"Copy\",\n class: \"btn quiet\",\n ariaLabel: `Copy ${command.label} setup${label ? ` for ${label}` : \"\"}`\n }\n )\n ] }),\n /* @__PURE__ */ u3(\"pre\", { class: \"setup-code\", children: command.text })\n ] }, command.id)),\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: \"No token is included. Clients sign in through this deployment's inbound auth.\" })\n ] })\n ] })\n ] });\n }\n function AuthActions({\n connector,\n name,\n manage,\n state: state2\n }) {\n const id = connector.id;\n const authorization = safeHttpHref(connector.authorizationUrl);\n const busy = state2.oauthBusy === id;\n if (connector.status === \"loading\") return null;\n if (!connector.oauth || !manage) {\n return authorization && connector.status !== \"ok\" ? /* @__PURE__ */ u3(\"a\", { class: \"btn primary\", href: authorization, target: \"_blank\", rel: \"noopener noreferrer\", children: \"Authorize connector\" }) : null;\n }\n if (state2.oauthBlocked === id && authorization) {\n return /* @__PURE__ */ u3(\n \"a\",\n {\n id: `authorize-${id}`,\n class: \"btn primary\",\n href: authorization,\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n children: \"Open authorization page\"\n }\n );\n }\n if (connector.status !== \"ok\") {\n const needsAuth = connector.status === \"auth_required\";\n return /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `connect-${id}`,\n class: needsAuth ? \"btn primary\" : \"btn\",\n \"aria-label\": `${needsAuth ? \"Connect\" : \"Reconnect\"} ${name}`,\n disabled: busy,\n onClick: () => void startOAuth(id, \"continue\"),\n children: busy ? \"Opening…\" : needsAuth ? \"Connect account\" : \"Reconnect\"\n }\n );\n }\n const switching = connector.authScope === \"personal\";\n return /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `reconnect-${id}`,\n class: \"btn\",\n \"aria-label\": `${switching ? \"Switch account for\" : \"Reconnect\"} ${name}`,\n disabled: busy,\n onClick: () => askConfirm(id, \"oauth_restart\"),\n children: busy ? \"Working…\" : switching ? \"Switch account\" : \"Reconnect\"\n }\n ),\n /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `disconnect-${id}`,\n class: \"btn danger\",\n \"aria-label\": `Disconnect ${name}`,\n disabled: busy,\n onClick: () => askConfirm(id, \"oauth_disconnect\"),\n children: \"Disconnect\"\n }\n )\n ] });\n }\n function ConnectorRow({\n connector,\n tools,\n forceOpen,\n state: state2\n }) {\n const [open, setOpen] = d2(false);\n const shown = open || forceOpen;\n const id = connector.id;\n const name = connector.title || id;\n const drift = driftState(connector.catalogDrift);\n const manage = Boolean(\n connector.permissions?.manageSharedAuth || connector.permissions?.connectPersonal\n );\n const local = state2.connectorFailures[id];\n const problem = connector.status === \"loading\" || local ? null : problemCopy(connector.problem);\n const confirming = state2.confirming?.connectorId === id ? state2.confirming : null;\n const oauthConfirm = confirming && confirming.action !== \"credential_remove\" ? confirming : null;\n const statusLabel = local ? \"Couldn't load\" : connectorStatusLabel(connector.status, connector.problem);\n const fixKind = problem && connector.problem && problemTone(connector.problem) === \"danger\" && connector.problem !== connector.credential?.problem ? connector.problem : null;\n const statusTone = local ? \"warn\" : connectorStatusTone(connector.status);\n return /* @__PURE__ */ u3(\"div\", { class: shown ? \"conn open\" : \"conn\", \"data-connector\": id, children: [\n /* @__PURE__ */ u3(\"div\", { class: \"conn-head\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"conn-main\", children: [\n /* @__PURE__ */ u3(\"span\", { class: `dot ${local ? \"warn\" : connector.status}`, \"aria-hidden\": \"true\" }),\n /* @__PURE__ */ u3(\"h2\", { class: \"conn-name\", children: /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n id: `conn-toggle-${id}`,\n class: \"conn-toggle\",\n \"aria-expanded\": shown ? \"true\" : \"false\",\n \"aria-controls\": `conn-body-${id}`,\n \"aria-describedby\": `conn-state-${id}`,\n onClick: () => setOpen(!shown),\n children: name\n }\n ) }),\n connector.title ? /* @__PURE__ */ u3(\"span\", { class: \"conn-id mono\", children: id }) : null\n ] }),\n /* @__PURE__ */ u3(\"span\", { class: \"conn-badges\", id: `conn-state-${id}`, children: [\n drift === \"warning\" ? /* @__PURE__ */ u3(Badge, { tone: \"warn\", children: \"drift\" }) : null,\n /* @__PURE__ */ u3(Badge, { children: authScopeLabel(connector.authScope) }),\n /* @__PURE__ */ u3(Badge, { children: connector.status === \"loading\" ? \"tools not loaded\" : toolCountLabel(connector.toolCount) }),\n /* @__PURE__ */ u3(Badge, { tone: statusTone, children: statusLabel }),\n /* @__PURE__ */ u3(\"span\", { class: \"conn-caret\", \"aria-hidden\": \"true\" })\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"conn-body\", id: `conn-body-${id}`, hidden: !shown, children: [\n connector.description ? /* @__PURE__ */ u3(\"p\", { class: \"conn-note\", children: connector.description }) : null,\n problem && connector.problem ? /* @__PURE__ */ u3(\n \"p\",\n {\n class: problemTone(connector.problem) === \"warn\" ? \"msg warn\" : \"msg\",\n \"data-problem\": connector.problem,\n children: problem\n }\n ) : null,\n local ? /* @__PURE__ */ u3(\"p\", { class: \"msg warn\", \"data-load-failure\": local, children: connectorLoadFailureCopy(local, productName) }) : null,\n connector.authorizationUrl && !safeHttpHref(connector.authorizationUrl) ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: [\n \"Authorization URL: \",\n connector.authorizationUrl\n ] }) : null,\n manage ? null : /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: permissionLabel(connector) }),\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n local ? null : /* @__PURE__ */ u3(AuthActions, { connector, name, manage, state: state2 }),\n fixKind ? /* @__PURE__ */ u3(FixPromptButton, { kind: fixKind, connectorId: id, name }) : null,\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: local ? \"btn primary\" : \"btn quiet\",\n type: \"button\",\n \"aria-label\": `Refresh ${name}`,\n disabled: connector.status === \"loading\",\n onClick: () => void refreshConnector(id),\n children: \"Refresh\"\n }\n )\n ] }),\n fixKind ? /* @__PURE__ */ u3(FixPromptPreview, { kind: fixKind, connectorId: id, standalone: true }) : null,\n oauthConfirm ? /* @__PURE__ */ u3(\n ConfirmBar,\n {\n id,\n ...confirmCopy(oauthConfirm.action, name),\n onConfirm: () => {\n if (oauthConfirm.action === \"oauth_restart\") void startOAuth(id, \"restart\");\n else void disconnectOAuth(id);\n },\n onCancel: () => cancelConfirm(\n focusableId(\n oauthConfirm.action === \"oauth_restart\" ? `reconnect-${id}` : `disconnect-${id}`,\n `conn-toggle-${id}`\n )\n )\n }\n ) : null,\n /* @__PURE__ */ u3(\n NoticeLine,\n {\n id: `oauthNotice-${id}`,\n notice: state2.oauthNoticeFor === id ? state2.oauthNotice : null\n }\n ),\n connector.credential ? /* @__PURE__ */ u3(\n CredentialCard,\n {\n connector,\n credential: connector.credential,\n editing: state2.credentialEditing === id,\n busy: state2.credentialBusy === id,\n confirming: confirming?.action === \"credential_remove\",\n notice: state2.credentialNoticeFor === id ? state2.credentialNotice : null\n }\n ) : null,\n tools.length ? /* @__PURE__ */ u3(\"details\", { open: forceOpen, children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: [\n \"Tools (\",\n tools.length,\n \")\"\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"tool-list\", children: [\n tools.some((tool) => tool.safety) ? /* @__PURE__ */ u3(\"p\", { class: \"meta tool-legend\", children: \"Read-only tools run inside execute_code programs. Everything else asks the host first: a program pauses for resume_execution, and a direct call goes through call_destructive_tool — unless this deployment's config exempts the tool, in which case programs call it unasked.\" }) : null,\n tools.map((tool) => /* @__PURE__ */ u3(\"div\", { class: \"tool\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"tool-head\", children: [\n /* @__PURE__ */ u3(\"code\", { children: tool.address }),\n /* @__PURE__ */ u3(SafetyBadge, { safety: tool.safety })\n ] }),\n tool.description ? /* @__PURE__ */ u3(\"span\", { class: \"td\", children: tool.description }) : null\n ] }, tool.address))\n ] })\n ] }) : null,\n /* @__PURE__ */ u3(\"details\", { children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: \"Diagnostics\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"subcard\", children: [\n /* @__PURE__ */ u3(DriftPanel, { connector }),\n connector.catalogAccess ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: [\n \"Agents last read its catalog\",\n \" \",\n connector.catalogAccess.state === \"stale\" ? \"from a stale cache\" : \"fresh\",\n \" · \",\n formatDate(connector.catalogAccess.observedAt)\n ] }) : null\n ] })\n ] })\n ] })\n ] });\n }\n function Endpoints({\n pools,\n serverName\n }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"endpoints\", children: [\n /* @__PURE__ */ u3(\n Endpoint,\n {\n url: mcpUrl,\n name: clientServerName(serverName),\n primary: true,\n ...pools.length ? { label: \"All tools\" } : {}\n }\n ),\n pools.map((pool) => /* @__PURE__ */ u3(\n Endpoint,\n {\n url: poolEndpointUrl(mcpUrl, pool),\n name: clientServerName(serverName, pool),\n label: `Pool · ${pool}`\n },\n pool\n ))\n ] });\n }\n function SummaryLine({ connectors }) {\n const parts = connectorSummaryParts(summarizeConnectors(connectors));\n return /* @__PURE__ */ u3(\"p\", { class: \"summary\", id: \"connectorSummary\", children: parts.map((part, index) => /* @__PURE__ */ u3(\"span\", { children: [\n index > 0 ? /* @__PURE__ */ u3(\"span\", { class: \"sep\", children: \" · \" }) : null,\n /* @__PURE__ */ u3(\"span\", { class: part.tone === \"neutral\" ? \"\" : part.tone, children: part.text })\n ] }, part.text)) });\n }\n function ConnectionsPage({ state: state2 }) {\n const data = state2.data;\n const query = state2.connectorFilter.trim();\n const filtered = data ? filterUiConnectors(data.connectors, query) : [];\n return /* @__PURE__ */ u3(\"section\", { id: \"connectionsView\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"connectionsHeading\", tabIndex: -1, children: \"Connections\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { children: \"Point an MCP client at this endpoint to reach the tools below.\" }),\n /* @__PURE__ */ u3(Endpoints, { pools: data?.pools ?? [], serverName: data?.serverInfo?.name }),\n /* @__PURE__ */ u3(\"p\", { class: \"cap\", id: \"serverInfo\", children: data ? `${data.serverInfo?.name || productName} v${data.connectaVersion || \"?\"}` : productOperatorLabel }),\n data ? /* @__PURE__ */ u3(SummaryLine, { connectors: data.connectors }) : null\n ] })\n ] }),\n /* @__PURE__ */ u3(\"section\", { class: \"section\", \"aria-labelledby\": \"connectorLedgerHeading\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"section-head\", children: [\n /* @__PURE__ */ u3(\"h2\", { id: \"connectorLedgerHeading\", tabIndex: -1, children: \"Connectors\" }),\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"filter\",\n type: \"search\",\n class: \"filter\",\n placeholder: \"Filter connectors or tools…\",\n \"aria-label\": \"Filter connectors or tools\",\n value: state2.connectorFilter,\n disabled: !data,\n onInput: (event) => setConnectorFilter(event.currentTarget.value)\n }\n )\n ] }),\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"list\",\n class: !data || filtered.length === 0 ? \"\" : \"rows\",\n \"aria-busy\": state2.refreshing || !data && !state2.loadFailure ? \"true\" : \"false\",\n children: !data ? state2.loadFailure ? /* @__PURE__ */ u3(LoadFailure, { state: state2 }) : /* @__PURE__ */ u3(Empty, { children: \"Loading connectors…\" }) : filtered.length === 0 ? /* @__PURE__ */ u3(Empty, { children: query ? \"No connectors or tools match this filter.\" : \"No connectors are declared in this deployment.\" }) : filtered.map(({ connector, tools }) => /* @__PURE__ */ u3(\n ConnectorRow,\n {\n connector,\n tools,\n forceOpen: Boolean(query),\n state: state2\n },\n connector.id\n ))\n }\n )\n ] })\n ] });\n }\n\n // src/operator-ui/app/main.tsx\n function useOperatorState() {\n const [, bump] = y2((count) => count + 1, 0);\n const snapshot = getState();\n _2(() => {\n const unsubscribe = subscribe(() => bump(void 0));\n if (getState() !== snapshot) bump(void 0);\n return unsubscribe;\n }, []);\n return snapshot;\n }\n function visiblePages(state2) {\n const hint = state2.data ? null : navHint();\n return OPERATOR_PAGES.filter((page) => {\n if (page === \"tokens\") return state2.data?.accessTokenManagement === \"available\";\n if (page === \"activity\") return hint ? hint.activity : Boolean(state2.data?.activityEnabled);\n if (page === \"artifacts\") {\n return isArtifactPage(state2.page) || (hint ? hint.artifacts : Boolean(state2.data?.artifactsEnabled));\n }\n return true;\n });\n }\n function OperatorNav() {\n const state2 = useOperatorState();\n if (state2.session !== \"ready\") return null;\n const onArtifactPage = isArtifactPage(state2.page);\n return /* @__PURE__ */ u3(\"div\", { class: \"mast-actions\", children: [\n /* @__PURE__ */ u3(\"nav\", { class: \"page-nav\", \"aria-label\": \"Operator pages\", children: visiblePages(state2).map(\n (page) => (\n // Crossing between artifact pages and the rest is a full navigation:\n // with a dedicated artifact origin, the two live on different hosts.\n page === \"artifacts\" || onArtifactPage ? /* @__PURE__ */ u3(\n \"a\",\n {\n class: \"navlink\",\n href: page === \"artifacts\" ? PAGE_META.artifacts.path : new URL(PAGE_META[page].path, new URL(homeUrl, window.location.href)).href,\n ...state2.page === page ? { \"aria-current\": \"page\" } : {},\n children: PAGE_META[page].label\n },\n page\n ) : /* @__PURE__ */ u3(\n PageLink,\n {\n page,\n class: \"navlink\",\n current: state2.page === page,\n children: PAGE_META[page].label\n },\n page\n )\n )\n ) }),\n /* @__PURE__ */ u3(\"div\", { class: \"session-actions\", \"aria-label\": \"Session actions\", children: auth.kind === \"clerk\" || auth.kind === \"cloudflare-access\" ? /* @__PURE__ */ u3(\"button\", { class: \"navlink\", type: \"button\", onClick: signOut, children: \"Sign out\" }) : /* @__PURE__ */ u3(\"button\", { class: \"navlink\", type: \"button\", onClick: forgetBearer, children: \"Change token\" }) })\n ] });\n }\n function Gate({ state: state2 }) {\n const [token, setToken] = d2(\"\");\n const signedIn = auth.kind === \"clerk\" && Boolean(window.Clerk?.user);\n const loading = state2.session === \"loading\";\n return /* @__PURE__ */ u3(\"section\", { id: \"gate\", class: \"gate lead\", \"aria-busy\": loading ? \"true\" : \"false\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"gateHeading\", tabIndex: -1, children: PAGE_META[state2.page].label }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { children: pageDescription(state2.page, productDescription) }),\n loading ? /* @__PURE__ */ u3(StateBlock, { id: \"gateCopy\", children: checkingCopy(state2.page) }) : /* @__PURE__ */ u3(\"p\", { id: \"gateCopy\", class: \"meta\", children: gateCopy(auth.kind, signedIn) }),\n loading ? null : auth.kind === \"clerk\" ? /* @__PURE__ */ u3(\"div\", { id: \"clerkGate\", class: \"actions\", children: signedIn ? /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"button\", onClick: signOut, children: \"Sign out\" }) : /* @__PURE__ */ u3(\"button\", { id: \"signin\", class: \"btn primary\", type: \"button\", onClick: signIn, children: \"Team sign in\" }) }) : auth.kind === \"cloudflare-access\" ? /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: /* @__PURE__ */ u3(\"button\", { class: \"btn\", type: \"button\", onClick: signOut, children: \"Sign out of Cloudflare Access\" }) }) : /* @__PURE__ */ u3(\n \"form\",\n {\n id: \"tokenGate\",\n class: \"row gate-form\",\n onSubmit: (event) => {\n event.preventDefault();\n const value = token.trim();\n if (!value) return;\n setToken(\"\");\n signInWithBearer(value);\n },\n children: [\n /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"token\",\n type: \"password\",\n placeholder: \"Bearer token\",\n autocomplete: \"off\",\n \"aria-label\": \"Bearer token\",\n value: token,\n onInput: (event) => setToken(event.currentTarget.value)\n }\n ),\n /* @__PURE__ */ u3(\"button\", { id: \"save\", class: \"btn primary\", type: \"submit\", children: \"Open operator pages\" })\n ]\n }\n ),\n /* @__PURE__ */ u3(NoticeLine, { id: \"err\", notice: state2.gate, className: \"\" })\n ] })\n ] });\n }\n function CurrentPage({ state: state2 }) {\n if (state2.page === \"tokens\") return /* @__PURE__ */ u3(TokensPage, { state: state2 });\n if (state2.page === \"activity\") return /* @__PURE__ */ u3(ActivityPage, { state: state2 });\n if (state2.page === \"artifacts\") return /* @__PURE__ */ u3(ArtifactsPage, { state: state2 });\n if (state2.page === \"artifact\") return /* @__PURE__ */ u3(ArtifactPage, { state: state2 });\n return /* @__PURE__ */ u3(ConnectionsPage, { state: state2 });\n }\n function OperatorApp() {\n const state2 = useOperatorState();\n const ready = state2.session === \"ready\";\n h2(() => {\n const label = state2.page === \"artifact\" && state2.artifactView ? state2.artifactView.title : PAGE_META[state2.page].label;\n document.title = `${label} — ${titleSuffix}`;\n }, [state2.page, state2.artifactView]);\n h2(() => {\n if (!ready) return;\n if (state2.page === \"tokens\" && state2.data?.accessTokenManagement === \"available\" && state2.tokenPhase === \"idle\") {\n void loadAccessTokens();\n }\n if (state2.page === \"activity\" && state2.data?.activityEnabled && state2.activityPhase === \"idle\") {\n void loadActivity(true);\n }\n });\n h2(() => {\n if (!state2.pendingFocus && !state2.focusIfLost) return;\n if (state2.pendingFocus) {\n document.getElementById(state2.pendingFocus)?.focus();\n } else if (state2.focusIfLost) {\n const active = document.activeElement;\n const lost = !active || active === document.body || !active.isConnected || active.disabled === true;\n if (lost) document.getElementById(state2.focusIfLost)?.focus();\n }\n focusHandled();\n }, [state2.pendingFocus, state2.focusIfLost]);\n return ready ? /* @__PURE__ */ u3(\"div\", { id: \"app\", children: /* @__PURE__ */ u3(CurrentPage, { state: state2 }) }) : /* @__PURE__ */ u3(Gate, { state: state2 });\n }\n function mount(id, view) {\n const host = document.getElementById(id);\n if (!host) return;\n host.textContent = \"\";\n R(view, host);\n }\n mount(\"operatorNav\", /* @__PURE__ */ u3(OperatorNav, {}));\n mount(\"operatorContent\", /* @__PURE__ */ u3(OperatorApp, {}));\n void boot();\n})();\n"; diff --git a/src/registry.ts b/src/registry.ts index 74be3f3c..71b67e69 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -612,17 +612,24 @@ export class Registry implements RegistryView { principalKey: string, ): Promise { const key = this.oauthHandoffKey(connectorId, await sha256Hex(state)); - const existing = await this.opts.storage.get(key); - if (existing && existing !== principalKey) { - throw new Error( - `Connector "${connectorId}" reused one OAuth state across principals`, - ); + for (let attempt = 0; attempt < 32; attempt++) { + const existing = await this.opts.storage.get(key); + if (existing && existing !== principalKey) { + throw new Error( + `Connector "${connectorId}" reused one OAuth state across principals`, + ); + } + const expiry = { ttlSeconds: OAUTH_HANDOFF_TTL_SECONDS }; + if (this.opts.storage.compareAndSet) { + // Bind ownership atomically, including renewal of the same owner's + // handoff. Two owners reading a miss must not overwrite each other. + if (!await this.opts.storage.compareAndSet(key, existing, principalKey, expiry)) continue; + } else { + await this.opts.storage.set(key, principalKey, expiry); + } + return; } - await this.opts.storage.set( - key, - principalKey, - { ttlSeconds: OAUTH_HANDOFF_TTL_SECONDS }, - ); + throw new Error(`OAuth handoff for "${connectorId}" is busy; retry authorization`); } async oauthCallbackView( diff --git a/src/routes/credentials.ts b/src/routes/credentials.ts index 59a4c596..adae4e6a 100644 --- a/src/routes/credentials.ts +++ b/src/routes/credentials.ts @@ -1,4 +1,5 @@ import { Effect } from "effect"; +import { closeConnectorScope } from "../connector-scope.js"; import { credentialTestRule, describeCredentialTestMismatch, @@ -210,17 +211,21 @@ function credentialRequest( } const storedValues = values!; const ctx = registry.contextFor(connectorId, baseUrl); - const result = - mode === "multiple" - ? await connector.testCredentials!(storedValues, ctx) - : await connector.testCredential!( - // The single-value shape check above guarantees this key. - storedValues.value!, - ctx, - ); - const ok = result?.ok === true; - logged(ok, result?.message); - return privateJson({ ok }); + try { + const result = + mode === "multiple" + ? await connector.testCredentials!(storedValues, ctx) + : await connector.testCredential!( + // The single-value shape check above guarantees this key. + storedValues.value!, + ctx, + ); + const ok = result?.ok === true; + logged(ok, result?.message); + return privateJson({ ok }); + } finally { + await closeConnectorScope(connector, ctx, context.defer); + } }, catch: (error) => error, }).pipe( diff --git a/src/routes/oauth.ts b/src/routes/oauth.ts index da4af257..7af93d39 100644 --- a/src/routes/oauth.ts +++ b/src/routes/oauth.ts @@ -1,4 +1,5 @@ import { Effect } from "effect"; +import { closeConnectorScope } from "../connector-scope.js"; import { oauthValueStorageKey } from "../auth/downstream-oauth.js"; import type { ConnectorContext } from "../types.js"; import { escapeHtml, renderPage, resolveBranding, STATUS_ICONS } from "../branding.js"; @@ -157,79 +158,83 @@ async function finishOAuthCallback( await equalizeRefusalCost(connectorContext); return refused(); } - const expectedPrincipalKey = callbackTarget?.principalKey; - // A browser returning from consent normally has no MCP Authorization - // header. An interactive bearer provider therefore answers 401 here; state - // and the saved state-to-principal handoff still prove ownership below. - // Rejecting 401 would break that callback. A 403 is an explicit denial. - const browserIdentity = await authorizeUiIdentity(context.request, baseUrl, opts.auth, "OAuth callback", context.runtimeContext, opts.identity); - if (browserIdentity.ok) { - try { validateAuthPermissions(browserIdentity, opts.registry); } catch { return refused(); } - if (!mayManageConnector(browserIdentity, connector) || (expectedPrincipalKey && browserIdentity.principalKey !== expectedPrincipalKey)) return refused(); - } else if (browserIdentity.response.status === 403 && opts.auth.some(provider => provider.interactiveOperator)) { - return refused(); - } - // CSRF / login-fixation guard: this route is intentionally public, so verify - // the `state` matches the flow connecta started BEFORE exchanging the code. - if (!connector.verifyState) { - await equalizeRefusalCost(connectorContext); - opts.logger.warn( - `[connecta] refused an OAuth callback for connector ` + - `${loggableValue(id)} with 400: it implements finishAuth but no ` + - "verifyState, so connecta cannot establish that it started this flow. " + - "No authorization code was exchanged. Implement verifyState before " + - "trying again.", - ); - return refused(); - } - let stateMatches: boolean; try { - stateMatches = await connector.verifyState(state, connectorContext); - } catch (err) { - opts.logger.warn( - `[connecta] refused an OAuth callback for connector ` + - `${loggableValue(id)} with 400: verifyState threw ` + - `${loggableValue(msg(err))}. No authorization code was exchanged. ` + - "Re-run authorization from connecta and check the verifier if it " + - "fails again.", - ); - return refused(); - } - if (!stateMatches) { - opts.logger.warn( - `[connecta] refused an OAuth callback for connector ` + - `${loggableValue(id)} with 400: ` + - (state === null - ? "the state parameter was missing" - : "the state did not match the pending authorization flow") + - ". No authorization code was exchanged. Re-run authorization from " + - "connecta and try again.", - ); - return refused(); - } - if (connector.authScope === "personal") { + const expectedPrincipalKey = callbackTarget?.principalKey; + // A browser returning from consent normally has no MCP Authorization + // header. An interactive bearer provider therefore answers 401 here; state + // and the saved state-to-principal handoff still prove ownership below. + // Rejecting 401 would break that callback. A 403 is an explicit denial. + const browserIdentity = await authorizeUiIdentity(context.request, baseUrl, opts.auth, "OAuth callback", context.runtimeContext, opts.identity); + if (browserIdentity.ok) { + try { validateAuthPermissions(browserIdentity, opts.registry); } catch { return refused(); } + if (!mayManageConnector(browserIdentity, connector) || (expectedPrincipalKey && browserIdentity.principalKey !== expectedPrincipalKey)) return refused(); + } else if (browserIdentity.response.status === 403 && opts.auth.some(provider => provider.interactiveOperator)) { + return refused(); + } + // CSRF / login-fixation guard: this route is intentionally public, so verify + // the `state` matches the flow connecta started BEFORE exchanging the code. + if (!connector.verifyState) { + await equalizeRefusalCost(connectorContext); + opts.logger.warn( + `[connecta] refused an OAuth callback for connector ` + + `${loggableValue(id)} with 400: it implements finishAuth but no ` + + "verifyState, so connecta cannot establish that it started this flow. " + + "No authorization code was exchanged. Implement verifyState before " + + "trying again.", + ); + return refused(); + } + let stateMatches: boolean; try { - await opts.registry.clearOAuthHandoff(id, state); + stateMatches = await connector.verifyState(state, connectorContext); } catch (err) { opts.logger.warn( `[connecta] refused an OAuth callback for connector ` + - `${loggableValue(id)} with 500: its principal handoff could not be ` + - `consumed (${loggableValue(msg(err))}). No authorization code was exchanged.`, + `${loggableValue(id)} with 400: verifyState threw ` + + `${loggableValue(msg(err))}. No authorization code was exchanged. ` + + "Re-run authorization from connecta and check the verifier if it " + + "fails again.", ); - return html("handoff_failed", opts, connector); + return refused(); } - } - try { - await connector.finishAuth(code, connectorContext, url.searchParams); - await callbackRegistry!.invalidateStored(id); - return html("connected", opts, connector); - } catch (err) { - // The page names the reason and nothing else; what the exchange threw can - // quote a token endpoint's body, so it goes only to the operator log. - opts.logger.warn( - `[connecta] OAuth callback for connector ${loggableValue(id)} failed ` + - `with 500: the authorization code exchange threw ${loggableValue(msg(err))}.`, - ); - return html("exchange_failed", opts, connector); + if (!stateMatches) { + opts.logger.warn( + `[connecta] refused an OAuth callback for connector ` + + `${loggableValue(id)} with 400: ` + + (state === null + ? "the state parameter was missing" + : "the state did not match the pending authorization flow") + + ". No authorization code was exchanged. Re-run authorization from " + + "connecta and try again.", + ); + return refused(); + } + if (connector.authScope === "personal") { + try { + await opts.registry.clearOAuthHandoff(id, state); + } catch (err) { + opts.logger.warn( + `[connecta] refused an OAuth callback for connector ` + + `${loggableValue(id)} with 500: its principal handoff could not be ` + + `consumed (${loggableValue(msg(err))}). No authorization code was exchanged.`, + ); + return html("handoff_failed", opts, connector); + } + } + try { + await connector.finishAuth(code, connectorContext, url.searchParams); + await callbackRegistry!.invalidateStored(id); + return html("connected", opts, connector); + } catch (err) { + // The page names the reason and nothing else; what the exchange threw can + // quote a token endpoint's body, so it goes only to the operator log. + opts.logger.warn( + `[connecta] OAuth callback for connector ${loggableValue(id)} failed ` + + `with 500: the authorization code exchange threw ${loggableValue(msg(err))}.`, + ); + return html("exchange_failed", opts, connector); + } + } finally { + await closeConnectorScope(connector, connectorContext, context.defer); } } diff --git a/src/runtime/run.ts b/src/runtime/run.ts index ea24fe64..3b5cc4ee 100644 --- a/src/runtime/run.ts +++ b/src/runtime/run.ts @@ -51,7 +51,9 @@ const runExit = Effect.runPromiseExitWith( ); function abortReason(signal: AbortSignal | undefined): unknown { - return signal?.reason ?? new DOMException("aborted", "AbortError"); + return signal && signal.reason !== undefined + ? signal.reason + : new DOMException("aborted", "AbortError"); } /** @@ -211,6 +213,9 @@ export function withDeadlineEffect( options: DeadlineOptions, ): Effect.Effect { return Effect.suspend(() => { + // Do not dispatch work that already lost its caller. The operation is the + // first race contender and can finish before the abort contender starts. + if (options.signal?.aborted) return Effect.fail(abortReason(options.signal)); const controller = new AbortController(); const forwardAbort = () => controller.abort(options.signal?.reason); options.signal?.addEventListener("abort", forwardAbort, { once: true }); diff --git a/src/storage/memory.ts b/src/storage/memory.ts index 6ed9f833..47624118 100644 --- a/src/storage/memory.ts +++ b/src/storage/memory.ts @@ -19,6 +19,13 @@ export function memoryStorage(): KVStorage { return e; }; const write = (key: string, value: string, ttlSeconds?: number) => { + if (ttlSeconds !== undefined && !Number.isFinite(ttlSeconds)) { + throw new RangeError("ttlSeconds must produce a finite expiration timestamp"); + } + const exp = ttlSeconds ? Date.now() + ttlSeconds * 1000 : undefined; + if (exp !== undefined && !Number.isFinite(exp)) { + throw new RangeError("ttlSeconds must produce a finite expiration timestamp"); + } // Rotate through at most 16 existing keys. Live entries cannot keep an // expired tail resident forever, and no request starts a background job. for (let i = 0; i < 16; i++) { @@ -28,7 +35,7 @@ export function memoryStorage(): KVStorage { } map.set(key, { value, - ...(ttlSeconds ? { exp: Date.now() + ttlSeconds * 1000 } : {}), + ...(exp !== undefined ? { exp } : {}), }); }; return { diff --git a/test/browser/operator-ui.spec.ts b/test/browser/operator-ui.spec.ts index 739c04fc..a907c3f2 100644 --- a/test/browser/operator-ui.spec.ts +++ b/test/browser/operator-ui.spec.ts @@ -641,6 +641,22 @@ test("navigates to the activity list and back without a shell reload", async ({ await expect(page.getByRole("heading", { name: "Connections" })).toBeVisible(); }); +for (const body of ["truncated JSON", "null", "{}"]) { + test(`offers Activity retry after an unreadable successful response: ${body}`, async ({ page }) => { + await page.route("**/ui/activity?**", route => route.fulfill({ + status: 200, contentType: "application/json", body, + })); + await openAuthenticated(page); + await page.getByRole("link", { name: "Activity" }).click(); + await expect(page.locator("#activityError")).toContainText("Activity couldn't be loaded"); + await expect(page.getByText("No connector tool calls recorded yet.", { exact: true })).toHaveCount(0); + await page.unroute("**/ui/activity?**"); + await page.getByRole("button", { name: "Retry", exact: true }).click(); + await expect(page.locator("#activityList").getByText("oauth.contacts")).toBeVisible(); + await expect(page.locator("#activityError")).toHaveCount(0); + }); +} + test("names the empty state of every collection a new deployment has", async ({ page, }) => { diff --git a/test/d1-storage-example.test.ts b/test/d1-storage-example.test.ts index 412df7e5..845e302d 100644 --- a/test/d1-storage-example.test.ts +++ b/test/d1-storage-example.test.ts @@ -93,6 +93,15 @@ describe("Worker example D1 storage", () => { expect(await storage.list?.("a_")).toEqual(["a_b"]); }); + it("matches embedded NUL bytes in list prefixes literally", async () => { + const storage = await open(); + await storage.set("a\0b:one", "1"); + await storage.set("a\0c:two", "2"); + await storage.set("a:other", "3"); + expect(await storage.list?.("a\0b:")).toEqual(["a\0b:one"]); + expect(await storage.list?.("a\0")).toEqual(["a\0b:one", "a\0c:two"]); + }); + it("removes expired rows physically on a later write", async () => { const storage = await open(); await storage.set("old", "v", { ttlSeconds: -1 }); diff --git a/test/downstream-oauth.test.ts b/test/downstream-oauth.test.ts index f7cf7e06..034e18ff 100644 --- a/test/downstream-oauth.test.ts +++ b/test/downstream-oauth.test.ts @@ -5360,6 +5360,35 @@ describe("/oauth/callback/ route", () => { return { connecta, storage }; } + it.each(["connected", "mismatch", "verify failure", "exchange failure"])( + "closes the callback's connector scope after %s", + async outcome => { + let active = 0; + let opened: ConnectorContext | undefined; + const closeScope = vi.fn(async (ctx: ConnectorContext) => { + expect(ctx).toBe(opened); + active--; + throw new Error("cleanup failed"); + }); + const connector = callbackConnector("svc", async () => { + if (outcome === "exchange failure") throw new Error("exchange failed"); + }, async (_state, ctx) => { + opened = ctx; + active++; + if (outcome === "verify failure") throw new Error("verification failed"); + return outcome !== "mismatch"; + }); + connector.closeScope = closeScope; + const connecta = createTestConnecta({ publicUrl: BASE, logger: silentLogger, connectors: [connector] }); + const response = await connecta.fetch(new Request( + `${BASE}/oauth/callback/svc?code=abc&state=verified-state`, + )); + expect(response.status).toBe(outcome === "connected" ? 200 : outcome === "exchange failure" ? 500 : 400); + expect(closeScope).toHaveBeenCalledTimes(1); + expect(active).toBe(0); + }, + ); + it("matching state + code → 200 'Connected' and calls finishAuth", async () => { const spy = vi.fn(); const { connecta, storage } = makeConnecta(spy); diff --git a/test/execute.test.ts b/test/execute.test.ts index 9bed1dd9..98417735 100644 --- a/test/execute.test.ts +++ b/test/execute.test.ts @@ -26,6 +26,7 @@ import type { AdmittingExecutor, Connector, Executor, + ExecuteResult, ExecutorLease, ExecutorProvider, } from "../src/types.js"; @@ -1943,6 +1944,25 @@ describe("execute_code handler", () => { expect(required(out.content[0]).text).toContain("step 1"); }); + it.each([null, undefined, 42, [], { result: undefined, error: 42 }])( + "reports a malformed executor reply as a structured failure: %j", + async (reply) => { + const handler = createExecuteTool( + makeRegistry([calcConnector]), + BASE, + { execute: async () => reply as unknown as ExecuteResult }, + silentLogger, + ); + const out = await handler({ code: "async () => 1", diagnostics: true }); + expect(out.isError).toBe(true); + expect(out.structuredContent).toMatchObject({ + error: { code: "executor_failed", retryable: false }, + diagnostics: { operations: [] }, + }); + expect(required(out.content[0]).text).toContain("ExecuteResult"); + }, + ); + it("turns an unserializable result into a structured error, keeping logs", async () => { const registry = makeRegistry([calcConnector]); const executor = fakeExecutor({ result: 1000n, logs: ["computed"] }); diff --git a/test/operator-store.test.ts b/test/operator-store.test.ts index 987d6a37..61298136 100644 --- a/test/operator-store.test.ts +++ b/test/operator-store.test.ts @@ -607,3 +607,38 @@ describe("operator unreadable collections", () => { expect(store.getState().tokens[0]?.id).toBe("recovered"); }); }); + + +describe("activity collection recovery", () => { + it.each(["truncated JSON", "null", "{}"])("offers retry for an unreadable activity page: %s", async body => { + const { store, fetchMock } = await loadStore({ id: "session", getToken: async () => "token" }); + fetchMock.mockResolvedValueOnce(Response.json(uiData("operator"))); + await store.boot(); + fetchMock.mockResolvedValueOnce(new Response(body, { status: 200 })); + await store.loadActivity(true); + expect(store.getState().activityPhase).toBe("error"); + expect(store.getState().activityNotice?.tone).toBe("error"); + fetchMock.mockResolvedValueOnce(Response.json({ events: [{ connectorId: "recovered" }] })); + await store.loadActivity(true); + expect(store.getState().activityPhase).toBe("ready"); + expect(store.getState().activityEvents).toEqual([{ connectorId: "recovered" }]); + }); + + it("drops an older pagination response after a collection reset", async () => { + const { store, fetchMock } = await loadStore({ id: "session", getToken: async () => "token" }); + fetchMock.mockResolvedValueOnce(Response.json(uiData("operator"))); + await store.boot(); + fetchMock.mockResolvedValueOnce(Response.json({ events: [{ connectorId: "initial" }], nextCursor: "page-two" })); + await store.loadActivity(true); + const old = deferred(); + fetchMock.mockReturnValueOnce(old.promise); + const pagination = store.loadActivity(false); + await vi.waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(3)); + fetchMock.mockResolvedValueOnce(Response.json({ events: [{ connectorId: "fresh" }], nextCursor: "fresh-cursor" })); + await store.loadActivity(true); + old.resolve(Response.json({ events: [{ connectorId: "old-page-two" }], nextCursor: "old-cursor" })); + await pagination; + expect(store.getState().activityEvents).toEqual([{ connectorId: "fresh" }]); + expect(store.getState().activityCursor).toBe("fresh-cursor"); + }); +}); diff --git a/test/registry.test.ts b/test/registry.test.ts index 089df937..a5340d99 100644 --- a/test/registry.test.ts +++ b/test/registry.test.ts @@ -68,6 +68,40 @@ describe("Registry construction", () => { }); }); +describe("personal OAuth handoffs", () => { + it("refuses concurrent reuse of one state by different owners", async () => { + const backing = memoryStorage(); + let reads = 0; + let release!: () => void; + const bothRead = new Promise(resolve => { release = resolve; }); + const storage: KVStorage = { + ...backing, + async get(key) { + const value = await backing.get(key); + if (key.startsWith("oauth-handoff:") && reads < 2) { + if (++reads === 2) release(); + await bothRead; + } + return value; + }, + }; + const registry = new Registry([{ ...calcConnector, authScope: "personal" }], { + storage, logger: silentLogger, + }); + const results = await Promise.allSettled([ + registry.storeOAuthHandoff("calc", "reused-state", "alice"), + registry.storeOAuthHandoff("calc", "reused-state", "bob"), + ]); + expect(results.filter(result => result.status === "fulfilled")).toHaveLength(1); + const failure = results.find(result => result.status === "rejected") as PromiseRejectedResult; + expect(failure.reason.message).toContain("reused one OAuth state across principals"); + const winner = results[0]?.status === "fulfilled" ? "alice" : "bob"; + expect((await registry.oauthCallbackView("calc", "reused-state"))?.principalKey).toBe(winner); + await registry.storeOAuthHandoff("calc", "reused-state", winner); + expect((await registry.oauthCallbackView("calc", "reused-state"))?.principalKey).toBe(winner); + }); +}); + describe("startup convention warnings", () => { function spyLogger(): { logger: Logger; warnings: string[] } { const warnings: string[] = []; diff --git a/test/runtime.test.ts b/test/runtime.test.ts index 3639ba56..035a5af8 100644 --- a/test/runtime.test.ts +++ b/test/runtime.test.ts @@ -76,6 +76,14 @@ describe("runEdge", () => { ).rejects.toBe(reason); }); + it("preserves an explicit null abort reason on interruption", async () => { + const controller = new AbortController(); + const running = runEdge(Effect.never, { signal: controller.signal }); + await drainMicrotasks(); + controller.abort(null); + await expect(running).rejects.toBeNull(); + }); + it("prefers the abort reason over a failure raised while interrupted", async () => { const controller = new AbortController(); const reason = new LabelledError("caller left"); @@ -159,6 +167,10 @@ describe("fromSignal", () => { ); }); + it("preserves an explicit null abort reason", async () => { + await expect(runEdge(fromSignal(AbortSignal.abort(null)))).rejects.toBeNull(); + }); + it("lets the work win a race against a signal that never aborts", async () => { const controller = new AbortController(); await expect( @@ -247,6 +259,18 @@ describe("withDeadlineEffect", () => { ).rejects.toBe(reason); }); + it("does not start an operation after its caller has already aborted", async () => { + const reason = new LabelledError("caller left before dispatch"); + const operation = vi.fn(() => Effect.succeed("dispatched")); + await expect( + runEdge(withDeadlineEffect(operation, { + signal: AbortSignal.abort(reason), + timeoutError: new Error("unused"), + })), + ).rejects.toBe(reason); + expect(operation).not.toHaveBeenCalled(); + }); + it("passes the operation's own failure through untouched", async () => { const error = new LabelledError("downstream 500"); await expect( diff --git a/test/storage-contract.ts b/test/storage-contract.ts index 3f02c70c..42c9bd16 100644 --- a/test/storage-contract.ts +++ b/test/storage-contract.ts @@ -113,6 +113,19 @@ export function compareAndSetContract( expect(await storage.compareAndSet("lease", null, "next")).toBe(true); }); + it("refuses non-finite or overflowing TTLs without changing a live value", async () => { + const storage = await open(); + for (const ttlSeconds of [Number.NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.MAX_VALUE]) { + await storage.set("ttl", "original"); + await expect(storage.set("ttl", "replacement", { ttlSeconds })).rejects.toThrow(); + expect(await storage.get("ttl")).toBe("original"); + await expect(storage.compareAndSet("ttl", "original", "replacement", { ttlSeconds })).rejects.toThrow(); + expect(await storage.get("ttl")).toBe("original"); + } + expect(await storage.compareAndSet("ttl", "different", "replacement", { ttlSeconds: Number.NaN })).toBe(false); + expect(await storage.compareAndSet("ttl", "original", null, { ttlSeconds: Number.NaN })).toBe(true); + }); + it("replaces the previous expiry exactly as set would", async () => { const advance = fakeClock(); const storage = await open(); diff --git a/test/ui-credentials.test.ts b/test/ui-credentials.test.ts index 175986d1..80aaaf94 100644 --- a/test/ui-credentials.test.ts +++ b/test/ui-credentials.test.ts @@ -3,6 +3,7 @@ import { CredentialVault } from "../src/credentials.js"; import { encryptedCredentialVault } from "../src/credentials.js"; import { describe, expect, it, vi } from "vitest"; import { api } from "../src/connectors/api.js"; +import type { ConnectorContext } from "../src/types.js"; import { bearerToken } from "../src/auth/bearer.js"; import { STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR, @@ -26,6 +27,35 @@ import { } from "./fixtures/ui.js"; describe("status UI credential management", () => { + it.each([false, true])("closes the credential test scope when the hook throws=%s", async throws => { + const storage = memoryStorage(); + await new CredentialVault(storage, CREDENTIAL_KEY).set("key", "test-secret", "operator"); + let active = 0; + const testCredential = vi.fn(async (_value: string, _ctx: ConnectorContext) => { + active++; + if (throws) throw new Error("test failed"); + return { ok: true }; + }); + const closeScope = vi.fn(async () => { + active--; + throw new Error("cleanup failed"); + }); + const connector = { ...credentialConnector(), id: "key", testCredential, closeScope }; + const connecta = createTestConnecta({ + connectors: [connector], + auth: [bearerToken(TOKEN), fakeClerkAuth(CLERK_OPTIONS)], + storage, + publicUrl: BASE, + vault: encryptedCredentialVault(storage, CREDENTIAL_KEY), + }); + const response = await credentialRequest(connecta, "/ui/credentials/key/test", { method: "POST" }); + expect(response.status).toBe(200); + expect(await response.json()).toEqual({ ok: !throws }); + expect(closeScope).toHaveBeenCalledTimes(1); + expect(closeScope).toHaveBeenCalledWith(testCredential.mock.calls[0]?.[1]); + expect(active).toBe(0); + }); + it("keeps a stored superset usable, testable, and flagged as leftover", async () => { // The redeploy issue #79's review probed: the connector used to declare // { email, apiKey } and now declares only { apiKey }. The stored secret From 894fd4911460b97a22035ab25a996e366b5a1b51 Mon Sep 17 00:00:00 2001 From: Zackery Bartolome Date: Thu, 1 Oct 2026 12:52:18 -0400 Subject: [PATCH 2/2] Give credential routes sole cleanup ownership for their scopes (#664) --- src/connector-scope.ts | 31 ++++++++++++++++ src/connectors/remote-mcp.ts | 7 ++-- src/routes/credentials.ts | 4 ++- test/remote-mcp-credential.test.ts | 57 ++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/src/connector-scope.ts b/src/connector-scope.ts index 1b4b1ae4..ea4fcbb2 100644 --- a/src/connector-scope.ts +++ b/src/connector-scope.ts @@ -2,6 +2,37 @@ import type { Connector, ConnectorContext } from "./types.js"; import { closeScope } from "./runtime/connector-scope.js"; import { runEdge } from "./runtime/run.js"; +// Internal ownership for credential probes invoked by a route. Context copies +// keep the requestScope, and each connector retains its own cleanup ownership. +// Standalone connector tests still close themselves. +const cleanupOwners = new WeakMap>(); + +export function claimConnectorScopeCleanup( + ctx: ConnectorContext, + connectorId: string, +): () => void { + const scope = ctx.requestScope ?? ctx; + let owners = cleanupOwners.get(scope); + if (!owners) cleanupOwners.set(scope, owners = new Map()); + owners.set(connectorId, (owners.get(connectorId) ?? 0) + 1); + let released = false; + return () => { + if (released) return; + released = true; + const remaining = owners.get(connectorId)! - 1; + if (remaining) owners.set(connectorId, remaining); + else owners.delete(connectorId); + if (!owners.size) cleanupOwners.delete(scope); + }; +} + +export function connectorScopeCleanupClaimed( + ctx: ConnectorContext, + connectorId: string, +): boolean { + return cleanupOwners.get(ctx.requestScope ?? ctx)?.has(connectorId) === true; +} + /** Runtime hook for work that may safely continue after a response is ready. */ export type DeferredWork = (promise: Promise) => void; diff --git a/src/connectors/remote-mcp.ts b/src/connectors/remote-mcp.ts index c9df92e8..2e6d3dd9 100644 --- a/src/connectors/remote-mcp.ts +++ b/src/connectors/remote-mcp.ts @@ -21,6 +21,7 @@ import { } from "../auth/downstream-oauth.js"; import { trackOAuthStartReset } from "../auth/oauth-start-reset.js"; import { MAX_CATALOG_TOOLS } from "../catalog-limits.js"; +import { connectorScopeCleanupClaimed } from "../connector-scope.js"; import { boundedEchoText, ConnectorCallError, @@ -1402,9 +1403,9 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector { } catch (err) { return { ok: false, message: msg(err) }; } finally { - // A test owns the scope it just opened; leaving the session for - // the downstream to age out is not this button's to spend. - await connector.closeScope?.(ctx); + // Standalone tests own their scope; an operator route owns + // bounded teardown for the context it supplied to this hook. + if (!connectorScopeCleanupClaimed(ctx, id)) await connector.closeScope?.(ctx); } }, } diff --git a/src/routes/credentials.ts b/src/routes/credentials.ts index adae4e6a..218b669e 100644 --- a/src/routes/credentials.ts +++ b/src/routes/credentials.ts @@ -1,5 +1,5 @@ import { Effect } from "effect"; -import { closeConnectorScope } from "../connector-scope.js"; +import { claimConnectorScopeCleanup, closeConnectorScope } from "../connector-scope.js"; import { credentialTestRule, describeCredentialTestMismatch, @@ -211,6 +211,7 @@ function credentialRequest( } const storedValues = values!; const ctx = registry.contextFor(connectorId, baseUrl); + const releaseCleanup = claimConnectorScopeCleanup(ctx, connectorId); try { const result = mode === "multiple" @@ -224,6 +225,7 @@ function credentialRequest( logged(ok, result?.message); return privateJson({ ok }); } finally { + releaseCleanup(); await closeConnectorScope(connector, ctx, context.defer); } }, diff --git a/test/remote-mcp-credential.test.ts b/test/remote-mcp-credential.test.ts index 2667f7a4..b1ba6938 100644 --- a/test/remote-mcp-credential.test.ts +++ b/test/remote-mcp-credential.test.ts @@ -535,6 +535,63 @@ describe("remoteMcp() credential auth — a value a header cannot carry", () => }); describe("remoteMcp() credential auth — the Test action", () => { + it.each([ + [true, "resolved", false], [true, "rejected", false], [true, "pending", false], + [false, "resolved", false], [false, "rejected", false], [false, "pending", false], + [true, "resolved", true], [true, "rejected", true], [true, "pending", true], + [false, "resolved", true], [false, "rejected", true], [false, "pending", true], + ] as const)("operator Test preserves ok=%s with one bounded %s cleanup, cloned context=%s", async (ok, cleanup, cloneContext) => { + const captured = serveDownstream(); + if (!ok) vi.stubGlobal("fetch", async () => new Response("nope", { status: 500 })); + const connector = remoteMcp("down", { + url: URL_UNDER_TEST, + auth: { type: "credential" }, + }); + const close = connector.closeScope!.bind(connector); + let release!: () => void; + const pending = new Promise(resolve => { release = resolve; }); + const closeScope = vi.fn(async (ctx: ConnectorContext) => { + await close(ctx); + if (cleanup === "rejected") throw new Error("cleanup failed"); + if (cleanup === "pending") await pending; + }); + connector.closeScope = closeScope; + if (cloneContext) { + const testCredential = connector.testCredential!; + connector.testCredential = (value, ctx) => testCredential(value, { ...ctx }); + } + const storage = memoryStorage(); + const vault = new CredentialVault(storage, CREDENTIAL_KEY); + await vault.set("down", "stored-secret", "operator"); + const connecta = createTestConnecta({ + connectors: [connector], storage, vault, publicUrl: BASE, logger: silentLogger, + auth: { + kind: "operator", interactiveOperator: true, activityActorNamespace: "test", + authorize: () => ({ ok: true, userId: "operator" }), + }, + }); + const response = connecta.fetch(new Request(`${BASE}/ui/credentials/down/test`, { + method: "POST", headers: { Origin: BASE }, + })); + let timer: ReturnType | undefined; + try { + const result = await Promise.race([ + response, + new Promise(resolve => { timer = setTimeout(() => resolve(undefined), 1_000); }), + ]); + expect(result, "cleanup must finish within the route's bounded window").toBeDefined(); + expect(result!.status).toBe(200); + expect(await result!.json()).toEqual({ ok }); + expect(closeScope).toHaveBeenCalledTimes(1); + if (ok) expect(sessionOpenAuthorizations(captured)).toEqual(["Bearer stored-secret"]); + await expect(connector.listTools(closeScope.mock.calls[0]![0])).rejects.toThrow("scope ended"); + } finally { + clearTimeout(timer); + release(); + await response; + } + }); + it("reports the catalog the stored credential reaches, and closes its scope", async () => { serveDownstream(); const connector = remoteMcp("down", {