@zackbart/connecta 0.24.2 → 0.24.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -20
- package/CHANGELOG.md +205 -1
- package/README.md +5 -6
- package/dist/auth/bearer.js +2 -0
- package/dist/auth/downstream-oauth.d.ts +12 -1
- package/dist/auth/downstream-oauth.js +147 -35
- package/dist/branding.d.ts +31 -2
- package/dist/branding.js +116 -8
- package/dist/call-admission.d.ts +4 -0
- package/dist/call-admission.js +26 -0
- package/dist/catalog-drift.js +9 -4
- package/dist/catalog-service.d.ts +2 -0
- package/dist/catalog-service.js +25 -8
- package/dist/catalog.d.ts +2 -0
- package/dist/catalog.js +246 -121
- package/dist/connectors/api.d.ts +1 -1
- package/dist/connectors/api.js +21 -3
- package/dist/connectors/guarded-fetch.d.ts +6 -2
- package/dist/connectors/guarded-fetch.js +61 -24
- package/dist/connectors/remote-mcp.js +92 -57
- package/dist/errors.d.ts +28 -3
- package/dist/errors.js +60 -1
- package/dist/execute.js +85 -23
- package/dist/executor-result.js +3 -1
- package/dist/executors/quickjs-child.js +5 -1
- package/dist/executors/quickjs-protocol.d.ts +4 -0
- package/dist/executors/quickjs-runtime.d.ts +1 -1
- package/dist/executors/quickjs-runtime.js +38 -21
- package/dist/executors/quickjs.js +68 -27
- package/dist/index.d.ts +15 -1
- package/dist/index.js +36 -4
- package/dist/invocation.js +134 -93
- package/dist/mcp-result.js +3 -2
- package/dist/meta-tools.js +191 -36
- package/dist/operator-ui/generated.js +2 -2
- package/dist/operator-ui/view.d.ts +38 -1
- package/dist/operator-ui/view.js +71 -0
- package/dist/providers/cloudflare.d.ts +14 -2
- package/dist/providers/cloudflare.js +107 -16
- package/dist/providers/linear.d.ts +26 -4
- package/dist/providers/linear.js +19 -4
- package/dist/providers/mixpanel.d.ts +16 -3
- package/dist/providers/mixpanel.js +13 -2
- package/dist/providers/notion.d.ts +8 -1
- package/dist/providers/notion.js +83 -10
- package/dist/providers/revenuecat.d.ts +30 -4
- package/dist/providers/revenuecat.js +42 -4
- package/dist/providers/stripe.d.ts +7 -1
- package/dist/providers/stripe.js +30 -4
- package/dist/providers/vercel.js +11 -1
- package/dist/registry.d.ts +22 -2
- package/dist/registry.js +101 -13
- package/dist/routes/mcp.d.ts +4 -1
- package/dist/routes/mcp.js +84 -13
- package/dist/routes/oauth.js +4 -0
- package/dist/routes/shared.d.ts +1 -0
- package/dist/routes/shared.js +4 -4
- package/dist/server.js +15 -3
- package/dist/skills.js +6 -5
- package/dist/storage/file.d.ts +6 -2
- package/dist/storage/file.js +312 -34
- package/dist/storage/memory.js +12 -1
- package/dist/types.d.ts +37 -0
- package/dist/ui.js +18 -10
- package/dist/validate.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +193 -165
- package/documentation/auth.md +199 -145
- package/documentation/code-mode.md +433 -316
- package/documentation/meta-tools.md +363 -355
- package/examples/worker/AGENTS.md +2 -1
- package/examples/worker/README.md +12 -10
- package/examples/worker/src/index.ts +12 -15
- package/package.json +1 -2
- package/templates/node/.env.example +3 -3
- package/templates/node/AGENTS.md +5 -4
- package/templates/node/README.md +2 -1
- package/templates/node/package.json +1 -1
- package/templates/node/src/index.ts +23 -22
- package/documentation/call-admission.md +0 -142
- package/documentation/cloudflare.md +0 -471
- package/documentation/connector-guides.md +0 -176
- package/documentation/connectors.md +0 -389
- package/documentation/linear.md +0 -193
- package/documentation/mixpanel.md +0 -160
- package/documentation/notion.md +0 -308
- package/documentation/operations.md +0 -359
- package/documentation/operator-ui.md +0 -135
- package/documentation/optional-modules-upgrade.md +0 -243
- package/documentation/provider-conventions.md +0 -722
- package/documentation/request-admission.md +0 -170
- package/documentation/revenuecat.md +0 -305
- package/documentation/storage-and-credentials.md +0 -201
- package/documentation/stripe.md +0 -262
- package/documentation/upgrading.md +0 -754
- package/documentation/vercel.md +0 -241
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Generated by scripts/build-operator-ui.mjs. Do not edit.
|
|
2
2
|
// Source: src/operator-ui/app/main.tsx and src/operator-ui/browser.css.
|
|
3
|
-
export const OPERATOR_UI_CSS = "/* src/operator-ui/browser.css */\n:root {\n color-scheme: light;\n --ink: #000;\n --paper: #fff;\n --rule: #ccc;\n --muted: #666;\n --trace: #f5f5f5;\n --shell: 70rem;\n --pad: 1rem;\n --gap: 1.5rem;\n --sans:\n \"Helvetica Neue\",\n Helvetica,\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}\n* {\n border-radius: 0;\n box-sizing: border-box;\n}\nhtml {\n background: var(--paper);\n color: var(--ink);\n font-family: var(--sans);\n font-size: 16px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n}\nbody {\n margin: 0;\n min-height: 100vh;\n}\n::selection {\n background: var(--ink);\n color: var(--paper);\n}\n:is(h1, h2, h3, p, ul, ol) {\n margin: 0;\n padding: 0;\n}\n:is(h1, h2, h3) {\n font-size: inherit;\n font-weight: 400;\n}\n:is(ul, ol) {\n list-style: none;\n}\na {\n color: inherit;\n}\nbutton,\ninput {\n font: inherit;\n}\nbutton {\n background: none;\n border: 0;\n color: inherit;\n cursor: pointer;\n margin: 0;\n padding: 0;\n text-align: left;\n}\nbutton:disabled {\n cursor: wait;\n opacity: .5;\n}\ninput {\n background: var(--paper);\n border: 1px solid var(--rule);\n color: var(--ink);\n min-height: 2rem;\n padding: .2rem .5rem;\n}\ninput:focus-visible {\n outline-offset: -1px;\n}\n:is(a, button, input, summary):focus-visible {\n outline: 1px solid var(--ink);\n}\n:is(a, button, summary):focus-visible {\n outline-offset: 2px;\n}\n.skip-link {\n background: var(--paper);\n left: var(--pad);\n padding: .5rem;\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.pgrid {\n column-gap: var(--gap);\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n row-gap: 1rem;\n}\n.pcap {\n grid-column: 1;\n}\n.pbody {\n grid-column: 2 / -1;\n min-width: 0;\n}\n.cap,\n.meta {\n color: var(--muted);\n font-size: .9em;\n}\n.mono {\n font-family: var(--mono);\n font-size: .78rem;\n}\n.visually-hidden {\n clip: rect(0 0 0 0);\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: start;\n padding-bottom: var(--pad);\n padding-top: var(--pad);\n}\n.brand {\n font-weight: 500;\n grid-column: 1;\n text-decoration: none;\n}\n.mast-nav {\n display: flex;\n gap: var(--gap);\n grid-column: 2 / -1;\n justify-content: space-between;\n min-width: 0;\n}\n.mast-actions {\n display: flex;\n gap: var(--gap);\n justify-content: flex-end;\n min-width: 0;\n}\n.page-nav,\n.session-actions {\n display: flex;\n flex-wrap: wrap;\n gap: .5rem var(--gap);\n}\n.mast-actions :is(a, button) {\n align-items: center;\n display: inline-flex;\n min-height: 2rem;\n}\n.navlink,\n.linklike {\n text-decoration: underline;\n text-decoration-thickness: 1.5px;\n text-underline-offset: .22em;\n}\n.navlink {\n text-decoration-color: transparent;\n}\n.navlink:hover,\n.navlink:focus-visible,\n.navlink[aria-current=page] {\n text-decoration-color: currentColor;\n}\n.linklike {\n text-decoration-color: currentColor;\n}\n.linklike:hover,\n.linklike:focus-visible {\n text-decoration-color: transparent;\n}\n.page {\n padding-bottom: 5rem;\n}\n.lead {\n margin-top: 3rem;\n}\n.section,\n.section + .section {\n margin-top: 2rem;\n}\n.lead-copy,\n.body-copy {\n max-width: 34em;\n}\n.lead-copy > * + *,\n.body-copy > * + * {\n margin-top: 1.5rem;\n}\n.row,\n.actions {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n gap: var(--gap);\n}\n.row input {\n flex: 1;\n min-width: 12rem;\n}\n.gate-actions {\n margin-top: 1.5rem;\n}\n#err {\n margin-top: 1.5rem;\n text-decoration: underline;\n}\n.endpoint {\n border-bottom: 1px solid var(--rule);\n border-top: 1px solid var(--rule);\n}\n.endpoint-row {\n align-items: baseline;\n display: flex;\n gap: var(--gap);\n min-width: 0;\n padding: .75rem 0;\n}\n.endpoint-row code {\n flex: 1;\n min-width: 0;\n overflow-x: auto;\n white-space: nowrap;\n}\n.endpoint-row button {\n flex: none;\n}\n.connector-tools {\n border-bottom: 1px solid var(--rule);\n}\n.toolbar {\n margin-bottom: 1.5rem;\n}\n.toolbar input {\n flex-basis: 18rem;\n}\n#oauthNotice {\n margin-bottom: .75rem;\n}\n#oauthNotice:empty {\n display: none;\n}\n.error-notice,\n.msg {\n text-decoration: underline;\n}\n.card,\n.credential-card,\n.activity-item {\n padding-left: 1.25rem;\n position: relative;\n}\n.card::before,\n.credential-card::before,\n.activity-item::before {\n background: var(--rule);\n bottom: 0;\n content: \"\";\n left: .25rem;\n position: absolute;\n top: 0;\n width: 1px;\n}\n.card {\n border-top: 1px solid var(--rule);\n padding-bottom: .75rem;\n padding-top: .75rem;\n}\n.connector-head {\n display: grid;\n gap: var(--gap);\n grid-template-columns: minmax(0, 2fr) minmax(10rem, 1fr);\n}\n.connector-title {\n align-items: baseline;\n display: flex;\n gap: .5rem;\n}\n.connector-title .dot,\n.activity-stamp .dot {\n margin-left: -1.25rem;\n}\n.activity-stamp {\n align-items: baseline;\n display: flex;\n gap: .75rem;\n}\n.card h2 {\n overflow-wrap: anywhere;\n}\n.connector-state {\n text-align: right;\n}\n.dot {\n background: var(--paper);\n border: 1px solid var(--ink);\n display: inline-block;\n flex: none;\n height: .5rem;\n width: .5rem;\n z-index: 1;\n}\n.dot.ok {\n background: var(--ink);\n}\n.dot.auth_required {\n background:\n linear-gradient(\n 90deg,\n var(--ink) 50%,\n var(--paper) 50%);\n}\n.connector-description {\n margin-top: .25rem;\n max-width: 40rem;\n}\n.connector-message,\n.connector-auth {\n margin-top: .75rem;\n}\n.connector-drift {\n border-top: 1px solid var(--rule);\n margin-top: .75rem;\n padding-top: .75rem;\n}\n.drift-summary {\n margin-top: .25rem;\n}\n.drift-counts {\n display: flex;\n flex-wrap: wrap;\n gap: .25rem var(--gap);\n margin-top: .5rem;\n}\n.drift-count {\n color: var(--muted);\n font-size: .9em;\n}\n.drift-count.flagged {\n color: var(--ink);\n}\n.drift-count-value {\n font-family: var(--mono);\n margin-right: .35rem;\n}\n.drift-count.flagged .drift-count-value {\n text-decoration: underline;\n}\n.credential-ledger {\n border-bottom: 1px solid var(--rule);\n}\n.credential-card {\n border-top: 1px solid var(--rule);\n padding-bottom: .75rem;\n padding-top: .75rem;\n}\n.credential-head {\n align-items: baseline;\n display: flex;\n flex-wrap: wrap;\n gap: .25rem var(--gap);\n justify-content: space-between;\n}\n.credential-copy {\n margin-top: .25rem;\n max-width: 40rem;\n}\n.credential-field-summary {\n border-top: 1px solid var(--rule);\n margin-top: .75rem;\n}\n.credential-field-summary > div {\n border-bottom: 1px solid var(--rule);\n display: flex;\n flex-wrap: wrap;\n gap: .25rem var(--gap);\n justify-content: space-between;\n padding: .5rem 0;\n}\n.credential-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--gap);\n margin-top: .75rem;\n}\n.credential-actions button,\n.credential-form button,\n.activity-controls button,\n.activity-more {\n align-items: center;\n display: inline-flex;\n min-height: 2.75rem;\n}\n.credential-form {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n gap: .75rem var(--gap);\n margin-top: .75rem;\n}\n.credential-form > input {\n flex: 1 1 18rem;\n}\n.credential-fields {\n display: grid;\n flex: 1 1 100%;\n gap: .75rem;\n}\n.credential-field {\n align-items: center;\n display: grid;\n gap: var(--gap);\n grid-template-columns: minmax(9rem, 12rem) 1fr;\n}\n.credential-field input {\n min-width: 0;\n width: 100%;\n}\n.danger {\n text-decoration-style: double;\n}\n.token-create {\n border-bottom: 1px solid var(--rule);\n border-top: 1px solid var(--rule);\n padding: .75rem 0;\n}\n.token-create > label {\n display: block;\n margin-bottom: .5rem;\n}\n.token-create input {\n flex: 1 1 18rem;\n}\n.token-create button,\n.token-card button,\n.token-reveal button {\n align-items: center;\n display: inline-flex;\n min-height: 2.75rem;\n}\n.token-reveal {\n background: var(--ink);\n color: var(--paper);\n margin-top: 1.5rem;\n padding: 1rem 1.25rem;\n}\n.token-reveal .meta,\n.token-reveal .cap {\n color: #bbb;\n}\n.token-reveal-head,\n.token-card-head {\n align-items: baseline;\n display: flex;\n flex-wrap: wrap;\n gap: .25rem var(--gap);\n justify-content: space-between;\n}\n.token-secret {\n border-bottom: 1px solid #555;\n border-top: 1px solid #555;\n margin-top: .75rem;\n}\n.token-secret code {\n color: var(--paper);\n user-select: all;\n}\n.token-ledger {\n border-bottom: 1px solid var(--rule);\n margin-top: 1.5rem;\n}\n.token-card {\n border-top: 1px solid var(--rule);\n padding: .75rem 0 .75rem 1.25rem;\n position: relative;\n}\n.token-card::before {\n background: var(--ink);\n bottom: 0;\n content: \"\";\n left: .25rem;\n position: absolute;\n top: 0;\n width: 1px;\n}\n.token-card.revoked {\n color: var(--muted);\n}\n.token-card.revoked::before {\n background: var(--rule);\n}\ndetails {\n margin-top: .75rem;\n}\nsummary {\n cursor: pointer;\n list-style: none;\n width: max-content;\n}\nsummary::-webkit-details-marker {\n display: none;\n}\n.tool-list {\n border-bottom: 1px solid var(--rule);\n margin-top: .5rem;\n}\n.tool {\n border-top: 1px solid var(--rule);\n display: grid;\n gap: .25rem var(--gap);\n grid-template-columns: minmax(12rem, 1fr) minmax(0, 2fr);\n padding: .5rem 0;\n}\n.tool code {\n font-family: var(--mono);\n font-size: .78rem;\n overflow-wrap: anywhere;\n}\n.tool .td {\n color: var(--muted);\n font-size: .9em;\n}\n.empty {\n border-top: 1px solid var(--rule);\n padding: .75rem 0;\n}\n.activity-copy {\n margin-bottom: 1.5rem;\n}\n.activity-controls {\n margin-bottom: 1.5rem;\n}\n.activity-controls input {\n flex: 1 1 18rem;\n}\n#activityNotice {\n margin-bottom: .75rem;\n}\n.activity-ledger {\n border-bottom: 1px solid var(--rule);\n}\n.activity-item {\n border-top: 1px solid var(--rule);\n display: grid;\n gap: .25rem var(--gap);\n grid-template-columns: minmax(9rem, .85fr) minmax(12rem, 1.4fr) minmax(8rem, .9fr);\n padding-bottom: .75rem;\n padding-top: .75rem;\n}\n.activity-time,\n.activity-actor,\n.activity-detail {\n color: var(--muted);\n font-size: .82rem;\n}\n.activity-actor-id {\n color: var(--muted);\n margin-top: .1rem;\n}\n.activity-address {\n font-family: var(--mono);\n font-size: .78rem;\n overflow-wrap: anywhere;\n}\n.activity-outcome {\n font-size: .9em;\n}\n.activity-item.error .activity-outcome,\n.activity-item.timeout .activity-outcome,\n.activity-item.cancelled .activity-outcome {\n text-decoration: underline;\n}\n.activity-empty {\n border-top: 1px solid var(--rule);\n padding: .75rem 0;\n}\n.activity-more {\n margin-top: .75rem;\n}\n.unavailable {\n background: var(--trace);\n border-bottom: 1px solid var(--rule);\n border-top: 1px solid var(--rule);\n padding: .75rem;\n}\n@media (prefers-reduced-motion: reduce) {\n html:focus-within {\n scroll-behavior: auto;\n }\n}\n@media (max-width: 36.99rem) {\n .pgrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n .pcap,\n .pbody {\n grid-column: 1 / -1;\n }\n .masthead .brand {\n grid-column: 1;\n }\n .mast-nav {\n grid-column: 1 / -1;\n grid-row: 2;\n justify-content: flex-start;\n }\n .product {\n display: none;\n }\n .mast-actions {\n align-items: flex-start;\n flex-direction: column;\n font-size: .875rem;\n gap: .25rem;\n }\n .lead {\n margin-top: 2rem;\n }\n .section,\n .section + .section {\n margin-top: 2.5rem;\n }\n .connector-head,\n .tool,\n .activity-item {\n grid-template-columns: 1fr;\n }\n .connector-state {\n text-align: left;\n }\n .credential-field {\n align-items: start;\n grid-template-columns: 1fr;\n gap: .25rem;\n }\n input {\n min-height: 2.75rem;\n }\n}\n";
|
|
4
|
-
export const OPERATOR_UI_SCRIPT = "\"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, A2, H2, T2, 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, A2 = l.__r, H2 = 0, M) p3.state = p3.__s, p3.__d = false, A2 && A2(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, A2 && A2(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)), T2 = null != s3 && s3.type === S && null == s3.key ? E(s3.props.children) : s3, f4 = L(n2, g(T2) ? T2 : [T2], 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 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 \"activity\"\n ];\n var PAGE_META = {\n connections: { path: \"/\", label: \"Connections\" },\n activity: { path: \"/activity\", label: \"Activity\" }\n };\n function pageForPath(path) {\n const match = OPERATOR_PAGES.find((page) => PAGE_META[page].path === path);\n return match ?? \"connections\";\n }\n function info(message2) {\n return { message: message2, tone: \"info\" };\n }\n function failure(message2) {\n return { message: message2, tone: \"error\" };\n }\n function initialState(page) {\n return {\n page,\n generation: 0,\n session: \"loading\",\n gate: null,\n refreshing: false,\n pendingFocus: null,\n ...identityScopedState()\n };\n }\n function identityScopedState() {\n return {\n data: null,\n connectorFilter: \"\",\n oauthNotice: null,\n oauthBusy: null,\n credentialNotice: null,\n credentialEditing: null,\n credentialBusy: null,\n activityPhase: \"idle\",\n activityNotice: null,\n activityEvents: [],\n activityCursor: null,\n activitySearch: \"\"\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 pendingFocus: null,\n ...identityScopedState()\n };\n }\n function withPage(state2, page) {\n return {\n ...state2,\n page,\n credentialEditing: null,\n credentialNotice: null\n };\n }\n function connectorStatusLabel(status) {\n if (status === \"loading\") return \"Loading details\";\n if (status === \"ok\") return \"Connected\";\n if (status === \"auth_required\") return \"Authorization needed\";\n return \"Unavailable\";\n }\n function toolCountLabel(count) {\n return `${count} ${count === 1 ? \"tool\" : \"tools\"}`;\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();\n }\n function actorLabel(actor) {\n if (!actor?.kind) return \"unknown\";\n if (actor.label) return `${actor.kind} · ${actor.label}`;\n return actor.id ? `${actor.kind} · ${actor.id}` : actor.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 ].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 \"Arguments and results are never stored.\";\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\"} · no arguments or results stored`;\n }\n var ACTIVITY_OUTCOMES = [\"success\", \"error\", \"timeout\", \"cancelled\"];\n function activityOutcomeClass(outcome) {\n return ACTIVITY_OUTCOMES.includes(outcome) ? outcome : \"error\";\n }\n function activityDetail(event) {\n const parts = [event.source];\n if (event.attempts > 1) parts.push(`${event.attempts} attempts`);\n if (event.friction) parts.push(event.friction);\n if (event.errorCode && event.errorCode !== event.friction) {\n parts.push(event.errorCode);\n }\n return parts.join(\" · \");\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 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/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 message(error, fallback) {\n return error instanceof Error && error.message ? error.message : fallback;\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 function gate(notice = null) {\n state = resetIdentity(state, notice);\n for (const listener of listeners) listener();\n }\n async function operatorRequest(path, method, current, body) {\n const token = await sessionToken();\n if (!current()) throw new Error(\"The operator session changed.\");\n if (!token && auth.kind !== \"cloudflare-access\") {\n throw new Error(\"Your operator session has expired.\");\n }\n const res = await fetch(path, {\n method,\n headers: requestHeaders(token, Boolean(body)),\n credentials: \"same-origin\",\n ...body ? { body: JSON.stringify(body) } : {}\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) {\n throw new Error(\"Your operator session was not accepted. Sign in again.\");\n }\n if (res.status === 403) {\n throw new Error(\"This identity may not perform that action.\");\n }\n if (!res.ok) {\n throw new Error(payload.error || `Request failed (${res.status}).`);\n }\n return payload;\n }\n async function loadData() {\n const current = fence();\n if (state.session === \"ready\") set({ refreshing: true });\n let token;\n try {\n token = await sessionToken();\n } catch (error) {\n if (!current()) return;\n const why = message(error, \"unknown error\");\n return gate(failure(`Could not read the Clerk session: ${why}`));\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 (error) {\n if (!current()) return;\n return gate(failure(`Network error: ${message(error, \"unknown error\")}`));\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 is not allowed to access connecta.\" : \"Your Clerk session was not accepted. Sign out and try again.\"\n )\n );\n }\n if (auth.kind === \"cloudflare-access\") {\n return gate(\n failure(\n \"Cloudflare Access admitted the request, but this identity is not an eligible operator.\"\n )\n );\n }\n localStorage.removeItem(TOKEN_KEY);\n return gate(failure(\"Token rejected — enter a valid bearer token.\"));\n }\n if (!res.ok) return gate(failure(`Error ${res.status}`));\n let data;\n try {\n data = await res.json();\n } catch {\n if (!current()) return;\n return gate(failure(\"Operator data could not be read.\"));\n }\n if (!current()) return;\n if (!Array.isArray(data.connectors)) return gate(failure(\"Connection list could not be read.\"));\n set({ data, session: \"ready\", gate: null, refreshing: false });\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;\n if (!current()) return;\n set(options.done(payload));\n if (options.reload) void refreshConnector(options.reload);\n } catch (error) {\n if (!current()) return;\n set(options.failed(failure(message(error, options.fallback))));\n }\n }\n function focusHandled() {\n if (state.pendingFocus !== null) set({ pendingFocus: null });\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 loadData().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 oauthAction(connector, action) {\n const disconnecting = action === \"disconnect\";\n const confirmed = window.confirm(\n disconnecting ? `Disconnect OAuth for ${connector}? Stored credentials and any pending authorization will be removed.` : `Restart OAuth for ${connector}? Stored credentials and any pending authorization will be replaced.`\n );\n if (!confirmed) return Promise.resolve();\n return mutate({\n request: (current) => operatorRequest(\n `/ui/oauth/${encodeURIComponent(connector)}`,\n disconnecting ? \"DELETE\" : \"POST\",\n current\n ),\n busy: { oauthNotice: null, oauthBusy: connector },\n done: (payload) => ({\n ...state.data ? { data: { ...state.data, 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, ...!disconnecting && payload?.authorizationUrl ? { authorizationUrl: payload.authorizationUrl } : {} };\n }) } } : {},\n oauthBusy: null,\n pendingFocus: \"oauthNotice\",\n oauthNotice: info(\n disconnecting ? \"OAuth disconnected. Restart authorization when you are ready to reconnect.\" : payload?.message || \"Authorization restarted. Open the authorization link to reconnect.\"\n )\n }),\n failed: (notice) => ({\n oauthBusy: null,\n oauthNotice: notice,\n pendingFocus: \"oauthNotice\"\n }),\n fallback: \"OAuth action failed.\",\n reload: connector\n });\n }\n function editCredential(connector) {\n set({ credentialEditing: connector, credentialNotice: null });\n }\n function refuseCredential(copy) {\n set({ credentialNotice: failure(copy), pendingFocus: \"credentialNotice\" });\n }\n function credentialMutation(connector, request, done, reload = true) {\n const land = (credentialNotice) => ({\n credentialBusy: null,\n credentialNotice,\n pendingFocus: \"credentialNotice\"\n });\n return mutate({\n request,\n busy: { credentialBusy: connector, credentialNotice: null },\n done: (payload) => land(done(payload)),\n failed: land,\n fallback: \"Credential action failed.\",\n reload: reload ? connector : void 0\n });\n }\n function saveCredential(connector, body) {\n return credentialMutation(\n connector,\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"PUT\",\n current,\n body\n ),\n () => {\n set({ credentialEditing: null });\n return info(\"Credential saved.\");\n }\n );\n }\n function removeCredential(connector) {\n const confirmed = window.confirm(\n \"Remove this credential? The connector will stop authenticating until a replacement is added.\"\n );\n if (!confirmed) return Promise.resolve();\n return credentialMutation(\n connector,\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"DELETE\",\n current\n ),\n () => info(\"Credential removed.\")\n );\n }\n function testCredential(connector) {\n return credentialMutation(\n connector,\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}/test`,\n \"POST\",\n current\n ),\n (payload) => {\n const copy = payload?.message || (payload?.ok ? \"Credential is valid.\" : \"Credential test failed.\");\n return payload?.ok ? info(copy) : failure(copy);\n },\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(message(error, \"Activity could not be loaded.\"))\n });\n }\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 async function boot() {\n const onPop = () => setPage(pageForPath(window.location.pathname), true);\n window.addEventListener(\"popstate\", onPop);\n if (auth.kind === \"clerk\") {\n const clerk = window.Clerk;\n if (!clerk) {\n const why = \"Clerk could not load. Check your network and try again.\";\n return gate(failure(why));\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 loadData();\n });\n } catch (error) {\n const why = message(error, \"unknown error\");\n return gate(failure(`Clerk could not initialize: ${why}`));\n }\n }\n await loadData();\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 let detail;\n try {\n const response = await fetch(`/ui/connectors/${encodeURIComponent(connector.id)}`, { headers: requestHeaders(token), credentials: \"same-origin\" });\n if (!response.ok) throw new Error(`Connection details unavailable (${response.status})`);\n detail = await response.json();\n } catch (error) {\n detail = { ...connector, status: \"error\", message: message(error, \"Connection details unavailable\") };\n }\n if (!current() || generation !== detailGeneration || !state.data) return;\n if (detailRevisions.get(connector.id) !== revision) continue;\n set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === connector.id ? detail : c3) } });\n }\n };\n await Promise.all(Array.from({ length: Math.min(4, data.connectors.length) }, worker));\n }\n async function refreshConnector(id) {\n const current = fence();\n const revision = (detailRevisions.get(id) ?? 0) + 1;\n detailRevisions.set(id, revision);\n if (state.data) set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...c3, status: \"loading\" } : c3) } });\n try {\n const token = await sessionToken();\n if (!current()) return;\n const response = await fetch(`/ui/connectors/${encodeURIComponent(id)}`, { headers: requestHeaders(token), credentials: \"same-origin\" });\n if (!response.ok) throw new Error(`Connection details unavailable (${response.status})`);\n const detail = await response.json();\n if (!current() || !state.data || detailRevisions.get(id) !== revision) return;\n set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...detail, ...detail.status === \"auth_required\" && c3.authorizationUrl ? { authorizationUrl: c3.authorizationUrl } : {} } : c3) } });\n } catch (error) {\n if (!current() || !state.data || detailRevisions.get(id) !== revision) return;\n set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...c3, status: \"error\", message: message(error, \"Connection details unavailable\") } : c3) } });\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(\n \"p\",\n {\n id,\n class: notice?.tone === \"error\" ? `${className} error-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 }\n function Empty({ children }) {\n return /* @__PURE__ */ u3(\"p\", { class: \"empty\", children });\n }\n function Unavailable({ children }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"unavailable\", children });\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 = \"linklike\"\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 onClick: () => {\n navigator.clipboard.writeText(value).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/activity.tsx\n function ActivityRow({ event }) {\n const outcome = activityOutcomeClass(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(\n \"span\",\n {\n class: outcome === \"success\" ? \"dot ok\" : \"dot\",\n \"aria-hidden\": \"true\"\n }\n ),\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\", { children: [\n /* @__PURE__ */ u3(\"div\", { class: \"activity-outcome\", children: event.outcome }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-detail\", children: [\n event.durationMs,\n \" ms\"\n ] })\n ] })\n ] });\n }\n function ActivityPage({ state: state2 }) {\n const enabled = Boolean(state2.data?.activityEnabled);\n const loading = state2.activityPhase === \"loading\";\n const visible = filterActivity(state2.activityEvents, state2.activitySearch);\n return /* @__PURE__ */ u3(\"section\", { id: \"activityView\", children: /* @__PURE__ */ u3(\"div\", { class: \"lead pgrid\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"activityHeading\", class: \"pcap\", tabIndex: -1, children: \"Activity\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"pbody\", children: [\n /* @__PURE__ */ u3(\"p\", { class: \"activity-copy\", id: \"activitySummary\", children: activitySummary(state2.activityEvents) }),\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\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"row activity-controls\", 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: \"linklike\",\n type: \"button\",\n disabled: loading,\n onClick: () => void loadActivity(true),\n children: loading ? \"Loading…\" : \"Refresh\"\n }\n )\n ] }),\n /* @__PURE__ */ u3(NoticeLine, { id: \"activityNotice\", notice: state2.activityNotice }),\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"activityList\",\n class: \"activity-ledger\",\n \"aria-busy\": loading ? \"true\" : \"false\",\n children: loading && state2.activityEvents.length === 0 ? /* @__PURE__ */ u3(\"div\", { class: \"activity-empty\", children: \"Loading activity…\" }) : state2.activityPhase === \"error\" && state2.activityEvents.length === 0 ? /* @__PURE__ */ u3(\"p\", { class: \"activity-empty\", children: /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"linklike\",\n type: \"button\",\n onClick: () => void loadActivity(true),\n children: \"Try loading activity again\"\n }\n ) }) : visible.length === 0 ? /* @__PURE__ */ u3(\"div\", { class: \"activity-empty\", children: state2.activitySearch.trim() ? \"No loaded activity matches this search.\" : \"No connector tool calls recorded yet.\" }) : visible.map((event, index) => /* @__PURE__ */ u3(\n ActivityRow,\n {\n event\n },\n `${event.occurredAt}-${event.address}-${index}`\n ))\n }\n ),\n state2.activityCursor ? /* @__PURE__ */ u3(\n \"button\",\n {\n id: \"moreActivity\",\n class: \"linklike 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\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(\"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 \"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(\"button\", { class: \"linklike\", type: \"button\", disabled: busy, onClick: submit, children: busy ? \"Saving…\" : \"Save\" }),\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"linklike\",\n type: \"button\",\n disabled: busy,\n onClick: () => editCredential(null),\n children: \"Cancel\"\n }\n )\n ] });\n }\n function CredentialCard({\n connector,\n credential,\n editing,\n busy\n }) {\n const configured = Boolean(credential.configured);\n const removable = configured || Boolean(credential.removable);\n return /* @__PURE__ */ u3(\n \"section\",\n {\n class: \"credential-card\",\n id: `credential-${connector.id}`,\n \"aria-labelledby\": `credential-title-${connector.id}`,\n children: [\n /* @__PURE__ */ u3(\"div\", { class: \"credential-head\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"connector-title\", children: /* @__PURE__ */ u3(\"h2\", { id: `credential-title-${connector.id}`, children: credential.label }) }),\n /* @__PURE__ */ u3(\"span\", { class: \"credential-state\", children: credentialStateLabel(credential) })\n ] }),\n credential.description ? /* @__PURE__ */ u3(\"p\", { class: \"credential-copy 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(\"div\", { class: \"msg\", children: credential.error }) : null,\n credential.notice ? /* @__PURE__ */ u3(\"p\", { class: \"credential-copy meta\", children: credential.notice }) : null,\n /* @__PURE__ */ u3(\"div\", { class: \"credential-actions\", children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"linklike\",\n type: \"button\",\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: \"linklike\",\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 class: \"linklike danger\",\n type: \"button\",\n disabled: busy,\n onClick: () => void removeCredential(connector.id),\n children: \"Remove\"\n }\n ) : null\n ] }),\n editing ? /* @__PURE__ */ u3(\n CredentialForm,\n {\n connector: connector.id,\n credential,\n busy\n }\n ) : null\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/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(\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 drift-summary\", 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 }\n function ConnectorCard({\n connector,\n tools,\n expanded,\n oauthManagement,\n busy,\n state: state2\n }) {\n const name = connector.title || connector.id;\n const authorization = safeHttpHref(connector.authorizationUrl);\n return /* @__PURE__ */ u3(\"div\", { class: \"card\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"connector-head\", children: [\n /* @__PURE__ */ u3(\"div\", { children: [\n /* @__PURE__ */ u3(\"div\", { class: \"connector-title\", children: [\n /* @__PURE__ */ u3(\"span\", { class: `dot ${connector.status}`, \"aria-hidden\": \"true\" }),\n /* @__PURE__ */ u3(\"h2\", { children: name })\n ] }),\n connector.description ? /* @__PURE__ */ u3(\"p\", { class: \"connector-description meta\", children: connector.description }) : null\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"connector-state cap\", children: [\n connectorStatusLabel(connector.status),\n \" ·\",\n \" \",\n connector.status === \"loading\" ? \"Tools not loaded\" : toolCountLabel(connector.toolCount),\n /* @__PURE__ */ u3(\"br\", {}),\n /* @__PURE__ */ u3(\"span\", { class: \"mono\", children: connector.id }),\n /* @__PURE__ */ u3(\"br\", {}),\n /* @__PURE__ */ u3(\"span\", { children: connector.authScope === \"personal\" ? \"personal auth\" : \"shared auth\" })\n ] })\n ] }),\n connector.message ? /* @__PURE__ */ u3(\"p\", { class: \"connector-message msg\", children: connector.message }) : null,\n connector.authorizationUrl ? /* @__PURE__ */ u3(\"p\", { class: authorization ? \"connector-auth\" : \"connector-auth meta\", children: authorization ? /* @__PURE__ */ u3(\n \"a\",\n {\n class: \"linklike\",\n href: authorization,\n target: \"_blank\",\n rel: \"noopener\",\n children: \"Authorize connector →\"\n }\n ) : `Authorization URL: ${connector.authorizationUrl}` }) : null,\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: [\n \"Can use this connection · \",\n connector.permissions?.manageSharedAuth ? \"Can manage shared authentication\" : connector.permissions?.connectPersonal ? \"Can connect your account\" : \"Authentication managed by your deployment\"\n ] }),\n connector.oauth && oauthManagement ? /* @__PURE__ */ u3(\"div\", { class: \"credential-actions\", children: [\n connector.status === \"ok\" ? /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n class: \"linklike danger\",\n \"aria-label\": `Disconnect OAuth for ${name}`,\n disabled: busy,\n onClick: () => void oauthAction(connector.id, \"disconnect\"),\n children: \"Disconnect OAuth\"\n }\n ) : null,\n /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n class: \"linklike\",\n \"aria-label\": `${connector.status === \"ok\" ? \"Reconnect OAuth for\" : \"Restart authorization for\"} ${name}`,\n disabled: busy,\n onClick: () => void oauthAction(connector.id, \"reconnect\"),\n children: connector.status === \"ok\" ? \"Reconnect OAuth\" : \"Connect account\"\n }\n )\n ] }) : null,\n connector.credential ? /* @__PURE__ */ u3(CredentialCard, { connector, credential: connector.credential, editing: state2.credentialEditing === connector.id, busy: state2.credentialBusy === connector.id }) : null,\n /* @__PURE__ */ u3(\"button\", { class: \"linklike\", type: \"button\", disabled: connector.status === \"loading\", onClick: () => void refreshConnector(connector.id), children: \"Refresh connection\" }),\n /* @__PURE__ */ u3(\"details\", { children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"linklike\", children: \"Connection diagnostics\" }),\n /* @__PURE__ */ u3(DriftPanel, { connector })\n ] }),\n connector.catalogAccess ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: [\n \"Last agent catalog read · \",\n connector.catalogAccess.state,\n \" ·\",\n \" \",\n new Date(connector.catalogAccess.observedAt).toLocaleString()\n ] }) : null,\n tools.length ? /* @__PURE__ */ u3(\"details\", { open: expanded, children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"linklike\", children: [\n \"Show tools (\",\n tools.length,\n \")\"\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"tool-list\", children: tools.map((tool) => /* @__PURE__ */ u3(\"div\", { class: \"tool\", children: [\n /* @__PURE__ */ u3(\"code\", { children: tool.address }),\n tool.description ? /* @__PURE__ */ u3(\"span\", { class: \"td\", children: tool.description }) : null\n ] }, tool.address)) })\n ] }) : null\n ] });\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 pgrid\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"connectionsHeading\", class: \"pcap\", tabIndex: -1, children: \"Connections\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"pbody lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { children: \"Use this endpoint to give an MCP client access to the tools below.\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"endpoint\", children: /* @__PURE__ */ u3(\"div\", { class: \"endpoint-row\", children: [\n /* @__PURE__ */ u3(\"code\", { id: \"mcpUrl\", class: \"mono\", children: mcpUrl }),\n /* @__PURE__ */ u3(CopyButton, { value: mcpUrl, label: \"Copy URL\" })\n ] }) }),\n /* @__PURE__ */ u3(\"p\", { class: \"cap\", id: \"serverInfo\", children: data ? `${data.serverInfo?.name || productName} v${data.connectaVersion || \"?\"}` : productOperatorLabel }),\n /* @__PURE__ */ u3(NoticeLine, { id: \"oauthNotice\", notice: state2.oauthNotice }),\n /* @__PURE__ */ u3(NoticeLine, { id: \"credentialNotice\", notice: state2.credentialNotice })\n ] })\n ] }),\n /* @__PURE__ */ u3(\"section\", { class: \"section pgrid\", \"aria-labelledby\": \"connectorLedgerHeading\", children: [\n /* @__PURE__ */ u3(\"h2\", { class: \"pcap\", id: \"connectorLedgerHeading\", children: \"Connectors\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"pbody\", children: [\n /* @__PURE__ */ u3(\"div\", { class: \"row toolbar\", children: /* @__PURE__ */ u3(\n \"input\",\n {\n id: \"filter\",\n type: \"search\",\n placeholder: \"Filter connectors or tools…\",\n \"aria-label\": \"Filter connectors or tools\",\n value: state2.connectorFilter,\n onInput: (event) => setConnectorFilter(event.currentTarget.value)\n }\n ) }),\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"list\",\n class: \"connector-tools\",\n \"aria-busy\": state2.refreshing || !data ? \"true\" : \"false\",\n children: !data ? /* @__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 ConnectorCard,\n {\n connector,\n tools,\n expanded: Boolean(query),\n oauthManagement: Boolean(connector.permissions?.manageSharedAuth || connector.permissions?.connectPersonal),\n state: state2,\n busy: state2.oauthBusy === connector.id\n },\n connector.id\n ))\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 return OPERATOR_PAGES.filter((page) => {\n if (page === \"activity\") return Boolean(state2.data?.activityEnabled);\n return true;\n });\n }\n function OperatorNav() {\n const state2 = useOperatorState();\n if (state2.session !== \"ready\") return null;\n return /* @__PURE__ */ u3(\"div\", { class: \"mast-actions\", children: [\n /* @__PURE__ */ u3(\"nav\", { class: \"page-nav\", \"aria-label\": \"Operator pages\", children: visiblePages(state2).map((page) => /* @__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 /* @__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\", children: /* @__PURE__ */ u3(\"div\", { class: \"lead pgrid\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"gateHeading\", class: \"pcap\", tabIndex: -1, children: PAGE_META[state2.page].label }),\n /* @__PURE__ */ u3(\"div\", { class: \"pbody lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { children: productDescription }),\n /* @__PURE__ */ u3(\"p\", { id: \"gateCopy\", class: \"meta\", children: loading ? \"Checking your session…\" : gateCopy(auth.kind, signedIn) }),\n loading ? null : auth.kind === \"clerk\" ? /* @__PURE__ */ u3(\"div\", { id: \"clerkGate\", class: \"actions gate-actions\", children: signedIn ? /* @__PURE__ */ u3(\"button\", { class: \"linklike\", type: \"button\", onClick: signOut, children: \"Sign out\" }) : /* @__PURE__ */ u3(\"button\", { id: \"signin\", class: \"linklike\", type: \"button\", onClick: signIn, children: \"Team sign in\" }) }) : auth.kind === \"cloudflare-access\" ? /* @__PURE__ */ u3(\"div\", { class: \"actions gate-actions\", children: /* @__PURE__ */ u3(\"button\", { class: \"linklike\", type: \"button\", onClick: signOut, children: \"Sign out of Cloudflare Access\" }) }) : /* @__PURE__ */ u3(\n \"form\",\n {\n id: \"tokenGate\",\n class: \"row gate-actions\",\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: \"linklike\", 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 === \"activity\") return /* @__PURE__ */ u3(ActivityPage, { 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 document.title = `${PAGE_META[state2.page].label} — ${titleSuffix}`;\n }, [state2.page]);\n h2(() => {\n if (!ready) return;\n if (state2.page === \"activity\" && state2.data?.activityEnabled && state2.activityPhase === \"idle\") {\n void loadActivity(true);\n }\n });\n h2(() => {\n if (!state2.pendingFocus) return;\n document.getElementById(state2.pendingFocus)?.focus();\n focusHandled();\n }, [state2.pendingFocus]);\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";
|
|
3
|
+
export const OPERATOR_UI_CSS = "/* src/operator-ui/browser.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 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}\ninput {\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 {\n flex: 1 1 14rem;\n width: auto;\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 background: var(--ok);\n}\n.dot.auth_required {\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.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.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.empty,\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 text-align: center;\n}\n.unavailable {\n text-align: left;\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.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 overflow-wrap: anywhere;\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] {\n background: var(--surface-2);\n}\n.conn-head {\n align-items: center;\n cursor: pointer;\n display: flex;\n gap: .75rem;\n justify-content: space-between;\n list-style: none;\n padding: .7rem var(--pad);\n}\n.conn-head::-webkit-details-marker {\n display: none;\n}\n.conn-head:focus-visible {\n outline-offset: -2px;\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-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-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}\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}\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-outcome {\n text-align: right;\n}\n.activity-item.error .activity-outcome,\n.activity-item.timeout .activity-outcome {\n color: var(--danger);\n}\n.activity-item.success .activity-outcome {\n color: var(--ok);\n}\n.activity-empty {\n color: var(--muted);\n padding: 1.5rem var(--pad);\n text-align: center;\n}\n.activity-more {\n margin-top: .75rem;\n}\n.gate {\n display: grid;\n gap: .75rem;\n margin: 3rem auto 0;\n max-width: 30rem;\n}\n.gate h1 {\n font-size: 1.25rem;\n}\n.gate .row {\n flex-wrap: nowrap;\n}\n@media (max-width: 40rem) {\n :root {\n --pad: 1rem;\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 .activity-item {\n grid-template-columns: minmax(0, 1fr);\n }\n .activity-outcome {\n text-align: left;\n }\n}\n";
|
|
4
|
+
export const OPERATOR_UI_SCRIPT = "\"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, A2, H2, T2, 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, A2 = l.__r, H2 = 0, M) p3.state = p3.__s, p3.__d = false, A2 && A2(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, A2 && A2(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)), T2 = null != s3 && s3.type === S && null == s3.key ? E(s3.props.children) : s3, f4 = L(n2, g(T2) ? T2 : [T2], 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 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 \"activity\"\n ];\n var PAGE_META = {\n connections: { path: \"/\", label: \"Connections\" },\n activity: { path: \"/activity\", label: \"Activity\" }\n };\n function pageForPath(path) {\n const match = OPERATOR_PAGES.find((page) => PAGE_META[page].path === path);\n return match ?? \"connections\";\n }\n function info(message2) {\n return { message: message2, tone: \"info\" };\n }\n function failure(message2) {\n return { message: message2, tone: \"error\" };\n }\n function initialState(page) {\n return {\n page,\n generation: 0,\n session: \"loading\",\n gate: null,\n refreshing: false,\n pendingFocus: null,\n ...identityScopedState()\n };\n }\n function identityScopedState() {\n return {\n data: null,\n connectorFilter: \"\",\n oauthNotice: null,\n oauthBusy: null,\n credentialNotice: null,\n credentialEditing: null,\n credentialBusy: null,\n activityPhase: \"idle\",\n activityNotice: null,\n activityEvents: [],\n activityCursor: null,\n activitySearch: \"\"\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 pendingFocus: null,\n ...identityScopedState()\n };\n }\n function withPage(state2, page) {\n return {\n ...state2,\n page,\n credentialEditing: null,\n credentialNotice: null\n };\n }\n function connectorStatusLabel(status) {\n if (status === \"loading\") return \"Loading details\";\n if (status === \"ok\") return \"Connected\";\n if (status === \"auth_required\") return \"Authorization needed\";\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 unavailable: 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\") summary.attention += 1;\n else if (connector.status !== \"loading\") 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 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.unavailable ? [{ text: `${summary.unavailable} unavailable`, tone: \"danger\" }] : [],\n { text: toolCountLabel(summary.tools), tone: \"neutral\" }\n ];\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();\n }\n function actorLabel(actor) {\n if (!actor?.kind) return \"unknown\";\n if (actor.label) return `${actor.kind} · ${actor.label}`;\n return actor.id ? `${actor.kind} · ${actor.id}` : actor.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 ].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 \"Arguments and results are never stored.\";\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\"} · no arguments or results stored`;\n }\n var ACTIVITY_OUTCOMES = [\"success\", \"error\", \"timeout\", \"cancelled\"];\n function activityOutcomeClass(outcome) {\n return ACTIVITY_OUTCOMES.includes(outcome) ? outcome : \"error\";\n }\n function activityDetail(event) {\n const parts = [event.source];\n if (event.attempts > 1) parts.push(`${event.attempts} attempts`);\n if (event.friction) parts.push(event.friction);\n if (event.errorCode && event.errorCode !== event.friction) {\n parts.push(event.errorCode);\n }\n return parts.join(\" · \");\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 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/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 message(error, fallback) {\n return error instanceof Error && error.message ? error.message : fallback;\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 function gate(notice = null) {\n state = resetIdentity(state, notice);\n for (const listener of listeners) listener();\n }\n async function operatorRequest(path, method, current, body) {\n const token = await sessionToken();\n if (!current()) throw new Error(\"The operator session changed.\");\n if (!token && auth.kind !== \"cloudflare-access\") {\n throw new Error(\"Your operator session has expired.\");\n }\n const res = await fetch(path, {\n method,\n headers: requestHeaders(token, Boolean(body)),\n credentials: \"same-origin\",\n ...body ? { body: JSON.stringify(body) } : {}\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) {\n throw new Error(\"Your operator session was not accepted. Sign in again.\");\n }\n if (res.status === 403) {\n throw new Error(\"This identity may not perform that action.\");\n }\n if (!res.ok) {\n throw new Error(payload.error || `Request failed (${res.status}).`);\n }\n return payload;\n }\n async function loadData() {\n const current = fence();\n if (state.session === \"ready\") set({ refreshing: true });\n let token;\n try {\n token = await sessionToken();\n } catch (error) {\n if (!current()) return;\n const why = message(error, \"unknown error\");\n return gate(failure(`Could not read the Clerk session: ${why}`));\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 (error) {\n if (!current()) return;\n return gate(failure(`Network error: ${message(error, \"unknown error\")}`));\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 is not allowed to access connecta.\" : \"Your Clerk session was not accepted. Sign out and try again.\"\n )\n );\n }\n if (auth.kind === \"cloudflare-access\") {\n return gate(\n failure(\n \"Cloudflare Access admitted the request, but this identity is not an eligible operator.\"\n )\n );\n }\n localStorage.removeItem(TOKEN_KEY);\n return gate(failure(\"Token rejected — enter a valid bearer token.\"));\n }\n if (!res.ok) return gate(failure(`Error ${res.status}`));\n let data;\n try {\n data = await res.json();\n } catch {\n if (!current()) return;\n return gate(failure(\"Operator data could not be read.\"));\n }\n if (!current()) return;\n if (!Array.isArray(data.connectors)) return gate(failure(\"Connection list could not be read.\"));\n set({ data, session: \"ready\", gate: null, refreshing: false });\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;\n if (!current()) return;\n set(options.done(payload));\n if (options.reload) void refreshConnector(options.reload);\n } catch (error) {\n if (!current()) return;\n set(options.failed(failure(message(error, options.fallback))));\n }\n }\n function focusHandled() {\n if (state.pendingFocus !== null) set({ pendingFocus: null });\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 loadData().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 oauthAction(connector, action) {\n const disconnecting = action === \"disconnect\";\n const confirmed = window.confirm(\n disconnecting ? `Disconnect OAuth for ${connector}? Stored credentials and any pending authorization will be removed.` : `Restart OAuth for ${connector}? Stored credentials and any pending authorization will be replaced.`\n );\n if (!confirmed) return Promise.resolve();\n return mutate({\n request: (current) => operatorRequest(\n `/ui/oauth/${encodeURIComponent(connector)}`,\n disconnecting ? \"DELETE\" : \"POST\",\n current\n ),\n busy: { oauthNotice: null, oauthBusy: connector },\n done: (payload) => ({\n ...state.data ? { data: { ...state.data, 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, ...!disconnecting && payload?.authorizationUrl ? { authorizationUrl: payload.authorizationUrl } : {} };\n }) } } : {},\n oauthBusy: null,\n pendingFocus: \"oauthNotice\",\n oauthNotice: info(\n disconnecting ? \"OAuth disconnected. Restart authorization when you are ready to reconnect.\" : payload?.message || \"Authorization restarted. Open the authorization link to reconnect.\"\n )\n }),\n failed: (notice) => ({\n oauthBusy: null,\n oauthNotice: notice,\n pendingFocus: \"oauthNotice\"\n }),\n fallback: \"OAuth action failed.\",\n reload: connector\n });\n }\n function editCredential(connector) {\n set({ credentialEditing: connector, credentialNotice: null });\n }\n function refuseCredential(copy) {\n set({ credentialNotice: failure(copy), pendingFocus: \"credentialNotice\" });\n }\n function credentialMutation(connector, request, done, reload = true) {\n const land = (credentialNotice) => ({\n credentialBusy: null,\n credentialNotice,\n pendingFocus: \"credentialNotice\"\n });\n return mutate({\n request,\n busy: { credentialBusy: connector, credentialNotice: null },\n done: (payload) => land(done(payload)),\n failed: land,\n fallback: \"Credential action failed.\",\n reload: reload ? connector : void 0\n });\n }\n function saveCredential(connector, body) {\n return credentialMutation(\n connector,\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"PUT\",\n current,\n body\n ),\n () => {\n set({ credentialEditing: null });\n return info(\"Credential saved.\");\n }\n );\n }\n function removeCredential(connector) {\n const confirmed = window.confirm(\n \"Remove this credential? The connector will stop authenticating until a replacement is added.\"\n );\n if (!confirmed) return Promise.resolve();\n return credentialMutation(\n connector,\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}`,\n \"DELETE\",\n current\n ),\n () => info(\"Credential removed.\")\n );\n }\n function testCredential(connector) {\n return credentialMutation(\n connector,\n (current) => operatorRequest(\n `/ui/credentials/${encodeURIComponent(connector)}/test`,\n \"POST\",\n current\n ),\n (payload) => {\n const copy = payload?.message || (payload?.ok ? \"Credential is valid.\" : \"Credential test failed.\");\n return payload?.ok ? info(copy) : failure(copy);\n },\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(message(error, \"Activity could not be loaded.\"))\n });\n }\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 async function boot() {\n const onPop = () => setPage(pageForPath(window.location.pathname), true);\n window.addEventListener(\"popstate\", onPop);\n if (auth.kind === \"clerk\") {\n const clerk = window.Clerk;\n if (!clerk) {\n const why = \"Clerk could not load. Check your network and try again.\";\n return gate(failure(why));\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 loadData();\n });\n } catch (error) {\n const why = message(error, \"unknown error\");\n return gate(failure(`Clerk could not initialize: ${why}`));\n }\n }\n await loadData();\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 let detail;\n try {\n const response = await fetch(`/ui/connectors/${encodeURIComponent(connector.id)}`, { headers: requestHeaders(token), credentials: \"same-origin\" });\n if (!response.ok) throw new Error(`Connection details unavailable (${response.status})`);\n detail = await response.json();\n } catch (error) {\n detail = { ...connector, status: \"error\", message: message(error, \"Connection details unavailable\") };\n }\n if (!current() || generation !== detailGeneration || !state.data) return;\n if (detailRevisions.get(connector.id) !== revision) continue;\n set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === connector.id ? detail : c3) } });\n }\n };\n await Promise.all(Array.from({ length: Math.min(4, data.connectors.length) }, worker));\n }\n async function refreshConnector(id) {\n const current = fence();\n const revision = (detailRevisions.get(id) ?? 0) + 1;\n detailRevisions.set(id, revision);\n if (state.data) set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...c3, status: \"loading\" } : c3) } });\n try {\n const token = await sessionToken();\n if (!current()) return;\n const response = await fetch(`/ui/connectors/${encodeURIComponent(id)}`, { headers: requestHeaders(token), credentials: \"same-origin\" });\n if (!response.ok) throw new Error(`Connection details unavailable (${response.status})`);\n const detail = await response.json();\n if (!current() || !state.data || detailRevisions.get(id) !== revision) return;\n set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...detail, ...detail.status === \"auth_required\" && c3.authorizationUrl ? { authorizationUrl: c3.authorizationUrl } : {} } : c3) } });\n } catch (error) {\n if (!current() || !state.data || detailRevisions.get(id) !== revision) return;\n set({ data: { ...state.data, connectors: state.data.connectors.map((c3) => c3.id === id ? { ...c3, status: \"error\", message: message(error, \"Connection details unavailable\") } : c3) } });\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(\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 }\n function Badge({\n tone = \"neutral\",\n children\n }) {\n return /* @__PURE__ */ u3(\"span\", { class: tone === \"neutral\" ? \"badge\" : `badge ${tone}`, children });\n }\n function Empty({ children }) {\n return /* @__PURE__ */ u3(\"p\", { class: \"empty\", children });\n }\n function Unavailable({ children }) {\n return /* @__PURE__ */ u3(\"div\", { class: \"unavailable\", children });\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 }) {\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 onClick: () => {\n navigator.clipboard.writeText(value).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/activity.tsx\n function ActivityRow({ event }) {\n const outcome = activityOutcomeClass(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\", { children: [\n /* @__PURE__ */ u3(\"div\", { class: \"activity-outcome\", children: event.outcome }),\n /* @__PURE__ */ u3(\"div\", { class: \"activity-detail\", children: [\n event.durationMs,\n \" ms\"\n ] })\n ] })\n ] });\n }\n function ActivityPage({ state: state2 }) {\n const enabled = Boolean(state2.data?.activityEnabled);\n const loading = state2.activityPhase === \"loading\";\n const visible = filterActivity(state2.activityEvents, state2.activitySearch);\n return /* @__PURE__ */ u3(\"section\", { id: \"activityView\", children: /* @__PURE__ */ u3(\"div\", { class: \"lead\", children: [\n /* @__PURE__ */ u3(\"h1\", { id: \"activityHeading\", tabIndex: -1, children: \"Activity\" }),\n /* @__PURE__ */ u3(\"div\", { class: \"lead-copy\", children: [\n /* @__PURE__ */ u3(\"p\", { id: \"activitySummary\", children: activitySummary(state2.activityEvents) }),\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\", children: [\n /* @__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(NoticeLine, { id: \"activityNotice\", notice: state2.activityNotice }),\n /* @__PURE__ */ u3(\n \"div\",\n {\n id: \"activityList\",\n class: \"activity-list\",\n \"aria-busy\": loading ? \"true\" : \"false\",\n children: loading && state2.activityEvents.length === 0 ? /* @__PURE__ */ u3(\"div\", { class: \"activity-empty\", children: \"Loading activity…\" }) : state2.activityPhase === \"error\" && state2.activityEvents.length === 0 ? /* @__PURE__ */ u3(\"p\", { class: \"activity-empty\", children: /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn\",\n type: \"button\",\n onClick: () => void loadActivity(true),\n children: \"Try loading activity again\"\n }\n ) }) : visible.length === 0 ? /* @__PURE__ */ u3(\"div\", { class: \"activity-empty\", children: state2.activitySearch.trim() ? \"No loaded activity matches this search.\" : \"No connector tool calls recorded yet.\" }) : visible.map((event, index) => /* @__PURE__ */ u3(\n ActivityRow,\n {\n event\n },\n `${event.occurredAt}-${event.address}-${index}`\n ))\n }\n ),\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\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(\"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 \"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 }) {\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(\"div\", { class: \"msg\", children: credential.error }) : 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: \"btn\",\n type: \"button\",\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 class: \"btn danger\",\n type: \"button\",\n disabled: busy,\n onClick: () => void removeCredential(connector.id),\n children: \"Remove\"\n }\n ) : null\n ] }),\n editing ? /* @__PURE__ */ u3(\n CredentialForm,\n {\n connector: connector.id,\n credential,\n busy\n }\n ) : null\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/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(\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 }\n function ConnectorRow({\n connector,\n tools,\n expanded,\n oauthManagement,\n busy,\n state: state2\n }) {\n const name = connector.title || connector.id;\n const authorization = safeHttpHref(connector.authorizationUrl);\n const drift = driftState(connector.catalogDrift);\n return /* @__PURE__ */ u3(\"details\", { class: \"conn\", open: expanded, children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"conn-head\", children: [\n /* @__PURE__ */ u3(\"span\", { class: \"conn-main\", children: [\n /* @__PURE__ */ u3(\"span\", { class: `dot ${connector.status}`, \"aria-hidden\": \"true\" }),\n /* @__PURE__ */ u3(\"h2\", { class: \"conn-name\", children: name }),\n connector.title ? /* @__PURE__ */ u3(\"span\", { class: \"conn-id mono\", children: connector.id }) : null\n ] }),\n /* @__PURE__ */ u3(\"span\", { class: \"conn-badges\", 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: connectorStatusTone(connector.status), children: connectorStatusLabel(connector.status) }),\n /* @__PURE__ */ u3(\"span\", { class: \"conn-caret\", \"aria-hidden\": \"true\" })\n ] })\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"conn-body\", children: [\n connector.description ? /* @__PURE__ */ u3(\"p\", { class: \"conn-note\", children: connector.description }) : null,\n connector.message ? /* @__PURE__ */ u3(\"p\", { class: \"msg\", children: connector.message }) : null,\n connector.authorizationUrl && !authorization ? /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: [\n \"Authorization URL: \",\n connector.authorizationUrl\n ] }) : null,\n /* @__PURE__ */ u3(\"p\", { class: \"meta\", children: permissionLabel(connector) }),\n /* @__PURE__ */ u3(\"div\", { class: \"actions\", children: [\n authorization ? /* @__PURE__ */ u3(\"a\", { class: \"btn primary\", href: authorization, target: \"_blank\", rel: \"noopener\", children: \"Authorize connector\" }) : null,\n connector.oauth && oauthManagement ? /* @__PURE__ */ u3(S, { children: [\n /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n class: \"btn\",\n \"aria-label\": `${connector.status === \"ok\" ? \"Reconnect OAuth for\" : \"Restart authorization for\"} ${name}`,\n disabled: busy,\n onClick: () => void oauthAction(connector.id, \"reconnect\"),\n children: connector.status === \"ok\" ? \"Reconnect OAuth\" : \"Connect account\"\n }\n ),\n connector.status === \"ok\" ? /* @__PURE__ */ u3(\n \"button\",\n {\n type: \"button\",\n class: \"btn danger\",\n \"aria-label\": `Disconnect OAuth for ${name}`,\n disabled: busy,\n onClick: () => void oauthAction(connector.id, \"disconnect\"),\n children: \"Disconnect OAuth\"\n }\n ) : null\n ] }) : null,\n /* @__PURE__ */ u3(\n \"button\",\n {\n class: \"btn quiet\",\n type: \"button\",\n \"aria-label\": `Refresh ${name}`,\n disabled: connector.status === \"loading\",\n onClick: () => void refreshConnector(connector.id),\n children: \"Refresh\"\n }\n )\n ] }),\n connector.credential ? /* @__PURE__ */ u3(\n CredentialCard,\n {\n connector,\n credential: connector.credential,\n editing: state2.credentialEditing === connector.id,\n busy: state2.credentialBusy === connector.id\n }\n ) : null,\n tools.length ? /* @__PURE__ */ u3(\"details\", { open: expanded, children: [\n /* @__PURE__ */ u3(\"summary\", { class: \"disclosure\", children: [\n \"Tools (\",\n tools.length,\n \")\"\n ] }),\n /* @__PURE__ */ u3(\"div\", { class: \"tool-list\", children: tools.map((tool) => /* @__PURE__ */ u3(\"div\", { class: \"tool\", children: [\n /* @__PURE__ */ u3(\"code\", { children: tool.address }),\n tool.description ? /* @__PURE__ */ u3(\"span\", { class: \"td\", children: tool.description }) : null\n ] }, tool.address)) })\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 \"Last agent catalog read · \",\n connector.catalogAccess.state,\n \" ·\",\n \" \",\n formatDate(connector.catalogAccess.observedAt)\n ] }) : null\n ] })\n ] })\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(\"div\", { class: \"endpoint\", children: [\n /* @__PURE__ */ u3(\"code\", { id: \"mcpUrl\", class: \"mono\", children: mcpUrl }),\n /* @__PURE__ */ u3(CopyButton, { value: mcpUrl, label: \"Copy URL\" })\n ] }),\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 /* @__PURE__ */ u3(NoticeLine, { id: \"oauthNotice\", notice: state2.oauthNotice }),\n /* @__PURE__ */ u3(NoticeLine, { id: \"credentialNotice\", notice: state2.credentialNotice })\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\", 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 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 ? \"true\" : \"false\",\n children: !data ? /* @__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 expanded: Boolean(query),\n oauthManagement: Boolean(\n connector.permissions?.manageSharedAuth || connector.permissions?.connectPersonal\n ),\n state: state2,\n busy: state2.oauthBusy === connector.id\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 return OPERATOR_PAGES.filter((page) => {\n if (page === \"activity\") return Boolean(state2.data?.activityEnabled);\n return true;\n });\n }\n function OperatorNav() {\n const state2 = useOperatorState();\n if (state2.session !== \"ready\") return null;\n return /* @__PURE__ */ u3(\"div\", { class: \"mast-actions\", children: [\n /* @__PURE__ */ u3(\"nav\", { class: \"page-nav\", \"aria-label\": \"Operator pages\", children: visiblePages(state2).map((page) => /* @__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 /* @__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\", children: /* @__PURE__ */ u3(\"div\", { 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: productDescription }),\n /* @__PURE__ */ u3(\"p\", { id: \"gateCopy\", class: \"meta\", children: loading ? \"Checking your session…\" : 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\",\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 === \"activity\") return /* @__PURE__ */ u3(ActivityPage, { 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 document.title = `${PAGE_META[state2.page].label} — ${titleSuffix}`;\n }, [state2.page]);\n h2(() => {\n if (!ready) return;\n if (state2.page === \"activity\" && state2.data?.activityEnabled && state2.activityPhase === \"idle\") {\n void loadActivity(true);\n }\n });\n h2(() => {\n if (!state2.pendingFocus) return;\n document.getElementById(state2.pendingFocus)?.focus();\n focusHandled();\n }, [state2.pendingFocus]);\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";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CatalogDriftReport } from "../types.js";
|
|
2
|
-
import type { CredentialManagementCapability, UiData } from "./model.js";
|
|
2
|
+
import type { CredentialManagementCapability, UiConnector, UiData } from "./model.js";
|
|
3
3
|
/**
|
|
4
4
|
* Everything the operator app knows, and every rule for changing it, with no
|
|
5
5
|
* DOM in sight. The components render this and nothing else, so the questions
|
|
@@ -97,6 +97,43 @@ export declare function withPage(state: OperatorState, page: OperatorPage): Oper
|
|
|
97
97
|
export declare function credentialUnavailableCopy(capability?: CredentialManagementCapability): string;
|
|
98
98
|
export declare function connectorStatusLabel(status: string): string;
|
|
99
99
|
export declare function toolCountLabel(count: number): string;
|
|
100
|
+
/** The tone a status carries wherever it is rendered as a badge or a tile. */
|
|
101
|
+
export type Tone = "ok" | "warn" | "danger" | "neutral";
|
|
102
|
+
export declare function connectorStatusTone(status: string): Tone;
|
|
103
|
+
/**
|
|
104
|
+
* The deployment in four numbers, so the page answers "is anything wrong"
|
|
105
|
+
* above the list instead of only inside it. `attention` is what an operator
|
|
106
|
+
* can act on now; `unavailable` is what they cannot. A connector still loading
|
|
107
|
+
* its catalog counts only toward `total`, since calling it connected or failed
|
|
108
|
+
* would be a guess either way.
|
|
109
|
+
*/
|
|
110
|
+
export interface ConnectorSummary {
|
|
111
|
+
total: number;
|
|
112
|
+
connected: number;
|
|
113
|
+
attention: number;
|
|
114
|
+
unavailable: number;
|
|
115
|
+
tools: number;
|
|
116
|
+
/** Connectors whose last observed catalog refresh differed from the manifest. */
|
|
117
|
+
drifting: number;
|
|
118
|
+
}
|
|
119
|
+
export declare function summarizeConnectors(connectors: readonly UiConnector[]): ConnectorSummary;
|
|
120
|
+
/**
|
|
121
|
+
* The one line above the list. Connected and tool counts are always present;
|
|
122
|
+
* the two counts an operator may have to act on appear only when they are not
|
|
123
|
+
* zero, so a healthy deployment stays short.
|
|
124
|
+
*/
|
|
125
|
+
export declare function connectorSummaryParts(summary: ConnectorSummary): Array<{
|
|
126
|
+
text: string;
|
|
127
|
+
tone: Tone;
|
|
128
|
+
}>;
|
|
129
|
+
/** Who owns this connector's downstream credentials, in two words. */
|
|
130
|
+
export declare function authScopeLabel(scope: UiConnector["authScope"]): string;
|
|
131
|
+
/**
|
|
132
|
+
* What this identity may do with a connector, in one line. Being able to use it
|
|
133
|
+
* is implied by seeing it at all, so the sentence covers authentication, which
|
|
134
|
+
* is the part that differs between operators.
|
|
135
|
+
*/
|
|
136
|
+
export declare function permissionLabel(connector: UiConnector): string;
|
|
100
137
|
/**
|
|
101
138
|
* Hosted-provider catalog drift, as an operator reads it
|
|
102
139
|
* ([#343](https://github.com/zackbart/connecta/issues/343)).
|
package/dist/operator-ui/view.js
CHANGED
|
@@ -97,6 +97,77 @@ export function connectorStatusLabel(status) {
|
|
|
97
97
|
export function toolCountLabel(count) {
|
|
98
98
|
return `${count} ${count === 1 ? "tool" : "tools"}`;
|
|
99
99
|
}
|
|
100
|
+
export function connectorStatusTone(status) {
|
|
101
|
+
if (status === "ok")
|
|
102
|
+
return "ok";
|
|
103
|
+
if (status === "auth_required")
|
|
104
|
+
return "warn";
|
|
105
|
+
if (status === "loading")
|
|
106
|
+
return "neutral";
|
|
107
|
+
return "danger";
|
|
108
|
+
}
|
|
109
|
+
export function summarizeConnectors(connectors) {
|
|
110
|
+
const summary = {
|
|
111
|
+
total: connectors.length,
|
|
112
|
+
connected: 0,
|
|
113
|
+
attention: 0,
|
|
114
|
+
unavailable: 0,
|
|
115
|
+
tools: 0,
|
|
116
|
+
drifting: 0,
|
|
117
|
+
};
|
|
118
|
+
for (const connector of connectors) {
|
|
119
|
+
if (connector.status === "ok")
|
|
120
|
+
summary.connected += 1;
|
|
121
|
+
else if (connector.status === "auth_required")
|
|
122
|
+
summary.attention += 1;
|
|
123
|
+
else if (connector.status !== "loading")
|
|
124
|
+
summary.unavailable += 1;
|
|
125
|
+
summary.tools += connector.toolCount || 0;
|
|
126
|
+
if (driftState(connector.catalogDrift) === "warning")
|
|
127
|
+
summary.drifting += 1;
|
|
128
|
+
}
|
|
129
|
+
return summary;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The one line above the list. Connected and tool counts are always present;
|
|
133
|
+
* the two counts an operator may have to act on appear only when they are not
|
|
134
|
+
* zero, so a healthy deployment stays short.
|
|
135
|
+
*/
|
|
136
|
+
export function connectorSummaryParts(summary) {
|
|
137
|
+
return [
|
|
138
|
+
{ text: `${summary.connected} connected`, tone: "neutral" },
|
|
139
|
+
...(summary.attention
|
|
140
|
+
? [
|
|
141
|
+
{
|
|
142
|
+
text: `${summary.attention} need${summary.attention === 1 ? "s" : ""} authorization`,
|
|
143
|
+
tone: "warn",
|
|
144
|
+
},
|
|
145
|
+
]
|
|
146
|
+
: []),
|
|
147
|
+
...(summary.unavailable
|
|
148
|
+
? [{ text: `${summary.unavailable} unavailable`, tone: "danger" }]
|
|
149
|
+
: []),
|
|
150
|
+
{ text: toolCountLabel(summary.tools), tone: "neutral" },
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
/** Who owns this connector's downstream credentials, in two words. */
|
|
154
|
+
export function authScopeLabel(scope) {
|
|
155
|
+
return scope === "personal" ? "personal auth" : "shared auth";
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* What this identity may do with a connector, in one line. Being able to use it
|
|
159
|
+
* is implied by seeing it at all, so the sentence covers authentication, which
|
|
160
|
+
* is the part that differs between operators.
|
|
161
|
+
*/
|
|
162
|
+
export function permissionLabel(connector) {
|
|
163
|
+
if (connector.permissions?.manageSharedAuth) {
|
|
164
|
+
return "You can manage shared authentication for this connection.";
|
|
165
|
+
}
|
|
166
|
+
if (connector.permissions?.connectPersonal) {
|
|
167
|
+
return "You can connect your own account to this connection.";
|
|
168
|
+
}
|
|
169
|
+
return "Authentication for this connection is managed by your deployment.";
|
|
170
|
+
}
|
|
100
171
|
/**
|
|
101
172
|
* The four categories, in the order an operator should read them: what the
|
|
102
173
|
* deployment refuses to call, what it can no longer call, what contradicts a
|
|
@@ -6,9 +6,21 @@ export declare const CLOUDFLARE_API_BASE = "https://api.cloudflare.com/client/v4
|
|
|
6
6
|
export declare const CLOUDFLARE_MCP_ENDPOINT = "https://mcp.cloudflare.com/mcp";
|
|
7
7
|
/** Authentication schemes accepted by Cloudflare's v4 API. */
|
|
8
8
|
export type CloudflareAuthentication = "apiToken" | "globalApiKey";
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* The 21 record types Cloudflare accepts. Eight carry a single `content`
|
|
11
|
+
* string; the other thirteen carry a per-type structured `data` object.
|
|
12
|
+
* `list_dns_records` filters on all 21 because reading them costs nothing.
|
|
13
|
+
*/
|
|
10
14
|
export declare const CLOUDFLARE_DNS_RECORD_TYPES: readonly ["A", "AAAA", "CAA", "CERT", "CNAME", "DNSKEY", "DS", "HTTPS", "LOC", "MX", "NAPTR", "NS", "OPENPGPKEY", "PTR", "SMIMEA", "SRV", "SSHFP", "SVCB", "TLSA", "TXT", "URI"];
|
|
11
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Content-valued types only, and the only types `create_dns_record` and
|
|
17
|
+
* `update_dns_record` accept. Covering the thirteen structured-`data` types
|
|
18
|
+
* would mean either a free-form `data` passthrough — the untyped body this
|
|
19
|
+
* connection exists to avoid — or thirteen more hand-written schemas for record
|
|
20
|
+
* types that are rare in day-to-day zone administration. They stay fully
|
|
21
|
+
* readable; writing one goes through the approval-gated raw mutation tool with
|
|
22
|
+
* Cloudflare's documented per-type `data` body.
|
|
23
|
+
*/
|
|
12
24
|
export declare const CLOUDFLARE_CONTENT_DNS_RECORD_TYPES: readonly ["A", "AAAA", "CNAME", "MX", "NS", "OPENPGPKEY", "PTR", "TXT"];
|
|
13
25
|
interface CloudflareCommonOptions {
|
|
14
26
|
/** Human-readable display name; defaults identify the selected interface. */
|