@burdenoff/microfe-vibecontrols 2026.524.6 → 2026.524.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/shared/PageHeader.js +2 -2
- package/dist/components/shared/PageHeader.js.map +1 -1
- package/dist/components/vibe/VibeLlmContextAdminPanel.js +2 -0
- package/dist/components/vibe/VibeLlmContextAdminPanel.js.map +1 -1
- package/dist/components/vibe/VibeLlmContextTabPanel.js +218 -194
- package/dist/components/vibe/VibeLlmContextTabPanel.js.map +1 -1
- package/package.json +1 -1
|
@@ -22,7 +22,7 @@ function r({ title: r, description: i, actions: a, breadcrumb: o }) {
|
|
|
22
22
|
}, r))
|
|
23
23
|
})
|
|
24
24
|
}), /* @__PURE__ */ n("div", {
|
|
25
|
-
className: "flex
|
|
25
|
+
className: "flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between",
|
|
26
26
|
children: [/* @__PURE__ */ n(e.div, {
|
|
27
27
|
initial: {
|
|
28
28
|
opacity: 0,
|
|
@@ -33,7 +33,7 @@ function r({ title: r, description: i, actions: a, breadcrumb: o }) {
|
|
|
33
33
|
y: 0
|
|
34
34
|
},
|
|
35
35
|
transition: { duration: .2 },
|
|
36
|
-
className: "
|
|
36
|
+
className: "min-w-0 lg:flex-1",
|
|
37
37
|
children: [/* @__PURE__ */ t("h1", {
|
|
38
38
|
className: "text-2xl sm:text-3xl font-bold text-text-primary break-words",
|
|
39
39
|
children: r
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.js","names":[],"sources":["../../../src/components/shared/PageHeader.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { motion } from 'framer-motion';\n\ninterface PageHeaderProps {\n title: string;\n description?: string;\n actions?: ReactNode;\n breadcrumb?: { label: string; path?: string }[];\n}\n\nexport function PageHeader({ title, description, actions, breadcrumb }: PageHeaderProps) {\n return (\n <div data-tour=\"page-header\" className=\"mb-6\">\n {breadcrumb && breadcrumb.length > 0 && (\n <nav className=\"mb-2\">\n <ol className=\"flex items-center gap-2 text-sm text-text-secondary\">\n {breadcrumb.map((item, index) => (\n <li key={index} className=\"flex items-center gap-2\">\n {index > 0 && <span>/</span>}\n {item.path ? (\n <a href={item.path} className=\"hover:text-text-primary transition-colors\">\n {item.label}\n </a>\n ) : (\n <span className=\"text-text-primary\">{item.label}</span>\n )}\n </li>\n ))}\n </ol>\n </nav>\n )}\n <div className=\"flex
|
|
1
|
+
{"version":3,"file":"PageHeader.js","names":[],"sources":["../../../src/components/shared/PageHeader.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { motion } from 'framer-motion';\n\ninterface PageHeaderProps {\n title: string;\n description?: string;\n actions?: ReactNode;\n breadcrumb?: { label: string; path?: string }[];\n}\n\nexport function PageHeader({ title, description, actions, breadcrumb }: PageHeaderProps) {\n return (\n <div data-tour=\"page-header\" className=\"mb-6\">\n {breadcrumb && breadcrumb.length > 0 && (\n <nav className=\"mb-2\">\n <ol className=\"flex items-center gap-2 text-sm text-text-secondary\">\n {breadcrumb.map((item, index) => (\n <li key={index} className=\"flex items-center gap-2\">\n {index > 0 && <span>/</span>}\n {item.path ? (\n <a href={item.path} className=\"hover:text-text-primary transition-colors\">\n {item.label}\n </a>\n ) : (\n <span className=\"text-text-primary\">{item.label}</span>\n )}\n </li>\n ))}\n </ol>\n </nav>\n )}\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <motion.div\n initial={{ opacity: 0, y: -4 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.2 }}\n className=\"min-w-0 lg:flex-1\"\n >\n <h1 className=\"text-2xl sm:text-3xl font-bold text-text-primary break-words\">{title}</h1>\n {description && (\n <p className=\"mt-1 text-sm sm:text-base text-text-secondary\">{description}</p>\n )}\n </motion.div>\n {actions && (\n <div\n data-tour=\"page-header-actions\"\n className=\"flex flex-shrink-0 flex-wrap items-center justify-end gap-2\"\n >\n {actions}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAUA,SAAgB,EAAW,EAAE,UAAO,gBAAa,YAAS,iBAA+B;AACvF,QACE,kBAAC,OAAD;EAAK,aAAU;EAAc,WAAU;YAAvC,CACG,KAAc,EAAW,SAAS,KACjC,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,MAAD;IAAI,WAAU;cACX,EAAW,KAAK,GAAM,MACrB,kBAAC,MAAD;KAAgB,WAAU;eAA1B,CACG,IAAQ,KAAK,kBAAC,QAAD,EAAA,UAAM,KAAQ,CAAA,EAC3B,EAAK,OACJ,kBAAC,KAAD;MAAG,MAAM,EAAK;MAAM,WAAU;gBAC3B,EAAK;MACJ,CAAA,GAEJ,kBAAC,QAAD;MAAM,WAAU;gBAAqB,EAAK;MAAa,CAAA,CAEtD;OATI,EASJ,CACL;IACC,CAAA;GACD,CAAA,EAER,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,EAAO,KAAR;IACE,SAAS;KAAE,SAAS;KAAG,GAAG;KAAI;IAC9B,SAAS;KAAE,SAAS;KAAG,GAAG;KAAG;IAC7B,YAAY,EAAE,UAAU,IAAK;IAC7B,WAAU;cAJZ,CAME,kBAAC,MAAD;KAAI,WAAU;eAAgE;KAAW,CAAA,EACxF,KACC,kBAAC,KAAD;KAAG,WAAU;eAAiD;KAAgB,CAAA,CAErE;OACZ,KACC,kBAAC,OAAD;IACE,aAAU;IACV,WAAU;cAET;IACG,CAAA,CAEJ;KACF"}
|
|
@@ -172,8 +172,10 @@ function p({ vibeId: a }) {
|
|
|
172
172
|
placeholder: "reason",
|
|
173
173
|
className: "w-28 px-1.5 py-1 text-xs bg-bg-sunken border border-border-default rounded text-text-primary"
|
|
174
174
|
}), /* @__PURE__ */ c("button", {
|
|
175
|
+
type: "button",
|
|
175
176
|
onClick: () => b(e.id),
|
|
176
177
|
title: "Admin revoke",
|
|
178
|
+
"aria-label": "Admin revoke URL",
|
|
177
179
|
className: "p-1.5 text-status-error-text hover:opacity-80",
|
|
178
180
|
children: /* @__PURE__ */ c(i, { className: "w-4 h-4" })
|
|
179
181
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VibeLlmContextAdminPanel.js","names":[],"sources":["../../../src/components/vibe/VibeLlmContextAdminPanel.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Clock, Info, Shield, Trash2 } from 'lucide-react';\n\ninterface AdminTokenRow {\n id: string;\n vibeId: string;\n userId: string;\n label: string | null;\n tokenFingerprint: string;\n includeCredentials: boolean;\n includes: string[];\n status: 'ACTIVE' | 'REVOKED';\n expiresAt: string;\n lastFetchedAt: string | null;\n fetchCount: number;\n createdAt: string;\n revokedAt: string | null;\n revokedReason: string | null;\n}\n\nconst ALL_TOKENS = gql`\n query AllVibeLlmContextTokens($vibeId: ID, $userId: ID) {\n allVibeLlmContextTokens(vibeId: $vibeId, userId: $userId) {\n id\n vibeId\n userId\n label\n tokenFingerprint\n includeCredentials\n includes\n status\n expiresAt\n lastFetchedAt\n fetchCount\n createdAt\n revokedAt\n revokedReason\n }\n }\n`;\n\nconst ADMIN_REVOKE = gql`\n mutation AdminRevokeVibeLlmContextToken($tokenId: ID!, $reason: String) {\n adminRevokeVibeLlmContextToken(tokenId: $tokenId, reason: $reason) {\n id\n status\n revokedAt\n revokedReason\n }\n }\n`;\n\nfunction formatExpiry(expiresAt: string): string {\n const diff = new Date(expiresAt).getTime() - Date.now();\n if (diff < 0) return 'expired';\n const hours = Math.floor(diff / (1000 * 60 * 60));\n const mins = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));\n if (hours > 24) return `${Math.floor(hours / 24)}d`;\n if (hours > 0) return `${hours}h ${mins}m`;\n return `${mins}m`;\n}\n\ninterface VibeLlmContextAdminPanelProps {\n vibeId: string;\n}\n\nexport function VibeLlmContextAdminPanel({ vibeId }: VibeLlmContextAdminPanelProps): ReactElement {\n const { data, loading, refetch } = useQuery<{ allVibeLlmContextTokens: AdminTokenRow[] }>(\n ALL_TOKENS,\n {\n variables: { vibeId },\n fetchPolicy: 'cache-and-network',\n errorPolicy: 'ignore',\n }\n );\n const [adminRevoke] = useMutation<\n { adminRevokeVibeLlmContextToken: AdminTokenRow },\n { tokenId: string; reason?: string | null }\n >(ADMIN_REVOKE, { refetchQueries: ['AllVibeLlmContextTokens'] });\n\n const [reasonDraft, setReasonDraft] = useState<Record<string, string>>({});\n const tokens = data?.allVibeLlmContextTokens ?? [];\n\n const onRevoke = async (tokenId: string) => {\n await adminRevoke({\n variables: {\n tokenId,\n reason: (reasonDraft[tokenId] ?? '').trim() || null,\n },\n });\n setReasonDraft((prev) => {\n const next = { ...prev };\n delete next[tokenId];\n return next;\n });\n await refetch();\n };\n\n return (\n <section className=\"bg-bg-surface border border-status-warning-border rounded-lg p-5 space-y-3\">\n <header className=\"flex items-start gap-3\">\n <Shield className=\"w-5 h-5 text-status-warning-text mt-0.5\" />\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n Admin · all URLs for this vibe\n </h3>\n <p className=\"text-sm text-text-secondary\">\n Visible only to workspace admins. Lists every user's signed URLs for this vibe. Use\n revoke to immediately invalidate any URL — takes effect on the next fetch.\n </p>\n </div>\n </header>\n\n {loading && tokens.length === 0 && (\n <div className=\"text-sm text-text-secondary py-3\">Loading…</div>\n )}\n {tokens.length === 0 && !loading && (\n <div className=\"text-sm text-text-secondary py-3 flex items-center gap-2\">\n <Info className=\"w-4 h-4\" />\n No URLs minted for this vibe by any user.\n </div>\n )}\n {tokens.length > 0 && (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-default text-left text-xs text-text-secondary\">\n <th className=\"py-2 pr-3\">User</th>\n <th className=\"py-2 pr-3\">Label</th>\n <th className=\"py-2 pr-3\">Fingerprint</th>\n <th className=\"py-2 pr-3\">Creds</th>\n <th className=\"py-2 pr-3\">Status</th>\n <th className=\"py-2 pr-3\">Expires</th>\n <th className=\"py-2 pr-3\">Fetches</th>\n <th className=\"py-2 pr-3\">Revoke</th>\n </tr>\n </thead>\n <tbody>\n {tokens.map((t) => (\n <tr key={t.id} className=\"border-b border-border-subtle align-top\">\n <td\n className=\"py-2 pr-3 font-mono text-xs text-text-secondary truncate max-w-[120px]\"\n title={t.userId}\n >\n {t.userId}\n </td>\n <td className=\"py-2 pr-3 text-text-primary\">{t.label ?? '—'}</td>\n <td className=\"py-2 pr-3 font-mono text-xs text-text-secondary\">\n {t.tokenFingerprint}\n </td>\n <td className=\"py-2 pr-3\">\n {t.includeCredentials ? (\n <span className=\"text-xs text-status-warning-text\">on</span>\n ) : (\n <span className=\"text-xs text-text-secondary\">off</span>\n )}\n </td>\n <td className=\"py-2 pr-3\">\n <span\n className={`text-xs px-1.5 py-0.5 rounded ${\n t.status === 'ACTIVE'\n ? 'bg-status-success-bg/20 text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {t.status}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"w-3 h-3\" />\n {formatExpiry(t.expiresAt)}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">{t.fetchCount}</td>\n <td className=\"py-2 pr-3\">\n {t.status === 'ACTIVE' ? (\n <div className=\"flex items-center gap-1\">\n <input\n type=\"text\"\n value={reasonDraft[t.id] ?? ''}\n onChange={(e) =>\n setReasonDraft((prev) => ({ ...prev, [t.id]: e.target.value }))\n }\n placeholder=\"reason\"\n className=\"w-28 px-1.5 py-1 text-xs bg-bg-sunken border border-border-default rounded text-text-primary\"\n />\n <button\n onClick={() => onRevoke(t.id)}\n title=\"Admin revoke\"\n className=\"p-1.5 text-status-error-text hover:opacity-80\"\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n ) : (\n <span className=\"text-xs text-text-secondary\" title={t.revokedReason ?? ''}>\n {t.revokedReason ?? '—'}\n </span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VibeLlmContextAdminPanel.js","names":[],"sources":["../../../src/components/vibe/VibeLlmContextAdminPanel.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Clock, Info, Shield, Trash2 } from 'lucide-react';\n\ninterface AdminTokenRow {\n id: string;\n vibeId: string;\n userId: string;\n label: string | null;\n tokenFingerprint: string;\n includeCredentials: boolean;\n includes: string[];\n status: 'ACTIVE' | 'REVOKED';\n expiresAt: string;\n lastFetchedAt: string | null;\n fetchCount: number;\n createdAt: string;\n revokedAt: string | null;\n revokedReason: string | null;\n}\n\nconst ALL_TOKENS = gql`\n query AllVibeLlmContextTokens($vibeId: ID, $userId: ID) {\n allVibeLlmContextTokens(vibeId: $vibeId, userId: $userId) {\n id\n vibeId\n userId\n label\n tokenFingerprint\n includeCredentials\n includes\n status\n expiresAt\n lastFetchedAt\n fetchCount\n createdAt\n revokedAt\n revokedReason\n }\n }\n`;\n\nconst ADMIN_REVOKE = gql`\n mutation AdminRevokeVibeLlmContextToken($tokenId: ID!, $reason: String) {\n adminRevokeVibeLlmContextToken(tokenId: $tokenId, reason: $reason) {\n id\n status\n revokedAt\n revokedReason\n }\n }\n`;\n\nfunction formatExpiry(expiresAt: string): string {\n const diff = new Date(expiresAt).getTime() - Date.now();\n if (diff < 0) return 'expired';\n const hours = Math.floor(diff / (1000 * 60 * 60));\n const mins = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));\n if (hours > 24) return `${Math.floor(hours / 24)}d`;\n if (hours > 0) return `${hours}h ${mins}m`;\n return `${mins}m`;\n}\n\ninterface VibeLlmContextAdminPanelProps {\n vibeId: string;\n}\n\nexport function VibeLlmContextAdminPanel({ vibeId }: VibeLlmContextAdminPanelProps): ReactElement {\n const { data, loading, refetch } = useQuery<{ allVibeLlmContextTokens: AdminTokenRow[] }>(\n ALL_TOKENS,\n {\n variables: { vibeId },\n fetchPolicy: 'cache-and-network',\n errorPolicy: 'ignore',\n }\n );\n const [adminRevoke] = useMutation<\n { adminRevokeVibeLlmContextToken: AdminTokenRow },\n { tokenId: string; reason?: string | null }\n >(ADMIN_REVOKE, { refetchQueries: ['AllVibeLlmContextTokens'] });\n\n const [reasonDraft, setReasonDraft] = useState<Record<string, string>>({});\n const tokens = data?.allVibeLlmContextTokens ?? [];\n\n const onRevoke = async (tokenId: string) => {\n await adminRevoke({\n variables: {\n tokenId,\n reason: (reasonDraft[tokenId] ?? '').trim() || null,\n },\n });\n setReasonDraft((prev) => {\n const next = { ...prev };\n delete next[tokenId];\n return next;\n });\n await refetch();\n };\n\n return (\n <section className=\"bg-bg-surface border border-status-warning-border rounded-lg p-5 space-y-3\">\n <header className=\"flex items-start gap-3\">\n <Shield className=\"w-5 h-5 text-status-warning-text mt-0.5\" />\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n Admin · all URLs for this vibe\n </h3>\n <p className=\"text-sm text-text-secondary\">\n Visible only to workspace admins. Lists every user's signed URLs for this vibe. Use\n revoke to immediately invalidate any URL — takes effect on the next fetch.\n </p>\n </div>\n </header>\n\n {loading && tokens.length === 0 && (\n <div className=\"text-sm text-text-secondary py-3\">Loading…</div>\n )}\n {tokens.length === 0 && !loading && (\n <div className=\"text-sm text-text-secondary py-3 flex items-center gap-2\">\n <Info className=\"w-4 h-4\" />\n No URLs minted for this vibe by any user.\n </div>\n )}\n {tokens.length > 0 && (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-default text-left text-xs text-text-secondary\">\n <th className=\"py-2 pr-3\">User</th>\n <th className=\"py-2 pr-3\">Label</th>\n <th className=\"py-2 pr-3\">Fingerprint</th>\n <th className=\"py-2 pr-3\">Creds</th>\n <th className=\"py-2 pr-3\">Status</th>\n <th className=\"py-2 pr-3\">Expires</th>\n <th className=\"py-2 pr-3\">Fetches</th>\n <th className=\"py-2 pr-3\">Revoke</th>\n </tr>\n </thead>\n <tbody>\n {tokens.map((t) => (\n <tr key={t.id} className=\"border-b border-border-subtle align-top\">\n <td\n className=\"py-2 pr-3 font-mono text-xs text-text-secondary truncate max-w-[120px]\"\n title={t.userId}\n >\n {t.userId}\n </td>\n <td className=\"py-2 pr-3 text-text-primary\">{t.label ?? '—'}</td>\n <td className=\"py-2 pr-3 font-mono text-xs text-text-secondary\">\n {t.tokenFingerprint}\n </td>\n <td className=\"py-2 pr-3\">\n {t.includeCredentials ? (\n <span className=\"text-xs text-status-warning-text\">on</span>\n ) : (\n <span className=\"text-xs text-text-secondary\">off</span>\n )}\n </td>\n <td className=\"py-2 pr-3\">\n <span\n className={`text-xs px-1.5 py-0.5 rounded ${\n t.status === 'ACTIVE'\n ? 'bg-status-success-bg/20 text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {t.status}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"w-3 h-3\" />\n {formatExpiry(t.expiresAt)}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">{t.fetchCount}</td>\n <td className=\"py-2 pr-3\">\n {t.status === 'ACTIVE' ? (\n <div className=\"flex items-center gap-1\">\n <input\n type=\"text\"\n value={reasonDraft[t.id] ?? ''}\n onChange={(e) =>\n setReasonDraft((prev) => ({ ...prev, [t.id]: e.target.value }))\n }\n placeholder=\"reason\"\n className=\"w-28 px-1.5 py-1 text-xs bg-bg-sunken border border-border-default rounded text-text-primary\"\n />\n <button\n type=\"button\"\n onClick={() => onRevoke(t.id)}\n title=\"Admin revoke\"\n aria-label=\"Admin revoke URL\"\n className=\"p-1.5 text-status-error-text hover:opacity-80\"\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </div>\n ) : (\n <span className=\"text-xs text-text-secondary\" title={t.revokedReason ?? ''}>\n {t.revokedReason ?? '—'}\n </span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { VIBE_PERMISSIONS as e } from "../../constants/permissions.js";
|
|
2
2
|
import { VibeLlmContextAdminPanel as t } from "./VibeLlmContextAdminPanel.js";
|
|
3
|
-
import {
|
|
4
|
-
import { Bot as
|
|
5
|
-
import { gql as
|
|
6
|
-
import { useMutation as
|
|
7
|
-
import { usePermissions as
|
|
8
|
-
import { Fragment as
|
|
3
|
+
import { Fragment as n, useEffect as r, useState as i } from "react";
|
|
4
|
+
import { AlertTriangle as a, Bot as o, Check as s, Clock as c, Copy as ee, EyeOff as te, Info as l, Lock as u, RefreshCw as ne, RotateCw as re, Trash2 as d } from "lucide-react";
|
|
5
|
+
import { gql as f } from "@apollo/client";
|
|
6
|
+
import { useMutation as p, useQuery as m } from "@apollo/client/react";
|
|
7
|
+
import { usePermissions as h } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
8
|
+
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
9
9
|
//#region src/components/vibe/VibeLlmContextTabPanel.tsx
|
|
10
|
-
var
|
|
10
|
+
var y = [
|
|
11
11
|
"core",
|
|
12
12
|
"agents",
|
|
13
13
|
"sessions",
|
|
@@ -17,7 +17,7 @@ var v = [
|
|
|
17
17
|
"config",
|
|
18
18
|
"security",
|
|
19
19
|
"plugins"
|
|
20
|
-
],
|
|
20
|
+
], ie = f`
|
|
21
21
|
query MyVibeLlmContextSettings($vibeId: ID!) {
|
|
22
22
|
myVibeLlmContextSettings(vibeId: $vibeId) {
|
|
23
23
|
vibeId
|
|
@@ -33,7 +33,7 @@ var v = [
|
|
|
33
33
|
updatedAt
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
`, b =
|
|
36
|
+
`, b = f`
|
|
37
37
|
query MyVibeLlmContextTokens($vibeId: ID!) {
|
|
38
38
|
myVibeLlmContextTokens(vibeId: $vibeId) {
|
|
39
39
|
id
|
|
@@ -52,7 +52,7 @@ var v = [
|
|
|
52
52
|
revokedReason
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
`,
|
|
55
|
+
`, x = f`
|
|
56
56
|
mutation SetMyVibeLlmContextSettings($vibeId: ID!, $input: VibeLlmContextSettingsInput!) {
|
|
57
57
|
setMyVibeLlmContextSettings(vibeId: $vibeId, input: $input) {
|
|
58
58
|
vibeId
|
|
@@ -68,7 +68,7 @@ var v = [
|
|
|
68
68
|
updatedAt
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
`,
|
|
71
|
+
`, ae = f`
|
|
72
72
|
mutation GenerateVibeLlmContextUrl($vibeId: ID!, $input: VibeLlmContextMintInput) {
|
|
73
73
|
generateVibeLlmContextUrl(vibeId: $vibeId, input: $input) {
|
|
74
74
|
tokenId
|
|
@@ -82,7 +82,7 @@ var v = [
|
|
|
82
82
|
tokenFingerprint
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
`,
|
|
85
|
+
`, oe = f`
|
|
86
86
|
mutation RevokeVibeLlmContextToken($tokenId: ID!) {
|
|
87
87
|
revokeVibeLlmContextToken(tokenId: $tokenId) {
|
|
88
88
|
id
|
|
@@ -90,7 +90,7 @@ var v = [
|
|
|
90
90
|
revokedAt
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
`,
|
|
93
|
+
`, S = f`
|
|
94
94
|
mutation RotateVibeLlmContextUrl($tokenId: ID!, $input: VibeLlmContextMintInput) {
|
|
95
95
|
rotateVibeLlmContextUrl(tokenId: $tokenId, input: $input) {
|
|
96
96
|
tokenId
|
|
@@ -104,11 +104,11 @@ var v = [
|
|
|
104
104
|
tokenFingerprint
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
`,
|
|
107
|
+
`, C = f`
|
|
108
108
|
mutation RevokeAllMyVibeLlmContextTokens($vibeId: ID!) {
|
|
109
109
|
revokeAllMyVibeLlmContextTokens(vibeId: $vibeId)
|
|
110
110
|
}
|
|
111
|
-
`,
|
|
111
|
+
`, w = f`
|
|
112
112
|
query MyVibeLlmContextTokenAudits($tokenId: ID!, $limit: Int) {
|
|
113
113
|
myVibeLlmContextTokenAudits(tokenId: $tokenId, limit: $limit) {
|
|
114
114
|
id
|
|
@@ -121,7 +121,7 @@ var v = [
|
|
|
121
121
|
status
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
`,
|
|
124
|
+
`, T = [
|
|
125
125
|
{
|
|
126
126
|
label: "1 hour",
|
|
127
127
|
hours: 1
|
|
@@ -139,7 +139,7 @@ var v = [
|
|
|
139
139
|
hours: 168
|
|
140
140
|
}
|
|
141
141
|
];
|
|
142
|
-
async function
|
|
142
|
+
async function se(e) {
|
|
143
143
|
try {
|
|
144
144
|
await navigator.clipboard.writeText(e);
|
|
145
145
|
} catch {
|
|
@@ -147,396 +147,420 @@ async function D(e) {
|
|
|
147
147
|
t.value = e, t.style.position = "fixed", t.style.opacity = "0", document.body.appendChild(t), t.select(), document.execCommand("copy"), document.body.removeChild(t);
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
-
function
|
|
150
|
+
function E(e) {
|
|
151
151
|
let t = new Date(e).getTime() - Date.now();
|
|
152
152
|
if (t < 0) return "expired";
|
|
153
153
|
let n = Math.floor(t / (1e3 * 60 * 60)), r = Math.floor(t % (1e3 * 60 * 60) / (1e3 * 60));
|
|
154
154
|
return n > 24 ? `${Math.floor(n / 24)}d` : n > 0 ? `${n}h ${r}m` : `${r}m`;
|
|
155
155
|
}
|
|
156
|
-
function
|
|
157
|
-
let { hasPermission:
|
|
158
|
-
variables: { vibeId:
|
|
156
|
+
function D({ vibeId: f, attachedAgents: w = [] }) {
|
|
157
|
+
let { hasPermission: D } = h(), le = D(e.VIBE_MANAGE), ue = m(ie, {
|
|
158
|
+
variables: { vibeId: f },
|
|
159
159
|
fetchPolicy: "cache-and-network"
|
|
160
|
-
}),
|
|
161
|
-
variables: { vibeId:
|
|
160
|
+
}), O = m(b, {
|
|
161
|
+
variables: { vibeId: f },
|
|
162
162
|
fetchPolicy: "cache-and-network"
|
|
163
|
-
}), [
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}, [
|
|
167
|
-
let
|
|
168
|
-
|
|
163
|
+
}), [de, k] = p(x, { refetchQueries: ["MyVibeLlmContextSettings"] }), [fe, A] = p(ae, { refetchQueries: ["MyVibeLlmContextTokens"] }), [j] = p(oe, { refetchQueries: ["MyVibeLlmContextTokens"] }), [M] = p(S, { refetchQueries: ["MyVibeLlmContextTokens"] }), [N] = p(C, { refetchQueries: ["MyVibeLlmContextTokens"] }), P = ue.data?.myVibeLlmContextSettings, F = O.data?.myVibeLlmContextTokens ?? [], [I, L] = i(1), [R, z] = i(!1), [B, V] = i(new Set(y)), [H, U] = i(""), [W, G] = i(""), [K, q] = i(""), [J, Y] = i(null), [pe, X] = i(!1), [Z, Q] = i(!1), [$, me] = i(null);
|
|
164
|
+
r(() => {
|
|
165
|
+
P && (L(Math.max(1, Math.round((P.ttlSeconds ?? 3600) / 3600))), z(P.includeCredentials), V(new Set(P.includes ?? y)), U(P.customContextText ?? ""), G(P.defaultAgentIdOverride ?? ""));
|
|
166
|
+
}, [P]);
|
|
167
|
+
let he = (e) => {
|
|
168
|
+
V((t) => {
|
|
169
169
|
let n = new Set(t);
|
|
170
170
|
return n.has(e) ? n.delete(e) : n.add(e), n;
|
|
171
171
|
});
|
|
172
172
|
};
|
|
173
|
-
return /* @__PURE__ */
|
|
173
|
+
return /* @__PURE__ */ v("div", {
|
|
174
174
|
className: "space-y-6 max-w-5xl",
|
|
175
175
|
children: [
|
|
176
|
-
/* @__PURE__ */
|
|
176
|
+
/* @__PURE__ */ _("div", {
|
|
177
177
|
className: "rounded-lg border border-status-warning-border bg-status-warning-bg/30 p-4",
|
|
178
|
-
children: /* @__PURE__ */
|
|
178
|
+
children: /* @__PURE__ */ v("div", {
|
|
179
179
|
className: "flex items-start gap-3",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
180
|
+
children: [/* @__PURE__ */ _(u, { className: "w-5 h-5 text-status-warning-text mt-0.5" }), /* @__PURE__ */ v("div", {
|
|
181
181
|
className: "text-sm text-text-primary",
|
|
182
|
-
children: [/* @__PURE__ */
|
|
182
|
+
children: [/* @__PURE__ */ _("p", {
|
|
183
183
|
className: "font-medium mb-1",
|
|
184
184
|
children: "LLM Context — share this vibe with any LLM via a signed URL"
|
|
185
|
-
}), /* @__PURE__ */
|
|
185
|
+
}), /* @__PURE__ */ _("p", {
|
|
186
186
|
className: "text-text-secondary",
|
|
187
187
|
children: "Anyone with the URL can read the snapshot until it expires. When \"Include credentials\" is on, the snapshot exposes agent tunnel URLs + API keys. Default is redacted. Rotate or revoke any URL from the list below at any time."
|
|
188
188
|
})]
|
|
189
189
|
})]
|
|
190
190
|
})
|
|
191
191
|
}),
|
|
192
|
-
/* @__PURE__ */
|
|
192
|
+
/* @__PURE__ */ v("section", {
|
|
193
193
|
className: "bg-bg-surface border border-border-default rounded-lg p-5 space-y-4",
|
|
194
194
|
children: [
|
|
195
|
-
/* @__PURE__ */
|
|
195
|
+
/* @__PURE__ */ v("header", {
|
|
196
196
|
className: "flex items-center justify-between",
|
|
197
|
-
children: [/* @__PURE__ */
|
|
197
|
+
children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("h3", {
|
|
198
198
|
className: "text-base font-semibold text-text-primary",
|
|
199
199
|
children: "Saved settings"
|
|
200
|
-
}), /* @__PURE__ */
|
|
200
|
+
}), /* @__PURE__ */ _("p", {
|
|
201
201
|
className: "text-sm text-text-secondary",
|
|
202
202
|
children: "Defaults used when you generate a URL. Snapshotted into each minted token, so future edits don't change already-minted URLs."
|
|
203
|
-
})] }), /* @__PURE__ */
|
|
203
|
+
})] }), /* @__PURE__ */ v("button", {
|
|
204
|
+
type: "button",
|
|
204
205
|
onClick: async () => {
|
|
205
|
-
await
|
|
206
|
-
vibeId:
|
|
206
|
+
await de({ variables: {
|
|
207
|
+
vibeId: f,
|
|
207
208
|
input: {
|
|
208
|
-
ttlSeconds: Math.max(60, Math.min(10080 * 60,
|
|
209
|
-
includeCredentials:
|
|
210
|
-
includes: Array.from(
|
|
211
|
-
customContextText:
|
|
212
|
-
defaultAgentIdOverride:
|
|
209
|
+
ttlSeconds: Math.max(60, Math.min(10080 * 60, I * 60 * 60)),
|
|
210
|
+
includeCredentials: R,
|
|
211
|
+
includes: Array.from(B),
|
|
212
|
+
customContextText: H,
|
|
213
|
+
defaultAgentIdOverride: W || null
|
|
213
214
|
}
|
|
214
|
-
} });
|
|
215
|
+
} }), Q(!0), setTimeout(() => Q(!1), 2e3);
|
|
215
216
|
},
|
|
216
|
-
disabled:
|
|
217
|
-
className: "px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50",
|
|
218
|
-
children:
|
|
217
|
+
disabled: k.loading,
|
|
218
|
+
className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50",
|
|
219
|
+
children: [Z && !k.loading && /* @__PURE__ */ _(s, { className: "w-4 h-4" }), k.loading ? "Saving…" : Z ? "Saved" : "Save settings"]
|
|
219
220
|
})]
|
|
220
221
|
}),
|
|
221
|
-
/* @__PURE__ */
|
|
222
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
|
|
222
223
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
223
224
|
children: "URL expiry"
|
|
224
|
-
}), /* @__PURE__ */
|
|
225
|
+
}), /* @__PURE__ */ v("div", {
|
|
225
226
|
className: "flex flex-wrap items-center gap-2",
|
|
226
227
|
children: [
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
T.map((e) => /* @__PURE__ */ _("button", {
|
|
229
|
+
type: "button",
|
|
230
|
+
onClick: () => L(e.hours),
|
|
231
|
+
className: `px-3 py-1.5 text-sm rounded-md border ${I === e.hours ? "bg-action-primary-bg text-action-primary-text border-action-primary-bg" : "bg-bg-sunken text-text-primary border-border-default"}`,
|
|
230
232
|
children: e.label
|
|
231
233
|
}, e.hours)),
|
|
232
|
-
/* @__PURE__ */
|
|
234
|
+
/* @__PURE__ */ _("span", {
|
|
233
235
|
className: "text-sm text-text-secondary mx-1",
|
|
234
236
|
children: "or custom hours:"
|
|
235
237
|
}),
|
|
236
|
-
/* @__PURE__ */
|
|
238
|
+
/* @__PURE__ */ _("input", {
|
|
237
239
|
type: "number",
|
|
238
240
|
min: 1,
|
|
239
241
|
max: 168,
|
|
240
|
-
value:
|
|
241
|
-
onChange: (e) =>
|
|
242
|
+
value: I,
|
|
243
|
+
onChange: (e) => L(Math.max(1, Math.min(168, Number(e.target.value) || 1))),
|
|
242
244
|
className: "w-24 px-2 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary"
|
|
243
245
|
})
|
|
244
246
|
]
|
|
245
247
|
})] }),
|
|
246
|
-
/* @__PURE__ */
|
|
248
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ v("label", {
|
|
247
249
|
className: "flex items-center gap-2 text-sm text-text-primary",
|
|
248
250
|
children: [
|
|
249
|
-
/* @__PURE__ */
|
|
251
|
+
/* @__PURE__ */ _("input", {
|
|
250
252
|
type: "checkbox",
|
|
251
|
-
checked:
|
|
252
|
-
onChange: (e) =>
|
|
253
|
+
checked: R,
|
|
254
|
+
onChange: (e) => z(e.target.checked),
|
|
253
255
|
className: "w-4 h-4"
|
|
254
256
|
}),
|
|
255
|
-
/* @__PURE__ */
|
|
256
|
-
|
|
257
|
+
/* @__PURE__ */ _("span", { children: "Include credentials (tunnel URLs + agent API keys)" }),
|
|
258
|
+
R ? /* @__PURE__ */ _(a, {
|
|
259
|
+
className: "w-4 h-4 text-status-warning-text",
|
|
260
|
+
"aria-label": "Credentials will be exposed in the snapshot"
|
|
261
|
+
}) : /* @__PURE__ */ _(te, {
|
|
262
|
+
className: "w-4 h-4 text-text-secondary",
|
|
263
|
+
"aria-label": "Credentials redacted"
|
|
264
|
+
})
|
|
257
265
|
]
|
|
258
|
-
})
|
|
259
|
-
|
|
266
|
+
}), R && /* @__PURE__ */ v("p", {
|
|
267
|
+
className: "mt-1.5 text-xs text-status-warning-text flex items-start gap-1.5",
|
|
268
|
+
children: [/* @__PURE__ */ _(a, { className: "w-3.5 h-3.5 mt-0.5 flex-shrink-0" }), /* @__PURE__ */ _("span", { children: "Anyone with a URL minted while this is on can read live agent tunnel URLs and API keys. Only enable for trusted recipients." })]
|
|
269
|
+
})] }),
|
|
270
|
+
/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
|
|
260
271
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
261
272
|
children: "Sections to include"
|
|
262
|
-
}), /* @__PURE__ */
|
|
273
|
+
}), /* @__PURE__ */ _("div", {
|
|
263
274
|
className: "flex flex-wrap gap-2",
|
|
264
|
-
children:
|
|
265
|
-
|
|
266
|
-
|
|
275
|
+
children: y.map((e) => /* @__PURE__ */ _("button", {
|
|
276
|
+
type: "button",
|
|
277
|
+
onClick: () => he(e),
|
|
278
|
+
className: `px-2.5 py-1 text-xs rounded-full border ${B.has(e) ? "bg-action-primary-bg/10 text-action-primary-bg border-action-primary-bg" : "bg-bg-sunken text-text-secondary border-border-default"}`,
|
|
267
279
|
children: e
|
|
268
280
|
}, e))
|
|
269
281
|
})] }),
|
|
270
|
-
|
|
282
|
+
w.length > 0 && /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
|
|
271
283
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
272
284
|
children: "Default agent for context fetch"
|
|
273
|
-
}), /* @__PURE__ */
|
|
274
|
-
value:
|
|
275
|
-
onChange: (e) =>
|
|
285
|
+
}), /* @__PURE__ */ v("select", {
|
|
286
|
+
value: W,
|
|
287
|
+
onChange: (e) => G(e.target.value),
|
|
276
288
|
className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary",
|
|
277
|
-
children: [/* @__PURE__ */
|
|
289
|
+
children: [/* @__PURE__ */ _("option", {
|
|
278
290
|
value: "",
|
|
279
291
|
children: "(use my per-vibe default from settings)"
|
|
280
|
-
}),
|
|
292
|
+
}), w.map((e) => /* @__PURE__ */ _("option", {
|
|
281
293
|
value: e.id,
|
|
282
294
|
children: e.name
|
|
283
295
|
}, e.id))]
|
|
284
296
|
})] }),
|
|
285
|
-
/* @__PURE__ */
|
|
286
|
-
/* @__PURE__ */
|
|
297
|
+
/* @__PURE__ */ v("div", { children: [
|
|
298
|
+
/* @__PURE__ */ _("label", {
|
|
287
299
|
className: "block text-sm font-medium text-text-primary mb-2",
|
|
288
300
|
children: "Custom context text"
|
|
289
301
|
}),
|
|
290
|
-
/* @__PURE__ */
|
|
291
|
-
value:
|
|
292
|
-
onChange: (e) =>
|
|
302
|
+
/* @__PURE__ */ _("textarea", {
|
|
303
|
+
value: H,
|
|
304
|
+
onChange: (e) => U(e.target.value.slice(0, 8192)),
|
|
293
305
|
rows: 5,
|
|
294
306
|
placeholder: "Free-form notes embedded in every snapshot you mint AFTER saving (existing tokens keep their original copy).",
|
|
295
307
|
className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder"
|
|
296
308
|
}),
|
|
297
|
-
/* @__PURE__ */
|
|
309
|
+
/* @__PURE__ */ v("p", {
|
|
298
310
|
className: "text-xs text-text-secondary mt-1",
|
|
299
|
-
children: [
|
|
311
|
+
children: [H.length, " / 8192 chars"]
|
|
300
312
|
})
|
|
301
313
|
] })
|
|
302
314
|
]
|
|
303
315
|
}),
|
|
304
|
-
/* @__PURE__ */
|
|
316
|
+
/* @__PURE__ */ v("section", {
|
|
305
317
|
className: "bg-bg-surface border border-border-default rounded-lg p-5 space-y-4",
|
|
306
318
|
children: [
|
|
307
|
-
/* @__PURE__ */
|
|
319
|
+
/* @__PURE__ */ v("header", { children: [/* @__PURE__ */ _("h3", {
|
|
308
320
|
className: "text-base font-semibold text-text-primary",
|
|
309
321
|
children: "Generate a new URL"
|
|
310
|
-
}), /* @__PURE__ */
|
|
322
|
+
}), /* @__PURE__ */ _("p", {
|
|
311
323
|
className: "text-sm text-text-secondary",
|
|
312
324
|
children: "Mints a fresh signed URL using your current settings. The full token is only shown once — copy it before navigating away. Use Rotate below if you lose it."
|
|
313
325
|
})] }),
|
|
314
|
-
/* @__PURE__ */
|
|
326
|
+
/* @__PURE__ */ v("div", {
|
|
315
327
|
className: "flex flex-wrap items-end gap-2",
|
|
316
|
-
children: [/* @__PURE__ */
|
|
328
|
+
children: [/* @__PURE__ */ v("div", {
|
|
317
329
|
className: "flex-1 min-w-[200px]",
|
|
318
|
-
children: [/* @__PURE__ */
|
|
330
|
+
children: [/* @__PURE__ */ _("label", {
|
|
319
331
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
320
332
|
children: "Label (optional)"
|
|
321
|
-
}), /* @__PURE__ */
|
|
333
|
+
}), /* @__PURE__ */ _("input", {
|
|
322
334
|
type: "text",
|
|
323
|
-
value:
|
|
324
|
-
onChange: (e) =>
|
|
335
|
+
value: K,
|
|
336
|
+
onChange: (e) => q(e.target.value.slice(0, 120)),
|
|
325
337
|
placeholder: "e.g. Claude desktop",
|
|
326
338
|
className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder"
|
|
327
339
|
})]
|
|
328
|
-
}), /* @__PURE__ */
|
|
340
|
+
}), /* @__PURE__ */ _("button", {
|
|
341
|
+
type: "button",
|
|
329
342
|
onClick: async () => {
|
|
330
|
-
let e = await
|
|
331
|
-
vibeId:
|
|
343
|
+
let e = await fe({ variables: {
|
|
344
|
+
vibeId: f,
|
|
332
345
|
input: {
|
|
333
|
-
label:
|
|
334
|
-
ttlSeconds: Math.max(60, Math.min(10080 * 60,
|
|
335
|
-
includeCredentials:
|
|
336
|
-
includes: Array.from(
|
|
346
|
+
label: K || null,
|
|
347
|
+
ttlSeconds: Math.max(60, Math.min(10080 * 60, I * 60 * 60)),
|
|
348
|
+
includeCredentials: R,
|
|
349
|
+
includes: Array.from(B)
|
|
337
350
|
}
|
|
338
351
|
} });
|
|
339
|
-
e.data && (
|
|
352
|
+
e.data && (Y(e.data.generateVibeLlmContextUrl), X(!1), q(""));
|
|
340
353
|
},
|
|
341
|
-
disabled:
|
|
354
|
+
disabled: A.loading,
|
|
342
355
|
className: "px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50",
|
|
343
|
-
children:
|
|
356
|
+
children: A.loading ? "Generating…" : "Generate URL"
|
|
344
357
|
})]
|
|
345
358
|
}),
|
|
346
|
-
|
|
359
|
+
J && /* @__PURE__ */ v("div", {
|
|
347
360
|
className: "rounded-md border border-status-success-border bg-status-success-bg/20 p-3",
|
|
348
|
-
children: [/* @__PURE__ */
|
|
361
|
+
children: [/* @__PURE__ */ v("div", {
|
|
349
362
|
className: "flex items-center gap-2 text-sm mb-2",
|
|
350
363
|
children: [
|
|
351
|
-
/* @__PURE__ */
|
|
352
|
-
/* @__PURE__ */
|
|
364
|
+
/* @__PURE__ */ _(s, { className: "w-4 h-4 text-status-success-text" }),
|
|
365
|
+
/* @__PURE__ */ _("span", {
|
|
353
366
|
className: "font-medium text-text-primary",
|
|
354
367
|
children: "URL generated"
|
|
355
368
|
}),
|
|
356
|
-
/* @__PURE__ */
|
|
369
|
+
/* @__PURE__ */ v("span", {
|
|
357
370
|
className: "text-xs text-text-secondary",
|
|
358
|
-
children: ["expires in ",
|
|
371
|
+
children: ["expires in ", E(J.expiresAt)]
|
|
359
372
|
})
|
|
360
373
|
]
|
|
361
|
-
}), /* @__PURE__ */
|
|
374
|
+
}), /* @__PURE__ */ v("div", {
|
|
362
375
|
className: "flex items-center gap-2",
|
|
363
|
-
children: [/* @__PURE__ */
|
|
376
|
+
children: [/* @__PURE__ */ _("input", {
|
|
364
377
|
readOnly: !0,
|
|
365
|
-
value:
|
|
378
|
+
value: J.url,
|
|
366
379
|
className: "flex-1 px-2 py-1.5 text-xs bg-bg-sunken border border-border-default rounded font-mono text-text-primary",
|
|
367
380
|
"aria-label": "Generated LLM context URL"
|
|
368
|
-
}), /* @__PURE__ */
|
|
381
|
+
}), /* @__PURE__ */ _("button", {
|
|
382
|
+
type: "button",
|
|
369
383
|
onClick: async () => {
|
|
370
|
-
|
|
384
|
+
J && (await se(J.url), X(!0), setTimeout(() => X(!1), 2e3));
|
|
371
385
|
},
|
|
372
386
|
className: "px-2 py-1.5 text-xs bg-bg-sunken border border-border-default rounded text-text-primary",
|
|
373
387
|
"aria-label": "Copy URL",
|
|
374
|
-
children:
|
|
388
|
+
children: pe ? /* @__PURE__ */ _(s, { className: "w-4 h-4 text-status-success-text" }) : /* @__PURE__ */ _(ee, { className: "w-4 h-4" })
|
|
375
389
|
})]
|
|
376
390
|
})]
|
|
377
391
|
})
|
|
378
392
|
]
|
|
379
393
|
}),
|
|
380
|
-
/* @__PURE__ */
|
|
394
|
+
/* @__PURE__ */ v("section", {
|
|
381
395
|
className: "bg-bg-surface border border-border-default rounded-lg p-5 space-y-3",
|
|
382
396
|
children: [
|
|
383
|
-
/* @__PURE__ */
|
|
397
|
+
/* @__PURE__ */ v("header", {
|
|
384
398
|
className: "flex items-center justify-between",
|
|
385
|
-
children: [/* @__PURE__ */
|
|
399
|
+
children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("h3", {
|
|
386
400
|
className: "text-base font-semibold text-text-primary",
|
|
387
401
|
children: "Your active URLs"
|
|
388
|
-
}), /* @__PURE__ */
|
|
402
|
+
}), /* @__PURE__ */ _("p", {
|
|
389
403
|
className: "text-sm text-text-secondary",
|
|
390
404
|
children: "Tokens you minted for this vibe. Revoke and rotate work immediately; revoked tokens fail with 403 even if the JWT hasn't expired."
|
|
391
|
-
})] }), /* @__PURE__ */
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
405
|
+
})] }), /* @__PURE__ */ v("button", {
|
|
406
|
+
type: "button",
|
|
407
|
+
onClick: async () => {
|
|
408
|
+
typeof window < "u" && !window.confirm("Revoke ALL active URLs for this vibe? Every minted URL stops working immediately and cannot be un-revoked (use Rotate to issue a fresh one).") || await N({ variables: { vibeId: f } });
|
|
409
|
+
},
|
|
410
|
+
disabled: F.every((e) => e.status !== "ACTIVE"),
|
|
411
|
+
className: "flex items-center gap-1 px-3 py-1.5 text-sm bg-status-error-bg/10 text-status-error-text border border-status-error-border rounded-md hover:bg-status-error-bg/20 disabled:opacity-40 disabled:cursor-not-allowed",
|
|
412
|
+
children: [/* @__PURE__ */ _(d, { className: "w-4 h-4" }), "Revoke all"]
|
|
395
413
|
})]
|
|
396
414
|
}),
|
|
397
|
-
|
|
415
|
+
O.loading && F.length === 0 && /* @__PURE__ */ v("div", {
|
|
398
416
|
className: "text-sm text-text-secondary py-4 flex items-center gap-2",
|
|
399
|
-
children: [/* @__PURE__ */
|
|
417
|
+
children: [/* @__PURE__ */ _(ne, { className: "w-4 h-4 animate-spin" }), "Loading tokens…"]
|
|
400
418
|
}),
|
|
401
|
-
|
|
419
|
+
F.length === 0 && !O.loading && /* @__PURE__ */ v("div", {
|
|
402
420
|
className: "text-sm text-text-secondary py-4 flex items-center gap-2",
|
|
403
|
-
children: [/* @__PURE__ */
|
|
421
|
+
children: [/* @__PURE__ */ _(l, { className: "w-4 h-4" }), "No URLs minted yet for this vibe."]
|
|
404
422
|
}),
|
|
405
|
-
|
|
423
|
+
F.length > 0 && /* @__PURE__ */ _("div", {
|
|
406
424
|
className: "overflow-x-auto",
|
|
407
|
-
children: /* @__PURE__ */
|
|
425
|
+
children: /* @__PURE__ */ v("table", {
|
|
408
426
|
className: "w-full text-sm",
|
|
409
|
-
children: [/* @__PURE__ */
|
|
427
|
+
children: [/* @__PURE__ */ _("thead", { children: /* @__PURE__ */ v("tr", {
|
|
410
428
|
className: "border-b border-border-default text-left text-xs text-text-secondary",
|
|
411
429
|
children: [
|
|
412
|
-
/* @__PURE__ */
|
|
430
|
+
/* @__PURE__ */ _("th", {
|
|
413
431
|
className: "py-2 pr-3",
|
|
414
432
|
children: "Label"
|
|
415
433
|
}),
|
|
416
|
-
/* @__PURE__ */
|
|
434
|
+
/* @__PURE__ */ _("th", {
|
|
417
435
|
className: "py-2 pr-3",
|
|
418
436
|
children: "Fingerprint"
|
|
419
437
|
}),
|
|
420
|
-
/* @__PURE__ */
|
|
438
|
+
/* @__PURE__ */ _("th", {
|
|
421
439
|
className: "py-2 pr-3",
|
|
422
440
|
children: "Sections"
|
|
423
441
|
}),
|
|
424
|
-
/* @__PURE__ */
|
|
442
|
+
/* @__PURE__ */ _("th", {
|
|
425
443
|
className: "py-2 pr-3",
|
|
426
444
|
children: "Creds"
|
|
427
445
|
}),
|
|
428
|
-
/* @__PURE__ */
|
|
446
|
+
/* @__PURE__ */ _("th", {
|
|
429
447
|
className: "py-2 pr-3",
|
|
430
448
|
children: "Status"
|
|
431
449
|
}),
|
|
432
|
-
/* @__PURE__ */
|
|
450
|
+
/* @__PURE__ */ _("th", {
|
|
433
451
|
className: "py-2 pr-3",
|
|
434
452
|
children: "Expires"
|
|
435
453
|
}),
|
|
436
|
-
/* @__PURE__ */
|
|
454
|
+
/* @__PURE__ */ _("th", {
|
|
437
455
|
className: "py-2 pr-3",
|
|
438
456
|
children: "Fetches"
|
|
439
457
|
}),
|
|
440
|
-
/* @__PURE__ */
|
|
458
|
+
/* @__PURE__ */ _("th", {
|
|
441
459
|
className: "py-2 pr-3",
|
|
442
460
|
children: "Actions"
|
|
443
461
|
})
|
|
444
462
|
]
|
|
445
|
-
}) }), /* @__PURE__ */
|
|
463
|
+
}) }), /* @__PURE__ */ _("tbody", { children: F.map((e) => /* @__PURE__ */ v(n, { children: [/* @__PURE__ */ v("tr", {
|
|
446
464
|
className: "border-b border-border-subtle align-top",
|
|
447
465
|
children: [
|
|
448
|
-
/* @__PURE__ */
|
|
466
|
+
/* @__PURE__ */ _("td", {
|
|
449
467
|
className: "py-2 pr-3 text-text-primary",
|
|
450
468
|
children: e.label ?? "—"
|
|
451
469
|
}),
|
|
452
|
-
/* @__PURE__ */
|
|
470
|
+
/* @__PURE__ */ _("td", {
|
|
453
471
|
className: "py-2 pr-3 font-mono text-xs text-text-secondary",
|
|
454
472
|
children: e.tokenFingerprint
|
|
455
473
|
}),
|
|
456
|
-
/* @__PURE__ */
|
|
474
|
+
/* @__PURE__ */ _("td", {
|
|
457
475
|
className: "py-2 pr-3 text-text-secondary",
|
|
458
|
-
children: /* @__PURE__ */
|
|
476
|
+
children: /* @__PURE__ */ _("span", {
|
|
459
477
|
className: "text-xs",
|
|
460
478
|
children: e.includes.join(", ")
|
|
461
479
|
})
|
|
462
480
|
}),
|
|
463
|
-
/* @__PURE__ */
|
|
481
|
+
/* @__PURE__ */ _("td", {
|
|
464
482
|
className: "py-2 pr-3",
|
|
465
|
-
children: e.includeCredentials ? /* @__PURE__ */
|
|
483
|
+
children: e.includeCredentials ? /* @__PURE__ */ _("span", {
|
|
466
484
|
className: "text-xs text-status-warning-text",
|
|
467
485
|
children: "on"
|
|
468
|
-
}) : /* @__PURE__ */
|
|
486
|
+
}) : /* @__PURE__ */ _("span", {
|
|
469
487
|
className: "text-xs text-text-secondary",
|
|
470
488
|
children: "off"
|
|
471
489
|
})
|
|
472
490
|
}),
|
|
473
|
-
/* @__PURE__ */
|
|
491
|
+
/* @__PURE__ */ _("td", {
|
|
474
492
|
className: "py-2 pr-3",
|
|
475
|
-
children: /* @__PURE__ */
|
|
493
|
+
children: /* @__PURE__ */ _("span", {
|
|
476
494
|
className: `text-xs px-1.5 py-0.5 rounded ${e.status === "ACTIVE" ? "bg-status-success-bg/20 text-status-success-text" : "bg-bg-sunken text-text-secondary"}`,
|
|
477
495
|
children: e.status
|
|
478
496
|
})
|
|
479
497
|
}),
|
|
480
|
-
/* @__PURE__ */
|
|
498
|
+
/* @__PURE__ */ _("td", {
|
|
481
499
|
className: "py-2 pr-3 text-xs text-text-secondary",
|
|
482
|
-
children: /* @__PURE__ */
|
|
500
|
+
children: /* @__PURE__ */ v("span", {
|
|
483
501
|
className: "inline-flex items-center gap-1",
|
|
484
|
-
children: [/* @__PURE__ */
|
|
502
|
+
children: [/* @__PURE__ */ _(c, { className: "w-3 h-3" }), E(e.expiresAt)]
|
|
485
503
|
})
|
|
486
504
|
}),
|
|
487
|
-
/* @__PURE__ */
|
|
505
|
+
/* @__PURE__ */ _("td", {
|
|
488
506
|
className: "py-2 pr-3 text-xs text-text-secondary",
|
|
489
507
|
children: e.fetchCount
|
|
490
508
|
}),
|
|
491
|
-
/* @__PURE__ */
|
|
509
|
+
/* @__PURE__ */ _("td", {
|
|
492
510
|
className: "py-2 pr-3",
|
|
493
|
-
children: /* @__PURE__ */
|
|
511
|
+
children: /* @__PURE__ */ v("div", {
|
|
494
512
|
className: "flex gap-1",
|
|
495
|
-
children: [/* @__PURE__ */
|
|
496
|
-
|
|
513
|
+
children: [/* @__PURE__ */ _("button", {
|
|
514
|
+
type: "button",
|
|
515
|
+
onClick: () => me($ === e.id ? null : e.id),
|
|
497
516
|
title: "Show fetch history",
|
|
517
|
+
"aria-label": "Show fetch history",
|
|
498
518
|
className: "p-1.5 text-text-secondary hover:text-text-primary",
|
|
499
|
-
children: /* @__PURE__ */
|
|
500
|
-
}), e.status === "ACTIVE" && /* @__PURE__ */
|
|
519
|
+
children: /* @__PURE__ */ _(l, { className: "w-4 h-4" })
|
|
520
|
+
}), e.status === "ACTIVE" && /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("button", {
|
|
521
|
+
type: "button",
|
|
501
522
|
onClick: async () => {
|
|
502
|
-
let t = await
|
|
503
|
-
t.data && (
|
|
523
|
+
let t = await M({ variables: { tokenId: e.id } });
|
|
524
|
+
t.data && (Y(t.data.rotateVibeLlmContextUrl), X(!1));
|
|
504
525
|
},
|
|
505
526
|
title: "Rotate (revoke + mint a new one with same settings)",
|
|
527
|
+
"aria-label": "Rotate URL",
|
|
506
528
|
className: "p-1.5 text-text-secondary hover:text-text-primary",
|
|
507
|
-
children: /* @__PURE__ */
|
|
508
|
-
}), /* @__PURE__ */
|
|
509
|
-
|
|
529
|
+
children: /* @__PURE__ */ _(re, { className: "w-4 h-4" })
|
|
530
|
+
}), /* @__PURE__ */ _("button", {
|
|
531
|
+
type: "button",
|
|
532
|
+
onClick: () => j({ variables: { tokenId: e.id } }),
|
|
510
533
|
title: "Revoke",
|
|
534
|
+
"aria-label": "Revoke URL",
|
|
511
535
|
className: "p-1.5 text-status-error-text hover:opacity-80",
|
|
512
|
-
children: /* @__PURE__ */
|
|
536
|
+
children: /* @__PURE__ */ _(d, { className: "w-4 h-4" })
|
|
513
537
|
})] })]
|
|
514
538
|
})
|
|
515
539
|
})
|
|
516
540
|
]
|
|
517
|
-
}
|
|
541
|
+
}), $ === e.id && /* @__PURE__ */ _("tr", { children: /* @__PURE__ */ _("td", {
|
|
518
542
|
colSpan: 8,
|
|
519
543
|
className: "py-2 pr-3 bg-bg-sunken/40",
|
|
520
|
-
children: /* @__PURE__ */
|
|
521
|
-
}) },
|
|
544
|
+
children: /* @__PURE__ */ _(ce, { tokenId: e.id })
|
|
545
|
+
}) })] }, e.id)) })]
|
|
522
546
|
})
|
|
523
547
|
})
|
|
524
548
|
]
|
|
525
549
|
}),
|
|
526
|
-
|
|
527
|
-
/* @__PURE__ */
|
|
550
|
+
le && /* @__PURE__ */ _(t, { vibeId: f }),
|
|
551
|
+
/* @__PURE__ */ v("p", {
|
|
528
552
|
className: "text-xs text-text-secondary flex items-center gap-1",
|
|
529
553
|
children: [
|
|
530
|
-
/* @__PURE__ */
|
|
554
|
+
/* @__PURE__ */ _(o, { className: "w-3 h-3" }),
|
|
531
555
|
"Tip: pipe the URL to any LLM with",
|
|
532
556
|
" ",
|
|
533
|
-
/* @__PURE__ */
|
|
557
|
+
/* @__PURE__ */ _("code", {
|
|
534
558
|
className: "bg-bg-sunken px-1 rounded",
|
|
535
559
|
children: "curl <url>"
|
|
536
560
|
}),
|
|
537
561
|
" or",
|
|
538
562
|
" ",
|
|
539
|
-
/* @__PURE__ */
|
|
563
|
+
/* @__PURE__ */ _("code", {
|
|
540
564
|
className: "bg-bg-sunken px-1 rounded",
|
|
541
565
|
children: "curl -H \"Accept: text/markdown\" <url>"
|
|
542
566
|
}),
|
|
@@ -547,76 +571,76 @@ function k({ vibeId: d, attachedAgents: T = [] }) {
|
|
|
547
571
|
]
|
|
548
572
|
});
|
|
549
573
|
}
|
|
550
|
-
function
|
|
551
|
-
let { data: t, loading: n } =
|
|
574
|
+
function ce({ tokenId: e }) {
|
|
575
|
+
let { data: t, loading: n } = m(w, {
|
|
552
576
|
variables: {
|
|
553
577
|
tokenId: e,
|
|
554
578
|
limit: 100
|
|
555
579
|
},
|
|
556
580
|
fetchPolicy: "cache-and-network"
|
|
557
581
|
}), r = t?.myVibeLlmContextTokenAudits ?? [];
|
|
558
|
-
return /* @__PURE__ */
|
|
582
|
+
return /* @__PURE__ */ _("div", {
|
|
559
583
|
className: "text-xs",
|
|
560
|
-
children: n && r.length === 0 ? /* @__PURE__ */
|
|
584
|
+
children: n && r.length === 0 ? /* @__PURE__ */ _("span", {
|
|
561
585
|
className: "text-text-secondary",
|
|
562
586
|
children: "Loading audit log…"
|
|
563
|
-
}) : r.length === 0 ? /* @__PURE__ */
|
|
587
|
+
}) : r.length === 0 ? /* @__PURE__ */ _("span", {
|
|
564
588
|
className: "text-text-secondary",
|
|
565
589
|
children: "No fetches yet."
|
|
566
|
-
}) : /* @__PURE__ */
|
|
590
|
+
}) : /* @__PURE__ */ v("table", {
|
|
567
591
|
className: "w-full",
|
|
568
|
-
children: [/* @__PURE__ */
|
|
592
|
+
children: [/* @__PURE__ */ _("thead", { children: /* @__PURE__ */ v("tr", {
|
|
569
593
|
className: "text-text-secondary",
|
|
570
594
|
children: [
|
|
571
|
-
/* @__PURE__ */
|
|
595
|
+
/* @__PURE__ */ _("th", {
|
|
572
596
|
className: "text-left py-1 pr-2",
|
|
573
597
|
children: "When"
|
|
574
598
|
}),
|
|
575
|
-
/* @__PURE__ */
|
|
599
|
+
/* @__PURE__ */ _("th", {
|
|
576
600
|
className: "text-left py-1 pr-2",
|
|
577
601
|
children: "IP"
|
|
578
602
|
}),
|
|
579
|
-
/* @__PURE__ */
|
|
603
|
+
/* @__PURE__ */ _("th", {
|
|
580
604
|
className: "text-left py-1 pr-2",
|
|
581
605
|
children: "Format"
|
|
582
606
|
}),
|
|
583
|
-
/* @__PURE__ */
|
|
607
|
+
/* @__PURE__ */ _("th", {
|
|
584
608
|
className: "text-left py-1 pr-2",
|
|
585
609
|
children: "Bytes"
|
|
586
610
|
}),
|
|
587
|
-
/* @__PURE__ */
|
|
611
|
+
/* @__PURE__ */ _("th", {
|
|
588
612
|
className: "text-left py-1 pr-2",
|
|
589
613
|
children: "Status"
|
|
590
614
|
}),
|
|
591
|
-
/* @__PURE__ */
|
|
615
|
+
/* @__PURE__ */ _("th", {
|
|
592
616
|
className: "text-left py-1 pr-2",
|
|
593
617
|
children: "UA"
|
|
594
618
|
})
|
|
595
619
|
]
|
|
596
|
-
}) }), /* @__PURE__ */
|
|
620
|
+
}) }), /* @__PURE__ */ _("tbody", { children: r.map((e) => /* @__PURE__ */ v("tr", {
|
|
597
621
|
className: "text-text-primary border-t border-border-subtle",
|
|
598
622
|
children: [
|
|
599
|
-
/* @__PURE__ */
|
|
623
|
+
/* @__PURE__ */ _("td", {
|
|
600
624
|
className: "py-1 pr-2",
|
|
601
625
|
children: new Date(e.fetchedAt).toLocaleString()
|
|
602
626
|
}),
|
|
603
|
-
/* @__PURE__ */
|
|
627
|
+
/* @__PURE__ */ _("td", {
|
|
604
628
|
className: "py-1 pr-2 font-mono",
|
|
605
629
|
children: e.remoteIp ?? "—"
|
|
606
630
|
}),
|
|
607
|
-
/* @__PURE__ */
|
|
631
|
+
/* @__PURE__ */ _("td", {
|
|
608
632
|
className: "py-1 pr-2",
|
|
609
633
|
children: e.format
|
|
610
634
|
}),
|
|
611
|
-
/* @__PURE__ */
|
|
635
|
+
/* @__PURE__ */ _("td", {
|
|
612
636
|
className: "py-1 pr-2",
|
|
613
637
|
children: e.bytes
|
|
614
638
|
}),
|
|
615
|
-
/* @__PURE__ */
|
|
639
|
+
/* @__PURE__ */ _("td", {
|
|
616
640
|
className: "py-1 pr-2",
|
|
617
641
|
children: e.status
|
|
618
642
|
}),
|
|
619
|
-
/* @__PURE__ */
|
|
643
|
+
/* @__PURE__ */ _("td", {
|
|
620
644
|
className: "py-1 pr-2 truncate max-w-[260px]",
|
|
621
645
|
title: e.userAgent ?? "",
|
|
622
646
|
children: e.userAgent ?? "—"
|
|
@@ -627,6 +651,6 @@ function ie({ tokenId: e }) {
|
|
|
627
651
|
});
|
|
628
652
|
}
|
|
629
653
|
//#endregion
|
|
630
|
-
export {
|
|
654
|
+
export { D as VibeLlmContextTabPanel };
|
|
631
655
|
|
|
632
656
|
//# sourceMappingURL=VibeLlmContextTabPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VibeLlmContextTabPanel.js","names":[],"sources":["../../../src/components/vibe/VibeLlmContextTabPanel.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n Bot,\n Check,\n Clock,\n Copy,\n EyeOff,\n Info,\n Lock,\n RefreshCw,\n RotateCw,\n Trash2,\n} from 'lucide-react';\n\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\n\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\n\nimport { VibeLlmContextAdminPanel } from './VibeLlmContextAdminPanel';\n\nconst ALL_INCLUDES = [\n 'core',\n 'agents',\n 'sessions',\n 'notes',\n 'catalogs',\n 'docs',\n 'config',\n 'security',\n 'plugins',\n] as const;\n\ntype IncludeKey = (typeof ALL_INCLUDES)[number];\n\ninterface VibeLlmContextSettings {\n vibeId: string;\n ttlSeconds: number;\n includeCredentials: boolean;\n includes: string[];\n customContextText: string | null;\n defaultAgentIdOverride: string | null;\n sessionsLimit: number;\n notesLimit: number;\n docsPagesLimit: number;\n securityRunsLimit: number;\n updatedAt: string;\n}\n\ninterface VibeLlmContextTokenRow {\n id: string;\n vibeId: string;\n userId: string;\n label: string | null;\n tokenFingerprint: string;\n includeCredentials: boolean;\n includes: string[];\n status: 'ACTIVE' | 'REVOKED';\n expiresAt: string;\n lastFetchedAt: string | null;\n fetchCount: number;\n createdAt: string;\n revokedAt: string | null;\n revokedReason: string | null;\n}\n\ninterface MintResult {\n tokenId: string;\n url: string;\n token: string;\n expiresAt: string;\n ttlSeconds: number;\n includes: string[];\n includeCredentials: boolean;\n label: string | null;\n tokenFingerprint: string;\n}\n\ninterface AuditRow {\n id: string;\n fetchedAt: string;\n remoteIp: string | null;\n userAgent: string | null;\n format: string;\n bytes: number;\n durationMs: number;\n status: number;\n}\n\nconst GET_SETTINGS = gql`\n query MyVibeLlmContextSettings($vibeId: ID!) {\n myVibeLlmContextSettings(vibeId: $vibeId) {\n vibeId\n ttlSeconds\n includeCredentials\n includes\n customContextText\n defaultAgentIdOverride\n sessionsLimit\n notesLimit\n docsPagesLimit\n securityRunsLimit\n updatedAt\n }\n }\n`;\n\nconst GET_TOKENS = gql`\n query MyVibeLlmContextTokens($vibeId: ID!) {\n myVibeLlmContextTokens(vibeId: $vibeId) {\n id\n vibeId\n userId\n label\n tokenFingerprint\n includeCredentials\n includes\n status\n expiresAt\n lastFetchedAt\n fetchCount\n createdAt\n revokedAt\n revokedReason\n }\n }\n`;\n\nconst SET_SETTINGS = gql`\n mutation SetMyVibeLlmContextSettings($vibeId: ID!, $input: VibeLlmContextSettingsInput!) {\n setMyVibeLlmContextSettings(vibeId: $vibeId, input: $input) {\n vibeId\n ttlSeconds\n includeCredentials\n includes\n customContextText\n defaultAgentIdOverride\n sessionsLimit\n notesLimit\n docsPagesLimit\n securityRunsLimit\n updatedAt\n }\n }\n`;\n\nconst GENERATE_URL = gql`\n mutation GenerateVibeLlmContextUrl($vibeId: ID!, $input: VibeLlmContextMintInput) {\n generateVibeLlmContextUrl(vibeId: $vibeId, input: $input) {\n tokenId\n url\n token\n expiresAt\n ttlSeconds\n includes\n includeCredentials\n label\n tokenFingerprint\n }\n }\n`;\n\nconst REVOKE_TOKEN = gql`\n mutation RevokeVibeLlmContextToken($tokenId: ID!) {\n revokeVibeLlmContextToken(tokenId: $tokenId) {\n id\n status\n revokedAt\n }\n }\n`;\n\nconst ROTATE_TOKEN = gql`\n mutation RotateVibeLlmContextUrl($tokenId: ID!, $input: VibeLlmContextMintInput) {\n rotateVibeLlmContextUrl(tokenId: $tokenId, input: $input) {\n tokenId\n url\n token\n expiresAt\n ttlSeconds\n includes\n includeCredentials\n label\n tokenFingerprint\n }\n }\n`;\n\nconst REVOKE_ALL = gql`\n mutation RevokeAllMyVibeLlmContextTokens($vibeId: ID!) {\n revokeAllMyVibeLlmContextTokens(vibeId: $vibeId)\n }\n`;\n\nconst GET_AUDITS = gql`\n query MyVibeLlmContextTokenAudits($tokenId: ID!, $limit: Int) {\n myVibeLlmContextTokenAudits(tokenId: $tokenId, limit: $limit) {\n id\n fetchedAt\n remoteIp\n userAgent\n format\n bytes\n durationMs\n status\n }\n }\n`;\n\nconst TTL_PRESETS: Array<{ label: string; hours: number }> = [\n { label: '1 hour', hours: 1 },\n { label: '6 hours', hours: 6 },\n { label: '24 hours', hours: 24 },\n { label: '7 days', hours: 24 * 7 },\n];\n\nasync function copyToClipboard(text: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n const ta = document.createElement('textarea');\n ta.value = text;\n ta.style.position = 'fixed';\n ta.style.opacity = '0';\n document.body.appendChild(ta);\n ta.select();\n document.execCommand('copy');\n document.body.removeChild(ta);\n }\n}\n\nfunction formatExpiry(expiresAt: string): string {\n const diff = new Date(expiresAt).getTime() - Date.now();\n if (diff < 0) return 'expired';\n const hours = Math.floor(diff / (1000 * 60 * 60));\n const mins = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));\n if (hours > 24) return `${Math.floor(hours / 24)}d`;\n if (hours > 0) return `${hours}h ${mins}m`;\n return `${mins}m`;\n}\n\ninterface AttachedAgent {\n id: string;\n name: string;\n}\n\ninterface VibeLlmContextTabPanelProps {\n vibeId: string;\n attachedAgents?: AttachedAgent[];\n}\n\nexport function VibeLlmContextTabPanel({\n vibeId,\n attachedAgents = [],\n}: VibeLlmContextTabPanelProps): ReactElement {\n const { hasPermission } = usePermissions();\n const isAdmin = hasPermission(VIBE_PERMISSIONS.VIBE_MANAGE);\n const settingsQuery = useQuery<{ myVibeLlmContextSettings: VibeLlmContextSettings }>(\n GET_SETTINGS,\n {\n variables: { vibeId },\n fetchPolicy: 'cache-and-network',\n }\n );\n const tokensQuery = useQuery<{ myVibeLlmContextTokens: VibeLlmContextTokenRow[] }>(GET_TOKENS, {\n variables: { vibeId },\n fetchPolicy: 'cache-and-network',\n });\n const [saveSettings, saveSettingsState] = useMutation<\n { setMyVibeLlmContextSettings: VibeLlmContextSettings },\n {\n vibeId: string;\n input: {\n ttlSeconds?: number;\n includeCredentials?: boolean;\n includes?: string[];\n customContextText?: string | null;\n defaultAgentIdOverride?: string | null;\n sessionsLimit?: number;\n notesLimit?: number;\n docsPagesLimit?: number;\n securityRunsLimit?: number;\n };\n }\n >(SET_SETTINGS, { refetchQueries: ['MyVibeLlmContextSettings'] });\n const [generateUrl, generateUrlState] = useMutation<\n { generateVibeLlmContextUrl: MintResult },\n {\n vibeId: string;\n input?: {\n label?: string | null;\n ttlSeconds?: number | null;\n includeCredentials?: boolean | null;\n includes?: string[] | null;\n } | null;\n }\n >(GENERATE_URL, { refetchQueries: ['MyVibeLlmContextTokens'] });\n const [revokeToken] = useMutation<\n { revokeVibeLlmContextToken: VibeLlmContextTokenRow },\n { tokenId: string }\n >(REVOKE_TOKEN, { refetchQueries: ['MyVibeLlmContextTokens'] });\n const [rotateToken] = useMutation<{ rotateVibeLlmContextUrl: MintResult }, { tokenId: string }>(\n ROTATE_TOKEN,\n { refetchQueries: ['MyVibeLlmContextTokens'] }\n );\n const [revokeAll] = useMutation<{ revokeAllMyVibeLlmContextTokens: number }, { vibeId: string }>(\n REVOKE_ALL,\n { refetchQueries: ['MyVibeLlmContextTokens'] }\n );\n\n const settings = settingsQuery.data?.myVibeLlmContextSettings;\n const tokens = tokensQuery.data?.myVibeLlmContextTokens ?? [];\n\n // Local editable copy of settings\n const [ttlHours, setTtlHours] = useState<number>(1);\n const [includeCreds, setIncludeCreds] = useState<boolean>(false);\n const [includesState, setIncludesState] = useState<Set<IncludeKey>>(new Set(ALL_INCLUDES));\n const [customText, setCustomText] = useState<string>('');\n const [defaultAgentOverride, setDefaultAgentOverride] = useState<string>('');\n const [label, setLabel] = useState<string>('');\n const [lastMint, setLastMint] = useState<MintResult | null>(null);\n const [copied, setCopied] = useState<boolean>(false);\n const [auditPanelTokenId, setAuditPanelTokenId] = useState<string | null>(null);\n\n // Hydrate local form when server settings arrive\n useMemo(() => {\n if (!settings) return;\n setTtlHours(Math.max(1, Math.round((settings.ttlSeconds ?? 3600) / 3600)));\n setIncludeCreds(settings.includeCredentials);\n setIncludesState(new Set((settings.includes as IncludeKey[]) ?? ALL_INCLUDES));\n setCustomText(settings.customContextText ?? '');\n setDefaultAgentOverride(settings.defaultAgentIdOverride ?? '');\n }, [settings]);\n\n const onToggleInclude = (key: IncludeKey) => {\n setIncludesState((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n });\n };\n\n const onSaveSettings = async () => {\n await saveSettings({\n variables: {\n vibeId,\n input: {\n ttlSeconds: Math.max(60, Math.min(7 * 24 * 60 * 60, ttlHours * 60 * 60)),\n includeCredentials: includeCreds,\n includes: Array.from(includesState),\n customContextText: customText,\n defaultAgentIdOverride: defaultAgentOverride || null,\n },\n },\n });\n };\n\n const onGenerate = async () => {\n const res = await generateUrl({\n variables: {\n vibeId,\n input: {\n label: label || null,\n ttlSeconds: Math.max(60, Math.min(7 * 24 * 60 * 60, ttlHours * 60 * 60)),\n includeCredentials: includeCreds,\n includes: Array.from(includesState),\n },\n },\n });\n if (res.data) {\n setLastMint(res.data.generateVibeLlmContextUrl);\n setCopied(false);\n }\n };\n\n const onCopyResultUrl = async () => {\n if (!lastMint) return;\n await copyToClipboard(lastMint.url);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n return (\n <div className=\"space-y-6 max-w-5xl\">\n {/* Header */}\n <div className=\"rounded-lg border border-status-warning-border bg-status-warning-bg/30 p-4\">\n <div className=\"flex items-start gap-3\">\n <Lock className=\"w-5 h-5 text-status-warning-text mt-0.5\" />\n <div className=\"text-sm text-text-primary\">\n <p className=\"font-medium mb-1\">\n LLM Context — share this vibe with any LLM via a signed URL\n </p>\n <p className=\"text-text-secondary\">\n Anyone with the URL can read the snapshot until it expires. When \"Include credentials\"\n is on, the snapshot exposes agent tunnel URLs + API keys. Default is redacted. Rotate\n or revoke any URL from the list below at any time.\n </p>\n </div>\n </div>\n </div>\n\n {/* Settings panel */}\n <section className=\"bg-bg-surface border border-border-default rounded-lg p-5 space-y-4\">\n <header className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">Saved settings</h3>\n <p className=\"text-sm text-text-secondary\">\n Defaults used when you generate a URL. Snapshotted into each minted token, so future\n edits don't change already-minted URLs.\n </p>\n </div>\n <button\n onClick={onSaveSettings}\n disabled={saveSettingsState.loading}\n className=\"px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n {saveSettingsState.loading ? 'Saving…' : 'Save settings'}\n </button>\n </header>\n\n {/* TTL */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">URL expiry</label>\n <div className=\"flex flex-wrap items-center gap-2\">\n {TTL_PRESETS.map((p) => (\n <button\n key={p.hours}\n onClick={() => setTtlHours(p.hours)}\n className={`px-3 py-1.5 text-sm rounded-md border ${\n ttlHours === p.hours\n ? 'bg-action-primary-bg text-action-primary-text border-action-primary-bg'\n : 'bg-bg-sunken text-text-primary border-border-default'\n }`}\n >\n {p.label}\n </button>\n ))}\n <span className=\"text-sm text-text-secondary mx-1\">or custom hours:</span>\n <input\n type=\"number\"\n min={1}\n max={168}\n value={ttlHours}\n onChange={(e) => setTtlHours(Math.max(1, Math.min(168, Number(e.target.value) || 1)))}\n className=\"w-24 px-2 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n />\n </div>\n </div>\n\n {/* Credentials toggle */}\n <div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={includeCreds}\n onChange={(e) => setIncludeCreds(e.target.checked)}\n className=\"w-4 h-4\"\n />\n <span>Include credentials (tunnel URLs + agent API keys)</span>\n {!includeCreds && <EyeOff className=\"w-4 h-4 text-text-secondary\" />}\n </label>\n </div>\n\n {/* Includes chips */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Sections to include\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {ALL_INCLUDES.map((key) => (\n <button\n key={key}\n onClick={() => onToggleInclude(key)}\n className={`px-2.5 py-1 text-xs rounded-full border ${\n includesState.has(key)\n ? 'bg-action-primary-bg/10 text-action-primary-bg border-action-primary-bg'\n : 'bg-bg-sunken text-text-secondary border-border-default'\n }`}\n >\n {key}\n </button>\n ))}\n </div>\n </div>\n\n {/* Default agent override */}\n {attachedAgents.length > 0 && (\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Default agent for context fetch\n </label>\n <select\n value={defaultAgentOverride}\n onChange={(e) => setDefaultAgentOverride(e.target.value)}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"\">(use my per-vibe default from settings)</option>\n {attachedAgents.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Custom context */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Custom context text\n </label>\n <textarea\n value={customText}\n onChange={(e) => setCustomText(e.target.value.slice(0, 8192))}\n rows={5}\n placeholder=\"Free-form notes embedded in every snapshot you mint AFTER saving (existing tokens keep their original copy).\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n <p className=\"text-xs text-text-secondary mt-1\">{customText.length} / 8192 chars</p>\n </div>\n </section>\n\n {/* Generate panel */}\n <section className=\"bg-bg-surface border border-border-default rounded-lg p-5 space-y-4\">\n <header>\n <h3 className=\"text-base font-semibold text-text-primary\">Generate a new URL</h3>\n <p className=\"text-sm text-text-secondary\">\n Mints a fresh signed URL using your current settings. The full token is only shown once\n — copy it before navigating away. Use Rotate below if you lose it.\n </p>\n </header>\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex-1 min-w-[200px]\">\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Label (optional)\n </label>\n <input\n type=\"text\"\n value={label}\n onChange={(e) => setLabel(e.target.value.slice(0, 120))}\n placeholder=\"e.g. Claude desktop\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <button\n onClick={onGenerate}\n disabled={generateUrlState.loading}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n {generateUrlState.loading ? 'Generating…' : 'Generate URL'}\n </button>\n </div>\n\n {lastMint && (\n <div className=\"rounded-md border border-status-success-border bg-status-success-bg/20 p-3\">\n <div className=\"flex items-center gap-2 text-sm mb-2\">\n <Check className=\"w-4 h-4 text-status-success-text\" />\n <span className=\"font-medium text-text-primary\">URL generated</span>\n <span className=\"text-xs text-text-secondary\">\n expires in {formatExpiry(lastMint.expiresAt)}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <input\n readOnly\n value={lastMint.url}\n className=\"flex-1 px-2 py-1.5 text-xs bg-bg-sunken border border-border-default rounded font-mono text-text-primary\"\n aria-label=\"Generated LLM context URL\"\n />\n <button\n onClick={onCopyResultUrl}\n className=\"px-2 py-1.5 text-xs bg-bg-sunken border border-border-default rounded text-text-primary\"\n aria-label=\"Copy URL\"\n >\n {copied ? (\n <Check className=\"w-4 h-4 text-status-success-text\" />\n ) : (\n <Copy className=\"w-4 h-4\" />\n )}\n </button>\n </div>\n </div>\n )}\n </section>\n\n {/* Active URLs list */}\n <section className=\"bg-bg-surface border border-border-default rounded-lg p-5 space-y-3\">\n <header className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">Your active URLs</h3>\n <p className=\"text-sm text-text-secondary\">\n Tokens you minted for this vibe. Revoke and rotate work immediately; revoked tokens\n fail with 403 even if the JWT hasn't expired.\n </p>\n </div>\n <button\n onClick={() => revokeAll({ variables: { vibeId } })}\n className=\"flex items-center gap-1 px-3 py-1.5 text-sm bg-status-error-bg/10 text-status-error-text border border-status-error-border rounded-md hover:bg-status-error-bg/20\"\n >\n <Trash2 className=\"w-4 h-4\" />\n Revoke all\n </button>\n </header>\n\n {tokensQuery.loading && tokens.length === 0 && (\n <div className=\"text-sm text-text-secondary py-4 flex items-center gap-2\">\n <RefreshCw className=\"w-4 h-4 animate-spin\" />\n Loading tokens…\n </div>\n )}\n {tokens.length === 0 && !tokensQuery.loading && (\n <div className=\"text-sm text-text-secondary py-4 flex items-center gap-2\">\n <Info className=\"w-4 h-4\" />\n No URLs minted yet for this vibe.\n </div>\n )}\n {tokens.length > 0 && (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-default text-left text-xs text-text-secondary\">\n <th className=\"py-2 pr-3\">Label</th>\n <th className=\"py-2 pr-3\">Fingerprint</th>\n <th className=\"py-2 pr-3\">Sections</th>\n <th className=\"py-2 pr-3\">Creds</th>\n <th className=\"py-2 pr-3\">Status</th>\n <th className=\"py-2 pr-3\">Expires</th>\n <th className=\"py-2 pr-3\">Fetches</th>\n <th className=\"py-2 pr-3\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {tokens.map((t) => (\n <>\n <tr key={t.id} className=\"border-b border-border-subtle align-top\">\n <td className=\"py-2 pr-3 text-text-primary\">{t.label ?? '—'}</td>\n <td className=\"py-2 pr-3 font-mono text-xs text-text-secondary\">\n {t.tokenFingerprint}\n </td>\n <td className=\"py-2 pr-3 text-text-secondary\">\n <span className=\"text-xs\">{t.includes.join(', ')}</span>\n </td>\n <td className=\"py-2 pr-3\">\n {t.includeCredentials ? (\n <span className=\"text-xs text-status-warning-text\">on</span>\n ) : (\n <span className=\"text-xs text-text-secondary\">off</span>\n )}\n </td>\n <td className=\"py-2 pr-3\">\n <span\n className={`text-xs px-1.5 py-0.5 rounded ${\n t.status === 'ACTIVE'\n ? 'bg-status-success-bg/20 text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {t.status}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"w-3 h-3\" />\n {formatExpiry(t.expiresAt)}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">{t.fetchCount}</td>\n <td className=\"py-2 pr-3\">\n <div className=\"flex gap-1\">\n <button\n onClick={() =>\n setAuditPanelTokenId(auditPanelTokenId === t.id ? null : t.id)\n }\n title=\"Show fetch history\"\n className=\"p-1.5 text-text-secondary hover:text-text-primary\"\n >\n <Info className=\"w-4 h-4\" />\n </button>\n {t.status === 'ACTIVE' && (\n <>\n <button\n onClick={async () => {\n const res = await rotateToken({ variables: { tokenId: t.id } });\n if (res.data) {\n setLastMint(res.data.rotateVibeLlmContextUrl);\n setCopied(false);\n }\n }}\n title=\"Rotate (revoke + mint a new one with same settings)\"\n className=\"p-1.5 text-text-secondary hover:text-text-primary\"\n >\n <RotateCw className=\"w-4 h-4\" />\n </button>\n <button\n onClick={() => revokeToken({ variables: { tokenId: t.id } })}\n title=\"Revoke\"\n className=\"p-1.5 text-status-error-text hover:opacity-80\"\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </>\n )}\n </div>\n </td>\n </tr>\n {auditPanelTokenId === t.id && (\n <tr key={`${t.id}-audits`}>\n <td colSpan={8} className=\"py-2 pr-3 bg-bg-sunken/40\">\n <AuditListInline tokenId={t.id} />\n </td>\n </tr>\n )}\n </>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n\n {/* Admin sub-panel — gated by vibe:manage permission */}\n {isAdmin && <VibeLlmContextAdminPanel vibeId={vibeId} />}\n\n {/* Help footer */}\n <p className=\"text-xs text-text-secondary flex items-center gap-1\">\n <Bot className=\"w-3 h-3\" />\n Tip: pipe the URL to any LLM with{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">curl <url></code> or{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">{`curl -H \"Accept: text/markdown\" <url>`}</code>{' '}\n for a markdown snapshot.\n </p>\n </div>\n );\n}\n\nfunction AuditListInline({ tokenId }: { tokenId: string }): ReactElement {\n const { data, loading } = useQuery<{ myVibeLlmContextTokenAudits: AuditRow[] }>(GET_AUDITS, {\n variables: { tokenId, limit: 100 },\n fetchPolicy: 'cache-and-network',\n });\n const rows = data?.myVibeLlmContextTokenAudits ?? [];\n return (\n <div className=\"text-xs\">\n {loading && rows.length === 0 ? (\n <span className=\"text-text-secondary\">Loading audit log…</span>\n ) : rows.length === 0 ? (\n <span className=\"text-text-secondary\">No fetches yet.</span>\n ) : (\n <table className=\"w-full\">\n <thead>\n <tr className=\"text-text-secondary\">\n <th className=\"text-left py-1 pr-2\">When</th>\n <th className=\"text-left py-1 pr-2\">IP</th>\n <th className=\"text-left py-1 pr-2\">Format</th>\n <th className=\"text-left py-1 pr-2\">Bytes</th>\n <th className=\"text-left py-1 pr-2\">Status</th>\n <th className=\"text-left py-1 pr-2\">UA</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((r) => (\n <tr key={r.id} className=\"text-text-primary border-t border-border-subtle\">\n <td className=\"py-1 pr-2\">{new Date(r.fetchedAt).toLocaleString()}</td>\n <td className=\"py-1 pr-2 font-mono\">{r.remoteIp ?? '—'}</td>\n <td className=\"py-1 pr-2\">{r.format}</td>\n <td className=\"py-1 pr-2\">{r.bytes}</td>\n <td className=\"py-1 pr-2\">{r.status}</td>\n <td className=\"py-1 pr-2 truncate max-w-[260px]\" title={r.userAgent ?? ''}>\n {r.userAgent ?? '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VibeLlmContextTabPanel.js","names":[],"sources":["../../../src/components/vibe/VibeLlmContextTabPanel.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { Fragment, useEffect, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport {\n AlertTriangle,\n Bot,\n Check,\n Clock,\n Copy,\n EyeOff,\n Info,\n Lock,\n RefreshCw,\n RotateCw,\n Trash2,\n} from 'lucide-react';\n\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\n\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\n\nimport { VibeLlmContextAdminPanel } from './VibeLlmContextAdminPanel';\n\nconst ALL_INCLUDES = [\n 'core',\n 'agents',\n 'sessions',\n 'notes',\n 'catalogs',\n 'docs',\n 'config',\n 'security',\n 'plugins',\n] as const;\n\ntype IncludeKey = (typeof ALL_INCLUDES)[number];\n\ninterface VibeLlmContextSettings {\n vibeId: string;\n ttlSeconds: number;\n includeCredentials: boolean;\n includes: string[];\n customContextText: string | null;\n defaultAgentIdOverride: string | null;\n sessionsLimit: number;\n notesLimit: number;\n docsPagesLimit: number;\n securityRunsLimit: number;\n updatedAt: string;\n}\n\ninterface VibeLlmContextTokenRow {\n id: string;\n vibeId: string;\n userId: string;\n label: string | null;\n tokenFingerprint: string;\n includeCredentials: boolean;\n includes: string[];\n status: 'ACTIVE' | 'REVOKED';\n expiresAt: string;\n lastFetchedAt: string | null;\n fetchCount: number;\n createdAt: string;\n revokedAt: string | null;\n revokedReason: string | null;\n}\n\ninterface MintResult {\n tokenId: string;\n url: string;\n token: string;\n expiresAt: string;\n ttlSeconds: number;\n includes: string[];\n includeCredentials: boolean;\n label: string | null;\n tokenFingerprint: string;\n}\n\ninterface AuditRow {\n id: string;\n fetchedAt: string;\n remoteIp: string | null;\n userAgent: string | null;\n format: string;\n bytes: number;\n durationMs: number;\n status: number;\n}\n\nconst GET_SETTINGS = gql`\n query MyVibeLlmContextSettings($vibeId: ID!) {\n myVibeLlmContextSettings(vibeId: $vibeId) {\n vibeId\n ttlSeconds\n includeCredentials\n includes\n customContextText\n defaultAgentIdOverride\n sessionsLimit\n notesLimit\n docsPagesLimit\n securityRunsLimit\n updatedAt\n }\n }\n`;\n\nconst GET_TOKENS = gql`\n query MyVibeLlmContextTokens($vibeId: ID!) {\n myVibeLlmContextTokens(vibeId: $vibeId) {\n id\n vibeId\n userId\n label\n tokenFingerprint\n includeCredentials\n includes\n status\n expiresAt\n lastFetchedAt\n fetchCount\n createdAt\n revokedAt\n revokedReason\n }\n }\n`;\n\nconst SET_SETTINGS = gql`\n mutation SetMyVibeLlmContextSettings($vibeId: ID!, $input: VibeLlmContextSettingsInput!) {\n setMyVibeLlmContextSettings(vibeId: $vibeId, input: $input) {\n vibeId\n ttlSeconds\n includeCredentials\n includes\n customContextText\n defaultAgentIdOverride\n sessionsLimit\n notesLimit\n docsPagesLimit\n securityRunsLimit\n updatedAt\n }\n }\n`;\n\nconst GENERATE_URL = gql`\n mutation GenerateVibeLlmContextUrl($vibeId: ID!, $input: VibeLlmContextMintInput) {\n generateVibeLlmContextUrl(vibeId: $vibeId, input: $input) {\n tokenId\n url\n token\n expiresAt\n ttlSeconds\n includes\n includeCredentials\n label\n tokenFingerprint\n }\n }\n`;\n\nconst REVOKE_TOKEN = gql`\n mutation RevokeVibeLlmContextToken($tokenId: ID!) {\n revokeVibeLlmContextToken(tokenId: $tokenId) {\n id\n status\n revokedAt\n }\n }\n`;\n\nconst ROTATE_TOKEN = gql`\n mutation RotateVibeLlmContextUrl($tokenId: ID!, $input: VibeLlmContextMintInput) {\n rotateVibeLlmContextUrl(tokenId: $tokenId, input: $input) {\n tokenId\n url\n token\n expiresAt\n ttlSeconds\n includes\n includeCredentials\n label\n tokenFingerprint\n }\n }\n`;\n\nconst REVOKE_ALL = gql`\n mutation RevokeAllMyVibeLlmContextTokens($vibeId: ID!) {\n revokeAllMyVibeLlmContextTokens(vibeId: $vibeId)\n }\n`;\n\nconst GET_AUDITS = gql`\n query MyVibeLlmContextTokenAudits($tokenId: ID!, $limit: Int) {\n myVibeLlmContextTokenAudits(tokenId: $tokenId, limit: $limit) {\n id\n fetchedAt\n remoteIp\n userAgent\n format\n bytes\n durationMs\n status\n }\n }\n`;\n\nconst TTL_PRESETS: Array<{ label: string; hours: number }> = [\n { label: '1 hour', hours: 1 },\n { label: '6 hours', hours: 6 },\n { label: '24 hours', hours: 24 },\n { label: '7 days', hours: 24 * 7 },\n];\n\nasync function copyToClipboard(text: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n const ta = document.createElement('textarea');\n ta.value = text;\n ta.style.position = 'fixed';\n ta.style.opacity = '0';\n document.body.appendChild(ta);\n ta.select();\n document.execCommand('copy');\n document.body.removeChild(ta);\n }\n}\n\nfunction formatExpiry(expiresAt: string): string {\n const diff = new Date(expiresAt).getTime() - Date.now();\n if (diff < 0) return 'expired';\n const hours = Math.floor(diff / (1000 * 60 * 60));\n const mins = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));\n if (hours > 24) return `${Math.floor(hours / 24)}d`;\n if (hours > 0) return `${hours}h ${mins}m`;\n return `${mins}m`;\n}\n\ninterface AttachedAgent {\n id: string;\n name: string;\n}\n\ninterface VibeLlmContextTabPanelProps {\n vibeId: string;\n attachedAgents?: AttachedAgent[];\n}\n\nexport function VibeLlmContextTabPanel({\n vibeId,\n attachedAgents = [],\n}: VibeLlmContextTabPanelProps): ReactElement {\n const { hasPermission } = usePermissions();\n const isAdmin = hasPermission(VIBE_PERMISSIONS.VIBE_MANAGE);\n const settingsQuery = useQuery<{ myVibeLlmContextSettings: VibeLlmContextSettings }>(\n GET_SETTINGS,\n {\n variables: { vibeId },\n fetchPolicy: 'cache-and-network',\n }\n );\n const tokensQuery = useQuery<{ myVibeLlmContextTokens: VibeLlmContextTokenRow[] }>(GET_TOKENS, {\n variables: { vibeId },\n fetchPolicy: 'cache-and-network',\n });\n const [saveSettings, saveSettingsState] = useMutation<\n { setMyVibeLlmContextSettings: VibeLlmContextSettings },\n {\n vibeId: string;\n input: {\n ttlSeconds?: number;\n includeCredentials?: boolean;\n includes?: string[];\n customContextText?: string | null;\n defaultAgentIdOverride?: string | null;\n sessionsLimit?: number;\n notesLimit?: number;\n docsPagesLimit?: number;\n securityRunsLimit?: number;\n };\n }\n >(SET_SETTINGS, { refetchQueries: ['MyVibeLlmContextSettings'] });\n const [generateUrl, generateUrlState] = useMutation<\n { generateVibeLlmContextUrl: MintResult },\n {\n vibeId: string;\n input?: {\n label?: string | null;\n ttlSeconds?: number | null;\n includeCredentials?: boolean | null;\n includes?: string[] | null;\n } | null;\n }\n >(GENERATE_URL, { refetchQueries: ['MyVibeLlmContextTokens'] });\n const [revokeToken] = useMutation<\n { revokeVibeLlmContextToken: VibeLlmContextTokenRow },\n { tokenId: string }\n >(REVOKE_TOKEN, { refetchQueries: ['MyVibeLlmContextTokens'] });\n const [rotateToken] = useMutation<{ rotateVibeLlmContextUrl: MintResult }, { tokenId: string }>(\n ROTATE_TOKEN,\n { refetchQueries: ['MyVibeLlmContextTokens'] }\n );\n const [revokeAll] = useMutation<{ revokeAllMyVibeLlmContextTokens: number }, { vibeId: string }>(\n REVOKE_ALL,\n { refetchQueries: ['MyVibeLlmContextTokens'] }\n );\n\n const settings = settingsQuery.data?.myVibeLlmContextSettings;\n const tokens = tokensQuery.data?.myVibeLlmContextTokens ?? [];\n\n // Local editable copy of settings\n const [ttlHours, setTtlHours] = useState<number>(1);\n const [includeCreds, setIncludeCreds] = useState<boolean>(false);\n const [includesState, setIncludesState] = useState<Set<IncludeKey>>(new Set(ALL_INCLUDES));\n const [customText, setCustomText] = useState<string>('');\n const [defaultAgentOverride, setDefaultAgentOverride] = useState<string>('');\n const [label, setLabel] = useState<string>('');\n const [lastMint, setLastMint] = useState<MintResult | null>(null);\n const [copied, setCopied] = useState<boolean>(false);\n const [justSaved, setJustSaved] = useState<boolean>(false);\n const [auditPanelTokenId, setAuditPanelTokenId] = useState<string | null>(null);\n\n // Hydrate local form when server settings arrive. This is a side effect\n // (it writes component state), so it belongs in useEffect — not useMemo.\n useEffect(() => {\n if (!settings) return;\n setTtlHours(Math.max(1, Math.round((settings.ttlSeconds ?? 3600) / 3600)));\n setIncludeCreds(settings.includeCredentials);\n setIncludesState(new Set((settings.includes as IncludeKey[]) ?? ALL_INCLUDES));\n setCustomText(settings.customContextText ?? '');\n setDefaultAgentOverride(settings.defaultAgentIdOverride ?? '');\n }, [settings]);\n\n const onToggleInclude = (key: IncludeKey) => {\n setIncludesState((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n });\n };\n\n const onSaveSettings = async () => {\n await saveSettings({\n variables: {\n vibeId,\n input: {\n ttlSeconds: Math.max(60, Math.min(7 * 24 * 60 * 60, ttlHours * 60 * 60)),\n includeCredentials: includeCreds,\n includes: Array.from(includesState),\n customContextText: customText,\n defaultAgentIdOverride: defaultAgentOverride || null,\n },\n },\n });\n setJustSaved(true);\n setTimeout(() => setJustSaved(false), 2000);\n };\n\n const onGenerate = async () => {\n const res = await generateUrl({\n variables: {\n vibeId,\n input: {\n label: label || null,\n ttlSeconds: Math.max(60, Math.min(7 * 24 * 60 * 60, ttlHours * 60 * 60)),\n includeCredentials: includeCreds,\n includes: Array.from(includesState),\n },\n },\n });\n if (res.data) {\n setLastMint(res.data.generateVibeLlmContextUrl);\n setCopied(false);\n setLabel('');\n }\n };\n\n const onRevokeAll = async () => {\n if (\n typeof window !== 'undefined' &&\n !window.confirm(\n 'Revoke ALL active URLs for this vibe? Every minted URL stops working immediately and cannot be un-revoked (use Rotate to issue a fresh one).'\n )\n ) {\n return;\n }\n await revokeAll({ variables: { vibeId } });\n };\n\n const onCopyResultUrl = async () => {\n if (!lastMint) return;\n await copyToClipboard(lastMint.url);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n return (\n <div className=\"space-y-6 max-w-5xl\">\n {/* Header */}\n <div className=\"rounded-lg border border-status-warning-border bg-status-warning-bg/30 p-4\">\n <div className=\"flex items-start gap-3\">\n <Lock className=\"w-5 h-5 text-status-warning-text mt-0.5\" />\n <div className=\"text-sm text-text-primary\">\n <p className=\"font-medium mb-1\">\n LLM Context — share this vibe with any LLM via a signed URL\n </p>\n <p className=\"text-text-secondary\">\n Anyone with the URL can read the snapshot until it expires. When \"Include credentials\"\n is on, the snapshot exposes agent tunnel URLs + API keys. Default is redacted. Rotate\n or revoke any URL from the list below at any time.\n </p>\n </div>\n </div>\n </div>\n\n {/* Settings panel */}\n <section className=\"bg-bg-surface border border-border-default rounded-lg p-5 space-y-4\">\n <header className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">Saved settings</h3>\n <p className=\"text-sm text-text-secondary\">\n Defaults used when you generate a URL. Snapshotted into each minted token, so future\n edits don't change already-minted URLs.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onSaveSettings}\n disabled={saveSettingsState.loading}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n {justSaved && !saveSettingsState.loading && <Check className=\"w-4 h-4\" />}\n {saveSettingsState.loading ? 'Saving…' : justSaved ? 'Saved' : 'Save settings'}\n </button>\n </header>\n\n {/* TTL */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">URL expiry</label>\n <div className=\"flex flex-wrap items-center gap-2\">\n {TTL_PRESETS.map((p) => (\n <button\n key={p.hours}\n type=\"button\"\n onClick={() => setTtlHours(p.hours)}\n className={`px-3 py-1.5 text-sm rounded-md border ${\n ttlHours === p.hours\n ? 'bg-action-primary-bg text-action-primary-text border-action-primary-bg'\n : 'bg-bg-sunken text-text-primary border-border-default'\n }`}\n >\n {p.label}\n </button>\n ))}\n <span className=\"text-sm text-text-secondary mx-1\">or custom hours:</span>\n <input\n type=\"number\"\n min={1}\n max={168}\n value={ttlHours}\n onChange={(e) => setTtlHours(Math.max(1, Math.min(168, Number(e.target.value) || 1)))}\n className=\"w-24 px-2 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n />\n </div>\n </div>\n\n {/* Credentials toggle */}\n <div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={includeCreds}\n onChange={(e) => setIncludeCreds(e.target.checked)}\n className=\"w-4 h-4\"\n />\n <span>Include credentials (tunnel URLs + agent API keys)</span>\n {includeCreds ? (\n <AlertTriangle\n className=\"w-4 h-4 text-status-warning-text\"\n aria-label=\"Credentials will be exposed in the snapshot\"\n />\n ) : (\n <EyeOff className=\"w-4 h-4 text-text-secondary\" aria-label=\"Credentials redacted\" />\n )}\n </label>\n {includeCreds && (\n <p className=\"mt-1.5 text-xs text-status-warning-text flex items-start gap-1.5\">\n <AlertTriangle className=\"w-3.5 h-3.5 mt-0.5 flex-shrink-0\" />\n <span>\n Anyone with a URL minted while this is on can read live agent tunnel URLs and API\n keys. Only enable for trusted recipients.\n </span>\n </p>\n )}\n </div>\n\n {/* Includes chips */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Sections to include\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {ALL_INCLUDES.map((key) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => onToggleInclude(key)}\n className={`px-2.5 py-1 text-xs rounded-full border ${\n includesState.has(key)\n ? 'bg-action-primary-bg/10 text-action-primary-bg border-action-primary-bg'\n : 'bg-bg-sunken text-text-secondary border-border-default'\n }`}\n >\n {key}\n </button>\n ))}\n </div>\n </div>\n\n {/* Default agent override */}\n {attachedAgents.length > 0 && (\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Default agent for context fetch\n </label>\n <select\n value={defaultAgentOverride}\n onChange={(e) => setDefaultAgentOverride(e.target.value)}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"\">(use my per-vibe default from settings)</option>\n {attachedAgents.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Custom context */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-2\">\n Custom context text\n </label>\n <textarea\n value={customText}\n onChange={(e) => setCustomText(e.target.value.slice(0, 8192))}\n rows={5}\n placeholder=\"Free-form notes embedded in every snapshot you mint AFTER saving (existing tokens keep their original copy).\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n <p className=\"text-xs text-text-secondary mt-1\">{customText.length} / 8192 chars</p>\n </div>\n </section>\n\n {/* Generate panel */}\n <section className=\"bg-bg-surface border border-border-default rounded-lg p-5 space-y-4\">\n <header>\n <h3 className=\"text-base font-semibold text-text-primary\">Generate a new URL</h3>\n <p className=\"text-sm text-text-secondary\">\n Mints a fresh signed URL using your current settings. The full token is only shown once\n — copy it before navigating away. Use Rotate below if you lose it.\n </p>\n </header>\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex-1 min-w-[200px]\">\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Label (optional)\n </label>\n <input\n type=\"text\"\n value={label}\n onChange={(e) => setLabel(e.target.value.slice(0, 120))}\n placeholder=\"e.g. Claude desktop\"\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <button\n type=\"button\"\n onClick={onGenerate}\n disabled={generateUrlState.loading}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n {generateUrlState.loading ? 'Generating…' : 'Generate URL'}\n </button>\n </div>\n\n {lastMint && (\n <div className=\"rounded-md border border-status-success-border bg-status-success-bg/20 p-3\">\n <div className=\"flex items-center gap-2 text-sm mb-2\">\n <Check className=\"w-4 h-4 text-status-success-text\" />\n <span className=\"font-medium text-text-primary\">URL generated</span>\n <span className=\"text-xs text-text-secondary\">\n expires in {formatExpiry(lastMint.expiresAt)}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <input\n readOnly\n value={lastMint.url}\n className=\"flex-1 px-2 py-1.5 text-xs bg-bg-sunken border border-border-default rounded font-mono text-text-primary\"\n aria-label=\"Generated LLM context URL\"\n />\n <button\n type=\"button\"\n onClick={onCopyResultUrl}\n className=\"px-2 py-1.5 text-xs bg-bg-sunken border border-border-default rounded text-text-primary\"\n aria-label=\"Copy URL\"\n >\n {copied ? (\n <Check className=\"w-4 h-4 text-status-success-text\" />\n ) : (\n <Copy className=\"w-4 h-4\" />\n )}\n </button>\n </div>\n </div>\n )}\n </section>\n\n {/* Active URLs list */}\n <section className=\"bg-bg-surface border border-border-default rounded-lg p-5 space-y-3\">\n <header className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">Your active URLs</h3>\n <p className=\"text-sm text-text-secondary\">\n Tokens you minted for this vibe. Revoke and rotate work immediately; revoked tokens\n fail with 403 even if the JWT hasn't expired.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onRevokeAll}\n disabled={tokens.every((t) => t.status !== 'ACTIVE')}\n className=\"flex items-center gap-1 px-3 py-1.5 text-sm bg-status-error-bg/10 text-status-error-text border border-status-error-border rounded-md hover:bg-status-error-bg/20 disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n <Trash2 className=\"w-4 h-4\" />\n Revoke all\n </button>\n </header>\n\n {tokensQuery.loading && tokens.length === 0 && (\n <div className=\"text-sm text-text-secondary py-4 flex items-center gap-2\">\n <RefreshCw className=\"w-4 h-4 animate-spin\" />\n Loading tokens…\n </div>\n )}\n {tokens.length === 0 && !tokensQuery.loading && (\n <div className=\"text-sm text-text-secondary py-4 flex items-center gap-2\">\n <Info className=\"w-4 h-4\" />\n No URLs minted yet for this vibe.\n </div>\n )}\n {tokens.length > 0 && (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-default text-left text-xs text-text-secondary\">\n <th className=\"py-2 pr-3\">Label</th>\n <th className=\"py-2 pr-3\">Fingerprint</th>\n <th className=\"py-2 pr-3\">Sections</th>\n <th className=\"py-2 pr-3\">Creds</th>\n <th className=\"py-2 pr-3\">Status</th>\n <th className=\"py-2 pr-3\">Expires</th>\n <th className=\"py-2 pr-3\">Fetches</th>\n <th className=\"py-2 pr-3\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {tokens.map((t) => (\n <Fragment key={t.id}>\n <tr className=\"border-b border-border-subtle align-top\">\n <td className=\"py-2 pr-3 text-text-primary\">{t.label ?? '—'}</td>\n <td className=\"py-2 pr-3 font-mono text-xs text-text-secondary\">\n {t.tokenFingerprint}\n </td>\n <td className=\"py-2 pr-3 text-text-secondary\">\n <span className=\"text-xs\">{t.includes.join(', ')}</span>\n </td>\n <td className=\"py-2 pr-3\">\n {t.includeCredentials ? (\n <span className=\"text-xs text-status-warning-text\">on</span>\n ) : (\n <span className=\"text-xs text-text-secondary\">off</span>\n )}\n </td>\n <td className=\"py-2 pr-3\">\n <span\n className={`text-xs px-1.5 py-0.5 rounded ${\n t.status === 'ACTIVE'\n ? 'bg-status-success-bg/20 text-status-success-text'\n : 'bg-bg-sunken text-text-secondary'\n }`}\n >\n {t.status}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"w-3 h-3\" />\n {formatExpiry(t.expiresAt)}\n </span>\n </td>\n <td className=\"py-2 pr-3 text-xs text-text-secondary\">{t.fetchCount}</td>\n <td className=\"py-2 pr-3\">\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() =>\n setAuditPanelTokenId(auditPanelTokenId === t.id ? null : t.id)\n }\n title=\"Show fetch history\"\n aria-label=\"Show fetch history\"\n className=\"p-1.5 text-text-secondary hover:text-text-primary\"\n >\n <Info className=\"w-4 h-4\" />\n </button>\n {t.status === 'ACTIVE' && (\n <>\n <button\n type=\"button\"\n onClick={async () => {\n const res = await rotateToken({ variables: { tokenId: t.id } });\n if (res.data) {\n setLastMint(res.data.rotateVibeLlmContextUrl);\n setCopied(false);\n }\n }}\n title=\"Rotate (revoke + mint a new one with same settings)\"\n aria-label=\"Rotate URL\"\n className=\"p-1.5 text-text-secondary hover:text-text-primary\"\n >\n <RotateCw className=\"w-4 h-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => revokeToken({ variables: { tokenId: t.id } })}\n title=\"Revoke\"\n aria-label=\"Revoke URL\"\n className=\"p-1.5 text-status-error-text hover:opacity-80\"\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </>\n )}\n </div>\n </td>\n </tr>\n {auditPanelTokenId === t.id && (\n <tr>\n <td colSpan={8} className=\"py-2 pr-3 bg-bg-sunken/40\">\n <AuditListInline tokenId={t.id} />\n </td>\n </tr>\n )}\n </Fragment>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n\n {/* Admin sub-panel — gated by vibe:manage permission */}\n {isAdmin && <VibeLlmContextAdminPanel vibeId={vibeId} />}\n\n {/* Help footer */}\n <p className=\"text-xs text-text-secondary flex items-center gap-1\">\n <Bot className=\"w-3 h-3\" />\n Tip: pipe the URL to any LLM with{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">curl <url></code> or{' '}\n <code className=\"bg-bg-sunken px-1 rounded\">{`curl -H \"Accept: text/markdown\" <url>`}</code>{' '}\n for a markdown snapshot.\n </p>\n </div>\n );\n}\n\nfunction AuditListInline({ tokenId }: { tokenId: string }): ReactElement {\n const { data, loading } = useQuery<{ myVibeLlmContextTokenAudits: AuditRow[] }>(GET_AUDITS, {\n variables: { tokenId, limit: 100 },\n fetchPolicy: 'cache-and-network',\n });\n const rows = data?.myVibeLlmContextTokenAudits ?? [];\n return (\n <div className=\"text-xs\">\n {loading && rows.length === 0 ? (\n <span className=\"text-text-secondary\">Loading audit log…</span>\n ) : rows.length === 0 ? (\n <span className=\"text-text-secondary\">No fetches yet.</span>\n ) : (\n <table className=\"w-full\">\n <thead>\n <tr className=\"text-text-secondary\">\n <th className=\"text-left py-1 pr-2\">When</th>\n <th className=\"text-left py-1 pr-2\">IP</th>\n <th className=\"text-left py-1 pr-2\">Format</th>\n <th className=\"text-left py-1 pr-2\">Bytes</th>\n <th className=\"text-left py-1 pr-2\">Status</th>\n <th className=\"text-left py-1 pr-2\">UA</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((r) => (\n <tr key={r.id} className=\"text-text-primary border-t border-border-subtle\">\n <td className=\"py-1 pr-2\">{new Date(r.fetchedAt).toLocaleString()}</td>\n <td className=\"py-1 pr-2 font-mono\">{r.remoteIp ?? '—'}</td>\n <td className=\"py-1 pr-2\">{r.format}</td>\n <td className=\"py-1 pr-2\">{r.bytes}</td>\n <td className=\"py-1 pr-2\">{r.status}</td>\n <td className=\"py-1 pr-2 truncate max-w-[260px]\" title={r.userAgent ?? ''}>\n {r.userAgent ?? '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAwBA,IAAM,IAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EA0DK,KAAe,CAAG;;;;;;;;;;;;;;;;GAkBlB,IAAa,CAAG;;;;;;;;;;;;;;;;;;;GAqBhB,IAAe,CAAG;;;;;;;;;;;;;;;;GAkBlB,KAAe,CAAG;;;;;;;;;;;;;;GAgBlB,KAAe,CAAG;;;;;;;;GAUlB,IAAe,CAAG;;;;;;;;;;;;;;GAgBlB,IAAa,CAAG;;;;GAMhB,IAAa,CAAG;;;;;;;;;;;;;GAehB,IAAuD;CAC3D;EAAE,OAAO;EAAU,OAAO;EAAG;CAC7B;EAAE,OAAO;EAAW,OAAO;EAAG;CAC9B;EAAE,OAAO;EAAY,OAAO;EAAI;CAChC;EAAE,OAAO;EAAU,OAAO;EAAQ;CACnC;AAED,eAAe,GAAgB,GAA6B;AAC1D,KAAI;AACF,QAAM,UAAU,UAAU,UAAU,EAAK;SACnC;EACN,IAAM,IAAK,SAAS,cAAc,WAAW;AAO7C,EANA,EAAG,QAAQ,GACX,EAAG,MAAM,WAAW,SACpB,EAAG,MAAM,UAAU,KACnB,SAAS,KAAK,YAAY,EAAG,EAC7B,EAAG,QAAQ,EACX,SAAS,YAAY,OAAO,EAC5B,SAAS,KAAK,YAAY,EAAG;;;AAIjC,SAAS,EAAa,GAA2B;CAC/C,IAAM,IAAO,IAAI,KAAK,EAAU,CAAC,SAAS,GAAG,KAAK,KAAK;AACvD,KAAI,IAAO,EAAG,QAAO;CACrB,IAAM,IAAQ,KAAK,MAAM,KAAQ,MAAO,KAAK,IAAI,EAC3C,IAAO,KAAK,MAAO,KAAQ,MAAO,KAAK,OAAQ,MAAO,IAAI;AAGhE,QAFI,IAAQ,KAAW,GAAG,KAAK,MAAM,IAAQ,GAAG,CAAC,KAC7C,IAAQ,IAAU,GAAG,EAAM,IAAI,EAAK,KACjC,GAAG,EAAK;;AAajB,SAAgB,EAAuB,EACrC,WACA,oBAAiB,EAAE,IACyB;CAC5C,IAAM,EAAE,qBAAkB,GAAgB,EACpC,KAAU,EAAc,EAAiB,YAAY,EACrD,KAAgB,EACpB,IACA;EACE,WAAW,EAAE,WAAQ;EACrB,aAAa;EACd,CACF,EACK,IAAc,EAA+D,GAAY;EAC7F,WAAW,EAAE,WAAQ;EACrB,aAAa;EACd,CAAC,EACI,CAAC,IAAc,KAAqB,EAgBxC,GAAc,EAAE,gBAAgB,CAAC,2BAA2B,EAAE,CAAC,EAC3D,CAAC,IAAa,KAAoB,EAWtC,IAAc,EAAE,gBAAgB,CAAC,yBAAyB,EAAE,CAAC,EACzD,CAAC,KAAe,EAGpB,IAAc,EAAE,gBAAgB,CAAC,yBAAyB,EAAE,CAAC,EACzD,CAAC,KAAe,EACpB,GACA,EAAE,gBAAgB,CAAC,yBAAyB,EAAE,CAC/C,EACK,CAAC,KAAa,EAClB,GACA,EAAE,gBAAgB,CAAC,yBAAyB,EAAE,CAC/C,EAEK,IAAW,GAAc,MAAM,0BAC/B,IAAS,EAAY,MAAM,0BAA0B,EAAE,EAGvD,CAAC,GAAU,KAAe,EAAiB,EAAE,EAC7C,CAAC,GAAc,KAAmB,EAAkB,GAAM,EAC1D,CAAC,GAAe,KAAoB,EAA0B,IAAI,IAAI,EAAa,CAAC,EACpF,CAAC,GAAY,KAAiB,EAAiB,GAAG,EAClD,CAAC,GAAsB,KAA2B,EAAiB,GAAG,EACtE,CAAC,GAAO,KAAY,EAAiB,GAAG,EACxC,CAAC,GAAU,KAAe,EAA4B,KAAK,EAC3D,CAAC,IAAQ,KAAa,EAAkB,GAAM,EAC9C,CAAC,GAAW,KAAgB,EAAkB,GAAM,EACpD,CAAC,GAAmB,MAAwB,EAAwB,KAAK;AAI/E,SAAgB;AACT,QACL,EAAY,KAAK,IAAI,GAAG,KAAK,OAAO,EAAS,cAAc,QAAQ,KAAK,CAAC,CAAC,EAC1E,EAAgB,EAAS,mBAAmB,EAC5C,EAAiB,IAAI,IAAK,EAAS,YAA6B,EAAa,CAAC,EAC9E,EAAc,EAAS,qBAAqB,GAAG,EAC/C,EAAwB,EAAS,0BAA0B,GAAG;IAC7D,CAAC,EAAS,CAAC;CAEd,IAAM,MAAmB,MAAoB;AAC3C,KAAkB,MAAS;GACzB,IAAM,IAAO,IAAI,IAAI,EAAK;AAG1B,UAFI,EAAK,IAAI,EAAI,GAAE,EAAK,OAAO,EAAI,GAC9B,EAAK,IAAI,EAAI,EACX;IACP;;AA0DJ,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAM,WAAU,2CAA4C,CAAA,EAC5D,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAmB;OAE5B,CAAA,EACJ,kBAAC,KAAD;OAAG,WAAU;iBAAsB;OAI/B,CAAA,CACA;QACF;;IACF,CAAA;GAGN,kBAAC,WAAD;IAAS,WAAU;cAAnB;KACE,kBAAC,UAAD;MAAQ,WAAU;gBAAlB,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;iBAA4C;OAAmB,CAAA,EAC7E,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAGvC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;OACE,MAAK;OACL,SAtFa,YAAY;AAcjC,QAbA,MAAM,GAAa,EACjB,WAAW;SACT;SACA,OAAO;UACL,YAAY,KAAK,IAAI,IAAI,KAAK,IAAI,QAAc,IAAI,IAAW,KAAK,GAAG,CAAC;UACxE,oBAAoB;UACpB,UAAU,MAAM,KAAK,EAAc;UACnC,mBAAmB;UACnB,wBAAwB,KAAwB;UACjD;SACF,EACF,CAAC,EACF,EAAa,GAAK,EAClB,iBAAiB,EAAa,GAAM,EAAE,IAAK;;OAyEnC,UAAU,EAAkB;OAC5B,WAAU;iBAJZ,CAMG,KAAa,CAAC,EAAkB,WAAW,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EACxE,EAAkB,UAAU,YAAY,IAAY,UAAU,gBACxD;SACF;;KAGT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAAkB,CAAA,EACtF,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,EAAY,KAAK,MAChB,kBAAC,UAAD;QAEE,MAAK;QACL,eAAe,EAAY,EAAE,MAAM;QACnC,WAAW,yCACT,MAAa,EAAE,QACX,2EACA;kBAGL,EAAE;QACI,EAVF,EAAE,MAUA,CACT;OACF,kBAAC,QAAD;QAAM,WAAU;kBAAmC;QAAuB,CAAA;OAC1E,kBAAC,SAAD;QACE,MAAK;QACL,KAAK;QACL,KAAK;QACL,OAAO;QACP,WAAW,MAAM,EAAY,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,OAAO,EAAE,OAAO,MAAM,IAAI,EAAE,CAAC,CAAC;QACrF,WAAU;QACV,CAAA;OACE;QACF,EAAA,CAAA;KAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAjB;OACE,kBAAC,SAAD;QACE,MAAK;QACL,SAAS;QACT,WAAW,MAAM,EAAgB,EAAE,OAAO,QAAQ;QAClD,WAAU;QACV,CAAA;OACF,kBAAC,QAAD,EAAA,UAAM,sDAAyD,CAAA;OAC9D,IACC,kBAAC,GAAD;QACE,WAAU;QACV,cAAW;QACX,CAAA,GAEF,kBAAC,IAAD;QAAQ,WAAU;QAA8B,cAAW;QAAyB,CAAA;OAEhF;SACP,KACC,kBAAC,KAAD;MAAG,WAAU;gBAAb,CACE,kBAAC,GAAD,EAAe,WAAU,oCAAqC,CAAA,EAC9D,kBAAC,QAAD,EAAA,UAAM,+HAGC,CAAA,CACL;QAEF,EAAA,CAAA;KAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAE5D,CAAA,EACR,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAa,KAAK,MACjB,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,GAAgB,EAAI;OACnC,WAAW,2CACT,EAAc,IAAI,EAAI,GAClB,4EACA;iBAGL;OACM,EAVF,EAUE,CACT;MACE,CAAA,CACF,EAAA,CAAA;KAGL,EAAe,SAAS,KACvB,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;MAAO,WAAU;gBAAmD;MAE5D,CAAA,EACR,kBAAC,UAAD;MACE,OAAO;MACP,WAAW,MAAM,EAAwB,EAAE,OAAO,MAAM;MACxD,WAAU;gBAHZ,CAKE,kBAAC,UAAD;OAAQ,OAAM;iBAAG;OAAgD,CAAA,EAChE,EAAe,KAAK,MACnB,kBAAC,UAAD;OAAmB,OAAO,EAAE;iBACzB,EAAE;OACI,EAFI,EAAE,GAEN,CACT,CACK;QACL,EAAA,CAAA;KAIR,kBAAC,OAAD,EAAA,UAAA;MACE,kBAAC,SAAD;OAAO,WAAU;iBAAmD;OAE5D,CAAA;MACR,kBAAC,YAAD;OACE,OAAO;OACP,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM,MAAM,GAAG,KAAK,CAAC;OAC7D,MAAM;OACN,aAAY;OACZ,WAAU;OACV,CAAA;MACF,kBAAC,KAAD;OAAG,WAAU;iBAAb,CAAiD,EAAW,QAAO,gBAAiB;;MAChF,EAAA,CAAA;KACE;;GAGV,kBAAC,WAAD;IAAS,WAAU;cAAnB;KACE,kBAAC,UAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA4C;MAAuB,CAAA,EACjF,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAGvC,CAAA,CACG,EAAA,CAAA;KACT,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QAAO,WAAU;kBAAmD;QAE5D,CAAA,EACR,kBAAC,SAAD;QACE,MAAK;QACL,OAAO;QACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM,MAAM,GAAG,IAAI,CAAC;QACvD,aAAY;QACZ,WAAU;QACV,CAAA,CACE;UACN,kBAAC,UAAD;OACE,MAAK;OACL,SA9NS,YAAY;QAC7B,IAAM,IAAM,MAAM,GAAY,EAC5B,WAAW;SACT;SACA,OAAO;UACL,OAAO,KAAS;UAChB,YAAY,KAAK,IAAI,IAAI,KAAK,IAAI,QAAc,IAAI,IAAW,KAAK,GAAG,CAAC;UACxE,oBAAoB;UACpB,UAAU,MAAM,KAAK,EAAc;UACpC;SACF,EACF,CAAC;AACF,QAAI,EAAI,SACN,EAAY,EAAI,KAAK,0BAA0B,EAC/C,EAAU,GAAM,EAChB,EAAS,GAAG;;OAgNN,UAAU,EAAiB;OAC3B,WAAU;iBAET,EAAiB,UAAU,gBAAgB;OACrC,CAAA,CACL;;KAEL,KACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD,EAAO,WAAU,oCAAqC,CAAA;QACtD,kBAAC,QAAD;SAAM,WAAU;mBAAgC;SAAoB,CAAA;QACpE,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CAA8C,eAChC,EAAa,EAAS,UAAU,CACvC;;QACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QACE,UAAA;QACA,OAAO,EAAS;QAChB,WAAU;QACV,cAAW;QACX,CAAA,EACF,kBAAC,UAAD;QACE,MAAK;QACL,SAzNU,YAAY;AAC7B,eACL,MAAM,GAAgB,EAAS,IAAI,EACnC,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,IAAK;;QAsN5B,WAAU;QACV,cAAW;kBAEV,KACC,kBAAC,GAAD,EAAO,WAAU,oCAAqC,CAAA,GAEtD,kBAAC,IAAD,EAAM,WAAU,WAAY,CAAA;QAEvB,CAAA,CACL;SACF;;KAEA;;GAGV,kBAAC,WAAD;IAAS,WAAU;cAAnB;KACE,kBAAC,UAAD;MAAQ,WAAU;gBAAlB,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;iBAA4C;OAAqB,CAAA,EAC/E,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAGvC,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,UAAD;OACE,MAAK;OACL,SAhQU,YAAY;AAE5B,eAAO,SAAW,OAClB,CAAC,OAAO,QACN,+IACD,IAIH,MAAM,EAAU,EAAE,WAAW,EAAE,WAAQ,EAAE,CAAC;;OAwPlC,UAAU,EAAO,OAAO,MAAM,EAAE,WAAW,SAAS;OACpD,WAAU;iBAJZ,CAME,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAAA,aAEvB;SACF;;KAER,EAAY,WAAW,EAAO,WAAW,KACxC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,IAAD,EAAW,WAAU,wBAAyB,CAAA,EAAA,kBAE1C;;KAEP,EAAO,WAAW,KAAK,CAAC,EAAY,WACnC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,oCAExB;;KAEP,EAAO,SAAS,KACf,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;QAAI,WAAU;kBAAd;SACE,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAU,CAAA;SACpC,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAgB,CAAA;SAC1C,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAa,CAAA;SACvC,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAU,CAAA;SACpC,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAW,CAAA;SACrC,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAY,CAAA;SACtC,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAY,CAAA;SACtC,kBAAC,MAAD;UAAI,WAAU;oBAAY;UAAY,CAAA;SACnC;WACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAO,KAAK,MACX,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAd;SACE,kBAAC,MAAD;UAAI,WAAU;oBAA+B,EAAE,SAAS;UAAS,CAAA;SACjE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAE;UACA,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACZ,kBAAC,QAAD;WAAM,WAAU;qBAAW,EAAE,SAAS,KAAK,KAAK;WAAQ,CAAA;UACrD,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAE,qBACD,kBAAC,QAAD;WAAM,WAAU;qBAAmC;WAAS,CAAA,GAE5D,kBAAC,QAAD;WAAM,WAAU;qBAA8B;WAAU,CAAA;UAEvD,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACZ,kBAAC,QAAD;WACE,WAAW,iCACT,EAAE,WAAW,WACT,qDACA;qBAGL,EAAE;WACE,CAAA;UACJ,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACZ,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EAC5B,EAAa,EAAE,UAAU,CACrB;;UACJ,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBAAyC,EAAE;UAAgB,CAAA;SACzE,kBAAC,MAAD;UAAI,WAAU;oBACZ,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,UAAD;YACE,MAAK;YACL,eACE,GAAqB,MAAsB,EAAE,KAAK,OAAO,EAAE,GAAG;YAEhE,OAAM;YACN,cAAW;YACX,WAAU;sBAEV,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;YACrB,CAAA,EACR,EAAE,WAAW,YACZ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,UAAD;YACE,MAAK;YACL,SAAS,YAAY;aACnB,IAAM,IAAM,MAAM,EAAY,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAC/D,aAAI,EAAI,SACN,EAAY,EAAI,KAAK,wBAAwB,EAC7C,EAAU,GAAM;;YAGpB,OAAM;YACN,cAAW;YACX,WAAU;sBAEV,kBAAC,IAAD,EAAU,WAAU,WAAY,CAAA;YACzB,CAAA,EACT,kBAAC,UAAD;YACE,MAAK;YACL,eAAe,EAAY,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;YAC5D,OAAM;YACN,cAAW;YACX,WAAU;sBAEV,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;YACvB,CAAA,CACR,EAAA,CAAA,CAED;;UACH,CAAA;SACF;WACJ,MAAsB,EAAE,MACvB,kBAAC,MAAD,EAAA,UACE,kBAAC,MAAD;QAAI,SAAS;QAAG,WAAU;kBACxB,kBAAC,IAAD,EAAiB,SAAS,EAAE,IAAM,CAAA;QAC/B,CAAA,EACF,CAAA,CAEE,EAAA,EArFI,EAAE,GAqFN,CACX,EACI,CAAA,CACF;;MACJ,CAAA;KAEA;;GAGT,MAAW,kBAAC,GAAD,EAAkC,WAAU,CAAA;GAGxD,kBAAC,KAAD;IAAG,WAAU;cAAb;KACE,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA;;KACO;KAClC,kBAAC,QAAD;MAAM,WAAU;gBAA4B;MAAuB,CAAA;;KAAI;KACvE,kBAAC,QAAD;MAAM,WAAU;gBAA6B;MAA+C,CAAA;KAAC;KAAI;KAE/F;;GACA;;;AAIV,SAAS,GAAgB,EAAE,cAA8C;CACvE,IAAM,EAAE,SAAM,eAAY,EAAsD,GAAY;EAC1F,WAAW;GAAE;GAAS,OAAO;GAAK;EAClC,aAAa;EACd,CAAC,EACI,IAAO,GAAM,+BAA+B,EAAE;AACpD,QACE,kBAAC,OAAD;EAAK,WAAU;YACZ,KAAW,EAAK,WAAW,IAC1B,kBAAC,QAAD;GAAM,WAAU;aAAsB;GAAyB,CAAA,GAC7D,EAAK,WAAW,IAClB,kBAAC,QAAD;GAAM,WAAU;aAAsB;GAAsB,CAAA,GAE5D,kBAAC,SAAD;GAAO,WAAU;aAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;IAAI,WAAU;cAAd;KACE,kBAAC,MAAD;MAAI,WAAU;gBAAsB;MAAS,CAAA;KAC7C,kBAAC,MAAD;MAAI,WAAU;gBAAsB;MAAO,CAAA;KAC3C,kBAAC,MAAD;MAAI,WAAU;gBAAsB;MAAW,CAAA;KAC/C,kBAAC,MAAD;MAAI,WAAU;gBAAsB;MAAU,CAAA;KAC9C,kBAAC,MAAD;MAAI,WAAU;gBAAsB;MAAW,CAAA;KAC/C,kBAAC,MAAD;MAAI,WAAU;gBAAsB;MAAO,CAAA;KACxC;OACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAK,KAAK,MACT,kBAAC,MAAD;IAAe,WAAU;cAAzB;KACE,kBAAC,MAAD;MAAI,WAAU;gBAAa,IAAI,KAAK,EAAE,UAAU,CAAC,gBAAgB;MAAM,CAAA;KACvE,kBAAC,MAAD;MAAI,WAAU;gBAAuB,EAAE,YAAY;MAAS,CAAA;KAC5D,kBAAC,MAAD;MAAI,WAAU;gBAAa,EAAE;MAAY,CAAA;KACzC,kBAAC,MAAD;MAAI,WAAU;gBAAa,EAAE;MAAW,CAAA;KACxC,kBAAC,MAAD;MAAI,WAAU;gBAAa,EAAE;MAAY,CAAA;KACzC,kBAAC,MAAD;MAAI,WAAU;MAAmC,OAAO,EAAE,aAAa;gBACpE,EAAE,aAAa;MACb,CAAA;KACF;MATI,EAAE,GASN,CACL,EACI,CAAA,CACF;;EAEN,CAAA"}
|